3dca8ac6ee0802b8678c06392c0a118201576be0
[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 #include <acess.h>
8 #include <mm_virt.h>
9 #include <hal_proc.h>
10
11 #define AP_KRW_ONLY     0x1
12 #define AP_KRO_ONLY     0x5
13 #define AP_RW_BOTH      0x3
14 #define AP_RO_BOTH      0x6
15
16 // === TYPES ===
17 typedef struct
18 {
19         tPAddr  PhysAddr;
20         Uint8   Size;
21         Uint8   Domain;
22         BOOL    bExecutable;
23         BOOL    bGlobal;
24         BOOL    bShared;
25          int    AP;
26 } tMM_PageInfo;
27
28 //#define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
29 #define FRACTAL(table1, addr)   ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
30 #define TLBIALL()       __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
31
32 // === PROTOTYPES ===
33 void    MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
34  int    MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
35  int    MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
36  int    MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
37
38 // === GLOBALS ===
39
40 // === CODE ===
41 int MM_InitialiseVirtual(void)
42 {
43         return 0;
44 }
45
46 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
47 {
48         if(VAddr & 0x80000000) {
49                 *Table0 = (void*)MM_TABLE0KERN; // Level 0
50                 *Table1 = (void*)MM_TABLE1KERN; // Level 1
51         }
52         else {
53                 *Table0 = (void*)MM_TABLE0USER;
54                 *Table1 = (void*)MM_TABLE1USER;
55         }
56 }
57
58 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
59 {
60         Uint32  *table0, *table1;
61         Uint32  *desc;
62         tPAddr  paddr;
63
64         MM_int_GetTables(VAddr, &table0, &table1);
65
66         VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
67
68         desc = &table0[VAddr>>20];      
69
70         if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
71          || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
72         {
73                 // Error?
74                 return 1;
75         }
76
77         paddr = MM_AllocPhys();
78         if( !paddr )
79         {
80                 // Error
81                 return 2;
82         }
83         
84         *desc = paddr | (Domain << 5) | 1;
85         desc[1] = desc[0] + 0x400;
86         desc[2] = desc[0] + 0x800;
87         desc[3] = desc[0] + 0xC00;
88
89         Log("FRACTAL(%p, %p) = %p", table1, VAddr, &FRACTAL(table1, VAddr));
90         FRACTAL(table1, VAddr) = paddr | 3;
91
92         // TLBIALL 
93         TLBIALL();      
94
95         return 0;
96 }       
97
98 int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
99 {
100         Uint32  *table0, *table1;
101         Uint32  *desc;
102
103         MM_int_GetTables(VAddr, &table0, &table1);
104
105         desc = &table0[ VAddr >> 20 ];
106
107         switch(pi->Size)
108         {
109         case 12:        // Small Page
110         case 16:        // Large Page
111                 if( (*desc & 3) == 0 ) {
112                         MM_int_AllocateCoarse( VAddr, pi->Domain );
113                 }
114                 desc = &table1[ VAddr >> 12 ];
115                 if( pi->Size == 12 )
116                 {
117                         // Small page
118                         // - Error if overwriting a large page
119                         if( (*desc & 3) == 1 )  return 1;
120                         if( pi->PhysAddr == 0 ) {
121                                 *desc = 0;
122                                 return 0;
123                         }
124
125                         *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
126                         if(!pi->bExecutable)    *desc |= 1;     // XN
127                         if(!pi->bGlobal)        *desc |= 1 << 11;       // NG
128                         if( pi->bShared)        *desc |= 1 << 10;       // S
129                         *desc |= (pi->AP & 3) << 4;     // AP
130                         *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
131                 }
132                 else
133                 {
134                         // Large page
135                         // TODO: 
136                 }
137                 break;
138         case 20:        // Section or unmapped
139                 Log_Warning("MM", "TODO: Implement sections");
140                 break;
141         case 24:        // Supersection
142                 // Error if not aligned
143                 if( VAddr & 0xFFFFFF ) {
144                         return 1;
145                 }
146                 if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
147                 {
148                         if( pi->PhysAddr == 0 ) {
149                                 *desc = 0;
150                                 // TODO: Apply to all entries
151                                 return 0;
152                         }
153                         // Apply
154                         *desc = pi->PhysAddr & 0xFF000000;
155 //                      *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
156 //                      *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
157                         *desc |= 2 | (1 << 18);
158                         // TODO: Apply to all entries
159                         return 0;
160                 }
161                 return 1;
162         }
163
164         return 1;
165 }
166
167 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
168 {
169         Uint32  *table0, *table1;
170         Uint32  desc;
171         
172         MM_int_GetTables(VAddr, &table0, &table1);
173
174         desc = table0[ VAddr >> 20 ];
175         
176         pi->bExecutable = 1;
177         pi->bGlobal = 0;
178         pi->bShared = 0;
179
180         switch( (desc & 3) )
181         {
182         // 0: Unmapped
183         case 0:
184                 pi->PhysAddr = 0;
185                 pi->Size = 20;
186                 pi->Domain = 0;
187                 return 1;
188
189         // 1: Coarse page table
190         case 1:
191                 // Domain from top level table
192                 pi->Domain = (desc >> 5) & 7;
193                 // Get next level
194                 desc = table1[ VAddr >> 12 ];
195                 switch( desc & 3 )
196                 {
197                 // 0: Unmapped
198                 case 0: 
199                         pi->Size = 12;
200                         return 1;
201                 // 1: Large Page (64KiB)
202                 case 1:
203                         pi->Size = 16;
204                         pi->PhysAddr = desc & 0xFFFF0000;
205                         return 0;
206                 // 2/3: Small page
207                 case 2:
208                 case 3:
209                         pi->Size = 12;
210                         pi->PhysAddr = desc & 0xFFFFF000;
211                         pi->bExecutable = desc & 1;
212                         pi->bGlobal = !(desc >> 11);
213                         pi->bShared = (desc >> 10) & 1;
214                         return 1;
215                 }
216                 return 1;
217         
218         // 2: Section (or Supersection)
219         case 2:
220                 if( desc & (1 << 18) ) {
221                         // Supersection
222                         pi->PhysAddr = desc & 0xFF000000;
223                         pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
224                         pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
225                         pi->Size = 24;
226                         pi->Domain = 0; // Superpages default to zero
227                         return 0;
228                 }
229                 
230                 // Section
231                 pi->PhysAddr = desc & 0xFFF80000;
232                 pi->Size = 20;
233                 pi->Domain = (desc >> 5) & 7;
234                 return 0;
235
236         // 3: Reserved (invalid)
237         case 3:
238                 pi->PhysAddr = 0;
239                 pi->Size = 20;
240                 pi->Domain = 0;
241                 return 2;
242         }
243         return 2;
244 }
245
246 // --- Exports ---
247 tPAddr MM_GetPhysAddr(tVAddr VAddr)
248 {
249         tMM_PageInfo    pi;
250         if( MM_int_GetPageInfo(VAddr, &pi) )
251                 return 0;
252         return pi.PhysAddr;
253 }
254
255 Uint MM_GetFlags(tVAddr VAddr)
256 {
257         tMM_PageInfo    pi;
258          int    ret;
259
260         if( MM_int_GetPageInfo(VAddr, &pi) )
261                 return 0;
262
263         ret = 0;
264         
265         switch(pi.AP)
266         {
267         case AP_KRW_ONLY:
268                 ret |= MM_PFLAG_KERNEL;
269                 break;
270         case AP_KRO_ONLY:
271                 ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
272                 break;
273         case AP_RW_BOTH:
274                 break;
275         case AP_RO_BOTH:
276                 ret |= MM_PFLAG_RO;
277                 break;
278         }
279
280         if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
281         return ret;
282 }
283
284 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
285 {
286         tMM_PageInfo    pi;
287         if( MM_int_GetPageInfo(VAddr, &pi) )
288                 return;
289         
290                 
291
292 }
293
294 int MM_Map(tVAddr VAddr, tPAddr PAddr)
295 {
296         tMM_PageInfo    pi = {0};
297         pi.PhysAddr = PAddr;
298         pi.Size = 12;
299         pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
300         pi.bExecutable = 1;
301         if( MM_int_SetPageInfo(VAddr, &pi) ) {
302                 MM_DerefPhys(pi.PhysAddr);
303                 return 0;
304         }
305         return pi.PhysAddr;
306 }
307
308 tPAddr MM_Allocate(tVAddr VAddr)
309 {
310         tMM_PageInfo    pi = {0};
311
312         pi.PhysAddr = MM_AllocPhys();
313         if( pi.PhysAddr == 0 )  return 0;
314         pi.Size = 12;
315         pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
316         pi.bExecutable = 1;
317         if( MM_int_SetPageInfo(VAddr, &pi) ) {
318                 MM_DerefPhys(pi.PhysAddr);
319                 return 0;
320         }
321         return pi.PhysAddr;
322 }
323
324 void MM_Deallocate(tVAddr VAddr)
325 {
326         tMM_PageInfo    pi;
327         
328         if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
329
330         if( pi.PhysAddr == 0 )  return;
331         MM_DerefPhys(pi.PhysAddr);
332         
333         pi.PhysAddr = 0;
334         pi.AP = 0;
335         pi.bExecutable = 0;
336         MM_int_SetPageInfo(VAddr, &pi);
337 }
338
339 tPAddr MM_ClearUser(void)
340 {
341         // TODO: Implement ClearUser
342         return 0;
343 }
344
345 tVAddr MM_MapTemp(tPAddr PAddr)
346 {
347         // TODO: Implement MapTemp
348         return 0;
349 }
350
351 void MM_FreeTemp(tVAddr VAddr)
352 {
353         // TODO: Implement FreeTemp
354 }
355
356 void MM_DumpTables(tVAddr Start, tVAddr End)
357 {
358         
359 }
360

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