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; + } + + 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

