Kernel/x86_64 - Implemented UserRIP/CS
[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
16 // === FLAGS ===
17 #define DEBUG_TRACE_SWITCH      0
18
19 // === CONSTANTS ===
20 #define SWITCH_MAGIC    0x55ECAFFF##FFFACE55    // There is no code in this area
21 // Base is 1193182
22 #define TIMER_DIVISOR   11931   //~100Hz
23
24 // === TYPES ===
25 typedef struct sCPU
26 {
27         Uint8   APICID;
28         Uint8   State;  // 0: Unavaliable, 1: Idle, 2: Active
29         Uint16  Resvd;
30         tThread *Current;
31         tThread *IdleThread;
32 }       tCPU;
33
34 // === IMPORTS ===
35 extern tGDT     gGDT[];
36 extern void     APStartup(void);        // 16-bit AP startup code
37 extern Uint     GetRIP(void);   // start.asm
38 extern Uint64   gInitialPML4[512];      // start.asm
39 extern char     gInitialKernelStack[];
40 extern tShortSpinlock   glThreadListLock;
41 extern int      giNumCPUs;
42 extern int      giNextTID;
43 extern int      giTotalTickets;
44 extern int      giNumActiveThreads;
45 extern tThread  gThreadZero;
46 extern void     Threads_Dump(void);
47 extern void     Proc_ReturnToUser(void);
48 extern int      GetCPUNum(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         #endif
291                 __asm__ __volatile__ ("ltr %%ax"::"a"(0x38+pos*16));
292         #if USE_MP
293         }
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, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
308         outb(0x40, (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                 return 0;
545         }
546         
547         // Set EIP as parent
548         newThread->SavedState.RIP = rip;
549         
550         // Lock list and add to active
551         Threads_AddActive(newThread);
552         
553         return newThread->TID;
554 }
555
556 /**
557  * \fn int Proc_SpawnWorker(void)
558  * \brief Spawns a new worker thread
559  */
560 int Proc_SpawnWorker(void)
561 {
562         tThread *new, *cur;
563         Uint    rip, rsp, rbp;
564         
565         cur = Proc_GetCurThread();
566         
567         // Create new thread
568         new = malloc( sizeof(tThread) );
569         if(!new) {
570                 Warning("Proc_SpawnWorker - Out of heap space!\n");
571                 return -1;
572         }
573         memcpy(new, &gThreadZero, sizeof(tThread));
574         // Set Thread ID
575         new->TID = giNextTID++;
576         // Create a new worker stack (in PID0's address space)
577         // The stack is relocated by this code
578         new->KernelStack = MM_NewWorkerStack();
579
580         // Get ESP and EBP based in the new stack
581         __asm__ __volatile__ ("mov %%rsp, %0": "=r"(rsp));
582         __asm__ __volatile__ ("mov %%rbp, %0": "=r"(rbp));
583         rsp = new->KernelStack - (cur->KernelStack - rsp);
584         rbp = new->KernelStack - (cur->KernelStack - rbp);      
585         
586         // Save core machine state
587         new->SavedState.RSP = rsp;
588         new->SavedState.RBP = rbp;
589         rip = GetRIP();
590         if(rip == SWITCH_MAGIC) {
591                 outb(0x20, 0x20);       // ACK Timer and return as child
592                 return 0;
593         }
594         
595         // Set EIP as parent
596         new->SavedState.RIP = rip;
597         // Mark as active
598         new->Status = THREAD_STAT_ACTIVE;
599         Threads_AddActive( new );
600         
601         return new->TID;
602 }
603
604 /**
605  * \fn Uint Proc_MakeUserStack(void)
606  * \brief Creates a new user stack
607  */
608 Uint Proc_MakeUserStack(void)
609 {
610          int    i;
611         Uint    base = USER_STACK_TOP - USER_STACK_SZ;
612         
613         // Check Prospective Space
614         for( i = USER_STACK_SZ >> 12; i--; )
615                 if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
616                         break;
617         
618         if(i != -1)     return 0;
619         
620         // Allocate Stack - Allocate incrementally to clean up MM_Dump output
621         for( i = 0; i < USER_STACK_SZ/0x1000; i++ )
622         {
623                 if( !MM_Allocate( base + (i<<12) ) )
624                 {
625                         // Error
626                         Log_Error("Proc", "Unable to allocate user stack (%i pages requested)", USER_STACK_SZ/0x1000);
627                         while( i -- )
628                                 MM_Deallocate( base + (i<<12) );
629                         return 0;
630                 }
631         }
632         
633         return base + USER_STACK_SZ;
634 }
635
636
637 /**
638  * \fn void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
639  * \brief Starts a user task
640  */
641 void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize)
642 {
643         Uint    *stack = (void*)Proc_MakeUserStack();
644          int    i;
645         Uint    delta;
646         Uint16  ss, cs;
647         
648         LOG("stack = 0x%x", stack);
649         
650         // Copy Arguments
651         stack = (void*)( (Uint)stack - DataSize );
652         memcpy( stack, ArgV, DataSize );
653         
654         // Adjust Arguments and environment
655         delta = (Uint)stack - (Uint)ArgV;
656         ArgV = (char**)stack;
657         for( i = 0; ArgV[i]; i++ )      ArgV[i] += delta;
658         i ++;
659         EnvP = &ArgV[i];
660         for( i = 0; EnvP[i]; i++ )      EnvP[i] += delta;
661         
662         // User Mode Segments
663         ss = 0x23;      cs = 0x1B;
664         
665         // Arguments
666         *--stack = (Uint)EnvP;
667         *--stack = (Uint)ArgV;
668         *--stack = (Uint)ArgC;
669         while(*Bases)
670                 *--stack = *Bases++;
671         *--stack = 0;   // Return Address
672         
673         Proc_StartProcess(ss, (Uint)stack, 0x202, cs, Entrypoint);
674 }
675
676 void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP)
677 {
678         Uint    *stack = (void*)Stack;
679         *--stack = SS;          //Stack Segment
680         *--stack = Stack;       //Stack Pointer
681         *--stack = Flags;       //EFLAGS (Resvd (0x2) and IF (0x20))
682         *--stack = CS;          //Code Segment
683         *--stack = IP;  //EIP
684         //PUSHAD
685         *--stack = 0xAAAAAAAA;  // eax
686         *--stack = 0xCCCCCCCC;  // ecx
687         *--stack = 0xDDDDDDDD;  // edx
688         *--stack = 0xBBBBBBBB;  // ebx
689         *--stack = 0xD1D1D1D1;  // edi
690         *--stack = 0x54545454;  // rsp - NOT POPED
691         *--stack = 0x51515151;  // esi
692         *--stack = 0xB4B4B4B4;  // rbp
693         //Individual PUSHs
694         *--stack = SS;  // ds
695         
696         __asm__ __volatile__ (
697         "mov %%rax,%%rsp;\n\t"  // Set stack pointer
698         "iret;\n\t" : : "a" (stack));
699         for(;;);
700 }
701
702 /**
703  * \fn int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
704  * \brief Demotes a process to a lower permission level
705  * \param Err   Pointer to user's errno
706  * \param Dest  New Permission Level
707  * \param Regs  Pointer to user's register structure
708  */
709 int Proc_Demote(Uint *Err, int Dest, tRegs *Regs)
710 {
711          int    cpl = Regs->CS & 3;
712         // Sanity Check
713         if(Dest > 3 || Dest < 0) {
714                 *Err = -EINVAL;
715                 return -1;
716         }
717         
718         // Permission Check
719         if(cpl > Dest) {
720                 *Err = -EACCES;
721                 return -1;
722         }
723         
724         // Change the Segment Registers
725         Regs->CS = (((Dest+1)<<4) | Dest) - 8;
726         Regs->SS = ((Dest+1)<<4) | Dest;
727         
728         return 0;
729 }
730
731 /**
732  * \brief Calls a signal handler in user mode
733  * \note Used for signals
734  */
735 void Proc_CallFaultHandler(tThread *Thread)
736 {
737         // Rewinds the stack and calls the user function
738         // Never returns
739         __asm__ __volatile__ ("mov %0, %%rbp;\n\tcall Proc_ReturnToUser" :: "r"(Thread->FaultHandler));
740         for(;;);
741 }
742
743 void Proc_DumpThreadCPUState(tThread *Thread)
744 {
745         Log("  At %04x:%016llx", Thread->SavedState.UserCS, Thread->SavedState.UserRIP);
746 }
747
748 /**
749  * \fn void Proc_Scheduler(int CPU)
750  * \brief Swap current thread and clears dead threads
751  */
752 void Proc_Scheduler(int CPU)
753 {
754         Uint    rsp, rbp, rip;
755         tThread *thread;
756         
757         // If the spinlock is set, let it complete
758         if(IS_LOCKED(&glThreadListLock))        return;
759         
760         // Get current thread
761         thread = gaCPUs[CPU].Current;
762
763         if( thread )
764         {
765                 tRegs   *regs;
766                 // Reduce remaining quantum and continue timeslice if non-zero
767                 if(thread->Remaining--) return;
768                 // Reset quantum for next call
769                 thread->Remaining = thread->Quantum;
770         
771                 // Get machine state
772                 __asm__ __volatile__ ("mov %%rsp, %0":"=r"(rsp));
773                 __asm__ __volatile__ ("mov %%rbp, %0":"=r"(rbp));
774                 rip = GetRIP();
775                 if(rip == SWITCH_MAGIC) return; // Check if a switch happened
776                 
777                 // Save machine state
778                 thread->SavedState.RSP = rsp;
779                 thread->SavedState.RBP = rbp;
780                 thread->SavedState.RIP = rip;
781                 
782                 // TODO: Make this more stable somehow
783                 regs = (tRegs*)(rbp+(2+1)*8);   // RBP,Ret + CurThread
784                 thread->SavedState.UserCS = regs->CS;
785                 thread->SavedState.UserRIP = regs->RIP;
786         }
787         
788         // Get next thread
789         thread = Threads_GetNextToRun(CPU, thread);
790         
791         // Error Check
792         if(thread == NULL) {
793                 thread = gaCPUs[CPU].IdleThread;
794                 //Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
795                 //LogF("Zzzzz.\n");
796                 return;
797         }
798         
799         #if DEBUG_TRACE_SWITCH
800         LogF("Switching to task %i, CR3 = 0x%x, RIP = %p",
801                 thread->TID,
802                 thread->MemState.CR3,
803                 thread->SavedState.RIP
804                 );
805         #endif
806         
807         
808         if(CPU > MAX_CPUS)
809                 LogF("CPU = %i", CPU);
810         // Set current thread
811         gaCPUs[CPU].Current = thread;
812         
813         // Update Kernel Stack pointer
814         gTSSs[CPU].RSP0 = thread->KernelStack-4;
815         
816         // Set address space
817         __asm__ __volatile__ ("mov %0, %%cr3"::"a"(thread->MemState.CR3));
818         
819         // Switch threads
820         __asm__ __volatile__ (
821                 "mov %1, %%rsp\n\t"     // Restore RSP
822                 "mov %2, %%rbp\n\t"     // and RBP
823                 "jmp *%3" : :   // And return to where we saved state (Proc_Clone or Proc_Scheduler)
824                 "a"(SWITCH_MAGIC), "b"(thread->SavedState.RSP),
825                 "d"(thread->SavedState.RBP), "c"(thread->SavedState.RIP)
826                 );
827         for(;;);        // Shouldn't reach here
828 }
829
830 // === EXPORTS ===
831 EXPORT(Proc_SpawnWorker);

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