页表概念
CPU并不是直接访问物理内存地址,而是通过虚拟地址空间来间接访问物理内存地址;虚拟地址空间是操作系统为每个正在执行的进程分配一个逻辑地址;比如在32位系统(处理器和内存地址总线都是32位),范围是0~(4G-1);操作系统通过将虚拟地址空间和物理内存地址之间建立映射关系,让CPU能够间接访问物理内存地址;
一般情况下,将虚拟地址空间以512byte~8kbyte,作为一个单位,称为页,并从0开始一次对它进行编号;这个大小就称为页面;将物理地址按照同样大小,作为一个单位,称为框或帧;也是从0开始依次对每个帧进行编号;
操作系统通过维护一张表,这张表记录每一对页和框的映射关系;
页表是一种特殊的数据结构,放在系统空间的页表区,存放逻辑页与物理页帧的对应关系;每个进程都拥有自己的页表,PCB(进程控制块)表中有指针指向页表;
系统位每一个进程建立一个页表,在进程逻辑地址空间中的每一页,依次在页表中有一个表项,记录该页对应的物理帧号;通过查找页表就可以找到该页在物理内存中的位置;页表具有逻辑地址到物理地址映射的作用;
页表用来把虚拟页映射到物理页,并且存放页的保护位,即访问权限;物理内存本身都是可读可写的,靠页表来控制访问权限,提高系统的安全性;
虚拟内存、页表、物理内存关系
页表结构
Linux内核把页表分为5级;
1)页全局目录(Page Global Directory,PGD);
2)页四级目录(Page 4th Directory,P4D);
3)页上层目录(Page Upper Directrory, PUD);
4)页中间目录(Page Middle Directory,PMD);
5)直接页表(Page Table,PT);
各种处理器架构可以选择使用五级、四级、三级或者两级页表;同一种处理器架构在页长度不同的情况可能选择不通的页表级数;可以使用CONFIG_PGTABLE_LEVELS配置页表的级数;
五级页表的结构如下图;每个进程有独立的页表,进程的mm_struct实例的成员pgd指向页全局目录;前面四级页表的表项存放下一级页表的起始地址,直接页表的表项存放页帧号(Page Frame Number,PFN);
内核页游一个页表,0号内核线程的进程描述符init_task的成员active_mm指向内存描述符init_mm,内存描述符init_mm的成员pgd指向内核的页全局目录swapper_pg_dir;
虚拟地址转换成物理地址流程
虚拟地址被分解为6个部分:页全局目录索引、页四级目录索引、页上层目录索引、页中间目录索引、直接页表索引和页内偏移;
查询页表,把虚拟地址转换成物理地址的过程如下:
- 根据页全局目录的起始地址和页全局目录索引得到页全局目录表项的地址,然后从表项得到页四级目录的起始地址;
- 根据页四级目录的起始地址和页四级目录索引得到页四级目录表项的地址,然后从表项中得到页上层目录的起始地址;
- 根据页上层目录的起始地址和页上层目录索引得到页上层目录表项的地址,然后从表项得到页中间目录的起始地址;
- 根据页中间目录的起始地址和页中间目录索引得到页中间目录表项的地址,然后从表项得到直接页表的起始地址;
- 根据直接页表的起始地址和直接页表索引得到页表项的地址,然后从表项得到页帧号;
- 把页帧号和页内偏移组合成物理地址;
ARM64处理器页表
ARM64处理器把页表称为转换表(translation table),最多4级;ARM64处理器支持3中页长度:4KB、16KB和64KB;页长度和虚拟地址的宽度决定了转换表的级数;
如果虚拟地址的宽度是48bit,页长度是4KB,则使用4级页表;转换表和内核的页表术语的对应关系:0级转换表对应页全局目录,1级转换表对应页上层目录,2级转换表对应页中间目录,3级转换表对应直接页表;
48位虚拟地址被分解如下:
每级转换表占用一页,有512项,索引是48位虚拟地址的9个位;