4 * include/tpl_mm_phys_bitmap.h
5 * Physical Memory Manager Template
10 * Uses 4.125+PtrSize bytes per page
13 #define MM_PAGE_REFCOUNTS MM_PMM_BASE
14 #define MM_PAGE_NODES (MM_PMM_BASE+(MM_MAXPHYSPAGE*sizeof(Uint32)))
15 #define MM_PAGE_BITMAP (MM_PAGE_NODES+(MM_MAXPHYSPAGE*sizeof(void*)))
17 #define PAGE_BITMAP_FREE(__pg) (gaPageBitmaps[(__pg)/32] & (1LL << ((__pg)&31)))
18 #define PAGE_BITMAP_SETFREE(__pg) do{gaPageBitmaps[(__pg)/32] |= (1LL << ((__pg)&31));}while(0)
19 #define PAGE_BITMAP_SETUSED(__pg) do{gaPageBitmaps[(__pg)/32] &= ~(1LL << ((__pg)&31));}while(0)
22 //void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
23 //tPAddr MM_AllocPhysRange(int Num, int Bits);
24 //tPAddr MM_AllocPhys(void);
25 //void MM_RefPhys(tPAddr PAddr);
26 //void MM_DerefPhys(tPAddr PAddr);
27 int MM_int_GetRangeID( tPAddr Addr );
28 int MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length );
29 void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap);
30 void MM_DumpStatistics(void);
33 tMutex glPhysicalPages;
34 void **gapPageNodes = (void*)MM_PAGE_NODES; //!< Associated VFS Node for each page
35 Uint32 *gaiPageReferences = (void*)MM_PAGE_REFCOUNTS; // Reference Counts
36 Uint32 *gaPageBitmaps = (void*)MM_PAGE_BITMAP; // Used bitmap (1 == avail)
37 Uint64 giMaxPhysPage = 0; // Maximum Physical page
45 * \brief Initialise the physical memory manager with a passed memory map
47 void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap)
50 tPAddr rangeStart, rangeLen;
52 if( MM_PAGE_BITMAP + (MM_MAXPHYSPAGE/8) > MM_PMM_END ) {
53 Log_KernelPanic("PMM", "Config Error, PMM cannot fit data in allocated range");
56 giMaxPhysPage = MaxRAMPage;
58 // for( i = 0; i < MM_RANGE_MAX; i ++ )
59 // gaiPhysRangeFirstFree[i] = -1;
62 while( MM_int_GetMapEntry(MemoryMap, mapIndex++, &rangeStart, &rangeLen) )
66 LOG("Range %i, %P to %P", mapIndex-1, rangeStart, rangeLen);
67 rangeStart /= PAGE_SIZE;
68 rangeLen /= PAGE_SIZE;
70 giPhysNumFree += rangeLen;
72 LOG("rangeStart = 0x%x, rangeLen = 0x%x", rangeStart, rangeLen);
74 if( giPhysFirstFree == -1 || giPhysFirstFree > rangeStart )
75 giPhysFirstFree = rangeStart;
77 if( giPhysLastFree < rangeStart + rangeLen )
78 giPhysLastFree = rangeStart + rangeLen;
80 LOG("giPhysFirstFree = 0x%x, giPhysLastFree = 0x%x", giPhysFirstFree, giPhysLastFree);
82 bitmap_page = (tVAddr)&gaPageBitmaps[rangeStart/32];
83 bitmap_page &= ~(PAGE_SIZE-1);
85 // Only need to allocate bitmaps
86 if( !MM_GetPhysAddr( bitmap_page ) ) {
87 if( !MM_Allocate( bitmap_page ) ) {
88 Log_KernelPanic("PMM", "Out of memory during init, this is bad");
91 // memset( (void*)bitmap_page, 0, (rangeStart/8) & ~(PAGE_SIZE-1) );
92 memset( (void*)bitmap_page, 0, PAGE_SIZE );
96 for( ; (rangeStart & 31) && rangeLen > 0; rangeStart++, rangeLen-- ) {
97 gaPageBitmaps[rangeStart / 32] |= 1 << (rangeStart&31);
98 LOG("gaPageBitmaps[%i] = 0x%x", rangeStart/32, gaPageBitmaps[rangeStart/32]);
100 // Mark blocks of 32 as avail
101 for( ; rangeLen > 31; rangeStart += 32, rangeLen -= 32 ) {
102 gaPageBitmaps[rangeStart / 32] = -1;
105 for( ; rangeLen > 0; rangeStart ++, rangeLen -- ) {
106 gaPageBitmaps[rangeStart / 32] |= 1 << (rangeStart&31);
112 LOG("giPhysFirstFree = 0x%x, giPhysLastFree = 0x%x", giPhysFirstFree, giPhysLastFree);
116 void MM_DumpStatistics(void)
118 // TODO: PM Statistics for tpl_mm_phys_bitmap
122 * \brief Allocate a contiguous range of physical pages with a maximum
123 * bit size of \a MaxBits
124 * \param Pages Number of pages to allocate
125 * \param MaxBits Maximum size of the physical address
126 * \note If \a MaxBits is <= 0, any sized address is used (with preference
127 * to higher addresses)
129 tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
134 ENTER("iPages iBits", Pages, MaxBits);
136 Mutex_Acquire(&glPhysicalPages);
138 // Check if there is enough in the range
139 if(giPhysNumFree >= Pages)
141 LOG("{0x%x -> 0x%x}", giPhysFirstFree, giPhysLastFree);
142 // Do a cheap scan, scanning upwards from the first free page in
145 addr = giPhysFirstFree;
146 while( addr <= giPhysLastFree )
149 // Check the super bitmap
150 if( gaSuperBitmap[addr / (32*32)] == 0 )
152 LOG("nFree = %i = 0 (super) (0x%x)", nFree, addr);
155 addr &= ~(32*32-1); // (1LL << 6+6) - 1
159 LOG("gaPageBitmaps[%i] = 0x%x", addr/32, gaPageBitmaps[addr/32]);
160 // Check page block (32 pages)
161 if( gaPageBitmaps[addr / 32] == 0) {
162 LOG("nFree = %i = 0 (block) (0x%x)", nFree, addr);
168 // Check individual page
169 if( !(gaPageBitmaps[addr / 32] & (1LL << (addr & 31))) )
171 LOG("nFree = %i = 0 (page) (0x%x)", nFree, addr);
178 LOG("nFree(%i) == %i (1x%x)", nFree, Pages, addr);
182 LOG("nFree = %i", nFree);
183 // If we don't find a contiguous block, nFree will not be equal
184 // to Num, so we set it to zero and do the expensive lookup.
185 if(nFree != Pages) nFree = 0;
191 // Oops. ok, let's do an expensive check (scan down the list
192 // until a free range is found)
194 addr = gaiPhysRangeLastFree[ rangeID ];
197 Mutex_Release(&glPhysicalPages);
200 Warning(" MM_AllocPhysRange: Out of memory (unable to fulfil request for %i pages)", Pages);
202 "Out of memory (unable to fulfil request for %i pages)",
208 LOG("nFree = %i, addr = 0x%08x", nFree, (addr-Pages) << 12);
210 // Mark pages as allocated
212 for( i = 0; i < Pages; i++, addr++ )
215 PAGE_BITMAP_SETUSED(addr);
216 // Maintain first possible free
218 if(addr == giPhysFirstFree)
219 giPhysFirstFree += 1;
221 LOG("if( MM_GetPhysAddr( %p ) )", &gaiPageReferences[addr]);
222 // Mark as referenced if the reference count page is valid
223 if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) ) {
224 gaiPageReferences[addr] = 1;
227 ret = addr - Pages; // Save the return address
228 LOG("ret = %x", ret);
231 LogF("MM_AllocPhysRange: %P (%i pages)\n", ret, Pages);
234 for(i = 1; i < Pages; i++)
241 // Update super bitmap
242 Pages += addr & (32-1);
244 Pages = (Pages + (32-1)) & ~(32-1);
245 for( i = 0; i < Pages/32; i++ )
247 if( gaPageBitmaps[ addr / 32 ] + 1 == 0 )
248 gaSuperBitmap[addr / (32*32)] |= 1LL << ((addr / 32) & 31);
252 Mutex_Release(&glPhysicalPages);
253 LEAVE('x', ret << 12);
258 * \brief Allocate a single physical page, with no preference as to address size.
260 tPAddr MM_AllocPhys(void)
266 // Hack to allow allocation during setup
267 for(i = 0; i < NUM_STATIC_ALLOC; i++) {
268 if( gaiStaticAllocPages[i] ) {
269 tPAddr ret = gaiStaticAllocPages[i];
270 gaiStaticAllocPages[i] = 0;
271 Log("MM_AllocPhys: Return %x, static alloc %i", ret, i);
277 for( ret = 0; ret < giMaxPhysPage; ret ++ )
279 if( !MM_GetPhysAddr( (tVAddr)&gaPageBitmaps[ret/32] ) ) {
283 if( gaPageBitmaps[ret/32] == 0 ) {
287 if( gaPageBitmaps[ret/32] & (1 << (ret&31)) ) {
288 gaPageBitmaps[ret/32] &= ~(1 << (ret&31));
289 return ret * PAGE_SIZE;
292 Log_Error("PMM", "MM_AllocPhys failed duing init");
296 Log("AllocPhys by %p", __builtin_return_address(0));
299 return MM_AllocPhysRange(1, -1);
303 * \brief Reference a physical page
305 void MM_RefPhys(tPAddr PAddr)
307 tPAddr page = PAddr / PAGE_SIZE;
308 tVAddr refpage = (tVAddr)&gaiPageReferences[page] & ~(PAGE_SIZE-1);
310 if( page >= giMaxPhysPage ) return ;
312 if( PAGE_BITMAP_FREE(page) )
315 PAGE_BITMAP_SETUSED(page);
317 if( gaPageBitmaps[page / 32] == 0 )
318 gaSuperBitmap[page / (32*32)] &= ~(1LL << ((page / 32) & 31));
320 if( MM_GetPhysAddr( refpage ) )
321 gaiPageReferences[page] = 1;
326 if( !MM_GetPhysAddr( refpage ) )
328 int pages_per_page, basepage, i;
329 if( MM_Allocate(refpage) == 0 ) {
330 // Out of memory, can this be resolved?
331 // TODO: Reclaim memory
332 Log_Error("PMM", "Out of memory (MM_RefPhys)");
335 pages_per_page = PAGE_SIZE/sizeof(*gaiPageReferences);
336 basepage = page & ~(pages_per_page-1);
337 for( i = 0; i < pages_per_page; i ++ ) {
338 if( PAGE_BITMAP_FREE(basepage+i) )
339 gaiPageReferences[basepage+i] = 0;
341 gaiPageReferences[basepage+i] = 1;
343 gaiPageReferences[page] = 2;
346 gaiPageReferences[ page ] ++;
350 int MM_GetRefCount(tPAddr PAddr)
353 if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
354 return gaiPageReferences[PAddr];
357 if( gaPageBitmaps[ PAddr / 32 ] & (1LL << (PAddr&31)) ) {
365 * \brief Dereference a physical page
367 void MM_DerefPhys(tPAddr PAddr)
369 Uint64 page = PAddr >> 12;
371 if( PAddr >> 12 > giMaxPhysPage ) return ;
373 ENTER("PPAddr", PAddr);
375 if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
377 if( gaiPageReferences[page] > 0 )
378 gaiPageReferences[ page ] --;
379 if( gaiPageReferences[ page ] == 0 ) {
380 gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
381 // TODO: Catch when all pages in this range have been dereferenced
385 gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
386 // Clear node if needed
387 if( MM_GetPhysAddr( (tVAddr)&gapPageNodes[page] ) ) {
388 gapPageNodes[page] = NULL;
389 // TODO: Catch when all pages in this range are not using nodes
392 // Update the free counts if the page was freed
393 if( gaPageBitmaps[ page / 32 ] & (1LL << (page&31)) )
396 if( giPhysFirstFree == -1 || giPhysFirstFree > page )
397 giPhysFirstFree = page;
398 if( giPhysLastFree < page )
399 giPhysLastFree = page;
403 // If the bitmap entry is not zero, set the bit free in the super bitmap
404 if(gaPageBitmaps[ page / 32 ] != 0 ) {
405 gaSuperBitmap[page / (32*32)] |= 1LL << ((page / 32) & 31);
411 int MM_SetPageNode(tPAddr PAddr, void *Node)
413 tPAddr page = PAddr >> 12;
414 tVAddr node_page = ((tVAddr)&gapPageNodes[page]) & ~(PAGE_SIZE-1);
416 if( !MM_GetRefCount(PAddr) ) return 1;
418 if( !MM_GetPhysAddr(node_page) ) {
419 if( !MM_Allocate(node_page) )
421 memset( (void*)node_page, 0, PAGE_SIZE );
424 gapPageNodes[page] = Node;
428 int MM_GetPageNode(tPAddr PAddr, void **Node)
430 if( !MM_GetRefCount(PAddr) ) return 1;
433 if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
438 *Node = gapPageNodes[PAddr];