X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fproc.c;h=bfd0e8f7b38c79e68fd2971ea7600d91c025734f;hb=de2ae10743172075f2d527780bdfd890ccddb8e7;hp=d510b98238e7e9eb4c2dc279b7f995940987c8d8;hpb=586a47ab9343a85c944a2cf7b27a74cf459a8423;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c index d510b982..bfd0e8f7 100644 --- a/Kernel/arch/x86/proc.c +++ b/Kernel/arch/x86/proc.c @@ -3,6 +3,7 @@ * proc.c */ #include +#include #include #include #include @@ -15,10 +16,10 @@ #define DEBUG_TRACE_SWITCH 0 // === CONSTANTS === -#define SWITCH_MAGIC 0xFFFACE55 // There is no code in this area +#define SWITCH_MAGIC 0xFF5317C8 // FF SWITCH - There is no code in this area // Base is 1193182 #define TIMER_BASE 1193182 -#define TIMER_DIVISOR 11931 //~100Hz +#define TIMER_DIVISOR 11932 //~100Hz // === TYPES === #if USE_MP @@ -28,6 +29,7 @@ typedef struct sCPU Uint8 State; // 0: Unavaliable, 1: Idle, 2: Active Uint16 Resvd; tThread *Current; + tThread *IdleThread; } tCPU; #endif @@ -39,21 +41,14 @@ extern void APStartup(void); // 16-bit AP startup code extern Uint GetEIP(void); // start.asm extern int GetCPUNum(void); // start.asm extern Uint32 gaInitPageDir[1024]; // start.asm -extern void Kernel_Stack_Top; -extern tSpinlock glThreadListLock; +extern char Kernel_Stack_Top[]; +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(void); extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags); extern void Isr8(void); // Double Fault -extern void Proc_ReturnToUser(void); +extern void Proc_ReturnToUser(tVAddr Handler, Uint Argument); // === PROTOTYPES === void ArchThreads_Init(void); @@ -82,6 +77,7 @@ tTSS gaTSSs[MAX_CPUS]; // TSS Array int giProc_BootProcessorID = 0; #else tThread *gCurrentThread = NULL; +tThread *gpIdleThread = NULL; #endif #if USE_PAE Uint32 *gPML4s[4] = NULL; @@ -308,6 +304,11 @@ void ArchThreads_Init(void) outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor outb(0x40, (TIMER_DIVISOR>>8)&0xFF); // High Byte + Log("Timer Frequency %i.%03i Hz", + TIMER_BASE/TIMER_DIVISOR, + ((Uint64)TIMER_BASE*1000/TIMER_DIVISOR)%1000 + ); + #if USE_MP // Get the count setting for APIC timer Log("Determining APIC Count"); @@ -338,7 +339,7 @@ void ArchThreads_Init(void) gTSSs[pos].SS0 = 0x10; gTSSs[pos].ESP0 = 0; // Set properly by scheduler gGDT[6+pos].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF; - gGDT[6+pos].BaseMid = ((Uint)(&gTSSs[pos])) >> 16; + gGDT[6+pos].BaseMid = ((Uint)(&gTSSs[pos]) >> 16) & 0xFFFF; gGDT[6+pos].BaseHi = ((Uint)(&gTSSs[pos])) >> 24; #if USE_MP } @@ -346,13 +347,16 @@ void ArchThreads_Init(void) // Load the BSP's TSS __asm__ __volatile__ ("ltr %%ax"::"a"(0x30)); + // Set Current Thread and CPU Number in DR0 and DR1 + __asm__ __volatile__ ("mov %0, %%db0"::"r"(&gThreadZero)); + __asm__ __volatile__ ("mov %0, %%db1"::"r"(0)); #if USE_MP gaCPUs[0].Current = &gThreadZero; #else gCurrentThread = &gThreadZero; #endif - gThreadZero.bIsRunning = 1; + gThreadZero.CurCPU = 0; #if USE_PAE gThreadZero.MemState.PDP[0] = 0; @@ -377,7 +381,7 @@ void MP_StartAP(int CPU) // Set location of AP startup code and mark for a warm restart *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APWait - (KERNEL_BASE|0xFFFF0); *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF; - outb(0x70, 0x0F); outb(0x71, 0x0A); // Warm Reset + outb(0x70, 0x0F); outb(0x71, 0x0A); // Set warm reset flag MP_SendIPI(gaCPUs[CPU].APICID, 0, 5); // Init IPI // Delay @@ -427,24 +431,55 @@ void Proc_Start(void) int i; #endif - // Start Interrupts (and hence scheduler) - __asm__ __volatile__("sti"); - #if USE_MP // Start APs for( i = 0; i < giNumCPUs; i ++ ) { - gaCPUs[i].Current = NULL; + 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"); + __asm__ __volatile__ ("sti"); while( giNumInitingCPUs ) __asm__ __volatile__ ("hlt"); - MM_FinishVirtualInit(); + #else + // Create Idle Task + if(Proc_Clone(0, 0) == 0) + { + gpIdleThread = Proc_GetCurThread(); + gpIdleThread->ThreadName = "Idle Thread"; + gpIdleThread->NumTickets = 0; // Never called randomly + gpIdleThread->Quantum = 1; // 1 slice quantum + for(;;) HALT(); // Just yeilds + } + + // Set current task + gCurrentThread = &gThreadZero; + + // Start Interrupts (and hence scheduler) + __asm__ __volatile__("sti"); #endif + MM_FinishVirtualInit(); } /** @@ -454,7 +489,6 @@ void Proc_Start(void) 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; @@ -569,7 +603,14 @@ int Proc_Clone(Uint *Err, Uint Flags) newThread->SavedState.EBP = ebp; eip = GetEIP(); if(eip == SWITCH_MAGIC) { - outb(0x20, 0x20); // ACK Timer and return as child + __asm__ __volatile__ ("mov %0, %%db0" : : "r" (newThread) ); + #if USE_MP + // ACK the interrupt + if(GetCPUNum()) + gpMP_LocalAPIC->EOI.Val = 0; + else + #endif + outb(0x20, 0x20); // ACK Timer and return as child __asm__ __volatile__ ("sti"); // Restart interrupts return 0; } @@ -604,7 +645,7 @@ int Proc_SpawnWorker(void) // Set Thread ID new->TID = giNextTID++; // Create a new worker stack (in PID0's address space) - // The stack is relocated by this code + // - The stack is relocated by this function new->KernelStack = MM_NewWorkerStack(); // Get ESP and EBP based in the new stack @@ -618,7 +659,15 @@ int Proc_SpawnWorker(void) new->SavedState.EBP = ebp; eip = GetEIP(); if(eip == SWITCH_MAGIC) { - outb(0x20, 0x20); // ACK Timer and return as child + __asm__ __volatile__ ("mov %0, %%db0" : : "r"(new)); + #if USE_MP + // ACK the interrupt + if(GetCPUNum()) + gpMP_LocalAPIC->EOI.Val = 0; + else + #endif + outb(0x20, 0x20); // ACK Timer and return as child + __asm__ __volatile__ ("sti"); // Restart interrupts return 0; } @@ -780,7 +829,7 @@ void Proc_CallFaultHandler(tThread *Thread) { // Rewinds the stack and calls the user function // Never returns - __asm__ __volatile__ ("mov %0, %%ebp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler)); + Proc_ReturnToUser( Thread->FaultHandler, Thread->CurFaultNum ); for(;;); } @@ -796,32 +845,6 @@ void Proc_Scheduler(int CPU) // 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) { - #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; - } - // Get current thread #if USE_MP thread = gaCPUs[CPU].Current; @@ -829,31 +852,46 @@ 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 (idle thread) if(thread == NULL) { - Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n"); - return; + #if USE_MP + thread = gaCPUs[CPU].IdleThread; + Log("CPU %i Running Idle Thread", CPU); + #else + thread = gpIdleThread; + #endif } + // Set current thread + #if USE_MP + gaCPUs[CPU].Current = thread; + #else + gCurrentThread = thread; + #endif + #if DEBUG_TRACE_SWITCH Log("Switching to task %i, CR3 = 0x%x, EIP = %p", thread->TID, @@ -862,17 +900,10 @@ void Proc_Scheduler(int CPU) ); #endif - // Set current thread - #if USE_MP - gaCPUs[CPU].Current->bIsRunning = 0; - gaCPUs[CPU].Current = thread; - thread->bIsRunning = 1; - #else - gCurrentThread = thread; + #if USE_MP // MP Debug + Log("CPU = %i, Thread %p", CPU, thread); #endif - //Log("CPU = %i", CPU); - // Update Kernel Stack pointer gTSSs[CPU].ESP0 = thread->KernelStack-4; @@ -880,7 +911,7 @@ void Proc_Scheduler(int CPU) #if USE_PAE # error "Todo: Implement PAE Address space switching" #else - __asm__ __volatile__ ("mov %0, %%cr3"::"a"(thread->MemState.CR3)); + __asm__ __volatile__ ("mov %0, %%cr3" : : "a" (thread->MemState.CR3)); #endif #if 0