S5PV210 uboot中的 MMU代码分析
Posted biaohc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了S5PV210 uboot中的 MMU代码分析相关的知识,希望对你有一定的参考价值。
1:经过上一节的分析,如果采用SECTION虚拟地址映射的话;
程序员只需要做的事情:
(1) 建立转换表,Tanslation Table;
(2) 将TTB(转换表基地址Tanslation Table Base)写入协处理器CP15的C2寄存器,这里要注意转换表
基地址为16K对齐的(因为4096*32bit=16K)所以TTB的bit0-bit13为0。
(3) 使能MMU,将CP15的C1寄存器0bit写1;
(4) 设置域的访问权限;设置C3寄存器;
CPU/MMU做的事情:
(1) CPU核心看到和用到的只是虚拟地址VA,至于VA如果去对应物理地址PA,CPU核心不理会,MVA是除CPU核心
外的其他部分看到的虚拟地址,VA与MVA的变化关系,如果VA<32M,需要使用进程标识号PID(通过读CP15的C13获得)
来转换为MVA
if (VA < 32M) then
MVA = VA | (PID << 25)
else
MVA = VA
(2) MMU做的事情,将MVA的bit20-bit31与TTB的bit14-bit31组合,通过这个值来查找转换表中的物理地址所在位置,
找到物理地址所在内存位置,即把所在位置的bit20-bit31与MVA的bit19-bit0,这个地址即为PA(物理地址)。
2:uboot中代码分析
s5pv210虚拟地址物理地址映射关系为:
虚拟地址:---------------------------------------------物理地址----------------------------写入权限
0x0000_0000--0x0FFF_FFFF 0x0000_0000--0x1000_0000 不可写入
0x1000_0000--0x1FFF_FFFF 无效
0x2000_0000--0x5FFF_FFFF 0x2000_0000--0x5FFF_FFFF WT、WB
0x6000_0000--0x7FFF_FFFF 无效
0x8000_0000--0xaFFF_FFFF 0x8000_0000--0xAFFF_FFFF 不可写入
0xb000_0000--0xbFFF_FFFF 0xb000_0000--0xbFFF_FFFF 不可写入
0xc000_0000--0xcFFF_FFFF 0x2000_0000--0x2FFF_FFFF WT、WB
0xD00 - 0xC80 无效
0x1000 - 0xD00 0x1000 - 0xD00 不可写入
#if defined(CONFIG_ENABLE_MMU) _mmu_table_base: .word mmu_table #endif #if defined(CONFIG_ENABLE_MMU) enable_mmu: /* enable domain access */ ldr r5, =0x0000ffff //设置域权限:设置16个域权限位可读可写,在写入C3寄存器 mcr p15, 0, r5, c3, c0, 0 @load domain access register /* Set the TTB register */ ldr r0, _mmu_table_base //把内存_mmu_table_base中的值写入到r0中,从最上面三行代码可以看出_mmu_table_base中的值为mmu_table ldr r1, =CFG_PHY_UBOOT_BASE //mmu_table定义在lowlevel_init函数中,mmu_table即为在SRAM中的向量表的地址,BL1中把整个uboot的代码 ldr r2, =0xfff00000 //复制到0x23e0_0000内存处,所以在内存中的向量表的地址为:0x23e0_0000+mmu_table的值 bic r0, r0, r2 //清mmu_table的高12bit,在位或0x23e0_0000,即把内存中的向量表的地址计算出来赋值给r1了, orr r1, r0, r1 //然后把r1写入到寄存器c2中,则完成了TTB的设置。 mcr p15, 0, r1, c2, c0, 0 /* Enable the MMU */ mmu_on: mrc p15, 0, r0, c1, c0, 0 //使能mmu,c3的M位置1,即使能mmu orr r0, r0, #1 mcr p15, 0, r0, c1, c0, 0 nop nop nop nop #endif /*这段代码的位于lowlevel_init中,作用就是建立TTB*/ .globl lowlevel_init lowlevel_init: #ifdef CONFIG_MCP_SINGLE /* * MMU Table for SMDKC110 * 0x0000_0000 -- 0xBFFF_FFFF => Not Allowed * 0xB000_0000 -- 0xB7FF_FFFF => A:0xB000_0000 -- 0xB7FF_FFFF * 0xC000_0000 -- 0xC7FF_FFFF => A:0x3000_0000 -- 0x37FF_FFFF * 0xC800_0000 -- 0xDFFF_FFFF => Not Allowed * 0xE000_0000 -- 0xFFFF_FFFF => A:0xE000_0000 -- 0XFFFF_FFFF */ /* form a first-level section entry */ .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 //开始设置MMU table base。 // Access for iRAM .rept 0x100 //TTB中一共有4096个字节,我们假设这是一个数组 unsigned int TTB[1096] FL_SECTION_ENTRY __base,3,0,0,0 //rept 0x100 意思是循环256次,即 TTB[0] = FL_SECTION_ENTRY __base,3,0,0,0 .set __base,__base+1 //TTB[1] = FL_SECTION_ENTRY __base+1,3,0,0,0 ----------最后TTB[0x100] = FL_SECTION_ENTRY __base+99,3,0,0,0 .endr //对应映射关系为:虚拟地址:0x0-0x100M----------物理地址0x0-0x100 //这段内存的读写权限设置在(\\c << 3) | (\\b << 2) C位WT模式直写模式, B位WB模式,write back 先写入cache在写入内存 // Not Allowed .rept 0x200 - 0x100 //0x200M-0x100M 内容为0,最低两位为0,表示无效; .word 0x00000000 .endr .set __base,0x200 //TTB[0x200]-TTB[0x600 -1]对应的内容为:0x200-0x599 // should be accessed //对应映射关系为:虚拟地址:0x200-0x600M----------物理地址0x200-0x600 .rept 0x600 - 0x200 //权限位WT、WB FL_SECTION_ENTRY __base,3,0,1,1 .set __base,__base+1 .endr .rept 0x800 - 0x600 //同样0x600-0x800物理地址是无效的 .word 0x00000000 .endr .set __base,0x800 //虚拟地址:0x800-0xB00M----------物理地址0x800-0xB00 // should be accessed //不可写入 .rept 0xb00 - 0x800 FL_SECTION_ENTRY __base,3,0,0,0 .set __base,__base+1 .endr /* .rept 0xc00 - 0xb00 .word 0x00000000 .endr */ .set __base,0xB00 //虚拟地址:0xB00-0xC00M----------物理地址0xB00-0xC00 .rept 0xc00 - 0xb00 //不可写入 FL_SECTION_ENTRY __base,3,0,0,0 .set __base,__base+1 .endr // 0xC000_0000鏄犲皠鍒?x2000_0000 //.set __base,0x300 .set __base,0x200 //虚拟地址:0xC00-0xD00M----------物理地址0x200-0x300 // 256MB for SDRAM with cacheable //WT、WB .rept 0xD00 - 0xC00 FL_SECTION_ENTRY __base,3,0,1,1 //虚拟地址0xc000_0000----0xcFFF_FFFF对应的物理地址是0x2000_0000-----0x2FFF_FFFF .set __base,__base+1 .endr // access is not allowed. @.rept 0xD00 - 0xC80 @.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
C设置TTB代码:
//16K对齐 #define MMU_TABLE_ADDR 0x00100000 #define TTB_VALUE_CONFIG(base, b, c, d, e) \\ (((base) << 20) | ((b) << 10) | ((c) << 5) | ((d) << 3) | ((e) << 2) | (1 << 1)) (\\ap << 10) | \\ (\\d << 5) | (1<<4) | (\\c << 3) | (\\b << 2) | (1<<1) unsigned int *p_mmu_table = (unsigned int*)MMU_TABLE_ADDR; void ttb_set(void) { int i = 0x0; int base = 0x0; for (i=0x0; i<0x100; i++) { *p_mmu_table = TTB_VALUE_CONFIG(base, 3, 0, 1, 1); p_mmu_table++; base++; //base 0x0-0x100 } for (; i<0x200; i++) { *p_mmu_table = 0; p_mmu_table++; base++; //base 0x100-0x200 } for (; i<0x600; i++) { *p_mmu_table = TTB_VALUE_CONFIG(base, 3, 0, 1, 1); p_mmu_table++; base++; //base 0x200-0x600 } for (; i<0x800; i++) { *p_mmu_table = 0; p_mmu_table++; base++; //base 0x600-0x800 } for (; i<0xB00; i++) { *p_mmu_table = TTB_VALUE_CONFIG(base, 3, 0, 0, 0); p_mmu_table++; base++; //base 0x800-0xB00 } for (; i<0xc00; i++) { *p_mmu_table = TTB_VALUE_CONFIG(base, 3, 0, 0, 0); p_mmu_table++; base++; } for (base=0x200; i<0xd00; i++) { *p_mmu_table = TTB_VALUE_CONFIG(base, 3, 0, 1, 1); p_mmu_table++; base++; } for (i=0xc80, p_mmu_table=p_mmu_table-0x80; i<D00; i++) { *p_mmu_table = 0; p_mmu_table++; } for (i=0xd00, base=0xD00; i<0x1000; i++) { *p_mmu_table = TTB_VALUE_CONFIG(base, 3, 0, 0, 0); p_mmu_table++; } }
设置cp15寄存器中的值:
#if defined(CONFIG_ENABLE_MMU) enable_mmu: /* enable domain access */ ldr r5, =0x0000ffff //设置域权限:设置16个域权限位可读可写,在写入C3寄存器 mcr p15, 0, r5, c3, c0, 0 @load domain access register /* Set the TTB register */ ldr r0, MMU_TABLE_ADDR //把内存_mmu_table_base中的值写入到r0中,从最上面三行代码可以看出_mmu_table_base中的值为mmu_table ldr r1, =CFG_PHY_UBOOT_BASE //mmu_table定义在lowlevel_init函数中,mmu_table即为在SRAM中的向量表的地址,BL1中把整个uboot的代码 ldr r2, =0xfff00000 //复制到0x23e0_0000内存处,所以在内存中的向量表的地址为:0x23e0_0000+mmu_table的值 bic r0, r0, r2 //清mmu_table的高12bit,在位或0x23e0_0000,即把内存中的向量表的地址计算出来赋值给r1了, orr r1, r0, r1 //然后把r1写入到寄存器c2中,则完成了TTB的设置。 mcr p15, 0, r1, c2, c0, 0 /* Enable the MMU */ mmu_on: mrc p15, 0, r0, c1, c0, 0 //使能mmu,c3的M位置1,即使能mmu orr r0, r0, #1 mcr p15, 0, r0, c1, c0, 0 nop nop nop nop #endif
以上是关于S5PV210 uboot中的 MMU代码分析的主要内容,如果未能解决你的问题,请参考以下文章
S5PV210芯片的uboot烧录脚本目录(sd_fusing)完整解析