From 67ac6b835aea7bbf88fe7847fcdf980b9112a54e Mon Sep 17 00:00:00 2001 From: Doug Gale Date: Sat, 28 Jan 2017 02:25:21 -0500 Subject: [PATCH] - HUGE APIC fix! Now works properly in qemu -enable-kvm! - Implement APIC spurious IRQ handling properly - Add API to get timer current count register - Stop using PIT for scheduling --- kernel/arch/x86_64/cpu/apic.c | 186 +++++++++++++++++++++++----- kernel/arch/x86_64/cpu/apic.h | 1 + kernel/arch/x86_64/cpu/legacy_pit.c | 3 +- 3 files changed, 157 insertions(+), 33 deletions(-) diff --git a/kernel/arch/x86_64/cpu/apic.c b/kernel/arch/x86_64/cpu/apic.c index 5e768ac8..6c528f60 100644 --- a/kernel/arch/x86_64/cpu/apic.c +++ b/kernel/arch/x86_64/cpu/apic.c @@ -15,6 +15,7 @@ #include "time.h" #include "cpuid.h" #include "spinlock.h" +#include "assert.h" // // MP Tables @@ -275,7 +276,7 @@ static uint32_t volatile *apic_ptr; #define APIC_DEST_BIT 24 #define APIC_DEST_BITS 8 -#define APIC_DEST_MASK ((1 << APIC_DEST_BITS)-1) +#define APIC_DEST_MASK ((1U << APIC_DEST_BITS)-1U) #define APIC_DEST_n(n) (((n) & APIC_DEST_MASK) << APIC_DEST_BIT) #define APIC_CMD_SIPI_PAGE_BIT 0 @@ -308,12 +309,12 @@ static uint32_t volatile *apic_ptr; #define APIC_CMD_VECTOR_n(n) (((n) & APIC_CMD_VECTOR_MASK) << APIC_CMD_VECTOR_BIT) -#define APIC_CMD_VECTOR (1 << APIC_CMD_VECTOR_BIT) -#define APIC_CMD_DEST_LOGICAL (1 << APIC_CMD_DEST_LOGICAL_BIT) -#define APIC_CMD_PENDING (1 << APIC_CMD_PENDING_BIT) -#define APIC_CMD_ILD_CLR (1 << APIC_CMD_ILD_CLR_BIT) -#define APIC_CMD_ILD_SET (1 << APIC_CMD_ILD_SET_BIT) -#define APIC_CMD_DEST_TYPE (1 << APIC_CMD_DEST_TYPE_BIT) +#define APIC_CMD_VECTOR (1U << APIC_CMD_VECTOR_BIT) +#define APIC_CMD_DEST_LOGICAL (1U << APIC_CMD_DEST_LOGICAL_BIT) +#define APIC_CMD_PENDING (1U << APIC_CMD_PENDING_BIT) +#define APIC_CMD_ILD_CLR (1U << APIC_CMD_ILD_CLR_BIT) +#define APIC_CMD_ILD_SET (1U << APIC_CMD_ILD_SET_BIT) +#define APIC_CMD_DEST_TYPE (1U << APIC_CMD_DEST_TYPE_BIT) #define APIC_CMD_DEST_MODE_NORMAL APIC_CMD_DEST_MODE_n(0) #define APIC_CMD_DEST_MODE_LOWPRI APIC_CMD_DEST_MODE_n(1) @@ -338,22 +339,56 @@ static uint32_t volatile *apic_ptr; #define APIC_LVT_DCR_BY_1 (8+3) #define APIC_SIR_APIC_ENABLE_BIT 8 - #define APIC_SIR_APIC_ENABLE (1<= 32) + sir = (sir & -256) | spurious_intr; + + APIC_SIR = sir; +} + +static int apic_dump_impl(int reg) +{ + // Reserved registers: + // 0x00, 0x10, + return (reg & 0xF) == 0 && + !(reg >= 0x000 && reg <= 0x010) && + !(reg >= 0x040 && reg <= 0x070) && + !(reg >= 0x290 && reg <= 0x2E0) && + !(reg >= 0x3A0 && reg <= 0x3D0) && + !(reg == 0x3F0) && + (reg < 0x400) && + (reg >= 0) && + // Bochs does not like these + (reg != 0x0C0) && + (reg != 0x2F0); +} + +static void apic_dump_regs(int ap) +{ + for (int i = 0; i < 256; i += 16) { + printdbg("ap=%d APIC: ", ap); + for (int x = 0; x < 16; x += 4) { + if (apic_dump_impl((i + x) * 4)) { + printdbg("[%3x]=%08x%s", (i + x) * 4, + apic_ptr[i + x], + x == 12 ? "\n" : " "); + } else { + printdbg("[%3x]=--------%s", (i + x) * 4, + x == 12 ? "\n" : " "); + } + } + } } static void apic_configure_timer( @@ -656,40 +739,74 @@ static void apic_configure_timer( { APIC_LVT_DCR = dcr; atomic_barrier(); - APIC_LVT_ICR = icr; - atomic_barrier(); - APIC_LVT_TR = APIC_LVT_TR_VECTOR_n(intr) | + APIC_LVT_TR = APIC_LVT_VECTOR_n(intr) | APIC_LVT_TR_MODE_n(timer_mode); + atomic_barrier(); + APIC_LVT_ICR = icr; } int apic_init(int ap) { - if (ap) { - apic_enable(1); + if (!ap) { + // Bootstrap CPU only + + assert(apic_base == 0); + apic_base = msr_get(APIC_BASE_MSR); + + // Set global enable if it is clear + if (!(apic_base & APIC_BASE_GENABLE)) { + printdbg("APIC was globally disabled!" + " Enabling...\n"); + msr_set(APIC_BASE_MSR, apic_base | + APIC_BASE_GENABLE); + } + + apic_base &= APIC_BASE_ADDR; - apic_configure_timer(APIC_LVT_DCR_BY_1, - ((2500000000U)/(60)), - APIC_LVT_TR_MODE_PERIODIC, - INTR_APIC_TIMER); + assert(apic_ptr == 0); + apic_ptr = mmap((void*)apic_base, 4096, + PROT_READ | PROT_WRITE, + MAP_PHYSICAL | + MAP_NOCACHE | + MAP_WRITETHRU, -1, 0); - return 1; - } else { intr_hook(INTR_APIC_TIMER, apic_timer_handler); + intr_hook(INTR_APIC_SPURIOUS, apic_spurious_handler); + + parse_mp_tables(); } - if (!parse_mp_tables()) - return 0; + apic_enable(1, INTR_APIC_SPURIOUS); + + APIC_TPR = 0; - printdbg("Found MP tables\n"); + apic_configure_timer(APIC_LVT_DCR_BY_1, + ((1000000000U)/(60)), + APIC_LVT_TR_MODE_PERIODIC, + INTR_APIC_TIMER); - apic_base = msr_get(APIC_BASE_MSR) & -(intptr_t)4096; + assert(apic_base == (msr_get(APIC_BASE_MSR) & APIC_BASE_ADDR)); - apic_ptr = mmap((void*)apic_base, 4096, - PROT_READ | PROT_WRITE, MAP_PHYSICAL, -1, 0); + apic_dump_regs(ap); return 1; } +//APIC_LVT_LNT0 |= APIC_LVT_MASK; +//APIC_LVT_LNT1 |= APIC_LVT_MASK; +//APIC_LVT_ERR |= APIC_LVT_MASK; +//APIC_LVT_PMCR |= APIC_LVT_MASK; +//APIC_LVT_TSR |= APIC_LVT_MASK; + +//uint32_t last_count = apic_timer_count(); +//uint32_t this_count; +//do { +// this_count = apic_timer_count(); +// if (this_count > last_count) +// printdbg("Tick\n"); +// last_count = this_count; +//} while(1); + static void apic_detect_topology(void) { cpuid_t info; @@ -805,3 +922,8 @@ void apic_start_smp(void) } } } + +uint32_t apic_timer_count(void) +{ + return APIC_LVT_CCR; +} diff --git a/kernel/arch/x86_64/cpu/apic.h b/kernel/arch/x86_64/cpu/apic.h index f1bd31d4..8dc36c3c 100644 --- a/kernel/arch/x86_64/cpu/apic.h +++ b/kernel/arch/x86_64/cpu/apic.h @@ -6,3 +6,4 @@ void apic_start_smp(void); unsigned apic_get_id(void); void apic_send_ipi(int target_apic_id, uint8_t intr); void apic_eoi(int intr); +uint32_t apic_timer_count(void); diff --git a/kernel/arch/x86_64/cpu/legacy_pit.c b/kernel/arch/x86_64/cpu/legacy_pit.c index 5a53c23e..985c2aa3 100644 --- a/kernel/arch/x86_64/cpu/legacy_pit.c +++ b/kernel/arch/x86_64/cpu/legacy_pit.c @@ -102,6 +102,7 @@ static void *pit8254_context_switch_handler(int intr, void *ctx) static void *pit8254_handler(int irq, void *ctx) { (void)irq; + assert(irq == 0); atomic_inc_uint64(&timer_ticks); @@ -128,7 +129,7 @@ static void *pit8254_handler(int irq, void *ctx) } - return thread_schedule(ctx); + return ctx;//thread_schedule(ctx); } static uint64_t pit8254_time_ms(void)