diff --git a/src/kernel/page_tree.cpp b/src/kernel/page_tree.cpp index 3e37359..5251a97 100644 --- a/src/kernel/page_tree.cpp +++ b/src/kernel/page_tree.cpp @@ -58,30 +58,8 @@ page_tree::contains(uint64_t offset, uint8_t &index) const return (offset & level_mask(m_level)) == m_base; } -bool -page_tree::find(const page_tree *root, uint64_t offset, uintptr_t &page) -{ - page_tree const *node = root; - while (node) { - uint8_t level = node->m_level; - uint8_t index = 0; - if (!node->contains(offset, index)) - return false; - - if (!level) { - uintptr_t entry = node->m_entries[index].entry; - page = entry & ~0xfffull; - return (entry & 1); // bit 0 marks 'present' - } - - node = node->m_entries[index].child; - } - - return false; -} - -bool -page_tree::find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page) +uintptr_t & +page_tree::get_entry(page_tree * &root, uint64_t offset) { page_tree *level0 = nullptr; @@ -125,7 +103,7 @@ page_tree::find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page) node = *parent; } - kassert( node || parent, "Both node and parent were null in find_or_add"); + kassert( node || parent, "Both node and parent were null in page_tree::get_entry"); if (!node) { // We found a parent with an empty spot where this node should @@ -135,9 +113,39 @@ page_tree::find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page) } } - kassert(level0, "Got through find_or_add without a level0"); + kassert(level0, "Got through page_tree::get_entry without a level0"); + uint8_t index = index_for(offset, 0); - uint64_t &ent = level0->m_entries[index].entry; + return level0->m_entries[index].entry; +} + +bool +page_tree::find(const page_tree *root, uint64_t offset, uintptr_t &page) +{ + page_tree const *node = root; + while (node) { + uint8_t level = node->m_level; + uint8_t index = 0; + if (!node->contains(offset, index)) + return false; + + if (!level) { + uintptr_t entry = node->m_entries[index].entry; + page = entry & ~0xfffull; + return (entry & 1); // bit 0 marks 'present' + } + + node = node->m_entries[index].child; + } + + return false; +} + +bool +page_tree::find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page) +{ + uint64_t &ent = get_entry(root, offset); + if (!(ent & 1)) { // No entry for this page exists, so make one if (!frame_allocator::get().allocate(1, &ent)) @@ -148,3 +156,12 @@ page_tree::find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page) page = ent & ~0xfffull; return true; } + +void +page_tree::add_existing(page_tree * &root, uint64_t offset, uintptr_t page) +{ + uint64_t &ent = get_entry(root, offset); + kassert(!(ent & 1), "Replacing existing mapping in page_tree::add_existing"); + + ent = page | 1; +} diff --git a/src/kernel/page_tree.h b/src/kernel/page_tree.h index bf31350..db9162c 100644 --- a/src/kernel/page_tree.h +++ b/src/kernel/page_tree.h @@ -23,6 +23,12 @@ public: /// \returns True if a page was found static bool find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page); + /// Add an existing mapping not allocated via find_or_add. + /// \arg root [inout] The root node of the tree. This pointer may be updated. + /// \arg offset Offset into the VMA, in bytes + /// \arg page The mapped page physical address + static void add_existing(page_tree * &root, uint64_t offset, uintptr_t page); + ~page_tree(); private: @@ -34,6 +40,9 @@ private: /// \returns True if the address is contained bool contains(uintptr_t offset, uint8_t &index) const; + /// Get a (writable) reference to a page in the tree + static uintptr_t & get_entry(page_tree * &root, uint64_t offset); + /// Stores the page offset of the start of this node's pages virtual addresses uint64_t m_base;