From 43be77083eba1fc5b11b46deddcf499bac054d6e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 17 Jul 2010 21:24:04 +0800 Subject: [PATCH 1/1] Adding support for the Local APIC Timer (requires some hacks) --- Kernel/arch/x86/desctab.asm | 19 ++++++++++++++ Kernel/arch/x86/include/mp.h | 41 +++++++++++++++++++++++++++--- Kernel/arch/x86/proc.asm | 49 ++++++++++++++++++++++++++++++++++++ Kernel/arch/x86/proc.c | 30 +++++++++++++--------- Kernel/arch/x86/start.asm | 6 +++++ 5 files changed, 130 insertions(+), 15 deletions(-) diff --git a/Kernel/arch/x86/desctab.asm b/Kernel/arch/x86/desctab.asm index 9d19300d..1513984a 100644 --- a/Kernel/arch/x86/desctab.asm +++ b/Kernel/arch/x86/desctab.asm @@ -76,6 +76,10 @@ Desctab_Install: SETISR 0xAC SETUSER 0xAC + %if USE_MP + SETISR 239 + %endif + %assign i 0xF0 %rep 16 SETISR i @@ -187,13 +191,27 @@ ISR_NOERR 31; 31: Reserved 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 @@ -258,6 +276,7 @@ SyscallCommon: ; IRQ Handling ; ------------ [extern IRQ_Handler] +[global IRQCommon] IRQCommon: pusha push ds diff --git a/Kernel/arch/x86/include/mp.h b/Kernel/arch/x86/include/mp.h index 30b2780f..3a42c0f0 100644 --- a/Kernel/arch/x86/include/mp.h +++ b/Kernel/arch/x86/include/mp.h @@ -96,10 +96,45 @@ typedef struct { } 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 diff --git a/Kernel/arch/x86/proc.asm b/Kernel/arch/x86/proc.asm index b0a1ef05..bcb0f586 100644 --- a/Kernel/arch/x86/proc.asm +++ b/Kernel/arch/x86/proc.asm @@ -8,6 +8,53 @@ KERNEL_BASE equ 0xC0000000 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 ; -------------- @@ -66,6 +113,8 @@ SpawnTask: ; Child push edx ; Argument call ebx ; Function + push eax ; Exit Code + push 0 ; Kill this thread call Threads_Exit ; Kill Thread .parent: diff --git a/Kernel/arch/x86/proc.c b/Kernel/arch/x86/proc.c index 5ee3ccc5..065e6de3 100644 --- a/Kernel/arch/x86/proc.c +++ b/Kernel/arch/x86/proc.c @@ -73,6 +73,7 @@ void Proc_Scheduler(int CPU); #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]; @@ -296,6 +297,17 @@ void ArchThreads_Init(void) 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>8)&0xFF); // High Byte - // Create Per-Process Data Block MM_Allocate(MM_PPD_CFG); @@ -370,6 +376,8 @@ void MP_StartAP(int CPU) // 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 @@ -389,18 +397,16 @@ void MP_StartAP(int CPU) */ 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 diff --git a/Kernel/arch/x86/start.asm b/Kernel/arch/x86/start.asm index 302d1c3c..74b5c710 100644 --- a/Kernel/arch/x86/start.asm +++ b/Kernel/arch/x86/start.asm @@ -93,6 +93,7 @@ start: [extern gGDTPtr] [extern gIDTPtr] [extern gpMP_LocalAPIC] +[extern giMP_TimerCount] [extern gaAPIC_to_CPU] [extern gaCPUs] [extern giNumInitingCPUs] @@ -154,6 +155,11 @@ APStartup: 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 -- 2.20.1