diff --git a/kernel/mem/kheap.c b/kernel/mem/kheap.c index e69de29..fecbf0c 100644 --- a/kernel/mem/kheap.c +++ b/kernel/mem/kheap.c @@ -0,0 +1,197 @@ +#include "kheap.h" +#include "paging.h" + +// TODO: add assert + +extern uint32_t end; +uint32_t placement_addr = (uint32_t)&end; +extern page_directory_t *kernel_directory; +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->fr*0x1000 + ((uint32_t)addr&0xFFF); + } + return (uint32_t)addr; + } else { + if(align == 1 && (placement_addr & 0xFFFFF000)) { + 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); +} + +static void expand(uint32_t new_size, heap_t *heap) { + // Get nearest page boundary + if((new_size&0xFFFFF000) != 0) { + new_size &= 0xFFFFF000; + new_size += 0x1000; + } + + uint32_t old_size = heap->end_adddress - heap->start_address; + + uint32_t it = old_size; + while(it < new_size) { + alloc_frame(get_page(heap->start_address+it, 1, kernel_directory), + (heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1); + it += 0x1000; // Page size + } + heap->end_adddress = heap->start_address+new_size; +} + +static uint32_t contract(uint32_t new_size, heap_t *heap) { + 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_adddress - heap->start_address; + uint32_t it = old_size - 0x1000; + while(new_size < it) { + free_frame(get_page(heap->start_address+it,0, kernel_directory)); + it -= 0x1000; + } + + heap->end_adddress = heap->start_address + new_size; + return new_size; +} + +static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) { + uint32_t it = 0; + + // Find smallest hole that fit our request + while(it < heap->index.size) { + header_t *head = (header_t*)lookup_ordered_array(it, &heap->index); + if(page_align > 0) { + // IF page must be aligned + uint32_t location = (uint32_t)head; + uint32_t offset = 0; + if((((location+sizeof(header_t)) & 0xFFFFF000) != 0)) + offset = 0x1000 - (location+sizeof(header_t))%0x1000; + uint32_t hole_size = (uint32_t)head->size - offset; + // Check if we can fit this page in that hole + if(hole_size >= (uint32_t)size) + break; + } else if(head->size >= size) + break; + it++; + } + + // If we didn't find anything + if(it == heap->index.size) + return -1; + else + return it; +} + +static uint8_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_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) { + heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t)); + + // Initialize the index + heap->index = place_ordered_array((void*)start, HEAP_MIN_SIZE, &header_t_less_than); + // Shift start address to the right + start += sizeof(type_t) * HEAP_INDEX_SIZE; + + // Check if start address is page-aligned + if ((start & 0xFFFFF000) != 0) { + start &= 0xFFFFF000; + start += 0x1000; + } + // Store vars into heap + heap->start_address = start; + heap->end_adddress = end_addr; + heap->max_address = max; + heap->supervisor = supervisor; + heap->readonly = readonly; + + header_t *hole = (header_t*)start; + hole->size = end - start; + hole->magic = HEAP_MAGIC; + hole->is_hole = 1; + insert_ordered_array((void*)hole, &heap->index); + + return heap; +} + +void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) { + uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t); + // Find smallest hole suitable + uint32_t it = find_smallest_hole(new_size, page_align, heap); + + if((int32_t)it == -1) { + uint32_t old_len = heap->end_adddress - heap->start_address; + uint32_t old_end_addr = heap->end_adddress; + + // Allocate more space + expand(old_len+new_size, heap); + uint32_t new_len = heap->end_adddress - heap->start_address; + + it = 0; + uint32_t idx = -1; uint32_t value = 0x0; + while(it < heap->index.size) { + uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index); + if(tmp > value) { + value = tmp; + idx = it; + } + it++; + } + + // If no headers has been found, add a new 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_array((void*)head, &heap->index); + } else { + header_t *head = lookup_ordered_array(idx, &heap->index); + head->size += new_len - old_len; + // Update the footer + footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); + foot->header = head; + foot->magic = HEAP_MAGIC; + } + // Now we have enough space, so recall this function again + return alloc(size, page_align, heap); + } +} \ No newline at end of file diff --git a/kernel/mem/kheap.h b/kernel/mem/kheap.h index 317fabd..38ece9b 100644 --- a/kernel/mem/kheap.h +++ b/kernel/mem/kheap.h @@ -61,13 +61,11 @@ heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervis 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); -uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys); +uint32_t kmalloc_int(uint32_t sz, int32_t 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/paging.c b/kernel/mem/paging.c index 5c8e79b..d3f6de3 100644 --- a/kernel/mem/paging.c +++ b/kernel/mem/paging.c @@ -2,17 +2,11 @@ #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 @@ -55,7 +49,7 @@ void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) { 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; + page->fr = fframe; // Set new frames as used uint32_t physical_addr = fframe * FRAME_SIZE; set_frame(physical_addr); @@ -74,11 +68,22 @@ void free_frame(page_t *page) { } void init_paging() { - setup_frame_allocations(); - setup_page_directory(); - map_heap_pages(); - identity_map(); - alloc_heap_pages(); + kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); + memset(kernel_directory, 0, sizeof(page_directory_t)); + current_directory = kernel_directory; + + kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); + memset(kernel_directory, 0, sizeof(page_directory_t)); + current_directory = kernel_directory; + + for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE) + get_page(i, 1, kernel_directory); + + for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE) + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); + + for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE) + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); // Register a new ISR to listen to IRQ 14 register_interrupt_handler(14, page_fault); @@ -86,38 +91,11 @@ void init_paging() { 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)); + asm volatile("mov %%cr0, %0" : "=r"(cr0)); cr0 |= 0x80000000; // Correct code to enable paging asm volatile("mov %0, %%cr0" :: "r"(cr0)); } @@ -129,7 +107,7 @@ page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) { 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); + dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(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]; diff --git a/kernel/mem/paging.h b/kernel/mem/paging.h index 85d7555..0908821 100644 --- a/kernel/mem/paging.h +++ b/kernel/mem/paging.h @@ -10,6 +10,7 @@ #include #include "../drivers/isr.h" +#include "kheap.h" #define FRAME_SIZE 4096 #define PAGE_TABLE_SIZE 1024