// http://www.brokenthorn.com/Resources/OSDev18.html #include "kernel.h" #include "x86.h" #include "mem.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; #define MAX_PAGEDIRS 10 pdirectory *page_dirs[MAX_PAGEDIRS]; int last_page_dir=0; int current_dir=0; //// 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; } physical_addr pt_entry_get_frame (pt_entry* e) { // *e = (*e & ~I86_PTE_FRAME) | addr; return *e&I86_PTE_FRAME; } 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 show_cr() { log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"cr0: 0x%08x",x86_get_cr0()); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"cr1: 0x%08x",x86_get_cr1()); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"cr2: 0x%08x",x86_get_cr2()); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"cr3: 0x%08x",x86_get_cr3()); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"cr4: 0x%08x",x86_get_cr4()); } uint32_t vmem_alloc_block_at(uint32_t virt_addr) { uint32_t phys_addr=pmmngr_alloc_block(); // get free space from the memory manager if (!phys_addr)panic(FOOLOS_MODULE_NAME,"unable to alloc spce"); pdirectory* dir = page_dirs[current_dir]; pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt_addr) ]; if(entry==0)panic(FOOLOS_MODULE_NAME,"no table present at requested addr :("); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"found entry at %08X",entry); //! create a new page pt_entry page=0; pt_entry_add_attrib (&page, I86_PTE_PRESENT); pt_entry_add_attrib (&page, I86_PTE_WRITABLE); pt_entry_set_frame (&page, phys_addr); //! ...and add it to the page table ptable *table=pt_entry_get_frame(entry); table->m_entries [PAGE_TABLE_INDEX (virt_addr) ] = page; return phys_addr; } */ int vmem_new_space_dir() { x86_paging_disable(); 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); for(int i=0;i<1024;i++)dir->m_entries [i]=0; uint32_t phys_addr=0; uint32_t virt_addr=0; // first pages are identity mapped for(int j=0;j<3;j++) { ptable* table = (ptable*) pmmngr_alloc_block (); if (!table)panic(FOOLOS_MODULE_NAME,"unable to alloc table"); // log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"table: 0x%X",table); //! idenitity mapping for (int i=0, frame=phys_addr, virt=virt_addr; 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_add_attrib (&page, I86_PTE_WRITABLE); pt_entry_set_frame (&page, frame); //! ...and add it to the page table table->m_entries [PAGE_TABLE_INDEX (virt) ] = page; } pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt_addr) ]; *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)table); phys_addr+=1024*4096; virt_addr+=1024*4096; } // programm space (for init) virt_addr=0x8048000; for(int j=0;j<2;j++) { ptable* table = (ptable*) pmmngr_alloc_block (); if (!table)panic(FOOLOS_MODULE_NAME,"unable to alloc table"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"alloc table: %08X",table); for (int i=0, virt=virt_addr; i<1024; i++, virt+=4096) { phys_addr=pmmngr_alloc_block(); // get free space from the memory manager if (!phys_addr)panic(FOOLOS_MODULE_NAME,"unable to alloc spce for frame"); int frame=phys_addr; //! create a new page pt_entry page=0; pt_entry_add_attrib (&page, I86_PTE_PRESENT); pt_entry_add_attrib (&page, I86_PTE_WRITABLE); pt_entry_set_frame (&page, frame); //! ...and add it to the page table table->m_entries [PAGE_TABLE_INDEX (virt) ] = page; } pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt_addr) ]; *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)table); virt_addr+=1024*4096; } page_dirs[last_page_dir]=dir; if(last_page_dir!=0)x86_paging_enable(); return last_page_dir++; } void vmem_set_dir(int dir) { // x86_paging_disable(); x86_set_pdbr(page_dirs[dir]); // log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"set pagedir to %d (0x%08X)",dir,page_dirs[dir]); current_dir=dir; // x86_paging_enable(); } void vmem_init() { //log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"init paging (vesa base: 0x%08x)",vesa_physbase); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"init paging"); vmem_set_dir(vmem_new_space_dir()); x86_paging_enable(); }