4 * ARM7 Virtual Memory Manager
5 * - arch/arm7/mm_virt.c
11 #define AP_KRW_ONLY 0x1
12 #define AP_KRO_ONLY 0x5
13 #define AP_RW_BOTH 0x3
14 #define AP_RO_BOTH 0x6
29 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
30 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
31 int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
32 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
37 int MM_InitialiseVirtual(void)
42 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
44 if(VAddr & 0x80000000) {
45 *Table0 = (void*)MM_TABLE0KERN; // Level 0
46 *Table1 = (void*)MM_TABLE1KERN; // Level 1
49 *Table0 = (void*)MM_TABLE0USER;
50 *Table1 = (void*)MM_TABLE1USER;
54 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
56 Uint32 *table0, *table1;
60 MM_int_GetTables(VAddr, &table0, &table1);
62 VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
64 desc = &table0[VAddr>>20];
66 if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
67 || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
73 paddr = MM_AllocPhys();
80 *desc = paddr | (Domain << 5) | 1;
81 desc[1] = desc[0] + 0x400;
82 desc[2] = desc[0] + 0x800;
83 desc[3] = desc[0] + 0xC00;
85 table1[(VAddr>>20)*256] = paddr | 3;
90 int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
92 Uint32 *table0, *table1;
95 MM_int_GetTables(VAddr, &table0, &table1);
97 desc = &table0[ VAddr >> 20 ];
101 case 12: // Small Page
102 case 16: // Large Page
103 if( (*desc & 3) == 0 ) {
104 MM_int_AllocateCoarse( VAddr, pi->Domain );
106 desc = &table1[ VAddr >> 12 ];
110 // - Error if overwriting a large page
111 if( (*desc & 3) == 1 ) return 1;
112 if( pi->PhysAddr == 0 ) {
117 *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
118 if(!pi->bExecutable) *desc |= 1; // XN
119 if(!pi->bGlobal) *desc |= 1 << 11; // NG
120 if( pi->bShared) *desc |= 1 << 10; // S
121 *desc |= (pi->AP & 3) << 4; // AP
122 *desc |= ((pi->AP >> 2) & 1) << 9; // APX
130 case 20: // Section or unmapped
131 Log_Warning("MM", "TODO: Implement sections");
133 case 24: // Supersection
134 // Error if not aligned
135 if( VAddr & 0xFFFFFF ) {
138 if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18))) )
140 if( pi->PhysAddr == 0 ) {
142 // TODO: Apply to all entries
146 *desc = pi->PhysAddr & 0xFF000000;
147 // *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
148 // *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
149 *desc |= 2 | (1 << 18);
150 // TODO: Apply to all entries
159 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
161 Uint32 *table0, *table1;
164 MM_int_GetTables(VAddr, &table0, &table1);
166 desc = table0[ VAddr >> 20 ];
181 // 1: Coarse page table
183 // Domain from top level table
184 pi->Domain = (desc >> 5) & 7;
186 desc = table1[ VAddr >> 12 ];
193 // 1: Large Page (64KiB)
196 pi->PhysAddr = desc & 0xFFFF0000;
202 pi->PhysAddr = desc & 0xFFFFF000;
203 pi->bExecutable = desc & 1;
204 pi->bGlobal = !(desc >> 11);
205 pi->bShared = (desc >> 10) & 1;
210 // 2: Section (or Supersection)
212 if( desc & (1 << 18) ) {
214 pi->PhysAddr = desc & 0xFF000000;
215 pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
216 pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
218 pi->Domain = 0; // Superpages default to zero
223 pi->PhysAddr = desc & 0xFFF80000;
225 pi->Domain = (desc >> 5) & 7;
228 // 3: Reserved (invalid)
239 tPAddr MM_GetPhysAddr(tVAddr VAddr)
242 if( MM_int_GetPageInfo(VAddr, &pi) )
247 Uint MM_GetFlags(tVAddr VAddr)
252 if( MM_int_GetPageInfo(VAddr, &pi) )
260 ret |= MM_PFLAG_KERNEL;
263 ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
272 if( pi.bExecutable ) ret |= MM_PFLAG_EXEC;
276 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
279 if( MM_int_GetPageInfo(VAddr, &pi) )
286 int MM_Map(tVAddr VAddr, tPAddr PAddr)
288 tMM_PageInfo pi = {0};
291 pi.AP = AP_KRW_ONLY; // Kernel Read/Write
293 if( MM_int_SetPageInfo(VAddr, &pi) ) {
294 MM_DerefPhys(pi.PhysAddr);
300 tPAddr MM_Allocate(tVAddr VAddr)
302 tMM_PageInfo pi = {0};
304 pi.PhysAddr = MM_AllocPhys();
305 if( pi.PhysAddr == 0 ) return 0;
307 pi.AP = AP_KRW_ONLY; // Kernel Read/Write
309 if( MM_int_SetPageInfo(VAddr, &pi) ) {
310 MM_DerefPhys(pi.PhysAddr);
316 void MM_Deallocate(tVAddr VAddr)
320 if( MM_int_GetPageInfo(VAddr, &pi) ) return ;
322 if( pi.PhysAddr == 0 ) return;
323 MM_DerefPhys(pi.PhysAddr);
328 MM_int_SetPageInfo(VAddr, &pi);
331 tPAddr MM_ClearUser(void)
333 // TODO: Implement ClearUser
337 tVAddr MM_MapTemp(tPAddr PAddr)
339 // TODO: Implement MapTemp
343 void MM_FreeTemp(tVAddr VAddr)
345 // TODO: Implement FreeTemp