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
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处理器的寄存器中
多寄存器和堆栈寻址的用法:多寄存器寻址: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]
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 程序状态字寄存器