0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ARM64 Linux内核页表的块映射

Linux阅码场 来源:Linuxer 作者:Linuxer 2021-01-04 13:37 次阅读

内核文档Documentation/arm64/memory.rst描述了ARM64 Linux内核空间的内存映射情况,应该是此方面最权威文档。

以典型的4K页和48位虚拟地址为例,整个内核空间的虚拟地址分布如下:

173d710c-4e4d-11eb-8b86-12bb97331649.png

从ffff000000000000到ffff7fffffffffff是一段针对物理地址的线性映射区,最大支持128TB的物理地址空间,这一段地址非常类似ARM32的low memory映射区。

我们看看这种情况下的页表,我们既可以用最终的【20:12】对应的PTE映射项,以4K为单位,进行虚拟地址到物理地址的映射;又可以以【29:21】对应的PMD映射项,以2M为单位,进行虚拟地址到物理地址的映射。

1764476e-4e4d-11eb-8b86-12bb97331649.png

对于用户空间的虚拟地址而言,当我们进行的是PMD映射的时候,我们得到的是Huge Page,ARM64的2MB的huge page,在虚拟和物理上都连续,它在实践工程中的好处是,可以减小TLB miss,因为,如果进行了2MB的映射,整个2MB不再需要PTE,映射关系大为减小。

178dd1ce-4e4d-11eb-8b86-12bb97331649.png

对于内核空间而言,从ffff000000000000到ffff7fffffffffff的这段虚拟地址,如果与物理地址进行的是一种PMD映射的话,显然也可以达到同样的效果。但是,这不意味着它们就是Huge Page。众所周知,内核开机把物理地址往虚拟地址进行线性映射,并不意味着这片内存被内核拿走了,它只是进行了一种映射,以便日后调用kmalloc(),get_free_pages()等API申请的内存是直接已经有虚实映射的。所以,即便内核进行的就是PMD映射,在内存的分割上,还是可以以4K为单位的:

17c8ca68-4e4d-11eb-8b86-12bb97331649.png

所以,即便我们在内核空间进行PMD映射,里面的每个蓝色圆圈(一个4K页),还是可以被单独分配的,这种分配可以是kmalloc、vmalloc,用户态的malloc等。内核态进行的PMD映射,不意味着相关的2MB成为了huge page,它纯粹只是为了服务于当内核以线性映射的虚拟地址访问该物理地址的时候(我们认为内核大多数时候是用这个线性映射的虚拟地址的),减小TLB miss。

当然,更牛逼的情况下,内核应该也可以直接用【38:30】位的PUD来进行映射,这样映射关系是1GB的,则整个1GB后面占TLB的时候,只需要占一个入口。

1835a250-4e4d-11eb-8b86-12bb97331649.png

当然,如果用户态的虚实映射是这样的,用户实际得到了一个1GB的巨页。但是对于内核的线性映射区域而言,即便我们进行了1GB的PUD映射,这1G内部就可以进一步切割为4KB页或者2MB的巨页。记住:内核态的线性映射区的映射只是个映射关系,不是个分配关系。比如下面的1GB的内核线性映射的1GB区域,仍然可以被4K分配走,或者被用户以huge page以2MB为单位分配走:

185868b2-4e4d-11eb-8b86-12bb97331649.png

我们需要一个真实的调试手段来验证我们的想法,这个调试手段就是PTDUMP(Page Table Dump),相关的代码在ARM64内核的:

arch/arm64/mm/ptdump.c和ptdump_debugfs.c

我们把它们全部选中,这样我们可以得到一个debugfs接口

/sys/kernel/debug/kernel_page_tables

来获知内核态页表的情况。

我用qemu启动了一个4GB内存的ARM64虚拟机,可以看到前1GB的虚拟地址空间大多数是PMD和PTE映射,后面的3GB,全是PUD映射:

188ac456-4e4d-11eb-8b86-12bb97331649.png

