From 03551659d4555f890f8607b60fbc80aba703c6ac Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Sun, 14 Feb 2016 15:24:01 +0100 Subject: [PATCH] revise code, stop x2APIC support if Linux doesn't use it --- hermit/arch/x86/include/asm/processor.h | 2 + hermit/arch/x86/kernel/apic.c | 112 ++++++++++++++++++------ hermit/arch/x86/kernel/entry.asm | 2 + hermit/arch/x86/kernel/timer.c | 51 ++++++----- 4 files changed, 119 insertions(+), 48 deletions(-) diff --git a/hermit/arch/x86/include/asm/processor.h b/hermit/arch/x86/include/asm/processor.h index be0c0fa9e..cc1073e86 100644 --- a/hermit/arch/x86/include/asm/processor.h +++ b/hermit/arch/x86/include/asm/processor.h @@ -194,6 +194,8 @@ extern "C" { /// SwapGS GS shadow #define MSR_KERNEL_GS_BASE 0xc0000102 +#define MSR_XAPIC_ENABLE (1UL << 11) +#define MSR_X2APIC_ENABLE (1UL << 10) #define MSR_IA32_MISC_ENABLE 0x000001a0 #define MSR_IA32_FEATURE_CONTROL 0x0000003a diff --git a/hermit/arch/x86/kernel/apic.c b/hermit/arch/x86/kernel/apic.c index c3ce0fd48..94e476e98 100644 --- a/hermit/arch/x86/kernel/apic.c +++ b/hermit/arch/x86/kernel/apic.c @@ -150,6 +150,48 @@ int apic_is_enabled(void) return (lapic && initialized); } +static inline void x2apic_disable(void) +{ + uint64_t msr; + + if (!has_x2apic()) + return; + + msr = rdmsr(MSR_APIC_BASE); + if (!(msr & MSR_X2APIC_ENABLE)) { + kprintf("X2APIC already disabled!\n"); + return; + } + + /* Disable xapic and x2apic first and then reenable xapic mode */ + wrmsr(MSR_APIC_BASE, msr & ~(MSR_X2APIC_ENABLE | MSR_XAPIC_ENABLE)); + wrmsr(MSR_APIC_BASE, msr & ~MSR_X2APIC_ENABLE); + + kprintf("Disable X2APIC support\n"); + lapic_read = lapic_read_default; + lapic_write = lapic_write_default; +} + +static inline void x2apic_enable(void) +{ + uint64_t msr; + + if (!has_x2apic()) + return; + + msr = rdmsr(MSR_APIC_BASE); + if (msr & MSR_X2APIC_ENABLE) { + kprintf("X2APIC already enabled!\n"); + return; + } + + wrmsr(MSR_APIC_BASE, msr | MSR_X2APIC_ENABLE); + + kprintf("Enable X2APIC support!\n"); + lapic_read = lapic_read_msr; + lapic_write = lapic_write_msr; +} + /* * Send a 'End of Interrupt' command to the APIC */ @@ -303,6 +345,8 @@ static int lapic_reset(void) if (!lapic) return -ENXIO; + x2apic_enable(); + max_lvt = apic_lvt_entries(); lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127 @@ -543,15 +587,16 @@ check_lapic: kprintf("Found APIC at 0x%x\n", lapic); if (has_x2apic()) { - kprintf("Enable X2APIC support!\n"); - wrmsr(MSR_APIC_BASE, lapic | 0xD00); - lapic_read = lapic_read_msr; - lapic_write = lapic_write_msr; + x2apic_enable(); } else { - page_map(LAPIC_ADDR, (size_t)lapic & PAGE_MASK, 1, PG_GLOBAL | PG_RW | PG_PCD); - vma_add(LAPIC_ADDR, LAPIC_ADDR + PAGE_SIZE, VMA_READ | VMA_WRITE); - lapic = LAPIC_ADDR; - kprintf("Map APIC to 0x%x\n", lapic); + if (page_map(LAPIC_ADDR, (size_t)lapic & PAGE_MASK, 1, PG_GLOBAL | PG_RW | PG_PCD)) { + kprintf("Failed to map APIC to 0x%x\n", LAPIC_ADDR); + goto out; + } else { + kprintf("Mapped APIC 0x%x to 0x%x\n", lapic, LAPIC_ADDR); + vma_add(LAPIC_ADDR, LAPIC_ADDR + PAGE_SIZE, VMA_READ | VMA_WRITE); + lapic = LAPIC_ADDR; + } } kprintf("Maximum LVT Entry: 0x%x\n", apic_lvt_entries()); @@ -592,8 +637,7 @@ extern atomic_int32_t current_boot_id; #if MAX_CORES > 1 int smp_start(void) { - if (has_x2apic()) // enable x2APIC support - wrmsr(MSR_APIC_BASE, lapic | 0xD00); + x2apic_enable(); // reset APIC and set id lapic_reset(); @@ -645,7 +689,7 @@ int ipi_tlb_flush(void) if (atomic_int32_read(&cpu_online) == 1) return 0; - if (BUILTIN_EXPECT(has_x2apic(), 1)) { + if (has_x2apic()) { flags = irq_nested_disable(); for(i=0; iid == apic_cpu_id()); + irq_disable(); + if (if_bootprocessor) { - kprintf("Receive an IPI to shutdown HermitCore\n"); + kprintf("Try to shutdown HermitCore\n"); while(atomic_int32_read(&cpu_online) != 1) PAUSE; network_shutdown(); - kprintf("Diable APIC timer\n"); + kprintf("Disable APIC timer\n"); } apic_disable_timer(); @@ -757,16 +806,29 @@ static void apic_shutdown(struct state *s) lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt - lapic_write(APIC_SVR, 0x00); // disable the apic + lapic_write(APIC_SVR, 0x00); // disable the apic + + // disable x2APIC + if (if_bootprocessor && disable_x2apic) + x2apic_disable(); if (if_bootprocessor) kprintf("System goes down...\n"); flush_cache(); atomic_int32_dec(&cpu_online); - HALT; - kprintf("Ups, we should never reach this point!\n"); - while(1); + while(1) { + HALT; + } +} + +volatile uint32_t go_down = 0; + +static void apic_shutdown(struct state * s) +{ + go_down = 1; + + kputs("Receive shutdown interrupt\n"); } static void apic_lint0(struct state * s) diff --git a/hermit/arch/x86/kernel/entry.asm b/hermit/arch/x86/kernel/entry.asm index 5b5a8a275..40c8ec917 100644 --- a/hermit/arch/x86/kernel/entry.asm +++ b/hermit/arch/x86/kernel/entry.asm @@ -65,6 +65,7 @@ align 4 global header_start_address global heap_size global header_size + global disable_x2apic base dq 0 limit dq 0 cpu_freq dd 0 @@ -83,6 +84,7 @@ align 4 possible_isles dd 1 heap_start_address dq 0 header_start_address dq 0 + disable_x2apic dd 1 ; Bootstrap page tables are used during the initialization. align 4096 diff --git a/hermit/arch/x86/kernel/timer.c b/hermit/arch/x86/kernel/timer.c index dca9e0258..5f6536173 100644 --- a/hermit/arch/x86/kernel/timer.c +++ b/hermit/arch/x86/kernel/timer.c @@ -140,30 +140,8 @@ int timer_wait(unsigned int ticks) while(rdtsc() - start < 1000000) ; \ } while (0) -/* - * Sets up the system clock by installing the timer handler - * into IRQ0 - */ -int timer_init(void) +static int pit_init(void) { - /* - * Installs 'timer_handler' for the PIC and APIC timer, - * only one handler will be later used. - */ - irq_install_handler(32, timer_handler); - irq_install_handler(123, timer_handler); - irq_install_handler(121, wakeup_handler); - -#ifdef DYNAMIC_TICKS - if (has_rdtscp()) - last_rdtsc = rdtscp(NULL); - else - last_rdtsc = rdtsc(); -#endif - - if (cpu_freq) // do we need to configure the timer? - return 0; - /* * Port 0x43 is for initializing the PIT: * @@ -189,3 +167,30 @@ int timer_init(void) return 0; } + +/* + * Sets up the system clock by installing the timer handler + * into IRQ0 + */ +int timer_init(void) +{ + /* + * Installs 'timer_handler' for the PIC and APIC timer, + * only one handler will be later used. + */ + irq_install_handler(32, timer_handler); + irq_install_handler(123, timer_handler); + irq_install_handler(121, wakeup_handler); + +#ifdef DYNAMIC_TICKS + if (has_rdtscp()) + last_rdtsc = rdtscp(NULL); + else + last_rdtsc = rdtsc(); +#endif + + if (cpu_freq) // do we need to configure the timer? + return 0; + + return pit_init(); +}