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

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