miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
vmm.c File Reference
#include <miniOS/mm/vmm.h>
#include <miniOS/mm/pmm.h>
#include <miniOS/ipi/ipi.h>
#include <miniOS/sched/sched.h>
#include <miniOS/fs/vfs.h>
#include <miniOS/types.h>
#include <string.h>
Include dependency graph for vmm.c:

Macros

#define PROT_WRITE   2

Functions

static uint64_tvirt_to_pml4_virt (void)
static uint64_tget_or_create_entry (uint64_t *table_virt, int index, uint64_t flags)
int vmm_map_page_in (uint64_t pml4_phys, uint64_t virt, uint64_t phys, uint64_t flags)
int vmm_map_page (uint64_t virt, uint64_t phys, uint64_t flags)
void vmm_unmap_page_in (uint64_t pml4_phys, uint64_t virt)
void vmm_unmap_page (uint64_t virt)
uint64_t vmm_virt_to_phys_in (uint64_t pml4_phys, uint64_t virt)
uint64_t vmm_virt_to_phys (uint64_t virt)
uint64_t vmm_virt_to_pte_in (uint64_t pml4_phys, uint64_t virt)
uint64_t vmm_virt_to_pte (uint64_t virt)
uint64_t vmm_new_address_space (void)
void vmm_free_address_space (uint64_t pml4_phys)
int vmm_resolve_user_fault (uint64_t cr2, uint64_t error_code)

Macro Definition Documentation

◆ PROT_WRITE

#define PROT_WRITE   2

Function Documentation

◆ get_or_create_entry()

uint64_t * get_or_create_entry ( uint64_t * table_virt,
int index,
uint64_t flags )
static
Here is the call graph for this function:
Here is the caller graph for this function:

◆ virt_to_pml4_virt()

uint64_t * virt_to_pml4_virt ( void )
inlinestatic
Here is the caller graph for this function:

◆ vmm_free_address_space()

void vmm_free_address_space ( uint64_t pml4_phys)

vmm_free_address_space() - Tear down a process's private page tables. @pml4_phys: PML4 physical address returned by vmm_new_address_space().

Walks only the user low half (PML4 indices 0..255 — the per-process range; indices 256..511 are the shared kernel half and are never touched or freed here). For every present leaf PTE, calls pmm_unref_frame() — private pages (refcount 1) are freed; CoW-shared pages still held by another process are just decremented. Also frees the intermediate PDPT/PD/PT frames (always private to this address space; never shared across processes), then the PML4 frame itself.

Here is the call graph for this function:

◆ vmm_map_page()

int vmm_map_page ( uint64_t virt,
uint64_t phys,
uint64_t flags )

vmm_map_page() - Install a PTE mapping virt -> phys in the live address space. @virt: Virtual address (>= KERNEL_VMA for kernel; user VA for ring-3 pages). @phys: Physical frame address (4 KiB-aligned). @flags: PTE attribute bits (PAGE_PRESENT, PAGE_WRITE, PAGE_USER).

Thin wrapper over vmm_map_page_in() using the live CR3.

Returns
: 0 on success, -1 on OOM (pmm_alloc_frame returned 0).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_map_page_in()

int vmm_map_page_in ( uint64_t pml4_phys,
uint64_t virt,
uint64_t phys,
uint64_t flags )

vmm_map_page_in() - Install a PTE mapping virt -> phys in an explicit PML4. @pml4_phys: Physical address of the target PML4 (not necessarily live in CR3).

Same walk as vmm_map_page(), but against @pml4_phys via the KERNEL_VMA direct-map alias rather than the live CR3 — lets a process's page tables be built (fork) or inspected (ptrace PEEK/POKE, once implemented) without ever loading that process's CR3. Still issues invlpg/shootdown for @virt; those are only meaningful if @pml4_phys happens to be live somewhere, but are cheap no-ops otherwise.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_new_address_space()

uint64_t vmm_new_address_space ( void )

vmm_new_address_space() - Allocate a fresh per-process PML4.

Copies PML4 entries 256..511 (the entire canonical higher half) by value from the currently-live PML4 into the new one, so every kernel mapping (kernel image, heap, DMA bounce buffer, GOP framebuffer, LAPIC/IOAPIC MMIO) is identically visible regardless of which process's PML4 is loaded in CR3 — all process PML4s share the same underlying PDPT/PD/PT chain for these entries, so kernel-side growth (e.g. heap.c mapping a new page) automatically stays visible to every process without re-syncing.

Invariant this relies on: every kernel top-level region (indices 256, 260, 262, 264 — KERNEL_VMA/VGA, HEAP_START, DMA_BUFFER_VA, GOP_FB_VA) must already have its first page mapped by the time the first process is created, so its PML4 entry exists to copy. True today — all of them are touched during early boot, before the first sched_create_user_task() call.

Entries 0..255 (user low half) are left zero — the caller builds those fresh via vmm_map_page_in().

Returns
: Physical address of the new PML4, or 0 on OOM.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_resolve_user_fault()

int vmm_resolve_user_fault ( uint64_t cr2,
uint64_t error_code )

vmm_resolve_user_fault() - Demand-page handler for user #PF. @cr2: Faulting virtual address (from CR2 register). @error_code: x86 page-fault error code pushed by CPU.

Called from the #PF exception handler when bit 2 (U/S) of error_code is set (user-mode fault). Checks whether the fault is a not-present fault (bit 0 = 0) in a lazy mmap region. If so, allocates a physical frame, zeros it, and installs the PTE with permissions derived from region.prot. Handles SMP double-fault races by checking vmm_virt_to_phys() first.

Returns
: 0 if the fault was resolved (iretq can resume execution), -1 if the fault is unresolvable (caller should deliver SIGSEGV).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_unmap_page()

void vmm_unmap_page ( uint64_t virt)

vmm_unmap_page() - Clear a leaf PTE and flush TLB. @virt: Virtual address of the page to unmap.

Walks all four page table levels. Writes 0 to the leaf PT entry (clears present bit). Issues invlpg on @virt. Does not free intermediate levels or the physical frame.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_unmap_page_in()

void vmm_unmap_page_in ( uint64_t pml4_phys,
uint64_t virt )

vmm_unmap_page_in() - Clear a leaf PTE in an explicit PML4 and flush TLB.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_virt_to_phys()

uint64_t vmm_virt_to_phys ( uint64_t virt)

vmm_virt_to_phys() - Walk page tables to resolve a virtual address. @virt: Virtual address to translate.

Thin wrapper over vmm_virt_to_phys_in() using the live CR3.

Returns
: Physical frame address (4 KiB-aligned), or 0 if not mapped.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_virt_to_phys_in()

uint64_t vmm_virt_to_phys_in ( uint64_t pml4_phys,
uint64_t virt )

vmm_virt_to_phys_in() - Walk an explicit PML4 to resolve a virtual address.

Here is the caller graph for this function:

◆ vmm_virt_to_pte()

uint64_t vmm_virt_to_pte ( uint64_t virt)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ vmm_virt_to_pte_in()

uint64_t vmm_virt_to_pte_in ( uint64_t pml4_phys,
uint64_t virt )
Here is the caller graph for this function: