X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Farch%2Fx86%2Fproc.c;h=b1dcb99dc1180ae1f993d2d438c92452d9ca0458;hb=14d0ba44433f0f828aff710184fd3c597ab73999;hp=fb6b52dee852d89b6031605ffeeb26cb39273401;hpb=533eecb9c9c351c668c3a6b9d49f28325a914162;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/arch/x86/proc.c b/KernelLand/Kernel/arch/x86/proc.c index fb6b52de..b1dcb99d 100644 --- a/KernelLand/Kernel/arch/x86/proc.c +++ b/KernelLand/Kernel/arch/x86/proc.c @@ -1,56 +1,53 @@ /* - * AcessOS Microkernel Version + * Acess2 Kernel (x86) + * - By John Hodge (thePowersGang) + * * proc.c + * - Low level thread management */ +#define DEBUG 0 #include #include #include #include #include #include -#if USE_MP -# include -#endif #include #include +#include +#if USE_MP +# include +#endif // === FLAGS === #define DEBUG_TRACE_SWITCH 0 #define DEBUG_DISABLE_DOUBLEFAULT 1 #define DEBUG_VERY_SLOW_PERIOD 0 +#define DEBUG_NOPREEMPT 1 +#define DISABLE_PIT 0 // === CONSTANTS === // Base is 1193182 #define TIMER_BASE 1193182 -#if DEBUG_VERY_SLOW_PERIOD +#if DISABLE_PIT +# define TIMER_DIVISOR 0xFFFF +#elif DEBUG_VERY_SLOW_PERIOD # define TIMER_DIVISOR 1193 //~10Hz switch, with 10 quantum = 1s per thread #else # define TIMER_DIVISOR 11932 //~100Hz #endif // === TYPES === -typedef struct sCPU -{ - Uint8 APICID; - Uint8 State; // 0: Unavaliable, 1: Idle, 2: Active - Uint16 Resvd; - tThread *Current; - tThread *LastTimerThread; // Used to do preeemption -} tCPU; // === IMPORTS === extern tGDT gGDT[]; extern tIDT gIDT[]; extern void APWait(void); // 16-bit AP pause code extern void APStartup(void); // 16-bit AP startup code -extern Uint GetEIP(void); // start.asm -extern Uint GetEIP_Sched(void); // proc.asm -extern void NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...); // Actually takes cdecl args extern Uint Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone); extern Uint32 gaInitPageDir[1024]; // start.asm extern char Kernel_Stack_Top[]; extern int giNumCPUs; -extern int giNextTID; extern tThread gThreadZero; extern tProcess gProcessZero; extern void Isr8(void); // Double Fault @@ -59,10 +56,7 @@ extern char scheduler_return[]; // Return address in SchedulerBase extern char IRQCommon[]; // Common IRQ handler code extern char IRQCommon_handled[]; // IRQCommon call return location extern char GetEIP_Sched_ret[]; // GetEIP call return location -extern void SwitchTasks(Uint NewSP, Uint *OldSP, Uint NewIP, Uint *OldIO, Uint CR3); -extern void Proc_InitialiseSSE(void); -extern void Proc_SaveSSE(Uint DestPtr); -extern void Proc_DisableSSE(void); +extern void Timer_CallTimers(void); // === PROTOTYPES === //void ArchThreads_Init(void); @@ -76,20 +70,20 @@ void Proc_IdleThread(void *Ptr); //tThread *Proc_GetCurThread(void); void Proc_ChangeStack(void); // int Proc_NewKThread(void (*Fcn)(void*), void *Data); +void NewTaskHeader(tThread *Thread, void (*Fcn)(void*), void *Data); // Actually takes cdecl args // int Proc_Clone(Uint *Err, Uint Flags); 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) NORETURN; - int Proc_Demote(Uint *Err, int Dest, tRegs *Regs); +void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen); //void Proc_CallFaultHandler(tThread *Thread); //void Proc_DumpThreadCPUState(tThread *Thread); -void Proc_Scheduler(int CPU); +void Proc_HandleEventTimer(int CPU); // === GLOBALS === // --- Multiprocessing --- #if USE_MP volatile int giNumInitingCPUs = 0; -tMPInfo *gMPFloatPtr = NULL; volatile Uint32 giMP_TimerCount; // Start Count for Local APIC Timer tAPIC *gpMP_LocalAPIC = NULL; Uint8 gaAPIC_to_CPU[256] = {0}; @@ -121,184 +115,25 @@ tTSS gDoubleFault_TSS = { */ void ArchThreads_Init(void) { - Uint pos = 0; - - #if USE_MP - tMPTable *mptable; - // Mark BSP as active gaCPUs[0].State = 2; + #if USE_MP // -- Initialise Multiprocessing - // Find MP Floating Table - // - EBDA/Last 1Kib (640KiB) - for(pos = KERNEL_BASE|0x9F000; pos < (KERNEL_BASE|0xA0000); pos += 16) { - if( *(Uint*)(pos) == MPPTR_IDENT ) { - Log("Possible %p", pos); - if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue; - gMPFloatPtr = (void*)pos; - break; - } - } - // - Last KiB (512KiB base mem) - if(!gMPFloatPtr) { - for(pos = KERNEL_BASE|0x7F000; pos < (KERNEL_BASE|0x80000); pos += 16) { - if( *(Uint*)(pos) == MPPTR_IDENT ) { - Log("Possible %p", pos); - if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue; - gMPFloatPtr = (void*)pos; - break; - } - } - } - // - BIOS ROM - if(!gMPFloatPtr) { - for(pos = KERNEL_BASE|0xE0000; pos < (KERNEL_BASE|0x100000); pos += 16) { - if( *(Uint*)(pos) == MPPTR_IDENT ) { - Log("Possible %p", pos); - if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue; - gMPFloatPtr = (void*)pos; - break; - } - } - } - - // If the MP Table Exists, parse it - if(gMPFloatPtr) + const void *mpfloatptr = MPTable_LocateFloatPtr(); + if( mpfloatptr ) { - int i; - tMPTable_Ent *ents; - #if DUMP_MP_TABLE - Log("gMPFloatPtr = %p", gMPFloatPtr); - Log("*gMPFloatPtr = {"); - Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig); - Log("\t.MPConfig = 0x%08x", gMPFloatPtr->MPConfig); - Log("\t.Length = 0x%02x", gMPFloatPtr->Length); - Log("\t.Version = 0x%02x", gMPFloatPtr->Version); - Log("\t.Checksum = 0x%02x", gMPFloatPtr->Checksum); - Log("\t.Features = [0x%02x,0x%02x,0x%02x,0x%02x,0x%02x]", - gMPFloatPtr->Features[0], gMPFloatPtr->Features[1], - gMPFloatPtr->Features[2], gMPFloatPtr->Features[3], - gMPFloatPtr->Features[4] - ); - Log("}"); - #endif - - mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig ); - #if DUMP_MP_TABLE - Log("mptable = %p", mptable); - Log("*mptable = {"); - Log("\t.Sig = 0x%08x", mptable->Sig); - Log("\t.BaseTableLength = 0x%04x", mptable->BaseTableLength); - Log("\t.SpecRev = 0x%02x", mptable->SpecRev); - Log("\t.Checksum = 0x%02x", mptable->Checksum); - Log("\t.OEMID = '%8c'", mptable->OemID); - Log("\t.ProductID = '%8c'", mptable->ProductID); - Log("\t.OEMTablePtr = %p'", mptable->OEMTablePtr); - Log("\t.OEMTableSize = 0x%04x", mptable->OEMTableSize); - Log("\t.EntryCount = 0x%04x", mptable->EntryCount); - Log("\t.LocalAPICMemMap = 0x%08x", mptable->LocalAPICMemMap); - Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen); - Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum); - Log("}"); - #endif - - gpMP_LocalAPIC = (void*)MM_MapHWPages(mptable->LocalAPICMemMap, 1); - - ents = mptable->Entries; - giNumCPUs = 0; - - for( i = 0; i < mptable->EntryCount; i ++ ) + giNumCPUs = MPTable_FillCPUs(mpfloatptr, gaCPUs, MAX_CPUS, &giProc_BootProcessorID); + for( int i = 0; i < giNumCPUs; i ++ ) { - int entSize = 0; - switch( ents->Type ) - { - case 0: // Processor - entSize = 20; - #if DUMP_MP_TABLE - Log("%i: Processor", i); - Log("\t.APICID = %i", ents->Proc.APICID); - Log("\t.APICVer = 0x%02x", ents->Proc.APICVer); - Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags); - Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature); - Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags); - #endif - - if( !(ents->Proc.CPUFlags & 1) ) { - Log("DISABLED"); - break; - } - - // Check if there is too many processors - if(giNumCPUs >= MAX_CPUS) { - giNumCPUs ++; // If `giNumCPUs` > MAX_CPUS later, it will be clipped - break; - } - - // Initialise CPU Info - gaAPIC_to_CPU[ents->Proc.APICID] = giNumCPUs; - gaCPUs[giNumCPUs].APICID = ents->Proc.APICID; - gaCPUs[giNumCPUs].State = 0; - giNumCPUs ++; - - // Set BSP Variable - if( ents->Proc.CPUFlags & 2 ) { - giProc_BootProcessorID = giNumCPUs-1; - } - - break; - - #if DUMP_MP_TABLE >= 2 - case 1: // Bus - entSize = 8; - Log("%i: Bus", i); - Log("\t.ID = %i", ents->Bus.ID); - Log("\t.TypeString = '%6C'", ents->Bus.TypeString); - break; - case 2: // I/O APIC - entSize = 8; - Log("%i: I/O APIC", i); - Log("\t.ID = %i", ents->IOAPIC.ID); - Log("\t.Version = 0x%02x", ents->IOAPIC.Version); - Log("\t.Flags = 0x%02x", ents->IOAPIC.Flags); - Log("\t.Addr = 0x%08x", ents->IOAPIC.Addr); - break; - case 3: // I/O Interrupt Assignment - entSize = 8; - Log("%i: I/O Interrupt Assignment", i); - Log("\t.IntType = %i", ents->IOInt.IntType); - Log("\t.Flags = 0x%04x", ents->IOInt.Flags); - Log("\t.SourceBusID = 0x%02x", ents->IOInt.SourceBusID); - Log("\t.SourceBusIRQ = 0x%02x", ents->IOInt.SourceBusIRQ); - Log("\t.DestAPICID = 0x%02x", ents->IOInt.DestAPICID); - Log("\t.DestAPICIRQ = 0x%02x", ents->IOInt.DestAPICIRQ); - break; - case 4: // Local Interrupt Assignment - entSize = 8; - Log("%i: Local Interrupt Assignment", i); - Log("\t.IntType = %i", ents->LocalInt.IntType); - Log("\t.Flags = 0x%04x", ents->LocalInt.Flags); - Log("\t.SourceBusID = 0x%02x", ents->LocalInt.SourceBusID); - Log("\t.SourceBusIRQ = 0x%02x", ents->LocalInt.SourceBusIRQ); - Log("\t.DestLocalAPICID = 0x%02x", ents->LocalInt.DestLocalAPICID); - Log("\t.DestLocalAPICIRQ = 0x%02x", ents->LocalInt.DestLocalAPICIRQ); - break; - default: - Log("%i: Unknown (%i)", i, ents->Type); - break; - #endif - } - ents = (void*)( (Uint)ents + entSize ); - } - - if( giNumCPUs > MAX_CPUS ) { - Warning("Too many CPUs detected (%i), only using %i of them", giNumCPUs, MAX_CPUS); - giNumCPUs = MAX_CPUS; + // TODO: Determine if there's an overlap + gaAPIC_to_CPU[gaCPUs[i].APICID] = i; } gTSSs = gaTSSs; } - else { - Log("No MP Table was found, assuming uniprocessor\n"); + else + { + Log("No MP Table was found, assuming uniprocessor"); giNumCPUs = 1; gTSSs = &gTSS0; } @@ -352,10 +187,10 @@ void ArchThreads_Init(void) } // Initialise Normal TSS(s) - for(pos=0;pos 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) @@ -438,11 +294,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 @@ -453,10 +307,12 @@ void Proc_IdleThread(void *Ptr) cpu->Current->ThreadName = strdup("Idle Thread"); Threads_SetPriority( cpu->Current, -1 ); // Never called randomly cpu->Current->Quantum = 1; // 1 slice quantum - for(;;) { + LOG("Idle thread for CPU %i ready", GetCPUNum()); + for(;;) + { __asm__ __volatile__ ("sti"); // Make sure interrupts are enabled - __asm__ __volatile__ ("hlt"); // Make sure interrupts are enabled - Proc_Reschedule(); + Proc_Reschedule(); // Reshedule + __asm__ __volatile__ ("hlt"); // And wait for an interrupt if we get scheduled again } } @@ -466,37 +322,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,11 +434,7 @@ void Proc_ClearThread(tThread *Thread) tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) { - Uint esp; - tThread *newThread, *cur; - - cur = Proc_GetCurThread(); - newThread = Threads_CloneTCB(0); + tThread *newThread = Threads_CloneTCB(0); if(!newThread) return -1; // Create new KStack @@ -600,12 +444,14 @@ tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) free(newThread); return -1; } + + LOG("%p(%i %s) SP=%p", newThread, newThread->TID, newThread->ThreadName, newThread->KernelStack); - esp = newThread->KernelStack; + Uint esp = newThread->KernelStack; *(Uint*)(esp-=4) = (Uint)Data; // Data (shadowed) - *(Uint*)(esp-=4) = 1; // Number of params *(Uint*)(esp-=4) = (Uint)Fcn; // Function to call *(Uint*)(esp-=4) = (Uint)newThread; // Thread ID + *(Uint*)(esp-=4) = (Uint)0; // Empty return address newThread->SavedState.ESP = esp; newThread->SavedState.EIP = (Uint)&NewTaskHeader; @@ -618,15 +464,24 @@ tTID Proc_NewKThread(void (*Fcn)(void*), void *Data) return newThread->TID; } +void NewTaskHeader(tThread *NewThread, void (*Fcn)(void*), void *Data) +{ + LOG("NewThread=%p, Fcn=%p, Data=%p", NewThread, Fcn, Data); + __asm__ __volatile__ ("mov %0, %%dr0" : : "r"(NewThread)); + SHORTREL(&glThreadListLock); + Fcn(Data); + + Threads_Exit(0, 0); + for(;;); +} + /** * \fn int Proc_Clone(Uint *Err, Uint Flags) * \brief Clone the current process */ tPID Proc_Clone(Uint Flags) { - tThread *newThread; tThread *cur = Proc_GetCurThread(); - Uint eip; // Sanity, please if( !(Flags & CLONE_VM) ) { @@ -635,16 +490,22 @@ tPID Proc_Clone(Uint Flags) } // New thread - newThread = Threads_CloneTCB(Flags); + tThread *newThread = Threads_CloneTCB(Flags); if(!newThread) return -1; + ASSERT(newThread->Process); newThread->KernelStack = cur->KernelStack; // Clone state - eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER); + Uint eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER); if( eip == 0 ) { + SHORTREL( &glThreadListLock ); + LOG("In new thread"); return 0; } + //ASSERT(newThread->Process); + //ASSERT(CheckMem(newThread->Process, sizeof(tProcess))); + //LOG("newThread->Process = %p", newThread->Process); newThread->SavedState.EIP = eip; newThread->SavedState.SSE = NULL; newThread->SavedState.bSSEModified = 0; @@ -665,26 +526,29 @@ 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]; + LOG("(Fcn=%p,Data=%p)", Fcn, Data); // Create new thread - new = Threads_CloneThreadZero(); + tThread *new = Threads_CloneThreadZero(); + LOG("new=%p", new); if(!new) { Warning("Proc_SpawnWorker - Out of heap space!\n"); - return -1; + return NULL; } + LOG("new = (%i %s)", new->TID, new->ThreadName); // Create the stack contents stack_contents[3] = (Uint)Data; - stack_contents[2] = 1; - stack_contents[1] = (Uint)Fcn; - stack_contents[0] = (Uint)new; + stack_contents[2] = (Uint)Fcn; + stack_contents[1] = (Uint)new; + stack_contents[0] = 0; // Create a new worker stack (in PID0's address space) new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents)); + LOG("new->KernelStack = %p", new->KernelStack); // Save core machine state new->SavedState.ESP = new->KernelStack - sizeof(stack_contents); @@ -695,8 +559,9 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data) // Mark as active new->Status = THREAD_STAT_PREINIT; Threads_AddActive( new ); + LOG("Added to active"); - return new->TID; + return new; } /** @@ -705,27 +570,28 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data) */ Uint Proc_MakeUserStack(void) { - int i; - Uint base = USER_STACK_TOP - USER_STACK_SZ; + tPage *base = (void*)(USER_STACK_TOP - USER_STACK_SZ); // Check Prospective Space - for( i = USER_STACK_SZ >> 12; i--; ) - if( MM_GetPhysAddr( base + (i<<12) ) != 0 ) - break; - - if(i != -1) return 0; - + for( Uint i = USER_STACK_SZ/PAGE_SIZE; i--; ) + { + if( MM_GetPhysAddr( base + i ) != 0 ) + { + Warning("Proc_MakeUserStack: Address %p in use", base + i); + return 0; + } + } // Allocate Stack - Allocate incrementally to clean up MM_Dump output - for( i = 0; i < USER_STACK_SZ/0x1000; i++ ) + for( Uint i = 0; i < USER_STACK_SZ/PAGE_SIZE; i++ ) { - if( !MM_Allocate( base + (i<<12) ) ) + if( MM_Allocate( base + i ) == 0 ) { Warning("OOM: Proc_MakeUserStack"); return 0; } } - return base + USER_STACK_SZ; + return (tVAddr)( base + USER_STACK_SZ/PAGE_SIZE ); } void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize) @@ -797,38 +663,32 @@ void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) for(;;); } -/** - * \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) +void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen) { - int cpl = Regs->cs & 3; - // Sanity Check - if(Dest > 3 || Dest < 0) { - *Err = -EINVAL; - return -1; - } - - // Permission Check - if(cpl > Dest) { - *Err = -EACCES; - return -1; - } - - // 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; + if( UserSP < StackDataLen ) + return ; + if( !CheckMem( (void*)(UserSP - StackDataLen), StackDataLen ) ) + return ; + memcpy( (void*)(UserSP - StackDataLen), StackData, StackDataLen ); - return 0; + __asm__ __volatile__ ( + "mov $0x23,%%ax;\n\t" + "mov %%ax, %%ds;\n\t" + "mov %%ax, %%es;\n\t" + "mov %%ax, %%fs;\n\t" + "mov %%ax, %%gs;\n\t" + "push $0x23;\n\t" + "push %1;\n\t" + "push $0x202;\n\t" + "push $0x1B;\n\t" + "push %0;\n\t" + "iret;\n\t" + : + : "r" (UserIP), "r" (UserSP - StackDataLen) + : "eax" + ); + for(;;) + ; } /** @@ -862,6 +722,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 @@ -878,10 +742,13 @@ void Proc_DumpThreadCPUState(tThread *Thread) return ; } - Log(" at %04x:%08x", regs->cs, regs->eip); + Log(" at %04x:%08x [EAX:%x]", regs->cs, regs->eip, regs->eax); + Error_Backtrace(regs->eip, regs->ebp); return ; } - + + Log(" Saved = %p (SP=%p)", Thread->SavedState.EIP, Thread->SavedState.ESP); + tVAddr diffFromScheduler = Thread->SavedState.EIP - (tVAddr)SwitchTasks; tVAddr diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_CloneInt; tVAddr diffFromSpawn = Thread->SavedState.EIP - (tVAddr)NewTaskHeader; @@ -910,91 +777,96 @@ void Proc_DumpThreadCPUState(tThread *Thread) void Proc_Reschedule(void) { - tThread *nextthread, *curthread; int cpu = GetCPUNum(); // TODO: Wait for the lock? - if(IS_LOCKED(&glThreadListLock)) return; + if(IS_LOCKED(&glThreadListLock)) { + LOG("Thread list locked, not rescheduling"); + return; + } - curthread = Proc_GetCurThread(); - - nextthread = Threads_GetNextToRun(cpu, curthread); - - if(!nextthread || nextthread == curthread) - return ; - - #if DEBUG_TRACE_SWITCH - // HACK: Ignores switches to the idle threads - if( nextthread->TID == 0 || nextthread->TID > giNumCPUs ) + SHORTLOCK(&glThreadListLock); + + tThread *curthread = Proc_GetCurThread(); + tThread *nextthread = Threads_GetNextToRun(cpu, curthread); + + if(nextthread && nextthread != curthread) { - LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n", - GetCPUNum(), - nextthread, nextthread->TID, nextthread->ThreadName, - nextthread->Process->MemState.CR3, - nextthread->SavedState.EIP, - nextthread->SavedState.ESP - ); - LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3); - } - #endif + #if DEBUG_TRACE_SWITCH + // HACK: Ignores switches to the idle threads + //if( nextthread->TID == 0 || nextthread->TID > giNumCPUs ) + { + LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n", + GetCPUNum(), + nextthread, nextthread->TID, nextthread->ThreadName, + nextthread->Process->MemState.CR3, + nextthread->SavedState.EIP, + nextthread->SavedState.ESP + ); + LogF(" from %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n", + curthread, curthread->TID, curthread->ThreadName, + curthread->Process->MemState.CR3, + curthread->SavedState.EIP, + curthread->SavedState.ESP + ); + } + #endif - // 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) ); + // 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) ); - // Save FPU/MMX/XMM/SSE state - if( curthread && curthread->SavedState.SSE ) - { - Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); - curthread->SavedState.bSSEModified = 0; - Proc_DisableSSE(); - } + // Save FPU/MMX/XMM/SSE state + if( curthread && curthread->SavedState.SSE ) + { + Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF ); + curthread->SavedState.bSSEModified = 0; + Proc_DisableSSE(); + } - if( curthread ) - { - SwitchTasks( - nextthread->SavedState.ESP, &curthread->SavedState.ESP, - nextthread->SavedState.EIP, &curthread->SavedState.EIP, - nextthread->Process->MemState.CR3 - ); - } - else - { - SwitchTasks( - nextthread->SavedState.ESP, 0, - nextthread->SavedState.EIP, 0, - nextthread->Process->MemState.CR3 - ); + if( curthread ) + { + SwitchTasks( + nextthread->SavedState.ESP, &curthread->SavedState.ESP, + nextthread->SavedState.EIP, &curthread->SavedState.EIP, + nextthread->Process->MemState.CR3 + ); + } + else + { + SwitchTasks( + nextthread->SavedState.ESP, 0, + nextthread->SavedState.EIP, 0, + nextthread->Process->MemState.CR3 + ); + } } - - return ; + + SHORTREL(&glThreadListLock); } /** - * \fn void Proc_Scheduler(int CPU) - * \brief Swap current thread and clears dead threads + * \brief Handle the per-CPU timer ticking + */ -void Proc_Scheduler(int CPU) +void Proc_HandleEventTimer(int CPU) { - #if USE_MP - if( GetCPUNum() ) - gpMP_LocalAPIC->EOI.Val = 0; - else - #endif - outb(0x20, 0x20); - __asm__ __volatile__ ("sti"); - - gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current; // 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 ) { + const tThread* const t = gaCPUs[CPU].Current; + LOG("Preempting thread %p(%i %s)", t, t->TID, t->ThreadName); Proc_Reschedule(); } + + gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current; + #endif } // === EXPORTS ===