首页 > 编程知识 正文

动物鲜为人知的秘密,鲜为人知的秘密的意思

时间:2023-05-03 11:18:19 阅读:163134 作者:4016

1 .开场白环境:

处理器体系结构: arm64

内核源: linux-5.11

ubuntu版本: 20.04.1

代码阅读工具: vim ctags cscope

在典型的操作系统中,mmu通常已打开以支持虚拟内存管理,但页表管理在虚拟内存管理中尤为重要。 本文主要回答了几个页表管理中的关键问题来解决Linux内核的页表管理,并看看页表管理中一些鲜为人知的秘密。

2 .页表的作用是什么?1)地址转换

将虚拟地址转换为物理地址

2)权限管理

管理对物理页面的cpu访问,包括读写执行权限

3)隔离地址空间

隔离每个进程的地址空间,避免相互影响,提供系统安全

打开mmu时,如果可以访问没有页表映射的虚拟内存,或者如果可以访问但没有页表映射,则会发生处理器异常,内核会选择杀死进程或panic; 使用页面表将内存的一部分设置为用户状态不可访问。 这样,处于用户状态的用户进程就无法访问内核地址空间的内容,由于用户进程各自都有自己的页表,所以彼此看不到对方的地址空间,也无法访问,各进程都是如果使用页表为单个内存设置只读属性,则不允许更改该内存的内容,并且内核与映射到用户进程地址空间的物理内存相对应,该物理内存保护内存不被重写使用页表可以方便地进行内存共享,并允许共享库中的许多进程映射到自己的地址空间来使用。使用页表可以在较小的内存中加载和运行较大的APP,然后在运行时根据需要进行加载和妈妈.

3 .页表的保管地点在哪里? 如果打开页表存放在物理内存中,mmu后需要修改页表,则为了访问页表,必须将页表所在的物理地址映射到虚拟地址。 例如,内核初始化后,物理内存会线性映射,以便根据物理地址和虚拟地址的偏移获得与页表中的物理地址相对应的虚拟地址。

4 .页表项中存储的是虚是实?页表基地址寄存器和各级页表项中存放的都是物理地址,而不是虚拟地址

5 .开启MMU后的地址转换流程? 虚拟地址转换物理地址的过程:打开mmu时,所有cpu都访问虚拟地址。 cpu访问一个虚拟地址后,通过cpu内部的mmu调查物理地址。 mmu首先通过虚拟地址在tlb中查找,如果找到相应的表条目,则直接获得物理地址。 如果找不到tlb,通过虚拟地址从页表基地址寄存器中保存的页表基地址中查询多级页表,直到最终找到对应的表条目,再将表条目

6 .为什么6. Linux内核使用多级页表? 1 )使用一级页面结构的优劣:

优点:

只需两次内存访问(一次访问页表,一次访问数据),效率高,简单易行

劣势:

需要在连续的大块存储器中存储每个进程的页表。 例如,在32位系统上,每个进程需要4米的页面表。 浪费内存。 虚拟内存越大,页表就越大,内存碎片时就越难分配给连续的大块内存,大多数虚拟内存都没有使用。

2 )使用多级页表结构的优劣:

优点:

1.节省内存

2.可以按需分配各级页表

3.可以离散存储页表

劣势:

必须遍历多个级别的页表,需要多次访问内存,这会增加复杂性

3 ) Linux内核综合考虑事项:

通常,通过按时间更改区域,可以将各级页表放置在物理内存中的任意位置。 无论是硬件路径还是内核路径,都比一级页表复杂,但为了节省内存,内核选择三级页表结构。

7 .减少多级页面表扫描优化? 1 )向mmu添加tlb

为了缓存最近访问的页面表条目,根据程序的时间和空间的局部性原理,tlb可具有较高的命中率。

2 )使用巨大页面

通过减少访问次数(例如使用1G或2M的大页面),可以减少tlb miss和缺少页面的异常。

8 .硬件做了什么?遍历页表,将va转换为pa,页面权限管理

相关硬件为:

mmu

-功能:遍历tlb查询或页面表

tlb

-功能:缓存最近转换的页表条目

页表基地址寄存器例如ttbr0_el1 ttbr1_el1

