uboot内存分布与汇编知识

    • 1 uboot内存分布
    • 2 start.S
    • 3 汇编知识
      • 3.1 指令
      • 3.2 多寄存器寻址指令
      • 3.3 寄存器

1 uboot内存分布



uboot内存分布与汇编知识_第1张图片

  对于uboot来说,DDR的地址并不是从0x0开始的。flash和DDR是统一编址的,但是并不会包含flash全部内容.uboot会将flash前面部分空间映射成内存空间,映射的起始地址可以当成是0x0,至于映射大小跟具体的平台、配置有关,这里我们并不需要关心其大小。
  flash中uboot镜像后一般是uboot环境变量。
  uboot重定位时将uboot镜像(从_stext地址开始,不包含.bss段)拷贝到TEXT_BASE(DDR)地址,然后再执行一次uboot,start.S会被再执行一次,但是这一次不会执行重定位代码,而是跳转到清.bss段代码。

2 start.S


  start.S重定位代码

#ifdef CONFIG_RELOC_TO_TEXT_BASE
relocate_to_text: /* 上面宏已定义,所以跑这部分 */
    /*
     * relocate u-boot code on memory to text base
     * for nexell arm core (add by jhkim)
     */
    adr r0, _stext              /* r0 保存uboot起始地址   */
    ldr r1, TEXT_BASE           /* r1 uboot偏移起始地址 0x42c00000 */
    cmp r0, r1                  /* 比较两个地址,相同就跳转, 清bss */
    beq clear_bss

    ldr r2, _bss_start_ofs
    add r2, r0, r2              /* r2 bss起始地址 */

copy_loop_text:
    ldmia   r0!, {r3-r10}       /* r0保存的地址开始的 8*4 字节数据加载到 r3 ~ r10  */
    stmia   r1!, {r3-r10}       /* r3 ~ r10 的数据保存到r1地址开始的32个字节空间里 */
    cmp r0, r2                  /* 检查拷贝是否到了bss, bss段内容不需要拷贝 */
    ble copy_loop_text

    ldr r1, TEXT_BASE           /* pc指向TEXT_BASE, 重新执行一次start.S, 这一次直接跳转到clear_bss */
    mov pc, r1

clear_bss:
#ifdef CONFIG_MMU_ENABLE
    bl  mmu_turn_on  /* 开mmu */
#endif
    ldr r0, _bss_start_ofs
    ldr r1, _bss_end_ofs
    ldr r4, TEXT_BASE           /* text addr */
    add r0, r0, r4              /* 重定位后bss的起始地址和结束地址 */
    add r1, r1, r4
    mov r2, #0x00000000         /* clear */

clbss_l:str r2, [r0]            /* r2中保存的数据mov到r0, 完成后bss段内容全为0 */
    add r0, r0, #4              /* 执行完成后r0 = r0 + 4 */
    cmp r0, r1
    bne clbss_l

    ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) /* CONFIG_SYS_INIT_SP_ADDR = TEXT_BASE,栈指针从0x42c00000开始 */
    bic sp, sp, #7                  /* 8-byte alignment for ABI compliance */
    sub sp, #GD_SIZE                /* sp = sp - GD_SIZE 保留TEXT_BASE,下GD_SIZE大小内存空间给GD  */
    bic sp, sp, #7                  /* 内存8字节对齐 */
    mov r9, sp                      /* GD is above SP, 现在sp指向GD的基地址 */
    mov r0, #0
    bl  board_init_f

    mov sp, r9                      /* SP is GD's base address */
    bic sp, sp, #7                  /* 8-byte alignment for ABI compliance */
    sub sp, #GENERATED_BD_INFO_SIZE /* GD下再栈空间再分配GENERATED_BD_INFO_SIZE大小给BD */
    bic sp, sp, #7                  /* 8-byte alignment for ABI compliance */

    mov r0, r9                      /* gd_t *gd, r9原来保存gd的地址 */
    ldr r1, TEXT_BASE               /* ulong text, r1偏移起始地址,也就是uboot起始地址 */
    mov r2, sp                      /* ulong sp,r2保存sp地址,bd地址 */
    bl  gdt_reset

    /* call board_init_r(gd_t *id, ulong dest_addr) */
    mov r0, r9                          /* gd_t, gd地址 */
    ldr r1,  =(CONFIG_SYS_MALLOC_END)   /* dest_addr for malloc heap end, 堆空间起始地址0x43000000, 0x43000000 - 0x42c00000 = 4M,也就是说uboot大小不超过4M,如果超过4M,uboot执行到后面部分可能会出现问题 */
    /* call board_init_r */
    ldr pc, =board_init_r               /* this is auto-relocated! */

