Kernel - General fixing after ARM7 changes
[tpg/acess2.git] / Kernel / arch / x86_64 / proc.c
index 5bb66af..31dd80e 100644 (file)
@@ -1,58 +1,71 @@
 /*
- * AcessOS Microkernel Version
+ * Acess2 x86_64 port
  * proc.c
  */
 #include <acess.h>
 #include <proc.h>
 #include <threads.h>
+#include <threads_int.h>
 #include <desctab.h>
 #include <mm_virt.h>
 #include <errno.h>
 #if USE_MP
 # include <mp.h>
 #endif
+#include <arch_config.h>
+#include <hal_proc.h>
 
 // === FLAGS ===
 #define DEBUG_TRACE_SWITCH     0
+//#define BREAK_ON_SWITCH      1       // Break into bochs debugger on a task switch
 
 // === CONSTANTS ===
 #define        SWITCH_MAGIC    0x55ECAFFF##FFFACE55    // There is no code in this area
-// Base is 1193182
-#define TIMER_DIVISOR  11931   //~100Hz
+
+// === TYPES ===
+typedef struct sCPU
+{
+       Uint8   APICID;
+       Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
+       Uint16  Resvd;
+       tThread *Current;
+       tThread *IdleThread;
+}      tCPU;
 
 // === IMPORTS ===
 extern tGDT    gGDT[];
-extern void APStartup();       // 16-bit AP startup code
-extern Uint    GetRIP();       // start.asm
-extern Uint64  gaInitPML4[512];        // start.asm
-extern void    Kernel_Stack_Top;
-extern tSpinlock       glThreadListLock;
+extern void    APStartup(void);        // 16-bit AP startup code
+extern Uint    GetRIP(void);   // start.asm
+extern Uint64  gInitialPML4[512];      // start.asm
+extern char    gInitialKernelStack[];
+extern tShortSpinlock  glThreadListLock;
 extern int     giNumCPUs;
 extern int     giNextTID;
 extern int     giTotalTickets;
 extern int     giNumActiveThreads;
 extern tThread gThreadZero;
-extern tThread *gActiveThreads;
-extern tThread *gSleepingThreads;
-extern tThread *gDeleteThreads;
-extern tThread *Threads_GetNextToRun(int CPU);
-extern void    Threads_Dump();
-extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
-extern void    Proc_AlterUserReturnAddr();
+extern void    Threads_Dump(void);
+extern void    Proc_ReturnToUser(void);
+extern void    Time_UpdateTimestamp(void);
 
 // === PROTOTYPES ===
-void   ArchThreads_Init();
+//void ArchThreads_Init(void);
 #if USE_MP
 void   MP_StartAP(int CPU);
 void   MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
 #endif
-void   Proc_Start();
-tThread        *Proc_GetCurThread();
-void   Proc_ChangeStack();
- int   Proc_Clone(Uint *Err, Uint Flags);
+//void Proc_Start(void);
+//tThread      *Proc_GetCurThread(void);
+void   Proc_ChangeStack(void);
+// int Proc_Clone(Uint *Err, Uint Flags);
+// int Proc_SpawnWorker(void);
+Uint   Proc_MakeUserStack(void);
+//void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
 void   Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP);
-void   Proc_CallFaultHandler(tThread *Thread);
-void   Proc_Scheduler();
+ int   Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
+//void Proc_CallFaultHandler(tThread *Thread);
+//void Proc_DumpThreadCPUState(tThread *Thread);
+void   Proc_Scheduler(int CPU);
 
 // === GLOBALS ===
 // --- Multiprocessing ---
@@ -61,10 +74,8 @@ volatile int giNumInitingCPUs = 0;
 tMPInfo        *gMPFloatPtr = NULL;
 tAPIC  *gpMP_LocalAPIC = NULL;
 Uint8  gaAPIC_to_CPU[256] = {0};
-tCPU   gaCPUs[MAX_CPUS];
-#else
-tThread        *gCurrentThread = NULL;
 #endif
