mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 20:58:22 +00:00
vmm: file mapping
This commit is contained in:
@@ -19,6 +19,11 @@
|
||||
#define VMM_ACTION_WRITE 2
|
||||
#define VMM_ACTION_EXEC 4
|
||||
|
||||
typedef struct {
|
||||
vnode_t *node;
|
||||
uintmax_t offset;
|
||||
} vmmfiledesc_t;
|
||||
|
||||
struct vmmcache_t;
|
||||
typedef struct vmmrange_t{
|
||||
struct vmmrange_t *next;
|
||||
@@ -27,7 +32,12 @@ typedef struct vmmrange_t{
|
||||
size_t size;
|
||||
int flags;
|
||||
mmuflags_t mmuflags;
|
||||
void *private;
|
||||
union {
|
||||
struct {
|
||||
vnode_t *vnode;
|
||||
size_t offset;
|
||||
};
|
||||
};
|
||||
} vmmrange_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -70,6 +80,18 @@ static inline mmuflags_t vnodeflagstommuflags(int flags) {
|
||||
return mmuflags;
|
||||
}
|
||||
|
||||
static inline int mmuflagstovnodeflags(mmuflags_t mmuflags) {
|
||||
int flags = 0;
|
||||
if (mmuflags & ARCH_MMU_FLAGS_READ)
|
||||
flags |= V_FFLAGS_READ;
|
||||
if (mmuflags & ARCH_MMU_FLAGS_WRITE)
|
||||
flags |= V_FFLAGS_READ;
|
||||
if ((mmuflags & ARCH_MMU_FLAGS_NOEXEC) == 0)
|
||||
flags |= V_FFLAGS_EXEC;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void *vmm_map(void *addr, size_t size, int flags, mmuflags_t mmuflags, void *private);
|
||||
void vmm_unmap(void *addr, size_t size, int flags);
|
||||
bool vmm_pagefault(void *addr, bool user, int actions);
|
||||
|
||||
+49
-13
@@ -179,14 +179,14 @@ static void insertrange(vmmspace_t *space, vmmrange_t *newrange) {
|
||||
|
||||
fragcheck:
|
||||
// TODO range type specific stuff
|
||||
if (newrange->next && newrange->next->start == newrangetop && newrange->flags == newrange->next->flags) {
|
||||
if (newrange->next && newrange->next->start == newrangetop && newrange->flags == newrange->next->flags && newrange->mmuflags == newrange->next->mmuflags) {
|
||||
vmmrange_t *oldrange = newrange->next;
|
||||
newrange->size += oldrange->size;
|
||||
newrange->next = oldrange->next;
|
||||
freerange(oldrange);
|
||||
}
|
||||
|
||||
if (newrange->prev && RANGE_TOP(newrange->prev) == newrange->start && newrange->flags == newrange->prev->flags) {
|
||||
if (newrange->prev && RANGE_TOP(newrange->prev) == newrange->start && newrange->flags == newrange->prev->flags && newrange->mmuflags == newrange->prev->mmuflags) {
|
||||
vmmrange_t *oldrange = newrange->prev;
|
||||
oldrange->size += newrange->size;
|
||||
oldrange->next = newrange->next;
|
||||
@@ -196,15 +196,26 @@ static void insertrange(vmmspace_t *space, vmmrange_t *newrange) {
|
||||
|
||||
static void destroyrange(vmmrange_t *range, uintmax_t _offset, size_t size) {
|
||||
uintmax_t top = _offset + size;
|
||||
__assert(!((range->flags & VMM_FLAGS_FILE) || (range->flags & VMM_FLAGS_COPY))); // unimplemented
|
||||
__assert(!(range->flags & VMM_FLAGS_COPY)); // TODO unimplemented
|
||||
|
||||
for (uintmax_t offset = _offset; offset < top; offset += PAGE_SIZE) {
|
||||
void *vaddr = (void *)((uintptr_t)range->start + offset);
|
||||
void *physical = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, vaddr);
|
||||
if (physical) {
|
||||
if (physical == NULL)
|
||||
continue;
|
||||
|
||||
if (range->flags & VMM_FLAGS_FILE) {
|
||||
VOP_LOCK(range->vnode);
|
||||
__assert(VOP_MUNMAP(range->vnode, vaddr, range->offset + offset, mmuflagstovnodeflags(range->mmuflags), NULL) == 0); // XXX pass cred struct
|
||||
VOP_UNLOCK(range->vnode);
|
||||
} else {
|
||||
pmm_free(physical, 1);
|
||||
arch_mmu_unmap(_cpu()->vmmctx->pagetable, vaddr);
|
||||
}
|
||||
}
|
||||
|
||||
if ((range->flags & VMM_FLAGS_FILE) && range->size == size)
|
||||
VOP_RELEASE(range->vnode);
|
||||
}
|
||||
|
||||
static void unmap(vmmspace_t *space, void *address, size_t size) {
|
||||
@@ -228,7 +239,7 @@ static void unmap(vmmspace_t *space, void *address, size_t size) {
|
||||
} else if (address > range->start && top < rangetop) { // split
|
||||
vmmrange_t *new = allocrange();
|
||||
__assert(new); // XXX deal with this better
|
||||
*new = *range; // XXX refcounts will break
|
||||
*new = *range;
|
||||
|
||||
destroyrange(range, (uintptr_t)address - (uintptr_t)range->start, size);
|
||||
|
||||
@@ -238,11 +249,20 @@ static void unmap(vmmspace_t *space, void *address, size_t size) {
|
||||
|
||||
new->prev = range;
|
||||
range->next = new;
|
||||
|
||||
if (range->flags & VMM_FLAGS_FILE) {
|
||||
VOP_HOLD(range->vnode);
|
||||
new->offset += range->size + size;
|
||||
|
||||
}
|
||||
} else if (top > range->start && range->start >= address) { // partially unmap from start
|
||||
size_t difference = (uintptr_t)top - (uintptr_t)range->start;
|
||||
destroyrange(range, 0, difference);
|
||||
range->start = (void *)((uintptr_t)range->start + difference);
|
||||
range->size -= difference;
|
||||
|
||||
if (range->flags & VMM_FLAGS_FILE)
|
||||
range->offset += difference;
|
||||
} else if (address < rangetop && rangetop <= top){ // partially unmap from end
|
||||
size_t difference = (uintptr_t)rangetop - (uintptr_t)address;
|
||||
range->size -= difference;
|
||||
@@ -289,14 +309,21 @@ bool vmm_pagefault(void *addr, bool user, int actions) {
|
||||
if (invalidactions & actions)
|
||||
goto cleanup;
|
||||
|
||||
// TODO file/CoW
|
||||
// TODO CoW
|
||||
|
||||
void *paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
|
||||
__assert(paddr); // XXX handle these better than an assert once there are signals and such
|
||||
__assert(arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, range->mmuflags));
|
||||
memset(addr, 0, PAGE_SIZE);
|
||||
|
||||
status = true;
|
||||
if (range->flags & VMM_FLAGS_FILE) {
|
||||
uintmax_t mapoffset = (uintptr_t)addr - (uintptr_t)range->start;
|
||||
VOP_LOCK(range->vnode);
|
||||
__assert(VOP_MMAP(range->vnode, addr, range->offset + mapoffset, mmuflagstovnodeflags(range->mmuflags), NULL) == 0); // XXX pass cred struct
|
||||
VOP_UNLOCK(range->vnode);
|
||||
status = true;
|
||||
} else {
|
||||
void *paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
|
||||
__assert(paddr); // XXX handle these better than an assert once there are signals and such
|
||||
__assert(arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, range->mmuflags));
|
||||
memset(addr, 0, PAGE_SIZE);
|
||||
status = true;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
spinlock_release(&space->lock);
|
||||
@@ -337,7 +364,15 @@ void *vmm_map(void *addr, volatile size_t size, int flags, mmuflags_t mmuflags,
|
||||
range->flags = VMM_PERMANENT_FLAGS_MASK & flags;
|
||||
range->mmuflags = mmuflags;
|
||||
|
||||
// TODO file mapping and CoW
|
||||
// TODO CoW
|
||||
|
||||
if (flags & VMM_FLAGS_FILE) {
|
||||
// XXX make sure that writes can't happen to executable memory mapped files and check file permissions
|
||||
vmmfiledesc_t *desc = private;
|
||||
range->vnode = desc->node;
|
||||
range->offset = desc->offset;
|
||||
VOP_HOLD(desc->node);
|
||||
}
|
||||
|
||||
if (flags & VMM_FLAGS_PHYSICAL) {
|
||||
// map to allocated virtual memory
|
||||
@@ -353,6 +388,7 @@ void *vmm_map(void *addr, volatile size_t size, int flags, mmuflags_t mmuflags,
|
||||
// allocate to virtual memory
|
||||
for (uintmax_t i = 0; i < size; i += PAGE_SIZE) {
|
||||
void *allocated = pmm_alloc(1, PMM_SECTION_DEFAULT);
|
||||
|
||||
if (arch_mmu_map(_cpu()->vmmctx->pagetable, allocated, (void *)((uintptr_t)start + i), mmuflags) == false) {
|
||||
for (uintmax_t j = 0; j < size; j += PAGE_SIZE) {
|
||||
void *virt = (void *)((uintptr_t)start + i);
|
||||
|
||||
Reference in New Issue
Block a user