#include #include #include #include #include #include #include // Try to create a new, empty virtual address space. errno_t vma_new(struct vma** out) { debug_assert(out != nullptr, "Missing out"); errno_t res; if (!out) return EINVAL; struct vma* vmspace = mem_alloc(sizeof(struct vma), 0); if (!vmspace) return ENOMEM; res = pmap_new_user(&vmspace->pmap, 0); if (res) goto err1; *out = vmspace; return 0; err1: mem_free(vmspace); err0: return res; } // Delete a virtual address space. void vma_free(struct vma* v) {} // Remove any mappings in the given address range. // May fail if there is no memory and a mapping needs to be split. errno_t vma_unmap(struct vma* v, uintptr_t vaddr, size_t size); // Change the protection of an existing mapping. // May fail if there is no memory and a mapping needs to be split. errno_t vma_protect(struct vma* v, uintptr_t vaddr, size_t size, enum prot_flags flags); // Try to handle a page fault. bool vma_page_fault(struct vma* v, const struct vma_fault_info* info) { // TODO return false; } errno_t vma_map( struct vma* vma, struct vmo* vmo, uintptr_t addr, size_t len, enum prot_flags flags, uintptr_t vmo_offset ) { const size_t page_size = arch_mem_page_size(); if (addr % page_size != vmo_offset % page_size) return EINVAL; size_t start_page = addr / page_size; const size_t addr_offset = addr % page_size; const size_t pages = ALIGN_UP(addr_offset + len, page_size) / page_size; size_t end_page = start_page + pages; if (!vma || !vmo) return EINVAL; const size_t first_vmo_page = vmo_offset / page_size; for (size_t p = start_page; p < end_page; ++p) { const size_t page_index = p - start_page; struct page* page_obj; errno_t status = vmo->get_page(vmo, first_vmo_page + page_index, &page_obj); if (status != 0) return status; phys_t paddr = (phys_t)vm_page_addr(page_obj); enum pte_flags pf = 0; if (flags & PROT_READ) pf |= PTE_READ; if (flags & PROT_WRITE) pf |= PTE_WRITE; if (flags & PROT_EXEC) pf |= PTE_EXEC; if (vma->pmap.is_user) pf |= PTE_USER; status = pmap_map(&vma->pmap, p * page_size, paddr, pf, CACHE_ANY); if (status != 0) return status; } return 0; }