-功能:存储页表基地址(物理地址)作为mmu遍历多级页表的起点

在mu进行多级页表扫描的情况下,在知道虚拟地址的最高位比特为1时,使用ttbr1_el1作为扫描开始点,在最高位比特为0时,使用ttbr0_el1作为扫描开始点。

9 .软件做了什么? 1 ) APP声明

p>访问虚拟内存即可如执行指令、读写内存, 没有权限管理页表

不管虚拟内存如何转换为物理内存,对应用来说透明。

2)Linux内核

填写页表,将页表基地址告诉mmu

内核初始化建立内核页表,实现缺页异常等机制为用户任务按需分配并映射页表。

当然,内核也可以遍历页表,如缺页异常时遍历进程页表。

10. 内核中涉及到的页表基地址?

内核:

idmap_pg_dir    恒等映射页表(va=pa 映射2M)

init_pg_dir        粗粒度内核页表

swapper_pg_dir   主内核页表

用户:

tsk->mm->pgd 用户进程fork的时候分配私有的pgd页,用于保存pgd表项(仅仅分配了第一级页表)。

11. 页表填写/切换时机

1)内核页表填充 

内核初始化过程:

物理地址 -> 恒等映射(建立恒等映射页表和粗粒度内核页表) ->打开mmu ->  paging_init(建立细粒度的内核页表和内存线性映射)  -> ...

恒等映射阶段:

将恒等映射页表idmap_pg_dir  地址保存到ttbr0_el1

将 粗粒度内核页表init_pg_dir 地址保存到ttbr1_el1 

paging_init阶段:

将内核主页表swapper_pg_dir 地址保存到ttbr1_el1

paging_init之后丢弃idmap_pg_dir  和init_pg_dir  页表的使用。

2)用户页表填充 

访问时缺页填充:

用户进程访问已经申请的虚拟内存时,发生缺页,缺页处理程序中为进程分配各级页表等物理页并建立页表映射关系。

进程切换时切换进程页表:

switch_mm的时候切换tsk->mm->pgd到ttbr0_el1以及asid 到ttbr1_el1,从而完成了进程地址空间切换。

12.页表遍历过程

下面以arm64处理器架构多级页表遍历作为结束(使用4级页表,页大小为4K):

Linux内核中 可以将页表扩展到5级,分别是页全局目录(Page Global Directory, PGD),  页4级目录(Page 4th Directory, P4D),   页上级目录(Page Upper Directory, PUD),页中间目录(Page Middle Directory, PMD),直接页表(Page Table, PT),而支持arm64的linux使用4级页表结构分别是 pgd,  pud, pmd, pt ,arm64手册中将他们分别叫做L0,L1,L2,L3级转换表,所以一下使用L0-L3表示各级页表。

tlb miss时,mmu会进行多级页表遍历遍历过程如下:

1.mmu根据虚拟地址的最高位判断使用哪个页表基地址寄存器作为起点:当最高位为0时,使用ttbr0_el1作为起点(访问的是用户空间地址);当最高位为1时,使用ttbr1_el1作为起点(访问的是内核空间地址) mmu从相应的页表基地址寄存器中获得L0转换表基地址。

2.找到L0级转换表,然后从虚拟地址中获得L0索引,通过L0索引找到相应的表项(arm64中称为L0表描述符,内核中叫做PGD表项),从表项中获得L1转换表基地址。

3.找到L1级转换表,然后从虚拟地址中获得L1索引,通过L1索引找到相应的表项(arm64中称为L1表描述符,内核中叫做PUD表项),从表项中获得L2转换表基地址。

4.找到L2级转换表,然后从虚拟地址中获得L2索引,通过L2索引找到相应的表项(arm64中称为L2表描述符,内核中叫做PUD表项),从表项中获得L3转换表基地址。

5.找到L3级转换表,然后从虚拟地址中获得L3索引,通过L3索引找到页表项(arm64中称为页描述符,内核中叫做页表项)。

6.从页表项中取出物理页帧号然后加上物理地址偏移(VA[11,0])获得最终的物理地址。

(END)

更多精彩,尽在"Linux阅码场",扫描下方二维码关注

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。