+tCPU   gaCPUs[MAX_CPUS];
 tTSS   *gTSSs = NULL;
 tTSS   gTSS0 = {0};
 // --- Error Recovery ---
@@ -72,10 +83,10 @@ Uint32      gaDoubleFaultStack[1024];
 
 // === CODE ===
 /**
- * \fn void ArchThreads_Init()
+ * \fn void ArchThreads_Init(void)
  * \brief Starts the process scheduler
  */
-void ArchThreads_Init()
+void ArchThreads_Init(void)
 {
        Uint    pos = 0;
        
@@ -269,37 +280,44 @@ void ArchThreads_Init()
        pos = 0;
        #endif
                gTSSs[pos].RSP0 = 0;    // Set properly by scheduler
-               gGDT[6+pos*2].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
-               gGDT[6+pos*2].BaseMid = ((Uint)(&gTSSs[pos])) >> 16;
-               gGDT[6+pos*2].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
-               gGDT[6+pos*2+1].DWord[0] = ((Uint)(&gTSSs[pos])) >> 32;
+               gGDT[7+pos*2].LimitLow = sizeof(tTSS) & 0xFFFF;
+               gGDT[7+pos*2].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
+               gGDT[7+pos*2].BaseMid = ((Uint)(&gTSSs[pos])) >> 16;
+               gGDT[7+pos*2].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
+               gGDT[7+pos*2+1].DWord[0] = ((Uint)(&gTSSs[pos])) >> 32;
        #if USE_MP
        }
        for(pos=0;pos<giNumCPUs;pos++) {
-       #endif
-               __asm__ __volatile__ ("ltr %%ax"::"a"(0x30+pos*8));
-       #if USE_MP
+               __asm__ __volatile__ ("ltr %%ax"::"a"(0x38+pos*16));
        }
+       #else
+       __asm__ __volatile__ ("ltr %%ax"::"a"(0x38));
        #endif
        
-       #if USE_MP
+       // Set Debug registers
+       __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
+       __asm__ __volatile__ ("mov %%rax, %%db1" : : "a"(0));
+       
        gaCPUs[0].Current = &gThreadZero;
-       #else
-       gCurrentThread = &gThreadZero;
-       #endif
        
-       gThreadZero.MemState.CR3 = (Uint)gaInitPML4 - KERNEL_BASE;
+       gThreadZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
+       gThreadZero.CurCPU = 0;
        
        // Set timer frequency
        outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
-       outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
-       outb(0x40, (TIMER_DIVISOR>>8)&0xFF);    // High Byte
+       outb(0x40, PIT_TIMER_DIVISOR&0xFF);     // Low Byte of Divisor
+       outb(0x40, (PIT_TIMER_DIVISOR>>8)&0xFF);        // High Byte
        
        // Create Per-Process Data Block
-       MM_Allocate(MM_PPD_CFG);
+       if( !MM_Allocate(MM_PPD_CFG) )
+       {
+               Warning("Oh, hell, Unable to allocate PPD for Thread#0");
+       }
        
        // Change Stacks
        Proc_ChangeStack();
+       
+       Log("Multithreading initialised");
 }
 
 #if USE_MP
@@ -331,33 +349,86 @@ void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
 #endif
 
 /**
- * \fn void Proc_Start()
+ * \fn void Proc_Start(void)
  * \brief Start process scheduler
  */
