From d5a4e32b35997b2275538ee21dc29ac360802b43 Mon Sep 17 00:00:00 2001 From: g1n Date: Tue, 7 Sep 2021 18:32:27 +0300 Subject: [PATCH] Kernel: Add working paging --- kernel/arch/i386/boot.S | 21 +++ kernel/kernel/early_kernel.c | 11 +- kernel/kernel/interrupts.c | 8 +- kernel/kernel/kernel.c | 4 +- kernel/kernel/paging.h | 286 ++++------------------------------- 5 files changed, 67 insertions(+), 263 deletions(-) diff --git a/kernel/arch/i386/boot.S b/kernel/arch/i386/boot.S index 1b92bb9..721e781 100644 --- a/kernel/arch/i386/boot.S +++ b/kernel/arch/i386/boot.S @@ -191,3 +191,24 @@ irq_common_stub: add $0x8, %esp //Cleans up the pushed error code and pushed ISR number sti iret + +.global loadPageDirectory +loadPageDirectory: + push %ebp + mov %esp, %ebp + mov 8(%esp), %eax + mov %eax, %cr3 + mov %ebp, %esp + pop %ebp + ret + +.global enable_paging +enable_paging: // FIXME + push %ebp + mov %esp, %ebp + mov %cr0, %eax + or $0x80000000, %eax + mov %eax, %cr0 + mov %ebp, %esp + pop %ebp + ret diff --git a/kernel/kernel/early_kernel.c b/kernel/kernel/early_kernel.c index 5a0a08a..2b3401c 100644 --- a/kernel/kernel/early_kernel.c +++ b/kernel/kernel/early_kernel.c @@ -7,7 +7,7 @@ #include "interrupts.c" //#include "timer.c" #include "keyboard.c" -//#include "paging.h" +#include "paging.h" void kernel_early_main(void) { gdt_init(); @@ -16,9 +16,10 @@ void kernel_early_main(void) { idt_init(); serial_printf("idt initialized!\n"); //init_timer(50); // Initialise timer to 50Hz - serial_printf("timer initialized!\n"); - //init_paging(); - //serial_printf("paging initialized!\n"); - terminal_initialize(); + //serial_printf("timer initialized!\n"); + init_paging(); + serial_printf("paging initialized!\n"); init_keyboard(); + serial_printf("keyboard initialized!\n"); + terminal_initialize(); } diff --git a/kernel/kernel/interrupts.c b/kernel/kernel/interrupts.c index 4193d9d..e6e40dc 100644 --- a/kernel/kernel/interrupts.c +++ b/kernel/kernel/interrupts.c @@ -183,13 +183,13 @@ void idt_init() { void isr_handler(registers_t regs) { - printf("Received Interrupt: %s\n", regs.int_no); // TODO: Fix from %s to %X - serial_printf("Received interrupt: %s\n", regs.int_no); // TODO: Fix %s to %X - if (interrupt_handlers[regs.int_no] != 0) { isr_t handler = interrupt_handlers[regs.int_no]; handler(regs); + } else { + //printf("Unhandled interrupt: %c\n", regs.int_no); // FIXME: Fix from %s to %X + //serial_printf("Unhandled interrupt: %c\n", regs.int_no); // FIXME: Fix from %s to %X } } @@ -209,6 +209,8 @@ void irq_handler(registers_t regs) { isr_t handler = interrupt_handlers[regs.int_no]; handler(regs); + } else { + //serial_printf("Unhandled IRQ interrupt: %c\n", regs.int_no); // FIXME: Fix from %s to %X } } diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c index 5834ab5..6e29b66 100644 --- a/kernel/kernel/kernel.c +++ b/kernel/kernel/kernel.c @@ -8,9 +8,11 @@ void kernel_main(void) { serial_printf("Newline test\n"); char * test_string = "test"; serial_printf("This is string from variable: %s\n", test_string); - printf("Test finished success!\n"); asm volatile("sti"); + uint32_t *ptr = (uint32_t*)0xA0000000; + uint32_t do_page_fault = *ptr; + printf("%s", do_page_fault); for(;;) { asm("hlt"); } diff --git a/kernel/kernel/paging.h b/kernel/kernel/paging.h index b5f0a44..4d855b6 100644 --- a/kernel/kernel/paging.h +++ b/kernel/kernel/paging.h @@ -1,98 +1,4 @@ -#ifndef PAGING_H -#define PAGING_H - -// A bitset of frames - used or free. -uint32_t *frames; -uint32_t nframes; - -/*extern */uint32_t placement_address; - -// Macros used in the bitset algorithms. -#define INDEX_FROM_BIT(a) (a/(8*4)) -#define OFFSET_FROM_BIT(a) (a%(8*4)) - -typedef struct page -{ - uint32_t present : 1; // Page present in memory - uint32_t rw : 1; // Read-only if clear, readwrite if set - uint32_t user : 1; // Supervisor level only if clear - uint32_t accessed : 1; // Has the page been accessed since last refresh? - uint32_t dirty : 1; // Has the page been written to since last refresh? - uint32_t unused : 7; // Amalgamation of unused and reserved bits - uint32_t frame : 20; // Frame address (shifted right 12 bits) -} page_t; - -typedef struct page_table -{ - page_t pages[1024]; -} page_table_t; - -typedef struct page_directory -{ - /* - Array of pointers to pagetables. - */ - page_table_t *tables[1024]; - /* - Array of pointers to the pagetables above, but gives their *physical* - location, for loading into the CR3 register. - */ - uint32_t tablesPhysical[1024]; - /* - The physical address of tablesPhysical. - */ - uint32_t physicalAddr; -} page_directory_t; - -uint32_t kmalloc(uint32_t sz) -{ - uint32_t tmp = placement_address; - placement_address += sz; - return tmp; -} - -uint32_t kmalloc_a(uint32_t sz) -{ - uint32_t tmp = placement_address; - placement_address += sz; - return tmp; -} - -/* -uint32_t kmalloc_a(uint32_t sz, int align) -{ - if (align == 1 && (placement_address & 0xFFFFF000)) // If the address is not already page-aligned - { - // Align it. - placement_address &= 0xFFFFF000; - placement_address += 0x1000; - } - uint32_t tmp = placement_address; - placement_address += sz; - return tmp; -} -*/ -uint32_t kmalloc_ap(uint32_t sz, int align, uint32_t *phys) -{ - if (align == 1 && (placement_address & 0xFFFFF000)) // If the address is not already page-aligned - { - // Align it. - placement_address &= 0xFFFFF000; - placement_address += 0x1000; - } - if (phys) - { - *phys = placement_address; - } - uint32_t tmp = placement_address; - placement_address += sz; - return tmp; -} - -//uint32_t kmalloc_a(uint32_t sz); // page aligned. -uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); // returns a physical address. -//uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); // page aligned and returns a physical address. -//uint32_t kmalloc(uint32_t sz); // vanilla (normal). +#include /* Handler for page faults. @@ -116,170 +22,42 @@ void page_fault(registers_t regs){ if (rw) {printf("read-only ");} if (us) {printf("user-mode ");} if (reserved) {printf("reserved ");} - printf(") at 0x%s\n", faulting_address); - panic("PAGE FAULT"); + printf(") at 0x%c\n", faulting_address); // FIXME: fix %c to %X + printf("PAGE FAULT\n"); } -/* - Retrieves a pointer to the page required. - If make == 1, if the page-table in which this page should - reside isn't created, create it! -*/ -page_t *get_page(uint32_t address, int make, page_directory_t *dir){ - // Turn the address into an index. - address /= 0x1000; - // Find the page table containing this address. - uint32_t table_idx = address / 1024; - if (dir->tables[table_idx]) // If this 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_ap(sizeof(page_table_t), 1, &tmp); - memset(dir->tables[table_idx], 0, 0x1000); - dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US. - return &dir->tables[table_idx]->pages[address%1024]; - } - else - { - return 0; - } -} + +uint32_t page_directory[1024] __attribute__((aligned(4096))); +uint32_t first_page_table[1024] __attribute__((aligned(4096))); + +extern void loadPageDirectory(unsigned int*); +extern void enable_paging(); void init_paging() { - - // The size of physical memory. For the moment we - // assume it is 16MB big. - uint32_t mem_end_page = 0x1000000; + //set each entry to not present + int i; + for(i = 0; i < 1024; i++) + { + // This sets the following flags to the pages: + // Supervisor: Only kernel-mode can access them + // Write Enabled: It can be both read from and written to + // Not Present: The page table is not present + page_directory[i] = 0x00000002; + } - nframes = mem_end_page / 0x1000; - frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes)); - memset(frames, 0, INDEX_FROM_BIT(nframes)); + //we will fill all 1024 entries in the table, mapping 4 megabytes + for(i = 0; i < 1024; i++) + { + // As the address is page aligned, it will always leave 12 bits zeroed. + // Those bits are used by the attributes ;) + first_page_table[i] = (i * 0x1000) | 3; // attributes: supervisor level, read/write, present. + } + + // attributes: supervisor level, read/write, present + page_directory[0] = ((unsigned int)first_page_table) | 3; - // Let's make a page directory. - void* kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); - memset(kernel_directory, 0, sizeof(page_directory_t)); - void* current_directory = kernel_directory; - - // We need to identity map (phys addr = virt addr) from - // 0x0 to the end of used memory, so we can access this - // transparently, as if paging wasn't enabled. - // NOTE that we use a while loop here deliberately. - // inside the loop body we actually change placement_address - // by calling kmalloc(). A while loop causes this to be - // computed on-the-fly rather than once at the start. - int i = 0; - while (i < placement_address) - { - // Kernel code is readable but not writeable from userspace. - alloc_frame( get_page(i, 1, kernel_directory), 0, 0); - i += 0x1000; - } + register_interrupt_handler(14, &page_fault); - // Before we enable paging, we must register our page fault handler. - register_interrupt_handler(14, page_fault); - - // Now, enable paging! - switch_page_directory(kernel_directory); + loadPageDirectory(page_directory); + enable_paging(); } - -/* - Causes the specified page directory to be loaded into the - CR3 register. -*/ -void switch_page_directory(page_directory_t *dir) { - void* current_directory = dir; - asm volatile("mov %0, %%eax":: "r"(&dir->tablesPhysical)); - asm("mov %eax, %cr3;"); - asm("mov %cr0, %eax;"); - asm("or 0x80000000, %eax;"); - asm("mov %eax, %cr0;"); -} - -// Static function to set a bit in the frames 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); -} - -// Static function to clear a bit in the frames 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); -} - -// Static function to 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)); -} - -// Static function to find the first free frame. -static uint32_t first_frame() -{ - uint32_t i, j; - for (i = 0; i < INDEX_FROM_BIT(nframes); i++) - { - if (frames[i] != 0xFFFFFFFF) // nothing free, exit early. - { - // at least one bit is free here. - for (j = 0; j < 32; j++) - { - uint32_t toTest = 0x1 << j; - if ( !(frames[i]&toTest) ) - { - return i*4*8+j; - } - } - } - } -} - -// Function to allocate a frame. -void alloc_frame(page_t *page, int is_kernel, int is_writeable) -{ - if (page->frame != 0) - { - return; // Frame was already allocated, return straight away. - } - else - { - uint32_t idx = first_frame(); // idx is now the index of the first free frame. - if (idx == (uint32_t)-1) - { - panic("No free frames!"); - } - set_frame(idx*0x1000); // this frame is now ours! - page->present = 1; // Mark it as present. - page->rw = (is_writeable)?1:0; // Should the page be writeable? - page->user = (is_kernel)?0:1; // Should the page be user-mode? - page->frame = idx; - } -} - -// Function to deallocate a frame. -void free_frame(page_t *page) -{ - uint32_t frame; - if (!(frame=page->frame)) - { - return; // The given page didn't actually have an allocated frame! - } - else - { - clear_frame(frame); // Frame is now free again. - page->frame = 0x0; // Page now doesn't have a frame. - } -} -#endif