设为首页 加入收藏

TOP

ppc-booting-sequence(二)
2014-11-24 12:00:15 来源: 作者: 【 】 浏览:1
Tags:ppc-booting-sequence
ddr_sp , r4 = gd, r5= addr


Relocate_code:


(1) 使能I/D cache


(2) 使用新的stack:r1=addr_sp。将gd(global data)保存在 r9中,将relocate code地址保存在r10中


mr r1, r3 /* Set new stack pointer */


mr r9, r4 /* Save copy of Init Data pointer */


mr r10, r5 /* Save copy of Destination Address */


(3) 重定位GOT


(4) Relocate code


(5) Flush D cache


(6) 跳转到in_ram代码中,r10中保存着RAM中代码起始位置,加上in_ram的相对位置即为in_ram在ram中的位置:


addi r0, r10, in_ram - _start + _START_OFFSET


mtlr r0


blr /* NEVER RETURNS! */


in_ram:


(1) 重定位GOT2


(2) Clear bss


(3) 将gd以及代码在内存中的起始位置作为参数,调用board_init_r


mr r3, r9 /* Init Data pointer */


mr r4, r10 /* Destination Address */


bl board_init_r


下面再次进入board.c 文件


board_init_r:


这部分代码初始化一些列外设,这里只提几个感兴趣的地方。


(1) 建立Command table。U-boot支持N多命令,通过一个cmdtbl来管理,这个cmdtbl是在运行时被负值的


for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {……}


u-boot的命令都被定义在.u_boot.cmd段,并在链接时确定期位置:在__u_boot_cmd_start和__u_boot_cmd_end之间。


(2) Trap的安装是通过调用start.s中的代码完成的。其实就是将原有的trap重定位到dest_addr,也就是RAM中的起始位置。


(3) 茫茫多设备的初始化 …………


(4) 进入main_loop()等待用户输入命令,如bootm命令。


三、 Bootm代码分析
目前大多数kernel的booting都由bootm来完成,可以说这个函数是连接U-boot和kernel的桥梁,bootm命令主要通过do_bootm()(/common/cmd_bootm.c)函数和do_bootm_linux()(/lib_ppc/bootm.c)函数来实现。后者是与架构相关的。Powerpc kernel booting有两种方式:1、使用of——open firmware;2、使用dt——device tree。现在高版本的u-boot基本都支持dt启动方式。在制作uImage时会在Image head中加入一段信息,告诉u-boot使用的启动方式。这里只讨论dt启动方式。


其实整个启动过程很简单,do_bootm命令接收命令行参数,根据命令行参数对内核的资源进行有效性校验,然后将所有信息存入image结构。并把这个结构传递给bootm.c。bootm.c 从image中找到内核、ramdisk、cmdline以及FDT,将cmdline保存在固定的位置,然后跳转到kernel所在的地址,并把FDT和kernel本身的地址作为参数传递过去,kernel会根据cmdline中的信息选择启动方式。


1、当用户敲入bootm kernel_addr – fdt_addr时,u-boot调用do_bootm函数。


2、Local memory block initiate。初始化本地存储块(可能是用户kernel内存管理)


3、boot_get_kernel(),这个函数找到kernel image,验证其完整性,并定位内核数据。将信息存放在images中。


fit_parse_conf;取出load_addr,这个地址在uImage编译时确定。


genimg_get_image;如果image在flash上,则拷贝到load_addr内存中。


image_get_type;判断image head的类型,显然kernel应该是IH_TYPE_KERNEL类型的。


image_get_kernel;根据image head中的信息对image进行校验。


image_get_data;取得kernel数据指针。


image_get_data_size;取得kernel大小。


返回image地址


4、判断压缩格式,并解压缩内核


5、调用do_bootm_linux()函数启动内核。


下面分析do_bootm_linux()函数。这个函数比较重要,我们将详细分析之。


(1) 首先为内核命令行参数分配空间,这个空间必须在内核可以访问的高地址,并且不会被其他数据干扰。取出sp值:int sp; asm( "mr %0,1": "=r"(sp) : );// sp=r1。即栈。


(2) sp -= 1024; 留出1k空间,保证访问安全


(3) lmb_reserve(lmb, sp, (CFG_SDRAM_BASE + get_effective_memsize() - sp)); //把这sp以上的空间加入到lmb保护起来。


(4) boot_get_fdt :获取fdt,这段代码较长,我没有细看。主要就是从image中获取tdt的地址和大小。


(5) boot_get_cmdline:获取命令行参数,在lmb中申请一段空间,然后把uboot中bootargs的内容复制到里面。


(6) boot_get_kbd:获取board info,也就是从gd(global data)中将bd复制到lmb中。


(7) 找到内核起始位置


(8) 找ramdisk。如果有,首先判断是否有效,是否是initrd,然后拷贝到RAM中的rd_load地址,这个地址在image 结构中有定义。


(9) boot_relocate_fdt :将fdt定位到lmb中


(10) 启动内核,将fdt参数和内核本身参数传递给内核。


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇双核处理器ARM+DSP如何实现协同工.. 下一篇移植Linux内核到S3C2410开发板的..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·C++ Lambda表达式保 (2025-12-26 05:49:45)
·C++ Lambda表达式的 (2025-12-26 05:49:42)
·深入浅出 C++ Lambda (2025-12-26 05:49:40)
·C语言指针从入门到基 (2025-12-26 05:21:36)
·【C语言指针初阶】C (2025-12-26 05:21:33)