Initial check in. Very preliminary and not really part of the kernel right now...
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@329 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
SubDir OBOS_TOP src kernel vm2 ;
|
||||||
|
|
||||||
|
Server vmTest : area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C test.C vmInterface.C vpage.C ;
|
||||||
|
|
||||||
|
LinkSharedOSLibs vmTest : root be ;
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
*1) There is no arch-level integration. This is to be tested (to death) in user land first.
|
||||||
|
2) Tests are not done. Barely started.
|
||||||
|
|
||||||
|
5) I use new and delete. I know that doesn't work in kernel land. Not too tough to change, though.
|
||||||
|
6) Need to make the paging daemon load the pages in, using semaphores.
|
||||||
|
|
||||||
|
* == can not be done in user land.
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
#include "area.h"
|
||||||
|
#include "areaManager.h"
|
||||||
|
#include "vpage.h"
|
||||||
|
|
||||||
|
area::area (areaManager *myManager)
|
||||||
|
{
|
||||||
|
manager=myManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long area::mapAddressSpecToAddress(addressSpec type,unsigned long requested,int pageCount)
|
||||||
|
{
|
||||||
|
unsigned long base;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EXACT:
|
||||||
|
base=manager->getNextAddress(pageCount,requested);
|
||||||
|
if (base!=requested)
|
||||||
|
return B_ERROR;
|
||||||
|
break;
|
||||||
|
case BASE:
|
||||||
|
base=manager->getNextAddress(pageCount,requested);
|
||||||
|
break;
|
||||||
|
case ANY:
|
||||||
|
base=manager->getNextAddress(pageCount,USER_BASE);
|
||||||
|
break;
|
||||||
|
case ANY_KERNEL:
|
||||||
|
base=manager->getNextAddress(pageCount,KERNEL_BASE);
|
||||||
|
break;
|
||||||
|
case CLONE: base=0;break; // Not sure what to do...
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t area::createAreaMappingFile(char *name, int pageCount,void **address, addressSpec type,pageState inState,protectType protect,int fd,size_t offset)
|
||||||
|
{
|
||||||
|
unsigned long requested=(unsigned long)(*address); // Hold onto this to make sure that EXACT works...
|
||||||
|
unsigned long base=mapAddressSpecToAddress(type,requested,pageCount);
|
||||||
|
vpage *newPage;
|
||||||
|
vnode newVnode;
|
||||||
|
for (int i=0;i<pageCount;i++)
|
||||||
|
{
|
||||||
|
newVnode.fd=fd;
|
||||||
|
newVnode.offset=offset+PAGE_SIZE*i;
|
||||||
|
newPage = new vpage(base+PAGE_SIZE*i,newVnode,NULL,protect,inState);
|
||||||
|
vpages.add(newPage);
|
||||||
|
}
|
||||||
|
state=inState;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t area::createArea(char *name, int pageCount,void **address, addressSpec type,pageState inState,protectType protect)
|
||||||
|
{
|
||||||
|
unsigned long requested=(unsigned long)(*address); // Hold onto this to make sure that EXACT works...
|
||||||
|
unsigned long base=mapAddressSpecToAddress(type,requested,pageCount);
|
||||||
|
vpage *newPage;
|
||||||
|
vnode newVnode;
|
||||||
|
newVnode.fd=0;
|
||||||
|
newVnode.offset=0;
|
||||||
|
for (int i=0;i<pageCount;i++)
|
||||||
|
{
|
||||||
|
newPage = new vpage(base+PAGE_SIZE*i,newVnode,NULL,protect,inState);
|
||||||
|
vpages.add(newPage);
|
||||||
|
}
|
||||||
|
state=inState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void area::freeArea(void)
|
||||||
|
{
|
||||||
|
for (struct node *cur=vpages.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
vpage *page=(vpage *)cur;
|
||||||
|
page->flush();
|
||||||
|
delete page; // Probably need to add a destructor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t area::getInfo(area_info *dest)
|
||||||
|
{
|
||||||
|
strcpy(dest->name,name);
|
||||||
|
dest->size=end_address-start_address;
|
||||||
|
dest->lock=state;
|
||||||
|
dest->team=manager->getTeam();
|
||||||
|
dest->ram_size=0;
|
||||||
|
dest->in_count=0;
|
||||||
|
dest->out_count=0;
|
||||||
|
dest->copy_count=0;
|
||||||
|
for (struct node *cur=vpages.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool area::contains(void *address)
|
||||||
|
{
|
||||||
|
unsigned long base=(unsigned long)(address);
|
||||||
|
return ((start_address>=base) && (end_address<=base));
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t area::resize(size_t newSize)
|
||||||
|
{
|
||||||
|
size_t oldSize =end_address-start_address;
|
||||||
|
if (newSize==oldSize)
|
||||||
|
return B_OK;
|
||||||
|
if (newSize>oldSize)
|
||||||
|
{
|
||||||
|
int pageCount = (newSize-oldSize) / PAGE_SIZE;
|
||||||
|
vpage *newPage;
|
||||||
|
vnode newVnode;
|
||||||
|
newVnode.fd=0;
|
||||||
|
newVnode.offset=0;
|
||||||
|
for (int i=0;i<pageCount;i++)
|
||||||
|
{
|
||||||
|
newPage = new vpage(end_address+PAGE_SIZE*i-1,newVnode,NULL,protection,state);
|
||||||
|
vpages.add(newPage);
|
||||||
|
}
|
||||||
|
end_address+=start_address+newSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pageCount = (oldSize -newSize) / PAGE_SIZE;
|
||||||
|
vpage *oldPage;
|
||||||
|
struct node *cur;
|
||||||
|
for (int i=0;i<pageCount;i++) // This is probably really slow. Adding an "end" to list would be faster.
|
||||||
|
{
|
||||||
|
for (cur=vpages.rock;cur->next;cur=cur->next); // INTENTIONAL - find the last one;
|
||||||
|
vpage *oldPage=(vpage *)cur;
|
||||||
|
delete oldPage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t area::setProtection(protectType prot)
|
||||||
|
{
|
||||||
|
for (struct node *cur=vpages.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
vpage *page=(vpage *)cur;
|
||||||
|
page->setProtection(prot);
|
||||||
|
}
|
||||||
|
protection=prot;
|
||||||
|
}
|
||||||
|
|
||||||
|
vpage *area::findVPage(unsigned long address)
|
||||||
|
{
|
||||||
|
for (struct node *cur=vpages.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
vpage *page=(vpage *)cur;
|
||||||
|
if (page->contains(address))
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char area::getByte(unsigned long address) // This is for testing only
|
||||||
|
{
|
||||||
|
vpage *page=findVPage(address);
|
||||||
|
if (page)
|
||||||
|
return page->getByte(address);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void area::setByte(unsigned long address,char value) // This is for testing only
|
||||||
|
{
|
||||||
|
vpage *page=findVPage(address);
|
||||||
|
if (page)
|
||||||
|
page->setByte(address,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int area::getInt(unsigned long address) // This is for testing only
|
||||||
|
{
|
||||||
|
vpage *page=findVPage(address);
|
||||||
|
if (page)
|
||||||
|
page->getInt(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void area::setInt(unsigned long address,int value) // This is for testing only
|
||||||
|
{
|
||||||
|
vpage *page=findVPage(address);
|
||||||
|
if (page)
|
||||||
|
page->setInt(address,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void area::pager(int desperation)
|
||||||
|
{
|
||||||
|
for (struct node *cur=vpages.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
vpage *page=(vpage *)cur;
|
||||||
|
page->pager(desperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void area::saver(void)
|
||||||
|
{
|
||||||
|
for (struct node *cur=vpages.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
vpage *page=(vpage *)cur;
|
||||||
|
page->saver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#ifndef _AREA_H
|
||||||
|
#define _AREA_H
|
||||||
|
#include "OS.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
class areaManager;
|
||||||
|
class vpage;
|
||||||
|
|
||||||
|
class area : public node
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
list vpages;
|
||||||
|
char name[B_OS_NAME_LENGTH];
|
||||||
|
pageState state;
|
||||||
|
protectType protection;
|
||||||
|
int areaID;
|
||||||
|
int in_count;
|
||||||
|
int out_count;
|
||||||
|
int copy_count;
|
||||||
|
areaManager *manager;
|
||||||
|
unsigned long start_address;
|
||||||
|
unsigned long end_address;
|
||||||
|
vpage *findVPage(unsigned long);
|
||||||
|
public:
|
||||||
|
area(areaManager *myManager);
|
||||||
|
bool nameMatch(char *matchName) {return (strcmp(matchName,name)==0);}
|
||||||
|
unsigned long mapAddressSpecToAddress(addressSpec type,unsigned long requested,int pageCount);
|
||||||
|
status_t createAreaMappingFile(char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect,int fd,size_t offset);
|
||||||
|
status_t createArea (char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect);
|
||||||
|
int getAreaID(void) {return areaID;}
|
||||||
|
void setAreaID(int id) {areaID=id;}
|
||||||
|
void freeArea(void);
|
||||||
|
status_t getInfo(area_info *dest);
|
||||||
|
bool contains(void *address);
|
||||||
|
status_t resize(size_t newSize);
|
||||||
|
status_t setProtection(protectType prot);
|
||||||
|
bool couldAdd(unsigned long start,unsigned long end) { return ((end<start_address) || (start>end_address));}
|
||||||
|
unsigned long getEndAddress(void) {return end_address;}
|
||||||
|
void pager(int desperation);
|
||||||
|
void saver(void);
|
||||||
|
|
||||||
|
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
|
||||||
|
|
||||||
|
char getByte(unsigned long ); // This is for testing only
|
||||||
|
void setByte(unsigned long ,char value); // This is for testing only
|
||||||
|
int getInt(unsigned long ); // This is for testing only
|
||||||
|
void setInt(unsigned long ,int value); // This is for testing only
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#include "areaManager.h"
|
||||||
|
|
||||||
|
areaManager::areaManager(void)
|
||||||
|
{
|
||||||
|
team=0; // should be proc_get_current_proc_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long areaManager::getNextAddress(int pages, unsigned long start)
|
||||||
|
{
|
||||||
|
unsigned long end=start+(pages*PAGE_SIZE)-1;
|
||||||
|
for (struct node *cur=areas.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
if (cur)
|
||||||
|
{
|
||||||
|
area *myArea=(area *)cur;
|
||||||
|
if (!myArea->couldAdd(start,end))
|
||||||
|
{ // if we don't work, there must be an overlap, so go to the end of this area.
|
||||||
|
start=myArea->getEndAddress();
|
||||||
|
end=start+(pages*PAGE_SIZE)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
area *areaManager::findArea(char *address)
|
||||||
|
{
|
||||||
|
for (struct node *cur=areas.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
area *myArea=(area *)cur;
|
||||||
|
if (myArea->nameMatch(address))
|
||||||
|
return myArea;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
area *areaManager::findArea(void *address)
|
||||||
|
{
|
||||||
|
for (struct node *cur=areas.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
area *myArea=(area *)cur;
|
||||||
|
if (myArea->contains(address))
|
||||||
|
return myArea;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
area *areaManager::findArea(area_id id)
|
||||||
|
{
|
||||||
|
for (struct node *cur=areas.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
area *myArea=(area *)cur;
|
||||||
|
if (myArea->getAreaID()==id)
|
||||||
|
return myArea;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool areaManager::fault(void *fault_address, bool writeError) // true = OK, false = panic.
|
||||||
|
{
|
||||||
|
area *myArea;
|
||||||
|
if (myArea=findArea(fault_address))
|
||||||
|
return myArea->fault(fault_address,writeError);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char areaManager::getByte(unsigned long address)
|
||||||
|
{
|
||||||
|
area *myArea;
|
||||||
|
if (myArea=findArea((void *)address))
|
||||||
|
return myArea->getByte(address);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int areaManager::getInt(unsigned long address)
|
||||||
|
{
|
||||||
|
area *myArea;
|
||||||
|
if (myArea=findArea((void *)address))
|
||||||
|
return myArea->getInt(address);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void areaManager::setByte(unsigned long offset,char value)
|
||||||
|
{
|
||||||
|
area *myArea;
|
||||||
|
if (myArea=findArea((void *)offset))
|
||||||
|
myArea->setByte(offset,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void areaManager::setInt(unsigned long offset,int value)
|
||||||
|
{
|
||||||
|
area *myArea;
|
||||||
|
if (myArea=findArea((void *)offset))
|
||||||
|
myArea->setInt(offset,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void areaManager::pager(int desperation)
|
||||||
|
{
|
||||||
|
for (struct node *cur=areas.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
area *myArea=(area *)cur;
|
||||||
|
myArea->pager(desperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void areaManager::saver(void)
|
||||||
|
{
|
||||||
|
for (struct node *cur=areas.rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
area *myArea=(area *)cur;
|
||||||
|
myArea->saver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include "area.h"
|
||||||
|
|
||||||
|
class areaManager // One of these per process
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
list areas;
|
||||||
|
team_id team;
|
||||||
|
public:
|
||||||
|
areaManager ();
|
||||||
|
void addArea(area *newArea) {areas.add(newArea);}
|
||||||
|
void removeArea(area *oldArea) {areas.remove(oldArea); }
|
||||||
|
team_id getTeam(void) {return team;}
|
||||||
|
unsigned long getNextAddress(int pages,unsigned long minimum=USER_BASE);
|
||||||
|
area *findArea(void *address);
|
||||||
|
area *findArea(char *address);
|
||||||
|
area *findArea(area_id id);
|
||||||
|
void pager(int desperation);
|
||||||
|
void saver(void);
|
||||||
|
|
||||||
|
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
|
||||||
|
|
||||||
|
char getByte(unsigned long offset); // This is for testing only
|
||||||
|
void setByte(unsigned long offset,char value); // This is for testing only
|
||||||
|
int getInt(unsigned long offset); // This is for testing only
|
||||||
|
void setInt(unsigned long offset,int value); // This is for testing only
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include <cacheManager.h>
|
||||||
|
|
||||||
|
cacheManager::cacheManager(void) : area (NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cacheManager::findBlock(vnode *target,bool readOnly)
|
||||||
|
{
|
||||||
|
if (!cacheMembers.rock)
|
||||||
|
return NULL;
|
||||||
|
for (struct cacheMember *cur=((cacheMember *)cacheMembers.rock);cur;cur=((cacheMember *)cur->next))
|
||||||
|
{
|
||||||
|
if ((target==cur->vn) && (readOnly || (cur->vp->getProtection()>=writable)))
|
||||||
|
return (cur->vp->getStartAddress());
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cacheManager::createBlock(vnode *target,bool readOnly)
|
||||||
|
{
|
||||||
|
bool foundSpot=false;
|
||||||
|
vpage *prev=NULL,*cur=NULL;
|
||||||
|
unsigned long begin=CACHE_BEGIN;
|
||||||
|
if (vpages.rock)
|
||||||
|
for (cur=((vpage *)(vpages.rock));!foundSpot && cur;cur=(vpage *)(cur->next))
|
||||||
|
if (cur->getStartAddress()!=(void *)begin)
|
||||||
|
foundSpot=true;
|
||||||
|
else // no joy
|
||||||
|
{
|
||||||
|
begin+=PAGE_SIZE;
|
||||||
|
prev=cur;
|
||||||
|
}
|
||||||
|
// Create a vnode here
|
||||||
|
vpage *newPage = new vpage(begin,*target,NULL,((readOnly)?readable:writable),NO_LOCK);
|
||||||
|
vpages.add(newPage);
|
||||||
|
cacheMembers.add(newPage);
|
||||||
|
// return address from this vnode
|
||||||
|
return (void *)begin;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cacheManager::readBlock(vnode *target)
|
||||||
|
{
|
||||||
|
void *destination=findBlock(target,true);
|
||||||
|
if (destination) return destination;
|
||||||
|
return createBlock(target,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *cacheManager::writeBlock(vnode *target)
|
||||||
|
{
|
||||||
|
void *destination=findBlock(target,false);
|
||||||
|
if (destination) return destination;
|
||||||
|
return createBlock(target,false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#include <list.h>
|
||||||
|
#include <vm.h>
|
||||||
|
#include <vpage.h>
|
||||||
|
#include <area.h>
|
||||||
|
|
||||||
|
struct cacheMember : public node
|
||||||
|
{
|
||||||
|
vnode *vn;
|
||||||
|
vpage *vp;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cacheManager : public area
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
list cacheMembers; // Yes, this is slow and should be a hash table. This should be done prior to
|
||||||
|
// moving into the kernel, so we can test it better.
|
||||||
|
// While this very much mirrors the area's vpage list, it won't when it is a hash table...
|
||||||
|
void *findBlock (vnode *target,bool readOnly);
|
||||||
|
void *createBlock (vnode *target,bool readOnly);
|
||||||
|
public:
|
||||||
|
// For these two, the VFS passes in the target vnode
|
||||||
|
// Return value is the address. Note that the paging daemon does the actual loading
|
||||||
|
cacheManager(void);
|
||||||
|
void *readBlock (vnode *target);
|
||||||
|
void *writeBlock (vnode *target);
|
||||||
|
void pager(int desperation); // override, as we should blow away useless nodes, not just free blocks.
|
||||||
|
void saver(void); // Override - not sure why
|
||||||
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef _LIST_H
|
||||||
|
#define _LIST_H
|
||||||
|
// Simple linked list
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct node
|
||||||
|
{
|
||||||
|
node *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
class list {
|
||||||
|
public:
|
||||||
|
list(void) {nodeCount=0;rock=NULL;}
|
||||||
|
void add (void *in)
|
||||||
|
{
|
||||||
|
struct node *newNode=(node *)in;
|
||||||
|
newNode->next=rock;
|
||||||
|
rock=newNode;
|
||||||
|
nodeCount++;
|
||||||
|
}
|
||||||
|
int count(void) {return nodeCount;}
|
||||||
|
void *next(void) {nodeCount--;node *n=rock;if (rock) rock=rock->next;return rock;}
|
||||||
|
void remove(void *in)
|
||||||
|
{
|
||||||
|
struct node *toNuke=(node *)in;
|
||||||
|
for (struct node *cur=rock;cur;cur=cur->next)
|
||||||
|
if (cur->next==toNuke)
|
||||||
|
{
|
||||||
|
cur->next=toNuke->next;
|
||||||
|
cur=NULL; // To bust out of the loop...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void dump(void)
|
||||||
|
{
|
||||||
|
for (struct node *cur=rock;cur;cur=cur->next)
|
||||||
|
{
|
||||||
|
printf ("At %x, next = %x\n",cur,cur->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct node *rock;
|
||||||
|
private:
|
||||||
|
int nodeCount;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/* $NetBSD: mman.h,v 1.24.2.1 2000/11/20 18:11:32 bouyer Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1982, 1986, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @(#)mman.h 8.2 (Berkeley) 1/9/95
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SYS_MMAN_H_
|
||||||
|
#define _SYS_MMAN_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protections are chosen from these bits, or-ed together
|
||||||
|
*/
|
||||||
|
#define PROT_NONE 0x00 /* no permissions */
|
||||||
|
#define PROT_READ 0x01 /* pages can be read */
|
||||||
|
#define PROT_WRITE 0x02 /* pages can be written */
|
||||||
|
#define PROT_EXEC 0x04 /* pages can be executed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags contain sharing type and options.
|
||||||
|
* Sharing types; choose one.
|
||||||
|
*/
|
||||||
|
#define MAP_SHARED 0x0001 /* share changes */
|
||||||
|
#define MAP_PRIVATE 0x0002 /* changes are private */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deprecated flag; these are treated as MAP_PRIVATE internally by
|
||||||
|
* the kernel.
|
||||||
|
*/
|
||||||
|
#define MAP_COPY 0x0004 /* "copy" region at mmap time */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Other flags
|
||||||
|
*/
|
||||||
|
#define MAP_FIXED 0x0010 /* map addr must be exactly as requested */
|
||||||
|
#define MAP_RENAME 0x0020 /* Sun: rename private pages to file */
|
||||||
|
#define MAP_NORESERVE 0x0040 /* Sun: don't reserve needed swap area */
|
||||||
|
#define MAP_INHERIT 0x0080 /* region is retained after exec */
|
||||||
|
#define MAP_NOEXTEND 0x0100 /* for MAP_FILE, don't change file size */
|
||||||
|
#define MAP_HASSEMAPHORE 0x0200 /* region may contain semaphores */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mapping type
|
||||||
|
*/
|
||||||
|
#define MAP_FILE 0x0000 /* map from file (default) */
|
||||||
|
#define MAP_ANON 0x1000 /* allocated from memory, swap space */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error indicator returned by mmap(2)
|
||||||
|
*/
|
||||||
|
#define MAP_FAILED ((void *) -1) /* mmap() failed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags to msync
|
||||||
|
*/
|
||||||
|
#define MS_ASYNC 0x01 /* perform asynchronous writes */
|
||||||
|
#define MS_INVALIDATE 0x02 /* invalidate cached data */
|
||||||
|
#define MS_SYNC 0x04 /* perform synchronous writes */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags to mlockall
|
||||||
|
*/
|
||||||
|
#define MCL_CURRENT 0x01 /* lock all pages currently mapped */
|
||||||
|
#define MCL_FUTURE 0x02 /* lock all pages mapped in the future */
|
||||||
|
|
||||||
|
#if !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)
|
||||||
|
/*
|
||||||
|
* Advice to madvise
|
||||||
|
*/
|
||||||
|
#define MADV_NORMAL 0 /* no further special treatment */
|
||||||
|
#define MADV_RANDOM 1 /* expect random page references */
|
||||||
|
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
|
||||||
|
#define MADV_WILLNEED 3 /* will need these pages */
|
||||||
|
#define MADV_DONTNEED 4 /* dont need these pages */
|
||||||
|
#define MADV_SPACEAVAIL 5 /* insure that resources are reserved */
|
||||||
|
#define MADV_FREE 6 /* pages are empty, free them */
|
||||||
|
/*
|
||||||
|
* Flags to minherit
|
||||||
|
*/
|
||||||
|
#define MAP_INHERIT_SHARE 0 /* share with child */
|
||||||
|
#define MAP_INHERIT_COPY 1 /* copy into child */
|
||||||
|
#define MAP_INHERIT_NONE 2 /* absent from child */
|
||||||
|
#define MAP_INHERIT_DONATE_COPY 3 /* copy and delete -- not
|
||||||
|
implemented in UVM */
|
||||||
|
#define MAP_INHERIT_DEFAULT MAP_INHERIT_COPY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !_SYS_MMAN_H_ */
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "page.h"
|
||||||
|
|
||||||
|
void page::zero(void)
|
||||||
|
{
|
||||||
|
for (int i=0;i<(PAGE_SIZE/4);i++)
|
||||||
|
((long *)physicalAddress)[i]=0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef _PAGE_H
|
||||||
|
#define _PAGE_H
|
||||||
|
#include "vm.h"
|
||||||
|
#include "list.h"
|
||||||
|
class page : public node {
|
||||||
|
private:
|
||||||
|
void *cpuSpecific;
|
||||||
|
void *physicalAddress;
|
||||||
|
public:
|
||||||
|
page(void *address) : physicalAddress(address) {} ;
|
||||||
|
void zero(void);
|
||||||
|
unsigned long getAddress(void) {return (unsigned long)physicalAddress;}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#include "pageManager.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void *addOffset(void *base,unsigned long offset)
|
||||||
|
{
|
||||||
|
return (void *)(((unsigned long)base+offset));
|
||||||
|
}
|
||||||
|
pageManager::pageManager(int pages)
|
||||||
|
{
|
||||||
|
// This is compatability for in BeOS usage only...
|
||||||
|
void *area;
|
||||||
|
if (0>=create_area("vm_test",&area,B_ANY_ADDRESS,B_PAGE_SIZE*pages,B_NO_LOCK,B_READ_AREA|B_WRITE_AREA))
|
||||||
|
{
|
||||||
|
printf ("No memory!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (int i=0;i<pages;i++)
|
||||||
|
unused.add(new page(addOffset(area,i*PAGE_SIZE)));
|
||||||
|
// unused.add(new page((void *)(i*PAGE_SIZE)));
|
||||||
|
cleanLock=create_sem (1,"clean_lock");
|
||||||
|
unusedLock=create_sem (1,"unused_lock");
|
||||||
|
inUseLock=create_sem (1,"inuse_lock");
|
||||||
|
totalPages=pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
page *pageManager::getPage(void)
|
||||||
|
{
|
||||||
|
page *ret=NULL;
|
||||||
|
// printf ("Checking clean\n");
|
||||||
|
if (clean.count())
|
||||||
|
{
|
||||||
|
acquire_sem(cleanLock);
|
||||||
|
ret=(page *)clean.next();
|
||||||
|
release_sem(cleanLock);
|
||||||
|
} // This could fail if someone swoops in and steal our page.
|
||||||
|
if (!ret && unused.count())
|
||||||
|
{
|
||||||
|
// printf ("Checking unused\n");
|
||||||
|
acquire_sem(unusedLock);
|
||||||
|
ret=(page *)unused.next();
|
||||||
|
release_sem(unusedLock);
|
||||||
|
// printf ("ret = %x\n",ret);
|
||||||
|
if (ret)
|
||||||
|
ret->zero();
|
||||||
|
} // This could fail if someone swoops in and steal our page.
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
acquire_sem(inUseLock);
|
||||||
|
inUse.add(ret);
|
||||||
|
release_sem(inUseLock);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pageManager::freePage(page *toFree)
|
||||||
|
{
|
||||||
|
acquire_sem(inUseLock);
|
||||||
|
inUse.remove(toFree);
|
||||||
|
release_sem(inUseLock);
|
||||||
|
acquire_sem(unusedLock);
|
||||||
|
unused.add(toFree);
|
||||||
|
release_sem(unusedLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pageManager::cleaner(void)
|
||||||
|
{
|
||||||
|
if (unused.count())
|
||||||
|
{
|
||||||
|
acquire_sem(unusedLock);
|
||||||
|
page *first=(page *)unused.next();
|
||||||
|
first->zero();
|
||||||
|
acquire_sem(cleanLock);
|
||||||
|
clean.add(first);
|
||||||
|
release_sem(cleanLock);
|
||||||
|
release_sem(unusedLock);
|
||||||
|
snooze(250000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pageManager::desperation(void)
|
||||||
|
{ // Formula to determine how desperate system is to get pages back...
|
||||||
|
int percentClean=(unused.count()+clean.count())/totalPages;
|
||||||
|
if (percentClean>30) return 1;
|
||||||
|
return (35-percentClean)/5;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _PAGE_MANAGER_H
|
||||||
|
#define _PAGE_MANAGER_H
|
||||||
|
#include "/boot/develop/headers/be/kernel/OS.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "page.h"
|
||||||
|
|
||||||
|
class pageManager {
|
||||||
|
public:
|
||||||
|
pageManager(int);
|
||||||
|
page *getPage(void);
|
||||||
|
void freePage(page *);
|
||||||
|
void cleaner(void);
|
||||||
|
int desperation(void);
|
||||||
|
private:
|
||||||
|
list clean,unused,inUse;
|
||||||
|
sem_id cleanLock,unusedLock,inUseLock;
|
||||||
|
int totalPages;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "swapFileManager.h"
|
||||||
|
//#include <stdio.h>
|
||||||
|
|
||||||
|
swapFileManager::swapFileManager(void)
|
||||||
|
{
|
||||||
|
swapFile = open("/tmp/OBOS_swap",O_RDWR );
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapFileManager::write_block(vnode node,void *loc,unsigned long size)
|
||||||
|
{
|
||||||
|
lseek(node.fd,SEEK_SET,node.offset);
|
||||||
|
write(node.fd,loc,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapFileManager::read_block(vnode node,void *loc,unsigned long size)
|
||||||
|
{
|
||||||
|
lseek(node.fd,SEEK_SET,node.offset);
|
||||||
|
read(node.fd,loc,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
vnode swapFileManager::findNode(void)
|
||||||
|
{
|
||||||
|
vnode tmp;
|
||||||
|
tmp.fd=swapFile;
|
||||||
|
tmp.offset=maxNode+=PAGE_SIZE; // Can't ever free, swap file grows forever... :-(
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
class swapFileManager {
|
||||||
|
public:
|
||||||
|
swapFileManager (void);
|
||||||
|
vnode findNode(void); // Get an unused node
|
||||||
|
void write_block(vnode node,void *loc,unsigned long size);
|
||||||
|
void read_block(vnode node,void *loc,unsigned long size);
|
||||||
|
private:
|
||||||
|
int swapFile;
|
||||||
|
unsigned long maxNode;
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "vmInterface.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc,char **argv)
|
||||||
|
{
|
||||||
|
vmInterface vm(10);
|
||||||
|
|
||||||
|
void *addr;
|
||||||
|
vm.createArea("Mine",1,&addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef _VM_TYPES
|
||||||
|
#define _VM_TYPES
|
||||||
|
|
||||||
|
const int PAGE_SIZE = 4096;
|
||||||
|
struct vnode
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
unsigned long offset;
|
||||||
|
};
|
||||||
|
typedef unsigned long owningProcess;
|
||||||
|
#define B_OS_NAME_LENGTH 32
|
||||||
|
enum protectType {none=0,readable, writable,copyOnWrite,symCopyOnWrite};
|
||||||
|
enum pageState {FULL,CONTIGUOUS,LAZY,NO_LOCK,LOMEM};
|
||||||
|
enum addressSpec {EXACT,BASE,ANY,ANY_KERNEL,CLONE};
|
||||||
|
#define USER_BASE 0
|
||||||
|
#define KERNEL_BASE 0x80000000
|
||||||
|
#define CACHE_BEGIN 0x90000000
|
||||||
|
#define CACHE_END 0xe0000000
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#include "vmInterface.h"
|
||||||
|
#include "areaManager.h"
|
||||||
|
#include "mman.h"
|
||||||
|
|
||||||
|
areaManager am;
|
||||||
|
|
||||||
|
areaManager *getAM(void)
|
||||||
|
{
|
||||||
|
// Normally, we would go to the current user process to get this. Since there no such thing exists here...
|
||||||
|
return &am;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmInterface::getAreaByAddress(void *address)
|
||||||
|
{
|
||||||
|
area *myArea = getAM()->findArea(address);
|
||||||
|
if (myArea)
|
||||||
|
return myArea->getAreaID();
|
||||||
|
else
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t vmInterface::setAreaProtection(int Area,protectType prot)
|
||||||
|
{
|
||||||
|
area *myArea = getAM()->findArea(Area);
|
||||||
|
if (myArea)
|
||||||
|
return myArea->setProtection(prot);
|
||||||
|
else
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t vmInterface::resizeArea(int Area,size_t size)
|
||||||
|
{
|
||||||
|
area *oldArea;
|
||||||
|
oldArea=getAM()->findArea(Area);
|
||||||
|
if (oldArea)
|
||||||
|
return oldArea->resize(size);
|
||||||
|
else
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmInterface::createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect)
|
||||||
|
{
|
||||||
|
area *newArea = new area(getAM());
|
||||||
|
newArea->createArea(AreaName,pageCount,address,addType,state,protect);
|
||||||
|
newArea->setAreaID(nextAreaID++); // THIS IS NOT THREAD SAFE
|
||||||
|
getAM()->addArea(newArea);
|
||||||
|
return newArea->getAreaID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmInterface::freeArea(int Area)
|
||||||
|
{
|
||||||
|
area *oldArea=getAM()->findArea(Area);
|
||||||
|
getAM()->removeArea(oldArea);
|
||||||
|
delete oldArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t vmInterface::getAreaInfo(int Area,area_info *dest)
|
||||||
|
{
|
||||||
|
area *oldArea=getAM()->findArea(Area);
|
||||||
|
return oldArea->getInfo(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t vmInterface::getNextAreaInfo(int process,int32 *cookie,area_info *dest)
|
||||||
|
// Left for later..
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmInterface::getAreaByName(char *name)
|
||||||
|
{
|
||||||
|
return getAM()->findArea(name)->getAreaID();
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmInterface::cloneArea(int area,char *AreaName,void **address, addressSpec addType=ANY, pageState state=NO_LOCK, protectType prot=writable)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmInterface::pager(void)
|
||||||
|
{
|
||||||
|
// This should iterate over all processes...
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
am.pager(pageMan.desperation());
|
||||||
|
snooze(250000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmInterface::saver(void)
|
||||||
|
{
|
||||||
|
// This should iterate over all processes...
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
am.saver();
|
||||||
|
snooze(250000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmInterface::cleaner(void)
|
||||||
|
{
|
||||||
|
// This loops on its own
|
||||||
|
pageMan.cleaner();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vmInterface::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");
|
||||||
|
|
||||||
|
addressSpec addType=((flags|MAP_FIXED)?EXACT:ANY);
|
||||||
|
protectType protType=(prot|PROT_WRITE)?writable:(prot|PROT_READ)?readable:none;
|
||||||
|
// Not doing anything with MAP_SHARED and MAP_COPY - needs to be done
|
||||||
|
if (flags | MAP_ANON)
|
||||||
|
{
|
||||||
|
createArea(name,(int)((len+PAGE_SIZE-1)/PAGE_SIZE),&addr, addType ,LAZY,protType);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
area *newArea = new area(getAM());
|
||||||
|
newArea->createAreaMappingFile(name,(int)((len+PAGE_SIZE-1)/PAGE_SIZE),&addr,addType,LAZY,protType,fd,offset);
|
||||||
|
newArea->setAreaID(nextAreaID++); // THIS IS NOT THREAD SAFE
|
||||||
|
getAM()->addArea(newArea);
|
||||||
|
newArea->getAreaID();
|
||||||
|
return addr;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#include "vm.h"
|
||||||
|
#include "pageManager.h"
|
||||||
|
#include "swapFileManager.h"
|
||||||
|
class vmInterface // This is the class that "owns" all of the managers.
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
swapFileManager swapMan;
|
||||||
|
pageManager pageMan;
|
||||||
|
int nextAreaID;
|
||||||
|
public:
|
||||||
|
vmInterface(int pages) : pageMan(pages) {nextAreaID=0;};
|
||||||
|
int createArea(char *AreaName,int pageCount,void **address,
|
||||||
|
addressSpec addType=ANY,
|
||||||
|
pageState state=NO_LOCK,protectType protect=writable);
|
||||||
|
void freeArea(int Area);
|
||||||
|
status_t getAreaInfo(int Area,area_info *dest);
|
||||||
|
status_t getNextAreaInfo(int process,int32 *cookie,area_info *dest);
|
||||||
|
int getAreaByName(char *name);
|
||||||
|
int getAreaByAddress(void *address);
|
||||||
|
int cloneArea(int area,char *AreaName,void **address,
|
||||||
|
addressSpec addType=ANY,
|
||||||
|
pageState state=NO_LOCK,
|
||||||
|
protectType prot=writable);
|
||||||
|
status_t resizeArea(int area,size_t size);
|
||||||
|
status_t setAreaProtection(int area,protectType prot);
|
||||||
|
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
|
||||||
|
void pager(void);
|
||||||
|
void saver(void);
|
||||||
|
void cleaner(void);
|
||||||
|
};
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#include "vpage.h"
|
||||||
|
|
||||||
|
swapFileManager *vpage::swapMan;
|
||||||
|
pageManager *vpage::pageMan;
|
||||||
|
|
||||||
|
void vpage::flush(void)
|
||||||
|
{
|
||||||
|
if (protection==writable && dirty)
|
||||||
|
swapMan->write_block(backingNode,physPage, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpage::refresh(void)
|
||||||
|
{
|
||||||
|
swapMan->read_block(backingNode,physPage, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
vpage *vpage::clone(unsigned long address) // The calling method will have to create this...
|
||||||
|
{
|
||||||
|
vnode node;
|
||||||
|
node.fd=0;
|
||||||
|
node.offset=0;
|
||||||
|
return new vpage(address,node,physPage,(protection==readable)?protection:copyOnWrite,LAZY); // Not sure if LAZY is right or not
|
||||||
|
}
|
||||||
|
|
||||||
|
// backing and/or physMem can be NULL/0.
|
||||||
|
vpage::vpage(unsigned long start,vnode backing, page *physMem,protectType prot,pageState state)
|
||||||
|
{
|
||||||
|
start_address=start;
|
||||||
|
end_address=start+PAGE_SIZE-1;
|
||||||
|
protection=prot;
|
||||||
|
swappable=(state==NO_LOCK);
|
||||||
|
if (backing.fd=0)
|
||||||
|
backingNode=swapMan->findNode();
|
||||||
|
else
|
||||||
|
backingNode=backing;
|
||||||
|
if (!physPage && (state!=LAZY) && (state!=NO_LOCK))
|
||||||
|
physPage=pageMan->getPage();
|
||||||
|
else
|
||||||
|
physPage=physMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpage::setProtection(protectType prot)
|
||||||
|
{
|
||||||
|
protection=prot;
|
||||||
|
// Change the hardware
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vpage::fault(void *fault_address, bool writeError) // true = OK, false = panic.
|
||||||
|
{ // This is dispatched by the real interrupt handler, who locates us
|
||||||
|
if (writeError)
|
||||||
|
{
|
||||||
|
dirty=true;
|
||||||
|
if (physPage)
|
||||||
|
{
|
||||||
|
if (protection==copyOnWrite) // Else, this was just a "let me know when I am dirty"...
|
||||||
|
{
|
||||||
|
page *newPhysPage=pageMan->getPage();
|
||||||
|
memcpy(newPhysPage,physPage,PAGE_SIZE);
|
||||||
|
physPage=newPhysPage;
|
||||||
|
protection=writable;
|
||||||
|
backingNode=swapMan->findNode(); // Need new backing store for this node, since it was copied, the original is no good...
|
||||||
|
// Update the architecture specific stuff here...
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
physPage=pageMan->getPage();
|
||||||
|
// Update the architecture specific stuff here...
|
||||||
|
refresh(); // I wonder if these vnode calls are safe during an interrupt...
|
||||||
|
}
|
||||||
|
|
||||||
|
char vpage::getByte(unsigned long address)
|
||||||
|
{
|
||||||
|
if (!physPage)
|
||||||
|
fault((void *)(address),false);
|
||||||
|
return *((char *)(address-start_address+physPage->getAddress()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpage::setByte(unsigned long address,char value)
|
||||||
|
{
|
||||||
|
if (!physPage)
|
||||||
|
fault((void *)(address),false);
|
||||||
|
*((char *)(address-start_address+physPage->getAddress()))=value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vpage::getInt(unsigned long address)
|
||||||
|
{
|
||||||
|
if (!physPage)
|
||||||
|
fault((void *)(address),false);
|
||||||
|
return *((int *)(address-start_address+physPage->getAddress()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpage::setInt(unsigned long address,int value)
|
||||||
|
{
|
||||||
|
if (!physPage)
|
||||||
|
fault((void *)(address),false);
|
||||||
|
*((int *)(address-start_address+physPage->getAddress()))=value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpage::pager(int desperation)
|
||||||
|
{
|
||||||
|
if (!swappable)
|
||||||
|
return;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
pageMan->freePage(physPage);
|
||||||
|
physPage=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vpage::saver(void)
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include <vm.h>
|
||||||
|
#include <pageManager.h>
|
||||||
|
#include <swapFileManager.h>
|
||||||
|
|
||||||
|
class vpage : public node
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
page *physPage;
|
||||||
|
vnode backingNode;
|
||||||
|
protectType protection;
|
||||||
|
bool dirty;
|
||||||
|
bool swappable;
|
||||||
|
unsigned long start_address;
|
||||||
|
unsigned long end_address;
|
||||||
|
public:
|
||||||
|
bool isMapped(void) {return (physPage);}
|
||||||
|
bool contains(uint32 address) { return ((start_address>=address) && (end_address<=address)); }
|
||||||
|
void flush(void); // write page to vnode, if necessary
|
||||||
|
void refresh(void); // Read page back in from vnode
|
||||||
|
vpage *clone(unsigned long); // Make a new vpage that is exactly the same as this one.
|
||||||
|
// If we are read only, it is read only.
|
||||||
|
// If we are read/write, both pages are copy on write
|
||||||
|
vpage(unsigned long start,vnode backing, page *physMem,protectType prot,pageState state); // backing and/or physMem can be NULL/0.
|
||||||
|
void setProtection(protectType prot);
|
||||||
|
protectType getProtection(void) {return protection;}
|
||||||
|
void *getStartAddress(void) {return (void *)start_address;}
|
||||||
|
|
||||||
|
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
|
||||||
|
|
||||||
|
void pager(int desperation);
|
||||||
|
void saver(void);
|
||||||
|
|
||||||
|
char getByte(unsigned long offset); // This is for testing only
|
||||||
|
void setByte(unsigned long offset,char value); // This is for testing only
|
||||||
|
int getInt(unsigned long offset); // This is for testing only
|
||||||
|
void setInt(unsigned long offset,int value); // This is for testing only
|
||||||
|
static swapFileManager *swapMan;
|
||||||
|
static pageManager *pageMan;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user