diff mbox series

[07/11] i386/hvf: Enables APIC_ACCESS VM exits by setting APICBASE

Message ID 20241209203629.74436-8-phil@philjordan.eu (mailing list archive)
State New
Headers show
Series hvf and APIC fixes, improvements, and optimisations | expand

Commit Message

Phil Dennis-Jordan Dec. 9, 2024, 8:36 p.m. UTC
From: Phil Dennis-Jordan <phil@philjordan.eu>

This change activates virtualised APIC access VM exits so the new
fast-pathed implementation will be taken.

Two parts are required for enabling APIC_ACCESS exits rather than
falling back to "regular" MMIO EPT faults: Hypervisor.framework
needs to know the current APIC base address, and the APIC access
virtualisation ctl, VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES,
must be set in the VMCS. The latter has already been set in QEMU's
HVF accel, but setting the APIC base address has been missing.

This change calls hv_vmx_vcpu_set_apic_address() before a vCPU
runs for the first time, and whenever the APICBASE MSR is modified
and the xAPIC is enabled. Additionally, the APIC access ctl is
toggled when the APIC is enabled or disabled, or changes mode.

In addition to making APIC access VM exits occur at all, it also
makes APIC relocation work, at least on the fast path. (QEMU does
not currently support different address spaces per vCPU, which
is why the purely EPT fault based software APIC - and thus the slow
path - does not properly support relocation.)

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
---
 target/i386/hvf/hvf.c     | 11 +++++++++++
 target/i386/hvf/x86_emu.c | 18 ++++++++++++++++++
 2 files changed, 29 insertions(+)
diff mbox series

Patch

diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index 2a13a9e49b..a7b8d124bb 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -341,6 +341,17 @@  int hvf_arch_init_vcpu(CPUState *cpu)
 
 void hvf_vcpu_before_first_run(CPUState *cpu)
 {
+    X86CPU *x86_cpu = X86_CPU(cpu);
+    hv_vcpuid_t vcpu = cpu->accel->fd;
+    uint64_t apic_base;
+    hv_return_t apicbase_result;
+
+    if (cpu_is_apic_enabled(x86_cpu->apic_state)
+        && !is_x2apic_mode(x86_cpu->apic_state)) {
+        apic_base = MSR_IA32_APICBASE_BASE & cpu_get_apic_base(x86_cpu->apic_state);
+        apicbase_result = hv_vmx_vcpu_set_apic_address(vcpu, apic_base);
+        assert_hvf_ok(apicbase_result);
+    }
 }
 
 static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_info)
diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c
index 197fa155a0..88a946cb0f 100644
--- a/target/i386/hvf/x86_emu.c
+++ b/target/i386/hvf/x86_emu.c
@@ -797,10 +797,28 @@  void simulate_wrmsr(CPUX86State *env)
         break;
     case MSR_IA32_APICBASE: {
         int r;
+        hv_return_t res;
 
         r = cpu_set_apic_base(cpu->apic_state, data);
         if (r < 0) {
             raise_exception(env, EXCP0D_GPF, 0);
+        } else {
+            uint64_t pbc = rvmcs(cs->accel->fd, VMCS_SEC_PROC_BASED_CTLS);
+            uint64_t new_pbc;
+            if (cpu_is_apic_enabled(cpu->apic_state)
+                && !is_x2apic_mode(cpu->apic_state)) {
+                res = hv_vmx_vcpu_set_apic_address(cs->accel->fd,
+                                                   data & MSR_IA32_APICBASE_BASE);
+                assert_hvf_ok(res);
+
+                new_pbc = pbc | VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES;
+            } else {
+                new_pbc = pbc & ~VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES;
+            }
+            if (new_pbc != pbc) {
+                wvmcs(cs->accel->fd, VMCS_SEC_PROC_BASED_CTLS,
+                    cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2, new_pbc));
+            }
         }
 
         break;