我的内核启动参数加了rodata=0:

$ cat/proc/cmdlineroot=/dev/vda2 rw console=ttyAMA0 ip=dhcp rodata=0

原因是内核在几种情况下,是不会做这种PMD和PUD映射的,相关代码见于:

18d0ee68-4e4d-11eb-8b86-12bb97331649.png

191e8b00-4e4d-11eb-8b86-12bb97331649.png

rodata_full在默认情况下总是成立的,它对应着内核的一个Config选项CONFIG_RODATA_FULL_DEFAULT_ENABLED, "Apply r/o permissions of VM areas also to their linear aliases",这个选项提高了内核的安全性,但是减小了内核的性能。

197a2640-4e4d-11eb-8b86-12bb97331649.png

我在内核启动参数加的rodata=0实际上是让rodata_full为false。如果我把这个kernel启动选项去掉,我得到的内核页表是完全不一样,线性映射区也全部是PTE映射:

199d2ee2-4e4d-11eb-8b86-12bb97331649.png

最后,值得一提的是,不仅线性映射区可以使用PMD映射,vmemmap映射区也是在4K页面情况下,默认用PMD映射的:

1a0676fe-4e4d-11eb-8b86-12bb97331649.png

字节跳动的宋牧春童鞋发了一个patchset,企图在用户分得巨页的情况下,删除巨页内部的4KB的小page占用的page struct的内存消耗,这个patchset在圣诞节前目前发到了V11:

https://lore.kernel.org/linux-mm/20201222142440.28930-1-songmuchun@bytedance.com/

1a6a8f18-4e4d-11eb-8b86-12bb97331649.png

在这个patchset中,它就需要拆分vmemmap的PMD映射为PTE映射:

1b367c4a-4e4d-11eb-8b86-12bb97331649.png

这个patchset的原理建立在,当内核以4KB分页的时候,每个page需要64字节的page struct。但是,当用户把它分配为巨页的时候,时候,我们不再需要一个个4KB单独用page struct描述,对于这种compound page的情况,我们应该可以把后面的page struct的内存直接释放掉,因为情况完全是雷同的,这样可以剩下不少内存。

责任编辑:xj

原文标题:宋宝华: ARM64 Linux内核页表的块映射

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM
    ARM
    +关注

    关注

    134

    文章

    8650

    浏览量

    361767
  • 内核
    +关注

    关注

    3

    文章

    1309

    浏览量

    39844
  • Linux
    +关注

    关注

    87

    文章

    10988

    浏览量

    206725
  • 板块
    +关注

    关注

    0

    文章

    3

    浏览量

    7545

