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 event support to the nVHE/pKVM hyp and trace remote

Allow the creation of hypervisor and trace remote events with a single
macro HYP_EVENT(). That macro expands in the kernel side to add all
the required declarations (based on REMOTE_EVENT()) as well as in the
hypervisor side to create the trace_<event>() function.

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

authored by

Vincent Donnefort and committed by
Marc Zyngier
0a90fbc8 2194d317

+184 -2
+1
arch/arm64/include/asm/kvm_asm.h
··· 95 95 __KVM_HOST_SMCCC_FUNC___tracing_swap_reader, 96 96 __KVM_HOST_SMCCC_FUNC___tracing_update_clock, 97 97 __KVM_HOST_SMCCC_FUNC___tracing_reset, 98 + __KVM_HOST_SMCCC_FUNC___tracing_enable_event, 98 99 }; 99 100 100 101 #define DECLARE_KVM_VHE_SYM(sym) extern char sym[]
+16
arch/arm64/include/asm/kvm_define_hypevents.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #define REMOTE_EVENT_INCLUDE_FILE arch/arm64/include/asm/kvm_hypevents.h 4 + 5 + #define REMOTE_EVENT_SECTION "_hyp_events" 6 + 7 + #define HE_STRUCT(__args) __args 8 + #define HE_PRINTK(__args...) __args 9 + #define he_field re_field 10 + 11 + #define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \ 12 + REMOTE_EVENT(__name, 0, RE_STRUCT(__struct), RE_PRINTK(__printk)) 13 + 14 + #define HYP_EVENT_MULTI_READ 15 + #include <trace/define_remote_events.h> 16 + #undef HYP_EVENT_MULTI_READ
+10
arch/arm64/include/asm/kvm_hypevents.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #if !defined(__ARM64_KVM_HYPEVENTS_H_) || defined(HYP_EVENT_MULTI_READ) 4 + #define __ARM64_KVM_HYPEVENTS_H_ 5 + 6 + #ifdef __KVM_NVHE_HYPERVISOR__ 7 + #include <nvhe/trace.h> 8 + #endif 9 + 10 + #endif
+13
arch/arm64/include/asm/kvm_hyptrace.h
··· 10 10 struct trace_buffer_desc trace_buffer_desc; 11 11 12 12 }; 13 + 14 + struct hyp_event_id { 15 + unsigned short id; 16 + atomic_t enabled; 17 + }; 18 + 19 + extern struct remote_event __hyp_events_start[]; 20 + extern struct remote_event __hyp_events_end[]; 21 + 22 + /* hyp_event section used by the hypervisor */ 23 + extern struct hyp_event_id __hyp_event_ids_start[]; 24 + extern struct hyp_event_id __hyp_event_ids_end[]; 25 + 13 26 #endif
+4
arch/arm64/kernel/image-vars.h
··· 138 138 KVM_NVHE_ALIAS(__hyp_data_end); 139 139 KVM_NVHE_ALIAS(__hyp_rodata_start); 140 140 KVM_NVHE_ALIAS(__hyp_rodata_end); 141 + #ifdef CONFIG_NVHE_EL2_TRACING 142 + KVM_NVHE_ALIAS(__hyp_event_ids_start); 143 + KVM_NVHE_ALIAS(__hyp_event_ids_end); 144 + #endif 141 145 142 146 /* pKVM static key */ 143 147 KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
+18
arch/arm64/kernel/vmlinux.lds.S
··· 13 13 *(__kvm_ex_table) \ 14 14 __stop___kvm_ex_table = .; 15 15 16 + #ifdef CONFIG_NVHE_EL2_TRACING 17 + #define HYPERVISOR_EVENT_IDS \ 18 + . = ALIGN(PAGE_SIZE); \ 19 + __hyp_event_ids_start = .; \ 20 + *(HYP_SECTION_NAME(.event_ids)) \ 21 + __hyp_event_ids_end = .; 22 + #else 23 + #define HYPERVISOR_EVENT_IDS 24 + #endif 25 + 16 26 #define HYPERVISOR_RODATA_SECTIONS \ 17 27 HYP_SECTION_NAME(.rodata) : { \ 18 28 . = ALIGN(PAGE_SIZE); \ 19 29 __hyp_rodata_start = .; \ 20 30 *(HYP_SECTION_NAME(.data..ro_after_init)) \ 21 31 *(HYP_SECTION_NAME(.rodata)) \ 32 + HYPERVISOR_EVENT_IDS \ 22 33 . = ALIGN(PAGE_SIZE); \ 23 34 __hyp_rodata_end = .; \ 24 35 } ··· 318 307 319 308 HYPERVISOR_DATA_SECTION 320 309 310 + #ifdef CONFIG_NVHE_EL2_TRACING 311 + .data.hyp_events : { 312 + __hyp_events_start = .; 313 + *(SORT(_hyp_events.*)) 314 + __hyp_events_end = .; 315 + } 316 + #endif 321 317 /* 322 318 * Data written with the MMU off but read with the MMU on requires 323 319 * cache lines to be invalidated, discarding up to a Cache Writeback
+14
arch/arm64/kvm/hyp/include/nvhe/define_events.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #undef HYP_EVENT 4 + #define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \ 5 + struct hyp_event_id hyp_event_id_##__name \ 6 + __section(".hyp.event_ids."#__name) = { \ 7 + .enabled = ATOMIC_INIT(0), \ 8 + } 9 + 10 + #define HYP_EVENT_MULTI_READ 11 + #include <asm/kvm_hypevents.h> 12 + #undef HYP_EVENT_MULTI_READ 13 + 14 + #undef HYP_EVENT
+31
arch/arm64/kvm/hyp/include/nvhe/trace.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 2 #ifndef __ARM64_KVM_HYP_NVHE_TRACE_H 3 3 #define __ARM64_KVM_HYP_NVHE_TRACE_H 4 + 5 + #include <linux/trace_remote_event.h> 6 + 4 7 #include <asm/kvm_hyptrace.h> 5 8 9 + #define HE_PROTO(__args...) __args 10 + #define HE_ASSIGN(__args...) __args 11 + #define HE_STRUCT RE_STRUCT 12 + #define he_field re_field 13 + 6 14 #ifdef CONFIG_NVHE_EL2_TRACING 15 + 16 + #define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \ 17 + REMOTE_EVENT_FORMAT(__name, __struct); \ 18 + extern struct hyp_event_id hyp_event_id_##__name; \ 19 + static __always_inline void trace_##__name(__proto) \ 20 + { \ 21 + struct remote_event_format_##__name *__entry; \ 22 + size_t length = sizeof(*__entry); \ 23 + \ 24 + if (!atomic_read(&hyp_event_id_##__name.enabled)) \ 25 + return; \ 26 + __entry = tracing_reserve_entry(length); \ 27 + if (!__entry) \ 28 + return; \ 29 + __entry->hdr.id = hyp_event_id_##__name.id; \ 30 + __assign \ 31 + tracing_commit_entry(); \ 32 + } 33 + 7 34 void *tracing_reserve_entry(unsigned long length); 8 35 void tracing_commit_entry(void); 9 36 ··· 40 13 int __tracing_swap_reader(unsigned int cpu); 41 14 void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc); 42 15 int __tracing_reset(unsigned int cpu); 16 + int __tracing_enable_event(unsigned short id, bool enable); 43 17 #else 44 18 static inline void *tracing_reserve_entry(unsigned long length) { return NULL; } 45 19 static inline void tracing_commit_entry(void) { } 20 + #define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \ 21 + static inline void trace_##__name(__proto) {} 46 22 47 23 static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { return -ENODEV; } 48 24 static inline void __tracing_unload(void) { } ··· 53 23 static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; } 54 24 static inline void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { } 55 25 static inline int __tracing_reset(unsigned int cpu) { return -ENODEV; } 26 + static inline int __tracing_enable_event(unsigned short id, bool enable) { return -ENODEV; } 56 27 #endif 57 28 #endif
+1 -1
arch/arm64/kvm/hyp/nvhe/Makefile
··· 29 29 ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o 30 30 hyp-obj-y += ../../../kernel/smccc-call.o 31 31 hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o 32 - hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o 32 + hyp-obj-$(CONFIG_NVHE_EL2_TRACING) += clock.o trace.o events.o 33 33 hyp-obj-y += $(lib-objs) 34 34 35 35 # Path to simple_ring_buffer.c
+25
arch/arm64/kvm/hyp/nvhe/events.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2025 Google LLC 4 + * Author: Vincent Donnefort <vdonnefort@google.com> 5 + */ 6 + 7 + #include <nvhe/mm.h> 8 + #include <nvhe/trace.h> 9 + 10 + #include <nvhe/define_events.h> 11 + 12 + int __tracing_enable_event(unsigned short id, bool enable) 13 + { 14 + struct hyp_event_id *event_id = &__hyp_event_ids_start[id]; 15 + atomic_t *enabled; 16 + 17 + if (event_id >= __hyp_event_ids_end) 18 + return -EINVAL; 19 + 20 + enabled = hyp_fixmap_map(__hyp_pa(&event_id->enabled)); 21 + atomic_set(enabled, enable); 22 + hyp_fixmap_unmap(); 23 + 24 + return 0; 25 + }
+9
arch/arm64/kvm/hyp/nvhe/hyp-main.c
··· 632 632 cpu_reg(host_ctxt, 1) = __tracing_reset(cpu); 633 633 } 634 634 635 + static void handle___tracing_enable_event(struct kvm_cpu_context *host_ctxt) 636 + { 637 + DECLARE_REG(unsigned short, id, host_ctxt, 1); 638 + DECLARE_REG(bool, enable, host_ctxt, 2); 639 + 640 + cpu_reg(host_ctxt, 1) = __tracing_enable_event(id, enable); 641 + } 642 + 635 643 typedef void (*hcall_t)(struct kvm_cpu_context *); 636 644 637 645 #define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x ··· 687 679 HANDLE_FUNC(__tracing_swap_reader), 688 680 HANDLE_FUNC(__tracing_update_clock), 689 681 HANDLE_FUNC(__tracing_reset), 682 + HANDLE_FUNC(__tracing_enable_event), 690 683 }; 691 684 692 685 static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
+6
arch/arm64/kvm/hyp/nvhe/hyp.lds.S
··· 16 16 HYP_SECTION(.text) 17 17 HYP_SECTION(.data..ro_after_init) 18 18 HYP_SECTION(.rodata) 19 + #ifdef CONFIG_NVHE_EL2_TRACING 20 + . = ALIGN(PAGE_SIZE); 21 + BEGIN_HYP_SECTION(.event_ids) 22 + *(SORT(.hyp.event_ids.*)) 23 + END_HYP_SECTION 24 + #endif 19 25 20 26 /* 21 27 * .hyp..data..percpu needs to be page aligned to maintain the same
+36 -1
arch/arm64/kvm/hyp_trace.c
··· 318 318 319 319 static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv) 320 320 { 321 + struct hyp_event_id *event_id = lm_alias(&__hyp_event_ids_start[id]); 322 + struct page *page; 323 + atomic_t *enabled; 324 + void *map; 325 + 326 + if (is_protected_kvm_enabled()) 327 + return kvm_call_hyp_nvhe(__tracing_enable_event, id, enable); 328 + 329 + enabled = &event_id->enabled; 330 + page = virt_to_page(enabled); 331 + map = vmap(&page, 1, VM_MAP, PAGE_KERNEL); 332 + if (!map) 333 + return -ENOMEM; 334 + 335 + enabled = map + offset_in_page(enabled); 336 + atomic_set(enabled, enable); 337 + 338 + vunmap(map); 339 + 321 340 return 0; 322 341 } 323 342 ··· 364 345 .enable_event = hyp_trace_enable_event, 365 346 }; 366 347 348 + #include <asm/kvm_define_hypevents.h> 349 + 350 + static void __init hyp_trace_init_events(void) 351 + { 352 + struct hyp_event_id *hyp_event_id = __hyp_event_ids_start; 353 + struct remote_event *event = __hyp_events_start; 354 + int id = 0; 355 + 356 + /* Events on both sides hypervisor are sorted */ 357 + for (; event < __hyp_events_end; event++, hyp_event_id++, id++) 358 + event->id = hyp_event_id->id = id; 359 + } 360 + 367 361 int __init kvm_hyp_trace_init(void) 368 362 { 369 363 int cpu; ··· 396 364 } 397 365 #endif 398 366 399 - return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0); 367 + hyp_trace_init_events(); 368 + 369 + return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, 370 + __hyp_events_start, __hyp_events_end - __hyp_events_start); 400 371 }