svn commit: r305978 - in head/sys/x86: acpica include x86 xen
Konstantin Belousov
kib at FreeBSD.org
Mon Sep 19 15:58:46 UTC 2016
Author: kib
Date: Mon Sep 19 15:58:45 2016
New Revision: 305978
URL: https://svnweb.freebsd.org/changeset/base/305978
Log:
Detect x2APIC mode on boot and obey it.
If BIOS performed hand-off to OS with BSP LAPIC in the x2APIC mode,
system usually consumes such configuration without a notice, since
x2APIC is turned on by OS if possible (nop). But if BIOS
simultaneously requested OS to not use x2APIC, code assumption that
that xAPIC is active breaks.
In my opinion, we cannot safely turn off x2APIC if control is passed
in this mode. Make madt.c ignore user or BIOS requests to turn x2APIC
off, and do not check the x2APIC black list. Just trust the config
and try to continue, giving a warning in dmesg.
Reported and tested by: Slawa Olhovchenkov <slw at zxy.spb.ru> (previous version)
Diagnosed by and discussed with: avg
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Modified:
head/sys/x86/acpica/madt.c
head/sys/x86/include/apicvar.h
head/sys/x86/x86/local_apic.c
head/sys/x86/xen/xen_apic.c
Modified: head/sys/x86/acpica/madt.c
==============================================================================
--- head/sys/x86/acpica/madt.c Mon Sep 19 15:58:33 2016 (r305977)
+++ head/sys/x86/acpica/madt.c Mon Sep 19 15:58:45 2016 (r305978)
@@ -135,10 +135,11 @@ madt_setup_local(void)
const char *reason;
char *hw_vendor;
u_int p[4];
+ int user_x2apic;
+ bool bios_x2apic;
madt = pmap_mapbios(madt_physaddr, madt_length);
if ((cpu_feature2 & CPUID2_X2APIC) != 0) {
- x2apic_mode = 1;
reason = NULL;
/*
@@ -150,21 +151,17 @@ madt_setup_local(void)
if (dmartbl_physaddr != 0) {
dmartbl = acpi_map_table(dmartbl_physaddr,
ACPI_SIG_DMAR);
- if ((dmartbl->Flags & ACPI_DMAR_X2APIC_OPT_OUT) != 0) {
- x2apic_mode = 0;
+ if ((dmartbl->Flags & ACPI_DMAR_X2APIC_OPT_OUT) != 0)
reason = "by DMAR table";
- }
acpi_unmap_table(dmartbl);
}
if (vm_guest == VM_GUEST_VMWARE) {
vmware_hvcall(VMW_HVCMD_GETVCPU_INFO, p);
if ((p[0] & VMW_VCPUINFO_VCPU_RESERVED) != 0 ||
- (p[0] & VMW_VCPUINFO_LEGACY_X2APIC) == 0) {
- x2apic_mode = 0;
- reason = "inside VMWare without intr redirection";
- }
+ (p[0] & VMW_VCPUINFO_LEGACY_X2APIC) == 0)
+ reason =
+ "inside VMWare without intr redirection";
} else if (vm_guest == VM_GUEST_XEN) {
- x2apic_mode = 0;
reason = "due to running under XEN";
} else if (vm_guest == VM_GUEST_NO &&
CPUID_TO_FAMILY(cpu_id) == 0x6 &&
@@ -184,16 +181,33 @@ madt_setup_local(void)
if (!strcmp(hw_vendor, "LENOVO") ||
!strcmp(hw_vendor,
"ASUSTeK Computer Inc.")) {
- x2apic_mode = 0;
reason =
"for a suspected SandyBridge BIOS bug";
}
freeenv(hw_vendor);
}
}
- TUNABLE_INT_FETCH("hw.x2apic_enable", &x2apic_mode);
- if (!x2apic_mode && reason != NULL && bootverbose)
+ bios_x2apic = lapic_is_x2apic();
+ if (reason != NULL && bios_x2apic) {
+ if (bootverbose)
+ printf("x2APIC should be disabled %s but "
+ "already enabled by BIOS; enabling.\n",
+ reason);
+ reason = NULL;
+ }
+ if (reason == NULL)
+ x2apic_mode = 1;
+ else if (bootverbose)
printf("x2APIC available but disabled %s\n", reason);
+ user_x2apic = x2apic_mode;
+ TUNABLE_INT_FETCH("hw.x2apic_enable", &user_x2apic);
+ if (user_x2apic != x2apic_mode) {
+ if (bios_x2apic && !user_x2apic)
+ printf("x2APIC disabled by tunable and "
+ "enabled by BIOS; ignoring tunable.");
+ else
+ x2apic_mode = user_x2apic;
+ }
}
lapic_init(madt->Address);
Modified: head/sys/x86/include/apicvar.h
==============================================================================
--- head/sys/x86/include/apicvar.h Mon Sep 19 15:58:33 2016 (r305977)
+++ head/sys/x86/include/apicvar.h Mon Sep 19 15:58:45 2016 (r305978)
@@ -206,6 +206,7 @@ struct apic_ops {
void (*create)(u_int, int);
void (*init)(vm_paddr_t);
void (*xapic_mode)(void);
+ bool (*is_x2apic)(void);
void (*setup)(int);
void (*dump)(const char *);
void (*disable)(void);
@@ -268,6 +269,13 @@ lapic_xapic_mode(void)
apic_ops.xapic_mode();
}
+static inline bool
+lapic_is_x2apic(void)
+{
+
+ return (apic_ops.is_x2apic());
+}
+
static inline void
lapic_setup(int boot)
{
Modified: head/sys/x86/x86/local_apic.c
==============================================================================
--- head/sys/x86/x86/local_apic.c Mon Sep 19 15:58:33 2016 (r305977)
+++ head/sys/x86/x86/local_apic.c Mon Sep 19 15:58:45 2016 (r305978)
@@ -269,6 +269,16 @@ native_lapic_enable_x2apic(void)
wrmsr(MSR_APICBASE, apic_base);
}
+static bool
+native_lapic_is_x2apic(void)
+{
+ uint64_t apic_base;
+
+ apic_base = rdmsr(MSR_APICBASE);
+ return ((apic_base & (APICBASE_X2APIC | APICBASE_ENABLED)) ==
+ (APICBASE_X2APIC | APICBASE_ENABLED));
+}
+
static void lapic_enable(void);
static void lapic_resume(struct pic *pic, bool suspend_cancelled);
static void lapic_timer_oneshot(struct lapic *);
@@ -329,6 +339,7 @@ struct apic_ops apic_ops = {
.create = native_lapic_create,
.init = native_lapic_init,
.xapic_mode = native_lapic_xapic_mode,
+ .is_x2apic = native_lapic_is_x2apic,
.setup = native_lapic_setup,
.dump = native_lapic_dump,
.disable = native_lapic_disable,
Modified: head/sys/x86/xen/xen_apic.c
==============================================================================
--- head/sys/x86/xen/xen_apic.c Mon Sep 19 15:58:33 2016 (r305977)
+++ head/sys/x86/xen/xen_apic.c Mon Sep 19 15:58:45 2016 (r305978)
@@ -139,6 +139,13 @@ xen_pv_lapic_disable(void)
}
+static bool
+xen_pv_lapic_is_x2apic(void)
+{
+
+ return (false);
+}
+
static void
xen_pv_lapic_eoi(void)
{
@@ -351,6 +358,7 @@ struct apic_ops xen_apic_ops = {
.create = xen_pv_lapic_create,
.init = xen_pv_lapic_init,
.xapic_mode = xen_pv_lapic_disable,
+ .is_x2apic = xen_pv_lapic_is_x2apic,
.setup = xen_pv_lapic_setup,
.dump = xen_pv_lapic_dump,
.disable = xen_pv_lapic_disable,
More information about the svn-src-all
mailing list