4 * Physical Memory Manager
12 MM_PHYS_16BIT, // Does anything need this?
13 MM_PHYS_20BIT, // Real-Mode
14 MM_PHYS_24BIT, // ISA DMA
15 MM_PHYS_32BIT, // x86 Hardware
16 MM_PHYS_MAX, // Doesn't care
21 tSpinlock glPhysicalPages;
22 Uint64 *gaSuperBitmap; // 1 bit = 64 Pages
23 Uint64 *gaPrimaryBitmap; // 1 bit = 64 Pages
24 Uint32 *gaiPageReferences; // Reference Counts
25 tPAddr giFirstFreePage; // First possibly free page
26 Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES]; // Number of free pages in each range
27 Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES]; // First free page in each range
28 Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range
29 Uint64 giMaxPhysPage = 0; // Maximum Physical page
32 void MM_InitPhys(tMBoot_Info *MBoot)
34 tMBoot_MMapEnt *mmapStart;
38 // Scan the physical memory map
39 mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
41 while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
43 // Adjust for the size of the entry
46 // If entry is RAM and is above `maxAddr`, change `maxAddr`
47 if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
48 maxAddr = ent->Base + ent->Length;
50 ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
54 giMaxPhysPage = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
57 giMaxPhysPage = maxAddr >> 12;
62 * \brief Allocate a contiguous range of physical pages with a maximum
64 * \param Num Number of pages to allocate
65 * \param Bits Maximum size of the physical address
66 * \note If \a Bits is <= 0, any sized address is used (with preference
67 * to higher addresses)
69 tPAddr MM_AllocPhysRange(int Num, int Bits)
75 if( Bits <= 0 ) // Speedup for the common case
76 rangeID = MM_PHYS_MAX;
78 rangeID = MM_PHYS_MAX;
80 rangeID = MM_PHYS_32BIT;
82 rangeID = MM_PHYS_24BIT;
84 rangeID = MM_PHYS_20BIT;
86 rangeID = MM_PHYS_16BIT;
88 LOCK(&glPhysicalPages);
90 // Check if the range actually has any free pages
91 while(giPhysRangeFree[rangeID] == 0 && rangeID)
94 // What the? Oh, man. No free pages
95 if(giPhysRangeFree[rangeID] == 0) {
96 RELEASE(&glPhysicalPages);
100 "Out of memory (unable to fulfil request for %i pages), zero remaining",
106 // Check if there is enough in the range
107 if(giPhysRangeFree[rangeID] >= Num)
109 // Do a cheap scan, scanning upwards from the first free page in
112 addr = giPhysRangeFirst[ rangeID ];
113 while( addr < giPhysRangeLast[ rangeID ] )
115 // Check the super bitmap
116 if( gaSuperBitmap[addr >> (6+6)] == -1 ) {
119 addr &= (1 << (6+6)) - 1;
122 // Check page block (64 pages)
123 if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) {
126 addr &= (1 << (12+6)) - 1;
129 // Check individual page
130 if( gaiPageReferences[addr] ) {
140 // If we don't find a contiguous block, nFree will not be equal
141 // to Num, so we set it to zero and do the expensive lookup.
142 if(nFree != Num) nFree = 0;
147 // Oops. ok, let's do an expensive check (scan down the list
148 // until a free range is found)
150 addr = giPhysRangeLast[ rangeID ];
151 RELEASE(&glPhysicalPages);
155 "Out of memory (unable to fulfil request for %i pages)",
161 // Mark pages as allocated
163 for( i = 0; i < Num; i++ )
165 gaiPageReferences[addr] = 1;
166 gaPrimaryBitmap[addr>>6] |= 1 << (addr & 63);
167 if( gaPrimaryBitmap[addr>>6] == -1 )
168 gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64);
170 if(addr >> 32) rangeID = MM_PHYS_MAX;
171 else if(addr >> 24) rangeID = MM_PHYS_32BIT;
172 else if(addr >> 20) rangeID = MM_PHYS_24BIT;
173 else if(addr >> 16) rangeID = MM_PHYS_20BIT;
174 else if(addr >> 0) rangeID = MM_PHYS_16BIT;
175 giPhysRangeFree[ rangeID ] --;
178 RELEASE(&glPhysicalPages);
183 * \brief Allocate a single physical page, with no preference as to address
186 tPAddr MM_AllocPhys(void)
188 return MM_AllocPhysRange(1, -1);
192 * \brief Reference a physical page
194 void MM_RefPhys(tPAddr PAddr)
196 if( PAddr >> 12 > giMaxPhysPage ) return ;
197 gaiPageReferences[ PAddr >> 12 ] ++;
199 gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63);
200 if( gaPrimaryBitmap[PAddr >> 18] == -1 )
201 gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
205 * \brief Dereference a physical page
207 void MM_DerefPhys(tPAddr PAddr)
209 if( PAddr >> 12 > giMaxPhysPage ) return ;
210 gaiPageReferences[ PAddr >> 12 ] --;
211 if( gaiPageReferences[ PAddr >> 12 ] )
213 gaPrimaryBitmap[PAddr >> 18] &= ~(1 << ((PAddr >> 12) & 63));
214 gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64));