返回信息流软件环境假设:uboot,linux
硬件环境假设:ppc 或 arm, nor flash
开发板从上电开始,到linux开始启动,都进行了哪些工作
前两天面试有好几次被问到了这个问题,自己当时的回答大致如下:
1、上电后cpu执行某个特定地址执行指令,这个地址一般都是一句跳转,调到uboot镜像位置
2、uboot img的代码在flash上做片上执行,进行第一阶段初始化:包括cpu初始化、内存初始化,此阶段主要是汇编代码。
3、代码搬移:执行代码由flash搬移到sdram上继续执行,进行第二阶段初始化,此阶段绝大部分是c代码
4、第二阶段初始化包括:串口、波特率、环境变量、flash芯片、中断和trap初始化
5、第二阶段初始化完成后,进入main_loop循环。在指定时间(环境变量配置)内如果用户未干预则尝试启动内核,如果用户干预则进入命令响应模式,可以执行命令查看cpu寄存器、flash状态等,也可以设置环境变量等。
6、如果是启动内核,则将内核镜像拷贝到内存的特定地址准备执行(具体地址是如何确定的跟cpu类型有关,此外内核编译的-e选项即entry point会有影响,详细的还在研究,请看楼下讨论)。uboot将cmdline、board description及initrd(如果有的话)参数传递给内核。最后一句采用函数指针调用的方式执行内核代码。
大致是这样,但是感觉说的还有些泛,被问到细节就说不清了,手头的资料大部分都是对uboot启动最前面那段汇编的分析。
大家有什么好的资料,尤其是对于上述过程有整体描述的(详细一些),分享一下吧~~
这是一条镜像帖。来源:北邮人论坛 / embedded-system / #6267同步于 2009/10/29
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Embedded_System机器人发帖
[求助&讨论]嵌入式开发板上电后的启动顺序
hobby
2009/10/29镜像同步39 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
http://www.chinaunix.net/jh/4/1019424.html
这个里面pdf第四章讲vivi的
基本就是按照上电流程讲的,一直到启动linux
uboot感觉太全面了,好像很少有写里面代码分析的,最多也就是一部分
vivi简单,代码容易看完,很多人写笔记,麻雀虽小五脏俱全啊
一个比较全的笔记
http://blog.chinaunix.net/u/21948/showart.php?id=344254
希望有帮助
多谢多谢
果然很有心得哇
我好好学习学习
【 在 eelb (熊猫酒仙) 的大作中提到: 】
: http://www.chinaunix.net/jh/4/1019424.html
: 这个里面pdf第四章讲vivi的
: 基本就是按照上电流程讲的,一直到启动linux
: ...................
PowerPC-uboot启动分析(MPC8349)
以下关系论文,暂时谢绝转载
对stage1汇编的分析请参考:http://blog.chinaunix.net/u2/80953/showart.php?id=2004705
3.1 系统上电启动分析
系统上电后,经过至少32个CLKIN时钟输入后,MPC8349E处理器会检测复位配置输入信号CFG_RESET_SOURCE[0:2]来确定输入时钟分频模式及进行复位配置字源选择。在目标板上可以设置跳线来改变CFG_RESET_SOURCE[0:2]来选择MPC83493E是从local bus EEPROM(flash)或者I2C EEPROM加载复位配置字,还是使用采用处理器内的硬编码默认配置字。设置跳线使CFG_RESET_SOURCE[0:2]为0b000,选择从local bus EEPROM上加载复位配置字。
读取复位配置字后(RCWL为0x04040000,RCWH为0xB460A000),会设置相应的寄存器。RCWL主要用于设置时钟;RCWH和PCI中断、主从模式、启动ROM位置、TSEC模式等相关。RCWH的BMS位值为1,定义了e300核心的MSR[IP]位初始值,也就决定了中断向量的前缀0xFFF,启动存储空间的位置为0xFF80_0000~0xFFFF_FFFF;SWEN位为0禁止软件看门狗;ROMLOC位为0b110,决定选择local bus GPCM-16bit ROM片上外围作启动ROM。对复位向量和本地地址映射的默认启动ROM的访问将直接指向ROMLOC指定的接口。选中的启动ROM的本地访问窗口将被使能,并初始化基地址为0xFF80_0000,窗口大小为8M。
以上工作完成以后,系统会向复位向量地址0xFFF0_0100获取第一条指令,也就是驻留在local bus EEPROM(flash)中的U-Boot第一条代码,由此正式进入Boot Loader职能的范围。U-Boot的启动主要分为stage1和stage2两个阶段:严重依赖于CPU体系结构的代码通常都放在stage1,主要由汇编语言实现,运行在系统flash中;而stage2在前者的基础上建立了“正常”的C语言环境,由C代码实现,这样可以实现更加复杂的功能,更具有可读性和可移植性,在系统RAM中运行,可以让执行速度更快。
3.2 U-Boot启动stage1阶段
U-Boot的stage1启动主要流程体现在cpu/mpc83xx/start.S文件中,用汇编语言写成。主要完成CPU初始化,RAM初始化,串口初始化,代码搬运等,
3.2.1 代码入口
一个可执行的镜像必须有一个入口点并且只能有一个全局入口,这个入口是由CPU目录下的连接器脚本u-boot.lds用语句ENTRY(_start)来告诉编译器代码入口,此入口代码即是系统上电后获取的第一条指令。代码对应如下:
. = EXC_OFF_SYS_RESET
.globl _start
_start: /* time t 0 */
li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH by starby */
nop
b boot_cold
3.2.2 代码分析
首先更改IMMR基址为CONFIG_SYS_IMMR;紧接着跳转到init_e300_core汇编例程中,初始化e300核心,禁止中断响应,只允许machine check中断和system reset中断,禁止指令和数据地址转换,即关闭MMU,进行实地址转换,设置为supervisor级别,禁止看门狗,无效指令和数据cache,设置HID0寄存器等,为系统创建一个干净可靠的初始环境[5]。
此时flash的映射需要重新设置映射到CONFIG_SYS_MONITOR_BASE,方法是写BR0和OR0寄存器。为防止程序跑飞,中间通过map_flash_by_law1例程用LAW1来映射flash做个过渡,并紧接着通过计算flash中代码的问题,跳转到flash中in_flash处执行代码。然后再次通过remap_flash_by_law0例程用LBIU LAW0和LBC bank 0映射flash的基地址为CONFIG_SYS_MONITOR_BASE,大小为16MB,然后清除LBIU LAW1对flash的映射。
setup_bats例程分别对DDR,PCI、PCI2、IMMR、flash及DCACHE中的栈空间设置指令和数据块地址转换表,同时无效所有的TLB页表[5]。为了构建一个C语言环境,就需要分配一个栈空间,但是系统在上电后,由于存储控制器未初始化,因此主存储器无法使用,也就没有数据段和BSS段,所以利用在MPC8349E处理器中的32k数据cache用作RAM分配一个栈空间。为了以后能使用此数据cache中分配的栈空间,需要使能BAT转换,通过enable_addr_trans例程使能指令和数据地址转换,即打开MMU。并由dcache_enable例程使能数据cache。lock_ram_in_cache例程在数据cache中分配初始化RAM并锁住,用作stage1的堆栈空间及存储全局数据结构gd_t。随后的指令设置gpr1做栈指针,这样就执行简单的C代码了。
进入cpu/mpc83xx.c中的cpu_init_f函数,声明全局数据结构体指针gd指向cache的全局数据地址,然后清零全局数据区。在此函数中主要完成对IMMR相关寄存器的初始化,设置中断优先级、时钟模式、内存映射窗口、 flash、VSC7385、LED、CF card等基址;并简单设置全局变量gd_t。
将启动类型赋给gpr3,作为板子初始化代码第一阶段board_init_f(lib_ppc/board.c)函数的参数。首先声明一个变量指向全局数据地址,通过一个内嵌汇编作内存屏障,更新cache中的数据,保持和RAM一致。然后通过下面一段代码依次调用函数指针数组init_sequence 中定义的函数完成一系列基本初始化,如果中途出错,调用hung()进入死循环。
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr) () != 0)
hang ();
}
上面的初始化序列完成以后,RAM映射完成,并可以工作。首先计算U-Boot镜像的长度,及搬运到RAM中的目的地址,建立起正常的C环境,跳转到lib_ppc/board.c中的board_init_r()函数中进行stage2的初始化。
3.3 U-Boot启动stage2阶段
此阶段运行在RAM中,进行CPU及外设的进一步初始化,代码主要由C语言完成,主要流程体现在lib_ppc/board.c的board_init_r()函数中,比较容易看懂。
【 在 hobby 的大作中提到: 】
: 软件环境假设:uboot,linux
: 硬件环境假设:ppc 或 arm, nor flash
: 开发板从上电开始,到linux开始启动,都进行了哪些工作
: ...................
对于第6条: 以下关于PowerPC平台的u-boot-1.2.0以后的版本
较新的内核已经有所变化,采用device tree 文件dts来给内核传递参数。设备外围需要一个dts来描述板子外围,比如中断,地址空间分配等,串口波特率等。
启动时采用bootm kern_addr ramdisk_addr dt_addr
恩,弄清楚这个过程会学习到很多东西阿,不过我还没时间琢磨这个呢
【 在 hobby (hobby) 的大作中提到: 】
: 软件环境假设:uboot,linux
: 硬件环境假设:ppc 或 arm, nor flash
: 开发板从上电开始,到linux开始启动,都进行了哪些工作
: ...................
嗯,昨天看yihang发的那个还是挺细的,但是条理上好像还不是很好,有功夫总结一个
【 在 ArmStrong (奶瓶) 的大作中提到: 】
: 恩,弄清楚这个过程会学习到很多东西阿,不过我还没时间琢磨这个呢
版主大人还在忙着找工作呢 有兴趣的话来我们这看看吧
【 在 hobby 的大作中提到: 】
1、上电后cpu执行某个特定地址执行指令,这个地址一般都是一句跳转,调到uboot镜像位置
上电后的第一个指令执行的位置取决于CPU
-----------
这个位置必须有映像 而不是有跳转语句再跳到uboot镜像
对于ARM 此地址是0 对于PowerPC 此地址一般是0x100或者0xFFF00100
可以瞅瞅http://blog.csdn.net/sailor_8318/archive/2009/09/20/4573932.aspx 供参考
2、uboot img的代码在flash上做片上执行,进行第一阶段初始化:包括cpu初始化、内存初始化,此阶段主要是汇编代码。
3、代码搬移:执行代码由flash搬移到sdram上继续执行,进行第二阶段初始化,此阶段绝大部分是c代码
4、第二阶段初始化包括:串口、波特率、环境变量、flash芯片、中断和trap初始化
--------
上面345几步基本是U-boot在ARM平台下的启动流程
但是U-boot在PPC架构下的启动和ARM平台还是差别挺大的 在PPC下更复杂
在PPC下 启动第一个阶段已经有C程序了 因为可以借用芯片内部DPRAM做栈
然后是初始化SDRAM 代码重定位 建立新的栈 跳转到SDRAM中
跳转前需要做很多修正 包括全局符号表 函数指针 环境变量等等
最近分析了下启动阶段的重定位问题 希望能对版主的面试有点借鉴意义
从反汇编来看U-boot在PPC架构下的PIC(位置无关程序)设计
http://blog.csdn.net/sailor_8318/archive/2009/11/22/4852691.aspx
6、如果是启动内核,则将内核镜像拷贝到内存的0地址准备执行。uboot将cmdline、board description及initrd(如果有的话)参数传递给内核。最后一句采用函数指针调用的方式执行内核代码。
------------
bootm在ARM平台和PPC平台下的实现不一样 参数也不一样 最新的2.6.25内核开始还需要设备配置文件