*x86: Support x2apic mode

Implement x2apic mode as existing code only supports apic mode.
Use info from LAPIC_BASE_MSR (LAPIC_BASE_MSR_X2APIC_MODE) to check
if apic mode or x2apic mode and implement x2apic mode according to
x2apic specfication.

Reference:
https://software.intel.com/content/www/us/en/develop/download/intel-64-architecture-x2apic-specification.html

BUG=None
BRANCH=None
TEST=boot to OS and check apic mode
cat /proc/cpuinfo | grep "apicid"
ex) can see apicid bigger than 255
apicid          : 256
apicid          : 260

Signed-off-by: Wonkyu Kim <wonkyu.kim@intel.com>
Change-Id: I0bb729b0521fb9dc38b7981014755daeaf9ca817
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51723
Reviewed-by: Ravishankar Sarawadi <ravishankar.sarawadi@intel.com>
Reviewed-by: Jamie Ryu <jamie.m.ryu@intel.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Wonkyu Kim
2021-03-22 19:59:18 -07:00
committed by Patrick Georgi
parent 5c9bacca32
commit 26ab9bfeb5
7 changed files with 110 additions and 24 deletions

View File

@@ -47,6 +47,6 @@ void lapic_virtual_wire_mode_init(void)
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");
}

View File

@@ -435,6 +435,28 @@ static int start_aps(struct bus *cpu_bus, int ap_count, atomic_t *num_aps)
printk(BIOS_DEBUG, "Attempting to start %d APs\n", ap_count);
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;
}
return 0;
}
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)) {
@@ -653,6 +675,11 @@ static void mp_initialize_cpu(void)
void smm_initiate_relocation_parallel(void)
{
if (is_x2apic_mode()) {
x2apic_send_ipi(LAPIC_DM_SMI | LAPIC_INT_LEVELTRIG, lapicid());
return;
}
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)) {

View File

@@ -11,6 +11,7 @@
#include <cpu/x86/cr.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/lapic_def.h>
.code32
.section ".module_parameters", "aw", @progbits
@@ -29,7 +30,7 @@ fxsave_area_size:
* 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 +98,31 @@ smm_trampoline32:
/* 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 xapic
x2apic:
mov $X2APIC_LAPIC_ID, %ecx
rdmsr
jmp apicid_end
xapic:
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