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 extern void gKernelEnd;
24 tSpinlock glPhysicalPages;
25 Uint64 *gaSuperBitmap; // 1 bit = 64 Pages
26 Uint32 *gaiPageReferences = (void*)MM_PAGE_COUNTS; // Reference Counts
27 tPAddr giFirstFreePage; // First possibly free page
28 Uint64 giPhysRangeFree[NUM_MM_PHYS_RANGES]; // Number of free pages in each range
29 Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES]; // First free page in each range
30 Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range
31 Uint64 giMaxPhysPage = 0; // Maximum Physical page
34 void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
36 tMBoot_MMapEnt *mmapStart;
41 Log("MM_InitPhys_Multiboot: (MBoot=%p)", MBoot);
43 // Scan the physical memory map
44 // Looking for the top of physical memory
45 mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
46 Log(" MM_InitPhys_Multiboot: mmapStart = %p", mmapStart);
48 while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
50 // Adjust for the size of the entry
52 Log(" MM_InitPhys_Multiboot: ent={Type:%i,Base:0x%x,Length:%x",
53 ent->Type, ent->Base, ent->Length);
55 // If entry is RAM and is above `maxAddr`, change `maxAddr`
56 if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
57 maxAddr = ent->Base + ent->Length;
60 ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
63 // Did we find a valid end?
65 // No, darn, let's just use the HighMem hack
66 giMaxPhysPage = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
69 // Goodie, goodie gumdrops
70 giMaxPhysPage = maxAddr >> 12;
72 Log(" MM_InitPhys_Multiboot: giMaxPhysPage = 0x%x", giMaxPhysPage);
74 // Find a contigous section of memory to hold it in
75 // - Starting from the end of the kernel
76 // - We also need a region for the super bitmap
77 numPages = (giMaxPhysPage + 7) * sizeof(*gaiPageReferences);
78 numPages = (numPages + 0xFFF) >> 12;
79 Log(" MM_InitPhys_Multiboot: numPages = %i", numPages);
82 // Ok, naieve allocation, just put it after the kernel
83 tVAddr vaddr = MM_PAGE_COUNTS;
84 tPAddr paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
91 // Allocate the super bitmap
92 gaSuperBitmap = (void*) MM_MapHWPages(
94 ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12
97 // Scan for a nice range
104 // - initialise to one, then clear the avaliable areas
105 memset(gaSuperBitmap, -1, (giMaxPhysPage+64*8-1)/(64*8));
106 memset(gaiPageReferences, -1, giMaxPhysPage*sizeof(*gaiPageReferences));
107 // - Clear all Type=1 areas
110 (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
111 ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
114 // Check if the type is RAM
115 if(ent->Type != 1) continue;
118 &gaiPageReferences[ ent->Base >> 12 ],
120 (ent->Size>>12)*sizeof(*gaiPageReferences)
126 * \brief Allocate a contiguous range of physical pages with a maximum
127 * bit size of \a Bits
128 * \param Num Number of pages to allocate
129 * \param Bits Maximum size of the physical address
130 * \note If \a Bits is <= 0, any sized address is used (with preference
131 * to higher addresses)
133 tPAddr MM_AllocPhysRange(int Num, int Bits)
139 Log("MM_AllocPhysRange: (Num=%i,Bits=%i)", Num, Bits);
141 if( Bits <= 0 ) // Speedup for the common case
142 rangeID = MM_PHYS_MAX;
144 rangeID = MM_PHYS_MAX;
146 rangeID = MM_PHYS_32BIT;
148 rangeID = MM_PHYS_24BIT;
150 rangeID = MM_PHYS_20BIT;
152 rangeID = MM_PHYS_16BIT;
154 Log(" MM_AllocPhysRange: rangeID = %i", rangeID);
156 LOCK(&glPhysicalPages);
157 Log(" MM_AllocPhysRange: i has lock");
159 // Check if the range actually has any free pages
160 while(giPhysRangeFree[rangeID] == 0 && rangeID)
163 Log(" MM_AllocPhysRange: rangeID = %i", rangeID);
165 // What the? Oh, man. No free pages
166 if(giPhysRangeFree[rangeID] == 0) {
167 RELEASE(&glPhysicalPages);
170 Warning(" MM_AllocPhysRange: Out of free pages");
172 "Out of memory (unable to fulfil request for %i pages), zero remaining",
178 // Check if there is enough in the range
179 if(giPhysRangeFree[rangeID] >= Num)
181 // Do a cheap scan, scanning upwards from the first free page in
184 addr = giPhysRangeFirst[ rangeID ];
185 while( addr < giPhysRangeLast[ rangeID ] )
187 // Check the super bitmap
188 if( gaSuperBitmap[addr >> (6+6)] == -1 ) {
191 addr &= (1 << (6+6)) - 1;
194 // Check page block (64 pages)
195 if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) {
198 addr &= (1 << (12+6)) - 1;
201 // Check individual page
202 if( gaiPageReferences[addr] ) {
212 // If we don't find a contiguous block, nFree will not be equal
213 // to Num, so we set it to zero and do the expensive lookup.
214 if(nFree != Num) nFree = 0;
219 // Oops. ok, let's do an expensive check (scan down the list
220 // until a free range is found)
222 addr = giPhysRangeLast[ rangeID ];
224 RELEASE(&glPhysicalPages);
228 "Out of memory (unable to fulfil request for %i pages)",
233 Log(" MM_AllocPhysRange: nFree = %i, addr = 0x%08x", nFree, addr);
235 // Mark pages as allocated
237 for( i = 0; i < Num; i++ )
239 gaiPageReferences[addr] = 1;
241 if(addr >> 32) rangeID = MM_PHYS_MAX;
242 else if(addr >> 24) rangeID = MM_PHYS_32BIT;
243 else if(addr >> 20) rangeID = MM_PHYS_24BIT;
244 else if(addr >> 16) rangeID = MM_PHYS_20BIT;
245 else if(addr >> 0) rangeID = MM_PHYS_16BIT;
246 giPhysRangeFree[ rangeID ] --;
249 Num += addr & (64-1);
251 Num = (Num + (64-1)) & ~(64-1);
252 for( i = 0; i < Num/64; i++ )
255 for( j = 0; j < 64; j ++ ) {
256 if( gaiPageReferences[addr+i*64+j] ) {
262 gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64);
265 RELEASE(&glPhysicalPages);
270 * \brief Allocate a single physical page, with no preference as to address
273 tPAddr MM_AllocPhys(void)
275 return MM_AllocPhysRange(1, -1);
279 * \brief Reference a physical page
281 void MM_RefPhys(tPAddr PAddr)
284 if( PAddr >> 12 > giMaxPhysPage ) return ;
285 gaiPageReferences[ PAddr >> 12 ] ++;
288 for( j = 0; j < 64; j++ ) {
289 if( gaiPageReferences[ PAddr >> 12 ] == 0 ) {
295 gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
299 * \brief Dereference a physical page
301 void MM_DerefPhys(tPAddr PAddr)
303 if( PAddr >> 12 > giMaxPhysPage ) return ;
304 gaiPageReferences[ PAddr >> 12 ] --;
305 if( gaiPageReferences[ PAddr >> 12 ] )
307 gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64));