|
miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
|
#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>
Macros | |
| #define | PROT_WRITE 2 |
Functions | |
| static uint64_t * | virt_to_pml4_virt (void) |
| static uint64_t * | get_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) |
| #define PROT_WRITE 2 |


|
inlinestatic |

| 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.

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.


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.


| 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().


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.


| 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.


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


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.


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


