diff options
author | dzwdz | 2021-09-05 18:32:08 +0200 |
---|---|---|
committer | dzwdz | 2021-09-05 18:32:08 +0200 |
commit | 838b142b7374150df63ec02b02377c114a14b314 (patch) | |
tree | b5b22e5517da7a4ac96a47f0cfe6a4755d00da44 /src/kernel/mem | |
parent | d6c1dceba2511fa2edf839942b237d3a27bb9535 (diff) |
move most of the memory stuff to kernel/mem/
Diffstat (limited to 'src/kernel/mem')
-rw-r--r-- | src/kernel/mem/alloc.c | 38 | ||||
-rw-r--r-- | src/kernel/mem/alloc.h | 15 | ||||
-rw-r--r-- | src/kernel/mem/virt.c | 78 | ||||
-rw-r--r-- | src/kernel/mem/virt.h | 28 |
4 files changed, 159 insertions, 0 deletions
diff --git a/src/kernel/mem/alloc.c b/src/kernel/mem/alloc.c new file mode 100644 index 0000000..42a2f3b --- /dev/null +++ b/src/kernel/mem/alloc.c @@ -0,0 +1,38 @@ +#include <kernel/arch/generic.h> +#include <kernel/mem/alloc.h> +#include <kernel/util.h> +#include <stdint.h> + +static void *highest_page; + +void mem_init(struct kmain_info *info) { + // finds the highest used page, and starts allocating pages above it + void *highest = &_bss_end; + + if (highest < info->init.at + info->init.size) + highest = info->init.at + info->init.size; + + // align up to PAGE_SIZE + highest_page = (void*)(((uintptr_t)highest + PAGE_MASK) & ~PAGE_MASK); +} + +void *page_alloc(size_t pages) { + void *bottom = highest_page; + highest_page += pages * PAGE_SIZE; + return bottom; +} + +// frees `pages` consecutive pages starting from *first +void page_free(void *first, size_t pages) { + // not implemented +} + + +void *kmalloc(size_t len) { + // extremely inefficient, but this is only temporary anyways + return page_alloc(len / PAGE_SIZE + 1); +} + +void kfree(void *ptr) { + // unimplemented +} diff --git a/src/kernel/mem/alloc.h b/src/kernel/mem/alloc.h new file mode 100644 index 0000000..571b289 --- /dev/null +++ b/src/kernel/mem/alloc.h @@ -0,0 +1,15 @@ +#pragma once +#include <kernel/arch/generic.h> +#include <kernel/main.h> +#include <stddef.h> + +void mem_init(struct kmain_info *); + +// allocates `pages` consecutive pages +void *page_alloc(size_t pages); + +// frees `pages` consecutive pages starting from *first +void page_free(void *first, size_t pages); + +void *kmalloc(size_t len); +void kfree(void *ptr); diff --git a/src/kernel/mem/virt.c b/src/kernel/mem/virt.c new file mode 100644 index 0000000..2990668 --- /dev/null +++ b/src/kernel/mem/virt.c @@ -0,0 +1,78 @@ +#include <kernel/arch/generic.h> +#include <kernel/mem/virt.h> +#include <kernel/util.h> + +void virt_iter_new( + struct virt_iter *iter, user_ptr virt, size_t length, + struct pagedir *pages, bool user, bool writeable) +{ + iter->frag = 0; + iter->frag_len = 0; + iter->prior = 0; + iter->error = false; + iter->_virt = virt; + iter->_remaining = length; + iter->_pages = pages; + iter->_user = user; + iter->_writeable = writeable; +} + +bool virt_iter_next(struct virt_iter *iter) { + /* note: While i'm pretty sure that this should always work, this + * was only tested in cases where the pages were consecutive both in + * virtual and physical memory, which might not always be the case. + * TODO test this */ + + user_ptr virt = iter->_virt; + size_t partial = iter->_remaining; + iter->prior += iter->frag_len; + if (partial <= 0) return false; + + // don't read past the page + if ((virt & PAGE_MASK) + partial > PAGE_SIZE) + partial = PAGE_SIZE - (virt & PAGE_MASK); + + iter->frag = pagedir_virt2phys(iter->_pages, + iter->_virt, iter->_user, iter->_writeable); + + if (iter->frag == 0) { + iter->error = true; + return false; + } + + iter->frag_len = partial; + iter->_remaining -= partial; + iter->_virt += partial; + return true; +} + +bool virt_user_cpy( + struct pagedir *dest_pages, user_ptr dest, + struct pagedir *src_pages, const user_ptr src, size_t length) +{ + struct virt_iter dest_iter, src_iter; + size_t min; + + virt_iter_new(&dest_iter, dest, length, dest_pages, true, true); + virt_iter_new( &src_iter, src, length, src_pages, true, false); + dest_iter.frag_len = 0; + src_iter.frag_len = 0; + + for (;;) { + if (dest_iter.frag_len <= 0) + if (!virt_iter_next(&dest_iter)) break; + if ( src_iter.frag_len <= 0) + if (!virt_iter_next( &src_iter)) break; + + min = src_iter.frag_len < dest_iter.frag_len + ? src_iter.frag_len : dest_iter.frag_len; + memcpy(dest_iter.frag, src_iter.frag, min); + + dest_iter.frag_len -= min; + dest_iter.frag += min; + src_iter.frag_len -= min; + src_iter.frag += min; + } + + return !(dest_iter.error || src_iter.error); +} diff --git a/src/kernel/mem/virt.h b/src/kernel/mem/virt.h new file mode 100644 index 0000000..98a7a16 --- /dev/null +++ b/src/kernel/mem/virt.h @@ -0,0 +1,28 @@ +/* contains utilities for interacting with virtual memory */ +#pragma once +#include <kernel/types.h> +#include <stdbool.h> +#include <stddef.h> + +struct virt_iter { + void *frag; + size_t frag_len; + size_t prior; // sum of all prior frag_lens + bool error; + + user_ptr _virt; + size_t _remaining; + struct pagedir *_pages; + bool _user; + bool _writeable; +}; + +void virt_iter_new( + struct virt_iter *iter, user_ptr virt, size_t length, + struct pagedir *pages, bool user, bool writeable); + +bool virt_iter_next(struct virt_iter *); + +bool virt_user_cpy( + struct pagedir *dest_pages, user_ptr dest, + struct pagedir *src_pages, const user_ptr src, size_t length); |