Kernel/armv7 - Bugfixing, can get to user relocation now
[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     1       // Kernel page
13 #define AP_KRO_ONLY     5       // Kernel RO page
14 #define AP_RW_BOTH      3       // Standard RW
15 #define AP_RO_BOTH      6       // COW Page
16 #define AP_RO_USER      2       // User RO Page
17 #define PADDR_MASK_LVL1 0xFFFFFC00
18
19 // === IMPORTS ===
20 extern Uint32   kernel_table0[];
21
22 // === TYPES ===
23 typedef struct
24 {
25         tPAddr  PhysAddr;
26         Uint8   Size;
27         Uint8   Domain;
28         BOOL    bExecutable;
29         BOOL    bGlobal;
30         BOOL    bShared;
31          int    AP;
32 } tMM_PageInfo;
33
34 //#define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
35 #define FRACTAL(table1, addr)   ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
36 #define USRFRACTAL(addr)        (*((Uint32*)(0x7FDFF000) + ((addr)>>22)))
37 #define TLBIALL()       __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
38 #define TLBIMVA(addr)   __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1" : : "r" (addr))
39
40 // === PROTOTYPES ===
41 void    MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
42  int    MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
43  int    MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
44  int    MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
45 tVAddr  MM_NewUserStack(void);
46 tPAddr  MM_AllocateZero(tVAddr VAddr);
47 tPAddr  MM_AllocateRootTable(void);
48 void    MM_int_CloneTable(Uint32 *DestEnt, int Table);
49 tPAddr  MM_Clone(void);
50 tVAddr  MM_NewKStack(int bGlobal);
51 void    MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
52 //void  MM_DumpTables(tVAddr Start, tVAddr End);
53
54 // === GLOBALS ===
55 tPAddr  giMM_ZeroPage;
56
57 // === CODE ===
58 int MM_InitialiseVirtual(void)
59 {
60         return 0;
61 }
62
63 void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
64 {
65         if(VAddr & 0x80000000) {
66                 *Table0 = (void*)&kernel_table0;        // Level 0
67                 *Table1 = (void*)MM_TABLE1KERN; // Level 1
68         }
69         else {
70                 *Table0 = (void*)MM_TABLE0USER;
71                 *Table1 = (void*)MM_TABLE1USER;
72         }
73 }
74
75 int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
76 {
77         Uint32  *table0, *table1;
78         Uint32  *desc;
79         tPAddr  paddr;
80         
81         ENTER("xVAddr iDomain", VAddr, Domain);
82
83         MM_int_GetTables(VAddr, &table0, &table1);
84
85         VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
86
87         desc = &table0[ VAddr>>20];
88         LOG("desc = %p", desc);
89         
90         // table0: 4 bytes = 1 MiB
91
92         LOG("desc[0] = %x", desc[0]);
93         LOG("desc[1] = %x", desc[1]);
94         LOG("desc[2] = %x", desc[2]);
95         LOG("desc[3] = %x", desc[3]);
96
97         if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
98          || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
99         {
100                 // Error?
101                 LEAVE('i', 1);
102                 return 1;
103         }
104
105         paddr = MM_AllocPhys();
106         if( !paddr )
107         {
108                 // Error
109                 LEAVE('i', 2);
110                 return 2;
111         }
112         
113         *desc = paddr | (Domain << 5) | 1;
114         desc[1] = desc[0] + 0x400;
115         desc[2] = desc[0] + 0x800;
116         desc[3] = desc[0] + 0xC00;
117
118         if( VAddr < 0x80000000 ) {
119 //              Log("USRFRACTAL(%p) = %p", VAddr, &USRFRACTAL(VAddr));
120                 USRFRACTAL(VAddr) = paddr | 3;
121         }
122         else {
123 //              Log("FRACTAL(%p) = %p", VAddr, &FRACTAL(table1, VAddr));
124                 FRACTAL(table1, VAddr) = paddr | 3;
125         }
126
127         // TLBIALL 
128         TLBIALL();      
129
130         LEAVE('i', 0);
131         return 0;
132 }       
133
134 int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
135 {
136         Uint32  *table0, *table1;
137         Uint32  *desc;
138
139         ENTER("pVAddr ppi", VAddr, pi);
140
141         MM_int_GetTables(VAddr, &table0, &table1);
142
143         desc = &table0[ VAddr >> 20 ];
144         LOG("desc = %p", desc);
145
146         switch(pi->Size)
147         {
148         case 12:        // Small Page
149         case 16:        // Large Page
150                 LOG("Page");
151                 if( (*desc & 3) == 0 ) {
152                         MM_int_AllocateCoarse( VAddr, pi->Domain );
153                 }
154                 desc = &table1[ VAddr >> 12 ];
155                 LOG("desc (2) = %p", desc);
156                 if( pi->Size == 12 )
157                 {
158                         // Small page
159                         // - Error if overwriting a large page
160                         if( (*desc & 3) == 1 )  LEAVE_RET('i', 1);
161                         if( pi->PhysAddr == 0 ) {
162                                 *desc = 0;
163                                 LEAVE('i', 0);
164                                 return 0;
165                         }
166
167                         *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
168                         if(!pi->bExecutable)    *desc |= 1;     // XN
169                         if(!pi->bGlobal)        *desc |= 1 << 11;       // NG
170                         if( pi->bShared)        *desc |= 1 << 10;       // S
171                         *desc |= (pi->AP & 3) << 4;     // AP
172                         *desc |= ((pi->AP >> 2) & 1) << 9;      // APX
173                         TLBIMVA(VAddr & 0xFFFFF000);
174                         LEAVE('i', 0);
175                         return 0;
176                 }
177                 else
178                 {
179                         // Large page
180                         // TODO: 
181                         Log_Warning("MMVirt", "TODO: Implement large pages in MM_int_SetPageInfo");
182                 }
183                 break;
184         case 20:        // Section or unmapped
185                 Warning("TODO: Implement sections");
186                 break;
187         case 24:        // Supersection
188                 // Error if not aligned
189                 if( VAddr & 0xFFFFFF ) {
190                         LEAVE('i', 1);
191                         return 1;
192                 }
193                 if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18)))  )
194                 {
195                         if( pi->PhysAddr == 0 ) {
196                                 *desc = 0;
197                                 // TODO: Apply to all entries
198                                 LEAVE('i', 0);
199                                 return 0;
200                         }
201                         // Apply
202                         *desc = pi->PhysAddr & 0xFF000000;
203 //                      *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
204 //                      *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
205                         *desc |= 2 | (1 << 18);
206                         // TODO: Apply to all entries
207                         LEAVE('i', 0);
208                         return 0;
209                 }
210                 // TODO: What here?
211                 LEAVE('i', 1);
212                 return 1;
213         }
214
215         LEAVE('i', 1);
216         return 1;
217 }
218
219 int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
220 {
221         Uint32  *table0, *table1;
222         Uint32  desc;
223
224 //      LogF("MM_int_GetPageInfo: VAddr=%p, pi=%p\n", VAddr, pi);
225         
226         MM_int_GetTables(VAddr, &table0, &table1);
227
228         desc = table0[ VAddr >> 20 ];
229
230 //      if( VAddr > 0x90000000)
231 //              LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
232         
233         pi->bExecutable = 1;
234         pi->bGlobal = 0;
235         pi->bShared = 0;
236         pi->AP = 0;
237
238         switch( (desc & 3) )
239         {
240         // 0: Unmapped
241         case 0:
242                 pi->PhysAddr = 0;
243                 pi->Size = 20;
244                 pi->Domain = 0;
245                 return 1;
246
247         // 1: Coarse page table
248         case 1:
249                 // Domain from top level table
250                 pi->Domain = (desc >> 5) & 7;
251                 // Get next level
252                 desc = table1[ VAddr >> 12 ];
253 //              LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
254                 switch( desc & 3 )
255                 {
256                 // 0: Unmapped
257                 case 0: 
258                         pi->Size = 12;
259                         return 1;
260                 // 1: Large Page (64KiB)
261                 case 1:
262                         pi->Size = 16;
263                         pi->PhysAddr = desc & 0xFFFF0000;
264                         pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
265                         pi->bExecutable = !(desc & 0x8000);
266                         pi->bShared = (desc >> 10) & 1;
267                         return 0;
268                 // 2/3: Small page
269                 case 2:
270                 case 3:
271                         pi->Size = 12;
272                         pi->PhysAddr = desc & 0xFFFFF000;
273                         pi->bExecutable = !(desc & 1);
274                         pi->bGlobal = !(desc >> 11);
275                         pi->bShared = (desc >> 10) & 1;
276                         pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
277                         return 0;
278                 }
279                 return 1;
280         
281         // 2: Section (or Supersection)
282         case 2:
283                 if( desc & (1 << 18) ) {
284                         // Supersection
285                         pi->PhysAddr = desc & 0xFF000000;
286                         pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
287                         pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
288                         pi->Size = 24;
289                         pi->Domain = 0; // Supersections default to zero
290                         pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
291                         return 0;
292                 }
293                 
294                 // Section
295                 pi->PhysAddr = desc & 0xFFF80000;
296                 pi->Size = 20;
297                 pi->Domain = (desc >> 5) & 7;
298                 pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
299                 return 0;
300
301         // 3: Reserved (invalid)
302         case 3:
303                 pi->PhysAddr = 0;
304                 pi->Size = 20;
305                 pi->Domain = 0;
306                 return 2;
307         }
308         return 2;
309 }
310
311 // --- Exports ---
312 tPAddr MM_GetPhysAddr(tVAddr VAddr)
313 {
314         tMM_PageInfo    pi;
315         if( MM_int_GetPageInfo(VAddr, &pi) )
316                 return 0;
317         return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
318 }
319
320 Uint MM_GetFlags(tVAddr VAddr)
321 {
322         tMM_PageInfo    pi;
323          int    ret;
324
325         if( MM_int_GetPageInfo(VAddr, &pi) )
326                 return 0;
327
328         ret = 0;
329         
330         switch(pi.AP)
331         {
332         case 0:
333                 break;
334         case AP_KRW_ONLY:
335                 ret |= MM_PFLAG_KERNEL;
336                 break;
337         case AP_KRO_ONLY:
338                 ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
339                 break;
340         case AP_RW_BOTH:
341                 break;
342         case AP_RO_BOTH:
343                 ret |= MM_PFLAG_COW;
344                 break;
345         case AP_RO_USER:
346                 ret |= MM_PFLAG_RO;
347                 break;
348         }
349
350         if( pi.bExecutable )    ret |= MM_PFLAG_EXEC;
351         return ret;
352 }
353
354 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
355 {
356         tMM_PageInfo    pi;
357         Uint    curFlags;
358         
359         if( MM_int_GetPageInfo(VAddr, &pi) )
360                 return ;
361         
362         curFlags = MM_GetPhysAddr(VAddr);
363         if( (curFlags & Mask) == Flags )
364                 return ;
365         curFlags &= ~Mask;
366         curFlags |= Flags;
367
368         if( curFlags & MM_PFLAG_COW )
369                 pi.AP = AP_RO_BOTH;
370         else
371         {
372                 switch(curFlags & (MM_PFLAG_KERNEL|MM_PFLAG_RO) )
373                 {
374                 case 0:
375                         pi.AP = AP_RW_BOTH;     break;
376                 case MM_PFLAG_KERNEL:
377                         pi.AP = AP_KRW_ONLY;    break;
378                 case MM_PFLAG_RO:
379                         pi.AP = AP_RO_USER;     break;
380                 case MM_PFLAG_KERNEL|MM_PFLAG_RO:
381                         pi.AP = AP_KRO_ONLY;    break;
382                 }
383         }
384         
385         pi.bExecutable = !!(curFlags & MM_PFLAG_EXEC);
386
387         MM_int_SetPageInfo(VAddr, &pi);
388 }
389
390 int MM_Map(tVAddr VAddr, tPAddr PAddr)
391 {
392         tMM_PageInfo    pi = {0};
393 //      Log("MM_Map %P=>%p", PAddr, VAddr);
394         
395         pi.PhysAddr = PAddr;
396         pi.Size = 12;
397         if(VAddr < USER_STACK_TOP)
398                 pi.AP = AP_RW_BOTH;
399         else
400                 pi.AP = AP_KRW_ONLY;    // Kernel Read/Write
401         pi.bExecutable = 1;
402         if( MM_int_SetPageInfo(VAddr, &pi) ) {
403                 MM_DerefPhys(pi.PhysAddr);
404                 return 0;
405         }
406         return pi.PhysAddr;
407 }
408
409 tPAddr MM_Allocate(tVAddr VAddr)
410 {
411         tMM_PageInfo    pi = {0};
412         
413         ENTER("pVAddr", VAddr);
414
415         pi.PhysAddr = MM_AllocPhys();
416         if( pi.PhysAddr == 0 )  LEAVE_RET('i', 0);
417         pi.Size = 12;
418         if(VAddr < USER_STACK_TOP)
419                 pi.AP = AP_RW_BOTH;
420         else
421                 pi.AP = AP_KRW_ONLY;
422         pi.bExecutable = 1;
423         if( MM_int_SetPageInfo(VAddr, &pi) ) {
424                 MM_DerefPhys(pi.PhysAddr);
425                 LEAVE('i', 0);
426                 return 0;
427         }
428         LEAVE('x', pi.PhysAddr);
429         return pi.PhysAddr;
430 }
431
432 tPAddr MM_AllocateZero(tVAddr VAddr)
433 {
434         if( !giMM_ZeroPage ) {
435                 giMM_ZeroPage = MM_Allocate(VAddr);
436                 MM_RefPhys(giMM_ZeroPage);
437                 memset((void*)VAddr, 0, PAGE_SIZE);
438         }
439         else {
440                 MM_RefPhys(giMM_ZeroPage);
441                 MM_Map(VAddr, giMM_ZeroPage);
442         }
443         MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
444         return giMM_ZeroPage;
445 }
446
447 void MM_Deallocate(tVAddr VAddr)
448 {
449         tMM_PageInfo    pi;
450         
451         if( MM_int_GetPageInfo(VAddr, &pi) )    return ;
452
453         if( pi.PhysAddr == 0 )  return;
454         MM_DerefPhys(pi.PhysAddr);
455         
456         pi.PhysAddr = 0;
457         pi.AP = 0;
458         pi.bExecutable = 0;
459         MM_int_SetPageInfo(VAddr, &pi);
460 }
461
462 tPAddr MM_AllocateRootTable(void)
463 {
464         tPAddr  ret;
465         
466         ret = MM_AllocPhysRange(2, -1);
467         if( ret & 0x1000 ) {
468                 MM_DerefPhys(ret);
469                 MM_DerefPhys(ret+0x1000);
470                 ret = MM_AllocPhysRange(3, -1);
471                 if( ret & 0x1000 ) {
472                         MM_DerefPhys(ret);
473                         ret += 0x1000;
474 //                      Log("MM_AllocateRootTable: Second try not aligned, %P", ret);
475                 }
476                 else {
477                         MM_DerefPhys(ret + 0x2000);
478 //                      Log("MM_AllocateRootTable: Second try aligned, %P", ret);
479                 }
480         }
481 //      else
482 //              Log("MM_AllocateRootTable: Got it in one, %P", ret);
483         return ret;
484 }
485
486 void MM_int_CloneTable(Uint32 *DestEnt, int Table)
487 {
488         tPAddr  table;
489         Uint32  *tmp_map;
490         Uint32  *cur = (void*)MM_TABLE0USER;
491 //      Uint32  *cur = &FRACTAL(MM_TABLE1USER,0);
492          int    i;
493         
494         table = MM_AllocPhys();
495         if(!table)      return ;
496         
497         tmp_map = (void*)MM_MapTemp(table);
498         
499         for( i = 0; i < 1024; i ++ )
500         {
501                 switch(cur[i] & 3)
502                 {
503                 case 0: tmp_map[i] = 0; break;
504                 case 1:
505                         tmp_map[i] = 0;
506                         Log_Error("MMVirt", "TODO: Support large pages in MM_int_CloneTable");
507                         // Large page?
508                         break;
509                 case 2:
510                 case 3:
511                         // Small page
512                         // - If full RW
513                         if( (cur[Table*256] & 0x230) == 0x030 )
514                                 cur[Table*256+i] |= 0x200;      // Set to full RO (Full RO=COW, User RO = RO)
515                         tmp_map[i] = cur[Table*256+i];
516                         break;
517                 }
518         }
519
520         DestEnt[0] = table + 0*0x400 + 1;
521         DestEnt[1] = table + 1*0x400 + 1;
522         DestEnt[2] = table + 2*0x400 + 1;
523         DestEnt[3] = table + 3*0x400 + 1;
524 }
525
526 tPAddr MM_Clone(void)
527 {
528         tPAddr  ret;
529         Uint32  *new_lvl1_1, *new_lvl1_2, *cur;
530         Uint32  *tmp_map;
531          int    i;
532         
533         ret = MM_AllocateRootTable();
534
535         cur = (void*)MM_TABLE0USER;
536         new_lvl1_1 = (void*)MM_MapTemp(ret);
537         new_lvl1_2 = (void*)MM_MapTemp(ret+0x1000);
538         tmp_map = new_lvl1_1;
539         for( i = 0; i < 0x800-4; i ++ )
540         {
541 //              Log("i = %i", i);
542                 if( i == 0x400 )
543                         tmp_map = &new_lvl1_2[-0x400];
544                 switch( cur[i] & 3 )
545                 {
546                 case 0: tmp_map[i] = 0; break;
547                 case 1:
548                         MM_int_CloneTable(&tmp_map[i], i);
549                         i += 3; // Tables are alocated in blocks of 4
550                         break;
551                 case 2:
552                 case 3:
553                         Log_Error("MMVirt", "TODO: Support Sections/Supersections in MM_Clone (i=%i)", i);
554                         tmp_map[i] = 0;
555                         break;
556                 }
557         }
558
559         // Allocate Fractal table
560         {
561                  int    j, num;
562                 tPAddr  tmp = MM_AllocPhys();
563                 Uint32  *table = (void*)MM_MapTemp(tmp);
564                 Uint32  sp;
565                 register Uint32 __SP asm("sp");
566
567                 // Map table to last 4MiB of user space
568                 new_lvl1_2[0x3FC] = tmp + 0*0x400 + 1;
569                 new_lvl1_2[0x3FD] = tmp + 1*0x400 + 1;
570                 new_lvl1_2[0x3FE] = tmp + 2*0x400 + 1;
571                 new_lvl1_2[0x3FF] = tmp + 3*0x400 + 1;
572                 
573                 tmp_map = new_lvl1_1;
574                 for( j = 0; j < 512; j ++ )
575                 {
576                         if( j == 256 )
577                                 tmp_map = &new_lvl1_2[-0x400];
578                         if( (tmp_map[j*4] & 3) == 1 )
579                         {
580                                 table[j] = tmp_map[j*4] & PADDR_MASK_LVL1;// 0xFFFFFC00;
581                                 table[j] |= 0x813;      // nG, Kernel Only, Small page, XN
582                         }
583                         else
584                                 table[j] = 0;
585                 }
586                 // Fractal
587                 table[j++] = (ret + 0x0000) | 0x813;
588                 table[j++] = (ret + 0x1000) | 0x813;
589                 // Nuke the rest
590                 for(      ; j < 1024; j ++ )
591                         table[j] = 0;
592                 
593                 // Get kernel stack bottom
594                 sp = __SP & ~(MM_KSTACK_SIZE-1);
595                 j = (sp / 0x1000) % 1024;
596                 num = MM_KSTACK_SIZE/0x1000;
597                 
598                 // Copy stack pages
599                 for(; num--; j ++, sp += 0x1000)
600                 {
601                         tVAddr  page;
602                         void    *tmp_page;
603                         
604                         page = MM_AllocPhys();
605                         table[j] = page | 0x813;
606
607                         tmp_page = (void*)MM_MapTemp(page);
608                         memcpy(tmp_page, (void*)sp, 0x1000);
609                         MM_FreeTemp( (tVAddr) tmp_page );
610                 }
611         
612                 MM_FreeTemp( (tVAddr)table );
613         }
614
615         MM_FreeTemp( (tVAddr)new_lvl1_1 );
616         MM_FreeTemp( (tVAddr)new_lvl1_2 );
617
618         return ret;
619 }
620
621 tPAddr MM_ClearUser(void)
622 {
623         // TODO: Implement ClearUser
624         return 0;
625 }
626
627 tVAddr MM_MapTemp(tPAddr PAddr)
628 {
629         tVAddr  ret;
630         tMM_PageInfo    pi;
631
632         for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
633         {
634                 if( MM_int_GetPageInfo(ret, &pi) == 0 )
635                         continue;
636
637 //              Log("MapTemp %P at %p", PAddr, ret);    
638                 MM_RefPhys(PAddr);      // Counter the MM_Deallocate in FreeTemp
639                 MM_Map(ret, PAddr);
640                 
641                 return ret;
642         }
643         Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
644         return 0;
645 }
646
647 void MM_FreeTemp(tVAddr VAddr)
648 {
649         // TODO: Implement FreeTemp
650         if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
651                 Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
652                 return ;
653         }
654         
655         MM_Deallocate(VAddr);
656 }
657
658 tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
659 {
660         tVAddr  ret;
661          int    i;
662         tMM_PageInfo    pi;
663
664         ENTER("xPAddr iNPages", PAddr, NPages);
665
666         // Scan for a location
667         for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
668         {
669 //              LOG("checking %p", ret);
670                 // Check if there is `NPages` free pages
671                 for( i = 0; i < NPages; i ++ )
672                 {
673                         if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
674                                 break;
675                 }
676                 // Nope, jump to after the used page found and try again
677 //              LOG("i = %i, ==? %i", i, NPages);
678                 if( i != NPages ) {
679                         ret += i * PAGE_SIZE;
680                         continue ;
681                 }
682         
683                 // Map the pages        
684                 for( i = 0; i < NPages; i ++ )
685                         MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAddr);
686                 // and return
687                 LEAVE('p', ret);
688                 return ret;
689         }
690         Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
691         LEAVE('p', 0);
692         return 0;
693 }
694
695 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
696 {
697         Log_Error("MMVirt", "TODO: Implement MM_AllocDMA");
698         return 0;
699 }
700
701 void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
702 {
703         Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
704 }
705
706 tVAddr MM_NewKStack(int bShared)
707 {
708         tVAddr  min_addr, max_addr;
709         tVAddr  addr, ofs;
710
711         if( bShared ) {
712                 min_addr = MM_GLOBALSTACKS;
713                 max_addr = MM_GLOBALSTACKS_END;
714         }
715         else {
716                 min_addr = MM_KSTACK_BASE;
717                 max_addr = MM_KSTACK_END;
718         }
719
720         // Locate a free slot
721         for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
722         {
723                 tMM_PageInfo    pi;
724                 if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) )    break;
725         }
726
727         // Check for an error   
728         if(addr >= max_addr) {
729                 return 0;
730         }
731
732         // 1 guard page
733         for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
734         {
735                 if( MM_Allocate(addr + ofs) == 0 )
736                 {
737                         while(ofs)
738                         {
739                                 ofs -= PAGE_SIZE;
740                                 MM_Deallocate(addr + ofs);
741                         }
742                         Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
743                         return 0;
744                 }
745         }
746         return addr + ofs;
747 }
748
749 tVAddr MM_NewUserStack(void)
750 {
751         tVAddr  addr, ofs;
752
753         addr = USER_STACK_TOP - USER_STACK_SIZE;
754         if( MM_GetPhysAddr(addr + PAGE_SIZE) ) {
755                 Log_Error("MMVirt", "Unable to create initial user stack, addr %p taken",
756                         addr + PAGE_SIZE
757                         );
758                 return 0;
759         }
760
761         // 1 guard page
762         for( ofs = PAGE_SIZE; ofs < USER_STACK_SIZE; ofs += PAGE_SIZE )
763         {
764                 tPAddr  rv;
765                 if(ofs >= USER_STACK_SIZE - USER_STACK_COMM)
766                         rv = MM_Allocate(addr + ofs);
767                 else
768                         rv = MM_AllocateZero(addr + ofs);
769                 if(rv == 0)
770                 {
771                         while(ofs)
772                         {
773                                 ofs -= PAGE_SIZE;
774                                 MM_Deallocate(addr + ofs);
775                         }
776                         Log_Warning("MMVirt", "MM_NewUserStack: Unable to allocate");
777                         return 0;
778                 }
779                 MM_SetFlags(addr+ofs, 0, MM_PFLAG_KERNEL);
780         }
781         Log("Return %p", addr + ofs);
782         MM_DumpTables(0, 0x80000000);
783         return addr + ofs;
784 }
785
786 void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
787 {
788         if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
789         {
790                 Log("%p => %8s - 0x%7x %i %x",
791                         Start, "ZERO", Len,
792                         Info->Domain, Info->AP
793                         );
794         }
795         else
796         {
797                 Log("%p => %8x - 0x%7x %i %x",
798                         Start, Info->PhysAddr-Len, Len,
799                         Info->Domain, Info->AP
800                         );
801         }
802 }
803
804 void MM_DumpTables(tVAddr Start, tVAddr End)
805 {
806         tVAddr  range_start = 0, addr;
807         tMM_PageInfo    pi, pi_old;
808          int    i = 0, inRange=0;
809         
810         pi_old.Size = 0;
811
812         Log("Page Table Dump:");
813         range_start = Start;
814         for( addr = Start; i == 0 || (addr && addr < End); i = 1 )
815         {
816 //              Log("addr = %p", addr);
817                 int rv = MM_int_GetPageInfo(addr, &pi);
818                 if( rv
819                  || pi.Size != pi_old.Size
820                  || pi.Domain != pi_old.Domain
821                  || pi.AP != pi_old.AP
822                  || pi_old.PhysAddr != pi.PhysAddr )
823                 {
824                         if(inRange) {
825                                 MM_int_DumpTableEnt(range_start, addr - range_start, &pi_old);
826                         }
827                         addr &= ~((1 << pi.Size)-1);
828                         range_start = addr;
829                 }
830                 
831                 pi_old = pi;
832                 // Handle the zero page
833                 if( !giMM_ZeroPage || pi_old.Size != 12 || pi_old.PhysAddr != giMM_ZeroPage )
834                         pi_old.PhysAddr += 1 << pi_old.Size;
835                 addr += 1 << pi_old.Size;
836                 inRange = (rv == 0);
837         }
838         if(inRange)
839                 MM_int_DumpTableEnt(range_start, addr - range_start, &pi);
840         Log("Done");
841 }
842

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