Files
zinnia/mem/vas.c
T
2026-09-16 04:37:37 +02:00

99 lines
2.5 KiB
C

#include <zinnia/alloc.h>
#include <zinnia/errno.h>
#include <zinnia/mman.h>
#include <zinnia/utils.h>
#include <zinnia/vas.h>
#include <assert.h>
// Try to create a new, empty virtual address space.
errno_t vma_new(struct vas** out) {
debug_assert(out != nullptr, "Missing out");
errno_t res;
if (!out)
return EINVAL;
struct vas* vmspace = mem_alloc(sizeof(struct vas), 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_delete(struct vas* vm) {}
// 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 vas* vm, 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 vas* vm, uintptr_t vaddr, size_t size, enum zn_vm_flags flags);
// Try to handle a page fault.
bool vma_page_fault(struct vas* vm, uintptr_t vaddr, enum zn_vm_flags access_type) {
// TODO
return false;
}
errno_t vma_map_vmo(
struct vas* vas,
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 (!vas || !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 (vas->pmap.is_user)
pf |= PTE_USER;
status = pmap_map(&vas->pmap, p * page_size, paddr, pf, CACHE_ANY);
if (status != 0)
return status;
}
return 0;
}