[PATCH v2 3/5] KVM: arm64: Add ESR class to the hyp_enter hyp event

Vincent Donnefort vdonnefort at google.com
Wed Nov 4 06:06:10 PST 2026


Give a more detailed reason the hyp has been entered by reading the ESR
class when relevant (that is on trap). Encode the ESR class directly
into the existing reason field.

To distinguish between a trap from host and from guest, add a "from="
field, which has 3 possibilities: "host", "vcpu" or "firmware". This
value can be deduced based on a combination of the existing vcpu and
reason fields.

Finally, add a "to=" field to the hyp_exit event to mirror "hyp_enter",
allowing HYP_REASON_ERET_HOST and HYP_REASON_ERET_GUEST to be collapsed
into a single HYP_REASON_ERET.

Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
---
 arch/arm64/include/asm/kvm_hypevents.h | 29 ++++++++------
 arch/arm64/kvm/hyp/nvhe/hyp-main.c     |  7 +---
 arch/arm64/kvm/hyp/nvhe/psci-relay.c   |  2 +-
 arch/arm64/kvm/hyp/nvhe/switch.c       |  6 ++-
 arch/arm64/kvm/hyp_trace.c             | 52 ++++++++++++++++++++------
 5 files changed, 66 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
index 3396deb1a1f8..7486d95455c5 100644
--- a/arch/arm64/include/asm/kvm_hypevents.h
+++ b/arch/arm64/include/asm/kvm_hypevents.h
@@ -3,22 +3,22 @@
 #if !defined(__ARM64_KVM_HYPEVENTS_H_) || defined(HYP_EVENT_MULTI_READ)
 #define __ARM64_KVM_HYPEVENTS_H_
 
+#include <asm/esr.h>
+
 #ifdef __KVM_NVHE_HYPERVISOR__
+#include <asm/kvm_hyp.h>
+
 #include <nvhe/trace.h>
 #endif
 
 #ifndef __HYP_ENTER_EXIT_REASON
 #define __HYP_ENTER_EXIT_REASON
 enum hyp_enter_exit_reason {
-	HYP_REASON_SMC,
-	HYP_REASON_HVC,
-	HYP_REASON_SYS,
+	HYP_REASON_SMC = ESR_ELx_EC_MAX + 1,
 	HYP_REASON_PSCI,
-	HYP_REASON_HOST_ABORT,
-	HYP_REASON_GUEST_EXIT,
-	HYP_REASON_ERET_HOST,
-	HYP_REASON_ERET_GUEST,
-	HYP_REASON_UNKNOWN	/* Must be last */
+	HYP_REASON_IRQ,
+	HYP_REASON_ERET,
+	HYP_REASON_USE_ESR, /* trace_hyp_enter() only, resolved to ESR_EL2.EC */
 };
 #endif
 
@@ -29,10 +29,14 @@ HYP_EVENT(hyp_enter,
 		he_field(pid_t, vcpu)
 	),
 	HE_ASSIGN(
-		__entry->reason = reason;
+		__entry->reason = reason == HYP_REASON_USE_ESR ?
+			ESR_ELx_EC(read_sysreg_el2(SYS_ESR)) : reason;
 		__entry->vcpu = __tracing_get_vcpu_pid(host_ctxt);
 	),
-	HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu)
+	HE_PRINTK("from=%s reason=%s vcpu=%d",
+		  __hyp_enter_exit_str(__entry->reason, __entry->vcpu),
+		  __hyp_enter_exit_reason_str(__entry->reason),
+		  __entry->vcpu)
 );
 
 HYP_EVENT(hyp_exit,
@@ -45,7 +49,10 @@ HYP_EVENT(hyp_exit,
 		__entry->reason = reason;
 		__entry->vcpu = __tracing_get_vcpu_pid(host_ctxt);
 	),
-	HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu)
+	HE_PRINTK("to=%s reason=%s vcpu=%d",
+		  __hyp_enter_exit_str(__entry->reason, __entry->vcpu),
+		  __hyp_enter_exit_reason_str(__entry->reason),
+		  __entry->vcpu)
 );
 
 HYP_EVENT(selftest,
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 179d7c8277b8..28e0191e443f 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -1758,23 +1758,20 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
 {
 	u64 esr = read_sysreg_el2(SYS_ESR);
 
+	trace_hyp_enter(host_ctxt, ESR_ELx_EC(esr));
 
 	switch (ESR_ELx_EC(esr)) {
 	case ESR_ELx_EC_HVC64:
-		trace_hyp_enter(host_ctxt, HYP_REASON_HVC);
 		handle_host_hcall(host_ctxt);
 		break;
 	case ESR_ELx_EC_SMC64:
-		trace_hyp_enter(host_ctxt, HYP_REASON_SMC);
 		handle_host_smc(host_ctxt);
 		break;
 	case ESR_ELx_EC_IABT_LOW:
 	case ESR_ELx_EC_DABT_LOW:
-		trace_hyp_enter(host_ctxt, HYP_REASON_HOST_ABORT);
 		handle_host_mem_abort(host_ctxt);
 		break;
 	case ESR_ELx_EC_SYS64:
-		trace_hyp_enter(host_ctxt, HYP_REASON_SYS);
 		if (handle_host_mte(esr))
 			break;
 		fallthrough;
@@ -1782,5 +1779,5 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
 		BUG();
 	}
 
-	trace_hyp_exit(host_ctxt, HYP_REASON_ERET_HOST);
+	trace_hyp_exit(host_ctxt, HYP_REASON_ERET);
 }
diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
index 48228991a7ba..c771c1d150c4 100644
--- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
@@ -213,7 +213,7 @@ static void __noreturn __kvm_host_psci_cpu_entry(unsigned long pc, unsigned long
 	write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR);
 	write_sysreg(INIT_PSTATE_EL1, SPSR_EL2);
 
-	trace_hyp_exit(host_ctxt, HYP_REASON_ERET_HOST);
+	trace_hyp_exit(host_ctxt, HYP_REASON_ERET);
 	__host_enter(host_ctxt);
 }
 
diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index 89fb9dd351ad..afb672dda5e8 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -345,13 +345,15 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	__debug_switch_to_guest(vcpu);
 
 	do {
-		trace_hyp_exit(host_ctxt, HYP_REASON_ERET_GUEST);
+		trace_hyp_exit(host_ctxt, HYP_REASON_ERET);
 
 		/* Jump in the fire! */
 		exit_code = __guest_enter(vcpu);
 
 		/* And we're baaack! */
-		trace_hyp_enter(host_ctxt, HYP_REASON_GUEST_EXIT);
+		trace_hyp_enter(host_ctxt,
+				ARM_EXCEPTION_CODE(exit_code) == ARM_EXCEPTION_IRQ ?
+				HYP_REASON_IRQ : HYP_REASON_USE_ESR);
 	} while (fixup_guest_exit(vcpu, &exit_code));
 
 	__sysreg_save_state_nvhe(guest_ctxt);
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index b9404496f977..ec97d412adfa 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -405,6 +405,7 @@ static struct trace_remote_callbacks trace_remote_callbacks = {
 	.enable_event		= hyp_trace_enable_event,
 };
 
+static const char *__hyp_enter_exit_str(u8 reason, pid_t vcpu);
 static const char *__hyp_enter_exit_reason_str(u8 reason);
 
 struct remote_event_format_hyp_printk;
@@ -412,21 +413,50 @@ static void __hyp_trace_printk(struct remote_event_format_hyp_printk *entry, str
 
 #include "define_hypevents.h"
 
+static const char *__hyp_enter_exit_str(u8 reason, pid_t vcpu)
+{
+	switch (reason) {
+	case 0 ... ESR_ELx_EC_MAX:
+	case HYP_REASON_IRQ:
+	case HYP_REASON_ERET:
+		return vcpu ? "vcpu" : "host";
+	case HYP_REASON_SMC:
+	case HYP_REASON_PSCI:
+		return "firmware";
+	default:
+		return "unknown";
+	}
+}
+
 static const char *__hyp_enter_exit_reason_str(u8 reason)
 {
-	static const char strs[][12] = {
-		"smc",
-		"hvc",
-		"sys",
-		"psci",
-		"host_abort",
-		"guest_exit",
-		"eret_host",
-		"eret_guest",
-		"unknown",
+	static const struct trace_print_flags class[] = {
+		kvm_arm_exception_class
 	};
 
-	return strs[min(reason, HYP_REASON_UNKNOWN)];
+	if (reason <= ESR_ELx_EC_MAX) {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(class); i++) {
+			if (class[i].mask == reason)
+				return class[i].name;
+		}
+
+		return "UNKNOWN_ESR";
+	}
+
+	switch (reason) {
+	case HYP_REASON_SMC:
+		return "SMC";
+	case HYP_REASON_PSCI:
+		return "PSCI";
+	case HYP_REASON_IRQ:
+		return "IRQ";
+	case HYP_REASON_ERET:
+		return "ERET";
+	default:
+		return "UNKNOWN_REASON";
+	}
 }
 
 static void __hyp_trace_printk(struct remote_event_format_hyp_printk *entry, struct trace_seq *seq)
-- 
2.56.0.455.g6c5a503b38-goog




More information about the linux-arm-kernel mailing list