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

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