From: Kameron Carr <[email protected]> Sent: Tuesday, June 9, 
2026 11:10 AM
> 
> Modify the five hypercall wrapper functions to check is_realm_world()
> and use the per-CPU rsi_host_call structure when inside a Realm.
> 
> Signed-off-by: Kameron Carr <[email protected]>
> ---
>  arch/arm64/hyperv/hv_core.c | 175 +++++++++++++++++++++++++++++-------
>  1 file changed, 141 insertions(+), 34 deletions(-)
> 
> diff --git a/arch/arm64/hyperv/hv_core.c b/arch/arm64/hyperv/hv_core.c
> index e33a9e3c366a1..1759998ef2667 100644
> --- a/arch/arm64/hyperv/hv_core.c
> +++ b/arch/arm64/hyperv/hv_core.c
> @@ -16,6 +16,7 @@
>  #include <asm-generic/bug.h>
>  #include <hyperv/hvhdk.h>
>  #include <asm/mshyperv.h>
> +#include <asm/rsi.h>
> 
>  /*
>   * hv_do_hypercall- Invoke the specified hypercall
> @@ -25,12 +26,32 @@ u64 hv_do_hypercall(u64 control, void *input, void 
> *output)
>       struct arm_smccc_res    res;
>       u64                     input_address;
>       u64                     output_address;
> +     struct rsi_host_call *hostcall;
> +     unsigned long flags;
> +     u64 ret;
> 
>       input_address = input ? virt_to_phys(input) : 0;
>       output_address = output ? virt_to_phys(output) : 0;
> 
> -     arm_smccc_1_1_hvc(HV_FUNC_ID, control,
> -                       input_address, output_address, &res);
> +     if (is_realm_world()) {
> +             local_irq_save(flags);
> +             hostcall = *this_cpu_ptr(hyperv_pcpu_hostcall_struct);
> +             memset(hostcall, 0, sizeof(*hostcall));
> +             hostcall->gprs[0] = HV_FUNC_ID;
> +             hostcall->gprs[1] = control;
> +             hostcall->gprs[2] = input_address;
> +             hostcall->gprs[3] = output_address;
> +
> +             if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS)
> +                     ret = hostcall->gprs[0];
> +             else
> +                     ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
> +             local_irq_restore(flags);
> +             return ret;

This code sequence for handling the realm case is almost exactly
duplicated for the three hypercall variants. The only difference is
how gprs[2] and gprs[3] are populated. So I think the code
sequence could go into a helper routine with the appropriate
values for gprs[2] and gprs[3] passed in. 

> +     }
> +
> +     arm_smccc_1_1_hvc(HV_FUNC_ID, control, input_address,
> +                       output_address, &res);
>       return res.a0;
>  }
>  EXPORT_SYMBOL_GPL(hv_do_hypercall);
> @@ -45,9 +66,28 @@ u64 hv_do_fast_hypercall8(u16 code, u64 input)
>  {
>       struct arm_smccc_res    res;
>       u64                     control;
> +     struct rsi_host_call *hostcall;
> +     unsigned long flags;
> +     u64 ret;
> 
>       control = (u64)code | HV_HYPERCALL_FAST_BIT;
> 
> +     if (is_realm_world()) {
> +             local_irq_save(flags);
> +             hostcall = *this_cpu_ptr(hyperv_pcpu_hostcall_struct);
> +             memset(hostcall, 0, sizeof(*hostcall));
> +             hostcall->gprs[0] = HV_FUNC_ID;
> +             hostcall->gprs[1] = control;
> +             hostcall->gprs[2] = input;
> +
> +             if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS)
> +                     ret = hostcall->gprs[0];
> +             else
> +                     ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
> +             local_irq_restore(flags);
> +             return ret;
> +     }
> +
>       arm_smccc_1_1_hvc(HV_FUNC_ID, control, input, &res);
>       return res.a0;
>  }
> @@ -62,9 +102,29 @@ u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 
> input2)
>  {
>       struct arm_smccc_res    res;
>       u64                     control;
> +     struct rsi_host_call *hostcall;
> +     unsigned long flags;
> +     u64 ret;
> 
>       control = (u64)code | HV_HYPERCALL_FAST_BIT;
> 
> +     if (is_realm_world()) {
> +             local_irq_save(flags);
> +             hostcall = *this_cpu_ptr(hyperv_pcpu_hostcall_struct);
> +             memset(hostcall, 0, sizeof(*hostcall));
> +             hostcall->gprs[0] = HV_FUNC_ID;
> +             hostcall->gprs[1] = control;
> +             hostcall->gprs[2] = input1;
> +             hostcall->gprs[3] = input2;
> +
> +             if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS)
> +                     ret = hostcall->gprs[0];
> +             else
> +                     ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
> +             local_irq_restore(flags);
> +             return ret;
> +     }
> +
>       arm_smccc_1_1_hvc(HV_FUNC_ID, control, input1, input2, &res);
>       return res.a0;
>  }
> @@ -76,24 +136,44 @@ EXPORT_SYMBOL_GPL(hv_do_fast_hypercall16);
>  void hv_set_vpreg(u32 msr, u64 value)
>  {
>       struct arm_smccc_res res;
> +     struct rsi_host_call *hostcall;
> +     unsigned long flags;
> +     u64 status;
> +
> +     if (is_realm_world()) {
> +             local_irq_save(flags);
> +             hostcall = *this_cpu_ptr(hyperv_pcpu_hostcall_struct);
> +             memset(hostcall, 0, sizeof(*hostcall));
> +             hostcall->gprs[0] = HV_FUNC_ID;
> +             hostcall->gprs[1] = HVCALL_SET_VP_REGISTERS |
> +                                 HV_HYPERCALL_FAST_BIT |
> +                                 HV_HYPERCALL_REP_COMP_1;
> +             hostcall->gprs[2] = HV_PARTITION_ID_SELF;
> +             hostcall->gprs[3] = HV_VP_INDEX_SELF;
> +             hostcall->gprs[4] = msr;
> +             hostcall->gprs[6] = value;
> 
> -     arm_smccc_1_1_hvc(HV_FUNC_ID,
> -             HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
> -                     HV_HYPERCALL_REP_COMP_1,
> -             HV_PARTITION_ID_SELF,
> -             HV_VP_INDEX_SELF,
> -             msr,
> -             0,
> -             value,
> -             0,
> -             &res);
> +             if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS)
> +                     status = hostcall->gprs[0];
> +             else
> +                     status = HV_STATUS_INVALID_HYPERCALL_INPUT;
> +             local_irq_restore(flags);
> +     } else {
> +             arm_smccc_1_1_hvc(HV_FUNC_ID,
> +                               HVCALL_SET_VP_REGISTERS |
> +                                       HV_HYPERCALL_FAST_BIT |
> +                                       HV_HYPERCALL_REP_COMP_1,
> +                               HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr,
> +                               0, value, 0, &res);
> +             status = res.a0;
> +     }
> 
>       /*
> -      * Something is fundamentally broken in the hypervisor if
> -      * setting a VP register fails. There's really no way to
> -      * continue as a guest VM, so panic.
> +      * Something is fundamentally broken in the hypervisor (or, in a
> +      * Realm, the RMM denied the host call) if setting a VP register
> +      * fails. There's really no way to continue as a guest VM, so panic.
>        */
> -     BUG_ON(!hv_result_success(res.a0));
> +     BUG_ON(!hv_result_success(status));
>  }
>  EXPORT_SYMBOL_GPL(hv_set_vpreg);
> 
> @@ -108,29 +188,56 @@ void hv_get_vpreg_128(u32 msr, struct
> hv_get_vp_registers_output *result)
>  {
>       struct arm_smccc_1_2_regs args;
>       struct arm_smccc_1_2_regs res;
> +     struct rsi_host_call *hostcall;
> +     u64 status;
> 
> -     args.a0 = HV_FUNC_ID;
> -     args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
> -                     HV_HYPERCALL_REP_COMP_1;
> -     args.a2 = HV_PARTITION_ID_SELF;
> -     args.a3 = HV_VP_INDEX_SELF;
> -     args.a4 = msr;
> +     if (is_realm_world()) {
> +             unsigned long flags;
> 
> -     /*
> -      * Use the SMCCC 1.2 interface because the results are in registers
> -      * beyond X0-X3.
> -      */
> -     arm_smccc_1_2_hvc(&args, &res);
> +             local_irq_save(flags);
> +             hostcall = *this_cpu_ptr(hyperv_pcpu_hostcall_struct);
> +             memset(hostcall, 0, sizeof(*hostcall));
> +
> +             hostcall->gprs[0] = HV_FUNC_ID;
> +             hostcall->gprs[1] = HVCALL_GET_VP_REGISTERS |
> +                                 HV_HYPERCALL_FAST_BIT |
> +                                 HV_HYPERCALL_REP_COMP_1;
> +             hostcall->gprs[2] = HV_PARTITION_ID_SELF;
> +             hostcall->gprs[3] = HV_VP_INDEX_SELF;
> +             hostcall->gprs[4] = msr;
> +
> +             if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS) {
> +                     status = hostcall->gprs[0];
> +                     result->as64.low = hostcall->gprs[6];
> +                     result->as64.high = hostcall->gprs[7];
> +             } else {
> +                     status = HV_STATUS_INVALID_HYPERCALL_INPUT;
> +             }
> +             local_irq_restore(flags);
> +     } else {
> +             args.a0 = HV_FUNC_ID;
> +             args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
> +                       HV_HYPERCALL_REP_COMP_1;
> +             args.a2 = HV_PARTITION_ID_SELF;
> +             args.a3 = HV_VP_INDEX_SELF;
> +             args.a4 = msr;
> +
> +             /*
> +              * Use the SMCCC 1.2 interface because the results are in
> +              * registers beyond X0-X3.
> +              */
> +             arm_smccc_1_2_hvc(&args, &res);
> +             status = res.a0;
> +             result->as64.low = res.a6;
> +             result->as64.high = res.a7;
> +     }
> 
>       /*
> -      * Something is fundamentally broken in the hypervisor if
> -      * getting a VP register fails. There's really no way to
> -      * continue as a guest VM, so panic.
> +      * Something is fundamentally broken in the hypervisor (or, in a
> +      * Realm, the RMM denied the host call) if getting a VP register
> +      * fails. There's really no way to continue as a guest VM, so panic.
>        */
> -     BUG_ON(!hv_result_success(res.a0));
> -
> -     result->as64.low = res.a6;
> -     result->as64.high = res.a7;
> +     BUG_ON(!hv_result_success(status));
>  }
>  EXPORT_SYMBOL_GPL(hv_get_vpreg_128);
> 
> --
> 2.45.4
> 


Reply via email to