Bugfixed MP scheduling code in MP build
[tpg/acess2.git] / Kernel / arch / x86 / proc.c
index 065e6de..bee311a 100644 (file)
@@ -3,6 +3,7 @@
  * proc.c
  */
 #include <acess.h>
+#include <threads.h>
 #include <proc.h>
 #include <desctab.h>
 #include <mm_virt.h>
@@ -17,7 +18,8 @@
 // === CONSTANTS ===
 #define        SWITCH_MAGIC    0xFFFACE55      // There is no code in this area
 // Base is 1193182
-#define TIMER_DIVISOR  11931   //~100Hz
+#define TIMER_BASE      1193182
+#define TIMER_DIVISOR   11931  //~100Hz
 
 // === TYPES ===
 #if USE_MP
@@ -27,6 +29,7 @@ typedef struct sCPU
        Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
        Uint16  Resvd;
        tThread *Current;
+       tThread *IdleThread;
 }      tCPU;
 #endif
 
@@ -48,7 +51,6 @@ extern tThread        gThreadZero;
 extern tThread *gActiveThreads;
 extern tThread *gSleepingThreads;
 extern tThread *gDeleteThreads;
-extern tThread *Threads_GetNextToRun(int CPU);
 extern void    Threads_Dump(void);
 extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
 extern void    Isr8(void);     // Double Fault
@@ -73,7 +75,7 @@ void  Proc_Scheduler(int CPU);
 #if USE_MP
 volatile int   giNumInitingCPUs = 0;
 tMPInfo        *gMPFloatPtr = NULL;
-Uint32 giMP_TimerCount;        // Start Count for Local APIC Timer
+volatile Uint32        giMP_TimerCount;        // Start Count for Local APIC Timer
 tAPIC  *gpMP_LocalAPIC = NULL;
 Uint8  gaAPIC_to_CPU[256] = {0};
 tCPU   gaCPUs[MAX_CPUS];
@@ -88,13 +90,13 @@ Uint32      *gPML4s[4] = NULL;
 tTSS   *gTSSs = NULL;  // Pointer to TSS array
 tTSS   gTSS0 = {0};
 // --- Error Recovery ---
-char   gaDoubleFaultStack[1024];
+char   gaDoubleFaultStack[1024] __attribute__ ((section(".padata")));
 tTSS   gDoubleFault_TSS = {
-       .ESP0 = (Uint)&gaDoubleFaultStack[1023],
+       .ESP0 = (Uint)&gaDoubleFaultStack[1024],
        .SS0 = 0x10,
        .CR3 = (Uint)gaInitPageDir - KERNEL_BASE,
        .EIP = (Uint)Isr8,
-       .ESP = (Uint)&gaDoubleFaultStack[1023],
+       .ESP = (Uint)&gaDoubleFaultStack[1024],
        .CS = 0x08,     .SS = 0x10,
        .DS = 0x10,     .ES = 0x10,
        .FS = 0x10,     .GS = 0x10,
@@ -228,6 +230,8 @@ void ArchThreads_Init(void)
                                }
                                
                                break;
+                       
+                       #if DUMP_MP_TABLES
                        case 1: // Bus
                                entSize = 8;
                                Log("%i: Bus", i);
@@ -265,6 +269,7 @@ void ArchThreads_Init(void)
                        default:
                                Log("%i: Unknown (%i)", i, ents->Type);
                                break;
+                       #endif
                        }
                        ents = (void*)( (Uint)ents + entSize );
                }
@@ -286,6 +291,7 @@ void ArchThreads_Init(void)
        MM_FinishVirtualInit();
        #endif
        
+       #if 0
        // Initialise Double Fault TSS
        gGDT[5].BaseLow = (Uint)&gDoubleFault_TSS & 0xFFFF;
        gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16;
@@ -296,19 +302,34 @@ void ArchThreads_Init(void)
        gIDT[8].CS = 5<<3;
        gIDT[8].Flags = 0x8500;
        gIDT[8].OffsetHi = 0;
+       #endif
        
        // 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
+       
+       #if USE_MP
        // Get the count setting for APIC timer
        Log("Determining APIC Count");
        __asm__ __volatile__ ("sti");
        while( giMP_TimerCount == 0 )   __asm__ __volatile__ ("hlt");
        __asm__ __volatile__ ("cli");
-       Log("APIC Count %i\n", giMP_TimerCount);
+       Log("APIC Count %i", giMP_TimerCount);
+       {
+               Uint64  freq = giMP_TimerCount;
+               freq /= TIMER_DIVISOR;
+               freq *= TIMER_BASE;
+               if( (freq /= 1000) < 2*1000)
+                       Log("Bus Frequency %i KHz", freq);
+               else if( (freq /= 1000) < 2*1000)
+                       Log("Bus Frequency %i MHz", freq);
+               else if( (freq /= 1000) < 2*1000)
+                       Log("Bus Frequency %i GHz", freq);
+               else
+                       Log("Bus Frequency %i THz", freq);
+       }
        
