linux kernel 内存管理-页表、TLB

1. 页表

1.1 统一的页表框架

页表用来把虚拟页映射到物理页,并且存放页的保护位(即访问权限)。
在Linux4.11版本以前,Linux内核把页表分为4级:
页全局目录表(PGD)、页上层目录(PUD)、页中间目录(PMD)、直接页表(PT)
4.11版本把页表扩展到5级,在页全局目录和页上层目录之间增加了页四级目录(P4D)
各处处理器架构可以选择使用5级,4级,3级或者2级页表,同一种处理器在页长度不同的情况可能选择不同的页表级数。可以使用配置宏CONFIG_PGTABLE_LEVELS配置页表的级数,一般使用默认值。
如果选择4级页表,那么使用PGD,PUD,PMD,PT;如果使用3级页表,那么使用PGD,PMD,PT;如果选择2级页表,那么使用PGD和PT。如果不使用页中间目录,那么内核模拟页中间目录,调用函数pmd_offset根据页上层目录表项和虚拟地址获取页中间目录表项时直接把页上层目录表项指针强制转换成页中间目录表项

static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
{
    return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
}

每个进程有独立的页表,进程的mm_struct实例的成员pgd指向页全局目录,前面四级页表的表项存放下一级页表的起始地址,直接页表的页表项存放页帧号(PFN)
内核也有一个页表,0号内核线程的进程描述符init_task的成员active_mm指向内存描述符init_mm,内存描述符init_mm的成员pgd指向内核的页全局目录swapper_pg_dir

1.2 ARM64处理器的页表

ARM64处理器把页表称为转换表,最多4级。ARM64处理器支持三种页长度:4KB,16KB,64KB。页长度和虚拟地址的宽度决定了转换表的级数,在虚拟地址的宽度为48位的条件下,页长度和转换表级数的关系如下所示:

页长度 转换表级数
4KB 4级页表
16KB 4级页表
64KB 3级页表

ARM64处理器把表项称为描述符,使用64位的长描述符格式。描述符的0bit指示描述符是不是有效的:0表示无效,1表示有效。第1位指定描述符类型。
在块描述符和页描述符中,内存属性被拆分为一个高属性和一个低属性块。

块/页描述符中的内存属性

(1)[59,63):基于页的硬件属性。
(2)[55,59):保留给软件使用。
(3)54:在异常级别0,表示UXN,即不运行异常级别0执行内核代码;在其他异常级别,表示XN,不允许执行
(4)53:PXN不运行在特权级别(el1,el2,el3)执行
(5)52:连续,指示这条转换表项属于一个连续表项集合,一个连续表项集合可以被换存在一条TLB表项里面。
(6)51:脏位修饰符(DBM),指示页或内存块是否被修改过。
(7)11:非全局(nG)。表示不是全局,是进程私有的,有一个关联的ASID;nG位是0,表示转换是全局的,是所有进程共享的,内核的页或内存块是所有进程共享的。
(8)10:访问标志,指示页或内存块自从相应的转换表描述符中的访问标志被设置为0后是否被访问过。
(9)[8,10):可共享性,00表示不共享,01保留值,10表示外部共享,11表示内部共享。
(10)[6,8): AP[2:1](数据访问权限)。
(11)5:非安全。对于安全状态的内存访问,指定输出地址在安全地址映射还是非安全地址映射。
(12)[2,5):内存属性索引,指定寄存器MAIR_ELx中内存属性字段的索引,内存属性间接寄存器有8个8位内存属性字段:Attr<n>,n等于0~7。

2. TLB

处理器的MMU负责把虚拟地址转换成物理地址,为了改进虚拟地址到物理地址的转换速度,避免每次转换都需要查询内存中的页表,处理器厂商在管理单元里加了称为TLB的高速缓存,TLB直译为转换后备缓冲区,意译为页表缓存。
页表缓存用来缓存最近使用过的页表项,有些处理器使用两级页表缓存第一级TLB分为指令TLB和数据TLB,好处是取指令和取数据可以并行;第二级TLB是统一TLB,即指令和数据共用的TLB

2.1TLB表项格式

不同处理器架构的TLB表项的格式不同。ARM64处理器的每条TLB表项不仅包含虚拟地址和物理地址,也包含属性:内存类型、缓存策略、访问权限、地址空间标识符(ASID)和虚拟机标识符(VMID)。地址空间标识符区分不同进程的页表项虚拟机标识符区分不同虚拟机的页表项

2.2 TLB管理

