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

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