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

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