当前位置: 首页 > 科技观察

了解ARM64内核中对52位虚拟地址的支持

时间:2023-03-12 16:51:06 科技观察

随着64位硬件的引入,处理更大地址空间的需求越来越大。当64位硬件可用时,处理更大地址空间(大于232字节)的需求变得明显。现在一些公司已经提供了64TiB或更多内存的服务器,x86_64架构和arm64架构现在允许大于248字节的地址空间(可以使用默认的48位地址支持)。x86_64架构通过硬件和软件启用五级页表来支持这些用例。它允许在等于257字节的地址空间中寻址(有关详细信息,请参阅x86:在4.12内核中启用5级页表)。突破了以往虚拟地址空间128PiB、物理地址空间4PiB的上限。arm64架构通过引入两个新架构——ARMv8.2LVA(更大的虚拟寻址)和ARMv8.2LPA(更大的物理寻址)进行了扩展以实现相同的功能。这允许使用4PiB的虚拟地址空间和4PiB的物理地址空间(即每个252位)。在新的arm64CPU中对ARMv8.2架构扩展的支持下,这两个新的硬件扩展现在都得到了开源软件的支持。从Linux5.4内核开始,支持arm64架构中的52位(大)虚拟地址(VA)和物理地址(PA)。尽管内核文档描述了这些特性和新内核运行时对旧CPU(不支持硬件级别的52位虚拟地址扩展)和较新的CPU(在硬件级别支持52位虚拟地址扩展)的影响,对于普通用户来说,理解这些以及如何“选择使用”52位地址空间可能会很复杂。因此,我将在本文中介绍以下几个比较新的概念:添加对这些功能的支持后,内核的内存布局如何“翻转”到Arm64程序如何(例如:kexec-tools、makedumpfile、crash-utility)通过指定大于48位的mmap参数,使用户态应用程序“选择加入”以接受来自52位地址空间的VA?ARMv8.2架构的LVA和LPA扩展ARMv8.2架构提供了两个重要的扩展:大型虚拟寻址(LVA)和大型物理寻址(LPA)。当使用64KB翻译粒度时,ARMv8.2-LVA为每个翻译表基地址寄存器提供了更大的52位虚拟地址空间。在ARMv8.2中,LVA允许:使用64KB转换粒度时,中间物理地址(IPA)和物理地址空间扩展到52位。如果使用64KB的翻译粒度来实现对52位物理地址的支持,那么一个一级块将覆盖4TB的地址空间。请注意,这些功能仅在AArch64架构上受支持。目前以下Arm64Cortex-A处理器支持ARMv8.2扩展:Cortex-A55Cortex-A75Cortex-A76详情请参考Armv8架构参考手册。Arm64的内核内存布局附带ARMv8.2扩展,增加了对LVA地址的支持(仅在以64KB的页面大小运行时可用),并且描述符的数量在第一级翻译期间增加。用户地址的第63-48位设置为0,而内核地址将这些位设置为1。TTBRx的选择由虚拟地址的63位决定。swapper_pg_dir仅包含内核(全局)映射,而pgd仅包含用户(非全局)映射。swapper_pg_dir地址被写入TTBR1而从未写入TTBR0。ThememorylayoutofLinuxundertheAArch64architecturewithapagesizeof64KBandthreelevels(with52-bithardwaresupport)isasfollows:startendsizeusage-----------------------------------------------------------------------0000000000000000000fffffffffffff4PB用户fff0000000000000fff7ffffffffffff2PB内核逻辑内存映射fff8000000000000fffd9fffffffffff1440TB[间隙]fffda00000000000ffff9fffffffffff512TBKasan阴影区ffffa00000000000ffffa00007ffffff128MBbpfjit区域ffffa00008000000ffffa0000fffffff128MB模块ffffa00010000000fffff81ffffeffff~88TBvmalloc区fffff81fffff0000fffffc1ffe58ffff~3TB[保护区域]fffffc1ffe590000fffffc1ffe9fffff4544KBFixedMappingfffffc1ffea00000fffffc1ffebfffff2MB[ProtectionArea]fffffc1ffec00000fffffc1fffbfffff16MBPCII/OSpaceffffffffffffff2MB[protectedarea]4KB页面的转换查找表如下:+-------+--------+-------+---------+--------+--------+--------+--------+|6356|5548|4740|3932|3124|2316|158|70|+--------+--------+--------+------+------+------+------+--------+|||||||||||v|||||[11:0]页内偏移||||+->[20:12]L3索引|||+------------>[29:21]L2索引||+-------------------->[38:30]L1指数|+------------------------------>[47:39]L0指数+------------------------------------------------>[63]TTBR0/164的转换查找表KB页面如下:+--------+-------+--------+--------+--------+--------+----------+--------+|6356|5548|4740|3932|3124|2316|158|70|+--------+---------+--------+--------+--------+--------+------+------+|||||||||v||||[15:0]页内偏移|||+------------>[28:16]L3索引||+-------------------------->[41:29]L2索引|+------------------------------>[47:42]L1索引(48位)|[51:42]L1索引(52位)+------------------------------------------------>[63]TTBR0/1arm64Multi-levelTranslationkernelpair52-bitvirtualaddresssupport因为支持LVA的较新内核应该可以在两个较旧的CPU上正常工作(不支持LVA的硬件扩展)和较新的CPU(支持LVA扩展的硬件),设计方法是使用单个二进制文件来支持52位(如果硬件不支持此功能,则必须能够回退到48位)thebeginningofthestartup)也就是说,为了满足52位的虚拟地址和PAGE_OFFSET的固定大小,VMEMMAP必须设置得足够大。这种设计方式需要内核为新的虚拟地址空间支持以下变量:VA_BITS常量*maximum*虚拟地址空间大小vabits_actual变量*actual*虚拟地址空间大小因此,虽然VA_BITS设置了最大虚拟地址空间大小,但是实际支持的虚拟地址空间大小由vabits_actual决定(取决于启动时的开关)。翻转内核内存布局以维护单个内核二进制文件的设计方法要求内核的.text位于高地址,因此它们对于48/52位虚拟地址是不变的。因为内核地址检测器(KASAN)区域只占整个内核虚拟地址空间的一小部分,对于48位或52位虚拟地址空间,KASAN区域的末尾也一定在内核的上半部分虚拟地址空间。(从48位切换到52位,KASAN区域的末尾不变,取决于~0UL,而起始地址会“增长”到低地址)为了优化phys_to_virt()和virt_to_phys(),页面偏移量将保存在0xFFF0000000000000(对应于52位),这样就无需读取其他变量。physvirt和vmemmap偏移量在早期引导时计算以启用此逻辑。考虑以下物理和虚拟RAM地址空间的转换:/**内核线性地址从虚拟地址空间的底部开始*测试区域开始的最高位已经足够检查,避免了担心标签的麻烦*/#definevirt_to_phys(addr)({\if(!(((u64)addr)&BIT(vabits_actual-1)))\(((addr)&~PAGE_OFFSET)+PHYS_OFFSET)})#definephys_to_virt(addr)((unsignedlong)((addr)-PHYS_OFFSET)|PAGE_OFFSET)在上面的代码中:PAGE_OFFSET—TTBR1地址空间中线性映射虚拟地址的开始PHYS_OFFSET—物理地址和vabits_actual的开始—*实际*虚拟地址空间的影响用于调试内核的用户空间程序的大小有几个用户空间应用程序可用于调试正在运行/活动的内核或从原因分析vmcore转储:kexec-tools、makedumpfile和crash-utility。当使用它们调试Arm64内核时,它也会影响它们,因为Arm64内核内存映射被“翻转”了。这些应用程序还需要遍历转换表以确定虚拟地址对应的物理地址(类似于内核中的做法)。相应地,在内核内存映射中引入“翻转”后,由于上游破坏了用户态应用程序,因此不得不对其进行修改。我已经为三个受影响的用户态应用程序提出了修复建议;一些已被上游接受,但其他仍在等待中:建议上游修复makedumpfile提议修复上游kexec-tools接受上游修复崩溃实用程序修复除非用户空间应用程序进行这些更改,否则它们仍然无法调试正在运行的/活动内核或分析系统崩溃的vmcore转储。52位用户空间虚拟地址为了保持与依赖ARMv8.0虚拟地址空间的用户空间应用程序的兼容性,最高可达48位,内核默认将48位范围内的虚拟地址返回给用户空间。用户空间程序可以通过指定大于48位的mmap提示参数来“选择加入”以从52位空间接收虚拟地址。例如:.mmap_high_addr.c----maybe_high_address=mmap(~0UL,size,prot,flags,...);也可以通过启用以下内核配置选项构建一个从52位空间返回地址的调试内核:CONFIG_EXPERT=y&&CONFIG_ARM64_FORCE_52BIT=y请注意,此选项仅用于调试应用程序,不应在实际生产中使用.结论总结:内核版本从5.14开始,新的Armv8.2硬件扩展LVA和LPA在内核中得到了很好的支持。用于调试内核的kexec-tools和makedumpfile等用户空间应用程序目前不支持新扩展,仍在等待上游修复。过去依赖Arm64内核提供的48位虚拟地址的用户态应用程序将继续按原样工作,而较新的用户态应用程序通过指定比48位从52位虚拟地址接受的更大的mmap提示参数来“选择加入”。