Merge branch 'master' of git://localhost/acess2
[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 void     NewTaskHeader(tThread *Thread, void *Fcn, int nArgs, ...);      // Actually takes cdecl args
48 extern Uint     Proc_CloneInt(Uint *ESP, Uint32 *CR3, int bNoUserClone);
49 extern Uint32   gaInitPageDir[1024];    // start.asm
50 extern char     Kernel_Stack_Top[];
51 extern int      giNumCPUs;
52 extern tThread  gThreadZero;
53 extern tProcess gProcessZero;
54 extern void     Isr8(void);     // Double Fault
55 extern void     Proc_ReturnToUser(tVAddr Handler, Uint Argument, tVAddr KernelStack);
56 extern char     scheduler_return[];     // Return address in SchedulerBase
57 extern char     IRQCommon[];    // Common IRQ handler code
58 extern char     IRQCommon_handled[];    // IRQCommon call return location
59 extern char     GetEIP_Sched_ret[];     // GetEIP call return location
60 extern void     Timer_CallTimers(void);
61
62 // === PROTOTYPES ===
63 //void  ArchThreads_Init(void);
64 #if USE_MP
65 void    MP_StartAP(int CPU);
66 void    MP_SendIPIVector(int CPU, Uint8 Vector);
67 void    MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
68 #endif
69 void    Proc_IdleThread(void *Ptr);
70 //void  Proc_Start(void);
71 //tThread       *Proc_GetCurThread(void);
72 void    Proc_ChangeStack(void);
73 // int  Proc_NewKThread(void (*Fcn)(void*), void *Data);
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_Scheduler(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         for(;;) {
311                 __asm__ __volatile__ ("sti");   // Make sure interrupts are enabled
312                 __asm__ __volatile__ ("hlt");
313                 Proc_Reschedule();
314         }
315 }
316
317 /**
318  * \fn void Proc_Start(void)
319  * \brief Start process scheduler
320  */
321 void Proc_Start(void)
322 {
323         #if USE_MP
324         // BSP still should run the current task
325         gaCPUs[giProc_BootProcessorID].Current = &gThreadZero;
326         
327         __asm__ __volatile__ ("sti");
328         
329         // Start APs
330         for( int i = 0; i < giNumCPUs; i ++ )
331         {
332                 if(i != giProc_BootProcessorID)
333                         gaCPUs[i].Current = NULL;
334
335                 // Create Idle Task
336                 Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
337                 
338                 // Start the AP
339                 if( i != giProc_BootProcessorID ) {
340                         MP_StartAP( i );
341                 }
342         }
343         #else
344         // Create Idle Task
345         Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
346         
347         // Set current task
348         gaCPUs[0].Current = &gThreadZero;
349
350         // Start Interrupts (and hence scheduler)
351         __asm__ __volatile__("sti");
352         #endif
353         MM_FinishVirtualInit();
354 }
355
356 /**
357  * \fn tThread *Proc_GetCurThread(void)
358  * \brief Gets the current thread
359  */
360 tThread *Proc_GetCurThread(void)
361 {
362         #if USE_MP
363         return gaCPUs[ GetCPUNum() ].Current;
364         #else
365         return gaCPUs[ 0 ].Current;
366         #endif
367 }
368
369 /**
370  * \fn void Proc_ChangeStack(void)
371  * \brief Swaps the current stack for a new one (in the proper stack reigon)
372  */
373 void Proc_ChangeStack(void)
374 {
375         Uint    esp, ebp;
376         Uint    tmpEbp, oldEsp;
377         Uint    curBase, newBase;
378
379         __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
380         __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
381
382         oldEsp = esp;
383
384         // Create new KStack
385         newBase = MM_NewKStack();
386         // Check for errors
387         if(newBase == 0) {
388                 Panic("What the?? Unable to allocate space for initial kernel stack");
389                 return;
390         }
391
392         curBase = (Uint)&Kernel_Stack_Top;
393         
394         LOG("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
395
396         // Get ESP as a used size
397         esp = curBase - esp;
398         LOG("memcpy( %p, %p, 0x%x )", (void*)(newBase - esp), (void*)(curBase - esp), esp );
399         // Copy used stack
400         memcpy( (void*)(newBase - esp), (void*)(curBase - esp), esp );
401         // Get ESP as an offset in the new stack
402         esp = newBase - esp;
403         // Adjust EBP
404         ebp = newBase - (curBase - ebp);
405
406         // Repair EBPs & Stack Addresses
407         // Catches arguments also, but may trash stack-address-like values
408         for(tmpEbp = esp; tmpEbp < newBase; tmpEbp += 4)
409         {
410                 if(oldEsp < *(Uint*)tmpEbp && *(Uint*)tmpEbp < curBase)
411                         *(Uint*)tmpEbp += newBase - curBase;
412         }
413         
414         Proc_GetCurThread()->KernelStack = newBase;
415         
416         __asm__ __volatile__ ("mov %0, %%esp"::"r"(esp));
417         __asm__ __volatile__ ("mov %0, %%ebp"::"r"(ebp));
418 }
419
420 void Proc_ClearProcess(tProcess *Process)
421 {
422         MM_ClearSpace(Process->MemState.CR3);
423 }
424
425 void Proc_ClearThread(tThread *Thread)
426 {
427         if(Thread->SavedState.SSE) {
428                 free(Thread->SavedState.SSE);
429                 Thread->SavedState.SSE = NULL;
430         }
431 }
432
433 tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
434 {
435         Uint    esp;
436         tThread *newThread;
437         
438         newThread = Threads_CloneTCB(0);
439         if(!newThread)  return -1;
440         
441         // Create new KStack
442         newThread->KernelStack = MM_NewKStack();
443         // Check for errors
444         if(newThread->KernelStack == 0) {
445                 free(newThread);
446                 return -1;
447         }
448
449         esp = newThread->KernelStack;
450         *(Uint*)(esp-=4) = (Uint)Data;  // Data (shadowed)
451         *(Uint*)(esp-=4) = 1;   // Number of params
452         *(Uint*)(esp-=4) = (Uint)Fcn;   // Function to call
453         *(Uint*)(esp-=4) = (Uint)newThread;     // Thread ID
454         
455         newThread->SavedState.ESP = esp;
456         newThread->SavedState.EIP = (Uint)&NewTaskHeader;
457         newThread->SavedState.SSE = NULL;
458 //      Log("New (KThread) %p, esp = %p", newThread->SavedState.EIP, newThread->SavedState.ESP);
459         
460 //      MAGIC_BREAK();  
461         Threads_AddActive(newThread);
462
463         return newThread->TID;
464 }
465
466 #if 0
467 tPID Proc_NewProcess(Uint Flags, void (*Fcn)(void*), size_t SaveSize, const void *Data)
468 {
469         tThread *newThread = Threads_CloneTCB(CLONE_VM);
470         return 0;
471 }
472 #endif
473
474 /**
475  * \fn int Proc_Clone(Uint *Err, Uint Flags)
476  * \brief Clone the current process
477  */
478 tPID Proc_Clone(Uint Flags)
479 {
480         tThread *newThread;
481         tThread *cur = Proc_GetCurThread();
482         Uint    eip;
483
484         Log_Warning("Proc", "Proc_Clone is deprecated");
485         // Sanity, please
486         if( !(Flags & CLONE_VM) ) {
487                 Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
488                 return -1;
489         }
490         
491         // New thread
492         newThread = Threads_CloneTCB(Flags);
493         if(!newThread)  return -1;
494         ASSERT(newThread->Process);
495         //ASSERT(CheckMem(newThread->Process, sizeof(tProcess)));
496         //LOG("newThread->Process = %p", newThread->Process);
497
498         newThread->KernelStack = cur->KernelStack;
499
500         // Clone state
501         eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
502         if( eip == 0 ) {
503                 return 0;
504         }
505         //ASSERT(newThread->Process);
506         //ASSERT(CheckMem(newThread->Process, sizeof(tProcess)));
507         //LOG("newThread->Process = %p", newThread->Process);
508         newThread->SavedState.EIP = eip;
509         newThread->SavedState.SSE = NULL;
510         newThread->SavedState.bSSEModified = 0;
511         
512         // Check for errors
513         if( newThread->Process->MemState.CR3 == 0 ) {
514                 Log_Error("Proc", "Proc_Clone: MM_Clone failed");
515                 Threads_Delete(newThread);
516                 return -1;
517         }
518
519         // Add the new thread to the run queue
520         Threads_AddActive(newThread);
521         return newThread->TID;
522 }
523
524 /**
525  * \fn int Proc_SpawnWorker(void)
526  * \brief Spawns a new worker thread
527  */
528 tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
529 {
530         Uint    stack_contents[4];
531         LOG("(Fcn=%p,Data=%p)", Fcn, Data);
532         
533         // Create new thread
534         tThread *new = Threads_CloneThreadZero();
535         LOG("new=%p", new);
536         if(!new) {
537                 Warning("Proc_SpawnWorker - Out of heap space!\n");
538                 return NULL;
539         }
540
541         // Create the stack contents
542         stack_contents[3] = (Uint)Data;
543         stack_contents[2] = 1;
544         stack_contents[1] = (Uint)Fcn;
545         stack_contents[0] = (Uint)new;
546         
547         // Create a new worker stack (in PID0's address space)
548         new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
549         LOG("new->KernelStack = %p", new->KernelStack);
550
551         // Save core machine state
552         new->SavedState.ESP = new->KernelStack - sizeof(stack_contents);
553         new->SavedState.EIP = (Uint)NewTaskHeader;
554         new->SavedState.SSE = NULL;
555         new->SavedState.bSSEModified = 0;
556         
557         // Mark as active
558         new->Status = THREAD_STAT_PREINIT;
559         Threads_AddActive( new );
560         LOG("Added to active");
561         
562         return new;
563 }
564
565 /**
566  * \fn Uint Proc_MakeUserStack(void)
567  * \brief Creates a new user stack
568  */
569 Uint Proc_MakeUserStack(void)
570 {
571         tPage   *base = (void*)(USER_STACK_TOP - USER_STACK_SZ);
572         
573         // Check Prospective Space
574         for( Uint i = USER_STACK_SZ/PAGE_SIZE; i--; )
575         {
576                 if( MM_GetPhysAddr( base + i ) != 0 )
577                 {
578                         Warning("Proc_MakeUserStack: Address %p in use", base + i);
579                         return 0;
580                 }
581         }
582         // Allocate Stack - Allocate incrementally to clean up MM_Dump output
583         for( Uint i = 0; i < USER_STACK_SZ/PAGE_SIZE; i++ )
584         {
585                 if( MM_Allocate( base + i ) == 0 )
586                 {
587                         Warning("OOM: Proc_MakeUserStack");
588                         return 0;
589                 }
590         }
591         
592         return (tVAddr)( base + USER_STACK_SZ/PAGE_SIZE );
593 }
594
595 void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
596 {
597         Uint    *stack;
598          int    i;
599         const char      **envp = NULL;
600         Uint16  ss, cs;
601         
602         // Copy data to the user stack and free original buffer
603         stack = (void*)Proc_MakeUserStack();
604         stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
605         memcpy( stack, ArgV, DataSize );
606         free(ArgV);
607         
608         // Adjust Arguments and environment
609         if( DataSize )
610         {
611                 Uint delta = (Uint)stack - (Uint)ArgV;
612                 ArgV = (const char**)stack;
613                 for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
614                 envp = &ArgV[i+1];
615                 for( i = 0; envp[i]; i++ )      envp[i] += delta;
616         }
617         
618         // User Mode Segments
619         ss = 0x23;      cs = 0x1B;
620         
621         // Arguments
622         *--stack = (Uint)envp;
623         *--stack = (Uint)ArgV;
624         *--stack = (Uint)ArgC;
625         *--stack = Base;
626         
627         Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
628 }
629
630 void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
631 {
632         Uint    *stack = (void*)Stack;
633         *--stack = SS;          //Stack Segment
634         *--stack = Stack;       //Stack Pointer
635         *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
636         *--stack = CS;          //Code Segment
637         *--stack = IP;  //EIP
638         //PUSHAD
639         *--stack = 0xAAAAAAAA;  // eax
640         *--stack = 0xCCCCCCCC;  // ecx
641         *--stack = 0xDDDDDDDD;  // edx
642         *--stack = 0xBBBBBBBB;  // ebx
643         *--stack = 0xD1D1D1D1;  // edi
644         *--stack = 0x54545454;  // esp - NOT POPED
645         *--stack = 0x51515151;  // esi
646         *--stack = 0xB4B4B4B4;  // ebp
647         //Individual PUSHs
648         *--stack = SS;  // ds
649         *--stack = SS;  // es
650         *--stack = SS;  // fs
651         *--stack = SS;  // gs
652         
653         __asm__ __volatile__ (
654         "mov %%eax,%%esp;\n\t"  // Set stack pointer
655         "pop %%gs;\n\t"
656         "pop %%fs;\n\t"
657         "pop %%es;\n\t"
658         "pop %%ds;\n\t"
659         "popa;\n\t"
660         "iret;\n\t" : : "a" (stack));
661         for(;;);
662 }
663
664 void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen)
665 {
666         if( UserSP < StackDataLen )
667                 return ;
668         if( !CheckMem( (void*)(UserSP - StackDataLen), StackDataLen ) )
669                 return ;
670         memcpy( (void*)(UserSP - StackDataLen), StackData, StackDataLen );
671         
672         __asm__ __volatile__ (
673                 "mov $0x23,%%ax;\n\t"
674                 "mov %%ax, %%ds;\n\t"
675                 "mov %%ax, %%es;\n\t"
676                 "mov %%ax, %%fs;\n\t"
677                 "mov %%ax, %%gs;\n\t"
678                 "push $0x23;\n\t"
679                 "push %1;\n\t"
680                 "push $0x202;\n\t"
681                 "push $0x1B;\n\t"
682                 "push %0;\n\t"
683                 "iret;\n\t"
684                 :
685                 : "r" (UserIP), "r" (UserSP - StackDataLen)
686                 : "eax"
687                 );
688         for(;;)
689                 ;
690 }
691
692 /**
693  * \brief Calls a signal handler in user mode
694  * \note Used for signals
695  */
696 void Proc_CallFaultHandler(tThread *Thread)
697 {
698         // Rewinds the stack and calls the user function
699         // Never returns
700         Proc_ReturnToUser( Thread->FaultHandler, Thread->CurFaultNum, Thread->KernelStack );
701         for(;;);
702 }
703
704 void Proc_DumpThreadCPUState(tThread *Thread)
705 {
706         if( Thread->CurCPU > -1 )
707         {
708                  int    maxBacktraceDistance = 6;
709                 tRegs   *regs = NULL;
710                 Uint32  *stack;
711                 
712                 if( Thread->CurCPU != GetCPUNum() ) {
713                         Log("  Currently running");
714                         return ;
715                 }
716                 
717                 // Backtrace to find the IRQ entrypoint
718                 // - This will usually only be called by an IRQ, so this should
719                 //   work
720                 __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
721                 while( maxBacktraceDistance -- )
722                 {
723                         if( !CheckMem(stack, 8) ) {
724                                 regs = NULL;
725                                 break;
726                         }
727                         // [ebp] = oldEbp
728                         // [ebp+4] = retaddr
729                         
730                         if( stack[1] == (tVAddr)&IRQCommon_handled ) {
731                                 regs = (void*)stack[2];
732                                 break;
733                         }
734                         
735                         stack = (void*)stack[0];
736                 }
737                 
738                 if( !regs ) {
739                         Log("  Unable to find IRQ Entry");
740                         return ;
741                 }
742                 
743                 Log("  at %04x:%08x [EAX:%x]", regs->cs, regs->eip, regs->eax);
744                 Error_Backtrace(regs->eip, regs->ebp);
745                 return ;
746         }
747
748         Log(" Saved = %p (SP=%p)", Thread->SavedState.EIP, Thread->SavedState.ESP);     
749
750         tVAddr  diffFromScheduler = Thread->SavedState.EIP - (tVAddr)SwitchTasks;
751         tVAddr  diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_CloneInt;
752         tVAddr  diffFromSpawn = Thread->SavedState.EIP - (tVAddr)NewTaskHeader;
753         
754         if( diffFromClone > 0 && diffFromClone < 40 )   // When I last checked, .newTask was at .+27
755         {
756                 Log("  Creating process");
757                 return ;
758         }
759         
760         if( diffFromSpawn == 0 )
761         {
762                 Log("  Creating thread");
763                 return ;
764         }
765         
766         if( diffFromScheduler > 0 && diffFromScheduler < 128 )  // When I last checked, GetEIP was at .+0x30
767         {
768                 // Scheduled out
769                 Log("  At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
770                 return ;
771         }
772         
773         Log("  Just created (unknown %p)", Thread->SavedState.EIP);
774 }
775
776 void Proc_Reschedule(void)
777 {
778         tThread *nextthread, *curthread;
779          int    cpu = GetCPUNum();
780
781         // TODO: Wait for the lock?
782         if(IS_LOCKED(&glThreadListLock))        return;
783         
784         curthread = Proc_GetCurThread();
785
786         nextthread = Threads_GetNextToRun(cpu, curthread);
787
788         if(!nextthread || nextthread == curthread)
789                 return ;
790
791         #if DEBUG_TRACE_SWITCH
792         // HACK: Ignores switches to the idle threads
793         if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
794         {
795                 LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
796                         GetCPUNum(),
797                         nextthread, nextthread->TID, nextthread->ThreadName,
798                         nextthread->Process->MemState.CR3,
799                         nextthread->SavedState.EIP,
800                         nextthread->SavedState.ESP
801                         );
802                 LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
803         }
804         #endif
805
806         // Update CPU state
807         gaCPUs[cpu].Current = nextthread;
808         gaCPUs[cpu].LastTimerThread = NULL;
809         gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
810         __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
811
812         // Save FPU/MMX/XMM/SSE state
813         if( curthread && curthread->SavedState.SSE )
814         {
815                 Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
816                 curthread->SavedState.bSSEModified = 0;
817                 Proc_DisableSSE();
818         }
819
820         if( curthread )
821         {
822                 SwitchTasks(
823                         nextthread->SavedState.ESP, &curthread->SavedState.ESP,
824                         nextthread->SavedState.EIP, &curthread->SavedState.EIP,
825                         nextthread->Process->MemState.CR3
826                         );
827         }
828         else
829         {
830                 SwitchTasks(
831                         nextthread->SavedState.ESP, 0,
832                         nextthread->SavedState.EIP, 0,
833                         nextthread->Process->MemState.CR3
834                         );
835         }
836
837         return ;
838 }
839
840 /**
841  * \fn void Proc_Scheduler(int CPU)
842  * \brief Swap current thread and clears dead threads
843  */
844 void Proc_Scheduler(int CPU)
845 {
846         #if USE_MP
847         if( GetCPUNum() )
848                 gpMP_LocalAPIC->EOI.Val = 0;
849         else
850         #endif
851                 outb(0x20, 0x20);
852         __asm__ __volatile__ ("sti");   
853
854         // Call the timer update code
855         Timer_CallTimers();
856
857         #if !DEBUG_NOPREEMPT
858         // If two ticks happen within the same task, and it's not an idle task, swap
859         if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread )
860         {
861                 Proc_Reschedule();
862         }
863         
864         gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current;
865         #endif
866 }
867
868 // === EXPORTS ===
869 EXPORT(Proc_SpawnWorker);

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