X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fproc.c;h=f9c5ba1fcaf4f004881c140e90bb6fc2e17050bc;hb=47e9dfd89189fc6b150bd6b20229cb047c7e0858;hp=31eb0557d8ad35e5425e608fc3d996c82cb4b317;hpb=f119d0e5b18b7286d04fc536a94e0f96e3c51714;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c index 31eb0557..f9c5ba1f 100644 --- a/Kernel/arch/x86/proc.c +++ b/Kernel/arch/x86/proc.c @@ -10,6 +10,9 @@ # include #endif +// === FLAGS === +#define DEBUG_TRACE_SWITCH 0 + // === CONSTANTS === #define SWITCH_MAGIC 0xFFFACE55 // There is no code in this area #define TIMER_DIVISOR 11931 //~100Hz @@ -24,9 +27,14 @@ 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 Isr7(); // === PROTOTYPES === void ArchThreads_Init(); @@ -38,7 +46,7 @@ void Proc_Scheduler(); // === GLOBALS === // --- Current State --- #if USE_MP -tThread **gCurrentThread = NULL; +tThread *gCurrentThread[MAX_CPUS] = {NULL}; #else tThread *gCurrentThread = NULL; #endif @@ -53,6 +61,13 @@ tTSS *gTSSs = NULL; #if !USE_MP tTSS gTSS0 = {0}; #endif +// --- Error Recovery --- +char gaDoubleFaultStack[1024]; +tTSS gDoubleFault_TSS = { + .ESP0 = (Uint)&gaDoubleFaultStack[1023], + .SS0 = 0x10, + .EIP = (Uint)Isr7 +}; // === CODE === /** @@ -99,6 +114,15 @@ void ArchThreads_Init() #if USE_MP } + // Initialise Double Fault TSS + gGDT[5].LimitLow = sizeof(tTSS); + gGDT[5].LimitHi = 0; + gGDT[5].Access = 0x89; // Type + gGDT[5].Flags = 0x4; + gGDT[5].BaseLow = (Uint)&gDoubleFault_TSS & 0xFFFF; + gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16; + gGDT[5].BaseHi = (Uint)&gDoubleFault_TSS >> 24; + // Initialise TSS for(pos=0;pos> 16; - gGDT[5+pos].BaseHi = (Uint)&gTSSs[pos] >> 24; + gGDT[6+pos].LimitLow = sizeof(tTSS); + gGDT[6+pos].LimitHi = 0; + gGDT[6+pos].Access = 0x89; // Type + gGDT[6+pos].Flags = 0x4; + gGDT[6+pos].BaseLow = (Uint)&gTSSs[pos] & 0xFFFF; + gGDT[6+pos].BaseMid = (Uint)&gTSSs[pos] >> 16; + gGDT[6+pos].BaseHi = (Uint)&gTSSs[pos] >> 24; #if USE_MP } for(pos=0;posKernelStack; + curBase = (Uint)&Kernel_Stack_Top; LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase); @@ -209,27 +254,25 @@ void Proc_ChangeStack() int Proc_Clone(Uint *Err, Uint Flags) { tThread *newThread; + tThread *cur = Proc_GetCurThread(); Uint eip, esp, ebp; __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp)); __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp)); - // Create new thread structure - newThread = malloc( sizeof(tThread) ); - if(!newThread) { - Warning("Proc_Clone - Out of memory when creating thread\n"); - *Err = -ENOMEM; - return -1; - } - // Base new thread on old - memcpy(newThread, gCurrentThread, sizeof(tThread)); + newThread = Threads_CloneTCB(Err, Flags); + if(!newThread) return -1; + // Initialise Memory Space (New Addr space or kernel stack) if(Flags & CLONE_VM) { - newThread->TGID = newThread->TID; newThread->MemState.CR3 = MM_Clone(); + newThread->KernelStack = cur->KernelStack; } else { Uint tmpEbp, oldEsp = esp; + // Set CR3 + newThread->MemState.CR3 = cur->MemState.CR3; + // Create new KStack newThread->KernelStack = MM_NewKStack(); // Check for errors @@ -239,35 +282,22 @@ int Proc_Clone(Uint *Err, Uint Flags) } // Get ESP as a used size - esp = gCurrentThread->KernelStack - esp; + esp = cur->KernelStack - esp; // Copy used stack - memcpy( (void*)(newThread->KernelStack - esp), (void*)(gCurrentThread->KernelStack - esp), esp ); + memcpy( (void*)(newThread->KernelStack - esp), (void*)(cur->KernelStack - esp), esp ); // Get ESP as an offset in the new stack esp = newThread->KernelStack - esp; // Adjust EBP - ebp = newThread->KernelStack - (gCurrentThread->KernelStack - ebp); + ebp = newThread->KernelStack - (cur->KernelStack - ebp); // Repair EBPs & Stack Addresses // Catches arguments also, but may trash stack-address-like values for(tmpEbp = esp; tmpEbp < newThread->KernelStack; tmpEbp += 4) { - if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < gCurrentThread->KernelStack) - *(Uint*)tmpEbp += newThread->KernelStack - gCurrentThread->KernelStack; + if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < cur->KernelStack) + *(Uint*)tmpEbp += newThread->KernelStack - cur->KernelStack; } } - - // Set Pointer, Spinlock and TID - newThread->Next = NULL; - newThread->IsLocked = 0; - newThread->TID = giNextTID++; - newThread->PTID = gCurrentThread->TID; - - // Clear message list (messages are not inherited) - newThread->Messages = NULL; - newThread->LastMessage = NULL; - - // Set remaining (sheduler expects remaining to be correct) - newThread->Remaining = newThread->Quantum; // Save core machine state newThread->SavedState.ESP = esp; @@ -282,68 +312,55 @@ int Proc_Clone(Uint *Err, Uint Flags) newThread->SavedState.EIP = eip; // Lock list and add to active - LOCK( &giThreadListLock ); - newThread->Next = gActiveThreads; - gActiveThreads = newThread; - giNumActiveThreads ++; - giTotalTickets += newThread->NumTickets; - RELEASE( &giThreadListLock ); + Threads_AddActive(newThread); return newThread->TID; } -#if 0 /** - * \fn void Proc_SetSignalHandler(int Num, void *Handler) - * \brief Sets the signal handler for a signal + * \fn int Proc_SpawnWorker() + * \brief Spawns a new worker thread */ -void Proc_SetSignalHandler(int Num, void *Handler) +int Proc_SpawnWorker() { - if(Num < 0 || Num >= NSIG) return; - - gCurrentThread->SignalHandlers[Num] = Handler; -} - -/** - * \fn void Proc_SendSignal(int TID, int Num) - */ -void Proc_SendSignal(int TID, int Num) -{ - tThread *thread = Proc_GetThread(TID); - void *handler; - - if(!thread) return ; + tThread *new, *cur; + Uint eip, esp, ebp; - handler = thread->SignalHandlers[Num]; + cur = Proc_GetCurThread(); - // Panic? - if(handler == SIG_ERR) { - Proc_Kill(TID); - return ; - } - // Dump Core? - if(handler == -2) { - Proc_Kill(TID); - return ; + // Create new thread + new = malloc( sizeof(tThread) ); + if(!new) { + Warning("Proc_SpawnWorker - Out of heap space!\n"); + return -1; } - // Ignore? - if(handler == -2) return; - - // Check the type and handle if the thread is already in a signal - if(thread->CurSignal != 0) { - if(Num < _SIGTYPE_FATAL) - Proc_Kill(TID); - } else { - while(thread->CurSignal != 0) - Proc_Yield(); - } + memcpy(new, &gThreadZero, sizeof(tThread)); + // Set Thread ID + new->TID = giNextTID++; + // Set kernel stack + new->KernelStack = MM_NewWorkerStack(); + + // Get ESP and EBP based in the new stack + __asm__ __volatile__ ("mov %%esp, %0": "=r"(esp)); + __asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp)); + esp = cur->KernelStack - (new->KernelStack - esp); + ebp = new->KernelStack - (cur->KernelStack - ebp); + + // Save core machine state + new->SavedState.ESP = esp; + new->SavedState.EBP = ebp; + eip = GetEIP(); + if(eip == SWITCH_MAGIC) { + outb(0x20, 0x20); // ACK Timer and return as child + return 0; } - //TODO: + // Set EIP as parent + new->SavedState.EIP = eip; + + return new->TID; } -#endif - /** * \fn Uint Proc_MakeUserStack() * \brief Creates a new user stack @@ -369,7 +386,7 @@ Uint Proc_MakeUserStack() /** - * \fn void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, char **EnvP, int DataSize) + * \fn void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize) * \brief Starts a user task */ void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize) @@ -440,6 +457,8 @@ void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char ** * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs) * \brief Demotes a process to a lower permission level * \param Err Pointer to user's errno + * \param Dest New Permission Level + * \param Regs Pointer to user's register structure */ int Proc_Demote(Uint *Err, int Dest, tRegs *Regs) { @@ -475,7 +494,6 @@ int Proc_Demote(Uint *Err, int Dest, tRegs *Regs) void Proc_Scheduler(int CPU) { Uint esp, ebp, eip; - Uint number, ticket; tThread *thread; // If the spinlock is set, let it complete @@ -494,12 +512,12 @@ void Proc_Scheduler(int CPU) // Check if there is any tasks running if(giNumActiveThreads == 0) { - Log("No Active threads, sleeping\n"); + Log("No Active threads, sleeping"); __asm__ __volatile__ ("hlt"); return; } - // Reduce remaining quantum + // Reduce remaining quantum and continue timeslice if non-zero if(gCurrentThread->Remaining--) return; // Reset quantum for next call gCurrentThread->Remaining = gCurrentThread->Quantum; @@ -515,52 +533,41 @@ void Proc_Scheduler(int CPU) gCurrentThread->SavedState.EBP = ebp; gCurrentThread->SavedState.EIP = eip; - // Special case: 1 thread - if(giNumActiveThreads == 1) - { - // Check if a switch is needed (NumActive can be 1 after a sleep) - if(gActiveThreads == gCurrentThread) return; - // Switch processes - gCurrentThread = gActiveThreads; - goto performSwitch; - } - - // Get the ticket number - ticket = number = rand() % giTotalTickets; - - // Find the next thread - for(thread=gActiveThreads;thread;thread=thread->Next) - { - if(thread->NumTickets > number) break; - number -= thread->NumTickets; - } + // Get next thread + thread = Threads_GetNextToRun(CPU); // Error Check - if(thread == NULL) - { - number = 0; - for(thread=gActiveThreads;thread;thread=thread->Next) - number += thread->NumTickets; - Panic("Bookeeping Failed - giTotalTicketCount (%i) != true count (%i)", - giTotalTickets, number); + if(thread == NULL) { + Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n"); + return; } + #if DEBUG_TRACE_SWITCH + Log("Switching to task %i, CR3 = 0x%x, EIP = %p", + thread->TID, + thread->MemState.CR3, + thread->SavedState.EIP + ); + #endif + // Set current thread gCurrentThread = thread; // Update Kernel Stack pointer gTSSs[CPU].ESP0 = thread->KernelStack; -performSwitch: // Set address space - //MM_SetCR3( gCurrentThread->CR3 ); __asm__ __volatile__ ("mov %0, %%cr3"::"a"(gCurrentThread->MemState.CR3)); // Switch threads __asm__ __volatile__ ( - "mov %1, %%esp\n\t" - "mov %2, %%ebp\n\t" - "jmp *%3" : : + "mov %1, %%esp\n\t" // Restore ESP + "mov %2, %%ebp\n\t" // and EBP + "jmp *%3" : : // And return to where we saved state (Proc_Clone or Proc_Scheduler) "a"(SWITCH_MAGIC), "b"(gCurrentThread->SavedState.ESP), - "d"(gCurrentThread->SavedState.EBP), "c"(gCurrentThread->SavedState.EIP)); + "d"(gCurrentThread->SavedState.EBP), "c"(gCurrentThread->SavedState.EIP) + ); for(;;); // Shouldn't reach here } + +// === EXPORTS === +EXPORT(Proc_SpawnWorker);