-void Proc_Start()
+void Proc_Start(void)
 {
+       #if USE_MP
+        int    i;
+       #endif
+       
+       #if USE_MP
+       // Start APs
+       for( i = 0; i < giNumCPUs; i ++ )
+       {
+                int    tid;
+               if(i)   gaCPUs[i].Current = NULL;
+               
+               // Create Idle Task
+               if( (tid = Proc_Clone(0, 0)) == 0)
+               {
+                       for(;;) HALT(); // Just yeilds
+               }
+               gaCPUs[i].IdleThread = Threads_GetThread(tid);
+               gaCPUs[i].IdleThread->ThreadName = "Idle Thread";
+               Threads_SetTickets( gaCPUs[i].IdleThread, 0 );  // Never called randomly
+               gaCPUs[i].IdleThread->Quantum = 1;      // 1 slice quantum
+               
+               
+               // Start the AP
+               if( i != giProc_BootProcessorID ) {
+                       MP_StartAP( i );
+               }
+       }
+       
+       // BSP still should run the current task
+       gaCPUs[0].Current = &gThreadZero;
+       
+       // Start interrupts and wait for APs to come up
+       Log("Waiting for APs to come up\n");
+       __asm__ __volatile__ ("sti");
+       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
+       #else
+       // Create Idle Task
+       if(Proc_Clone(0) == 0)
+       {
+               gaCPUs[0].IdleThread = Proc_GetCurThread();
+               gaCPUs[0].IdleThread->ThreadName = (char*)"Idle Thread";
+               Threads_SetPriority( gaCPUs[0].IdleThread, -1 );        // Never called randomly
+               gaCPUs[0].IdleThread->Quantum = 1;      // 1 slice quantum
+               for(;;) HALT(); // Just yeilds
+       }
+       
+       // Set current task
+       gaCPUs[0].Current = &gThreadZero;
+       gaCPUs[0].Current->CurCPU = 0;
+       
        // Start Interrupts (and hence scheduler)
        __asm__ __volatile__("sti");
+       #endif
+       MM_FinishVirtualInit();
+       Log("Multithreading started");
 }
 
 /**
- * \fn tThread *Proc_GetCurThread()
+ * \fn tThread *Proc_GetCurThread(void)
  * \brief Gets the current thread
  */
-tThread *Proc_GetCurThread()
+tThread *Proc_GetCurThread(void)
 {
        #if USE_MP
-       return gaCPUs[ gaAPIC_to_CPU[gpMP_LocalAPIC->ID.Val&0xFF] ].Current;
+       return gaCPUs[ GetCPUNum() ].Current;
        #else
-       return gCurrentThread;
+       return gaCPUs[ 0 ].Current;
        #endif
 }
 
 /**
- * \fn void Proc_ChangeStack()
+ * \fn void Proc_ChangeStack(void)
  * \brief Swaps the current stack for a new one (in the proper stack reigon)
  */
-void Proc_ChangeStack()
+void Proc_ChangeStack(void)
 {
        Uint    rsp, rbp;
        Uint    tmp_rbp, old_rsp;
@@ -376,13 +447,13 @@ void Proc_ChangeStack()
                return;
        }
 
-       curBase = (Uint)&Kernel_Stack_Top;
+       curBase = (Uint)&gInitialKernelStack;
        
-       LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
+       Log("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
 
        // Get ESP as a used size
        rsp = curBase - rsp;
-       LOG("memcpy( %p, %p, 0x%x )", (void*)(newBase - rsp), (void*)(curBase - rsp), rsp );
+       Log("memcpy( %p, %p, 0x%x )", (void*)(newBase - rsp), (void*)(curBase - rsp), rsp );
        // Copy used stack
        memcpy( (void*)(newBase - rsp), (void*)(curBase - rsp), rsp );
        // Get ESP as an offset in the new stack
@@ -390,25 +461,26 @@ void Proc_ChangeStack()
        // Adjust EBP
        rbp = newBase - (curBase - rbp);
 
+       Log("Update stack");
        // Repair EBPs & Stack Addresses
        // Catches arguments also, but may trash stack-address-like values
-       for(tmp_rbp = rsp; tmp_rbp < newBase; tmp_rbp += 4)
+       for(tmp_rbp = rsp; tmp_rbp < newBase; tmp_rbp += sizeof(Uint))
        {
                if(old_rsp < *(Uint*)tmp_rbp && *(Uint*)tmp_rbp < curBase)
                        *(Uint*)tmp_rbp += newBase - curBase;
        }
        
+       Log("Applying Changes");
        Proc_GetCurThread()->KernelStack = newBase;
-       
        __asm__ __volatile__ ("mov %0, %%rsp"::"r"(rsp));
        __asm__ __volatile__ ("mov %0, %%rbp"::"r"(rbp));
 }
 
 /**
- * \fn int Proc_Clone(Uint *Err, Uint Flags)
+ * \fn int Proc_Clone(Uint Flags)
  * \brief Clone the current process
  */
