Kernel/arm7 - Now with less crash
[tpg/acess2.git] / Kernel / arch / arm7 / 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
42 // === GLOBALS ===
43
44 // === CODE ===
45 int MM_InitialiseVirtual(void)
46 {
47         return 0;
48 }
49
50 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
51 {
52         if(VAddr & 0x80000000) {
53                 *Table0 = (void*)&kernel_table0;        // Level 0
54                 *Table1 = (void*)MM_TABLE1KERN; // Level 1
55         }
56         else {
57                 *Table0 = (void*)MM_TABLE0USER;
58                 *Table1 = (void*)MM_TABLE1USER;
59         }
60 }
61
62 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
63 {
64         Uint32  *table0, *table1;
65         Uint32  *desc;
66         tPAddr  paddr;
67         
68         ENTER("xVAddr iDomain", VAddr, Domain);
69
70         MM_int_GetTables(VAddr, &table0, &table1);
71
72         VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
73
74         desc = &table0[ VAddr>>20];
75         LOG("desc = %p", desc);
76         
77         // table0: 4 bytes = 1 MiB
78
79         LOG("desc[0] = %x", desc[0]);
80         LOG("desc[1] = %x", desc[1]);
81         LOG("desc[2] = %x", desc[2]);
82         LOG("desc[3] = %x", desc[3]);
83
84         if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
85          || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
86         {
87                 // Error?
88                 LEAVE('i', 1);
89                 return 1;
90         }
91
92         paddr = MM_AllocPhys();
93         if( !paddr )
94         {
95                 // Error
96                 LEAVE('i', 2);
97                 return 2;
98         }
99         
100         *desc = paddr | (Domain << 5) | 1;
101         desc[1] = desc[0] + 0x400;
102         desc[2] = desc[0] + 0x800;
103         desc[3] = desc[0] + 0xC00;
104
105         Log("FRACTAL(%p, %p) = %p", table1, VAddr, &FRACTAL(table1, VAddr));
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                 }
155                 else
156                 {
157                         // Large page
158                         // TODO: 
159                 }
160                 break;
161         case 20:        // Section or unmapped
162                 Log_Warning("MM", "TODO: Implement sections");
163                 break;
164         case 24:        // Supersection
165                 // Error if not aligned
166                 if( VAddr & 0xFFFFFF ) {
167                         LEAVE('i', 1);
168                         return 1;
169                 }
170                 if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
171                 {
172                         if( pi->PhysAddr == 0 ) {
173                                 *desc = 0;
174                                 // TODO: Apply to all entries
175                                 LEAVE('i', 0);
176                                 return 0;
177                         }
178                         // Apply
179                         *desc = pi->PhysAddr & 0xFF000000;
180 //                      *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
181 //                      *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
182                         *desc |= 2 | (1 << 18);
183                         // TODO: Apply to all entries
184                         LEAVE('i', 0);
185                         return 0;
186                 }
187                 LEAVE('i', 1);
188                 return 1;
189         }
190
191         LEAVE('i', 1);
192         return 1;
193 }
194
195 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
196 {
197         Uint32  *table0, *table1;
198         Uint32  desc;
199         
200         MM_int_GetTables(VAddr, &table0, &table1);
201
202         desc = table0[ VAddr >> 20 ];
203         
204         pi->bExecutable = 1;
205         pi->bGlobal = 0;
206         pi->bShared = 0;
207
208         switch( (desc & 3) )
209         {
210         // 0: Unmapped
211         case 0:
212                 pi->PhysAddr = 0;
213                 pi->Size = 20;
214                 pi->Domain = 0;
215                 return 1;
216
217         // 1: Coarse page table
218         case 1:
219                 // Domain from top level table
220                 pi->Domain = (desc >> 5) & 7;
221                 // Get next level
222                 desc = table1[ VAddr >> 12 ];
223                 switch( desc & 3 )
224                 {
225                 // 0: Unmapped
226                 case 0: 
227                         pi->Size = 12;
228                         return 1;
229                 // 1: Large Page (64KiB)
230                 case 1:
231                         pi->Size = 16;
232                         pi->PhysAddr = desc & 0xFFFF0000;
233                         return 0;
234                 // 2/3: Small page
235                 case 2:
236                 case 3:
237                         pi->Size = 12;
238                         pi->PhysAddr = desc & 0xFFFFF000;
239                         pi->bExecutable = desc & 1;
240                         pi->bGlobal = !(desc >> 11);
241                         pi->bShared = (desc >> 10) & 1;
242                         return 1;
243                 }
244                 return 1;
245         
246         // 2: Section (or Supersection)
247         case 2:
248                 if( desc & (1 << 18) ) {
249                         // Supersection
250                         pi->PhysAddr = desc & 0xFF000000;
251                         pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
252                         pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
253                         pi->Size = 24;
254                         pi->Domain = 0; // Superpages default to zero
255                         return 0;
256                 }
257                 
258                 // Section
259                 pi->PhysAddr = desc & 0xFFF80000;
260                 pi->Size = 20;
261                 pi->Domain = (desc >> 5) & 7;
262                 return 0;
263
264         // 3: Reserved (invalid)
265         case 3:
266                 pi->PhysAddr = 0;
267                 pi->Size = 20;
268                 pi->Domain = 0;
269                 return 2;
270         }
271         return 2;
272 }
273
274 // --- Exports ---
275 tPAddr MM_GetPhysAddr(tVAddr VAddr)
276 {
277         tMM_PageInfo    pi;
278         if( MM_int_GetPageInfo(VAddr, &pi) )
279                 return 0;
280         return pi.PhysAddr;
281 }
282
283 Uint MM_GetFlags(tVAddr VAddr)
284 {
285         tMM_PageInfo    pi;
286          int    ret;
287
288         if( MM_int_GetPageInfo(VAddr, &pi) )
289                 return 0;
290
291         ret = 0;
292         
293         switch(pi.AP)
294         {
295         case AP_KRW_ONLY:
296                 ret |= MM_PFLAG_KERNEL;
297                 break;
298         case AP_KRO_ONLY:
299                 ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
300                 break;
301         case AP_RW_BOTH:
302                 break;
303         case AP_RO_BOTH:
304                 ret |= MM_PFLAG_RO;
305                 break;
306         }
307
308         if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
309         return ret;
310 }
311
312 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
313 {
314         tMM_PageInfo    pi;
315         if( MM_int_GetPageInfo(VAddr, &pi) )
316                 return;
317         
318                 
319
320 }
321
322 int MM_Map(tVAddr VAddr, tPAddr PAddr)
323 {
324         tMM_PageInfo    pi = {0};
325         pi.PhysAddr = PAddr;
326         pi.Size = 12;
327         pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
328         pi.bExecutable = 1;
329         if( MM_int_SetPageInfo(VAddr, &pi) ) {
330                 MM_DerefPhys(pi.PhysAddr);
331                 return 0;
332         }
333         return pi.PhysAddr;
334 }
335
336 tPAddr MM_Allocate(tVAddr VAddr)
337 {
338         tMM_PageInfo    pi = {0};
339         
340         ENTER("pVAddr", VAddr);
341
342         pi.PhysAddr = MM_AllocPhys();
343         if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
344         pi.Size = 12;
345         pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
346         pi.bExecutable = 1;
347         if( MM_int_SetPageInfo(VAddr, &pi) ) {
348                 MM_DerefPhys(pi.PhysAddr);
349                 LEAVE('i', 0);
350                 return 0;
351         }
352         LEAVE('x', pi.PhysAddr);
353         return pi.PhysAddr;
354 }
355
356 void MM_Deallocate(tVAddr VAddr)
357 {
358         tMM_PageInfo    pi;
359         
360         if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
361
362         if( pi.PhysAddr == 0 )  return;
363         MM_DerefPhys(pi.PhysAddr);
364         
365         pi.PhysAddr = 0;
366         pi.AP = 0;
367         pi.bExecutable = 0;
368         MM_int_SetPageInfo(VAddr, &pi);
369 }
370
371 tPAddr MM_ClearUser(void)
372 {
373         // TODO: Implement ClearUser
374         return 0;
375 }
376
377 tVAddr MM_MapTemp(tPAddr PAddr)
378 {
379         // TODO: Implement MapTemp
380         return 0;
381 }
382
383 void MM_FreeTemp(tVAddr VAddr)
384 {
385         // TODO: Implement FreeTemp
386 }
387
388 void MM_DumpTables(tVAddr Start, tVAddr End)
389 {
390         
391 }
392

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