@@ -79,16 +79,32 @@ static void handle_pvm_entry_psci(struct pkvm_hyp_vcpu *hyp_vcpu)
static void handle_pvm_entry_hvc64(struct pkvm_hyp_vcpu *hyp_vcpu)
{
- u32 fn = smccc_get_function(&hyp_vcpu->vcpu);
+ struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
+ u32 fn = smccc_get_function(vcpu);
switch (fn) {
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID:
fallthrough;
- case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID:
- fallthrough;
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID:
- vcpu_set_reg(&hyp_vcpu->vcpu, 0, SMCCC_RET_SUCCESS);
+ vcpu_set_reg(vcpu, 0, SMCCC_RET_SUCCESS);
+ break;
+ case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID:
+ {
+ /*
+ * Get the host vcpu view of whether the unshare is successful.
+ * If the host wasn't able to unmap it first, hyp cannot unshare
+ * it as the host would have a mapping to a private guest page.
+ */
+ int smccc_ret = vcpu_get_reg(hyp_vcpu->host_vcpu, 0);
+ u64 ipa = smccc_get_arg1(vcpu);
+
+ if (smccc_ret != SMCCC_RET_SUCCESS ||
+ __pkvm_guest_unshare_host(hyp_vcpu, ipa))
+ smccc_set_retval(vcpu, SMCCC_RET_INVALID_PARAMETER, 0, 0, 0);
+ else
+ smccc_set_retval(vcpu, SMCCC_RET_SUCCESS, 0, 0, 0);
break;
+ }
default:
handle_pvm_entry_psci(hyp_vcpu);
break;
@@ -1236,26 +1236,19 @@ static bool pkvm_memshare_call(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
return false;
}
-static bool pkvm_memunshare_call(struct pkvm_hyp_vcpu *hyp_vcpu)
+static bool pkvm_memunshare_check(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
- u64 ipa = smccc_get_arg1(vcpu);
+ u64 arg1 = smccc_get_arg1(vcpu);
u64 arg2 = smccc_get_arg2(vcpu);
u64 arg3 = smccc_get_arg3(vcpu);
- int err;
-
- if (arg2 || arg3)
- goto out_guest_err;
- err = __pkvm_guest_unshare_host(hyp_vcpu, ipa);
- if (err)
- goto out_guest_err;
+ if (!arg1 || arg2 || arg3) {
+ smccc_set_retval(vcpu, SMCCC_RET_INVALID_PARAMETER, 0, 0, 0);
+ return true;
+ }
return false;
-
-out_guest_err:
- smccc_set_retval(vcpu, SMCCC_RET_INVALID_PARAMETER, 0, 0, 0);
- return true;
}
static bool pkvm_meminfo_call(struct pkvm_hyp_vcpu *hyp_vcpu)
@@ -1343,7 +1336,8 @@ bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code)
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID:
return pkvm_memshare_call(hyp_vcpu, exit_code);
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID:
- return pkvm_memunshare_call(hyp_vcpu);
+ /* Handle unshare on guest return because it could be denied by the host. */
+ return pkvm_memunshare_check(hyp_vcpu);
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID:
return pkvm_memrelinquish_call(hyp_vcpu);
default:
Host might not be able to unmap memory that's unshared with it. If that happens, the host will deny the unshare, and the guest will be notified of its failure when returning from its unshare call. Signed-off-by: Fuad Tabba <tabba@google.com> --- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 24 ++++++++++++++++++++---- arch/arm64/kvm/hyp/nvhe/pkvm.c | 22 ++++++++-------------- 2 files changed, 28 insertions(+), 18 deletions(-)