From eff64e81c27e591166ffe02709ca21f3529b1744 Mon Sep 17 00:00:00 2001 From: ice-bit Date: Thu, 19 Sep 2019 12:04:12 +0200 Subject: [PATCH] Added alloc function(heap) --- kernel/cpu/assert.c | 31 ++++++++++ kernel/cpu/assert.h | 21 +++++++ kernel/drivers/kheap.c | 104 +++++++++++++++++++++++++++++++++- kernel/drivers/kheap.h | 14 +++++ kernel/drivers/ordered_list.c | 2 +- kernel/drivers/ordered_list.h | 7 +++ kernel/drivers/tty.c | 23 ++++++++ kernel/drivers/tty.h | 1 + 8 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 kernel/cpu/assert.c create mode 100644 kernel/cpu/assert.h diff --git a/kernel/cpu/assert.c b/kernel/cpu/assert.c new file mode 100644 index 0000000..2aff799 --- /dev/null +++ b/kernel/cpu/assert.c @@ -0,0 +1,31 @@ +#include "assert.h" + +// We panic when we find a critical error, this function is called by assert macro +extern void panic(const char *message, const char *file, uint32_t line) { + asm volatile("cli"); // Disable interrupts + + kprint("PANIC("); + kprint(message); + kprint(") at "); + kprint(file); + kprint(":"); + kprint_dec(line); + kprint("\n"); + // Now hang on for ever + for(;;); +} + +// Check for assertion failed, this function call by assert macro +extern void panic_assert(const char *file, uint32_t line, const char *desc) { + asm volatile("cli"); // Disable interrupts + + kprint("ASSERTION-FAILED("); + kprint(desc); + kprint(") at "); + kprint(file); + kprint(":"); + kprint_dec(line); + kprint("\n"); + // Now hang on forever + for(;;); +} \ No newline at end of file diff --git a/kernel/cpu/assert.h b/kernel/cpu/assert.h new file mode 100644 index 0000000..b242f15 --- /dev/null +++ b/kernel/cpu/assert.h @@ -0,0 +1,21 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ +#ifndef ASSERT_H +#define ASSERT_H + +#include +#include "../drivers/tty.h" +// These functions are used for error checking + +#define PANIC(msg) panic(msg, __FILE__, __LINE__); +#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b)) + +extern void panic(const char *message, const char *file, uint32_t line); +extern void panic_assert(const char *file, uint32_t line, const char *desc); + +#endif \ No newline at end of file diff --git a/kernel/drivers/kheap.c b/kernel/drivers/kheap.c index 334718d..58f8bcf 100644 --- a/kernel/drivers/kheap.c +++ b/kernel/drivers/kheap.c @@ -1,5 +1,11 @@ #include "kheap.h" +// Extern variables are declared in the linker script +extern uint32_t end; +uint32_t placement_addr = (uint32_t)&end; +extern page_directory_t *kernel_directory; // FIXME: +heap_t *kheap = 0; + /* The following function is a simple method to find the smallest hole that * fit user space request, since we will do this process many times, it's a good * idea to wrap it in a function */ @@ -78,7 +84,7 @@ static void expand(uint32_t new_size, heap_t *heap) { uint32_t old_size = heap->end_address-heap->start_address; uint32_t i = old_size; while(i < new_size) { - alloc_frame(get_page(heap->start_address+i, 1, kernel_directory), // FIXME: + alloc_frame(get_page(heap->start_address+i, 1, kernel_directory), (heap->supervisor)?1:0, (heap->readonly)?0:1); } } @@ -104,3 +110,99 @@ static uint32_t contract(uint32_t new_size, heap_t *heap) { return new_size; } +void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) { + uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t); + int32_t i = find_smallest_hole(new_size, page_align, heap); + // Error checking for "no hole available" + if(i == -1) { + // Save previous data + uint32_t old_len = heap->end_address - heap->start_address; + uint32_t old_end_addr = heap->end_address; + + // Allocate more space + expand(old_len+new_size, heap); + uint32_t new_len = heap->end_address-heap->start_address; + + i = 0; // Endmost header in location + uint32_t idx = -1; // Endmost header's index + uint32_t value = 0x0; // Endmost header's value + while(i < heap->index.size) { + uint32_t tmp = (uint32_t)lookup_ordered_list(i, &heap->index); + if(tmp > value) { + value = tmp; + idx = i; + } + i++; + } + // In case we did not find any headers, we need to add one + if(idx == -1) { + header_t *head = (header_t*)old_end_addr; + head->magic = HEAP_MAGIC; + head->size = new_len - old_len; + head->is_hole = 1; + footer_t *foot = (footer_t*) (old_end_addr + head->size - sizeof(footer_t)); + foot->magic = HEAP_MAGIC; + foot->header = head; + insert_ordered_list((void*)head, &heap->index); + } else { + header_t *head = lookup_ordered_list(idx, &heap->index); + head->size += new_len - old_len; + // Rewrite the footer + footer_t *foot = (footer_t*) ((uint32_t)head + head->size - sizeof(footer_t)); + foot->header = head; + foot->magic = HEAP_MAGIC; + } + // Now that we have enough space, use recursing to call this function again + return alloc(size, page_align, heap); + } + + header_t *origin_hole_header = (header_t*)lookup_ordered_list(i, &heap->index); + uint32_t origin_hole_p = (uint32_t)origin_hole_header; + uint32_t origin_hole_s = origin_hole_header->size; + // Now check if we should split the hole into two parts + if(origin_hole_s-new_size < sizeof(header_t)+sizeof(header_t)) { + size += origin_hole_s-new_size; + new_size = origin_hole_s; + } + + // Now check if we need page-aligned data + if(page_align && origin_hole_p&0xFFFFF000) { + uint32_t new_location = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t); + header_t *hole_header = (header_t*)origin_hole_p; + hole_header -= 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t); + hole_header->magic = HEAP_MAGIC; + hole_header->is_hole = 1; + footer_t *hole_footer = (footer_t*) ((uint32_t)new_location - sizeof(footer_t)); + hole_footer->magic = HEAP_MAGIC; + hole_footer->header = hole_header; + origin_hole_p = new_location; + origin_hole_s = origin_hole_s - hole_header->size; + } else // Otherwise delete this hole from the index since we don't need it anymore + remove_ordered_list(i, &heap->index); + + // Since we're creating a new hole at the old hole's address we can reuse the old hole + header_t *block_header = (header_t*)origin_hole_p; + block_header->magic = HEAP_MAGIC; + block_header->is_hole = 0; + block_header->size = new_size; + // Now overwrite original footer + footer_t *block_footer = (footer_t*)(origin_hole_p + sizeof(header_t) + size); + block_footer->magic = HEAP_MAGIC; + block_footer->header = block_header; + + // If the new block have positive size, then write a new hole after new block + if(origin_hole_s - new_size > 0) { + header_t *hole_head = (header_t*)(origin_hole_p * sizeof(header_t) + size + sizeof(footer_t)); + hole_head->magic = HEAP_MAGIC; + hole_head->is_hole = 1; + hole_head->size = origin_hole_s - (new_size); + footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t)); + if((uint32_t)hole_foot < heap->end_address) { + hole_foot->magic = HEAP_MAGIC; + hole_foot->header = hole_head; + } + insert_ordered_list((void*)hole_head, &heap->index); + } + // Finally, return the new hole + return (void*)(uint32_t)block_header+sizeof(header_t)); +} \ No newline at end of file diff --git a/kernel/drivers/kheap.h b/kernel/drivers/kheap.h index ce79ce8..b0acf2b 100644 --- a/kernel/drivers/kheap.h +++ b/kernel/drivers/kheap.h @@ -1,3 +1,17 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ + + +/*** Heap implementation from James Molloy's tutorial: + * http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/ + + + /* This heap algorithm uses two different data structures: blocks and holes. * Blocks: Contiguous areas of memory containing user data * Holes: Special kind of blocks that are not in use, this is the result diff --git a/kernel/drivers/ordered_list.c b/kernel/drivers/ordered_list.c index 4288698..0f6afa4 100644 --- a/kernel/drivers/ordered_list.c +++ b/kernel/drivers/ordered_list.c @@ -34,7 +34,7 @@ void destroy_ordered_list(ordered_list_t *array) { // Insert item into the array void insert_ordered_list(type_t item, ordered_list_t *array) { - ASSERT(array->less_then); // TODO: implement assert + ASSERT(array->less_then); uint32_t iterator = 0; while(iterator < array->size && array->less_then(array->array[iterator], item)) iterator++; diff --git a/kernel/drivers/ordered_list.h b/kernel/drivers/ordered_list.h index 2b7668e..72169a2 100644 --- a/kernel/drivers/ordered_list.h +++ b/kernel/drivers/ordered_list.h @@ -1,3 +1,10 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ #ifndef ORDERED_LIST #define ORDERED_LIST diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c index 144e47b..f671e8f 100644 --- a/kernel/drivers/tty.c +++ b/kernel/drivers/tty.c @@ -69,6 +69,29 @@ void kprint(uint8_t *buf) { kprint_c(buf, strlen(buf), WHITE, BLACK); } +void kprint_dec(uint32_t num) { + if(num == 0) { + const uint8_t buf = (uint8_t)'0'; + kprint_c(buf, strlen(buf), WHITE, BLACK);; + return; + } + int32_t acc = num; + uint8_t c[32]; + uint32_t i = 0; + while(acc > 0) { + c[i] = '0' + acc%10; + acc /= 10; + i++; + } + c[i] = 0; + uint8_t c2[32]; + c2[i--] = 0; + uint32_t j = 0; + while(i >= 0) + c2[i--] = c[j++]; + kprint(c2); +} + void init_prompt() { uint8_t *prompt = (uint8_t*)"\nring0@iceOS-$ "; kprint_c(prompt, strlen(prompt), LIGHT_RED, BLACK); diff --git a/kernel/drivers/tty.h b/kernel/drivers/tty.h index 36550a9..67cb7e2 100644 --- a/kernel/drivers/tty.h +++ b/kernel/drivers/tty.h @@ -53,6 +53,7 @@ void cursor_adv(); void backspace(); void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg); void kprint(uint8_t *buf); +void kprint_dec(uint32_t num); void init_prompt(); void clear_prompt(); void clear_row(uint8_t row);