type
status
date
slug
summary
tags
category
icon
password
URL
Linux初始化过程页表建立
Linux初始化过程,会依次建立如下页表映射:
- 恒等映射:页表基地址idmap_pg_dir;
- 粗粒度内核镜像映射:页表基地址init_pg_dir;
- fixmap映射:页表基地址为init_pg_dir,待paging_init之后为swapper_pg_end;
- 细粒度内核镜像映射:页表基地址为swapper_pg_dir;
- 线性映射: 页表基地址为swapper_pg_dir;
- 用户空间页表映射:页表基地址task->mm->pgd;
上篇解析 "fixmap映射" , 这里来解析主内核页表的创建, 包括"4.细粒度内核镜像映射"和"5.线性映射";
创建完固定映射后,会初始化物理页面分配器,即初始化伙伴系统;有了物理页面分配器,内核主页表就可以建立动态映射页表:
页面分配器这里略去,先来看主内核页表的建立,分两部分:
建立内核的细粒度映射
map_kernel()函数
将内核的每个段,分别建立页表
map_kernel_segment函数
为内核的段建立动态映射
__create_pgd_mapping函数
建立页表
动态分配页表
页表建立过程很简单,就不过多啰嗦了,这里标记两点:1.由于页面分配器已经初始化完,这里可以动态分配页表;(内核启动到这里之前,都是静态页表,即页表都是固定页面);2.动态分配的页表,拿到的是物理地址,要继续向下一级页表遍历,必须将物理地址转化为虚拟地址, CPU才能正确访问;
这样,内核镜像的各个段,就全部做了动态映射,后面访问,就不再依赖于固定映射;
但是pgd一级页表基地址,还是用的固定地址swapper_pg_dir, 内核页表建立后,需要将页表基地址更新到init进程的mm_struct结构体;
现在内核镜像本身可以自由访问了,但物理内存的其他区域,依然无法访问,为方便内核自由访问所有物理内存,Linux做了一个线性映射,
线性映射
将物理内存全部线性映射到虚拟地址段(仅做一个偏移),后续在内核空间可以直接用偏移地址访问整个物理内存;
线性映射核心函数map_mem()
__map_memblock
实际建立页表映射过程过程与细粒度大致相似
至此,Linux内核主页表创建完毕。