b6d022df7aca17480653d9e84deb7167b2dde41e
[tpg/acess2.git] / Kernel / arch / armv7 / mm_virt.c
1 /*
2  * Acess2
3  * 
4  * ARM7 Virtual Memory Manager
5  * - arch/arm7/mm_virt.c
6  */
7 #define DEBUG   0
8 #include <acess.h>
9 #include <mm_virt.h>
10 #include <hal_proc.h>
11
12 #define AP_KRW_ONLY     0x1
13 #define AP_KRO_ONLY     0x5
14 #define AP_RW_BOTH      0x3
15 #define AP_RO_BOTH      0x6
16
17 // === IMPORTS ===
18 extern Uint32   kernel_table0[];
19
20 // === TYPES ===
21 typedef struct
22 {
23         tPAddr  PhysAddr;
24         Uint8   Size;
25         Uint8   Domain;
26         BOOL    bExecutable;
27         BOOL    bGlobal;
28         BOOL    bShared;
29          int    AP;
30 } tMM_PageInfo;
31
32 //#define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
33 #define FRACTAL(table1, addr)   ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
34 #define TLBIALL()       __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
35
36 // === PROTOTYPES ===
37 void    MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
38  int    MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
39  int    MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
40  int    MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
41 tVAddr  MM_NewKStack(int bGlobal);
42
43 // === GLOBALS ===
44
45 // === CODE ===
46 int MM_InitialiseVirtual(void)
47 {
48         return 0;
49 }
50
51 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
52 {
53         if(VAddr & 0x80000000) {
54                 *Table0 = (void*)&kernel_table0;        // Level 0
55                 *Table1 = (void*)MM_TABLE1KERN; // Level 1
56         }
57         else {
58                 *Table0 = (void*)MM_TABLE0USER;
59                 *Table1 = (void*)MM_TABLE1USER;
60         }
61 }
62
63 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
64 {
65         Uint32  *table0, *table1;
66         Uint32  *desc;
67         tPAddr  paddr;
68         
69         ENTER("xVAddr iDomain", VAddr, Domain);
70
71         MM_int_GetTables(VAddr, &table0, &table1);
72
73         VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
74
75         desc = &table0[ VAddr>>20];
76         LOG("desc = %p", desc);
77         
78         // table0: 4 bytes = 1 MiB
79
80         LOG("desc[0] = %x", desc[0]);
81         LOG("desc[1] = %x", desc[1]);
82         LOG("desc[2] = %x", desc[2]);
83         LOG("desc[3] = %x", desc[3]);
84
85         if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
86          || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
87         {
88                 // Error?
89                 LEAVE('i', 1);
90                 return 1;
91         }
92
93         paddr = MM_AllocPhys();
94         if( !paddr )
95         {
96                 // Error
97                 LEAVE('i', 2);
98                 return 2;
99         }
100         
101         *desc = paddr | (Domain << 5) | 1;
102         desc[1] = desc[0] + 0x400;
103         desc[2] = desc[0] + 0x800;
104         desc[3] = desc[0] + 0xC00;
105
106         FRACTAL(table1, VAddr) = paddr | 3;
107
108         // TLBIALL 
109         TLBIALL();      
110
111         LEAVE('i', 0);
112         return 0;
113 }       
114
115 int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
116 {
117         Uint32  *table0, *table1;
118         Uint32  *desc;
119
120         ENTER("pVADdr ppi", VAddr, pi);
121
122         MM_int_GetTables(VAddr, &table0, &table1);
123
124         desc = &table0[ VAddr >> 20 ];
125         LOG("desc = %p", desc);
126
127         switch(pi->Size)
128         {
129         case 12:        // Small Page
130         case 16:        // Large Page
131                 LOG("Page");
132                 if( (*desc & 3) == 0 ) {
133                         MM_int_AllocateCoarse( VAddr, pi->Domain );
134                 }
135                 desc = &table1[ VAddr >> 12 ];
136                 LOG("desc (2) = %p", desc);
137                 if( pi->Size == 12 )
138                 {
139                         // Small page
140                         // - Error if overwriting a large page
141                         if( (*desc & 3) == 1 )  LEAVE_RET('i', 1);
142                         if( pi->PhysAddr == 0 ) {
143                                 *desc = 0;
144                                 LEAVE('i', 0);
145                                 return 0;
146                         }
147
148                         *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
149                         if(!pi->bExecutable)    *desc |= 1;     // XN
150                         if(!pi->bGlobal)        *desc |= 1 << 11;       // NG
151                         if( pi->bShared)        *desc |= 1 << 10;       // S
152                         *desc |= (pi->AP & 3) << 4;     // AP
153                         *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
154                         LEAVE('i', 0);
155                         return 0;
156                 }
157                 else
158                 {
159                         // Large page
160                         // TODO: 
161                 }
162                 break;
163         case 20:        // Section or unmapped
164                 Warning("TODO: Implement sections");
165                 break;
166         case 24:        // Supersection
167                 // Error if not aligned
168                 if( VAddr & 0xFFFFFF ) {
169                         LEAVE('i', 1);
170                         return 1;
171                 }
172                 if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
173                 {
174                         if( pi->PhysAddr == 0 ) {
175                                 *desc = 0;
176                                 // TODO: Apply to all entries
177                                 LEAVE('i', 0);
178                                 return 0;
179                         }
180                         // Apply
181                         *desc = pi->PhysAddr & 0xFF000000;
182 //                      *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
183 //                      *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
184                         *desc |= 2 | (1 << 18);
185                         // TODO: Apply to all entries
186                         LEAVE('i', 0);
187                         return 0;
188                 }
189                 // TODO: What here?
190                 LEAVE('i', 1);
191                 return 1;
192         }
193
194         LEAVE('i', 1);
195         return 1;
196 }
197
198 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
199 {
200         Uint32  *table0, *table1;
201         Uint32  desc;
202         
203         MM_int_GetTables(VAddr, &table0, &table1);
204
205         desc = table0[ VAddr >> 20 ];
206
207 //      if( VAddr > 0x90000000)
208 //              LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
209         
210         pi->bExecutable = 1;
211         pi->bGlobal = 0;
212         pi->bShared = 0;
213
214
215         switch( (desc & 3) )
216         {
217         // 0: Unmapped
218         case 0:
219                 pi->PhysAddr = 0;
220                 pi->Size = 20;
221                 pi->Domain = 0;
222                 return 1;
223
224         // 1: Coarse page table
225         case 1:
226                 // Domain from top level table
227                 pi->Domain = (desc >> 5) & 7;
228                 // Get next level
229                 desc = table1[ VAddr >> 12 ];
230 //              LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
231                 switch( desc & 3 )
232                 {
233                 // 0: Unmapped
234                 case 0: 
235                         pi->Size = 12;
236                         return 1;
237                 // 1: Large Page (64KiB)
238                 case 1:
239                         pi->Size = 16;
240                         pi->PhysAddr = desc & 0xFFFF0000;
241                         return 0;
242                 // 2/3: Small page
243                 case 2:
244                 case 3:
245                         pi->Size = 12;
246                         pi->PhysAddr = desc & 0xFFFFF000;
247                         pi->bExecutable = desc & 1;
248                         pi->bGlobal = !(desc >> 11);
249                         pi->bShared = (desc >> 10) & 1;
250                         return 0;
251                 }
252                 return 1;
253         
254         // 2: Section (or Supersection)
255         case 2:
256                 if( desc & (1 << 18) ) {
257                         // Supersection
258                         pi->PhysAddr = desc & 0xFF000000;
259                         pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
260                         pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
261                         pi->Size = 24;
262                         pi->Domain = 0; // Superpages default to zero
263                         return 0;
264                 }
265                 
266                 // Section
267                 pi->PhysAddr = desc & 0xFFF80000;
268                 pi->Size = 20;
269                 pi->Domain = (desc >> 5) & 7;
270                 return 0;
271
272         // 3: Reserved (invalid)
273         case 3:
274                 pi->PhysAddr = 0;
275                 pi->Size = 20;
276                 pi->Domain = 0;
277                 return 2;
278         }
279         return 2;
280 }
281
282 // --- Exports ---
283 tPAddr MM_GetPhysAddr(tVAddr VAddr)
284 {
285         tMM_PageInfo    pi;
286         if( MM_int_GetPageInfo(VAddr, &pi) )
287                 return 0;
288         return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
289 }
290
291 Uint MM_GetFlags(tVAddr VAddr)
292 {
293         tMM_PageInfo    pi;
294          int    ret;
295
296         if( MM_int_GetPageInfo(VAddr, &pi) )
297                 return 0;
298
299         ret = 0;
300         
301         switch(pi.AP)
302         {
303         case AP_KRW_ONLY:
304                 ret |= MM_PFLAG_KERNEL;
305                 break;
306         case AP_KRO_ONLY:
307                 ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
308                 break;
309         case AP_RW_BOTH:
310                 break;
311         case AP_RO_BOTH:
312                 ret |= MM_PFLAG_RO;
313                 break;
314         }
315
316         if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
317         return ret;
318 }
319
320 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
321 {
322         tMM_PageInfo    pi;
323         if( MM_int_GetPageInfo(VAddr, &pi) )
324                 return;
325 }
326
327 int MM_Map(tVAddr VAddr, tPAddr PAddr)
328 {
329         tMM_PageInfo    pi = {0};
330         pi.PhysAddr = PAddr;
331         pi.Size = 12;
332         pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
333         pi.bExecutable = 1;
334         if( MM_int_SetPageInfo(VAddr, &pi) ) {
335                 MM_DerefPhys(pi.PhysAddr);
336                 return 0;
337         }
338         return pi.PhysAddr;
339 }
340
341 tPAddr MM_Allocate(tVAddr VAddr)
342 {
343         tMM_PageInfo    pi = {0};
344         
345         ENTER("pVAddr", VAddr);
346
347         pi.PhysAddr = MM_AllocPhys();
348         if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
349         pi.Size = 12;
350         pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
351         pi.bExecutable = 1;
352         if( MM_int_SetPageInfo(VAddr, &pi) ) {
353                 MM_DerefPhys(pi.PhysAddr);
354                 LEAVE('i', 0);
355                 return 0;
356         }
357         LEAVE('x', pi.PhysAddr);
358         return pi.PhysAddr;
359 }
360
361 void MM_Deallocate(tVAddr VAddr)
362 {
363         tMM_PageInfo    pi;
364         
365         if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
366
367         if( pi.PhysAddr == 0 )  return;
368         MM_DerefPhys(pi.PhysAddr);
369         
370         pi.PhysAddr = 0;
371         pi.AP = 0;
372         pi.bExecutable = 0;
373         MM_int_SetPageInfo(VAddr, &pi);
374 }
375
376 tPAddr MM_ClearUser(void)
377 {
378         // TODO: Implement ClearUser
379         return 0;
380 }
381
382 tVAddr MM_MapTemp(tPAddr PAddr)
383 {
384         tVAddr  ret;
385         tMM_PageInfo    pi;
386         
387         for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
388         {
389                 if( MM_int_GetPageInfo(ret, &pi) == 0 )
390                         continue;
391         
392                 MM_Map(ret, PAddr);
393                 
394                 return ret;
395         }
396         Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
397         return 0;
398 }
399
400 void MM_FreeTemp(tVAddr VAddr)
401 {
402         // TODO: Implement FreeTemp
403         if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
404                 Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
405                 return ;
406         }
407         
408         MM_Deallocate(VAddr);
409 }
410
411 tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
412 {
413         tVAddr  ret;
414          int    i;
415         tMM_PageInfo    pi;
416
417         // Scan for a location
418         for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
419         {
420                 // Check if there is `NPages` free pages
421                 for( i = 0; i < NPages; i ++ )
422                 {
423                         if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
424                                 break;
425                 }
426                 // Nope, jump to after the used page found and try again
427                 if( i != NPages ) {
428                         ret += i * PAGE_SIZE;
429                         continue ;
430                 }
431         
432                 // Map the pages        
433                 for( i = 0; i < NPages; i ++ )
434                         MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAddr);
435                 // and return
436                 return ret;
437         }
438         Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
439         return 0;
440 }
441
442 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
443 {
444         Log_Error("MMVirt", "TODO: Implement MM_AllocDMA");
445         return 0;
446 }
447
448 void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
449 {
450         Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
451 }
452
453 tVAddr MM_NewKStack(int bShared)
454 {
455         tVAddr  min_addr, max_addr;
456         tVAddr  addr, ofs;
457
458         if( bShared ) {
459                 min_addr = MM_GLOBALSTACKS;
460                 max_addr = MM_GLOBALSTACKS_END;
461         }
462         else {
463                 min_addr = MM_KSTACK_BASE;
464                 max_addr = MM_KSTACK_END;
465         }
466
467         // Locate a free slot
468         for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
469         {
470                 tMM_PageInfo    pi;
471                 if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) )    break;
472         }
473
474         // Check for an error   
475         if(addr >= max_addr) {
476                 return 0;
477         }
478
479         // 1 guard page
480         for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
481         {
482                 if( MM_Allocate(addr + ofs) == 0 )
483                 {
484                         while(ofs)
485                         {
486                                 ofs -= PAGE_SIZE;
487                                 MM_Deallocate(addr + ofs);
488                         }
489                         Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
490                         return 0;
491                 }
492         }
493         return addr + ofs;
494 }
495
496 void MM_DumpTables(tVAddr Start, tVAddr End)
497 {
498         
499 }
500

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