From 2d83a99f3202f0e4688b58405f67604a24420861 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 31 Jul 2010 23:10:04 +0800 Subject: [PATCH] Working on MP build (now can run, just crashes due to CPUs treading on each other's toes) --- Kernel/arch/x86/errors.c | 14 ++++- Kernel/arch/x86/mm_virt.c | 6 ++ Kernel/arch/x86/proc.asm | 6 ++ Kernel/arch/x86/proc.c | 119 ++++++++++++++++++-------------------- Kernel/arch/x86/start.asm | 18 +++--- Kernel/arch/x86/vm8086.c | 11 +++- 6 files changed, 99 insertions(+), 75 deletions(-) diff --git a/Kernel/arch/x86/errors.c b/Kernel/arch/x86/errors.c index 796300f6..1e0278b6 100644 --- a/Kernel/arch/x86/errors.c +++ b/Kernel/arch/x86/errors.c @@ -14,6 +14,7 @@ extern void MM_PageFault(Uint Addr, Uint ErrorCode, tRegs *Regs); extern void VM8086_GPF(tRegs *Regs); extern void Threads_Dump(void); extern void Threads_Fault(int Num); +extern int GetCPUNum(void); // === PROTOTYPES === void __stack_chk_fail(void); @@ -97,9 +98,16 @@ void ErrorHandler(tRegs *Regs) } Debug_KernelPanic(); - Warning("CPU Error %i - %s, Code: 0x%x", - Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code); - Warning(" CS:EIP = 0x%04x:%08x", Regs->cs, Regs->eip); + + LogF("CPU %i Error %i - %s, Code: 0x%x - At %08x", + GetCPUNum(), + Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code, + Regs->eip); + + //Warning("CPU Error %i - %s, Code: 0x%x", + // Regs->int_num, csaERROR_NAMES[Regs->int_num], Regs->err_code); + //Warning(" CS:EIP = 0x%04x:%08x", Regs->cs, Regs->eip); + __ASM__ ("xchg %bx, %bx"); if(Regs->cs == 0x08) Warning(" SS:ESP = 0x0010:%08x", (Uint)Regs+sizeof(tRegs)); else diff --git a/Kernel/arch/x86/mm_virt.c b/Kernel/arch/x86/mm_virt.c index 4c2455e1..8902837c 100644 --- a/Kernel/arch/x86/mm_virt.c +++ b/Kernel/arch/x86/mm_virt.c @@ -252,6 +252,12 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) //Log("SS:ESP %04x:%08x", Regs->ss, Regs->esp); Log("CS:EIP %04x:%08x", Regs->cs, Regs->eip); Log("DS %04x ES %04x FS %04x GS %04x", Regs->ds, Regs->es, Regs->fs, Regs->gs); + { + Uint dr0, dr1; + __ASM__ ("mov %%dr0, %0":"=r"(dr0):); + __ASM__ ("mov %%dr1, %0":"=r"(dr1):); + Log("DR0 %08x DR1 %08x", dr0, dr1); + } Panic("Page Fault at 0x%x (Accessed 0x%x)", Regs->eip, Addr); } diff --git a/Kernel/arch/x86/proc.asm b/Kernel/arch/x86/proc.asm index 20a4fd78..9dc7f08a 100644 --- a/Kernel/arch/x86/proc.asm +++ b/Kernel/arch/x86/proc.asm @@ -74,6 +74,9 @@ SchedulerBase: push fs push gs + mov eax, dr0 + push eax ; Debug Register 0, Current Thread + mov ax, 0x10 mov ds, ax mov es, ax @@ -107,6 +110,9 @@ SchedulerBase: mov DWORD [eax+0x0B0], 0 %endif .ret: + pop eax ; Debug Register 0, Current Thread + mov dr0, eax + pop gs pop fs pop es diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c index 94de734f..e9b4a681 100644 --- a/Kernel/arch/x86/proc.c +++ b/Kernel/arch/x86/proc.c @@ -16,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 @@ -41,17 +41,11 @@ 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 char Kernel_Stack_Top[]; extern tSpinlock 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 void Threads_Dump(void); extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags); extern void Isr8(void); // Double Fault extern void Proc_ReturnToUser(void); @@ -310,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"); @@ -340,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 } @@ -348,6 +347,9 @@ 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; @@ -379,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 @@ -433,16 +435,19 @@ void Proc_Start(void) // Start APs for( i = 0; i < giNumCPUs; i ++ ) { + int tid; + if(i) gaCPUs[i].Current = NULL; + // Create Idle Task - if(Proc_Clone(0, 0) == 0) + if( (tid = 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; + 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 ) { @@ -457,7 +462,6 @@ void Proc_Start(void) 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) @@ -475,6 +479,7 @@ void Proc_Start(void) // Start Interrupts (and hence scheduler) __asm__ __volatile__("sti"); #endif + MM_FinishVirtualInit(); } /** @@ -484,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; @@ -599,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; } @@ -634,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 @@ -648,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; } @@ -826,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; @@ -862,13 +855,14 @@ void Proc_Scheduler(int CPU) if( thread ) { // Reduce remaining quantum and continue timeslice if non-zero - if(thread->Remaining--) return; + 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)); + __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 @@ -881,17 +875,23 @@ void Proc_Scheduler(int CPU) // Get next thread to run thread = Threads_GetNextToRun(CPU, thread); - // No avaliable tasks, just go into low power mode + // No avaliable tasks, just go into low power mode (idle thread) if(thread == NULL) { - //HALT(); - //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, @@ -900,15 +900,10 @@ void Proc_Scheduler(int CPU) ); #endif - // Set current thread - #if USE_MP - gaCPUs[CPU].Current = thread; - #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; @@ -916,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 diff --git a/Kernel/arch/x86/start.asm b/Kernel/arch/x86/start.asm index f79c647e..0988a773 100644 --- a/Kernel/arch/x86/start.asm +++ b/Kernel/arch/x86/start.asm @@ -145,26 +145,30 @@ APStartup: lidt [gIDTPtr] mov ebp, [gpMP_LocalAPIC] - mov esi, [eax+0x20] ; Read ID - shr esi, 24 + mov ebx, [ebp+0x20] ; Read ID + shr ebx, 24 ;xchg bx, bx ; MAGIC BREAK ; CL is now local APIC ID - mov cl, BYTE [gaAPIC_to_CPU+esi] - ; CL is now the CPU ID - mov BYTE [gaCPUs+esi*8+1], 1 + mov cl, BYTE [gaAPIC_to_CPU+ebx] + xor ebx, ebx + mov bl, cl + ; BL is now the CPU ID + mov BYTE [gaCPUs+ebx*8+1], 1 ; Decrement the remaining CPU count dec DWORD [giNumInitingCPUs] ; Create a stack - lea edx, [esi+1] + lea edx, [ebx+1] shl edx, 5+2 ; *32 *4 lea esp, [gInitAPStacks+edx] call MM_NewKStack mov esp, eax ; Set TSS - lea ecx, [esi*8+0x30] + lea ecx, [ebx*8+0x30] ltr cx + ; Save the CPU number to a debug register + mov dr1, ebx ;xchg bx, bx ; MAGIC_BREAK ; Enable Local APIC diff --git a/Kernel/arch/x86/vm8086.c b/Kernel/arch/x86/vm8086.c index 1f4f1f43..86f440d1 100644 --- a/Kernel/arch/x86/vm8086.c +++ b/Kernel/arch/x86/vm8086.c @@ -130,7 +130,8 @@ int VM8086_Install(char **Arguments) gVM8086_WorkerPID = pid; Log_Log("VM8086", "gVM8086_WorkerPID = %i", pid); - Threads_Yield(); // Yield to allow the child to initialise + while( gpVM8086_State != NULL ) + Threads_Yield(); // Yield to allow the child to initialise return MODULE_ERR_OK; } @@ -149,6 +150,8 @@ void VM8086_GPF(tRegs *Regs) RELEASE( &glVM8086_Process ); // Release lock obtained in VM8086_Install gpVM8086_State = NULL; } + //Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i", + // gpVM8086_State, gVM8086_CallingThread); if( gpVM8086_State ) { gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx; gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx; @@ -156,7 +159,9 @@ void VM8086_GPF(tRegs *Regs) gpVM8086_State->SI = Regs->esi; gpVM8086_State->DI = Regs->edi; gpVM8086_State->DS = Regs->ds; gpVM8086_State->ES = Regs->es; gpVM8086_State = NULL; - Threads_WakeTID(gVM8086_CallingThread); + // Ensure the caller wakes + //while(Threads_WakeTID(gVM8086_CallingThread) == -EALREADY) + // Threads_Yield(); } //Log_Log("VM8086", "Waiting for something to do"); @@ -402,7 +407,7 @@ void VM8086_Int(tVM8086 *State, Uint8 Interrupt) gVM8086_CallingThread = Threads_GetTID(); Threads_WakeTID( gVM8086_WorkerPID ); while( gpVM8086_State != NULL ) - Threads_Sleep(); + Threads_Yield(); RELEASE( &glVM8086_Process ); } -- 2.20.1