Files
jsix_import/src/kernel/page_tree.h
Justin C. Miller d60f8ed8d5 [kernel] Improve VMA lifecycle
The vm_area objects had a number of issues I have been running into when
working on srv.init:

- It was impossible to map a VMA, fill it, unmap it, and hand it to
  another process. Unmapping the VMA in this process would cause all the
  pages to be freed, since it was removed from its last mapping.
- If a VMA was marked with vm_flag::zero, it would be zeroed out _every
  time_ it was mapped into a vm_space.
- The vm_area_open class was leaking its page_tree nodes.

In order to fix these issues, the different VMA types all work slightly
differently now:

- Physical pages allocated for a VMA are now freed when the VMA is
  deleted, not when it is unmapped.
- A knock-on effect from the first point is that vm_area_guarded is now
  based on vm_area_open, instead of vm_area_untracked. An untracked area
  cannot free its pages, since it does not track them.
- The vm_area_open type now deletes its root page_tree node. And
  page_tree nodes will delete child nodes or free physical pages in
  their dtors.
- vm_flag::zero has been removed; pages will need to be zeroed out
  further at a higher level.
- vm_area also no longer deletes itself only on losing its last handle -
  it will only self-delete when all handles _and_ mappings are gone.
2021-09-12 21:55:02 -07:00

51 lines
1.8 KiB
C++

#pragma once
/// \file page_tree.h
/// Definition of mapped page tracking structure and related definitions
#include <stdint.h>
/// A radix tree node that tracks mapped pages
class page_tree
{
public:
/// Get the physical address of the page at the given offset.
/// \arg root The root node of the tree
/// \arg offset Offset into the VMA, in bytes
/// \arg page [out] Receives the page physical address, if found
/// \returns True if a page was found
static bool find(const page_tree *root, uint64_t offset, uintptr_t &page);
/// Get the physical address of the page at the given offset. If one does
/// not exist yet, allocate a page, insert it, and return that.
/// \arg root [inout] The root node of the tree. This pointer may be updated.
/// \arg offset Offset into the VMA, in bytes
/// \arg page [out] Receives the page physical address, if found
/// \returns True if a page was found
static bool find_or_add(page_tree * &root, uint64_t offset, uintptr_t &page);
~page_tree();
private:
page_tree(uint64_t base, uint8_t level);
/// Check if this node should contain the given virtual address
/// \arg offset The offset into the VMA, in bytes
/// \arg index [out] If found, what entry index should contain addr
/// \returns True if the address is contained
bool contains(uintptr_t offset, uint8_t &index) const;
/// Stores the page offset of the start of this node's pages virtual addresses
uint64_t m_base;
/// Level of this node: 0 maps actual physical pages. Other levels N point to
/// nodes of level N-1.
uint8_t m_level;
/// For a level 0 node, the entries area all physical page addresses.
/// Other nodes contain pointers to child tree nodes.
union {
uintptr_t entry;
page_tree *child;
} m_entries[64];
};