linux内核是如何实现分页机制的
注意:请使用谷歌浏览器阅读(IE浏览器排版混乱)
【摘要】
.epu swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE;//页全局描述符起始虚拟地址:0x80004000
PAGE_OFFSET:物理地址从此开始映射,内核空间虚拟地址即线性地址的起始地址.
经常定义为0xc0000000或0x80000000,如下例子:
#define PAGE_OFFSET CONFIG_PAGE_OFFSET
- - 关键地址,用户态和内核态虚拟地址分界点,有的平台使用0xc0000000 (arch/arm/include/asm/memory.h)
#define CONFIG_PAGE_OFFSET 0x80000000 (autoconf.h)
2) 物理地址的起始地址 PHYS_OFFSET(如0x200000).该地址映射到线性地址起始地址处,即 PAGE_OFFSET .
PHYS_OFFSET+TEXT_OFFSET- PG_DIR_SIZE=0x204000
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) (arch/arm/kernel/head.s)
- - 0x80008000内核代码段起始虚拟地址,uImage代码段从此开始;页全局描述符地址,据此算出.
#define PG_DIR_SIZE=0x4000 (arch/arm/kernel/head.s)
src/scripts/Makefile.lib :quiet_cmd_uimage= -a 0x208000 -e0x208000 其中0x200000是物理地址起始地址;
此处表明在uImage头中指定uImage代码段需要加载到的物理地址,boot中将uImage去头后读取到此地址,
内核态下0x208000映射到线性地址空间0x80008000即代码段所在物理地址对应的线性地址;
.text: 0x80008000-0x803cfea0 (3872kB--uImage代码段大小)
setup_arch->paging_init->map_lowmem()->create_mapping
static void __init create_mapping(struct map_desc *md)
{unsigned long addr, length, end;phys_addr_t phys;const struct mem_type *type;pgd_t *pgd;if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {printk(KERN_WARNING "BUG: not creating mapping for 0x%08llx"" at 0x%08lx in user region\n",(long long)__pfn_to_phys((u64)md->pfn), md->virtual);return;}if ((md->type == MT_DEVICE || md->type == MT_ROM) &&md->virtual >= PAGE_OFFSET &&(md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {printk(KERN_WARNING "BUG: mapping for 0x%08llx"" at 0x%08lx out of vmalloc space\n",(long long)__pfn_to_phys((u64)md->pfn), md->virtual);}/* mem_type中保存了页表属性和页中间目录的属性 */type = &mem_types[md->type];addr = md->virtual & PAGE_MASK;/*phys对应物理地址,本函数实际上就是把phys映射到addr*/phys = __pfn_to_phys(md->pfn);length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {printk(KERN_WARNING "BUG: map for 0x%08llx at 0x%08lx can not ""be mapped using pages, ignoring.\n",(long long)__pfn_to_phys(md->pfn), addr);return;}/* 页表创建过程如下:*/pgd = pgd_offset_k(addr);end = addr + length;do {unsigned long next = pgd_addr_end(addr, end);alloc_init_pud(pgd, addr, next, phys, type);phys += next - addr;addr = next;} while (pgd++, addr != end);
}
static void __init create_mapping(struct map_desc *md)
{
/*
1 init_task进程的页全局目录地址:swapper_pg_dir
以后每个进程都从这里拷贝页全局目录到各自的pgd里dup_mm->pgd_alloc中实现,cpu_switch_mm中切换。
*/pgd = pgd_offset_k(addr);end = addr + length;do {unsigned long next = pgd_addr_end(addr, end);/* 每个页全局目录 都要初始化页二级目录 */ alloc_init_pud(pgd, addr, next, phys, type);phys += next - addr;addr = next;} while (pgd++, addr != end);
}
->
2 页二级目录初始化:
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,unsigned long end, phys_addr_t phys,const struct mem_type *type)
{
/*
页二级目录地址,因为不使用页二级目录,所以页二级目录地址等于页全局目录地址。
为实现软件兼容性所以代码中还保留了页二级目录的处理流程,只不过它的地址即是页全局目录
*/pud_t *pud = pud_offset(pgd, addr);unsigned long next;do {next = pud_addr_end(addr, end);/*页三级目录初始化*/alloc_init_pmd(pud, addr, next, phys, type);phys += next - addr;} while (pud++, addr = next, addr != end);
}
->
3页三级目录初始化:
static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,unsigned long end, phys_addr_t phys,const struct mem_type *type)
{
/*
页三级目录地址,因为不使用页三级目录,所以页三级目录地址等于页二级目录,当然也等于页全局目录地址。
为实现软件兼容性所以代码中还保留了页三级目录的处理流程,只不过它的地址即是页全局目录
*/pmd_t *pmd = pmd_offset(pud, addr);unsigned long next;do {next = pmd_addr_end(addr, end);/*if;else都有可能执行到*//* 当我们创建页表项的虚拟地址区间是1M对齐时 */if (type->prot_sect && ((addr | next | phys) & ~SECTION_MASK) == 0) {__map_init_section(pmd, addr, next, phys, type);} /* 当我们创建页表项的虚拟地址区间非1M对齐时 */else {alloc_init_pte(pmd, addr, next,__phys_to_pfn(phys), type);}phys += next - addr;} while (pmd++, addr = next, addr != end);
}->
4 页表初始化:
虚拟地址区间1M时,如下方式MMU映射:
static void __init __map_init_section(pmd_t *pmd, unsigned long addr,unsigned long end, phys_addr_t phys,const struct mem_type *type)
{pmd_t *p = pmd;do { *pmd = __pmd(phys | type->prot_sect);phys += SECTION_SIZE;} while (pmd++, addr += SECTION_SIZE, addr != end);flush_pmd_entry(p);
}虚拟地址区间非1M对齐时,如下方式MMU映射,即创建页表:
static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,unsigned long end, unsigned long pfn,const struct mem_type *type)
{/* 此时申请页表的地址(一个页表项4byte,一个pmd有512个页表项)页表的基地址会赋值给pmd ,__pmd_populate中完成赋值*/pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);do {/*为每一页配置页表属性,注意此时用到了mem_types定义的属性*/set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);pfn++;} while (pte++, addr += PAGE_SIZE, addr != end);
}
ENTRY(cpu_v7_set_pte_ext)
/*
r0:页表项地址
r1:页表属性|物理地址偏移
将页表属性r1配置给页表项r0
*/str r1, [r0] @ linux versionbic r3, r1, #0x000003f0bic r3, r3, #PTE_TYPE_MASKorr r3, r3, r2orr r3, r3, #PTE_EXT_AP0 | 2tst r1, #1 << 4orrne r3, r3, #PTE_EXT_TEX(1)eor r1, r1, #L_PTE_DIRTYtst r1, #L_PTE_RDONLY | L_PTE_DIRTYorrne r3, r3, #PTE_EXT_APXtst r1, #L_PTE_USERorrne r3, r3, #PTE_EXT_AP1tst r1, #L_PTE_XNorrne r3, r3, #PTE_EXT_XNtst r1, #L_PTE_YOUNGtstne r1, #L_PTE_VALIDeorne r1, r1, #L_PTE_NONEtstne r1, #L_PTE_NONEmoveq r3, #0ARM( str r3, [r0, #2048]! )THUMB( add r0, r0, #2048 )THUMB( str r3, [r0] )ALT_SMP(W(nop))ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_ptebx lr
ENDPROC(cpu_v7_set_pte_ext)
1) 可以通过配置全局变量mem_types属性修改低端内存cache的开启情况,create_mapping中真正使用该配置。内核在初始化中的会为低端内存、io地址等地址空间设置页表属性,如果要修改这一部分内存的属性包括cache开启关闭情况,mem_types中定义了初始页表项属性,形如:
prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY
其实在内核启动过程的build_mem_type_table()函数里,还会根据不同arm版本做调整。
2)可以在映射一段物理内存之前通过系统的标志宏来修改cache使用情况。
举例:/dev/mem驱动中实现物理内存的重新映射(即mmap函数的实现过程).
mmap_mem->remap_pfn_range中:vm_page_prot = pgprot_writecombine(pVma->vm_page_prot);这段代码就是配置cache属性的。
内存映射前关闭cache的宏:
#define pgprot_noncached(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
关闭cache时使用的具体标志位:
#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0) << 2) /* strongly ordered */
#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 1) << 2) /* normal non-cacheable */
【总结】
附录:
· 关于存储器管理单元的结构
· 存储器访问的顺序
· 转换过程
· 访问权限
· 域
· 异常
· CP15 寄存器
http://embedded.homeunix.org 30/06/2003
Page 3 of 3
3.1 关于存储器管理单元的结构
MMU 存储器系统的结构允许对存储器系统的精细控制。大部分的控制细节由存在存
储器中的转换表提供。这些表的入口定义了从1KB 到1MB 的各种存储器区域的属
性。这些属性包括:
虚拟地址到物理地址映射
ARM 处理器产生的地址叫虚拟地址,MMU 允许把这个虚拟地址映射到一个不
同的物理地址去。这个物理地址表示了被访问的主存储器的位置。
它允许用很多方式管理物理存储器的位置,例如:它可以用具有潜在冲突的
地址映射为不同的进程分配存储器,或允许具有不连续地址的应用把它映射
到连续的地址空间。
------注------
如果使用了快速上下文切换扩展(Fast Context Switch Extension),则在
本文中的虚拟地址的意思应该是修改过的虚拟地址(Modified virtual
address)
---------------
存储器访问权限(permissions)
这些控制对存储器区域的不可访问权限、只读权限、读写权限。当访问不可
访问权限的存储器时,会有一个存储器异常通知ARM 处理器。
允许权限的级别也受程序运行在用户状态还是特权状态影响,还受是否使用
了域有关。
高速缓存和缓冲位(Cachability and bufferability bits [C and B])
这些在高速缓存和缓冲一节讲
系统控制协处理器的寄存器允许对系统的高级控制,如转换表的位置。他们也用来
为ARM 提供内存异常的状态信息。
查找整个转换表的过程叫转换表遍历。它由硬件制动进行,并需要大量的执行时间
(至少一个存储器访问,通常是两个)。为了减少存储器访问的平均消耗, 转换表
http://embedded.homeunix.org 30/06/2003
Page 4 of 4
遍历结果被高速缓存在一个或多个叫作Translation Lookaside Buffers(TLBs)的
结构中。通常在ARM 的实现中每个内存接口有一个TLB。
· 有一个存储器接口的系统通常有一个唯一的TLB
· 指令和数据的内存接口分开的系统通常有分开的指令TLB 和数据TLB
如果系统有高速缓存, 高速缓存的数量也通常是由同样的方法确定的。所以在高
速缓存的系统中,每个高速缓存一个TLB。
当存储器中的转换表被改变或选中了不同的转换表(通过写CP15 的寄存器2),先
前高速缓存的转换表遍历结果将不再有效。MMU 结构提供了刷新TLB 的操作。
MMU 结构也允许特定的转换表遍历结果被锁定在一个TLB 中,这就保证了对相关的
存储器区域的访问绝不会导致转换表遍历,这也对那些把指令和数据锁定在高速缓
存中的实时代码有相同的好处。
3.2 存储器访问的顺序
当ARM 要访问存储器时,MMU 先查找TLB 中的虚拟地址表,如果ARM 的结构支持分
开的地址TLB 和指令TLB,那么它用:
· 取指令使用指令TLB
· 其它的所有访问类别用数据TLB
如果TLB 中没有虚拟地址的入口,则转换表遍历硬件从存在主存储器中的转换表中
获取转换和访问权限,一旦取到,这些信息将被放在TLB 中,它会放在一个没有使
用的入口处或覆盖一个已有的入口。关于转换表的信息和转换表遍历的实现参见转
换过程一节。
一旦为存储器访问的TLB 的入口被拿到,这些信息将被用于:
1. C(高速缓存)和B(缓冲)位被用来控制高速缓存和写缓冲,并决定是否高速
缓存。(如果系统中没有高速缓存和写缓冲,则对应的位将被忽略)
2. 访问权限和域位用来控制访问是否被允许。如果不允许,则MMU 将向ARM 处理
器发送一个存储器异常;否则访问将被允许进行。
访问权限、域和异常几节有详细描述。
http://embedded.homeunix.org 30/06/2003
Page 5 of 5
3. 对没有高速缓存的系统(包括在没有高速缓存系统中的所有存储器访问),物
理地址将被用作主存储器访问的地址。
对有高速缓存的系统,在高速缓存没有选中的情况下,物理地址将被用行取
(line fetch)的地址。如果选中了高速缓存,则物理地址将被忽略。
图3-1 说明了这种高速缓存系统
访问控
制硬件
TLB
ARM
处理器
高速缓
存和写
缓冲
转换表遍历
硬件
高速缓
存行取
硬件
主
存
储
器
虚拟地址
异常
域位
C, B位
物理地址
图3-1 高速缓存的MMU存储器系统
http://embedded.homeunix.org 30/06/2003
Page 6 of 6
3.2.1 允许和禁止MMU
通过写系统控制协处理器的寄存器1 的第0 位可以允许和禁止MMU。在复位后这位
是0,MMU 被禁止。
当MMU 被禁止时,存储器访问将被按如下处理:
1. 由具体的实现确定当MMU 被禁止时是否能够允许高速缓存和写缓冲。
· 当MMU 被禁止时不能允许高速缓存和写缓冲时,C 和B 位不起作用。
· 当MMU 被禁止时能允许高速缓存和写缓冲时:
i. 访问数据时被认为没有高速缓存和写缓冲(C==0,B==0)
ii. 取指令时:
a) 当系统只有一个唯一的TLB 时,认为是没有高速缓存。(C==0)
b) 当系统只有独立的指令TLB 时,认为是有高速缓存。(C==1)
2. 没有存储器访问权限的检查,MMU 也不产生异常信号。
3. 物理地址与虚拟地址相同(即所谓的平坦地址映射模式)。
在允许MMU 之前,必须在内存中建立适当的转换表,并且所有相关的CP15 寄存器
要被初始化正确。
注:-------------------
允许和禁止MMU 直接改变了虚拟地址到物理地址的映射(除非转换表被设定为平坦
地址映射模式)。所以很可能在允许MMU 时所有的高速缓存需要被刷新。
另外,如果允许MMU 的指令的物理地址和虚拟地址不同,取指令将变得复杂化。所
以,强烈建议允许MMU 的指令具有相同的物理地址和虚拟地址。
--------------------------
http://embedded.homeunix.org 30/06/2003
Page 7 of 7
3.3 转换过程
MMU 支持基于节或页的存储器访问:
节(Section) 构成1MB 的存储器块
支持3 中不同的页尺寸:
微页(Tiny page) 构成1KB 的存储器块
小页(Small page) 构成4KB 的存储器块
大页(Large page) 构成64KB 的存储器块
节和大页是支持允许只用一个TLB 入口去映射大的存储器区间。小页和大页有附加
的访问控制:小页分成1KB 的子页,和大页分成16KB 的子页。微页没有子页,对
微页的访问控制是对整个页。
存在主存储器内的转换表有两个级别:
第一级表 存储节转换表和指向第二级表的指针。
第二级表 存储大页和小页的转换表。一种类型的第二级表存储微页转换表。
MMU 把CPU 产生的虚拟地址转换成物理地址去访问外部存储器,同时继承并检查访
问权限。地址转换有四条路径。路径的选取由这个地址是被标记成节映射访问还是
页映射访问确定。页映射访问可以是大、小和微页的访问。
然而,转换过程总是由下面所描述的那样由第一级表的获取开始。节映射的访问只
需要读取第一级表,页映射的访问还需要读取第二级表。
3.3.1 转换表基址
当片上(on-chip)的TLB 中不包含被要求的虚拟地址的入口时,转换过程被启
动。转换表基址寄存器(CP15 的寄存器2)保存着第一级转换表基址的物理地址。
只有bits[31:14]有效,bits[13:0]应该是零(SBZ)。所以第一级表必须在16KB
的边界。
3.3.2 取第一级表
http://embedded.homeunix.org 30/06/2003
Page 8 of 8
转换表基址寄存器的bits[31:14]与虚拟地址的bits[31:20]和两个0 位连接形成
32 为物理地址,如图3-2。这个地址选择了一个四字节的转换表入口,它是第一级
描述符或是指向第二级页表的指针。
转换基址 SBZ
转换基址 表索引 00
31 14 13 0
31 20 19 0
31 14 13 2 10
表索引 xxxxxxxxxxxxxxxxxxxxxx
图3-2 访问转换表的第一级描述符
http://embedded.homeunix.org 30/06/2003
Page 9 of 9
3.3.3 第一级描述符
第一级表的每个入口是一个描述它所关联的1MB 虚拟地址是如何映射的描述符。见
表3-1,根据bits[1:0]的组合,有四种可能:
· 如果bits[1:0]==0b00,所关联的地址没有被映射,试图访问他们将产生一
个转换错(fault)。因为他们被硬件忽略,所以软件可以利用这样的描述
符的bits[31:2]做自己的用途。推荐为描述符继续保持正确的访问权限。
· 如果bits[1:0]==0b10,这个入口是它所关联地址的节描述符。见节描述符
和转换节参考中的细节。
· 如果bits[0]==1,这个入口给出粗糙第二级表(bit[1]==0),或精细第二
级表(bit[1]==1)。每一种类型的表描述了它所关联的1MB 存储区域的映
射。粗糙第二级表较小,每个表1KB,每个精细第二级表4KB。然而粗糙第
二级表只能映射大页和小页,精细第二级表可以映射大页、小页和微页。
3.3.4 节描述符和转换节参考
如果第一级描述符是节描述符,那么各个字段有如下的意义:
Bits[1:0] 描述符类型标识(0b10 表示节描述符)
Bits[3:2] 高速缓存和缓冲位
Bits[4] 由具体实现定义
Bits[8:5] 这个描述符控制的节的16 种域之一
Bits[9] 现在没有使用,应该为零
Bits[11:10] 访问控制,见表3-3
Bits[19:12] 现在没有使用,应该为零
Bits[31:20] 节基址,形成物理地址的高12 位
忽略 00
粗糙页表基址 sbz 域 imp 00
节基址 SBZ AP sbz 域 imp C B 10
精细页表基址 SBZ 域 imp 11
31 20 19 12 11 10 9 8 5 4 3 2 10
表 3-1 第一级描述符格式
错
粗糙页表
节
精细页表
http://embedded.homeunix.org 30/06/2003
Page 10 of 10
图3-3 表示了节转换的完整过程。
注:---------------
访问权限必须在物理地址产生之前去检查,检查访问权限的顺序见访问权限一节。
---------------------
表索引 节索引
31 20 19 0
虚拟地址
转换基址 SBZ
31 14 13 0
转换表基址
转换基址 表索引 00
31 14 13 2 1 0
第一级表地址
节基址 SBZ AP sbz 域 imp C B 10
31 20 19 12 11 10 9 8 5 4 3 2 1 0
第一级表描述符
节基址 节索引
31 20 19 0
物理地址
图3-3 节转换
First-level fetch
http://embedded.homeunix.org 30/06/2003
Page 11 of 11
3.3.5 粗糙页表描述符
如果第一级描述符是粗糙页表描述符,那么各个字段有如下的意义:
Bits[1:0] 描述符类型标识(0b01 表示粗糙页表描述符)
Bits[4:2] 由具体实现定义
Bits[8:5] 这个描述符控制的页的16 种域之一
Bits[9] 现在没有使用,应该为零
Bits[31:10] 页表基地址是一个指向第二极粗糙页表的指针,它给出第二级表访问
的基地址。而第二级粗糙页表必须在1KB 边界对齐。
如果从第一级读取到的是二级粗糙页表描述符,那么会象图3-4 所示执行第二级描
述符读取。
第一级表索引 第二级表索引 xxxxx
31 20 19 12 11 0
虚拟地址
转换基址 SBZ
31 14 13 0
转换表基址
转换基址 第一级表索引 0 0
31 14 13 2 1 0
第一级描述符地址
页表基址 sbz 域 imp 01
31 10 9 8 5 4 2 1 0
第一级描述符
页表基址 第二级表索引 00
31 10 9 2 1 0
第二级描述符地址
First-level fetch
图3-4 访问粗糙页表第二级描述符
http://embedded.homeunix.org 30/06/2003
Page 12 of 12
3.3.6 精细页表描述符
如果第一级描述符是精细页表描述符,那么各个字段有如下的意义:
Bits[1:0] 描述符类型标识(0b11 表示精细页表描述符)
Bits[4:2] 由具体实现定义
Bits[8:5] 这个描述符控制的页的16 种域之一
Bits[11:9] 现在没有使用,应该为零
Bits[31:10] 页表基地址是一个指向第二级精细页表的指针,它给出第二级表访问
的基地址。而第二级精细页表必须在4KB 边界对齐。
如果从第一级读取到的是二级精细页表描述符,那么会象图3-5 所示执行第二级描
述符读取。
第一级表索引 第二级表索引 xxxxx
31 20 19 10 9 0
虚拟地址
转换基址 SBZ
31 14 13 0
转换表基址
转换基址 第一级表索引 0 0
31 14 13 2 1 0
第一级描述符地址
页表基址 sbz 域 imp 01
31 12 11 9 8 5 4 2 1 0
第一级描述符
页表基址 第二级表索引 00
31 12 11 2 1 0
第二级描述符地址
First-level fetch
图3-5 访问精细页表第二级描述符
http://embedded.homeunix.org 30/06/2003
Page 13 of 13
3.3.7 第二级描述符
每个粗糙第二级表对映着以4KB 为单位的虚拟地址范围市怎么映射的,每个精细第
二级表对映着以1KB 为单位的虚拟地址范围市怎么映射的。那些入口是页描述符,
他们能够分别描述大于4KB 或1KB 的页。在这种情况下,这个描述符必须被重复足
够次,以保证这个页始终使用相同的描述符,不论访问这个页中的哪个虚拟地址。
对于一个第二级描述符,有四种可能,由描述符的bits[1:0]选择。见表3-2:
· 如果bits[1:0]==0b00,说关联的虚拟地址没有被映射,任何对这些虚拟地
址的访问将会导致转换错(fault)。软件可以利用这样的描述符的
bits[31:2]做自己的用途,因为他们被硬件忽略。推荐为描述符继续保持正
确的访问权限。
· 如果bits[1:0]==0b01,这个入口是大页描述符,描述64KB 的虚拟地址。
见转换大页参考。
一个大页描述符在精细第二级表中必须被重复64 次,在粗糙第二级表中必
须被重复16 次以保证所有的虚拟地址都被描述。
· 如果bits[1:0]== 0b10,这个入口是小页描述符,描述4KB 的虚拟地址。
见转换小页参考。
一个小页描述符在精细第二级表中必须被重复4 次,以保证所有的虚拟地址
都被描述。在粗糙第二级表中只有一个实例。
· 如果bits[1:0]== 0b11,这个入口是微页描述符,描述1KB 的虚拟地址。
见转换微页参考。
在精细第二级表中只需要一个微页描述符的实例。微页描述符不能在粗糙第
二级表中出现,如果出现了,结果不可预测。
忽略 00
大页基地址 SBZ AP3 AP2 AP1 AP0 C B 01
小页基地址 AP3 AP2 AP1 AP0 C B 01
微页基地址 SBZ AP C B 11
表3-2 第二级描述符格式
31 16 15 12 11 10 9 8 7 6 5 4 3 2 1 0
错
大页
小页
微页
http://embedded.homeunix.org 30/06/2003
Page 14 of 14
大页描述符字段
大页描述符的字段有如下意义:
bits[1:0] 表示描述符的类型
bits[3:2] 高速缓促和缓冲位
bits[11:4] 访问权限位。这些为控制对页的访问。关于这些位的解释见表3-3。
大页被分成4 各子页。
AP0 编码对第一个子页的访问权限。
AP1 编码对第二个子页的访问权限。
AP2 编码对第三个子页的访问权限。
AP3 编码对第四个子页的访问权限。
bits[15:12] 现在没有使用,应该为零。
bits[31:16] 用来形成物理地址的对应位。
小页描述符字段
小页描述符的字段有如下意义:
bits[1:0] 表示描述符的类型
bits[3:2] 高速缓促和缓冲位
bits[11:4] 访问权限位。这些为控制对页的访问。关于这些位的解释见表3-3。
小页被分成4 各子页。
AP0 编码对第一个子页的访问权限。
AP1 编码对第二个子页的访问权限。
AP2 编码对第三个子页的访问权限。
AP3 编码对第四个子页的访问权限。
bits[31:12] 用来形成物理地址的对应位。
微页描述符字段
微页描述符的字段有如下意义:
bits[1:0] 表示描述符的类型
bits[3:2] 高速缓促和缓冲位
bits[5:4] 访问权限位。这些为控制对页的访问。关于这些位的解释见表3-3 关
于微页的解释。
bits[9:6] 现在没有使用,应该为零。
bits[31:10] 用来形成物理地址的对应位。
http://embedded.homeunix.org 30/06/2003
Page 15 of 15
3.3.8 转换大页参考
图3-6 显示了在粗糙第二级表中转换一个64KB 的大页的完整顺序。在精细第二级
表中的转换顺序页相似,只是第二级描述符的地址如精细页表描述符一节所决定。
注:-----------------------------
页索引的高4 位和第二级表的低阶4 位重叠,在粗糙页表中大页的每个页表入口必
须被重复16 次。在精细页表中大页的每个页表入口必须被重复64 次。
-----------------------------------
大页基址 页索引
31 16 15 0
物理地址
大页基址 SBZ AP3 AP2 AP1 AP0 C B 0 1
31 16 15 121110 9 8 7 6 5 4 3 2 10
0
第二级描述符
页表基址 第二级表索引 00
31 10 9 2 10
第二级描述符地址
页表基址 sbz 域 imp 01
31 10 9 8 5 4 2 10
第一级描述符
转换基址 第一级表索引00
31 14 13 2 10
第一级描述符地址
转换基址 SBZ
31 14 13 2 10
转换表基址
第一级表索引 第二级表索引 页索引
31 20 19 16 15 12 11 0
虚拟地址
Second-level fetch
First-level fetch
图3-6 粗糙第二级表中的大页转换
http://embedded.homeunix.org 30/06/2003
Page 16 of 16
3.3.9 转换小页参考
图3-7 显示了在粗糙第二级表中转换一个4KB 的小页的完整顺序。在精细第二级表
中的转换顺序页相似,只是第二级描述符的地址如精细页表描述符一节所决定。
注:-----------------------------
当小页出现在精细第二级表中时,页索引的高2 位和第二级表的低阶2 位重叠,在
精细页表中小页的每个页表入口必须被重复4 次。
-----------------------------------
图3-7 粗糙第二级表中的小页转换
小页基址 页索引
31 12 11 0
物理地址
小页基址 AP3 AP2 AP1 AP0 C B 10
31 12 11 10 9 8 7 6 5 4 3 2 10
0
第二级描述符
页表基址 第二级表索引00
31 10 9 2 10
第二级描述符地址
页表基址 sbz 域 imp 01
31 10 9 8 5 4 2 10
第一级描述符
转换基址 第一级表索引 00
31 14 13 2 10
第一级描述符地址
第一级表索引 第二级表索引 页索引
31 20 19 12 11 0
虚拟地址
转换基址 SBZ
31 14 13 0
转换表基址
First-level fetch
Second-level fetch
http://embedded.homeunix.org 30/06/2003
Page 17 of 17
3.3.10 转换微页索引
图3-8 显示了在精细第二级表中转换1KB 微页的完整过程。
注:---------------------------
微页不能出现在粗糙第二级表中。
---------------------------------
转换基址 SBZ
31 14 13 0
转换表基址
第一级表索引 第二级表索引 页索引
31 20 19 10 9 0
虚拟地址
转换基址 第一级表索引 00
31 14 13 2 10
第一级描述符地址
页表基址 sbz 域 imp11
31 12 11 9 8 5 4 2 10
第一级描述符
微页表基址 SBZ AP C B 11
31 10 9 6 5 4 3 2 10
第二级描述符
页表基址 第二级表索引00
31 12 11 2 10
第二级描述符地址
微页表基址 页索引
31 10 9 0
物理地址
Second-level fetch
First-level fetch
图3-8 精细第二级表中的微页转换
http://embedded.homeunix.org 30/06/2003
Page 18 of 18
3.4 访问权限
在节和页描述符中的访问权限位控制对相应的节和页的访问。访问权限由CP15 的
寄存器1 的System(S)和ROM(R)位修改。表3-3 描述了访问权限位和S、R 位相互
作用时的意义。如果访问了没有访问权限的存储器空间,将会产生权限错(见异常
一节)。
表3-3 MMU 访问权限
AP
S
R
Privileged permissions
User permissions
0b00 0 0 不能访问 不能访问
0b00 1 0 只读 不能访问
0b00 0 1 只读 只读
0b00 1 1 不可预测 不可预测
0b01 X X 读/写 不能访问
0b10 X X 读/写 只读
0b11 X X 读/写 读/写
http://embedded.homeunix.org 30/06/2003
Page 19 of 19
3.5 域
域是节、大页和小页的集合。ARM 结构支持16 个域。对域的访问由域访问控制寄
存器的两个位字段控制。因为每个字段对访问对应的域的使能非常迅速,所以整个
存储器区间能很快地交换进出虚拟存储器。这里支持2 种域访问方式:
客户 域的用户(执行程序,访问数据),被形成这个域的节或页来监督访
问权限。
管理者 控制域的行为(域中的当前节和页,对域的访问),不被形成这个域
的节或页来监督访问权限。
一个程序可以是一些域的客户,也是另外一些域的管理者,同时没有对其它域的访
问权限。这允许对程序访问不同存储器资源的非常灵活的存储器保护。表3-4 说明
了域访问控制寄存器的位编码方式。
表3-4 域访问的值
值
访问方式
描述
0b00 不能访问 任何访问都将导致一个域错(domain fault)
0b01 客户 能否访问将根据节或页描述符中的访问权限位
确定
0b10 保留 使用这个值将导致不可预料的结果
0b11 管理者 不根据节或页描述符中的访问权限位确定能否
访问,所以不会产生权限错。(permission
fault)
http://embedded.homeunix.org 30/06/2003
Page 20 of 20
linux内核是如何实现分页机制的相关推荐
- Linux 内核中的 Device Mapper 机制
本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...
- 【Linux 内核 内存管理】RCU 机制 ② ( RCU 机制适用场景 | RCU 机制特点 | 使用 RCU 机制保护链表 )
文章目录 一.RCU 机制适用场景 二.RCU 机制特点 三.使用 RCU 机制保护链表 一.RCU 机制适用场景 在上一篇博客 [Linux 内核 内存管理]RCU 机制 ① ( RCU 机制简介 ...
- 【Linux 内核 内存管理】RCU 机制 ① ( RCU 机制简介 | RCU 机制的优势与弊端 | RCU 机制的链表应用场景 )
文章目录 一.RCU 机制 二.RCU 机制的优势与弊端 三.RCU 机制的链表应用场景 一.RCU 机制 RCU , 英文全称是 " Read-Copy-Update " , 对 ...
- linux kernel and user space通信机制,Linux内核空间与用户空间通信机制地研究.doc
实用文案 标准文档 Linux内核空间与用户空间通信机制的研究 Linux kernel space and user space communication mechanism 摘 要 Linux ...
- 【Linux内核】RW读写锁机制
读写锁机制 Linux内核中读写锁的机制是一种多读单写的锁机制,它允许多个读操作同时进行,但只能有一个写操作进行.当有写操作时,所有读操作都会被阻塞,直到写操作完成. 在内核中,读写锁主要由以下两个结 ...
- Linux 内核的文件 Cache 管理机制介绍
1 前言 自从诞生以来,Linux 就被不断完善和普及,目前它已经成为主流通用操作系统之一,使用得非常广泛,它与 Windows.UNIX 一起占据了操作系统领域几乎所有的市场份额.特别是在高性能计算 ...
- Linux内核品读 /基础组件/ 模块机制快速入门
哈喽,我是杰克吴,继续记录我的学习心得. 一.关于兴趣的几点思考 1. 享受不是兴趣,愿意付出才是: 兴趣很容易跟享受混淆.享受是被动的,无需付出:而兴趣则要求你甘愿为了这件事情付出努力. 2.任何事 ...
- Linux宏定义实现类成员函数,全面解析Linux内核的同步与互斥机制
http://blog.csdn.net/sailor_8318/archive/2008/06/30/2599357.aspx [摘 要]本文分析了内核的同步及互斥的几种机制:原子运算符(atomi ...
- Linux内核编程01:模块机制
模块机制是Linux内核非常重要的一个功能,如果从C语言的模块化编程角度来看,Linux内核其实就是由大大小小.层次不同的模块构成的.有的模块比较小,一个C源文件就实现了:有的模块比较复杂,由多个源文 ...
最新文章
- Java中的异常处理:何时抛出异常,何时捕获异常?
- php yof框架特点_腾讯正式开源高性能超轻量级 PHP 框架 Biny
- Linux网络编程 之 UDP编程(六)
- springboot activiti工作流简单示例
- 吴裕雄 19-Mysql 连接的使用
- 17家银行工资单:招行人均45万夺冠
- 使用Spring AOP和番石榴速率限制器的节气门方法
- php文件读取文件内容,PHP文件系统函数-读取文件内容几种方式
- Portainer 安装与使用
- 数据结构与算法 迷宫问题
- EDA实验课课程笔记(四)——TCL脚本语言的学习2
- 循环冗余校验 使用及记忆方法
- e-HR推动知识型企业人力资源管理提升
- [书籍翻译]12周撰写期刊文章 学术出版成功指南——第 12周:文章投稿
- c语言怎么写注释,C语言如何注释一段代码?
- 计算机自带游戏怎么调,电脑游戏声音小怎么调,教您电脑游戏声音小怎么调
- OPENCV(七)对啤酒盖进行缺陷检测
- 2017 开源中国新增开源项目排行榜 TOP 100
- 行人重识别(ReID) ——数据集描述 DukeMTMC-reID
- 【数据挖掘】任务6:DBSCAN聚类