From f7b5b482661ce0dae01dbe21ebb5631e8d301028 Mon Sep 17 00:00:00 2001 From: Tomoki Shirasawa Date: Wed, 6 Jan 2016 13:53:02 +0900 Subject: [PATCH] support x2apic --- arch/x86/kernel/cpu.c | 201 +++++++++++++++++++++++++++++++----------- 1 file changed, 150 insertions(+), 51 deletions(-) diff --git a/arch/x86/kernel/cpu.c b/arch/x86/kernel/cpu.c index 1312c993..57543763 100644 --- a/arch/x86/kernel/cpu.c +++ b/arch/x86/kernel/cpu.c @@ -52,6 +52,11 @@ #define APIC_DIVISOR 16 #define APIC_LVT_TIMER_PERIODIC (1 << 17) +#define APIC_BASE_MSR 0x800 +#define IA32_X2APIC_APICID 0x802 +#define IA32_X2APIC_ICR 0x830 +#define X2APIC_ENABLE (1UL << 10) +#define NMI_VECTOR 0x02 //#define DEBUG_PRINT_CPU @@ -61,6 +66,13 @@ #define dkprintf(...) do { if (0) kprintf(__VA_ARGS__); } while (0) #endif +static void *lapic_vp; +static int x2apic; +static void (*lapic_write)(int reg, unsigned int value); +static unsigned int (*lapic_read)(int reg); +static void (*lapic_icr_write)(unsigned int h, unsigned int l); +static void (*lapic_wait_icr_idle)(void); +void (*x86_issue_ipi)(unsigned int apicid, unsigned int low); void init_processors_local(int max_id); void assign_processor_id(void); @@ -238,25 +250,39 @@ void init_gdt(void) reload_gdt(&gdt_desc); } -static void *lapic_vp; -void lapic_write(int reg, unsigned int value) +static void +apic_write(int reg, unsigned int value) { *(volatile unsigned int *)((char *)lapic_vp + reg) = value; } -unsigned int lapic_read(int reg) +static void +x2apic_write(int reg, unsigned int value) +{ + reg >>= 4; + reg |= APIC_BASE_MSR; + wrmsr(reg, value); +} + +static unsigned int +apic_read(int reg) { return *(volatile unsigned int *)((char *)lapic_vp + reg); } -void lapic_icr_write(unsigned int h, unsigned int l) +static unsigned int +x2apic_read(int reg) { - lapic_write(LAPIC_ICR2, (unsigned int)h); - lapic_write(LAPIC_ICR0, l); + unsigned long value; + + reg >>= 4; + reg |= APIC_BASE_MSR; + value = rdmsr(reg); + return (int)value; } - -void lapic_timer_enable(unsigned int clocks) +void +lapic_timer_enable(unsigned int clocks) { unsigned int lvtt_value; @@ -268,11 +294,116 @@ void lapic_timer_enable(unsigned int clocks) lapic_write(LAPIC_TIMER, lvtt_value); } -void lapic_timer_disable() +void +lapic_timer_disable() { lapic_write(LAPIC_TIMER_INITIAL, 0); } +void +lapic_ack(void) +{ + lapic_write(LAPIC_EOI, 0); +} + +static void +x2apic_wait_icr_idle(void) +{ +} + +static void +apic_wait_icr_idle(void) +{ + while (lapic_read(LAPIC_ICR0) & APIC_ICR_BUSY) { + cpu_pause(); + } +} + +static void +x2apic_icr_write(unsigned int low, unsigned int apicid) +{ + wrmsr(IA32_X2APIC_ICR, (((unsigned long)apicid) << 32) | low); +} + +static void +apic_icr_write(unsigned int h, unsigned int l) +{ + lapic_write(LAPIC_ICR2, (unsigned int)h); + lapic_write(LAPIC_ICR0, l); +} + +static void +x2apic_x86_issue_ipi(unsigned int apicid, unsigned int low) +{ + unsigned long icr = low; + unsigned long flags; + + ihk_mc_mb(); + flags = cpu_disable_interrupt_save(); + x2apic_icr_write(icr, apicid); + cpu_restore_interrupt(flags); +} + +static void +apic_x86_issue_ipi(unsigned int apicid, unsigned int low) +{ + unsigned long flags; + + flags = cpu_disable_interrupt_save(); + apic_wait_icr_idle(); + apic_icr_write(apicid << LAPIC_ICR_ID_SHIFT, low); + cpu_restore_interrupt(flags); +} + +unsigned long +x2apic_is_enabled() +{ + unsigned long msr; + + msr = rdmsr(MSR_IA32_APIC_BASE); + + return (msr & X2APIC_ENABLE); +} + +void init_lapic_bsp(void) +{ + if(x2apic_is_enabled()){ + x2apic = 1; + lapic_write = x2apic_write; + lapic_read = x2apic_read; + lapic_icr_write = x2apic_icr_write; + lapic_wait_icr_idle = x2apic_wait_icr_idle; + x86_issue_ipi = x2apic_x86_issue_ipi; + } + else{ + x2apic = 0; + lapic_write = apic_write; + lapic_read = apic_read; + lapic_icr_write = apic_icr_write; + lapic_wait_icr_idle = apic_wait_icr_idle; + x86_issue_ipi = apic_x86_issue_ipi; + + } +} + +void +init_lapic() +{ + if(!x2apic){ + unsigned long baseaddr; + + /* Enable Local APIC */ + baseaddr = rdmsr(MSR_IA32_APIC_BASE); + if (!lapic_vp) { + lapic_vp = map_fixed_area(baseaddr & PAGE_MASK, PAGE_SIZE, 1); + } + baseaddr |= 0x800; + wrmsr(MSR_IA32_APIC_BASE, baseaddr); + } + + lapic_write(LAPIC_SPURIOUS, 0x1ff); +} + void print_msr(int idx) { int bit; @@ -423,26 +554,6 @@ void init_pat(void) dkprintf("PAT support detected and reconfigured.\n"); } -void init_lapic(void) -{ - unsigned long baseaddr; - - /* Enable Local APIC */ - baseaddr = rdmsr(MSR_IA32_APIC_BASE); - if (!lapic_vp) { - lapic_vp = map_fixed_area(baseaddr & PAGE_MASK, PAGE_SIZE, 1); - } - baseaddr |= 0x800; - wrmsr(MSR_IA32_APIC_BASE, baseaddr); - - lapic_write(LAPIC_SPURIOUS, 0x1ff); -} - -void lapic_ack(void) -{ - lapic_write(LAPIC_EOI, 0); -} - static void set_kstack(unsigned long ptr) { struct x86_cpu_local_variables *v; @@ -460,7 +571,12 @@ static void init_smp_processor(void) v = get_x86_this_cpu_local(); tss_addr = (unsigned long)&v->tss; - v->apic_id = lapic_read(LAPIC_ID) >> LAPIC_ID_SHIFT; + if(x2apic_is_enabled()){ + v->apic_id = rdmsr(IA32_X2APIC_APICID); + } + else{ + v->apic_id = lapic_read(LAPIC_ID) >> LAPIC_ID_SHIFT; + } memcpy(v->gdt, gdt, sizeof(v->gdt)); @@ -497,9 +613,6 @@ void ihk_mc_init_ap(void) kprintf("# of cpus : %d\n", cpu_info->ncpus); init_processors_local(cpu_info->ncpus); - kprintf("IKC IRQ vector: %d, IKC target CPU APIC: %d\n", - ihk_ikc_irq, ihk_ikc_irq_apicid); - /* Do initialization for THIS cpu (BSP) */ assign_processor_id(); @@ -621,6 +734,8 @@ void setup_x86(void) check_no_execute(); + init_lapic_bsp(); + init_cpu(); init_gettime_support(); @@ -809,22 +924,6 @@ void int3_handler(struct x86_user_context *regs) check_need_resched(); } -static void wait_icr_idle(void) -{ - while (lapic_read(LAPIC_ICR0) & APIC_ICR_BUSY) { - cpu_pause(); - } -} - -void x86_issue_ipi(unsigned int apicid, unsigned int low) -{ - unsigned long flags; - - flags = cpu_disable_interrupt_save(); - wait_icr_idle(); - lapic_icr_write(apicid << LAPIC_ICR_ID_SHIFT, low); - cpu_restore_interrupt(flags); -} static void outb(uint8_t v, uint16_t port) { @@ -852,12 +951,12 @@ static void __x86_wakeup(int apicid, unsigned long ip) x86_issue_ipi(apicid, APIC_INT_LEVELTRIG | APIC_DM_INIT); - wait_icr_idle(); + lapic_wait_icr_idle(); while (retry--) { lapic_read(LAPIC_ESR); x86_issue_ipi(apicid, APIC_DM_STARTUP | (ip >> 12)); - wait_icr_idle(); + lapic_wait_icr_idle(); arch_delay(200);