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

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