More memory management functions implemented, other fixes too
[tpg/acess2.git] / Kernel / arch / x86_64 / mm_phys.c
1 /*
2  * Acess2 x86_64 Port
3  * 
4  * Physical Memory Manager
5  */
6 #include <acess.h>
7 //#include <mm_phys.h>
8
9 enum eMMPhys_Ranges
10 {
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
16         NUM_MM_PHYS_RANGES
17 };
18
19 // === GLOBALS ===
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
29
30 // === CODE ===
31 void MM_InitPhys()
32 {
33 }
34
35 /**
36  * \brief Allocate a contiguous range of physical pages with a maximum
37  *        bit size of \a Bits
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)
42  */
43 tPAddr MM_AllocPhysRange(int Num, int Bits)
44 {
45         tPAddr  addr;
46          int    rangeID;
47          int    nFree = 0, i;
48         
49         if( Bits <= 0 ) // Speedup for the common case
50                 rangeID = MM_PHYS_MAX;
51         else if( Bits > 32 )
52                 rangeID = MM_PHYS_MAX;
53         else if( Bits > 24 )
54                 rangeID = MM_PHYS_32BIT;
55         else if( Bits > 20 )
56                 rangeID = MM_PHYS_24BIT;
57         else if( Bits > 16 )
58                 rangeID = MM_PHYS_20BIT;
59         else
60                 rangeID = MM_PHYS_16BIT;
61         
62         LOCK(&glPhysicalPages);
63         
64         // Check if the range actually has any free pages
65         while(giPhysRangeFree[rangeID] == 0 && rangeID)
66                 rangeID --;
67         
68         // What the? Oh, man. No free pages
69         if(giPhysRangeFree[rangeID] == 0) {
70                 RELEASE(&glPhysicalPages);
71                 // TODO: Page out
72                 // ATM. Just Warning
73                 Log_Warning("Arch",
74                         "Out of memory (unable to fulfil request for %i pages), zero remaining",
75                         Num
76                         );
77                 return 0;
78         }
79         
80         // Check if there is enough in the range
81         if(giPhysRangeFree[rangeID] >= Num)
82         {
83                 // Do a cheap scan, scanning upwards from the first free page in
84                 // the range
85                 nFree = 1;
86                 addr = giPhysRangeFirst[ rangeID ];
87                 while( addr < giPhysRangeLast[ rangeID ] )
88                 {
89                         // Check the super bitmap
90                         if( gaSuperBitmap[addr >> (6+6)] == -1 ) {
91                                 nFree = 0;
92                                 addr += 1 << (6+6);
93                                 addr &= (1 << (6+6)) - 1;
94                                 continue;
95                         }
96                         // Check page block (64 pages)
97                         if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) {
98                                 nFree = 0;
99                                 addr += 1 << (12+6);
100                                 addr &= (1 << (12+6)) - 1;
101                                 continue;
102                         }
103                         // Check individual page
104                         if( gaiPageReferences[addr] ) {
105                                 nFree = 0;
106                                 addr ++;
107                                 continue;
108                         }
109                         nFree ++;
110                         addr ++;
111                         if(nFree == Num)
112                                 break;
113                 }
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;
117         }
118         
119         if( !nFree )
120         {
121                 // Oops. ok, let's do an expensive check (scan down the list
122                 // until a free range is found)
123                 nFree = 1;
124                 addr = giPhysRangeLast[ rangeID ];
125                 RELEASE(&glPhysicalPages);
126                 // TODO: Page out
127                 // ATM. Just Warning
128                 Log_Warning("Arch",
129                         "Out of memory (unable to fulfil request for %i pages)",
130                         Num
131                         );
132                 return 0;
133         }
134         
135         // Mark pages as allocated
136         addr -= Num;
137         for( i = 0; i < Num; i++ )
138         {
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);
143                 
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 ] --;
150         }
151         
152         RELEASE(&glPhysicalPages);
153         return addr;
154 }
155
156 /**
157  * \brief Allocate a single physical page, with no preference as to address
158  *        size.
159  */
160 tPAddr MM_AllocPhys(void)
161 {
162         return MM_AllocPhysRange(1, -1);
163 }
164
165 void MM_RefPhys(tPAddr PAddr)
166 {
167         if( PAddr > giMaxPhysPage )     return ;
168         gaiPageReferences[ PAddr >> 12 ] ++;
169         
170         gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63);
171         if( gaPrimaryBitmap[PAddr >> 18] == -1 )
172                 gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
173 }
174
175 void MM_DerefPhys(tPAddr PAddr)
176 {
177         if( PAddr > giMaxPhysPage )     return ;
178         gaiPageReferences[ PAddr >> 12 ] --;
179         if( gaiPageReferences[ PAddr >> 12 ] )
180         {
181                 gaPrimaryBitmap[PAddr >> 18] &= ~(1 << ((PAddr >> 12) & 63));
182                 gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64));
183         }
184 }

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