4 * Physical Memory Manager
11 MM_PHYS_16BIT, // Does anything need this?
12 MM_PHYS_20BIT, // Real-Mode
13 MM_PHYS_24BIT, // ISA DMA
14 MM_PHYS_32BIT, // x86 Hardware
15 MM_PHYS_MAX, // Doesn't care
20 tSpinlock glPhysicalPages;
21 Uint64 *gaSuperBitmap; // 1 bit = 64 Pages
22 Uint64 *gaPrimaryBitmap; // 1 bit = 64 Pages
23 Uint32 *gaiPageReferences; // Reference Counts
24 tPAddr giFirstFreePage; // First possibly free page
25 Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES]; // Number of free pages in each range
26 Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES]; // First free page in each range
27 Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range
28 Uint64 giMaxPhysPage = 0; // Maximum Physical page
36 * \brief Allocate a contiguous range of physical pages with a maximum
38 * \param Num Number of pages to allocate
39 * \param Bits Maximum size of the physical address
40 * \note If \a Bits is <= 0, any sized address is used (with preference
41 * to higher addresses)
43 tPAddr MM_AllocPhysRange(int Num, int Bits)
49 if( Bits <= 0 ) // Speedup for the common case
50 rangeID = MM_PHYS_MAX;
52 rangeID = MM_PHYS_MAX;
54 rangeID = MM_PHYS_32BIT;
56 rangeID = MM_PHYS_24BIT;
58 rangeID = MM_PHYS_20BIT;
60 rangeID = MM_PHYS_16BIT;
62 LOCK(&glPhysicalPages);
64 // Check if the range actually has any free pages
65 while(giPhysRangeFree[rangeID] == 0 && rangeID)
68 // What the? Oh, man. No free pages
69 if(giPhysRangeFree[rangeID] == 0) {
70 RELEASE(&glPhysicalPages);
74 "Out of memory (unable to fulfil request for %i pages), zero remaining",
80 // Check if there is enough in the range
81 if(giPhysRangeFree[rangeID] >= Num)
83 // Do a cheap scan, scanning upwards from the first free page in
86 addr = giPhysRangeFirst[ rangeID ];
87 while( addr < giPhysRangeLast[ rangeID ] )
89 // Check the super bitmap
90 if( gaSuperBitmap[addr >> (6+6)] == -1 ) {
93 addr &= (1 << (6+6)) - 1;
96 // Check page block (64 pages)
97 if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) {
100 addr &= (1 << (12+6)) - 1;
103 // Check individual page
104 if( gaiPageReferences[addr] ) {
114 // If we don't find a contiguous block, nFree will not be equal
115 // to Num, so we set it to zero and do the expensive lookup.
116 if(nFree != Num) nFree = 0;
121 // Oops. ok, let's do an expensive check (scan down the list
122 // until a free range is found)
124 addr = giPhysRangeLast[ rangeID ];
125 RELEASE(&glPhysicalPages);
129 "Out of memory (unable to fulfil request for %i pages)",
135 // Mark pages as allocated
137 for( i = 0; i < Num; i++ )
139 gaiPageReferences[addr] = 1;
140 gaPrimaryBitmap[addr>>6] |= 1 << (addr & 63);
141 if( gaPrimaryBitmap[addr>>6] == -1 )
142 gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64);
144 if(addr >> 32) rangeID = MM_PHYS_MAX;
145 else if(addr >> 24) rangeID = MM_PHYS_32BIT;
146 else if(addr >> 20) rangeID = MM_PHYS_24BIT;
147 else if(addr >> 16) rangeID = MM_PHYS_20BIT;
148 else if(addr >> 0) rangeID = MM_PHYS_16BIT;
149 giPhysRangeFree[ rangeID ] --;
152 RELEASE(&glPhysicalPages);
157 * \brief Allocate a single physical page, with no preference as to address
160 tPAddr MM_AllocPhys(void)
162 return MM_AllocPhysRange(1, -1);
165 void MM_RefPhys(tPAddr PAddr)
167 if( PAddr > giMaxPhysPage ) return ;
168 gaiPageReferences[ PAddr >> 12 ] ++;
170 gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63);
171 if( gaPrimaryBitmap[PAddr >> 18] == -1 )
172 gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
175 void MM_DerefPhys(tPAddr PAddr)
177 if( PAddr > giMaxPhysPage ) return ;
178 gaiPageReferences[ PAddr >> 12 ] --;
179 if( gaiPageReferences[ PAddr >> 12 ] )
181 gaPrimaryBitmap[PAddr >> 18] &= ~(1 << ((PAddr >> 12) & 63));
182 gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64));