uboot启动第一阶段--start.S代码分析笔记(3)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SilverFOX111/article/details/86629629

uboot启动第一阶段–start.S代码分析笔记(2)



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中运行。

猜你喜欢

转载自blog.csdn.net/SilverFOX111/article/details/86629629