diff --git a/src/kernel/vm2/Jamfile b/src/kernel/vm2/Jamfile index ac38aee3cd..626661847e 100644 --- a/src/kernel/vm2/Jamfile +++ b/src/kernel/vm2/Jamfile @@ -2,6 +2,7 @@ SubDir OBOS_TOP src kernel vm2 ; BinCommand vmTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C vnodeManager.C test.C : root be ; BinCommand simpleTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C vnodeManager.C simpleTest.C : root be ; +BinCommand testSetup : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C vnodeManager.C simpleTest.C : root be ; BinCommand hashTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C vnodeManager.C hashTest.C : root be ; BinCommand olTest : error.C olTest.C : root be ; BinCommand pmTest : error.C pageManager.C pageManTest.C page.C : root be ; diff --git a/src/kernel/vm2/TODO b/src/kernel/vm2/TODO index 9f262119b7..0b238be6e4 100644 --- a/src/kernel/vm2/TODO +++ b/src/kernel/vm2/TODO @@ -1,6 +1,5 @@ -1) Must lock original area when clone()ing. Sigh. Also must add ability to clone other process' areas. The issue here is that areaManager is finding the areas. Need to keep a global list of areas for this. An area might well work. -2) Add statistics counting for copy in/out -3) Tests are not done. +1) Change the architecture so that instead of multiple threads of tests, we have multiple apps of tests... +2) Tests are not done. Test: getNextAreaInfo cloneArea @@ -9,10 +8,7 @@ mmap / munmap paging disk caching -4) Change the architecture so that instead of multiple threads of tests, we have multiple apps of tests... -5) Need to make the paging daemon load the pages in, using semaphores. - -- Looks like we *don't* have to do this, based on what is done in NewOS. Need to consult... -6) See how unresolvable page faults and permissions errors are handled - need to properly handle +4) See how unresolvable page faults and permissions errors are handled - need to properly handle * - This may have to come at HW integration time, since they will be app signals, etc... -7) There is no arch-level integration. This is to be tested (to death) in user land first. * == can not be done in user land. +5) There is no arch-level integration. This is to be tested (to death) in user land first. * == can not be done in user land. diff --git a/src/kernel/vm2/area.C b/src/kernel/vm2/area.C index 032a9d97c5..4582676d36 100644 --- a/src/kernel/vm2/area.C +++ b/src/kernel/vm2/area.C @@ -95,6 +95,7 @@ status_t area::createAreaGuts( char *inName, int pageCount, void **address, addr base+=PAGE_SIZE; } dump(); + vmBlock->areas.add(this); return B_OK; } @@ -152,16 +153,13 @@ status_t area::getInfo(area_info *dest) { dest->protection=protection; dest->team=manager->getTeam(); dest->ram_size=0; - dest->in_count=0; - dest->out_count=0; + dest->in_count=in_count; + dest->out_count=out_count; dest->copy_count=0; for (hashIterate hi(vpages);node *cur=hi.get();) { vpage *page=(vpage *)cur; if (page->isMapped()) dest->ram_size+=PAGE_SIZE; - dest->in_count+=PAGE_SIZE; - dest->out_count+=PAGE_SIZE; - dest->copy_count+=PAGE_SIZE; } dest->address=(void *)start_address; return B_OK; @@ -234,7 +232,7 @@ vpage *area::findVPage(unsigned long address) { bool area::fault(void *fault_address, bool writeError) { // true = OK, false = panic. vpage *page=findVPage((unsigned long)fault_address); if (page) - return page->fault(fault_address,writeError); + return page->fault(fault_address,writeError,in_count); else return false; } @@ -271,7 +269,8 @@ void area::setInt(unsigned long address,int value) { // This is for testing only void area::pager(int desperation) { for (hashIterate hi(vpages);node *cur=hi.get();) { vpage *page=(vpage *)cur; - page->pager(desperation); + if (page->pager(desperation)) + out_count++; } } diff --git a/src/kernel/vm2/areaManager.C b/src/kernel/vm2/areaManager.C index fa3d6bb061..459fbb1245 100644 --- a/src/kernel/vm2/areaManager.C +++ b/src/kernel/vm2/areaManager.C @@ -5,14 +5,12 @@ #include "areaPool.h" extern vmHeaderBlock *vmBlock; -bool areaIsLessThan(void *a,void *b) -{ +bool areaIsLessThan(void *a,void *b) { return (((reinterpret_cast(a))->getStartAddress()) < (reinterpret_cast(b))->getStartAddress()); } // This creates the one true lock for this area -areaManager::areaManager(void) -{ +areaManager::areaManager(void) { team=0; // should be proc_get_current_proc_id() myLock=0; myLock=create_sem(1,"Area Manager Semaphore"); // Should have team name in it. @@ -20,8 +18,7 @@ areaManager::areaManager(void) } // Loops over every area looking for someplace where we can get the space we need. -unsigned long areaManager::getNextAddress(int pages, unsigned long start) -{ +unsigned long areaManager::getNextAddress(int pages, unsigned long start) { // This function needs to deal with the possibility that we run out of address space... // areas.dump(); unsigned long end=start+(pages*PAGE_SIZE)-1; @@ -42,8 +39,7 @@ unsigned long areaManager::getNextAddress(int pages, unsigned long start) } // Remove the area from our list, put it on the area pool and move on -void areaManager::freeArea(area_id areaID) -{ +void areaManager::freeArea(area_id areaID) { error ("areaManager::freeArea: begin\n"); lock(); area *oldArea=findArea(areaID); @@ -54,6 +50,7 @@ void areaManager::freeArea(area_id areaID) // error ("areaManager::freeArea: areaManager = %x \n",manager); removeArea(oldArea); // error ("areaManager::freeArea: deleting area %x \n",oldArea); + vmBlock->areas.remove(oldArea); oldArea->freeArea(); // error ("areaManager::freeArea: freeArea complete \n"); vmBlock->areaPool->put(oldArea); @@ -63,8 +60,7 @@ void areaManager::freeArea(area_id areaID) unlock(); } -area *areaManager::findAreaLock(void *address) -{ +area *areaManager::findAreaLock(void *address) { lock(); area *retVal=findArea(address); unlock(); @@ -72,8 +68,7 @@ area *areaManager::findAreaLock(void *address) } // Loops over our areas looking for this one by name -area *areaManager::findArea(char *address) -{ +area *areaManager::findArea(char *address) { error ("Finding area by string\n"); area *retVal=NULL; lock(); @@ -88,8 +83,7 @@ area *areaManager::findArea(char *address) } // Loops over our areas looking for the one whose virtual address matches the passed in address -area *areaManager::findArea(void *address) -{ +area *areaManager::findArea(void *address) { // THIS DOES NOT HAVE LOCKING - all callers must lock. // error ("Finding area by void * address\n"); for (struct node *cur=areas.rock;cur;cur=cur->next) @@ -103,8 +97,7 @@ area *areaManager::findArea(void *address) return NULL; } -area *areaManager::findAreaLock(area_id id) -{ +area *areaManager::findAreaLock(area_id id) { error ("Finding area by areaID \n"); lock(); area *retVal=findArea(id); @@ -113,8 +106,7 @@ area *areaManager::findAreaLock(area_id id) } // Loops over our areas looking for the one whose ID was passed in -area *areaManager::findArea(area_id id) -{ +area *areaManager::findArea(area_id id) { //error ("Finding area by area_id\n"); area *retVal=NULL; for (struct node *cur=areas.rock;cur && !retVal;cur=cur->next) @@ -127,8 +119,7 @@ area *areaManager::findArea(area_id id) } // Find the area whose address matches this page fault and dispatch the fault to it. -bool areaManager::fault(void *fault_address, bool writeError) // true = OK, false = panic. -{ +bool areaManager::fault(void *fault_address, bool writeError) { // true = OK, false = panic. area *myArea; bool retVal; error ("Faulting \n"); @@ -145,8 +136,7 @@ bool areaManager::fault(void *fault_address, bool writeError) // true = OK, fals long areaManager::nextAreaID=0; // Create an area; get a new structure, call setup, create the guts, set its ID, add it to our list -int areaManager::createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect) -{ +int areaManager::createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect) { error ("areaManager::createArea - Creating an area\n"); lock(); area *newArea = new (vmBlock->areaPool->get()) area; @@ -167,14 +157,24 @@ int areaManager::createArea(char *AreaName,int pageCount,void **address, address return retVal; } +area *findAreaGlobal(int areaID) { + for (struct node *cur=vmBlock->areas.rock;cur;cur=cur->next) { + area *myArea=(area *)cur; + if (((area *)(cur))->getAreaID()==areaID) + return myArea; + } + return NULL; +} + // FIX: THIS IS WRONG! It will only clone areas in our areaManager. // Should: find the specified area, create a new area to be its clone, and set it up -int areaManager::cloneArea(int newAreaID,char *AreaName,void **address, addressSpec addType,pageState state,protectType protect) - { +int areaManager::cloneArea(int newAreaID,char *AreaName,void **address, addressSpec addType,pageState state,protectType protect) { int retVal; error ("Cloning an area\n"); lock(); area *oldArea=findArea(newAreaID); + if (!oldArea) + oldArea=findAreaGlobal(newAreaID); if (oldArea) { area *newArea = new (vmBlock->areaPool->get()) area; @@ -191,8 +191,7 @@ int areaManager::cloneArea(int newAreaID,char *AreaName,void **address, addressS return retVal; } -char areaManager::getByte(unsigned long address) -{ +char areaManager::getByte(unsigned long address) { area *myArea; // error ("areaManager::getByte : starting\n"); int retVal; @@ -210,8 +209,7 @@ char areaManager::getByte(unsigned long address) return retVal; } -int areaManager::getInt(unsigned long address) -{ +int areaManager::getInt(unsigned long address) { area *myArea; int retVal; lock(); @@ -228,8 +226,7 @@ int areaManager::getInt(unsigned long address) return retVal; } -void areaManager::setByte(unsigned long address,char value) -{ +void areaManager::setByte(unsigned long address,char value) { // error ("areaManager::setByte : starting\n"); area *myArea; lock(); @@ -245,15 +242,13 @@ void areaManager::setByte(unsigned long address,char value) unlock(); } -void areaManager::setInt(unsigned long address,int value) -{ +void areaManager::setInt(unsigned long address,int value) { area *myArea; lock(); myArea=findArea((void *)address); if (myArea) myArea->setInt(address,value); - else - { + else { char temp[1000]; sprintf (temp,"Unable to find an area for address %d\n",address); throw (temp); @@ -262,11 +257,9 @@ void areaManager::setInt(unsigned long address,int value) } // Call pager for each of our areas -void areaManager::pager(int desperation) -{ +void areaManager::pager(int desperation) { lock(); - for (struct node *cur=areas.rock;cur;cur=cur->next) - { + for (struct node *cur=areas.rock;cur;cur=cur->next) { area *myArea=(area *)cur; //error ("areaManager::pager; area = \n"); //myArea->dump(); @@ -276,11 +269,9 @@ void areaManager::pager(int desperation) } // Call saver for each of our areas -void areaManager::saver(void) -{ +void areaManager::saver(void) { lock(); - for (struct node *cur=areas.rock;cur;cur=cur->next) - { + for (struct node *cur=areas.rock;cur;cur=cur->next) { area *myArea=(area *)cur; myArea->saver(); } @@ -288,8 +279,7 @@ void areaManager::saver(void) } // mmap is basically map POSIX values to ours and call createAreaMappingFile... -void *areaManager::mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) -{ +void *areaManager::mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { char name[MAXPATHLEN]; // Get the filename from fd... strcpy( name,"mmap - need to include fileName"); @@ -299,8 +289,7 @@ void *areaManager::mmap(void *addr, size_t len, int prot, int flags, int fd, off // Not doing anything with MAP_SHARED and MAP_COPY - needs to be done //error ("flags = %x, anon = %x\n",flags,MAP_ANON); lock(); - if (flags & MAP_ANON) - { + if (flags & MAP_ANON) { createArea(name,(int)((len+PAGE_SIZE-1)/PAGE_SIZE),&addr, addType ,LAZY,protType); return addr; } @@ -326,14 +315,12 @@ status_t areaManager::munmap(void *addr,size_t len) status_t retVal=B_OK; lock(); area *myArea=findArea(addr); - if (myArea) - { + if (myArea) { removeArea(myArea); myArea->freeArea(); vmBlock->areaPool->put(myArea); } - else - { + else { error ("areaManager::munmap: unable to find requested area\n"); retVal=B_ERROR; } diff --git a/src/kernel/vm2/testSetup.C b/src/kernel/vm2/testSetup.C new file mode 100644 index 0000000000..9746f64281 --- /dev/null +++ b/src/kernel/vm2/testSetup.C @@ -0,0 +1,30 @@ +#include "vmInterface.h" +#include +#include +#include +#include +#include + +vmInterface *vm; + +int main(int argc,char **argv) +{ + try { + vm = new vmInterface (30); + + while (1) + snooze(1000000); + } + catch (const char *t) + { + error ("Exception thrown! %s\n",t); + exit(1); + } + catch (...) + { + error ("Unknown Exception thrown!\n"); + exit(1); + } + + return 0; +} diff --git a/src/kernel/vm2/vm.h b/src/kernel/vm2/vm.h index 82e0b0b644..85d3c30cf5 100644 --- a/src/kernel/vm2/vm.h +++ b/src/kernel/vm2/vm.h @@ -18,7 +18,7 @@ struct vnode : public node } }; #define B_OS_NAME_LENGTH 32 -enum protectType {none=0,readable, writable,copyOnWrite,symCopyOnWrite}; +enum protectType {none=0,readable, writable,copyOnWrite}; //B_EXACT_ADDRESS You want the value of *addr to be taken literally and strictly. // If the area can't be allocated at that location, the function fails. //B_BASE_ADDRESS The area can start at a location equal to or greater than *addr. diff --git a/src/kernel/vm2/vmHeaderBlock.h b/src/kernel/vm2/vmHeaderBlock.h index 288c3439ab..1215691dd4 100644 --- a/src/kernel/vm2/vmHeaderBlock.h +++ b/src/kernel/vm2/vmHeaderBlock.h @@ -10,6 +10,7 @@ class pageManager; class swapFileManager; class cacheManager; class vnodeManager; +class list; #endif struct vmHeaderBlock @@ -21,6 +22,7 @@ struct vmHeaderBlock swapFileManager *swapMan; cacheManager *cacheMan; vnodeManager *vnodeMan; + list areas; }; #endif diff --git a/src/kernel/vm2/vpage.C b/src/kernel/vm2/vpage.C index d9cc6e2248..15f6f8de36 100644 --- a/src/kernel/vm2/vpage.C +++ b/src/kernel/vm2/vpage.C @@ -102,7 +102,7 @@ void vpage::setProtection(protectType prot) { // This is dispatched by the real interrupt handler, who locates us // true = OK, false = panic. -bool vpage::fault(void *fault_address, bool writeError) { +bool vpage::fault(void *fault_address, bool writeError, int &in_count) { error ("vpage::fault: virtual address = %lx, write = %s\n",(unsigned long) fault_address,((writeError)?"true":"false")); if (writeError && physPage) { // If we already have a page and this is a write, it is either a copy on write or a "dirty" notice dirty=true; @@ -112,7 +112,9 @@ bool vpage::fault(void *fault_address, bool writeError) { memcpy((void *)(newPhysPage->getAddress()),(void *)(physPage->getAddress()),PAGE_SIZE); physPage=newPhysPage; protection=writable; + vmBlock->vnodeMan->remove(*backingNode,*this); backingNode=&(vmBlock->swapMan->findNode()); // Need new backing store for this node, since it was copied, the original is no good... + vmBlock->vnodeMan->addVnode(backingNode,*this); // Update the architecture specific stuff here... } return true; @@ -128,6 +130,7 @@ bool vpage::fault(void *fault_address, bool writeError) { dump(); refresh(); // I wonder if these vnode calls are safe during an interrupt... dirty=false; + in_count++; error ("vpage::fault: Refreshed\n"); dump(); error ("vpage::fault: exiting\n"); @@ -170,18 +173,18 @@ void vpage::setInt(unsigned long address,int value,areaManager *manager) { } // Swaps pages out where necessary. -void vpage::pager(int desperation) { +bool vpage::pager(int desperation) { //error ("vpage::pager start desperation = %d\n",desperation); if (!swappable) - return; + return false; error ("vpage::pager swappable\n"); switch (desperation) { - case 1: return; break; - case 2: if (!physPage || protection!=readable) return;break; - case 3: if (!physPage || dirty) return;break; - case 4: if (!physPage) return;break; - case 5: if (!physPage) return;break; - default: return;break; + case 1: return false; break; + case 2: if (!physPage || protection!=readable) return false;break; + case 3: if (!physPage || dirty) return false;break; + case 4: if (!physPage) return false;break; + case 5: if (!physPage) return false;break; + default: return false;break; } error ("vpage::pager flushing\n"); flush(); @@ -189,11 +192,13 @@ void vpage::pager(int desperation) { vmBlock->pageMan->freePage(physPage); error ("vpage::pager going to NULL\n"); physPage=NULL; + return true; } // Saves dirty pages void vpage::saver(void) { - if (dirty) + if (dirty) { flush(); - dirty=false; + dirty=false; + } } diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h index d73ef8cf63..a3d1a0ff7a 100644 --- a/src/kernel/vm2/vpage.h +++ b/src/kernel/vm2/vpage.h @@ -41,8 +41,8 @@ class vpage : public node bool contains(uint32 address) { return ((start_address<=address) && (end_address>=address)); } // External methods for "server" type calls - bool fault(void *fault_address, bool writeError); // true = OK, false = panic. - void pager(int desperation); + bool fault(void *fault_address, bool writeError, int &in_count); // true = OK, false = panic. + bool pager(int desperation); void saver(void); // Debugging