-       #if USE_MP
        // Initialise Normal TSS(s)
        for(pos=0;pos<giNumCPUs;pos++)
        {
@@ -322,20 +343,6 @@ void ArchThreads_Init(void)
                gGDT[6+pos].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
        #if USE_MP
        }
-       
-       // Start APs
-       for( pos = 0; pos < giNumCPUs; pos ++ )
-       {
-               gaCPUs[pos].Current = NULL;
-               if( pos != giProc_BootProcessorID ) {
-                       MP_StartAP( pos );
-               }
-       }
-       
-       Log("Waiting for APs to come up\n");
-       while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
-       MM_FinishVirtualInit();
-       //Panic("Uh oh... MP Table Parsing is unimplemented\n");
        #endif
        
        // Load the BSP's TSS
@@ -346,6 +353,7 @@ void ArchThreads_Init(void)
        #else
        gCurrentThread = &gThreadZero;
        #endif
+       gThreadZero.CurCPU = 0;
        
        #if USE_PAE
        gThreadZero.MemState.PDP[0] = 0;
@@ -416,8 +424,56 @@ void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
  */
 void Proc_Start(void)
 {
+       #if USE_MP
+        int    i;
+       #endif
+       
+       #if USE_MP
+       // Start APs
+       for( i = 0; i < giNumCPUs; i ++ )
+       {
+               // Create Idle Task
+               if(Proc_Clone(0, 0) == 0)
+               {
+                       gaCPUs[i].IdleThread = Proc_GetCurThread();
+                       gaCPUs[i].IdleThread->ThreadName = "Idle Thread";
+                       gaCPUs[i].IdleThread->NumTickets = 0;   // Never called randomly
+                       gaCPUs[i].IdleThread->Quantum = 1;      // 1 slice quantum
+                       for(;;) HALT(); // Just yeilds
+               }
+               gaCPUs[i].Current = NULL;
+               
+               // 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");
+       MM_FinishVirtualInit();
+       #else
+       // Create Idle Task
+       if(Proc_Clone(0, 0) == 0)
+       {
+               tThread *cur = Proc_GetCurThread();
+               cur->ThreadName = "Idle Thread";
+               Threads_SetTickets(0);  // Never called randomly
+               cur->Quantum = 1;       // 1 slice quantum
+               for(;;) HALT(); // Just yeilds
+       }
+       
+       // Set current task
+       gCurrentThread = &gThreadZero;
+       
        // Start Interrupts (and hence scheduler)
        __asm__ __volatile__("sti");
+       #endif
 }
 
 /**
@@ -543,6 +599,7 @@ int Proc_Clone(Uint *Err, Uint Flags)
        eip = GetEIP();
        if(eip == SWITCH_MAGIC) {
                outb(0x20, 0x20);       // ACK Timer and return as child
+               __asm__ __volatile__ ("sti");   // Restart interrupts
                return 0;
        }
        
@@ -781,7 +838,15 @@ void Proc_Scheduler(int CPU)
        
        // Check if there is any tasks running
        if(giNumActiveThreads == 0) {
+               #if 0
                Log("No Active threads, sleeping");
+               #endif
+               #if USE_MP
+               if(CPU)
+                       gpMP_LocalAPIC->EOI.Val = 0;
+               else
+               #endif
+                       outb(0x20, 0x20);
                __asm__ __volatile__ ("hlt");
                return;
        }
@@ -793,29 +858,33 @@ void Proc_Scheduler(int CPU)
        thread = gCurrentThread;
        #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 %%esp, %0":"=r"(esp));
-       __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
-       eip = GetEIP();
-       if(eip == SWITCH_MAGIC) return; // Check if a switch happened
-       
-       // Save machine state
-       thread->SavedState.ESP = esp;
-       thread->SavedState.EBP = ebp;
-       thread->SavedState.EIP = eip;
+       if( thread )
+       {
+               // 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 %%esp, %0":"=r"(esp));
+               __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
+               eip = GetEIP();
+               if(eip == SWITCH_MAGIC) return; // Check if a switch happened
+               
+               // Save machine state
+               thread->SavedState.ESP = esp;
+               thread->SavedState.EBP = ebp;
+               thread->SavedState.EIP = eip;
+       }
        
-       // Get next thread
-       thread = Threads_GetNextToRun(CPU);
+       // Get next thread to run
+       thread = Threads_GetNextToRun(CPU, thread);
        
-       // Error Check
+       // No avaliable tasks, just go into low power mode
        if(thread == NULL) {
-               Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
-               return;
+               //HALT();
+               //return;
+               thread = gaCPUs[CPU].IdleThread;
        }
        
        #if DEBUG_TRACE_SWITCH

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