[PATCH v2 07/18] KVM: arm64: Add pkvm_hyp_req infrastructure
Fuad Tabba
fuad.tabba at linux.dev
Tue Jul 14 12:45:00 PDT 2026
On Mon, 6 Jul 2026 at 18:54, Vincent Donnefort <vdonnefort at google.com> wrote:
>
> Introduce a struct pkvm_hyp_req to enable the pKVM hypervisor to request
> resources from the host.
>
> Provide serialisation helpers to transport these requests via SMCCC
> registers (starting from a2):
>
> pkvm_hyp_req_to_smccc() to encode into the SMCCC args.
> smccc_to_pkvm_hyp_req() to decode them.
>
> When the hypervisor raises a request, the host must handle it and retry
> the HVC. To automate this sequence, introduce the pkvm_call_hyp_req()
> macro. This intercepts pending requests, invokes the handler and retries
> the HVC.
>
> Additionally, introduce a trace event to track the handling of these
> requests.
>
> Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
Reviewed-by: Fuad Tabba <fuad.tabba at linux.dev>
Cheers,
/fuad
>
> diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
> index 870f7870bb62..0be1469e7874 100644
> --- a/arch/arm64/include/asm/kvm_pkvm.h
> +++ b/arch/arm64/include/asm/kvm_pkvm.h
> @@ -203,6 +203,95 @@ struct pkvm_mapping {
> u64 __subtree_last; /* Internal member for interval tree */
> };
>
> +enum pkvm_hyp_req_type {
> + PKVM_HYP_NO_REQ = 0,
> + __PKVM_HYP_REQ_TYPE_MAX,
> +};
> +
> +#define PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX \
> + (sizeof(struct arm_smccc_res) - offsetof(struct arm_smccc_res, a2) - 1)
> +
> +struct pkvm_hyp_req {
> + u8 type;
> + union {
> + struct {
> + u32 nr_pages;
> + } mem;
> + struct {
> + /* Helper for SMCCC encoding/decoding */
> + u8 args[PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX];
> + } args;
> + };
> +};
> +
> +static inline size_t pkvm_hyp_req_arg_size(u8 type)
> +{
> + switch (type) {
> + case PKVM_HYP_NO_REQ:
> + return 0;
> + default:
> + WARN_ON(1);
> + }
> +
> + return 0;
> +}
> +
> +/* Encode the pending pkvm_hyp_req type into the SMCCC args */
> +static inline void
> +pkvm_hyp_req_to_smccc(struct kvm_cpu_context *host_ctxt, struct pkvm_hyp_req *req)
> +{
> + u8 *dst, type = req->type;
> + size_t size;
> +
> + if (type == PKVM_HYP_NO_REQ || type >= __PKVM_HYP_REQ_TYPE_MAX) {
> + host_ctxt->regs.regs[2] = 0;
> + return;
> + }
> +
> + size = pkvm_hyp_req_arg_size(type);
> + if (WARN_ON(size > PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX))
> + return;
> +
> + dst = (u8 *)&host_ctxt->regs.regs[2];
> + *dst = type;
> +
> + memcpy(dst + 1, &req->args, size);
> +}
> +
> +/* Return true if a pkvm_hyp_req has been decoded from the SMCCC args */
> +static inline bool smccc_to_pkvm_hyp_req(struct pkvm_hyp_req *req, struct arm_smccc_res *res)
> +{
> + u8 *src = (u8 *)res + offsetof(struct arm_smccc_res, a2);
> + u8 type = *src;
> +
> + if (type == PKVM_HYP_NO_REQ || type >= __PKVM_HYP_REQ_TYPE_MAX)
> + return false;
> +
> + req->type = type;
> + memcpy(&req->args, src + 1, pkvm_hyp_req_arg_size(type));
> +
> + return true;
> +}
> +
> +int __pkvm_handle_smccc_req(struct arm_smccc_res *res);
> +
> +#define pkvm_call_hyp_req(f, ...) \
> +({ \
> + struct arm_smccc_res __res; \
> + int __ret; \
> + do { \
> + __ret = -1; \
> + arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f), ##__VA_ARGS__, &__res); \
> + if (WARN_ON(__res.a0 != SMCCC_RET_SUCCESS)) \
> + break; \
> + __ret = __res.a1; \
> + if (!__ret) \
> + break; \
> + __ret = __pkvm_handle_smccc_req(&__res); \
> + } while (!__ret); \
> + __ret; \
> +})
> +
> int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
> struct kvm_pgtable_mm_ops *mm_ops);
> void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> index e2c8714e8ccc..5ba8b81b8c6c 100644
> --- a/arch/arm64/kvm/pkvm.c
> +++ b/arch/arm64/kvm/pkvm.c
> @@ -16,6 +16,9 @@
>
> #include "hyp_constants.h"
>
> +#define CREATE_TRACE_POINTS
> +#include "trace_pkvm.h"
> +
> DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
>
> static struct memblock_region *hyp_memory = kvm_nvhe_sym(hyp_memory);
> @@ -617,3 +620,25 @@ bool pkvm_force_reclaim_guest_page(phys_addr_t phys)
>
> return !ret || ret == -EAGAIN;
> }
> +
> +static int pkvm_handle_hyp_req(struct pkvm_hyp_req *req)
> +{
> + int ret = -EINVAL;
> +
> + switch (req->type) {
> + }
> +
> + trace_kvm_handle_pkvm_hyp_req(req, ret);
> +
> + return ret;
> +}
> +
> +int __pkvm_handle_smccc_req(struct arm_smccc_res *res)
> +{
> + struct pkvm_hyp_req req;
> +
> + if (smccc_to_pkvm_hyp_req(&req, res))
> + return pkvm_handle_hyp_req(&req);
> +
> + return res->a1;
> +}
> diff --git a/arch/arm64/kvm/trace_pkvm.h b/arch/arm64/kvm/trace_pkvm.h
> new file mode 100644
> index 000000000000..4bf57c12e7de
> --- /dev/null
> +++ b/arch/arm64/kvm/trace_pkvm.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#if !defined(_TRACE_PKVM_ARM64_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
> +#define _TRACE_PKVM_ARM64_KVM_H
> +
> +#include <linux/tracepoint.h>
> +#include <asm/kvm_pkvm.h>
> +
> +#undef TRACE_SYSTEM
> +#define TRACE_SYSTEM kvm
> +
> +TRACE_EVENT(kvm_handle_pkvm_hyp_req,
> + TP_PROTO(struct pkvm_hyp_req *req, int ret),
> + TP_ARGS(req, ret),
> +
> + TP_STRUCT__entry(
> + __field(u8, type)
> + __field(int, ret)
> + ),
> +
> + TP_fast_assign(
> + __entry->type = req->type;
> + __entry->ret = ret;
> + ),
> +
> + TP_printk("type: %u ret: %d",
> + __entry->type, __entry->ret)
> +);
> +
> +#endif /* _TRACE_PKVM_ARM64_KVM_H */
> +
> +#undef TRACE_INCLUDE_PATH
> +#define TRACE_INCLUDE_PATH .
> +#undef TRACE_INCLUDE_FILE
> +#define TRACE_INCLUDE_FILE trace_pkvm
> +
> +/* This part must be outside protection */
> +#include <trace/define_trace.h>
> --
> 2.55.0.rc2.803.g1fd1e6609c-goog
>
More information about the linux-arm-kernel
mailing list