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

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