Kernel/x86_64 - Bugfixing
[tpg/acess2.git] / Kernel / arch / x86_64 / mm_virt.c
1 /*
2  * Acess2 x86_64 Port
3  * 
4  * Virtual Memory Manager
5  */
6 #define DEBUG   0
7 #include <acess.h>
8 #include <mm_virt.h>
9 #include <proc.h>
10
11 // === CONSTANTS ===
12 #define PHYS_BITS       52      // TODO: Move out
13
14 #define PML4_SHIFT      39
15 #define PDP_SHIFT       30
16 #define PDIR_SHIFT      21
17 #define PTAB_SHIFT      12
18
19 #define PADDR_MASK      0x7FFFFFFF##FFFFF000
20 #define PAGE_MASK       (((Uint)1 << 36)-1)
21 #define TABLE_MASK      (((Uint)1 << 27)-1)
22 #define PDP_MASK        (((Uint)1 << 18)-1)
23 #define PML4_MASK       (((Uint)1 << 9)-1)
24
25 #define PF_PRESENT      0x001
26 #define PF_WRITE        0x002
27 #define PF_USER         0x004
28 #define PF_LARGE        0x000
29 #define PF_COW          0x200
30 #define PF_PAGED        0x400
31 #define PF_NX           0x80000000##00000000
32
33 // === MACROS ===
34 #define PAGETABLE(idx)  (*((tPAddr*)MM_FRACTAL_BASE+((idx)&PAGE_MASK)))
35 #define PAGEDIR(idx)    PAGETABLE((MM_FRACTAL_BASE>>12)+((idx)&TABLE_MASK))
36 #define PAGEDIRPTR(idx) PAGEDIR((MM_FRACTAL_BASE>>21)+((idx)&PDP_MASK))
37 #define PAGEMAPLVL4(idx)        PAGEDIRPTR((MM_FRACTAL_BASE>>30)+((idx)&PML4_MASK))
38
39 #define TMPCR3()        PAGEMAPLVL4(MM_TMPFRAC_BASE>>39)
40 #define TMPTABLE(idx)   (*((tPAddr*)MM_TMPFRAC_BASE+((idx)&PAGE_MASK)))
41 #define TMPDIR(idx)     PAGETABLE((MM_TMPFRAC_BASE>>12)+((idx)&TABLE_MASK))
42 #define TMPDIRPTR(idx)  PAGEDIR((MM_TMPFRAC_BASE>>21)+((idx)&PDP_MASK))
43 #define TMPMAPLVL4(idx) PAGEDIRPTR((MM_TMPFRAC_BASE>>30)+((idx)&PML4_MASK))
44
45 #define INVLPG(__addr)  __asm__ __volatile__ ("invlpg (%0)"::"r"(__addr));
46
47 // === CONSTS ===
48 //tPAddr        * const gaPageTable = MM_FRACTAL_BASE;
49
50 // === IMPORTS ===
51 extern void     Error_Backtrace(Uint IP, Uint BP);
52 extern tPAddr   gInitialPML4[512];
53
54 // === PROTOTYPES ===
55 void    MM_InitVirt(void);
56 //void  MM_FinishVirtualInit(void);
57 void    MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
58 void    MM_DumpTables(tVAddr Start, tVAddr End);
59  int    MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer);
60  int    MM_MapEx(tVAddr VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge);
61 // int  MM_Map(tVAddr VAddr, tPAddr PAddr);
62 void    MM_Unmap(tVAddr VAddr);
63 void    MM_ClearUser(void);
64  int    MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags);
65
66 // === GLOBALS ===
67 tMutex  glMM_TempFractalLock;
68
69 // === CODE ===
70 void MM_InitVirt(void)
71 {
72         MM_DumpTables(0, -1L);
73 }
74
75 void MM_FinishVirtualInit(void)
76 {
77 }
78
79 /**
80  * \brief Called on a page fault
81  */
82 void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
83 {
84         // TODO: Implement Copy-on-Write
85         #if 0
86         if( gaPageDir  [Addr>>22] & PF_PRESENT
87          && gaPageTable[Addr>>12] & PF_PRESENT
88          && gaPageTable[Addr>>12] & PF_COW )
89         {
90                 tPAddr  paddr;
91                 if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
92                 {
93                         gaPageTable[Addr>>12] &= ~PF_COW;
94                         gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
95                 }
96                 else
97                 {
98                         //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr);
99                         paddr = MM_DuplicatePage( Addr );
100                         MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
101                         gaPageTable[Addr>>12] &= PF_USER;
102                         gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
103                 }
104                 
105                 INVLPG( Addr & ~0xFFF );
106                 return;
107         }
108         #endif
109         
110         // If it was a user, tell the thread handler
111         if(ErrorCode & 4) {
112                 Warning("%s %s %s memory%s",
113                         (ErrorCode&4?"User":"Kernel"),
114                         (ErrorCode&2?"write to":"read from"),
115                         (ErrorCode&1?"bad/locked":"non-present"),
116                         (ErrorCode&16?" (Instruction Fetch)":"")
117                         );
118                 Warning("User Pagefault: Instruction at %04x:%08x accessed %p",
119                         Regs->CS, Regs->RIP, Addr);
120                 __asm__ __volatile__ ("sti");   // Restart IRQs
121 //              Threads_SegFault(Addr);
122                 return ;
123         }
124         
125         // Kernel #PF
126         Debug_KernelPanic();
127         // -- Check Error Code --
128         if(ErrorCode & 8)
129                 Warning("Reserved Bits Trashed!");
130         else
131         {
132                 Warning("%s %s %s memory%s",
133                         (ErrorCode&4?"User":"Kernel"),
134                         (ErrorCode&2?"write to":"read from"),
135                         (ErrorCode&1?"bad/locked":"non-present"),
136                         (ErrorCode&16?" (Instruction Fetch)":"")
137                         );
138         }
139         
140         Log("Code at %p accessed %p", Regs->RIP, Addr);
141         // Print Stack Backtrace
142         Error_Backtrace(Regs->RIP, Regs->RBP);
143         
144         MM_DumpTables(0, -1);
145         
146         __asm__ __volatile__ ("cli");
147         for( ;; )
148                 HALT();
149 }
150
151 /**
152  * \brief Dumps the layout of the page tables
153  */
154 void MM_DumpTables(tVAddr Start, tVAddr End)
155 {
156         #define CANOICAL(addr)  ((addr)&0x800000000000?(addr)|0xFFFF000000000000:(addr))
157         const tPAddr    CHANGEABLE_BITS = 0xFF8;
158         const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
159         tVAddr  rangeStart = 0;
160         tPAddr  expected = CHANGEABLE_BITS;     // CHANGEABLE_BITS is used because it's not a vaild value
161         tVAddr  curPos;
162         Uint    page;
163         
164         Log("Table Entries: (%p to %p)", Start, End);
165         
166         End &= (1L << 48) - 1;
167         
168         Start >>= 12;   End >>= 12;
169         
170         for(page = Start, curPos = Start<<12;
171                 page < End;
172                 curPos += 0x1000, page++)
173         {
174                 if( curPos == 0x800000000000L )
175                         curPos = 0xFFFF800000000000L;
176                 
177                 //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27));
178                 //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18));
179                 //Debug("&PAGEDIR(%i page>>9) = %p", page>>9, &PAGEDIR(page>>9));
180                 //Debug("&PAGETABLE(%i page) = %p", page, &PAGETABLE(page));
181                 
182                 // End of a range
183                 if(
184                         !(PAGEMAPLVL4(page>>27) & PF_PRESENT)
185                 ||      !(PAGEDIRPTR(page>>18) & PF_PRESENT)
186                 ||      !(PAGEDIR(page>>9) & PF_PRESENT)
187                 ||  !(PAGETABLE(page) & PF_PRESENT)
188                 ||  (PAGETABLE(page) & MASK) != expected)
189                 {                       
190                         if(expected != CHANGEABLE_BITS) {
191                                 Log("%016llx => %013llx : 0x%6llx (%c%c%c%c)",
192                                         CANOICAL(rangeStart),
193                                         PAGETABLE(rangeStart>>12) & ~0xFFF,
194                                         curPos - rangeStart,
195                                         (expected & PF_PAGED ? 'p' : '-'),
196                                         (expected & PF_COW ? 'C' : '-'),
197                                         (expected & PF_USER ? 'U' : '-'),
198                                         (expected & PF_WRITE ? 'W' : '-')
199                                         );
200                                 expected = CHANGEABLE_BITS;
201                         }
202                         if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) ) {
203                                 page += (1 << 27) - 1;
204                                 curPos += (1L << 39) - 0x1000;
205                                 //Debug("pml4 ent unset (page = 0x%x now)", page);
206                                 continue;
207                         }
208                         if( !(PAGEDIRPTR(page>>18) & PF_PRESENT) ) {
209                                 page += (1 << 18) - 1;
210                                 curPos += (1L << 30) - 0x1000;
211                                 //Debug("pdp ent unset (page = 0x%x now)", page);
212                                 continue;
213                         }
214                         if( !(PAGEDIR(page>>9) & PF_PRESENT) ) {
215                                 page += (1 << 9) - 1;
216                                 curPos += (1L << 21) - 0x1000;
217                                 //Debug("pd ent unset (page = 0x%x now)", page);
218                                 continue;
219                         }
220                         if( !(PAGETABLE(page) & PF_PRESENT) )   continue;
221                         
222                         expected = (PAGETABLE(page) & MASK);
223                         rangeStart = curPos;
224                 }
225                 if(expected != CHANGEABLE_BITS)
226                         expected += 0x1000;
227         }
228         
229         if(expected != CHANGEABLE_BITS) {
230                 Log("%016llx => %013llx : 0x%6llx (%c%c%c%c)",
231                         CANOICAL(rangeStart),
232                         PAGETABLE(rangeStart>>12) & ~0xFFF,
233                         curPos - rangeStart,
234                         (expected & PF_PAGED ? 'p' : '-'),
235                         (expected & PF_COW ? 'C' : '-'),
236                         (expected & PF_USER ? 'U' : '-'),
237                         (expected & PF_WRITE ? 'W' : '-')
238                         );
239                 expected = 0;
240         }
241         #undef CANOICAL
242 }
243
244 /**
245  * \brief Get a pointer to a page entry
246  * \param Addr  Virtual Address
247  * \param bTemp Use the Temporary fractal mapping
248  * \param bAllocate     Allocate entries
249  * \param bLargePage    Request a large page
250  * \param Pointer       Location to place the calculated pointer
251  * \return Page size, or -ve on error
252  */
253 int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer)
254 {
255         tPAddr  *pmlevels[4];
256         tPAddr  tmp;
257         const int       ADDR_SIZES[] = {39, 30, 21, 12};
258         const int       nADDR_SIZES = sizeof(ADDR_SIZES)/sizeof(ADDR_SIZES[0]);
259          int    i;
260         
261         if( bTemp )
262                 pmlevels[3] = (void*)MM_TMPFRAC_BASE;   // Temporary Page Table
263         else
264                 pmlevels[3] = (void*)MM_FRACTAL_BASE;   // Page Table
265         pmlevels[2] = &pmlevels[3][(MM_FRACTAL_BASE>>12)&PAGE_MASK];    // PDIR
266         pmlevels[1] = &pmlevels[2][(MM_FRACTAL_BASE>>21)&TABLE_MASK];   // PDPT
267         pmlevels[0] = &pmlevels[1][(MM_FRACTAL_BASE>>30)&PDP_MASK];     // PML4
268         
269         // Mask address
270         Addr &= (1ULL << 48)-1;
271         
272         for( i = 0; i < nADDR_SIZES-1; i ++ )
273         {
274 //              INVLPG( &pmlevels[i][ (Addr >> ADDR_SIZES[i]) & 
275                 
276                 // Check for a large page
277                 if( (Addr & ((1ULL << ADDR_SIZES[i])-1)) == 0 && bLargePage )
278                 {
279                         if(Pointer)     *Pointer = &pmlevels[i][Addr >> ADDR_SIZES[i]];
280                         return ADDR_SIZES[i];
281                 }
282                 // Allocate an entry if required
283                 if( !(pmlevels[i][Addr >> ADDR_SIZES[i]] & 1) )
284                 {
285                         if( !bAllocate )        return -4;      // If allocation is not requested, error
286                         tmp = MM_AllocPhys();
287                         if(!tmp)        return -2;
288                         pmlevels[i][Addr >> ADDR_SIZES[i]] = tmp | 3;
289                         INVLPG( &pmlevels[i+1][ (Addr>>ADDR_SIZES[i])<<9 ] );
290                         memset( &pmlevels[i+1][ (Addr>>ADDR_SIZES[i])<<9 ], 0, 0x1000 );
291                 }
292                 // Catch large pages
293                 else if( pmlevels[i][Addr >> ADDR_SIZES[i]] & PF_LARGE )
294                 {
295                         // Alignment
296                         if( (Addr & ((1ULL << ADDR_SIZES[i])-1)) != 0 ) return -3;
297                         if(Pointer)     *Pointer = &pmlevels[i][Addr >> ADDR_SIZES[i]];
298                         return ADDR_SIZES[i];   // Large page warning
299                 }
300         }
301         
302         // And, set the page table entry
303         if(Pointer)     *Pointer = &pmlevels[i][Addr >> ADDR_SIZES[i]];
304         return ADDR_SIZES[i];
305 }
306
307 /**
308  * \brief Map a physical page to a virtual one
309  * \param VAddr Target virtual address
310  * \param PAddr Physical address of page
311  * \param bTemp Use tempoary mappings
312  * \param bLarge        Treat as a large page
313  */
314 int MM_MapEx(tVAddr VAddr, tPAddr PAddr, BOOL bTemp, BOOL bLarge)
315 {
316         tPAddr  *ent;
317          int    rv;
318         
319         ENTER("xVAddr xPAddr", VAddr, PAddr);
320         
321         // Get page pointer (Allow allocating)
322         rv = MM_GetPageEntryPtr(VAddr, bTemp, 1, bLarge, &ent);
323         if(rv < 0)      LEAVE_RET('i', 0);
324         
325         if( *ent & 1 )  LEAVE_RET('i', 0);
326         
327         *ent = PAddr | 3;
328         
329         INVLPG( VAddr );
330
331         LEAVE('i', 1);  
332         return 1;
333 }
334
335 /**
336  * \brief Map a physical page to a virtual one
337  * \param VAddr Target virtual address
338  * \param PAddr Physical address of page
339  */
340 int MM_Map(tVAddr VAddr, tPAddr PAddr)
341 {
342         return MM_MapEx(VAddr, PAddr, 0, 0);
343 }
344
345 /**
346  * \brief Removed a mapped page
347  */
348 void MM_Unmap(tVAddr VAddr)
349 {
350         // Check PML4
351         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )   return ;
352         // Check PDP
353         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )    return ;
354         // Check Page Dir
355         if( !(PAGEDIR(VAddr >> 21) & 1) )       return ;
356         
357         PAGETABLE(VAddr >> PTAB_SHIFT) = 0;
358         INVLPG( VAddr );
359 }
360
361 /**
362  * \brief Allocate a block of memory at the specified virtual address
363  */
364 tPAddr MM_Allocate(tVAddr VAddr)
365 {
366         tPAddr  ret;
367         
368         ENTER("xVAddr", VAddr);
369         
370         // Ensure the tables are allocated before the page (keeps things neat)
371         MM_GetPageEntryPtr(VAddr, 0, 1, 0, NULL);
372         
373         // Allocate the page
374         ret = MM_AllocPhys();
375         LOG("ret = %x", ret);
376         if(!ret)        LEAVE_RET('i', 0);
377         
378         if( !MM_Map(VAddr, ret) )
379         {
380                 Warning("MM_Allocate: Unable to map. Strange, we should have errored earlier");
381                 MM_DerefPhys(ret);
382                 LEAVE('i');
383                 return 0;
384         }
385         
386         LEAVE('X', ret);
387         return ret;
388 }
389
390 /**
391  * \brief Deallocate a page at a virtual address
392  */
393 void MM_Deallocate(tVAddr VAddr)
394 {
395         tPAddr  phys;
396         
397         phys = MM_GetPhysAddr(VAddr);
398         if(!phys)       return ;
399         
400         MM_Unmap(VAddr);
401         
402         MM_DerefPhys(phys);
403 }
404
405 /**
406  * \brief Get the page table entry of a virtual address
407  * \param Addr  Virtual Address
408  * \param Phys  Location to put the physical address
409  * \param Flags Flags on the entry (set to zero if unmapped)
410  * \return Size of the entry (in address bits) - 12 = 4KiB page
411  */
412 int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags)
413 {
414         tPAddr  *ptr;
415          int    ret;
416         
417         if(!Phys || !Flags)     return 0;
418         
419         ret = MM_GetPageEntryPtr(Addr, 0, 0, 0, &ptr);
420         if( ret < 0 )   return 0;
421         
422         *Phys = *ptr & ~0xFFF;
423         *Flags = *ptr & 0xFFF;
424         return ret;
425 }
426
427 /**
428  * \brief Get the physical address of a virtual location
429  */
430 tPAddr MM_GetPhysAddr(tVAddr Addr)
431 {
432         tPAddr  *ptr;
433          int    ret;
434         
435         ret = MM_GetPageEntryPtr(Addr, 0, 0, 0, &ptr);
436         if( ret < 0 )   return 0;
437         
438         return (*ptr & ~0xFFF) | (Addr & 0xFFF);
439 }
440
441 /**
442  * \brief Sets the flags on a page
443  */
444 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
445 {
446         tPAddr  *ent;
447          int    rv;
448         
449         // Get pointer
450         rv = MM_GetPageEntryPtr(VAddr, 0, 0, 0, &ent);
451         if(rv < 0)      return ;
452         
453         // Ensure the entry is valid
454         if( !(*ent & 1) )       return ;
455         
456         // Read-Only
457         if( Mask & MM_PFLAG_RO )
458         {
459                 if( Flags & MM_PFLAG_RO ) {
460                         *ent &= ~PF_WRITE;
461                 }
462                 else {
463                         *ent |= PF_WRITE;
464                 }
465         }
466         
467         // Kernel
468         if( Mask & MM_PFLAG_KERNEL )
469         {
470                 if( Flags & MM_PFLAG_KERNEL ) {
471                         *ent &= ~PF_USER;
472                 }
473                 else {
474                         *ent |= PF_USER;
475                 }
476         }
477         
478         // Copy-On-Write
479         if( Mask & MM_PFLAG_COW )
480         {
481                 if( Flags & MM_PFLAG_COW ) {
482                         *ent &= ~PF_WRITE;
483                         *ent |= PF_COW;
484                 }
485                 else {
486                         *ent &= ~PF_COW;
487                         *ent |= PF_WRITE;
488                 }
489         }
490         
491         // Execute
492         if( Mask & MM_PFLAG_EXEC )
493         {
494                 if( Flags & MM_PFLAG_EXEC ) {
495                         *ent &= ~PF_NX;
496                 }
497                 else {
498                         *ent |= PF_NX;
499                 }
500         }
501 }
502
503 /**
504  * \brief Get the flags applied to a page
505  */
506 Uint MM_GetFlags(tVAddr VAddr)
507 {
508         tPAddr  *ent;
509          int    rv, ret = 0;
510         
511         rv = MM_GetPageEntryPtr(VAddr, 0, 0, 0, &ent);
512         if(rv < 0)      return 0;
513         
514         if( !(*ent & 1) )       return 0;
515         
516         // Read-Only
517         if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
518         // Kernel
519         if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
520         // Copy-On-Write
521         if( *ent & PF_COW )     ret |= MM_PFLAG_COW;    
522         // Execute
523         if( !(*ent & PF_NX) )   ret |= MM_PFLAG_EXEC;
524         
525         return ret;
526 }
527
528 // --- Hardware Mappings ---
529 /**
530  * \brief Map a range of hardware pages
531  */
532 tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
533 {
534         tVAddr  ret;
535          int    num;
536         
537         //TODO: Add speedups (memory of first possible free)
538         for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_TOP; ret += 0x1000 )
539         {
540                 for( num = Number; num -- && ret < MM_HWMAP_TOP; ret += 0x1000 )
541                 {
542                         if( MM_GetPhysAddr(ret) != 0 )  break;
543                 }
544                 if( num >= 0 )  continue;
545                 
546                 PAddr += 0x1000 * Number;
547                 
548                 while( Number -- )
549                 {
550                         ret -= 0x1000;
551                         PAddr -= 0x1000;
552                         MM_Map(ret, PAddr);
553                 }
554                 
555                 return ret;
556         }
557         
558         Log_KernelPanic("MM", "TODO: Implement MM_MapHWPages");
559         return 0;
560 }
561
562 /**
563  * \brief Free a range of hardware pages
564  */
565 void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
566 {
567 //      Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
568         while( Number -- )
569         {
570                 MM_Unmap(VAddr);
571                 VAddr += 0x1000;
572         }
573 }
574
575
576 /**
577  * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
578  * \brief Allocates DMA physical memory
579  * \param Pages Number of pages required
580  * \param MaxBits       Maximum number of bits the physical address can have
581  * \param PhysAddr      Pointer to the location to place the physical address allocated
582  * \return Virtual address allocate
583  */
584 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
585 {
586         tPAddr  phys;
587         tVAddr  ret;
588         
589         // Sanity Check
590         if(MaxBits < 12 || !PhysAddr)   return 0;
591         
592         // Fast Allocate
593         if(Pages == 1 && MaxBits >= PHYS_BITS)
594         {
595                 phys = MM_AllocPhys();
596                 *PhysAddr = phys;
597                 ret = MM_MapHWPages(phys, 1);
598                 if(ret == 0) {
599                         MM_DerefPhys(phys);
600                         return 0;
601                 }
602                 return ret;
603         }
604         
605         // Slow Allocate
606         phys = MM_AllocPhysRange(Pages, MaxBits);
607         // - Was it allocated?
608         if(phys == 0)   return 0;
609         
610         // Allocated successfully, now map
611         ret = MM_MapHWPages(phys, Pages);
612         if( ret == 0 ) {
613                 // If it didn't map, free then return 0
614                 for(;Pages--;phys+=0x1000)
615                         MM_DerefPhys(phys);
616                 return 0;
617         }
618         
619         *PhysAddr = phys;
620         return ret;
621 }
622
623 // --- Tempory Mappings ---
624 tVAddr MM_MapTemp(tPAddr PAddr)
625 {
626         Log_KernelPanic("MM", "TODO: Implement MM_MapTemp");
627         return 0;
628 }
629
630 void MM_FreeTemp(tVAddr VAddr)
631 {
632         Log_KernelPanic("MM", "TODO: Implement MM_FreeTemp");
633         return ;
634 }
635
636
637 // --- Address Space Clone --
638 tPAddr MM_Clone(void)
639 {
640         tPAddr  ret;
641         
642         // #1 Create a copy of the PML4
643         ret = MM_AllocPhys();
644         if(!ret)        return 0;
645         
646         // #2 Alter the fractal pointer
647         Mutex_Acquire(&glMM_TempFractalLock);
648         TMPCR3() = ret | 3;
649         
650         INVLPG(&TMPMAPLVL4(0));
651         memcpy(&TMPMAPLVL4(0), &PAGEMAPLVL4(0), 0x1000);
652         
653         Log_KernelPanic("MM", "TODO: Implement MM_Clone");
654         
655         // #3 Set Copy-On-Write to all user pages
656         
657         
658         // #4 Return
659         TMPCR3() = 0;
660         INVLPG(&TMPMAPLVL4(0));
661         Mutex_Release(&glMM_TempFractalLock);
662         return 0;
663 }
664
665 void MM_ClearUser(void)
666 {
667         tVAddr  addr = 0;
668         // #1 Traverse the structure < 2^47, Deref'ing all pages
669         // #2 Free tables/dirs/pdps once they have been cleared
670         
671         for( addr = 0; addr < 0x800000000000; )
672         {
673                 if( PAGEMAPLVL4(addr >> PML4_SHIFT) & 1 )
674                 {
675                         if( PAGEDIRPTR(addr >> PDP_SHIFT) & 1 )
676                         {
677                                 if( PAGEDIR(addr >> PDIR_SHIFT) & 1 )
678                                 {
679                                         // Page
680                                         if( PAGETABLE(addr >> PTAB_SHIFT) & 1 ) {
681                                                 MM_DerefPhys( PAGETABLE(addr >> PTAB_SHIFT) & PADDR_MASK );
682                                                 PAGETABLE(addr >> PTAB_SHIFT) = 0;
683                                         }
684                                         addr += 1 << PTAB_SHIFT;
685                                         // Dereference the PDIR Entry
686                                         if( (addr + (1 << PTAB_SHIFT)) >> PDIR_SHIFT != (addr >> PDIR_SHIFT) ) {
687                                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PDIR_SHIFT) & PADDR_MASK );
688                                                 PAGEDIR(addr >> PDIR_SHIFT) = 0;
689                                         }
690                                 }
691                                 else {
692                                         addr += 1 << PDIR_SHIFT;
693                                         continue;
694                                 }
695                                 // Dereference the PDP Entry
696                                 if( (addr + (1 << PDIR_SHIFT)) >> PDP_SHIFT != (addr >> PDP_SHIFT) ) {
697                                         MM_DerefPhys( PAGEMAPLVL4(addr >> PDP_SHIFT) & PADDR_MASK );
698                                         PAGEDIRPTR(addr >> PDP_SHIFT) = 0;
699                                 }
700                         }
701                         else {
702                                 addr += 1 << PDP_SHIFT;
703                                 continue;
704                         }
705                         // Dereference the PML4 Entry
706                         if( (addr + (1 << PDP_SHIFT)) >> PML4_SHIFT != (addr >> PML4_SHIFT) ) {
707                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PML4_SHIFT) & PADDR_MASK );
708                                 PAGEMAPLVL4(addr >> PML4_SHIFT) = 0;
709                         }
710                 }
711                 else {
712                         addr += (tVAddr)1 << PML4_SHIFT;
713                         continue;
714                 }
715         }
716 }
717
718 tVAddr MM_NewWorkerStack(void)
719 {
720         tVAddr  ret;
721          int    i;
722         
723 //      Log_KernelPanic("MM", "TODO: Implement MM_NewWorkerStack");
724         
725         // #1 Set temp fractal to PID0
726         Mutex_Acquire(&glMM_TempFractalLock);
727         TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3;
728         
729         // #2 Scan for a free stack addresss < 2^47
730         for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE)
731         {
732                 if( MM_GetPhysAddr(ret) == 0 )  break;
733         }
734         if( ret >= (1ULL << 47) ) {
735                 Mutex_Release(&glMM_TempFractalLock);
736                 return 0;
737         }
738         
739         // #3 Map all save the last page in the range
740         //    - This acts as as guard page, and doesn't cost us anything.
741         for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ )
742         {
743                 tPAddr  phys = MM_AllocPhys();
744                 if(!phys) {
745                         // TODO: Clean up
746                         Log_Error("MM", "MM_NewWorkerStack - Unable to allocate page");
747                         return 0;
748                 }
749                 MM_MapEx(ret + i*0x1000, phys, 1, 0);
750         }
751         
752         Mutex_Release(&glMM_TempFractalLock);
753         
754         return ret + i*0x1000;
755 }
756
757 /**
758  * \brief Allocate a new kernel stack
759  */
760 tVAddr MM_NewKStack(void)
761 {
762         tVAddr  base = MM_KSTACK_BASE;
763         Uint    i;
764         for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
765         {
766                 if(MM_GetPhysAddr(base) != 0)
767                         continue;
768                 
769                 //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
770                 for( i = 0; i < KERNEL_STACK_SIZE; i += 0x1000)
771                 {
772                         if( !MM_Allocate(base+i) )
773                         {
774                                 Log_Warning("MM", "MM_NewKStack - Allocation failed");
775                                 for( i -= 0x1000; i; i -= 0x1000)
776                                         MM_Deallocate(base+i);
777                                 return 0;
778                         }
779                 }
780                 
781                 return base + KERNEL_STACK_SIZE;
782         }
783         Log_Warning("MM", "MM_NewKStack - No address space left\n");
784         return 0;
785 }

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