Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: Add hyp_enter/hyp_exit events to nVHE/pKVM hyp

The hyp_enter and hyp_exit events are logged by the hypervisor any time
it is entered and exited.

Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Link: https://patch.msgid.link/20260309162516.2623589-29-vdonnefort@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>

authored by

Vincent Donnefort and committed by
Marc Zyngier
696dfec2 0a90fbc8

+131 -17
+3
arch/arm64/include/asm/kvm_host.h
··· 920 920 921 921 /* Per-vcpu TLB for VNCR_EL2 -- NULL when !NV */ 922 922 struct vncr_tlb *vncr_tlb; 923 + 924 + /* Hyp-readable copy of kvm_vcpu::pid */ 925 + pid_t pid; 923 926 }; 924 927 925 928 /*
+39
arch/arm64/include/asm/kvm_hypevents.h
··· 7 7 #include <nvhe/trace.h> 8 8 #endif 9 9 10 + #ifndef __HYP_ENTER_EXIT_REASON 11 + #define __HYP_ENTER_EXIT_REASON 12 + enum hyp_enter_exit_reason { 13 + HYP_REASON_SMC, 14 + HYP_REASON_HVC, 15 + HYP_REASON_PSCI, 16 + HYP_REASON_HOST_ABORT, 17 + HYP_REASON_GUEST_EXIT, 18 + HYP_REASON_ERET_HOST, 19 + HYP_REASON_ERET_GUEST, 20 + HYP_REASON_UNKNOWN /* Must be last */ 21 + }; 22 + #endif 23 + 24 + HYP_EVENT(hyp_enter, 25 + HE_PROTO(struct kvm_cpu_context *host_ctxt, u8 reason), 26 + HE_STRUCT( 27 + he_field(u8, reason) 28 + he_field(pid_t, vcpu) 29 + ), 30 + HE_ASSIGN( 31 + __entry->reason = reason; 32 + __entry->vcpu = __tracing_get_vcpu_pid(host_ctxt); 33 + ), 34 + HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu) 35 + ); 36 + 37 + HYP_EVENT(hyp_exit, 38 + HE_PROTO(struct kvm_cpu_context *host_ctxt, u8 reason), 39 + HE_STRUCT( 40 + he_field(u8, reason) 41 + he_field(pid_t, vcpu) 42 + ), 43 + HE_ASSIGN( 44 + __entry->reason = reason; 45 + __entry->vcpu = __tracing_get_vcpu_pid(host_ctxt); 46 + ), 47 + HE_PRINTK("reason=%s vcpu=%d", __hyp_enter_exit_reason_str(__entry->reason), __entry->vcpu) 48 + ); 10 49 #endif
+2
arch/arm64/kvm/arm.c
··· 707 707 708 708 if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus)) 709 709 vcpu_set_on_unsupported_cpu(vcpu); 710 + 711 + vcpu->arch.pid = pid_nr(vcpu->pid); 710 712 } 711 713 712 714 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
+23
arch/arm64/kvm/hyp/include/nvhe/arm-smccc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__ 3 + #define __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__ 4 + 5 + #include <asm/kvm_hypevents.h> 6 + 7 + #include <linux/arm-smccc.h> 8 + 9 + #define hyp_smccc_1_1_smc(...) \ 10 + do { \ 11 + trace_hyp_exit(NULL, HYP_REASON_SMC); \ 12 + arm_smccc_1_1_smc(__VA_ARGS__); \ 13 + trace_hyp_enter(NULL, HYP_REASON_SMC); \ 14 + } while (0) 15 + 16 + #define hyp_smccc_1_2_smc(...) \ 17 + do { \ 18 + trace_hyp_exit(NULL, HYP_REASON_SMC); \ 19 + arm_smccc_1_2_smc(__VA_ARGS__); \ 20 + trace_hyp_enter(NULL, HYP_REASON_SMC); \ 21 + } while (0) 22 + 23 + #endif /* __ARM64_KVM_HYP_NVHE_ARM_SMCCC_H__ */
+12
arch/arm64/kvm/hyp/include/nvhe/trace.h
··· 6 6 7 7 #include <asm/kvm_hyptrace.h> 8 8 9 + static inline pid_t __tracing_get_vcpu_pid(struct kvm_cpu_context *host_ctxt) 10 + { 11 + struct kvm_vcpu *vcpu; 12 + 13 + if (!host_ctxt) 14 + host_ctxt = host_data_ptr(host_ctxt); 15 + 16 + vcpu = host_ctxt->__hyp_running_vcpu; 17 + 18 + return vcpu ? vcpu->arch.pid : 0; 19 + } 20 + 9 21 #define HE_PROTO(__args...) __args 10 22 #define HE_ASSIGN(__args...) __args 11 23 #define HE_STRUCT RE_STRUCT
+14 -14
arch/arm64/kvm/hyp/nvhe/ffa.c
··· 26 26 * the duration and are therefore serialised. 27 27 */ 28 28 29 - #include <linux/arm-smccc.h> 30 29 #include <linux/arm_ffa.h> 31 30 #include <asm/kvm_pkvm.h> 32 31 32 + #include <nvhe/arm-smccc.h> 33 33 #include <nvhe/ffa.h> 34 34 #include <nvhe/mem_protect.h> 35 35 #include <nvhe/memory.h> ··· 147 147 { 148 148 struct arm_smccc_1_2_regs res; 149 149 150 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 150 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 151 151 .a0 = FFA_FN64_RXTX_MAP, 152 152 .a1 = hyp_virt_to_phys(hyp_buffers.tx), 153 153 .a2 = hyp_virt_to_phys(hyp_buffers.rx), ··· 161 161 { 162 162 struct arm_smccc_1_2_regs res; 163 163 164 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 164 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 165 165 .a0 = FFA_RXTX_UNMAP, 166 166 .a1 = HOST_FFA_ID, 167 167 }, &res); ··· 172 172 static void ffa_mem_frag_tx(struct arm_smccc_1_2_regs *res, u32 handle_lo, 173 173 u32 handle_hi, u32 fraglen, u32 endpoint_id) 174 174 { 175 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 175 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 176 176 .a0 = FFA_MEM_FRAG_TX, 177 177 .a1 = handle_lo, 178 178 .a2 = handle_hi, ··· 184 184 static void ffa_mem_frag_rx(struct arm_smccc_1_2_regs *res, u32 handle_lo, 185 185 u32 handle_hi, u32 fragoff) 186 186 { 187 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 187 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 188 188 .a0 = FFA_MEM_FRAG_RX, 189 189 .a1 = handle_lo, 190 190 .a2 = handle_hi, ··· 196 196 static void ffa_mem_xfer(struct arm_smccc_1_2_regs *res, u64 func_id, u32 len, 197 197 u32 fraglen) 198 198 { 199 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 199 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 200 200 .a0 = func_id, 201 201 .a1 = len, 202 202 .a2 = fraglen, ··· 206 206 static void ffa_mem_reclaim(struct arm_smccc_1_2_regs *res, u32 handle_lo, 207 207 u32 handle_hi, u32 flags) 208 208 { 209 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 209 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 210 210 .a0 = FFA_MEM_RECLAIM, 211 211 .a1 = handle_lo, 212 212 .a2 = handle_hi, ··· 216 216 217 217 static void ffa_retrieve_req(struct arm_smccc_1_2_regs *res, u32 len) 218 218 { 219 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 219 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 220 220 .a0 = FFA_FN64_MEM_RETRIEVE_REQ, 221 221 .a1 = len, 222 222 .a2 = len, ··· 225 225 226 226 static void ffa_rx_release(struct arm_smccc_1_2_regs *res) 227 227 { 228 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 228 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 229 229 .a0 = FFA_RX_RELEASE, 230 230 }, res); 231 231 } ··· 728 728 size_t min_rxtx_sz; 729 729 struct arm_smccc_1_2_regs res; 730 730 731 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){ 731 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){ 732 732 .a0 = FFA_ID_GET, 733 733 }, &res); 734 734 if (res.a0 != FFA_SUCCESS) ··· 737 737 if (res.a2 != HOST_FFA_ID) 738 738 return -EINVAL; 739 739 740 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){ 740 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs){ 741 741 .a0 = FFA_FEATURES, 742 742 .a1 = FFA_FN64_RXTX_MAP, 743 743 }, &res); ··· 788 788 * first if TEE supports it. 789 789 */ 790 790 if (FFA_MINOR_VERSION(ffa_req_version) < FFA_MINOR_VERSION(hyp_ffa_version)) { 791 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 791 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 792 792 .a0 = FFA_VERSION, 793 793 .a1 = ffa_req_version, 794 794 }, res); ··· 824 824 goto out_unlock; 825 825 } 826 826 827 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 827 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 828 828 .a0 = FFA_PARTITION_INFO_GET, 829 829 .a1 = uuid0, 830 830 .a2 = uuid1, ··· 939 939 if (kvm_host_psci_config.smccc_version < ARM_SMCCC_VERSION_1_2) 940 940 return 0; 941 941 942 - arm_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 942 + hyp_smccc_1_2_smc(&(struct arm_smccc_1_2_regs) { 943 943 .a0 = FFA_VERSION, 944 944 .a1 = FFA_VERSION_1_2, 945 945 }, &res);
+11
arch/arm64/kvm/hyp/nvhe/hyp-main.c
··· 12 12 #include <asm/kvm_emulate.h> 13 13 #include <asm/kvm_host.h> 14 14 #include <asm/kvm_hyp.h> 15 + #include <asm/kvm_hypevents.h> 15 16 #include <asm/kvm_mmu.h> 16 17 17 18 #include <nvhe/ffa.h> ··· 138 137 hyp_vcpu->vcpu.arch.vsesr_el2 = host_vcpu->arch.vsesr_el2; 139 138 140 139 hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3; 140 + 141 + hyp_vcpu->vcpu.arch.pid = host_vcpu->arch.pid; 141 142 } 142 143 143 144 static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) ··· 731 728 732 729 static void default_host_smc_handler(struct kvm_cpu_context *host_ctxt) 733 730 { 731 + trace_hyp_exit(host_ctxt, HYP_REASON_SMC); 734 732 __kvm_hyp_host_forward_smc(host_ctxt); 733 + trace_hyp_enter(host_ctxt, HYP_REASON_SMC); 735 734 } 736 735 737 736 static void handle_host_smc(struct kvm_cpu_context *host_ctxt) ··· 820 815 { 821 816 u64 esr = read_sysreg_el2(SYS_ESR); 822 817 818 + 823 819 switch (ESR_ELx_EC(esr)) { 824 820 case ESR_ELx_EC_HVC64: 821 + trace_hyp_enter(host_ctxt, HYP_REASON_HVC); 825 822 handle_host_hcall(host_ctxt); 826 823 break; 827 824 case ESR_ELx_EC_SMC64: 825 + trace_hyp_enter(host_ctxt, HYP_REASON_SMC); 828 826 handle_host_smc(host_ctxt); 829 827 break; 830 828 case ESR_ELx_EC_IABT_LOW: 831 829 case ESR_ELx_EC_DABT_LOW: 830 + trace_hyp_enter(host_ctxt, HYP_REASON_HOST_ABORT); 832 831 handle_host_mem_abort(host_ctxt); 833 832 break; 834 833 case ESR_ELx_EC_SYS64: ··· 842 833 default: 843 834 BUG(); 844 835 } 836 + 837 + trace_hyp_exit(host_ctxt, HYP_REASON_ERET_HOST); 845 838 }
+5 -2
arch/arm64/kvm/hyp/nvhe/psci-relay.c
··· 6 6 7 7 #include <asm/kvm_asm.h> 8 8 #include <asm/kvm_hyp.h> 9 + #include <asm/kvm_hypevents.h> 9 10 #include <asm/kvm_mmu.h> 10 - #include <linux/arm-smccc.h> 11 11 #include <linux/kvm_host.h> 12 12 #include <uapi/linux/psci.h> 13 13 14 + #include <nvhe/arm-smccc.h> 14 15 #include <nvhe/memory.h> 15 16 #include <nvhe/trap_handler.h> 16 17 ··· 66 65 { 67 66 struct arm_smccc_res res; 68 67 69 - arm_smccc_1_1_smc(fn, arg0, arg1, arg2, &res); 68 + hyp_smccc_1_1_smc(fn, arg0, arg1, arg2, &res); 70 69 return res.a0; 71 70 } 72 71 ··· 207 206 struct kvm_cpu_context *host_ctxt; 208 207 209 208 host_ctxt = host_data_ptr(host_ctxt); 209 + trace_hyp_enter(host_ctxt, HYP_REASON_PSCI); 210 210 211 211 if (is_cpu_on) 212 212 boot_args = this_cpu_ptr(&cpu_on_args); ··· 223 221 write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR); 224 222 write_sysreg(INIT_PSTATE_EL1, SPSR_EL2); 225 223 224 + trace_hyp_exit(host_ctxt, HYP_REASON_PSCI); 226 225 __host_enter(host_ctxt); 227 226 } 228 227
+4 -1
arch/arm64/kvm/hyp/nvhe/switch.c
··· 7 7 #include <hyp/switch.h> 8 8 #include <hyp/sysreg-sr.h> 9 9 10 - #include <linux/arm-smccc.h> 11 10 #include <linux/kvm_host.h> 12 11 #include <linux/types.h> 13 12 #include <linux/jump_label.h> ··· 20 21 #include <asm/kvm_asm.h> 21 22 #include <asm/kvm_emulate.h> 22 23 #include <asm/kvm_hyp.h> 24 + #include <asm/kvm_hypevents.h> 23 25 #include <asm/kvm_mmu.h> 24 26 #include <asm/fpsimd.h> 25 27 #include <asm/debug-monitors.h> ··· 308 308 __debug_switch_to_guest(vcpu); 309 309 310 310 do { 311 + trace_hyp_exit(host_ctxt, HYP_REASON_ERET_GUEST); 312 + 311 313 /* Jump in the fire! */ 312 314 exit_code = __guest_enter(vcpu); 313 315 314 316 /* And we're baaack! */ 317 + trace_hyp_enter(host_ctxt, HYP_REASON_GUEST_EXIT); 315 318 } while (fixup_guest_exit(vcpu, &exit_code)); 316 319 317 320 __sysreg_save_state_nvhe(guest_ctxt);
+18
arch/arm64/kvm/hyp_trace.c
··· 364 364 .enable_event = hyp_trace_enable_event, 365 365 }; 366 366 367 + static const char *__hyp_enter_exit_reason_str(u8 reason); 368 + 367 369 #include <asm/kvm_define_hypevents.h> 370 + 371 + static const char *__hyp_enter_exit_reason_str(u8 reason) 372 + { 373 + static const char strs[][12] = { 374 + "smc", 375 + "hvc", 376 + "psci", 377 + "host_abort", 378 + "guest_exit", 379 + "eret_host", 380 + "eret_guest", 381 + "unknown", 382 + }; 383 + 384 + return strs[min(reason, HYP_REASON_UNKNOWN)]; 385 + } 368 386 369 387 static void __init hyp_trace_init_events(void) 370 388 {