Download raw body.
[1/5] vmm: handle MSR_APICBASE and x2APIC MSR reads without injecting #GP
This is a series of commits to expose ACPI tables to vmd guests.
These were committed and tested individually.
They can be reviewed in their entirety here:
https://github.com/openbsd/src/compare/master...nomadium:src:add-support-for-acpi-in-vmd.patch
---
sys/arch/amd64/amd64/vmm_machdep.c | 60 ++++++++++++++++++++++++++++++
sys/arch/amd64/include/vmmvar.h | 3 +-
2 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/sys/arch/amd64/amd64/vmm_machdep.c b/sys/arch/amd64/amd64/vmm_machdep.c
index 787b65e29e1..cd1544db9bf 100644
--- a/sys/arch/amd64/amd64/vmm_machdep.c
+++ b/sys/arch/amd64/amd64/vmm_machdep.c
@@ -39,6 +39,7 @@
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/ghcb.h>
+#include <machine/i82489reg.h>
#include <machine/vmmvar.h>
#include <dev/isa/isareg.h>
@@ -5852,11 +5853,40 @@ vmx_handle_rdmsr(struct vcpu *vcpu)
*rax = 0;
*rdx = 0;
break;
+ case MSR_APICBASE:
+ /*
+ * Return the LAPIC base address with the global enable bit.
+ * APICBASE_ENABLE_X2APIC is intentionally omitted: guests
+ * that read this MSR before enabling x2APIC (e.g. Linux)
+ * will see x2APIC as not yet enabled, remain in xAPIC mode,
+ * and fall back gracefully when their WRMSR to enable it is
+ * silently discarded. OpenBSD guests synthesize the x2APIC
+ * flag from CPUID when CPUIDECX_HV and CPUIDECX_X2APIC are
+ * both set, skipping rdmsr(MSR_APICBASE), so they are
+ * unaffected. The BSP flag is set only for VCPU 0.
+ */
+ *rax = LAPIC_BASE | APICBASE_GLOBAL_ENABLE;
+ if (vcpu->vc_id == 0)
+ *rax |= APICBASE_BSP;
+ *rdx = 0;
+ break;
case MSR_CR_PAT:
*rax = (vcpu->vc_shadow_pat & 0xFFFFFFFFULL);
*rdx = (vcpu->vc_shadow_pat >> 32);
break;
default:
+ /*
+ * x2APIC MSRs (0x800-0x8ff): return the VCPU id for the LAPIC
+ * ID register and 0 for everything else. Returning 0 for the
+ * current-count register (0x839) causes lapic_calibrate_timer()
+ * to see lapic_per_second == 0 and fall back to the PIT.
+ */
+ if (*rcx >= MSR_X2APIC_BASE &&
+ *rcx < MSR_X2APIC_BASE + 0x100) {
+ *rax = (*rcx == MSR_X2APIC_ID) ? vcpu->vc_id : 0;
+ *rdx = 0;
+ break;
+ }
/* Unsupported MSRs causes #GP exception, don't advance %rip */
DPRINTF("%s: unsupported rdmsr (msr=0x%llx), injecting #GP\n",
__func__, *rcx);
@@ -6163,6 +6193,23 @@ svm_handle_msr(struct vcpu *vcpu)
*rax = 0;
*rdx = 0;
break;
+ case MSR_APICBASE:
+ /*
+ * Return the LAPIC base address with the global enable bit.
+ * APICBASE_ENABLE_X2APIC is intentionally omitted: guests
+ * that read this MSR before enabling x2APIC (e.g. Linux)
+ * will see x2APIC as not yet enabled, remain in xAPIC mode,
+ * and fall back gracefully when their WRMSR to enable it is
+ * silently discarded. OpenBSD guests synthesize the x2APIC
+ * flag from CPUID when CPUIDECX_HV and CPUIDECX_X2APIC are
+ * both set, skipping rdmsr(MSR_APICBASE), so they are
+ * unaffected. The BSP flag is set only for VCPU 0.
+ */
+ *rax = LAPIC_BASE | APICBASE_GLOBAL_ENABLE;
+ if (vcpu->vc_id == 0)
+ *rax |= APICBASE_BSP;
+ *rdx = 0;
+ break;
case MSR_CR_PAT:
*rax = (vcpu->vc_shadow_pat & 0xFFFFFFFFULL);
*rdx = (vcpu->vc_shadow_pat >> 32);
@@ -6173,6 +6220,19 @@ svm_handle_msr(struct vcpu *vcpu)
*rdx = 0;
break;
default:
+ /*
+ * x2APIC MSRs (0x800-0x8ff): return the VCPU id for
+ * the LAPIC ID register and 0 for everything else.
+ * Returning 0 for the current-count register (0x839)
+ * causes lapic_calibrate_timer() to see
+ * lapic_per_second == 0 and fall back to the PIT.
+ */
+ if (*rcx >= MSR_X2APIC_BASE &&
+ *rcx < MSR_X2APIC_BASE + 0x100) {
+ *rax = (*rcx == MSR_X2APIC_ID) ? vcpu->vc_id : 0;
+ *rdx = 0;
+ break;
+ }
/*
* Unsupported MSRs causes #GP exception, don't advance
* %rip
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index 25b1618ad1f..5ba454d5cc4 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -520,7 +520,6 @@ struct vm_rwregs_params {
* perf/debug (CPUIDECX_PDCM)
* pcid (CPUIDECX_PCID)
* direct cache access (CPUIDECX_DCA)
- * x2APIC (CPUIDECX_X2APIC)
* apic deadline (CPUIDECX_DEADLINE)
* apic (CPUID_APIC)
* psn (CPUID_PSN)
@@ -534,7 +533,7 @@ struct vm_rwregs_params {
CPUIDECX_PDCM | CPUIDECX_VMX | CPUIDECX_DTES64 | \
CPUIDECX_DSCPL | CPUIDECX_SMX | CPUIDECX_CNXTID | \
CPUIDECX_SDBG | CPUIDECX_XTPR | CPUIDECX_PCID | \
- CPUIDECX_DCA | CPUIDECX_X2APIC | CPUIDECX_DEADLINE)
+ CPUIDECX_DCA | CPUIDECX_DEADLINE)
#define VMM_ECPUIDECX_MASK ~(CPUIDECX_SVM | CPUIDECX_MWAITX)
#define VMM_CPUIDEDX_MASK ~(CPUID_ACPI | CPUID_TM | \
CPUID_HTT | CPUID_DS | CPUID_APIC | \
--
2.54.0
[1/5] vmm: handle MSR_APICBASE and x2APIC MSR reads without injecting #GP