Linux内核虚拟内存之页表管理

时间:2024-04-06 22:45:31

linux采用了一种同时适用于32位和64位系统的普通分页模型。对于像32位arm系统来说两级页表已经足够,但64位系统需要更多数量的分页级别。2.6.10版本以前,linux采用三级分页的模型,从2.6.11版本开始采用4级分页模型。4种页表如下:

页全局目录(pgd)

页上级目录(pud)

页中间目录(pmd)

页表(pte)

其分页模型如下:

Linux内核虚拟内存之页表管理

图中没有显示具体位数,主要是每一部分大小与体系结构相关。

对于没有启用物理地址扩展的32位系统使用两级页表,下面主要介绍基于32位的arm系统。

启动了物理地址扩展的32位系统使用三级页表。

64位系统使用三级还是四级分页取决与硬件对线性地址的位划分。

 

         以下分析arm的二级页表:

1、四级页表与二级页表

         linux模型是四级页表,而32位的arm是使用二级页表,之间如何对应起来:

pgd = pgd_offset_k(addr) = init_mm.pgd + ((addr)>>PGDIR_SHIFT)

         #definepgd_index(addr)     ((addr) >>PGDIR_SHIFT)

#definepgd_offset(mm, addr)    ((mm)->pgd +pgd_index(addr))

#define pgd_offset_k(addr)  pgd_offset(&init_mm, addr)

 

pud_t *pud = pud_offset(pgd, addr) = pgd

static inlinepud_t * pud_offset(pgd_t * pgd, unsigned long address)

{

             return (pud_t *)pgd;

}

 

pmd_t *pmd = pmd_offset(pud, addr) = pud =pgd

         staticinline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)

{  

             return (pmd_t *)pud;

}

 

pte_t *pte = start_pte + pte_index(addr);

         #definepte_index(addr)     (((addr) >>PAGE_SHIFT) & (PTRS_PER_PTE - 1))

 

从上面代码可以看出二级页表时,没有pud和pmd只剩下了pgd和pte。

 

2、页表类型                     

第一级页表pgd是由虚拟地址的高12bit(bits[31:20])组成,共有4096个表项,每个表项4个字节,因此4096 *4= 16K,这就是上面说的swapper_pg_dir总共为16K的原因,每个表项支持1MB,4096*1MB=4G。每个entry的最低2bit用来区分具体是什么种类的页表项,2bit可以区分4种页表项,具体每种表项的结构如下:

Linux内核虚拟内存之页表管理

arm体系主要用到了sectionentry和fine page table两种页表类型。前者在linux内核启动的初始化阶段,建立临时页表使用;后者则是正常工作使用(见下一节分析)。

arch/arm/kernel/head.S中__create_page_tables创建了sectionentry类型临时页表,供linux内核初始化执行环境,一个表项可以映射1MB的物理空间,mmu硬件执行虚拟地址转物理地址的过程如下:

Linux内核虚拟内存之页表管理

对于所有进程kernel部分的页表都是一样的,在内核do_fork的时候,申请pgd空间后,先清0,然后将拷贝init_mm内核部分的页表项到创建进程的页表项;而用户部分每个进程有自己的页表从而达到进程地址空间独立。

 

3、arm 二级页表

上面建立的临时页表在paging_init中被prepare_page_table清除,然后map_lowmem建立正常工作的二级页表(create_mapping),该函数为物理内存从0到lowmem_limit建立一个一一映射的映射表,就是物理地址和虚拟地址偏差一个固定偏移量PAGE_OFFSET。而有高端内存时,则通过VMALLOC_START~VMALLOC_END线性空间进行动态映射,建立mmu硬件使用的页表,访问完后,将映射清除线性空间释放,达到访问高端内存目的。

一级页表项:4096项16K,二级页表项256项1K,每个表项指向4K 空间(一个page),mmu将虚拟空间转化为物理空间如下:

Linux内核虚拟内存之页表管理

TLB:存放最近转化后的映射表,可以认为是一个页表的子集,加速查找不必每次都需要MMU进行硬件转化。

 

4、最新内核优化

         上面是arm典型的mmu映射框图,linux在此基础上进行了重要调整(细节看源码):

第一级页表从4096个项变成2048个项,每个项从4个字节变成8个字节,还是16K大小。

         第二级页表从1个256项变成2个256项,每项还是4个字节,这样总计256 *2 * 4 = 2KB,放置在page页的下半部,而上部分放置对应的linux内存管理系统使用页表,mmu硬件是不会去使用它,刚好占满4KB,不浪费空间。