ptos/amd64+hal: Add page mapping interface

Signed-off-by: Chloe M <chloe@mensia.org>
This commit is contained in:
2026-07-11 04:48:18 -04:00
parent 89841b3563
commit 3593c66e3d
2 changed files with 217 additions and 0 deletions
+193
View File
@@ -7,8 +7,169 @@
*/
#include <hal/mmu.h>
#include <machine/mmu.h>
#include <machine/tlb.h>
#include <mm/pm.h>
#include <mm/vm.h>
#include <ke/bugcheck.h>
#include <ptdef.h>
/*
* Valid paging structure levels
*/
typedef enum {
PAGEMAP_PML1,
PAGEMAP_PML2,
PAGEMAP_PML3,
PAGEMAP_PML4
} PAGEMAP_LEVEL;
/*
* Returns true if the given page size is valid
*
* @PageSize: Page size to check
*/
ALWAYS_INLINE static inline BOOLEAN
MmuPageSizeValid(MMU_PAGESIZE PageSize)
{
switch (PageSize) {
case PAGESIZE_4K:
return true;
}
return false;
}
/*
* Obtain the pagemap top-level index
*
* XXX: In future revisions we should read CR4 and determine
* if 57-bit linear addresses are enabled for 5-level
* paging.
*/
ALWAYS_INLINE static inline PAGEMAP_LEVEL
MmuTopLevel(VOID)
{
return PAGEMAP_PML4;
}
/*
* Obtain PTE flags from MI page protection
* flags
*
* @Prot: Protection flags to convert
*/
static USIZE
MmuProtToPte(MM_PROT Prot)
{
USIZE PteFlags = PTE_P | PTE_NX;
if (ISSET(Prot, PAGE_WRITE))
PteFlags |= PTE_RW;
if (ISSET(Prot, PAGE_EXEC))
PteFlags &= ~PTE_NX;
if (ISSET(Prot, PAGE_USER))
PteFlags |= PTE_US;
return PteFlags;
}
/*
* Extract a pagemap index from a virtual address for a given
* level.
*
* @VirtualBase: Virtual base address
* @Level: Pagemap level to get index of
*
* XXX: Caller should ensure the page alignment of @VirtualBase
*/
static inline USHORT
MmuPageMapIndex(UPTR VirtualBase, PAGEMAP_LEVEL Level)
{
switch (Level) {
case PAGEMAP_PML1:
return (VirtualBase >> 12) & 0x1FF;
case PAGEMAP_PML2:
return (VirtualBase >> 21) & 0x1FF;
case PAGEMAP_PML3:
return (VirtualBase >> 30) & 0x1FF;
case PAGEMAP_PML4:
return (VirtualBase >> 39) & 0x1FF;
}
/* This should not happen */
KeBugCheck(
BUGCHECK_IO_ERROR,
"bad pagemap level in MmuPageMapIndex()\n"
);
}
/*
* Extract a pagemap at a specific level
*
* @Vas: Virtual address space to translate from
* @VirtualBase: Virtual base address
* @Level: Level to extract
* @Alloc: If true, allocate new level
*
* Returns the pogemap level base on success, otherwise NULL
* on failure.
*
* XXX: Caller should ensure the page alignment of @VirtualBase
*/
static UPTR *
MmuPageMapExtract(MMU_VAS *Vas, UPTR VirtualBase, PAGEMAP_LEVEL Level, BOOLEAN Alloc)
{
UPTR *PageMap;
PAGEMAP_LEVEL CurrentLevel;
MM_PFN Pfn;
UPTR PhysicalBase;
USIZE Index;
if (Vas == NULL) {
return NULL;
}
/* Get the top-level */
CurrentLevel = MmuTopLevel();
PageMap = PMA_TO_VMA((Vas->Cr3 & PTE_ADDR_MASK));
/* Walk through each level */
while (CurrentLevel > Level) {
Index = MmuPageMapIndex(VirtualBase, CurrentLevel);
/* Is this entry already present? */
if (ISSET(PageMap[Index], PTE_P)) {
PageMap = PMA_TO_VMA((PageMap[Index] & PTE_ADDR_MASK));
--CurrentLevel;
continue;
}
if (!Alloc) {
return NULL;
}
/*
* Now we allocate a level for this entry
*
* XXX: We need to consider how we'll clean up when unmapping pages
* as the destruction of a virtual address space will end up
* leaking memory if this point is reached.
*/
Pfn = MmRequestFrame();
if (Pfn == PFN_ERROR) {
return NULL;
}
PhysicalBase = PFN_TO_ADDRESS(Pfn);
PageMap[Index] = PhysicalBase | (PTE_P | PTE_RW | PTE_US);
PageMap = PMA_TO_VMA(PhysicalBase);
--CurrentLevel;
}
return PageMap;
}
VOID
HalMmuReadVas(MMU_VAS *Result)
{
@@ -38,3 +199,35 @@ HalMmuWriteVas(const MMU_VAS *Vas)
: "memory"
);
}
PT_STATUS
HalMmuMapPage(
MMU_VAS *Vas, UPTR VirtualBase,
UPTR PhysicalBase, MM_PROT Prot,
MMU_PAGESIZE PageSize)
{
UPTR *PageTable;
USIZE PageTableIndex;
USIZE PteFlags;
if (Vas == NULL) {
return STATUS_INVALID_PARAM;
}
if (!MmuPageSizeValid(PageSize)) {
return STATUS_INVALID_PARAM;
}
PageTable = MmuPageMapExtract(Vas, VirtualBase, PAGEMAP_PML1, true);
if (PageTable == NULL) {
return STATUS_NO_MEMORY;
}
PageTableIndex = MmuPageMapIndex(VirtualBase, PAGEMAP_PML1);
PteFlags = MmuProtToPte(Prot);
/* Map the memory and flush the TLB entry */
PageTable[PageTableIndex] = PhysicalBase | PteFlags;
MdTlbFlushSingle(VirtualBase);
return STATUS_SUCCESS;
}