SETISR 0xAC
SETUSER 0xAC
+ %if USE_MP
+ SETISR 239
+ %endif
+
%assign i 0xF0
%rep 16
SETISR i
DEF_SYSCALL 0xAC ; Acess System Call
+; AP's Timer Interrupt
+%if USE_MP
+[global Isr239]
+[extern SchedulerBase]
+Isr239:
+ push 0
+ jmp SchedulerBase
+%endif
+
; IRQs
; - Timer
[global Isr240]
[extern SchedulerBase]
+[extern SetAPICTimerCount]
Isr240:
push 0
+ %if USE_MP
+ jmp SetAPICTimerCount
+ %else
jmp SchedulerBase
+ %endif
; - Assignable
%assign i 0xF1
%rep 16
; IRQ Handling
; ------------
[extern IRQ_Handler]
+[global IRQCommon]
IRQCommon:
pusha
push ds
} tReg;
typedef volatile struct {
- tReg _unused;
- tReg _unused2;
+ tReg _unused1[2];
tReg ID;
tReg Version;
-} tAPIC;
+ tReg _unused2[4];
+ tReg TPR; // Task Priority Register
+ tReg APR; // Arbitration Priority Register (RO)
+ tReg PPR; // Processor Priority Register (RO)
+ tReg EOI; // EOI Register (Write Only)
+ tReg _unused3[1];
+ tReg LogDest; // Logical Destination Register
+ tReg DestFmt; // Destination Format Register (0-27: RO, 28-31: RW)
+ tReg SIV; // Spurious Interrupt Vector Register (0-8: RW, 9-31: RO)
+ tReg ISR[8]; // In-Service Register - Total 256 Bits (RO)
+ tReg TMR[8]; // Trigger Mode Register - Total 256 Bits (RO)
+ tReg IRR[8]; // Interrupt Request Register - Total 256 Bits (RO)
+ tReg ErrorStatus; // Error Status Register (RO)
+ tReg _unused4[6];
+ tReg LVTCMI; // LVT CMI Registers
+ // 0x300
+ tReg ICR[2]; // Interrupt Command Register (RW)
+ // LVT Registers (Controls Local Vector Table)
+ // Structure:
+ // 0-7: Vector - IDT Vector for the interrupt
+ // 12: Delivery Status (0: Idle, 1: Send Pending)
+ // 16: Mask (0: Enabled, 1: Disabled)
+ // 0x320
+ tReg LVTTimer; // LVT Timer Register (RW)
+ tReg LVTThermalSensor; // LVT Thermal Sensor Register (RW)
+ tReg LVTPerfMonCounters; // LVT Performance Monitor Counters Register (RW)
+ tReg LVTLInt0; // LVT Local Interrupt (LINT) #0 Register (RW);
+ tReg LVTLInt1; // LVT Local Interrupt (LINT) #1 Register (RW);
+ tReg LVTError; // LVT Error Register (RW);
+ // 0x380
+ tReg InitialCount; // Initial Count Register (Used for the timer) (RW)
+ tReg CurrentCount; // Current Count Register (Used for the timer) (RW)
+ tReg _unused5[4];
+ // 0x3E0
+ tReg DivideConifg; // Divide Configuration Register (RW)
+ tReg _unused6[1];
+} volatile tAPIC;
#endif
KSTACK_USERSTATE_SIZE equ (4+8+1+5)*4 ; SRegs, GPRegs, CPU, IRET
[section .text]
+[extern giMP_TimerCount]
+[extern gpMP_LocalAPIC]
+[extern Isr240]
+[global SetAPICTimerCount]
+SetAPICTimerCount:
+ pusha
+ push ds
+ push es
+ push fs
+ push gs
+
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov eax, [gpMP_LocalAPIC]
+ mov ecx, [eax+0x320]
+ test ecx, 0x0001000
+ jz .setTime
+ mov DWORD [eax+0x380], 0xFFFFFFFF ; Set Initial Count
+ mov DWORD [eax+0x320], 0x000000F0 ; Enable the timer on IVT#0xEF (One Shot)
+ jmp .ret
+
+.setTime:
+ ; Get Timer Count
+ mov ecx, 0xFFFFFFFF
+ sub ecx, [eax+0x390]
+ mov DWORD [giMP_TimerCount], ecx
+ ; Disable APIC Timer
+ mov DWORD [eax+0x320], 0x00010000
+
+ ; Update Timer IRQ to the IRQ code
+ mov eax, SchedulerBase
+ sub eax, Isr240+5+5+1
+ mov DWORD [Isr240+5+5+1], eax
+
+.ret:
+ mov dx, 0x20
+ mov al, 0x20
+ out dx, al ; ACK IRQ
+ popa
+ add esp, 4 ; CPU ID
+ ; No Error code / int num
+ iret
+
; --------------
; Task Scheduler
; --------------
; Child
push edx ; Argument
call ebx ; Function
+ push eax ; Exit Code
+ push 0 ; Kill this thread
call Threads_Exit ; Kill Thread
.parent:
#if USE_MP
volatile int giNumInitingCPUs = 0;
tMPInfo *gMPFloatPtr = NULL;
+Uint32 giMP_TimerCount; // Start Count for Local APIC Timer
tAPIC *gpMP_LocalAPIC = NULL;
Uint8 gaAPIC_to_CPU[256] = {0};
tCPU gaCPUs[MAX_CPUS];
gIDT[8].Flags = 0x8500;
gIDT[8].OffsetHi = 0;
+ // 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
+ // 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);
+
#if USE_MP
// Initialise Normal TSS(s)
for(pos=0;pos<giNumCPUs;pos++)
{
gaCPUs[pos].Current = NULL;
if( pos != giProc_BootProcessorID ) {
- Log("Starting AP %i, (APIC %i)\n", pos, gaCPUs[pos].APICID);
MP_StartAP( pos );
}
}
gThreadZero.MemState.CR3 = (Uint)gaInitPageDir - KERNEL_BASE;
#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
-
// Create Per-Process Data Block
MM_Allocate(MM_PPD_CFG);
// Delay
inb(0x80); inb(0x80); inb(0x80); inb(0x80);
+ // TODO: Use a better address, preferably registered with the MM
+ // - MM_AllocDMA mabye?
// Create a far jump
*(Uint8*)(KERNEL_BASE|0x11000) = 0xEA; // Far JMP
*(Uint16*)(KERNEL_BASE|0x11001) = (Uint)&APStartup - (KERNEL_BASE|0xFFFF0); // IP
*/
void MP_SendIPI(Uint8 APICID, int Vector, int DeliveryMode)
{
- Uint32 addr = (Uint)gpMP_LocalAPIC + 0x300;
Uint32 val;
// Hi
val = (Uint)APICID << 24;
- Log("*%p = 0x%08x", addr+0x10, val);
- *(Uint32*)(addr+0x10) = val;
-
+ Log("*%p = 0x%08x", &gpMP_LocalAPIC->ICR[1], val);
+ gpMP_LocalAPIC->ICR[1].Val = val;
// Low (and send)
val = ((DeliveryMode & 7) << 8) | (Vector & 0xFF);
- Log("*%p = 0x%08x", addr, val);
- *(Uint32*)addr = val;
+ Log("*%p = 0x%08x", &gpMP_LocalAPIC->ICR[0], val);
+ gpMP_LocalAPIC->ICR[0].Val = val;
}
#endif
[extern gGDTPtr]
[extern gIDTPtr]
[extern gpMP_LocalAPIC]
+[extern giMP_TimerCount]
[extern gaAPIC_to_CPU]
[extern gaCPUs]
[extern giNumInitingCPUs]
shl cx, 3
add cx, 0x30
ltr cx
+ ; Enable Local APIC Timer
+ mov ecx, [giMP_TimerCount]
+ mov [eax+0x380], ecx ; Set Initial Count
+ mov DWORD [eax+0x320], 0x000200EF ; Enable the timer on IVT#0xEF
+
; CPU is now marked as initialised
sti
;xchg bx, bx ; MAGIC BREAK