[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