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

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