100 lines
2.5 KiB
C
100 lines
2.5 KiB
C
#include <zinnia/alloc.h>
|
|
#include <zinnia/assert.h>
|
|
#include <zinnia/errno.h>
|
|
#include <zinnia/mman.h>
|
|
#include <zinnia/pmap.h>
|
|
#include <zinnia/utils.h>
|
|
#include <zinnia/vma.h>
|
|
|
|
// 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;
|
|
}
|