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