* Physical Memory Manager
*/
#include <acess.h>
+#include <mboot.h>
//#include <mm_phys.h>
enum eMMPhys_Ranges
// === GLOBALS ===
tSpinlock glPhysicalPages;
Uint64 *gaSuperBitmap; // 1 bit = 64 Pages
-Uint64 *gaPrimaryBitmap; // 1 bit = 1 Page
+Uint64 *gaPrimaryBitmap; // 1 bit = 64 Pages
+Uint32 *gaiPageReferences; // Reference Counts
tPAddr giFirstFreePage; // First possibly free page
Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES]; // Number of free pages in each range
Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES]; // First free page in each range
Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range
+Uint64 giMaxPhysPage = 0; // Maximum Physical page
// === CODE ===
-void MM_InitPhys()
+void MM_InitPhys(tMBoot_Info *MBoot)
{
+ tMBoot_MMapEnt *mmapStart;
+ tMBoot_MMapEnt *ent;
+ Uint64 maxAddr = 0;
+
+ // Scan the physical memory map
+ mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
+ ent = mmapStart;
+ while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
+ {
+ // Adjust for the size of the entry
+ ent->Size += 4;
+
+ // If entry is RAM and is above `maxAddr`, change `maxAddr`
+ if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
+ maxAddr = ent->Base + ent->Length;
+ // Go to next entry
+ ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ }
+
+ if(maxAddr == 0) {
+ giMaxPhysPage = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
+ }
+ else {
+ giMaxPhysPage = maxAddr >> 12;
+ }
}
/**
continue;
}
// Check page block (64 pages)
- if( gaPrimaryBitmap[addr >> 6] == -1) {
+ if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) {
nFree = 0;
addr += 1 << (12+6);
addr &= (1 << (12+6)) - 1;
continue;
}
// Check individual page
- if( gaPrimaryBitmap[addr >> 6] & (1 << (addr&63)) ) {
+ if( gaiPageReferences[addr] ) {
nFree = 0;
addr ++;
continue;
addr -= Num;
for( i = 0; i < Num; i++ )
{
+ gaiPageReferences[addr] = 1;
gaPrimaryBitmap[addr>>6] |= 1 << (addr & 63);
if( gaPrimaryBitmap[addr>>6] == -1 )
gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64);
{
return MM_AllocPhysRange(1, -1);
}
+
+/**
+ * \brief Reference a physical page
+ */
+void MM_RefPhys(tPAddr PAddr)
+{
+ if( PAddr >> 12 > giMaxPhysPage ) return ;
+ gaiPageReferences[ PAddr >> 12 ] ++;
+
+ gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63);
+ if( gaPrimaryBitmap[PAddr >> 18] == -1 )
+ gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
+}
+
+/**
+ * \brief Dereference a physical page
+ */
+void MM_DerefPhys(tPAddr PAddr)
+{
+ if( PAddr >> 12 > giMaxPhysPage ) return ;
+ gaiPageReferences[ PAddr >> 12 ] --;
+ if( gaiPageReferences[ PAddr >> 12 ] )
+ {
+ gaPrimaryBitmap[PAddr >> 18] &= ~(1 << ((PAddr >> 12) & 63));
+ gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64));
+ }
+}