最好的模板网站,协会网站建设方案,德阳做网站的公司,网站建设前就应该进行网站推广工作MMU与PTS表格
最近在FPGA上仿真调试Virgo#xff08;基于ARM11的一款处理器#xff09;芯片。MMU部分总是出错#xff0c;具体的现象是查看物理地址和虚拟地址的映射时候芯片经常会挂掉。先是怀疑MMU的寄存器配置有问题#xff0c;后来又怀疑MMU映射使用的PTS表格有问题基于ARM11的一款处理器芯片。MMU部分总是出错具体的现象是查看物理地址和虚拟地址的映射时候芯片经常会挂掉。先是怀疑MMU的寄存器配置有问题后来又怀疑MMU映射使用的PTS表格有问题最后发现竟然是RAM没有清零导致的唉竟然犯了这种的错误实在是雷人。
为了解决问题这两天对这部分代码进行了分析和调试担心过两天会忘掉赶紧写下来。
1MMU初始化代码分析
其实MMU的初始化过程就是PTS表格的初始化过程。
那么啥是PTS表格呢
PTS表格是供MMU进行地址映射和察看内存属性信息的表格。
PTS表格主要记录了两方面的信息第一虚拟地址对应的物理地址在哪个位置第二虚拟地址的属性信息如上面的0x402/0x40e/0x41e。
MMU详细的初始化过程参照下面的代码解释 b . INCLUDE oemaddrtab_cfg.inc ;------------------------------------------------------------------ ; Compute physical address of the OEMAddressTable. 20 add r11, pc, #g_oalAddressTable - (. 8) ldr r10, PTs ; (r10) 1st level page table ; Setup 1st level page table (using section descriptor) ; Fill in first level page table entries to create un-mapped regions ; from the contents of the MemoryMap array. ; ; (r10) 1st level page table ; (r11) ptr to MemoryMap array ; 接下来这三行代码是配置ptr指针的位置以及初始化DRAM部分物理地址在PTS映射表中的标记即E ; 后面会将这个标记放置到PTS映射表中 add r10, r10, #0x2000 ; (r10) ptr to 1st PTE for unmapped space mov r0, #0x0E ; (r0) PTE for 0: 1MB cachable bufferable orr r0, r0, #0x400 ; set kernel r/w permission 25 mov r1, r11 ; (r1) ptr to MemoryMap array ; 获取g_oalAddressTable的参数 ; 哈哈这个就不用解释了 30 ldr r2, [r1], #4 ; (r2) virtual address to map Bank at ldr r3, [r1], #4 ; (r3) physical address to map from ldr r4, [r1], #4 ; (r4) num MB to map ; g_oalAddressTable表格的最后一行是DCD 0x00000000, 0x00000000, 0 ; 也即r4 0 cmp r4, #0 ; End of table? beq %f40 ; 这里也不用说了就是限定最大值为MB和GB ldr r5, 0x1FF00000 and r2, r2, r5 ; VA needs 512MB, 1MB aligned. ldr r5, 0xFFF00000 and r3, r3, r5 ; PA needs 4GB, 1MB aligned. ; 值得一提的是下面的这个值网上的争论也比较多 ; PTS表格中的最小元素代表了MB的物理地址空间这也是g_oalAddressTable中映射的最小单位是MB的原因 ; 假如说有MB的DRAM需要进行映射每MB在PTS表格中占据一个元素四个字节的位置最终就是 ; 第一个MB放置在PTS表格偏移为x0的位置假如说这段MB DRAM 的物理地址是x3000 0000则存放到这里的数据就是x3000 0000 ; 第二个MB放置在PTS表格中偏移为x4的位置数据是x3010 0000[即这MB空间的起始物理地址] ; 第三个MB放置在PTS表格中偏移为x8的位置数据是x3020 0000[即这MB空间的起始物理地址] ; 第四个MB放置在PTS表格中偏移为xc的位置数据是x3030 0000[即这MB空间的起始物理地址] ; 如果DRAM很大的话依次类推 ; 注意观察一下上面的偏移x0其实可以通过x3000 0000-0x3000 000018计算出来 ; 注意观察一下上面的偏移x4其实可以通过x3010 0000-0x3000 000018计算出来 ; 注意观察一下上面的偏移x8其实可以通过x3020 0000-0x3000 000018计算出来 ; 注意观察一下上面的偏移xc其实可以通过x3030 0000-0x3000 000018计算出来 ; 很明显这个为的右移值是由PTS的最小元素所代表的物理空间大小决定的 add r2, r10, r2, LSR #18 add r0, r0, r3 ; (r0) PTE for next physical page ; 接下来这四行代码就是将DRAM或者寄存器对应的物理地址填充到PTS表格中r2是表格的指针r0是待映射的物理地址 35 str r0, [r2], #4 add r0, r0, #0x00100000 ; (r0) PTE for next physical page sub r4, r4, #1 ; Decrement number of MB left cmp r4, #0 bne %b35 ; Map next MB bic r0, r0, #0xF0000000 ; Clear Section Base Address Field bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field ; 查询g_oalAddressTable表格的下一个Element不知道该咋翻译 ; 起始一个Element就对应表格g_oalAddressTable的一行如DCD 0x93300000, 0xD0102000, 1就是一个element b %b30 ; Get next element ; 下面这行代码是用来将g_oalAddressTable表格中的物理地址同时也映射到xa000 0000~0xbfff ffff这个Uncache空间中 ; tst r0, #8和bic r0, r0, #0x0C是用来计算后需要填充PTS表格中的标记其实结果就是x402 ; 第三行add r10, r10, #0x0800中的x0800其实就是xa000 0000在PTS表格中的相对偏移相对于虚拟地址x8000 0000 ; 在pts表格中位置的偏移可以这样计算 ; (0xa000 0000-0x8000 0000)18 0x0800 ; 第行代码没有意义可以删除 40 tst r0, #8 bic r0, r0, #0x0C ; clear cachable bufferable bits in PTE add r10, r10, #0x0800 ; (r10) ptr to 1st PTE for unmapped uncached space bne %b25 ; go setup PTEs for uncached space sub r10, r10, #0x3000 ; (r10) restore address of 1st level page table ? ; 接下来是将虚拟地址x0000 0000~0x000f ffff这段空间映射到物理RAM的前MB空间 ; 该芯片上RAM的物理基址在x7000 0000所以对应的就是x7000 0000~0x700f ffff ; 值得说明的是x7000040E表示位于x7000 0000这MB空间的基址 ; 而r0表示虚拟地址x0000 0000在PTS表格中的位置其实就在PTS表格中的最开始位置 ; 1. Setup mmu to map (VA 0) to (PA 0x70000000). ; 1-1. cached area. ldr r0, PTs ; PTE entry for VA 0 ldr r1, 0x7000040E ; cache/buffer/rw, PA base 0x70000000 ;ldr r1, 0x70000402 ; cache/buffer/rw, PA base 0x70000000 str r1, [r0] ; 下面三行其实和上面的四行代码类似表示将虚拟地址x2000 0000映射到物理地址x7000 0000 ; 第一行代码中的x0800表示虚拟地址x2000 0000在PTS表格中的偏移 ; 而是UNCACHE ram的标记 ; 1-2. uncached area. add r0, r0, #0x0800 ; PTE entry for VA 0x0200.0000 , uncached ldr r1, 0x70000402 ; uncache/unbuffer/rw, base 0x70000000 str r1, [r0] ; 接下来这段代码将虚拟地址x7000 0000映射到物理地址x7000 0000这段映射空间的大小是MB ; 即DRAM空间的大小 ; Comment: ; The following loop is to direct map RAM VA PA. i.e. ; VA 0x70XXXXXX PA 0x70XXXXXX for Virgo ; Fill in 8 entries to have a direct mapping for DRAM ; ldr r10, PTs ; restore address of 1st level page table ldr r0, PHYBASE ; 下面这一行#(0x7000 / 4)同样是计算虚拟地址x7000 0000在PTS表格中的偏移 ; 下面这段代码我没有改抄袭了三星的做法它们没有写好正确的写法应该是 ; (0x7000 000018)是不是搞得你云里雾里的鄙视Samsung将来Vrigo的方案 ; 出去之后一定要把公版BSP给改的简单易懂要不然OEM厂家又要骂了 add r10, r10, #(0x7000 / 4) ; (r10) ptr to 1st PTE for (0x7000000016)/sizeof(DWORD) ; 下面的#0x1E和#0x400最终组合成一个标记x40e类似于前面的x402和x40e。 add r0, r0, #0x1E ; 1MB cachable bufferable orr r0, r0, #0x400 ; set kernel r/w permission mov r1, #0 mov r3, #64 ; 128MB SDRAM ;mov r3, #128 ; 128MB SDRAM ; 下面的r2表示当前的映射在PTS表格中的偏移 ; 第三行代码纯属三星的人发贱正确易懂的写法是add r2, r10, r2, LSL2 ; 干脆用C语言写更加易懂一些就是r2 r2*4 r10这里的左移Bit主要原因还是PTS中的每个元素是个字节 45 mov r2, r1 ; (r2) virtual address to map Bank at cmp r2, #0x20000000:SHR:BANK_SHIFT add r2, r10, r2, LSL #BANK_SHIFT-18 strlo r0, [r2] add r0, r0, #0x00100000 ; (r0) PTE for next physical page subs r3, r3, #1 add r1, r1, #1 bgt %b45 ; 兄弟们肯定在想我考你在这里搞了大半天修改的都是PTS那MMU咋能知道呢 ; 呵呵不要急到了下面的p15, 0, r10, c2, c0, 0不是把PTS的地址给MMU了么哈哈大功告成 ; 就剩下启动MMU了 ldr r10, PTs ; (r10) restore address of 1st level page table ; The page tables and exception vectors are setup. ; Initialize the MMU and turn it on. mov r1, #1 mcr p15, 0, r1, c3, c0, 0 ; setup access to domain 0 mcr p15, 0, r10, c2, c0, 0 mcr p15, 0, r0, c8, c7, 0 ; flush ID TLBs ; mrc p15,0,r1,c1,c0,0 orr r1, r1, #0x0071 ; Enable: MMU orr r1, r1, #0x0004 ; Enable the cache ldr r0, VirtualStart cmp r0, #0 ; make sure no stall on mov pc,r0 below ; OK终于把MMU给enable了可以用了哈哈爽 mcr p15, 0, r1, c1, c0, 0 mov pc, r0 ; jump to new virtual address nop ; MMU caches now enabled. ; (r10) physcial address of 1st level page table ; ;------------------------------------------------------------------ VirtualStart mrs r0, cpsr ; 下面这段是堆栈的配置如果你发现EBoot下面的变量和数组比较多的话一定要调整下面 ; 如Samsung的whimory.eboot就需要相当大的Stack空间小的话就会出莫名其妙的问题 ; 哦对了差点忘了Stack是从上朝下增长的而Ram是从从下朝上增长的不要越界了 bic r0, r0, #Mode_MASK orr r1, r0, #Mode_IRQ | NOINT msr cpsr_cxsf, r1 ; IRQMode mov sp, #0x80000000 add sp, sp, #0x3d000 ; bic r0, r0, #Mode_MASK | NOINT orr r1, r0, #Mode_SVC msr cpsr_cxsf, r1 ; SVCMode mov sp, #0x80000000 add sp, sp, #0x40000 ; b main ENTRY_END LTORG
2最终生成的PTS表格
上面的代码太抽象了我把PTS表格Dump出来之后用表格列写了以下如下
其中第四列表示虚拟地址第三列表示虚拟地址对应物理地址第一列表示PTS表格中的位置偏移而第二列为PTS表格中存放的数据。每1MB的虚拟地址在下面的表格中都对应一行。 address value physical address VIRTUAL ADD CHIP SPACE 0X70012000 0X7000040E 0X70000000 0x80000000 DDR Cached Space 0X70012004 0X7010040E 0X70100000 0X70012008 0X7020040E 0X70200000 0X7001200C 0X7030040E 0X70300000 … … … 0X700121FC 0X77F0040E 0X77F00000 0x700124C8 0xD010040E 0xD0101000 0x93200000 UART0 0X70012800 0x70000402 0X70000000 0xA0000000 DDR UNCACHED SPACE 0X70012804 0x70100402 0X70100000 0xA0100000 … … … 0x70012CC8 0xD0100402 0xD0101000 0xA3200000 UART0 0X70010000 0X7000040E 0X70000000 0X00000000 DDR 映射0地址到物理内存的开始位置这里只映射1MB的空间属性为Cache 0X70010800 0xD0100402 0X70000000 0X20000000 DDR 映射0x20000000地址到物理内存的开始位置这里也是仅仅映射1MB的空间属性为UnCache 0X70011C00 0X7000041E 0X70000000 X70000000 DDR 映射地址0X70000000到物理内存开始的位置 0X70011C04 0X7010041E 0X70100000 0X70100000 0X70011C08 0X7020041E 0X70200000 0X70200000 … … … … 0X70011DFC 0X77F0041E 0X77F00000 0X77F00000
最终赋值给MMU的值如下 Value MMU.SFR About 1 c3c0 Open MMU PTs0x70010000 c2c0 set up access to domain 0 7800041e c8c7 flush ID TLBs 5007d c0c1 Enable: MMU and cache
3物理地址和虚拟地址映射关系图形化显示
感觉上面的物理地址和虚拟地址的映射不够形象我把他们的映射关系用下面的图形表示。
1 0x0000 0000~0x000f ffff和0x7000 0000~0x700f ffff的映射如下 2 0x2000 0000~0x200f ffff和0x7000 0000~0x700f ffff的映射如下 3 0x8000 0000~0x83ff ffff与0x7000 0000~0x73ff ffff的映射如下 4 0xa000 0000~0xa3ff ffff与0x7000 0000~0x73ff ffff的映射如下 5 UART寄存器的映射如下 4附g_oalAddressTable表格 ; Export Definition EXPORT g_oalAddressTable[DATA] ;------------------------------------------------------------------------------ ; ; TABLE FORMAT ; cached address, physical address, size ;------------------------------------------------------------------------------ g_oalAddressTable DCD 0x80000000, 0x70000000, 64 ; 512 MB DRAM BANK DCD 0x93200000, 0xD0101000, 1 ; uart0 slv register DCD 0x00000000, 0x00000000, 0 ; end of table ;------------------------------------------------------------------------------ END 累死我了终于写完了。
如果有没写清楚的地方欢迎发邮件到guopeixin126.com或者在此留言。