Kernel/x86 - Clean up some of the task switching code (possibly a little broken)
[tpg/acess2.git] / KernelLand / Kernel / arch / x86 / proc.c
1 /*
2  * Acess2 Kernel (x86)
3  * - By John Hodge (thePowersGang)
4  *
5  * proc.c
6  * - Low level thread management
7  */
8 #define DEBUG   0
9 #include <acess.h>
10 #include <threads.h>
11 #include <proc.h>
12 #include <desctab.h>
13 #include <mm_virt.h>
14 #include <errno.h>
15 #include <hal_proc.h>
16 #include <arch_int.h>
17 #include <proc_int.h>
18 #if USE_MP
19 # include <apic.h>
20 #endif
21
22 // === FLAGS ===
23 #define DEBUG_TRACE_SWITCH      0
24 #define DEBUG_DISABLE_DOUBLEFAULT       1
25 #define DEBUG_VERY_SLOW_PERIOD  0
26 #define DEBUG_NOPREEMPT 1
27 #define DISABLE_PIT     0
28
29 // === CONSTANTS ===
30 // Base is 1193182
31 #define TIMER_BASE      1193182
32 #if DISABLE_PIT
33 # define TIMER_DIVISOR  0xFFFF
34 #elif DEBUG_VERY_SLOW_PERIOD
35 # define TIMER_DIVISOR  1193    //~10Hz switch, with 10 quantum = 1s per thread
36 #else
37 # define TIMER_DIVISOR  11932   //~100Hz
38 #endif
39
40 // === TYPES ===
41
42 // === IMPORTS ===
43 extern tGDT     gGDT[];
44 extern tIDT     gIDT[];
45 extern void     APWait(void);   // 16-bit AP pause code
46 extern void     APStartup(void);        // 16-bit AP startup code
47 extern Uint     Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
48 extern Uint32   gaInitPageDir[1024];    // start.asm
49 extern char     Kernel_Stack_Top[];
50 extern int      giNumCPUs;
51 extern tThread  gThreadZero;
52 extern tProcess gProcessZero;
53 extern void     Isr8(void);     // Double Fault
54 extern void     Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
55 extern char     scheduler_return[];     // Return address in SchedulerBase
56 extern char     IRQCommon[];    // Common IRQ handler code
57 extern char     IRQCommon_handled[];    // IRQCommon call return location
58 extern char     GetEIP_Sched_ret[];     // GetEIP call return location
59 extern void     Timer_CallTimers(void);
60
61 // === PROTOTYPES ===
62 //void  ArchThreads_Init(void);
63 #if USE_MP
64 void    MP_StartAP(int CPU);
65 void    MP_SendIPIVector(int CPU, Uint8 Vector);
66 void    MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
67 #endif
68 void    Proc_IdleThread(void *Ptr);
69 //void  Proc_Start(void);
70 //tThread       *Proc_GetCurThread(void);
71 void    Proc_ChangeStack(void);
72 // int  Proc_NewKThread(void (*Fcn)(void*), void *Data);
73 void    NewTaskHeader(tThread *Thread, void (*Fcn)(void*), void *Data); // Actually takes cdecl args
74 // int  Proc_Clone(Uint *Err, Uint Flags);
75 Uint    Proc_MakeUserStack(void);
76 //void  Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
77 void    Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NORETURN;
78 void    Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen);
79 //void  Proc_CallFaultHandler(tThread *Thread);
80 //void  Proc_DumpThreadCPUState(tThread *Thread);
81 void    Proc_HandleEventTimer(int CPU);
82
83 // === GLOBALS ===
84 // --- Multiprocessing ---
85 #if USE_MP
86 volatile int    giNumInitingCPUs = 0;
87 volatile Uint32 giMP_TimerCount;        // Start Count for Local APIC Timer
88 tAPIC   *gpMP_LocalAPIC = NULL;
89 Uint8   gaAPIC_to_CPU[256] = {0};
90  int    giProc_BootProcessorID = 0;
91 tTSS    gaTSSs[MAX_CPUS];       // TSS Array
92 #endif
93 tCPU    gaCPUs[MAX_CPUS] = {
94         {.Current = &gThreadZero}
95         };
96 tTSS    *gTSSs = NULL;  // Pointer to TSS array
97 tTSS    gTSS0 = {0};
98 // --- Error Recovery ---
99 char    gaDoubleFaultStack[1024] __attribute__ ((section(".padata")));
100 tTSS    gDoubleFault_TSS = {
101         .ESP0 = (Uint)&gaDoubleFaultStack[1024],
102         .SS0 = 0x10,
103         .CR3 = (Uint)gaInitPageDir - KERNEL_BASE,
104         .EIP = (Uint)Isr8,
105         .ESP = (Uint)&gaDoubleFaultStack[1024],
106         .CS = 0x08,     .SS = 0x10,
107         .DS = 0x10,     .ES = 0x10,
108         .FS = 0x10,     .GS = 0x10,
109 };
110
111 // === CODE ===
112 /**
113  * \fn void ArchThreads_Init(void)
114  * \brief Starts the process scheduler
115  */
116 void ArchThreads_Init(void)
117 {
118         // Mark BSP as active
119         gaCPUs[0].State = 2;
120         
121         #if USE_MP
122         // -- Initialise Multiprocessing
123         const void *mpfloatptr = MPTable_LocateFloatPtr();
124         if( mpfloatptr )
125         {
126                 giNumCPUs = MPTable_FillCPUs(mpfloatptr, gaCPUs, MAX_CPUS, &giProc_BootProcessorID);
127                 for( int i = 0; i < giNumCPUs; i ++ )
128                 {
129                         // TODO: Determine if there's an overlap
130                         gaAPIC_to_CPU[gaCPUs[i].APICID] = i;
131                 }
132                 gTSSs = gaTSSs;
133         }
134         else
135         {
136                 Log("No MP Table was found, assuming uniprocessor");
137                 giNumCPUs = 1;
138                 gTSSs = &gTSS0;
139         }
140         #else
141         giNumCPUs = 1;
142         gTSSs = &gTSS0;
143         #endif
144         
145         #if !DEBUG_DISABLE_DOUBLEFAULT
146         // Initialise Double Fault TSS
147         gGDT[5].BaseLow = (Uint)&gDoubleFault_TSS & 0xFFFF;
148         gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16;
149         gGDT[5].BaseHi = (Uint)&gDoubleFault_TSS >> 24;
150         
151         // Set double fault IDT to use the new TSS
152         gIDT[8].OffsetLo = 0;
153         gIDT[8].CS = 5<<3;
154         gIDT[8].Flags = 0x8500;
155         gIDT[8].OffsetHi = 0;
156         #endif
157         
158         // Set timer frequency
159         outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
160         outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
161         outb(0x40, (TIMER_DIVISOR>>8)&0xFF);    // High Byte
162         
163         Log_Debug("Proc", "PIT Frequency %i.%03i Hz",
164                 TIMER_BASE/TIMER_DIVISOR,
165                 ((Uint64)TIMER_BASE*1000/TIMER_DIVISOR)%1000
166                 );
167         
168         #if USE_MP
169         // Get the count setting for APIC timer
170         Log("Determining APIC Count");
171         __asm__ __volatile__ ("sti");
172         while( giMP_TimerCount == 0 )   __asm__ __volatile__ ("hlt");
173         __asm__ __volatile__ ("cli");
174         Log("APIC Count %i", giMP_TimerCount);
175         {
176                 Uint64  freq = giMP_TimerCount;
177                 freq *= TIMER_BASE;
178                 freq /= TIMER_DIVISOR;
179                 if( (freq /= 1000) < 2*1000)
180                         Log("Bus Frequency %i KHz", freq);
181                 else if( (freq /= 1000) < 2*1000)
182                         Log("Bus Frequency %i MHz", freq);
183                 else if( (freq /= 1000) < 2*1000)
184                         Log("Bus Frequency %i GHz", freq);
185                 else
186                         Log("Bus Frequency %i THz", freq);
187         }
188         
189         // Initialise Normal TSS(s)
190         for(int pos=0;pos<giNumCPUs;pos++)
191         {
192         #else
193         const int pos = 0;
194         #endif
195                 gTSSs[pos].SS0 = 0x10;
196                 gTSSs[pos].ESP0 = 0;    // Set properly by scheduler
197                 gGDT[6+pos].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
198                 gGDT[6+pos].BaseMid = ((Uint)(&gTSSs[pos]) >> 16) & 0xFFFF;
199                 gGDT[6+pos].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
200         #if USE_MP
201         }
202         #endif
203         
204         // Load the BSP's TSS
205         __asm__ __volatile__ ("ltr %%ax"::"a"(0x30));
206         // Set Current Thread and CPU Number in DR0 and DR1
207         __asm__ __volatile__ ("mov %0, %%db0"::"r"(&gThreadZero));
208         __asm__ __volatile__ ("mov %0, %%db1"::"r"(0));
209         
210         gaCPUs[0].Current = &gThreadZero;
211         gThreadZero.CurCPU = 0;
212         
213         gProcessZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
214         
215         // Create Per-Process Data Block
216         if( MM_Allocate( (void*)MM_PPD_CFG ) == 0 )
217         {
218                 Panic("OOM - No space for initial Per-Process Config");
219         }
220
221         // Initialise SSE support
222         Proc_InitialiseSSE();
223         
224         // Change Stacks
225         Proc_ChangeStack();
226 }
227
228 #if USE_MP
229 /**
230  * \brief Start an AP
231  */
232 void MP_StartAP(int CPU)
233 {
234         Log_Log("Proc", "Starting AP %i (APIC %i)", CPU, gaCPUs[CPU].APICID);
235         
236         // Set location of AP startup code and mark for a warm restart
237         *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APWait - (KERNEL_BASE|0xFFFF0);
238         *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
239         outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Set warm reset flag
240         MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);   // Init IPI
241
242         // Take a quick nap (20ms)
243         Time_Delay(20);
244
245         // TODO: Use a better address, preferably registered with the MM
246         // - MM_AllocDMA mabye?
247         // Create a far jump
248         *(Uint8*)(KERNEL_BASE|0x11000) = 0xEA;  // Far JMP
249         *(Uint16*)(KERNEL_BASE|0x11001) = (Uint16)(tVAddr)&APStartup + 0x10;    // IP
250         *(Uint16*)(KERNEL_BASE|0x11003) = 0xFFFF;       // CS
251         
252         giNumInitingCPUs ++;
253         
254         // Send a Startup-IPI to make the CPU execute at 0x11000 (which we
255         // just filled)
256         MP_SendIPI(gaCPUs[CPU].APICID, 0x11, 6);        // StartupIPI
257         
258         tTime   timeout = now() + 2;
259         while( giNumInitingCPUs && now() > timeout )
260                 HALT();
261         
262         if( giNumInitingCPUs == 0 )
263                 return ;
264         
265         // First S-IPI failed, send again
266         MP_SendIPI(gaCPUs[CPU].APICID, 0x11, 6);
267         timeout = now() + 2;
268         while( giNumInitingCPUs && now() > timeout )
269                 HALT();
270         if( giNumInitingCPUs == 0 )
271                 return ;
272
273         Log_Notice("Proc", "CPU %i (APIC %x) didn't come up", CPU, gaCPUs[CPU].APICID); 
274
275         // Oh dammit.
276         giNumInitingCPUs = 0;
277 }
278
279 void MP_SendIPIVector(int CPU, Uint8 Vector)
280 {
281         MP_SendIPI(gaCPUs[CPU].APICID, Vector, 0);
282 }
283
284 /**
285  * \brief Send an Inter-Processor Interrupt
286  * \param APICID        Processor's Local APIC ID
287  * \param Vector        Argument of some kind
288  * \param DeliveryMode  Type of signal
289  * \note 3A 10.5 "APIC/Handling Local Interrupts"
290  */
291 void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
292 {
293         Uint32  val;
294         
295         // Hi
296         val = (Uint)APICID << 24;
297         gpMP_LocalAPIC->ICR[1].Val = val;
298         // Low (and send)
299         val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
300         gpMP_LocalAPIC->ICR[0].Val = val;
301 }
302 #endif
303
304 void Proc_IdleThread(void *Ptr)
305 {
306         tCPU    *cpu = &gaCPUs[GetCPUNum()];
307         cpu->Current->ThreadName = strdup("Idle Thread");
308         Threads_SetPriority( cpu->Current, -1 );        // Never called randomly
309         cpu->Current->Quantum = 1;      // 1 slice quantum
310         LOG("Idle thread for CPU %i ready", GetCPUNum());
311         for(;;)
312         {
313                 __asm__ __volatile__ ("sti");   // Make sure interrupts are enabled
314                 Proc_Reschedule();      // Reshedule
315                 __asm__ __volatile__ ("hlt");   // And wait for an interrupt if we get scheduled again
316         }
317 }
318
319 /**
320  * \fn void Proc_Start(void)
321  * \brief Start process scheduler
322  */
323 void Proc_Start(void)
324 {
325         #if USE_MP
326         // BSP still should run the current task
327         gaCPUs[giProc_BootProcessorID].Current = &gThreadZero;
328         
329         __asm__ __volatile__ ("sti");
330         
331         // Start APs
332         for( int i = 0; i < giNumCPUs; i ++ )
333         {
334                 if(i != giProc_BootProcessorID)
335                         gaCPUs[i].Current = NULL;
336
337                 // Create Idle Task
338                 Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
339                 
340                 // Start the AP
341                 if( i != giProc_BootProcessorID ) {
342                         MP_StartAP( i );
343                 }
344         }
345         #else
346         // Create Idle Task
347         Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
348         
349         // Set current task
350         gaCPUs[0].Current = &gThreadZero;
351
352         // Start Interrupts (and hence scheduler)
353         __asm__ __volatile__("sti");
354         #endif
355         MM_FinishVirtualInit();
356 }
357
358 /**
359  * \fn tThread *Proc_GetCurThread(void)
360  * \brief Gets the current thread
361  */
362 tThread *Proc_GetCurThread(void)
363 {
364         #if USE_MP
365         return gaCPUs[ GetCPUNum() ].Current;
366         #else
367         return gaCPUs[ 0 ].Current;
368         #endif
369 }
370
371 /**
372  * \fn void Proc_ChangeStack(void)
373  * \brief Swaps the current stack for a new one (in the proper stack reigon)
374  */
375 void Proc_ChangeStack(void)
376 {
377         Uint    esp, ebp;
378         Uint    tmpEbp, oldEsp;
379         Uint    curBase, newBase;
380
381         __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
382         __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
383
384         oldEsp = esp;
385
386         // Create new KStack
387         newBase = MM_NewKStack();
388         // Check for errors
389         if(newBase == 0) {
390                 Panic("What the?? Unable to allocate space for initial kernel stack");
391                 return;
392         }
393
394         curBase = (Uint)&Kernel_Stack_Top;
395         
396         LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
397
398         // Get ESP as a used size
399         esp = curBase - esp;
400         LOG("memcpy( %p, %p, 0x%x )", (void*)(newBase - esp), (void*)(curBase - esp), esp );
401         // Copy used stack
402         memcpy( (void*)(newBase - esp), (void*)(curBase - esp), esp );
403         // Get ESP as an offset in the new stack
404         esp = newBase - esp;
405         // Adjust EBP
406         ebp = newBase - (curBase - ebp);
407
408         // Repair EBPs & Stack Addresses
409         // Catches arguments also, but may trash stack-address-like values
410         for(tmpEbp = esp; tmpEbp < newBase; tmpEbp += 4)
411         {
412                 if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < curBase)
413                         *(Uint*)tmpEbp += newBase - curBase;
414         }
415         
416         Proc_GetCurThread()->KernelStack = newBase;
417         
418         __asm__ __volatile__ ("mov %0, %%esp"::"r"(esp));
419         __asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
420 }
421
422 void Proc_ClearProcess(tProcess *Process)
423 {
424         MM_ClearSpace(Process->MemState.CR3);
425 }
426
427 void Proc_ClearThread(tThread *Thread)
428 {
429         if(Thread->SavedState.SSE) {
430                 free(Thread->SavedState.SSE);
431                 Thread->SavedState.SSE = NULL;
432         }
433 }
434
435 tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
436 {
437         tThread *newThread = Threads_CloneTCB(0);
438         if(!newThread)  return -1;
439         
440         // Create new KStack
441         newThread->KernelStack = MM_NewKStack();
442         // Check for errors
443         if(newThread->KernelStack == 0) {
444                 free(newThread);
445                 return -1;
446         }
447         
448         LOG("%p(%i %s) SP=%p", newThread, newThread->TID, newThread->ThreadName, newThread->KernelStack);
449
450         Uint esp = newThread->KernelStack;
451         *(Uint*)(esp-=4) = (Uint)Data;  // Data (shadowed)
452         *(Uint*)(esp-=4) = (Uint)Fcn;   // Function to call
453         *(Uint*)(esp-=4) = (Uint)newThread;     // Thread ID
454         *(Uint*)(esp-=4) = (Uint)0;     // Empty return address
455         
456         newThread->SavedState.ESP = esp;
457         newThread->SavedState.EIP = (Uint)&NewTaskHeader;
458         newThread->SavedState.SSE = NULL;
459 //      Log("New (KThread) %p, esp = %p", newThread->SavedState.EIP, newThread->SavedState.ESP);
460         
461 //      MAGIC_BREAK();  
462         Threads_AddActive(newThread);
463
464         return newThread->TID;
465 }
466
467 void NewTaskHeader(tThread *NewThread, void (*Fcn)(void*), void *Data)
468 {
469         LOG("NewThread=%p, Fcn=%p, Data=%p", NewThread, Fcn, Data);
470         __asm__ __volatile__ ("mov %0, %%dr0" : : "r"(NewThread));
471         SHORTREL(&glThreadListLock);
472         Fcn(Data);
473         
474         Threads_Exit(0, 0);
475         for(;;);
476 }
477
478 /**
479  * \fn int Proc_Clone(Uint *Err, Uint Flags)
480  * \brief Clone the current process
481  */
482 tPID Proc_Clone(Uint Flags)
483 {
484         tThread *cur = Proc_GetCurThread();
485
486         // Sanity, please
487         if( !(Flags & CLONE_VM) ) {
488                 Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
489                 return -1;
490         }
491         
492         // New thread
493         tThread *newThread = Threads_CloneTCB(Flags);
494         if(!newThread)  return -1;
495         ASSERT(newThread->Process);
496
497         newThread->KernelStack = cur->KernelStack;
498
499         // Clone state
500         Uint eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
501         if( eip == 0 ) {
502                 SHORTREL( &glThreadListLock );
503                 LOG("In new thread");
504                 return 0;
505         }
506         //ASSERT(newThread->Process);
507         //ASSERT(CheckMem(newThread->Process, sizeof(tProcess)));
508         //LOG("newThread->Process = %p", newThread->Process);
509         newThread->SavedState.EIP = eip;
510         newThread->SavedState.SSE = NULL;
511         newThread->SavedState.bSSEModified = 0;
512         
513         // Check for errors
514         if( newThread->Process->MemState.CR3 == 0 ) {
515                 Log_Error("Proc", "Proc_Clone: MM_Clone failed");
516                 Threads_Delete(newThread);
517                 return -1;
518         }
519
520         // Add the new thread to the run queue
521         Threads_AddActive(newThread);
522         return newThread->TID;
523 }
524
525 /**
526  * \fn int Proc_SpawnWorker(void)
527  * \brief Spawns a new worker thread
528  */
529 tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
530 {
531         Uint    stack_contents[4];
532         LOG("(Fcn=%p,Data=%p)", Fcn, Data);
533         
534         // Create new thread
535         tThread *new = Threads_CloneThreadZero();
536         LOG("new=%p", new);
537         if(!new) {
538                 Warning("Proc_SpawnWorker - Out of heap space!\n");
539                 return NULL;
540         }
541         LOG("new = (%i %s)", new->TID, new->ThreadName);
542
543         // Create the stack contents
544         stack_contents[3] = (Uint)Data;
545         stack_contents[2] = (Uint)Fcn;
546         stack_contents[1] = (Uint)new;
547         stack_contents[0] = 0;
548         
549         // Create a new worker stack (in PID0's address space)
550         new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
551         LOG("new->KernelStack = %p", new->KernelStack);
552
553         // Save core machine state
554         new->SavedState.ESP = new->KernelStack - sizeof(stack_contents);
555         new->SavedState.EIP = (Uint)NewTaskHeader;
556         new->SavedState.SSE = NULL;
557         new->SavedState.bSSEModified = 0;
558         
559         // Mark as active
560         new->Status = THREAD_STAT_PREINIT;
561         Threads_AddActive( new );
562         LOG("Added to active");
563         
564         return new;
565 }
566
567 /**
568  * \fn Uint Proc_MakeUserStack(void)
569  * \brief Creates a new user stack
570  */
571 Uint Proc_MakeUserStack(void)
572 {
573         tPage   *base = (void*)(USER_STACK_TOP - USER_STACK_SZ);
574         
575         // Check Prospective Space
576         for( Uint i = USER_STACK_SZ/PAGE_SIZE; i--; )
577         {
578                 if( MM_GetPhysAddr( base + i ) != 0 )
579                 {
580                         Warning("Proc_MakeUserStack: Address %p in use", base + i);
581                         return 0;
582                 }
583         }
584         // Allocate Stack - Allocate incrementally to clean up MM_Dump output
585         for( Uint i = 0; i < USER_STACK_SZ/PAGE_SIZE; i++ )
586         {
587                 if( MM_Allocate( base + i ) == 0 )
588                 {
589                         Warning("OOM: Proc_MakeUserStack");
590                         return 0;
591                 }
592         }
593         
594         return (tVAddr)( base + USER_STACK_SZ/PAGE_SIZE );
595 }
596
597 void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
598 {
599         Uint    *stack;
600          int    i;
601         const char      **envp = NULL;
602         Uint16  ss, cs;
603         
604         // Copy data to the user stack and free original buffer
605         stack = (void*)Proc_MakeUserStack();
606         stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
607         memcpy( stack, ArgV, DataSize );
608         free(ArgV);
609         
610         // Adjust Arguments and environment
611         if( DataSize )
612         {
613                 Uint delta = (Uint)stack - (Uint)ArgV;
614                 ArgV = (const char**)stack;
615                 for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
616                 envp = &ArgV[i+1];
617                 for( i = 0; envp[i]; i++ )      envp[i] += delta;
618         }
619         
620         // User Mode Segments
621         ss = 0x23;      cs = 0x1B;
622         
623         // Arguments
624         *--stack = (Uint)envp;
625         *--stack = (Uint)ArgV;
626         *--stack = (Uint)ArgC;
627         *--stack = Base;
628         
629         Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
630 }
631
632 void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
633 {
634         Uint    *stack = (void*)Stack;
635         *--stack = SS;          //Stack Segment
636         *--stack = Stack;       //Stack Pointer
637         *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
638         *--stack = CS;          //Code Segment
639         *--stack = IP;  //EIP
640         //PUSHAD
641         *--stack = 0xAAAAAAAA;  // eax
642         *--stack = 0xCCCCCCCC;  // ecx
643         *--stack = 0xDDDDDDDD;  // edx
644         *--stack = 0xBBBBBBBB;  // ebx
645         *--stack = 0xD1D1D1D1;  // edi
646         *--stack = 0x54545454;  // esp - NOT POPED
647         *--stack = 0x51515151;  // esi
648         *--stack = 0xB4B4B4B4;  // ebp
649         //Individual PUSHs
650         *--stack = SS;  // ds
651         *--stack = SS;  // es
652         *--stack = SS;  // fs
653         *--stack = SS;  // gs
654         
655         __asm__ __volatile__ (
656         "mov %%eax,%%esp;\n\t"  // Set stack pointer
657         "pop %%gs;\n\t"
658         "pop %%fs;\n\t"
659         "pop %%es;\n\t"
660         "pop %%ds;\n\t"
661         "popa;\n\t"
662         "iret;\n\t" : : "a" (stack));
663         for(;;);
664 }
665
666 void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen)
667 {
668         if( UserSP < StackDataLen )
669                 return ;
670         if( !CheckMem( (void*)(UserSP - StackDataLen), StackDataLen ) )
671                 return ;
672         memcpy( (void*)(UserSP - StackDataLen), StackData, StackDataLen );
673         
674         __asm__ __volatile__ (
675                 "mov $0x23,%%ax;\n\t"
676                 "mov %%ax, %%ds;\n\t"
677                 "mov %%ax, %%es;\n\t"
678                 "mov %%ax, %%fs;\n\t"
679                 "mov %%ax, %%gs;\n\t"
680                 "push $0x23;\n\t"
681                 "push %1;\n\t"
682                 "push $0x202;\n\t"
683                 "push $0x1B;\n\t"
684                 "push %0;\n\t"
685                 "iret;\n\t"
686                 :
687                 : "r" (UserIP), "r" (UserSP - StackDataLen)
688                 : "eax"
689                 );
690         for(;;)
691                 ;
692 }
693
694 /**
695  * \brief Calls a signal handler in user mode
696  * \note Used for signals
697  */
698 void Proc_CallFaultHandler(tThread *Thread)
699 {
700         // Rewinds the stack and calls the user function
701         // Never returns
702         Proc_ReturnToUser( Thread->FaultHandler, Thread->CurFaultNum, Thread->KernelStack );
703         for(;;);
704 }
705
706 void Proc_DumpThreadCPUState(tThread *Thread)
707 {
708         if( Thread->CurCPU > -1 )
709         {
710                  int    maxBacktraceDistance = 6;
711                 tRegs   *regs = NULL;
712                 Uint32  *stack;
713                 
714                 if( Thread->CurCPU != GetCPUNum() ) {
715                         Log("  Currently running");
716                         return ;
717                 }
718                 
719                 // Backtrace to find the IRQ entrypoint
720                 // - This will usually only be called by an IRQ, so this should
721                 //   work
722                 __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
723                 while( maxBacktraceDistance -- )
724                 {
725                         if( !CheckMem(stack, 8) ) {
726                                 regs = NULL;
727                                 break;
728                         }
729                         // [ebp] = oldEbp
730                         // [ebp+4] = retaddr
731                         
732                         if( stack[1] == (tVAddr)&IRQCommon_handled ) {
733                                 regs = (void*)stack[2];
734                                 break;
735                         }
736                         
737                         stack = (void*)stack[0];
738                 }
739                 
740                 if( !regs ) {
741                         Log("  Unable to find IRQ Entry");
742                         return ;
743                 }
744                 
745                 Log("  at %04x:%08x [EAX:%x]", regs->cs, regs->eip, regs->eax);
746                 Error_Backtrace(regs->eip, regs->ebp);
747                 return ;
748         }
749
750         Log(" Saved = %p (SP=%p)", Thread->SavedState.EIP, Thread->SavedState.ESP);     
751
752         tVAddr  diffFromScheduler = Thread->SavedState.EIP - (tVAddr)SwitchTasks;
753         tVAddr  diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_CloneInt;
754         tVAddr  diffFromSpawn = Thread->SavedState.EIP - (tVAddr)NewTaskHeader;
755         
756         if( diffFromClone > 0 && diffFromClone < 40 )   // When I last checked, .newTask was at .+27
757         {
758                 Log("  Creating process");
759                 return ;
760         }
761         
762         if( diffFromSpawn == 0 )
763         {
764                 Log("  Creating thread");
765                 return ;
766         }
767         
768         if( diffFromScheduler > 0 && diffFromScheduler < 128 )  // When I last checked, GetEIP was at .+0x30
769         {
770                 // Scheduled out
771                 Log("  At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
772                 return ;
773         }
774         
775         Log("  Just created (unknown %p)", Thread->SavedState.EIP);
776 }
777
778 void Proc_Reschedule(void)
779 {
780          int    cpu = GetCPUNum();
781
782         // TODO: Wait for the lock?
783         if(IS_LOCKED(&glThreadListLock)) {
784                 LOG("Thread list locked, not rescheduling");
785                 return;
786         }
787         
788         SHORTLOCK(&glThreadListLock);
789         
790         tThread *curthread = Proc_GetCurThread();
791         tThread *nextthread = Threads_GetNextToRun(cpu, curthread);
792         
793         if(nextthread && nextthread != curthread)
794         {
795                 #if DEBUG_TRACE_SWITCH
796                 // HACK: Ignores switches to the idle threads
797                 //if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
798                 {
799                         LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
800                                 GetCPUNum(),
801                                 nextthread, nextthread->TID, nextthread->ThreadName,
802                                 nextthread->Process->MemState.CR3,
803                                 nextthread->SavedState.EIP,
804                                 nextthread->SavedState.ESP
805                                 );
806                         LogF(" from %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
807                                 curthread, curthread->TID, curthread->ThreadName,
808                                 curthread->Process->MemState.CR3,
809                                 curthread->SavedState.EIP,
810                                 curthread->SavedState.ESP
811                                 );
812                 }
813                 #endif
814
815                 // Update CPU state
816                 gaCPUs[cpu].Current = nextthread;
817                 gaCPUs[cpu].LastTimerThread = NULL;
818                 gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
819                 __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
820
821                 // Save FPU/MMX/XMM/SSE state
822                 if( curthread && curthread->SavedState.SSE )
823                 {
824                         Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
825                         curthread->SavedState.bSSEModified = 0;
826                         Proc_DisableSSE();
827                 }
828
829                 if( curthread )
830                 {
831                         SwitchTasks(
832                                 nextthread->SavedState.ESP, &curthread->SavedState.ESP,
833                                 nextthread->SavedState.EIP, &curthread->SavedState.EIP,
834                                 nextthread->Process->MemState.CR3
835                                 );
836                 }
837                 else
838                 {
839                         SwitchTasks(
840                                 nextthread->SavedState.ESP, 0,
841                                 nextthread->SavedState.EIP, 0,
842                                 nextthread->Process->MemState.CR3
843                                 );
844                 }
845         }
846         
847         SHORTREL(&glThreadListLock);
848 }
849
850 /**
851  * \brief Handle the per-CPU timer ticking
852  
853  */
854 void Proc_HandleEventTimer(int CPU)
855 {
856         // Call the timer update code
857         Timer_CallTimers();
858
859         #if !DEBUG_NOPREEMPT
860         // If two ticks happen within the same task, and it's not an idle task, swap
861         if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread )
862         {
863                 const tThread* const t = gaCPUs[CPU].Current;
864                 LOG("Preempting thread %p(%i %s)", t, t->TID, t->ThreadName);
865                 Proc_Reschedule();
866         }
867         
868         gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current;
869         #endif
870 }
871
872 // === EXPORTS ===
873 EXPORT(Proc_SpawnWorker);

UCC git Repository :: git.ucc.asn.au