[PATCH 08/17] KVM: arm64: Implement HVC handling for protected guests at EL2

Fuad Tabba fuad.tabba at linux.dev
Thu Sep 3 09:25:28 PDT 2026


On Thu, 3 Sept 2026 at 16:13, Joey Gouly <joey.gouly at arm.com> wrote:
>
> On Mon, Aug 31, 2026 at 05:34:12PM +0100, Fuad Tabba wrote:
> > Extend kvm_handle_pvm_hvc64() to handle SMCCC_VERSION,
> > SMCCC_ARCH_FEATURES and the vendor hypervisor call UID at EL2, so
> > these queries do not reach the host. ARCH_FEATURES is mandatory from
> > SMCCC 1.1, the version EL2 reports: it returns SUCCESS for itself and
> > for SMCCC_VERSION, and NOT_SUPPORTED for anything else.
> >
> > Add handle_pvm_entry_hvc64() and handle_pvm_exit_hvc64(), which
> > forward a protected guest's HVCs to the host and return the reply; a
> > later patch wires them into the per-EC dispatch tables.
>
> These two functions are unused in this commit, and are modified in the
> next commit, while still being unused. Then handle_pvm_entry_hvc64()
> becomes a wrapper for handle_pvm_entry_psci() (which was the whole body
> of handle_pvm_entry_hvc64). It's quite hard to follow. If these
> functions are really unused and then modified, maybe it's just better to
> remove them from this commit?

Both move to the patch that first calls them, so each appears once, in
its final form, beside its caller.

The wrapper should go with it: handle_pvm_entry_hvc64() only calls
handle_pvm_entry_psci(), and PSCI calls are the only HVCs forwarded to
the host, so the split has no non-PSCI case to handle.

Thanks for the reviews!
/fuad

>
> Thanks,
> Joey
>
> >
> > Signed-off-by: Fuad Tabba <fuad.tabba at linux.dev>
> > ---
> >  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 28 ++++++++++++++++++++++++++++
> >  arch/arm64/kvm/hyp/nvhe/pkvm.c     | 29 +++++++++++++++++++++++++++++
> >  2 files changed, 57 insertions(+)
> >
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index d4b0f69ff130c..62864db1e099a 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -4,6 +4,8 @@
> >   * Author: Andrew Scull <ascull at google.com>
> >   */
> >
> > +#include <kvm/arm_hypercalls.h>
> > +
> >  #include <hyp/adjust_pc.h>
> >  #include <hyp/switch.h>
> >
> > @@ -33,6 +35,32 @@ void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
> >
> >  typedef void (*hyp_entry_exit_handler_fn)(struct pkvm_hyp_vcpu *);
> >
> > +static void __maybe_unused handle_pvm_entry_hvc64(struct pkvm_hyp_vcpu *hyp_vcpu)
> > +{
> > +     int i;
> > +
> > +     for (i = 0; i < 4; i++) {
> > +             u64 ret =
> > +                     READ_ONCE(hyp_vcpu->host_vcpu->arch.ctxt.regs.regs[i]);
> > +             vcpu_set_reg(&hyp_vcpu->vcpu, i, ret);
> > +     }
> > +}
> > +
> > +static void __maybe_unused handle_pvm_exit_hvc64(struct pkvm_hyp_vcpu *hyp_vcpu)
> > +{
> > +     struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
> > +     int i;
> > +
> > +     WRITE_ONCE(host_vcpu->arch.fault.esr_el2,
> > +                hyp_vcpu->vcpu.arch.fault.esr_el2);
> > +
> > +     /* Pass the HVC function id (r0) and its arguments. */
> > +     for (i = 0; i < 8; i++) {
> > +             WRITE_ONCE(host_vcpu->arch.ctxt.regs.regs[i],
> > +                        vcpu_get_reg(&hyp_vcpu->vcpu, i));
> > +     }
> > +}
> > +
> >  static void handle_vm_entry_generic(struct pkvm_hyp_vcpu *hyp_vcpu)
> >  {
> >       vcpu_copy_flag(&hyp_vcpu->vcpu, hyp_vcpu->host_vcpu, PC_UPDATE_REQ);
> > diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> > index af334318d0a03..0fe11f95e2e26 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> > @@ -1144,8 +1144,37 @@ bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code)
> >  {
> >       u64 val[4] = { SMCCC_RET_INVALID_PARAMETER };
> >       bool handled = true;
> > +     u32 feature;
> > +     uuid_t uuid;
> >
> >       switch (smccc_get_function(vcpu)) {
> > +     case ARM_SMCCC_VERSION_FUNC_ID:
> > +             /* Nothing to be handled by the host. Go back to the guest. */
> > +             val[0] = ARM_SMCCC_VERSION_1_1;
> > +             val[1] = 0;
> > +             val[2] = 0;
> > +             val[3] = 0;
> > +             break;
> > +     case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +             /* SUCCESS only for the architecture calls EL2 implements. */
> > +             feature = smccc_get_arg1(vcpu);
> > +             switch (feature) {
> > +             case ARM_SMCCC_VERSION_FUNC_ID:
> > +             case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> > +                     val[0] = SMCCC_RET_SUCCESS;
> > +                     break;
> > +             default:
> > +                     val[0] = SMCCC_RET_NOT_SUPPORTED;
> > +                     break;
> > +             }
> > +             break;
> > +     case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
> > +             uuid = ARM_SMCCC_VENDOR_HYP_UID_KVM;
> > +             val[0] = smccc_uuid_to_reg(&uuid, 0);
> > +             val[1] = smccc_uuid_to_reg(&uuid, 1);
> > +             val[2] = smccc_uuid_to_reg(&uuid, 2);
> > +             val[3] = smccc_uuid_to_reg(&uuid, 3);
> > +             break;
> >       case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
> >               val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
> >               val[0] |= BIT(ARM_SMCCC_KVM_FUNC_HYP_MEMINFO);
> > --
> > 2.39.5
> >



More information about the linux-arm-kernel mailing list