#else   /* CONFIG_RELOC_TO_TEXT_BASE */
    bl  _main
#endif

3 汇编知识


3.1 指令

ldr
ldr r0, 0x8000 //将0x8000的值mov或者mvn到r0,如果0x8000换成label,也就是标签(会被当成地址),地址加载到r0

adr adrl
adr r0, _stext
ldr r0, _stext
adr adrl 伪指令用于将一个地址加载到寄存器中,adr为小范围的地址读取伪指令。adr指令将基于PC相对偏移的地址值读取到寄存器中。通常,编译器用一条add指令或sub指令来实现该adr伪指令的功能。adrl是中等范围的地址读取指令,会被编译器翻译成两条指令。
地址范围

指令 四字节对齐 非字节对齐
adr -1020~1020 -255~255
adrl -256k~256k -64k~64k  

bic orr
bic r0,r0,#0x1f
0x1f=11111b
其含义:清除r0的bit[4:0]位。

orr r0,r0,#0xd3
0xd3=1101 0111
r0与0xd3作算数或运算,然后将结果返还给r0,即把r0的bit[7:6]和bit[4]和bit[2:0]置为1

MCR MRC

MCR指令将ARM处理器的寄存器中的数据传送到协处理器的寄存器中

MRC指令将协处理器的寄存器中数值传送到ARM处理器的寄存器中

3.2 多寄存器寻址指令

多寄存器和堆栈寻址的用法:多寄存器寻址:LDMIA,LDMIB,STMIA,STMIB,LDMDA,LDMDB,STMDA,STMDB;

堆栈寻址:LDMFA,LDMFD,STMFA,STMFD,LDMEA,LDMED,STMEA,STMED;

弄清堆栈寻址的SP的变化:LDMFA,LDMFD,STMFA,STMFD,LDMEA,LDMED,STMEA,STMED;

LD: load 加载, 方向 >
ST: store 保存, 方向 <
M: multi 多
IA: 每次传送后地址加4;
IB: 每次传送前地址加4;
DA: 每次传送后地址减4;
DB: 每次传送前地址减4;
FD: 满递减堆栈;
ED: 空递减堆栈;
FA: 满递增堆栈;
EA: 空递增堆栈

LDMIA R0!,{R1-R4}  
相当于下面几个操作, STMIA方向则相反
R1<----[R0]
R2<----[R0+4]
R3<----[R0+8]
R4<----[R0+12]   

3.3 寄存器

R0 ~ R7 不分组通用寄存器, 这意味着在所有处理器模式下,访问的都是同一个物理寄存器

R8 ~ R12
1、FIQ模式分组寄存器R8-R12
2、FIQ以外的分组寄存器R8-R12

R13 也叫做SP,通常用作于堆栈指针

R14 也叫做LR(链接寄存器),通常用作于保存子程序或中断返回的地址,通常是产生中断或者跳转指令的下一条指令的地址(由于ARM中PC总是当前指令地址+8,所以保存到LR中的地址应该总是PC-4)

R15 也叫做PC,由于ARM采用流水线技术,所以PC总是指向正在取值的指令,根据不同cpu架构,当前正常执行的指令地址与PC所指向的地址不同。

CPSR 程序状态字寄存器

你可能感兴趣的:(uboot)