100 lines
4.9 KiB
C
100 lines
4.9 KiB
C
#pragma once
|
|
// mm_virt.h - virtual memory manager (VMM)
|
|
// Manages the single shared PML4, kernel pool, and user heap.
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <mm_phys.h>
|
|
#include <ke_status.h>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Page flags (x86-64 PTE bits)
|
|
// ---------------------------------------------------------------------------
|
|
#define PAGE_PRESENT (1ULL << 0)
|
|
#define PAGE_WRITE (1ULL << 1)
|
|
#define PAGE_USER (1ULL << 2)
|
|
#define PAGE_NOCACHE (1ULL << 4)
|
|
#define PAGE_NX (1ULL << 63)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Virtual address space constants
|
|
// ---------------------------------------------------------------------------
|
|
#define USER_BASE 0x0000000000001000ULL
|
|
#define USER_LIMIT 0x00007FFFFFFFF000ULL
|
|
|
|
#define KERNEL_BASE 0xFFFF800000000000ULL
|
|
#define PHYS_MAP_BASE 0xFFFF880000000000ULL
|
|
#define POOL_BASE 0xFFFFC00000000000ULL
|
|
#define POOL_LIMIT 0xFFFFE00000000000ULL
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Initialisation
|
|
// ---------------------------------------------------------------------------
|
|
// Called by KernelMain after MmInitializePhysical.
|
|
// bootPml4Phys: the PML4 set up by the bootloader.
|
|
// poolSize: initial reservation for kernel pool (bytes, page-aligned).
|
|
void MmInitializeVirtual(PHYSICAL_ADDRESS bootPml4Phys, size_t poolSize);
|
|
|
|
// Install the shared PML4 into CR3. Called once at the end of KernelMain init.
|
|
void MmActivate(void);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Page mapping
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags);
|
|
__declspec(dllexport) KSTATUS MmUnmapPage(uintptr_t virt);
|
|
|
|
// Modify protection flags on an already-mapped virtual range.
|
|
// 'flags' is the complete new set of PAGE_* bits - it replaces the old flags
|
|
// entirely (except the physical address, which is preserved).
|
|
// Returns STATUS_NOT_FOUND if any page in the range is not mapped.
|
|
__declspec(dllexport) KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint64_t flags);
|
|
|
|
// Walk the page tables to translate a virtual address to physical.
|
|
// Returns 0 if the address is not mapped.
|
|
__declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt);
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// User/kernel copy boundary helpers
|
|
// ---------------------------------------------------------------------------
|
|
// MmQueryPage returns the physical address and effective PAGE_* bits for a
|
|
// mapped virtual address. The reported PAGE_USER/PAGE_WRITE bits account for
|
|
// every page-table level, not just the leaf entry.
|
|
__declspec(dllexport) KSTATUS MmQueryPage(uintptr_t virt, PHYSICAL_ADDRESS* physOut, uint64_t* flagsOut);
|
|
|
|
// Probe a user virtual range without copying it. These functions only accept
|
|
// lower-half user mappings with PAGE_USER set; MmProbeUserWrite additionally
|
|
// requires PAGE_WRITE.
|
|
__declspec(dllexport) KSTATUS MmProbeUserRead(const void* ptr, size_t size);
|
|
__declspec(dllexport) KSTATUS MmProbeUserWrite(void* ptr, size_t size);
|
|
|
|
// Copy through the syscall trust boundary. Kernel subsystems should receive
|
|
// kernel-owned buffers, not raw user pointers, unless explicitly documented.
|
|
__declspec(dllexport) KSTATUS CopyFromUser(void* kernelDst, const void* userSrc, size_t size);
|
|
__declspec(dllexport) KSTATUS CopyToUser(void* userDst, const void* kernelSrc, size_t size);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Kernel pool - ring 0 only, never PAGE_USER.
|
|
// Best-fit free-list allocator, thread-safe via spinlock.
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) void* MmAllocatePool(size_t size);
|
|
__declspec(dllexport) void MmFreePool(void* ptr);
|
|
__declspec(dllexport) void* MmReallocatePool(void* ptr, size_t newSize);
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// User heap - shared flat space, ring 3 accessible.
|
|
// Allocations are writable user pages with NX set by default; PE image
|
|
// sections opt back into execution through the loader.
|
|
// ---------------------------------------------------------------------------
|
|
__declspec(dllexport) void* MmAllocateUserMemory(size_t size);
|
|
__declspec(dllexport) void MmFreeUserMemory(void* ptr);
|
|
__declspec(dllexport) void* MmReallocateUserMemory(void* ptr, size_t newSize);
|
|
|
|
// Page-aligned user image mapping. PE section protection is page based, so
|
|
// executable images must not be allocated from the normal sub-page heap.
|
|
__declspec(dllexport) void* MmAllocateUserImage(size_t size);
|
|
__declspec(dllexport) void MmFreeUserImage(void* ptr, size_t size);
|
|
|
|
size_t MmGetKernelPoolUsage(void);
|
|
size_t MmGetUserHeapUsage(void);
|