diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-07 17:37:26 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-07 17:37:26 -0400 |
| commit | 434ddcd907832b1febc7d70e4faa52109c7eb3bd (patch) | |
| tree | 00c1ade91f9806d831f10e6006732b294e73f613 | |
| parent | 8d48bbd9746228b63bafa5f92b621998d7d8f3d3 (diff) | |
| download | jove-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.h | 2 | ||||
| -rw-r--r-- | api/obj.h | 3 | ||||
| -rw-r--r-- | api/syscall.h | 43 | ||||
| -rw-r--r-- | arch/x86_64/hal/obj.c | 2 | ||||
| -rw-r--r-- | arch/x86_64/hal/paging.c | 8 | ||||
| -rw-r--r-- | arch/x86_64/main.c | 3 | ||||
| -rw-r--r-- | boot/limine/memorymap.c | 28 | ||||
| -rw-r--r-- | doc/memory.md | 87 | ||||
| -rw-r--r-- | hal/memory.h | 55 | ||||
| -rw-r--r-- | hal/region.c | 263 | ||||
| -rw-r--r-- | lib/bitmap.c | 51 | ||||
| -rw-r--r-- | lib/bitmap.h | 25 | ||||
| -rw-r--r-- | proc/init.c | 21 | ||||
| -rw-r--r-- | proc/scheduler.c | 3 | ||||
| -rw-r--r-- | proc/scheduler.h | 6 | ||||
| -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.c | 1 | ||||
| -rw-r--r-- | sys/syscall.h | 1 | ||||
| -rw-r--r-- | sys/syscall_region.c | 68 |
20 files changed, 629 insertions, 43 deletions
@@ -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, @@ -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(®ion->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(®ion->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(®ion->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(®ion->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(®ion->bitmap); + if(foundfree < 0) { + ret = foundfree; + goto release_return; + } + bitmap_set(®ion->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(®ion->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; + } +} |
