More work on x86_64 port, also cleaned up a little of the API.
[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 = 1 Page
23 tPAddr  giFirstFreePage;        // First possibly free page
24 Uint64  giPhysRangeFree[NUM_MM_PHYS_RANGES];    // Number of free pages in each range
25 Uint64  giPhysRangeFirst[NUM_MM_PHYS_RANGES];   // First free page in each range
26 Uint64  giPhysRangeLast[NUM_MM_PHYS_RANGES];    // Last free page in each range
27
28 // === CODE ===
29 void MM_InitPhys()
30 {
31 }
32
33 /**
34  * \brief Allocate a contiguous range of physical pages with a maximum
35  *        bit size of \a Bits
36  * \param Num   Number of pages to allocate
37  * \param Bits  Maximum size of the physical address
38  * \note If \a Bits is <= 0, any sized address is used (with preference
39  *       to higher addresses)
40  */
41 tPAddr MM_AllocPhysRange(int Num, int Bits)
42 {
43         tPAddr  addr;
44          int    rangeID;
45          int    nFree = 0, i;
46         
47         if( Bits <= 0 ) // Speedup for the common case
48                 rangeID = MM_PHYS_MAX;
49         else if( Bits > 32 )
50                 rangeID = MM_PHYS_MAX;
51         else if( Bits > 24 )
52                 rangeID = MM_PHYS_32BIT;
53         else if( Bits > 20 )
54                 rangeID = MM_PHYS_24BIT;
55         else if( Bits > 16 )
56                 rangeID = MM_PHYS_20BIT;
57         else
58                 rangeID = MM_PHYS_16BIT;
59         
60         LOCK(&glPhysicalPages);
61         
62         // Check if the range actually has any free pages
63         while(giPhysRangeFree[rangeID] == 0 && rangeID)
64                 rangeID --;
65         
66         // What the? Oh, man. No free pages
67         if(giPhysRangeFree[rangeID] == 0) {
68                 RELEASE(&glPhysicalPages);
69                 // TODO: Page out
70                 // ATM. Just Warning
71                 Log_Warning("Arch",
72                         "Out of memory (unable to fulfil request for %i pages), zero remaining",
73                         Num
74                         );
75                 return 0;
76         }
77         
78         // Check if there is enough in the range
79         if(giPhysRangeFree[rangeID] >= Num)
80         {
81                 // Do a cheap scan, scanning upwards from the first free page in
82                 // the range
83                 nFree = 1;
84                 addr = giPhysRangeFirst[ rangeID ];
85                 while( addr < giPhysRangeLast[ rangeID ] )
86                 {
87                         // Check the super bitmap
88                         if( gaSuperBitmap[addr >> (6+6)] == -1 ) {
89                                 nFree = 0;
90                                 addr += 1 << (6+6);
91                                 addr &= (1 << (6+6)) - 1;
92                                 continue;
93                         }
94                         // Check page block (64 pages)
95                         if( gaPrimaryBitmap[addr >> 6] == -1) {
96                                 nFree = 0;
97                                 addr += 1 << (12+6);
98                                 addr &= (1 << (12+6)) - 1;
99                                 continue;
100                         }
101                         // Check individual page
102                         if( gaPrimaryBitmap[addr >> 6] & (1 << (addr&63)) ) {
103                                 nFree = 0;
104                                 addr ++;
105                                 continue;
106                         }
107                         nFree ++;
108                         addr ++;
109                         if(nFree == Num)
110                                 break;
111                 }
112                 // If we don't find a contiguous block, nFree will not be equal
113                 // to Num, so we set it to zero and do the expensive lookup.
114                 if(nFree != Num)        nFree = 0;
115         }
116         
117         if( !nFree )
118         {
119                 // Oops. ok, let's do an expensive check (scan down the list
120                 // until a free range is found)
121                 nFree = 1;
122                 addr = giPhysRangeLast[ rangeID ];
123                 RELEASE(&glPhysicalPages);
124                 // TODO: Page out
125                 // ATM. Just Warning
126                 Log_Warning("Arch",
127                         "Out of memory (unable to fulfil request for %i pages)",
128                         Num
129                         );
130                 return 0;
131         }
132         
133         // Mark pages as allocated
134         addr -= Num;
135         for( i = 0; i < Num; i++ )
136         {
137                 gaPrimaryBitmap[addr>>6] |= 1 << (addr & 63);
138                 if( gaPrimaryBitmap[addr>>6] == -1 )
139                         gaSuperBitmap[addr>>12] |= 1 << ((addr >> 6) & 64);
140                 
141                      if(addr >> 32)     rangeID = MM_PHYS_MAX;
142                 else if(addr >> 24)     rangeID = MM_PHYS_32BIT;
143                 else if(addr >> 20)     rangeID = MM_PHYS_24BIT;
144                 else if(addr >> 16)     rangeID = MM_PHYS_20BIT;
145                 else if(addr >> 0)      rangeID = MM_PHYS_16BIT;
146                 giPhysRangeFree[ rangeID ] --;
147         }
148         
149         RELEASE(&glPhysicalPages);
150         return addr;
151 }
152
153 /**
154  * \brief Allocate a single physical page, with no preference as to address
155  *        size.
156  */
157 tPAddr MM_AllocPhys(void)
158 {
159         return MM_AllocPhysRange(1, -1);
160 }

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