Fiddling with the x86_64 port
[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 PML4_SHIFT      39
13 #define PDP_SHIFT       30
14 #define PDIR_SHIFT      21
15 #define PTAB_SHIFT      12
16
17 #define PADDR_MASK      0x7FFFFFFF##FFFFF000
18 #define PAGE_MASK       (((Uint)1 << 36)-1)
19 #define TABLE_MASK      (((Uint)1 << 27)-1)
20 #define PDP_MASK        (((Uint)1 << 18)-1)
21 #define PML4_MASK       (((Uint)1 << 9)-1)
22
23 #define PF_PRESENT      0x1
24 #define PF_WRITE        0x2
25 #define PF_USER         0x4
26 #define PF_LARGE        0x0
27 #define PF_COW          0x200
28 #define PF_PAGED        0x400
29 #define PF_NX           0x80000000##00000000
30
31 // === MACROS ===
32 #define PAGETABLE(idx)  (*((tPAddr*)MM_FRACTAL_BASE+((idx)&PAGE_MASK)))
33 #define PAGEDIR(idx)    PAGETABLE((MM_FRACTAL_BASE>>12)+((idx)&TABLE_MASK))
34 #define PAGEDIRPTR(idx) PAGEDIR((MM_FRACTAL_BASE>>21)+((idx)&PDP_MASK))
35 #define PAGEMAPLVL4(idx)        PAGEDIRPTR((MM_FRACTAL_BASE>>30)+((idx)&PML4_MASK))
36
37 #define INVLPG(__addr)  __asm__ __volatile__ ("invlpg (%0)"::"r"(__addr));
38
39 // === PROTOTYPES ===
40 void    MM_InitVirt(void);
41 //void  MM_FinishVirtualInit(void);
42 void    MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs);
43 void    MM_DumpTables(tVAddr Start, tVAddr End);
44 // int  MM_Map(tVAddr VAddr, tPAddr PAddr);
45 void    MM_Unmap(tVAddr VAddr);
46 void    MM_ClearUser(void);
47  int    MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags);
48
49 // === GLOBALS ===
50
51 // === CODE ===
52 void MM_InitVirt(void)
53 {
54         MM_DumpTables(0, -1L);
55 }
56
57 void MM_FinishVirtualInit(void)
58 {
59 }
60
61 /**
62  * \brief Called on a page fault
63  */
64 void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs)
65 {
66         // TODO: Copy on Write
67         #if 0
68         if( gaPageDir  [Addr>>22] & PF_PRESENT
69          && gaPageTable[Addr>>12] & PF_PRESENT
70          && gaPageTable[Addr>>12] & PF_COW )
71         {
72                 tPAddr  paddr;
73                 if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1)
74                 {
75                         gaPageTable[Addr>>12] &= ~PF_COW;
76                         gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE;
77                 }
78                 else
79                 {
80                         //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr);
81                         paddr = MM_DuplicatePage( Addr );
82                         MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF );
83                         gaPageTable[Addr>>12] &= PF_USER;
84                         gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE;
85                 }
86                 
87                 INVLPG( Addr & ~0xFFF );
88                 return;
89         }
90         #endif
91         
92         // If it was a user, tell the thread handler
93         if(ErrorCode & 4) {
94                 Warning("%s %s %s memory%s",
95                         (ErrorCode&4?"User":"Kernel"),
96                         (ErrorCode&2?"write to":"read from"),
97                         (ErrorCode&1?"bad/locked":"non-present"),
98                         (ErrorCode&16?" (Instruction Fetch)":"")
99                         );
100                 Warning("User Pagefault: Instruction at %04x:%08x accessed %p",
101                         Regs->CS, Regs->RIP, Addr);
102                 __asm__ __volatile__ ("sti");   // Restart IRQs
103 //              Threads_SegFault(Addr);
104                 return ;
105         }
106         
107         // Kernel #PF
108         Debug_KernelPanic();
109         // -- Check Error Code --
110         if(ErrorCode & 8)
111                 Warning("Reserved Bits Trashed!");
112         else
113         {
114                 Warning("%s %s %s memory%s",
115                         (ErrorCode&4?"User":"Kernel"),
116                         (ErrorCode&2?"write to":"read from"),
117                         (ErrorCode&1?"bad/locked":"non-present"),
118                         (ErrorCode&16?" (Instruction Fetch)":"")
119                         );
120         }
121         
122         Log("Code at %p accessed %p", Regs->RIP, Addr);
123         // Print Stack Backtrace
124 //      Error_Backtrace(Regs->RIP, Regs->RBP);
125         
126         MM_DumpTables(0, -1);
127         
128         __asm__ __volatile__ ("cli");
129         for( ;; )
130                 HALT();
131 }
132
133 /**
134  * \brief Dumps the layout of the page tables
135  */
136 void MM_DumpTables(tVAddr Start, tVAddr End)
137 {
138         const tPAddr    CHANGEABLE_BITS = 0xFF8;
139         const tPAddr    MASK = ~CHANGEABLE_BITS;        // Physical address and access bits
140         tVAddr  rangeStart = 0;
141         tPAddr  expected = CHANGEABLE_BITS;     // MASK is used because it's not a vaild value
142         tVAddr  curPos;
143         Uint    page;
144         
145         Log("Table Entries: (%p to %p)", Start, End);
146         
147         End &= (1L << 48) - 1;
148         
149         Start >>= 12;   End >>= 12;
150         
151         for(page = Start, curPos = Start<<12;
152                 page < End;
153                 curPos += 0x1000, page++)
154         {
155                 if( curPos == 0x800000000000L )
156                         curPos = 0xFFFF800000000000L;
157                 
158                 //Debug("&PAGEMAPLVL4(%i page>>27) = %p", page>>27, &PAGEMAPLVL4(page>>27));
159                 //Debug("&PAGEDIRPTR(%i page>>18) = %p", page>>18, &PAGEDIRPTR(page>>18));
160                 //Debug("&PAGEDIR(%i page>>9) = %p", page>>9, &PAGEDIR(page>>9));
161                 //Debug("&PAGETABLE(%i page) = %p", page, &PAGETABLE(page));
162                 
163                 // End of a range
164                 if(
165                         !(PAGEMAPLVL4(page>>27) & PF_PRESENT)
166                 ||      !(PAGEDIRPTR(page>>18) & PF_PRESENT)
167                 ||      !(PAGEDIR(page>>9) & PF_PRESENT)
168                 ||  !(PAGETABLE(page) & PF_PRESENT)
169                 ||  (PAGETABLE(page) & MASK) != expected)
170                 {                       
171                         if(expected != CHANGEABLE_BITS) {
172                                 Log("%016x-0x%016x => %013x-%013x (%c%c%c%c)",
173                                         rangeStart, curPos - 1,
174                                         PAGETABLE(rangeStart>>12) & ~0xFFF,
175                                         (expected & ~0xFFF) - 1,
176                                         (expected & PF_PAGED ? 'p' : '-'),
177                                         (expected & PF_COW ? 'C' : '-'),
178                                         (expected & PF_USER ? 'U' : '-'),
179                                         (expected & PF_WRITE ? 'W' : '-')
180                                         );
181                                 expected = CHANGEABLE_BITS;
182                         }
183                         if( !(PAGEMAPLVL4(page>>27) & PF_PRESENT) ) {
184                                 page += (1 << 27) - 1;
185                                 curPos += (1L << 39) - 0x1000;
186                                 //Debug("pml4 ent unset (page = 0x%x now)", page);
187                                 continue;
188                         }
189                         if( !(PAGEDIRPTR(page>>18) & PF_PRESENT) ) {
190                                 page += (1 << 18) - 1;
191                                 curPos += (1L << 30) - 0x1000;
192                                 //Debug("pdp ent unset (page = 0x%x now)", page);
193                                 continue;
194                         }
195                         if( !(PAGEDIR(page>>9) & PF_PRESENT) ) {
196                                 page += (1 << 9) - 1;
197                                 curPos += (1L << 21) - 0x1000;
198                                 //Debug("pd ent unset (page = 0x%x now)", page);
199                                 continue;
200                         }
201                         if( !(PAGETABLE(page) & PF_PRESENT) )   continue;
202                         
203                         expected = (PAGETABLE(page) & MASK);
204                         rangeStart = curPos;
205                 }
206                 if(expected != CHANGEABLE_BITS)
207                         expected += 0x1000;
208         }
209         
210         if(expected != CHANGEABLE_BITS) {
211                 Log("%016x-%016x => %013x-%013x (%s%s%s%s)",
212                         rangeStart, curPos - 1,
213                         PAGETABLE(rangeStart>>12) & ~0xFFF,
214                         (expected & ~0xFFF) - 1,
215                         (expected & PF_PAGED ? "p" : "-"),
216                         (expected & PF_COW ? "C" : "-"),
217                         (expected & PF_USER ? "U" : "-"),
218                         (expected & PF_WRITE ? "W" : "-")
219                         );
220                 expected = 0;
221         }
222 }
223
224 /**
225  * \brief Map a physical page to a virtual one
226  */
227 int MM_Map(tVAddr VAddr, tPAddr PAddr)
228 {
229         tPAddr  tmp;
230         
231         ENTER("xVAddr xPAddr", VAddr, PAddr);
232         
233         // Check that the page hasn't been mapped already
234         {
235                 Uint    flags;
236                  int    ret;
237                 ret = MM_GetPageEntry(VAddr, &tmp, &flags);
238                 if( flags & PF_PRESENT ) {
239                         LEAVE('i', 0);
240                         return 0;
241                 }
242         }
243         
244         // Check PML4
245         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
246         {
247                 tmp = MM_AllocPhys();
248                 if(!tmp) {
249                         LEAVE('i', 0);
250                         return 0;
251                 }
252                 PAGEMAPLVL4(VAddr >> 39) = tmp | 3;
253                 INVLPG( &PAGEDIRPTR( (VAddr>>39)<<9 ) );
254                 memset( &PAGEDIRPTR( (VAddr>>39)<<9 ), 0, 4096 );
255         }
256         
257         // Check PDP
258         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
259         {
260                 tmp = MM_AllocPhys();
261                 if(!tmp) {
262                         LEAVE('i', 0);
263                         return 0;
264                 }
265                 PAGEDIRPTR(VAddr >> 30) = tmp | 3;
266                 INVLPG( &PAGEDIR( (VAddr>>30)<<9 ) );
267                 memset( &PAGEDIR( (VAddr>>30)<<9 ), 0, 0x1000 );
268         }
269         
270         // Check Page Dir
271         if( !(PAGEDIR(VAddr >> 21) & 1) )
272         {
273                 tmp = MM_AllocPhys();
274                 if(!tmp) {
275                         LEAVE('i', 0);
276                         return 0;
277                 }
278                 PAGEDIR(VAddr >> 21) = tmp | 3;
279                 INVLPG( &PAGETABLE( (VAddr>>21)<<9 ) );
280                 memset( &PAGETABLE( (VAddr>>21)<<9 ), 0, 4096 );
281         }
282         
283         // Check if this virtual address is already mapped
284         if( PAGETABLE(VAddr >> PTAB_SHIFT) & 1 ) {
285                 LEAVE('i', 0);
286                 return 0;
287         }
288         
289         PAGETABLE(VAddr >> PTAB_SHIFT) = PAddr | 3;
290         
291         INVLPG( VAddr );
292
293         LEAVE('i', 1);  
294         return 1;
295 }
296
297 /**
298  * \brief Removed a mapped page
299  */
300 void MM_Unmap(tVAddr VAddr)
301 {
302         // Check PML4
303         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )   return ;
304         // Check PDP
305         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )    return ;
306         // Check Page Dir
307         if( !(PAGEDIR(VAddr >> 21) & 1) )       return ;
308         
309         PAGETABLE(VAddr >> PTAB_SHIFT) = 0;
310         INVLPG( VAddr );
311 }
312
313 /**
314  * \brief Allocate a block of memory at the specified virtual address
315  */
316 tPAddr MM_Allocate(tVAddr VAddr)
317 {
318         tPAddr  ret;
319         
320         ENTER("xVAddr", VAddr);
321         
322         // NOTE: This is hack, but I like my dumps to be neat
323         #if 1
324         if( !MM_Map(VAddr, 0) ) // Make sure things are allocated
325         {
326                 Warning("MM_Allocate: Unable to map, tables did not initialise");
327                 LEAVE('i', 0);
328                 return 0;
329         }
330         MM_Unmap(VAddr);
331         #endif
332         
333         ret = MM_AllocPhys();
334         LOG("ret = %x", ret);
335         if(!ret) {
336                 LEAVE('i', 0);
337                 return 0;
338         }
339         
340         if( !MM_Map(VAddr, ret) )
341         {
342                 Warning("MM_Allocate: Unable to map. Strange, we should have errored earlier");
343                 MM_DerefPhys(ret);
344                 LEAVE('i');
345                 return 0;
346         }
347         
348         LEAVE('x', ret);
349         return ret;
350 }
351
352 void MM_Deallocate(tVAddr VAddr)
353 {
354         tPAddr  phys;
355         
356         phys = MM_GetPhysAddr(VAddr);
357         if(!phys)       return ;
358         
359         MM_Unmap(VAddr);
360         
361         MM_DerefPhys(phys);
362 }
363
364 /**
365  * \brief Get the page table entry of a virtual address
366  * \param Addr  Virtual Address
367  * \param Phys  Location to put the physical address
368  * \param Flags Flags on the entry (set to zero if unmapped)
369  * \return Size of the entry (in address bits) - 12 = 4KiB page
370  */
371 int MM_GetPageEntry(tVAddr Addr, tPAddr *Phys, Uint *Flags)
372 {
373         if(!Phys || !Flags)     return 0;
374         
375         // Check if the PML4 entry is present
376         if( !(PAGEMAPLVL4(Addr >> 39) & 1) ) {
377                 *Phys = 0;
378                 *Flags = 0;
379                 return 39;
380         }
381         // - Check for large page
382         if( PAGEMAPLVL4(Addr >> 39) & PF_LARGE ) {
383                 *Phys = PAGEMAPLVL4(Addr >> 39) & ~0xFFF;
384                 *Flags = PAGEMAPLVL4(Addr >> 39) & 0xFFF;
385                 return 39;
386         }
387         
388         // Check the PDP entry
389         if( !(PAGEDIRPTR(Addr >> 30) & 1) ) {
390                 *Phys = 0;
391                 *Flags = 0;
392                 return 30;
393         }
394         // - Check for large page
395         if( PAGEDIRPTR(Addr >> 30) & PF_LARGE ) {
396                 *Phys = PAGEDIRPTR(Addr >> 30) & ~0xFFF;
397                 *Flags = PAGEDIRPTR(Addr >> 30) & 0xFFF;
398                 return 30;
399         }
400         
401         // Check PDIR Entry
402         if( !(PAGEDIR(Addr >> 21) & 1) ) {
403                 *Phys = 0;
404                 *Flags = 0;
405                 return 21;
406         }
407         // - Check for large page
408         if( PAGEDIR(Addr >> 21) & PF_LARGE ) {
409                 *Phys = PAGEDIR(Addr >> 21) & ~0xFFF;
410                 *Flags = PAGEDIR(Addr >> 21) & 0xFFF;
411                 return 21;
412         }
413         
414         // And, check the page table entry
415         if( !(PAGETABLE(Addr >> PTAB_SHIFT) & 1) ) {
416                 *Phys = 0;
417                 *Flags = 0;
418         }
419         else {
420                 *Phys = PAGETABLE(Addr >> PTAB_SHIFT) & ~0xFFF;
421                 *Flags = PAGETABLE(Addr >> PTAB_SHIFT) & 0xFFF;
422         }
423         return 12;
424 }
425
426 /**
427  * \brief Get the physical address of a virtual location
428  */
429 tPAddr MM_GetPhysAddr(tVAddr Addr)
430 {
431         tPAddr  ret;
432         Uint    flags;
433         
434         MM_GetPageEntry(Addr, &ret, &flags);
435         
436         return ret | (Addr & 0xFFF);
437 }
438
439 /**
440  * \brief Sets the flags on a page
441  */
442 void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
443 {
444         tPAddr  *ent;
445         
446         // Validity Check
447         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
448                 return ;
449         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
450                 return ;
451         if( !(PAGEDIR(VAddr >> 21) & 1) )
452                 return ;
453         if( !(PAGETABLE(VAddr >> 12) & 1) )
454                 return ;
455         
456         // Set Flags
457         ent = &PAGETABLE(VAddr >> 12);
458         
459         // Read-Only
460         if( Mask & MM_PFLAG_RO )
461         {
462                 if( Flags & MM_PFLAG_RO ) {
463                         *ent &= ~PF_WRITE;
464                 }
465                 else {
466                         *ent |= PF_WRITE;
467                 }
468         }
469         
470         // Kernel
471         if( Mask & MM_PFLAG_KERNEL )
472         {
473                 if( Flags & MM_PFLAG_KERNEL ) {
474                         *ent &= ~PF_USER;
475                 }
476                 else {
477                         *ent |= PF_USER;
478                 }
479         }
480         
481         // Copy-On-Write
482         if( Mask & MM_PFLAG_COW )
483         {
484                 if( Flags & MM_PFLAG_COW ) {
485                         *ent &= ~PF_WRITE;
486                         *ent |= PF_COW;
487                 }
488                 else {
489                         *ent &= ~PF_COW;
490                         *ent |= PF_WRITE;
491                 }
492         }
493         
494         // Execute
495         if( Mask & MM_PFLAG_EXEC )
496         {
497                 if( Flags & MM_PFLAG_EXEC ) {
498                         *ent &= ~PF_NX;
499                 }
500                 else {
501                         *ent |= PF_NX;
502                 }
503         }
504 }
505
506 /**
507  * \brief Get the flags applied to a page
508  */
509 Uint MM_GetFlags(tVAddr VAddr)
510 {
511         tPAddr  *ent;
512         Uint    ret = 0;
513         
514         // Validity Check
515         if( !(PAGEMAPLVL4(VAddr >> 39) & 1) )
516                 return 0;
517         if( !(PAGEDIRPTR(VAddr >> 30) & 1) )
518                 return 0;
519         if( !(PAGEDIR(VAddr >> 21) & 1) )
520                 return 0;
521         if( !(PAGETABLE(VAddr >> 12) & 1) )
522                 return 0;
523         
524         // Set Flags
525         ent = &PAGETABLE(VAddr >> 12);
526         
527         // Read-Only
528         if( !(*ent & PF_WRITE) )        ret |= MM_PFLAG_RO;
529         // Kernel
530         if( !(*ent & PF_USER) ) ret |= MM_PFLAG_KERNEL;
531         // Copy-On-Write
532         if( *ent & PF_COW )     ret |= MM_PFLAG_COW;    
533         // Execute
534         if( !(*ent & PF_NX) )   ret |= MM_PFLAG_EXEC;
535         
536         return ret;
537 }
538
539 // --- Hardware Mappings ---
540 /**
541  * \brief Map a range of hardware pages
542  */
543 tVAddr MM_MapHWPages(tPAddr PAddr, Uint Number)
544 {
545         Log_KernelPanic("MM", "TODO: Implement MM_MapHWPages");
546         return 0;
547 }
548
549 /**
550  * \brief Free a range of hardware pages
551  */
552 void MM_UnmapHWPages(tVAddr VAddr, Uint Number)
553 {
554         Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
555 }
556
557 // --- Tempory Mappings ---
558 tVAddr MM_MapTemp(tPAddr PAddr)
559 {
560         Log_KernelPanic("MM", "TODO: Implement MM_MapTemp");
561         return 0;
562 }
563
564 void MM_FreeTemp(tVAddr VAddr)
565 {
566         Log_KernelPanic("MM", "TODO: Implement MM_FreeTemp");
567         return ;
568 }
569
570
571 // --- Address Space Clone --
572 tPAddr MM_Clone(void)
573 {
574         tPAddr  ret;
575         
576         // #1 Create a copy of the PML4
577         ret = MM_AllocPhys();
578         if(!ret)        return 0;
579         
580         Log_KernelPanic("MM", "TODO: Implement MM_Clone");
581         
582         // #2 Alter the fractal pointer
583         // #3 Set Copy-On-Write to all user pages
584         // #4 Return
585         return 0;
586 }
587
588 void MM_ClearUser(void)
589 {
590         tVAddr  addr = 0;
591         // #1 Traverse the structure < 2^47, Deref'ing all pages
592         // #2 Free tables/dirs/pdps once they have been cleared
593         
594         for( addr = 0; addr < 0x800000000000; )
595         {
596                 if( PAGEMAPLVL4(addr >> PML4_SHIFT) & 1 )
597                 {
598                         if( PAGEDIRPTR(addr >> PDP_SHIFT) & 1 )
599                         {
600                                 if( PAGEDIR(addr >> PDIR_SHIFT) & 1 )
601                                 {
602                                         // Page
603                                         if( PAGETABLE(addr >> PTAB_SHIFT) & 1 ) {
604                                                 MM_DerefPhys( PAGETABLE(addr >> PTAB_SHIFT) & PADDR_MASK );
605                                                 PAGETABLE(addr >> PTAB_SHIFT) = 0;
606                                         }
607                                         addr += 1 << PTAB_SHIFT;
608                                         // Dereference the PDIR Entry
609                                         if( (addr + (1 << PTAB_SHIFT)) >> PDIR_SHIFT != (addr >> PDIR_SHIFT) ) {
610                                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PDIR_SHIFT) & PADDR_MASK );
611                                                 PAGEDIR(addr >> PDIR_SHIFT) = 0;
612                                         }
613                                 }
614                                 else {
615                                         addr += 1 << PDIR_SHIFT;
616                                         continue;
617                                 }
618                                 // Dereference the PDP Entry
619                                 if( (addr + (1 << PDIR_SHIFT)) >> PDP_SHIFT != (addr >> PDP_SHIFT) ) {
620                                         MM_DerefPhys( PAGEMAPLVL4(addr >> PDP_SHIFT) & PADDR_MASK );
621                                         PAGEDIRPTR(addr >> PDP_SHIFT) = 0;
622                                 }
623                         }
624                         else {
625                                 addr += 1 << PDP_SHIFT;
626                                 continue;
627                         }
628                         // Dereference the PML4 Entry
629                         if( (addr + (1 << PDP_SHIFT)) >> PML4_SHIFT != (addr >> PML4_SHIFT) ) {
630                                 MM_DerefPhys( PAGEMAPLVL4(addr >> PML4_SHIFT) & PADDR_MASK );
631                                 PAGEMAPLVL4(addr >> PML4_SHIFT) = 0;
632                         }
633                 }
634                 else {
635                         addr += (tVAddr)1 << PML4_SHIFT;
636                         continue;
637                 }
638         }
639 }
640
641 tVAddr MM_NewWorkerStack(void)
642 {
643         Log_KernelPanic("MM", "TODO: Implement MM_NewWorkerStack");
644         return 0;
645 }
646
647 /**
648  * \brief Allocate a new kernel stack
649  */
650 tVAddr MM_NewKStack(void)
651 {
652         tVAddr  base = MM_KSTACK_BASE;
653         Uint    i;
654         for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
655         {
656                 if(MM_GetPhysAddr(base) != 0)
657                         continue;
658                 
659                 //Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
660                 for( i = 0; i < KERNEL_STACK_SIZE; i += 0x1000)
661                 {
662                         if( !MM_Allocate(base+i) )
663                         {
664                                 Log_Warning("MM", "MM_NewKStack - Allocation failed");
665                                 for( i -= 0x1000; i; i -= 0x1000)
666                                         MM_Deallocate(base+i);
667                                 return 0;
668                         }
669                 }
670                 
671                 return base + KERNEL_STACK_SIZE;
672         }
673         Log_Warning("MM", "MM_NewKStack - No address space left\n");
674         return 0;
675 }

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