#include <mboot.h>
#include <mm_virt.h>
+#define TRACE_REF 0
+
enum eMMPhys_Ranges
{
MM_PHYS_16BIT, // Does anything need this?
//void MM_DerefPhys(tPAddr PAddr);
int MM_int_GetRangeID( tPAddr Addr );
+// === MACROS ===
+#define PAGE_ALLOC_TEST(__page) (gaMainBitmap[(__page)>>6] & (1ULL << ((__page)&63)))
+#define PAGE_ALLOC_SET(__page) do{gaMainBitmap[(__page)>>6] |= (1ULL << ((__page)&63));}while(0)
+#define PAGE_ALLOC_CLEAR(__page) do{gaMainBitmap[(__page)>>6] &= ~(1ULL << ((__page)&63));}while(0)
+//#define PAGE_MULTIREF_TEST(__page) (gaMultiBitmap[(__page)>>6] & (1ULL << ((__page)&63)))
+//#define PAGE_MULTIREF_SET(__page) do{gaMultiBitmap[(__page)>>6] |= 1ULL << ((__page)&63);}while(0)
+//#define PAGE_MULTIREF_CLEAR(__page) do{gaMultiBitmap[(__page)>>6] &= ~(1ULL << ((__page)&63));}while(0)
+
// === GLOBALS ===
tMutex glPhysicalPages;
-Uint64 *gaSuperBitmap = (void*)MM_PAGE_SUPBMP; // 1 bit = 64 Pages, 16 MiB Per Word
+Uint64 *gaSuperBitmap = (void*)MM_PAGE_SUPBMP; // 1 bit = 64 Pages, 16 MiB per Word
Uint64 *gaMainBitmap = (void*)MM_PAGE_BITMAP; // 1 bit = 1 Page, 256 KiB per Word
Uint64 *gaMultiBitmap = (void*)MM_PAGE_DBLBMP; // Each bit means that the page is being used multiple times
Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS; // Reference Counts
+void **gapPageNodes = (void*)MM_PAGE_NODES; // 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
paddr = ent->Base;
}
- Log(" MM_InitPhys_Multiboot: paddr=0x%x, avail=%i", paddr, avail);
+ Log("MM_InitPhys_Multiboot: paddr=0x%x, avail=0x%x pg", paddr, avail);
// Map
while( todo && avail --)
if(base & 63) {
Uint64 val = -1LL << (base & 63);
gaSuperBitmap[base / 64] &= ~val;
- size -= (base & 63);
- base += 64 - (base & 63);
+// size -= (base & 63);
+// base += 64 - (base & 63);
}
}
{
// Oops. ok, let's do an expensive check (scan down the list
// until a free range is found)
- nFree = 1;
- addr = giPhysRangeLast[ rangeID ];
- // TODO
+// nFree = 1;
+// addr = giPhysRangeLast[ rangeID ];
+ // TODO: Expensive Check
Mutex_Release(&glPhysicalPages);
// TODO: Page out
// ATM. Just Warning
for( i = 0; i < Pages; i++, addr++ )
{
gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
+ if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) )
+ gaiPageReferences[addr] = 1;
+// Log("page %P refcount = %i", MM_GetRefCount(addr<<12));
rangeID = MM_int_GetRangeID(addr << 12);
giPhysRangeFree[ rangeID ] --;
LOG("%x == %x", addr, giPhysRangeFirst[ rangeID ]);
if(addr == giPhysRangeFirst[ rangeID ])
giPhysRangeFirst[ rangeID ] += 1;
}
+ addr -= Pages;
ret = addr; // Save the return address
// Update super bitmap
}
Mutex_Release(&glPhysicalPages);
+ #if TRACE_REF
+ Log("MM_AllocPhysRange: ret = %P (Ref %i)", ret << 12, MM_GetRefCount(ret<<12));
+ #endif
LEAVE('x', ret << 12);
return ret << 12;
}
if( gaiStaticAllocPages[i] ) {
tPAddr ret = gaiStaticAllocPages[i];
gaiStaticAllocPages[i] = 0;
- Log("MM_AllocPhys: Return %x, static alloc %i", ret, i);
+ Log("MM_AllocPhys: Return %P, static alloc %i", ret, i);
return ret;
}
}
{
Uint64 page = PAddr >> 12;
- if( PAddr >> 12 > giMaxPhysPage ) return ;
+ if( page > giMaxPhysPage ) return ;
- if( gaMainBitmap[ page >> 6 ] & (1LL << (page&63)) )
+ if( PAGE_ALLOC_TEST(page) )
{
- // Reference again
- gaMultiBitmap[ page >> 6 ] |= 1LL << (page&63);
- gaiPageReferences[ page ] ++;
+ tVAddr ref_base = ((tVAddr)&gaiPageReferences[ page ]) & ~0xFFF;
+ // Allocate reference page
+ if( !MM_GetPhysAddr(ref_base) )
+ {
+ const int pages_per_refpage = PAGE_SIZE/sizeof(gaiPageReferences[0]);
+ int i;
+ int page_base = page / pages_per_refpage * pages_per_refpage;
+ if( !MM_Allocate( ref_base ) ) {
+ Log_Error("Arch", "Out of memory when allocating reference count page");
+ return ;
+ }
+ // Fill block
+ Log("Allocated references for %P-%P", page_base << 12, (page_base+pages_per_refpage)<<12);
+ for( i = 0; i < pages_per_refpage; i ++ ) {
+ int pg = page_base + i;
+ gaiPageReferences[pg] = !!PAGE_ALLOC_TEST(pg);
+ }
+ }
+ gaiPageReferences[page] ++;
}
else
{
// Allocate
- gaMainBitmap[page >> 6] |= 1LL << (page&63);
- if( gaMainBitmap[page >> 6 ] + 1 == 0 )
+ PAGE_ALLOC_SET(page);
+ if( gaMainBitmap[page >> 6] + 1 == 0 )
gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
+ if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+ gaiPageReferences[page] = 1;
}
+
+ #if TRACE_REF
+ Log("MM_RefPhys: %P referenced (%i)", page << 12, MM_GetRefCount(page << 12));
+ #endif
}
/**
if( PAddr >> 12 > giMaxPhysPage ) return ;
- if( gaMultiBitmap[ page >> 6 ] & (1LL << (page&63)) ) {
+ if( MM_GetPhysAddr( (tVAddr) &gaiPageReferences[page] ) )
+ {
gaiPageReferences[ page ] --;
- if( gaiPageReferences[ page ] == 1 )
- gaMultiBitmap[ page >> 6 ] &= ~(1LL << (page&63));
if( gaiPageReferences[ page ] == 0 )
- gaMainBitmap[ page >> 6 ] &= ~(1LL << (page&63));
+ PAGE_ALLOC_CLEAR(page);
}
else
- gaMainBitmap[ page >> 6 ] &= ~(1LL << (page&63));
+ PAGE_ALLOC_CLEAR(page);
// Update the free counts if the page was freed
- if( !(gaMainBitmap[ page >> 6 ] & (1LL << (page&63))) )
+ if( !PAGE_ALLOC_TEST(page) )
{
int rangeID;
rangeID = MM_int_GetRangeID( PAddr );
if(gaMainBitmap[ page >> 6 ] + 1 != 0 ) {
gaSuperBitmap[page >> 12] &= ~(1LL << ((page >> 6) & 63));
}
+
+ #if TRACE_REF
+ Log("Page %P dereferenced (%i)", page << 12, MM_GetRefCount(page << 12));
+ #endif
+}
+
+int MM_GetRefCount( tPAddr PAddr )
+{
+ PAddr >>= 12;
+
+ if( PAddr > giMaxPhysPage ) return 0;
+
+ if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+ return gaiPageReferences[PAddr];
+ }
+
+ if( PAGE_ALLOC_TEST(PAddr) )
+ {
+ return 1;
+ }
+ return 0;
}
/**
else
return MM_PHYS_16BIT;
}
+
+int MM_SetPageNode(tPAddr PAddr, void *Node)
+{
+ tPAddr page = PAddr >> 12;
+ tVAddr node_page = ((tVAddr)&gapPageNodes[page]) & ~(PAGE_SIZE-1);
+
+// if( !MM_GetRefCount(PAddr) ) return 1;
+
+ if( !MM_GetPhysAddr(node_page) ) {
+ if( !MM_Allocate(node_page) )
+ return -1;
+ memset( (void*)node_page, 0, PAGE_SIZE );
+ }
+
+ gapPageNodes[page] = Node;
+ return 0;
+}
+
+int MM_GetPageNode(tPAddr PAddr, void **Node)
+{
+// if( !MM_GetRefCount(PAddr) ) return 1;
+ PAddr >>= 12;
+
+ if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+ *Node = NULL;
+ return 0;
+ }
+
+ *Node = gapPageNodes[PAddr];
+ return 0;
+}
+