Paging Manager (:p)
Posted: Mon Aug 15, 2005 3:46 pm
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.
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;
}