2

有人可以解释一下内核页表中的宏吗?

#define pgd_bad(pgd)            (!(pgd_val(pgd) & 2))
#define pmd_bad(pmd)            (!(pmd_val(pmd) & 2))
#define pud_bad(pud)            (!(pud_val(pud) & 2))
4

2 回答 2

6

正如现在相当过时(但非常好)中最初定义的那样,了解 Linux 虚拟内存管理器_bad()宏确定指定的页表条目是否处于适合修改的状态。

然而事实证明,这些宏在架构之间有点模糊,最好在 arm64 中描述为确定一个条目是否包含对包含下一级页表的表的页面的引用——有关一些详细信息,请参阅此提交

扩展@Notlikethat的答案,宏确实引用了“表”位,而后者(至少在Linux内核使用中,可能有更详细的体系结构特定细节在起作用)确定条目的物理地址是否指的是一个巨大的页面(64KiB - 请参阅arm64 内存布局文档)或不。

如果我们查看pte_huge()哪个确定页面条目是否引用大页面,我们会看到:

#define pte_huge(pte)           (!(pte_val(pte) & PTE_TABLE_BIT))

这表明如果设置了该位,则页面大小为 4KiB,如果将其清除,则为 64KiB,因此是巨大的。

这导致结论,在 arm64 中,pXX_bad()如果使用大页面,宏将返回 true。

但是,如果启用了大表,则实际上不会使用您提供的定义:)

再次查看上面引用的内存布局文档,原来巨大的页表布局只使用了 2 个级别。linux 处理具有少于 4 个页表级别的体系结构的方式是将不存在的级别“折叠”到现有表中,并让编译器删除所有不必要的代码。

如果我们查看arch/arm64/include/asm/pgtable.h上面的pgd_bad()定义(在撰写本文时在第 445 行),我们会看到:

#if CONFIG_PGTABLE_LEVELS > 3

pud_bad()定义之上(在撰写本文时在第 392 行),我们看到:

#if CONFIG_PGTABLE_LEVELS > 2

所以实际上由于CONFIG_PGTABLE_LEVELS == 2在大表情况下,使用了不同的定义。

我们看到(在arch/arm64/include/asm/pgtable-types.h撰写本文时第 89 行):

#if CONFIG_PGTABLE_LEVELS == 2
#include <asm-generic/pgtable-nopmd.h>
#elif CONFIG_PGTABLE_LEVELS == 3
#include <asm-generic/pgtable-nopud.h>
#endif

所以实际上使用了 frominclude/asm-generic/pgtable-nopmd.h的定义,它本身就是 imports include/asm-generic/pgtable-nopud.h,给我们:

static inline int pgd_bad(pgd_t pgd)            { return 0; }
static inline int pud_bad(pud_t pud)            { return 0; }

我们已经有了:

#define pmd_bad(pmd)            (!(pmd_val(pmd) & 2))

这意味着任何pmd_bad()调用它的大页面 PMD 条目都将返回 true。但是,如果您查看我上面提到的提交,您会发现在提交之前,_bad()返回 true 将导致代码处理“部分映射”情况,其中可能 PMD 包含不同的元数据(我不希望在这里潜水太深:) 并且使用了单独的代码,现在它是通过处理的,如果条目是截面图pmd_sect(),我们不在乎说什么。pmd_bad()

arch/arm64/mm/mmu.cpmd_set_huge()(撰写本文时的第 828 行),似乎巨大的表 PMD 被设置为截面图,这意味着我们不需要关心pmd_bad()(我可能在这里弄错了,我没有深入研究或经历过使用调试器,但似乎是这样。)

因此,总体而言,这种_bad()情况现在似乎意味着一些不同的东西——它只是表明一个错误导致了一些代码,这些代码本应处理一个非节映射/巨大的页表条目正在处理一个巨大的节映射页表条目,这显然需要予以说明。

注意:由于我创建了一个帐户只是为了在这里回复,我没有足够的声誉来提供更多链接 :) 一个有更多代表的善良的人可能想要在他们有意义的地方添加链接,例如'at line XX at the写作时间的条目。)

于 2016-05-25T09:37:54.107 回答
1

在 ARMv8 64 位页表描述符格式中,对于有效(即位 0 集)级别 0、1 或 2 条目,位 1 区分表和块(大页)条目。因此,如果给定条目设置了第 1 位,则这些宏将返回 false,指示预期的表条目,或者如果明确指示块或无效条目,则返回 true。p*d_val()访问器只是可选地强制执行类型安全的包装器。

于 2016-04-27T20:23:32.050 回答