uboot 源码导读MIPS(二) start.S篇
这一篇我会陆续加更多的注释。。。写得不对的请大家指正,感谢。我现在也是小白啊。
mips架构说明;uboot 20121.04.01版本。
总体流程:

紫色部分我下面会有说明:
1 lowlevel_init:
这个在mips和arm不大一样。mips仅仅是设置有一些CP0的寄存器;arm有很多汇编;
2 board_init_f:
2.1调用init_sequence 函数队列,对板子进行一些初始化:
init_fnc_t *init_sequence[] = {
board_early_init_f,
timer_init,
env_init, /* initialize environment */
#ifdef CONFIG_INCA_IP
incaip_set_cpuclk, /* set cpu clock according to env. variable */
#endif
init_baudrate, /* initialize baudrate settings */
serial_init, /* serial communications setup */
console_init_f,
display_banner, /* say that we are here */
checkboard,
init_func_ram,
NULL,
};
2.2 然后计算:addr_sp, id, addr 这三个参数;
2.3 最后调用:relocate_code(addr_sp, id, addr);
3 relocate_code:
3.1 然后计算出了t0 t1 t2;
3.2 将uboot.bin搬到RAM;
3.3 flush_cache;
3.4 计算in_ram地址,然后到in_ram执行代码;
4 board_init_r
该函数在arch/mips/lib/board.c中。
初始化:FLASH NAND PCI console environment ...
最后进入:main_loop (); //循环执行,试图自动启动,接受用户从串口输入的命令,然后进行相应的工作,设置延时时间,确定目标板是进入下载模式还是启动加载模式
下面是源码说明:
#include <asm-offsets.h> #include <config.h> #include <asm/regdef.h> #include <asm/mipsregs.h> #ifndef CONFIG_SYS_MIPS_CACHE_MODE #define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT #endif /* * For the moment disable interrupts, mark the kernel mode and * set ST0_KX so that the CPU does not spit fire when using * 64-bit addresses. */ /*下面定义了两个宏,后面会用到*/ .macro setup_c0_status set clr .set push mfc0 t0, CP0_STATUS or t0, ST0_CU0 | \set | 0x1f | \clr xor t0, 0x1f | \clr mtc0 t0, CP0_STATUS .set noreorder sll zero, 3 # ehb .set pop .endm .macro setup_c0_status_reset #ifdef CONFIG_64BIT setup_c0_status ST0_KX 0 #else setup_c0_status 0 0 #endif .endm #define RVECENT(f,n) \ b f; nop #define XVECENT(f,bev) \ b f ; \ li k0,bev .set noreorder .globl _start .text _start: RVECENT(reset,0) # U-boot entry point RVECENT(reset,1) # software reboot #ifdef CONFIG_SYS_XWAY_EBU_BOOTCFG /* * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to * access external NOR flashes. If the board boots from NOR flash the * internal BootROM does a blind read at address 0xB0000010 to read the * initial configuration for that EBU in order to access the flash * device with correct parameters. This config option is board-specific. */ .word CONFIG_SYS_XWAY_EBU_BOOTCFG .word 0x00000000 #else RVECENT(romReserved,2) #endif RVECENT(romReserved,3) .... //此处省略若干行。 RVECENT(romReserved,127) /* * We hope there are no more reserved vectors! * 128 * 8 == 1024 == 0x400 * so this is address R_VEC+0x400 == 0xbfc00400 */ .align 4 reset: /* Clear watch registers */ mtc0 zero, CP0_WATCHLO /*# 把数据送到协处理器0*/ mtc0 zero, CP0_WATCHHI /* WP(Watch Pending), SW0/1 should be cleared */ mtc0 zero, CP0_CAUSE /**清 CAUSE 寄存器**/ setup_c0_status_reset /**汇编宏代码见本文件开始位置*/ /* Init Timer 这两个寄存器一起构造高精度时钟*/ mtc0 zero, CP0_COUNT mtc0 zero, CP0_COMPARE #ifndef CONFIG_SKIP_LOWLEVEL_INIT /* CONFIG0 register 将t0和CONFIG寄存器置2*/ /* 下面给大家注释下CONFIG_SKIP_LOWLEVEL_INIT 这个宏的意思。 3406 - CONFIG_SKIP_LOWLEVEL_INIT 3407 [ARM, NDS32, MIPS only] If this variable is defined, then certain 3408 low level initializations (like setting up the memory 3409 controller) are omitted and/or U-Boot does not 3410 relocate itself into RAM. 3411 3412 Normally this variable MUST NOT be defined. The only 3413 exception is when U-Boot is loaded (to RAM) by some 3414 other boot loader or by a debugger which performs 3415 these initializations itself. */ li t0, CONF_CM_UNCACHED mtc0 t0, CP0_CONFIG #endif /* Initialize $gp */ bal 1f nop .word _gp /*此处放一个word 型的值*/ 1: lw gp, 0(ra) /*bal 之后的ra 寄存器保存的是当前存储介质的绝对地址。*/ #ifndef CONFIG_SKIP_LOWLEVEL_INIT /* Initialize any external memory la指令用于将一个地址(或者标签)存入一个通用寄存器*/ la t9, lowlevel_init /*这是第一个需要我们自己定义的函数。由于没有初始化堆栈,这里只能用汇编。*/ jalr t9 /*jal、jalr:这两条指令分别实现了直接和间接子程序调用。 在跳转到指定地址实现子程序调用的同时, 需要将返回地址(当前指令地址+8)保存到ra($31)寄存器中。*/ nop /* Initialize caches... */ la t9, mips_cache_reset /*cache.S 它会来清理数据和指令的cache,并设置为正确的值。然后就可以打开cache了*/ jalr t9 nop /* ... and enable them cache 当内存用了*/ li t0, CONFIG_SYS_MIPS_CACHE_MODE /*宏定义中定义的: 3*/ mtc0 t0, CP0_CONFIG /*寄存器16, CPU 参数设定*/ #endif /* Set up temporary stack */ li t0, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET la sp, 0(t0) /*sp is stack pointer 使用堆栈时,一般需要重新设定SP的初始值。*/ la t9, board_init_f /*C code 做一些初始化的工作*/ jr t9 nop /* * void relocate_code (addr_sp, gd, addr_moni) * * This "function" does not return, instead it continues in RAM * after relocating the monitor code. * * a0 = addr_sp * a1 = gd * a2 = destination address */ .globl relocate_code /*表示全局可见*/ .ent relocate_code relocate_code: /*relocate_code的工作就是将代码搬移到RAM中执行*/ move sp, a0 # set new stack pointer li t0, CONFIG_SYS_MONITOR_BASE /*#假设CONFIG_SYS_MONITOR_BASE 是0xbfc00000。*/ la t3, in_ram /* 这里将一个地址存入通用寄存器t3 #in_ram是个标号,此刻是相对于0xbfc00000。 顺便介绍下in_ram的作用。 in_ram的主要工作是: 更新GOT;清空BSS段; 最后跳到board_init_r。 我们可以看到: board_init_r 最后一个参数是在分支延迟槽中赋值的。 */ /*#关注lds文件,在链接的时候会确定uboot_end_data 的值,此刻取值是从FLASH中。*/ lw t2, -12(t3) # t2 <-- uboot_end_data move t1, a2 move s2, a2 # s2 <-- destination address /* * Fix $gp: * * New $gp = (Old $gp - CONFIG_SYS_MONITOR_BASE) + Destination Address */ move t6, gp /*#把以前的gp 寄存器保存起来。*/ sub gp, CONFIG_SYS_MONITOR_BASE /*#因为我们链接的时候指定了TEXT_BASE,所以可以算出gp相对于TEXT_BASE的偏移。*/ /*#这里的a2,就是我们假设会relocate到内存中的起始地址0x800xxxxx ,此刻我们的EXT_BASE变了,所以gp的地址要调整, 但是它相对于TEXT_BASE的偏移是一定了, 因此我们可以利用它相对CONFIG_SYS_MONITOR_BASE 的偏移求出新的 RAM地址。*/ add gp, a2 # gp now adjusted /*#当然,不光是gp,其他的代码也要调整, 所以把这个要调整的偏移记录下来。*/ sub s1, gp, t6 # s1 <-- relocation offset /* * t0 = source address * t1 = target address * t2 = source end address */ /* * Save destination address and size for later usage in flush_cache() */ move s0, a1 # save gd in s0 move a0, t1 # a0 <-- destination addr sub a1, t2, t0 # a1 <-- size 1: /*#下面这段循环的代码就是把整个uboot.bin 从FLASH 复制到RAM中。*/ lw t3, 0(t0) /*从flash读取一个字*/ sw t3, 0(t1) /*将这一个字写到t1 的位置也就是RAM*/ addu t0, 4 ble t0, t2, 1b addu t1, 4 /* If caches were enabled, we would have to flush them here. */ /* a0 & a1 are already set up for flush_cache(start, size) */ la t9, flush_cache jalr t9 nop /* Jump to where we've relocated ourselves */ addi t0, s2, in_ram - _start /*in_ram 在ram中的地址计算*/ jr t0 /*start run in_ram...*/ nop /*#以下几个变量要结合lds 文件看*/ .word _gp .word _GLOBAL_OFFSET_TABLE_ .word uboot_end_data .word uboot_end .word num_got_entries in_ram: /* * Now we want to update GOT. * * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object * generated by GNU ld. Skip these reserved entries from relocation. */ /*#下面是从RAM中取值,不是从FLASH中了,虽然值的内容是一样的。*/ lw t3, -4(t0) # t3 <-- num_got_entries lw t4, -16(t0) # t4 <-- _GLOBAL_OFFSET_TABLE_ lw t5, -20(t0) # t5 <-- _gp /*#这里用另外的一种方法算偏移,为什么没有利用前面的s1?*/ sub t4, t5 # compute offset add t4, t4, gp # t4 now holds relocated _G_O_T_ addi t4, t4, 8 # skipping first two entries li t2, 2 /*#调整GOT中的内容*/ 1: lw t1, 0(t4) beqz t1, 2f add t1, s1 sw t1, 0(t4) 2: addi t2, 1 blt t2, t3, 1b addi t4, 4 /* Clear BSS #这里是从RAM中取值,不过取得的值是相对于0xbfc00000,所以需要调整。*/ lw t1, -12(t0) # t1 <-- uboot_end_data lw t2, -8(t0) # t2 <-- uboot_end add t1, s1 # adjust pointers add t2, s1 sub t1, 4 /*#把BSS段清0。*/ 1: addi t1, 4 bltl t1, t2, 1b sw zero, 0(t1) move a0, s0 # a0 <-- gd la t9, board_init_r /*#board_init_r中的r应该代表的是RAM, 前面提到的board_init_f中的f应该代表的是FLASH,到此刻为止 运行C代码的环境已经构建完成。*/ jr t9 /*跳转开始执行*/ move a1, s2 .end relocate_code /* Exception handlers */ romReserved: b romReserved romExcHandle: b romExcHandle

浙公网安备 33010602011771号