Kernel - Fixes from clang's scan-build tool
[tpg/acess2.git] / Kernel / arch / x86_64 / proc.c
1 /*
2  * Acess2 x86_64 port
3  * proc.c
4  */
5 #include <acess.h>
6 #include <proc.h>
7 #include <threads.h>
8 #include <threads_int.h>
9 #include <desctab.h>
10 #include <mm_virt.h>
11 #include <errno.h>
12 #if USE_MP
13 # include <mp.h>
14 #endif
15 #include <arch_config.h>
16
17 // === FLAGS ===
18 #define DEBUG_TRACE_SWITCH      0
19
20 // === CONSTANTS ===
21 #define SWITCH_MAGIC    0x55ECAFFF##FFFACE55    // There is no code in this area
22
23 // === TYPES ===
24 typedef struct sCPU
25 {
26         Uint8   APICID;
27         Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
28         Uint16  Resvd;
29         tThread *Current;
30         tThread *IdleThread;
31 }       tCPU;
32
33 // === IMPORTS ===
34 extern tGDT     gGDT[];
35 extern void     APStartup(void);        // 16-bit AP startup code
36 extern Uint     GetRIP(void);   // start.asm
37 extern Uint64   gInitialPML4[512];      // start.asm
38 extern char     gInitialKernelStack[];
39 extern tShortSpinlock   glThreadListLock;
40 extern int      giNumCPUs;
41 extern int      giNextTID;
42 extern int      giTotalTickets;
43 extern int      giNumActiveThreads;
44 extern tThread  gThreadZero;
45 extern void     Threads_Dump(void);
46 extern void     Proc_ReturnToUser(void);
47 extern int      GetCPUNum(void);
48 extern void     Time_UpdateTimestamp(void);
49
50 // === PROTOTYPES ===
51 void    ArchThreads_Init(void);
52 #if USE_MP
53 void    MP_StartAP(int CPU);
54 void    MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode);
55 #endif
56 //void  Proc_Start(void);
57 //tThread       *Proc_GetCurThread(void);
58 void    Proc_ChangeStack(void);
59 // int  Proc_Clone(Uint *Err, Uint Flags);
60 // int  Proc_SpawnWorker(void);
61 Uint    Proc_MakeUserStack(void);
62 void    Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize);
63 void    Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP);
64  int    Proc_Demote(Uint *Err, int Dest, tRegs *Regs);
65 void    Proc_CallFaultHandler(tThread *Thread);
66 void    Proc_DumpThreadCPUState(tThread *Thread);
67 void    Proc_Scheduler(int CPU);
68
69 // === GLOBALS ===
70 // --- Multiprocessing ---
71 #if USE_MP
72 volatile int    giNumInitingCPUs = 0;
73 tMPInfo *gMPFloatPtr = NULL;
74 tAPIC   *gpMP_LocalAPIC = NULL;
75 Uint8   gaAPIC_to_CPU[256] = {0};
76 #endif
77 tCPU    gaCPUs[MAX_CPUS];
78 tTSS    *gTSSs = NULL;
79 tTSS    gTSS0 = {0};
80 // --- Error Recovery ---
81 Uint32  gaDoubleFaultStack[1024];
82
83 // === CODE ===
84 /**
85  * \fn void ArchThreads_Init(void)
86  * \brief Starts the process scheduler
87  */
88 void ArchThreads_Init(void)
89 {
90         Uint    pos = 0;
91         
92         #if USE_MP
93         tMPTable        *mptable;
94         
95         // Mark BSP as active
96         gaCPUs[0].State = 2;
97         
98         // -- Initialise Multiprocessing
99         // Find MP Floating Table
100         // - EBDA/Last 1Kib (640KiB)
101         for(pos = KERNEL_BASE|0x9F000; pos < (KERNEL_BASE|0xA0000); pos += 16) {
102                 if( *(Uint*)(pos) == MPPTR_IDENT ) {
103                         Log("Possible %p", pos);
104                         if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
105                         gMPFloatPtr = (void*)pos;
106                         break;
107                 }
108         }
109         // - Last KiB (512KiB base mem)
110         if(!gMPFloatPtr) {
111                 for(pos = KERNEL_BASE|0x7F000; pos < (KERNEL_BASE|0x80000); pos += 16) {
112                         if( *(Uint*)(pos) == MPPTR_IDENT ) {
113                                 Log("Possible %p", pos);
114                                 if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
115                                 gMPFloatPtr = (void*)pos;
116                                 break;
117                         }
118                 }
119         }
120         // - BIOS ROM
121         if(!gMPFloatPtr) {
122                 for(pos = KERNEL_BASE|0xE0000; pos < (KERNEL_BASE|0x100000); pos += 16) {
123                         if( *(Uint*)(pos) == MPPTR_IDENT ) {
124                                 Log("Possible %p", pos);
125                                 if( ByteSum((void*)pos, sizeof(tMPInfo)) != 0 ) continue;
126                                 gMPFloatPtr = (void*)pos;
127                                 break;
128                         }
129                 }
130         }
131         
132         // If the MP Table Exists, parse it
133         if(gMPFloatPtr)
134         {
135                  int    i;
136                 tMPTable_Ent    *ents;
137                 Log("gMPFloatPtr = %p", gMPFloatPtr);
138                 Log("*gMPFloatPtr = {");
139                 Log("\t.Sig = 0x%08x", gMPFloatPtr->Sig);
140                 Log("\t.MPConfig = 0x%08x", gMPFloatPtr->MPConfig);
141                 Log("\t.Length = 0x%02x", gMPFloatPtr->Length);
142                 Log("\t.Version = 0x%02x", gMPFloatPtr->Version);
143                 Log("\t.Checksum = 0x%02x", gMPFloatPtr->Checksum);
144                 Log("\t.Features = [0x%02x,0x%02x,0x%02x,0x%02x,0x%02x]",
145                         gMPFloatPtr->Features[0],       gMPFloatPtr->Features[1],
146                         gMPFloatPtr->Features[2],       gMPFloatPtr->Features[3],
147                         gMPFloatPtr->Features[4]
148                         );
149                 Log("}");
150                 
151                 mptable = (void*)( KERNEL_BASE|gMPFloatPtr->MPConfig );
152                 Log("mptable = %p", mptable);
153                 Log("*mptable = {");
154                 Log("\t.Sig = 0x%08x", mptable->Sig);
155                 Log("\t.BaseTableLength = 0x%04x", mptable->BaseTableLength);
156                 Log("\t.SpecRev = 0x%02x", mptable->SpecRev);
157                 Log("\t.Checksum = 0x%02x", mptable->Checksum);
158                 Log("\t.OEMID = '%8c'", mptable->OemID);
159                 Log("\t.ProductID = '%8c'", mptable->ProductID);
160                 Log("\t.OEMTablePtr = %p'", mptable->OEMTablePtr);
161                 Log("\t.OEMTableSize = 0x%04x", mptable->OEMTableSize);
162                 Log("\t.EntryCount = 0x%04x", mptable->EntryCount);
163                 Log("\t.LocalAPICMemMap = 0x%08x", mptable->LocalAPICMemMap);
164                 Log("\t.ExtendedTableLen = 0x%04x", mptable->ExtendedTableLen);
165                 Log("\t.ExtendedTableChecksum = 0x%02x", mptable->ExtendedTableChecksum);
166                 Log("}");
167                 
168                 gpMP_LocalAPIC = (void*)MM_MapHWPage(mptable->LocalAPICMemMap, 1);
169                 
170                 ents = mptable->Entries;
171                 giNumCPUs = 0;
172                 
173                 for( i = 0; i < mptable->EntryCount; i ++ )
174                 {
175                          int    entSize = 0;
176                         switch( ents->Type )
177                         {
178                         case 0: // Processor
179                                 entSize = 20;
180                                 Log("%i: Processor", i);
181                                 Log("\t.APICID = %i", ents->Proc.APICID);
182                                 Log("\t.APICVer = 0x%02x", ents->Proc.APICVer);
183                                 Log("\t.CPUFlags = 0x%02x", ents->Proc.CPUFlags);
184                                 Log("\t.CPUSignature = 0x%08x", ents->Proc.CPUSignature);
185                                 Log("\t.FeatureFlags = 0x%08x", ents->Proc.FeatureFlags);
186                                 
187                                 
188                                 if( !(ents->Proc.CPUFlags & 1) ) {
189                                         Log("DISABLED");
190                                         break;
191                                 }
192                                 
193                                 // Check if there is too many processors
194                                 if(giNumCPUs >= MAX_CPUS) {
195                                         giNumCPUs ++;   // If `giNumCPUs` > MAX_CPUS later, it will be clipped
196                                         break;
197                                 }
198                                 
199                                 // Initialise CPU Info
200                                 gaAPIC_to_CPU[ents->Proc.APICID] = giNumCPUs;
201                                 gaCPUs[giNumCPUs].APICID = ents->Proc.APICID;
202                                 gaCPUs[giNumCPUs].State = 0;
203                                 giNumCPUs ++;
204                                 
205                                 // Send IPI
206                                 if( !(ents->Proc.CPUFlags & 2) )
207                                 {
208                                         MP_StartAP( giNumCPUs-1 );
209                                 }
210                                 
211                                 break;
212                         case 1: // Bus
213                                 entSize = 8;
214                                 Log("%i: Bus", i);
215                                 Log("\t.ID = %i", ents->Bus.ID);
216                                 Log("\t.TypeString = '%6c'", ents->Bus.TypeString);
217                                 break;
218                         case 2: // I/O APIC
219                                 entSize = 8;
220                                 Log("%i: I/O APIC", i);
221                                 Log("\t.ID = %i", ents->IOAPIC.ID);
222                                 Log("\t.Version = 0x%02x", ents->IOAPIC.Version);
223                                 Log("\t.Flags = 0x%02x", ents->IOAPIC.Flags);
224                                 Log("\t.Addr = 0x%08x", ents->IOAPIC.Addr);
225                                 break;
226                         case 3: // I/O Interrupt Assignment
227                                 entSize = 8;
228                                 Log("%i: I/O Interrupt Assignment", i);
229                                 Log("\t.IntType = %i", ents->IOInt.IntType);
230                                 Log("\t.Flags = 0x%04x", ents->IOInt.Flags);
231                                 Log("\t.SourceBusID = 0x%02x", ents->IOInt.SourceBusID);
232                                 Log("\t.SourceBusIRQ = 0x%02x", ents->IOInt.SourceBusIRQ);
233                                 Log("\t.DestAPICID = 0x%02x", ents->IOInt.DestAPICID);
234                                 Log("\t.DestAPICIRQ = 0x%02x", ents->IOInt.DestAPICIRQ);
235                                 break;
236                         case 4: // Local Interrupt Assignment
237                                 entSize = 8;
238                                 Log("%i: Local Interrupt Assignment", i);
239                                 Log("\t.IntType = %i", ents->LocalInt.IntType);
240                                 Log("\t.Flags = 0x%04x", ents->LocalInt.Flags);
241                                 Log("\t.SourceBusID = 0x%02x", ents->LocalInt.SourceBusID);
242                                 Log("\t.SourceBusIRQ = 0x%02x", ents->LocalInt.SourceBusIRQ);
243                                 Log("\t.DestLocalAPICID = 0x%02x", ents->LocalInt.DestLocalAPICID);
244                                 Log("\t.DestLocalAPICIRQ = 0x%02x", ents->LocalInt.DestLocalAPICIRQ);
245                                 break;
246                         default:
247                                 Log("%i: Unknown (%i)", i, ents->Type);
248                                 break;
249                         }
250                         ents = (void*)( (Uint)ents + entSize );
251                 }
252                 
253                 if( giNumCPUs > MAX_CPUS ) {
254                         Warning("Too many CPUs detected (%i), only using %i of them", giNumCPUs, MAX_CPUS);
255                         giNumCPUs = MAX_CPUS;
256                 }
257         
258                 while( giNumInitingCPUs )
259                         MM_FinishVirtualInit();
260                 
261                 Panic("Uh oh... MP Table Parsing is unimplemented\n");
262         }
263         else {
264                 Log("No MP Table was found, assuming uniprocessor\n");
265                 giNumCPUs = 1;
266                 gTSSs = &gTSS0;
267         }
268         #else
269         giNumCPUs = 1;
270         gTSSs = &gTSS0;
271         MM_FinishVirtualInit();
272         #endif
273         
274         #if USE_MP
275         // Initialise Normal TSS(s)
276         for(pos=0;pos<giNumCPUs;pos++)
277         {
278         #else
279         pos = 0;
280         #endif
281                 gTSSs[pos].RSP0 = 0;    // Set properly by scheduler
282                 gGDT[7+pos*2].LimitLow = sizeof(tTSS) & 0xFFFF;
283                 gGDT[7+pos*2].BaseLow = ((Uint)(&gTSSs[pos])) & 0xFFFF;
284                 gGDT[7+pos*2].BaseMid = ((Uint)(&gTSSs[pos])) >> 16;
285                 gGDT[7+pos*2].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
286                 gGDT[7+pos*2+1].DWord[0] = ((Uint)(&gTSSs[pos])) >> 32;
287         #if USE_MP
288         }
289         for(pos=0;pos<giNumCPUs;pos++) {
290                 __asm__ __volatile__ ("ltr %%ax"::"a"(0x38+pos*16));
291         }
292         #else
293         __asm__ __volatile__ ("ltr %%ax"::"a"(0x38));
294         #endif
295         
296         // Set Debug registers
297         __asm__ __volatile__ ("mov %0, %%db0" : : "r"(&gThreadZero));
298         __asm__ __volatile__ ("mov %%rax, %%db1" : : "a"(0));
299         
300         gaCPUs[0].Current = &gThreadZero;
301         
302         gThreadZero.MemState.CR3 = (Uint)gInitialPML4 - KERNEL_BASE;
303         gThreadZero.CurCPU = 0;
304         
305         // Set timer frequency
306         outb(0x43, 0x34);       // Set Channel 0, Low/High, Rate Generator
307         outb(0x40, PIT_TIMER_DIVISOR&0xFF);     // Low Byte of Divisor
308         outb(0x40, (PIT_TIMER_DIVISOR>>8)&0xFF);        // High Byte
309         
310         // Create Per-Process Data Block
311         if( !MM_Allocate(MM_PPD_CFG) )
312         {
313                 Warning("Oh, hell, Unable to allocate PPD for Thread#0");
314         }
315         
316         // Change Stacks
317         Proc_ChangeStack();
318         
319         Log("Multithreading initialised");
320 }
321
322 #if USE_MP
323 void MP_StartAP(int CPU)
324 {
325         Log("Starting AP %i (APIC %i)", CPU, gaCPUs[CPU].APICID);
326         // Set location of AP startup code and mark for a warm restart
327         *(Uint16*)(KERNEL_BASE|0x467) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0);
328         *(Uint16*)(KERNEL_BASE|0x469) = 0xFFFF;
329         outb(0x70, 0x0F);       outb(0x71, 0x0A);       // Warm Reset
330         MP_SendIPI(gaCPUs[CPU].APICID, 0, 5);
331         giNumInitingCPUs ++;
332 }
333
334 void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
335 {
336         Uint32  addr = (Uint)gpMP_LocalAPIC + 0x300;
337         Uint32  val;
338         
339         // High
340         val = (Uint)APICID << 24;
341         Log("*%p = 0x%08x", addr+0x10, val);
342         *(Uint32*)(addr+0x10) = val;
343         // Low (and send)
344         val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
345         Log("*%p = 0x%08x", addr, val);
346         *(Uint32*)addr = val;
347 }
348 #endif
349
350 /**
351  * \fn void Proc_Start(void)
352  * \brief Start process scheduler
353  */
354 void Proc_Start(void)
355 {
356         #if USE_MP
357          int    i;
358         #endif
359         
360         #if USE_MP
361         // Start APs
362         for( i = 0; i < giNumCPUs; i ++ )
363         {
364                  int    tid;
365                 if(i)   gaCPUs[i].Current = NULL;
366                 
367                 // Create Idle Task
368                 if( (tid = Proc_Clone(0, 0)) == 0)
369                 {
370                         for(;;) HALT(); // Just yeilds
371                 }
372                 gaCPUs[i].IdleThread = Threads_GetThread(tid);
373                 gaCPUs[i].IdleThread->ThreadName = "Idle Thread";
374                 Threads_SetTickets( gaCPUs[i].IdleThread, 0 );  // Never called randomly
375                 gaCPUs[i].IdleThread->Quantum = 1;      // 1 slice quantum
376                 
377                 
378                 // Start the AP
379                 if( i != giProc_BootProcessorID ) {
380                         MP_StartAP( i );
381                 }
382         }
383         
384         // BSP still should run the current task
385         gaCPUs[0].Current = &gThreadZero;
386         
387         // Start interrupts and wait for APs to come up
388         Log("Waiting for APs to come up\n");
389         __asm__ __volatile__ ("sti");
390         while( giNumInitingCPUs )       __asm__ __volatile__ ("hlt");
391         #else
392         // Create Idle Task
393         if(Proc_Clone(0, 0) == 0)
394         {
395                 gaCPUs[0].IdleThread = Proc_GetCurThread();
396                 gaCPUs[0].IdleThread->ThreadName = (char*)"Idle Thread";
397                 Threads_SetPriority( gaCPUs[0].IdleThread, -1 );        // Never called randomly
398                 gaCPUs[0].IdleThread->Quantum = 1;      // 1 slice quantum
399                 for(;;) HALT(); // Just yeilds
400         }
401         
402         // Set current task
403         gaCPUs[0].Current = &gThreadZero;
404         gaCPUs[0].Current->CurCPU = 0;
405         
406         // Start Interrupts (and hence scheduler)
407         __asm__ __volatile__("sti");
408         #endif
409         MM_FinishVirtualInit();
410         Log("Multithreading started");
411 }
412
413 /**
414  * \fn tThread *Proc_GetCurThread(void)
415  * \brief Gets the current thread
416  */
417 tThread *Proc_GetCurThread(void)
418 {
419         #if USE_MP
420         return gaCPUs[ GetCPUNum() ].Current;
421         #else
422         return gaCPUs[ 0 ].Current;
423         #endif
424 }
425
426 /**
427  * \fn void Proc_ChangeStack(void)
428  * \brief Swaps the current stack for a new one (in the proper stack reigon)
429  */
430 void Proc_ChangeStack(void)
431 {
432         Uint    rsp, rbp;
433         Uint    tmp_rbp, old_rsp;
434         Uint    curBase, newBase;
435
436         __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
437         __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
438
439         old_rsp = rsp;
440
441         // Create new KStack
442         newBase = MM_NewKStack();
443         // Check for errors
444         if(newBase == 0) {
445                 Panic("What the?? Unable to allocate space for initial kernel stack");
446                 return;
447         }
448
449         curBase = (Uint)&gInitialKernelStack;
450         
451         Log("curBase = 0x%x, newBase = 0x%x", curBase, newBase);
452
453         // Get ESP as a used size
454         rsp = curBase - rsp;
455         Log("memcpy( %p, %p, 0x%x )", (void*)(newBase - rsp), (void*)(curBase - rsp), rsp );
456         // Copy used stack
457         memcpy( (void*)(newBase - rsp), (void*)(curBase - rsp), rsp );
458         // Get ESP as an offset in the new stack
459         rsp = newBase - rsp;
460         // Adjust EBP
461         rbp = newBase - (curBase - rbp);
462
463         Log("Update stack");
464         // Repair EBPs & Stack Addresses
465         // Catches arguments also, but may trash stack-address-like values
466         for(tmp_rbp = rsp; tmp_rbp < newBase; tmp_rbp += sizeof(Uint))
467         {
468                 if(old_rsp < *(Uint*)tmp_rbp && *(Uint*)tmp_rbp < curBase)
469                         *(Uint*)tmp_rbp += newBase - curBase;
470         }
471         
472         Log("Applying Changes");
473         Proc_GetCurThread()->KernelStack = newBase;
474         __asm__ __volatile__ ("mov %0, %%rsp"::"r"(rsp));
475         __asm__ __volatile__ ("mov %0, %%rbp"::"r"(rbp));
476 }
477
478 /**
479  * \fn int Proc_Clone(Uint *Err, Uint Flags)
480  * \brief Clone the current process
481  */
482 int Proc_Clone(Uint *Err, Uint Flags)
483 {
484         tThread *newThread;
485         tThread *cur = Proc_GetCurThread();
486         Uint    rip, rsp, rbp;
487         
488         __asm__ __volatile__ ("mov %%rsp, %0": "=r"(rsp));
489         __asm__ __volatile__ ("mov %%rbp, %0": "=r"(rbp));
490         
491         newThread = Threads_CloneTCB(Err, Flags);
492         if(!newThread)  return -1;
493         
494         Log("Proc_Clone: newThread = %p", newThread);
495         
496         // Initialise Memory Space (New Addr space or kernel stack)
497         if(Flags & CLONE_VM) {
498                 Log("Proc_Clone: Cloning VM");
499                 newThread->MemState.CR3 = MM_Clone();
500                 newThread->KernelStack = cur->KernelStack;
501         } else {
502                 Uint    tmp_rbp, old_rsp = rsp;
503
504                 // Set CR3
505                 newThread->MemState.CR3 = cur->MemState.CR3;
506
507                 // Create new KStack
508                 newThread->KernelStack = MM_NewKStack();
509                 Log("Proc_Clone: newKStack = %p", newThread->KernelStack);
510                 // Check for errors
511                 if(newThread->KernelStack == 0) {
512                         free(newThread);
513                         return -1;
514                 }
515
516                 // Get ESP as a used size
517                 rsp = cur->KernelStack - rsp;
518                 // Copy used stack
519                 memcpy(
520                         (void*)(newThread->KernelStack - rsp),
521                         (void*)(cur->KernelStack - rsp),
522                         rsp
523                         );
524                 // Get ESP as an offset in the new stack
525                 rsp = newThread->KernelStack - rsp;
526                 // Adjust EBP
527                 rbp = newThread->KernelStack - (cur->KernelStack - rbp);
528
529                 // Repair EBPs & Stack Addresses
530                 // Catches arguments also, but may trash stack-address-like values
531                 for(tmp_rbp = rsp; tmp_rbp < newThread->KernelStack; tmp_rbp += sizeof(Uint))
532                 {
533                         if(old_rsp < *(Uint*)tmp_rbp && *(Uint*)tmp_rbp < cur->KernelStack)
534                                 *(Uint*)tmp_rbp += newThread->KernelStack - cur->KernelStack;
535                 }
536         }
537         
538         // Save core machine state
539         newThread->SavedState.RSP = rsp;
540         newThread->SavedState.RBP = rbp;
541         rip = GetRIP();
542         if(rip == SWITCH_MAGIC) {
543                 outb(0x20, 0x20);       // ACK Timer and return as child
544                 __asm__ __volatile__ ("sti");
545                 return 0;
546         }
547         
548         // Set EIP as parent
549         newThread->SavedState.RIP = rip;
550         
551         // Lock list and add to active
552         Threads_AddActive(newThread);
553         
554         return newThread->TID;
555 }
556
557 /**
558  * \fn int Proc_SpawnWorker(void)
559  * \brief Spawns a new worker thread
560  */
561 int Proc_SpawnWorker(void)
562 {
563         tThread *new, *cur;
564         Uint    rip, rsp, rbp;
565         
566         cur = Proc_GetCurThread();
567         
568         // Create new thread
569         new = malloc( sizeof(tThread) );
570         if(!new) {
571                 Warning("Proc_SpawnWorker - Out of heap space!\n");
572                 return -1;
573         }
574         memcpy(new, &gThreadZero, sizeof(tThread));
575         // Set Thread ID
576         new->TID = giNextTID++;
577         // Create a new worker stack (in PID0's address space)
578         // The stack is relocated by this code
579         new->KernelStack = MM_NewWorkerStack();
580
581         // Get ESP and EBP based in the new stack
582         __asm__ __volatile__ ("mov %%rsp, %0": "=r"(rsp));
583         __asm__ __volatile__ ("mov %%rbp, %0": "=r"(rbp));
584         rsp = new->KernelStack - (cur->KernelStack - rsp);
585         rbp = new->KernelStack - (cur->KernelStack - rbp);      
586         
587         // Save core machine state
588         new->SavedState.RSP = rsp;
589         new->SavedState.RBP = rbp;
590         rip = GetRIP();
591         if(rip == SWITCH_MAGIC) {
592                 outb(0x20, 0x20);       // ACK Timer and return as child
593                 __asm__ __volatile__ ("sti");
594                 return 0;
595         }
596         
597         // Set EIP as parent
598         new->SavedState.RIP = rip;
599         // Mark as active
600         new->Status = THREAD_STAT_ACTIVE;
601         Threads_AddActive( new );
602         
603         return new->TID;
604 }
605
606 /**
607  * \fn Uint Proc_MakeUserStack(void)
608  * \brief Creates a new user stack
609  */
610 Uint Proc_MakeUserStack(void)
611 {
612          int    i;
613         Uint    base = USER_STACK_TOP - USER_STACK_SZ;
614         
615         // Check Prospective Space
616         for( i = USER_STACK_SZ >> 12; i--; )
617                 if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
618                         break;
619         
620         if(i != -1)     return 0;
621         
622         // Allocate Stack - Allocate incrementally to clean up MM_Dump output
623         for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
624         {
625                 if( !MM_Allocate( base + (i<<12) ) )
626                 {
627                         // Error
628                         Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
629                         while( i -- )
630                                 MM_Deallocate( base + (i<<12) );
631                         return 0;
632                 }
633         }
634         
635         return base + USER_STACK_SZ;
636 }
637
638
639 /**
640  * \fn void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
641  * \brief Starts a user task
642  */
643 void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
644 {
645         Uint    *stack = (void*)Proc_MakeUserStack();
646          int    i;
647         Uint    delta;
648         Uint16  ss, cs;
649         
650         LOG("stack = 0x%x", stack);
651         
652         // Copy Arguments
653         stack = (void*)( (Uint)stack - DataSize );
654         memcpy( stack, ArgV, DataSize );
655         
656         // Adjust Arguments and environment
657         delta = (Uint)stack - (Uint)ArgV;
658         ArgV = (char**)stack;
659         for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
660         i ++;
661         EnvP = &ArgV[i];
662         for( i = 0; EnvP[i]; i++ )      EnvP[i] += delta;
663         
664         // User Mode Segments
665         ss = 0x23;      cs = 0x1B;
666         
667         // Arguments
668         *--stack = (Uint)EnvP;
669         *--stack = (Uint)ArgV;
670         *--stack = (Uint)ArgC;
671         while(*Bases)
672                 *--stack = *Bases++;
673         *--stack = 0;   // Return Address
674         
675         Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
676 }
677
678 void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
679 {
680         Uint    *stack = (void*)Stack;
681         *--stack = SS;          //Stack Segment
682         *--stack = Stack;       //Stack Pointer
683         *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
684         *--stack = CS;          //Code Segment
685         *--stack = IP;  //EIP
686         //PUSHAD
687         *--stack = 0xAAAAAAAA;  // eax
688         *--stack = 0xCCCCCCCC;  // ecx
689         *--stack = 0xDDDDDDDD;  // edx
690         *--stack = 0xBBBBBBBB;  // ebx
691         *--stack = 0xD1D1D1D1;  // edi
692         *--stack = 0x54545454;  // rsp - NOT POPED
693         *--stack = 0x51515151;  // esi
694         *--stack = 0xB4B4B4B4;  // rbp
695         //Individual PUSHs
696         *--stack = SS;  // ds
697         
698         __asm__ __volatile__ (
699         "mov %%rax,%%rsp;\n\t"  // Set stack pointer
700         "iret;\n\t" : : "a" (stack));
701         for(;;);
702 }
703
704 /**
705  * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
706  * \brief Demotes a process to a lower permission level
707  * \param Err   Pointer to user's errno
708  * \param Dest  New Permission Level
709  * \param Regs  Pointer to user's register structure
710  */
711 int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
712 {
713          int    cpl = Regs->CS & 3;
714         // Sanity Check
715         if(Dest > 3 || Dest < 0) {
716                 *Err = -EINVAL;
717                 return -1;
718         }
719         
720         // Permission Check
721         if(cpl > Dest) {
722                 *Err = -EACCES;
723                 return -1;
724         }
725         
726         // Change the Segment Registers
727         Regs->CS = (((Dest+1)<<4) | Dest) - 8;
728         Regs->SS = ((Dest+1)<<4) | Dest;
729         
730         return 0;
731 }
732
733 /**
734  * \brief Calls a signal handler in user mode
735  * \note Used for signals
736  */
737 void Proc_CallFaultHandler(tThread *Thread)
738 {
739         // Rewinds the stack and calls the user function
740         // Never returns
741         __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler));
742         for(;;);
743 }
744
745 void Proc_DumpThreadCPUState(tThread *Thread)
746 {
747         Log("  At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
748 }
749
750 /**
751  * \fn void Proc_Scheduler(int CPU)
752  * \brief Swap current thread and clears dead threads
753  */
754 void Proc_Scheduler(int CPU)
755 {
756         Uint    rsp, rbp, rip;
757         tThread *thread;
758
759         if( CPU == 0 )
760                 Time_UpdateTimestamp();
761         
762         // If the spinlock is set, let it complete
763         if(IS_LOCKED(&glThreadListLock))        return;
764         
765         // Get current thread
766         thread = gaCPUs[CPU].Current;
767
768         if( thread )
769         {
770                 tRegs   *regs;
771                 // Reduce remaining quantum and continue timeslice if non-zero
772                 if(thread->Remaining--) return;
773                 // Reset quantum for next call
774                 thread->Remaining = thread->Quantum;
775         
776                 // Get machine state
777                 __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
778                 __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
779                 rip = GetRIP();
780                 if(rip == SWITCH_MAGIC) return; // Check if a switch happened
781                 
782                 // Save machine state
783                 thread->SavedState.RSP = rsp;
784                 thread->SavedState.RBP = rbp;
785                 thread->SavedState.RIP = rip;
786                 
787                 // TODO: Make this more stable somehow
788                 regs = (tRegs*)(rbp+(2+1)*8);   // RBP,Ret + CurThread
789                 thread->SavedState.UserCS = regs->CS;
790                 thread->SavedState.UserRIP = regs->RIP;
791         }
792         
793         // Get next thread
794         thread = Threads_GetNextToRun(CPU, thread);
795         
796         // Error Check
797         if(thread == NULL) {
798                 thread = gaCPUs[CPU].IdleThread;
799                 //Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
800                 //LogF("Zzzzz.\n");
801                 //return;
802         }
803         
804         #if DEBUG_TRACE_SWITCH
805         LogF("Switching to task %i, CR3 = 0x%x, RIP = %p",
806                 thread->TID,
807                 thread->MemState.CR3,
808                 thread->SavedState.RIP
809                 );
810         #endif
811         
812         
813         if(CPU > MAX_CPUS)
814                 LogF("CPU = %i", CPU);
815         // Set current thread
816         gaCPUs[CPU].Current = thread;
817         
818         // Update Kernel Stack pointer
819         gTSSs[CPU].RSP0 = thread->KernelStack-4;
820         
821         // Set address space
822         __asm__ __volatile__ ("mov %0, %%cr3"::"a"(thread->MemState.CR3));
823         
824         // Switch threads
825         __asm__ __volatile__ (
826                 "mov %1, %%rsp\n\t"     // Restore RSP
827                 "mov %2, %%rbp\n\t"     // and RBP
828                 "jmp *%3" : :   // And return to where we saved state (Proc_Clone or Proc_Scheduler)
829                 "a"(SWITCH_MAGIC), "b"(thread->SavedState.RSP),
830                 "d"(thread->SavedState.RBP), "c"(thread->SavedState.RIP)
831                 );
832         for(;;);        // Shouldn't reach here
833 }
834
835 // === EXPORTS ===
836 EXPORT(Proc_SpawnWorker);

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