版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SilverFOX111/article/details/86629629
start.S代码分析笔记
17. 重定位(2)-- 虚拟地址映射
after_copy:
#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop
#endif
17.1 设置域访问
- mcr指令定义:mcr p15, opcode_1, Rd, Crn, Crm, opcode_2,对于cp15,opcode_1永远为0,Rd为ARM的普通寄存器,Crn为cp15的寄存器,Crm一般为c0,opcode_2一般省略或设0。本指令作用为将Rd中数据写入Crn中。mrc指令定义也一样,但作用相反,是将Crn的内容读入Rd中。
- cp15的c3寄存器在MMU状态下定义了 ARM 处理器的 16 个域的访问权限,c3寄存器共32位,每连续两位定义一个域的权限,00表示不允许访问,11表示不进行权限检查。
17.2 设置TTB(转换表)
- _mmu_table_base 是整个TTB表的首地址,TTB定义在lowlevel_init.S 文件中第675行。整块表定义如下:
.macro FL_SECTION_ENTRY base,ap,d,c,b
.word (\base << 20) | (\ap << 10) | \
(\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm
.section .mmudata, "a"
.align 14
// the following alignment creates the mmu table at address 0x4000.
.globl mmu_table
mmu_table:
.set __base,0
// Access for iRAM
.rept 0x100
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
// Not Allowed
.rept 0x300 - 0x100
.word 0x00000000
.endr
.set __base,0x300
// should be accessed
.rept 0x400 - 0x300
//.rept 0x350 - 0x300
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
// Not Allowed
//.rept 0x400 - 0x350
//.word 0x00000000
//.endr
// DRAM - DMC1 area - used for STL_write : djpark (20090729)
.set __base,0x400
// should be accessed
.rept 0x500 - 0x400
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
.rept 0x800 - 0x500
.word 0x00000000
.endr
.set __base,0x800
// should be accessed
.rept 0xb00 - 0x800
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
.set __base,0xB00
.rept 0xc00 - 0xb00
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
.set __base,0x300
// 80MB for SDRAM with cacheable
.rept 0xd00 - 0xC00
//.rept 0xC50 - 0xC00
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
// Not Allowed
@.rept 0xD00 - 0xC80
@.word 0x00000000
@.endr
// Not Allowed
//.rept 0xD00 - 0xC50
//.word 0x00000000
//.endr
.set __base,0xD00
// 1:1 mapping for debugging with non-cacheable
.rept 0x1000 - 0xD00
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
- .macro伪指令定义宏,base,ap,d,c,b都是参数,FL_SECTION_ENTRY是宏名,该宏通过这几个参数构造了TTB的表项。
- .rept与.endr构成了循环体,.rept后的数表示循环次数,.set伪指令为变量赋值。上面共8个循环体定义了地址从0x00000000-0xFFFFFFFF的转换表。结果如下:
虚拟地址 | 物理地址 | 大小 | 允许访问 |
---|---|---|---|
0x00000000-0x0FFFFFFF | 0x00000000-0x0FFFFFFF | 256MB | 读/写 |
0x10000000-0x1FFFFFFF | ---- | 256MB | 读/写 |
0x20000000-0x5FFFFFFF | 0x20000000-0x5FFFFFFF | 1GB | 读/写 |
0x60000000-0x7FFFFFFF | ---- | 512MB | 读/写 |
0x80000000-0xAFFFFFFF | 0x80000000-0xAFFFFFFF | 768MB | 读/写 |
0xB0000000-0xBFFFFFFF | 0xB0000000-0xBFFFFFFF | 256MB | 读/写 |
0xC0000000-0xCFFFFFFF | 0x30000000-0x3FFFFFFF | 256MB | 读/写 |
0xD0000000-0xFFFFFFFF | 0xD0000000-0xFFFFFFFF | 768MB | 读/写 |
- uboot设置的虚拟地址是以段(1MB)为单位的,关于TTB内容如下,每个单位32bit,具体内容如下:
31 : 20 | 19 : 12 | 11 : 10 | 9 | 8 : 5 | 4 | 3 | 2 | 1:0 |
---|---|---|---|---|---|---|---|---|
section base address | SBZ | AP | SBZ | domain | IMP | C | B | 1 0 |
- section base address存放了虚拟地址转化后的物理地址基址。
- AP表示访问权限,11表示可读/写。
- bit[3:2](C,B),控制cache和buffer,若C=1,将此地址存入cache中,若B=1,则通过写缓冲方式写此地址的数据。
- 最后两位如果是10就表示1MB段虚拟映射。
17.3 小结
从上可以发现,只有虚拟地址为0xC0000000-0xCFFFFFFF最后映射到了可以读写的DRAM地址(0x30000000-0x3FFFFFFF)中,所以Uboot代码链接地址为0xC3E00000。
17.4 9-15行代码
该段将TTB物理基地址设置到了c2协处理器的寄存器中,中间的过程是将uboot代码中TTB的虚拟地址掐头,与物理地址组合后形成TTB的物理地址。
17.5 18-25行代码
该段开启了MMU。
18. 386-398行代码(第三次设置栈)
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#if defined(CONFIG_USE_IRQ)
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#endif
这次是最后一次设置栈,比之前又更为合理,sp的地址为CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000 ,其中,CFG_UBOOT_BASE 为0x33E00000,CFG_UBOOT_SIZE 为 2 * 1024 * 1024。
19. 400-409行代码(初始化bss段)
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
20. 411行代码(执行BL2)
ldr pc, _start_armboot
这句话是uboot的第一阶段与第二阶段的分界点,至此,uboot跳转到第二阶段在DRAM中运行。