// === FLAGS ===
#define DEBUG_TRACE_SWITCH 0
#define DEBUG_DISABLE_DOUBLEFAULT 1
+#define DEBUG_VERY_SLOW_SWITCH 0
// === CONSTANTS ===
#define SWITCH_MAGIC 0xFF5317C8 // FF SWITCH - There is no code in this area
// Base is 1193182
#define TIMER_BASE 1193182
-#define TIMER_DIVISOR 11932 //~100Hz
+#if DEBUG_VERY_SLOW_PERIOD
+# define TIMER_DIVISOR 1193 //~10Hz switch, with 10 quantum = 1s per thread
+#else
+# define TIMER_DIVISOR 11932 //~100Hz
+#endif
// === TYPES ===
#if USE_MP
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 int GetCPUNum(void); // start.asm
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
extern tThread gThreadZero;
extern void Isr8(void); // Double Fault
extern void Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
+extern void scheduler_return; // Return address in SchedulerBase
+extern void IRQCommon; // Common IRQ handler code
+extern void IRQCommon_handled; // IRQCommon call return location
+extern void GetEIP_Sched_ret; // GetEIP call return location
// === PROTOTYPES ===
void ArchThreads_Init(void);
void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP);
int Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
void Proc_CallFaultHandler(tThread *Thread);
+void Proc_DumpThreadCPUState(tThread *Thread);
void Proc_Scheduler(int CPU);
// === GLOBALS ===
tThread *gCurrentThread = NULL;
tThread *gpIdleThread = NULL;
#endif
-#if USE_PAE
-Uint32 *gPML4s[4] = NULL;
-#endif
tTSS *gTSSs = NULL; // Pointer to TSS array
tTSS gTSS0 = {0};
// --- Error Recovery ---
#else
giNumCPUs = 1;
gTSSs = &gTSS0;
- MM_FinishVirtualInit();
#endif
#if !DEBUG_DISABLE_DOUBLEFAULT
#endif
gThreadZero.CurCPU = 0;
- #if USE_PAE
- gThreadZero.MemState.PDP[0] = 0;
- gThreadZero.MemState.PDP[1] = 0;
- gThreadZero.MemState.PDP[2] = 0;
- #else
gThreadZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
- #endif
// Create Per-Process Data Block
if( !MM_Allocate(MM_PPD_CFG) )
{
- Panic("OOM - No space for initiali Per-Process Config");
+ Panic("OOM - No space for initial Per-Process Config");
}
// Change Stacks
Uint tmpEbp, oldEsp = esp;
// Set CR3
- #if USE_PAE
- # warning "PAE Unimplemented"
- #else
newThread->MemState.CR3 = cur->MemState.CR3;
- #endif
// Create new KStack
newThread->KernelStack = MM_NewKStack();
newThread->SavedState.EBP = ebp;
eip = GetEIP();
if(eip == SWITCH_MAGIC) {
- __asm__ __volatile__ ("mov %0, %%db0" : : "r" (newThread) );
+ //__asm__ __volatile__ ("mov %0, %%db0" : : "r" (newThread) );
#if USE_MP
// ACK the interrupt
if( GetCPUNum() )
new->SavedState.EBP = ebp;
eip = GetEIP();
if(eip == SWITCH_MAGIC) {
- __asm__ __volatile__ ("mov %0, %%db0" : : "r"(new));
+ //__asm__ __volatile__ ("mov %0, %%db0" : : "r"(new));
#if USE_MP
// ACK the interrupt
if(GetCPUNum())
for(;;);
}
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+ if( Thread->CurCPU > -1 )
+ {
+ int maxBacktraceDistance = 6;
+ tRegs *regs = NULL;
+ Uint32 *stack;
+
+ if( Thread->CurCPU != GetCPUNum() ) {
+ Log(" Currently running");
+ return ;
+ }
+
+ // Backtrace to find the IRQ entrypoint
+ // - This will usually only be called by an IRQ, so this should
+ // work
+ __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
+ while( maxBacktraceDistance -- )
+ {
+ // [ebp] = oldEbp
+ // [ebp+4] = retaddr
+
+ if( stack[1] == (tVAddr)&IRQCommon_handled ) {
+ regs = (void*)stack[2];
+ break;
+ }
+
+ stack = (void*)stack[0];
+ }
+
+ if( !regs ) {
+ Log(" Unable to find IRQ Entry");
+ return ;
+ }
+
+ Log(" at %04x:%08x", regs->cs, regs->eip);
+ return ;
+ }
+
+ #if 1
+ tVAddr diffFromScheduler = Thread->SavedState.EIP - (tVAddr)Proc_Scheduler;
+ tVAddr diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_Clone;
+ tVAddr diffFromSpawn = Thread->SavedState.EIP - (tVAddr)Proc_SpawnWorker;
+
+ if( diffFromClone > 0 && diffFromClone < 512 ) // When I last checked, GetEIP was at .+0x183
+ {
+ Log(" Creating full thread");
+ return ;
+ }
+
+ if( diffFromSpawn > 0 && diffFromSpawn < 512 ) // When I last checked, GetEIP was at .+0x99
+ {
+ Log(" Creating worker thread");
+ return ;
+ }
+
+ if( diffFromScheduler > 0 && diffFromScheduler < 256 ) // When I last checked, GetEIP was at .+0x60
+ #else
+ Uint32 data[3];
+ MM_ReadFromAddrSpace(Thread->MemState.CR3, Thread->SavedState.EBP, data, 12);
+ if( data[1] == (Uint32)&IRQCommon + 25 )
+ {
+ tRegs *regs = (void *) data[2];
+ Log(" oldebp = 0x%08x, ret = 0x%08x, regs = 0x%x",
+ data[0], data[1], data[2]
+ );
+ // [EBP] = old EBP
+ // [EBP+0x04] = Return Addr
+ // [EBP+0x08] = Arg 1 (CPU Number)
+ // [EBP+0x0C] = Arg 2 (Thread)
+ // [EBP+0x10] = GS (start of tRegs)
+ Log(" IRQ%i from %02x:%08x", regs->int_num regs->cs, regs->eip);
+ }
+ if( stack[1] == (Uint32)&scheduler_return )
+ #endif
+ {
+ // Scheduled out
+ Log(" At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
+ return ;
+ }
+
+ Log(" Just created (unknow %p)", Thread->SavedState.EIP);
+}
+
/**
* \fn void Proc_Scheduler(int CPU)
* \brief Swap current thread and clears dead threads
thread = gCurrentThread;
#endif
+ // NOTE:
+ // 2011-04-05
+ // Bug may be caused by DR0 not being maintained somewhere, hence
+ // login is getting loaded with the idle state.
if( thread )
{
+ tRegs *regs;
// Reduce remaining quantum and continue timeslice if non-zero
if( thread->Remaining-- )
return;
thread->SavedState.ESP = esp;
thread->SavedState.EBP = ebp;
thread->SavedState.EIP = eip;
+
+ // TODO: Make this more stable somehow
+ regs = (tRegs*)(ebp+(2+2)*4); // EBP,Ret + CPU,CurThread
+ thread->SavedState.UserCS = regs->cs;
+ thread->SavedState.UserEIP = regs->eip;
+
+ if(thread->bInstrTrace) {
+ regs->eflags |= 0x100; // Set TF
+ Log("%p De-scheduled", thread);
+ }
+ else
+ regs->eflags &= ~0x100; // Clear TF
}
// Get next thread to run
thread = Threads_GetNextToRun(CPU, thread);
+
// No avaliable tasks, just go into low power mode (idle thread)
if(thread == NULL) {
#if USE_MP
#endif
}
+ #if DEBUG_TRACE_SWITCH
+ if(thread && thread != Proc_GetCurThread() ) {
+ Log("Switching to task %i(%s), CR3 = 0x%x, EIP = %p",
+ thread->TID,
+ thread->ThreadName,
+ thread->MemState.CR3,
+ thread->SavedState.EIP
+ );
+ }
+ #endif
+
// Set current thread
#if USE_MP
gaCPUs[CPU].Current = thread;
gCurrentThread = thread;
#endif
- #if DEBUG_TRACE_SWITCH
- Log("Switching to task %i, CR3 = 0x%x, EIP = %p",
- thread->TID,
- thread->MemState.CR3,
- thread->SavedState.EIP
- );
- #endif
-
#if USE_MP // MP Debug
- Log("CPU = %i, Thread %p", CPU, thread);
+// Log("CPU = %i, Thread %p", CPU, thread);
#endif
// Update Kernel Stack pointer
}
#endif
- #if USE_PAE
- # error "Todo: Implement PAE Address space switching"
- #else
+ if( thread->bInstrTrace ) {
+ Log("%p Scheduled", thread);
+ }
+
+ // Set thread pointer
+ __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(thread) );
// Switch threads
__asm__ __volatile__ (
"mov %4, %%cr3\n\t" // Set address space
"mov %1, %%esp\n\t" // Restore ESP
"mov %2, %%ebp\n\t" // and EBP
+ "or %5, 72(%%ebp)\n\t" // or trace flag to eflags (2+2+4+8+2)*4
"jmp *%3" : : // And return to where we saved state (Proc_Clone or Proc_Scheduler)
"a"(SWITCH_MAGIC), "b"(thread->SavedState.ESP),
"d"(thread->SavedState.EBP), "c"(thread->SavedState.EIP),
- "r"(thread->MemState.CR3)
+ "r"(thread->MemState.CR3),
+ "r"(thread->bInstrTrace&&thread->SavedState.EIP==(Uint)&GetEIP_Sched_ret?0x100:0)
);
- #endif
for(;;); // Shouldn't reach here
}