linux那些事之early pape fault
由linux那些事之中断与异常(AMD64架构)_2》分析可知,在kernel启动过程中首先安装的early中断dt_setup_early_handler中,主要是对page fault中断支持,这是早期第一个page fault中断处理称为early page fault.
early page fault处理的内核空间
early page fault主要是为后续用到的虚拟地址空间建立映射方式。
需要特别指出的是,此段空间映射采用虚拟地址 与物理地址一一对应映射的方式,主要是方便进行管理,并且此时buddy还没有启动不能通过buddy分配物理内存,由内核空间划分可知,内核中存在一段虚拟地址和物理地址一一映射空间, 4级page table 位于0xfff888000000000~ffffc87fffffffff
5级 page table位于 0xff11000000000000~0xff90ffffffffffff:
early page table entry划分
根据 五级转换分布使用如下:
- early_top_pgt 用于专门管理pgd表
- 其余p4d、pud、pmd统一使用 early_dynamic_pgts进行管理以节约物理内存
- 采用huge page
early_top_pgt
early_top_pgt 定义如下:
extern pgd_t early_top_pgt[PTRS_PER_PGD];
entry 占用8个字节,early_top_pgt 实际占用内存大小为512*8=4096 一个page 大小。
由于在内核还为启动因此early_top_pgt 不能通过buddy分配物理内存,只能通过汇编初始化并申请空间(arch\x86\kernel\head_64.S:
SYM_DATA_START_PTI_ALIGNED(early_top_pgt).fill 512,8,0.fill PTI_USER_PGD_FILL,8,0
SYM_DATA_END(early_top_pgt)
通过.file 指令,重复执行512次,每次将8个字节空间填充为0。
early_dynamic_pgts
early_dynamic_pgts定义如下:
#define EARLY_DYNAMIC_PAGE_TABLES 64extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
共计64*512=32,768 个entry ,占用64个page 物理页。(并没有为一一映射空间申请全部entry,个人认为主要是用于节约物理内存,内核需要并不需要太多物理内存)。
early_dynamic_pgts 初始化同样是使用汇编:
SYM_DATA_START_PAGE_ALIGNED(early_dynamic_pgts).fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0
SYM_DATA_END(early_dynamic_pgts)
early_make_pgtable()
early_make_pgtable()函数为:
int __init early_make_pgtable(unsigned long address)
{unsigned long physaddr = address - __PAGE_OFFSET;pmdval_t pmd;pmd = (physaddr & PMD_MASK) + early_pmd_flags;return __early_make_pgtable(address, pmd);
}
- unsigned long physaddr = address - __PAGE_OFFSET; 计算虚拟地址对应的物理地址,一一映射,虚拟地址减去__PAGE_OFFSET偏移,4级别page table __PAGE_OFFSET为0xfff888000000000
- 计算之后的物理地址 结合early_pmd_flags (主要是权限),组成PTE entry ,调用__early_make_pgtable 设置到page table中
__early_make_pgtable
__early_make_pgtable walk page table, 并设置PTE entry到page table中:
/* Create a new PMD entry */
int __init __early_make_pgtable(unsigned long address, pmdval_t pmd)
{unsigned long physaddr = address - __PAGE_OFFSET;pgdval_t pgd, *pgd_p;p4dval_t p4d, *p4d_p;pudval_t pud, *pud_p;pmdval_t *pmd_p;/* Invalid address or early pgt is done ? */if (physaddr >= MAXMEM || read_cr3_pa() != __pa_nodebug(early_top_pgt))return -1;again:pgd_p = &early_top_pgt[pgd_index(address)].pgd;pgd = *pgd_p;/** The use of __START_KERNEL_map rather than __PAGE_OFFSET here is* critical -- __PAGE_OFFSET would point us back into the dynamic* range and we might end up looping forever...*/if (!pgtable_l5_enabled())p4d_p = pgd_p;else if (pgd)p4d_p = (p4dval_t *)((pgd & PTE_PFN_MASK) + __START_KERNEL_map - phys_base);else {if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) {reset_early_page_tables();goto again;}p4d_p = (p4dval_t *)early_dynamic_pgts[next_early_pgt++];memset(p4d_p, 0, sizeof(*p4d_p) * PTRS_PER_P4D);*pgd_p = (pgdval_t)p4d_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE;}p4d_p += p4d_index(address);p4d = *p4d_p;if (p4d)pud_p = (pudval_t *)((p4d & PTE_PFN_MASK) + __START_KERNEL_map - phys_base);else {if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) {reset_early_page_tables();goto again;}pud_p = (pudval_t *)early_dynamic_pgts[next_early_pgt++];memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);*p4d_p = (p4dval_t)pud_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE;}pud_p += pud_index(address);pud = *pud_p;if (pud)pmd_p = (pmdval_t *)((pud & PTE_PFN_MASK) + __START_KERNEL_map - phys_base);else {if (next_early_pgt >= EARLY_DYNAMIC_PAGE_TABLES) {reset_early_page_tables();goto again;}pmd_p = (pmdval_t *)early_dynamic_pgts[next_early_pgt++];memset(pmd_p, 0, sizeof(*pmd_p) * PTRS_PER_PMD);*pud_p = (pudval_t)pmd_p - __START_KERNEL_map + phys_base + _KERNPG_TABLE;}pmd_p[pmd_index(address)] = pmd;return 0;
}
- pgd_p = &early_top_pgt[pgd_index(address)].pgd; 根据虚拟地址 查找到对应pgd 表
- 如果pgtable_l5_enabled 5级映射没有使能,则p4d表不存在,直接与pdg相等
- 如果设置5级 page table,则查找p4d entry是否存在,如果不存在则从early_dynamic_pgts 获取到一个entry,并设置到pdg 表中
- pud表 过程同上
- 后续一直遍历到pmd表中 并将entry 设置到pmd中(没有PTE表采用huge page进一步节约early_top_pgt 物理内存。
linux那些事之early pape fault相关推荐
- linux那些事之page fault(AMD64架构)(user space)(2)
do_user_addr_fault 用户空间地址处理是page fault主要处理流程,x86 64位系统主要是do_user_addr_fault()函数 该处理部分是x86架构特有部分 即与架构 ...
- linux那些事之LRU(3)
继续承接<linux那些事之LRU(2)>,shrink_active_list()函数中需要将调用isolate_lru_pages函数将active LRU中从链表尾部隔离出nr_to ...
- linux那些事之pin memory相关API
内核中为pin memory 用户空间申请物理内存除了get_user_pages() API函数之外,还有其他相关一系列函数,主要位于mm\gup.c 主要都是针对get_user_pages进行的 ...
- linux那些事之TLB(Translation-Lookaside Buffer)无效操作
TLB 为了加速虚拟地址转换物理地址过程,CPU内部一般都集成TLB硬件单元,通过缓存存取虚拟地址与物理地址映射关系,避免再通过MMU 通过多级查表引入多次内存开销,直接将映射关系存储到硬件单元中,本 ...
- linux那些事之follow_page
follow_page()函数是内核中用于根据虚拟地址查找对应的物理页函数,函数定义如下: struct page *follow_page(struct vm_area_struct *vma, u ...
- 网吧软件正版化,别拿Linux说事
<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } --> 5月15日,媒体盛传微软开始对东莞市网吧行业"下手" ...
- Linux内核运行时错误:general protection fault
最近帮师兄做内核实验,错误不断,由于是修改的内核代码,所以经常遇到错误排查起来都比较麻烦,刚解决了一个问题下一个问题就又出现了. 直接上新问题的描述:general protection fault ...
- linux内核那些事之early boot memory-memblock
Why need early boot memory? early boot memory即位于系统上电到内核内存管理模型构建之前这段内存管理阶段,严格说它只是系统启动过程中一个中间阶段的内存管理,当 ...
- linux那些事之page fault(AMD64架构)(1)
应用程序或者内核都是运行在虚拟内存空间之中,kernel 启动完成之后如果一个虚拟地址要访问物理内存需要通过CPU MMU硬件进行地址转换,整个虚拟地址访问物理内存逻辑过程如下: kernel 启动完 ...
最新文章
- NAT技术解决了IPv4地址短缺的问题,假设内网的地址数是m,而外网地址数n,若mn,则这种技术叫做(66),若mn,且n=1,则这种技术这叫做(67)。【答案】A C
- 讲真,上班路上 1 小时算很幸福了!
- python实现实例_用python语言实现斗地主基础版-案例
- [Qt教程] 第23篇 数据库(三)利用QSqlQuery类执行SQL语句
- Spark配置参数详解
- c语言宏高级用法,C语言宏高级用法 [总结]
- sapmto生产模式配置及操作详解_硬岩制砂线怎么设计?300t/h的生产流程与设备配置详解...
- bartender的安全策略不允许指定的用户执行此操作_Linux sudo 被曝提权漏洞,任意用户均能以 root 身份运行命令...
- java python c++比喻图_Java/Python/PHP/C++图文详解它们之间的尿性
- from scipy import special, optimize, from ._nnls import nnls ImportError: DLL load failed: 找不到指定的模块。
- opengl代码实例_一步步学OpenGL(22) -《OpenGL使用Assimp库导入3d模型》
- Intouch2020安装与授权
- 诺基亚PC套件界面设计
- 【Python系列】python文件或文本加密(4种方法)
- HTML网页制作——制作一个属于自己的网页
- 上传漏洞靶场:upload-labs 8-13关
- Android Studio中关于消除“Permission is only granted to system apps”错误的方法
- Attach函数的讲解
- 计算机分享硬盘,共享磁盘是什么怎么设置
- 中科院自动化所 模式识别国家重点实验室(NLPR)