// http://www.brokenthorn.com/Resources/OSDev18.html // #include #include "kernel.h" #include "x86.h" #include "mem.h" #include "vmem.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 }; //// //! virtual address typedef uint32_t virtual_addr; typedef uint32_t physical_addr; //// 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) { 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; } physical_addr pd_entry_get_frame (pd_entry* e) { return *e&I86_PDE_FRAME; } 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; } void vmem_free_dir(pdirectory *dir) { x86_paging_disable(); uint32_t virt_addr=0; // first pages are identity mapped (kernel space) just remove links for(int j=0;j<3;j++) { pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt_addr) ]; virt_addr+=1024*4096; } // programm space virt_addr=0x8000000; for(int j=0;j<2;j++) { pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt_addr) ]; ptable *table=pd_entry_get_frame(entry); for (int i=0, virt=virt_addr; i<1024; i++, virt+=4096) { pt_entry pte=&table->m_entries [PAGE_TABLE_INDEX (virt) ]; pmmngr_free_block(pt_entry_get_frame(pte)); // get free space from the memory manager } pmmngr_free_block(pd_entry_get_frame (entry)); virt_addr+=1024*4096; } // stack virt_addr=0x8c00000; for(int j=0;j<1;j++) { pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (virt_addr) ]; ptable *table=pd_entry_get_frame(entry); for (int i=0, virt=virt_addr; i<1024; i++, virt+=4096) { pt_entry pte=&table->m_entries [PAGE_TABLE_INDEX (virt) ]; pmmngr_free_block(pt_entry_get_frame(pte)); // get free space from the memory manager } pmmngr_free_block(pd_entry_get_frame (entry)); virt_addr+=1024*4096; } pmmngr_free_block(dir); x86_paging_enable(); } // // vmem init / also copies all the shit over for FORK // if copy_dir==NULL creates brandnew dir // otherwise copies kernel pages and copies // programm pages procreates new programmspace // // TODO: FIX // KERNEL SPACE HARDCODED TO 5 first PAGES // PROGRAMM SPACE HARDCODED TO 0x8000000+2 pages and 0x8c00000+1 pages // pdirectory* vmem_new_space_dir(pdirectory *copy_dir) { x86_paging_disable(); // pdirectory* dir = (pdirectory*) kballoc(1); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"new pdirectory: 0x%X",dir); if (!dir)panic(FOOLOS_MODULE_NAME,"unable to alloc pdirectory"); // first of all let's zero all the entries for(int i=0;i<1024;i++)dir->m_entries [i]=0; // identity mapping for first blocks uint32_t phys_addr=0; uint32_t virt_addr=0; // first pages are identity mapped for(int j=0;j<5;j++) { // this is the table for our page directory. It maps 1024*4096 bytes ptable* table; // create new tables on init if(copy_dir==NULL) { // alloc space for our new table table = (ptable*) kballoc(1); if (!table)panic(FOOLOS_MODULE_NAME,"unable to alloc 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); } // otherwise simply take existing stuff from pdir 0 else { dir->m_entries[PAGE_DIRECTORY_INDEX(virt_addr)]= copy_dir->m_entries[PAGE_DIRECTORY_INDEX(virt_addr)]; } phys_addr+=1024*4096; virt_addr+=1024*4096; } // programm space virt_addr=0x8000000; for(int j=0;j<2;j++) { ptable* table = (ptable*) kballoc (1); pd_entry *oldentry=NULL; ptable* oldtable=NULL; if(copy_dir!=NULL) { oldentry=&(copy_dir->m_entries[PAGE_DIRECTORY_INDEX(virt_addr)]); oldtable=pd_entry_get_frame(oldentry); } log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"oldtable at: 0x%08X",oldtable); if (!table)panic(FOOLOS_MODULE_NAME,"unable to alloc table"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"alloc table: %08X",table); for (int i=0, virt=virt_addr; i<1024; i++, virt+=4096) { //log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"i = %d",i); 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"); // if this is not init , copy contents from current space! if(copy_dir!=NULL) { uint32_t addr_old=pt_entry_get_frame(&oldtable->m_entries[PAGE_TABLE_INDEX(virt)]); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_FINE,"physical memcpy(0x%08X,0x%08X,4096)",phys_addr, addr_old); memcpy(phys_addr,addr_old,4096); } uint32_t 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; } // programm space virt_addr=0x8c00000; for(int j=0;j<1;j++) { ptable* table = (ptable*) kballoc (1); pd_entry *oldentry=NULL; ptable* oldtable=NULL; if(copy_dir!=NULL) { oldentry=&(copy_dir->m_entries[PAGE_DIRECTORY_INDEX(virt_addr)]); oldtable=pd_entry_get_frame(oldentry); } log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"oldtable at: 0x%08X",oldtable); if (!table)panic(FOOLOS_MODULE_NAME,"unable to alloc table"); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_DEBUG,"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"); // if this is not init , copy contents from current space! if(copy_dir!=NULL) { uint32_t addr_old=pt_entry_get_frame(&oldtable->m_entries[PAGE_TABLE_INDEX(virt)]); log(FOOLOS_MODULE_NAME,FOOLOS_LOG_FINE,"physical memcpy(0x%08X,0x%08X,4096)",phys_addr, addr_old); memcpy(phys_addr,addr_old,4096); } uint32_t 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; } if(copy_dir==NULL) // this happens only on init { log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"initializing virtual memory (paging)"); vmem_set_dir(dir); } //while(1); x86_paging_enable(); return dir; } void vmem_set_dir(pdirectory *dir) { x86_set_pdbr(dir); }