// http://www.brokenthorn.com/Resources/OSDev18.html #include "kernel.h" #include "x86.h" #include "../lib/logger/log.h" // logger facilities #define FOOLOS_MODULE_NAME "vmem" // TODO : why is the frame not 0xfffff?? enum PAGE_PTE_FLAGS { I86_PTE_PRESENT = 1, //0000000000000000000000000000001 I86_PTE_WRITABLE = 2, //0000000000000000000000000000010 I86_PTE_USER = 4, //0000000000000000000000000000100 I86_PTE_WRITETHOUGH = 8, //0000000000000000000000000001000 I86_PTE_NOT_CACHEABLE = 0x10, //0000000000000000000000000010000 I86_PTE_ACCESSED = 0x20, //0000000000000000000000000100000 I86_PTE_DIRTY = 0x40, //0000000000000000000000001000000 I86_PTE_PAT = 0x80, //0000000000000000000000010000000 I86_PTE_CPU_GLOBAL = 0x100, //0000000000000000000000100000000 I86_PTE_LV4_GLOBAL = 0x200, //0000000000000000000001000000000 I86_PTE_FRAME = 0xFFFFF000 //1111111111111111111000000000000 }; enum PAGE_PDE_FLAGS { I86_PDE_PRESENT = 1, //0000000000000000000000000000001 I86_PDE_WRITABLE = 2, //0000000000000000000000000000010 I86_PDE_USER = 4, //0000000000000000000000000000100 I86_PDE_PWT = 8, //0000000000000000000000000001000 I86_PDE_PCD = 0x10, //0000000000000000000000000010000 I86_PDE_ACCESSED = 0x20, //0000000000000000000000000100000 I86_PDE_DIRTY = 0x40, //0000000000000000000000001000000 I86_PDE_4MB = 0x80, //0000000000000000000000010000000 I86_PDE_CPU_GLOBAL = 0x100, //0000000000000000000000100000000 I86_PDE_LV4_GLOBAL = 0x200, //0000000000000000000001000000000 I86_PDE_FRAME = 0xFFFFF000 //1111111111111111111000000000000 }; //! page table entry typedef uint32_t pt_entry; //! a page directery entry typedef uint32_t pd_entry; //// //! virtual address typedef uint32_t virtual_addr; typedef uint32_t physical_addr; typedef uint8_t bool; //! i86 architecture defines 1024 entries per table--do not change #define PAGES_PER_TABLE 1024 #define PAGES_PER_DIR 1024 #define PAGE_DIRECTORY_INDEX(x) (((x) >> 22) & 0x3ff) #define PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3ff) #define PAGE_GET_PHYSICAL_ADDRESS(x) (*x & ~0xfff) //! page table represents 4mb address space #define PTABLE_ADDR_SPACE_SIZE 0x400000 //! directory table represents 4gb address space #define DTABLE_ADDR_SPACE_SIZE 0x100000000 //! page sizes are 4k #define PAGE_SIZE 4096 //! page table typedef struct ptable_struct { pt_entry m_entries[PAGES_PER_TABLE]; }ptable ; //! page directory typedef struct pdirectory_struct { pd_entry m_entries[PAGES_PER_DIR]; }pdirectory; void pt_entry_add_attrib (pt_entry* e, uint32_t attrib) { *e|=attrib; } void pt_entry_del_attrib (pt_entry* e, uint32_t attrib) { *e&=~attrib; } void pt_entry_set_frame (pt_entry* e , physical_addr addr) { // *e = (*e & ~I86_PTE_FRAME) | addr; *e|=I86_PTE_FRAME&addr; } bool pt_entry_is_present (pt_entry e) { return e&I86_PTE_PRESENT; } bool pt_entry_is_writable (pt_entry e) { return e&I86_PTE_WRITABLE; } physical_addr pt_entry_pfn (pt_entry e) { return e&I86_PTE_FRAME; } void pd_entry_add_attrib (pd_entry* e, uint32_t attrib) { *e|=attrib; } void pd_entry_del_attrib (pd_entry* e, uint32_t attrib) { *e&=~attrib; } void pd_entry_set_frame (pd_entry* e, physical_addr add) { *e|=I86_PDE_FRAME&add; } bool pd_entry_is_present (pd_entry e) { return e&I86_PDE_PRESENT; } /* bool pd_entry_is_user (pd_entry e) { return 1; } bool pd_entry_is_4mb (pd_entry e) { return 1; } */ bool pd_entry_is_writable (pd_entry e) { return e&I86_PDE_WRITABLE; } physical_addr pd_entry_pfn (pd_entry e) { return e&I86_PDE_FRAME; } /* void pd_entry_enable_global (pd_entry e) { } */ uint8_t vmmngr_alloc_page (pt_entry* e) { //! allocate a free physical frame void* p = pmmngr_alloc_block (); if (!p) return 0; //! map it to the page pt_entry_set_frame (e, (physical_addr)p); pt_entry_add_attrib (e, I86_PTE_PRESENT); return 1; } void vmmngr_free_page (pt_entry* e) { void* p = (void*)pt_entry_pfn (*e); if (p) pmmngr_free_block (p); pt_entry_del_attrib (e, I86_PTE_PRESENT); } pt_entry* vmmngr_ptable_lookup_entry (ptable* p, virtual_addr addr) { if (p) return &p->m_entries[ PAGE_TABLE_INDEX (addr) ]; return 0; } // TODO !? http://www.brokenthorn.com/Resources/OSDev18.html void vmmngr_map_page (void* phys, void* virt) { } void vmem_init(uint32_t vesa_physbase) { log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"init paging (vesa base: 0x%08x)",vesa_physbase); ptable* table1 = (ptable*) pmmngr_alloc_block (); if (!table1)panic(FOOLOS_MODULE_NAME,"unable to alloc table1"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"table1: 0x%X",table1); ptable* table2 = (ptable*) pmmngr_alloc_block (); if (!table1)panic(FOOLOS_MODULE_NAME,"unable to alloc table2"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"table2: 0x%X",table2); // TODO: 3blocks? pdirectory* dir = (pdirectory*) pmmngr_alloc_block (); if (!dir)panic(FOOLOS_MODULE_NAME,"unable to alloc pdirectory"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"pdirectory: 0x%X",dir); //! map 1mb to 3gb (where we are at) for (int i=0, frame=vesa_physbase, virt=vesa_physbase; i<1024; i++, frame+=4096, virt+=4096) { //! create a new page pt_entry page=0; pt_entry_add_attrib (&page, I86_PTE_PRESENT); pt_entry_set_frame (&page, frame); //! ...and add it to the page table table1->m_entries [PAGE_TABLE_INDEX (virt) ] = page; } //! 1st 4mb are idenitity mapped for (int i=0, frame=0x0, virt=0x00000000; i<1024; i++, frame+=4096, virt+=4096) { //! create a new page pt_entry page=0; pt_entry_add_attrib (&page, I86_PTE_PRESENT); pt_entry_set_frame (&page, frame); //! ...and add it to the page table table2->m_entries [PAGE_TABLE_INDEX (virt) ] = page; } pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (vesa_physbase) ]; *entry=0; pd_entry_add_attrib (entry, I86_PDE_PRESENT); pd_entry_add_attrib (entry, I86_PDE_WRITABLE); pd_entry_set_frame (entry, (physical_addr)table1); pd_entry* entry2 = &dir->m_entries [PAGE_DIRECTORY_INDEX (0x00000000) ]; *entry2=0; pd_entry_add_attrib (entry2, I86_PDE_PRESENT); pd_entry_add_attrib (entry2, I86_PDE_WRITABLE); pd_entry_set_frame (entry2, (physical_addr)table2); x86_set_pdbr(dir); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"enabling paging..."); x86_paging_enable(); }