From bf738c95dab586d19b6424b51be86375280c94b8 Mon Sep 17 00:00:00 2001 From: Michael Phipps Date: Sat, 21 Dec 2002 07:47:05 +0000 Subject: [PATCH] Added the device driver API that Axel reminded me about. Updated the TODO list. This is 99% feature complete. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2271 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/vm2/TODO | 5 ++-- src/kernel/vm2/area.C | 45 +++++++++++++++++++++++++++++++++++- src/kernel/vm2/area.h | 5 +++- src/kernel/vm2/areaManager.C | 37 ++++++++++++++++++++++++++++- src/kernel/vm2/areaManager.h | 5 +++- src/kernel/vm2/vm.h | 7 ++++++ src/kernel/vm2/vmInterface.C | 23 ++++++++++++++++++ src/kernel/vm2/vmInterface.h | 8 +++++++ src/kernel/vm2/vpage.C | 27 ++++++++++++++++++---- src/kernel/vm2/vpage.h | 4 ++++ 10 files changed, 155 insertions(+), 11 deletions(-) diff --git a/src/kernel/vm2/TODO b/src/kernel/vm2/TODO index 0b238be6e4..3a9acab68e 100644 --- a/src/kernel/vm2/TODO +++ b/src/kernel/vm2/TODO @@ -1,5 +1,6 @@ -1) Change the architecture so that instead of multiple threads of tests, we have multiple apps of tests... -2) Tests are not done. +1) Implement the sharing methodology of mmap (PRIVATE vs SHARED, etc) +2) Change the architecture so that instead of multiple threads of tests, we have multiple apps of tests... +3) Tests are not done. Test: getNextAreaInfo cloneArea diff --git a/src/kernel/vm2/area.C b/src/kernel/vm2/area.C index 4582676d36..b1a797e904 100644 --- a/src/kernel/vm2/area.C +++ b/src/kernel/vm2/area.C @@ -165,7 +165,7 @@ status_t area::getInfo(area_info *dest) { return B_OK; } -bool area::contains(void *address) { +bool area::contains(const void *address) { unsigned long base=(unsigned long)(address); // error ("area::contains: looking for %d in %d -- %d, value = %d\n",base,start_address,end_address, ((start_address<=base) && (end_address>=base))); @@ -292,3 +292,46 @@ void area::dump(void) { } } +long area::get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries) { + unsigned long vbase=(unsigned long)address; + long prevMem=0,tableEntry=-1; + // Cycle over each "page to find"; + for (int byteOffset=0;byteOffset<=numBytes;byteOffset+=PAGE_SIZE) { + vpage search(vbase+byteOffset); + vpage *found=reinterpret_cast(vpages.find(&search)); + if (!found) return B_ERROR; + unsigned long mem=found->getPhysPage()->getAddress(); + if (mem!=prevMem+PAGE_SIZE) { + if (++tableEntry==numEntries) + return B_ERROR; // Ran out of places to fill in + prevMem=mem; + table[tableEntry].address=(void *)mem; + } + table[tableEntry].size+=PAGE_SIZE; + } + if (++tableEntry==numEntries) + return B_ERROR; // Ran out of places to fill in + table[tableEntry].size=0; +} + +long area::lock_memory(void *address, ulong numBytes, ulong flags) { + unsigned long vbase=(unsigned long)address; + for (int byteOffset=0;byteOffset<=numBytes;byteOffset+=PAGE_SIZE) { + vpage search(vbase+byteOffset); + vpage *found=reinterpret_cast(vpages.find(&search)); + if (!found) return B_ERROR; + if (!found->lock(flags)) return B_ERROR; + } + return B_OK; + } + +long area::unlock_memory(void *address, ulong numBytes, ulong flags) { + unsigned long vbase=(unsigned long)address; + for (int byteOffset=0;byteOffset<=numBytes;byteOffset+=PAGE_SIZE) { + vpage search(vbase+byteOffset); + vpage *found=reinterpret_cast(vpages.find(&search)); + if (!found) return B_ERROR; + found->unlock(flags); + } + return B_OK; + } diff --git a/src/kernel/vm2/area.h b/src/kernel/vm2/area.h index d92a64b5b9..b7c3e5fe27 100644 --- a/src/kernel/vm2/area.h +++ b/src/kernel/vm2/area.h @@ -39,6 +39,9 @@ class area : public node void setAreaID(int id) {areaID=id;} status_t setProtection(protectType prot); status_t resize(size_t newSize); + long get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries); + long lock_memory(void *address, ulong numBytes, ulong flags); + long unlock_memory(void *address, ulong numBytes, ulong flags); // Accessors status_t getInfo(area_info *dest); @@ -59,7 +62,7 @@ class area : public node // Comparisson with others bool nameMatch(char *matchName) {return (strcmp(matchName,name)==0);} bool couldAdd(unsigned long start,unsigned long end) { return ((endend_address));} - bool contains(void *address); + bool contains(const void *address); // External methods for "server" type calls void pager(int desperation); diff --git a/src/kernel/vm2/areaManager.C b/src/kernel/vm2/areaManager.C index 459fbb1245..03c2563a77 100644 --- a/src/kernel/vm2/areaManager.C +++ b/src/kernel/vm2/areaManager.C @@ -83,7 +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(const 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) @@ -327,3 +327,38 @@ status_t areaManager::munmap(void *addr,size_t len) unlock(); return retVal; } + + +long areaManager::get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries) { + long retVal = B_ERROR; // Be pessimistic + lock(); + // First, figure out what area we should be talking about... + area *myArea=findArea(address); + if (myArea) + retVal = myArea->get_memory_map(address, numBytes,table,numEntries); + unlock(); + return retVal; +} + +long areaManager::lock_memory(void *address, ulong numBytes, ulong flags) { + long retVal = B_ERROR; // Be pessimistic + lock(); + // First, figure out what area we should be talking about... + area *myArea=findArea(address); + if (myArea) + retVal = myArea->lock_memory(address, numBytes,flags); + unlock(); + return retVal; +} + +long areaManager::unlock_memory(void *address, ulong numBytes, ulong flags) { + long retVal = B_ERROR; // Be pessimistic + lock(); + // First, figure out what area we should be talking about... + area *myArea=findArea(address); + if (myArea) + retVal = myArea->unlock_memory(address, numBytes,flags); + unlock(); + return retVal; +} + diff --git a/src/kernel/vm2/areaManager.h b/src/kernel/vm2/areaManager.h index be2f097e6d..30b297bea1 100644 --- a/src/kernel/vm2/areaManager.h +++ b/src/kernel/vm2/areaManager.h @@ -46,7 +46,7 @@ class areaManager // One of these per process status_t munmap(void *addr,size_t len); // Mutators - area *findArea(void *address); + area *findArea(const void *address); area *findAreaLock(void *address); area *findArea(char *address); area *findArea(area_id id); @@ -90,6 +90,9 @@ class areaManager // One of these per process } void lock() { acquire_sem(myLock); } void unlock() {release_sem(myLock);} + long get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries); + long lock_memory(void *address, ulong numBytes, ulong flags); + long unlock_memory(void *address, ulong numBytes, ulong flags); // External methods for "server" type calls bool fault(void *fault_address, bool writeError); // true = OK, false = panic. diff --git a/src/kernel/vm2/vm.h b/src/kernel/vm2/vm.h index 85d3c30cf5..807ecbd600 100644 --- a/src/kernel/vm2/vm.h +++ b/src/kernel/vm2/vm.h @@ -44,4 +44,11 @@ enum pageState {FULL,CONTIGUOUS,LAZY,NO_LOCK,LOMEM}; #define CACHE_BEGIN 0x90000000 #define CACHE_END 0xe0000000 +#define B_DMA_IO 0x00000001 +#define B_READ_DEVICE 0x00000002 + +struct physical_entry {void *address; + ulong size; + }; + #endif diff --git a/src/kernel/vm2/vmInterface.C b/src/kernel/vm2/vmInterface.C index 031d705f20..02d822bfe0 100644 --- a/src/kernel/vm2/vmInterface.C +++ b/src/kernel/vm2/vmInterface.C @@ -226,3 +226,26 @@ status_t vmInterface::munmap(void *addr, size_t len) retVal = getAM()->munmap(addr,len); return retVal; } + +// Driver Interface +long vmInterface::get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries) { + getAM()->get_memory_map(address, numBytes,table,numEntries); + return B_OK; + } + +long vmInterface::lock_memory(void *address, ulong numBytes, ulong flags) { + return getAM()->lock_memory(address,numBytes,flags); +} + +long vmInterface::unlock_memory(void *address, ulong numBytes, ulong flags) { + return getAM()->unlock_memory(address,numBytes,flags); +} + +area_id vmInterface::map_physical_memory(const char *areaName, void *physAddress, size_t bytes, uint32 spec, uint32 protectionIn, void **vaddress) { + int pages=(bytes + (PAGE_SIZE) - 1)/PAGE_SIZE; + addressSpec as=(addressSpec) spec; + protectType pro=(protectType) protectionIn; + return getAM()->createArea((char *)areaName, pages, vaddress, as, LAZY, pro); + +} + diff --git a/src/kernel/vm2/vmInterface.h b/src/kernel/vm2/vmInterface.h index e6e17d199e..f3eaf102db 100644 --- a/src/kernel/vm2/vmInterface.h +++ b/src/kernel/vm2/vmInterface.h @@ -29,6 +29,14 @@ class vmInterface // This is the class that "owns" all of the managers. void cleaner(void); status_t writeCachedBlock(int fd, size_t offset, void *data); status_t readCachedBlock(int fd, size_t offset, void *data); + + // Driver Interface + long get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries); + long lock_memory(void *address, ulong numBytes, ulong flags); + long unlock_memory(void *address, ulong numBytes, ulong flags); + area_id map_physical_memory(const char *areaName, void *physAddress, size_t bytes, uint32 spec, uint32 protection, void **vaddress); + + char getByte(unsigned long offset) {return getAM()->getByte(offset);} // This is for testing only void setByte(unsigned long offset,char value) {getAM()->setByte(offset,value);} // This is for testing only int getInt(unsigned long offset) {return getAM()->getInt(offset);} // This is for testing only diff --git a/src/kernel/vm2/vpage.C b/src/kernel/vm2/vpage.C index 15f6f8de36..c09574fbb5 100644 --- a/src/kernel/vm2/vpage.C +++ b/src/kernel/vm2/vpage.C @@ -34,7 +34,7 @@ void vpage::refresh(void) { } // Simple, empty constructor -vpage::vpage(void) : physPage(NULL),backingNode(NULL),protection(none),dirty(false),swappable(false),start_address(0),end_address(0) +vpage::vpage(void) : physPage(NULL),backingNode(NULL),protection(none),dirty(false),swappable(false),start_address(0),end_address(0), locked(false) { } @@ -137,6 +137,23 @@ bool vpage::fault(void *fault_address, bool writeError, int &in_count) { return true; } +bool vpage::lock(long flags) { + locked=true; + if (!physPage) { + physPage=vmBlock->pageMan->getPage(); + if (!physPage) + return false; + refresh(); + } + return true; +} + +void vpage::unlock(long flags) { + if ((flags & B_DMA_IO) || (!(flags & B_READ_DEVICE))) + dirty=true; + locked=false; +} + char vpage::getByte(unsigned long address,areaManager *manager) { // error ("vpage::getByte: address = %ld\n",address ); if (!physPage) @@ -180,10 +197,10 @@ bool vpage::pager(int desperation) { error ("vpage::pager swappable\n"); switch (desperation) { 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; + case 2: if (!physPage || protection!=readable || locked) return false;break; + case 3: if (!physPage || dirty || locked) return false;break; + case 4: if (!physPage || locked) return false;break; + case 5: if (!physPage || locked) return false;break; default: return false;break; } error ("vpage::pager flushing\n"); diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h index a3d1a0ff7a..2ccefff5f2 100644 --- a/src/kernel/vm2/vpage.h +++ b/src/kernel/vm2/vpage.h @@ -13,6 +13,7 @@ class vpage : public node protectType protection; bool dirty; bool swappable; + bool locked; unsigned long start_address; unsigned long end_address; public: @@ -27,6 +28,9 @@ class vpage : public node void setProtection(protectType prot); void flush(void); // write page to vnode, if necessary void refresh(void); // Read page back in from vnode + bool lock(long flags); // lock this page into memory + void unlock(long flags); // unlock this page from memory + // Accessors protectType getProtection(void) {return protection;}