#include "headers/paging.h" #include "headers/kheap.h" #include "headers/screen.h" #include "headers/serial.h" #include // The kernel's page directory page_directory_t *kernel_directory=0; // The current page directory; page_directory_t *current_directory=0; // a bitset of frames - used or free uint32_t *frames; uint32_t nframes; // defined in kheap.c extern uint32_t placement_address; // Macros for bitset algo's #define INDEX_FROM_BIT(a) (a/(8*4)) #define OFFSET_FROM_BIT(a) (a%(8*4)) // 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); } // clear frame in a 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); } /*// test if a bit is set static u32int 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 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 { // atleast one bit is free for(j = 0; j < 32; j++) { uint32_t toTest = 0x1 << j; if(!(frames[i]&toTest)) { return i*4*8+j; } } } } return -1; } // alloc a frame void alloc_frame(page_t *page, int is_kernel, int is_writeable) { if(page->frame != 0) { return; // frame allready alloced } else { uint32_t idx = first_frame(); // idx now index for first free frame if(idx == (uint32_t)-1) { PANIC("No free frames!"); } set_frame(idx*0x1000); // frame is now ours page->present = 1; // mark as present page->rw = (is_writeable)?1:0; // should page be w page->user = (is_kernel)?0:1; // should page be user-mode page->frame = idx; } } // function to dealloc a frame void free_frame(page_t * page) { uint32_t frame; if(!(frame=page->frame)) { return; // page didnt actually have a alloced frame } else { clear_frame(frame); // free the frame page->frame = 0x0; // page has no frame } } void initialize_paging() { //size of physcial mem for now we assume it is 16MB uint32_t mem_end_page = 0x1000000; nframes = mem_end_page / 0x1000; frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes),0,0); memset(frames,0,INDEX_FROM_BIT(nframes)); // lets make a page directory <--- cont here kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); memset(kernel_directory, 0, sizeof(page_directory_t)); current_directory = kernel_directory; // my need to identify map (phys addr = virt addr from // 0x0 to end of used mem so this can be accessed transparently // as if paging isnt enabled uint32_t i = 0; while(i < placement_address) { // read but not writeable from user space alloc_frame(get_page(i,1,kernel_directory),0,0); i += 0x1000; } // before we enable paging set our page fault handler register_interrupt_handler(14, &page_fault); // enable paging! <-- should have a seperate function // for the first time this is done and not constantly renable it switch_page_directory(kernel_directory); print("Paging enabled!\n"); } void switch_page_directory(page_directory_t *dir) { current_directory = dir; asm volatile("mov cr3, %0":: "r"(&dir->tablesPhysical)); uint32_t cr0; asm volatile("mov %0, cr0": "=r"(cr0)); serial_printf("cr0 = %x\n",cr0); cr0 |= 0x80000000; // Enable paging! asm volatile("mov cr0, %0":: "r"(cr0)); } page_t *get_page(uint32_t address, int make, page_directory_t *dir) { // turn address into an index address /= 0x1000; // find the page table that contains this address uint32_t table_idx = address / 1024; if(dir->tables[table_idx]) // if this page is allready 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), &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; } } // fix issue with page fault passing see // Problem: Interrupt handlers corrupt interrupted state // & Problem 3: regs var must called by reference instead of by value in the irq and isr handlers void page_fault(registers_t *regs) { // a page fault has occured // faulting address is in cr2 uint32_t faulting_address; asm volatile("mov %0, cr2" : "=r" (faulting_address)); // the error codes gives us details of what happened int present = !(regs->err_code & 0x1); // Page not present int rw = regs->err_code & 0x2; // Write operation? int us = regs->err_code & 0x4; // Processor was in user-mode? int reserved = regs->err_code & 0x8; // Overwritten CPU-reserved bits of page entry? int id = regs->err_code & 0x10; // Caused by an instruction fetch? // output an error message print("Page fault! ( "); if(present) { print("present "); } else if(rw) { print("read-only "); } else if(us) { print("user-mode "); } else if(id) { print("instr-fetch "); } else if(reserved) {print("reserved "); } kprintf(") at 0x%x\n",faulting_address); PANIC("Page fault"); }