#if USE_MP
# include <mp.h>
#endif
+#include <hal_proc.h>
// === FLAGS ===
-#define DEBUG_TRACE_SWITCH 1
+#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 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 void NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...); // Actually takes cdecl args
extern Uint32 gaInitPageDir[1024]; // start.asm
extern char Kernel_Stack_Top[];
extern tShortSpinlock glThreadListLock;
extern void GetEIP_Sched_ret; // GetEIP call return location
// === PROTOTYPES ===
-void ArchThreads_Init(void);
+//void ArchThreads_Init(void);
#if USE_MP
void MP_StartAP(int CPU);
void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
void Proc_ChangeStack(void);
// 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_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);
int Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
-void Proc_CallFaultHandler(tThread *Thread);
-void Proc_DumpThreadCPUState(tThread *Thread);
+//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 ---
#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
while( giNumInitingCPUs ) __asm__ __volatile__ ("hlt");
#else
// Create Idle Task
- if(Proc_Clone(0, 0) == 0)
+ if(Proc_Clone(0) == 0)
{
gpIdleThread = Proc_GetCurThread();
gpIdleThread->ThreadName = strdup("Idle Thread");
* \fn int Proc_Clone(Uint *Err, Uint Flags)
* \brief Clone the current process
*/
-int Proc_Clone(Uint *Err, Uint Flags)
+int Proc_Clone(Uint Flags)
{
tThread *newThread;
tThread *cur = Proc_GetCurThread();
__asm__ __volatile__ ("mov %%esp, %0": "=r"(esp));
__asm__ __volatile__ ("mov %%ebp, %0": "=r"(ebp));
- newThread = Threads_CloneTCB(Err, Flags);
+ newThread = Threads_CloneTCB(NULL, Flags);
if(!newThread) return -1;
// Initialise Memory Space (New Addr space or kernel stack)
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.ESP = esp;
newThread->SavedState.EBP = ebp;
eip = GetEIP();
- if(eip == SWITCH_MAGIC) {
+ if(eip == 0) {
//__asm__ __volatile__ ("mov %0, %%db0" : : "r" (newThread) );
#if USE_MP
// ACK the interrupt
* \fn int Proc_SpawnWorker(void)
* \brief Spawns a new worker thread
*/
-int Proc_SpawnWorker(void)
+int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
{
- tThread *new, *cur;
- Uint eip, esp, ebp;
-
- cur = Proc_GetCurThread();
+ tThread *new;
+ Uint stack_contents[4];
// Create new thread
new = Threads_CloneThreadZero();
Warning("Proc_SpawnWorker - Out of heap space!\n");
return -1;
}
- // Create a new worker stack (in PID0's address space)
- // - The stack is relocated by this function
- 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 = new->KernelStack - (cur->KernelStack - esp);
- ebp = new->KernelStack - (cur->KernelStack - ebp);
+ // Create the stack contents
+ stack_contents[3] = (Uint)Data;
+ stack_contents[2] = 1;
+ stack_contents[1] = (Uint)Fcn;
+ stack_contents[0] = (Uint)new;
+ // Create a new worker stack (in PID0's address space)
+ new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
+
// Save core machine state
- new->SavedState.ESP = esp;
- new->SavedState.EBP = ebp;
- eip = GetEIP();
- if(eip == SWITCH_MAGIC) {
- //__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;
- }
+ new->SavedState.ESP = new->KernelStack - sizeof(stack_contents);
+ new->SavedState.EBP = 0;
+ new->SavedState.EIP = (Uint)NewTaskHeader;
- // Set EIP as parent
- new->SavedState.EIP = eip;
// Mark as active
+ new->Status = THREAD_STAT_PREINIT;
Threads_AddActive( new );
return new->TID;
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;
__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
+ if(eip == 0) {
+ __asm__ __volatile__ ( "nop" : : : "eax","ebx","ecx","edx","edi","esi");
+ regs = (tRegs*)(ebp+(2+2)*4); // EBP,Ret + CPU,CurThread
+ #if USE_MP
+ thread = gaCPUs[CPU].Current;
+ #else
+ thread = gCurrentThread;
+ #endif
+ if(thread->bInstrTrace) {
+ regs->eflags |= 0x100; // Set TF
+// LogF("Tracing enabled\n");
+ Log("%p Scheduled (EIP = %p)", thread, thread->SavedState.EIP);
+ }
+ else
+ regs->eflags &= ~0x100;
+
+ return; // Check if a switch happened
+ }
// Save machine state
thread->SavedState.ESP = esp;
thread = Threads_GetNextToRun(CPU, thread);
- #if DEBUG_TRACE_SWITCH
- if(thread) {
- Log("Switching to task %i(%s), CR3 = 0x%x, EIP = %p",
- thread->TID,
- thread->ThreadName,
- thread->MemState.CR3,
- thread->SavedState.EIP
- );
- }
- #endif
-
// 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;
#endif
if( thread->bInstrTrace ) {
- Log("%p Scheduled", thread);
+ Log("%p Scheduled (EIP = %p)", thread, thread->SavedState.EIP);
}
- #if USE_PAE
- # error "Todo: Implement PAE Address space switching"
- #else
// 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),
+ "mov %3, %%cr3\n\t" // Set address space
+ "mov %0, %%esp\n\t" // Restore ESP
+ "mov %1, %%ebp\n\t" // and EBP
+ "test %4, %4\n\t"
+ "jz 1f\n\t"
+ "or %4, 72(%%ebp)\n\t" // or trace flag to eflags (2+2+4+8+2)*4
+ "1:"
+ "xor %%eax, %%eax\n\t"
+ "jmp *%2" : : // And return to where we saved state (Proc_Clone or Proc_Scheduler)
+ "r"(thread->SavedState.ESP),
+ "r"(thread->SavedState.EBP),
+ "r"(thread->SavedState.EIP),
"r"(thread->MemState.CR3),
"r"(thread->bInstrTrace&&thread->SavedState.EIP==(Uint)&GetEIP_Sched_ret?0x100:0)
);
- #endif
for(;;); // Shouldn't reach here
}