From 3315d85e0c063a6f67e09eb26d8bf0df6e66fdb4 Mon Sep 17 00:00:00 2001 From: 0x35c Date: Tue, 19 Nov 2024 16:57:19 +0100 Subject: [PATCH] wip: frame_allocator working pretty good (?) core: remove physical allocatory --- headers/memory.h | 20 ++++- src/kernel.c | 6 +- src/memory/frame.c | 44 ++++++---- src/memory/memory.c | 11 ++- src/memory/page.c | 7 +- src/memory/page_table.c | 2 +- src/memory/phys/allocator.c | 65 --------------- src/memory/phys/info.c | 50 ----------- src/memory/phys/kfree.c | 116 -------------------------- src/memory/phys/kmalloc.c | 152 ---------------------------------- src/memory/phys/krealloc.c | 37 --------- src/memory/phys/ksize.c | 9 -- src/memory/virt/vrealloc.c | 2 +- src/shell/commands/heap_cmd.c | 11 +-- 14 files changed, 61 insertions(+), 471 deletions(-) delete mode 100644 src/memory/phys/allocator.c delete mode 100644 src/memory/phys/info.c delete mode 100644 src/memory/phys/kfree.c delete mode 100644 src/memory/phys/kmalloc.c delete mode 100644 src/memory/phys/krealloc.c delete mode 100644 src/memory/phys/ksize.c diff --git a/headers/memory.h b/headers/memory.h index 7667cbe..635dcf7 100644 --- a/headers/memory.h +++ b/headers/memory.h @@ -21,9 +21,25 @@ #define GET_PAGE_ADDR(pd_index, pt_index) \ ((((uint32_t)pd_index * 1024) + (uint32_t)pt_index) * 4096) +#define GET_FRAME(frame_table, i) (frame_table[i / 8] & (1 << (i % 8))) +#define SET_FRAME(frame_table, i, used) \ + do { \ + if (used) \ + frame_table[i / 8] |= (1 << (i % 8)); \ + else \ + frame_table[i / 8] &= ~(1 << (i % 8)); \ + } while (0) + +/* + * len is the total size of the zone (ratio starnakin) + * size is the remaining usable size after allocating + * the struct for the linked list + */ struct frame_zone { void *addr; + uint32_t first_free_frame; uint32_t *frame_table; + uint32_t len; uint32_t size; uint32_t remaining_frames; struct frame_zone *next; @@ -40,8 +56,8 @@ extern struct frame_zone *head; uint32_t *virt_to_phys(uint32_t *virt_addr); void init_memory(multiboot_info_t *mbd, uint32_t magic); -void *alloc_frames(size_t size); -int free_frames(void *frame_ptr, size_t size); +void *alloc_frame(void); +int free_frame(void *frame_ptr); void *alloc_pages(size_t size); int free_pages(void *page_ptr, size_t size); void init_page_table(uint32_t page_table[1024], uint16_t start); diff --git a/src/kernel.c b/src/kernel.c index 4e4214b..c637694 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -66,9 +66,9 @@ void kernel_main(multiboot_info_t *mbd, uint32_t magic) "I see no way to confuse an array of 256 seg:off pairs with a " "complex 8*unknown quantity -byte descriptor table. -- Troy " "Martin 03:50, 22 March 2009 (UTC)\n"); - alloc_frames(1); + /* alloc_frame(); */ /* vmalloc(10); */ - /* while (vmalloc(10)) */ - /* ; */ + while (vmalloc(10)) + ; shell_init(); } diff --git a/src/memory/frame.c b/src/memory/frame.c index bc7de8f..05aec19 100644 --- a/src/memory/frame.c +++ b/src/memory/frame.c @@ -8,28 +8,36 @@ #include "string.h" #include "utils.h" -void *alloc_frames(size_t size) +void *alloc_frame(void) { - const uint32_t nb_frames = CEIL(size, PAGE_SIZE); - for (uint32_t i = 0; i < mmap_length; i++) { - multiboot_memory_map_t *mmmt = - (multiboot_memory_map_t *)mmap_addr + i; - if (mmmt->type == MULTIBOOT_MEMORY_AVAILABLE) { - kprintf("type: %d, addr: %p, len: %u, size: %u, \n", - mmmt->type, mmmt->addr, mmmt->len, mmmt->size); - } - PRINT_PTR(mmmt); + struct frame_zone *it = head; + while (it && !it->remaining_frames) + it = it->next; + if (it->remaining_frames == 0) { + kprintf(KERN_CRIT "No memory zone available (ratio)\n"); + return NULL; } - PRINT_PTR(head); - PRINT_PTR(head->addr); - PRINT_PTR(head->frame_table); - PRINT_UINT(head->size); - PRINT_UINT(head->remaining_frames); - PRINT_PTR(head->next); - return NULL; + + size_t i = it->first_free_frame; + for (; GET_FRAME(it->frame_table, i); i++) + ; + it->first_free_frame++; + it->remaining_frames--; + SET_FRAME(it->frame_table, i, 1); + return it->addr + i * PAGE_SIZE; } -int free_frames(void *frame_ptr, size_t size) +int free_frame(void *frame_ptr) { + struct frame_zone *it = head; + while (it && (frame_ptr < it->addr || frame_ptr >= it->addr + it->len)) + it = it->next; + + uint32_t index = + (frame_ptr + (it->len - it->size) - it->addr) / PAGE_SIZE; + SET_FRAME(it->frame_table, index, 0); + if (it->first_free_frame > index) + it->first_free_frame = index; + it->remaining_frames++; return 0; } diff --git a/src/memory/memory.c b/src/memory/memory.c index 4522a30..2570cb4 100644 --- a/src/memory/memory.c +++ b/src/memory/memory.c @@ -53,10 +53,11 @@ static void add_frame_node(multiboot_memory_map_t *mmmt) init_page_table(frame_zones_page_table, 0); page_directory[1022] = ((uint32_t)frame_zones_page_table - HEAP_END) | 0x03; - frame_zones_page_table[index++] = + frame_zones_page_table[index] = ((uint32_t)zone & PAGE_MASK) | INIT_FLAGS; + struct frame_zone *current = - (struct frame_zone *)GET_PAGE_ADDR(1022, 0); + (struct frame_zone *)GET_PAGE_ADDR(1022, index++); memset(current, 0, sizeof(struct frame_zone)); current->addr = (void *)mmmt->addr; current->frame_table = (uint32_t *)current + sizeof(struct frame_zone); @@ -68,16 +69,18 @@ static void add_frame_node(multiboot_memory_map_t *mmmt) frame_zones_page_table[index] = ((uint32_t)zone + PAGE_SIZE & PAGE_MASK) | INIT_FLAGS; // glhf reading this bozo + current->len = mmmt->len; current->size = (mmmt->len - (sizeof(struct frame_zone) + (mmmt->len / PAGE_SIZE) / 32)); current->remaining_frames = current->size / PAGE_SIZE; + current->first_free_frame = 0; current->next = NULL; - struct frame_zone *it = head; - if (!it) { + if (!head) { head = current; return; } + struct frame_zone *it = head; while (it->next) it = it->next; it->next = current; diff --git a/src/memory/page.c b/src/memory/page.c index fc5f261..6e38ffa 100644 --- a/src/memory/page.c +++ b/src/memory/page.c @@ -46,11 +46,10 @@ void *alloc_pages(size_t size) return NULL; } for (size_t i = index; i - (size_t)index < nb_pages; i++) { - void *frame = alloc_frames(PAGE_SIZE); + void *frame = alloc_frame(); if (!frame) { for (size_t j = index; j < i; j++) - free_frames((void *)(page_table[j] >> 12), - PAGE_SIZE); + free_frame((void *)(page_table[j] >> 12)); return NULL; } page_table[i] = ((uint32_t)frame & PAGE_MASK) | INIT_FLAGS; @@ -83,7 +82,7 @@ int free_pages(void *page_ptr, size_t size) kprintf(KERN_WARNING "Page already free\n"); return -2; } - free_frames((void *)(page_table[i] & PAGE_MASK), PAGE_SIZE); + free_frame((void *)(page_table[i] & PAGE_MASK)); page_table[i] = i << 12; } diff --git a/src/memory/page_table.c b/src/memory/page_table.c index bc23224..0e574c0 100644 --- a/src/memory/page_table.c +++ b/src/memory/page_table.c @@ -9,7 +9,7 @@ void init_page_table(uint32_t page_table[1024], uint16_t start) int16_t add_page_table(uint16_t pd_index) { - void *frame = alloc_frames(PAGE_SIZE); + void *frame = alloc_frame(); if (!frame) return -1; page_table_default[PT_START + pd_index] = diff --git a/src/memory/phys/allocator.c b/src/memory/phys/allocator.c deleted file mode 100644 index b03dd0b..0000000 --- a/src/memory/phys/allocator.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "alloc.h" -#include "kprintf.h" -#include "memory.h" -#include - -Zone *kzones[3]; - -static void add_zone(Zone *zone, block_type_t type) -{ - // We put the zone at the beginning of the list - if (kzones[type]) { - zone->next = kzones[type]; - kzones[type]->prev = zone; - } - kzones[type] = zone; -} - -static void new_block(Zone *zone, uint32_t zone_size) -{ - Block *new_block = (Block *)align_mem((uint32_t)zone + sizeof(Zone)); - - // Metadata - new_block->in_use = false; - new_block->size = zone_size - sizeof(Zone) - sizeof(Block); - new_block->sub_size = new_block->size; - new_block->ptr = (Block *)((uint32_t)new_block + sizeof(Block)); - new_block->zone = zone; - - // Init future linked lists - new_block->prev = NULL; - new_block->prev_free = NULL; - new_block->prev_used = NULL; - new_block->next = NULL; - new_block->next_free = NULL; - new_block->next_used = NULL; - - if (zone->free) { - zone->free->prev = new_block; - zone->free->prev_free = new_block; - new_block->next = zone->free; - new_block->next_free = zone->free; - } - zone->free = new_block; -} - -int new_kzone(block_type_t type, uint32_t size) -{ - void *heap = alloc_frames(size); - if (heap == NULL) { - kprintf(KERN_ERR "error: alloc_frames failed\n"); - return (-1); - } - - Zone *zone = (Zone *)heap; - zone->type = type; - zone->size = size; - zone->used = NULL; - zone->next = NULL; - zone->prev = NULL; - - new_block(zone, size); - add_zone(heap, type); - - return (0); -} diff --git a/src/memory/phys/info.c b/src/memory/phys/info.c deleted file mode 100644 index ab817c3..0000000 --- a/src/memory/phys/info.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "alloc.h" -#include "kprintf.h" -#include - -// FULL_INFO is to display (or not) both used and unused blocks -#define FULL_INFO 1 - -void show_kalloc_mem(void) -{ - char *const kzones_name[3] = {"TINY", "SMALL", "LARGE"}; - uint32_t total_size = 0; - - for (block_type_t type = 0; type < 3; ++type) { - int count = 0; - for (Zone *zone_it = kzones[type]; zone_it != NULL; - zone_it = zone_it->next) { -#if FULL_INFO - if (zone_it->free) - kprintf("---------- AVAILABLE %s [n°%d - %p] " - "----------\n", - kzones_name[type], count, zone_it); - for (Block *block_it = zone_it->free; block_it != NULL; - block_it = block_it->next_free) { - kprintf("%p - %p : %u bytes\n", block_it->ptr, - (uint32_t)block_it->ptr + - block_it->sub_size + sizeof(Block), - block_it->sub_size); - } - if (zone_it->free) - kprintf("\n"); -#endif - if (zone_it->used) - kprintf("---------- IN_USE %s [n°%d - %p] " - "----------\n", - kzones_name[type], count, zone_it); - for (Block *block_it = zone_it->used; block_it != NULL; - block_it = block_it->next_used) { - kprintf("%p - %p : %u bytes\n", block_it->ptr, - (uint32_t)block_it->ptr + - block_it->sub_size + sizeof(Block), - block_it->sub_size); - total_size += block_it->sub_size; - } - if (zone_it->used) - kprintf("\n"); - count++; - } - } - kprintf("Total: %u\n", total_size); -} diff --git a/src/memory/phys/kfree.c b/src/memory/phys/kfree.c deleted file mode 100644 index 9645baf..0000000 --- a/src/memory/phys/kfree.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "alloc.h" -#include "kprintf.h" -#include "memory.h" -#include - -static void remove_used(Block *to_free) -{ - Block *left = to_free->prev_used; - Block *right = to_free->next_used; - - to_free->next_used = NULL; - to_free->prev_used = NULL; - - if (!left && !right) { - to_free->zone->used = NULL; - return; - } - if (!left) - to_free->zone->used = right; - else - left->next_used = right; - if (right) - right->prev_used = left; -} - -/* - * If all the blocks of the zone have been kfreed, - * we can unmap the zone and delete it from the list of kzones - */ -static int unmap_zone(Zone *zone) -{ - int err = 0; - block_type_t type = zone->type; - Zone *left = zone->prev; - Zone *right = zone->next; - zone->prev = NULL; - zone->next = NULL; - - if (!left && !right) { - kzones[type] = NULL; - goto unmap; - } - if (!left) - kzones[type] = right; - else - left->next = right; - if (right) - right->prev = left; -unmap: - err = free_frames((void *)zone, zone->size); - if (err) - kprintf(KERN_ERR "error: munmap failed\n"); - return (err); -} - -/* - * If the newly kfreed block is next to another previously - * kfreed block, merge both of these and update the size - */ -static Block *merge_blocks(Block *left, Block *right) -{ - if (right->next) - right->next->prev = left; - if (right->next_free) { - right->next_free->prev_free = left; - left->next_free = right->next_free; - } - left->next = right->next; - left->size += right->size + sizeof(Block); - return (left); -} - -// Simply add the new block to the list of available blocks -static int add_available(Block *available, Block *merged) -{ - Zone *zone = available->zone; - if (merged != zone->free && available != zone->free) - available->next_free = zone->free; - if (zone->free) - zone->free->prev_free = available; - zone->free = available; - if (zone->type == LARGE) - return (unmap_zone(zone)); - return (0); -} - -/* - * ptr: pointer to kfree, if the pointer is invalid the kfree() - * function will have an undefined behavior (most likely segfault) - * - * First, we remove the block from the list of in_use blocks - * Then, we check if the block needs to be merged with another - * neighboring block, if so we replace the previous block by the - * newly merged block - * Finally, we add the block to the list of available blocks - */ -void kfree(void *ptr) -{ - if (ptr == NULL) - return; - Block *to_free = (Block *)((uint32_t)ptr - sizeof(Block)); - Block *to_merge = NULL; - to_free->in_use = false; - remove_used(to_free); - if (to_free->prev && !to_free->prev->in_use) { - to_merge = to_free; - to_free = merge_blocks(to_free->prev, to_free); - } - if (to_free->next && !to_free->next->in_use) { - to_merge = to_free->next; - to_free = merge_blocks(to_free, to_free->next); - } - int err = add_available(to_free, to_merge); - if (err) - kprintf(KERN_ERR "kfree: fatal error\n"); -} diff --git a/src/memory/phys/kmalloc.c b/src/memory/phys/kmalloc.c deleted file mode 100644 index f933807..0000000 --- a/src/memory/phys/kmalloc.c +++ /dev/null @@ -1,152 +0,0 @@ -#include "alloc.h" -#include "debug.h" -#include "kprintf.h" -#include - -/* - * Find first available (not in_use) block - * in a zone matching the size we need - */ -static Block *find_block(Zone *head, uint32_t size) -{ - for (Zone *zone_it = head; zone_it != NULL; zone_it = zone_it->next) { - for (Block *block_it = zone_it->free; block_it != NULL; - block_it = block_it->next_free) { - assert(!block_it->in_use); - if (size <= block_it->size) { - assert(block_it->zone == zone_it); - return (block_it); - } - } - } - return (NULL); -} - -// PARTIALLY DEPRECATED -/* - * This will split the newly allocated block to use - * the remaining bytes for a new block - * This is our linked list of blocks - * ... -> [5] -> [6] -> ... - * After the allocation, this will become - * ... -> [5] -> [new] -> [6] -> ... - * - * For an example of [5].size = 32 and requiring a kmalloc of 10 - * Let's say the metadata takes a size of 2: - * ... -> [metadata][data][remaining size] -> [6] - * ^ ^ ^ - * 2 10 20 - * - * So now our block [new] will become: - * [5] -> [metadata][available data] -> [6] - * ^ ^ - * 2 18 - * We can see that it now has its own metadata and available - * data and it points towards [6] - */ -static void frag_block(Zone *zone, Block *old_block, uint32_t size) -{ - Block *new_block = (Block *)align_mem((uint32_t)old_block + size); - assert(!(new_block >= - (Block *)((uint32_t)zone + get_zone_size(zone->type)))); - - // Newly created block metadata - new_block->size = old_block->size - size; - new_block->sub_size = new_block->size; - new_block->in_use = false; - new_block->ptr = (void *)((uint32_t)new_block + sizeof(Block)); - new_block->zone = zone; - - new_block->prev = old_block; - new_block->next = old_block->next; - old_block->next = new_block; - - new_block->prev_used = NULL; - new_block->next_used = NULL; - - new_block->prev_free = old_block->prev_free; - new_block->next_free = old_block->next_free; - - if (zone->free == old_block) - zone->free = new_block; - - old_block->next_free = NULL; - old_block->prev_free = NULL; - - // Newly in_use block metadata - old_block->in_use = true; - old_block->size = size - sizeof(Block); - old_block->sub_size = old_block->size; - - if (zone->used == NULL) { - zone->used = old_block; - return; - } - old_block->prev_used = NULL; - old_block->next_used = zone->used; - zone->used->prev_used = old_block; - zone->used = old_block; -} - -// Set the block to use and unset free -static void save_block(Zone *head, Block *block, Zone *zone) -{ - zone->free = NULL; - block->in_use = true; - if (head->used) { - head->used->prev_used = block; - head->used->prev = block; - block->next = head->used; - block->next_used = head->used; - } - head->used = block; -} - -/* - * size: size needed by the user to get allocated - * - * First, we init the allocator if it's the first time - * Then we search if there is an available block in all - * the kzones currently mapped - * If no block has been found (NULL), we create 1 new zone of - * the corresponding type - * We then search again for an available block (should not be NULL) - * Finally, if type == LARGE, we just have to change the block to used - * else, we frag the block to use just what's needed - * - * ptr: returns the aligned pointer of the block (after the metadata) - */ -void *kmalloc(uint32_t size) -{ - void *ptr = NULL; - - if (size == 0) { - kprintf(KERN_WARNING "kmalloc: can't kmalloc(0)\n"); - return NULL; - } - - // Find the zone we need to search - block_type_t type = get_type(size); - Zone *head = kzones[type]; - - // Find an available block in a zone of type "type" - Block *available = find_block(head, size); - if (available == NULL) { - uint32_t full_size; - if (type == LARGE) - full_size = size + sizeof(Block) + sizeof(Zone); - else - full_size = get_zone_size(type); - if (new_kzone(type, full_size) == -1) - return NULL; - head = kzones[type]; - available = find_block(head, size); - } - assert(available != NULL); - if (type == LARGE) - save_block(head, available, available->zone); - else - frag_block(available->zone, available, size + sizeof(Block)); - ptr = available->ptr; - return ptr; -} diff --git a/src/memory/phys/krealloc.c b/src/memory/phys/krealloc.c deleted file mode 100644 index 647de68..0000000 --- a/src/memory/phys/krealloc.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "alloc.h" -#include "string.h" -#include - -// Prototype for kfree and kmalloc -void kfree(void *ptr); -void *kmalloc(uint32_t size); - -/* - * ptr: block to resize (undefined behavior if invalid) - * size: size needed by the user to get kreallocated - * - * If we have a size <= to the previous size, we don't have - * to do anything, we just change sub_size for info purposes - * and return the same pointer - * Else, we allocate a new block and copy the content of - * the previous block in the new one and kfree the old block - * - * ptr: returns the aligned pointer of the kreallocated block - */ -void *krealloc(void *ptr, uint32_t size) -{ - void *new_ptr = NULL; - if (ptr == NULL) - return NULL; - Block *block = (Block *)((uint32_t)ptr - sizeof(Block)); - if (block->size >= size) { - block->sub_size = size; - return (ptr); - } - new_ptr = kmalloc(size); - if (new_ptr == NULL) - return NULL; - memmove(new_ptr, ptr, block->size); - kfree(ptr); - return (new_ptr); -} diff --git a/src/memory/phys/ksize.c b/src/memory/phys/ksize.c deleted file mode 100644 index 952d993..0000000 --- a/src/memory/phys/ksize.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "alloc.h" -#include - -uint32_t ksize(void *ptr) -{ - Block *meta_data = (Block *)((uint32_t)ptr - sizeof(Block)); - - return meta_data->sub_size; -} diff --git a/src/memory/virt/vrealloc.c b/src/memory/virt/vrealloc.c index 61247fd..026115d 100644 --- a/src/memory/virt/vrealloc.c +++ b/src/memory/virt/vrealloc.c @@ -32,6 +32,6 @@ void *vrealloc(void *ptr, uint32_t size) if (new_ptr == NULL) return NULL; memmove(new_ptr, ptr, block->size); - kfree(ptr); + vfree(ptr); return (new_ptr); } diff --git a/src/shell/commands/heap_cmd.c b/src/shell/commands/heap_cmd.c index 05b10b2..14a7c61 100644 --- a/src/shell/commands/heap_cmd.c +++ b/src/shell/commands/heap_cmd.c @@ -4,13 +4,6 @@ void heap_cmd(char *arg) { - if (!arg) - kprintf(KERN_INFO "You must specify an argument (phys/virt)\n"); - else if (!strcmp(arg, "phys")) - show_kalloc_mem(); - else if (!strcmp(arg, "virt")) - show_valloc_mem(); - else - kprintf(KERN_INFO "%s: invalid argument to heap (phys/virt)\n", - arg); + (void)arg; + show_valloc_mem(); }