Skip to content

Memory Descriptor

struct mm_context (3 fields) source
TODO

hold 6 per-cpu, switch between them with generation counters. we can look towards linux once we go and implement this thing for ASID

§ size_t ctx_id
§ atomic_size_t tlb_gen
§ struct cpu_mask cpus
struct mm (7 fields) source
§ struct vas *vas
§ struct rbit vma_range_tree
§ struct rwlock lock

top of the lock order

§ paddr_t pml4

physical root of the page tables

§ vaddr_t mmap_cursor

next-fit hint: where the last gap search ended

§ refcount_t users

threads sharing this address space

§ refcount_t refcount

keep the struct alive past last user

enum mm_map_flags (2 variants) source
§ MM_MAP_FIXED = 1 << 0
§ MM_MAP_ANON = 1 << 1
enum mm_fault_flags (3 variants) source
TODO

MM_MAP_SHARED / file-backed…

§ MM_FAULT_WRITE = 1 << 0

error_code & 0x02

§ MM_FAULT_USER = 1 << 1

error_code & 0x04

§ MM_FAULT_INSN = 1 << 2

error_code & 0x10

enum mm_fault_result (4 variants) source
§ MM_FAULT_OK
§ MM_FAULT_RETRY
§ MM_FAULT_SIGSEGV
§ MM_FAULT_OOM
struct mm * mm_alloc(void)
source
void mm_free(struct mm *mm)
source
struct mm * mm_fork(struct mm *src)
source

clone VMAs + anon_vma_fork each

void mm_exit(struct mm *mm)
source

exit_mmap: unmap + tear down every VMA, but leave the struct/pml4 standing

void mm_vma_range_insert(struct mm *mm, struct vma_range *vma_range)
source
void mm_vma_range_remove(struct mm *mm, struct vma_range *vma_range)
source
struct vma_range * mm_vma_range_find(struct mm *mm, vaddr_t addr)
source
struct vma_range * mm_vma_range_find_intersection(
    struct mm *mm,
    vaddr_t s,
    vaddr_t e
)
source
vaddr_t mm_vma_range_find_gap(
    struct mm *mm,
    size_t len,
    size_t align,
    vaddr_t low,
    vaddr_t high
)
source

lowest gap >= len in [low, high)

vaddr_t mm_map(
    struct mm *mm,
    vaddr_t hint,
    size_t len,
    enum vma_range_protection prot,
    enum mm_map_flags flags
)
source

find a gap (or honor a hint), build a vma_range, insert

enum err mm_unmap(struct mm *mm, vaddr_t start, size_t len)
source

tear down [start, start+len): split VMAs at the boundaries, unmap their PTEs, drop rmap, free/trim the VMAs

enum err mm_protect(
    struct mm *mm,
    vaddr_t start,
    size_t len,
    enum vma_range_protection prot
)
source

change protection over a range: split at boundaries, vma_range_set_prot each, re-protect the live PTEs

enum err mm_pgtable_init(struct mm *mm)
source
void mm_pgtable_free(struct mm *mm)
source

free user PT pages; never the shared kernel higher-half

void mm_activate(struct mm *mm)
source

load CR3 = mm->pml4 on switch

enum err mm_map_page(
    struct mm *mm,
    vaddr_t va,
    paddr_t pa,
    uint64_t pflags
)
source
void mm_unmap_page(struct mm *mm, vaddr_t va)
source
paddr_t mm_query(struct mm *mm, vaddr_t va, uint64_t *pflags_out)
source
enum mm_fault_result mm_fault(
    struct mm *mm,
    vaddr_t addr,
    enum mm_fault_flags flags
)
source
enum mm_fault_result mm_do_anon_fault(
    struct vma_range *vma_range,
    vaddr_t addr,
    enum mm_fault_flags
)
source
enum mm_fault_result mm_do_cow_fault(
    struct vma_range *vma_range,
    vaddr_t addr,
    enum mm_fault_flags
)
source
bool mm_getref(struct mm *mm)
source
void mm_putref(struct mm *mm)
source
bool mm_users_getref(struct mm *mm)
source

a new thread joins the address space

void mm_users_putref(struct mm *mm)
source

last user -> mm_exit(mm); then mm_putref()