mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-31 22:48:21 +00:00
vmm: file mapping
This commit is contained in:
@@ -19,6 +19,11 @@
|
|||||||
#define VMM_ACTION_WRITE 2
|
#define VMM_ACTION_WRITE 2
|
||||||
#define VMM_ACTION_EXEC 4
|
#define VMM_ACTION_EXEC 4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vnode_t *node;
|
||||||
|
uintmax_t offset;
|
||||||
|
} vmmfiledesc_t;
|
||||||
|
|
||||||
struct vmmcache_t;
|
struct vmmcache_t;
|
||||||
typedef struct vmmrange_t{
|
typedef struct vmmrange_t{
|
||||||
struct vmmrange_t *next;
|
struct vmmrange_t *next;
|
||||||
@@ -27,7 +32,12 @@ typedef struct vmmrange_t{
|
|||||||
size_t size;
|
size_t size;
|
||||||
int flags;
|
int flags;
|
||||||
mmuflags_t mmuflags;
|
mmuflags_t mmuflags;
|
||||||
void *private;
|
union {
|
||||||
|
struct {
|
||||||
|
vnode_t *vnode;
|
||||||
|
size_t offset;
|
||||||
|
};
|
||||||
|
};
|
||||||
} vmmrange_t;
|
} vmmrange_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -70,6 +80,18 @@ static inline mmuflags_t vnodeflagstommuflags(int flags) {
|
|||||||
return mmuflags;
|
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_map(void *addr, size_t size, int flags, mmuflags_t mmuflags, void *private);
|
||||||
void vmm_unmap(void *addr, size_t size, int flags);
|
void vmm_unmap(void *addr, size_t size, int flags);
|
||||||
bool vmm_pagefault(void *addr, bool user, int actions);
|
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:
|
fragcheck:
|
||||||
// TODO range type specific stuff
|
// 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;
|
vmmrange_t *oldrange = newrange->next;
|
||||||
newrange->size += oldrange->size;
|
newrange->size += oldrange->size;
|
||||||
newrange->next = oldrange->next;
|
newrange->next = oldrange->next;
|
||||||
freerange(oldrange);
|
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;
|
vmmrange_t *oldrange = newrange->prev;
|
||||||
oldrange->size += newrange->size;
|
oldrange->size += newrange->size;
|
||||||
oldrange->next = newrange->next;
|
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) {
|
static void destroyrange(vmmrange_t *range, uintmax_t _offset, size_t size) {
|
||||||
uintmax_t top = _offset + 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) {
|
for (uintmax_t offset = _offset; offset < top; offset += PAGE_SIZE) {
|
||||||
void *vaddr = (void *)((uintptr_t)range->start + offset);
|
void *vaddr = (void *)((uintptr_t)range->start + offset);
|
||||||
void *physical = arch_mmu_getphysical(_cpu()->vmmctx->pagetable, vaddr);
|
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);
|
pmm_free(physical, 1);
|
||||||
arch_mmu_unmap(_cpu()->vmmctx->pagetable, vaddr);
|
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) {
|
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
|
} else if (address > range->start && top < rangetop) { // split
|
||||||
vmmrange_t *new = allocrange();
|
vmmrange_t *new = allocrange();
|
||||||
__assert(new); // XXX deal with this better
|
__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);
|
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;
|
new->prev = range;
|
||||||
range->next = new;
|
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
|
} else if (top > range->start && range->start >= address) { // partially unmap from start
|
||||||
size_t difference = (uintptr_t)top - (uintptr_t)range->start;
|
size_t difference = (uintptr_t)top - (uintptr_t)range->start;
|
||||||
destroyrange(range, 0, difference);
|
destroyrange(range, 0, difference);
|
||||||
range->start = (void *)((uintptr_t)range->start + difference);
|
range->start = (void *)((uintptr_t)range->start + difference);
|
||||||
range->size -= difference;
|
range->size -= difference;
|
||||||
|
|
||||||
|
if (range->flags & VMM_FLAGS_FILE)
|
||||||
|
range->offset += difference;
|
||||||
} else if (address < rangetop && rangetop <= top){ // partially unmap from end
|
} else if (address < rangetop && rangetop <= top){ // partially unmap from end
|
||||||
size_t difference = (uintptr_t)rangetop - (uintptr_t)address;
|
size_t difference = (uintptr_t)rangetop - (uintptr_t)address;
|
||||||
range->size -= difference;
|
range->size -= difference;
|
||||||
@@ -289,14 +309,21 @@ bool vmm_pagefault(void *addr, bool user, int actions) {
|
|||||||
if (invalidactions & actions)
|
if (invalidactions & actions)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
// TODO file/CoW
|
// TODO CoW
|
||||||
|
|
||||||
void *paddr = pmm_alloc(1, PMM_SECTION_DEFAULT);
|
if (range->flags & VMM_FLAGS_FILE) {
|
||||||
__assert(paddr); // XXX handle these better than an assert once there are signals and such
|
uintmax_t mapoffset = (uintptr_t)addr - (uintptr_t)range->start;
|
||||||
__assert(arch_mmu_map(_cpu()->vmmctx->pagetable, paddr, addr, range->mmuflags));
|
VOP_LOCK(range->vnode);
|
||||||
memset(addr, 0, PAGE_SIZE);
|
__assert(VOP_MMAP(range->vnode, addr, range->offset + mapoffset, mmuflagstovnodeflags(range->mmuflags), NULL) == 0); // XXX pass cred struct
|
||||||
|
VOP_UNLOCK(range->vnode);
|
||||||
status = true;
|
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:
|
cleanup:
|
||||||
spinlock_release(&space->lock);
|
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->flags = VMM_PERMANENT_FLAGS_MASK & flags;
|
||||||
range->mmuflags = mmuflags;
|
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) {
|
if (flags & VMM_FLAGS_PHYSICAL) {
|
||||||
// map to allocated virtual memory
|
// 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
|
// allocate to virtual memory
|
||||||
for (uintmax_t i = 0; i < size; i += PAGE_SIZE) {
|
for (uintmax_t i = 0; i < size; i += PAGE_SIZE) {
|
||||||
void *allocated = pmm_alloc(1, PMM_SECTION_DEFAULT);
|
void *allocated = pmm_alloc(1, PMM_SECTION_DEFAULT);
|
||||||
|
|
||||||
if (arch_mmu_map(_cpu()->vmmctx->pagetable, allocated, (void *)((uintptr_t)start + i), mmuflags) == false) {
|
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) {
|
for (uintmax_t j = 0; j < size; j += PAGE_SIZE) {
|
||||||
void *virt = (void *)((uintptr_t)start + i);
|
void *virt = (void *)((uintptr_t)start + i);
|
||||||
|
|||||||
Reference in New Issue
Block a user