如果内核修改了可能缓存在TLB里面的页表项,那么内核必须负责使旧的TLB表项失效,内核定义了每种处理器架构必须实现的函数。

函数 说明
void flush_tlb_all(void); 使所有TLB表项失效
void flush_tlb_mm(struct mm_struct *mm); 使指定用户地址空间的所有TLB表项失效,参数mm是进程的内存描述符
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,unsigned long end); 使指定用户地址空间的指定虚拟页的TLB表项失效,参数vma是虚拟内存区域,uaddr是一个虚拟页中的任意虚拟地址
void flush_tlb_kernel_range(unsigned long start, unsigned long end); 使内核的某个虚拟地址范围的TLB表项失效,参数start是起始地址,end是结束地址

当TLB没有命中的时候,ARM64处理器的MMU自动遍历内存中的页表,把页表项复制到TLB,不需要软件把页表项写到TLB,所以ARM64架构没有提供写TLB的指令。

2.3 地址空间标识符

为了减少在进程切换时清空页表缓存的需要,ARM64处理器的页表缓存使用非全局位区分内核和进程的页表项(nG位为0表示内核的页表项),使用地址空间标识符(ASID)区分不同进程的页表项
ARM64处理器的ASID长度是由具体实现定义的,可以选择8位或者16位。寄存器TTBR0_EL1或者TTBR1_EL1都可以用来存放当前进程的ASID,通常使用寄存器TCR_EL1的A1位决定使用哪个寄存器存放当前进程的ASID,通常使用寄存器TTBR0_EL1。寄存器TTBR0_EL1的位[63:48]或者[63:56]存放当前进程的ASID,位[47:1]存放当前进程的页全局目录的物理地址。
在SMP系统中,ARM64架构要求ASID在处理器的所有核是唯一的。假设ASID为8位,ASID只有256个值,其中0是保留值,可分配的ASID范围1~255,进程的数量可能超过255,两个进程的ASID可能相同,内核引入ASID版本号解决这个问题。
(1)每个进程有一个64位的软件ASID,低8位存放硬件ASID,高56位存放ASID版本号
(2)64位全局变量asid_generation的高56位保存全局ASID版本号
(3)当进程被调度时,比较进程的ASID版本号和全局版本号。如果版本号相同,那么直接使用上次分配的ASID,否则需要给进程重新分配硬件ASID。
存在空闲ASID,那么选择一个分配给进程。不存在空闲ASID时,把全局ASID版本号加1,重新从1开始分配硬件ASID,即硬件ASID从255回绕到1。因为刚分配的硬件ASID可能和某个进程的ASID相同,只是ASID版本号不同,页表缓存可能包含了这个进程的页表项,所以必须把所有处理器的页表缓存清空。
引入ASID版本号的好处是:避免每次进程切换都需要清空页表缓存,只需要在硬件ASID回环时把处理器的页表缓存清空

2.4 虚拟机标识符

虚拟机里面运行的客户操作系统的虚拟地址转物理地址分两个阶段:
(1)把虚拟地址转换成中间物理地址,由客户操作系统的内核控制,和非虚拟化的转换过程相同。
(2)把中间物理地址转换成物理地址,由虚拟机监控器控制,虚拟机监控器为每个虚拟机维护一个转换表,分配一个虚拟机标识符,寄存器VTTBR_EL2存放当前虚拟机的阶段2转换表的物理地址。
每个虚拟机有独立的ASID空间,页表缓存使用虚拟机标识符区分不同虚拟机的转换表项,避免每次虚拟机切换都要清空页表缓存,在虚拟机标识符回绕时把处理器的页表缓存清空。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1 内存组织 1.1 体系结构 (1)非一致内存访问(NUMA):指内存被划分为多个节点的多处理器系统,访问一个内...
    CHCD阅读 1,888评论 0 0
  • 1 内存管理概述 内存管理子系统可分为用户空间,内核空间和硬件3个层面。 1.1 用户空间 应用程序使用mallo...
    CHCD阅读 1,822评论 0 0
  • 内存映射是在进程的虚拟空间中创建一个映射,分为以下两种:(1)文件映射:文件支持的内存映射,把文件的一个区间映射到...
    CHCD阅读 2,856评论 0 0
  • 最近开始想稍微深入一点地学习Linux内核,主要参考内容是《深入理解Linux内核》和《深入理解Linux内核架构...
    ice_camel阅读 1,816评论 0 2
  • 操作系统对内存的管理 没有内存抽象的年代 在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物...
    Mr槑阅读 16,759评论 3 24