More work on x86_64 port, near compiling now
[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 <mboot.h>
8 //#include <mm_phys.h>
9
10 enum eMMPhys_Ranges
11 {
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
17         NUM_MM_PHYS_RANGES
18 };
19
20 // === GLOBALS ===
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
30
31 // === CODE ===
32 void MM_InitPhys(tMBoot_Info *MBoot)
33 {
34         tMBoot_MMapEnt  *mmapStart;
35         tMBoot_MMapEnt  *ent;
36         Uint64  maxAddr = 0;
37         
38         // Scan the physical memory map
39         mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
40         ent = mmapStart;
41         while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
42         {
43                 // Adjust for the size of the entry
44                 ent->Size += 4;
45                 
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;
49                 // Go to next entry
50                 ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
51         }
52         
53         if(maxAddr == 0) {
54                 giMaxPhysPage = (MBoot->HighMem >> 2) + 256;    // HighMem is a kByte value
55         }
56         else {
57                 giMaxPhysPage = maxAddr >> 12;
58         }
59 }
60
61 /**
62  * \brief Allocate a contiguous range of physical pages with a maximum
63  *        bit size of \a Bits
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)
68  */
69 tPAddr MM_AllocPhysRange(int Num, int Bits)
70 {
71         tPAddr  addr;
72          int    rangeID;
73          int    nFree = 0, i;
74         
75         if( Bits <= 0 ) // Speedup for the common case
76                 rangeID = MM_PHYS_MAX;
77         else if( Bits > 32 )
78                 rangeID = MM_PHYS_MAX;
79         else if( Bits > 24 )
80                 rangeID = MM_PHYS_32BIT;
81         else if( Bits > 20 )
82                 rangeID = MM_PHYS_24BIT;
83         else if( Bits > 16 )
84                 rangeID = MM_PHYS_20BIT;
85         else
86                 rangeID = MM_PHYS_16BIT;
87         
88         LOCK(&glPhysicalPages);
89         
90         // Check if the range actually has any free pages
91         while(giPhysRangeFree[rangeID] == 0 && rangeID)
92                 rangeID --;
93         
94         // What the? Oh, man. No free pages
95         if(giPhysRangeFree[rangeID] == 0) {
96                 RELEASE(&glPhysicalPages);
97                 // TODO: Page out
98                 // ATM. Just Warning
99                 Log_Warning("Arch",
100                         "Out of memory (unable to fulfil request for %i pages), zero remaining",
101                         Num
102                         );
103                 return 0;
104         }
105         
106         // Check if there is enough in the range
107         if(giPhysRangeFree[rangeID] >= Num)
108         {
109                 // Do a cheap scan, scanning upwards from the first free page in
110                 // the range
111                 nFree = 1;
112                 addr = giPhysRangeFirst[ rangeID ];
113                 while( addr < giPhysRangeLast[ rangeID ] )
114                 {
115                         // Check the super bitmap
116                         if( gaSuperBitmap[addr >> (6+6)] == -1 ) {
117                                 nFree = 0;
118                                 addr += 1 << (6+6);
119                                 addr &= (1 << (6+6)) - 1;
120                                 continue;
121                         }
122                         // Check page block (64 pages)
123                         if( gaSuperBitmap[addr >> (6+6)] & (1 << (addr>>6)&63)) {
124                                 nFree = 0;
125                                 addr += 1 << (12+6);
126                                 addr &= (1 << (12+6)) - 1;
127                                 continue;
128                         }
129                         // Check individual page
130                         if( gaiPageReferences[addr] ) {
131                                 nFree = 0;
132                                 addr ++;
133                                 continue;
134                         }
135                         nFree ++;
136                         addr ++;
137                         if(nFree == Num)
138                                 break;
139                 }
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;
143         }
144         
145         if( !nFree )
146         {
147                 // Oops. ok, let's do an expensive check (scan down the list
148                 // until a free range is found)
149                 nFree = 1;
150                 addr = giPhysRangeLast[ rangeID ];
151                 RELEASE(&glPhysicalPages);
152                 // TODO: Page out
153                 // ATM. Just Warning
154                 Log_Warning("Arch",
155                         "Out of memory (unable to fulfil request for %i pages)",
156                         Num
157                         );
158                 return 0;
159         }
160         
161         // Mark pages as allocated
162         addr -= Num;
163         for( i = 0; i < Num; i++ )
164         {
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);
169                 
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 ] --;
176         }
177         
178         RELEASE(&glPhysicalPages);
179         return addr;
180 }
181
182 /**
183  * \brief Allocate a single physical page, with no preference as to address
184  *        size.
185  */
186 tPAddr MM_AllocPhys(void)
187 {
188         return MM_AllocPhysRange(1, -1);
189 }
190
191 /**
192  * \brief Reference a physical page
193  */
194 void MM_RefPhys(tPAddr PAddr)
195 {
196         if( PAddr >> 12 > giMaxPhysPage )       return ;
197         gaiPageReferences[ PAddr >> 12 ] ++;
198         
199         gaPrimaryBitmap[PAddr >> 18] |= 1 << ((PAddr>>12) & 63);
200         if( gaPrimaryBitmap[PAddr >> 18] == -1 )
201                 gaSuperBitmap[PAddr >> 24] |= 1 << ((PAddr >> 18) & 64);
202 }
203
204 /**
205  * \brief Dereference a physical page
206  */
207 void MM_DerefPhys(tPAddr PAddr)
208 {
209         if( PAddr >> 12 > giMaxPhysPage )       return ;
210         gaiPageReferences[ PAddr >> 12 ] --;
211         if( gaiPageReferences[ PAddr >> 12 ] )
212         {
213                 gaPrimaryBitmap[PAddr >> 18] &= ~(1 << ((PAddr >> 12) & 63));
214                 gaSuperBitmap[PAddr >> 24] &= ~(1 << ((PAddr >> 18) & 64));
215         }
216 }

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