X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Farch%2Fx86%2Fproc.c;h=2c595168738fdb5a5f49deb8adc155aeff2297cd;hb=74ea5e7e82ed3a4f7fa981907177cf55b9b88f07;hp=de0d5c3c4b5850c5947a10a0a85b37d539ca7f54;hpb=e02f66c7125bf18f77c6c53587238cbd49da2c89;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/arch/x86/proc.c b/KernelLand/Kernel/arch/x86/proc.c index de0d5c3c..2c595168 100644 --- a/KernelLand/Kernel/arch/x86/proc.c +++ b/KernelLand/Kernel/arch/x86/proc.c @@ -8,11 +8,12 @@ #include #include #include -#if USE_MP -# include -#endif #include #include +#include +#if USE_MP +# include +#endif // === FLAGS === #define DEBUG_TRACE_SWITCH 0 @@ -30,28 +31,17 @@ #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 @@ -60,10 +50,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); @@ -81,7 +68,7 @@ void Proc_ChangeStack(void); 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); @@ -90,7 +77,6 @@ void Proc_Scheduler(int CPU); // --- 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}; @@ -122,184 +108,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; } @@ -353,10 +180,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) @@ -439,11 +287,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 @@ -456,7 +302,7 @@ void Proc_IdleThread(void *Ptr) cpu->Current->Quantum = 1; // 1 slice quantum for(;;) { __asm__ __volatile__ ("sti"); // Make sure interrupts are enabled - __asm__ __volatile__ ("hlt"); // Make sure interrupts are enabled + __asm__ __volatile__ ("hlt"); Proc_Reschedule(); } } @@ -468,15 +314,17 @@ void Proc_IdleThread(void *Ptr) void Proc_Start(void) { #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 Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]); @@ -485,14 +333,6 @@ void Proc_Start(void) 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 Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]); @@ -663,7 +503,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]; @@ -672,7 +512,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 @@ -694,7 +534,7 @@ int Proc_SpawnWorker(void (*Fcn)(void*), void *Data) new->Status = THREAD_STAT_PREINIT; Threads_AddActive( new ); - return new->TID; + return new; } /** @@ -795,38 +635,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(;;) + ; } /** @@ -880,7 +714,7 @@ 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); return ; }