2016-04-27 24 views

Antwort

1

Wie ursprünglich in der jetzt eher definiert (aber sehr zufrieden) die Linux Virtual Memory Manager zu verstehen _bad() Makros bestimmen, ob eine bestimmte Seitentabelleneintrag nicht in einem geeigneten Zustand für die Änderung ist.

Allerdings stellt sich heraus, die Makros über Architekturen etwas nebulös sind, und vielleicht besser in arm64 beschrieben werden, wie die Bestimmung, ob ein Eintrag tut nicht einen Verweis auf eine Seite enthält die Tabelle für die nächste Ebene Seitentabelle enthält - siehe this commit für einige Details.

Erweiternd auf @ Notlikethat's Antwort beziehen sich die Makros auf das 'table'-Bit, das wiederum (zumindest in Linux-Kernel-Verwendung detailliertere architekturspezifische Details bei der Wiedergabe) bestimmt, ob die physikalische Adresse des Eintrags ist bezieht sich auf eine riesige Seite (64KiB - siehe arm64 memory layout doc) oder nicht.

Wenn wir pte_huge() suchen, die feststellt, ob ein Seiteneintrag zu einer großen Seite bezieht oder nicht, wir sehen:

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

Dies zeigt, dass, wenn das Bit die Seitengröße 4KiB gesetzt ist, wenn es ist cleared es ist 64KiB und daher riesig.

Dies führt zu der Schlussfolgerung, dass in Arm64 die pXX_bad() Makros True zurückgegeben werden, wenn große Seiten verwendet werden.

Allerdings sind die Definitionen, die Sie geben, werden verwendet, eigentlich nicht, wenn große Tabellen aktiviert sind :)

wieder Blick auf das Speicherlayout doc oben Bezug genommen wurde, es stellt sich heraus, dass die große Seitentabellenlayout nur 2 Ebenen verwendet. Die Art und Weise, wie Linux mit Architekturen mit weniger als 4 Tabellenebenen umgeht, besteht darin, nicht existierende Ebenen in existierende Tabellen einzufügen und den gesamten überflüssigen Code vom Compiler entfernen zu lassen.

Und wenn wir bei arch/arm64/include/asm/pgtable.h über der pgd_bad() Definition sehen (auf der Linie 445 zum Zeitpunkt des Schreibens), sehen wir:

#if CONFIG_PGTABLE_LEVELS > 3 

Und über die pud_bad() Definition (auf der Linie 392 zum Zeitpunkt des Schreibens) sehen wir:

#if CONFIG_PGTABLE_LEVELS > 2 

in der Tat so, da CONFIG_PGTABLE_LEVELS == 2 in dem riesigen Tisch Fall werden verschiedene Definitionen verwendet.

In arch/arm64/include/asm/pgtable-types.h wir sehen (an der Linie 89 zum Zeitpunkt des Schreibens):

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

So in der Tat Definitionen von include/asm-generic/pgtable-nopmd.h verwendet werden, die sich include/asm-generic/pgtable-nopud.h importiert, was uns:

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

und hatten wir schon:

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

Welche m dass jeder riesige PMD-Eintrag, der pmd_bad() aufgerufen hat, wahr zurückgibt. Wenn Sie sich jedoch das Commit ansehen, das ich oben erwähnt habe, sehen Sie, dass vor dem Commit eine _bad(), die "true" zurückgibt, zu Code führt, der den Fall "Section Map" behandelt, wo vermutlich die PMD andere Metadaten enthält (tue ich nicht wollen zu tief hier zu tauchen :) und separater Code verwendet wird, behandelt das ist jetzt über pmd_sect() und wir kümmern uns nicht darum, was pmd_bad() sagt, wenn der Eintrag einen Abschnitt der Karte ist.

bei arch/arm64/mm/mmu.c Sehen, pmd_set_huge() (Linie 828 zum Zeitpunkt des Schreibens), wie es scheint, riesigen Tisch PMD als Abschnitt Karten gesetzt sind was bedeutet, dass wir nicht brauchen, um kümmern uns um pmd_bad() (I kann hier verwechselt werden, Ich habe nicht tief oder mit einem Debugger durchgegangen, aber es scheint so.)

So scheint es insgesamt der _bad() Fall bedeutet jetzt etwas anderes - es zeigt nur, dass ein Fehler in einigen Code, der gemeint ist, zu haben bedeutet Die Verarbeitung einer Nicht-Bereichs-Map/eines riesigen Seitentabellen-Eintrags behandelt einen riesigen Abschnitt-Map-Page-Tabelleneintrag, der eindeutig angegeben werden muss.

HINWEIS: Da ich ein Konto erstellt habe, nur um hier zu antworten, habe ich nicht genug Ruf, um mehr Links zu geben :) eine nette Person mit mehr Rep könnte Links hinzufügen, wo sie Sinn machen, z. die 'bei Zeile XX zum Zeitpunkt des Schreibens' Einträge.)

1

Im ARMv8 64-Bit-Seitentabelle Descriptor Format für eine gültige (das heißt Bit 0 gesetzt), Ebene 0, 1 oder 2 Eintrag, Bit 1 unterscheidet zwischen Tisch und Block (hugepage) Einträge. Daher geben diese Makros false zurück, wenn der angegebene Eintrag das Bit 1 gesetzt hat, das den erwarteten Tabelleneintrag angibt, oder wahr, wenn es eindeutig ist und einen Block oder einen ungültigen Eintrag angibt. Die p*d_val() Accessoren sind einfach Wrapper für optionally enforcing type-safety. veralten