added page_iterate(): a recursive page tree walker

This commit is contained in:
Steffen Vogel 2013-12-03 16:34:34 +01:00
parent 4514080014
commit 8fe165c162
2 changed files with 82 additions and 2 deletions

View file

@ -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

View file

@ -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<PAGE_MAP_LEVELS; i++) {
entry[i] = virt_to_entry(start, i);
// this last addresses are exclusive!
// for end == 0 we take the whole address space (overflow => 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<level; i++)
entry[i] = (page_entry_t*) (next << (PAGE_MAP_SHIFT*(level-i)));
}
// post-order callback
if (post)
ret = post(entry[level], level);
if (BUILTIN_EXPECT(ret < 0, 0))
return ret;
// return if
// - we are not at the root table
// - and we've reached the end of the current table
entry[level]++;
if (((size_t) entry[level] & ~PAGE_MASK) == 0x000)
return 0;
}
return 0;
}
return iterate(PAGE_MAP_LEVELS-1);
}
/** @brief Copy a single page frame
*
* @param src virtual address of source page frame