Wonkyu Kim has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/51723 )
Change subject: src/*/x86 : Support x2apic mode ......................................................................
src/*/x86 : Support x2apic mode
Implmenet x2apic mode(16bit apic id) as existing code only supports x1apic mode(8bit mode)
BUG=None BRANCH=None TEST=boot to OS and check apic mode cat /proc/cpuinfo | grep "apicid"
Signed-off-by: Wonkyu Kim wonkyu.kim@intel.com Change-Id: I0bb729b0521fb9dc38b7981014755daeaf9ca817 --- M src/arch/x86/cpu.c M src/cpu/x86/lapic/lapic.c M src/cpu/x86/lapic/lapic_cpu_init.c M src/cpu/x86/mp_init.c M src/cpu/x86/smm/smm_stub.S M src/include/cpu/x86/lapic.h M src/include/cpu/x86/lapic_def.h M src/include/cpu/x86/smm.h 8 files changed, 291 insertions(+), 184 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/23/51723/1
diff --git a/src/arch/x86/cpu.c b/src/arch/x86/cpu.c index 3ef878f..11c62f9 100644 --- a/src/arch/x86/cpu.c +++ b/src/arch/x86/cpu.c @@ -213,15 +213,10 @@ /* Keep track of default APIC ids for SMM. */ static int cpus_default_apic_id[CONFIG_MAX_CPUS];
-/* - * When CPUID executes with EAX set to 1, additional processor identification - * information is returned to EBX register: - * Default APIC ID: EBX[31-24] - this number is the 8 bit ID that is assigned - * to the local APIC on the processor during power on. - */ +/* Use lapicid funciton to support x2apic mode */ static int initial_lapicid(void) { - return cpuid_ebx(1) >> 24; + return lapicid(); }
/* Function to keep track of cpu default apic_id */ diff --git a/src/cpu/x86/lapic/lapic.c b/src/cpu/x86/lapic/lapic.c index 988d664..a5b4cd5 100644 --- a/src/cpu/x86/lapic/lapic.c +++ b/src/cpu/x86/lapic/lapic.c @@ -47,6 +47,6 @@ LAPIC_DELIVERY_MODE_NMI) );
- printk(BIOS_DEBUG, " apic_id: 0x%02x ", lapicid()); + printk(BIOS_DEBUG, " apic_id: 0x%x ", lapicid()); printk(BIOS_INFO, "done.\n"); } diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c index f89d9e3..828d420f 100644 --- a/src/cpu/x86/lapic/lapic_cpu_init.c +++ b/src/cpu/x86/lapic/lapic_cpu_init.c @@ -100,62 +100,73 @@
printk(BIOS_SPEW, "Asserting INIT.\n");
- /* - * Turn INIT on target chip - */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); - - /* - * Send IPI - */ - - lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT - | LAPIC_DM_INIT); - - printk(BIOS_SPEW, "Waiting for send to finish...\n"); - timeout = 0; - do { - printk(BIOS_SPEW, "+"); + if (is_x2apic_mode()) { + x2apic_send_ipi( + LAPIC_DM_INIT | LAPIC_INT_LEVELTRIG, apicid); udelay(100); - send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; - } while (send_status && (timeout++ < 1000)); - if (timeout >= 1000) { - printk(BIOS_ERR, "CPU %ld: First APIC write timed out. " - "Disabling\n", apicid); - // too bad. - printk(BIOS_ERR, "ESR is 0x%x\n", lapic_read(LAPIC_ESR)); - if (lapic_read(LAPIC_ESR)) { - printk(BIOS_ERR, "Try to reset ESR\n"); - lapic_write_around(LAPIC_ESR, 0); - printk(BIOS_ERR, "ESR is 0x%x\n", - lapic_read(LAPIC_ESR)); + } else { + /* + * Turn INIT on target chip + */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + + /* + * Send IPI + */ + + lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_INT_ASSERT + | LAPIC_DM_INIT); + + printk(BIOS_SPEW, "Waiting for send to finish...\n"); + timeout = 0; + do { + printk(BIOS_SPEW, "+"); + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + if (timeout >= 1000) { + printk(BIOS_ERR, "CPU %ld: First APIC write timed out. " + "Disabling\n", apicid); + // too bad. + printk(BIOS_ERR, "ESR is 0x%x\n", lapic_read(LAPIC_ESR)); + if (lapic_read(LAPIC_ESR)) { + printk(BIOS_ERR, "Try to reset ESR\n"); + lapic_write_around(LAPIC_ESR, 0); + printk(BIOS_ERR, "ESR is 0x%x\n", + lapic_read(LAPIC_ESR)); + } + return 0; } - return 0; } mdelay(10);
printk(BIOS_SPEW, "Deasserting INIT.\n");
- /* Target chip */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); - - /* Send IPI */ - lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT); - - printk(BIOS_SPEW, "Waiting for send to finish...\n"); - timeout = 0; - do { - printk(BIOS_SPEW, "+"); + if (is_x2apic_mode()) { + x2apic_send_ipi( + LAPIC_DM_INIT | LAPIC_INT_LEVELTRIG, apicid); udelay(100); - send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; - } while (send_status && (timeout++ < 1000)); - if (timeout >= 1000) { - printk(BIOS_ERR, "CPU %ld: Second APIC write timed out. " - "Disabling\n", apicid); - // too bad. - return 0; - } + } else { + /* Target chip */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
+ /* Send IPI */ + lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT); + + printk(BIOS_SPEW, "Waiting for send to finish...\n"); + timeout = 0; + do { + printk(BIOS_SPEW, "+"); + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + if (timeout >= 1000) { + printk(BIOS_ERR, "CPU %ld: Second APIC write timed out. " + "Disabling\n", apicid); + // too bad. + return 0; + } + } /* * Run STARTUP IPI loop. */ @@ -173,30 +184,35 @@ /* * STARTUP IPI */ + if (is_x2apic_mode()) { + x2apic_send_ipi( + LAPIC_DM_STARTUP | LAPIC_INT_LEVELTRIG | + (AP_SIPI_VECTOR >> 12), apicid); + udelay(300); + } else { + /* Target chip */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
- /* Target chip */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid)); + /* Boot on the stack */ + /* Kick the second */ + lapic_write_around(LAPIC_ICR, LAPIC_DM_STARTUP + | (AP_SIPI_VECTOR >> 12));
- /* Boot on the stack */ - /* Kick the second */ - lapic_write_around(LAPIC_ICR, LAPIC_DM_STARTUP - | (AP_SIPI_VECTOR >> 12)); + /* + * Give the other CPU some time to accept the IPI. + */ + udelay(300);
- /* - * Give the other CPU some time to accept the IPI. - */ - udelay(300); + printk(BIOS_SPEW, "Startup point 1.\n");
- printk(BIOS_SPEW, "Startup point 1.\n"); - - printk(BIOS_SPEW, "Waiting for send to finish...\n"); - timeout = 0; - do { - printk(BIOS_SPEW, "+"); - udelay(100); - send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; - } while (send_status && (timeout++ < 1000)); - + printk(BIOS_SPEW, "Waiting for send to finish...\n"); + timeout = 0; + do { + printk(BIOS_SPEW, "+"); + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + } /* * Give the other CPU some time to accept the IPI. */ @@ -333,27 +349,32 @@
printk(BIOS_DEBUG, "CPU %ld going down...\n", id);
- /* send an LAPIC INIT to myself */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id)); - lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | - LAPIC_INT_ASSERT | LAPIC_DM_INIT); + if (is_x2apic_mode()) { + x2apic_send_ipi( + LAPIC_DM_INIT | LAPIC_INT_LEVELTRIG, id); + } else { + /* send an LAPIC INIT to myself */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id)); + lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | + LAPIC_INT_ASSERT | LAPIC_DM_INIT);
- /* wait for the ipi send to finish */ + /* wait for the ipi send to finish */ #if DEBUG_HALT_SELF - printk(BIOS_SPEW, "Waiting for send to finish...\n"); + printk(BIOS_SPEW, "Waiting for send to finish...\n"); #endif - timeout = 0; - do { + timeout = 0; + do { #if DEBUG_HALT_SELF - printk(BIOS_SPEW, "+"); + printk(BIOS_SPEW, "+"); #endif - udelay(100); - send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; - } while (send_status && (timeout++ < 1000)); - if (timeout >= 1000) { + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + if (timeout >= 1000) { #if DEBUG_HALT_SELF - printk(BIOS_ERR, "timed out\n"); + printk(BIOS_ERR, "timed out\n"); #endif + } } mdelay(10);
@@ -361,24 +382,28 @@ printk(BIOS_SPEW, "Deasserting INIT.\n"); #endif /* Deassert the LAPIC INIT */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id)); - lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT); + if (is_x2apic_mode()) { + x2apic_send_ipi(LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT, id); + } else { + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(id)); + lapic_write_around(LAPIC_ICR, LAPIC_INT_LEVELTRIG | LAPIC_DM_INIT);
#if DEBUG_HALT_SELF - printk(BIOS_SPEW, "Waiting for send to finish...\n"); + printk(BIOS_SPEW, "Waiting for send to finish...\n"); #endif - timeout = 0; - do { + timeout = 0; + do { #if DEBUG_HALT_SELF - printk(BIOS_SPEW, "+"); + printk(BIOS_SPEW, "+"); #endif - udelay(100); - send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; - } while (send_status && (timeout++ < 1000)); - if (timeout >= 1000) { + udelay(100); + send_status = lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY; + } while (send_status && (timeout++ < 1000)); + if (timeout >= 1000) { #if DEBUG_HALT_SELF - printk(BIOS_ERR, "timed out\n"); + printk(BIOS_ERR, "timed out\n"); #endif + } }
halt(); diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c index 94a8fd8..359214b 100644 --- a/src/cpu/x86/mp_init.c +++ b/src/cpu/x86/mp_init.c @@ -435,75 +435,95 @@
printk(BIOS_DEBUG, "Attempting to start %d APs\n", ap_count);
- if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { - printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); - if (apic_wait_timeout(1000 /* 1 ms */, 50)) { - printk(BIOS_ERR, "timed out. Aborting.\n"); + if (is_x2apic_mode()) { + x2apic_send_ipi(LAPIC_DM_INIT | LAPIC_INT_LEVELTRIG | + LAPIC_INT_ASSERT | LAPIC_DEST_ALLBUT, 0); + mdelay(10); + x2apic_send_ipi(LAPIC_DM_STARTUP | LAPIC_INT_LEVELTRIG | + LAPIC_DEST_ALLBUT | sipi_vector, 0); + + /* Wait for CPUs to check in up to 200 us. */ + wait_for_aps(num_aps, ap_count, 200 /* us */, 15 /* us */); + + x2apic_send_ipi(LAPIC_DM_STARTUP | LAPIC_INT_LEVELTRIG | + LAPIC_DEST_ALLBUT | sipi_vector, 0); + + /* Wait for CPUs to check in. */ + if (wait_for_aps(num_aps, ap_count, 100000 /* 100 ms */, 50 /* us */)) { + printk(BIOS_ERR, "Not all APs checked in: %d/%d.\n", + atomic_read(num_aps), ap_count); + return -1; + } + + } else { + if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { + printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); + if (apic_wait_timeout(1000 /* 1 ms */, 50)) { + printk(BIOS_ERR, "timed out. Aborting.\n"); + return -1; + } + printk(BIOS_DEBUG, "done.\n"); + } + + /* Send INIT IPI to all but self. */ + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_INIT); + printk(BIOS_DEBUG, "Waiting for 10ms after sending INIT.\n"); + mdelay(10); + + /* Send 1st SIPI */ + if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { + printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); + if (apic_wait_timeout(1000 /* 1 ms */, 50)) { + printk(BIOS_ERR, "timed out. Aborting.\n"); + return -1; + } + printk(BIOS_DEBUG, "done.\n"); + } + + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_STARTUP | sipi_vector); + printk(BIOS_DEBUG, "Waiting for 1st SIPI to complete..."); + if (apic_wait_timeout(10000 /* 10 ms */, 50 /* us */)) { + printk(BIOS_ERR, "timed out.\n"); return -1; } printk(BIOS_DEBUG, "done.\n"); - }
- /* Send INIT IPI to all but self. */ - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_INIT); - printk(BIOS_DEBUG, "Waiting for 10ms after sending INIT.\n"); - mdelay(10); + /* Wait for CPUs to check in up to 200 us. */ + wait_for_aps(num_aps, ap_count, 200 /* us */, 15 /* us */);
- /* Send 1st SIPI */ - if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { - printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); - if (apic_wait_timeout(1000 /* 1 ms */, 50)) { - printk(BIOS_ERR, "timed out. Aborting.\n"); + if (CONFIG(X86_AMD_INIT_SIPI)) + return 0; + + /* Send 2nd SIPI */ + if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { + printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); + if (apic_wait_timeout(1000 /* 1 ms */, 50)) { + printk(BIOS_ERR, "timed out. Aborting.\n"); + return -1; + } + printk(BIOS_DEBUG, "done.\n"); + } + + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); + lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | + LAPIC_DM_STARTUP | sipi_vector); + printk(BIOS_DEBUG, "Waiting for 2nd SIPI to complete..."); + if (apic_wait_timeout(10000 /* 10 ms */, 50 /* us */)) { + printk(BIOS_ERR, "timed out.\n"); return -1; } printk(BIOS_DEBUG, "done.\n"); - } - - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_STARTUP | sipi_vector); - printk(BIOS_DEBUG, "Waiting for 1st SIPI to complete..."); - if (apic_wait_timeout(10000 /* 10 ms */, 50 /* us */)) { - printk(BIOS_ERR, "timed out.\n"); - return -1; - } - printk(BIOS_DEBUG, "done.\n"); - - /* Wait for CPUs to check in up to 200 us. */ - wait_for_aps(num_aps, ap_count, 200 /* us */, 15 /* us */); - - if (CONFIG(X86_AMD_INIT_SIPI)) - return 0; - - /* Send 2nd SIPI */ - if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { - printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); - if (apic_wait_timeout(1000 /* 1 ms */, 50)) { - printk(BIOS_ERR, "timed out. Aborting.\n"); + /* Wait for CPUs to check in. */ + if (wait_for_aps(num_aps, ap_count, 100000 /* 100 ms */, 50 /* us */)) { + printk(BIOS_ERR, "Not all APs checked in: %d/%d.\n", + atomic_read(num_aps), ap_count); return -1; } - printk(BIOS_DEBUG, "done.\n"); } - - lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(0)); - lapic_write_around(LAPIC_ICR, LAPIC_DEST_ALLBUT | LAPIC_INT_ASSERT | - LAPIC_DM_STARTUP | sipi_vector); - printk(BIOS_DEBUG, "Waiting for 2nd SIPI to complete..."); - if (apic_wait_timeout(10000 /* 10 ms */, 50 /* us */)) { - printk(BIOS_ERR, "timed out.\n"); - return -1; - } - printk(BIOS_DEBUG, "done.\n"); - - /* Wait for CPUs to check in. */ - if (wait_for_aps(num_aps, ap_count, 100000 /* 100 ms */, 50 /* us */)) { - printk(BIOS_ERR, "Not all APs checked in: %d/%d.\n", - atomic_read(num_aps), ap_count); - return -1; - } - return 0; }
@@ -653,21 +673,25 @@
void smm_initiate_relocation_parallel(void) { - if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { - printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); - if (apic_wait_timeout(1000 /* 1 ms */, 50)) { - printk(BIOS_DEBUG, "timed out. Aborting.\n"); - return; + if (is_x2apic_mode()) { + x2apic_send_ipi(LAPIC_DM_SMI | LAPIC_INT_LEVELTRIG, lapicid()); + } else { + if ((lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY)) { + printk(BIOS_DEBUG, "Waiting for ICR not to be busy..."); + if (apic_wait_timeout(1000 /* 1 ms */, 50)) { + printk(BIOS_DEBUG, "timed out. Aborting.\n"); + return; + } + printk(BIOS_DEBUG, "done.\n"); } - printk(BIOS_DEBUG, "done.\n"); - }
- lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(lapicid())); - lapic_write_around(LAPIC_ICR, LAPIC_INT_ASSERT | LAPIC_DM_SMI); - if (apic_wait_timeout(1000 /* 1 ms */, 100 /* us */)) - printk(BIOS_DEBUG, "SMI Relocation timed out.\n"); - else - printk(BIOS_DEBUG, "Relocation complete.\n"); + lapic_write_around(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(lapicid())); + lapic_write_around(LAPIC_ICR, LAPIC_INT_ASSERT | LAPIC_DM_SMI); + if (apic_wait_timeout(1000 /* 1 ms */, 100 /* us */)) + printk(BIOS_DEBUG, "SMI Relocation timed out.\n"); + else + printk(BIOS_DEBUG, "Relocation complete.\n"); + } }
DECLARE_SPIN_LOCK(smm_relocation_lock); diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S index 7c09e04..2778eb1c 100644 --- a/src/cpu/x86/smm/smm_stub.S +++ b/src/cpu/x86/smm/smm_stub.S @@ -11,6 +11,9 @@
#include <cpu/x86/cr.h> #include <cpu/x86/msr.h> +#include <cpu/x86/lapic_def.h> + +#define X2LAPIC_ID 0x802
.code32 .section ".module_parameters", "aw", @progbits @@ -29,7 +32,7 @@ * APIC id is found at the given index, the contiguous CPU number is index * into the table. */ apic_to_cpu_num: -.fill CONFIG_MAX_CPUS,1,0xff +.fill CONFIG_MAX_CPUS,2,0xffff /* allows the STM to bring up SMM in 32-bit mode */ start32_offset: .long smm_trampoline32 - _start @@ -97,16 +100,32 @@
/* The CPU number is calculated by reading the initial APIC id. Since * the OS can maniuplate the APIC id use the non-changing cpuid result - * for APIC id (ebx[31:24]). A table is used to handle a discontiguous + * for APIC id (ax). A table is used to handle a discontiguous * APIC id space. */ - mov $1, %eax - cpuid - bswap %ebx /* Default APIC id in bl. */ - mov $(apic_to_cpu_num), %eax - xor %ecx, %ecx +apic_id: + mov $LAPIC_BASE_MSR, %ecx + rdmsr + andl $LAPIC_BASE_MSR_X2APIC_MODE, %eax + jz x1apic + +x2apic: + mov $X2LAPIC_ID, %ecx + rdmsr + jmp apicid_end + +x1apic: + /* Get this CPU's LAPIC ID */ + movl $(LOCAL_APIC_ADDR | LAPIC_ID), %esi + movl (%esi), %eax + shr $24, %eax + +apicid_end: + + mov $(apic_to_cpu_num), %ebx + xor %ecx, %ecx
1: - cmp (%eax, %ecx, 1), %bl + cmp (%ebx, %ecx, 2), %ax je 1f inc %ecx cmp $CONFIG_MAX_CPUS, %ecx diff --git a/src/include/cpu/x86/lapic.h b/src/include/cpu/x86/lapic.h index f4291ab..4307af6 100644 --- a/src/include/cpu/x86/lapic.h +++ b/src/include/cpu/x86/lapic.h @@ -6,15 +6,52 @@ #include <cpu/x86/msr.h> #include <halt.h> #include <stdint.h> +#include <console/console.h> + +static inline bool is_x2apic_mode(void) +{ + msr_t msr; + msr = rdmsr(LAPIC_BASE_MSR); + return (msr.lo & LAPIC_BASE_MSR_X2APIC_MODE); +} + +static inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid) +{ + msr_t icr; + icr.hi = apicid; + icr.lo = icrlow; + wrmsr(X2APIC_MSR_ICR_ADDRESS, icr); +}
static __always_inline uint32_t lapic_read(unsigned int reg) { - return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg)); + uint32_t value, index; + msr_t msr; + + if (is_x2apic_mode()) { + msr.hi = 0xf; + msr.lo = 0xf; + index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4); + msr = rdmsr(index); + value = msr.lo; + } else { + value = read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg)); + } + return value; }
static __always_inline void lapic_write(unsigned int reg, uint32_t v) { - write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v); + msr_t msr; + uint32_t index; + if (is_x2apic_mode()) { + index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4); + msr.hi = 0x0; + msr.lo = v; + wrmsr(index, msr); + } else { + write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v); + } }
static __always_inline void lapic_wait_icr_idle(void) @@ -43,7 +80,12 @@
static __always_inline unsigned int lapicid(void) { - return lapic_read(LAPIC_ID) >> 24; + uint32_t lapicid = lapic_read(LAPIC_ID); + + /* check x2apic mode and return accordingly */ + if (!is_x2apic_mode()) + lapicid >>= 24; + return lapicid; }
#if !CONFIG(AP_IN_SIPI_WAIT) diff --git a/src/include/cpu/x86/lapic_def.h b/src/include/cpu/x86/lapic_def.h index 9da89ee..ebb6ef7 100644 --- a/src/include/cpu/x86/lapic_def.h +++ b/src/include/cpu/x86/lapic_def.h @@ -3,6 +3,7 @@
#define LAPIC_BASE_MSR 0x1B #define LAPIC_BASE_MSR_BOOTSTRAP_PROCESSOR (1 << 8) +#define LAPIC_BASE_MSR_X2APIC_MODE (1 << 10) #define LAPIC_BASE_MSR_ENABLE (1 << 11) #define LAPIC_BASE_MSR_ADDR_MASK 0xFFFFF000
@@ -93,5 +94,6 @@ #define LAPIC_TDR_DIV_32 0x8 #define LAPIC_TDR_DIV_64 0x9 #define LAPIC_TDR_DIV_128 0xA - +#define X2APIC_MSR_BASE_ADDRESS 0x800 +#define X2APIC_MSR_ICR_ADDRESS 0x830 #endif /* CPU_X86_LAPIC_DEF_H */ diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h index b42f3fa..c42eb8c 100644 --- a/src/include/cpu/x86/smm.h +++ b/src/include/cpu/x86/smm.h @@ -85,7 +85,7 @@ * initializes this array with a 1:1 mapping. If the APIC ids are not * contiguous like the 1:1 mapping it is up to the caller of the stub * loader to adjust this mapping. */ - u8 apic_id_to_cpu[CONFIG_MAX_CPUS]; + u16 apic_id_to_cpu[CONFIG_MAX_CPUS]; /* STM's 32bit entry into SMI handler */ u32 start32_offset; } __packed;