如何在linux内核中测试地址是虚拟的还是逻辑的?
Posted
技术标签:
【中文标题】如何在linux内核中测试地址是虚拟的还是逻辑的?【英文标题】:How to test if address is virtual or logical in linux kernel? 【发布时间】:2021-10-26 15:09:48 【问题描述】:我熟悉Linux内核内存通常是1:1映射的(达到一定的区域限制)。据我了解,为了使这种 1:1 映射更有效,struct page 数组是虚拟映射的。
我想看看是不是这样。有没有办法测试 - 给定地址(让我们说 struct page 的地址)检查它是 1:1 映射还是虚拟映射?
【问题讨论】:
很想知道是否有专门为此测试的功能。但我想一个迂回的方法是检查结构页面是如何分配的。根据分配方式,应该告诉您地址是逻辑地址还是虚拟地址。请参阅 here 和 cmets here @wxz 谢谢。在浏览完链接之后,我还有另一个稍微无关但至关重要的问题来理解核心概念。虚拟页面(通过页表)能否换出逻辑内核页面(1:1 映射的页面)。似乎有可能,因为同一页框可用于另一页。但是内核是否知道它需要在内核访问时将 1:1 映射的页面带回来?也许内核使所有这些 1:1 映射的页面不可交换? 您能否提供您在哪里看到关于“1:1 映射”的声明的来源?我想我可能误解了你最初的问题,但如果你告诉我你以前在哪里看到过这个陈述,我可能会有一个答案来提供帮助。 你得到答案了吗?您能否提供您看到 1:1 映射的来源? @wxz 仍然没有找到答案,但我认为枚举所有结构页面将显示页面是逻辑映射 (1:1) 还是虚拟映射。我没有来源,我只是在问内核在内存不足时是否可以换出逻辑映射的页面。 【参考方案1】:64 位机器的地址空间概念包括2^64
地址。这远远大于一台机器中任何现代物理内存量。因此,可以将整个物理内存映射到有足够空间的地址空间。正如this post 和here 中所讨论的那样,Linux 为物理映射留出了 64 TB 的地址空间。因此,如果内核需要遍历物理内存中的所有字节,它可以只遍历地址0+offset
到total_bytes_of_RAM + offset
,其中offset
是直接映射开始的地址(64 位内存中的ffff888000000000
上面链接的布局)。此外,此直接映射区域位于“所有进程之间共享”的内核地址范围内,因此该范围内的地址应始终是逻辑的。
您的帖子有两个问题:一个是如何测试地址是逻辑地址还是虚拟地址。正如我所提到的,答案是如果地址在直接映射范围内,那么它是合乎逻辑的。否则它是虚拟的。如果是虚拟地址,那么通过页表获取物理地址应该可以让你按照上面提到的physical_addr + offset
数学逻辑访问地址。
此外,kmalloc
直接使用此逻辑映射分配/保留内存,因此您立即知道如果您使用的地址来自 kmalloc,那么它就是一个逻辑地址。但是,vmalloc
和任何用户空间内存分配都使用虚拟地址,必须对其进行转换才能获得逻辑等价物。
您的第二个问题是“逻辑映射的页面”是否可以换出。应该重新表述这个问题,因为从技术上讲,RAM 中的所有页面都在逻辑上映射到该直接映射区域。是的,主内存中的某些页面可以被换出或踢出以供同一页框中的另一个页面使用。现在,如果您要问是否可以换出仅逻辑映射而不是虚拟映射的页面(例如kmalloc
,gets memory from slab),我认为答案是它们can be reclaimed 如果不被使用,但是aren't generally swapped out。内核页面一般不会换出,except for hibernation。
【讨论】:
你如何在内核中做到这一点?鉴于您可以运行内核模块。模块如何找到这些 highmem 和 lowmem 界限?作为澄清。我的意思是,一般来说,如果您正在创建一个内核模块,您将如何知道界限。当然,如果您希望仅在 64 位 x86 机器上运行,那么只需查找它,但如果您想在 ARM 32 位或 powerpc 或任何其他架构上运行,则在编译期间您的代码中不能有查找表(它会太乏味)。不同的linux内核版本也需要不同,所以根本不实用。 我刚刚发现 this document 包含像 PHYS_OFFSET 这样的内核符号,但我认为它是专门针对 ARM 架构的。不确定是否有一种统一的方法来解决所有拱门的问题。 其实我认为PAGE_OFFSET
通常被用作内核内存中RAM的直接映射部分的通用起始地址。有关 ARM,请参阅 this comment。在 x86-64 中,PAGE_OFFSET
转到 this definition,这与我的答案中链接的内存布局相匹配。
@anon 不确定我是否必须标记您以便您收到 cmets 的通知。你看到我最近的评论了吗?
是的,我看到了你的回答。我不认为它回答了我的问题。我不明白记忆漏洞如何适合这个解释。是的,您可以测试地址是否在范围内,但这并不意味着地址有效。此外,如果内核页面可以交换,您不知道它是在 RAM 中还是已交换,因此如果您仅测试地址在一个范围内,您将错过这两种地址无效的情况。以上是关于如何在linux内核中测试地址是虚拟的还是逻辑的?的主要内容,如果未能解决你的问题,请参考以下文章
linux内存管理---虚拟地址逻辑地址线性地址物理地址的区别