MIPS uboot代码注释
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
MIPS U-Boot
——by M.C
Uboot启动流程
关中断
设置kseg0no cache
初始化gp指针
lowlevel_init mips_cache_reset 设置kseg0cache mips_cache_lock
Board_init_f relocate_code Board_init_r
启动内核根据CPU rate初始化外部时钟、内存初始化cache
cache未初始化前不能用
cache已初始化
设置临时cache栈
把uboot程序从flash搬到ram执行
start.S
mtc0zero, CP0_WATCHLO mtc0zero, CP0_WATCHHI 清除硬件数据断点,防止产生调试断点,导致程序停止。
芯片在复位后,某些寄存器的内容也许是你想要的结果,但是谁知道呢,为了保证准确无误,最好还是重新进行手动初始化
mfc0k0, CP0_STATUS
li k1, ~ST0_IE
and k0, k1
mtc0k0, CP0_STATUS
禁止全局中断
mtc0zero, CP0_CAUSE初始化异常寄存器,清除异常原因指示
mtc0zero, CP0_COUNT
mtc0zero, CP0_COMPARE
初始化时钟寄存器,防止产生计数器中断
li t0, CONF_CM_UNCACHED
mtc0t0, CP0_CONFIG
设置kseg0区不经过cache。cache需要先初始化才能使用。
bal1f
nop
.word_gp
1:
lw gp, 0(ra)bal分支调用,ra返回地址指向下下一条指令,即.word _gp
把.word_gp的存储位置载入gp寄存器,即设置GOT表的起始位置
la t9, lowlevel_init jalr t9
nop 根据CPU rate初始化外部时钟、内存。lowlevel_init函数定义见lowlevel_init.S
la t9, mips_cache_reset jalr t9
nop 初始化高速缓存cache。
mips_cache_reset函数定义见cache.S
li t0, CONF_CM_CACHABLE_NONCOHERENT
mtc0t0, CP0_CONFIG
设置kseg0区经过cache
li a0, CFG_INIT_SP_OFFSET la t9, mips_cache_lock
jalr t9
nop
li t0, CFG_SDRAM_BASE + CFG_INIT_SP_OFFSET
la sp, 0(t0)C语言程序(接下来的函数board_init_f)调用需要栈,而ram还没有初始化不能使用,所以用CACHE_LOCK_SIZE大小的L1 D-cache锁定作为临时栈使用
#define CFG_INIT_SP_OFFSET 0x400000
以sp开始,CACHE_LOCK_SIZE大小的堆栈,使用
D-cache临时替代
la t9, board_init_f j t9
nop 初始化。
board_init_f函数定义见board.c
kseg0CACHE_LOCK_SIZE
CFG_INIT_SP_OFFSET
sp
start.S
relocate_code:对应board.c里的relocate_code(addr_sp, id, addr),此时a0=addr_sp,a1=id,a3=addr。
move sp, a0设置新的sp= addr_sp
li t0, CFG_MONITOR_BASE la t3, in_ram
lw t2, -12(t3)
move t1, a2board/xxx/config.mk #define CFG_MONITOR_BASE TEXT_BASE
t0= uboot程序在flash的超始地址,t1 = 准备把uboot程序移到ram中的起始地址t2 = uboot程序的结束地址
move t6, gp
sub gp, CFG_MONITOR_BASE add gp, a2
sub t6, gp, t6t6 = 旧gp
计算旧的gp与相对于TEXT_BASE的偏移
计算新的gp在移动目的地内存中的地址
t6 = 新gp(内存中)与旧gp(flash中)的地址偏移量,这个值也是整个uboot从flash移到内存的偏移量。等同于(Destination Address -CFG_MONITOR_BASE)
1:
lw t3, 0(t0)
sw t3, 0(t1) addu t0, 4
ble t0, t2, 1b addu t1, 4按字拷贝,把uboot bin的内容从源地址(flash)拷贝到目的地址(内存),拷贝的长度是从uboot开始到uboot_end_data为止,uboot_end_data后面是bss段,详见u-boot.lds
addi t0, a2, in_ram-_start
j t0
nop
计算in_ram在内存中的新地址保存到t0,然后跳转到内存中运行in_ram。从此开始,uboot的代码将在ram中运行了
.gpword_GLOBAL_OFFSET_TABLE
.word uboot_end_data
.word uboot_end
.word num_got_entries
in_ram:
t3 = num_got_entries,t4 = 新的GOT[2]
li t2, 2
1:
lw t1, 0(t4)
beqz t1, 2f
add t1, t6
sw t1, 0(t4) 2:
addi t2, 1
blt t2, t3, 1b
addi t4, 4这里是一个循环,从GOT[2]开始,判断如果GOT表项有内容,则把内容从旧的GOT表拷贝到新的GOT表里。为什么要做拷贝呢?上面的程序已经把uboot整个程序从flash拷贝到了ram里,注意,只是内容拷贝,GOT里的地址还是老地址,所以要做重定位(如果是静态编译且属于模块内相对偏移,就不需要这个步骤了)。手工重定位的方法就是把旧GOT里的内容读取,然后加上偏移(uboot在flash与ram的偏移)赋值给新GOT里的对应表项
程序构建过程(编译和生成程序时的链接)为每个链接单元(构成动态链接程序的二进制文件,如.o、.a、.so)至少定义一个GOT,每个函数都可以找到自己的GOT,因为GOT的位置离链接单元的入口点的偏移量是固定已知的。链接单元作为一个整体载入内存,所以GOT的内部偏移量与编译时是一样的。
u-boot在编译时使用-fpic,会生成一个.got段来存储绝对地址符号。
lw t1, -12(t0) lw t2, -8(t0) add t1, t6
add t2, t6
sub t1, 4
1:
addi t1, 4
bltl t1, t2, 1b
sw zero, 0(t1)t1 = uboot_end_data,t2 = uboot_end
进行BSS段的清零,此时还没有操作系统,动态链接器,加载器等这些东东都还没有,所以要手动执行清零
move a0, a1
la t9, board_init_r j t9
move a1, a2跳转到ram中的board_init_r执行,根据MIPS ABI规范,a0、a1分别是board_init_r的第一个、第二个参数,即board_init_r(gd_t*id, ulong dest_addr)中id = a0,dest_addr= a2