From 3e0e8043d5397594461aa9f0a09134390567aa27 Mon Sep 17 00:00:00 2001 From: ice-bit Date: Thu, 26 Sep 2019 17:45:46 +0200 Subject: [PATCH] Trying to fix kheap... --- Makefile | 6 +- kernel/cpu/Makefile | 10 +- kernel/drivers/Makefile | 2 +- kernel/drivers/kheap.c | 320 -------------------------------- kernel/drivers/ordered_list.c | 72 ------- kernel/drivers/ordered_list.h | 40 ---- kernel/drivers/paging.c | 168 ----------------- kernel/drivers/paging.h | 68 ------- kernel/kernel_main.c | 6 +- kernel/libc/Makefile | 2 +- kernel/{cpu => libc}/assert.c | 0 kernel/{cpu => libc}/assert.h | 0 kernel/mem/Makefile | 9 + kernel/mem/kheap.c | 0 kernel/{drivers => mem}/kheap.h | 37 ++-- kernel/mem/ordered_array.c | 66 +++++++ kernel/mem/ordered_array.h | 39 ++++ kernel/mem/paging.c | 159 ++++++++++++++++ kernel/mem/paging.h | 80 ++++++++ 19 files changed, 383 insertions(+), 701 deletions(-) delete mode 100644 kernel/drivers/kheap.c delete mode 100644 kernel/drivers/ordered_list.c delete mode 100644 kernel/drivers/ordered_list.h delete mode 100644 kernel/drivers/paging.c delete mode 100644 kernel/drivers/paging.h rename kernel/{cpu => libc}/assert.c (100%) rename kernel/{cpu => libc}/assert.h (100%) create mode 100644 kernel/mem/Makefile create mode 100644 kernel/mem/kheap.c rename kernel/{drivers => mem}/kheap.h (74%) create mode 100644 kernel/mem/ordered_array.c create mode 100644 kernel/mem/ordered_array.h create mode 100644 kernel/mem/paging.c create mode 100644 kernel/mem/paging.h diff --git a/Makefile b/Makefile index 949cada..47d09f8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ LD = i686-elf-ld LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld -all: prepare cpu kernel_code drivers libc shell link iso +all: prepare cpu kernel_code drivers libc shell mem link iso prepare: mkdir -p obj/ @@ -28,6 +28,10 @@ shell: make -C kernel/shell cp kernel/shell/*.o obj/ +mem: + make -C kernel/mem + cp kernel/mem/*.o obj/ + link: $(LD) $(LFLAGS) -o isodir/boot/iceOS.bin obj/*.o diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile index 3217e17..c563e23 100644 --- a/kernel/cpu/Makefile +++ b/kernel/cpu/Makefile @@ -1,14 +1,8 @@ OBJS = multiboot.asm.o kernel_loader.asm.o ports.asm.o \ - gdt.asm.o idt.asm.o interrupts.asm.o assert.o + gdt.asm.o idt.asm.o interrupts.asm.o ASM = nasm ASMFLAGS = -f elf -CC = i686-elf-gcc # cross-compiler -CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c - all: $(OBJS) %.asm.o: %.asm - $(ASM) $(ASMFLAGS) $< -o $@ - -%.o: %.c - $(CC) $(CFLAGS) $< -o $@ \ No newline at end of file + $(ASM) $(ASMFLAGS) $< -o $@ \ No newline at end of file diff --git a/kernel/drivers/Makefile b/kernel/drivers/Makefile index a1284c4..622502f 100644 --- a/kernel/drivers/Makefile +++ b/kernel/drivers/Makefile @@ -1,5 +1,5 @@ OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \ - fs.o ordered_list.o kheap.o paging.o + fs.o CC = i686-elf-gcc # cross-compiler CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c diff --git a/kernel/drivers/kheap.c b/kernel/drivers/kheap.c deleted file mode 100644 index 64b055a..0000000 --- a/kernel/drivers/kheap.c +++ /dev/null @@ -1,320 +0,0 @@ -#include "kheap.h" - -// end is declared in the linker script -extern uint32_t end; -extern page_directory_t *kernel_directory; -uint32_t placement_addr = (uint32_t)&end; -heap_t *kheap = 0; - -uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) { - if(kheap != 0) { - void *addr = alloc(sz, (uint8_t)align, kheap); - if(phys != 0) { - page_t *page = get_page((uint32_t)addr, 0, kernel_directory); - *phys = (page->frame*0x1000 + (uint32_t)addr)&0xFFF; - } - return (uint32_t)addr; - } else { - if(align == 1 && (placement_addr & 0xFFFFF000)) { - // Align - placement_addr &= 0xFFFFF000; - placement_addr += 0x1000; - } - if(phys) - *phys = placement_addr; - uint32_t tmp = placement_addr; - placement_addr += sz; - return tmp; - } -} - -void kfree(void *p) { - free(p, kheap); -} - -uint32_t kmalloc_a(uint32_t sz) { - return kmalloc_int(sz, 1, 0); -} - -uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) { - return kmalloc_int(sz, 0, phys); -} - -uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) { - return kmalloc_int(sz, 1, phys); -} - -uint32_t kmalloc(uint32_t sz) { - return kmalloc_int(sz, 0, 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 */ -static int32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) { - uint32_t i = 0; - while(i < heap->index.size) { - header_t *header = (header_t*)lookup_ordered_list(i, &heap->index); - if(page_align > 0) { - uint32_t loc = (uint32_t)header; - int32_t offset = 0; - if(((loc+sizeof(header_t)) & 0xFFFFF000) != 0) // Page aligned memory - offset = 0x1000 - (loc+sizeof(header_t))%0x1000; - int32_t hole_size = (int32_t)header->size - offset; - if(hole_size >= (int32_t)size) - break; - } else if(header->size >= size) - break; - i++; - } - // Return something according to the iterator - if(i == heap->index.size) - return -1; // Nothing found - else - return i; -} - -static int8_t header_t_less_than(void *a, void *b) { - return (((header_t*)a)->size < ((header_t*)b)->size)?1:0; -} - -heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly) { - heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t)); - - ASSERT(start%0x1000 == 0); - ASSERT(end%0x1000 == 0); - - // Init heap's index - heap->index = place_ordered_list((void*)start, HEAP_INDEX_SIZE, &header_t_less_than); - - // Shift start address to the corrent position, where we can put on data - start += sizeof(type_t)*HEAP_INDEX_SIZE; - - // Check if start address is page-aligned - if((start & 0xFFFFF000) != 0) { - start &= 0xFFFFF000; - start += 0x1000; - } - - // Fill the heap structure with start, end and max addresses - heap->start_address = start; - heap->end_address = end; - heap->max_address = max; - heap->supervisor = supervisor; - heap->readonly = readonly; - - // Let's create one large hole in the new index - header_t *hole = (header_t*)start; - hole->size = end-start; - hole->magic = HEAP_MAGIC; - hole->is_hole = 1; - insert_ordered_list((void*)hole, &heap->index); - - return heap; -} - -static void expand(uint32_t new_size, heap_t *heap) { - // Before anything else let's check that new size is greater than older one - ASSERT(new_size > heap->end_address - heap->start_address); - if((new_size&0xFFFFF000) != 0) { - new_size &= 0xFFFFF000; - new_size += 0x1000; - } - // Check if new size is not greater than maximum size - ASSERT(heap->start_address+new_size <= heap->max_address); - - 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), - (heap->supervisor)?1:0, (heap->readonly)?0:1); - i += 0x1000; // pAge size - } - heap->end_address = heap->start_address+new_size; -} - -static uint32_t contract(uint32_t new_size, heap_t *heap) { - // This function will be literally the opposite of the previous one - ASSERT(new_size < heap->end_address-heap->start_address); - - if(new_size&0x1000) { - new_size &= 0x1000; - new_size += 0x1000; - } - - if(new_size < HEAP_MIN_SIZE) - new_size = HEAP_MIN_SIZE; - - uint32_t old_size = heap->end_address-heap->start_address; - uint32_t i = old_size - 0x1000; - while(new_size < i) { - free_frame(get_page(heap->start_address+i, 0, kernel_directory)); - i -= 0x1000; - } - heap->end_address = heap->start_address + new_size; - 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); - uint32_t i = find_smallest_hole(new_size, page_align, heap); - // Error checking for "no hole available" - if((int32_t)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((int32_t)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->size -= 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)); -} - -void free(void *p, heap_t *heap) { - // Exit for null pointer - if(p == 0) - return; - - // Retrieve the header and the footer for this pointer - header_t *head = (header_t*) ((uint32_t)p - sizeof(header_t)); - footer_t *foot = (footer_t*) ((uint32_t)head + head->size - sizeof(footer_t)); - - ASSERT(head->magic == HEAP_MAGIC); - ASSERT(foot->magic == HEAP_MAGIC); - - // Set hole flag - head->is_hole = 1; - // Add header to free hole's index. - int8_t add_to_free_hole = 1; - - // If left-most thing is a footer, then perform left unification - footer_t *test_footer = (footer_t*) ((uint32_t)head - sizeof(footer_t)); - if(test_footer->magic == HEAP_MAGIC && - test_footer->header->is_hole == 1) { - uint32_t cache_size = head->size; // Save size - head = test_footer->header; // Change header's size with new one - foot->header = head; // Update header's pointer - head->size += cache_size; - add_to_free_hole = 0; - } - - header_t *test_header = (header_t*) ((uint32_t)foot + sizeof(footer_t)); - if(test_header->magic == HEAP_MAGIC && test_header->is_hole) { - head->size += test_header->size; // Increase size - test_footer = (footer_t*) ((uint32_t)test_header + test_header->size - sizeof(footer_t)); - foot = test_footer; - // remove this header from the index - uint32_t it = 0; - while((it < heap->index.size) && (lookup_ordered_list(it, &heap->index) != (void*)test_header)) - it++; - - // Check if we found the item - ASSERT(it < heap->index.size); - // Then remove it - remove_ordered_list(it, &heap->index); - } - - // Contract footer if it is at end address - if((uint32_t)foot+sizeof(footer_t) == heap->end_address) { - uint32_t old_len = heap->end_address - heap->start_address; - uint32_t new_len = contract((uint32_t)head - heap->start_address, heap); - // Check header size after resizing - if(head->size - (old_len-new_len) > 0) { - head->size -= old_len-new_len; - foot = (footer_t*) ((uint32_t)head + head->size - sizeof(footer_t)); - foot->magic = HEAP_MAGIC; - foot->header = head; - } else { // Remove empty holes, this reduce fragmentation - uint32_t it = 0; - while((it < heap->index.size) && (lookup_ordered_list(it, &heap->index) != (void*)test_header)) - it++; - // If nothing has been found, nothing will be removed - if(it < heap->index.size) - remove_ordered_list(it, &heap->index); - } - } - if(add_to_free_hole == 1) - insert_ordered_list((void*) head, &heap->index); -} \ No newline at end of file diff --git a/kernel/drivers/ordered_list.c b/kernel/drivers/ordered_list.c deleted file mode 100644 index 1cebbfe..0000000 --- a/kernel/drivers/ordered_list.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "ordered_list.h" -#include "kheap.h" -#include "../cpu/assert.h" -#include "../libc/string.h" - -uint8_t standard_lessthan_predicate(type_t a, type_t b) { - if(a < b) - return 1; - return 0; -} - -// Create an ordered list -ordered_list_t create_ordered_list(uint32_t max_size, lessthan_predicate_t less_than) { - ordered_list_t to_ret; - to_ret.array = (void*)kmalloc(max_size*sizeof(type_t)); - memset(to_ret.array, 0, max_size * sizeof(type_t)); - to_ret.size = 0; - to_ret.max_size = max_size; - to_ret.less_then = less_than; - return to_ret; -} - -ordered_list_t place_ordered_list(void *addr, uint32_t max_size, lessthan_predicate_t less_than) { - ordered_list_t to_ret; - to_ret.array = (type_t*)addr; - memset(to_ret.array, 0, max_size * sizeof(type_t)); - to_ret.size = 0; - to_ret.max_size = max_size; - to_ret.less_then = less_than; - return to_ret; -} - -// Destroy an ordered list -void destroy_ordered_list(ordered_list_t *array) { - kfree(array->array); -} - -// Insert item into the array -void insert_ordered_list(type_t item, ordered_list_t *array) { - ASSERT(array->less_then); - uint32_t iterator = 0; - while(iterator < array->size && array->less_then(array->array[iterator], item)) - iterator++; - if(iterator == array->size) - array->array[array->size++] = item; - else { - type_t tmp = array->array[iterator]; - array->array[iterator] = item; - while(iterator < array->size) { - iterator++; - type_t tmp2 = array->array[iterator]; - array->array[iterator] = tmp; - tmp = tmp2; - } - array->size++; - } -} - -// Find item at given index -type_t lookup_ordered_list(uint32_t i, ordered_list_t *array) { - ASSERT(i < array->size); - return array->array[i]; -} - -// Delete item from the array -void remove_ordered_list(uint32_t i, ordered_list_t *array) { - while(i < array->size) { - array->array[i] = array->array[i+1]; - i++; - } - array->size--; -} \ No newline at end of file diff --git a/kernel/drivers/ordered_list.h b/kernel/drivers/ordered_list.h deleted file mode 100644 index 6e6dc90..0000000 --- a/kernel/drivers/ordered_list.h +++ /dev/null @@ -1,40 +0,0 @@ -/************************************** - * iceOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef ORDERED_LIST_H -#define ORDERED_LIST_H - -#include - -/* Our list is always in a 'sorted state', - * it can store anything that can be casted - * to void* */ -typedef void* type_t; -/* The following predicate should return non-zero - * if the first argument is less than the second */ -typedef int8_t (*lessthan_predicate_t)(type_t, type_t); -typedef struct { - type_t *array; - uint32_t size; - uint32_t max_size; - lessthan_predicate_t less_then; -} ordered_list_t; -uint8_t standard_lessthan_predicate(type_t a, type_t b); - -// Create an ordered list -ordered_list_t create_ordered_list(uint32_t max_size, lessthan_predicate_t less_than); -ordered_list_t place_ordered_list(void *addr, uint32_t max_size, lessthan_predicate_t less_than); -// Destroy an ordered list -void destroy_ordered_list(ordered_list_t *array); -// Insert item into the array -void insert_ordered_list(type_t item, ordered_list_t *array); -// Find item at given index -type_t lookup_ordered_list(uint32_t i, ordered_list_t *array); -// Delete item from the array -void remove_ordered_list(uint32_t i, ordered_list_t *array); - -#endif \ No newline at end of file diff --git a/kernel/drivers/paging.c b/kernel/drivers/paging.c deleted file mode 100644 index 84a64f9..0000000 --- a/kernel/drivers/paging.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "paging.h" -#include "kheap.h" -#include "../libc/string.h" - -// Macros for bitset algorithms -#define INDEX_FROM_BIT(a) (a/(8*4)) -#define OFFSET_FROM_BIT(a) (a%(8*4)) - -// Kernel's page directory -page_directory_t *kernel_directory = 0; -// Current page directory -page_directory_t *current_directory = 0; - -// Bitset of frames, used or free -uint32_t *frames; -uint32_t nframes; - -// From kheap.c -extern uint32_t placement_addr; -extern heap_t *kheap; - -// Set a bit in the frame bitset -static void set_frame(uint32_t frame_addr) { - uint32_t frame = frame_addr / 0x1000; - uint32_t idx = INDEX_FROM_BIT(frame); - uint32_t off = OFFSET_FROM_BIT(frame); - frames[idx] |= (0x1 << off); -} - -// clear a bit in the frame bitset -static void clear_frame(uint32_t frame_addr) { - uint32_t frame = frame_addr / 0x1000; - uint32_t idx = INDEX_FROM_BIT(frame); - uint32_t off = OFFSET_FROM_BIT(frame); - frames[idx] &= ~(0x1 << off); -} - -// Find the first free frames -static uint32_t first_frame() { - uint32_t nsections = nframes / FRAME_ALLOCATION_SECTION_SIZE; - for(uint32_t section = 0; section < INDEX_FROM_BIT(nframes); section++) - if(frames[section] != 0xFFFFFFFF) // If nothing is free, exit - for(uint32_t idx = 0; idx < FRAME_ALLOCATION_SECTION_SIZE; idx++) - if (!(frames[idx] & (0x1 << idx))) - return (section * FRAME_ALLOCATION_SECTION_SIZE) + idx; - return nsections * FRAME_ALLOCATION_SECTION_SIZE; -} - -void alloc_frame(page_t *page, int32_t is_supervisored, int32_t is_writeable) { - if(page->frame != 0) - return; // Frame already allocated - else { - uint32_t free_frame = first_frame(); - if(free_frame == (uint32_t)-1) { - PANIC("No free frames found!"); - } else { - // Set free frames to page - page->present = PAGE_PRESENT; - page->rw = (is_writeable) ? PAGE_READ_WRITE : PAGE_READ_ONLY; - page->user = (is_supervisored) ? PAGE_SUPERVISOR : PAGE_USER; - page->frame = free_frame; - - // Set new frames as used - uint32_t physical_address = free_frame * FRAME_SIZE; - set_frame(physical_address); - } - } -} - -void free_frame(page_t *page) { - uint32_t frame; - if(!(frame=page->frame)) - return; - else { - clear_frame(frame); - page->frame = 0x0; - } -} - -void init_paging() { - uint32_t nframes = PHYSICAL_MEMORY_SIZE / FRAME_SIZE; - frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes)); - - // Create a page directory - kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); - memset(frames, 0, INDEX_FROM_BIT(nframes)); - current_directory = kernel_directory; - - /* Map pages in the kernel heap area. - * We only call get_page and not alloc_frame to create a new page_table_t - * only where necessary.*/ - for(int32_t i = KHEAP_START; i < (int32_t)KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000) - get_page(i, 1, kernel_directory); - - /* We have eto identify map from 0x0 to the end of the use memory - * so we can use this memory region as if paging was not enabled. */ - int32_t i = 0; - while(i < (int32_t)placement_addr+0x1000) { - // Kernel code is read only from userspace - alloc_frame(get_page(i, 1, kernel_directory), 0, 0); - i += 0x1000; - } - // Perform the real allocation of what we have done so far - for(i = KHEAP_START; i < (int32_t)KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000) - alloc_frame(get_page(i, 1, kernel_directory), 0, 0); - - // Register a new ISR to handle page faults - register_interrupt_handler(14, page_fault); - - // Enable paging - enable_paging(kernel_directory); - - // Set up kernel heap - kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); -} - -void enable_paging(page_directory_t *dir) { - current_directory = dir; - asm volatile("mov %0, %%cr3" :: "r"(&dir->page_table_physical)); - uint32_t cr0; - asm volatile("mov %%cr0, %0": "=r"(cr0)); - cr0 |= 0x80000000; // code to enable paging - asm volatile("mov %0, %%cr0":: "r"(cr0)); -} - -page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) { - // Turn address into an index - address /= 0x1000; - // Find page table that contains this index - uint32_t table_idx = address / 1024; - if(dir->page_table_virtual[table_idx]) // If current table is already assigned - return &dir->page_table_virtual[table_idx]->pages[address%1024]; - else if(make) { - uint32_t tmp; - dir->page_table_virtual[table_idx] = (page_table_t*)kmalloc_p(sizeof(page_table_t), &tmp); - memset(dir->page_table_virtual[table_idx], 0, 0x1000); - dir->page_table_physical[table_idx] = tmp | 0x7; - return &dir->page_table_virtual[table_idx]->pages[address%1024]; - } else - return 0; -} - -void page_fault(registers_t regs) { - // Retrieve faulted address from CR2 register - uint32_t fault_addr; - asm volatile("mov %%cr2, %0" : "=r"(fault_addr)); - - // Retrieve other infos about the error - int32_t present = !(regs.err_code & 0x1); // Page not present - int32_t rw = regs.err_code & 0x2; // Write operation - int32_t us = regs.err_code & 0x4; // CPU mode(kernel or user mode) - int32_t reserved = regs.err_code & 0x8; - - // Output of those informations - kprint((uint8_t*)"Page fault! ( "); - if(present) - kprint((uint8_t*)"present "); - if(rw) - kprint((uint8_t*)"read-only"); - if(us) - kprint((uint8_t*)"user-mode"); - if(reserved) - kprint((uint8_t*)"reserved"); - kprint((uint8_t*)") at 0x"); - kprint_hex(fault_addr); - kprint((uint8_t*)"\n"); - PANIC("Page fault"); -} \ No newline at end of file diff --git a/kernel/drivers/paging.h b/kernel/drivers/paging.h deleted file mode 100644 index d479bf8..0000000 --- a/kernel/drivers/paging.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef PAGING_H -#define PAGING_H - -#include -#include "isr.h" - -#define FRAME_SIZE 4096 -#define PAGE_TABLE_SIZE 1024 -#define PAGE_DIRECTORY_SIZE 1024 -#define PAGE_NOT_PRESENT 0 -#define PAGE_PRESENT 1 -#define PAGE_READ_ONLY 0 -#define PAGE_READ_WRITE 1 -#define PAGE_USER 0 -#define PAGE_SUPERVISOR 0 -#define PAGE_SIZE_4KB 0 -#define PAGE_SIZE_4MB 1 -#define FRAME_ALLOCATION_SECTION_SIZE 32 -#define USED_FRAME_ALLOCATIONS_SECTION 0xFFFFFFFF -#define FREE_FRAME_ALLOCATIONS_SECTION 0x00000000 - -// Reserve 16 MiB of physical memory -#define PHYSICAL_MEMORY_SIZE 0x10000000 - -struct page { // Page structure from Intel's developer manual - uint8_t present : 1; - uint8_t rw : 1; - uint8_t user : 1; - uint8_t pwt : 1; - uint8_t pcd : 1; - uint8_t a : 1; - uint8_t d : 1; - uint8_t pat : 1; - uint8_t g : 1; - uint8_t unused : 3; - uint32_t frame : 20; -} __attribute__((packed)); -typedef struct page page_t; - -struct page_table { - page_t pages[PAGE_TABLE_SIZE]; -}; -typedef struct page_table page_table_t; - -/* For each page we hold two arrays: - * one is used by the CPU to hold the physical address - * the other is used to hold the virtual address to actual read - * or write to it. */ -struct page_directory { - page_table_t *page_table_virtual[PAGE_DIRECTORY_SIZE]; - uint32_t page_table_physical[PAGE_DIRECTORY_SIZE]; -}; -typedef struct page_directory page_directory_t; - -// Setup the environment -void init_paging(); -// Load specified page directory into CR3 register -void enable_paging(page_directory_t *new); -// Retrieve pointer to specified page address -page_t *get_page(uint32_t addr, int32_t make, page_directory_t *dir); -// Handle page faults -void page_fault(registers_t regs); -// Allocate a new frame -void alloc_frame(page_t *page, int32_t is_supervisored, int32_t is_writeable); -// Deallocate frame -void free_frame(page_t *page); - -#endif \ No newline at end of file diff --git a/kernel/kernel_main.c b/kernel/kernel_main.c index 92b7590..9167dd8 100644 --- a/kernel/kernel_main.c +++ b/kernel/kernel_main.c @@ -10,8 +10,6 @@ #include "drivers/idt.h" #include "drivers/timer.h" #include "drivers/keyboard.h" -#include "drivers/paging.h" -#include "drivers/kheap.h" #include "shell/shell.h" #include "libc/stdio.h" @@ -37,7 +35,7 @@ void kernel_main() { printf_color("\n[INFO]", LIGHT_CYAN, BLACK); printf_color(" - Loaded PS/2 driver", WHITE, BLACK); - printf_color("\n[TEST]", LIGHT_BROWN, BLACK); // Testing heap + /* printf_color("\n[TEST]", LIGHT_BROWN, BLACK); // Testing heap printf_color(" - Allocating heap blocks..\n", LIGHT_BROWN, BLACK); uint32_t x = kmalloc(8), y = kmalloc(16), z = kmalloc(32); @@ -48,7 +46,7 @@ void kernel_main() { kfree((void*)x), kfree((void*)y), kfree((void*)z); printf_color("\n[STATUS]", LIGHT_GREEN, BLACK); - printf_color(" - Heap worked successfullt!", WHITE, BLACK); + printf_color(" - Heap worked successfullt!", WHITE, BLACK); */ iceos_ascii_logo(); init_prompt(); // Initialize frame buffer diff --git a/kernel/libc/Makefile b/kernel/libc/Makefile index 0743096..aea3a52 100644 --- a/kernel/libc/Makefile +++ b/kernel/libc/Makefile @@ -1,4 +1,4 @@ -OBJS = stdio.o string.o +OBJS = stdio.o string.o assert.o CC = i686-elf-gcc # cross-compiler CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c diff --git a/kernel/cpu/assert.c b/kernel/libc/assert.c similarity index 100% rename from kernel/cpu/assert.c rename to kernel/libc/assert.c diff --git a/kernel/cpu/assert.h b/kernel/libc/assert.h similarity index 100% rename from kernel/cpu/assert.h rename to kernel/libc/assert.h diff --git a/kernel/mem/Makefile b/kernel/mem/Makefile new file mode 100644 index 0000000..ba06a1c --- /dev/null +++ b/kernel/mem/Makefile @@ -0,0 +1,9 @@ +OBJS = paging.o kheap.o ordered_array.o + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + +all:${OBJS} + +%.o: %.c + ${CC} ${CFLAGS} $< -o $@ \ No newline at end of file diff --git a/kernel/mem/kheap.c b/kernel/mem/kheap.c new file mode 100644 index 0000000..e69de29 diff --git a/kernel/drivers/kheap.h b/kernel/mem/kheap.h similarity index 74% rename from kernel/drivers/kheap.h rename to kernel/mem/kheap.h index 2f00771..317fabd 100644 --- a/kernel/drivers/kheap.h +++ b/kernel/mem/kheap.h @@ -10,7 +10,6 @@ /*** 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 @@ -25,48 +24,50 @@ #ifndef KHEAP_H #define KHEAP_H -#define KHEAP_START 0xC0000000 // starting location can be different +#define KHEAP_START 0xC0000000 #define KHEAP_INITIAL_SIZE 0x100000 + #define HEAP_INDEX_SIZE 0x20000 #define HEAP_MAGIC 0x123890AB #define HEAP_MIN_SIZE 0x70000 #include -#include "../cpu/assert.h" -#include "ordered_list.h" -#include "paging.h" +#include "ordered_array.h" -// Data structure for single block/hole +// Data structure for single hole/block typedef struct { uint32_t magic; // Magic number for error checking - uint8_t is_hole; // 1 if its an hole, 0 for a block - uint32_t size; // Size of the block + uint8_t is_hole; // 1 if it's an hole, 0 for a block + uint32_t size; // Size of block } header_t; typedef struct { - uint32_t magic; - header_t *header; // Pointer to the head + uint32_t magic; // Same as above + header_t *header; // Pointer to the header block } footer_t; typedef struct { - ordered_list_t index; - uint32_t start_address; // Start of allocated space - uint32_t end_address; // End of allocated space - uint32_t max_address; // Maximum size, heap can be expanded to + ordered_array_t index; + uint32_t start_address; // Begin of allocated space + uint32_t end_adddress; // End of allocated space + uint32_t max_address; // Maximum size heap ca be expanded to uint8_t supervisor; uint8_t readonly; } heap_t; -// Heap functions +// Create a new heap heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly); +// Allocates a contigious region of memory in size void *alloc(uint32_t size, uint8_t page_align, heap_t *heap); +// Free a block allocated with alloc void free(void *p, heap_t *heap); -// Public heap functions -uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys); -void kfree(void *p); +uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys); uint32_t kmalloc_a(uint32_t sz); uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); uint32_t kmalloc(uint32_t sz); +void kfree(void *p); + + #endif \ No newline at end of file diff --git a/kernel/mem/ordered_array.c b/kernel/mem/ordered_array.c new file mode 100644 index 0000000..e18cbe3 --- /dev/null +++ b/kernel/mem/ordered_array.c @@ -0,0 +1,66 @@ +#include "ordered_array.h" +#include "kheap.h" +#include "../libc/assert.h" +#include "../libc/string.h" + +uint8_t standard_lessthan_predicate(type_t a, type_t b) { + if (a < b) + return 1; + else + return 0; +} + +ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) { + ordered_array_t to_ret; + to_ret.array = (void*)kmalloc(max_size*sizeof(type_t)); + memset(to_ret.array, 0, max_size*sizeof(type_t)); + to_ret.size = 0; + to_ret.max_size = max_size; + to_ret.less_than = less_than; + return to_ret; +} + +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) { + ordered_array_t to_ret; + to_ret.array = (type_t*)addr; + memset(to_ret.array, 0, max_size*sizeof(type_t)); + to_ret.size = 0; + to_ret.max_size = max_size; + to_ret.less_than = less_than; + return to_ret; +} + +void destroy_ordered_array(ordered_array_t *array) { + kfree(array->array); +} + +void insert_ordered_array(type_t item, ordered_array_t *array) { + uint32_t it = 0; + while(it < array->size && array->less_than(array->array[it], it)); + it++; + if(it == array->size) + array->array[array->size++] = item; + else { + type_t tmp = array->array[it]; + array->array[it] = it; + while(it < array->size) { + it++; + type_t tmp = array->array[it]; + array->array[it] = tmp; + tmp = tmp2; + } + array->size++; + } +} + +type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) { + return array->array[i]; +} + +void remove_ordered_array(uint32_t i, ordered_array_t *array) { + while(i < array->size) { + array->array[i] = array->array[i+1]; + i++; + } + array->size--; +} \ No newline at end of file diff --git a/kernel/mem/ordered_array.h b/kernel/mem/ordered_array.h new file mode 100644 index 0000000..972d6f2 --- /dev/null +++ b/kernel/mem/ordered_array.h @@ -0,0 +1,39 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ +#ifndef ORDERED_ARRAY_H +#define ORDERED_ARRAY_H + +#include + +/* Our list is always in a 'sorted state', + * it can store anything that can be casted + * to void* */ +typedef void* type_t; +/* The following predicate should return non-zero + * if the first argument is less than the second */ +typedef uint8_t (*lessthan_predicate_t)(type_t,type_t); +typedef struct { + type_t *array; + uint32_t size; + uint32_t max_size; + lessthan_predicate_t less_than; +} ordered_array_t; + +uint8_t standard_lessthan_predicate(type_t a, type_t b); + +// Create a new ordered array +ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than); +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than); +// Destroy an ordered array +void destroy_ordered_array(ordered_array_t *array); +// Add an item into the array +void insert_ordered_array(type_t item, ordered_array_t *array); +type_t lookup_ordered_array(uint32_t i, ordered_array_t *array); +void remove_ordered_array(uint32_t i, ordered_array_t *array); + +#endif \ No newline at end of file diff --git a/kernel/mem/paging.c b/kernel/mem/paging.c new file mode 100644 index 0000000..5c8e79b --- /dev/null +++ b/kernel/mem/paging.c @@ -0,0 +1,159 @@ +#include "paging.h" +#include "../libc/string.h" +#include "../libc/assert.h" +#include "../drivers/tty.h" +// #include "kheap.h" FIXME: + +// External definitions from kheap.c +extern uint32_t placement_addr; +extern heap_t *kheap; + +void map_heap_pages(); +void setup_frame_allocations(); +void setup_page_directory(); +void alloc_heap_pages(); + +// Bitset of frames, used or free +uint32_t *frame_allocations; +uint32_t nframes; // Number of physical frames +page_directory_t *kernel_directory = 0; +page_directory_t *current_directory = 0; + +static void set_frame(uint32_t addr) { + uint32_t frame = FRAME(addr); + uint32_t frame_alloc_s = FRAME_SECTION(frame); + uint32_t frame_alloc_o = FRAME_OFFSET(frame); + frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o); +} + +static void clear_frame(uint32_t addr) { + uint32_t frame = FRAME(addr); + uint32_t frame_alloc_s = FRAME_SECTION(frame); + uint32_t frame_alloc_o = FRAME_OFFSET(frame); + frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o); +} + +static uint32_t first_frame() { + uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE; + for(uint32_t sec = 0; sec < nsections; sec++) + if(frame_allocations[sec] != USED_FRAME_SECTION) + for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++) + if(!(frame_allocations[sec] & (0x1 << idx))) + return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx; + return nsections * FRAME_ALLOCATIONS_SECTION_SIZE; +} + +void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) { + if(page->fr != 0) + return; + else { + uint32_t fframe = first_frame(); + if(fframe == (uint32_t)-1) { + PANIC("No free frames availables!"); + } else { + // Set free frames to the page + page->pr = PAGE_PRESENT; + page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY; + page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER; + page->fr = free_frame; + // Set new frames as used + uint32_t physical_addr = fframe * FRAME_SIZE; + set_frame(physical_addr); + } + } +} + +void free_frame(page_t *page) { + uint32_t frame; + if(!(frame=page->fr)) + return; // page doesn't have a frame in first place + else { + clear_frame(frame); + page->fr = 0x0; + } +} + +void init_paging() { + setup_frame_allocations(); + setup_page_directory(); + map_heap_pages(); + identity_map(); + alloc_heap_pages(); + + // Register a new ISR to listen to IRQ 14 + register_interrupt_handler(14, page_fault); + enable_paging(kernel_directory); + kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); +} + +void map_heap_pages() { + for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i != FRAME_SIZE) + get_page(i, 1, kernel_directory); +} + +void setup_frame_allocations() { + nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE; + frame_allocations = (uint32_t*)kmalloc(nframes / FRAME_ALLOCATIONS_SECTION_SIZE); + memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE); +} + +void setup_page_directory() { + kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); + memset(kernel_directory, 0, sizeof(page_directory_t)); + current_directory = kernel_directory; +} + +void alloc_heap_pages() { + for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE) + alloca_frame(get_page(i, 1, kernel_directory), 0, 0); +} + +void identity_map() { + for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE) + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); +} + +void enable_paging(page_directory_t *dir) { + current_directory = dir; + asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical)); + uint32_t cr0; + asm volatile("mov %%cr0, %d" : "=r"(cr0)); + cr0 |= 0x80000000; // Correct code to enable paging + asm volatile("mov %0, %%cr0" :: "r"(cr0)); +} + +page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) { + address /= 0x1000; // turn address into an index + uint32_t table_idx = address / 1024; // Find page that contains the address + if(dir->page_tables_virtual[table_idx]) + return &dir->page_tables_virtual[table_idx]->pages[address%1024]; + else if(make) { + uint32_t tmp; + dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_sp(sizeof(page_table_t), &tmp); + memset(dir->page_tables_virtual[table_idx], 0, 0x1000); + dir->page_tables_physical[table_idx] = tmp | 0x7; + return &dir->page_tables_virtual[table_idx]->pages[address%1024]; + } else + return 0; +} + +void page_fault(registers_t regs) { + // Handle a page fault + uint32_t faulting_addr; + asm volatile("mov %%cr2, %0" : "=r" (faulting_addr)); + + // Gracefully print the error + kprint((uint8_t*)"Page fault! ( "); + if(!(regs.err_code & 0x1)) + kprint((uint8_t*)"Present"); + if(regs.err_code & 0x2) + kprint((uint8_t*)"Read-Only"); + if(regs.err_code & 0x4) + kprint((uint8_t*)"User-Mode"); + if(regs.err_code & 0x8) + kprint((uint8_t*)"Reserved"); + kprint((uint8_t*)") at 0x"); + kprint_hex(faulting_addr); + kprint((uint8_t*)"\n"); + PANIC("Page fault"); +} \ No newline at end of file diff --git a/kernel/mem/paging.h b/kernel/mem/paging.h new file mode 100644 index 0000000..85d7555 --- /dev/null +++ b/kernel/mem/paging.h @@ -0,0 +1,80 @@ +/************************************** + * iceOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ +#ifndef PAGING_H +#define PAGING_H + +#include +#include "../drivers/isr.h" + +#define FRAME_SIZE 4096 +#define PAGE_TABLE_SIZE 1024 +#define PAGE_DIRECTORY_SIZE 1024 +#define PAGE_NOT_PRESENT 0 +#define PAGE_PRESENT 1 +#define PAGE_READ_ONLY 0 +#define PAGE_READ_WRITE 1 +#define PAGE_USER 0 +#define PAGE_SUPERVISOR 0 +#define PAGE_SIZE_4KB 0 +#define PAGE_SIZE_4MB 1 +// Frames macros +#define FRAME_ALLOCATIONS_SECTION_SIZE 32 +#define USED_FRAME_SECTION 0xFFFFFFFF +#define FREE_FRAME_SECTION 0x00000000 + +#define FRAME(addr) (addr/FRAME_SIZE) +#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE) +#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE) + +// Set physical memory to 15 MiB +#define PHYSICAL_MEM_SIZE 0x10000000 + +struct page { // Single page structure, from intel's developer manual + uint8_t pr : 1; // Present: 1 to map 4KB page + uint8_t rw : 1; // Read/Write mode + uint8_t us : 1; // if 0, user mode access aren't allowed to the page + uint8_t pw : 1; // Page-level write through + uint8_t pc : 1; // Page-level cache disable + uint8_t ac : 1; // 1 if we have accessed 4kb page + uint8_t di : 1; // 1 if page has been written(dirty) + uint8_t pa : 1; // Unused bit + uint8_t gl : 1; // 1 if page is global + uint8_t ig : 3; // Unused bit + uint32_t fr: 20; // Physical address of frame +} __attribute__((packed)); +typedef struct page page_t; + +typedef struct page_table { + page_t pages[PAGE_TABLE_SIZE]; +} page_table_t; + +/* Holds 2 arrays for each page directory + * one holds the physical address, while + * the other one holds the virtual address + * (to write/read to it) */ +typedef struct page_directory { + page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE]; + uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE]; +} page_directory_t; + +// Setup environment, page directories and enable paging +void init_paging(); +// Perform the "enable-paging" operation to the right register +void enable_paging(page_directory_t *dir); +// Retrieve a pointer from the given page +page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir); +// Identity map(phys = virtual addr) to access it as if paging wasn't enabled +void identity_map(); +// Delete a frame +void free_frame(page_t *page); +// Allocate a new frame +void alloc_frame(page_t *page, int32_t is_super, int32_t is_write); +// Page faults handler(ISR recorder) +void page_fault(registers_t regs); + +#endif \ No newline at end of file