Added some very pedantic warning flags
[tpg/acess2.git] / Kernel / arch / x86 / mm_phys.c
1 /*
2  * Acess2
3  * - Physical memory manager
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <mboot.h>
8 #include <mm_virt.h>
9
10 //#define USE_STACK     1
11 #define TRACE_ALLOCS    0       // Print trace messages on AllocPhys/DerefPhys
12
13 #define REFERENCE_BASE  0xE0400000
14
15 // === IMPORTS ===
16 extern void     gKernelEnd;
17
18 // === PROTOTYPES ===
19 void    MM_Install(tMBoot_Info *MBoot);
20 //tPAddr        MM_AllocPhys(void);
21 //tPAddr        MM_AllocPhysRange(int Pages, int MaxBits);
22 //void  MM_RefPhys(tPAddr PAddr);
23 //void  MM_DerefPhys(tPAddr PAddr);
24 // int  MM_GetRefCount(tPAddr PAddr);
25
26 // === GLOBALS ===
27 tMutex  glPhysAlloc;
28 Uint64  giPhysAlloc = 0;        // Number of allocated pages
29 Uint64  giPageCount = 0;        // Total number of pages
30 Uint64  giLastPossibleFree = 0; // Last possible free page (before all pages are used)
31
32 Uint32  gaSuperBitmap[1024];    // Blocks of 1024 Pages
33 Uint32  gaPageBitmap[1024*1024/32];     // Individual pages
34 Uint32  *gaPageReferences;
35
36 // === CODE ===
37 void MM_Install(tMBoot_Info *MBoot)
38 {
39         Uint    kernelPages, num;
40         Uint    i;
41         Uint64  maxAddr = 0;
42         tMBoot_Module   *mods;
43         tMBoot_MMapEnt  *ent;
44         
45         // --- Find largest address
46         MBoot->MMapAddr |= KERNEL_BASE;
47         ent = (void *)( MBoot->MMapAddr );
48         while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
49         {
50                 // Adjust for size
51                 ent->Size += 4;
52                 
53                 // If entry is RAM and is above `maxAddr`, change `maxAddr`
54                 if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
55                         maxAddr = ent->Base + ent->Length;
56                 // Go to next entry
57                 ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
58         }
59         
60         if(maxAddr == 0) {      
61                 giPageCount = (MBoot->HighMem >> 2) + 256;      // HighMem is a kByte value
62         }
63         else {
64                 giPageCount = maxAddr >> 12;
65         }
66         giLastPossibleFree = giPageCount - 1;
67         
68         memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
69         
70         // Set up allocateable space
71         ent = (void *)( MBoot->MMapAddr );
72         while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
73         {               
74                 memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) );
75                 ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
76         }
77         
78         // Get used page count (Kernel)
79         kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
80         kernelPages += 0xFFF;   // Page Align
81         kernelPages >>= 12;
82         
83         // Fill page bitmap
84         num = kernelPages/32;
85         memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num );
86         gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1;
87         
88         // Fill Superpage bitmap
89         num = kernelPages/(32*32);
90         memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num );
91         gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1;
92         
93         // Mark Multiboot's pages as taken
94         // - Structure
95         MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
96         // - Module List
97         for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
98                 MM_RefPhys( MBoot->Modules + (i << 12) );
99         // - Modules
100         mods = (void*)(MBoot->Modules + KERNEL_BASE);
101         for(i = 0; i < MBoot->ModuleCount; i++)
102         {
103                 num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
104                 while(num--)
105                         MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
106         }
107         
108         // Allocate References
109         //LOG("Reference Pages %i", (giPageCount*4+0xFFF)>>12);
110         for(num = 0; num < (giPageCount*4+0xFFF)>>12; num++)
111         {
112                 if( !MM_Allocate( REFERENCE_BASE + (num<<12) ) )
113                 {
114                         Panic("Oh, ****, no space for the reference pages, that's bad");
115                         for(;;);
116                 }
117         }
118         
119         //LOG("Filling");
120         // Fill references
121         gaPageReferences = (void*)REFERENCE_BASE;
122         memsetd(gaPageReferences, 1, kernelPages);
123         for( num = kernelPages; num < giPageCount; num++ )
124         {
125                 gaPageReferences[num] = (gaPageBitmap[ num / 32 ] >> (num&31)) & 1;
126         }
127 }
128
129 /**
130  * \fn tPAddr MM_AllocPhys(void)
131  * \brief Allocates a physical page from the general pool
132  */
133 tPAddr MM_AllocPhys(void)
134 {
135         // int  a, b, c;
136          int    indx = -1;
137         tPAddr  ret;
138         
139         ENTER("");
140         
141         Mutex_Acquire( &glPhysAlloc );
142         
143         // Classful scan
144         #if 1
145         {
146         const int addrClasses[] = {0,16,20,24,32,64};
147         const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
148          int    i;
149          int    first, last;
150         for( i = numAddrClasses; i -- > 1; )
151         {
152 //              Log("Scanning %i (%i bits)", i, addrClasses[i]);
153                 first = 1 << (addrClasses[i-1] - 12);
154                 last = (1 << (addrClasses[i] - 12)) - 1;
155                 // Range is above the last free page
156                 if( first > giLastPossibleFree )
157                         continue;
158                 // Last possible free page is in the range
159                 if( last > giLastPossibleFree )
160                         last = giLastPossibleFree;
161                         
162 //              Log(" first=%i,max=%i", first, last);
163                 // Scan the range
164                 for( indx = first; indx < last; )
165                 {
166 //                      Log("indx = %i (< %i?)", indx, last);
167                         if( gaSuperBitmap[indx>>10] == -1 ) {
168                                 indx += 1024;
169                                 continue;
170                         }
171                         
172                         if( gaPageBitmap[indx>>5] == -1 ) {
173                                 indx += 32;
174                                 continue;
175                         }
176                         
177                         if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
178                                 indx ++;
179                                 continue;
180                         }
181                         break;
182                 }
183                 if( indx < last )       break;
184                 
185                 giLastPossibleFree = first;     // Well, we couldn't find any in this range
186         }
187         // Out of memory?
188         if( i <= 1 )    indx = -1;
189 //      Log("indx = %i", indx);
190         }
191         #elif 0
192         // Find free page
193         // Scan downwards
194         LOG("giLastPossibleFree = %i", giLastPossibleFree);
195         for( indx = giLastPossibleFree; indx >= 0; )
196         {
197                 if( gaSuperBitmap[indx>>10] == -1 ) {
198                         indx -= 1024;
199                         continue;
200                 }
201                 
202                 if( gaPageBitmap[indx>>5] == -1 ) {
203                         indx -= 32;
204                         continue;
205                 }
206                 
207                 if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
208                         indx --;
209                         continue;
210                 }
211                 break;
212         }
213         if( indx >= 0 )
214                 giLastPossibleFree = indx;
215         LOG("indx = %i", indx);
216         #else
217         c = giLastPossibleFree % 32;
218         b = (giLastPossibleFree / 32) % 32;
219         a = giLastPossibleFree / 1024;
220         
221         LOG("a=%i,b=%i,c=%i", a, b, c);
222         for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
223         if(a < 0) {
224                 Mutex_Release( &glPhysAlloc );
225                 Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used",
226                         __builtin_return_address(0), giPhysAlloc, giPageCount);
227                 LEAVE('i', 0);
228                 return 0;
229         }
230         for( ; gaSuperBitmap[a] & (1<<b); b-- );
231         for( ; gaPageBitmap[a*32+b] & (1<<c); c-- );
232         LOG("a=%i,b=%i,c=%i", a, b, c);
233         indx = (a << 10) | (b << 5) | c;
234         if( indx >= 0 )
235                 giLastPossibleFree = indx;
236         #endif
237         
238         if( indx < 0 ) {
239                 Mutex_Release( &glPhysAlloc );
240                 Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used (indx = %x)",
241                         __builtin_return_address(0), giPhysAlloc, giPageCount, indx);
242                 Log_Debug("PMem", "giLastPossibleFree = %lli", giLastPossibleFree);
243                 LEAVE('i', 0);
244                 return 0;
245         }
246         
247         if( indx > 0xFFFFF ) {
248                 Panic("The fuck? Too many pages! (indx = 0x%x)", indx);
249         }
250         
251         // Mark page used
252         if(gaPageReferences)
253                 gaPageReferences[ indx ] = 1;
254         gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
255         
256         giPhysAlloc ++;
257         
258         // Get address
259         ret = indx << 12;
260         
261         // Mark used block
262         if(gaPageBitmap[ indx>>5 ] == -1) {
263                 gaSuperBitmap[indx>>10] |= 1 << ((indx>>5)&31);
264         }
265
266         // Release Spinlock
267         Mutex_Release( &glPhysAlloc );
268         
269         LEAVE('X', ret);
270         #if TRACE_ALLOCS
271         Log_Debug("PMem", "MM_AllocPhys: RETURN 0x%llx (%i free)", ret, giPageCount-giPhysAlloc);
272         #endif
273         return ret;
274 }
275
276 /**
277  * \fn tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
278  * \brief Allocate a range of physical pages
279  * \param Pages Number of pages to allocate
280  * \param MaxBits       Maximum number of address bits to use
281  */
282 tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
283 {
284          int    a, b;
285          int    i, idx, sidx;
286         tPAddr  ret;
287         
288         ENTER("iPages iMaxBits", Pages, MaxBits);
289         
290         // Sanity Checks
291         if(MaxBits < 0) {
292                 LEAVE('i', 0);
293                 return 0;
294         }
295         if(MaxBits > PHYS_BITS) MaxBits = PHYS_BITS;
296         
297         // Lock
298         Mutex_Acquire( &glPhysAlloc );
299         
300         // Set up search state
301         if( giLastPossibleFree > ((tPAddr)1 << (MaxBits-12)) ) {
302                 sidx = (tPAddr)1 << (MaxBits-12);
303         }
304         else {
305                 sidx = giLastPossibleFree;
306         }
307         idx = sidx / 32;
308         sidx %= 32;
309         b = idx % 32;
310         a = idx / 32;
311         
312         #if 0
313         LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
314         
315         // Find free page
316         for( ; gaSuperBitmap[a] == -1 && a --; )        b = 31;
317         if(a < 0) {
318                 Mutex_Release( &glPhysAlloc );
319                 Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
320                 LEAVE('i', 0);
321                 return 0;
322         }
323         LOG("a = %i", a);
324         for( ; gaSuperBitmap[a] & (1 << b); b-- )       sidx = 31;
325         LOG("b = %i", b);
326         idx = a * 32 + b;
327         for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
328                 LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
329         
330         LOG("idx = %i, sidx = %i", idx, sidx);
331         #else
332         
333         #endif
334         
335         // Check if the gap is large enough
336         while( idx >= 0 )
337         {
338                 // Find a free page
339                 for( ; ; )
340                 {
341                         // Bulk Skip
342                         if( gaPageBitmap[idx] == -1 ) {
343                                 idx --;
344                                 sidx = 31;
345                                 continue;
346                         }
347                         
348                         if( gaPageBitmap[idx] & (1 << sidx) ) {
349                                 sidx --;
350                                 if(sidx < 0) {  sidx = 31;      idx --; }
351                                 if(idx < 0)     break;
352                                 continue;
353                         }
354                         break;
355                 }
356                 if( idx < 0 )   break;
357                 
358                 // Check if it is a free range
359                 for( i = 0; i < Pages; i++ )
360                 {
361                         // Used page? break
362                         if( gaPageBitmap[idx] & (1 << sidx) )
363                                 break;
364                         
365                         sidx --;
366                         if(sidx < 0) {  sidx = 31;      idx --; }
367                         if(idx < 0)     break;
368                 }
369                 
370                 if( i == Pages )
371                         break;
372         }
373         
374         // Check if an address was found
375         if( idx < 0 ) {
376                 Mutex_Release( &glPhysAlloc );
377                 Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
378                 LEAVE('i', 0);
379                 return 0;
380         }
381         
382         // Mark pages used
383         for( i = 0; i < Pages; i++ )
384         {
385                 if(gaPageReferences)
386                         gaPageReferences[idx*32+sidx] = 1;
387                 gaPageBitmap[ idx ] |= 1 << sidx;
388                 sidx ++;
389                 giPhysAlloc ++;
390                 if(sidx == 32) { sidx = 0;      idx ++; }
391         }
392         
393         // Get address
394         ret = (idx << 17) | (sidx << 12);
395         
396         // Mark used block
397         if(gaPageBitmap[ idx ] == -1)   gaSuperBitmap[idx/32] |= 1 << (idx%32);
398
399         // Release Spinlock
400         Mutex_Release( &glPhysAlloc );
401         
402         LEAVE('X', ret);
403         #if TRACE_ALLOCS
404         Log_Debug("PMem", "MM_AllocPhysRange: RETURN 0x%llx-0x%llx (%i free)",
405                 ret, ret + (1<<Pages)-1, giPageCount-giPhysAlloc);
406         #endif
407         return ret;
408 }
409
410 /**
411  * \fn void MM_RefPhys(tPAddr PAddr)
412  */
413 void MM_RefPhys(tPAddr PAddr)
414 {
415         // Get page number
416         PAddr >>= 12;
417         
418         // We don't care about non-ram pages
419         if(PAddr >= giPageCount)        return;
420         
421         // Lock Structures
422         Mutex_Acquire( &glPhysAlloc );
423         
424         // Reference the page
425         if(gaPageReferences)
426                 gaPageReferences[ PAddr ] ++;
427         
428         // Mark as used
429         gaPageBitmap[ PAddr / 32 ] |= 1 << (PAddr&31);
430         
431         // Mark used block
432         if(gaPageBitmap[ PAddr / 32 ] == -1)
433                 gaSuperBitmap[PAddr/1024] |= 1 << ((PAddr/32)&31);
434         
435         // Release Spinlock
436         Mutex_Release( &glPhysAlloc );
437 }
438
439 /**
440  * \fn void MM_DerefPhys(tPAddr PAddr)
441  * \brief Dereferences a physical page
442  */
443 void MM_DerefPhys(tPAddr PAddr)
444 {
445         // Get page number
446         PAddr >>= 12;
447         
448         // We don't care about non-ram pages
449         if(PAddr >= giPageCount)        return;
450         
451         // Check if it is freed
452         if(gaPageReferences[ PAddr ] == 0) {
453                 Warning("MM_DerefPhys - Non-referenced memory dereferenced");
454                 return;
455         }
456         
457         // Lock Structures
458         Mutex_Acquire( &glPhysAlloc );
459         
460         if( giLastPossibleFree < PAddr )
461                 giLastPossibleFree = PAddr;
462
463         // Dereference
464         gaPageReferences[ PAddr ] --;
465         
466         // Mark as free in bitmaps
467         if( gaPageReferences[ PAddr ] == 0 )
468         {
469                 #if TRACE_ALLOCS
470                 Log_Debug("PMem", "MM_DerefPhys: Free'd 0x%x (%i free)", PAddr, giPageCount-giPhysAlloc);
471                 #endif
472                 //LOG("Freed 0x%x by %p\n", PAddr<<12, __builtin_return_address(0));
473                 giPhysAlloc --;
474                 gaPageBitmap[ PAddr / 32 ] &= ~(1 << (PAddr&31));
475                 if(gaPageReferences[ PAddr ] == 0)
476                         gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
477         }
478         
479         // Release spinlock
480         Mutex_Release( &glPhysAlloc );
481 }
482
483 /**
484  * \fn int MM_GetRefCount(tPAddr Addr)
485  */
486 int MM_GetRefCount(tPAddr PAddr)
487 {
488         // Get page number
489         PAddr >>= 12;
490         
491         // We don't care about non-ram pages
492         if(PAddr >= giPageCount)        return -1;
493         
494         // Check if it is freed
495         return gaPageReferences[ PAddr ];
496 }

UCC git Repository :: git.ucc.asn.au