4 * ARM7 Virtual Memory Manager
5 * - arch/arm7/mm_virt.c
12 #define AP_KRW_ONLY 0x1
13 #define AP_KRO_ONLY 0x5
14 #define AP_RW_BOTH 0x3
15 #define AP_RO_BOTH 0x6
18 extern Uint32 kernel_table0[];
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))
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);
46 int MM_InitialiseVirtual(void)
51 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
53 if(VAddr & 0x80000000) {
54 *Table0 = (void*)&kernel_table0; // Level 0
55 *Table1 = (void*)MM_TABLE1KERN; // Level 1
58 *Table0 = (void*)MM_TABLE0USER;
59 *Table1 = (void*)MM_TABLE1USER;
63 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
65 Uint32 *table0, *table1;
69 ENTER("xVAddr iDomain", VAddr, Domain);
71 MM_int_GetTables(VAddr, &table0, &table1);
73 VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
75 desc = &table0[ VAddr>>20];
76 LOG("desc = %p", desc);
78 // table0: 4 bytes = 1 MiB
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]);
85 if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
86 || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
93 paddr = MM_AllocPhys();
101 *desc = paddr | (Domain << 5) | 1;
102 desc[1] = desc[0] + 0x400;
103 desc[2] = desc[0] + 0x800;
104 desc[3] = desc[0] + 0xC00;
106 FRACTAL(table1, VAddr) = paddr | 3;
115 int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
117 Uint32 *table0, *table1;
120 ENTER("pVADdr ppi", VAddr, pi);
122 MM_int_GetTables(VAddr, &table0, &table1);
124 desc = &table0[ VAddr >> 20 ];
125 LOG("desc = %p", desc);
129 case 12: // Small Page
130 case 16: // Large Page
132 if( (*desc & 3) == 0 ) {
133 MM_int_AllocateCoarse( VAddr, pi->Domain );
135 desc = &table1[ VAddr >> 12 ];
136 LOG("desc (2) = %p", desc);
140 // - Error if overwriting a large page
141 if( (*desc & 3) == 1 ) LEAVE_RET('i', 1);
142 if( pi->PhysAddr == 0 ) {
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
163 case 20: // Section or unmapped
164 Warning("TODO: Implement sections");
166 case 24: // Supersection
167 // Error if not aligned
168 if( VAddr & 0xFFFFFF ) {
172 if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18))) )
174 if( pi->PhysAddr == 0 ) {
176 // TODO: Apply to all entries
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
198 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
200 Uint32 *table0, *table1;
203 MM_int_GetTables(VAddr, &table0, &table1);
205 desc = table0[ VAddr >> 20 ];
207 // if( VAddr > 0x90000000)
208 // LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
224 // 1: Coarse page table
226 // Domain from top level table
227 pi->Domain = (desc >> 5) & 7;
229 desc = table1[ VAddr >> 12 ];
230 // LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
237 // 1: Large Page (64KiB)
240 pi->PhysAddr = desc & 0xFFFF0000;
246 pi->PhysAddr = desc & 0xFFFFF000;
247 pi->bExecutable = desc & 1;
248 pi->bGlobal = !(desc >> 11);
249 pi->bShared = (desc >> 10) & 1;
254 // 2: Section (or Supersection)
256 if( desc & (1 << 18) ) {
258 pi->PhysAddr = desc & 0xFF000000;
259 pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
260 pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
262 pi->Domain = 0; // Superpages default to zero
267 pi->PhysAddr = desc & 0xFFF80000;
269 pi->Domain = (desc >> 5) & 7;
272 // 3: Reserved (invalid)
283 tPAddr MM_GetPhysAddr(tVAddr VAddr)
286 if( MM_int_GetPageInfo(VAddr, &pi) )
288 return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
291 Uint MM_GetFlags(tVAddr VAddr)
296 if( MM_int_GetPageInfo(VAddr, &pi) )
304 ret |= MM_PFLAG_KERNEL;
307 ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
316 if( pi.bExecutable ) ret |= MM_PFLAG_EXEC;
320 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
323 if( MM_int_GetPageInfo(VAddr, &pi) )
327 int MM_Map(tVAddr VAddr, tPAddr PAddr)
329 tMM_PageInfo pi = {0};
332 pi.AP = AP_KRW_ONLY; // Kernel Read/Write
334 if( MM_int_SetPageInfo(VAddr, &pi) ) {
335 MM_DerefPhys(pi.PhysAddr);
341 tPAddr MM_Allocate(tVAddr VAddr)
343 tMM_PageInfo pi = {0};
345 ENTER("pVAddr", VAddr);
347 pi.PhysAddr = MM_AllocPhys();
348 if( pi.PhysAddr == 0 ) LEAVE_RET('i', 0);
350 pi.AP = AP_KRW_ONLY; // Kernel Read/Write
352 if( MM_int_SetPageInfo(VAddr, &pi) ) {
353 MM_DerefPhys(pi.PhysAddr);
357 LEAVE('x', pi.PhysAddr);
361 void MM_Deallocate(tVAddr VAddr)
365 if( MM_int_GetPageInfo(VAddr, &pi) ) return ;
367 if( pi.PhysAddr == 0 ) return;
368 MM_DerefPhys(pi.PhysAddr);
373 MM_int_SetPageInfo(VAddr, &pi);
376 tPAddr MM_ClearUser(void)
378 // TODO: Implement ClearUser
382 tVAddr MM_MapTemp(tPAddr PAddr)
387 for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
389 if( MM_int_GetPageInfo(ret, &pi) == 0 )
396 Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
400 void MM_FreeTemp(tVAddr VAddr)
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);
408 MM_Deallocate(VAddr);
411 tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
417 // Scan for a location
418 for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
420 // Check if there is `NPages` free pages
421 for( i = 0; i < NPages; i ++ )
423 if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
426 // Nope, jump to after the used page found and try again
428 ret += i * PAGE_SIZE;
433 for( i = 0; i < NPages; i ++ )
434 MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAddr);
438 Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
442 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
444 Log_Error("MMVirt", "TODO: Implement MM_AllocDMA");
448 void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
450 Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
453 tVAddr MM_NewKStack(int bShared)
455 tVAddr min_addr, max_addr;
459 min_addr = MM_GLOBALSTACKS;
460 max_addr = MM_GLOBALSTACKS_END;
463 min_addr = MM_KSTACK_BASE;
464 max_addr = MM_KSTACK_END;
467 // Locate a free slot
468 for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
471 if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) ) break;
474 // Check for an error
475 if(addr >= max_addr) {
480 for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
482 if( MM_Allocate(addr + ofs) == 0 )
487 MM_Deallocate(addr + ofs);
489 Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
496 void MM_DumpTables(tVAddr Start, tVAddr End)