* [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 18:32 ` Steven Rostedt
2026-07-20 16:13 ` [PATCH v1 02/11] KVM: arm64: nVHE: Share the stacktrace per-CPU declarations with EL2 Fuad Tabba
` (8 subsequent siblings)
9 siblings, 1 reply; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
trace_remote_event.h uses bool without including linux/types.h, so a
translation unit that includes it ahead of anything else that pulls
types.h in fails to build, as with nvhe/trace.h at EL2.
Fixes: 072529158e60 ("tracing: Add events to trace remotes")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
include/linux/trace_remote_event.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remote_event.h
index c8ae1e1f5e721..e4cc2d4497bcf 100644
--- a/include/linux/trace_remote_event.h
+++ b/include/linux/trace_remote_event.h
@@ -3,6 +3,8 @@
#ifndef _LINUX_TRACE_REMOTE_EVENTS_H
#define _LINUX_TRACE_REMOTE_EVENTS_H
+#include <linux/types.h>
+
struct trace_remote;
struct trace_event_fields;
struct trace_seq;
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h
2026-07-20 16:13 ` [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h Fuad Tabba
@ 2026-07-20 18:32 ` Steven Rostedt
0 siblings, 0 replies; 13+ messages in thread
From: Steven Rostedt @ 2026-07-20 18:32 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, linux-arm-kernel, kvmarm, catalin.marinas, will,
mhiramat, alexandru.elisei, vdonnefort, joey.gouly, seiden,
suzuki.poulose, yuzenghui, qperret, ardb, linux-kernel,
linux-trace-kernel, tabba
On Mon, 20 Jul 2026 17:13:33 +0100
Fuad Tabba <fuad.tabba@linux.dev> wrote:
> diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remote_event.h
> index c8ae1e1f5e721..e4cc2d4497bcf 100644
> --- a/include/linux/trace_remote_event.h
> +++ b/include/linux/trace_remote_event.h
> @@ -3,6 +3,8 @@
> #ifndef _LINUX_TRACE_REMOTE_EVENTS_H
> #define _LINUX_TRACE_REMOTE_EVENTS_H
>
> +#include <linux/types.h>
> +
> struct trace_remote;
> struct trace_event_fields;
> struct trace_seq;
I don't know if this is correct or not, but here's my ack so others can
decide and take it through their trees.
Acked-by: Steven Rostedt <rostedt@goodmis.org.
-- Steve
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v1 02/11] KVM: arm64: nVHE: Share the stacktrace per-CPU declarations with EL2
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 03/11] KVM: arm64: nVHE: Declare the hyp event IDs before defining them Fuad Tabba
` (7 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
The declarations for overflow_stack, kvm_stacktrace_info and
pkvm_stacktrace are only visible to the host (the first two sit in the
host-only section of stacktrace/nvhe.h, the last is private to
kvm/stacktrace.c), so the definitions in nvhe/stacktrace.c compile
with no declaration in sight and sparse suggests making them static.
DECLARE_KVM_NVHE_PER_CPU() resolves to the right symbol name on both
sides of the build: move the declarations where both can see them and
include the header from the EL2 side unconditionally.
No functional change intended.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/include/asm/stacktrace/nvhe.h | 10 ++++++++--
arch/arm64/kvm/hyp/nvhe/stacktrace.c | 3 +--
arch/arm64/kvm/stacktrace.c | 3 ---
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h
index 171f9edef49fc..a631a577cbe5d 100644
--- a/arch/arm64/include/asm/stacktrace/nvhe.h
+++ b/arch/arm64/include/asm/stacktrace/nvhe.h
@@ -37,6 +37,14 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state,
state->pc = pc;
}
+DECLARE_KVM_NVHE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
+DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info);
+
+#ifdef CONFIG_PKVM_STACKTRACE
+DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)],
+ pkvm_stacktrace);
+#endif
+
#ifndef __KVM_NVHE_HYPERVISOR__
/*
* Conventional (non-protected) nVHE HYP stack unwinder
@@ -45,8 +53,6 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state,
* (by the host in EL1).
*/
-DECLARE_KVM_NVHE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
-DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info);
DECLARE_PER_CPU(unsigned long, kvm_arm_hyp_stack_base);
void kvm_nvhe_dump_backtrace(unsigned long hyp_offset);
diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c
index 7c832d60d22bb..11fadbebbf1d6 100644
--- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c
+++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c
@@ -8,6 +8,7 @@
#include <asm/kvm_hyp.h>
#include <asm/memory.h>
#include <asm/percpu.h>
+#include <asm/stacktrace/nvhe.h>
DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
__aligned(16);
@@ -35,8 +36,6 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc)
}
#ifdef CONFIG_PKVM_STACKTRACE
-#include <asm/stacktrace/nvhe.h>
-
DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace);
static struct stack_info stackinfo_get_overflow(void)
diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c
index 9724c320126b7..69377195e18b7 100644
--- a/arch/arm64/kvm/stacktrace.c
+++ b/arch/arm64/kvm/stacktrace.c
@@ -198,9 +198,6 @@ static void hyp_dump_backtrace(unsigned long hyp_offset)
}
#ifdef CONFIG_PKVM_STACKTRACE
-DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)],
- pkvm_stacktrace);
-
/*
* pkvm_dump_backtrace - Dump the protected nVHE HYP backtrace.
*
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 03/11] KVM: arm64: nVHE: Declare the hyp event IDs before defining them
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 02/11] KVM: arm64: nVHE: Share the stacktrace per-CPU declarations with EL2 Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 04/11] KVM: arm64: nVHE: Use NULL to reset the trace buffer backing pointer Fuad Tabba
` (6 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
The defining expansion of HYP_EVENT() in events.c is the first time
its translation unit meets hyp_event_id_<name>, so sparse suggests
making the symbols static. Include kvm_hypevents.h ahead of
define_events.h so the extern declarations come first, as with the
tracepoint headers.
No functional change intended.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp/nvhe/events.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/kvm/hyp/nvhe/events.c b/arch/arm64/kvm/hyp/nvhe/events.c
index add9383aadb5a..b845be0acd117 100644
--- a/arch/arm64/kvm/hyp/nvhe/events.c
+++ b/arch/arm64/kvm/hyp/nvhe/events.c
@@ -7,6 +7,8 @@
#include <nvhe/mm.h>
#include <nvhe/trace.h>
+#include <asm/kvm_hypevents.h>
+
#include <nvhe/define_events.h>
int __tracing_enable_event(unsigned short id, bool enable)
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 04/11] KVM: arm64: nVHE: Use NULL to reset the trace buffer backing pointer
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (2 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 03/11] KVM: arm64: nVHE: Declare the hyp event IDs before defining them Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 05/11] KVM: arm64: nVHE: Run the source checker under C=2 Fuad Tabba
` (5 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
bpages_backing_start is a pointer; resetting it to plain 0 triggers a
sparse warning.
No functional change intended.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp/nvhe/trace.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index e7e150ab265ff..177fe3d8fbb13 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -93,7 +93,7 @@ static void hyp_trace_buffer_unload_bpage_backing(struct hyp_trace_buffer *trace
__release_host_mem(start, size);
- trace_buffer->bpages_backing_start = 0;
+ trace_buffer->bpages_backing_start = NULL;
trace_buffer->bpages_backing_size = 0;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 05/11] KVM: arm64: nVHE: Run the source checker under C=2
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (3 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 04/11] KVM: arm64: nVHE: Use NULL to reset the trace buffer backing pointer Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 06/11] arm64: pi: Run the source checker on the libfdt objects " Fuad Tabba
` (4 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
The custom %.nvhe.o rule reuses rule_cc_o_c, which hooks the source
checker only for C=1, and that only when the object is rebuilt. The
C=2 hook, cmd_force_checksrc, hangs off the standard %.o rule that
nVHE objects do not use, so "make C=2" silently skips every nVHE
source file. Call cmd_force_checksrc after the compile rule, as the
standard rule does.
Fixes: 7621712918ad4 ("KVM: arm64: Add build rules for separate VHE/nVHE object files")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp/nvhe/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index f57450ebcb498..ccc1fe8394094 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -49,6 +49,7 @@ targets += $(hyp-obj) kvm_nvhe.tmp.o kvm_nvhe.rel.o hyp.lds hyp-reloc.S hyp-relo
# avoids file name clashes for files shared with VHE.
$(obj)/%.nvhe.o: $(src)/%.c FORCE
$(call if_changed_rule,cc_o_c)
+ $(call cmd,force_checksrc)
$(obj)/%.nvhe.o: $(src)/%.S FORCE
$(call if_changed_rule,as_o_S)
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 06/11] arm64: pi: Run the source checker on the libfdt objects under C=2
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (4 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 05/11] KVM: arm64: nVHE: Run the source checker under C=2 Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 07/11] KVM: arm64: nVHE: Pass host VA arguments as pointers Fuad Tabba
` (3 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
The custom lib-%.o rule reuses rule_cc_o_c, which hooks the source
checker only for C=1, and that only when the object is rebuilt. The
C=2 hook, cmd_force_checksrc, hangs off the standard %.o rule, so
"make C=2" silently skips the two libfdt objects. Call
cmd_force_checksrc after the compile rule, as the standard rule does.
Fixes: aacd149b6238 ("arm64: head: avoid relocating the kernel twice for KASLR")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kernel/pi/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile
index be92d73c25b21..96243c291e39d 100644
--- a/arch/arm64/kernel/pi/Makefile
+++ b/arch/arm64/kernel/pi/Makefile
@@ -34,6 +34,7 @@ $(obj)/lib-%.pi.o: OBJCOPYFLAGS += --prefix-alloc-sections=.init
$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
$(call if_changed_rule,cc_o_c)
+ $(call cmd,force_checksrc)
obj-y := idreg-override.pi.o \
map_kernel.pi.o map_range.pi.o \
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 07/11] KVM: arm64: nVHE: Pass host VA arguments as pointers
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (5 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 06/11] arm64: pi: Run the source checker on the libfdt objects " Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 08/11] KVM: arm64: Move the host hypercall interface to its own header Fuad Tabba
` (2 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
Four hypercalls take host VAs as unsigned long: the donated vm, pgd
and vcpu regions, and the tracing descriptor. Retype the arguments
and their EL2 consumers as void *, so that the typed hypercall
declarations introduced later in the series can attach a sparse
address space to them; an address space attaches only to pointers.
No functional change intended.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 5 ++---
arch/arm64/kvm/hyp/include/nvhe/trace.h | 4 ++--
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 8 ++++----
arch/arm64/kvm/hyp/nvhe/pkvm.c | 11 +++++------
arch/arm64/kvm/hyp/nvhe/trace.c | 4 ++--
5 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
index c904647d2f760..2643a1a819668 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
@@ -69,10 +69,9 @@ void pkvm_hyp_vm_table_init(void *tbl);
int __pkvm_reserve_vm(void);
void __pkvm_unreserve_vm(pkvm_handle_t handle);
-int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
- unsigned long pgd_hva);
+int __pkvm_init_vm(struct kvm *host_kvm, void *vm_hva, void *pgd_hva);
int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
- unsigned long vcpu_hva);
+ void *vcpu_hva);
int __pkvm_reclaim_dying_guest_page(pkvm_handle_t handle, u64 gfn);
int __pkvm_start_teardown_vm(pkvm_handle_t handle);
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 8813ff250f8e0..4aa36fd76b9e2 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -46,7 +46,7 @@ static inline pid_t __tracing_get_vcpu_pid(struct kvm_cpu_context *host_ctxt)
void *tracing_reserve_entry(unsigned long length);
void tracing_commit_entry(void);
-int __tracing_load(unsigned long desc_va, size_t desc_size);
+int __tracing_load(void *desc_va, size_t desc_size);
void __tracing_unload(void);
int __tracing_enable(bool enable);
int __tracing_swap_reader(unsigned int cpu);
@@ -59,7 +59,7 @@ static inline void tracing_commit_entry(void) { }
#define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \
static inline void trace_##__name(__proto) {}
-static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { return -ENODEV; }
+static inline int __tracing_load(void *desc_va, size_t desc_size) { return -ENODEV; }
static inline void __tracing_unload(void) { }
static inline int __tracing_enable(bool enable) { return -ENODEV; }
static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index d3c69de698f48..7537d422deab3 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -577,8 +577,8 @@ static void handle___pkvm_unreserve_vm(struct kvm_cpu_context *host_ctxt)
static void handle___pkvm_init_vm(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(struct kvm *, host_kvm, host_ctxt, 1);
- DECLARE_REG(unsigned long, vm_hva, host_ctxt, 2);
- DECLARE_REG(unsigned long, pgd_hva, host_ctxt, 3);
+ DECLARE_REG(void *, vm_hva, host_ctxt, 2);
+ DECLARE_REG(void *, pgd_hva, host_ctxt, 3);
host_kvm = kern_hyp_va(host_kvm);
cpu_reg(host_ctxt, 1) = __pkvm_init_vm(host_kvm, vm_hva, pgd_hva);
@@ -588,7 +588,7 @@ static void handle___pkvm_init_vcpu(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
DECLARE_REG(struct kvm_vcpu *, host_vcpu, host_ctxt, 2);
- DECLARE_REG(unsigned long, vcpu_hva, host_ctxt, 3);
+ DECLARE_REG(void *, vcpu_hva, host_ctxt, 3);
host_vcpu = kern_hyp_va(host_vcpu);
cpu_reg(host_ctxt, 1) = __pkvm_init_vcpu(handle, host_vcpu, vcpu_hva);
@@ -634,7 +634,7 @@ static void handle___pkvm_finalize_teardown_vm(struct kvm_cpu_context *host_ctxt
static void handle___tracing_load(struct kvm_cpu_context *host_ctxt)
{
- DECLARE_REG(unsigned long, desc_hva, host_ctxt, 1);
+ DECLARE_REG(void *, desc_hva, host_ctxt, 1);
DECLARE_REG(size_t, desc_size, host_ctxt, 2);
cpu_reg(host_ctxt, 1) = __tracing_load(desc_hva, desc_size);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 24d6f164129ac..205c52535c887 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -644,9 +644,9 @@ static size_t pkvm_get_hyp_vm_size(unsigned int nr_vcpus)
size_mul(sizeof(struct pkvm_hyp_vcpu *), nr_vcpus));
}
-static void *map_donated_memory_noclear(unsigned long host_va, size_t size)
+static void *map_donated_memory_noclear(void *host_va, size_t size)
{
- void *va = (void *)kern_hyp_va(host_va);
+ void *va = kern_hyp_va(host_va);
if (!PAGE_ALIGNED(va))
return NULL;
@@ -658,7 +658,7 @@ static void *map_donated_memory_noclear(unsigned long host_va, size_t size)
return va;
}
-static void *map_donated_memory(unsigned long host_va, size_t size)
+static void *map_donated_memory(void *host_va, size_t size)
{
void *va = map_donated_memory_noclear(host_va, size);
@@ -805,8 +805,7 @@ void teardown_selftest_vm(void)
*
* Return 0 success, negative error code on failure.
*/
-int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
- unsigned long pgd_hva)
+int __pkvm_init_vm(struct kvm *host_kvm, void *vm_hva, void *pgd_hva)
{
struct pkvm_hyp_vm *hyp_vm = NULL;
size_t vm_size, pgd_size;
@@ -897,7 +896,7 @@ static int register_hyp_vcpu(struct pkvm_hyp_vm *hyp_vm,
}
int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
- unsigned long vcpu_hva)
+ void *vcpu_hva)
{
struct pkvm_hyp_vcpu *hyp_vcpu;
struct pkvm_hyp_vm *hyp_vm;
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index 177fe3d8fbb13..97203ddd3cf45 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -206,9 +206,9 @@ static bool hyp_trace_desc_is_valid(struct hyp_trace_desc *desc, size_t desc_siz
return true;
}
-int __tracing_load(unsigned long desc_hva, size_t desc_size)
+int __tracing_load(void *desc_hva, size_t desc_size)
{
- struct hyp_trace_desc *desc = (struct hyp_trace_desc *)kern_hyp_va(desc_hva);
+ struct hyp_trace_desc *desc = kern_hyp_va(desc_hva);
int ret;
ret = __admit_host_mem(desc, desc_size);
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 08/11] KVM: arm64: Move the host hypercall interface to its own header
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (6 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 07/11] KVM: arm64: nVHE: Pass host VA arguments as pointers Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:13 ` [PATCH v1 09/11] KVM: arm64: Type-check hypercall arguments at the caller Fuad Tabba
2026-07-20 16:24 ` [PATCH v1 10/11] KVM: arm64: nVHE: Check hypercall handlers against the declared ABI Fuad Tabba
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
Move the kvm_call_hyp() dispatch macros and pkvm_handle_t out of
kvm_host.h into a new kvm_hcall.h, giving the host<->hyp hypercall
interface a single home that subsequent patches build on to restore
type-checking across the boundary. The only adjustment to the moved
code is the checkpatch-mandated space in "while (0)".
No functional change intended.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/include/asm/kvm_hcall.h | 68 ++++++++++++++++++++++++++++++
arch/arm64/include/asm/kvm_host.h | 48 +--------------------
2 files changed, 69 insertions(+), 47 deletions(-)
create mode 100644 arch/arm64/include/asm/kvm_hcall.h
diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
new file mode 100644
index 0000000000000..d925b2c28a3d8
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_hcall.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * The host<->hyp hypercall interface.
+ *
+ * Copyright (C) 2026 Google LLC
+ * Author: Fuad Tabba <fuad.tabba@linux.dev>
+ */
+
+#ifndef __ARM64_KVM_HCALL_H__
+#define __ARM64_KVM_HCALL_H__
+
+#include <linux/arm-smccc.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <asm/barrier.h>
+#include <asm/kvm_asm.h>
+#include <asm/virt.h>
+
+typedef u16 pkvm_handle_t;
+
+#ifndef __KVM_NVHE_HYPERVISOR__
+#define kvm_call_hyp_nvhe(f, ...) \
+ ({ \
+ struct arm_smccc_res res; \
+ \
+ arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f), \
+ ##__VA_ARGS__, &res); \
+ if (WARN_ON(res.a0 != SMCCC_RET_SUCCESS)) \
+ res.a1 = -EOPNOTSUPP; \
+ \
+ res.a1; \
+ })
+
+/*
+ * The isb() below is there to guarantee the same behaviour on VHE as on !VHE,
+ * where the eret to EL1 acts as a context synchronization event.
+ */
+#define kvm_call_hyp(f, ...) \
+ do { \
+ if (has_vhe()) { \
+ f(__VA_ARGS__); \
+ isb(); \
+ } else { \
+ kvm_call_hyp_nvhe(f, ##__VA_ARGS__); \
+ } \
+ } while (0)
+
+#define kvm_call_hyp_ret(f, ...) \
+ ({ \
+ typeof(f(__VA_ARGS__)) ret; \
+ \
+ if (has_vhe()) { \
+ ret = f(__VA_ARGS__); \
+ } else { \
+ ret = kvm_call_hyp_nvhe(f, ##__VA_ARGS__); \
+ } \
+ \
+ ret; \
+ })
+#else /* __KVM_NVHE_HYPERVISOR__ */
+#define kvm_call_hyp(f, ...) f(__VA_ARGS__)
+#define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
+#define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
+#endif /* __KVM_NVHE_HYPERVISOR__ */
+
+#endif /* __ARM64_KVM_HCALL_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bae2c4f92ef5c..81d359ac7af14 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
#include <asm/fpsimd.h>
#include <asm/kvm.h>
#include <asm/kvm_asm.h>
+#include <asm/kvm_hcall.h>
#include <asm/vncr_mapping.h>
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -251,8 +252,6 @@ struct kvm_smccc_features {
unsigned long vendor_hyp_bmap_2; /* Function numbers 64-127 */
};
-typedef u16 pkvm_handle_t;
-
struct kvm_protected_vm {
pkvm_handle_t handle;
struct kvm_hyp_memcache teardown_mc;
@@ -1252,51 +1251,6 @@ void kvm_arm_resume_guest(struct kvm *kvm);
#define vcpu_has_run_once(vcpu) (!!READ_ONCE((vcpu)->pid))
-#ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...) \
- ({ \
- struct arm_smccc_res res; \
- \
- arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f), \
- ##__VA_ARGS__, &res); \
- if (WARN_ON(res.a0 != SMCCC_RET_SUCCESS)) \
- res.a1 = -EOPNOTSUPP; \
- \
- res.a1; \
- })
-
-/*
- * The isb() below is there to guarantee the same behaviour on VHE as on !VHE,
- * where the eret to EL1 acts as a context synchronization event.
- */
-#define kvm_call_hyp(f, ...) \
- do { \
- if (has_vhe()) { \
- f(__VA_ARGS__); \
- isb(); \
- } else { \
- kvm_call_hyp_nvhe(f, ##__VA_ARGS__); \
- } \
- } while(0)
-
-#define kvm_call_hyp_ret(f, ...) \
- ({ \
- typeof(f(__VA_ARGS__)) ret; \
- \
- if (has_vhe()) { \
- ret = f(__VA_ARGS__); \
- } else { \
- ret = kvm_call_hyp_nvhe(f, ##__VA_ARGS__); \
- } \
- \
- ret; \
- })
-#else /* __KVM_NVHE_HYPERVISOR__ */
-#define kvm_call_hyp(f, ...) f(__VA_ARGS__)
-#define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
-#define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
-#endif /* __KVM_NVHE_HYPERVISOR__ */
-
int handle_exit(struct kvm_vcpu *vcpu, int exception_index);
void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index);
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 09/11] KVM: arm64: Type-check hypercall arguments at the caller
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (7 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 08/11] KVM: arm64: Move the host hypercall interface to its own header Fuad Tabba
@ 2026-07-20 16:13 ` Fuad Tabba
2026-07-20 16:24 ` [PATCH v1 10/11] KVM: arm64: nVHE: Check hypercall handlers against the declared ABI Fuad Tabba
9 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
kvm_call_hyp_nvhe() reduces its target to an SMCCC function number, so
the compiler never sees a callable: arguments that are wrong in number,
type or order are silently marshalled into registers. The kvm_call_hyp()
wrappers only catch this on the VHE branch, and the pKVM-only hypercalls
have no such branch.
Declare each hypercall's signature once in kvm_hcall.h and generate a
typed stub from it, in the mold of the syscall wrappers. Make
kvm_call_hyp_nvhe() resolve to the stub so every caller is checked
against the declared signature; a stale or mistyped call now fails to
compile. The stubs inline to the same SMCCC call the untyped macro used
to make: the compiled callers are unchanged, apart from hypercall
returns now being tested at their declared width.
The stage-2 protection arguments are declared u64 rather than
enum kvm_pgtable_prot, as kvm_pgtable.h includes linux/kvm_host.h and
the enum cannot be completed here.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/include/asm/kvm_hcall.h | 165 ++++++++++++++++++++++++++++-
arch/arm64/kvm/hyp_trace.c | 2 +-
2 files changed, 165 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
index d925b2c28a3d8..51bfd14748464 100644
--- a/arch/arm64/include/asm/kvm_hcall.h
+++ b/arch/arm64/include/asm/kvm_hcall.h
@@ -16,12 +16,35 @@
#include <asm/barrier.h>
#include <asm/kvm_asm.h>
+#include <asm/spectre.h>
#include <asm/virt.h>
typedef u16 pkvm_handle_t;
+struct kvm;
+struct kvm_s2_mmu;
+struct kvm_vcpu;
+struct vgic_v3_cpu_if;
+struct vgic_v5_cpu_if;
+
+/*
+ * Hypercall signatures are declared as (type, name) argument pairs.
+ * __KVM_HCALL_MAP() applies a macro to each pair, in the mold of __MAP()
+ * in <linux/syscalls.h>.
+ */
+#define __KVM_HCALL_MAP1(m, t, a, ...) m(t, a)
+#define __KVM_HCALL_MAP2(m, t, a, ...) m(t, a), __KVM_HCALL_MAP1(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP3(m, t, a, ...) m(t, a), __KVM_HCALL_MAP2(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP4(m, t, a, ...) m(t, a), __KVM_HCALL_MAP3(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP5(m, t, a, ...) m(t, a), __KVM_HCALL_MAP4(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP6(m, t, a, ...) m(t, a), __KVM_HCALL_MAP5(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP(n, ...) __KVM_HCALL_MAP##n(__VA_ARGS__)
+
+#define __KVM_HCALL_DECL(t, a) t a
+#define __KVM_HCALL_ARGS(t, a) a
+
#ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...) \
+#define __kvm_call_hyp_nvhe(f, ...) \
({ \
struct arm_smccc_res res; \
\
@@ -33,6 +56,43 @@ typedef u16 pkvm_handle_t;
res.a1; \
})
+/*
+ * Generate a typed stub for each declared hypercall. kvm_call_hyp_nvhe()
+ * resolves to the stub, so a call with the wrong argument count or types
+ * fails to compile instead of being silently truncated to an SMCCC function
+ * number and a pile of registers. The stub inlines to the same SMCCC call
+ * the untyped macro used to make.
+ */
+#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...) \
+ static __always_inline \
+ ret nvhe_hvc_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__)) \
+ { \
+ return (ret)__kvm_call_hyp_nvhe(name, \
+ __KVM_HCALL_MAP(x, __KVM_HCALL_ARGS, __VA_ARGS__)); \
+ }
+
+#define DECLARE_KVM_HOST_HCALL_VOID(name, x, ...) \
+ static __always_inline \
+ void nvhe_hvc_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__)) \
+ { \
+ __kvm_call_hyp_nvhe(name, \
+ __KVM_HCALL_MAP(x, __KVM_HCALL_ARGS, __VA_ARGS__)); \
+ }
+
+#define DECLARE_KVM_HOST_HCALL0(ret, name) \
+ static __always_inline ret nvhe_hvc_##name(void) \
+ { \
+ return (ret)__kvm_call_hyp_nvhe(name); \
+ }
+
+#define DECLARE_KVM_HOST_HCALL0_VOID(name) \
+ static __always_inline void nvhe_hvc_##name(void) \
+ { \
+ __kvm_call_hyp_nvhe(name); \
+ }
+
+#define kvm_call_hyp_nvhe(f, ...) nvhe_hvc_##f(__VA_ARGS__)
+
/*
* The isb() below is there to guarantee the same behaviour on VHE as on !VHE,
* where the eret to EL1 acts as a context synchronization event.
@@ -63,6 +123,109 @@ typedef u16 pkvm_handle_t;
#define kvm_call_hyp(f, ...) f(__VA_ARGS__)
#define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
#define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
+
+#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...)
+#define DECLARE_KVM_HOST_HCALL_VOID(name, x, ...)
+#define DECLARE_KVM_HOST_HCALL0(ret, name)
+#define DECLARE_KVM_HOST_HCALL0_VOID(name)
#endif /* __KVM_NVHE_HYPERVISOR__ */
+/* Hypercalls that are unavailable once pKVM has finalised. */
+DECLARE_KVM_HOST_HCALL(int, __pkvm_init, 4,
+ phys_addr_t, phys, unsigned long, size,
+ unsigned long *, per_cpu_base, u32, hyp_va_bits)
+DECLARE_KVM_HOST_HCALL(unsigned long, __pkvm_create_private_mapping, 3,
+ phys_addr_t, phys, size_t, size, u64, prot)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_cpu_set_vector, 1,
+ enum arm64_hyp_spectre_vector, slot)
+DECLARE_KVM_HOST_HCALL0_VOID(__kvm_enable_ssbs)
+DECLARE_KVM_HOST_HCALL0_VOID(__vgic_v3_init_lrs)
+DECLARE_KVM_HOST_HCALL0(u64, __vgic_v3_get_gic_config)
+
+DECLARE_KVM_HOST_HCALL0(int, __pkvm_prot_finalize)
+
+/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_adjust_pc, 1,
+ struct kvm_vcpu *, vcpu)
+DECLARE_KVM_HOST_HCALL(int, __kvm_vcpu_run, 1,
+ struct kvm_vcpu *, vcpu)
+DECLARE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa, 3,
+ struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa_nsh, 3,
+ struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid, 1,
+ struct kvm_s2_mmu *, mmu)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_range, 3,
+ struct kvm_s2_mmu *, mmu, phys_addr_t, start, unsigned long, pages)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_flush_cpu_context, 1,
+ struct kvm_s2_mmu *, mmu)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_timer_set_cntvoff, 1,
+ u64, cntvoff)
+DECLARE_KVM_HOST_HCALL(int, __tracing_load, 2,
+ void *, desc_hva, size_t, desc_size)
+DECLARE_KVM_HOST_HCALL0_VOID(__tracing_unload)
+DECLARE_KVM_HOST_HCALL(int, __tracing_enable, 1,
+ bool, enable)
+DECLARE_KVM_HOST_HCALL(int, __tracing_swap_reader, 1,
+ unsigned int, cpu)
+DECLARE_KVM_HOST_HCALL_VOID(__tracing_update_clock, 4,
+ u32, mult, u32, shift, u64, epoch_ns, u64, epoch_cyc)
+DECLARE_KVM_HOST_HCALL(int, __tracing_reset, 1,
+ unsigned int, cpu)
+DECLARE_KVM_HOST_HCALL(int, __tracing_enable_event, 2,
+ unsigned short, id, bool, enable)
+DECLARE_KVM_HOST_HCALL_VOID(__tracing_write_event, 1,
+ u64, id)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs, 1,
+ struct vgic_v3_cpu_if *, cpu_if)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_restore_vmcr_aprs, 1,
+ struct vgic_v3_cpu_if *, cpu_if)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_save_apr, 1,
+ struct vgic_v5_cpu_if *, cpu_if)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_restore_vmcr_apr, 1,
+ struct vgic_v5_cpu_if *, cpu_if)
+
+/* Hypercalls that are available only when pKVM has finalised. */
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_share_hyp, 1,
+ u64, pfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_unshare_hyp, 1,
+ u64, pfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_donate_guest, 2,
+ u64, pfn, u64, gfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_share_guest, 4,
+ u64, pfn, u64, gfn, u64, nr_pages, u64, prot)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_unshare_guest, 3,
+ pkvm_handle_t, handle, u64, gfn, u64, nr_pages)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_relax_perms_guest, 2,
+ u64, gfn, u64, prot)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_wrprotect_guest, 3,
+ pkvm_handle_t, handle, u64, gfn, u64, nr_pages)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_test_clear_young_guest, 4,
+ pkvm_handle_t, handle, u64, gfn, u64, nr_pages, bool, mkold)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_mkyoung_guest, 1,
+ u64, gfn)
+DECLARE_KVM_HOST_HCALL0(int, __pkvm_reserve_vm)
+DECLARE_KVM_HOST_HCALL_VOID(__pkvm_unreserve_vm, 1,
+ pkvm_handle_t, handle)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vm, 3,
+ struct kvm *, host_kvm, void *, vm_hva, void *, pgd_hva)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vcpu, 3,
+ pkvm_handle_t, handle, struct kvm_vcpu *, host_vcpu,
+ void *, vcpu_hva)
+DECLARE_KVM_HOST_HCALL0(int, __pkvm_vcpu_in_poison_fault)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_force_reclaim_guest_page, 1,
+ phys_addr_t, phys)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_reclaim_dying_guest_page, 2,
+ pkvm_handle_t, handle, u64, gfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_start_teardown_vm, 1,
+ pkvm_handle_t, handle)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_finalize_teardown_vm, 1,
+ pkvm_handle_t, handle)
+DECLARE_KVM_HOST_HCALL_VOID(__pkvm_vcpu_load, 3,
+ pkvm_handle_t, handle, unsigned int, vcpu_idx, u64, hcr_el2)
+DECLARE_KVM_HOST_HCALL0_VOID(__pkvm_vcpu_put)
+DECLARE_KVM_HOST_HCALL_VOID(__pkvm_tlb_flush_vmid, 1,
+ pkvm_handle_t, handle)
+
#endif /* __ARM64_KVM_HCALL_H__ */
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 2411b4c32932c..7fe0e8feb7d7c 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -264,7 +264,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
if (ret)
goto err_free_buffer;
- ret = kvm_call_hyp_nvhe(__tracing_load, (unsigned long)desc, desc_size);
+ ret = kvm_call_hyp_nvhe(__tracing_load, desc, desc_size);
if (ret)
goto err_unload_pages;
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 10/11] KVM: arm64: nVHE: Check hypercall handlers against the declared ABI
2026-07-20 16:13 [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary Fuad Tabba
` (8 preceding siblings ...)
2026-07-20 16:13 ` [PATCH v1 09/11] KVM: arm64: Type-check hypercall arguments at the caller Fuad Tabba
@ 2026-07-20 16:24 ` Fuad Tabba
2026-07-20 16:24 ` [PATCH v1 11/11] KVM: arm64: Tag host-VA hypercall parameters __hostva Fuad Tabba
9 siblings, 1 reply; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:24 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
Each hypercall handler unmarshals its arguments from the host context
with hand-written DECLARE_REG() casts that nothing ties to what the
caller passed: a handler can disagree with its caller in argument type,
count or register index without a diagnostic.
Generate the unmarshalling instead. DEFINE_KVM_HOST_HCALL() expands to
the handle_<name>() glue, modelled on the syscall wrappers, and checks
the handler's parameter list against the signature declared in
kvm_hcall.h, so both ends of every hypercall are now compiled against
the same declaration. Handler bodies keep their logic and lose the
DECLARE_REG() and return-register boilerplate. The compiled handlers
are instruction-for-instruction identical, apart from flush_hyp_vcpu()
and sync_hyp_vcpu() now being inlined into their only caller.
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/include/asm/kvm_hcall.h | 19 +-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 420 ++++++++++++++---------------
2 files changed, 213 insertions(+), 226 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
index 51bfd14748464..6aa2df90a14a4 100644
--- a/arch/arm64/include/asm/kvm_hcall.h
+++ b/arch/arm64/include/asm/kvm_hcall.h
@@ -41,6 +41,8 @@ struct vgic_v5_cpu_if;
#define __KVM_HCALL_MAP(n, ...) __KVM_HCALL_MAP##n(__VA_ARGS__)
#define __KVM_HCALL_DECL(t, a) t a
+#define __KVM_HCALL_LONG(t, a) unsigned long a
+#define __KVM_HCALL_CAST(t, a) (__force t) a
#define __KVM_HCALL_ARGS(t, a) a
#ifndef __KVM_NVHE_HYPERVISOR__
@@ -124,10 +126,19 @@ struct vgic_v5_cpu_if;
#define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
#define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
-#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...)
-#define DECLARE_KVM_HOST_HCALL_VOID(name, x, ...)
-#define DECLARE_KVM_HOST_HCALL0(ret, name)
-#define DECLARE_KVM_HOST_HCALL0_VOID(name)
+/*
+ * At EL2 each declaration emits the canonical signature of the hypercall,
+ * which DEFINE_KVM_HOST_HCALL() in hyp-main.c checks the handler
+ * definition against.
+ */
+#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...) \
+ typedef ret kvm_host_hcall_sig_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__));
+#define DECLARE_KVM_HOST_HCALL_VOID(name, x, ...) \
+ typedef void kvm_host_hcall_sig_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__));
+#define DECLARE_KVM_HOST_HCALL0(ret, name) \
+ typedef ret kvm_host_hcall_sig_##name(void);
+#define DECLARE_KVM_HOST_HCALL0_VOID(name) \
+ typedef void kvm_host_hcall_sig_##name(void);
#endif /* __KVM_NVHE_HYPERVISOR__ */
/* Hypercalls that are unavailable once pKVM has finalised. */
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 7537d422deab3..f2501249f4391 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -24,6 +24,62 @@
DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
+/*
+ * Define a hypercall handler: handle_<name> unmarshals the arguments from
+ * the host context and hands them, correctly typed, to the body that
+ * follows the macro. The parameter list is type-checked against the
+ * signature declared in <asm/kvm_hcall.h>, so the handler cannot drift
+ * from what the typed caller stubs marshal in. Modelled on the syscall
+ * wrappers.
+ */
+#define KVM_HOST_HCALL_REGS(x) \
+ __KVM_HCALL_MAP(x, __KVM_HCALL_ARGS \
+ ,, cpu_reg(host_ctxt, 1),, cpu_reg(host_ctxt, 2) \
+ ,, cpu_reg(host_ctxt, 3),, cpu_reg(host_ctxt, 4) \
+ ,, cpu_reg(host_ctxt, 5),, cpu_reg(host_ctxt, 6))
+
+#define DEFINE_KVM_HOST_HCALL(ret, name, x, ...) \
+ static kvm_host_hcall_sig_##name __do_##name; \
+ static __always_inline \
+ ret __se_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_LONG, __VA_ARGS__)) \
+ { \
+ return __do_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_CAST, __VA_ARGS__)); \
+ } \
+ static void handle_##name(struct kvm_cpu_context *host_ctxt) \
+ { \
+ cpu_reg(host_ctxt, 1) = __se_##name(KVM_HOST_HCALL_REGS(x)); \
+ } \
+ static ret __do_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__))
+
+#define DEFINE_KVM_HOST_HCALL_VOID(name, x, ...) \
+ static kvm_host_hcall_sig_##name __do_##name; \
+ static __always_inline \
+ void __se_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_LONG, __VA_ARGS__)) \
+ { \
+ __do_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_CAST, __VA_ARGS__)); \
+ } \
+ static void handle_##name(struct kvm_cpu_context *host_ctxt) \
+ { \
+ __se_##name(KVM_HOST_HCALL_REGS(x)); \
+ } \
+ static void __do_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__))
+
+#define DEFINE_KVM_HOST_HCALL0(ret, name) \
+ static kvm_host_hcall_sig_##name __do_##name; \
+ static void handle_##name(struct kvm_cpu_context *host_ctxt) \
+ { \
+ cpu_reg(host_ctxt, 1) = __do_##name(); \
+ } \
+ static ret __do_##name(void)
+
+#define DEFINE_KVM_HOST_HCALL0_VOID(name) \
+ static kvm_host_hcall_sig_##name __do_##name; \
+ static void handle_##name(struct kvm_cpu_context *host_ctxt) \
+ { \
+ __do_##name(); \
+ } \
+ static void __do_##name(void)
+
/* Number of implemented GICv3 LRs. Used by flush_hyp_vcpu(). */
unsigned int hyp_gicv3_nr_lr;
@@ -185,11 +241,9 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
host_cpu_if->vgic_lr[i] = hyp_cpu_if->vgic_lr[i];
}
-static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__pkvm_vcpu_load, 3,
+ pkvm_handle_t, handle, unsigned int, vcpu_idx, u64, hcr_el2)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
- DECLARE_REG(unsigned int, vcpu_idx, host_ctxt, 2);
- DECLARE_REG(u64, hcr_el2, host_ctxt, 3);
struct pkvm_hyp_vcpu *hyp_vcpu;
hyp_vcpu = pkvm_load_hyp_vcpu(handle, vcpu_idx);
@@ -206,7 +260,7 @@ static void handle___pkvm_vcpu_load(struct kvm_cpu_context *host_ctxt)
}
}
-static void handle___pkvm_vcpu_put(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0_VOID(__pkvm_vcpu_put)
{
struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
@@ -214,9 +268,9 @@ static void handle___pkvm_vcpu_put(struct kvm_cpu_context *host_ctxt)
pkvm_put_hyp_vcpu(hyp_vcpu);
}
-static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __kvm_vcpu_run, 1,
+ struct kvm_vcpu *, host_vcpu)
{
- DECLARE_REG(struct kvm_vcpu *, host_vcpu, host_ctxt, 1);
int ret;
if (unlikely(is_protected_kvm_enabled())) {
@@ -228,15 +282,11 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
* loading a vcpu. Therefore, if SME features enabled the host
* is misbehaving.
*/
- if (unlikely(system_supports_sme() && read_sysreg_s(SYS_SVCR))) {
- ret = -EINVAL;
- goto out;
- }
+ if (unlikely(system_supports_sme() && read_sysreg_s(SYS_SVCR)))
+ return -EINVAL;
- if (!hyp_vcpu) {
- ret = -EINVAL;
- goto out;
- }
+ if (!hyp_vcpu)
+ return -EINVAL;
flush_hyp_vcpu(hyp_vcpu);
@@ -251,8 +301,8 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
ret = __kvm_vcpu_run(vcpu);
fpsimd_lazy_switch_to_host(vcpu);
}
-out:
- cpu_reg(host_ctxt, 1) = ret;
+
+ return ret;
}
static int pkvm_refill_memcache(struct pkvm_hyp_vcpu *hyp_vcpu)
@@ -264,184 +314,150 @@ static int pkvm_refill_memcache(struct pkvm_hyp_vcpu *hyp_vcpu)
&host_vcpu->arch.pkvm_memcache);
}
-static void handle___pkvm_host_donate_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_donate_guest, 2,
+ u64, pfn, u64, gfn)
{
- DECLARE_REG(u64, pfn, host_ctxt, 1);
- DECLARE_REG(u64, gfn, host_ctxt, 2);
struct pkvm_hyp_vcpu *hyp_vcpu;
- int ret = -EINVAL;
+ int ret;
hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
if (!hyp_vcpu || !pkvm_hyp_vcpu_is_protected(hyp_vcpu))
- goto out;
+ return -EINVAL;
ret = pkvm_refill_memcache(hyp_vcpu);
if (ret)
- goto out;
+ return ret;
- ret = __pkvm_host_donate_guest(pfn, gfn, hyp_vcpu);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+ return __pkvm_host_donate_guest(pfn, gfn, hyp_vcpu);
}
-static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_share_guest, 4,
+ u64, pfn, u64, gfn, u64, nr_pages, u64, prot)
{
- DECLARE_REG(u64, pfn, host_ctxt, 1);
- DECLARE_REG(u64, gfn, host_ctxt, 2);
- DECLARE_REG(u64, nr_pages, host_ctxt, 3);
- DECLARE_REG(enum kvm_pgtable_prot, prot, host_ctxt, 4);
struct pkvm_hyp_vcpu *hyp_vcpu;
- int ret = -EINVAL;
+ int ret;
hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
if (!hyp_vcpu || pkvm_hyp_vcpu_is_protected(hyp_vcpu))
- goto out;
+ return -EINVAL;
ret = pkvm_refill_memcache(hyp_vcpu);
if (ret)
- goto out;
+ return ret;
- ret = __pkvm_host_share_guest(pfn, gfn, nr_pages, hyp_vcpu, prot);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+ return __pkvm_host_share_guest(pfn, gfn, nr_pages, hyp_vcpu, prot);
}
-static void handle___pkvm_host_unshare_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_unshare_guest, 3,
+ pkvm_handle_t, handle, u64, gfn, u64, nr_pages)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
- DECLARE_REG(u64, gfn, host_ctxt, 2);
- DECLARE_REG(u64, nr_pages, host_ctxt, 3);
struct pkvm_hyp_vm *hyp_vm;
- int ret = -EINVAL;
+ int ret;
hyp_vm = get_np_pkvm_hyp_vm(handle);
if (!hyp_vm)
- goto out;
+ return -EINVAL;
ret = __pkvm_host_unshare_guest(gfn, nr_pages, hyp_vm);
put_pkvm_hyp_vm(hyp_vm);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+
+ return ret;
}
-static void handle___pkvm_host_relax_perms_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_relax_perms_guest, 2,
+ u64, gfn, u64, prot)
{
- DECLARE_REG(u64, gfn, host_ctxt, 1);
- DECLARE_REG(enum kvm_pgtable_prot, prot, host_ctxt, 2);
struct pkvm_hyp_vcpu *hyp_vcpu;
- int ret = -EINVAL;
hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
if (!hyp_vcpu || pkvm_hyp_vcpu_is_protected(hyp_vcpu))
- goto out;
+ return -EINVAL;
- ret = __pkvm_host_relax_perms_guest(gfn, hyp_vcpu, prot);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+ return __pkvm_host_relax_perms_guest(gfn, hyp_vcpu, prot);
}
-static void handle___pkvm_host_wrprotect_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_wrprotect_guest, 3,
+ pkvm_handle_t, handle, u64, gfn, u64, nr_pages)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
- DECLARE_REG(u64, gfn, host_ctxt, 2);
- DECLARE_REG(u64, nr_pages, host_ctxt, 3);
struct pkvm_hyp_vm *hyp_vm;
- int ret = -EINVAL;
+ int ret;
hyp_vm = get_np_pkvm_hyp_vm(handle);
if (!hyp_vm)
- goto out;
+ return -EINVAL;
ret = __pkvm_host_wrprotect_guest(gfn, nr_pages, hyp_vm);
put_pkvm_hyp_vm(hyp_vm);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+
+ return ret;
}
-static void handle___pkvm_host_test_clear_young_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_test_clear_young_guest, 4,
+ pkvm_handle_t, handle, u64, gfn, u64, nr_pages, bool, mkold)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
- DECLARE_REG(u64, gfn, host_ctxt, 2);
- DECLARE_REG(u64, nr_pages, host_ctxt, 3);
- DECLARE_REG(bool, mkold, host_ctxt, 4);
struct pkvm_hyp_vm *hyp_vm;
- int ret = -EINVAL;
+ int ret;
hyp_vm = get_np_pkvm_hyp_vm(handle);
if (!hyp_vm)
- goto out;
+ return -EINVAL;
ret = __pkvm_host_test_clear_young_guest(gfn, nr_pages, mkold, hyp_vm);
put_pkvm_hyp_vm(hyp_vm);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+
+ return ret;
}
-static void handle___pkvm_host_mkyoung_guest(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_mkyoung_guest, 1,
+ u64, gfn)
{
- DECLARE_REG(u64, gfn, host_ctxt, 1);
struct pkvm_hyp_vcpu *hyp_vcpu;
- int ret = -EINVAL;
hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
if (!hyp_vcpu || pkvm_hyp_vcpu_is_protected(hyp_vcpu))
- goto out;
+ return -EINVAL;
- ret = __pkvm_host_mkyoung_guest(gfn, hyp_vcpu);
-out:
- cpu_reg(host_ctxt, 1) = ret;
+ return __pkvm_host_mkyoung_guest(gfn, hyp_vcpu);
}
-static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_adjust_pc, 1,
+ struct kvm_vcpu *, vcpu)
{
- DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
-
__kvm_adjust_pc(kern_hyp_va(vcpu));
}
-static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context)
{
__kvm_flush_vm_context();
}
-static void handle___kvm_tlb_flush_vmid_ipa(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa, 3,
+ struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
{
- DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
- DECLARE_REG(phys_addr_t, ipa, host_ctxt, 2);
- DECLARE_REG(int, level, host_ctxt, 3);
-
__kvm_tlb_flush_vmid_ipa(kern_hyp_va(mmu), ipa, level);
}
-static void handle___kvm_tlb_flush_vmid_ipa_nsh(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa_nsh, 3,
+ struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
{
- DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
- DECLARE_REG(phys_addr_t, ipa, host_ctxt, 2);
- DECLARE_REG(int, level, host_ctxt, 3);
-
__kvm_tlb_flush_vmid_ipa_nsh(kern_hyp_va(mmu), ipa, level);
}
-static void
-handle___kvm_tlb_flush_vmid_range(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_range, 3,
+ struct kvm_s2_mmu *, mmu, phys_addr_t, start, unsigned long, pages)
{
- DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
- DECLARE_REG(phys_addr_t, start, host_ctxt, 2);
- DECLARE_REG(unsigned long, pages, host_ctxt, 3);
-
__kvm_tlb_flush_vmid_range(kern_hyp_va(mmu), start, pages);
}
-static void handle___kvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid, 1,
+ struct kvm_s2_mmu *, mmu)
{
- DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
-
__kvm_tlb_flush_vmid(kern_hyp_va(mmu));
}
-static void handle___pkvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__pkvm_tlb_flush_vmid, 1,
+ pkvm_handle_t, handle)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
struct pkvm_hyp_vm *hyp_vm = get_np_pkvm_hyp_vm(handle);
if (!hyp_vm)
@@ -451,19 +467,19 @@ static void handle___pkvm_tlb_flush_vmid(struct kvm_cpu_context *host_ctxt)
put_pkvm_hyp_vm(hyp_vm);
}
-static void handle___kvm_flush_cpu_context(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_flush_cpu_context, 1,
+ struct kvm_s2_mmu *, mmu)
{
- DECLARE_REG(struct kvm_s2_mmu *, mmu, host_ctxt, 1);
-
__kvm_flush_cpu_context(kern_hyp_va(mmu));
}
-static void handle___kvm_timer_set_cntvoff(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__kvm_timer_set_cntvoff, 1,
+ u64, cntvoff)
{
- __kvm_timer_set_cntvoff(cpu_reg(host_ctxt, 1));
+ __kvm_timer_set_cntvoff(cntvoff);
}
-static void handle___kvm_enable_ssbs(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0_VOID(__kvm_enable_ssbs)
{
u64 tmp;
@@ -472,72 +488,61 @@ static void handle___kvm_enable_ssbs(struct kvm_cpu_context *host_ctxt)
write_sysreg_el2(tmp, SYS_SCTLR);
}
-static void handle___vgic_v3_get_gic_config(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0(u64, __vgic_v3_get_gic_config)
{
- cpu_reg(host_ctxt, 1) = __vgic_v3_get_gic_config();
+ return __vgic_v3_get_gic_config();
}
-static void handle___vgic_v3_init_lrs(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0_VOID(__vgic_v3_init_lrs)
{
__vgic_v3_init_lrs();
}
-static void handle___vgic_v3_save_aprs(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs, 1,
+ struct vgic_v3_cpu_if *, cpu_if)
{
- DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1);
-
__vgic_v3_save_aprs(kern_hyp_va(cpu_if));
}
-static void handle___vgic_v3_restore_vmcr_aprs(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__vgic_v3_restore_vmcr_aprs, 1,
+ struct vgic_v3_cpu_if *, cpu_if)
{
- DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1);
-
__vgic_v3_restore_vmcr_aprs(kern_hyp_va(cpu_if));
}
-static void handle___pkvm_init(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_init, 4,
+ phys_addr_t, phys, unsigned long, size,
+ unsigned long *, per_cpu_base, u32, hyp_va_bits)
{
- DECLARE_REG(phys_addr_t, phys, host_ctxt, 1);
- DECLARE_REG(unsigned long, size, host_ctxt, 2);
- DECLARE_REG(unsigned long *, per_cpu_base, host_ctxt, 3);
- DECLARE_REG(u32, hyp_va_bits, host_ctxt, 4);
-
/*
* __pkvm_init() will return only if an error occurred, otherwise it
* will tail-call in __pkvm_init_finalise() which will have to deal
* with the host context directly.
*/
- cpu_reg(host_ctxt, 1) = __pkvm_init(phys, size, per_cpu_base, hyp_va_bits);
+ return __pkvm_init(phys, size, per_cpu_base, hyp_va_bits);
}
-static void handle___pkvm_cpu_set_vector(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_cpu_set_vector, 1,
+ enum arm64_hyp_spectre_vector, slot)
{
- DECLARE_REG(enum arm64_hyp_spectre_vector, slot, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = pkvm_cpu_set_vector(slot);
+ return pkvm_cpu_set_vector(slot);
}
-static void handle___pkvm_host_share_hyp(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_share_hyp, 1,
+ u64, pfn)
{
- DECLARE_REG(u64, pfn, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __pkvm_host_share_hyp(pfn);
+ return __pkvm_host_share_hyp(pfn);
}
-static void handle___pkvm_host_unshare_hyp(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_host_unshare_hyp, 1,
+ u64, pfn)
{
- DECLARE_REG(u64, pfn, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __pkvm_host_unshare_hyp(pfn);
+ return __pkvm_host_unshare_hyp(pfn);
}
-static void handle___pkvm_create_private_mapping(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(unsigned long, __pkvm_create_private_mapping, 3,
+ phys_addr_t, phys, size_t, size, u64, prot)
{
- DECLARE_REG(phys_addr_t, phys, host_ctxt, 1);
- DECLARE_REG(size_t, size, host_ctxt, 2);
- DECLARE_REG(enum kvm_pgtable_prot, prot, host_ctxt, 3);
-
/*
* __pkvm_create_private_mapping() populates a pointer with the
* hypervisor start address of the allocation.
@@ -554,154 +559,125 @@ static void handle___pkvm_create_private_mapping(struct kvm_cpu_context *host_ct
if (err)
haddr = (unsigned long)ERR_PTR(err);
- cpu_reg(host_ctxt, 1) = haddr;
+ return haddr;
}
-static void handle___pkvm_prot_finalize(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0(int, __pkvm_prot_finalize)
{
- cpu_reg(host_ctxt, 1) = __pkvm_prot_finalize();
+ return __pkvm_prot_finalize();
}
-static void handle___pkvm_reserve_vm(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0(int, __pkvm_reserve_vm)
{
- cpu_reg(host_ctxt, 1) = __pkvm_reserve_vm();
+ return __pkvm_reserve_vm();
}
-static void handle___pkvm_unreserve_vm(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__pkvm_unreserve_vm, 1,
+ pkvm_handle_t, handle)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
-
__pkvm_unreserve_vm(handle);
}
-static void handle___pkvm_init_vm(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_init_vm, 3,
+ struct kvm *, host_kvm, void *, vm_hva, void *, pgd_hva)
{
- DECLARE_REG(struct kvm *, host_kvm, host_ctxt, 1);
- DECLARE_REG(void *, vm_hva, host_ctxt, 2);
- DECLARE_REG(void *, pgd_hva, host_ctxt, 3);
-
- host_kvm = kern_hyp_va(host_kvm);
- cpu_reg(host_ctxt, 1) = __pkvm_init_vm(host_kvm, vm_hva, pgd_hva);
+ return __pkvm_init_vm(kern_hyp_va(host_kvm), vm_hva, pgd_hva);
}
-static void handle___pkvm_init_vcpu(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_init_vcpu, 3,
+ pkvm_handle_t, handle, struct kvm_vcpu *, host_vcpu,
+ void *, vcpu_hva)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
- DECLARE_REG(struct kvm_vcpu *, host_vcpu, host_ctxt, 2);
- DECLARE_REG(void *, vcpu_hva, host_ctxt, 3);
-
- host_vcpu = kern_hyp_va(host_vcpu);
- cpu_reg(host_ctxt, 1) = __pkvm_init_vcpu(handle, host_vcpu, vcpu_hva);
+ return __pkvm_init_vcpu(handle, kern_hyp_va(host_vcpu), vcpu_hva);
}
-static void handle___pkvm_vcpu_in_poison_fault(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0(int, __pkvm_vcpu_in_poison_fault)
{
- int ret;
struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
- ret = hyp_vcpu ? __pkvm_vcpu_in_poison_fault(hyp_vcpu) : -EINVAL;
- cpu_reg(host_ctxt, 1) = ret;
+ return hyp_vcpu ? __pkvm_vcpu_in_poison_fault(hyp_vcpu) : -EINVAL;
}
-static void handle___pkvm_force_reclaim_guest_page(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_force_reclaim_guest_page, 1,
+ phys_addr_t, phys)
{
- DECLARE_REG(phys_addr_t, phys, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __pkvm_host_force_reclaim_page_guest(phys);
+ return __pkvm_host_force_reclaim_page_guest(phys);
}
-static void handle___pkvm_reclaim_dying_guest_page(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_reclaim_dying_guest_page, 2,
+ pkvm_handle_t, handle, u64, gfn)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
- DECLARE_REG(u64, gfn, host_ctxt, 2);
-
- cpu_reg(host_ctxt, 1) = __pkvm_reclaim_dying_guest_page(handle, gfn);
+ return __pkvm_reclaim_dying_guest_page(handle, gfn);
}
-static void handle___pkvm_start_teardown_vm(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_start_teardown_vm, 1,
+ pkvm_handle_t, handle)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __pkvm_start_teardown_vm(handle);
+ return __pkvm_start_teardown_vm(handle);
}
-static void handle___pkvm_finalize_teardown_vm(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __pkvm_finalize_teardown_vm, 1,
+ pkvm_handle_t, handle)
{
- DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __pkvm_finalize_teardown_vm(handle);
+ return __pkvm_finalize_teardown_vm(handle);
}
-static void handle___tracing_load(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __tracing_load, 2,
+ void *, desc_hva, size_t, desc_size)
{
- DECLARE_REG(void *, desc_hva, host_ctxt, 1);
- DECLARE_REG(size_t, desc_size, host_ctxt, 2);
-
- cpu_reg(host_ctxt, 1) = __tracing_load(desc_hva, desc_size);
+ return __tracing_load(desc_hva, desc_size);
}
-static void handle___tracing_unload(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL0_VOID(__tracing_unload)
{
__tracing_unload();
}
-static void handle___tracing_enable(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __tracing_enable, 1,
+ bool, enable)
{
- DECLARE_REG(bool, enable, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __tracing_enable(enable);
+ return __tracing_enable(enable);
}
-static void handle___tracing_swap_reader(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __tracing_swap_reader, 1,
+ unsigned int, cpu)
{
- DECLARE_REG(unsigned int, cpu, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __tracing_swap_reader(cpu);
+ return __tracing_swap_reader(cpu);
}
-static void handle___tracing_update_clock(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__tracing_update_clock, 4,
+ u32, mult, u32, shift, u64, epoch_ns, u64, epoch_cyc)
{
- DECLARE_REG(u32, mult, host_ctxt, 1);
- DECLARE_REG(u32, shift, host_ctxt, 2);
- DECLARE_REG(u64, epoch_ns, host_ctxt, 3);
- DECLARE_REG(u64, epoch_cyc, host_ctxt, 4);
-
__tracing_update_clock(mult, shift, epoch_ns, epoch_cyc);
}
-static void handle___tracing_reset(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __tracing_reset, 1,
+ unsigned int, cpu)
{
- DECLARE_REG(unsigned int, cpu, host_ctxt, 1);
-
- cpu_reg(host_ctxt, 1) = __tracing_reset(cpu);
+ return __tracing_reset(cpu);
}
-static void handle___tracing_enable_event(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL(int, __tracing_enable_event, 2,
+ unsigned short, id, bool, enable)
{
- DECLARE_REG(unsigned short, id, host_ctxt, 1);
- DECLARE_REG(bool, enable, host_ctxt, 2);
-
- cpu_reg(host_ctxt, 1) = __tracing_enable_event(id, enable);
+ return __tracing_enable_event(id, enable);
}
-static void handle___tracing_write_event(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__tracing_write_event, 1,
+ u64, id)
{
- DECLARE_REG(u64, id, host_ctxt, 1);
-
trace_selftest(id);
}
-static void handle___vgic_v5_save_apr(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__vgic_v5_save_apr, 1,
+ struct vgic_v5_cpu_if *, cpu_if)
{
- DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
-
__vgic_v5_save_apr(kern_hyp_va(cpu_if));
}
-static void handle___vgic_v5_restore_vmcr_apr(struct kvm_cpu_context *host_ctxt)
+DEFINE_KVM_HOST_HCALL_VOID(__vgic_v5_restore_vmcr_apr, 1,
+ struct vgic_v5_cpu_if *, cpu_if)
{
- DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt, 1);
-
__vgic_v5_restore_vmcr_apr(kern_hyp_va(cpu_if));
}
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v1 11/11] KVM: arm64: Tag host-VA hypercall parameters __hostva
2026-07-20 16:24 ` [PATCH v1 10/11] KVM: arm64: nVHE: Check hypercall handlers against the declared ABI Fuad Tabba
@ 2026-07-20 16:24 ` Fuad Tabba
0 siblings, 0 replies; 13+ messages in thread
From: Fuad Tabba @ 2026-07-20 16:24 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
fuad.tabba
The nVHE hypervisor takes host virtual addresses as hypercall arguments
and translates each with kern_hyp_va() before use. Nothing marks them as
host-owned, so dereferencing one untranslated at EL2 - a recurring bug
class - is invisible to the compiler.
Add a __hostva sparse address space, active only for EL2 code, and tag
the host-VA parameters in the hypercall declarations. kern_hyp_va_host()
is the only sanctioned unwrap: it translates the address, preserves the
pointee type (stripped of qualifiers, as with the percpu accessors) and
drops the tag with a __force cast, so an untranslated host VA fails
sparse. The tag flows from the shared declaration into the generated
handler and on into the donated-memory and tracing-descriptor helpers,
so a handler cannot extract a host VA without it. Host code sees plain
pointers, and the tag is checker-only: no code is generated.
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/include/asm/kvm_hcall.h | 43 ++++++++++++-------
arch/arm64/include/asm/kvm_mmu.h | 10 +++++
arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 6 ++-
arch/arm64/kvm/hyp/include/nvhe/trace.h | 5 ++-
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 57 +++++++++++++------------
arch/arm64/kvm/hyp/nvhe/pkvm.c | 11 ++---
arch/arm64/kvm/hyp/nvhe/trace.c | 4 +-
7 files changed, 82 insertions(+), 54 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
index 6aa2df90a14a4..3033a6ba1462a 100644
--- a/arch/arm64/include/asm/kvm_hcall.h
+++ b/arch/arm64/include/asm/kvm_hcall.h
@@ -27,6 +27,18 @@ struct kvm_vcpu;
struct vgic_v3_cpu_if;
struct vgic_v5_cpu_if;
+/*
+ * A host VA carried by a hypercall argument. At EL2 such a pointer must not
+ * be dereferenced until it is translated with kern_hyp_va_host(); sparse
+ * flags any use that skips the translation. The tag describes the EL2 view
+ * only: the host dereferences its own VAs freely.
+ */
+#if defined(__KVM_NVHE_HYPERVISOR__) && defined(__CHECKER__)
+#define __hostva __attribute__((noderef, address_space(__hostva)))
+#else
+#define __hostva
+#endif
+
/*
* Hypercall signatures are declared as (type, name) argument pairs.
* __KVM_HCALL_MAP() applies a macro to each pair, in the mold of __MAP()
@@ -157,24 +169,24 @@ DECLARE_KVM_HOST_HCALL0(int, __pkvm_prot_finalize)
/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
DECLARE_KVM_HOST_HCALL_VOID(__kvm_adjust_pc, 1,
- struct kvm_vcpu *, vcpu)
+ struct kvm_vcpu __hostva *, vcpu)
DECLARE_KVM_HOST_HCALL(int, __kvm_vcpu_run, 1,
- struct kvm_vcpu *, vcpu)
+ struct kvm_vcpu __hostva *, vcpu)
DECLARE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context)
DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa, 3,
- struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+ struct kvm_s2_mmu __hostva *, mmu, phys_addr_t, ipa, int, level)
DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa_nsh, 3,
- struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+ struct kvm_s2_mmu __hostva *, mmu, phys_addr_t, ipa, int, level)
DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid, 1,
- struct kvm_s2_mmu *, mmu)
+ struct kvm_s2_mmu __hostva *, mmu)
DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_range, 3,
- struct kvm_s2_mmu *, mmu, phys_addr_t, start, unsigned long, pages)
+ struct kvm_s2_mmu __hostva *, mmu, phys_addr_t, start, unsigned long, pages)
DECLARE_KVM_HOST_HCALL_VOID(__kvm_flush_cpu_context, 1,
- struct kvm_s2_mmu *, mmu)
+ struct kvm_s2_mmu __hostva *, mmu)
DECLARE_KVM_HOST_HCALL_VOID(__kvm_timer_set_cntvoff, 1,
u64, cntvoff)
DECLARE_KVM_HOST_HCALL(int, __tracing_load, 2,
- void *, desc_hva, size_t, desc_size)
+ void __hostva *, desc_hva, size_t, desc_size)
DECLARE_KVM_HOST_HCALL0_VOID(__tracing_unload)
DECLARE_KVM_HOST_HCALL(int, __tracing_enable, 1,
bool, enable)
@@ -189,13 +201,13 @@ DECLARE_KVM_HOST_HCALL(int, __tracing_enable_event, 2,
DECLARE_KVM_HOST_HCALL_VOID(__tracing_write_event, 1,
u64, id)
DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs, 1,
- struct vgic_v3_cpu_if *, cpu_if)
+ struct vgic_v3_cpu_if __hostva *, cpu_if)
DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_restore_vmcr_aprs, 1,
- struct vgic_v3_cpu_if *, cpu_if)
+ struct vgic_v3_cpu_if __hostva *, cpu_if)
DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_save_apr, 1,
- struct vgic_v5_cpu_if *, cpu_if)
+ struct vgic_v5_cpu_if __hostva *, cpu_if)
DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_restore_vmcr_apr, 1,
- struct vgic_v5_cpu_if *, cpu_if)
+ struct vgic_v5_cpu_if __hostva *, cpu_if)
/* Hypercalls that are available only when pKVM has finalised. */
DECLARE_KVM_HOST_HCALL(int, __pkvm_host_share_hyp, 1,
@@ -220,10 +232,11 @@ DECLARE_KVM_HOST_HCALL0(int, __pkvm_reserve_vm)
DECLARE_KVM_HOST_HCALL_VOID(__pkvm_unreserve_vm, 1,
pkvm_handle_t, handle)
DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vm, 3,
- struct kvm *, host_kvm, void *, vm_hva, void *, pgd_hva)
+ struct kvm __hostva *, host_kvm, void __hostva *, vm_hva,
+ void __hostva *, pgd_hva)
DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vcpu, 3,
- pkvm_handle_t, handle, struct kvm_vcpu *, host_vcpu,
- void *, vcpu_hva)
+ pkvm_handle_t, handle, struct kvm_vcpu __hostva *, host_vcpu,
+ void __hostva *, vcpu_hva)
DECLARE_KVM_HOST_HCALL0(int, __pkvm_vcpu_in_poison_fault)
DECLARE_KVM_HOST_HCALL(int, __pkvm_force_reclaim_guest_page, 1,
phys_addr_t, phys)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6eae7e7e2a684..55fac40377c03 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -7,6 +7,8 @@
#ifndef __ARM64_KVM_MMU_H__
#define __ARM64_KVM_MMU_H__
+#include <linux/compiler.h>
+
#include <asm/page.h>
#include <asm/memory.h>
#include <asm/mmu.h>
@@ -140,6 +142,14 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)
#define kern_hyp_va(v) ((typeof(v))(__kern_hyp_va((unsigned long)(v))))
+/*
+ * Translate a __hostva-tagged host VA, dropping the tag: the only sanctioned
+ * unwrap. Translation only, no ownership or bounds validation; the result
+ * carries the pointee type stripped of the tag and of any cv-qualifiers.
+ */
+#define kern_hyp_va_host(v) \
+ ((TYPEOF_UNQUAL(*(v)) *)__kern_hyp_va((unsigned long)(__force void *)(v)))
+
extern u32 __hyp_va_bits;
/*
diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
index 2643a1a819668..dcbe8b8913270 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
@@ -7,6 +7,7 @@
#ifndef __ARM64_KVM_NVHE_PKVM_H__
#define __ARM64_KVM_NVHE_PKVM_H__
+#include <asm/kvm_hcall.h>
#include <asm/kvm_pkvm.h>
#include <nvhe/gfp.h>
@@ -69,9 +70,10 @@ void pkvm_hyp_vm_table_init(void *tbl);
int __pkvm_reserve_vm(void);
void __pkvm_unreserve_vm(pkvm_handle_t handle);
-int __pkvm_init_vm(struct kvm *host_kvm, void *vm_hva, void *pgd_hva);
+int __pkvm_init_vm(struct kvm *host_kvm, void __hostva *vm_hva,
+ void __hostva *pgd_hva);
int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
- void *vcpu_hva);
+ void __hostva *vcpu_hva);
int __pkvm_reclaim_dying_guest_page(pkvm_handle_t handle, u64 gfn);
int __pkvm_start_teardown_vm(pkvm_handle_t handle);
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 4aa36fd76b9e2..58e0ad3329034 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -4,6 +4,7 @@
#include <linux/trace_remote_event.h>
+#include <asm/kvm_hcall.h>
#include <asm/kvm_hyptrace.h>
static inline pid_t __tracing_get_vcpu_pid(struct kvm_cpu_context *host_ctxt)
@@ -46,7 +47,7 @@ static inline pid_t __tracing_get_vcpu_pid(struct kvm_cpu_context *host_ctxt)
void *tracing_reserve_entry(unsigned long length);
void tracing_commit_entry(void);
-int __tracing_load(void *desc_va, size_t desc_size);
+int __tracing_load(void __hostva *desc_va, size_t desc_size);
void __tracing_unload(void);
int __tracing_enable(bool enable);
int __tracing_swap_reader(unsigned int cpu);
@@ -59,7 +60,7 @@ static inline void tracing_commit_entry(void) { }
#define HYP_EVENT(__name, __proto, __struct, __assign, __printk) \
static inline void trace_##__name(__proto) {}
-static inline int __tracing_load(void *desc_va, size_t desc_size) { return -ENODEV; }
+static inline int __tracing_load(void __hostva *desc_va, size_t desc_size) { return -ENODEV; }
static inline void __tracing_unload(void) { }
static inline int __tracing_enable(bool enable) { return -ENODEV; }
static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index f2501249f4391..679b6df9c998d 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -269,7 +269,7 @@ DEFINE_KVM_HOST_HCALL0_VOID(__pkvm_vcpu_put)
}
DEFINE_KVM_HOST_HCALL(int, __kvm_vcpu_run, 1,
- struct kvm_vcpu *, host_vcpu)
+ struct kvm_vcpu __hostva *, host_vcpu)
{
int ret;
@@ -294,7 +294,7 @@ DEFINE_KVM_HOST_HCALL(int, __kvm_vcpu_run, 1,
sync_hyp_vcpu(hyp_vcpu);
} else {
- struct kvm_vcpu *vcpu = kern_hyp_va(host_vcpu);
+ struct kvm_vcpu *vcpu = kern_hyp_va_host(host_vcpu);
/* The host is fully trusted, run its vCPU directly. */
fpsimd_lazy_switch_to_guest(vcpu);
@@ -421,9 +421,9 @@ DEFINE_KVM_HOST_HCALL(int, __pkvm_host_mkyoung_guest, 1,
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_adjust_pc, 1,
- struct kvm_vcpu *, vcpu)
+ struct kvm_vcpu __hostva *, vcpu)
{
- __kvm_adjust_pc(kern_hyp_va(vcpu));
+ __kvm_adjust_pc(kern_hyp_va_host(vcpu));
}
DEFINE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context)
@@ -432,27 +432,27 @@ DEFINE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context)
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa, 3,
- struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+ struct kvm_s2_mmu __hostva *, mmu, phys_addr_t, ipa, int, level)
{
- __kvm_tlb_flush_vmid_ipa(kern_hyp_va(mmu), ipa, level);
+ __kvm_tlb_flush_vmid_ipa(kern_hyp_va_host(mmu), ipa, level);
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa_nsh, 3,
- struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+ struct kvm_s2_mmu __hostva *, mmu, phys_addr_t, ipa, int, level)
{
- __kvm_tlb_flush_vmid_ipa_nsh(kern_hyp_va(mmu), ipa, level);
+ __kvm_tlb_flush_vmid_ipa_nsh(kern_hyp_va_host(mmu), ipa, level);
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_range, 3,
- struct kvm_s2_mmu *, mmu, phys_addr_t, start, unsigned long, pages)
+ struct kvm_s2_mmu __hostva *, mmu, phys_addr_t, start, unsigned long, pages)
{
- __kvm_tlb_flush_vmid_range(kern_hyp_va(mmu), start, pages);
+ __kvm_tlb_flush_vmid_range(kern_hyp_va_host(mmu), start, pages);
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid, 1,
- struct kvm_s2_mmu *, mmu)
+ struct kvm_s2_mmu __hostva *, mmu)
{
- __kvm_tlb_flush_vmid(kern_hyp_va(mmu));
+ __kvm_tlb_flush_vmid(kern_hyp_va_host(mmu));
}
DEFINE_KVM_HOST_HCALL_VOID(__pkvm_tlb_flush_vmid, 1,
@@ -468,9 +468,9 @@ DEFINE_KVM_HOST_HCALL_VOID(__pkvm_tlb_flush_vmid, 1,
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_flush_cpu_context, 1,
- struct kvm_s2_mmu *, mmu)
+ struct kvm_s2_mmu __hostva *, mmu)
{
- __kvm_flush_cpu_context(kern_hyp_va(mmu));
+ __kvm_flush_cpu_context(kern_hyp_va_host(mmu));
}
DEFINE_KVM_HOST_HCALL_VOID(__kvm_timer_set_cntvoff, 1,
@@ -499,15 +499,15 @@ DEFINE_KVM_HOST_HCALL0_VOID(__vgic_v3_init_lrs)
}
DEFINE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs, 1,
- struct vgic_v3_cpu_if *, cpu_if)
+ struct vgic_v3_cpu_if __hostva *, cpu_if)
{
- __vgic_v3_save_aprs(kern_hyp_va(cpu_if));
+ __vgic_v3_save_aprs(kern_hyp_va_host(cpu_if));
}
DEFINE_KVM_HOST_HCALL_VOID(__vgic_v3_restore_vmcr_aprs, 1,
- struct vgic_v3_cpu_if *, cpu_if)
+ struct vgic_v3_cpu_if __hostva *, cpu_if)
{
- __vgic_v3_restore_vmcr_aprs(kern_hyp_va(cpu_if));
+ __vgic_v3_restore_vmcr_aprs(kern_hyp_va_host(cpu_if));
}
DEFINE_KVM_HOST_HCALL(int, __pkvm_init, 4,
@@ -579,16 +579,17 @@ DEFINE_KVM_HOST_HCALL_VOID(__pkvm_unreserve_vm, 1,
}
DEFINE_KVM_HOST_HCALL(int, __pkvm_init_vm, 3,
- struct kvm *, host_kvm, void *, vm_hva, void *, pgd_hva)
+ struct kvm __hostva *, host_kvm, void __hostva *, vm_hva,
+ void __hostva *, pgd_hva)
{
- return __pkvm_init_vm(kern_hyp_va(host_kvm), vm_hva, pgd_hva);
+ return __pkvm_init_vm(kern_hyp_va_host(host_kvm), vm_hva, pgd_hva);
}
DEFINE_KVM_HOST_HCALL(int, __pkvm_init_vcpu, 3,
- pkvm_handle_t, handle, struct kvm_vcpu *, host_vcpu,
- void *, vcpu_hva)
+ pkvm_handle_t, handle, struct kvm_vcpu __hostva *, host_vcpu,
+ void __hostva *, vcpu_hva)
{
- return __pkvm_init_vcpu(handle, kern_hyp_va(host_vcpu), vcpu_hva);
+ return __pkvm_init_vcpu(handle, kern_hyp_va_host(host_vcpu), vcpu_hva);
}
DEFINE_KVM_HOST_HCALL0(int, __pkvm_vcpu_in_poison_fault)
@@ -623,7 +624,7 @@ DEFINE_KVM_HOST_HCALL(int, __pkvm_finalize_teardown_vm, 1,
}
DEFINE_KVM_HOST_HCALL(int, __tracing_load, 2,
- void *, desc_hva, size_t, desc_size)
+ void __hostva *, desc_hva, size_t, desc_size)
{
return __tracing_load(desc_hva, desc_size);
}
@@ -670,15 +671,15 @@ DEFINE_KVM_HOST_HCALL_VOID(__tracing_write_event, 1,
}
DEFINE_KVM_HOST_HCALL_VOID(__vgic_v5_save_apr, 1,
- struct vgic_v5_cpu_if *, cpu_if)
+ struct vgic_v5_cpu_if __hostva *, cpu_if)
{
- __vgic_v5_save_apr(kern_hyp_va(cpu_if));
+ __vgic_v5_save_apr(kern_hyp_va_host(cpu_if));
}
DEFINE_KVM_HOST_HCALL_VOID(__vgic_v5_restore_vmcr_apr, 1,
- struct vgic_v5_cpu_if *, cpu_if)
+ struct vgic_v5_cpu_if __hostva *, cpu_if)
{
- __vgic_v5_restore_vmcr_apr(kern_hyp_va(cpu_if));
+ __vgic_v5_restore_vmcr_apr(kern_hyp_va_host(cpu_if));
}
typedef void (*hcall_t)(struct kvm_cpu_context *);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 205c52535c887..bfc9f07f336a1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -644,9 +644,9 @@ static size_t pkvm_get_hyp_vm_size(unsigned int nr_vcpus)
size_mul(sizeof(struct pkvm_hyp_vcpu *), nr_vcpus));
}
-static void *map_donated_memory_noclear(void *host_va, size_t size)
+static void *map_donated_memory_noclear(void __hostva *host_va, size_t size)
{
- void *va = kern_hyp_va(host_va);
+ void *va = kern_hyp_va_host(host_va);
if (!PAGE_ALIGNED(va))
return NULL;
@@ -658,7 +658,7 @@ static void *map_donated_memory_noclear(void *host_va, size_t size)
return va;
}
-static void *map_donated_memory(void *host_va, size_t size)
+static void *map_donated_memory(void __hostva *host_va, size_t size)
{
void *va = map_donated_memory_noclear(host_va, size);
@@ -805,7 +805,8 @@ void teardown_selftest_vm(void)
*
* Return 0 success, negative error code on failure.
*/
-int __pkvm_init_vm(struct kvm *host_kvm, void *vm_hva, void *pgd_hva)
+int __pkvm_init_vm(struct kvm *host_kvm, void __hostva *vm_hva,
+ void __hostva *pgd_hva)
{
struct pkvm_hyp_vm *hyp_vm = NULL;
size_t vm_size, pgd_size;
@@ -896,7 +897,7 @@ static int register_hyp_vcpu(struct pkvm_hyp_vm *hyp_vm,
}
int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
- void *vcpu_hva)
+ void __hostva *vcpu_hva)
{
struct pkvm_hyp_vcpu *hyp_vcpu;
struct pkvm_hyp_vm *hyp_vm;
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index 97203ddd3cf45..5d0fcdce9507d 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -206,9 +206,9 @@ static bool hyp_trace_desc_is_valid(struct hyp_trace_desc *desc, size_t desc_siz
return true;
}
-int __tracing_load(void *desc_hva, size_t desc_size)
+int __tracing_load(void __hostva *desc_hva, size_t desc_size)
{
- struct hyp_trace_desc *desc = kern_hyp_va(desc_hva);
+ struct hyp_trace_desc *desc = kern_hyp_va_host(desc_hva);
int ret;
ret = __admit_host_mem(desc, desc_size);
--
2.39.5
^ permalink raw reply related [flat|nested] 13+ messages in thread