Merge branch 'master' of git://git.ucc.asn.au/tpg/acess2
[tpg/acess2.git] / KernelLand / Kernel / arch / x86 / proc.c
index 82a3f40..d3aea16 100644 (file)
@@ -18,6 +18,7 @@
 #define DEBUG_TRACE_SWITCH     0
 #define DEBUG_DISABLE_DOUBLEFAULT      1
 #define DEBUG_VERY_SLOW_PERIOD 0
+#define DEBUG_NOPREEMPT        1
 
 // === CONSTANTS ===
 // Base is 1193182
@@ -35,6 +36,7 @@ typedef struct sCPU
        Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
        Uint16  Resvd;
        tThread *Current;
+       tThread *LastTimerThread;       // Used to do preeemption
 }      tCPU;
 
 // === IMPORTS ===
@@ -402,21 +404,42 @@ void MP_StartAP(int CPU)
        *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
        outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Set warm reset flag
        MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);   // Init IPI
-       
-       // Delay
-       inb(0x80); inb(0x80); inb(0x80); inb(0x80);
-       
+
+       // Take a quick nap (20ms)
+       Time_Delay(20);
+
        // TODO: Use a better address, preferably registered with the MM
        // - MM_AllocDMA mabye?
        // Create a far jump
        *(Uint8*)(KERNEL_BASE|0x11000) = 0xEA;  // Far JMP
-       *(Uint16*)(KERNEL_BASE|0x11001) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0);     // IP
+       *(Uint16*)(KERNEL_BASE|0x11001) = (Uint16)&APStartup + 0x10;    // IP
        *(Uint16*)(KERNEL_BASE|0x11003) = 0xFFFF;       // CS
+       
+       giNumInitingCPUs ++;
+       
        // Send a Startup-IPI to make the CPU execute at 0x11000 (which we
        // just filled)
        MP_SendIPI(gaCPUs[CPU].APICID, 0x11, 6);        // StartupIPI
        
-       giNumInitingCPUs ++;
+       tTime   timeout = now() + 2;
+       while( giNumInitingCPUs && now() > timeout )
+               HALT();
+       
+       if( giNumInitingCPUs == 0 )
+               return ;
+       
+       // First S-IPI failed, send again
+       MP_SendIPI(gaCPUs[CPU].APICID, 0x11, 6);
+       timeout = now() + 2;
+       while( giNumInitingCPUs && now() > timeout )
+               HALT();
+       if( giNumInitingCPUs == 0 )
+               return ;
+
+       Log_Notice("Proc", "CPU %i (APIC %x) didn't come up", CPU, gaCPUs[CPU].APICID); 
+
+       // Oh dammit.
+       giNumInitingCPUs = 0;
 }
 
 void MP_SendIPIVector(int CPU, Uint8 Vector)
@@ -437,11 +460,9 @@ void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
        
        // Hi
        val = (Uint)APICID << 24;
-//     Log("%p = 0x%08x", &gpMP_LocalAPIC->ICR[1], val);
        gpMP_LocalAPIC->ICR[1].Val = val;
        // Low (and send)
        val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
-//     Log("%p = 0x%08x", &gpMP_LocalAPIC->ICR[0], val);
        gpMP_LocalAPIC->ICR[0].Val = val;
 }
 #endif
