Fixes to Libc, Doxygen Comments and VTerm layout
[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   1
13 #include <common.h>
14 #include <mm_phys.h>
15 #include <proc.h>
16
17 #define KERNEL_STACKS           0xF0000000
18 #define KERNEL_STACK_SIZE       0x00002000
19 #define KERNEL_STACKS_END       0xFD000000
20 #define WORKER_STACKS           0x00100000      // Thread0 Only!
21 #define WORKER_STACK_SIZE       KERNEL_STACK_SIZE
22 #define WORKER_STACKS_END       0xB0000000
23 #define NUM_WORKER_STACKS       ((WORKER_STACKS_END-WORKER_STACKS)/WORKER_STACK_SIZE)
24 #define PAGE_TABLE_ADDR 0xFD000000
25 #define PAGE_DIR_ADDR   0xFD3F4000
26 #define PAGE_CR3_ADDR   0xFD3F4FD0
27 #define TMP_CR3_ADDR    0xFD3F4FD4      // Part of core instead of temp
28 #define TMP_DIR_ADDR    0xFD3F5000      // Same
29 #define TMP_TABLE_ADDR  0xFD400000
30 #define HW_MAP_ADDR             0xFD800000
31 #define HW_MAP_MAX              0xFEFF0000
32 #define NUM_HW_PAGES    ((HW_MAP_MAX-HW_MAP_ADDR)/0x1000)
33 #define TEMP_MAP_ADDR   0xFEFF0000      // Allows 16 "temp" pages
34 #define NUM_TEMP_PAGES  16
35
36 #define PF_PRESENT      0x1
37 #define PF_WRITE        0x2
38 #define PF_USER         0x4
39 #define PF_COW          0x200
40 #define PF_PAGED        0x400
41
42 #define INVLPG(addr)    __asm__ __volatile__ ("invlpg (%0)"::"r"(addr))
43
44 // === IMPORTS ===
45 extern Uint32   gaInitPageDir[1024];
46 extern Uint32   gaInitPageTable[1024];
47 extern void     Threads_SegFault(Uint Addr);
48 extern void     Error_Backtrace(Uint eip, Uint ebp);
49
50 // === PROTOTYPES ===
51 void    MM_PreinitVirtual();
52 void    MM_InstallVirtual();
53 void    MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs);
54 void    MM_DumpTables(tVAddr Start, tVAddr End);
55 tPAddr  MM_DuplicatePage(Uint VAddr);
56
57 // === GLOBALS ===
58 tPAddr  *gaPageTable = (void*)PAGE_TABLE_ADDR;
59 tPAddr  *gaPageDir = (void*)PAGE_DIR_ADDR;
60 tPAddr  *gaPageCR3 = (void*)PAGE_CR3_ADDR;
61 tPAddr  *gaTmpTable = (void*)TMP_TABLE_ADDR;
62 tPAddr  *gaTmpDir = (void*)TMP_DIR_ADDR;
63 tPAddr  *gTmpCR3 = (void*)TMP_CR3_ADDR;
64  int    gilTempMappings = 0;
65  int    gilTempFractal = 0;
66 Uint32  gWorkerStacks[NUM_WORKER_STACKS/32];
67  int    giLastUsedWorker = 0;
68
69 // === CODE ===
70 /**
71  * \fn void MM_PreinitVirtual()
72  * \brief Maps the fractal mappings
73  */
74 void MM_PreinitVirtual()
75 {
76         gaInitPageDir[ 0 ] = 0;
77         gaInitPageDir[ PAGE_TABLE_ADDR >> 22 ] = ((Uint)&gaInitPageDir - KERNEL_BASE) | 3;
78 }
79
80 /**
81  * \fn void MM_InstallVirtual()
82  * \brief Sets up the constant page mappings
83  */
84 void MM_InstallVirtual()
85 {
86          int    i;
87         
88         // --- Pre-Allocate kernel tables
89         for( i = KERNEL_BASE>>22; i < 1024; i ++ )
90         {
91                 if( gaPageDir[ i ] )    continue;
92                 // Skip stack tables, they are process unique
93                 if( i > KERNEL_STACKS >> 22 && i < KERNEL_STACKS_END >> 22) {
94                         gaPageDir[ i ] = 0;
95                         continue;
96                 }
97                 // Preallocate table
98                 gaPageDir[ i ] = MM_AllocPhys() | 3;
99                 INVLPG( &gaPageTable[i*1024] );
100                 memset( &gaPageTable[i*1024], 0, 0x1000 );
101         }
102 }
103
104 /**
105  * \fn void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs)
106  * \brief Called on a page fault
107  */
108 void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs)
109 {
110         //ENTER("xAddr bErrorCode", Addr, ErrorCode);
111         
112         // -- Check for COW --
113         if( gaPageDir  [Addr>>22] & PF_PRESENT
114          && gaPageTable[Addr>>12] & PF_PRESENT
115          && gaPageTable[Addr>>12] & PF_COW )
116         {
117                 tPAddr  paddr;
118                 if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
119                 {
120                         gaPageTable[Addr>>12] &= ~PF_COW;
121                         gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
122                 }
123                 else
124                 {
125                         paddr = MM_DuplicatePage( Addr );
126                         MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
127                         gaPageTable[Addr>>12] &= PF_USER;
128                         gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
129                 }
130                 
131                 INVLPG( Addr & ~0xFFF );
132                 //LEAVE('-')
133                 return;
134         }
135         
136         // If it was a user, tell the thread handler
137         if(ErrorCode & 4) {
138                 Warning("%s %s %s memory%s",
139                         (ErrorCode&4?"User":"Kernel"),
140                         (ErrorCode&2?"write to":"read from"),
141                         (ErrorCode&1?"bad/locked":"non-present"),
142                         (ErrorCode&16?" (Instruction Fetch)":"")
143                         );
144                 Warning("User Pagefault: Instruction at %p accessed %p", Regs->eip, Addr);
145                 __asm__ __volatile__ ("sti");   // Restart IRQs
146                 Threads_SegFault(Addr);
147                 return ;
148         }
149         
150         // -- Check Error Code --
151         if(ErrorCode & 8)
152                 Warning("Reserved Bits Trashed!");
153         else
154         {
155                 Warning("%s %s %s memory%s",
156                         (ErrorCode&4?"User":"Kernel"),
157                         (ErrorCode&2?"write to":"read from"),
158                         (ErrorCode&1?"bad/locked":"non-present"),
159                         (ErrorCode&16?" (Instruction Fetch)":"")
160                         );
161         }
162         
163         Log("Code at %p accessed %p", Regs->eip, Addr);
164         // Print Stack Backtrace
165         Error_Backtrace(Regs->eip, Regs->ebp);
166         
167         Log("gaPageDir[0x%x] = 0x%x", Addr>>22, gaPageDir[Addr>>22]);
168         if( gaPageDir[Addr>>22] & PF_PRESENT )
169                 Log("gaPageTable[0x%x] = 0x%x", Addr>>12, gaPageTable[Addr>>12]);
170         
171         MM_DumpTables(0, -1);   
172         
173         Panic("Page Fault at 0x%x\n", Regs->eip);
174 }
175
176 /**
177  * \fn void MM_DumpTables(tVAddr Start, tVAddr End)
178  * \brief Dumps the layout of the page tables
179  */
180 void MM_DumpTables(tVAddr Start, tVAddr End)
181 {
182         tVAddr  rangeStart = 0;
183         tPAddr  expected = 0;
184         tVAddr  curPos;
185         Uint    page;
186         const tPAddr    MASK = ~0xF98;
187         
188         Start >>= 12;   End >>= 12;
189         
190         #if 0
191         Log("Directory Entries:");
192         for(page = Start >> 10;
193                 page < (End >> 10)+1;
194                 page ++)
195         {
196                 if(gaPageDir[page])
197                 {
198                         Log(" 0x%08x-0x%08x :: 0x%08x",
199                                 page<<22, ((page+1)<<22)-1,
200                                 gaPageDir[page]&~0xFFF
201                                 );
202                 }
203         }
204         #endif
205         
206         Log("Table Entries:");
207         for(page = Start, curPos = Start<<12;
208                 page < End;
209                 curPos += 0x1000, page++)
210         {
211                 if( !(gaPageDir[curPos>>22] & PF_PRESENT)
212                 ||  !(gaPageTable[page] & PF_PRESENT)
213                 ||  (gaPageTable[page] & MASK) != expected)
214                 {
215                         if(expected) {
216                                 Log(" 0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)",
217                                         rangeStart, curPos - 1,
218                                         gaPageTable[rangeStart>>12] & ~0xFFF,
219                                         (expected & ~0xFFF) - 1,
220                                         (expected & PF_PAGED ? "p" : "-"),
221                                         (expected & PF_COW ? "C" : "-"),
222                                         (expected & PF_USER ? "U" : "-"),
223                                         (expected & PF_WRITE ? "W" : "-")
224                                         );
225                                 expected = 0;
226                         }
227                         if( !(gaPageDir[curPos>>22] & PF_PRESENT) )     continue;
228                         if( !(gaPageTable[curPos>>12] & PF_PRESENT) )   continue;
229                         
230                         expected = (gaPageTable[page] & MASK);
231                         rangeStart = curPos;
232                 }
233                 if(expected)    expected += 0x1000;
234         }
235         
236         if(expected) {
237                 Log("0x%08x-0x%08x => 0x%08x-0x%08x (%s%s%s%s)",
238                         rangeStart, curPos - 1,
239                         gaPageTable[rangeStart>>12] & ~0xFFF,
240                         (expected & ~0xFFF) - 1,
241                         (expected & PF_PAGED ? "p" : "-"),
242                         (expected & PF_COW ? "C" : "-"),
243                         (expected & PF_USER ? "U" : "-"),
244                         (expected & PF_WRITE ? "W" : "-")
245                         );
246                 expected = 0;
247         }
248 }
249
250 /**
251  * \fn tPAddr MM_Allocate(Uint VAddr)
252  */
253 tPAddr MM_Allocate(Uint VAddr)
254 {
255         tPAddr  paddr;
256         // Check if the directory is mapped
257         if( gaPageDir[ VAddr >> 22 ] == 0 )
258         {
259                 // Allocate directory
260                 paddr = MM_AllocPhys();
261                 if( paddr == 0 ) {
262                         Warning("MM_Allocate - Out of Memory (Called by %p)", __builtin_return_address(0));
263                         return 0;
264                 }
265                 // Map
266                 gaPageDir[ VAddr >> 22 ] = paddr | 3;
267                 // Mark as user
268                 if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
269                 
270                 INVLPG( &gaPageDir[ VAddr >> 22 ] );
271                 memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
272         }
273         // Check if the page is already allocated
274         else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
275                 Warning("MM_Allocate - Allocating to used address (%p)", VAddr);
276                 return gaPageTable[ VAddr >> 12 ] & ~0xFFF;
277         }
278         
279         // Allocate
280         paddr = MM_AllocPhys();
281         if( paddr == 0 ) {
282                 Warning("MM_Allocate - Out of Memory when allocating at %p (Called by %p)",
283                         VAddr, __builtin_return_address(0));
284                 return 0;
285         }
286         // Map
287         gaPageTable[ VAddr >> 12 ] = paddr | 3;
288         // Mark as user
289         if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
290         // Invalidate Cache for address
291         INVLPG( VAddr & ~0xFFF );
292         
293         return paddr;
294 }
295
296 /**
297  * \fn void MM_Deallocate(Uint VAddr)
298  */
299 void MM_Deallocate(Uint VAddr)
300 {
301         if( gaPageDir[ VAddr >> 22 ] == 0 ) {
302                 Warning("MM_Deallocate - Directory not mapped");
303                 return;
304         }
305         
306         if(gaPageTable[ VAddr >> 12 ] == 0) {
307                 Warning("MM_Deallocate - Page is not allocated");
308                 return;
309         }
310         
311         // Dereference page
312         MM_DerefPhys( gaPageTable[ VAddr >> 12 ] & ~0xFFF );
313         // Clear page
314         gaPageTable[ VAddr >> 12 ] = 0;
315 }
316
317 /**
318  * \fn tPAddr MM_GetPhysAddr(Uint Addr)
319  * \brief Checks if the passed address is accesable
320  */
321 tPAddr MM_GetPhysAddr(Uint Addr)
322 {
323         if( !(gaPageDir[Addr >> 22] & 1) )
324                 return 0;
325         if( !(gaPageTable[Addr >> 12] & 1) )
326                 return 0;
327         return (gaPageTable[Addr >> 12] & ~0xFFF) | (Addr & 0xFFF);
328 }
329
330 /**
331  * \fn void MM_SetCR3(Uint CR3)
332  * \brief Sets the current process space
333  */
334 void MM_SetCR3(Uint CR3)
335 {
336         __asm__ __volatile__ ("mov %0, %%cr3"::"r"(CR3));
337 }
338
339 /**
340  * \fn int MM_Map(Uint VAddr, tPAddr PAddr)
341  * \brief Map a physical page to a virtual one
342  */
343 int MM_Map(Uint VAddr, tPAddr PAddr)
344 {
345         //ENTER("xVAddr xPAddr", VAddr, PAddr);
346         // Sanity check
347         if( PAddr & 0xFFF || VAddr & 0xFFF ) {
348                 Warning("MM_Map - Physical or Virtual Addresses are not aligned");
349                 //LEAVE('i', 0);
350                 return 0;
351         }
352         
353         // Align addresses
354         PAddr &= ~0xFFF;        VAddr &= ~0xFFF;
355         
356         // Check if the directory is mapped
357         if( gaPageDir[ VAddr >> 22 ] == 0 )
358         {
359                 gaPageDir[ VAddr >> 22 ] = MM_AllocPhys() | 3;
360                 
361                 // Mark as user
362                 if(VAddr < MM_USER_MAX) gaPageDir[ VAddr >> 22 ] |= PF_USER;
363                 
364                 INVLPG( &gaPageTable[ (VAddr >> 12) & ~0x3FF ] );
365                 memsetd( &gaPageTable[ (VAddr >> 12) & ~0x3FF ], 0, 1024 );
366         }
367         // Check if the page is already allocated
368         else if( gaPageTable[ VAddr >> 12 ] != 0 ) {
369                 Warning("MM_Map - Allocating to used address");
370                 //LEAVE('i', 0);
371                 return 0;
372         }
373         
374         // Map
375         gaPageTable[ VAddr >> 12 ] = PAddr | 3;
376         // Mark as user
377         if(VAddr < MM_USER_MAX) gaPageTable[ VAddr >> 12 ] |= PF_USER;
378         
379         //LOG("gaPageTable[ 0x%x ] = (Uint)%p = 0x%x",
380         //      VAddr >> 12, &gaPageTable[ VAddr >> 12 ], gaPageTable[ VAddr >> 12 ]);
381         
382         // Reference
383         MM_RefPhys( PAddr );
384         
385         //LOG("INVLPG( 0x%x )", VAddr);
386         INVLPG( VAddr );
387         
388         //LEAVE('i', 1);
389         return 1;
390 }
391
392 /**
393  * \fn Uint MM_ClearUser()
394  * \brief Clear user's address space
395  */
396 Uint MM_ClearUser()
397 {
398         Uint    i, j;
399         
400         // Copy Directories
401         for( i = 0; i < (MM_USER_MAX>>22); i ++ )
402         {
403                 // Check if directory is not allocated
404                 if( !(gaPageDir[i] & PF_PRESENT) ) {
405                         gaPageDir[i] = 0;
406                         continue;
407                 }
408                 
409                 
410                 for( j = 0; j < 1024; j ++ )
411                 {
412                         if( gaPageTable[i*1024+j] & 1 )
413                                 MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF );
414                         gaPageTable[i*1024+j] = 0;
415                 }
416                 
417                 MM_DerefPhys( gaPageDir[i] & ~0xFFF );
418                 gaPageDir[i] = 0;
419                 INVLPG( &gaPageTable[i*1024] );
420         }
421         INVLPG( gaPageDir );
422         
423         return *gaPageCR3;
424 }
425
426 /**
427  * \fn Uint MM_Clone()
428  * \brief Clone the current address space
429  */
430 Uint MM_Clone()
431 {
432         Uint    i, j;
433         Uint    ret;
434         Uint    page = 0;
435         Uint    kStackBase = Proc_GetCurThread()->KernelStack - KERNEL_STACK_SIZE;
436         void    *tmp;
437         
438         LOCK( &gilTempFractal );
439         
440         // Create Directory Table
441         *gTmpCR3 = MM_AllocPhys() | 3;
442         INVLPG( gaTmpDir );
443         //LOG("Allocated Directory (%x)", *gTmpCR3);
444         memsetd( gaTmpDir, 0, 1024 );
445         
446         // Copy Tables
447         for(i=0;i<768;i++)
448         {
449                 // Check if table is allocated
450                 if( !(gaPageDir[i] & PF_PRESENT) ) {
451                         gaTmpDir[i] = 0;
452                         page += 1024;
453                         continue;
454                 }
455                 
456                 // Allocate new table
457                 gaTmpDir[i] = MM_AllocPhys() | (gaPageDir[i] & 7);
458                 INVLPG( &gaTmpTable[page] );
459                 // Fill
460                 for( j = 0; j < 1024; j ++, page++ )
461                 {
462                         if( !(gaPageTable[page] & PF_PRESENT) ) {
463                                 gaTmpTable[page] = 0;
464                                 continue;
465                         }
466                         
467                         // Refrence old page
468                         MM_RefPhys( gaPageTable[page] & ~0xFFF );
469                         // Add to new table
470                         if(gaPageTable[page] & PF_WRITE) {
471                                 gaTmpTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
472                                 gaPageTable[page] = (gaPageTable[page] & ~PF_WRITE) | PF_COW;
473                                 INVLPG( page << 12 );
474                         }
475                         else
476                                 gaTmpTable[page] = gaPageTable[page];
477                 }
478         }
479         
480         // Map in kernel tables (and make fractal mapping)
481         for( i = 768; i < 1024; i ++ )
482         {
483                 // Fractal
484                 if( i == (PAGE_TABLE_ADDR >> 22) ) {
485                         gaTmpDir[ PAGE_TABLE_ADDR >> 22 ] = *gTmpCR3;
486                         continue;
487                 }
488                 
489                 if( gaPageDir[i] == 0 ) {
490                         gaTmpDir[i] = 0;
491                         continue;
492                 }
493                 
494                 //LOG("gaPageDir[%x/4] = 0x%x", i*4, gaPageDir[i]);
495                 MM_RefPhys( gaPageDir[i] & ~0xFFF );
496                 gaTmpDir[i] = gaPageDir[i];
497         }
498         
499         // Allocate kernel stack
500         for(i = KERNEL_STACKS >> 22;
501                 i < KERNEL_STACKS_END >> 22;
502                 i ++ )
503         {
504                 // Check if directory is allocated
505                 if( (gaPageDir[i] & 1) == 0 ) {
506                         gaTmpDir[i] = 0;
507                         continue;
508                 }               
509                 
510                 // We don't care about other kernel stacks, just the current one
511                 if( i != kStackBase >> 22 ) {
512                         MM_DerefPhys( gaPageDir[i] & ~0xFFF );
513                         gaTmpDir[i] = 0;
514                         continue;
515                 }
516                 
517                 // Create a copy
518                 gaTmpDir[i] = MM_AllocPhys() | 3;
519                 INVLPG( &gaTmpTable[i*1024] );
520                 for( j = 0; j < 1024; j ++ )
521                 {
522                         // Is the page allocated? If not, skip
523                         if( !(gaPageTable[i*1024+j] & 1) ) {
524                                 gaTmpTable[i*1024+j] = 0;
525                                 continue;
526                         }
527                         
528                         // We don't care about other kernel stacks
529                         if( ((i*1024+j)*4096 & ~(KERNEL_STACK_SIZE-1)) != kStackBase ) {
530                                 gaTmpTable[i*1024+j] = 0;
531                                 continue;
532                         }
533                         
534                         // Allocate page
535                         gaTmpTable[i*1024+j] = MM_AllocPhys() | 3;
536                         
537                         MM_RefPhys( gaTmpTable[i*1024+j] & ~0xFFF );
538                         
539                         tmp = (void *) MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
540                         memcpy( tmp, (void *)( (i*1024+j)*0x1000 ), 0x1000 );
541                         MM_FreeTemp( (Uint)tmp );
542                 }
543         }
544         
545         ret = *gTmpCR3 & ~0xFFF;
546         RELEASE( &gilTempFractal );
547         
548         //LEAVE('x', ret);
549         return ret;
550 }
551
552 /**
553  * \fn Uint MM_NewKStack()
554  * \brief Create a new kernel stack
555  */
556 Uint MM_NewKStack()
557 {
558         Uint    base = KERNEL_STACKS;
559         Uint    i;
560         for(;base<KERNEL_STACKS_END;base+=KERNEL_STACK_SIZE)
561         {
562                 if(MM_GetPhysAddr(base) != 0)   continue;
563                 for(i=0;i<KERNEL_STACK_SIZE;i+=0x1000) {
564                         MM_Allocate(base+i);
565                 }
566                 return base+KERNEL_STACK_SIZE;
567         }
568         Warning("MM_NewKStack - No address space left\n");
569         return 0;
570 }
571
572 /**
573  * \fn Uint MM_NewWorkerStack()
574  * \brief Creates a new worker stack
575  */
576 Uint MM_NewWorkerStack()
577 {
578         Uint    esp, ebp;
579         Uint    oldstack;
580         Uint    base, addr;
581          int    i, j;
582         Uint    *tmpPage;
583         tPAddr  pages[WORKER_STACK_SIZE>>12];
584         
585         // Get the old ESP and EBP
586         __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp));
587         __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp));
588         
589         // Find a free worker stack address
590         for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++)
591         {
592                 // Used block
593                 if( gWorkerStacks[base/32] == -1 ) {
594                         base += 31;     base &= ~31;
595                         base --;        // Counteracted by the base++
596                         continue;
597                 }
598                 // Used stack
599                 if( gWorkerStacks[base/32] & (1 << base) ) {
600                         continue;
601                 }
602         }
603         if(base >= NUM_WORKER_STACKS) {
604                 Warning("Uh-oh! Out of worker stacks");
605                 return 0;
606         }
607         
608         // It's ours now!
609         gWorkerStacks[base/32] |= (1 << base);
610         // Make life easier for later calls
611         giLastUsedWorker = base;
612         // We have one
613         base = WORKER_STACKS + base * WORKER_STACK_SIZE;
614         
615         // Acquire the lock for the temp fractal mappings
616         LOCK(&gilTempFractal);
617         
618         // Set the temp fractals to TID0's address space
619         *gTmpCR3 = (Uint)gaInitPageDir | 3;
620         INVLPG( gaTmpDir );
621         
622         // Check if the directory is mapped (we are assuming that the stacks
623         // will fit neatly in a directory
624         if(gaTmpDir[ base >> 22 ] == 0) {
625                 gaTmpDir[ base >> 22 ] = MM_AllocPhys() | 3;
626                 INVLPG( &gaTmpTable[ (base>>22) & ~0x3FF ] );
627         }
628         
629         // Mapping Time!
630         for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 )
631         {
632                 pages[ addr >> 12 ] = MM_AllocPhys();
633                 gaTmpTable[ (base + addr) >> 12 ] = pages[addr>>12] | 3;
634         }
635         // Release the temp mapping lock
636         RELEASE(&gilTempFractal);
637         
638         // Copy the old stack
639         oldstack = (esp + KERNEL_STACK_SIZE-1) & ~(KERNEL_STACK_SIZE-1);
640         esp = oldstack - esp;   // ESP as an offset in the stack
641         
642         i = (WORKER_STACK_SIZE>>12) - 1;
643         // Copy the contents of the old stack to the new one, altering the addresses
644         // `addr` is refering to bytes from the stack base (mem downwards)
645         for(addr = 0; addr < esp; addr += 0x1000)
646         {
647                 Uint    *stack = (Uint*)( oldstack-(addr+0x1000) );
648                 tmpPage = (void*)MM_MapTemp( pages[i] );
649                 // Copy old stack
650                 for(j = 0; j < 1024; j++)
651                 {
652                         // Possible Stack address?
653                         if(oldstack-esp < stack[j] && stack[j] < oldstack)
654                                 tmpPage[j] = base - (oldstack - stack[j]);
655                         else    // Seems not, best leave it alone
656                                 tmpPage[j] = stack[j];
657                 }
658                 MM_FreeTemp((Uint)tmpPage);
659                 i --;
660         }
661         
662         return base;
663 }
664
665 /**
666  * \fn void MM_SetFlags(Uint VAddr, Uint Flags, Uint Mask)
667  * \brief Sets the flags on a page
668  */
669 void MM_SetFlags(Uint VAddr, Uint Flags, Uint Mask)
670 {
671         tPAddr  *ent;
672         if( !(gaPageDir[VAddr >> 22] & 1) )     return ;
673         if( !(gaPageTable[VAddr >> 12] & 1) )   return ;
674         
675         ent = &gaPageTable[VAddr >> 12];
676         
677         // Read-Only
678         if( Mask & MM_PFLAG_RO )
679         {
680                 if( Flags & MM_PFLAG_RO )       *ent &= ~PF_WRITE;
681                 else    *ent |= PF_WRITE;
682         }
683         
684         // Kernel
685         if( Mask & MM_PFLAG_KERNEL )
686         {
687                 if( Flags & MM_PFLAG_KERNEL )   *ent &= ~PF_USER;
688                 else    *ent |= PF_USER;
689         }
690         
691         // Copy-On-Write
692         if( Mask & MM_PFLAG_COW )
693         {
694                 if( Flags & MM_PFLAG_COW ) {
695                         *ent &= ~PF_WRITE;
696                         *ent |= PF_COW;
697                 }
698                 else {
699                         *ent &= ~PF_COW;
700                         *ent |= PF_WRITE;
701                 }
702         }
703 }
704
705 /**
706  * \fn tPAddr MM_DuplicatePage(Uint VAddr)
707  * \brief Duplicates a virtual page to a physical one
708  */
709 tPAddr MM_DuplicatePage(Uint VAddr)
710 {
711         tPAddr  ret;
712         Uint    temp;
713          int    wasRO = 0;
714         
715         // Check if mapped
716         if( !(gaPageDir  [VAddr >> 22] & PF_PRESENT) )  return 0;
717         if( !(gaPageTable[VAddr >> 12] & PF_PRESENT) )  return 0;
718         
719         // Page Align
720         VAddr &= ~0xFFF;
721         
722         // Allocate new page
723         ret = MM_AllocPhys();
724         
725         // Write-lock the page (to keep data constistent), saving its R/W state
726         wasRO = (gaPageTable[VAddr >> 12] & PF_WRITE ? 0 : 1);
727         gaPageTable[VAddr >> 12] &= ~PF_WRITE;
728         INVLPG( VAddr );
729         
730         // Copy Data
731         temp = MM_MapTemp(ret);
732         memcpy( (void*)temp, (void*)VAddr, 0x1000 );
733         MM_FreeTemp(temp);
734         
735         // Restore Writeable status
736         if(!wasRO)      gaPageTable[VAddr >> 12] |= PF_WRITE;
737         INVLPG(VAddr);
738         
739         return ret;
740 }
741
742 /**
743  * \fn Uint MM_MapTemp(tPAddr PAddr)
744  * \brief Create a temporary memory mapping
745  * \todo Show Luigi Barone (C Lecturer) and see what he thinks
746  */
747 Uint MM_MapTemp(tPAddr PAddr)
748 {
749          int    i;
750         
751         //ENTER("XPAddr", PAddr);
752         
753         PAddr &= ~0xFFF;
754         
755         //LOG("gilTempMappings = %i", gilTempMappings);
756         
757         for(;;)
758         {
759                 LOCK( &gilTempMappings );
760                 
761                 for( i = 0; i < NUM_TEMP_PAGES; i ++ )
762                 {
763                         // Check if page used
764                         if(gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] & 1)        continue;
765                         // Mark as used
766                         gaPageTable[ (TEMP_MAP_ADDR >> 12) + i ] = PAddr | 3;
767                         INVLPG( TEMP_MAP_ADDR + (i << 12) );
768                         //LEAVE('p', TEMP_MAP_ADDR + (i << 12));
769                         RELEASE( &gilTempMappings );
770                         return TEMP_MAP_ADDR + (i << 12);
771                 }
772                 RELEASE( &gilTempMappings );
773                 Threads_Yield();
774         }
775 }
776
777 /**
778  * \fn void MM_FreeTemp(Uint PAddr)
779  * \brief Free's a temp mapping
780  */
781 void MM_FreeTemp(Uint VAddr)
782 {
783          int    i = VAddr >> 12;
784         //ENTER("xVAddr", VAddr);
785         
786         if(i >= (TEMP_MAP_ADDR >> 12))
787                 gaPageTable[ i ] = 0;
788         
789         //LEAVE('-');
790 }
791
792 /**
793  * \fn Uint MM_MapHWPage(tPAddr PAddr, Uint Number)
794  * \brief Allocates a contigous number of pages
795  */
796 Uint MM_MapHWPage(tPAddr PAddr, Uint Number)
797 {
798          int    i, j;
799         
800         PAddr &= ~0xFFF;
801         
802         // Scan List
803         for( i = 0; i < NUM_HW_PAGES; i ++ )
804         {               
805                 // Check if addr used
806                 if( gaPageTable[ (HW_MAP_ADDR >> 12) + i ] & 1 )
807                         continue;
808                 
809                 // Check possible region
810                 for( j = 0; j < Number && i + j < NUM_HW_PAGES; j ++ )
811                 {
812                         // If there is an allocated page in the region we are testing, break
813                         if( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] & 1 )    break;
814                 }
815                 // Is it all free?
816                 if( j == Number )
817                 {
818                         // Allocate
819                         for( j = 0; j < Number; j++ ) {
820                                 MM_RefPhys( PAddr + (j<<12) );
821                                 gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = (PAddr + (j<<12)) | 3;
822                         }
823                         return HW_MAP_ADDR + (i<<12);
824                 }
825         }
826         // If we don't find any, return NULL
827         return 0;
828 }
829
830 /**
831  * \fn void MM_UnmapHWPage(Uint VAddr, Uint Number)
832  * \brief Unmap a hardware page
833  */
834 void MM_UnmapHWPage(Uint VAddr, Uint Number)
835 {
836          int    i, j;
837         // Sanity Check
838         if(VAddr < HW_MAP_ADDR || VAddr-Number*0x1000 > HW_MAP_MAX)     return;
839         
840         i = VAddr >> 12;
841         
842         LOCK( &gilTempMappings );       // Temp and HW share a directory, so they share a lock
843         
844         for( j = 0; j < Number; j++ )
845         {
846                 MM_DerefPhys( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] );
847                 gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = 0;
848         }
849         
850         RELEASE( &gilTempMappings );
851 }
852
853 // --- EXPORTS ---
854 EXPORT(MM_GetPhysAddr);
855 EXPORT(MM_Map);
856 //EXPORT(MM_Unmap);
857 EXPORT(MM_MapHWPage);
858 EXPORT(MM_UnmapHWPage);

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