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

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