From 8d545ea74f1387c7c99b88ee12ed26fe84bf6061 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 17:42:10 -0400 Subject: kernel: vm: Add physical memory allocator Signed-off-by: Ian Moffett --- sys/include/vm/physmem.h | 39 ++++++++++ sys/include/vm/vm.h | 4 ++ sys/vm/vm_init.c | 7 ++ sys/vm/vm_physmem.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 sys/include/vm/physmem.h create mode 100644 sys/vm/vm_physmem.c (limited to 'sys') diff --git a/sys/include/vm/physmem.h b/sys/include/vm/physmem.h new file mode 100644 index 0000000..196a9a8 --- /dev/null +++ b/sys/include/vm/physmem.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _VM_PHYSMEM_H_ +#define _VM_PHYSMEM_H_ + +#include + +void vm_physmem_init(void); +uintptr_t vm_alloc_frame(size_t count); +void vm_free_frame(uintptr_t base, size_t count); + +#endif /* !_VM_PHYSMEM_H_ */ diff --git a/sys/include/vm/vm.h b/sys/include/vm/vm.h index a4a073f..a2caa8c 100644 --- a/sys/include/vm/vm.h +++ b/sys/include/vm/vm.h @@ -39,4 +39,8 @@ extern volatile struct limine_hhdm_request g_hhdm_request; #define PHYS_TO_VIRT(phys) (void *)((uintptr_t)phys + VM_HIGHER_HALF) #define VIRT_TO_PHYS(virt) ((uintptr_t)virt - VM_HIGHER_HALF) +#define DEFAULT_PAGESIZE 4096 + +void vm_init(void); + #endif diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c index 255821a..3e9718d 100644 --- a/sys/vm/vm_init.c +++ b/sys/vm/vm_init.c @@ -29,8 +29,15 @@ #include #include +#include volatile struct limine_hhdm_request g_hhdm_request = { .id = LIMINE_HHDM_REQUEST, .revision = 0 }; + +void +vm_init(void) +{ + vm_physmem_init(); +} diff --git a/sys/vm/vm_physmem.c b/sys/vm/vm_physmem.c new file mode 100644 index 0000000..19e3927 --- /dev/null +++ b/sys/vm/vm_physmem.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +size_t highest_frame_idx = 0; +size_t bitmap_size = 0; +size_t bitmap_free_start = 0; + +uint8_t *bitmap; +static struct limine_memmap_response *resp = NULL; +static struct spinlock lock = {0}; + +static struct limine_memmap_request mmap_req = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0 +}; + +/* + * Populate physical memory bitmap. + */ +static void +physmem_populate_bitmap(void) +{ + struct limine_memmap_entry *ent; + + for (size_t i = 0; i < resp->entry_count; ++i) { + ent = resp->entries[i]; + + if (ent->type != LIMINE_MEMMAP_USABLE) { + /* This memory is not usable */ + continue; + } + + if (bitmap_free_start == 0) { + bitmap_free_start = ent->base / DEFAULT_PAGESIZE; + } + + for (size_t j = 0; j < ent->length; j += DEFAULT_PAGESIZE) { + clrbit(bitmap, (ent->base + j) / DEFAULT_PAGESIZE); + } + } +} + +/* + * Allocate physical memory for the bitmap + * we'll use to keep track of free memory. + */ +static void +physmem_alloc_bitmap(void) +{ + struct limine_memmap_entry *ent; + uintptr_t highest_addr = 0; + + for (size_t i = 0; i < resp->entry_count; ++i) { + ent = resp->entries[i]; + + if (ent->type != LIMINE_MEMMAP_USABLE) { + /* This memory is not usable */ + continue; + } + + if (ent->length >= bitmap_size) { + bitmap = PHYS_TO_VIRT(ent->base); + memset(bitmap, 0xFF, bitmap_size); + ent->length -= bitmap_size; + ent->base += bitmap_size; + return; + } + + highest_addr = MAX(highest_addr, ent->base + ent->length); + } +} + + +/* + * Init the physical memory bitmap. + */ +static void +physmem_init_bitmap(void) +{ + uintptr_t highest_addr = 0; + struct limine_memmap_entry *ent; + + for (size_t i = 0; i < resp->entry_count; ++i) { + ent = resp->entries[i]; + + if (ent->type != LIMINE_MEMMAP_USABLE) { + continue; + } + + highest_addr = MAX(highest_addr, ent->base + ent->length); + } + + highest_frame_idx = highest_addr / DEFAULT_PAGESIZE; + bitmap_size = ALIGN_UP(highest_frame_idx / 8, DEFAULT_PAGESIZE); + + physmem_alloc_bitmap(); + physmem_populate_bitmap(); +} + +/* + * Allocate page frames. + * + * @count: Number of frames to allocate. + */ +uintptr_t +vm_alloc_frame(size_t count) +{ + size_t frames = 0; + uintptr_t ret = 0; + + spinlock_acquire(&lock); + for (size_t i = 0; i < highest_frame_idx; ++i) { + if (!testbit(bitmap, i)) { + /* We have a free page */ + if (++frames != count) { + continue; + } + + for (size_t j = i; j < i + count; ++j) { + setbit(bitmap, j); + } + + ret = i * DEFAULT_PAGESIZE; + break; + } + } + + spinlock_release(&lock); + return ret; +} + +void +vm_free_frame(uintptr_t base, size_t count) +{ + size_t stop_at = base + (count * DEFAULT_PAGESIZE); + + spinlock_acquire(&lock); + for (uintptr_t p = base; p < stop_at; p += DEFAULT_PAGESIZE) { + clrbit(bitmap, p / DEFAULT_PAGESIZE); + } + spinlock_release(&lock); +} + +void +vm_physmem_init(void) +{ + resp = mmap_req.response; + physmem_init_bitmap(); +} -- cgit v1.2.3