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

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