转换内核地址时pgd_bad、pmd_bad、pud_bad是什么意思?

what is meaning of pgd_bad, pmd_bad, pud_bad, while converting kernel addressess?

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

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

在 ARMv8 64 位页面 table 描述符格式中,对于有效(即第 0 位设置)级别 0、1 或 2 条目,第 1 位区分 table 和块 (大页面)条目。因此,如果给定条目设置了位 1,则这些宏将为 return false,指示预期的 table 条目,或者如果明确指示块或无效条目,则为 true。 p*d_val() 访问器只是 optionally enforcing type-safety.

的包装器

最初定义在现在已经过时了(但是非常好)理解Linux虚拟内存管理器_bad()宏确定指定页面table条目是否是处于待修改状态table。

然而事实证明,这些宏在不同架构之间有些模糊,最好在 arm64 中将其描述为确定条目是否 包含对包含 table 用于下一级页面 table - 有关详细信息,请参阅 this commit

扩展@Notlikethat 的回答,宏确实引用了 'table' 位,反过来(至少在 linux 内核使用中,可能有更详细的特定于体系结构的细节在起作用) 确定条目的物理地址是否指向大页面(64KiB - 参见 arm64 memory layout doc)。

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

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

这表示如果设置了该位,页面大小为 4KiB,如果 清除,则页面大小为 64KiB,因此很大。

由此得出的结论是,在 arm64 中,如果使用大页面,pXX_bad() 宏 return 为真。

但是,如果启用了巨大的 tables,您给出的定义实际上不会被使用:)

再看上面引用的内存布局文档,原来大页table布局只用了2层。 linux 处理少于 4 页 table 级别的体系结构的方法是将 'fold in' 不存在的级别放入现有的 table 中,并让编译器删除所有不必要的代码。

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

#if CONFIG_PGTABLE_LEVELS > 3

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

#if CONFIG_PGTABLE_LEVELS > 2

所以实际上因为 CONFIG_PGTABLE_LEVELS == 2 在巨大的 table 案例中,使用了不同的定义。

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

所以实际上使用了 include/asm-generic/pgtable-nopmd.h 的定义,它本身导入 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 条目都将 return 为真。但是,如果您查看我上面提到的提交,您会发现在提交之前,_bad() return 为真将导致代码处理 'section map' 情况,其中大概PMD 包含不同的元数据(我不想在这里深入 :) 并使用单独的代码,现在通过 pmd_sect() 处理,我们不关心pmd_bad() 说什么,如果 条目是剖面图。

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

因此,总体而言,_bad() 案例现在似乎意味着一些不同的东西 - 它只是表明错误导致一些代码本应处理非部分 map/huge 页面 table词条正在处理一个巨大的版块地图页面table词条,明确需要注明。

注意: 因为我创建了一个帐户只是为了在这里回复,所以我没有足够的声誉来提供更多链接 :) 有更多代表的好心人可能想添加有意义的链接,例如'at line XX at the time of writing' 个条目。)