Page 1 of 1

Paging Manager (:p)

Posted: Mon Aug 15, 2005 3:46 pm
by Cjmovie
How's this? I've abstracted ALL issues of paging into a simple function set: MapTo, CreateMap, ChangeMap

Also, within it, I have two converter functions. One takes a DWORD and splits the parts of the paging info into seperate variables. The other recombines them.

Code: Select all

typedef UINT PageEntry;    //One Page entry or directory

typedef struct{            //Create structure to read PageTable's/Directory's
 PageEntry Entry[1024];    //1024 entries that are 4 bytes
} PageTable;               //Name it

typedef struct{            //Intermediate for easy editing of Page Entry
 PageEntry* Address;       //Address held in entry
 UCHAR Available;          //Extra data space for whatever
 bool AccessLevel;         //Level - User (1) or Supervisor (0)
 bool Write;               //If you can write to it (1), Read-Only (0)
 bool Present;             //(0) for not present, (1) for present
} PageEntryExpanded;       //Name It

typedef PageTable PageDirectory; //Create 'PageDirectory' for ease-of-use

void EnablePaging(){       //Enable Paging
 WriteCR0(ReadCR0() | 0x80000000); //Write bit 32 to CR0
}

void DisablePaging(){      //Disable Paging (I can't find a use for this...)
 WriteCR0(ReadCR0() & ~(0x80000000)); //Clear bit 32 bit of CR0
}

void SetPageTable(UINT ptr){//Set pointer to page table
 WriteCR3(ptr);             //Write it to CR3
}

PageEntryExpanded PageEntryVerbose(PageEntry pge){ //Make verbose of page entry
 PageEntryExpanded tmp;           //Temporary working copy
 tmp.Address = pge & 0xFFFFF000;  //Pointer is upper 20 bits
 tmp.Available = (pge >> 9) & 7;  //Available is bits 11-9
 tmp.AccessLevel = (pge >> 2) & 1;//Access Level is bit 2
 tmp.Write = (pge >> 1) & 1;      //Read/Write is bit 1
 tmp.Present = pge & 1;           //Present is bit 0, easy!
 return tmp;                      //Return verbose version
}

PageEntry PageEntryDword(PageEntryExpanded pge){ //Convert Verbose back to real
 PageEntry tmp;                   //Temporary for working
 tmp  = pge.Address & 0xFFFFF000; //Start with address, top 20 bits
 tmp |= (pge.Available & 7) << 9; //Next, bits 9-11 should be 'Available'
 tmp |= (pge.AccessLevel & 1) << 2; //Access level is bit 2
 tmp |= (pge.Write & 1) << 1;     //Write/Read bit is #1
 tmp |= pge.Present & 1;          //Present is bit 0, easy!
 return tmp;                      //Return compact version!
}

//This function will wipe out a page entry and set it
//to not present, supervisor, read/write
void PageClearEntry(PageEntry* adr){
 UINT i;                      //Loop variable
 PageEntryExpanded tmp;       //Expanded entry to create blank
 PageEntry tmp2;              //'real' entry to write back
 
 tmp.Address = 0;             //Set address to NULL
 tmp.Present = 0;             //Not present
 tmp.Write = 1;               //Read/Write
 tmp.AccessLevel = 0;         //Supervisor only
 
 tmp2 = PageEntryDword(tmp);  //Turn it back into a real entry
 for(i=0; i<1024; i++){       //Loop through all 1024 page entries
  adr[i] = tmp2;              //And set them to the NULL entry
 }
}

//This function takes a page directory, and two addresses
//It reads the directory and maps the second address (physical)
//To the first address (virtual)
//And set it to write/read if rw is set, read-only otherwise
//And lvl is 0 if it's supervisor level, 1 for user, other ungaruanteed
bool PageMapTo(PageDirectory* table, void* virt, void* phys, bool rw, UCHAR lvl){
 UINT PageTableNum, PageNum;        //Number into page dir. and page table
 PageTable* entryset;               //Where we write final entry
 PageEntryExpanded tmp1, tmp2;      //Expanded entry for easy editing!
 virt = (virt & 0xFFFFF000) / 4096; //Get linear page number
 PageTableNum = virt / 1024;        //First 1024 pages is first table, ...
 PageNum = virt % 1024;             //Remainder is index into table
 
 tmp1 = PageEntryVerbose(table.Entry[PageTableNum]); //Get 'easy' version
 
 if(tmp1.Present == 0){             //Is it there to work with?
  tmp1.Present = 1;                 //Now it is!
  tmp1.Address = PageAlloc();       //Allocate 4k for it
  if(tmp1.Address == NULL)return false; //Oh well, no memory!
  tmp1.Write = rw;                      //Read/Write mode
  tmp1.AccessLevel = lvl;               //Access level (super/user)
  table.Entry[PageTableNum] = PageEntryDword(); //Write it back
  PageClearEntry(tmp1.Address);         //Now clear the new entry
 }
 
 entryset = (PageTable*)(tmp1.Address); //Get pointer to table
 tmp2.Present = 1;                      //Present now
 tmp2.Address = phys;                   //Address is provided in arg's
 tmp2.Write = rw;                       //Set it to requested mode, ...
 tmp2.AccessLevel = lvl;                //... and requested access level
 entryset[PageNum] = PageEntryDword(tmp2); //Now write it back!
 
 return true;
}