miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
vmm.h File Reference
#include <miniOS/types.h>
Include dependency graph for vmm.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define PAGE_PRESENT   (1ULL << 0)
#define PAGE_WRITE   (1ULL << 1)
#define PAGE_USER   (1ULL << 2)
#define PAGE_COW   (1ULL << 9) /* software: copy-on-write pending */
#define KERNEL_VMA   0xFFFF800000000000ULL
#define HEAP_START   0xFFFF820000000000ULL
#define HEAP_MAX   (HEAP_START + 4ULL * 1024 * 1024)
#define DMA_BUFFER_VA   0xFFFF830000000000ULL
#define GOP_FB_VA   0xFFFF840000000000ULL
#define VGA_BUFFER_VA   (KERNEL_VMA + 0xB8000ULL)
#define PAGE_SIZE   4096ULL
#define PML4_SHIFT   39 /* bits [47:39] index PML4 */
#define PDPT_SHIFT   30 /* bits [38:30] index PDPT */
#define PD_SHIFT   21 /* bits [29:21] index PD */
#define PT_SHIFT   12 /* bits [20:12] index PT */
#define PT_INDEX_MASK   0x1FFULL /* 9-bit mask for any level index */
#define PTE_ADDR_MASK   0x000FFFFFFFFFF000ULL

Functions

int vmm_map_page (uint64_t virt, uint64_t phys, uint64_t flags)
void vmm_unmap_page (uint64_t virt)
uint64_t vmm_virt_to_phys (uint64_t virt)
uint64_t vmm_virt_to_pte (uint64_t virt)
int vmm_resolve_user_fault (uint64_t cr2, uint64_t error_code)
uint64_t vmm_new_address_space (void)
void vmm_free_address_space (uint64_t pml4_phys)
int vmm_map_page_in (uint64_t pml4_phys, uint64_t virt, uint64_t phys, uint64_t flags)
void vmm_unmap_page_in (uint64_t pml4_phys, uint64_t virt)
uint64_t vmm_virt_to_phys_in (uint64_t pml4_phys, uint64_t virt)
uint64_t vmm_virt_to_pte_in (uint64_t pml4_phys, uint64_t virt)

Macro Definition Documentation

◆ DMA_BUFFER_VA

#define DMA_BUFFER_VA   0xFFFF830000000000ULL

◆ GOP_FB_VA

#define GOP_FB_VA   0xFFFF840000000000ULL

◆ HEAP_MAX

#define HEAP_MAX   (HEAP_START + 4ULL * 1024 * 1024)

◆ HEAP_START

#define HEAP_START   0xFFFF820000000000ULL

◆ KERNEL_VMA

#define KERNEL_VMA   0xFFFF800000000000ULL

◆ PAGE_COW

#define PAGE_COW   (1ULL << 9) /* software: copy-on-write pending */

◆ PAGE_PRESENT

#define PAGE_PRESENT   (1ULL << 0)

◆ PAGE_SIZE

#define PAGE_SIZE   4096ULL

◆ PAGE_USER

#define PAGE_USER   (1ULL << 2)

◆ PAGE_WRITE

#define PAGE_WRITE   (1ULL << 1)

◆ PD_SHIFT

#define PD_SHIFT   21 /* bits [29:21] index PD */

◆ PDPT_SHIFT

#define PDPT_SHIFT   30 /* bits [38:30] index PDPT */

◆ PML4_SHIFT

#define PML4_SHIFT   39 /* bits [47:39] index PML4 */

◆ PT_INDEX_MASK

#define PT_INDEX_MASK   0x1FFULL /* 9-bit mask for any level index */

◆ PT_SHIFT

#define PT_SHIFT   12 /* bits [20:12] index PT */

◆ PTE_ADDR_MASK

#define PTE_ADDR_MASK   0x000FFFFFFFFFF000ULL

◆ VGA_BUFFER_VA

#define VGA_BUFFER_VA   (KERNEL_VMA + 0xB8000ULL)

Function Documentation

◆ vmm_free_address_space()

void vmm_free_address_space ( uint64_t pml4_phys)

vmm_free_address_space() - Free a process's private page tables. @pml4_phys: PML4 physical address from vmm_new_address_space().

Walks only the user low half, pmm_unref_frame()'ing every mapped leaf page (frees private pages, decrements still-shared CoW pages) and freeing every intermediate PDPT/PD/PT frame plus the PML4 itself. Never touches the shared kernel high half.

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() - Map a 4 KiB virtual page to a physical frame. @virt: Virtual address to map. Must be >= KERNEL_VMA (0xFFFF800000000000) for kernel mappings, or a valid user VA for user mappings. @phys: Physical frame address (must be 4 KiB-aligned). @flags: PTE flags: PAGE_PRESENT (bit 0), PAGE_WRITE (bit 1), PAGE_USER (bit 2). Combine as needed.

Walks the 4-level page table (PML4 -> PDPT -> PD -> PT), allocating missing intermediate levels via pmm_alloc_frame. All intermediate-level entries are created with PAGE_PRESENT|PAGE_WRITE|PAGE_USER to allow both kernel and user mappings to be installed. Flushes TLB via invlpg.

Context: ISR-safe — pmm_alloc_frame uses spinlock_irqsave.

Returns
: 0 on success, -1 if pmm_alloc_frame returned 0 (OOM) while allocating an intermediate page table level.

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.

Higher half (kernel/heap/DMA/GOP/MMIO, PML4[256..511]) is copied by value from the live PML4 so kernel mappings are identical in every process. Low half (PML4[0..255], user code/stack/mmap) starts zeroed.

Returns
: Physical address of the new PML4, or 0 on OOM.

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() - Remove a page mapping. @virt: Virtual address of the page to unmap (4 KiB-aligned).

Clears the leaf PTE to 0 (not-present) and flushes the TLB via invlpg. Does NOT free the physical frame — that is the caller's responsibility. Does NOT reclaim depopulated intermediate page table levels.

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() - Translate a virtual address to its physical frame address. @virt: Virtual address to translate.

Walks the 4-level page table via cr3 + KERNEL_VMA. Stops and returns 0 if any level's entry is not-present (bit 0 = 0).

Returns
: Physical address (4 KiB-aligned) of the frame backing @virt, or 0 if the mapping does not exist at any page table level.

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: