全部博文(86)
分类: LINUX
2015-07-13 19:21:24
CP15可以包含16个32bit的寄存器,分别标记为0~15。但是对于同一个寄存器的物理寄存器可能会对应多个。
实际上对于CP15的访问的指令相当简单,只有MCR于MRC。并且这两个指令的格式是相同的。
MCR/MRC {<cond>} p15, 0 ,<Rd>,<CRn>,<CRm>{,<opcode_2>}
其中Rd 为ARM的寄存器,CRn和CRm为协处理寄存器。CRn为主,而CRm与opcode_2为辅助寄存器,主要区分同一编号的不同寄存器。如果不需要的情况下CRm为C0,而opcode_2为0;
其中c1寄存器的bit0为禁止或者使能MMU。
如使能MMU:
MRC P15,0,R0,C1,C0,0
ORR R0,#01
MCR P15,0,R0,C1,C0,0
ARM中TTB(Translation Table Base)中存储了段描述符的物理地址,它必须与16KB对齐,所以低14bit都是零。如下图所示
它将4GB的空间划分为4096X32bit的区域虚拟寻址。这种寻址方式又分为两个步骤进行,分别为一级页表查询和二级页表查询。
下图为整个寻址方式的总框图:
从图中我们可以清楚的看到页表的查询分为直接的section base查询和基于二级页表的查询。下面将对这两种查询方式分别讨论和讲解。
这种方式是MMU里面最为简单的,也是用的最多的一种查询方式,它没有二级页表,在虚拟到物理地址的转换过程中加载了一部分访问权限。
当CPU从C2中读取TTB地址之后,如上图所示,将通过virtual address的[31:20]进行索引,这个索引所需要的地址当然也就是由这两部分合成的地址。具体的合成方法如下:
如图所示,最后的索引值(也就是所谓的地址转换条目地址)高16bit是由TTB的高16bit组成,而[13:2]是virtual address的高12bit,剩下的[1:0]保持为0(实际如果你对ARM创建这些东西原因有所研究就不难发现这其实就是为了32bit对齐而准备的)。通过这个地址索引便可以找到我们需要的一级描述符,也就是我们框图中的Translation Table。
而这个一级描述符可能存在几种格式,这几种格式又会代表不同的地址查询方法,如下图所示:
如果[1:0]是00,则表示访问失效,这个时候MMU没有适用这个地址,当然软件就可以使用这块内存了。
如果[1:0]是01,则表示这是二级页表粗颗粒方式(coarse page table),下节讨论。
如果[1:0]是10,则表示段组寻址(section base),是这节我们讨论的重点。
如果[1:0]是11,则表示这是二级页表细颗粒方式(fine page table),下节讨论。
当我们确认是段组寻址的时候,我们就必须确认这个段描述符中的访问权限,对于这些仿真权限的定义如下图:
我们先来看看段描述符中的定义,大家重点注意bit 11,10,4,3,2,1,0。其中bit[11:10]为访问允许位(access permission bits)。对于这两位的定义如下表所示:
而bit [4]要求必须是1,bit[3:2]表示C(cache)和B(buffer)的控制位。Bit[1:0]必须为10,表示为段组查询方式。如下表所示:
整个合成过程其实也比较简单,下图已经说的相当明白:
下面我举一组boot load在创建mmu一级页表的代码进行说明:
; Entry (r0) = pointer to MemoryMap array in physical memory
; Exit returns if MemoryMap is invalid
; For SMDK2440, we are always in RAM.
LEAF_ENTRY KernelStart
15 mov r11, r0 ; (r11) = &MemoryMap (save pointer)
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
add r10, r10, #0x2000 ; (r10) = ptr to 1st PTE for "unmapped space"//将虚拟地址0x8000 0000加到TTB的地址上创建一级页表的第一条
mov r0, #0x0E ; (r0) = PTE for 0: 1MB cachable bufferable//bit 4指定为1,此处为0,可以改为1.C/B为1设置为写回
orr r0, r0, #0x400 ; set kernel r/w permission//bit[11:10]为01,只允许管理模式访问,保护内核
20 mov r1, r11 ; (r1) = ptr to MemoryMap array
25 ldr r2, [r1], #4 ; (r2) = virtual address to map Bank at//读取OEMAddressTable中的数据,读后*r1+1
ldr r3, [r1], #4 ; (r3) = physical address to map from
ldr r4, [r1], #4 ; (r4) = num MB to map
cmp r4, #0 ; End of table?
beq %F29 //段组描述符创建完成
ldr r5, =0x1FF00000
and r2, r2, r5 ; VA needs 512MB, 1MB aligned.
ldr r5, =0xFFF00000
and r3, r3, r5 ; PA needs 4GB, 1MB aligned.
add r2, r10, r2, LSR #18
add r0, r0, r3 ; (r0) = PTE for next physical page
28 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 %B28 ; Map next MB
bic r0, r0, #0xF0000000 ; Clear Section Base Address Field
bic r0, r0, #0x0FF00000 ; Clear Section Base Address Field
b %B25 ; Get next element
29 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 %B20 ; go setup PTEs for uncached space
sub r10, r10, #0x3000 ; (r10) = restore address of 1st level page table
; setup mmu to map (VA == 0) to (PA == 0x30000000)
ldr r0, =PTs ; PTE entry for VA = 0
ldr r1, =0x3000040E ; uncache/unbuffer/rw, PA base == 0x30000000
str r1, [r0]
; uncached area
add r0, r0, #0x0800 ; PTE entry for VA = 0x0200.0000 , uncached
ldr r1, =0x30000402 ; uncache/unbuffer/rw, base == 0x30000000
str r1, [r0]
; Comment:
; The following loop is to direct map RAM VA == PA. i.e.
; VA == 0x30XXXXXX => PA == 0x30XXXXXX for S3C2400
; Fill in 8 entries to have a direct mapping for DRAM
ldr r10, =PTs ; restore address of 1st level page table
ldr r0, =PHYBASE
add r10, r10, #(0x3000 / 4) ; (r10) = ptr to 1st PTE for 0x30000000
add r0, r0, #0x1E ; 1MB cachable bufferable
orr r0, r0, #0x400 ; set kernel r/w permission
mov r1, #0
mov r3, #64
35 mov r2, r1 ; (r2) = virtual address to map Bank at//从0开始
cmp r2, #0x20000000:SHR:BANK_SHIFT//一直到200
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 %B35
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
MTC15 r1, c3 ; setup access to domain 0
MTC15 r10, c2 //把段组描述符TTB写入C2等待程序运行调用
mcr p15, 0, r0, c8, c7, 0 ; flush I+D TLBs//刷新快表
mov 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
MTC15 r1, c1 ; enable the MMU & Caches
mov pc, r0 ; & jump to new virtual address
nop
; MMU & caches now enabled.
;
; (r10) = physcial address of 1st level page table
(待续。。。)