2016-04-27 108 views

回答

1

按照最初定义的,而现在已经过时(但优秀)的深入理解Linux虚拟内存管理器_bad()宏确定指定的页表项是否在修改一个合适的状态不是

然而事实证明宏是不同的体系结构稍有含糊不清,并可能更好arm64作为确定条目是否确实包含对包含该表为下一级页面表页面的引用来描述 - 见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()宏返回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 

所以从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)) 

其中m意味着任何有pmd_bad()调用的大页面PMD条目将返回true。然而,如果你看看我上面提到的提交,你会看到在提交之前,_bad()返回true会导致代码处理'section map'情况,其中大概是PMD包含不同的元数据(我不想要潜水深在这里:),并使用单独的代码,现在通过pmd_sect()处理,我们不在乎pmd_bad()说什么,如果条目是一个部分地图。在arch/arm64/mm/mmu.c

来看,pmd_set_huge()(线828在写作的时候),它看起来像巨大的表的PMD被设置为部分地图意味着我们并不需要关心pmd_bad()(我可以在这里误会,我没有深入研究过,也没有经过调试器,但似乎是这样。)

所以看起来总体上_bad()案例现在意味着不同的东西 - 它只是表明一个错误导致了一些代码意味着正在处理一个非剖面图/巨大的页面表项正在处理一个巨大的剖面图页面表项,这显然需要指出。

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

1

在ARMv8 64位页表描述符的格式,一个有效的(即,第0位组)0级,1或2项,位表和块(hugepage)条目之间1个判别。因此,如果给定条目具有位1设置,则这些宏将返回false,指示预期的表条目,如果它清楚指示块或无效条目,则这些宏将返回false。 p*d_val()访问器只是optionally enforcing type-safety的包装器。

相关问题