From nobody Sat Oct 4 01:43:17 2025 Received: from mail.zytor.com (terminus.zytor.com [198.137.202.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BFFC52EA731; Thu, 21 Aug 2025 22:37:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.137.202.136 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755815880; cv=none; b=W8+0yGWkKoC5sdp+clwkKPLbqj8+qYoUiPywEVant+vYo0YW3ZNm9Z2saM0i73pwsYHfWesHnCVuweleIeKVI7PNRrCd0kxtoazQA3lH2hhdM6awQLe+Rd1OF1X1UiXigOxbhYY7JVIoXWp/UKYYnomJgz550PcJyCEcu18eHaw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755815880; c=relaxed/simple; bh=LeTYllX8jeK+QDZFgGOpcshtN3JKVe01g7tt1F7k10M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jZWo9cQgZu8h2I7EBTHaXhBKGAJXbxhAdek2sXojQCqqJN1a/xfbLo8+96KII4bNIjgBh6oVQQ3i/PUlxfuwc9/hsSPqQbZsl66R/vpNPbnlXYiliU6PxHJfDWEdiijEgJ38j/+SsnfkjtQx85lMnwxjPneR535zBvktzMvl1FM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zytor.com; spf=pass smtp.mailfrom=zytor.com; dkim=pass (2048-bit key) header.d=zytor.com header.i=@zytor.com header.b=o2uFxea9; arc=none smtp.client-ip=198.137.202.136 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zytor.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zytor.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=zytor.com header.i=@zytor.com header.b="o2uFxea9" Received: from terminus.zytor.com (terminus.zytor.com [IPv6:2607:7c80:54:3:0:0:0:136]) (authenticated bits=0) by mail.zytor.com (8.18.1/8.17.1) with ESMTPSA id 57LMaUOY984441 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Thu, 21 Aug 2025 15:36:50 -0700 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.zytor.com 57LMaUOY984441 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zytor.com; s=2025072201; t=1755815811; bh=A+/laUZnaw5YyFjS7FqOP4Sm7PXvK3sDT+lFXNfphzA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o2uFxea9IS2Z0Ubr0E73JSsTltz3iRBlNTPTfL0SkCM2JCw3+5E4wYXHbKw/oCKUn 6K4FE44RcC5sjd4wwZEh+LB4o2rUJbhazGsnaNxJFn+709Cu7ooRMwRKtxOtvt2M2d XCChfaVhpk2wL0mf73HK2l2zNYo10yfmmEKhs9y66omFH+WLOKcx47gIEJZ8qmWdDx oboihhCLzIHaJwU410PhfH5ASBVTD3eW8DNa2I4l9F+XUBzNn8YY+s+fXxsKD/uDq2 Rnoxfx8YNiIzkrg8Rrowyb/SV3JkebQqRiqiWtsZDjTkerVIivS1incvBEbs3ovilu 5FWMIwZhAcIfA== From: "Xin Li (Intel)" To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org Cc: pbonzini@redhat.com, seanjc@google.com, corbet@lwn.net, tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com, xin@zytor.com, luto@kernel.org, peterz@infradead.org, andrew.cooper3@citrix.com, chao.gao@intel.com, hch@infradead.org Subject: [PATCH v6 10/20] KVM: VMX: Virtualize FRED event_data Date: Thu, 21 Aug 2025 15:36:19 -0700 Message-ID: <20250821223630.984383-11-xin@zytor.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250821223630.984383-1-xin@zytor.com> References: <20250821223630.984383-1-xin@zytor.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Xin Li Set injected-event data when injecting a #PF, #DB, or #NM caused by extended feature disable using FRED event delivery, and save original-event data for being used as injected-event data. Unlike IDT using some extra CPU register as part of an event context, e.g., %cr2 for #PF, FRED saves a complete event context in its stack frame, e.g., FRED saves the faulting linear address of a #PF into the event data field defined in its stack frame. Thus a new VMX control field called injected-event data is added to provide the event data that will be pushed into a FRED stack frame for VM entries that inject an event using FRED event delivery. In addition, a new VM exit information field called original-event data is added to store the event data that would have saved into a FRED stack frame for VM exits that occur during FRED event delivery. After such a VM exit is handled to allow the original-event to be delivered, the data in the original-event data VMCS field needs to be set into the injected-event data VMCS field for the injection of the original event. Signed-off-by: Xin Li [ Sean: reworked event data injection for nested ] Signed-off-by: Sean Christopherson Signed-off-by: Xin Li (Intel) Tested-by: Shan Kang Tested-by: Xuelian Guo --- Change in v5: * Add TB from Xuelian Guo. Change in v3: * Rework event data injection for nested (Chao Gao & Sean Christopherson). Changes in v2: * Document event data should be equal to CR2/DR6/IA32_XFD_ERR instead of using WARN_ON() (Chao Gao). * Zero event data if a #NM was not caused by extended feature disable (Chao Gao). --- arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/include/asm/vmx.h | 4 ++++ arch/x86/kvm/svm/svm.c | 2 +- arch/x86/kvm/vmx/vmx.c | 22 ++++++++++++++++++---- arch/x86/kvm/x86.c | 16 +++++++++++++++- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 061c0cd73d39..dce6471194f7 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -759,6 +759,7 @@ struct kvm_queued_exception { u32 error_code; unsigned long payload; bool has_payload; + u64 event_data; }; =20 /* @@ -2222,7 +2223,7 @@ void kvm_queue_exception(struct kvm_vcpu *vcpu, unsig= ned nr); void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_c= ode); void kvm_queue_exception_p(struct kvm_vcpu *vcpu, unsigned nr, unsigned lo= ng payload); void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned int nr, - bool has_error_code, u32 error_code); + bool has_error_code, u32 error_code, u64 event_data); void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fa= ult); void kvm_inject_emulated_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault); diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 6f8b8947c60c..539af190ad3e 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -269,8 +269,12 @@ enum vmcs_field { PID_POINTER_TABLE_HIGH =3D 0x00002043, SECONDARY_VM_EXIT_CONTROLS =3D 0x00002044, SECONDARY_VM_EXIT_CONTROLS_HIGH =3D 0x00002045, + INJECTED_EVENT_DATA =3D 0x00002052, + INJECTED_EVENT_DATA_HIGH =3D 0x00002053, GUEST_PHYSICAL_ADDRESS =3D 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH =3D 0x00002401, + ORIGINAL_EVENT_DATA =3D 0x00002404, + ORIGINAL_EVENT_DATA_HIGH =3D 0x00002405, VMCS_LINK_POINTER =3D 0x00002800, VMCS_LINK_POINTER_HIGH =3D 0x00002801, GUEST_IA32_DEBUGCTL =3D 0x00002802, diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 0e2c60466797..72f54befd0d0 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4144,7 +4144,7 @@ static void svm_complete_interrupts(struct kvm_vcpu *= vcpu) =20 kvm_requeue_exception(vcpu, vector, exitintinfo & SVM_EXITINTINFO_VALID_ERR, - error_code); + error_code, 0); break; } case SVM_EXITINTINFO_TYPE_INTR: diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 225c4638ffd7..e1eb55fb3fb8 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1862,6 +1862,9 @@ void vmx_inject_exception(struct kvm_vcpu *vcpu) =20 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); =20 + if (is_fred_enabled(vcpu)) + vmcs_write64(INJECTED_EVENT_DATA, ex->event_data); + vmx_clear_hlt(vcpu); } =20 @@ -7262,7 +7265,8 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx = *vmx) static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, u32 idt_vectoring_info, int instr_len_field, - int error_code_field) + int error_code_field, + int event_data_field) { u8 vector; int type; @@ -7297,13 +7301,17 @@ static void __vmx_complete_interrupts(struct kvm_vc= pu *vcpu, fallthrough; case INTR_TYPE_HARD_EXCEPTION: { u32 error_code =3D 0; + u64 event_data =3D 0; =20 if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) error_code =3D vmcs_read32(error_code_field); + if (is_fred_enabled(vcpu)) + event_data =3D vmcs_read64(event_data_field); =20 kvm_requeue_exception(vcpu, vector, idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK, - error_code); + error_code, + event_data); break; } case INTR_TYPE_SOFT_INTR: @@ -7321,7 +7329,8 @@ static void vmx_complete_interrupts(struct vcpu_vmx *= vmx) { __vmx_complete_interrupts(&vmx->vcpu, vmx->idt_vectoring_info, VM_EXIT_INSTRUCTION_LEN, - IDT_VECTORING_ERROR_CODE); + IDT_VECTORING_ERROR_CODE, + ORIGINAL_EVENT_DATA); } =20 void vmx_cancel_injection(struct kvm_vcpu *vcpu) @@ -7329,7 +7338,8 @@ void vmx_cancel_injection(struct kvm_vcpu *vcpu) __vmx_complete_interrupts(vcpu, vmcs_read32(VM_ENTRY_INTR_INFO_FIELD), VM_ENTRY_INSTRUCTION_LEN, - VM_ENTRY_EXCEPTION_ERROR_CODE); + VM_ENTRY_EXCEPTION_ERROR_CODE, + INJECTED_EVENT_DATA); =20 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); } @@ -7483,6 +7493,10 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_v= cpu *vcpu, =20 vmx_disable_fb_clear(vmx); =20 + /* + * Note, even though FRED delivers the faulting linear address via the + * event data field on the stack, CR2 is still updated. + */ if (vcpu->arch.cr2 !=3D native_read_cr2()) native_write_cr2(vcpu->arch.cr2); =20 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1f9a09b34742..f082255852a9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -807,9 +807,22 @@ void kvm_deliver_exception_payload(struct kvm_vcpu *vc= pu, * breakpoint), it is reserved and must be zero in DR6. */ vcpu->arch.dr6 &=3D ~BIT(12); + + /* + * FRED #DB event data matches DR6, but follows the polarity of + * VMX's pending debug exceptions, not DR6. + */ + ex->event_data =3D ex->payload & ~BIT(12); + break; + case NM_VECTOR: + ex->event_data =3D ex->payload; break; case PF_VECTOR: vcpu->arch.cr2 =3D ex->payload; + ex->event_data =3D ex->payload; + break; + default: + ex->event_data =3D 0; break; } =20 @@ -917,7 +930,7 @@ static void kvm_queue_exception_e_p(struct kvm_vcpu *vc= pu, unsigned nr, } =20 void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned int nr, - bool has_error_code, u32 error_code) + bool has_error_code, u32 error_code, u64 event_data) { =20 /* @@ -942,6 +955,7 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsig= ned int nr, vcpu->arch.exception.error_code =3D error_code; vcpu->arch.exception.has_payload =3D false; vcpu->arch.exception.payload =3D 0; + vcpu->arch.exception.event_data =3D event_data; } EXPORT_SYMBOL_GPL(kvm_requeue_exception); =20 --=20 2.50.1