Kernel - x86_64 mm_virt rework
[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()        PAGETABLE(MM_TMPFRAC_BASE>>12)
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_Map(tVAddr VAddr, tPAddr PAddr);
60 void    MM_Unmap(tVAddr VAddr);
61 void    MM_ClearUser(void);
62  int    MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags);
63
64 // === GLOBALS ===
65 tMutex  glMM_TempFractalLock;
66
67 // === CODE ===
68 void MM_InitVirt(void)
69 {
70         MM_DumpTables(0, -1L);
71 }
72
73 void MM_FinishVirtualInit(void)
74 {
75 }
76
77 /**
78  * \brief Called on a page fault
79  */
80 void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
81 {
82         // TODO: Implement Copy-on-Write
83         #if 0
84         if( gaPageDir  [Addr>>22] & PF_PRESENT
85          && gaPageTable[Addr>>12] & PF_PRESENT
86          && gaPageTable[Addr>>12] & PF_COW )
87         {
88                 tPAddr  paddr;
89                 if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
90                 {
91                         gaPageTable[Addr>>12] &= ~PF_COW;
92                         gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
93                 }
94                 else
95                 {
96                         //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr);
97                         paddr = MM_DuplicatePage( Addr );
98                         MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
99                         gaPageTable[Addr>>12] &= PF_USER;
100                         gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
101                 }
102                 
103                 INVLPG( Addr & ~0xFFF );
104                 return;
105         }
106         #endif
107         
108         // If it was a user, tell the thread handler
109         if(ErrorCode & 4) {
110                 Warning("%s %s %s memory%s",
111                         (ErrorCode&4?"User":"Kernel"),
112                         (ErrorCode&2?"write to":"read from"),
113                         (ErrorCode&1?"bad/locked":"non-present"),
114                         (ErrorCode&16?" (Instruction Fetch)":"")
115                         );
116                 Warning("User Pagefault: Instruction at %04x:%08x accessed %p",
117                         Regs->CS, Regs->RIP, Addr);
118                 __asm__ __volatile__ ("sti");   // Restart IRQs
119 //              Threads_SegFault(Addr);
120                 return ;
121         }
122         
123         // Kernel #PF
124         Debug_KernelPanic();
125         // -- Check Error Code --
126         if(ErrorCode & 8)
127                 Warning("Reserved Bits Trashed!");
128         else
129         {
130                 Warning("%s %s %s memory%s",
131                         (ErrorCode&4?"User":"Kernel"),
132                         (ErrorCode&2?"write to":"read from"),
133                         (ErrorCode&1?"bad/locked":"non-present"),
134                         (ErrorCode&16?" (Instruction Fetch)":"")
135                         );
136         }
137         
138         Log("Code at %p accessed %p", Regs->RIP, Addr);
139         // Print Stack Backtrace
140 //      Error_Backtrace(Regs->RIP, Regs->RBP);
141         
142         MM_DumpTables(0, -1);
143         
144         __asm__ __volatile__ ("cli");
145         for( ;; )
146                 HALT();
147 }
148
149 /**
150  * \brief Dumps the layout of the page tables
151  */
152 void MM_DumpTables(tVAddr Start, tVAddr End)
153 {
154         const tPAddr    CHANGEABLE_BITS = 0xFF8;
155         const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
156         tVAddr  rangeStart = 0;
157         tPAddr  expected = CHANGEABLE_BITS;     // MASK is used because it's not a vaild value
158         tVAddr  curPos;
159         Uint    page;
160         
161         Log("Table Entries: (%p to %p)", Start, End);
162         
163         End &= (1L << 48) - 1;
164         
165         Start >>= 12;   End >>= 12;
166         
167         for(page = Start, curPos = Start<<12;
168                 page < End;
169                 curPos += 0x1000, page++)
170         {
171                 if( curPos == 0x800000000000L )
172                         curPos = 0xFFFF800000000000L;
173                 
174                 //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27));
175                 //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18));
176                 //Debug("&PAGEDIR(%i page>>9) = %p", page>>9, &PAGEDIR(page>>9));
177                 //Debug("&PAGETABLE(%i page) = %p", page, &PAGETABLE(page));
178                 
179                 // End of a range
180                 if(
181                         !(PAGEMAPLVL4(page>>27) & PF_PRESENT)
182                 ||      !(PAGEDIRPTR(page>>18) & PF_PRESENT)
183                 ||      !(PAGEDIR(page>>9) & PF_PRESENT)
184                 ||  !(PAGETABLE(page) & PF_PRESENT)
185                 ||  (PAGETABLE(page) & MASK) != expected)
186                 {                       
187                         if(expected != CHANGEABLE_BITS) {
188                                 Log("%016x-0x%016x => %013x-%013x (%c%c%c%c)",
189                                         rangeStart, curPos - 1,
190                                         PAGETABLE(rangeStart>>12) & ~0xFFF,
191                                         (expected & ~0xFFF) - 1,
192                                         (expected & PF_PAGED ? 'p' : '-'),
193                                         (expected & PF_COW ? 'C' : '-'),
194                                         (expected & PF_USER ? 'U' : '-'),
195                                         (expected & PF_WRITE ? 'W' : '-')
196                                         );
197                                 expected = CHANGEABLE_BITS;
198                         }
199                         if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) ) {
200                                 page += (1 << 27) - 1;
201                                 curPos += (1L << 39) - 0x1000;
202                                 //Debug("pml4 ent unset (page = 0x%x now)", page);
203                                 continue;
204                         }
205                         if( !(PAGEDIRPTR(page>>18) & PF_PRESENT) ) {
206                                 page += (1 << 18) - 1;
207                                 curPos += (1L << 30) - 0x1000;
208                                 //Debug("pdp ent unset (page = 0x%x now)", page);
209                                 continue;
210                         }
211                         if( !(PAGEDIR(page>>9) & PF_PRESENT) ) {
212                                 page += (1 << 9) - 1;
213                                 curPos += (1L << 21) - 0x1000;
214                                 //Debug("pd ent unset (page = 0x%x now)", page);
215                                 continue;
216                         }
217                         if( !(PAGETABLE(page) & PF_PRESENT) )   continue;
218                         
219                         expected = (PAGETABLE(page) & MASK);
220                         rangeStart = curPos;
221                 }
222                 if(expected != CHANGEABLE_BITS)
223                         expected += 0x1000;
224         }
225         
226         if(expected != CHANGEABLE_BITS) {
227                 Log("%016x-%016x => %013x-%013x (%s%s%s%s)",
228                         rangeStart, curPos - 1,
229                         PAGETABLE(rangeStart>>12) & ~0xFFF,
230                         (expected & ~0xFFF) - 1,
231                         (expected & PF_PAGED ? "p" : "-"),
232                         (expected & PF_COW ? "C" : "-"),
233                         (expected & PF_USER ? "U" : "-"),
234                         (expected & PF_WRITE ? "W" : "-")
235                         );
236                 expected = 0;
237         }
238 }
239
240 /**
241  * \brief Get a pointer to a page entry
242  * \param Addr  Virtual Address
243  * \param bTemp Use the Temporary fractal mapping
244  * \param bAllocate     Allocate entries
245  * \param bLargePage    Request a large page
246  * \param Pointer       Location to place the calculated pointer
247  * \return Page size, or -ve on error
248  */
249 int MM_GetPageEntryPtr(tVAddr Addr, BOOL bTemp, BOOL bAllocate, BOOL bLargePage, tPAddr **Pointer)
250 {
251         tPAddr  *pmlevels[4];
252         tPAddr  tmp;
253         const int       ADDR_SIZES[] = {39, 30, 21, 12};
254         const int       nADDR_SIZES = sizeof(ADDR_SIZES)/sizeof(ADDR_SIZES[0]);
255          int    i;
256         
257         if( bTemp )
258                 pmlevels[3] = (void*)MM_TMPFRAC_BASE;   // Temporary Page Table
259         else
260                 pmlevels[3] = (void*)MM_FRACTAL_BASE;   // Page Table
261         pmlevels[2] = &pmlevels[3][(MM_FRACTAL_BASE>>12)&PAGE_MASK];    // PDIR
262         pmlevels[1] = &pmlevels[2][(MM_FRACTAL_BASE>>21)&TABLE_MASK];   // PDPT
263         pmlevels[0] = &pmlevels[1][(MM_FRACTAL_BASE>>30)&PDP_MASK];     // PML4
264 //      Log("pmlevels = {%p, %p, %p, %p}",
265 //              MM_FRACTAL_BASE>>30, MM_FRACTAL_BASE>>21, MM_FRACTAL_BASE>>12, MM_FRACTAL_BASE);
266 //      Log("pmlevels = {%p, %p, %p, %p}",
267 //              pmlevels[0], pmlevels[1], pmlevels[2], pmlevels[3]);
268         
269         // Mask address
270         Addr &= (1ULL << 48)-1;
271         
272         for( i = 0; i < nADDR_SIZES-1; i ++ )
273         {
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 //              Log("&pmlevels[%i][0x%llx (>> %i)] = %p", i, Addr >> ADDR_SIZES[i], ADDR_SIZES[i],
282 //                      &pmlevels[i][Addr >> ADDR_SIZES[i]]);
283                 // Allocate an entry if required
284                 if( !(pmlevels[i][Addr >> ADDR_SIZES[i]] & 1) )
285                 {
286                         if( !bAllocate )        return -4;      // If allocation is not requested, error
287                         tmp = MM_AllocPhys();
288                         if(!tmp)        return -2;
289                         pmlevels[i][Addr >> ADDR_SIZES[i]] = tmp | 3;
290                         INVLPG( &pmlevels[i+1][ (Addr>>ADDR_SIZES[i])<<9 ] );
291                         memset( &pmlevels[i+1][ (Addr>>ADDR_SIZES[i])<<9 ], 0, 0x1000 );
292                 }
293                 else if( pmlevels[i][Addr >> ADDR_SIZES[i]] & PF_LARGE )
294                 {
295                         if( (Addr & ((1ULL << ADDR_SIZES[i])-1)) != 0 )
296                                 return -3;      // Alignment
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  */
310 int MM_Map(tVAddr VAddr, tPAddr PAddr)
311 {
312         tPAddr  *ent;
313          int    rv;
314         
315         ENTER("xVAddr xPAddr", VAddr, PAddr);
316         
317         // Get page pointer (Allow allocating)
318         rv = MM_GetPageEntryPtr(VAddr, 0, 1, 0, &ent);
319         if(rv < 0)      LEAVE_RET('i', 0);
320         
321         if( *ent & 1 )
322                 LEAVE_RET('i', 0);
323         
324         *ent = PAddr | 3;
325         
326         INVLPG( VAddr );
327
328         LEAVE('i', 1);  
329         return 1;
330 }
331
332 /**
333  * \brief Removed a mapped page
334  */
335 void MM_Unmap(tVAddr VAddr)
336 {
337         // Check PML4
338         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )   return ;
339         // Check PDP
340         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )    return ;
341         // Check Page Dir
342         if( !(PAGEDIR(VAddr >> 21) & 1) )       return ;
343         
344         PAGETABLE(VAddr >> PTAB_SHIFT) = 0;
345         INVLPG( VAddr );
346 }
347
348 /**
349  * \brief Allocate a block of memory at the specified virtual address
350  */
351 tPAddr MM_Allocate(tVAddr VAddr)
352 {
353         tPAddr  ret;
354         
355         ENTER("xVAddr", VAddr);
356         
357         // NOTE: This is hack, but I like my dumps to be neat
358         #if 1
359         MM_GetPageEntryPtr(VAddr, 0, 1, 0, NULL);
360         #elif 1
361         if( !MM_Map(VAddr, 0) ) // Make sure things are allocated
362         {
363                 Warning("MM_Allocate: Unable to map, tables did not initialise");
364                 LEAVE('i', 0);
365                 return 0;
366         }
367         MM_Unmap(VAddr);
368         #endif
369         
370         ret = MM_AllocPhys();
371         LOG("ret = %x", ret);
372         if(!ret) {
373                 LEAVE('i', 0);
374                 return 0;
375         }
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                 while( Number -- )
546                 {
547                         ret -= 0x1000;
548                         MM_Map(ret, PAddr);
549                         PAddr += 0x1000;
550                 }
551                 
552                 return ret;
553         }
554         
555         Log_KernelPanic("MM", "TODO: Implement MM_MapHWPages");
556         return 0;
557 }
558
559 /**
560  * \brief Free a range of hardware pages
561  */
562 void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
563 {
564 //      Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
565         while( Number -- )
566         {
567                 MM_Unmap(VAddr);
568                 VAddr += 0x1000;
569         }
570 }
571
572
573 /**
574  * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
575  * \brief Allocates DMA physical memory
576  * \param Pages Number of pages required
577  * \param MaxBits       Maximum number of bits the physical address can have
578  * \param PhysAddr      Pointer to the location to place the physical address allocated
579  * \return Virtual address allocate
580  */
581 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
582 {
583         tPAddr  phys;
584         tVAddr  ret;
585         
586         // Sanity Check
587         if(MaxBits < 12 || !PhysAddr)   return 0;
588         
589         // Fast Allocate
590         if(Pages == 1 && MaxBits >= PHYS_BITS)
591         {
592                 phys = MM_AllocPhys();
593                 *PhysAddr = phys;
594                 ret = MM_MapHWPages(phys, 1);
595                 if(ret == 0) {
596                         MM_DerefPhys(phys);
597                         return 0;
598                 }
599                 return ret;
600         }
601         
602         // Slow Allocate
603         phys = MM_AllocPhysRange(Pages, MaxBits);
604         // - Was it allocated?
605         if(phys == 0)   return 0;
606         
607         // Allocated successfully, now map
608         ret = MM_MapHWPages(phys, Pages);
609         if( ret == 0 ) {
610                 // If it didn't map, free then return 0
611                 for(;Pages--;phys+=0x1000)
612                         MM_DerefPhys(phys);
613                 return 0;
614         }
615         
616         *PhysAddr = phys;
617         return ret;
618 }
619
620 // --- Tempory Mappings ---
621 tVAddr MM_MapTemp(tPAddr PAddr)
622 {
623         Log_KernelPanic("MM", "TODO: Implement MM_MapTemp");
624         return 0;
625 }
626
627 void MM_FreeTemp(tVAddr VAddr)
628 {
629         Log_KernelPanic("MM", "TODO: Implement MM_FreeTemp");
630         return ;
631 }
632
633
634 // --- Address Space Clone --
635 tPAddr MM_Clone(void)
636 {
637         tPAddr  ret;
638         
639         // #1 Create a copy of the PML4
640         ret = MM_AllocPhys();
641         if(!ret)        return 0;
642         
643         // #2 Alter the fractal pointer
644         Mutex_Acquire(&glMM_TempFractalLock);
645         TMPCR3() = ret | 3;
646         
647         INVLPG(TMPMAPLVL4(0));
648         memcpy(&TMPMAPLVL4(0), &PAGEMAPLVL4(0), 0x1000);
649         
650         Log_KernelPanic("MM", "TODO: Implement MM_Clone");
651         
652         // #3 Set Copy-On-Write to all user pages
653         // #4 Return
654         TMPCR3() = 0;
655         INVLPG(TMPMAPLVL4(0));
656         Mutex_Release(&glMM_TempFractalLock);
657         return 0;
658 }
659
660 void MM_ClearUser(void)
661 {
662         tVAddr  addr = 0;
663         // #1 Traverse the structure < 2^47, Deref'ing all pages
664         // #2 Free tables/dirs/pdps once they have been cleared
665         
666         for( addr = 0; addr < 0x800000000000; )
667         {
668                 if( PAGEMAPLVL4(addr >> PML4_SHIFT) & 1 )
669                 {
670                         if( PAGEDIRPTR(addr >> PDP_SHIFT) & 1 )
671                         {
672                                 if( PAGEDIR(addr >> PDIR_SHIFT) & 1 )
673                                 {
674                                         // Page
675                                         if( PAGETABLE(addr >> PTAB_SHIFT) & 1 ) {
676                                                 MM_DerefPhys( PAGETABLE(addr >> PTAB_SHIFT) & PADDR_MASK );
677                                                 PAGETABLE(addr >> PTAB_SHIFT) = 0;
678                                         }
679                                         addr += 1 << PTAB_SHIFT;
680                                         // Dereference the PDIR Entry
681                                         if( (addr + (1 << PTAB_SHIFT)) >> PDIR_SHIFT != (addr >> PDIR_SHIFT) ) {
682                                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PDIR_SHIFT) & PADDR_MASK );
683                                                 PAGEDIR(addr >> PDIR_SHIFT) = 0;
684                                         }
685                                 }
686                                 else {
687                                         addr += 1 << PDIR_SHIFT;
688                                         continue;
689                                 }
690                                 // Dereference the PDP Entry
691                                 if( (addr + (1 << PDIR_SHIFT)) >> PDP_SHIFT != (addr >> PDP_SHIFT) ) {
692                                         MM_DerefPhys( PAGEMAPLVL4(addr >> PDP_SHIFT) & PADDR_MASK );
693                                         PAGEDIRPTR(addr >> PDP_SHIFT) = 0;
694                                 }
695                         }
696                         else {
697                                 addr += 1 << PDP_SHIFT;
698                                 continue;
699                         }
700                         // Dereference the PML4 Entry
701                         if( (addr + (1 << PDP_SHIFT)) >> PML4_SHIFT != (addr >> PML4_SHIFT) ) {
702                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PML4_SHIFT) & PADDR_MASK );
703                                 PAGEMAPLVL4(addr >> PML4_SHIFT) = 0;
704                         }
705                 }
706                 else {
707                         addr += (tVAddr)1 << PML4_SHIFT;
708                         continue;
709                 }
710         }
711 }
712
713 tVAddr MM_NewWorkerStack(void)
714 {
715         tVAddr  ret;
716          int    i;
717         
718         Log_KernelPanic("MM", "TODO: Implement MM_NewWorkerStack");
719         
720         // #1 Set temp fractal to PID0
721         Mutex_Acquire(&glMM_TempFractalLock);
722         TMPCR3() = ((tPAddr)gInitialPML4 - KERNEL_BASE) | 3;
723         
724         // #2 Scan for a free stack addresss < 2^47
725         for(ret = 0x100000; ret < (1ULL << 47); ret += KERNEL_STACK_SIZE)
726         {
727                 if( MM_GetPhysAddr(ret) == 0 )  break;
728         }
729         if( ret >= (1ULL << 47) ) {
730                 Mutex_Release(&glMM_TempFractalLock);
731                 return 0;
732         }
733         
734         // #3 Map all save the last page in the range
735         //    - This acts as as guard page, and doesn't cost us anything.
736         for( i = 0; i < KERNEL_STACK_SIZE/0x1000 - 1; i ++ )
737         {
738 //              MM_MapTemp
739         }
740         
741         Mutex_Release(&glMM_TempFractalLock);
742         
743         return 0;
744 }
745
746 /**
747  * \brief Allocate a new kernel stack
748  */
749 tVAddr MM_NewKStack(void)
750 {
751         tVAddr  base = MM_KSTACK_BASE;
752         Uint    i;
753         for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
754         {
755                 if(MM_GetPhysAddr(base) != 0)
756                         continue;
757                 
758                 //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
759                 for( i = 0; i < KERNEL_STACK_SIZE; i += 0x1000)
760                 {
761                         if( !MM_Allocate(base+i) )
762                         {
763                                 Log_Warning("MM", "MM_NewKStack - Allocation failed");
764                                 for( i -= 0x1000; i; i -= 0x1000)
765                                         MM_Deallocate(base+i);
766                                 return 0;
767                         }
768                 }
769                 
770                 return base + KERNEL_STACK_SIZE;
771         }
772         Log_Warning("MM", "MM_NewKStack - No address space left\n");
773         return 0;
774 }

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