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 trace remote for the nVHE/pKVM hyp

In both protected and nVHE mode, the hypervisor is capable of writing
events into tracefs compatible ring-buffers. Create a trace remote so
the kernel can read those buffers.

This currently doesn't provide any event support which will come later.

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

authored by

Vincent Donnefort and committed by
Marc Zyngier
3aed038a 680a04c3

+238
+1
arch/arm64/kvm/Kconfig
··· 75 75 config NVHE_EL2_TRACING 76 76 bool 77 77 depends on TRACING 78 + select TRACE_REMOTE 78 79 default y 79 80 80 81 config PKVM_DISABLE_STAGE2_ON_PANIC
+2
arch/arm64/kvm/Makefile
··· 30 30 kvm-$(CONFIG_ARM64_PTR_AUTH) += pauth.o 31 31 kvm-$(CONFIG_PTDUMP_STAGE2_DEBUGFS) += ptdump.o 32 32 33 + kvm-$(CONFIG_NVHE_EL2_TRACING) += hyp_trace.o 34 + 33 35 always-y := hyp_constants.h hyp-constants.s 34 36 35 37 define rule_gen_hyp_constants
+5
arch/arm64/kvm/arm.c
··· 24 24 25 25 #define CREATE_TRACE_POINTS 26 26 #include "trace_arm.h" 27 + #include "hyp_trace.h" 27 28 28 29 #include <linux/uaccess.h> 29 30 #include <asm/ptrace.h> ··· 2415 2414 goto out; 2416 2415 2417 2416 kvm_register_perf_callbacks(); 2417 + 2418 + err = kvm_hyp_trace_init(); 2419 + if (err) 2420 + kvm_err("Failed to initialize Hyp tracing\n"); 2418 2421 2419 2422 out: 2420 2423 if (err)
+219
arch/arm64/kvm/hyp_trace.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 <linux/trace_remote.h> 8 + #include <linux/simple_ring_buffer.h> 9 + 10 + #include <asm/kvm_host.h> 11 + #include <asm/kvm_hyptrace.h> 12 + #include <asm/kvm_mmu.h> 13 + 14 + #include "hyp_trace.h" 15 + 16 + /* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */ 17 + static struct hyp_trace_buffer { 18 + struct hyp_trace_desc *desc; 19 + size_t desc_size; 20 + } trace_buffer; 21 + 22 + static int __map_hyp(void *start, size_t size) 23 + { 24 + if (is_protected_kvm_enabled()) 25 + return 0; 26 + 27 + return create_hyp_mappings(start, start + size, PAGE_HYP); 28 + } 29 + 30 + static int __share_page(unsigned long va) 31 + { 32 + return kvm_share_hyp((void *)va, (void *)va + 1); 33 + } 34 + 35 + static void __unshare_page(unsigned long va) 36 + { 37 + kvm_unshare_hyp((void *)va, (void *)va + 1); 38 + } 39 + 40 + static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_buffer, size_t size) 41 + { 42 + int nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1; 43 + size_t backing_size; 44 + void *start; 45 + 46 + backing_size = PAGE_ALIGN(sizeof(struct simple_buffer_page) * nr_bpages * 47 + num_possible_cpus()); 48 + 49 + start = alloc_pages_exact(backing_size, GFP_KERNEL_ACCOUNT); 50 + if (!start) 51 + return -ENOMEM; 52 + 53 + trace_buffer->desc->bpages_backing_start = (unsigned long)start; 54 + trace_buffer->desc->bpages_backing_size = backing_size; 55 + 56 + return __map_hyp(start, backing_size); 57 + } 58 + 59 + static void hyp_trace_buffer_free_bpages_backing(struct hyp_trace_buffer *trace_buffer) 60 + { 61 + free_pages_exact((void *)trace_buffer->desc->bpages_backing_start, 62 + trace_buffer->desc->bpages_backing_size); 63 + } 64 + 65 + static void hyp_trace_buffer_unshare_hyp(struct hyp_trace_buffer *trace_buffer, int last_cpu) 66 + { 67 + struct ring_buffer_desc *rb_desc; 68 + int cpu, p; 69 + 70 + for_each_ring_buffer_desc(rb_desc, cpu, &trace_buffer->desc->trace_buffer_desc) { 71 + if (cpu > last_cpu) 72 + break; 73 + 74 + __share_page(rb_desc->meta_va); 75 + for (p = 0; p < rb_desc->nr_page_va; p++) 76 + __unshare_page(rb_desc->page_va[p]); 77 + } 78 + } 79 + 80 + static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer) 81 + { 82 + struct ring_buffer_desc *rb_desc; 83 + int cpu, p, ret = 0; 84 + 85 + for_each_ring_buffer_desc(rb_desc, cpu, &trace_buffer->desc->trace_buffer_desc) { 86 + ret = __share_page(rb_desc->meta_va); 87 + if (ret) 88 + break; 89 + 90 + for (p = 0; p < rb_desc->nr_page_va; p++) { 91 + ret = __share_page(rb_desc->page_va[p]); 92 + if (ret) 93 + break; 94 + } 95 + 96 + if (ret) { 97 + for (p--; p >= 0; p--) 98 + __unshare_page(rb_desc->page_va[p]); 99 + break; 100 + } 101 + } 102 + 103 + if (ret) 104 + hyp_trace_buffer_unshare_hyp(trace_buffer, cpu--); 105 + 106 + return ret; 107 + } 108 + 109 + static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv) 110 + { 111 + struct hyp_trace_buffer *trace_buffer = priv; 112 + struct hyp_trace_desc *desc; 113 + size_t desc_size; 114 + int ret; 115 + 116 + if (WARN_ON(trace_buffer->desc)) 117 + return ERR_PTR(-EINVAL); 118 + 119 + desc_size = trace_buffer_desc_size(size, num_possible_cpus()); 120 + if (desc_size == SIZE_MAX) 121 + return ERR_PTR(-E2BIG); 122 + 123 + desc_size = PAGE_ALIGN(desc_size); 124 + desc = (struct hyp_trace_desc *)alloc_pages_exact(desc_size, GFP_KERNEL); 125 + if (!desc) 126 + return ERR_PTR(-ENOMEM); 127 + 128 + ret = __map_hyp(desc, desc_size); 129 + if (ret) 130 + goto err_free_desc; 131 + 132 + trace_buffer->desc = desc; 133 + 134 + ret = hyp_trace_buffer_alloc_bpages_backing(trace_buffer, size); 135 + if (ret) 136 + goto err_free_desc; 137 + 138 + ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, desc_size, size, 139 + cpu_possible_mask); 140 + if (ret) 141 + goto err_free_backing; 142 + 143 + ret = hyp_trace_buffer_share_hyp(trace_buffer); 144 + if (ret) 145 + goto err_free_buffer; 146 + 147 + ret = kvm_call_hyp_nvhe(__tracing_load, (unsigned long)desc, desc_size); 148 + if (ret) 149 + goto err_unload_pages; 150 + 151 + return &desc->trace_buffer_desc; 152 + 153 + err_unload_pages: 154 + hyp_trace_buffer_unshare_hyp(trace_buffer, INT_MAX); 155 + 156 + err_free_buffer: 157 + trace_remote_free_buffer(&desc->trace_buffer_desc); 158 + 159 + err_free_backing: 160 + hyp_trace_buffer_free_bpages_backing(trace_buffer); 161 + 162 + err_free_desc: 163 + free_pages_exact(desc, desc_size); 164 + trace_buffer->desc = NULL; 165 + 166 + return ERR_PTR(ret); 167 + } 168 + 169 + static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv) 170 + { 171 + struct hyp_trace_buffer *trace_buffer = priv; 172 + 173 + if (WARN_ON(desc != &trace_buffer->desc->trace_buffer_desc)) 174 + return; 175 + 176 + kvm_call_hyp_nvhe(__tracing_unload); 177 + hyp_trace_buffer_unshare_hyp(trace_buffer, INT_MAX); 178 + trace_remote_free_buffer(desc); 179 + hyp_trace_buffer_free_bpages_backing(trace_buffer); 180 + free_pages_exact(trace_buffer->desc, trace_buffer->desc_size); 181 + trace_buffer->desc = NULL; 182 + } 183 + 184 + static int hyp_trace_enable_tracing(bool enable, void *priv) 185 + { 186 + return kvm_call_hyp_nvhe(__tracing_enable, enable); 187 + } 188 + 189 + static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv) 190 + { 191 + return kvm_call_hyp_nvhe(__tracing_swap_reader, cpu); 192 + } 193 + 194 + static int hyp_trace_reset(unsigned int cpu, void *priv) 195 + { 196 + return 0; 197 + } 198 + 199 + static int hyp_trace_enable_event(unsigned short id, bool enable, void *priv) 200 + { 201 + return 0; 202 + } 203 + 204 + static struct trace_remote_callbacks trace_remote_callbacks = { 205 + .load_trace_buffer = hyp_trace_load, 206 + .unload_trace_buffer = hyp_trace_unload, 207 + .enable_tracing = hyp_trace_enable_tracing, 208 + .swap_reader_page = hyp_trace_swap_reader_page, 209 + .reset = hyp_trace_reset, 210 + .enable_event = hyp_trace_enable_event, 211 + }; 212 + 213 + int __init kvm_hyp_trace_init(void) 214 + { 215 + if (is_kernel_in_hyp_mode()) 216 + return 0; 217 + 218 + return trace_remote_register("hypervisor", &trace_remote_callbacks, &trace_buffer, NULL, 0); 219 + }
+11
arch/arm64/kvm/hyp_trace.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __ARM64_KVM_HYP_TRACE_H__ 4 + #define __ARM64_KVM_HYP_TRACE_H__ 5 + 6 + #ifdef CONFIG_NVHE_EL2_TRACING 7 + int kvm_hyp_trace_init(void); 8 + #else 9 + static inline int kvm_hyp_trace_init(void) { return 0; } 10 + #endif 11 + #endif