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

Joey Gouly joey.gouly at arm.com
Thu Sep 3 08:12:55 PDT 2026


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?

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