aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsigsegv7 <ian@vegaa.systems>2023-10-07 16:52:15 -0400
committersigsegv7 <ian@vegaa.systems>2023-10-07 16:52:15 -0400
commit32dbfb1ae399904c9fadc5b7fff232fcbc139add (patch)
tree8f3b1063fc0a1e6d91e2e07731ac5c42407a43b3
parent75ce5c6864b5b9b7a060d813d6d4c9f27e8ffabd (diff)
kernel: vm: Add pageframe allocation
This commit introduces pageframe allocation logic to the Vega virtual memory subsystem. Signed-off-by: sigsegv7 <ian@vegaa.systems>
-rw-r--r--sys/include/vm/vm.h15
-rw-r--r--sys/include/vm/vm_physseg.h4
-rw-r--r--sys/vm/vm_physseg.c92
3 files changed, 107 insertions, 4 deletions
diff --git a/sys/include/vm/vm.h b/sys/include/vm/vm.h
index 78038f0..baf7677 100644
--- a/sys/include/vm/vm.h
+++ b/sys/include/vm/vm.h
@@ -32,6 +32,8 @@
#include <sys/types.h>
#include <sys/limine.h>
+#include <sys/cdefs.h>
+#include <vm/vm_page.h>
extern volatile struct limine_hhdm_request g_hhdm_request;
@@ -40,6 +42,19 @@ 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)
+/*
+ * Returns the machine's pagesize:
+ *
+ * XXX TODO: This needs to be moved to vmm_init.c
+ * while returning a non-constant value.
+ */
+static inline size_t
+vm_get_page_size(void)
+{
+ return 4096;
+}
+
void vm_init(void);
+struct vas vm_new_vas(void);
#endif /* !_VM_H_ */
diff --git a/sys/include/vm/vm_physseg.h b/sys/include/vm/vm_physseg.h
index 5bf21db..5865a84 100644
--- a/sys/include/vm/vm_physseg.h
+++ b/sys/include/vm/vm_physseg.h
@@ -30,6 +30,10 @@
#ifndef _VM_VM_PHYSSEG_H_
#define _VM_VM_PHYSSEG_H_
+#include <sys/types.h>
+
void vm_physseg_init(void);
+uintptr_t vm_alloc_pageframe(size_t count);
+void vm_free_pageframe(uintptr_t base, size_t count);
#endif /* !_VM_VM_PHYSSEG_H_ */
diff --git a/sys/vm/vm_physseg.c b/sys/vm/vm_physseg.c
index f21c282..12f6844 100644
--- a/sys/vm/vm_physseg.c
+++ b/sys/vm/vm_physseg.c
@@ -67,13 +67,16 @@ static const int MAX_SEGMENTS = __ARRAY_COUNT(segment_name);
static bitmap_t bitmap = NULL;
+static size_t last_used_idx = 0;
static size_t bitmap_size = 0;
+static size_t highest_frame_idx;
static size_t bitmap_free_start; /* Beginning bit of free region */
static void
vm_physseg_bitmap_alloc(void)
{
struct limine_memmap_entry *entry;
+ uintptr_t highest_addr = 0;
for (size_t i = 0; i < resp->entry_count; ++i) {
entry = resp->entries[i];
@@ -95,6 +98,8 @@ vm_physseg_bitmap_alloc(void)
entry->base += bitmap_size;
return;
}
+
+ highest_addr = __MAX(highest_addr, entry->base + entry->length);
}
}
@@ -142,11 +147,10 @@ static void
vm_physseg_bitmap_init(void)
{
uintptr_t highest_addr;
- size_t highest_page_idx;
struct limine_memmap_entry *entry;
highest_addr = 0;
- highest_page_idx = 0;
+ highest_frame_idx = 0;
/* Find the highest entry */
for (size_t i = 0; i < resp->entry_count; ++i) {
@@ -160,8 +164,8 @@ vm_physseg_bitmap_init(void)
highest_addr = __MAX(highest_addr, entry->base + entry->length);
}
- highest_page_idx = highest_addr / 0x1000;
- bitmap_size = __ALIGN_UP(highest_page_idx / 8, 0x1000);
+ highest_frame_idx = highest_addr / 0x1000;
+ bitmap_size = __ALIGN_UP(highest_frame_idx / 8, 0x1000);
DPRINTF("Bitmap size: %d bytes\n", bitmap_size);
DPRINTF("Allocating and populating bitmap now...\n");
@@ -170,6 +174,86 @@ vm_physseg_bitmap_init(void)
vm_physseg_bitmap_populate();
}
+static uintptr_t
+vm_alloc_pageframe_internal(size_t count)
+{
+ bool can_alloc = false;
+
+ bool is_free; /* True if we found a free frame */
+ size_t free_count = 0; /* How many we found that are free? */
+ uintptr_t frame_idx = 0; /* The base index of first free frame */
+
+ for (size_t i = last_used_idx; i < bitmap_size*8; ++i) {
+ is_free = !bitmap_test_bit(bitmap, i);
+
+ if (!is_free) {
+ free_count = 0;
+ continue;
+ }
+
+ if (free_count == count) {
+ can_alloc = true;
+ break;
+ }
+
+ /* Assume free here */
+ if (frame_idx == 0)
+ frame_idx = i;
+
+ ++free_count;
+ }
+
+ if (!can_alloc) {
+ /* No free memory! */
+ last_used_idx = 0;
+ return 0;
+ }
+
+ /* Mark the memory as allocated */
+ for (size_t i = frame_idx; i < frame_idx+count; ++i) {
+ bitmap_set_bit(bitmap, i);
+ }
+
+ /* Return the physical address */
+ last_used_idx = frame_idx;
+ return frame_idx*vm_get_page_size();
+}
+
+/*
+ * Allocates physical pageframes.
+ *
+ * @count: Number of pageframes to allocate.
+ */
+uintptr_t
+vm_alloc_pageframe(size_t count)
+{
+ uintptr_t phys;
+
+ phys = vm_alloc_pageframe_internal(count);
+
+ if (phys == 0)
+ return 0;
+
+ vm_zero_page(PHYS_TO_VIRT(phys), count);
+ return phys;
+}
+
+/*
+ * Frees physical pageframes.
+ *
+ * @base: Base to start freeing at.
+ * @count: Number of pageframes to free.
+ */
+void
+vm_free_pageframe(uintptr_t base, size_t count)
+{
+ const size_t PAGE_SIZE = vm_get_page_size();
+
+ for (uintptr_t p = base; p < base + (count*PAGE_SIZE); p += PAGE_SIZE) {
+ bitmap_unset_bit(bitmap, p/0x1000);
+ }
+}
+
void
vm_physseg_init(void)
{