Changed the x86 architecture to have tPAddr be 64-bits always
[tpg/acess2.git] / Kernel / arch / x86 / mm_phys.c
1 /*
2  * Acess2
3  * - Physical memory manager
4  */
5 #define DEBUG   1
6 #include <common.h>
7 #include <mboot.h>
8 #include <mm_virt.h>
9
10 #define REFERENCE_BASE  0xE0400000
11
12 // === IMPORTS ===
13 extern void     gKernelEnd;
14
15 // === PROTOTYPES ===
16 tPAddr  MM_AllocPhys();
17 tPAddr  MM_AllocPhysRange(int Pages);
18 void    MM_RefPhys(tPAddr Addr);
19 void    MM_DerefPhys(tPAddr Addr);
20
21 // === GLOBALS ===
22  int    giPhysAlloc = 0;
23 Uint    giPageCount = 0;
24 Uint32  gaSuperBitmap[1024];    // Blocks of 1024 Pages
25 Uint32  gaPageBitmap[1024*1024/32];     // Individual pages
26 Uint32  *gaPageReferences;
27
28 // === CODE ===
29 void MM_Install(tMBoot_Info *MBoot)
30 {
31         Uint    kernelPages, num;
32         Uint    i;
33         tMBoot_Module   *mods;
34         
35         // Initialise globals
36         giPageCount = (MBoot->HighMem >> 2) + 256;      // HighMem is a kByte value
37         LOG("giPageCount = %i", giPageCount);
38         
39         // Get used page count
40         kernelPages = (Uint)&gKernelEnd - KERNEL_BASE;
41         kernelPages += 0xFFF;   // Page Align
42         kernelPages >>= 12;
43         
44         // Fill page bitmap
45         num = kernelPages/32;
46         memsetd(gaPageBitmap, -1, num);
47         gaPageBitmap[ num ] = (1 << (kernelPages & 31)) - 1;
48         
49         // Fill Superpage bitmap
50         num = kernelPages/(32*32);
51         memsetd(gaSuperBitmap, -1, num);
52         gaSuperBitmap[ num ] = (1 << ((kernelPages / 32) & 31)) - 1;
53         
54         // Mark Multiboot's pages as taken
55         // - Structure
56         MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
57         // - Module List
58         for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
59                 MM_RefPhys( MBoot->Modules + (i << 12) );
60         // - Modules
61         mods = (void*)(MBoot->Modules + KERNEL_BASE);
62         for(i = 0; i < MBoot->ModuleCount; i++)
63         {
64                 num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
65                 while(num--)
66                         MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
67         }
68         
69         // Allocate References
70         LOG("Reference Pages %i", (giPageCount*4+0xFFF)>>12);
71         for(num = 0; num < (giPageCount*4+0xFFF)>>12; num++)
72         {
73                 MM_Allocate( REFERENCE_BASE + (num<<12) );
74         }
75         
76         LOG("Filling");
77         // Fill references
78         gaPageReferences = (void*)REFERENCE_BASE;
79         memsetd(gaPageReferences, 1, kernelPages);
80         for( num = kernelPages; num < giPageCount; num++ )
81         {
82                 gaPageReferences[num] = (gaPageBitmap[ num / 32 ] >> (num&31)) & 1;
83         }
84 }
85
86 /**
87  * \fn tPAddr MM_AllocPhys()
88  * \brief Allocates a physical page
89  */
90 tPAddr MM_AllocPhys()
91 {
92          int    num = giPageCount / 32 / 32;
93          int    a, b, c;
94         tPAddr  ret;
95         
96         LOCK( &giPhysAlloc );
97         
98         // Find free page
99         for(a=0;gaSuperBitmap[a]==-1&&a<num;a++);
100         if(a == num) {
101                 RELEASE( &giPhysAlloc );
102                 Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
103                 return 0;
104         }
105         for(b=0;gaSuperBitmap[a]&(1<<b);b++);
106         for(c=0;gaPageBitmap[a*32+b]&(1<<c);c++);
107         
108         // Mark page used
109         if(gaPageReferences)
110                 gaPageReferences[a*32*32+b*32+c] = 1;
111         gaPageBitmap[ a*32+b ] |= 1 << c;
112         
113         // Get address
114         ret = (a << 22) + (b << 17) + (c << 12);
115         
116         // Mark used block
117         if(gaPageBitmap[ a*32+b ] == -1)        gaSuperBitmap[a] |= 1 << b;
118
119         // Release Spinlock
120         RELEASE( &giPhysAlloc );
121         
122         return ret;
123 }
124
125 /**
126  * \fn tPAddr MM_AllocPhysRange(int Pages)
127  * \brief Allocate a range of physical pages
128  * \param Pages Number of pages to allocate
129  */
130 tPAddr MM_AllocPhysRange(int Pages)
131 {
132          int    num = giPageCount / 32 / 32;
133          int    a, b, c;
134         tPAddr  ret;
135         
136         LOCK( &giPhysAlloc );
137         
138         // Find free page
139         for(a=0;gaSuperBitmap[a]==-1&&a<num;a++);
140         if(a == num) {
141                 RELEASE( &giPhysAlloc );
142                 Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
143                 return 0;
144         }
145         for(b=0;gaSuperBitmap[a]&(1<<b);b++);
146         for(c=0;gaPageBitmap[a*32+b]&(1<<c);c++);
147         
148         // Mark page used
149         if(gaPageReferences)
150                 gaPageReferences[a*32*32+b*32+c] = 1;
151         gaPageBitmap[ a*32+b ] |= 1 << c;
152         
153         // Get address
154         ret = (a << 22) + (b << 17) + (c << 12);
155         
156         // Mark used block
157         if(gaPageBitmap[ a*32+b ] == -1)        gaSuperBitmap[a] |= 1 << b;
158
159         // Release Spinlock
160         RELEASE( &giPhysAlloc );
161         
162         return ret;
163 }
164
165 /**
166  * \fn void MM_RefPhys(tPAddr Addr)
167  */
168 void MM_RefPhys(tPAddr Addr)
169 {
170         // Get page number
171         Addr >>= 12;
172         
173         // We don't care about non-ram pages
174         if(Addr >= giPageCount) return;
175         
176         // Lock Structures
177         LOCK( &giPhysAlloc );
178         
179         // Reference the page
180         if(gaPageReferences)
181                 gaPageReferences[ Addr ] ++;
182         
183         // Mark as used
184         gaPageBitmap[ Addr / 32 ] |= 1 << (Addr&31);
185         
186         // Mark used block
187         if(gaPageBitmap[ Addr / 32 ] == -1)     gaSuperBitmap[Addr/1024] |= 1 << ((Addr/32)&31);
188         
189         // Release Spinlock
190         RELEASE( &giPhysAlloc );
191 }
192
193 /**
194  * \fn void MM_DerefPhys(Uint32 Addr)
195  */
196 void MM_DerefPhys(tPAddr Addr)
197 {
198         // Get page number
199         Addr >>= 12;
200         
201         // We don't care about non-ram pages
202         if(Addr >= giPageCount) return;
203         
204         // Check if it is freed
205         if(gaPageReferences[ Addr ] == 0) {
206                 Warning("MM_DerefPhys - Non-referenced memory dereferenced");
207                 return;
208         }
209         
210         // Lock Structures
211         LOCK( &giPhysAlloc );
212         
213         // Dereference
214         gaPageReferences[ Addr ] --;
215         
216         // Mark as free in bitmaps
217         if( gaPageReferences[ Addr ] == 0 )
218         {
219                 //LOG("Freed 0x%x by %p\n", Addr<<12, __builtin_return_address(0));
220                 gaPageBitmap[ Addr / 32 ] &= ~(1 << (Addr&31));
221                 if(gaPageReferences[ Addr ] == 0)
222                         gaSuperBitmap[ Addr >> 10 ] &= ~(1 << ((Addr >> 5)&31));
223         }
224         
225         // Release spinlock
226         RELEASE( &giPhysAlloc );
227 }
228
229 /**
230  * \fn int MM_GetRefCount(tPAddr Addr)
231  */
232 int MM_GetRefCount(tPAddr Addr)
233 {
234         // Get page number
235         Addr >>= 12;
236         
237         // We don't care about non-ram pages
238         if(Addr >= giPageCount) return -1;
239         
240         // Check if it is freed
241         return gaPageReferences[ Addr ];
242 }

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