MIPS架构之start.s汇编分析

一、mips架构通用寄存器命名

 

 

二、mips汇编指令操作

1、指令集

2、实例:

#example 
.data 
array1: .space 12         #  declare 12 bytes of storage        
                           # to hold array of 3 integers  
.text 
__start:  
la  $t0, array1              #  load base address of array       
                              # into register 
$t0  li  $t1, 5              #  $t1 = 5   ("load immediate")
sw  $t1, ($t0)              #  first array element set to 5
                            # indirect addressing  
li  $t1, 13                #   $t1 = 13 
sw  $t1, 4($t0)           # second array element set to 13  
li $t1, -7                 #   $t1 = -7  
sw  $t1, 8($t0)            # third array element set to -7


start.s汇编分析

 

    mtc0 zero, CP0_WATCHLO
    mtc0 zero, CP0_WATCHHI                清除硬件数据断点,防止产生调试断点,导致程序停止。
                                      芯片在复位后,某些寄存器的内容也许是你想要的结果,但是谁知道呢,为了保证准确无误,最好还是重新进行手动初始化
    mfc0 k0, CP0_STATUS
    li  k1, ~ST0_IE
    and k0, k1
    mtc0 k0, CP0_STATUS                    禁止全局中断
    mtc0 zero, CP0_CAUSE                  初始化异常寄存器,清除异常原因指示
    mtc0 zero, CP0_COUNT
    mtc0 zero, CP0_COMPARE
                                  初始化时钟寄存器,防止产生计数器中断
    li t0, CONF_CM_UNCACHED
    mtc0 t0, CP0_CONFIG
                                 设置kseg0区不经过cache。cache需要先初始化才能使用。
    bal 1f
    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
    mtc0 t0, 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 Dcache锁定作为临时栈使用
                          以sp开始,CACHE_LOCK_SIZE大小的堆栈,使用
                          D-cache临时替代
    la t9, board_init_f   初始化
    j t9
    nop
                      
    board_init_f函数定义见board
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      board/xxx/config.mk #define CFG_MONITOR_BASE TEXT_BASE  board/xxx/config.mk #define CFG_MONITOR_BASE TEXT_BASE

 

    la t3, in_ram                  t0 = uboot程序在flash的超始地址,t1 =  准备把uboot程序移到ram中的起始地址
    lw t2, -12(t3)                t2 = uboot程序的结束地址        
    move t1, a2
                           
    move t6, gp
    sub gp, CFG_MONITOR_BASE     计算旧的gp与相对于TEXT_BASE的偏移   
    add gp, a2                    计算新的gp在移动目的地内存中的地址
    sub t6, gp, t6                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段,详见uboot.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 = a2t0 = uboot程序在flash的超始地址,t1 =  准备把uboot程序移到ram中的起始地址
    lw t2, -12(t3)                t2 = uboot程序的结束地址        
    move t1, a2
                           
    move t6, gp
    sub gp, CFG_MONITOR_BASE     计算旧的gp与相对于TEXT_BASE的偏移   
    add gp, a2                    计算新的gp在移动目的地内存中的地址
    sub t6, gp, t6                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段,详见uboot.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


 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值