From 3c574238cf1de5a8fdde04fc08ac8f56607b52c1 Mon Sep 17 00:00:00 2001 From: ice-bit Date: Tue, 24 Sep 2019 18:32:38 +0200 Subject: [PATCH] Fixed bugs about kheap, paging and ordered list Furthermore, added Heap kernel driver code for both allocation and deallocation free() does not works yet: `ASSERTION-FAILED(head->magic == HEAP_MAGIC) at kheap.c:261` --- kernel/drivers/kheap.c | 2 +- kernel/drivers/ordered_list.c | 3 + kernel/drivers/ordered_list.h | 3 - kernel/drivers/paging.c | 102 ++++++++++++++++------------------ kernel/drivers/paging.h | 70 +++++++++++++++-------- kernel/kernel_main.c | 17 ++++++ 6 files changed, 117 insertions(+), 80 deletions(-) diff --git a/kernel/drivers/kheap.c b/kernel/drivers/kheap.c index 4da21e2..355125a 100644 --- a/kernel/drivers/kheap.c +++ b/kernel/drivers/kheap.c @@ -251,7 +251,7 @@ void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) { void free(void *p, heap_t *heap) { // Exit for null pointer - if(p == NULL) + if(p == 0) return; // Retrieve the header and the footer for this pointer diff --git a/kernel/drivers/ordered_list.c b/kernel/drivers/ordered_list.c index 31f09ce..1cebbfe 100644 --- a/kernel/drivers/ordered_list.c +++ b/kernel/drivers/ordered_list.c @@ -1,4 +1,7 @@ #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) diff --git a/kernel/drivers/ordered_list.h b/kernel/drivers/ordered_list.h index 1390e9c..6e6dc90 100644 --- a/kernel/drivers/ordered_list.h +++ b/kernel/drivers/ordered_list.h @@ -9,9 +9,6 @@ #define ORDERED_LIST_H #include -#include "kheap.h" -#include "../cpu/assert.h" -#include "../libc/string.h" /* Our list is always in a 'sorted state', * it can store anything that can be casted diff --git a/kernel/drivers/paging.c b/kernel/drivers/paging.c index d785098..84a64f9 100644 --- a/kernel/drivers/paging.c +++ b/kernel/drivers/paging.c @@ -1,4 +1,6 @@ #include "paging.h" +#include "kheap.h" +#include "../libc/string.h" // Macros for bitset algorithms #define INDEX_FROM_BIT(a) (a/(8*4)) @@ -14,10 +16,9 @@ uint32_t *frames; uint32_t nframes; // From kheap.c -extern uint32_t placement_address; +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; @@ -34,40 +35,35 @@ static void clear_frame(uint32_t frame_addr) { frames[idx] &= ~(0x1 << off); } -// Test if a bit is set -static uint32_t test_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); - return (frames[idx] & (0x1 << off)); -} - -// Find the first three frames +// Find the first free frames static uint32_t first_frame() { - for(uint32_t i = 0; i < INDEX_FROM_BIT(nframes); i++) { - if(frames[i] != 0xFFFFFFFF) { // If nothing is free, exit - for(uint32_t j = 0; j < 32; j++) { - uint32_t to_test = 0x1 << j; - if (!(frames[i]&to_test)) - return i*4*8+j; - } - } - } + 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_kernel, int32_t is_writeable) { +void alloc_frame(page_t *page, int32_t is_supervisored, int32_t is_writeable) { if(page->frame != 0) - return; + return; // Frame already allocated else { - uint32_t idx = first_frame(); - if(idx == (uint32_t)-1) { - // panic + 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); } - set_frame(idx*0x1000); - page->present = 1; - page->rw = (is_writeable) ? 1 : 0; - page->user = (is_kernel) ? 1 : 0; - page->frame = idx; } } @@ -82,46 +78,45 @@ void free_frame(page_t *page) { } void init_paging() { - uint32_t mem_end_page = 0x1000000; // Physical address memory(16MiB big) - nframes = mem_end_page / 0x1000; + uint32_t nframes = PHYSICAL_MEMORY_SIZE / FRAME_SIZE; frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes)); - memset(frames, 0, 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 < KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000) + 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 < placement_address+0x1000) { + 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 < KHEAP_START+KHEAP_INITIAL_SIZE; i += 0x1000) + 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 - switch_page_directory(kernel_directory); + enable_paging(kernel_directory); // Set up kernel heap kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); } -void switch_page_directory(page_directory_t *dir) { +void enable_paging(page_directory_t *dir) { current_directory = dir; - asm volatile("mov %0, %%cr3" :: "r"(&dir->tables_physical)); + 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 @@ -133,14 +128,14 @@ page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) { address /= 0x1000; // Find page table that contains this index uint32_t table_idx = address / 1024; - if(dir->tables[table_idx]) // If current table is already assigned - return &dir->tables[table_idx]->pages[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->tables[table_idx] = (page_table_t*)kmalloc_p(sizeof(page_table_t), &tmp); - memset(dir->tables[table_idx], 0, 0x1000); - dir->tables_physical[table_idx] = tmp | 0x7; - return &dir->tables[table_idx]->pages[address%1024]; + 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; } @@ -155,20 +150,19 @@ void page_fault(registers_t regs) { 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; - int32_t id = regs.err_code & 0x10; // Output of those informations - kprint("Page fault! ( "); + kprint((uint8_t*)"Page fault! ( "); if(present) - kprint("present "); + kprint((uint8_t*)"present "); if(rw) - kprint("read-only"); + kprint((uint8_t*)"read-only"); if(us) - kprint("user-mode"); + kprint((uint8_t*)"user-mode"); if(reserved) - kprint("reserved"); - kprint(") at 0x"); + kprint((uint8_t*)"reserved"); + kprint((uint8_t*)") at 0x"); kprint_hex(fault_addr); - kprint("\n"); + 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 index aed583a..d479bf8 100644 --- a/kernel/drivers/paging.h +++ b/kernel/drivers/paging.h @@ -1,41 +1,67 @@ #ifndef PAGING_H -#define PAGING_G +#define PAGING_H #include #include "isr.h" -#include "tty.h" -#include "kheap.h" -typedef struct page { - uint32_t present : 1; // Presence in memory of single page - uint32_t rw : 1; // if set read write otherwise read only - uint32_t user : 1; // Supervisored mode only if cleared - uint32_t accessed : 1; // true if page has been accessed since last refresh - uint32_t dirty : 1; // Same as above for write. - uint32_t unused : 7; // unused bits - uint32_t frame : 20; // Frame address (shifted to the right) -} page_t; +#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 -typedef struct page_table { - page_t pages[1024]; -} page_table_t; +// Reserve 16 MiB of physical memory +#define PHYSICAL_MEMORY_SIZE 0x10000000 -typedef struct page_directory { - page_table_t *tables[1024]; // array of pointers to page tables - uint32_t tables_physical[1024]; // address of tables physical. - uint32_t physical_addr; -} page_directory_t; +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 switch_page_directory(page_directory_t *new); +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_kernel, int32_t is_writeable); +void alloc_frame(page_t *page, int32_t is_supervisored, int32_t is_writeable); // Deallocate frame void free_frame(page_t *page); diff --git a/kernel/kernel_main.c b/kernel/kernel_main.c index f10adc0..92b7590 100644 --- a/kernel/kernel_main.c +++ b/kernel/kernel_main.c @@ -10,9 +10,13 @@ #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" +#include + void kernel_main() { printf_color("\n[STATUS]", LIGHT_GREEN, BLACK); printf_color(" - Loading kernel, wait please...", WHITE, BLACK); @@ -33,6 +37,19 @@ 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(" - Allocating heap blocks..\n", LIGHT_BROWN, BLACK); + + uint32_t x = kmalloc(8), y = kmalloc(16), z = kmalloc(32); + printf("x: %x, y: %x, z: %x", x, y, z); + + printf_color("\n[TEST]", LIGHT_BROWN, BLACK); // Testing heap + printf_color(" - Freeing heap blocks..\n", LIGHT_BROWN, BLACK); + kfree((void*)x), kfree((void*)y), kfree((void*)z); + + printf_color("\n[STATUS]", LIGHT_GREEN, BLACK); + printf_color(" - Heap worked successfullt!", WHITE, BLACK); + iceos_ascii_logo(); init_prompt(); // Initialize frame buffer } \ No newline at end of file