x86_64 now compiles and builds :) :)
[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         ret = MM_AllocPhys();
109         if(!ret)        return 0;
110         
111         if( !MM_Map(VAddr, ret) )
112         {
113                 MM_DerefPhys(ret);
114                 return 0;
115         }
116         
117         return ret;
118 }
119
120 void MM_Deallocate(tVAddr VAddr)
121 {
122         tPAddr  phys;
123         
124         phys = MM_GetPhysAddr(VAddr);
125         if(!phys)       return ;
126         
127         MM_Unmap(VAddr);
128         
129         MM_DerefPhys(phys);
130 }
131
132 /**
133  * \brief Get the physical address of a virtual location
134  */
135 tPAddr MM_GetPhysAddr(tVAddr Addr)
136 {
137         if( !(PAGEMAPLVL4(Addr >> 39) & 1) )
138                 return 0;
139         if( !(PAGEDIRPTR(Addr >> 30) & 1) )
140                 return 0;
141         if( !(PAGEDIR(Addr >> 21) & 1) )
142                 return 0;
143         if( !(PAGETABLE(Addr >> 12) & 1) )
144                 return 0;
145         
146         return (PAGETABLE(Addr >> 12) & ~0xFFF) | (Addr & 0xFFF);
147 }
148
149 /**
150  * \brief Sets the flags on a page
151  */
152 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
153 {
154         tPAddr  *ent;
155         
156         // Validity Check
157         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
158                 return ;
159         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
160                 return ;
161         if( !(PAGEDIR(VAddr >> 21) & 1) )
162                 return ;
163         if( !(PAGETABLE(VAddr >> 12) & 1) )
164                 return ;
165         
166         // Set Flags
167         ent = &PAGETABLE(VAddr >> 12);
168         
169         // Read-Only
170         if( Mask & MM_PFLAG_RO )
171         {
172                 if( Flags & MM_PFLAG_RO ) {
173                         *ent &= ~PF_WRITE;
174                 }
175                 else {
176                         *ent |= PF_WRITE;
177                 }
178         }
179         
180         // Kernel
181         if( Mask & MM_PFLAG_KERNEL )
182         {
183                 if( Flags & MM_PFLAG_KERNEL ) {
184                         *ent &= ~PF_USER;
185                 }
186                 else {
187                         *ent |= PF_USER;
188                 }
189         }
190         
191         // Copy-On-Write
192         if( Mask & MM_PFLAG_COW )
193         {
194                 if( Flags & MM_PFLAG_COW ) {
195                         *ent &= ~PF_WRITE;
196                         *ent |= PF_COW;
197                 }
198                 else {
199                         *ent &= ~PF_COW;
200                         *ent |= PF_WRITE;
201                 }
202         }
203         
204         // Execute
205         if( Mask & MM_PFLAG_EXEC )
206         {
207                 if( Flags & MM_PFLAG_EXEC ) {
208                         *ent &= ~PF_NX;
209                 }
210                 else {
211                         *ent |= PF_NX;
212                 }
213         }
214 }
215
216 /**
217  * \brief Get the flags applied to a page
218  */
219 Uint MM_GetFlags(tVAddr VAddr)
220 {
221         tPAddr  *ent;
222         Uint    ret = 0;
223         
224         // Validity Check
225         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
226                 return 0;
227         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
228                 return 0;
229         if( !(PAGEDIR(VAddr >> 21) & 1) )
230                 return 0;
231         if( !(PAGETABLE(VAddr >> 12) & 1) )
232                 return 0;
233         
234         // Set Flags
235         ent = &PAGETABLE(VAddr >> 12);
236         
237         // Read-Only
238         if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
239         // Kernel
240         if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
241         // Copy-On-Write
242         if( *ent & PF_COW )     ret |= MM_PFLAG_COW;    
243         // Execute
244         if( !(*ent & PF_NX) )   ret |= MM_PFLAG_EXEC;
245         
246         return ret;
247 }
248
249 // --- Hardware Mappings ---
250 /**
251  * \brief Map a range of hardware pages
252  */
253 tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
254 {
255         Log_KernelPanic("MM", "TODO: Implement MM_MapHWPages");
256         return 0;
257 }
258
259 /**
260  * \brief Free a range of hardware pages
261  */
262 void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
263 {
264         Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
265 }
266
267 // --- Tempory Mappings ---
268 tVAddr MM_MapTemp(tPAddr PAddr)
269 {
270         Log_KernelPanic("MM", "TODO: Implement MM_MapTemp");
271         return 0;
272 }
273
274 void MM_FreeTemp(tVAddr VAddr)
275 {
276         Log_KernelPanic("MM", "TODO: Implement MM_FreeTemp");
277         return ;
278 }
279
280
281 // --- Address Space Clone --
282 tPAddr MM_Clone(void)
283 {
284         tPAddr  ret;
285         
286         // #1 Create a copy of the PML4
287         ret = MM_AllocPhys();
288         if(!ret)        return 0;
289         
290         // #2 Alter the fractal pointer
291         // #3 Set Copy-On-Write to all user pages
292         // #4 Return
293         return 0;
294 }
295
296 void MM_ClearUser(void)
297 {
298         tVAddr  addr = 0;
299         // #1 Traverse the structure < 2^47, Deref'ing all pages
300         // #2 Free tables/dirs/pdps once they have been cleared
301         
302         for( addr = 0; addr < 0x800000000000; )
303         {
304                 if( PAGEMAPLVL4(addr >> PML4_SHIFT) & 1 )
305                 {
306                         if( PAGEDIRPTR(addr >> PDP_SHIFT) & 1 )
307                         {
308                                 if( PAGEDIR(addr >> PDIR_SHIFT) & 1 )
309                                 {
310                                         // Page
311                                         if( PAGETABLE(addr >> PTAB_SHIFT) & 1 ) {
312                                                 MM_DerefPhys( PAGETABLE(addr >> PTAB_SHIFT) & PADDR_MASK );
313                                                 PAGETABLE(addr >> PTAB_SHIFT) = 0;
314                                         }
315                                         addr += 1 << PTAB_SHIFT;
316                                         // Dereference the PDIR Entry
317                                         if( (addr + (1 << PTAB_SHIFT)) >> PDIR_SHIFT != (addr >> PDIR_SHIFT) ) {
318                                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PDIR_SHIFT) & PADDR_MASK );
319                                                 PAGEDIR(addr >> PDIR_SHIFT) = 0;
320                                         }
321                                 }
322                                 else {
323                                         addr += 1 << PDIR_SHIFT;
324                                         continue;
325                                 }
326                                 // Dereference the PDP Entry
327                                 if( (addr + (1 << PDIR_SHIFT)) >> PDP_SHIFT != (addr >> PDP_SHIFT) ) {
328                                         MM_DerefPhys( PAGEMAPLVL4(addr >> PDP_SHIFT) & PADDR_MASK );
329                                         PAGEDIRPTR(addr >> PDP_SHIFT) = 0;
330                                 }
331                         }
332                         else {
333                                 addr += 1 << PDP_SHIFT;
334                                 continue;
335                         }
336                         // Dereference the PML4 Entry
337                         if( (addr + (1 << PDP_SHIFT)) >> PML4_SHIFT != (addr >> PML4_SHIFT) ) {
338                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PML4_SHIFT) & PADDR_MASK );
339                                 PAGEMAPLVL4(addr >> PML4_SHIFT) = 0;
340                         }
341                 }
342                 else {
343                         addr += (tVAddr)1 << PML4_SHIFT;
344                         continue;
345                 }
346         }
347 }
348
349 tVAddr MM_NewWorkerStack(void)
350 {
351         return 0;
352 }
353
354 tVAddr MM_NewKStack(void)
355 {
356         return 0;
357 }

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