+ * \fn tVAddr MM_NewWorkerStack()
+ * \brief Creates a new worker stack
+ */
+tVAddr MM_NewWorkerStack(Uint *StackContents, size_t ContentsSize)
+{
+ Uint base, addr;
+ tVAddr tmpPage;
+ tPAddr page;
+
+ // TODO: Thread safety
+ // Find a free worker stack address
+ for(base = giLastUsedWorker; base < NUM_WORKER_STACKS; base++)
+ {
+ // Used block
+ if( gWorkerStacks[base/32] == -1 ) {
+ base += 31; base &= ~31;
+ base --; // Counteracted by the base++
+ continue;
+ }
+ // Used stack
+ if( gWorkerStacks[base/32] & (1 << base) ) {
+ continue;
+ }
+ break;
+ }
+ if(base >= NUM_WORKER_STACKS) {
+ Warning("Uh-oh! Out of worker stacks");
+ return 0;
+ }
+
+ // It's ours now!
+ gWorkerStacks[base/32] |= (1 << base);
+ // Make life easier for later calls
+ giLastUsedWorker = base;
+ // We have one
+ base = WORKER_STACKS + base * WORKER_STACK_SIZE;
+ //Log(" MM_NewWorkerStack: base = 0x%x", base);
+
+ // Acquire the lock for the temp fractal mappings
+ Mutex_Acquire(&glTempFractal);
+
+ // Set the temp fractals to TID0's address space
+ *gpTmpCR3 = ((Uint)gaInitPageDir - KERNEL_BASE) | 3;
+ //Log(" MM_NewWorkerStack: *gpTmpCR3 = 0x%x", *gpTmpCR3);
+ INVLPG( gaTmpDir );
+
+
+ // Check if the directory is mapped (we are assuming that the stacks
+ // will fit neatly in a directory)
+ //Log(" MM_NewWorkerStack: gaTmpDir[ 0x%x ] = 0x%x", base>>22, gaTmpDir[ base >> 22 ]);
+ if(gaTmpDir[ base >> 22 ] == 0) {
+ gaTmpDir[ base >> 22 ] = MM_AllocPhys() | 3;
+ INVLPG( &gaTmpTable[ (base>>12) & ~0x3FF ] );
+ }
+
+ // Mapping Time!
+ for( addr = 0; addr < WORKER_STACK_SIZE; addr += 0x1000 )
+ {
+ page = MM_AllocPhys();
+ gaTmpTable[ (base + addr) >> 12 ] = page | 3;
+ }
+ *gpTmpCR3 = 0;
+ // Release the temp mapping lock
+ Mutex_Release(&glTempFractal);
+
+ // NOTE: Max of 1 page
+ // `page` is the last allocated page from the previious for loop
+ tmpPage = MM_MapTemp( page );
+ memcpy( (void*)( tmpPage + (0x1000 - ContentsSize) ), StackContents, ContentsSize);
+ MM_FreeTemp(tmpPage);
+
+ //Log("MM_NewWorkerStack: RETURN 0x%x", base);
+ return base + WORKER_STACK_SIZE;
+}
+
+/**
+ * \fn void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)