git: ee9205f068c7 - main - vmm: Add a bulk TMR reset hook for Intel APICv

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 02 Nov 2026 16:27:15 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=ee9205f068c7675cf4d23e51cc98238d95ba1950

commit ee9205f068c7675cf4d23e51cc98238d95ba1950
Author:     Hayzam Sherif <hayzam@gmail.com>
AuthorDate: 2026-11-02 16:21:18 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-11-02 16:26:52 +0000

    vmm: Add a bulk TMR reset hook for Intel APICv
    
    vioapic_update_tmr() resets all 256 vectors before rebuilding the
    level-triggered vector set. With Intel virtual interrupt delivery,
    each per-vector reset loads the VMCS, reads and writes an EOI-exit
    bitmap, and clears the VMCS.
    
    Add an optional bulk-reset hook so VMX can clear the four EOI-exit
    bitmaps with one VMCS load/clear pair. Clear the software TMR banks
    directly when using the hook, and retain the per-vector fallback
    for backends without it.
    
    Reviewed by:    markj
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D60692
---
 sys/amd64/vmm/intel/vmx.c      | 21 +++++++++++++++++++++
 sys/amd64/vmm/io/vlapic.c      | 12 +++++++++++-
 sys/amd64/vmm/io/vlapic_priv.h |  1 +
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index ff0e1cb2b882..0b9a4eea3ebb 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -3921,6 +3921,26 @@ vmx_set_tmr(struct vlapic *vlapic, int vector, bool level)
 	VMCLEAR(vmcs);
 }
 
+static void
+vmx_reset_tmr(struct vlapic *vlapic)
+{
+	struct vlapic_vtx *vlapic_vtx;
+	struct vmcs *vmcs;
+
+	KASSERT(!vcpu_is_running(vlapic->vcpu, NULL),
+	    ("vmx_reset_tmr: vcpu cannot be running"));
+
+	vlapic_vtx = (struct vlapic_vtx *)vlapic;
+	vmcs = vlapic_vtx->vcpu->vmcs;
+
+	VMPTRLD(vmcs);
+	vmcs_write(VMCS_EOI_EXIT0, 0);
+	vmcs_write(VMCS_EOI_EXIT1, 0);
+	vmcs_write(VMCS_EOI_EXIT2, 0);
+	vmcs_write(VMCS_EOI_EXIT3, 0);
+	VMCLEAR(vmcs);
+}
+
 static void
 vmx_enable_x2apic_mode_ts(struct vlapic *vlapic)
 {
@@ -4121,6 +4141,7 @@ vmx_vlapic_init(void *vcpui)
 		vlapic->ops.pending_intr = vmx_pending_intr;
 		vlapic->ops.intr_accepted = vmx_intr_accepted;
 		vlapic->ops.set_tmr = vmx_set_tmr;
+		vlapic->ops.reset_tmr = vmx_reset_tmr;
 		vlapic->ops.enable_x2apic_mode = vmx_enable_x2apic_mode_vid;
 	}
 
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index e0a1359dffb6..a5009804d72b 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -1776,10 +1776,20 @@ vlapic_set_tmr(struct vlapic *vlapic, int vector, bool level)
 void
 vlapic_reset_tmr(struct vlapic *vlapic)
 {
-	int vector;
+	uint32_t *tmrptr;
+	int i, vector;
 
 	VLAPIC_CTR0(vlapic, "vlapic resetting all vectors to edge-triggered");
 
+	if (vlapic->ops.reset_tmr != NULL) {
+		tmrptr = &vlapic->apic_page->tmr0;
+		/* APIC register slots are 16 bytes apart. */
+		for (i = 0; i < 8; i++)
+			tmrptr[i * 4] = 0;
+		(*vlapic->ops.reset_tmr)(vlapic);
+		return;
+	}
+
 	for (vector = 0; vector <= 255; vector++)
 		vlapic_set_tmr(vlapic, vector, false);
 }
diff --git a/sys/amd64/vmm/io/vlapic_priv.h b/sys/amd64/vmm/io/vlapic_priv.h
index 1dce593b9444..f8d23530d277 100644
--- a/sys/amd64/vmm/io/vlapic_priv.h
+++ b/sys/amd64/vmm/io/vlapic_priv.h
@@ -139,6 +139,7 @@ struct vlapic_ops {
 	void (*intr_accepted)(struct vlapic *vlapic, int vector);
 	void (*post_intr)(struct vlapic *vlapic, int hostcpu);
 	void (*set_tmr)(struct vlapic *vlapic, int vector, bool level);
+	void (*reset_tmr)(struct vlapic *vlapic);
 	void (*enable_x2apic_mode)(struct vlapic *vlapic);
 };