Function EarlyReserveRegion reserves contiguous virtual address space
regions beginning at the end of the available kernel space and moving
towards lower virtual addresses. The only state that is tracked by this
function is the last allocated virtual page address which is adjusted
after each reservation request.
Starting at the end of the kernel address space ensures that we will not
step on the virtual addresses used by the kernel code and data sections.
This allows us to remove the allocFn argument from the vmm functions
which causes the compiler's escape analysis to sometimes incorectly flag
it as escaping to the heap.
The linked.ld script is extended to include the _kernel_start and
_kernel_end symbols which are passed by the rt0 code to Kmain. The
allocator converts these addresses to a start/end frame index by
rounding down the kernel start address to the nearest page and rounding
up the kernel end address to the nearest page.
When allocating frames, the allocator will treat the region defined by
these 2 indices as reserved and skip over it.
AllocFrame now rounds up the region start address to the nearest page
multiple and rounds down the region end address to the nearest page
multiple. It also ignores memory regions with size smaller than a page.
Instead of using frame indices and converting them to a pmm.Frame, the
allocator now just keeps track of the last allocated pmm.Frame.
As the allocator is now unexported, a package-exported Init() method is
now provided whose purpose is to initialize the physical allocator
sub-system.
The Map/Unmap methods of PageDirectoryTable operate similar to the
global Map/Unmap functions. While the global functions work with the
currently active PDT, the PageDirectoryTable methods can also
work with inactive page tables by temporarily modifying the recursive
mapping of the active PDT to point to the inactive PDT frame before
delegating the mapping/unmapping to the global Map/Unmap functions.
The API provides the Map() and MapTemporary() functions that establish
virtual -> physical address mappings using the currently active page
directory table.
Mapped pages can be unmapped using the Unmap() function. When unmapping
virtual addresses, the page tables leading to them will not be
automatically released even if they are empty. This will be addressed by
a future commit.
The page table walker provides a mechanism for accessing the individual
page table entries that correspond to a particular virtual memory
address. This implementation will serve as the basis for implementing
page mapping/unmapping and virtual to physical address translation.
This is equivalent to pmm.Frame (also a uintptr) but having different
types for physical and virtual frames serves as an additional layer of
protection for functions/methods that receive physical and/or virtual
page arguments.
To keep the implementation portable, the Frame type had to be changed
from uint64 to uintptr. Using uintptr ensures that the frame will always
match the pointer size of the platform.