Adding support for the Local APIC Timer (requires some hacks)
authorJohn Hodge <[email protected]>
Sat, 17 Jul 2010 13:24:04 +0000 (21:24 +0800)
committerJohn Hodge <[email protected]>
Sat, 17 Jul 2010 13:24:04 +0000 (21:24 +0800)
Kernel/arch/x86/desctab.asm
Kernel/arch/x86/include/mp.h
Kernel/arch/x86/proc.asm
Kernel/arch/x86/proc.c
Kernel/arch/x86/start.asm

index 9d19300..1513984 100644 (file)
@@ -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
index 30b2780..3a42c0f 100644 (file)
@@ -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
index b0a1ef0..bcb0f58 100644 (file)
@@ -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:
index 5ee3ccc..065e6de 100644 (file)
@@ -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<giNumCPUs;pos++)
@@ -316,7 +328,6 @@ void ArchThreads_Init(void)
        {
                gaCPUs[pos].Current = NULL;
                if( pos != giProc_BootProcessorID ) {
-                       Log("Starting AP %i, (APIC %i)\n", pos, gaCPUs[pos].APICID);
                        MP_StartAP( pos );
                }
        }
@@ -344,11 +355,6 @@ void ArchThreads_Init(void)
        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);
        
@@ -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
 
index 302d1c3..74b5c71 100644 (file)
@@ -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

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