Fixes to 64-bit port, now working on physical memory allocation
[tpg/acess2.git] / Kernel / arch / x86_64 / mm_virt.c
1 /*
2  * Acess2 x86_64 Port
3  * 
4  * Virtual Memory Manager
5  */
6 #include <acess.h>
7 #include <mm_virt.h>
8
9 // === CONSTANTS ===
10 #define PML4_SHIFT      39
11 #define PDP_SHIFT       30
12 #define PDIR_SHIFT      21
13 #define PTAB_SHIFT      12
14
15 #define PADDR_MASK      0x7FFFFFFF##FFFFF000
16
17 #define PF_PRESENT      0x1
18 #define PF_WRITE        0x2
19 #define PF_USER         0x4
20 #define PF_COW          0x200
21 #define PF_PAGED        0x400
22 #define PF_NX           0x80000000##00000000
23
24 // === MACROS ===
25 #define PAGETABLE(idx)  (*((tPAddr*)MM_FRACTAL_BASE+(idx)))
26 #define PAGEDIR(idx)    PAGETABLE((MM_FRACTAL_BASE>>12)+((idx)&0x7FFFFFF))
27 #define PAGEDIRPTR(idx) PAGEDIR((MM_FRACTAL_BASE>>21)+((idx)&0x3FFFF))
28 #define PAGEMAPLVL4(idx)        PAGEDIRPTR((MM_FRACTAL_BASE>>30)+((idx)&0x1FF))
29
30 // === GLOBALS ===
31
32 // === CODE ===
33 void MM_InitVirt(void)
34 {
35         
36 }
37
38 void MM_FinishVirtualInit(void)
39 {
40         
41 }
42
43 /**
44  * \brief Map a physical page to a virtual one
45  */
46 int MM_Map(tVAddr VAddr, tPAddr PAddr)
47 {
48         tPAddr  tmp;
49         
50         // Check PML4
51         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
52         {
53                 tmp = MM_AllocPhys();
54                 if(!tmp)        return 0;
55                 PAGEMAPLVL4(VAddr >> 39) = tmp | 3;
56                 memset( &PAGEDIRPTR( (VAddr>>39)<<9 ), 0, 4096 );
57         }
58         
59         // Check PDP
60         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
61         {
62                 tmp = MM_AllocPhys();
63                 if(!tmp)        return 0;
64                 PAGEDIRPTR(VAddr >> 30) = tmp | 3;
65                 memset( &PAGEDIR( (VAddr>>30)<<9 ), 0, 4096 );
66         }
67         
68         // Check Page Dir
69         if( !(PAGEDIR(VAddr >> 21) & 1) )
70         {
71                 tmp = MM_AllocPhys();
72                 if(!tmp)        return 0;
73                 PAGEDIR(VAddr >> 21) = tmp | 3;
74                 memset( &PAGETABLE( (VAddr>>21)<<9 ), 0, 4096 );
75         }
76         
77         // Check if this virtual address is already mapped
78         if( PAGETABLE(VAddr >> 12) & 1 )
79                 return 0;
80         
81         PAGETABLE(VAddr >> 12) = PAddr | 3;
82         
83         return 1;
84 }
85
86 /**
87  * \brief Removed a mapped page
88  */
89 void MM_Unmap(tVAddr VAddr)
90 {
91         // Check PML4
92         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )   return ;
93         // Check PDP
94         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )    return ;
95         // Check Page Dir
96         if( !(PAGEDIR(VAddr >> 21) & 1) )       return ;
97         
98         PAGETABLE(VAddr >> 12) = 0;
99 }
100
101 /**
102  * \brief Allocate a block of memory at the specified virtual address
103  */
104 tPAddr MM_Allocate(tVAddr VAddr)
105 {
106         tPAddr  ret;
107         
108         Log("MM_Allocate: (VAddr=%x)", VAddr);
109         Log("MM_Allocate: MM_AllocPhys()");
110         ret = MM_AllocPhys();
111         Log("MM_Allocate: ret = %x", ret);
112         if(!ret)        return 0;
113         
114         if( !MM_Map(VAddr, ret) )
115         {
116                 Warning("MM_Allocate: Unable to map", ret);
117                 MM_DerefPhys(ret);
118                 return 0;
119         }
120         
121         return ret;
122 }
123
124 void MM_Deallocate(tVAddr VAddr)
125 {
126         tPAddr  phys;
127         
128         phys = MM_GetPhysAddr(VAddr);
129         if(!phys)       return ;
130         
131         MM_Unmap(VAddr);
132         
133         MM_DerefPhys(phys);
134 }
135
136 /**
137  * \brief Get the physical address of a virtual location
138  */
139 tPAddr MM_GetPhysAddr(tVAddr Addr)
140 {
141         if( !(PAGEMAPLVL4(Addr >> 39) & 1) )
142                 return 0;
143         if( !(PAGEDIRPTR(Addr >> 30) & 1) )
144                 return 0;
145         if( !(PAGEDIR(Addr >> 21) & 1) )
146                 return 0;
147         if( !(PAGETABLE(Addr >> 12) & 1) )
148                 return 0;
149         
150         return (PAGETABLE(Addr >> 12) & ~0xFFF) | (Addr & 0xFFF);
151 }
152
153 /**
154  * \brief Sets the flags on a page
155  */
156 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
157 {
158         tPAddr  *ent;
159         
160         // Validity Check
161         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
162                 return ;
163         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
164                 return ;
165         if( !(PAGEDIR(VAddr >> 21) & 1) )
166                 return ;
167         if( !(PAGETABLE(VAddr >> 12) & 1) )
168                 return ;
169         
170         // Set Flags
171         ent = &PAGETABLE(VAddr >> 12);
172         
173         // Read-Only
174         if( Mask & MM_PFLAG_RO )
175         {
176                 if( Flags & MM_PFLAG_RO ) {
177                         *ent &= ~PF_WRITE;
178                 }
179                 else {
180                         *ent |= PF_WRITE;
181                 }
182         }
183         
184         // Kernel
185         if( Mask & MM_PFLAG_KERNEL )
186         {
187                 if( Flags & MM_PFLAG_KERNEL ) {
188                         *ent &= ~PF_USER;
189                 }
190                 else {
191                         *ent |= PF_USER;
192                 }
193         }
194         
195         // Copy-On-Write
196         if( Mask & MM_PFLAG_COW )
197         {
198                 if( Flags & MM_PFLAG_COW ) {
199                         *ent &= ~PF_WRITE;
200                         *ent |= PF_COW;
201                 }
202                 else {
203                         *ent &= ~PF_COW;
204                         *ent |= PF_WRITE;
205                 }
206         }
207         
208         // Execute
209         if( Mask & MM_PFLAG_EXEC )
210         {
211                 if( Flags & MM_PFLAG_EXEC ) {
212                         *ent &= ~PF_NX;
213                 }
214                 else {
215                         *ent |= PF_NX;
216                 }
217         }
218 }
219
220 /**
221  * \brief Get the flags applied to a page
222  */
223 Uint MM_GetFlags(tVAddr VAddr)
224 {
225         tPAddr  *ent;
226         Uint    ret = 0;
227         
228         // Validity Check
229         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
230                 return 0;
231         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
232                 return 0;
233         if( !(PAGEDIR(VAddr >> 21) & 1) )
234                 return 0;
235         if( !(PAGETABLE(VAddr >> 12) & 1) )
236                 return 0;
237         
238         // Set Flags
239         ent = &PAGETABLE(VAddr >> 12);
240         
241         // Read-Only
242         if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
243         // Kernel
244         if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
245         // Copy-On-Write
246         if( *ent & PF_COW )     ret |= MM_PFLAG_COW;    
247         // Execute
248         if( !(*ent & PF_NX) )   ret |= MM_PFLAG_EXEC;
249         
250         return ret;
251 }
252
253 // --- Hardware Mappings ---
254 /**
255  * \brief Map a range of hardware pages
256  */
257 tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
258 {
259         Log_KernelPanic("MM", "TODO: Implement MM_MapHWPages");
260         return 0;
261 }
262
263 /**
264  * \brief Free a range of hardware pages
265  */
266 void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
267 {
268         Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
269 }
270
271 // --- Tempory Mappings ---
272 tVAddr MM_MapTemp(tPAddr PAddr)
273 {
274         Log_KernelPanic("MM", "TODO: Implement MM_MapTemp");
275         return 0;
276 }
277
278 void MM_FreeTemp(tVAddr VAddr)
279 {
280         Log_KernelPanic("MM", "TODO: Implement MM_FreeTemp");
281         return ;
282 }
283
284
285 // --- Address Space Clone --
286 tPAddr MM_Clone(void)
287 {
288         tPAddr  ret;
289         
290         // #1 Create a copy of the PML4
291         ret = MM_AllocPhys();
292         if(!ret)        return 0;
293         
294         // #2 Alter the fractal pointer
295         // #3 Set Copy-On-Write to all user pages
296         // #4 Return
297         return 0;
298 }
299
300 void MM_ClearUser(void)
301 {
302         tVAddr  addr = 0;
303         // #1 Traverse the structure < 2^47, Deref'ing all pages
304         // #2 Free tables/dirs/pdps once they have been cleared
305         
306         for( addr = 0; addr < 0x800000000000; )
307         {
308                 if( PAGEMAPLVL4(addr >> PML4_SHIFT) & 1 )
309                 {
310                         if( PAGEDIRPTR(addr >> PDP_SHIFT) & 1 )
311                         {
312                                 if( PAGEDIR(addr >> PDIR_SHIFT) & 1 )
313                                 {
314                                         // Page
315                                         if( PAGETABLE(addr >> PTAB_SHIFT) & 1 ) {
316                                                 MM_DerefPhys( PAGETABLE(addr >> PTAB_SHIFT) & PADDR_MASK );
317                                                 PAGETABLE(addr >> PTAB_SHIFT) = 0;
318                                         }
319                                         addr += 1 << PTAB_SHIFT;
320                                         // Dereference the PDIR Entry
321                                         if( (addr + (1 << PTAB_SHIFT)) >> PDIR_SHIFT != (addr >> PDIR_SHIFT) ) {
322                                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PDIR_SHIFT) & PADDR_MASK );
323                                                 PAGEDIR(addr >> PDIR_SHIFT) = 0;
324                                         }
325                                 }
326                                 else {
327                                         addr += 1 << PDIR_SHIFT;
328                                         continue;
329                                 }
330                                 // Dereference the PDP Entry
331                                 if( (addr + (1 << PDIR_SHIFT)) >> PDP_SHIFT != (addr >> PDP_SHIFT) ) {
332                                         MM_DerefPhys( PAGEMAPLVL4(addr >> PDP_SHIFT) & PADDR_MASK );
333                                         PAGEDIRPTR(addr >> PDP_SHIFT) = 0;
334                                 }
335                         }
336                         else {
337                                 addr += 1 << PDP_SHIFT;
338                                 continue;
339                         }
340                         // Dereference the PML4 Entry
341                         if( (addr + (1 << PDP_SHIFT)) >> PML4_SHIFT != (addr >> PML4_SHIFT) ) {
342                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PML4_SHIFT) & PADDR_MASK );
343                                 PAGEMAPLVL4(addr >> PML4_SHIFT) = 0;
344                         }
345                 }
346                 else {
347                         addr += (tVAddr)1 << PML4_SHIFT;
348                         continue;
349                 }
350         }
351 }
352
353 tVAddr MM_NewWorkerStack(void)
354 {
355         return 0;
356 }
357
358 tVAddr MM_NewKStack(void)
359 {
360         return 0;
361 }

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