* proc.c
*/
#include <acess.h>
+#include <threads.h>
#include <proc.h>
#include <desctab.h>
#include <mm_virt.h>
// === CONSTANTS ===
#define SWITCH_MAGIC 0xFFFACE55 // There is no code in this area
// Base is 1193182
-#define TIMER_DIVISOR 11931 //~100Hz
+#define TIMER_BASE 1193182
+#define TIMER_DIVISOR 11931 //~100Hz
// === TYPES ===
#if USE_MP
Uint8 State; // 0: Unavaliable, 1: Idle, 2: Active
Uint16 Resvd;
tThread *Current;
+ tThread *IdleThread;
} tCPU;
#endif
extern tThread *gActiveThreads;
extern tThread *gSleepingThreads;
extern tThread *gDeleteThreads;
-extern tThread *Threads_GetNextToRun(int CPU);
extern void Threads_Dump(void);
extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
extern void Isr8(void); // Double Fault
#if USE_MP
volatile int giNumInitingCPUs = 0;
tMPInfo *gMPFloatPtr = NULL;
-Uint32 giMP_TimerCount; // Start Count for Local APIC Timer
+volatile Uint32 giMP_TimerCount; // Start Count for Local APIC Timer
tAPIC *gpMP_LocalAPIC = NULL;
Uint8 gaAPIC_to_CPU[256] = {0};
tCPU gaCPUs[MAX_CPUS];
tTSS *gTSSs = NULL; // Pointer to TSS array
tTSS gTSS0 = {0};
// --- Error Recovery ---
-char gaDoubleFaultStack[1024];
+char gaDoubleFaultStack[1024] __attribute__ ((section(".padata")));
tTSS gDoubleFault_TSS = {
- .ESP0 = (Uint)&gaDoubleFaultStack[1023],
+ .ESP0 = (Uint)&gaDoubleFaultStack[1024],
.SS0 = 0x10,
.CR3 = (Uint)gaInitPageDir - KERNEL_BASE,
.EIP = (Uint)Isr8,
- .ESP = (Uint)&gaDoubleFaultStack[1023],
+ .ESP = (Uint)&gaDoubleFaultStack[1024],
.CS = 0x08, .SS = 0x10,
.DS = 0x10, .ES = 0x10,
.FS = 0x10, .GS = 0x10,
}
break;
+
+ #if DUMP_MP_TABLES
case 1: // Bus
entSize = 8;
Log("%i: Bus", i);
default:
Log("%i: Unknown (%i)", i, ents->Type);
break;
+ #endif
}
ents = (void*)( (Uint)ents + entSize );
}
MM_FinishVirtualInit();
#endif
+ #if 0
// Initialise Double Fault TSS
gGDT[5].BaseLow = (Uint)&gDoubleFault_TSS & 0xFFFF;
gGDT[5].BaseMid = (Uint)&gDoubleFault_TSS >> 16;
gIDT[8].CS = 5<<3;
gIDT[8].Flags = 0x8500;
gIDT[8].OffsetHi = 0;
+ #endif
// Set timer frequency
outb(0x43, 0x34); // Set Channel 0, Low/High, Rate Generator
outb(0x40, TIMER_DIVISOR&0xFF); // Low Byte of Divisor
outb(0x40, (TIMER_DIVISOR>>8)&0xFF); // High Byte
+
+ #if USE_MP
// Get the count setting for APIC timer
Log("Determining APIC Count");
__asm__ __volatile__ ("sti");
while( giMP_TimerCount == 0 ) __asm__ __volatile__ ("hlt");
__asm__ __volatile__ ("cli");
- Log("APIC Count %i\n", giMP_TimerCount);
+ Log("APIC Count %i", giMP_TimerCount);
+ {
+ Uint64 freq = giMP_TimerCount;
+ freq /= TIMER_DIVISOR;
+ freq *= TIMER_BASE;
+ if( (freq /= 1000) < 2*1000)
+ Log("Bus Frequency %i KHz", freq);
+ else if( (freq /= 1000) < 2*1000)
+ Log("Bus Frequency %i MHz", freq);
+ else if( (freq /= 1000) < 2*1000)
+ Log("Bus Frequency %i GHz", freq);
+ else
+ Log("Bus Frequency %i THz", freq);
+ }
- #if USE_MP
// Initialise Normal TSS(s)
for(pos=0;pos<giNumCPUs;pos++)
{
gGDT[6+pos].BaseHi = ((Uint)(&gTSSs[pos])) >> 24;
#if USE_MP
}
-
- // Start APs
- for( pos = 0; pos < giNumCPUs; pos ++ )
- {
- gaCPUs[pos].Current = NULL;
- if( pos != giProc_BootProcessorID ) {
- MP_StartAP( pos );
- }
- }
-
- Log("Waiting for APs to come up\n");
- while( giNumInitingCPUs ) __asm__ __volatile__ ("hlt");
- MM_FinishVirtualInit();
- //Panic("Uh oh... MP Table Parsing is unimplemented\n");
#endif
// Load the BSP's TSS
#else
gCurrentThread = &gThreadZero;
#endif
+ gThreadZero.CurCPU = 0;
#if USE_PAE
gThreadZero.MemState.PDP[0] = 0;
*/
void Proc_Start(void)
{
+ #if USE_MP
+ int i;
+ #endif
+
+ #if USE_MP
+ // Start APs
+ for( i = 0; i < giNumCPUs; i ++ )
+ {
+ // Create Idle Task
+ if(Proc_Clone(0, 0) == 0)
+ {
+ gaCPUs[i].IdleThread = Proc_GetCurThread();
+ gaCPUs[i].IdleThread->ThreadName = "Idle Thread";
+ gaCPUs[i].IdleThread->NumTickets = 0; // Never called randomly
+ gaCPUs[i].IdleThread->Quantum = 1; // 1 slice quantum
+ for(;;) HALT(); // Just yeilds
+ }
+ gaCPUs[i].Current = NULL;
+
+ // Start the AP
+ if( i != giProc_BootProcessorID ) {
+ MP_StartAP( i );
+ }
+ }
+
+ // BSP still should run the current task
+ gaCPUs[0].Current = &gThreadZero;
+
+ // Start interrupts and wait for APs to come up
+ Log("Waiting for APs to come up\n");
+ __asm__ __volatile__ ("sti");
+ while( giNumInitingCPUs ) __asm__ __volatile__ ("hlt");
+ MM_FinishVirtualInit();
+ #else
+ // Create Idle Task
+ if(Proc_Clone(0, 0) == 0)
+ {
+ tThread *cur = Proc_GetCurThread();
+ cur->ThreadName = "Idle Thread";
+ Threads_SetTickets(0); // Never called randomly
+ cur->Quantum = 1; // 1 slice quantum
+ for(;;) HALT(); // Just yeilds
+ }
+
+ // Set current task
+ gCurrentThread = &gThreadZero;
+
// Start Interrupts (and hence scheduler)
__asm__ __volatile__("sti");
+ #endif
}
/**
eip = GetEIP();
if(eip == SWITCH_MAGIC) {
outb(0x20, 0x20); // ACK Timer and return as child
+ __asm__ __volatile__ ("sti"); // Restart interrupts
return 0;
}
// Check if there is any tasks running
if(giNumActiveThreads == 0) {
+ #if 0
Log("No Active threads, sleeping");
+ #endif
+ #if USE_MP
+ if(CPU)
+ gpMP_LocalAPIC->EOI.Val = 0;
+ else
+ #endif
+ outb(0x20, 0x20);
__asm__ __volatile__ ("hlt");
return;
}
thread = gCurrentThread;
#endif
- // Reduce remaining quantum and continue timeslice if non-zero
- if(thread->Remaining--) return;
- // Reset quantum for next call
- thread->Remaining = thread->Quantum;
-
- // Get machine state
- __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
- __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
- eip = GetEIP();
- if(eip == SWITCH_MAGIC) return; // Check if a switch happened
-
- // Save machine state
- thread->SavedState.ESP = esp;
- thread->SavedState.EBP = ebp;
- thread->SavedState.EIP = eip;
+ if( thread )
+ {
+ // Reduce remaining quantum and continue timeslice if non-zero
+ if(thread->Remaining--) return;
+ // Reset quantum for next call
+ thread->Remaining = thread->Quantum;
+
+ // Get machine state
+ __asm__ __volatile__ ("mov %%esp, %0":"=r"(esp));
+ __asm__ __volatile__ ("mov %%ebp, %0":"=r"(ebp));
+ eip = GetEIP();
+ if(eip == SWITCH_MAGIC) return; // Check if a switch happened
+
+ // Save machine state
+ thread->SavedState.ESP = esp;
+ thread->SavedState.EBP = ebp;
+ thread->SavedState.EIP = eip;
+ }
- // Get next thread
- thread = Threads_GetNextToRun(CPU);
+ // Get next thread to run
+ thread = Threads_GetNextToRun(CPU, thread);
- // Error Check
+ // No avaliable tasks, just go into low power mode
if(thread == NULL) {
- Warning("Hmm... Threads_GetNextToRun returned NULL, I don't think this should happen.\n");
- return;
+ //HALT();
+ //return;
+ thread = gaCPUs[CPU].IdleThread;
}
#if DEBUG_TRACE_SWITCH