原文标题:宋宝华: ARM64 Linux内核页表的块映射

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    向后移植了cypress-fmac-v5.15.58-2023_0801到arm64内核 5.10.104,insmod brcmfmac崩溃怎么解决?

    向后移植了 cypress-fmac-v5.15.58-2023_0801 到 arm64 内核 5.10.104。 在加载内核模块 brcmfmac.ko 时,按照自述文件中的说明进行操作, 我
    发表于 03-01 09:00

    TQT507开发板如何修改和保存内核配置

    ,如果不存在,则使用默认配置单。编译前请使用原厂的配置单配置内核。 进入/Embedsky/TQT507/CoreA/longan/kernel/linux-4.9/arch/arm64
    的头像 发表于 12-28 14:13 179次阅读
    TQT507开发板如何修改和保存<b class='flag-5'>内核</b>配置

    【飞腾派4G版免费试用】2.手把手实战编译Linux内核

    /phytium-linux-kernel-master-Uboot-V1.0.0$ ls ./arch/arm64/boot/Image 这行命令用于列出目录内容,显示了编译后的内核镜像的位置。 zero@pc:~/work
    发表于 12-16 23:28

    如何修改内核设备树

    longan/kernel/linux-4.9/arch/arm64/boot/dts/sunxi/sun50iw9p1-pinctrl.dtsi longan/kernel/linux-4.9/arch
    发表于 12-14 13:42

    基于Debian的Sparky Linux 7.2的亮点

    Linux kernel 6.1 LTS 提供支持,Sparky Linux 7.2采用 LXQt 1.2.0 和 KDE Plasma 5.27.5,现在提供 ARMHF 和 ARM64 镜像。
    的头像 发表于 12-14 10:13 250次阅读
    基于Debian的Sparky <b class='flag-5'>Linux</b> 7.2的亮点

    ARM64位与ARM32位OP-TEE启动过程的差异

    ARM32的OP-TEE与ARM64的OP-TEE启动过程大致相同。ARM64的OP-TEE的_start函数定义在generic_entry_a64.S文件中,而且该函数不像
    的头像 发表于 11-07 15:12 277次阅读

    Linux实时内核准备支持RISC-V

    目前,Linux RT补丁集允许为ARM64(AArch64)、ARM、PowerPC和x86/x86_64架构启用PREEMPT_RT。最
    的头像 发表于 10-31 16:29 334次阅读

    基于ARM Linux和S3C2440的嵌入式Linux内核设计

    电子发烧友网站提供《基于ARM Linux和S3C2440的嵌入式Linux内核设计.pdf》资料免费下载
    发表于 10-12 10:37 2次下载
    基于<b class='flag-5'>ARM</b> <b class='flag-5'>Linux</b>和S3C2440的嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>设计

    【飞凌AM6254开发板试用】+5内核编译串口芯片Linux驱动(原创)

    arch/arm64/include/generated .config .version Module.symvers /home/forlinx/6254/OK6254-linux
    发表于 09-23 23:21

    C语言函数指针在Arm Linux内核源码中的高级玩法

    函数指针在ARM Linux内核源码中有许多高级应用。在这里,我将列举一些常见的应用,附上相应的代码示例,并对代码进行解释。
    发表于 09-06 11:23 241次阅读
    C语言函数指针在<b class='flag-5'>Arm</b> <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>源码中的高级玩法

    海凌科新款arm64开发板wukongPi 4B简述

    海凌科新款arm64开发板——wukongPi 4B上架,兼容树莓派,采用RK3399 SoC。
    的头像 发表于 08-07 14:53 607次阅读
    海凌科新款<b class='flag-5'>arm64</b>开发板wukongPi 4B简述

    Arm64程序调用通用寄存器的使用方法

    下面是Arm64程序调用标准规定的通用寄存器的使用方法。 参数寄存器(X0-X7) 函数参数数量小于等于8个时,使用X0-X7传递,大于8个时,多余的使用栈传递,函数返回时返回值保存在X0
    的头像 发表于 07-28 11:28 1816次阅读
    <b class='flag-5'>Arm64</b>程序调用通用寄存器的使用方法

    Arm64栈回溯 结构介绍

    Arm64有4种栈,分别是空增栈(Empty Ascendant Stack,EA)、空减栈(Empty Descendant Stack,ED)、满增栈(Full Ascendant Stack
    的头像 发表于 07-28 11:25 449次阅读
    <b class='flag-5'>Arm64</b>栈回溯 结构介绍

    64内核 V1.0.7-RT 的 RZ/G Verified Linux Package 发行说明

    64内核 V1.0.7-RT 的 RZ/G Verified Linux Package 发行说明
    发表于 07-04 19:17 0次下载
    <b class='flag-5'>64</b> 位<b class='flag-5'>内核</b> V1.0.7-RT 的 RZ/G Verified <b class='flag-5'>Linux</b> Package 发行说明

    迅为iTOP-RK3588开发板Android12源码定制开发kernel开发

    内核版本是 5.10.66 版本,内核默认的配置文件是 3588-android12/kernel-5.10/arch/arm64/configs/rockchip_defconfig 如果我们要使
    发表于 06-09 15:54