2002-08-28 01:34:19 +00:00
#include <new.h>
2002-07-19 03:55:07 +00:00
#include "area.h"
#include "areaManager.h"
#include "vpage.h"
2002-08-26 20:14:54 +00:00
#include "vnodePool.h"
2002-09-05 03:26:02 +00:00
#include "vpagePool.h"
#include "vmHeaderBlock.h"
2002-07-19 03:55:07 +00:00
2002-09-05 03:26:02 +00:00
extern vmHeaderBlock * vmBlock ;
2002-08-26 20:14:54 +00:00
2002-10-03 03:42:59 +00:00
bool vpageIsLessThan ( void * a , void * b )
{
return ((( reinterpret_cast < vpage *> ( a )) -> getStartAddress ()) < ( reinterpret_cast < vpage *> ( b )) -> getStartAddress ());
}
2002-08-26 20:14:54 +00:00
area :: area ( void )
{
2002-10-03 03:42:59 +00:00
vpages . setIsLessThan ( vpageIsLessThan );
2002-08-26 20:14:54 +00:00
}
void area :: setup ( areaManager * myManager )
2002-07-19 03:55:07 +00:00
{
2002-09-16 03:14:44 +00:00
//error ("area::setup setting up new area\n");
2002-07-19 03:55:07 +00:00
manager = myManager ;
2002-09-16 03:14:44 +00:00
//error ("area::setup done setting up new area\n");
2002-07-19 03:55:07 +00:00
}
2002-10-03 03:42:59 +00:00
unsigned long area :: mapAddressSpecToAddress ( addressSpec type , void * req , int pageCount )
2002-07-19 03:55:07 +00:00
{
2002-07-25 01:27:00 +00:00
// We will lock in the callers
2002-10-03 03:42:59 +00:00
unsigned long base , requested = ( unsigned long ) req ;
2002-07-19 03:55:07 +00:00
switch ( type )
{
case EXACT :
base = manager -> getNextAddress ( pageCount , requested );
if ( base != requested )
2002-09-14 17:03:16 +00:00
return 0 ;
2002-07-19 03:55:07 +00:00
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...
2002-09-14 17:03:16 +00:00
default : // should never happen
throw ( "Unknown type passed to mapAddressSpecToAddress" );
2002-07-19 03:55:07 +00:00
}
2002-09-16 03:14:44 +00:00
// error ("area::mapAddressSpecToAddress, in type: %s, address = %x, size = %d\n", ((type==EXACT)?"Exact":(type==BASE)?"BASE":(type==ANY)?"ANY":(type==CLONE)?"CLONE":"ANY_KERNEL"), requested,pageCount);
2002-07-19 03:55:07 +00:00
return base ;
}
2002-10-03 03:42:59 +00:00
status_t area :: createAreaGuts ( char * inName , int pageCount , void ** address , addressSpec type , pageState inState , protectType protect , bool inFinalWrite , int fd , size_t offset , area * originalArea = NULL /* For clone only*/ )
{
2002-08-16 01:09:45 +00:00
strcpy ( name , inName );
2002-07-19 03:55:07 +00:00
vpage * newPage ;
2002-08-16 01:09:45 +00:00
2002-10-03 03:42:59 +00:00
unsigned long base = mapAddressSpecToAddress ( type , * address , pageCount );
2002-09-14 17:03:16 +00:00
if ( base == 0 )
return B_ERROR ;
2002-07-19 03:55:07 +00:00
state = inState ;
2002-07-25 01:27:00 +00:00
start_address = base ;
2002-09-14 17:03:16 +00:00
end_address = base + ( pageCount * PAGE_SIZE ) - 1 ;
2002-08-16 01:09:45 +00:00
* address = ( void * ) base ;
2002-10-03 03:42:59 +00:00
finalWrite = inFinalWrite ;
if ( ! originalArea )
for ( int i = 0 ; i < pageCount ; i ++ )
{
newPage = new ( vmBlock -> vpagePool -> get ()) vpage ;
if ( fd )
{
vnode * newVnode = new ( vmBlock -> vnodePool -> get ()) vnode ;
newVnode -> fd = fd ;
newVnode -> offset = offset + PAGE_SIZE * i ;
newVnode -> valid = true ;
newPage -> setup ( base + PAGE_SIZE * i , newVnode , NULL , protect , inState );
}
else
newPage -> setup ( base + PAGE_SIZE * i , NULL , NULL , protect , inState );
vpages . add ( newPage );
}
else
for ( struct node * cur = originalArea -> vpages . rock ; cur ; cur = cur -> next )
{
vpage * page = ( vpage * ) cur ;
newPage = new ( vmBlock -> vpagePool -> get ()) vpage ;
newPage -> setup ( base , page -> getBacking (), page -> getPhysPage (), protect , inState ); // Cloned area has the same physical page and backing store...
vpages . add ( newPage );
base += PAGE_SIZE ;
}
2002-09-14 17:03:16 +00:00
return B_OK ;
2002-10-03 03:42:59 +00:00
}
status_t area :: createAreaMappingFile ( char * inName , int pageCount , void ** address , addressSpec type , pageState inState , protectType protect , int fd , size_t offset )
{
return createAreaGuts ( inName , pageCount , address , type , inState , protect , true , fd , offset );
2002-07-19 03:55:07 +00:00
}
2002-08-16 01:09:45 +00:00
status_t area :: createArea ( char * inName , int pageCount , void ** address , addressSpec type , pageState inState , protectType protect )
2002-07-19 03:55:07 +00:00
{
2002-10-03 03:42:59 +00:00
return createAreaGuts ( inName , pageCount , address , type , inState , protect , false , 0 , 0 );
2002-07-19 03:55:07 +00:00
}
2002-08-26 03:12:35 +00:00
status_t area :: cloneArea ( area * origArea , char * inName , void ** address , addressSpec type , pageState inState , protectType protect )
{
2002-10-03 03:42:59 +00:00
if ( type == CLONE )
2002-08-26 03:12:35 +00:00
{
2002-10-03 03:42:59 +00:00
* address = ( void * )( origArea -> getStartAddress ());
type = EXACT ;
2002-08-26 03:12:35 +00:00
}
2002-10-03 03:42:59 +00:00
if ( origArea -> getAreaManager () != manager )
{
origArea -> getAreaManager () -> lock (); // This is just begging for a deadlock...
status_t retVal = createAreaGuts ( inName , origArea -> getPageCount (), address , type , inState , protect , false , 0 , 0 , origArea );
origArea -> getAreaManager () -> unlock ();
return retVal ;
}
else
return createAreaGuts ( inName , origArea -> getPageCount (), address , type , inState , protect , false , 0 , 0 , origArea );
2002-08-26 03:12:35 +00:00
}
2002-07-19 03:55:07 +00:00
void area :: freeArea ( void )
{
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: starting \n");
2002-07-31 02:20:33 +00:00
2002-08-07 03:21:02 +00:00
// vpages.dump();
2002-08-26 20:14:54 +00:00
node * cur ;
2002-09-14 17:03:16 +00:00
while (( cur = vpages . next ()) != NULL )
2002-07-19 03:55:07 +00:00
{
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: wasting a page: %x\n",cur);
2002-08-26 20:14:54 +00:00
vpage * page = reinterpret_cast < vpage *> ( cur );
2002-08-26 03:12:35 +00:00
if ( finalWrite )
page -> flush ();
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: flushed a page \n");
2002-08-26 20:14:54 +00:00
page -> cleanup ();
//page->next=NULL;
2002-09-05 03:26:02 +00:00
vmBlock -> vpagePool -> put ( page );
2002-07-19 03:55:07 +00:00
}
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: unlocking \n");
//error ("area::freeArea: ending \n");
2002-07-19 03:55:07 +00:00
}
status_t area :: getInfo ( area_info * dest )
{
2002-09-14 17:03:16 +00:00
dest -> area = areaID ;
2002-07-19 03:55:07 +00:00
strcpy ( dest -> name , name );
dest -> size = end_address - start_address ;
dest -> lock = state ;
2002-09-14 17:03:16 +00:00
dest -> protection = protection ;
2002-07-19 03:55:07 +00:00
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 );
2002-09-16 03:14:44 +00:00
// error ("area::contains: looking for %d in %d -- %d, value = %d\n",base,start_address,end_address, ((start_address<=base) && (end_address>=base)));
2002-07-25 01:27:00 +00:00
2002-09-14 17:03:16 +00:00
return (( start_address <= base ) && ( base <= end_address ));
2002-07-19 03:55:07 +00:00
}
status_t area :: resize ( size_t newSize )
{
size_t oldSize = end_address - start_address ;
if ( newSize == oldSize )
return B_OK ;
if ( newSize > oldSize )
{
2002-10-03 03:42:59 +00:00
int pageCount = ( newSize - oldSize + PAGE_SIZE - 1 ) / PAGE_SIZE ;
2002-07-19 03:55:07 +00:00
vpage * newPage ;
for ( int i = 0 ; i < pageCount ; i ++ )
{
2002-09-05 03:26:02 +00:00
newPage = new ( vmBlock -> vpagePool -> get ()) vpage ;
2002-08-26 20:14:54 +00:00
newPage -> setup ( end_address + PAGE_SIZE * i - 1 , NULL , NULL , protection , state );
2002-07-19 03:55:07 +00:00
vpages . add ( newPage );
}
end_address += start_address + newSize ;
}
else
{
2002-10-03 03:42:59 +00:00
int pageCount = ( oldSize - newSize + PAGE_SIZE - 1 ) / PAGE_SIZE ;
2002-07-19 03:55:07 +00:00
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;
2002-09-14 17:03:16 +00:00
oldPage = ( vpage * ) cur ;
vpages . remove ( cur );
2002-10-03 03:42:59 +00:00
if ( finalWrite )
oldPage -> flush ();
2002-08-26 20:14:54 +00:00
oldPage -> cleanup ();
2002-09-05 03:26:02 +00:00
vmBlock -> vpagePool -> put ( oldPage );
2002-07-19 03:55:07 +00:00
}
}
2002-09-14 17:03:16 +00:00
return B_OK ;
2002-07-19 03:55:07 +00:00
}
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 ;
2002-09-14 17:03:16 +00:00
return B_OK ;
2002-07-19 03:55:07 +00:00
}
vpage * area :: findVPage ( unsigned long address )
{
for ( struct node * cur = vpages . rock ; cur ; cur = cur -> next )
{
vpage * page = ( vpage * ) cur ;
2002-09-16 03:14:44 +00:00
//error ("Examining following vpage, looking for address %lx\n",address);
2002-09-14 17:03:16 +00:00
//page->dump();
2002-07-19 03:55:07 +00:00
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 )
2002-09-14 17:03:16 +00:00
return page -> getByte ( address , manager );
2002-07-19 03:55:07 +00:00
else
return 0 ;
}
void area :: setByte ( unsigned long address , char value ) // This is for testing only
{
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
page -> setByte ( address , value , manager );
2002-07-19 03:55:07 +00:00
}
int area :: getInt ( unsigned long address ) // This is for testing only
{
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
return page -> getInt ( address , manager );
else
return 0 ;
2002-07-19 03:55:07 +00:00
}
void area :: setInt ( unsigned long address , int value ) // This is for testing only
{
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
page -> setInt ( address , value , manager );
2002-07-19 03:55:07 +00:00
}
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 ();
}
}
2002-08-26 03:12:35 +00:00
void area :: dump ( void )
{
2002-09-16 03:14:44 +00:00
error ( "area::dump: size = %ld, lock = %d, address = %lx \n " , end_address - start_address , state , start_address );
2002-08-26 03:12:35 +00:00
for ( struct node * cur = vpages . rock ; cur ;)
{
vpage * page = ( vpage * ) cur ;
page -> dump ();
cur = cur -> next ;
}
}