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

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