@@ -465,37 +486,29 @@ void Proc_IdleThread(void *Ptr)
  */
 void Proc_Start(void)
 {
-        int    tid;
        #if USE_MP
-        int    i;
-       #endif
+       // BSP still should run the current task
+       gaCPUs[giProc_BootProcessorID].Current = &gThreadZero;
+       
+       __asm__ __volatile__ ("sti");
        
-       #if USE_MP
        // Start APs
-       for( i = 0; i < giNumCPUs; i ++ )
+       for( int i = 0; i < giNumCPUs; i ++ )
        {
-               if(i)   gaCPUs[i].Current = NULL;
-               
+               if(i != giProc_BootProcessorID)
+                       gaCPUs[i].Current = NULL;
+
                // Create Idle Task
-               tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
+               Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
                
                // 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_Debug("Proc", "Waiting for APs to come up");
-       __asm__ __volatile__ ("sti");
-       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
        #else
        // Create Idle Task
-       tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
-//     gaCPUs[0].IdleThread = Threads_GetThread(tid);
+       Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
        
        // Set current task
        gaCPUs[0].Current = &gThreadZero;
@@ -586,9 +599,8 @@ void Proc_ClearThread(tThread *Thread)
 tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
 {
        Uint    esp;
-       tThread *newThread, *cur;
+       tThread *newThread;
        
-       cur = Proc_GetCurThread();
        newThread = Threads_CloneTCB(0);
        if(!newThread)  return -1;
        
@@ -664,7 +676,7 @@ tPID Proc_Clone(Uint Flags)
  * \fn int Proc_SpawnWorker(void)
  * \brief Spawns a new worker thread
  */
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
 {
        tThread *new;
        Uint    stack_contents[4];
@@ -673,7 +685,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        new = Threads_CloneThreadZero();
        if(!new) {
                Warning("Proc_SpawnWorker - Out of heap space!\n");
-               return -1;
+               return NULL;
        }
 
        // Create the stack contents
@@ -695,7 +707,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
        new->Status = THREAD_STAT_PREINIT;
        Threads_AddActive( new );
        
-       return new->TID;
+       return new;
 }
 
 /**
@@ -709,7 +721,7 @@ Uint Proc_MakeUserStack(void)
        
        // Check Prospective Space
        for( i = USER_STACK_SZ >> 12; i--; )
-               if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+               if( MM_GetPhysAddr( (void*)(base + (i<<12)) ) != 0 )
                        break;
        
        if(i != -1)     return 0;
@@ -861,6 +873,10 @@ void Proc_DumpThreadCPUState(tThread *Thread)
                __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
                while( maxBacktraceDistance -- )
                {
+                       if( !CheckMem(stack, 8) ) {
+                               regs = NULL;
+                               break;
+                       }
                        // [ebp] = oldEbp
                        // [ebp+4] = retaddr
                        
@@ -939,6 +955,7 @@ void Proc_Reschedule(void)
 
        // Update CPU state
        gaCPUs[cpu].Current = nextthread;
+       gaCPUs[cpu].LastTimerThread = NULL;
        gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
        __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
 
@@ -976,49 +993,26 @@ void Proc_Reschedule(void)
  */
 void Proc_Scheduler(int CPU)
 {
-#if 0
-       tThread *thread;
-       
-       // If the spinlock is set, let it complete
-       if(IS_LOCKED(&glThreadListLock))        return;
-       
-       // Get current thread
-       thread = gaCPUs[CPU].Current;
-       
-       if( thread )
-       {
-               tRegs   *regs;
-               Uint    ebp;
-               // Reduce remaining quantum and continue timeslice if non-zero
-               if( thread->Remaining-- )
-                       return;
-               // Reset quantum for next call
-               thread->Remaining = thread->Quantum;
-               
-               // TODO: Make this more stable somehow
-               __asm__ __volatile__("mov %%ebp, %0" : "=r" (ebp));
-               regs = (tRegs*)(ebp+(2+2)*4);   // EBP,Ret + CPU,CurThread
-               thread->SavedState.UserCS = regs->cs;
-               thread->SavedState.UserEIP = regs->eip;
-               
-               if(thread->bInstrTrace) {
-                       regs->eflags |= 0x100;  // Set TF
-                       Log("%p De-scheduled", thread);
-               }
-               else
-                       regs->eflags &= ~0x100; // Clear TF
-       }
-
-       // TODO: Ack timer?
        #if USE_MP
        if( GetCPUNum() )
                gpMP_LocalAPIC->EOI.Val = 0;
        else
        #endif
                outb(0x20, 0x20);
-       __asm__ __volatile__ ("sti");
-       Proc_Reschedule();
-#endif
+       __asm__ __volatile__ ("sti");   
+
+       // Call the timer update code
+       Timer_CallTimers();
+
+       #if !DEBUG_NOPREEMPT
+       // If two ticks happen within the same task, and it's not an idle task, swap
+       if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread )
+       {
+               Proc_Reschedule();
+       }
+       
+       gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current;
+       #endif
 }
 
 // === EXPORTS ===

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