summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2026-10-07 17:37:26 -0400
committerJon Santmyer <jon@jonsantmyer.com>2026-10-07 17:37:26 -0400
commit434ddcd907832b1febc7d70e4faa52109c7eb3bd (patch)
tree00c1ade91f9806d831f10e6006732b294e73f613
parent8d48bbd9746228b63bafa5f92b621998d7d8f3d3 (diff)
downloadjove-kernel-434ddcd907832b1febc7d70e4faa52109c7eb3bd.tar.gz
jove-kernel-434ddcd907832b1febc7d70e4faa52109c7eb3bd.tar.bz2
jove-kernel-434ddcd907832b1febc7d70e4faa52109c7eb3bd.zip
add memory region object for better memory managment
-rw-r--r--api/init.h2
-rw-r--r--api/obj.h3
-rw-r--r--api/syscall.h43
-rw-r--r--arch/x86_64/hal/obj.c2
-rw-r--r--arch/x86_64/hal/paging.c8
-rw-r--r--arch/x86_64/main.c3
-rw-r--r--boot/limine/memorymap.c28
-rw-r--r--doc/memory.md87
-rw-r--r--hal/memory.h55
-rw-r--r--hal/region.c263
-rw-r--r--lib/bitmap.c51
-rw-r--r--lib/bitmap.h25
-rw-r--r--proc/init.c21
-rw-r--r--proc/scheduler.c3
-rw-r--r--proc/scheduler.h6
-rw-r--r--sys/lock.c (renamed from arch/x86_64/lock.c)2
-rw-r--r--sys/lock.h (renamed from arch/x86_64/lock.h)0
-rw-r--r--sys/syscall.c1
-rw-r--r--sys/syscall.h1
-rw-r--r--sys/syscall_region.c68
20 files changed, 629 insertions, 43 deletions
diff --git a/api/init.h b/api/init.h
index e92c910..3458ca1 100644
--- a/api/init.h
+++ b/api/init.h
@@ -8,7 +8,7 @@ enum {
ROOTDIR_DIR_I,
ROOTDIR_PROCESSORS_I,
ROOTDIR_PAGEDIR_I,
- ROOTDIR_UNTYPED_I,
+ ROOTDIR_FREEMEMORY_I,
ROOTDIR_HWMEMORY_I,
ROOTDIR_PCB_I,
ROOTDIR_INTERRUPTS_I,
diff --git a/api/obj.h b/api/obj.h
index 6e9ddc6..29238c1 100644
--- a/api/obj.h
+++ b/api/obj.h
@@ -3,6 +3,8 @@
#include <stdint.h>
+typedef unsigned char objtype_t;
+
enum
{
JOVE_OBJ_NONE = 0,
@@ -10,6 +12,7 @@ enum
JOVE_OBJ_OBJDIR,
JOVE_OBJ_PAGEDIR,
JOVE_OBJ_PROCESSOR,
+ JOVE_OBJ_REGION,
JOVE_OBJ_SHMEMORY,
JOVE_OBJ_INT_HANDLE,
JOVE_OBJ_PCB,
diff --git a/api/syscall.h b/api/syscall.h
index 2502621..3f9d115 100644
--- a/api/syscall.h
+++ b/api/syscall.h
@@ -124,6 +124,49 @@ struct syscall_pagedir_unmap
objpath_part_t none_path[];
};
+/**JOVE_OBJ_REGION syscalls.
+ * */
+
+enum
+{
+ _SYSCALL_REGION_NONE = 0,
+ SYSCALL_REGION_ADDRESS,
+ SYSCALL_REGION_TOTAL_PAGES,
+ SYSCALL_REGION_FREE_PAGES,
+ SYSCALL_REGION_ALLOC,
+ SYSCALL_REGION_SPLIT,
+ SYSCALL_REGION_RELEASE,
+};
+
+#define SYSCALL_PERM_REGION_GETTERS (JOVE_PERM_READ)
+#define SYSCALL_PERM_REGION_ALLOC (JOVE_PERM_WRITE)
+#define SYSCALL_PERM_REGION_SPLIT (JOVE_PERM_WRITE | JOVE_PERM_MUTATE)
+#define SYSCALL_PERM_REGION_MERGE (JOVE_PERM_WRITE | JOVE_PERM_MUTATE)
+
+#define SYSCALL_PERM_REGION_ALLOC_TGT (JOVE_PERM_MUTATE)
+#define SYSCALL_PERM_REGION_SPLIT_TGT (JOVE_PERM_MUTATE)
+#define SYSCALL_PERM_REGION_MERGE_TGT (JOVE_PERM_WRITE | JOVE_PERM_MUTATE)
+
+struct syscall_region_alloc
+{
+ size_t alloc_pages;
+ objpath_part_t dest_pathlen;
+ objpath_part_t dest_path[];
+};
+
+struct syscall_region_split
+{
+ size_t split_pages;
+ objpath_part_t dest_pathlen;
+ objpath_part_t dest_path[];
+};
+
+struct syscall_region_merge
+{
+ objpath_part_t dest_pathlen;
+ objpath_part_t dest_path[];
+};
+
/**JOVE_OBJ_PCB syscalls.
* */
diff --git a/arch/x86_64/hal/obj.c b/arch/x86_64/hal/obj.c
index 75cb0c0..110351c 100644
--- a/arch/x86_64/hal/obj.c
+++ b/arch/x86_64/hal/obj.c
@@ -1,5 +1,5 @@
#include "obj.h"
-#include "arch/x86_64/lock.h"
+#include "sys/lock.h"
#include "lib/printf.h"
#include "paging.h"
#include "hal/obj.h"
diff --git a/arch/x86_64/hal/paging.c b/arch/x86_64/hal/paging.c
index a0d6ca9..1587c62 100644
--- a/arch/x86_64/hal/paging.c
+++ b/arch/x86_64/hal/paging.c
@@ -28,6 +28,14 @@ phys_tovirt(uintptr_t phys)
return (void*)(phys | IDENT_VIRT_BASE);
}
+physaddr_t
+phys_fromvirt(virtaddr_t virt)
+{
+ if(virt < IDENT_VIRT_BASE) return 0;
+ if(virt > KERNEL_VIRT_BASE) return KPTR_TOPHYS(virt);
+ return virt & ~IDENT_VIRT_BASE;
+}
+
uintptr_t
paging_get_pml4(void)
{
diff --git a/arch/x86_64/main.c b/arch/x86_64/main.c
index 92f9fe1..6e2fcb8 100644
--- a/arch/x86_64/main.c
+++ b/arch/x86_64/main.c
@@ -38,6 +38,7 @@ kernel_entry(void)
serial_com_init();
smp_init_bsp();
+ mem_setup_regions();
initrd_setup();
fb_init();
@@ -45,8 +46,6 @@ kernel_entry(void)
cmdline_print();
- mem_setup_untyped();
-
extern void processing_setup(void*);
processing_setup(kernel_process_entry);
hcf();
diff --git a/boot/limine/memorymap.c b/boot/limine/memorymap.c
index b90f176..e470e14 100644
--- a/boot/limine/memorymap.c
+++ b/boot/limine/memorymap.c
@@ -10,7 +10,7 @@
extern struct limine_memmap_response *_limine_memmap_resp;
PAGEALIGN
-static jove_objdir_t s_untyped_objdir;
+static jove_objdir_t s_region_objdir;
static jove_objdir_t s_hwmemory_objdir;
#define MEMMAP_MAX_ENTRIES 255
@@ -28,13 +28,13 @@ static const char *limine_mmap_entry_type_str[9] = {
};
void
-mem_setup_untyped(void)
+mem_setup_regions(void)
{
{
- jove_owned_obj_t *untyped_objdir_obj = objdir_getlocal(_rootdir_obj, ROOTDIR_UNTYPED_I);
- obj_settype(untyped_objdir_obj, JOVE_OBJ_OBJDIR);
- obj_setvalue(untyped_objdir_obj, (uintptr_t)&s_untyped_objdir);
- obj_release(untyped_objdir_obj);
+ jove_owned_obj_t *region_objdir_obj = objdir_getlocal(_rootdir_obj, ROOTDIR_FREEMEMORY_I);
+ obj_settype(region_objdir_obj, JOVE_OBJ_OBJDIR);
+ obj_setvalue(region_objdir_obj, (uintptr_t)&s_region_objdir);
+ obj_release(region_objdir_obj);
}
if(_limine_memmap_resp == NULL) {
@@ -43,10 +43,9 @@ mem_setup_untyped(void)
kprintf("Memory map provided by Limine:\n");
- size_t untyped_i = 0;
+ size_t region_i = 0;
size_t hwmem_i = 0;
- uintptr_t highest_phys = 0;
for(size_t i = 0; i < _limine_memmap_resp->entry_count; i++) {
struct limine_memmap_entry *entry = _limine_memmap_resp->entries[i];
@@ -54,23 +53,18 @@ mem_setup_untyped(void)
entry->type == LIMINE_MEMMAP_ACPI_RECLAIMABLE ||
entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
{
- if(untyped_i > JOVE_OBJDIR_ENTRIES){
+ if(region_i > JOVE_OBJDIR_ENTRIES){
kprintf("%s: Provided memory map exceeds kernel limits. Some memory may not be accessable.", __func__);
break;
}
klogf("%p : %p %s\n", entry->base, entry->length, limine_mmap_entry_type_str[entry->type]);
if(entry->base == 0) continue;
- if(entry->base + entry->length > highest_phys) highest_phys = entry->base + entry->length;
{
- jove_owned_obj_t *untyped_obj = obj_take(&s_untyped_objdir.entries[untyped_i++]);
- obj_settype(untyped_obj, JOVE_OBJ_UNTYPED);
- obj_setvalue(untyped_obj, entry->base);
-
- jove_untyped_t *untyped_data = obj_deref(untyped_obj);
- untyped_data->limit = entry->length;
- obj_release(untyped_obj);
+ jove_owned_obj_t *region_obj = obj_take(&s_region_objdir.entries[region_i++]);
+ region_new(region_obj, entry->base, entry->length / 0x1000);
+ obj_release(region_obj);
}
}
if(entry->type == LIMINE_MEMMAP_RESERVED |
diff --git a/doc/memory.md b/doc/memory.md
new file mode 100644
index 0000000..75e4adc
--- /dev/null
+++ b/doc/memory.md
@@ -0,0 +1,87 @@
+## Jove Physical Memory Managment
+
+Memory in the Jove kernel is managed by `JOVE_OBJ_REGION` objects which
+represent a contiguous span of physical memory page frames that can be split into
+sub-region objects or spawn page-sized `JOVE_OBJ_UNTYPED` objects.
+
+Each `JOVE_OBJ_REGION` object is represented in a doubly-linked list datastructure
+sorted by physical address.
+
+### Reasoning
+
+Microkernels need a way to delegate memory alloc and free to userspace programs.
+Therefore microkernels need to pass information about the available memory regions
+and provide systems to allocate and release page frames quickly, atomically, and efficiently.
+For Jove, initially the plan was to represent free pages using untyped objects.
+However this system would require extensive userspace book-keeping per allocation.
+
+To fix this problem, Jove uses "Memory region" objects, which control an allocation
+bitmap per page-frame so that every allocation is marked and traceable back to any specific region.
+If a user program tries to free a marked page, it's easy to trace that page back to the
+allocated region and mark it as released.
+
+### Interface
+
+The following functions are made available to user programs through system calls:
+
+```
+physaddr_t region_base(jove_owned_obj_t *region_obj);
+```
+Returns the physical address marking the start of the physical region.
+
+```
+unsigned int region_pages(jove_owned_obj_t *region_obj);
+```
+Returns the total number of pages referenced by the physical region.
+
+```
+unsigned int region_freepages(jove_owned_obj_t *region_obj);
+```
+Returns the number of pages freely alloc-able by the physical region.
+
+```
+int region_split(jove_owned_obj_t *source_obj, jove_owned_obj_t *dest_obj, size_t pages);
+```
+Splits off a new memory region from the source region into the destination object sized by some number of pages.
+
+If `pages == 0`, then the kernel will return `-EBADSIZE`.
+
+If `pages % JOVE_REGION_GRANULARITY != 0`, then the kernel will return `-EBADSIZE`.
+
+If `pages > region_pages(source_obj)`, then the kernel will return `-ETOOBIG`.
+
+If `region_pages(source_obj) - pages == 0`, then the kernel will return `-ETOOBIG`.
+
+If the source region's mutex is taken, then the kernel will return `-EBUSY`.
+
+The final region will be sized for `pages` pages with 1 or more pages marked taken for the region overhead.
+
+```
+int region_release(jove_owned_obj_t *region_obj);
+```
+Returns a sub-region to a super region. Does not remove page allocations.
+
+If the region object is a top-level region, then the kernel will return `-EPERM`.
+
+If the region object has sub-regions, the kernel will return `-EBUSY`.
+
+If the region object's mutex is locked, the kernel will return `-EBUSY`.
+
+If the super region's mutex is locked, the kernel will return `-EBUSY`.
+
+```
+int region_alloc(jove_owned_obj_t *region_obj, jove_owned_obj_t *dest_obj);
+```
+Tries to allocate an untyped page frame from the region object into the dest object.
+
+If the region's mutex is locked, the kernel will return `-EBUSY`.
+
+If the region has no free pages, the kernel will return `-EFULL`.
+
+If the region's bitmap was unable to find an allocable page, the kernel will return `-EFULL`.
+
+The new page object will be a `JOVE_OBJ_UNTYPED` object aligned and sized to `0x1000`.
+
+```
+int region_alloc_contig(jove_owned_obj_t *region_obj, jove_owned_obj_t *dest_obj, size_t pages);
+```
diff --git a/hal/memory.h b/hal/memory.h
index ab5f6ad..84cb7f2 100644
--- a/hal/memory.h
+++ b/hal/memory.h
@@ -4,7 +4,27 @@
#include "hal/obj.h"
#include "api/syscall.h"
#include "sys/syscall.h"
+#include "lib/bitmap.h"
#include <stdbool.h>
+#include <stdatomic.h>
+
+typedef uintptr_t physaddr_t;
+typedef uintptr_t virtaddr_t;
+typedef unsigned short shmem_off_t;
+
+/**Represents a region of alloc-able memory.
+ * */
+typedef struct jove_memory_region
+{
+ struct jove_memory_region *next;
+ struct jove_memory_region *prev;
+ atomic_flag lock;
+ bool toplevel;
+ struct bitmap bitmap;
+} jove_region_t;
+
+#define JOVE_REGION_GRANULARITY BITMAP_BLOCK_BITS
+#define JOVE_REGION_OVERHEAD(pages) (sizeof(jove_region_t) + ((pages) + JOVE_REGION_GRANULARITY-1) / JOVE_REGION_GRANULARITY)
typedef struct jove_obj_untyped
{
@@ -13,34 +33,47 @@ typedef struct jove_obj_untyped
#define JOVE_UNTYPED_MINSIZE 0x10
-void mem_setup_untyped(void);
+void mem_setup_regions(void);
+
+physaddr_t phys_fromvirt(virtaddr_t virt);
+void *phys_tovirt(physaddr_t phys);
+
+jove_region_t *region_from_addr(physaddr_t addr);
+jove_region_t *region_data(jove_owned_obj_t *region_obj);
+physaddr_t region_base(jove_owned_obj_t *region_obj);
+unsigned int region_pages(jove_owned_obj_t *region_obj);
+unsigned int region_freepages(jove_owned_obj_t *region_obj);
+
+void region_new(jove_owned_obj_t *dest_obj, physaddr_t base, size_t pages);
+int region_split(jove_owned_obj_t *source_obj, jove_owned_obj_t *dest_obj, size_t pages);
+int region_release(jove_owned_obj_t *region_obj);
-void *phys_tovirt(uintptr_t phys);
+int region_alloc(jove_owned_obj_t *region_obj, jove_owned_obj_t *dest_obj);
+int region_alloc_contig(jove_owned_obj_t *region_obj, jove_owned_obj_t *dest_obj, size_t pages);
uintptr_t untyped_address(jove_owned_obj_t *tgt);
size_t untyped_size(jove_owned_obj_t *tgt);
int untyped_split(jove_owned_obj_t *tgt, jove_owned_obj_t *dst, size_t bytes);
int untyped_merge(jove_owned_obj_t *a, jove_owned_obj_t *b);
-int untyped_retype(jove_owned_obj_t *tgt, uint8_t newtype);
-void pagedir_invlpg(uintptr_t vptr);
+void pagedir_invlpg(virtaddr_t vptr);
-uintptr_t *pagedir_get_mapping(
- jove_owned_obj_t *pagedir, uintptr_t vptr);
+virtaddr_t *pagedir_get_mapping(
+ jove_owned_obj_t *pagedir, virtaddr_t vptr);
-uintptr_t pagedir_ident_from_mapping(uintptr_t *mapping);
-void pagedir_mapping_set_present(uintptr_t *mapping, bool present);
+virtaddr_t pagedir_ident_from_mapping(virtaddr_t *mapping);
+void pagedir_mapping_set_present(virtaddr_t *mapping, bool present);
int pagedir_map_untyped_frame(
jove_owned_obj_t *tgt, jove_perm_obj_t *untyped_obj,
- uintptr_t vptr, struct syscall_pagedir_flags flg);
+ virtaddr_t vptr, struct syscall_pagedir_flags flg);
int pagedir_map_untyped_table(
jove_owned_obj_t *tgt, jove_perm_obj_t *untyped_obj,
- uintptr_t vptr);
+ virtaddr_t vptr);
int pagedir_map_shmem_frame(
jove_owned_obj_t *tgt, jove_perm_obj_t *shmem_obj, uint8_t page_offset,
- uintptr_t vptr, struct syscall_pagedir_flags flg);
+ virtaddr_t vptr, struct syscall_pagedir_flags flg);
int pagedir_unmap_untyped_frame(
jove_owned_obj_t *tgt, jove_owned_obj_t *dst, uintptr_t vptr);
diff --git a/hal/region.c b/hal/region.c
new file mode 100644
index 0000000..d238305
--- /dev/null
+++ b/hal/region.c
@@ -0,0 +1,263 @@
+#include "api/error.h"
+#include "sys/lock.h"
+#include "hal/obj.h"
+#include "lib/printf.h"
+#include "lib/string.h"
+#include "panic/panic.h"
+#include "memory.h"
+
+jove_region_t *region_list_head;
+
+jove_region_t*
+region_from_addr(physaddr_t addr)
+{
+ jove_region_t *bestfit = NULL;
+ for(jove_region_t *region = region_list_head; region; region = region->next)
+ {
+ virtaddr_t region_virt = phys_fromvirt((virtaddr_t)addr);
+ if(region_virt < addr) {
+ if(bestfit) return bestfit;
+ continue;
+ }
+
+ virtaddr_t region_limit = region_virt + (region->bitmap.total_bits * 0x1000);
+ if(region_limit < addr) {
+ if(bestfit) return bestfit;
+ continue;
+ }
+
+ if(addr < region_limit) {
+ if(bestfit) return bestfit;
+ continue;
+ }
+
+ if(!bestfit)
+ bestfit = region;
+ else {
+ if(bestfit->bitmap.total_bits > region->bitmap.total_bits) {
+ bestfit = region;
+ }
+ }
+ }
+ klogf("Failed to get region from phys address %p\n", addr);
+ return NULL;
+}
+
+jove_region_t*
+region_data(jove_owned_obj_t *obj)
+{
+ return obj_deref(obj);
+}
+
+physaddr_t
+region_base(jove_owned_obj_t *region)
+{
+ return obj_getvalue(region);
+}
+
+unsigned int
+region_pages(jove_owned_obj_t *region_obj)
+{
+ jove_region_t *region = region_data(region_obj);
+ return region->bitmap.total_bits;
+}
+
+unsigned int
+region_freepages(jove_owned_obj_t *region_obj)
+{
+ jove_region_t *region = region_data(region_obj);
+ return region->bitmap.free_bits;
+}
+
+void
+region_new(jove_owned_obj_t *dest_obj, physaddr_t base, size_t pages)
+{
+ //Round to next region granularity.
+ const size_t blocks = (pages + BITMAP_BLOCK_BITS - 1) / BITMAP_BLOCK_BITS;
+
+ obj_settype(dest_obj, JOVE_OBJ_REGION);
+ obj_setvalue(dest_obj, base);
+
+ jove_region_t *dest = phys_tovirt(base);
+ memset(dest, 0, sizeof(jove_region_t) + blocks);
+
+ //Mark overhead pages as taken.
+ const size_t overhead_bytes = sizeof(jove_region_t) + blocks;
+ const size_t overhead_pages = (overhead_bytes + 0xFFF) / 0x1000;
+ for(size_t i = 0; i < overhead_pages; i++) {
+ bitmap_set(&dest->bitmap, i);
+ }
+
+ //Setup metadata for top-level pages.
+ dest->toplevel = true;
+ dest->bitmap.total_bits = pages;
+ dest->bitmap.free_bits = pages - overhead_pages;
+
+ //Place new region at the front of the region list.
+ dest->next = region_list_head;
+ if(dest->next) {
+ dest->prev = dest->next->prev;
+ dest->next->prev = dest;
+ }
+ release_mutex(&dest->lock);
+}
+
+int
+region_split(jove_owned_obj_t *source_obj,
+ jove_owned_obj_t *dest_obj, size_t pages)
+{
+ if(pages == 0) return -EBADSIZE;
+ if(pages % JOVE_REGION_GRANULARITY != 0) return -EBADSIZE;
+
+ /*Ensure that the source and destination memory regions keep a minimum size.*/
+ if(pages > region_pages(source_obj)) return -ETOOBIG;
+ if(region_pages(source_obj) - pages == 0) return -ETOOBIG;
+
+ physaddr_t source_base = region_base(source_obj);
+ jove_region_t *source = region_data(source_obj);
+
+ //Ensure that the source region can't change as we're splitting.
+ if(try_take_mutex(&source->lock)) {
+ return -EBUSY;
+ }
+
+ //Check that the destination wouldn't clobber some allocated pages.
+ const size_t dest_overhead = JOVE_REGION_OVERHEAD(pages);
+ for(size_t i = 0; i < dest_overhead; i++) {
+ if(bitmap_check(&source->bitmap, source->bitmap.total_bits - pages + i)) {
+ release_mutex(&source->lock);
+ return -EFULL;
+ }
+ }
+
+ //Create and zero-fill new region.
+ const physaddr_t dest_base = source_base + (pages * 0x1000);
+ jove_region_t *dest = phys_tovirt(dest_base);
+ memset(dest, 0, sizeof(jove_region_t));
+ take_mutex(&dest->lock);
+
+ //Link region to after source region.
+ dest->prev = source;
+ dest->next = source->next;
+ if(dest->next) dest->next->prev = dest;
+
+ //Populate destination bitmap.
+ dest->bitmap.total_bits = pages;
+ const size_t dest_blocks = pages / BITMAP_BLOCK_BITS;
+ const size_t source_blocks = source->bitmap.total_bits / BITMAP_BLOCK_BITS;
+ memcpy(dest->bitmap.data, &source->bitmap.data[source_blocks - dest_blocks], dest_blocks);
+ memset(&source->bitmap.data[source_blocks - dest_blocks], 0, dest_blocks);
+
+ //Count free pages per block.
+ for(size_t i = 0; i < dest_blocks; i++) {
+ const bitmap_block_t dest_block = dest->bitmap.data[i];
+ for(bitmap_block_t bit = 0; bit < BITMAP_BLOCK_BITS; bit++) {
+ source->bitmap.free_bits--;
+ if(dest_block & (1U << bit)) continue;
+ dest->bitmap.free_bits++;
+ }
+ }
+
+ //Mark the overhead pages in the dest as taken.
+ for(size_t i = 0; i < dest_overhead; i++) {
+ bitmap_set(&dest->bitmap, i);
+ }
+
+ obj_settype(dest_obj, JOVE_OBJ_REGION);
+ obj_setvalue(dest_obj, dest_base);
+
+ release_mutex(&dest->lock);
+ release_mutex(&source->lock);
+
+ return 0;
+}
+
+int region_release(jove_owned_obj_t *region_obj)
+{
+ jove_region_t *region = region_data(region_obj);
+ if(region->toplevel) return -EPERM;
+
+ //Ensure this region doesn't have any children.
+ if(region->next && !region->next->toplevel)
+ return -EBUSY;
+
+ if(try_take_mutex(&region->lock))
+ return -EBUSY;
+
+ int ret = 0;
+
+ //Ensure that we can change the source mutex.
+ jove_region_t *source_region = region->prev;
+ if(try_take_mutex(&source_region->lock)) {
+ ret = -EBUSY;
+ goto release_region_return;
+ }
+
+ //Mark overhead pages as available.
+ const size_t region_overhead = JOVE_REGION_OVERHEAD(region->bitmap.total_bits);
+ for(size_t i = 0; i < region_overhead; i++) {
+ bitmap_set(&region->bitmap, i);
+ }
+
+ //Copy child bitmap onto source bitmap.
+ const size_t source_blocks = source_region->bitmap.total_bits / BITMAP_BLOCK_BITS;
+ const size_t child_blocks = region->bitmap.total_bits / BITMAP_BLOCK_BITS;
+
+ memcpy(&source_region->bitmap.data[source_blocks - child_blocks], region->bitmap.data, child_blocks);
+ source_region->bitmap.free_bits += region->bitmap.free_bits;
+
+ //Unlink the child region
+ if(region->next) region->next->prev = region->prev;
+ region->prev->next = region->next;
+
+ //Set the region object to JOVE_OBJ_NONE
+ obj_settype(region_obj, JOVE_OBJ_NONE);
+
+ //Release and return.
+ release_mutex(&source_region->lock);
+release_region_return:
+ release_mutex(&region->lock);
+ return ret;
+}
+
+int
+region_alloc(jove_owned_obj_t *region_obj, jove_owned_obj_t *dest_obj)
+{
+ //Ensure exclusive access to the region.
+ jove_region_t *region = region_data(region_obj);
+ if(try_take_mutex(&region->lock)) {
+ return -EBUSY;
+ }
+
+ int ret = 0;
+ //Ensure that the region has free pages.
+ if(region->bitmap.free_bits == 0) {
+ ret = -EFULL;
+ goto release_return;
+ }
+
+ //Ensure that the bitmap can find the free pages.
+ int foundfree = bitmap_findfree(&region->bitmap);
+ if(foundfree < 0) {
+ ret = foundfree;
+ goto release_return;
+ }
+ bitmap_set(&region->bitmap, foundfree);
+
+ //Create new untyped object for the new page frame.
+ obj_settype(dest_obj, JOVE_OBJ_UNTYPED);
+ obj_setvalue(dest_obj, region_base(region_obj) + ((uintmax_t)foundfree * 0x1000));
+
+ jove_untyped_t *untyped = obj_deref(dest_obj);
+ untyped->limit = 0x1000;
+
+release_return:
+ release_mutex(&region->lock);
+ return ret;
+}
+
+int
+region_alloc_contig(jove_owned_obj_t *region_obj, jove_owned_obj_t *dest_obj, size_t pages)
+{
+ kpanic("Region alloc contig stub!\n");
+}
diff --git a/lib/bitmap.c b/lib/bitmap.c
new file mode 100644
index 0000000..bfd6cbc
--- /dev/null
+++ b/lib/bitmap.c
@@ -0,0 +1,51 @@
+#include "bitmap.h"
+#include "api/error.h"
+
+inline bool
+bitmap_check(struct bitmap *bitmap, size_t idx)
+{
+ return bitmap->data[idx / BITMAP_BLOCK_BITS] & (1U << (idx % BITMAP_BLOCK_BITS));
+}
+
+inline void
+bitmap_set(struct bitmap *bitmap, size_t idx)
+{
+ bitmap->data[idx / BITMAP_BLOCK_BITS] |= (1U << (idx % BITMAP_BLOCK_BITS));
+ bitmap->free_bits--;
+}
+
+inline void
+bitmap_unset(struct bitmap *bitmap, size_t idx)
+{
+ bitmap->data[idx / BITMAP_BLOCK_BITS] &= ~(1U << (idx % BITMAP_BLOCK_BITS));
+ bitmap->free_bits++;
+}
+
+int
+bitmap_findfree(struct bitmap *bitmap)
+{
+ int cycles = 0;
+ while(cycles++ < bitmap->total_bits) {
+ if(bitmap_check(bitmap, bitmap->last_free_bit)) {
+ bitmap->last_free_bit = (bitmap->last_free_bit + 1) % bitmap->total_bits;
+ continue;
+ }
+ return bitmap->last_free_bit++;
+ }
+ return -EFULL;
+}
+
+int
+bitmap_findfree_contig(struct bitmap *bitmap, size_t size)
+{
+ size_t last_contig = 0;
+ for(size_t i = 0; i < bitmap->total_bits; i++) {
+ if(bitmap_check(bitmap, i)) {
+ last_contig = i++;
+ continue;
+ }
+ if(last_contig - i == size - 1)
+ return last_contig;
+ }
+ return -EFULL;
+}
diff --git a/lib/bitmap.h b/lib/bitmap.h
new file mode 100644
index 0000000..db9653a
--- /dev/null
+++ b/lib/bitmap.h
@@ -0,0 +1,25 @@
+#ifndef _JOVE_LIB_BITMAP_H
+#define _JOVE_LIB_BITMAP_H 1
+
+#include <stddef.h>
+#include <stdbool.h>
+
+typedef unsigned char bitmap_block_t;
+#define BITMAP_BLOCK_BITS (sizeof(bitmap_block_t) * 8)
+
+struct bitmap
+{
+ unsigned int total_bits;
+ unsigned int free_bits;
+ unsigned int last_free_bit;
+ bitmap_block_t data[];
+};
+
+extern bool bitmap_check(struct bitmap *bitmap, size_t idx);
+extern void bitmap_set(struct bitmap *bitmap, size_t idx);
+extern void bitmap_unset(struct bitmap *bitmap, size_t idx);
+
+int bitmap_findfree(struct bitmap *bitmap);
+int bitmap_findfree_contig(struct bitmap *bitmap, size_t size);
+
+#endif
diff --git a/proc/init.c b/proc/init.c
index 65299f4..4389187 100644
--- a/proc/init.c
+++ b/proc/init.c
@@ -2,32 +2,33 @@
#include "hal/memory.h"
#include "panic/panic.h"
-objpath_part_t s_last_untyped = JOVE_OBJDIR_ENTRIES-1;
+objpath_part_t s_last_region = JOVE_OBJDIR_ENTRIES-1;
jove_owned_obj_t
init_pop_alloc(void)
{
- jove_owned_obj_t *untyped_dir = objdir_trygetlocal(_rootdir_obj, ROOTDIR_UNTYPED_I);
- if(untyped_dir == 0) {
+ jove_owned_obj_t *freemem_dir = objdir_trygetlocal(_rootdir_obj, ROOTDIR_FREEMEMORY_I);
+ if(freemem_dir == 0) {
kpanic("Untyped directory is locked!\n");
}
int cycles = 0;
while(cycles++ < 512) {
- if(objdir_peeklocal(untyped_dir, s_last_untyped).type != JOVE_OBJ_UNTYPED) {
- s_last_untyped--;
+ if(objdir_peeklocal(freemem_dir, s_last_region).type != JOVE_OBJ_REGION) {
+ s_last_region--;
continue;
}
jove_owned_obj_t frame = { 0 };
- jove_owned_obj_t *untyped = objdir_getlocal(untyped_dir, s_last_untyped);
+ jove_owned_obj_t *region = objdir_getlocal(freemem_dir, s_last_region);
- if(untyped_split(untyped, &frame, 0x1000) < 0) {
- kpanic("%s: Failed to split last untyped.\n", __func__);
+ if(region_alloc(region, &frame) < 0) {
+ obj_release(region);
+ continue;
}
- obj_release(untyped);
- obj_release(untyped_dir);
+ obj_release(region);
+ obj_release(freemem_dir);
return frame;
}
kpanic("%s: Kernel is out of memory!\n", __func__);
diff --git a/proc/scheduler.c b/proc/scheduler.c
new file mode 100644
index 0000000..852cfef
--- /dev/null
+++ b/proc/scheduler.c
@@ -0,0 +1,3 @@
+#include "scheduler.h"
+
+
diff --git a/proc/scheduler.h b/proc/scheduler.h
new file mode 100644
index 0000000..6f1b6b2
--- /dev/null
+++ b/proc/scheduler.h
@@ -0,0 +1,6 @@
+#ifndef _JOVE_PROC_SCHEDULER_H
+#define _JOVE_PROC_SCHEDULER_H 1
+
+
+
+#endif
diff --git a/arch/x86_64/lock.c b/sys/lock.c
index a34cee6..095a08e 100644
--- a/arch/x86_64/lock.c
+++ b/sys/lock.c
@@ -14,7 +14,7 @@ take_mutex(atomic_flag *lock)
int
try_take_mutex(atomic_flag *lock)
{
- if(_kernel_panic_unlock) return 1;
+ if(_kernel_panic_unlock) return 0;
return atomic_flag_test_and_set(lock);
}
diff --git a/arch/x86_64/lock.h b/sys/lock.h
index 3592ea1..3592ea1 100644
--- a/arch/x86_64/lock.h
+++ b/sys/lock.h
diff --git a/sys/syscall.c b/sys/syscall.c
index 54d5468..05eeb58 100644
--- a/sys/syscall.c
+++ b/sys/syscall.c
@@ -37,6 +37,7 @@ static const syscall_handle_t s_syscall_handles[128] = {
[JOVE_OBJ_OBJDIR] = _syscall_handle_objdir,
[JOVE_OBJ_PAGEDIR] = _syscall_handle_pagedir,
[JOVE_OBJ_PROCESSOR] = _syscall_handle_generic,
+ [JOVE_OBJ_REGION] = _syscall_handle_region,
[JOVE_OBJ_SHMEMORY] = _syscall_handle_generic,
[JOVE_OBJ_PCB] = _syscall_handle_pcb,
[JOVE_OBJ_INT_HANDLE] = _syscall_handle_generic,
diff --git a/sys/syscall.h b/sys/syscall.h
index 082fe29..6387d79 100644
--- a/sys/syscall.h
+++ b/sys/syscall.h
@@ -57,6 +57,7 @@ int _syscall_handle_vtt(syscall_context_t *ctx);
int _syscall_handle_objdir(syscall_context_t *ctx);
int _syscall_handle_untyped(syscall_context_t *ctx);
int _syscall_handle_pagedir(syscall_context_t *ctx);
+int _syscall_handle_region(syscall_context_t *ctx);
int _syscall_handle_pcb(syscall_context_t *ctx);
int _syscall_handle_initrd_file(syscall_context_t *ctx);
int _syscall_handle_message(syscall_context_t *ctx);
diff --git a/sys/syscall_region.c b/sys/syscall_region.c
new file mode 100644
index 0000000..959d615
--- /dev/null
+++ b/sys/syscall_region.c
@@ -0,0 +1,68 @@
+#include "api/error.h"
+#include "api/syscall.h"
+#include "hal/memory.h"
+#include "lib/printf.h"
+#include "jove.h"
+#include "syscall.h"
+
+static int
+s_syscall_region_alloc(jove_owned_obj_t *region_obj,
+ jove_owned_obj_t *objdir_obj,
+ lockstack_t *lockstack,
+ size_t bytes_left,
+ void *payload_data)
+{
+ size_t bytes_needed = sizeof(struct syscall_region_alloc);
+ CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");
+
+ struct syscall_region_alloc *payload = payload_data;
+ bytes_needed += payload->dest_pathlen * sizeof(objpath_part_t);
+
+ CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for subject path");
+
+ jove_perm_obj_t subject = link_try_traverse_objdir(
+ objdir_obj, lockstack, payload->dest_pathlen, payload->dest_path);
+ CHECK_OBJEXISTS(subject.obj, "Destination path is bad.");
+ CHECK_OBJPERM(subject, SYSCALL_PERM_REGION_ALLOC_TGT, "Destination path does not have correct permissions.");
+ CHECK_OBJTYPE(subject.obj, JOVE_OBJ_NONE, "Destination object is not JOVE_OBJ_NONE");
+
+ int sysret = 0;
+ if(payload->alloc_pages == 1) {
+ sysret = region_alloc(region_obj, subject.obj);
+ }else{
+ sysret = region_alloc_contig(region_obj, subject.obj, payload->alloc_pages);
+ }
+ if(sysret < 0) {
+ klogf("Region alloc failed with reason: %s\n", errstr(-sysret));
+ }
+ return sysret;
+}
+
+int
+_syscall_handle_region(syscall_context_t *ctx)
+{
+ switch(ctx->header->callid) {
+ case SYSCALL_REGION_ADDRESS:
+ if(ctx->target.permissions & SYSCALL_PERM_REGION_GETTERS)
+ return region_base(ctx->target.obj);
+ return -EPERM;
+
+ case SYSCALL_REGION_TOTAL_PAGES:
+ if(ctx->target.permissions & SYSCALL_PERM_REGION_GETTERS)
+ return region_pages(ctx->target.obj);
+ return -EPERM;
+
+ case SYSCALL_REGION_FREE_PAGES:
+ if(ctx->target.permissions & SYSCALL_PERM_REGION_GETTERS)
+ return region_freepages(ctx->target.obj);
+ return -EPERM;
+
+ case SYSCALL_REGION_ALLOC:
+ if(ctx->target.permissions & SYSCALL_PERM_REGION_ALLOC)
+ return s_syscall_region_alloc(ctx->target.obj, ctx->objdir, &ctx->lockstack, ctx->bytes_left, ctx->payload);
+ return -EPERM;
+
+ default:
+ return -EBADCALL;
+ }
+}