999ac679ed6234dbde6710f007648819c0a84632
[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         // Sanity, please
485         if( !(Flags & CLONE_VM) ) {
486                 Log_Error("Proc", "Proc_Clone: Don't leave CLONE_VM unset, use Proc_NewKThread instead");
487                 return -1;
488         }
489         
490         // New thread
491         newThread = Threads_CloneTCB(Flags);
492         if(!newThread)  return -1;
493         ASSERT(newThread->Process);
494         //ASSERT(CheckMem(newThread->Process, sizeof(tProcess)));
495         //LOG("newThread->Process = %p", newThread->Process);
496
497         newThread->KernelStack = cur->KernelStack;
498
499         // Clone state
500         eip = Proc_CloneInt(&newThread->SavedState.ESP, &newThread->Process->MemState.CR3, Flags & CLONE_NOUSER);
501         if( eip == 0 ) {
502                 return 0;
503         }
504         //ASSERT(newThread->Process);
505         //ASSERT(CheckMem(newThread->Process, sizeof(tProcess)));
506         //LOG("newThread->Process = %p", newThread->Process);
507         newThread->SavedState.EIP = eip;
508         newThread->SavedState.SSE = NULL;
509         newThread->SavedState.bSSEModified = 0;
510         
511         // Check for errors
512         if( newThread->Process->MemState.CR3 == 0 ) {
513                 Log_Error("Proc", "Proc_Clone: MM_Clone failed");
514                 Threads_Delete(newThread);
515                 return -1;
516         }
517
518         // Add the new thread to the run queue
519         Threads_AddActive(newThread);
520         return newThread->TID;
521 }
522
523 /**
524  * \fn int Proc_SpawnWorker(void)
525  * \brief Spawns a new worker thread
526  */
527 tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
528 {
529         Uint    stack_contents[4];
530         LOG("(Fcn=%p,Data=%p)", Fcn, Data);
531         
532         // Create new thread
533         tThread *new = Threads_CloneThreadZero();
534         LOG("new=%p", new);
535         if(!new) {
536                 Warning("Proc_SpawnWorker - Out of heap space!\n");
537                 return NULL;
538         }
539
540         // Create the stack contents
541         stack_contents[3] = (Uint)Data;
542         stack_contents[2] = 1;
543         stack_contents[1] = (Uint)Fcn;
544         stack_contents[0] = (Uint)new;
545         
546         // Create a new worker stack (in PID0's address space)
547         new->KernelStack = MM_NewWorkerStack(stack_contents, sizeof(stack_contents));
548         LOG("new->KernelStack = %p", new->KernelStack);
549
550         // Save core machine state
551         new->SavedState.ESP = new->KernelStack - sizeof(stack_contents);
552         new->SavedState.EIP = (Uint)NewTaskHeader;
553         new->SavedState.SSE = NULL;
554         new->SavedState.bSSEModified = 0;
555         
556         // Mark as active
557         new->Status = THREAD_STAT_PREINIT;
558         Threads_AddActive( new );
559         LOG("Added to active");
560         
561         return new;
562 }
563
564 /**
565  * \fn Uint Proc_MakeUserStack(void)
566  * \brief Creates a new user stack
567  */
568 Uint Proc_MakeUserStack(void)
569 {
570         tPage   *base = (void*)(USER_STACK_TOP - USER_STACK_SZ);
571         
572         // Check Prospective Space
573         for( Uint i = USER_STACK_SZ/PAGE_SIZE; i--; )
574         {
575                 if( MM_GetPhysAddr( base + i ) != 0 )
576                 {
577                         Warning("Proc_MakeUserStack: Address %p in use", base + i);
578                         return 0;
579                 }
580         }
581         // Allocate Stack - Allocate incrementally to clean up MM_Dump output
582         for( Uint i = 0; i < USER_STACK_SZ/PAGE_SIZE; i++ )
583         {
584                 if( MM_Allocate( base + i ) == 0 )
585                 {
586                         Warning("OOM: Proc_MakeUserStack");
587                         return 0;
588                 }
589         }
590         
591         return (tVAddr)( base + USER_STACK_SZ/PAGE_SIZE );
592 }
593
594 void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
595 {
596         Uint    *stack;
597          int    i;
598         const char      **envp = NULL;
599         Uint16  ss, cs;
600         
601         // Copy data to the user stack and free original buffer
602         stack = (void*)Proc_MakeUserStack();
603         stack -= (DataSize+sizeof(*stack)-1)/sizeof(*stack);
604         memcpy( stack, ArgV, DataSize );
605         free(ArgV);
606         
607         // Adjust Arguments and environment
608         if( DataSize )
609         {
610                 Uint delta = (Uint)stack - (Uint)ArgV;
611                 ArgV = (const char**)stack;
612                 for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
613                 envp = &ArgV[i+1];
614                 for( i = 0; envp[i]; i++ )      envp[i] += delta;
615         }
616         
617         // User Mode Segments
618         ss = 0x23;      cs = 0x1B;
619         
620         // Arguments
621         *--stack = (Uint)envp;
622         *--stack = (Uint)ArgV;
623         *--stack = (Uint)ArgC;
624         *--stack = Base;
625         
626         Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
627 }
628
629 void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
630 {
631         Uint    *stack = (void*)Stack;
632         *--stack = SS;          //Stack Segment
633         *--stack = Stack;       //Stack Pointer
634         *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
635         *--stack = CS;          //Code Segment
636         *--stack = IP;  //EIP
637         //PUSHAD
638         *--stack = 0xAAAAAAAA;  // eax
639         *--stack = 0xCCCCCCCC;  // ecx
640         *--stack = 0xDDDDDDDD;  // edx
641         *--stack = 0xBBBBBBBB;  // ebx
642         *--stack = 0xD1D1D1D1;  // edi
643         *--stack = 0x54545454;  // esp - NOT POPED
644         *--stack = 0x51515151;  // esi
645         *--stack = 0xB4B4B4B4;  // ebp
646         //Individual PUSHs
647         *--stack = SS;  // ds
648         *--stack = SS;  // es
649         *--stack = SS;  // fs
650         *--stack = SS;  // gs
651         
652         __asm__ __volatile__ (
653         "mov %%eax,%%esp;\n\t"  // Set stack pointer
654         "pop %%gs;\n\t"
655         "pop %%fs;\n\t"
656         "pop %%es;\n\t"
657         "pop %%ds;\n\t"
658         "popa;\n\t"
659         "iret;\n\t" : : "a" (stack));
660         for(;;);
661 }
662
663 void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen)
664 {
665         if( UserSP < StackDataLen )
666                 return ;
667         if( !CheckMem( (void*)(UserSP - StackDataLen), StackDataLen ) )
668                 return ;
669         memcpy( (void*)(UserSP - StackDataLen), StackData, StackDataLen );
670         
671         __asm__ __volatile__ (
672                 "mov $0x23,%%ax;\n\t"
673                 "mov %%ax, %%ds;\n\t"
674                 "mov %%ax, %%es;\n\t"
675                 "mov %%ax, %%fs;\n\t"
676                 "mov %%ax, %%gs;\n\t"
677                 "push $0x23;\n\t"
678                 "push %1;\n\t"
679                 "push $0x202;\n\t"
680                 "push $0x1B;\n\t"
681                 "push %0;\n\t"
682                 "iret;\n\t"
683                 :
684                 : "r" (UserIP), "r" (UserSP - StackDataLen)
685                 : "eax"
686                 );
687         for(;;)
688                 ;
689 }
690
691 /**
692  * \brief Calls a signal handler in user mode
693  * \note Used for signals
694  */
695 void Proc_CallFaultHandler(tThread *Thread)
696 {
697         // Rewinds the stack and calls the user function
698         // Never returns
699         Proc_ReturnToUser( Thread->FaultHandler, Thread->CurFaultNum, Thread->KernelStack );
700         for(;;);
701 }
702
703 void Proc_DumpThreadCPUState(tThread *Thread)
704 {
705         if( Thread->CurCPU > -1 )
706         {
707                  int    maxBacktraceDistance = 6;
708                 tRegs   *regs = NULL;
709                 Uint32  *stack;
710                 
711                 if( Thread->CurCPU != GetCPUNum() ) {
712                         Log("  Currently running");
713                         return ;
714                 }
715                 
716                 // Backtrace to find the IRQ entrypoint
717                 // - This will usually only be called by an IRQ, so this should
718                 //   work
719                 __asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
720                 while( maxBacktraceDistance -- )
721                 {
722                         if( !CheckMem(stack, 8) ) {
723                                 regs = NULL;
724                                 break;
725                         }
726                         // [ebp] = oldEbp
727                         // [ebp+4] = retaddr
728                         
729                         if( stack[1] == (tVAddr)&IRQCommon_handled ) {
730                                 regs = (void*)stack[2];
731                                 break;
732                         }
733                         
734                         stack = (void*)stack[0];
735                 }
736                 
737                 if( !regs ) {
738                         Log("  Unable to find IRQ Entry");
739                         return ;
740                 }
741                 
742                 Log("  at %04x:%08x [EAX:%x]", regs->cs, regs->eip, regs->eax);
743                 Error_Backtrace(regs->eip, regs->ebp);
744                 return ;
745         }
746
747         Log(" Saved = %p (SP=%p)", Thread->SavedState.EIP, Thread->SavedState.ESP);     
748
749         tVAddr  diffFromScheduler = Thread->SavedState.EIP - (tVAddr)SwitchTasks;
750         tVAddr  diffFromClone = Thread->SavedState.EIP - (tVAddr)Proc_CloneInt;
751         tVAddr  diffFromSpawn = Thread->SavedState.EIP - (tVAddr)NewTaskHeader;
752         
753         if( diffFromClone > 0 && diffFromClone < 40 )   // When I last checked, .newTask was at .+27
754         {
755                 Log("  Creating process");
756                 return ;
757         }
758         
759         if( diffFromSpawn == 0 )
760         {
761                 Log("  Creating thread");
762                 return ;
763         }
764         
765         if( diffFromScheduler > 0 && diffFromScheduler < 128 )  // When I last checked, GetEIP was at .+0x30
766         {
767                 // Scheduled out
768                 Log("  At %04x:%08x", Thread->SavedState.UserCS, Thread->SavedState.UserEIP);
769                 return ;
770         }
771         
772         Log("  Just created (unknown %p)", Thread->SavedState.EIP);
773 }
774
775 void Proc_Reschedule(void)
776 {
777         tThread *nextthread, *curthread;
778          int    cpu = GetCPUNum();
779
780         // TODO: Wait for the lock?
781         if(IS_LOCKED(&glThreadListLock))        return;
782         
783         curthread = Proc_GetCurThread();
784
785         nextthread = Threads_GetNextToRun(cpu, curthread);
786
787         if(!nextthread || nextthread == curthread)
788                 return ;
789
790         #if DEBUG_TRACE_SWITCH
791         // HACK: Ignores switches to the idle threads
792         if( nextthread->TID == 0 || nextthread->TID > giNumCPUs )
793         {
794                 LogF("\nSwitching CPU %i to %p (%i %s) - CR3 = 0x%x, EIP = %p, ESP = %p\n",
795                         GetCPUNum(),
796                         nextthread, nextthread->TID, nextthread->ThreadName,
797                         nextthread->Process->MemState.CR3,
798                         nextthread->SavedState.EIP,
799                         nextthread->SavedState.ESP
800                         );
801                 LogF("OldCR3 = %P\n", curthread->Process->MemState.CR3);
802         }
803         #endif
804
805         // Update CPU state
806         gaCPUs[cpu].Current = nextthread;
807         gaCPUs[cpu].LastTimerThread = NULL;
808         gTSSs[cpu].ESP0 = nextthread->KernelStack-4;
809         __asm__ __volatile__("mov %0, %%db0\n\t" : : "r"(nextthread) );
810
811         // Save FPU/MMX/XMM/SSE state
812         if( curthread && curthread->SavedState.SSE )
813         {
814                 Proc_SaveSSE( ((Uint)curthread->SavedState.SSE + 0xF) & ~0xF );
815                 curthread->SavedState.bSSEModified = 0;
816                 Proc_DisableSSE();
817         }
818
819         if( curthread )
820         {
821                 SwitchTasks(
822                         nextthread->SavedState.ESP, &curthread->SavedState.ESP,
823                         nextthread->SavedState.EIP, &curthread->SavedState.EIP,
824                         nextthread->Process->MemState.CR3
825                         );
826         }
827         else
828         {
829                 SwitchTasks(
830                         nextthread->SavedState.ESP, 0,
831                         nextthread->SavedState.EIP, 0,
832                         nextthread->Process->MemState.CR3
833                         );
834         }
835
836         return ;
837 }
838
839 /**
840  * \fn void Proc_Scheduler(int CPU)
841  * \brief Swap current thread and clears dead threads
842  */
843 void Proc_Scheduler(int CPU)
844 {
845         #if USE_MP
846         if( GetCPUNum() )
847                 gpMP_LocalAPIC->EOI.Val = 0;
848         else
849         #endif
850                 outb(0x20, 0x20);
851         __asm__ __volatile__ ("sti");   
852
853         // Call the timer update code
854         Timer_CallTimers();
855
856         #if !DEBUG_NOPREEMPT
857         // If two ticks happen within the same task, and it's not an idle task, swap
858         if( gaCPUs[CPU].Current->TID > giNumCPUs && gaCPUs[CPU].Current == gaCPUs[CPU].LastTimerThread )
859         {
860                 Proc_Reschedule();
861         }
862         
863         gaCPUs[CPU].LastTimerThread = gaCPUs[CPU].Current;
864         #endif
865 }
866
867 // === EXPORTS ===
868 EXPORT(Proc_SpawnWorker);

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