Kernel - Cleaning up
[tpg/acess2.git] / Kernel / arch / x86 / mm_virt.c
1 /*
2  * AcessOS Microkernel Version
3  * mm_virt.c
4  * 
5  * Memory Map
6  * 0xE0 - Kernel Base
7  * 0xF0 - Kernel Stacks
8  * 0xFD - Fractals
9  * 0xFE - Unused
10  * 0xFF - System Calls / Kernel's User Code
11  */
12 #define DEBUG   0
13 #define SANITY  1
14 #include <acess.h>
15 #include <mm_virt.h>
16 #include <mm_phys.h>
17 #include <proc.h>
18
19 #if USE_PAE
20 # define TAB    21
21 # define DIR    30
22 #else
23 # define TAB    22
24 #endif
25
26 #define KERNEL_STACKS           0xF0000000
27 #define KERNEL_STACK_SIZE       0x00008000
28 #define KERNEL_STACKS_END       0xFC000000
29 #define WORKER_STACKS           0x00100000      // Thread0 Only!
30 #define WORKER_STACK_SIZE       KERNEL_STACK_SIZE
31 #define WORKER_STACKS_END       0xB0000000
32 #define NUM_WORKER_STACKS       ((WORKER_STACKS_END-WORKER_STACKS)/WORKER_STACK_SIZE)
33
34 #define PAE_PAGE_TABLE_ADDR     0xFC000000      // 16 MiB
35 #define PAE_PAGE_DIR_ADDR       0xFCFC0000      // 16 KiB
36 #define PAE_PAGE_PDPT_ADDR      0xFCFC3F00      // 32 bytes
37 #define PAE_TMP_PDPT_ADDR       0xFCFC3F20      // 32 bytes
38 #define PAE_TMP_DIR_ADDR        0xFCFE0000      // 16 KiB
39 #define PAE_TMP_TABLE_ADDR      0xFD000000      // 16 MiB
40
41 #define PAGE_TABLE_ADDR 0xFC000000
42 #define PAGE_DIR_ADDR   0xFC3F0000
43 #define PAGE_CR3_ADDR   0xFC3F0FC0
44 #define TMP_CR3_ADDR    0xFC3F0FC4      // Part of core instead of temp
45 #define TMP_DIR_ADDR    0xFC3F1000      // Same
46 #define TMP_TABLE_ADDR  0xFC400000
47
48 #define HW_MAP_ADDR             0xFE000000
49 #define HW_MAP_MAX              0xFFEF0000
50 #define NUM_HW_PAGES    ((HW_MAP_MAX-HW_MAP_ADDR)/0x1000)
51 #define TEMP_MAP_ADDR   0xFFEF0000      // Allows 16 "temp" pages
52 #define NUM_TEMP_PAGES  16
53 #define LAST_BLOCK_ADDR 0xFFFF0000      // Free space for kernel provided user code/ *(-1) protection
54
55 #define PF_PRESENT      0x1
56 #define PF_WRITE        0x2
57 #define PF_USER         0x4
58 #define PF_GLOBAL       0x80
59 #define PF_COW          0x200
60 #define PF_NOPAGE       0x400
61
62 #define INVLPG(addr)    __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
63
64 #if USE_PAE
65 typedef Uint64  tTabEnt;
66 #else
67 typedef Uint32  tTabEnt;
68 #endif
69
70 // === IMPORTS ===
71 extern void     _UsertextEnd, _UsertextBase;
72 extern Uint32   gaInitPageDir[1024];
73 extern Uint32   gaInitPageTable[1024];
74 extern void     Threads_SegFault(tVAddr Addr);
75 extern void     Error_Backtrace(Uint eip, Uint ebp);
76
77 // === PROTOTYPES ===
78 void    MM_PreinitVirtual(void);
79 void    MM_InstallVirtual(void);
80 void    MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
81 void    MM_DumpTables(tVAddr Start, tVAddr End);
82 tVAddr  MM_ClearUser(void);
83 tPAddr  MM_DuplicatePage(tVAddr VAddr);
84
85 // === GLOBALS ===
86 #define gaPageTable     ((tTabEnt*)PAGE_TABLE_ADDR)
87 #define gaPageDir       ((tTabEnt*)PAGE_DIR_ADDR)
88 #define gaTmpTable      ((tTabEnt*)TMP_TABLE_ADDR)
89 #define gaTmpDir        ((tTabEnt*)TMP_DIR_ADDR)
90 #define gpPageCR3       ((tTabEnt*)PAGE_CR3_ADDR)
91 #define gpTmpCR3        ((tTabEnt*)TMP_CR3_ADDR)
92
93 #define gaPAE_PageTable ((tTabEnt*)PAE_PAGE_TABLE_ADDR)
94 #define gaPAE_PageDir   ((tTabEnt*)PAE_PAGE_DIR_ADDR)
95 #define gaPAE_MainPDPT  ((tTabEnt*)PAE_PAGE_PDPT_ADDR)
96 #define gaPAE_TmpTable  ((tTabEnt*)PAE_TMP_DIR_ADDR)
97 #define gaPAE_TmpDir    ((tTabEnt*)PAE_TMP_DIR_ADDR)
98 #define gaPAE_TmpPDPT   ((tTabEnt*)PAE_TMP_PDPT_ADDR)
99  int    gbUsePAE = 0;
100 tMutex  glTempMappings;
101 tMutex  glTempFractal;
102 Uint32  gWorkerStacks[(NUM_WORKER_STACKS+31)/32];
103  int    giLastUsedWorker = 0;
104 struct sPageInfo {
105         void    *Node;
106         tVAddr  Base;
107         Uint64  Offset;
108          int    Length;
109          int    Flags;
110 }       *gaMappedRegions;       // sizeof = 24 bytes
111
112 // === CODE ===
113 /**
114  * \fn void MM_PreinitVirtual(void)
115  * \brief Maps the fractal mappings
116  */
117 void MM_PreinitVirtual(void)
118 {
119         #if USE_PAE
120         gaInitPageDir[ ((PAGE_TABLE_ADDR >> TAB)-3*512+3)*2 ] = ((tTabEnt)&gaInitPageDir - KERNEL_BASE) | 3;
121         #else
122         gaInitPageDir[ PAGE_TABLE_ADDR >> 22 ] = ((tTabEnt)&gaInitPageDir - KERNEL_BASE) | 3;
123         #endif
124         INVLPG( PAGE_TABLE_ADDR );
125 }
126
127 /**
128  * \fn void MM_InstallVirtual(void)
129  * \brief Sets up the constant page mappings
130  */
131 void MM_InstallVirtual(void)
132 {
133          int    i;
134         
135         #if USE_PAE
136         // --- Pre-Allocate kernel tables
137         for( i = KERNEL_BASE >> TAB; i < 1024*4; i ++ )
138         {
139                 if( gaPAE_PageDir[ i ] )        continue;
140                 
141                 // Skip stack tables, they are process unique
142                 if( i > KERNEL_STACKS >> TAB && i < KERNEL_STACKS_END >> TAB) {
143                         gaPAE_PageDir[ i ] = 0;
144                         continue;
145                 }
146                 // Preallocate table
147                 gaPAE_PageDir[ i ] = MM_AllocPhys() | 3;
148                 INVLPG( &gaPAE_PageTable[i*512] );
149                 memset( &gaPAE_PageTable[i*512], 0, 0x1000 );
150         }
151         #else
152         // --- Pre-Allocate kernel tables
153         for( i = KERNEL_BASE>>22; i < 1024; i ++ )
154         {
155                 if( gaPageDir[ i ] )    continue;
156                 // Skip stack tables, they are process unique
157                 if( i > KERNEL_STACKS >> 22 && i < KERNEL_STACKS_END >> 22) {
158                         gaPageDir[ i ] = 0;
159                         continue;
160                 }
161                 // Preallocate table
162                 gaPageDir[ i ] = MM_AllocPhys() | 3;
163                 INVLPG( &gaPageTable[i*1024] );
164                 memset( &gaPageTable[i*1024], 0, 0x1000 );
165         }
166         #endif
167         
168         // Unset kernel on the User Text pages
169         for( i = ((tVAddr)&_UsertextEnd-(tVAddr)&_UsertextBase+0xFFF)/4096; i--; ) {
170                 MM_SetFlags( (tVAddr)&_UsertextBase + i*4096, 0, MM_PFLAG_KERNEL );
171         }
172 }
173
174 /**
175  * \brief Cleans up the SMP required mappings
176  */
177 void MM_FinishVirtualInit(void)
178 {
179         #if USE_PAE
180         gaInitPDPT[ 0 ] = 0;
181         #else
182         gaInitPageDir[ 0 ] = 0;
183         #endif
184 }
185
186 /**
187  * \fn void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
188  * \brief Called on a page fault
189  */
190 void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
191 {
192         //ENTER("xAddr bErrorCode", Addr, ErrorCode);
193         
194         // -- Check for COW --
195         if( gaPageDir  [Addr>>22] & PF_PRESENT  && gaPageTable[Addr>>12] & PF_PRESENT
196          && gaPageTable[Addr>>12] & PF_COW )
197         {
198                 tPAddr  paddr;
199                 if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
200                 {
201                         gaPageTable[Addr>>12] &= ~PF_COW;
202                         gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
203                 }
204                 else
205                 {
206                         //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr);
207                         paddr = MM_DuplicatePage( Addr );
208                         MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
209                         gaPageTable[Addr>>12] &= PF_USER;
210                         gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
211                 }
212                 
213                 INVLPG( Addr & ~0xFFF );
214                 return;
215         }
216         
217         // If it was a user, tell the thread handler
218         if(ErrorCode & 4) {
219                 Warning("%s %s %s memory%s",
220                         (ErrorCode&4?"User":"Kernel"),
221                         (ErrorCode&2?"write to":"read from"),
222                         (ErrorCode&1?"bad/locked":"non-present"),
223                         (ErrorCode&16?" (Instruction Fetch)":"")
224                         );
225                 Warning("User Pagefault: Instruction at %04x:%08x accessed %p", Regs->cs, Regs->eip, Addr);
226                 __asm__ __volatile__ ("sti");   // Restart IRQs
227                 #if 1
228                 Error_Backtrace(Regs->eip, Regs->ebp);
229                 #endif
230                 Threads_SegFault(Addr);
231                 return ;
232         }
233         
234         Debug_KernelPanic();
235         
236         // -- Check Error Code --
237         if(ErrorCode & 8)
238                 Warning("Reserved Bits Trashed!");
239         else
240         {
241                 Warning("%s %s %s memory%s",
242                         (ErrorCode&4?"User":"Kernel"),
243                         (ErrorCode&2?"write to":"read from"),
244                         (ErrorCode&1?"bad/locked":"non-present"),
245                         (ErrorCode&16?" (Instruction Fetch)":"")
246                         );
247         }
248         
249         Log("Code at %p accessed %p", Regs->eip, Addr);
250         // Print Stack Backtrace
251         Error_Backtrace(Regs->eip, Regs->ebp);
252         
253         Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]);
254         if( gaPageDir[Addr>>22] & PF_PRESENT )
255                 Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]);
256         
257         //MM_DumpTables(0, -1); 
258         
259         // Register Dump
260         Log("EAX %08x ECX %08x EDX %08x EBX %08x", Regs->eax, Regs->ecx, Regs->edx, Regs->ebx);
261         Log("ESP %08x EBP %08x ESI %08x EDI %08x", Regs->esp, Regs->ebp, Regs->esi, Regs->edi);
262         //Log("SS:ESP %04x:%08x", Regs->ss, Regs->esp);
263         Log("CS:EIP %04x:%08x", Regs->cs, Regs->eip);
264         Log("DS %04x ES %04x FS %04x GS %04x", Regs->ds, Regs->es, Regs->fs, Regs->gs);
265         {
266                 Uint    dr0, dr1;
267                 __ASM__ ("mov %%dr0, %0":"=r"(dr0):);
268                 __ASM__ ("mov %%dr1, %0":"=r"(dr1):);
269                 Log("DR0 %08x DR1 %08x", dr0, dr1);
270         }
271         
272         Panic("Page Fault at 0x%x (Accessed 0x%x)", Regs->eip, Addr);
273 }
274
275 /**
276  * \fn void MM_DumpTables(tVAddr Start, tVAddr End)
277  * \brief Dumps the layout of the page tables
278  */
279 void MM_DumpTables(tVAddr Start, tVAddr End)
280 {
281         tVAddr  rangeStart = 0;
282         tPAddr  expected = 0;
283         tVAddr  curPos;
284         Uint    page;
285         const tPAddr    MASK = ~0xF78;
286         
287         Start >>= 12;   End >>= 12;
288         
289         #if 0
290         Log("Directory Entries:");
291         for(page = Start >> 10;
292                 page < (End >> 10)+1;
293                 page ++)
294         {
295                 if(gaPageDir[page])
296                 {
297                         Log(" 0x%08x-0x%08x :: 0x%08x",
298                                 page<<22, ((page+1)<<22)-1,
299                                 gaPageDir[page]&~0xFFF
300                                 );
301                 }
302         }
303         #endif
304         
305         Log("Table Entries:");
306         for(page = Start, curPos = Start<<12;
307                 page < End;
308                 curPos += 0x1000, page++)
309         {
310                 if( !(gaPageDir[curPos>>22] & PF_PRESENT)
311                 ||  !(gaPageTable[page] & PF_PRESENT)
312                 ||  (gaPageTable[page] & MASK) != expected)
313                 {
314                         if(expected) {
315                                 Log(" 0x%08x => 0x%08x - 0x%08x (%s%s%s%s%s)",
316                                         rangeStart,
317                                         gaPageTable[rangeStart>>12] & ~0xFFF,
318                                         curPos - rangeStart,
319                                         (expected & PF_NOPAGE ? "P" : "-"),
320                                         (expected & PF_COW ? "C" : "-"),
321                                         (expected & PF_GLOBAL ? "G" : "-"),
322                                         (expected & PF_USER ? "U" : "-"),
323                                         (expected & PF_WRITE ? "W" : "-"),
324                                         gaPageTable[page] & MASK, expected
325                                         );
326                                 expected = 0;
327                         }
328                         if( !(gaPageDir[curPos>>22] & PF_PRESENT) )     continue;
329                         if( !(gaPageTable[curPos>>12] & PF_PRESENT) )   continue;
330                         
331                         expected = (gaPageTable[page] & MASK);
332                         rangeStart = curPos;
333                 }
334                 if(expected)    expected += 0x1000;
335         }
336         
337         if(expected) {
338                 Log("0x%08x => 0x%08x - 0x%08x (%s%s%s%s)",
339                         rangeStart,
340                         gaPageTable[rangeStart>>12] & ~0xFFF,
341                         curPos - rangeStart,
342                         (expected & PF_NOPAGE ? "p" : "-"),
343                         (expected & PF_COW ? "C" : "-"),
344                         (expected & PF_USER ? "U" : "-"),
345                         (expected & PF_WRITE ? "W" : "-")
346                         );
347                 expected = 0;
348         }
349 }
350
351 /**
352  * \fn tPAddr MM_Allocate(tVAddr VAddr)
353  */
354 tPAddr MM_Allocate(tVAddr VAddr)
355 {
356         tPAddr  paddr;
357         //ENTER("xVAddr", VAddr);
358         //__asm__ __volatile__ ("xchg %bx,%bx");
359         // Check if the directory is mapped
360         if( gaPageDir[ VAddr >> 22 ] == 0 )
361         {
362                 // Allocate directory
363                 paddr = MM_AllocPhys();
364                 if( paddr == 0 ) {
365                         Warning("MM_Allocate - Out of Memory (Called by %p)", __builtin_return_address(0));
366                         //LEAVE('i',0);
367                         return 0;
368                 }
369                 // Map and mark as user (if needed)
370                 gaPageDir[ VAddr >> 22 ] = paddr | 3;
371                 if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
372                 
373                 INVLPG( &gaPageDir[ VAddr >> 22 ] );
374                 memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
375         }
376         // Check if the page is already allocated
377         else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
378                 Warning("MM_Allocate - Allocating to used address (%p)", VAddr);
379                 //LEAVE('X', gaPageTable[ VAddr >> 12 ] & ~0xFFF);
380                 return gaPageTable[ VAddr >> 12 ] & ~0xFFF;
381         }
382         
383         // Allocate
384         paddr = MM_AllocPhys();
385         //LOG("paddr = 0x%llx", paddr);
386         if( paddr == 0 ) {
387                 Warning("MM_Allocate - Out of Memory when allocating at %p (Called by %p)",
388                         VAddr, __builtin_return_address(0));
389                 //LEAVE('i',0);
390                 return 0;
391         }
392         // Map
393         gaPageTable[ VAddr >> 12 ] = paddr | 3;
394         // Mark as user
395         if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
396         // Invalidate Cache for address
397         INVLPG( VAddr & ~0xFFF );
398         
399         //LEAVE('X', paddr);
400         return paddr;
401 }
402
403 /**
404  * \fn void MM_Deallocate(tVAddr VAddr)
405  */
406 void MM_Deallocate(tVAddr VAddr)
407 {
408         if( gaPageDir[ VAddr >> 22 ] == 0 ) {
409                 Warning("MM_Deallocate - Directory not mapped");
410                 return;
411         }
412         
413         if(gaPageTable[ VAddr >> 12 ] == 0) {
414                 Warning("MM_Deallocate - Page is not allocated");
415                 return;
416         }
417         
418         // Dereference page
419         MM_DerefPhys( gaPageTable[ VAddr >> 12 ] & ~0xFFF );
420         // Clear page
421         gaPageTable[ VAddr >> 12 ] = 0;
422 }
423
424 /**
425  * \fn tPAddr MM_GetPhysAddr(tVAddr Addr)
426  * \brief Checks if the passed address is accesable
427  */
428 tPAddr MM_GetPhysAddr(tVAddr Addr)
429 {
430         if( !(gaPageDir[Addr >> 22] & 1) )
431                 return 0;
432         if( !(gaPageTable[Addr >> 12] & 1) )
433                 return 0;
434         return (gaPageTable[Addr >> 12] & ~0xFFF) | (Addr & 0xFFF);
435 }
436
437 /**
438  * \fn void MM_SetCR3(Uint CR3)
439  * \brief Sets the current process space
440  */
441 void MM_SetCR3(Uint CR3)
442 {
443         __asm__ __volatile__ ("mov %0, %%cr3"::"r"(CR3));
444 }
445
446 /**
447  * \fn int MM_Map(tVAddr VAddr, tPAddr PAddr)
448  * \brief Map a physical page to a virtual one
449  */
450 int MM_Map(tVAddr VAddr, tPAddr PAddr)
451 {
452         //ENTER("xVAddr xPAddr", VAddr, PAddr);
453         // Sanity check
454         if( PAddr & 0xFFF || VAddr & 0xFFF ) {
455                 Warning("MM_Map - Physical or Virtual Addresses are not aligned");
456                 //LEAVE('i', 0);
457                 return 0;
458         }
459         
460         // Align addresses
461         PAddr &= ~0xFFF;        VAddr &= ~0xFFF;
462         
463         // Check if the directory is mapped
464         if( gaPageDir[ VAddr >> 22 ] == 0 )
465         {
466                 gaPageDir[ VAddr >> 22 ] = MM_AllocPhys() | 3;
467                 
468                 // Mark as user
469                 if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
470                 
471                 INVLPG( &gaPageTable[ (VAddr >> 12) & ~0x3FF ] );
472                 memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
473         }
474         // Check if the page is already allocated
475         else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
476                 Warning("MM_Map - Allocating to used address");
477                 //LEAVE('i', 0);
478                 return 0;
479         }
480         
481         // Map
482         gaPageTable[ VAddr >> 12 ] = PAddr | 3;
483         // Mark as user
484         if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
485         
486         //LOG("gaPageTable[ 0x%x ] = (Uint)%p = 0x%x",
487         //      VAddr >> 12, &gaPageTable[ VAddr >> 12 ], gaPageTable[ VAddr >> 12 ]);
488         
489         // Reference
490         MM_RefPhys( PAddr );
491         
492         //LOG("INVLPG( 0x%x )", VAddr);
493         INVLPG( VAddr );
494         
495         //LEAVE('i', 1);
496         return 1;
497 }
498
499 /**
500  * \fn tVAddr MM_ClearUser()
501  * \brief Clear user's address space
502  */
503 tVAddr MM_ClearUser(void)
504 {
505         Uint    i, j;
506         
507         for( i = 0; i < (MM_USER_MAX>>22); i ++ )
508         {
509                 // Check if directory is not allocated
510                 if( !(gaPageDir[i] & PF_PRESENT) ) {
511                         gaPageDir[i] = 0;
512                         continue;
513                 }
514                 
515                 // Deallocate tables
516                 for( j = 0; j < 1024; j ++ )
517                 {
518                         if( gaPageTable[i*1024+j] & 1 )
519                                 MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF );
520                         gaPageTable[i*1024+j] = 0;
521                 }
522                 
523                 // Deallocate directory
524                 MM_DerefPhys( gaPageDir[i] & ~0xFFF );
525                 gaPageDir[i] = 0;
526                 INVLPG( &gaPageTable[i*1024] );
527         }
528         INVLPG( gaPageDir );
529         
530         return *gpPageCR3;
531 }
532
533 /**
534  * \fn tPAddr MM_Clone(void)
535  * \brief Clone the current address space
536  */
537 tPAddr MM_Clone(void)
538 {
539         Uint    i, j;
540         tVAddr  ret;
541         Uint    page = 0;
542         tVAddr  kStackBase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE;
543         void    *tmp;
544         
545         Mutex_Acquire( &glTempFractal );
546         
547         // Create Directory Table
548         *gpTmpCR3 = MM_AllocPhys() | 3;
549         INVLPG( gaTmpDir );
550         //LOG("Allocated Directory (%x)", *gpTmpCR3);
551         memsetd( gaTmpDir, 0, 1024 );
552         
553         if( Threads_GetPID() != 0 )
554         {       
555                 // Copy Tables
556                 for( i = 0; i < 768; i ++)
557                 {
558                         // Check if table is allocated
559                         if( !(gaPageDir[i] & PF_PRESENT) ) {
560                                 gaTmpDir[i] = 0;
561                                 page += 1024;
562                                 continue;
563                         }
564                         
565                         // Allocate new table
566                         gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7);
567                         INVLPG( &gaTmpTable[page] );
568                         // Fill
569                         for( j = 0; j < 1024; j ++, page++ )
570                         {
571                                 if( !(gaPageTable[page] & PF_PRESENT) ) {
572                                         gaTmpTable[page] = 0;
573                                         continue;
574                                 }
575                                 
576                                 // Refrence old page
577                                 MM_RefPhys( gaPageTable[page] & ~0xFFF );
578                                 // Add to new table
579                                 if(gaPageTable[page] & PF_WRITE) {
580                                         gaTmpTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
581                                         gaPageTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
582                                         INVLPG( page << 12 );
583                                 }
584                                 else
585                                         gaTmpTable[page] = gaPageTable[page];
586                         }
587                 }
588         }
589         
590         // Map in kernel tables (and make fractal mapping)
591         for( i = 768; i < 1024; i ++ )
592         {
593                 // Fractal
594                 if( i == (PAGE_TABLE_ADDR >> 22) ) {
595                         gaTmpDir[ PAGE_TABLE_ADDR >> 22 ] = *gpTmpCR3;
596                         continue;
597                 }
598                 
599                 if( gaPageDir[i] == 0 ) {
600                         gaTmpDir[i] = 0;
601                         continue;
602                 }
603                 
604                 //LOG("gaPageDir[%x/4] = 0x%x", i*4, gaPageDir[i]);
605                 MM_RefPhys( gaPageDir[i] & ~0xFFF );
606                 gaTmpDir[i] = gaPageDir[i];
607         }
608         
609         // Allocate kernel stack
610         for(i = KERNEL_STACKS >> 22;
611                 i < KERNEL_STACKS_END >> 22;
612                 i ++ )
613         {
614                 // Check if directory is allocated
615                 if( (gaPageDir[i] & 1) == 0 ) {
616                         gaTmpDir[i] = 0;
617                         continue;
618                 }               
619                 
620                 // We don't care about other kernel stacks, just the current one
621                 if( i != kStackBase >> 22 ) {
622                         MM_DerefPhys( gaPageDir[i] & ~0xFFF );
623                         gaTmpDir[i] = 0;
624                         continue;
625                 }
626                 
627                 // Create a copy
628                 gaTmpDir[i] = MM_AllocPhys() | 3;
629                 INVLPG( &gaTmpTable[i*1024] );
630                 for( j = 0; j < 1024; j ++ )
631                 {
632                         // Is the page allocated? If not, skip
633                         if( !(gaPageTable[i*1024+j] & 1) ) {
634                                 gaTmpTable[i*1024+j] = 0;
635                                 continue;
636                         }
637                         
638                         // We don't care about other kernel stacks
639                         if( ((i*1024+j)*4096 & ~(KERNEL_STACK_SIZE-1)) != kStackBase ) {
640                                 gaTmpTable[i*1024+j] = 0;
641                                 continue;
642                         }
643                         
644                         // Allocate page
645                         gaTmpTable[i*1024+j] = MM_AllocPhys() | 3;
646                         
647                         MM_RefPhys( gaTmpTable[i*1024+j] & ~0xFFF );
648                         
649                         tmp = (void *) MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
650                         memcpy( tmp, (void *)( (i*1024+j)*0x1000 ), 0x1000 );
651                         MM_FreeTemp( (Uint)tmp );
652                 }
653         }
654         
655         ret = *gpTmpCR3 & ~0xFFF;
656         Mutex_Release( &glTempFractal );
657         
658         //LEAVE('x', ret);
659         return ret;
660 }
661
662 /**
663  * \fn tVAddr MM_NewKStack(void)
664  * \brief Create a new kernel stack
665  */
666 tVAddr MM_NewKStack(void)
667 {
668         tVAddr  base;
669         Uint    i;
670         for(base = KERNEL_STACKS; base < KERNEL_STACKS_END; base += KERNEL_STACK_SIZE)
671         {
672                 // Check if space is free
673                 if(MM_GetPhysAddr(base) != 0)   continue;
674                 // Allocate
675                 //for(i = KERNEL_STACK_SIZE; i -= 0x1000 ; )
676                 for(i = 0; i < KERNEL_STACK_SIZE; i += 0x1000 )
677                 {
678                         if( MM_Allocate(base+i) == 0 )
679                         {
680                                 // On error, print a warning and return error
681                                 Warning("MM_NewKStack - Out of memory");
682                                 // - Clean up
683                                 //for( i += 0x1000 ; i < KERNEL_STACK_SIZE; i += 0x1000 )
684                                 //      MM_Deallocate(base+i);
685                                 return 0;
686                         }
687                 }
688                 // Success
689                 Log("MM_NewKStack - Allocated %p", base + KERNEL_STACK_SIZE);
690                 return base+KERNEL_STACK_SIZE;
691         }
692         // No stacks left
693         Warning("MM_NewKStack - No address space left");
694         return 0;
695 }
696
697 /**
698  * \fn tVAddr MM_NewWorkerStack()
699  * \brief Creates a new worker stack
700  */
701 tVAddr MM_NewWorkerStack()
702 {
703         Uint    esp, ebp;
704         Uint    oldstack;
705         Uint    base, addr;
706          int    i, j;
707         Uint    *tmpPage;
708         tPAddr  pages[WORKER_STACK_SIZE>>12];
709         
710         // Get the old ESP and EBP
711         __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp));
712         __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp));
713         
714         // TODO: Thread safety
715         // Find a free worker stack address
716         for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++)
717         {
718                 // Used block
719                 if( gWorkerStacks[base/32] == -1 ) {
720                         base += 31;     base &= ~31;
721                         base --;        // Counteracted by the base++
722                         continue;
723                 }
724                 // Used stack
725                 if( gWorkerStacks[base/32] & (1 << base) ) {
726                         continue;
727                 }
728                 break;
729         }
730         if(base >= NUM_WORKER_STACKS) {
731                 Warning("Uh-oh! Out of worker stacks");
732                 return 0;
733         }
734         
735         // It's ours now!
736         gWorkerStacks[base/32] |= (1 << base);
737         // Make life easier for later calls
738         giLastUsedWorker = base;
739         // We have one
740         base = WORKER_STACKS + base * WORKER_STACK_SIZE;
741         //Log(" MM_NewWorkerStack: base = 0x%x", base);
742         
743         // Acquire the lock for the temp fractal mappings
744         Mutex_Acquire(&glTempFractal);
745         
746         // Set the temp fractals to TID0's address space
747         *gpTmpCR3 = ((Uint)gaInitPageDir - KERNEL_BASE) | 3;
748         //Log(" MM_NewWorkerStack: *gpTmpCR3 = 0x%x", *gpTmpCR3);
749         INVLPG( gaTmpDir );
750         
751         
752         // Check if the directory is mapped (we are assuming that the stacks
753         // will fit neatly in a directory)
754         //Log(" MM_NewWorkerStack: gaTmpDir[ 0x%x ] = 0x%x", base>>22, gaTmpDir[ base >> 22 ]);
755         if(gaTmpDir[ base >> 22 ] == 0) {
756                 gaTmpDir[ base >> 22 ] = MM_AllocPhys() | 3;
757                 INVLPG( &gaTmpTable[ (base>>12) & ~0x3FF ] );
758         }
759         
760         // Mapping Time!
761         for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 )
762         //for( addr = WORKER_STACK_SIZE; addr; addr -= 0x1000 )
763         {
764                 pages[ addr >> 12 ] = MM_AllocPhys();
765                 gaTmpTable[ (base + addr) >> 12 ] = pages[addr>>12] | 3;
766         }
767         *gpTmpCR3 = 0;
768         // Release the temp mapping lock
769         Mutex_Release(&glTempFractal);
770         
771         // Copy the old stack
772         oldstack = (esp + KERNEL_STACK_SIZE-1) & ~(KERNEL_STACK_SIZE-1);
773         esp = oldstack - esp;   // ESP as an offset in the stack
774         
775         // Make `base` be the top of the stack
776         base += WORKER_STACK_SIZE;
777         
778         i = (WORKER_STACK_SIZE>>12) - 1;
779         // Copy the contents of the old stack to the new one, altering the addresses
780         // `addr` is refering to bytes from the stack base (mem downwards)
781         for(addr = 0; addr < esp; addr += 0x1000)
782         {
783                 Uint    *stack = (Uint*)( oldstack-(addr+0x1000) );
784                 tmpPage = (void*)MM_MapTemp( pages[i] );
785                 // Copy old stack
786                 for(j = 0; j < 1024; j++)
787                 {
788                         // Possible Stack address?
789                         if(oldstack-esp < stack[j] && stack[j] < oldstack)
790                                 tmpPage[j] = base - (oldstack - stack[j]);
791                         else    // Seems not, best leave it alone
792                                 tmpPage[j] = stack[j];
793                 }
794                 MM_FreeTemp((tVAddr)tmpPage);
795                 i --;
796         }
797         
798         //Log("MM_NewWorkerStack: RETURN 0x%x", base);
799         return base;
800 }
801
802 /**
803  * \fn void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
804  * \brief Sets the flags on a page
805  */
806 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
807 {
808         tTabEnt *ent;
809         if( !(gaPageDir[VAddr >> 22] & 1) )     return ;
810         if( !(gaPageTable[VAddr >> 12] & 1) )   return ;
811         
812         ent = &gaPageTable[VAddr >> 12];
813         
814         // Read-Only
815         if( Mask & MM_PFLAG_RO )
816         {
817                 if( Flags & MM_PFLAG_RO ) {
818                         *ent &= ~PF_WRITE;
819                 }
820                 else {
821                         gaPageDir[VAddr >> 22] |= PF_WRITE;
822                         *ent |= PF_WRITE;
823                 }
824         }
825         
826         // Kernel
827         if( Mask & MM_PFLAG_KERNEL )
828         {
829                 if( Flags & MM_PFLAG_KERNEL ) {
830                         *ent &= ~PF_USER;
831                 }
832                 else {
833                         gaPageDir[VAddr >> 22] |= PF_USER;
834                         *ent |= PF_USER;
835                 }
836         }
837         
838         // Copy-On-Write
839         if( Mask & MM_PFLAG_COW )
840         {
841                 if( Flags & MM_PFLAG_COW ) {
842                         *ent &= ~PF_WRITE;
843                         *ent |= PF_COW;
844                 }
845                 else {
846                         *ent &= ~PF_COW;
847                         *ent |= PF_WRITE;
848                 }
849         }
850         
851         //Log("MM_SetFlags: *ent = 0x%08x, gaPageDir[%i] = 0x%08x",
852         //      *ent, VAddr >> 22, gaPageDir[VAddr >> 22]);
853 }
854
855 /**
856  * \brief Get the flags on a page
857  */
858 Uint MM_GetFlags(tVAddr VAddr)
859 {
860         tTabEnt *ent;
861         Uint    ret = 0;
862         
863         // Validity Check
864         if( !(gaPageDir[VAddr >> 22] & 1) )     return 0;
865         if( !(gaPageTable[VAddr >> 12] & 1) )   return 0;
866         
867         ent = &gaPageTable[VAddr >> 12];
868         
869         // Read-Only
870         if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
871         // Kernel
872         if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
873         // Copy-On-Write
874         if( *ent & PF_COW )     ret |= MM_PFLAG_COW;
875         
876         return ret;
877 }
878
879 /**
880  * \fn tPAddr MM_DuplicatePage(tVAddr VAddr)
881  * \brief Duplicates a virtual page to a physical one
882  */
883 tPAddr MM_DuplicatePage(tVAddr VAddr)
884 {
885         tPAddr  ret;
886         Uint    temp;
887          int    wasRO = 0;
888         
889         //ENTER("xVAddr", VAddr);
890         
891         // Check if mapped
892         if( !(gaPageDir  [VAddr >> 22] & PF_PRESENT) )  return 0;
893         if( !(gaPageTable[VAddr >> 12] & PF_PRESENT) )  return 0;
894         
895         // Page Align
896         VAddr &= ~0xFFF;
897         
898         // Allocate new page
899         ret = MM_AllocPhys();
900         
901         // Write-lock the page (to keep data constistent), saving its R/W state
902         wasRO = (gaPageTable[VAddr >> 12] & PF_WRITE ? 0 : 1);
903         gaPageTable[VAddr >> 12] &= ~PF_WRITE;
904         INVLPG( VAddr );
905         
906         // Copy Data
907         temp = MM_MapTemp(ret);
908         memcpy( (void*)temp, (void*)VAddr, 0x1000 );
909         MM_FreeTemp(temp);
910         
911         // Restore Writeable status
912         if(!wasRO)      gaPageTable[VAddr >> 12] |= PF_WRITE;
913         INVLPG(VAddr);
914         
915         //LEAVE('X', ret);
916         return ret;
917 }
918
919 /**
920  * \fn Uint MM_MapTemp(tPAddr PAddr)
921  * \brief Create a temporary memory mapping
922  * \todo Show Luigi Barone (C Lecturer) and see what he thinks
923  */
924 tVAddr MM_MapTemp(tPAddr PAddr)
925 {
926          int    i;
927         
928         //ENTER("XPAddr", PAddr);
929         
930         PAddr &= ~0xFFF;
931         
932         //LOG("glTempMappings = %i", glTempMappings);
933         
934         for(;;)
935         {
936                 Mutex_Acquire( &glTempMappings );
937                 
938                 for( i = 0; i < NUM_TEMP_PAGES; i ++ )
939                 {
940                         // Check if page used
941                         if(gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] & 1)        continue;
942                         // Mark as used
943                         gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] = PAddr | 3;
944                         INVLPG( TEMP_MAP_ADDR + (i << 12) );
945                         //LEAVE('p', TEMP_MAP_ADDR + (i << 12));
946                         Mutex_Release( &glTempMappings );
947                         return TEMP_MAP_ADDR + (i << 12);
948                 }
949                 Mutex_Release( &glTempMappings );
950                 Threads_Yield();        // TODO: Use a sleep queue here instead
951         }
952 }
953
954 /**
955  * \fn void MM_FreeTemp(tVAddr PAddr)
956  * \brief Free's a temp mapping
957  */
958 void MM_FreeTemp(tVAddr VAddr)
959 {
960          int    i = VAddr >> 12;
961         //ENTER("xVAddr", VAddr);
962         
963         if(i >= (TEMP_MAP_ADDR >> 12))
964                 gaPageTable[ i ] = 0;
965         
966         //LEAVE('-');
967 }
968
969 /**
970  * \fn tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
971  * \brief Allocates a contigous number of pages
972  */
973 tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
974 {
975          int    i, j;
976         
977         PAddr &= ~0xFFF;
978         
979         // Scan List
980         for( i = 0; i < NUM_HW_PAGES; i ++ )
981         {               
982                 // Check if addr used
983                 if( gaPageTable[ (HW_MAP_ADDR >> 12) + i ] & 1 )
984                         continue;
985                 
986                 // Check possible region
987                 for( j = 0; j < Number && i + j < NUM_HW_PAGES; j ++ )
988                 {
989                         // If there is an allocated page in the region we are testing, break
990                         if( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] & 1 )    break;
991                 }
992                 // Is it all free?
993                 if( j == Number )
994                 {
995                         // Allocate
996                         for( j = 0; j < Number; j++ ) {
997                                 MM_RefPhys( PAddr + (j<<12) );
998                                 gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = (PAddr + (j<<12)) | 3;
999                         }
1000                         return HW_MAP_ADDR + (i<<12);
1001                 }
1002         }
1003         // If we don't find any, return NULL
1004         return 0;
1005 }
1006
1007 /**
1008  * \fn tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
1009  * \brief Allocates DMA physical memory
1010  * \param Pages Number of pages required
1011  * \param MaxBits       Maximum number of bits the physical address can have
1012  * \param PhysAddr      Pointer to the location to place the physical address allocated
1013  * \return Virtual address allocate
1014  */
1015 tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
1016 {
1017         tPAddr  maxCheck = (1 << MaxBits);
1018         tPAddr  phys;
1019         tVAddr  ret;
1020         
1021         ENTER("iPages iMaxBits pPhysAddr", Pages, MaxBits, PhysAddr);
1022         
1023         // Sanity Check
1024         if(MaxBits < 12 || !PhysAddr) {
1025                 LEAVE('i', 0);
1026                 return 0;
1027         }
1028         
1029         // Bound
1030         if(MaxBits >= PHYS_BITS)        maxCheck = -1;
1031         
1032         // Fast Allocate
1033         if(Pages == 1 && MaxBits >= PHYS_BITS)
1034         {
1035                 phys = MM_AllocPhys();
1036                 *PhysAddr = phys;
1037                 ret = MM_MapHWPages(phys, 1);
1038                 if(ret == 0) {
1039                         MM_DerefPhys(phys);
1040                         LEAVE('i', 0);
1041                         return 0;
1042                 }
1043                 LEAVE('x', ret);
1044                 return ret;
1045         }
1046         
1047         // Slow Allocate
1048         phys = MM_AllocPhysRange(Pages, MaxBits);
1049         // - Was it allocated?
1050         if(phys == 0) {
1051                 LEAVE('i', 0);
1052                 return 0;
1053         }
1054         
1055         // Allocated successfully, now map
1056         ret = MM_MapHWPages(phys, Pages);
1057         if( ret == 0 ) {
1058                 // If it didn't map, free then return 0
1059                 for(;Pages--;phys+=0x1000)
1060                         MM_DerefPhys(phys);
1061                 LEAVE('i', 0);
1062                 return 0;
1063         }
1064         
1065         *PhysAddr = phys;
1066         LEAVE('x', ret);
1067         return ret;
1068 }
1069
1070 /**
1071  * \fn void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
1072  * \brief Unmap a hardware page
1073  */
1074 void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
1075 {
1076          int    i, j;
1077         
1078         //Log_Debug("VirtMem", "MM_UnmapHWPages: (VAddr=0x%08x, Number=%i)", VAddr, Number);
1079         
1080         // Sanity Check
1081         if(VAddr < HW_MAP_ADDR || VAddr+Number*0x1000 > HW_MAP_MAX)     return;
1082         
1083         i = VAddr >> 12;
1084         
1085         Mutex_Acquire( &glTempMappings );       // Temp and HW share a directory, so they share a lock
1086         
1087         for( j = 0; j < Number; j++ )
1088         {
1089                 MM_DerefPhys( gaPageTable[ i + j ] & ~0xFFF );
1090                 gaPageTable[ i + j ] = 0;
1091         }
1092         
1093         Mutex_Release( &glTempMappings );
1094 }
1095

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