diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 3018675f..be968356 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -40,15 +40,19 @@ #define PAGE_MAP_LEVELS 2 /// Page map bits #define PAGE_MAP_SHIFT 10 + /// Total operand width in bits + #define BITS 32 /// Linear/virtual address width - #define VIRT_BITS 32 + #define VIRT_BITS BITS /// Physical address width (we dont support PAE) - #define PHYS_BITS 32 + #define PHYS_BITS BITS #elif defined(CONFIG_X86_64) /// Number of page map indirections #define PAGE_MAP_LEVELS 4 /// Page map bits #define PAGE_MAP_SHIFT 9 + /// Total operand width in bits + #define BITS 64 /// Linear/virtual address width #define VIRT_BITS 48 /// Physical address width (maximum value) @@ -133,6 +137,15 @@ typedef struct page_map { page_entry_t entries[PAGE_MAP_ENTRIES]; } __attribute__ ((aligned (PAGE_SIZE))) page_map_t; +/** @brief A callback type for the page map iterator + * + * @param entry A pointer to the current page map entry + * @return + * - 0 if we want to skip underlying page tables + * - >0 if want to recurse into underlying page tables + */ +typedef int (*page_cb_t)(page_entry_t* entry, int level); + /** @brief Converts a virtual address to a physical * * @param viraddr Virtual address to convert diff --git a/arch/x86/mm/page64.c b/arch/x86/mm/page64.c index 946506c0..ae6b4c8e 100644 --- a/arch/x86/mm/page64.c +++ b/arch/x86/mm/page64.c @@ -91,6 +91,73 @@ static int entry_to_level(page_entry_t* entry) { return level; } + +/** @brief Recursive traversal through the page map tree + * + * @param start The first address whose page map entry we will call on + * @param end The exclusive end address whose page map entry we will call on + * @param pre Callback which is called for every page map entry (pre-order traversal) + * @param post Callback which is called for every page map entry (post-order traversal) + */ +int page_iterate(size_t start, size_t end, page_cb_t pre, page_cb_t post) +{ + page_entry_t* entry[PAGE_MAP_LEVELS]; + page_entry_t* last[PAGE_MAP_LEVELS]; + + // setup subtree boundaries + int i; + for (i=0; i 0) + last[i] = (end) ? virt_to_entry(end - PAGE_SIZE, i) + 1 : 0; + } + + // nested iterator function (sees the scope of parent) + int iterate(int level) { + int ret; + while (entry[level] != last[level]) { + //if (*entry[level] && level) kprintf("page_iterate: level=%u, entry[level]=%p, last[level]=%p\n", level, entry[level], last[level]); + + // pre-order callback + if (pre) + ret = pre(entry[level], level); + + if (BUILTIN_EXPECT(ret < 0, 0)) + return ret; + + // recurse if + // - we are not in the PGT + // - and the inferior page table is present + // - and the current entry is no huge page + if (level && (*entry[level] & PG_PRESENT) && !(*entry[level] & PG_PSE)) + iterate(level-1); + // or skip the entries we've omit... + else { + size_t next = (size_t) (entry[level]+1); + for (i=0; i