extern Uint GetRIP(void); // start.asm
extern Uint SaveState(Uint *RSP, Uint *Regs);
+extern Uint Proc_CloneInt(Uint *RSP, Uint *CR3);
extern void NewTaskHeader(void); // Actually takes cdecl args
extern Uint64 gInitialPML4[512]; // start.asm
extern int giNumActiveThreads;
extern tThread gThreadZero;
extern void Threads_Dump(void);
-extern void Proc_ReturnToUser(void);
+extern void Proc_ReturnToUser(tVAddr Handler, tVAddr KStackTop, int Argument);
extern void Time_UpdateTimestamp(void);
+extern void SwitchTasks(Uint NewSP, Uint *OldSP, Uint NewIP, Uint *OldIO, Uint CR3);
// === PROTOTYPES ===
//void ArchThreads_Init(void);
int Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
//void Proc_CallFaultHandler(tThread *Thread);
//void Proc_DumpThreadCPUState(tThread *Thread);
+//void Proc_Reschedule(void);
void Proc_Scheduler(int CPU, Uint RSP, Uint RIP);
// === GLOBALS ===
cpu->IdleThread->ThreadName = (char*)"Idle Thread";
Threads_SetPriority( cpu->IdleThread, -1 ); // Never called randomly
cpu->IdleThread->Quantum = 1; // 1 slice quantum
- for(;;) HALT(); // Just yeilds
+ for(;;) {
+ HALT(); // Just yeilds
+ Threads_Yield();
+ }
}
/**
__asm__ __volatile__("sti");
#endif
MM_FinishVirtualInit();
- Log("Multithreading started");
+ Log_Log("Proc", "Multithreading started");
}
/**
#endif
}
+/**
+ * \brief Create a new kernel thread
+ */
int Proc_NewKThread(void (*Fcn)(void*), void *Data)
{
Uint rsp;
tThread *newThread, *cur;
cur = Proc_GetCurThread();
- newThread = Threads_CloneTCB(NULL, 0);
+ newThread = Threads_CloneTCB(0);
if(!newThread) return -1;
// Set CR3
newThread->SavedState.RSP = rsp;
newThread->SavedState.RIP = (Uint)&NewTaskHeader;
- Log("New (KThread) %p, rsp = %p\n", newThread->SavedState.RIP, newThread->SavedState.RSP);
+// Log("New (KThread) %p, rsp = %p\n", newThread->SavedState.RIP, newThread->SavedState.RSP);
// MAGIC_BREAK();
Threads_AddActive(newThread);
{
tThread *newThread, *cur = Proc_GetCurThread();
Uint rip;
- Uint _savedregs[16+1];
-
- newThread = Threads_CloneTCB(NULL, Flags);
- if(!newThread) return -1;
-
- // Save core machine state
- rip = SaveState(&newThread->SavedState.RSP, &_savedregs[0]);
- if(rip == 0) {
- outb(0x20, 0x20); // ACK Timer and return as child
- __asm__ __volatile__ ("sti");
- return 0;
- }
-
- // Initialise Memory Space (New Addr space or kernel stack)
- if(Flags & CLONE_VM) {
- newThread->MemState.CR3 = MM_Clone();
- newThread->KernelStack = cur->KernelStack;
- }
- else {
+
+ // Sanity check
+ if( !(Flags & CLONE_VM) ) {
Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
return -1;
}
+
+ // Create new TCB
+ newThread = Threads_CloneTCB(Flags);
+ if(!newThread) return -1;
- Log("New (Clone) %p, rsp = %p", rip, newThread->SavedState.RSP);
+ // Save core machine state
+ rip = Proc_CloneInt(&newThread->SavedState.RSP, &newThread->MemState.CR3);
+ if(rip == 0) return 0; // Child
+ newThread->KernelStack = cur->KernelStack;
+ newThread->SavedState.RIP = rip;
+
+ // DEBUG
+ #if 0
+ Log("New (Clone) %p, rsp = %p, cr3 = %p", rip, newThread->SavedState.RSP, newThread->MemState.CR3);
{
Uint cr3;
__asm__ __volatile__ ("mov %%cr3, %0" : "=r" (cr3));
- Log(" CR3 = %x, PADDR(RSP) = %x", cr3, MM_GetPhysAddr(newThread->SavedState.RSP));
+ Log("Current CR3 = 0x%x, PADDR(RSP) = 0x%x", cr3, MM_GetPhysAddr(newThread->SavedState.RSP));
}
-
- // Set EIP as parent
- newThread->SavedState.RIP = rip;
+ #endif
+ // /DEBUG
// Lock list and add to active
Threads_AddActive(newThread);
new->SavedState.RSP = new->KernelStack - sizeof(stack_contents);
new->SavedState.RIP = (Uint)&NewTaskHeader;
- Log("New (Worker) %p, rsp = %p\n", new->SavedState.RIP, new->SavedState.RSP);
+// Log("New (Worker) %p, rsp = %p\n", new->SavedState.RIP, new->SavedState.RSP);
// Mark as active
new->Status = THREAD_STAT_PREINIT;
}
/**
- * \fn Uint Proc_MakeUserStack(void)
* \brief Creates a new user stack
*/
Uint Proc_MakeUserStack(void)
// Check Prospective Space
for( i = USER_STACK_SZ >> 12; i--; )
+ {
if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
break;
+ }
if(i != -1) return 0;
// Allocate Stack - Allocate incrementally to clean up MM_Dump output
- for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
+ for( i = 0; i < (USER_STACK_SZ-USER_STACK_PREALLOC)/0x1000; i++ )
+ {
+ MM_AllocateZero( base + (i<<12) );
+ }
+ for( ; i < USER_STACK_SZ/0x1000; i++ )
{
- if( !MM_Allocate( base + (i<<12) ) )
+ tPAddr alloc = MM_Allocate( base + (i<<12) );
+ if( !alloc )
{
// Error
Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
}
-/**
- * \fn void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
- * \brief Starts a user task
- */
-void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, char **ArgV, int DataSize)
{
- Uint *stack = (void*)Proc_MakeUserStack();
+ Uint *stack;
+ char **envp;
int i;
Uint delta;
Uint16 ss, cs;
- LOG("stack = 0x%x", stack);
// Copy Arguments
- stack = (void*)( (Uint)stack - DataSize );
+ stack = (void*)Proc_MakeUserStack();
+ if(!stack) {
+ Log_Error("Proc", "Unable to create user stack!");
+ Threads_Exit(0, -1);
+ }
+ stack -= (DataSize+7)/8;
+ LOG("stack = 0x%x", stack);
+ Log("stack = %p, DataSize = %i", stack, DataSize);
memcpy( stack, ArgV, DataSize );
+ free(ArgV);
// Adjust Arguments and environment
delta = (Uint)stack - (Uint)ArgV;
ArgV = (char**)stack;
for( i = 0; ArgV[i]; i++ ) ArgV[i] += delta;
- i ++;
- EnvP = &ArgV[i];
- for( i = 0; EnvP[i]; i++ ) EnvP[i] += delta;
+ envp = &ArgV[i+1];
+ for( i = 0; envp[i]; i++ ) envp[i] += delta;
// User Mode Segments
// 0x2B = 64-bit
ss = 0x23; cs = 0x2B;
// Arguments
- *--stack = (Uint)EnvP;
+ *--stack = (Uint)envp;
*--stack = (Uint)ArgV;
*--stack = (Uint)ArgC;
- while(*Bases)
- *--stack = *Bases++;
+ *--stack = Base;
Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
}
CS, SS);
Threads_Exit(0, -1);
}
- Log("Proc_StartProcess: (SS=%x, Stack=%p, Flags=%x, CS=%x, IP=%p)",
- SS, Stack, Flags, CS, IP);
+// Log("Proc_StartProcess: (SS=%x, Stack=%p, Flags=%x, CS=%x, IP=%p)", SS, Stack, Flags, CS, IP);
+// MM_DumpTables(0, USER_MAX);
if(CS == 0x1B)
{
// 32-bit return
*/
void Proc_CallFaultHandler(tThread *Thread)
{
- // Rewinds the stack and calls the user function
// Never returns
- __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler));
+ Proc_ReturnToUser(Thread->FaultHandler, Thread->KernelStack, Thread->CurFaultNum);
for(;;);
}
Log(" At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
}
+void Proc_Reschedule(void)
+{
+ tThread *nextthread, *curthread;
+ int cpu = GetCPUNum();
+
+ // TODO: Wait for it?
+ if(IS_LOCKED(&glThreadListLock)) return;
+
+ curthread = gaCPUs[cpu].Current;
+
+ nextthread = Threads_GetNextToRun(cpu, curthread);
+
+ if(nextthread == curthread) return ;
+ if(!nextthread)
+ nextthread = gaCPUs[cpu].IdleThread;
+ if(!nextthread)
+ return ;
+
+ #if DEBUG_TRACE_SWITCH
+ LogF("\nSwitching to task CR3 = 0x%x, RIP = %p, RSP = %p - %i (%s)\n",
+ nextthread->MemState.CR3,
+ nextthread->SavedState.RIP,
+ nextthread->SavedState.RSP,
+ nextthread->TID,
+ nextthread->ThreadName
+ );
+ #endif
+
+ // Update CPU state
+ gaCPUs[cpu].Current = nextthread;
+ gTSSs[cpu].RSP0 = nextthread->KernelStack-4;
+ __asm__ __volatile__ ("mov %0, %%db0" : : "r" (nextthread));
+
+ SwitchTasks(
+ nextthread->SavedState.RSP, &curthread->SavedState.RSP,
+ nextthread->SavedState.RIP, &curthread->SavedState.RIP,
+ nextthread->MemState.CR3
+ );
+ return ;
+}
+
/**
* \fn void Proc_Scheduler(int CPU)
* \brief Swap current thread and clears dead threads
*/
void Proc_Scheduler(int CPU, Uint RSP, Uint RIP)
{
+#if 0
+ {
tThread *thread;
- if( CPU == 0 )
- Time_UpdateTimestamp();
-
// If the spinlock is set, let it complete
if(IS_LOCKED(&glThreadListLock)) return;
if(thread->Remaining--) return;
// Reset quantum for next call
thread->Remaining = thread->Quantum;
-
- // Save machine state
- thread->SavedState.RSP = RSP;
- thread->SavedState.RIP = RIP;
-
-// LogF("\nSaved %i, RIP = %p, rsp = %p\n", thread->TID, thread->SavedState.RIP, thread->SavedState.RSP);
// TODO: Make this more stable somehow
{
}
}
- #if BREAK_ON_SWITCH
- {
- tThread *oldthread = thread;
- #endif
+ // ACK Timer here?
- // Get next thread
- thread = Threads_GetNextToRun(CPU, thread);
-
- // Error Check
- if(thread == NULL) {
- thread = gaCPUs[CPU].IdleThread;
- //Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
-// LogF("Zzzzz.\n");
- //return;
- }
- if(thread == NULL ) {
- return ;
- }
- #if BREAK_ON_SWITCH
- if( thread != oldthread ) {
- MAGIC_BREAK();
+ Proc_Reschedule();
}
- }
- #endif
-
- #if DEBUG_TRACE_SWITCH
- LogF("\nSwitching to task %i, CR3 = 0x%x, RIP = %p, RSP = %p\n",
- thread->TID,
- thread->MemState.CR3,
- thread->SavedState.RIP,
- thread->SavedState.RSP
- );
- #endif
-
-
- if(CPU > MAX_CPUS)
- LogF("CPU = %i", CPU);
- // Set current thread
- gaCPUs[CPU].Current = thread;
-
- // Update Kernel Stack pointer
- gTSSs[CPU].RSP0 = thread->KernelStack-4;
-
- // Switch threads
- __asm__ __volatile__ (
- "mov %2, %%cr3\n\t"
- "mov %0, %%rsp\n\t" // Restore RSP
- "invlpg (%%rsp)\n\t"
- "invlpg 0x1000(%%rsp)\n\t"
- "invlpg -0x1000(%%rsp)\n\t"
- "xor %%eax, %%eax\n\t"
- "jmp *%1" : : // And return to where we saved state (Proc_Clone or Proc_Scheduler)
- "r"(thread->SavedState.RSP), "r"(thread->SavedState.RIP),
- "r"(thread->MemState.CR3)
- );
- for(;;); // Shouldn't reach here
+#endif
}
// === EXPORTS ===