From 9b5bf087b5452eee61eea374254422670c1b8c45 Mon Sep 17 00:00:00 2001 From: ice-bit Date: Mon, 23 Sep 2019 17:27:21 +0200 Subject: [PATCH] Added last part of paging, print_hex function and updated linker script --- kernel/drivers/kheap.c | 4 +- kernel/drivers/kheap.h | 1 + kernel/drivers/paging.c | 118 ++++++++++++++++++++++++++++++++++++++++ kernel/drivers/paging.h | 3 +- kernel/drivers/tty.c | 31 +++++++++++ kernel/drivers/tty.h | 1 + link.ld | 33 +++++------ 7 files changed, 168 insertions(+), 23 deletions(-) diff --git a/kernel/drivers/kheap.c b/kernel/drivers/kheap.c index 9f46758..1141ade 100644 --- a/kernel/drivers/kheap.c +++ b/kernel/drivers/kheap.c @@ -1,8 +1,8 @@ #include "kheap.h" -// Extern variables are declared in the linker script +// end is declared in the linker script extern uint32_t end; -extern page_directory_t *kernel_directory; // FIXME: +extern page_directory_t *kernel_directory; uint32_t placement_addr = (uint32_t)&end; heap_t *kheap = 0; diff --git a/kernel/drivers/kheap.h b/kernel/drivers/kheap.h index c8f1530..e56dc20 100644 --- a/kernel/drivers/kheap.h +++ b/kernel/drivers/kheap.h @@ -34,6 +34,7 @@ #include #include "ordered_list.h" +#include "paging.h" // Data structure for single block/hole typedef struct { diff --git a/kernel/drivers/paging.c b/kernel/drivers/paging.c index 75e37cb..d785098 100644 --- a/kernel/drivers/paging.c +++ b/kernel/drivers/paging.c @@ -53,4 +53,122 @@ static uint32_t first_frame() { } } } +} + +void alloc_frame(page_t *page, int32_t is_kernel, int32_t is_writeable) { + if(page->frame != 0) + return; + else { + uint32_t idx = first_frame(); + if(idx == (uint32_t)-1) { + // panic + } + set_frame(idx*0x1000); + page->present = 1; + page->rw = (is_writeable) ? 1 : 0; + page->user = (is_kernel) ? 1 : 0; + page->frame = idx; + } +} + +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 mem_end_page = 0x1000000; // Physical address memory(16MiB big) + nframes = mem_end_page / 0x1000; + 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)); + 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) + 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) { + // 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) + 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); + + // 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) { + current_directory = dir; + asm volatile("mov %0, %%cr3" :: "r"(&dir->tables_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->tables[table_idx]) // If current table is already assigned + return &dir->tables[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]; + } 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; + int32_t id = regs.err_code & 0x10; + + // Output of those informations + kprint("Page fault! ( "); + if(present) + kprint("present "); + if(rw) + kprint("read-only"); + if(us) + kprint("user-mode"); + if(reserved) + kprint("reserved"); + kprint(") at 0x"); + kprint_hex(fault_addr); + kprint("\n"); + PANIC("Page fault"); } \ No newline at end of file diff --git a/kernel/drivers/paging.h b/kernel/drivers/paging.h index 21bfa84..796e202 100644 --- a/kernel/drivers/paging.h +++ b/kernel/drivers/paging.h @@ -3,11 +3,12 @@ #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 fw : 1; // if set read write otherwise read only + 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. diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c index 1fe306d..e644f2f 100644 --- a/kernel/drivers/tty.c +++ b/kernel/drivers/tty.c @@ -92,6 +92,37 @@ void kprint_dec(uint32_t num) { kprint(c2); } +void kprint_hex(uint32_t num) { + int32_t tmp; + uint8_t no_zeros = 1; + + kprint((uint8_t*)"0x"); + + for(int32_t i = 28; i > 0; i -= 4) { + tmp = (num >> i) & 0xF; + if(tmp == 0 && no_zeros != 0) + continue; + + if(tmp >= 0xA) { + no_zeros = 0; + uint8_t *buf = (uint8_t*)tmp-0xA+'a'; + kprint_c(buf, strlen(buf), WHITE, BLACK); + } else { + uint8_t *buf = (uint8_t*)tmp+'a'; + kprint_c(buf, strlen(buf), WHITE, BLACK); + } + } + + tmp = num & 0xF; + if(tmp >= 0xA) { + uint8_t *buf = (uint8_t*)tmp-0xA+'a'; + kprint_c(buf, strlen(buf), WHITE, BLACK); + } else { + uint8_t *buf = (uint8_t*)tmp+'a'; + kprint_c(buf, strlen(buf), WHITE, BLACK); + } +} + 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 67cb7e2..c23330f 100644 --- a/kernel/drivers/tty.h +++ b/kernel/drivers/tty.h @@ -54,6 +54,7 @@ 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 kprint_hex(uint32_t num); void init_prompt(); void clear_prompt(); void clear_row(uint8_t row); diff --git a/link.ld b/link.ld index 3328d73..201e2dc 100644 --- a/link.ld +++ b/link.ld @@ -1,35 +1,28 @@ ENTRY(kernel_loader) +SECTIONS +{ -. = 0x00100000; - -SECTIONS { - - .boot ALIGN (0x1000): - { - *(.multiboot) - } - - .text ALIGN (0x1000): + .text 0x100000 : { + code = .; _code = .; __code = .; *(.text) + . = ALIGN(4096); } - .rodata ALIGN (0x1000): - { - *(.rodata*) - } - - .data ALIGN (0x1000): + .data : { + data = .; _data = .; __data = .; *(.data) + *(.rodata) + . = ALIGN(4096); } - .bss ALIGN (0x1000): + .bss : { - *(COMMON) + bss = .; _bss = .; __bss = .; *(.bss) + . = ALIGN(4096); } + end = .; _end = .; __end = .; } - -end = .; \ No newline at end of file