-int Proc_Clone(Uint *Err, Uint Flags)
+int Proc_Clone(Uint Flags)
 {
        tThread *newThread;
        tThread *cur = Proc_GetCurThread();
@@ -417,13 +489,17 @@ int Proc_Clone(Uint *Err, Uint Flags)
        __asm__ __volatile__ ("mov %%rsp, %0": "=r"(rsp));
        __asm__ __volatile__ ("mov %%rbp, %0": "=r"(rbp));
        
-       newThread = Threads_CloneTCB(Err, Flags);
+       newThread = Threads_CloneTCB(NULL, Flags);
        if(!newThread)  return -1;
        
+       Log("Proc_Clone: newThread = %p", newThread);
+       
        // Initialise Memory Space (New Addr space or kernel stack)
        if(Flags & CLONE_VM) {
+               Log("Proc_Clone: Cloning VM");
                newThread->MemState.CR3 = MM_Clone();
                newThread->KernelStack = cur->KernelStack;
+//             MAGIC_BREAK();
        } else {
                Uint    tmp_rbp, old_rsp = rsp;
 
@@ -432,6 +508,7 @@ int Proc_Clone(Uint *Err, Uint Flags)
 
                // Create new KStack
                newThread->KernelStack = MM_NewKStack();
+               Log("Proc_Clone: newKStack = %p", newThread->KernelStack);
                // Check for errors
                if(newThread->KernelStack == 0) {
                        free(newThread);
@@ -453,7 +530,7 @@ int Proc_Clone(Uint *Err, Uint Flags)
 
                // Repair EBPs & Stack Addresses
                // Catches arguments also, but may trash stack-address-like values
-               for(tmp_rbp = rsp; tmp_rbp < newThread->KernelStack; tmp_rbp += 4)
+               for(tmp_rbp = rsp; tmp_rbp < newThread->KernelStack; tmp_rbp += sizeof(Uint))
                {
                        if(old_rsp < *(Uint*)tmp_rbp && *(Uint*)tmp_rbp < cur->KernelStack)
                                *(Uint*)tmp_rbp += newThread->KernelStack - cur->KernelStack;
@@ -466,6 +543,8 @@ int Proc_Clone(Uint *Err, Uint Flags)
        rip = GetRIP();
        if(rip == SWITCH_MAGIC) {
                outb(0x20, 0x20);       // ACK Timer and return as child
+               __asm__ __volatile__ ("sti");
+//             MAGIC_BREAK();
                return 0;
        }
        
@@ -479,10 +558,10 @@ int Proc_Clone(Uint *Err, Uint Flags)
 }
 
 /**
- * \fn int Proc_SpawnWorker()
+ * \fn int Proc_SpawnWorker(void)
  * \brief Spawns a new worker thread
  */
-int Proc_SpawnWorker()
+int Proc_SpawnWorker(void)
 {
        tThread *new, *cur;
        Uint    rip, rsp, rbp;
@@ -514,23 +593,24 @@ int Proc_SpawnWorker()
        rip = GetRIP();
        if(rip == SWITCH_MAGIC) {
                outb(0x20, 0x20);       // ACK Timer and return as child
+               __asm__ __volatile__ ("sti");
                return 0;
        }
        
        // Set EIP as parent
        new->SavedState.RIP = rip;
        // Mark as active
-       new->Status = THREAD_STAT_ACTIVE;
+       new->Status = THREAD_STAT_PREINIT;
        Threads_AddActive( new );
        
        return new->TID;
 }
 
 /**
- * \fn Uint Proc_MakeUserStack()
+ * \fn Uint Proc_MakeUserStack(void)
  * \brief Creates a new user stack
  */
-Uint Proc_MakeUserStack()
+Uint Proc_MakeUserStack(void)
 {
         int    i;
        Uint    base = USER_STACK_TOP - USER_STACK_SZ;
@@ -543,8 +623,17 @@ Uint Proc_MakeUserStack()
        if(i != -1)     return 0;
        
        // Allocate Stack - Allocate incrementally to clean up MM_Dump output
-       for( i = 0; i < USER_STACK_SZ/4069; i++ )
-               MM_Allocate( base + (i<<12) );
+       for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
+       {
+               if( !MM_Allocate( base + (i<<12) ) )
+               {
+                       // Error
+                       Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
+                       while( i -- )
+                               MM_Deallocate( base + (i<<12) );
+                       return 0;
+               }
+       }
        
        return base + USER_STACK_SZ;
 }
@@ -624,7 +713,7 @@ void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
  */
 int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
 {
-        int    cpl = Regs->cs & 3;
+        int    cpl = Regs->CS & 3;
        // Sanity Check
        if(Dest > 3 || Dest < 0) {
                *Err = -EINVAL;
@@ -638,13 +727,8 @@ int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
        }
        
        // Change the Segment Registers
-       Regs->cs = (((Dest+1)<<4) | Dest) - 8;
-       Regs->ss = ((Dest+1)<<4) | Dest;
-       // Check if the GP Segs are GDT, then change them
-       if(!(Regs->ds & 4))     Regs->ds = ((Dest+1)<<4) | Dest;
-       if(!(Regs->es & 4))     Regs->es = ((Dest+1)<<4) | Dest;
-       if(!(Regs->fs & 4))     Regs->fs = ((Dest+1)<<4) | Dest;
-       if(!(Regs->gs & 4))     Regs->gs = ((Dest+1)<<4) | Dest;
+       Regs->CS = (((Dest+1)<<4) | Dest) - 8;
+       Regs->SS = ((Dest+1)<<4) | Dest;
        
        return 0;
 }
@@ -657,10 +741,15 @@ void Proc_CallFaultHandler(tThread *Thread)
 {
        // Rewinds the stack and calls the user function
        // Never returns
-       __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_AlterUserReturnAddr" :: "r"(Thread->FaultHandler));
+       __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler));
        for(;;);
 }
 
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+       Log("  At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
+}
+
 /**
  * \fn void Proc_Scheduler(int CPU)
  * \brief Swap current thread and clears dead threads
@@ -669,99 +758,92 @@ void Proc_Scheduler(int CPU)
 {
        Uint    rsp, rbp, rip;
        tThread *thread;
+
+       if( CPU == 0 )
+               Time_UpdateTimestamp();
        
        // If the spinlock is set, let it complete
        if(IS_LOCKED(&glThreadListLock))        return;
        
-       // Clear Delete Queue
-       while(gDeleteThreads)
-       {
-               thread = gDeleteThreads->Next;
-               if(gDeleteThreads->IsLocked) {  // Only free if structure is unused
-                       gDeleteThreads->Status = THREAD_STAT_NULL;
-                       free( gDeleteThreads );
-               }
-               gDeleteThreads = thread;
-       }
-       
-       // Check if there is any tasks running
-       if(giNumActiveThreads == 0) {
-               Log("No Active threads, sleeping");
-               __asm__ __volatile__ ("hlt");
-               return;
-       }
-       
        // Get current thread
-       #if USE_MP
        thread = gaCPUs[CPU].Current;
-       #else
-       thread = gCurrentThread;
+
+       if( thread )
+       {
+               tRegs   *regs;
+               // Reduce remaining quantum and continue timeslice if non-zero
+               if(thread->Remaining--) return;
+               // Reset quantum for next call
+               thread->Remaining = thread->Quantum;
+       
+               // Get machine state
+               __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
+               __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
+               rip = GetRIP();
+               if(rip == SWITCH_MAGIC) return; // Check if a switch happened
+               
+               // Save machine state
+               thread->SavedState.RSP = rsp;
+               thread->SavedState.RBP = rbp;
+               thread->SavedState.RIP = rip;
+               
+               // TODO: Make this more stable somehow
+               regs = (tRegs*)(rbp+(2+1)*8);   // RBP,Ret + CurThread
+               thread->SavedState.UserCS = regs->CS;
+               thread->SavedState.UserRIP = regs->RIP;
+       }
+
+       #if BREAK_ON_SWITCH
+       {
+       tThread *oldthread = thread;
        #endif
-       
-       // Reduce remaining quantum and continue timeslice if non-zero
-       if(thread->Remaining--) return;
-       // Reset quantum for next call
-       thread->Remaining = thread->Quantum;
-       
-       // Get machine state
-       __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
-       __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
-       rip = GetRIP();
-       if(rip == SWITCH_MAGIC) return; // Check if a switch happened
-       
-       // Save machine state
-       thread->SavedState.RSP = rsp;
-       thread->SavedState.RBP = rbp;
-       thread->SavedState.RIP = rip;
-       
+
        // Get next thread
-       thread = Threads_GetNextToRun(CPU);
+       thread = Threads_GetNextToRun(CPU, thread);
        
        // Error Check
        if(thread == NULL) {
-               Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
-               return;
+               thread = gaCPUs[CPU].IdleThread;
+               //Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
+//             LogF("Zzzzz.\n");
+               //return;
+       }
+       if(thread == NULL ) {
+               return ;
+       }
+       #if BREAK_ON_SWITCH
+       if( thread != oldthread ) {
+               MAGIC_BREAK();
        }
+       }
+       #endif
        
        #if DEBUG_TRACE_SWITCH
-       Log("Switching to task %i, CR3 = 0x%x, RIP = %p",
+       LogF("Switching to task %i, CR3 = 0x%x, RIP = %p",
                thread->TID,
                thread->MemState.CR3,
                thread->SavedState.RIP
                );
        #endif
        
+       
+       if(CPU > MAX_CPUS)
+               LogF("CPU = %i", CPU);
        // Set current thread
-       #if USE_MP
        gaCPUs[CPU].Current = thread;
-       #else
-       gCurrentThread = thread;
-       #endif
        
        // Update Kernel Stack pointer
        gTSSs[CPU].RSP0 = thread->KernelStack-4;
        
-       // Set address space
-       #if USE_PAE
-       # error "Todo: Implement PAE Address space switching"
-       #else
-               __asm__ __volatile__ ("mov %0, %%cr3"::"a"(thread->MemState.CR3));
-       #endif
-       
-       #if 0
-       if(thread->SavedState.RSP > 0xC0000000
-       && thread->SavedState.RSP < thread->KernelStack-0x2000) {
-               Log_Warning("Proc", "Possible bad ESP %p (PID %i)", thread->SavedState.ESP);
-       }
-       #endif
-       
        // Switch threads
        __asm__ __volatile__ (
+               "mov %4, %%cr3\n\t"
                "mov %1, %%rsp\n\t"     // Restore RSP
                "mov %2, %%rbp\n\t"     // and RBP
                "jmp *%3" : :   // And return to where we saved state (Proc_Clone or Proc_Scheduler)
-               "a"(SWITCH_MAGIC), "b"(thread->SavedState.RSP),
-               "d"(thread->SavedState.RBP), "c"(thread->SavedState.RIP)
+               "a"(SWITCH_MAGIC), "r"(thread->SavedState.RSP),
+               "r"(thread->SavedState.RBP), "r"(thread->SavedState.RIP),
+               "r"(thread->MemState.CR3)
                );
        for(;;);        // Shouldn't reach here
 }

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