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

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