From f913779a806b95f04412c92c57b9a9d5577fae55 Mon Sep 17 00:00:00 2001 From: Michael Phipps Date: Fri, 19 Jul 2002 03:55:07 +0000 Subject: [PATCH] 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 --- src/kernel/vm2/Jamfile | 6 + src/kernel/vm2/TODO | 7 + src/kernel/vm2/area.C | 215 +++++++++++++++++++++++++++++++ src/kernel/vm2/area.h | 50 +++++++ src/kernel/vm2/areaManager.C | 117 +++++++++++++++++ src/kernel/vm2/areaManager.h | 26 ++++ src/kernel/vm2/cacheManager.C | 54 ++++++++ src/kernel/vm2/cacheManager.h | 28 ++++ src/kernel/vm2/list.h | 45 +++++++ src/kernel/vm2/mman.h | 118 +++++++++++++++++ src/kernel/vm2/page.C | 7 + src/kernel/vm2/page.h | 14 ++ src/kernel/vm2/pageManager.C | 86 +++++++++++++ src/kernel/vm2/pageManager.h | 19 +++ src/kernel/vm2/swapFileManager.C | 27 ++++ src/kernel/vm2/swapFileManager.h | 14 ++ src/kernel/vm2/test.C | 11 ++ src/kernel/vm2/vm.h | 20 +++ src/kernel/vm2/vmInterface.C | 127 ++++++++++++++++++ src/kernel/vm2/vmInterface.h | 30 +++++ src/kernel/vm2/vpage.C | 121 +++++++++++++++++ src/kernel/vm2/vpage.h | 39 ++++++ 22 files changed, 1181 insertions(+) create mode 100644 src/kernel/vm2/Jamfile create mode 100644 src/kernel/vm2/TODO create mode 100644 src/kernel/vm2/area.C create mode 100644 src/kernel/vm2/area.h create mode 100644 src/kernel/vm2/areaManager.C create mode 100644 src/kernel/vm2/areaManager.h create mode 100644 src/kernel/vm2/cacheManager.C create mode 100644 src/kernel/vm2/cacheManager.h create mode 100644 src/kernel/vm2/list.h create mode 100644 src/kernel/vm2/mman.h create mode 100644 src/kernel/vm2/page.C create mode 100644 src/kernel/vm2/page.h create mode 100644 src/kernel/vm2/pageManager.C create mode 100644 src/kernel/vm2/pageManager.h create mode 100644 src/kernel/vm2/swapFileManager.C create mode 100644 src/kernel/vm2/swapFileManager.h create mode 100644 src/kernel/vm2/test.C create mode 100644 src/kernel/vm2/vm.h create mode 100644 src/kernel/vm2/vmInterface.C create mode 100644 src/kernel/vm2/vmInterface.h create mode 100644 src/kernel/vm2/vpage.C create mode 100644 src/kernel/vm2/vpage.h diff --git a/src/kernel/vm2/Jamfile b/src/kernel/vm2/Jamfile new file mode 100644 index 0000000000..b9558099fb --- /dev/null +++ b/src/kernel/vm2/Jamfile @@ -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 ; + diff --git a/src/kernel/vm2/TODO b/src/kernel/vm2/TODO new file mode 100644 index 0000000000..38bd8427e8 --- /dev/null +++ b/src/kernel/vm2/TODO @@ -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. diff --git a/src/kernel/vm2/area.C b/src/kernel/vm2/area.C new file mode 100644 index 0000000000..1397d171ec --- /dev/null +++ b/src/kernel/vm2/area.C @@ -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;inext) + { + 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;inext;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(); + } + } + diff --git a/src/kernel/vm2/area.h b/src/kernel/vm2/area.h new file mode 100644 index 0000000000..975e66f6aa --- /dev/null +++ b/src/kernel/vm2/area.h @@ -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 ((endend_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 diff --git a/src/kernel/vm2/areaManager.C b/src/kernel/vm2/areaManager.C new file mode 100644 index 0000000000..3dbeff85cb --- /dev/null +++ b/src/kernel/vm2/areaManager.C @@ -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(); + } +} + diff --git a/src/kernel/vm2/areaManager.h b/src/kernel/vm2/areaManager.h new file mode 100644 index 0000000000..88585113e5 --- /dev/null +++ b/src/kernel/vm2/areaManager.h @@ -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 +}; diff --git a/src/kernel/vm2/cacheManager.C b/src/kernel/vm2/cacheManager.C new file mode 100644 index 0000000000..d24b30f420 --- /dev/null +++ b/src/kernel/vm2/cacheManager.C @@ -0,0 +1,54 @@ +#include + +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); +} diff --git a/src/kernel/vm2/cacheManager.h b/src/kernel/vm2/cacheManager.h new file mode 100644 index 0000000000..ab7e99d042 --- /dev/null +++ b/src/kernel/vm2/cacheManager.h @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +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 +}; diff --git a/src/kernel/vm2/list.h b/src/kernel/vm2/list.h new file mode 100644 index 0000000000..12b8ace04d --- /dev/null +++ b/src/kernel/vm2/list.h @@ -0,0 +1,45 @@ +#ifndef _LIST_H +#define _LIST_H +// Simple linked list +#include +#include + +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 diff --git a/src/kernel/vm2/mman.h b/src/kernel/vm2/mman.h new file mode 100644 index 0000000000..595e602f2f --- /dev/null +++ b/src/kernel/vm2/mman.h @@ -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_ */ diff --git a/src/kernel/vm2/page.C b/src/kernel/vm2/page.C new file mode 100644 index 0000000000..c7959525b8 --- /dev/null +++ b/src/kernel/vm2/page.C @@ -0,0 +1,7 @@ +#include "page.h" + +void page::zero(void) +{ + for (int i=0;i<(PAGE_SIZE/4);i++) + ((long *)physicalAddress)[i]=0; +} diff --git a/src/kernel/vm2/page.h b/src/kernel/vm2/page.h new file mode 100644 index 0000000000..400067363c --- /dev/null +++ b/src/kernel/vm2/page.h @@ -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 diff --git a/src/kernel/vm2/pageManager.C b/src/kernel/vm2/pageManager.C new file mode 100644 index 0000000000..d7b22777c0 --- /dev/null +++ b/src/kernel/vm2/pageManager.C @@ -0,0 +1,86 @@ +#include "pageManager.h" +#include +#include + +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;izero(); + } // 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; + } diff --git a/src/kernel/vm2/pageManager.h b/src/kernel/vm2/pageManager.h new file mode 100644 index 0000000000..43e8dbf62b --- /dev/null +++ b/src/kernel/vm2/pageManager.h @@ -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 diff --git a/src/kernel/vm2/swapFileManager.C b/src/kernel/vm2/swapFileManager.C new file mode 100644 index 0000000000..fc6ef372b6 --- /dev/null +++ b/src/kernel/vm2/swapFileManager.C @@ -0,0 +1,27 @@ +#include "swapFileManager.h" +//#include + +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; + } diff --git a/src/kernel/vm2/swapFileManager.h b/src/kernel/vm2/swapFileManager.h new file mode 100644 index 0000000000..be532cd2f5 --- /dev/null +++ b/src/kernel/vm2/swapFileManager.h @@ -0,0 +1,14 @@ +#include +#include +#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; +}; diff --git a/src/kernel/vm2/test.C b/src/kernel/vm2/test.C new file mode 100644 index 0000000000..feca0ab811 --- /dev/null +++ b/src/kernel/vm2/test.C @@ -0,0 +1,11 @@ +#include "vmInterface.h" +#include + +int main(int argc,char **argv) +{ + vmInterface vm(10); + + void *addr; + vm.createArea("Mine",1,&addr); + return 0; +} diff --git a/src/kernel/vm2/vm.h b/src/kernel/vm2/vm.h new file mode 100644 index 0000000000..80a0b45b25 --- /dev/null +++ b/src/kernel/vm2/vm.h @@ -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 diff --git a/src/kernel/vm2/vmInterface.C b/src/kernel/vm2/vmInterface.C new file mode 100644 index 0000000000..55f61029d8 --- /dev/null +++ b/src/kernel/vm2/vmInterface.C @@ -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; + + } diff --git a/src/kernel/vm2/vmInterface.h b/src/kernel/vm2/vmInterface.h new file mode 100644 index 0000000000..f4e9d90ce7 --- /dev/null +++ b/src/kernel/vm2/vmInterface.h @@ -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); +}; diff --git a/src/kernel/vm2/vpage.C b/src/kernel/vm2/vpage.C new file mode 100644 index 0000000000..bdbbb25345 --- /dev/null +++ b/src/kernel/vm2/vpage.C @@ -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(); + } diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h new file mode 100644 index 0000000000..02007dec14 --- /dev/null +++ b/src/kernel/vm2/vpage.h @@ -0,0 +1,39 @@ +#include +#include +#include + +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; +};