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

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