ANDROID: KVM: arm64: Add a range to the guest share/unshare hypercalls

Extend the guest share and unshare HVCs with a size argument. For ABI
compabitiliy with guests, a 0 range is treated as a single page, while
the range argument is advertised in the meminfo HVC.

Bug: 357781595
Bug: 243642516
Change-Id: Ic4927124282c430cf57f112eb96ea01740ff9967
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
This commit is contained in:
Vincent Donnefort
2024-02-29 18:08:06 +00:00
parent 14f9711ecc
commit cea326332b
6 changed files with 57 additions and 58 deletions
@@ -53,8 +53,10 @@ int __pkvm_host_unshare_guest(u64 gfn, struct pkvm_hyp_vm *hyp_vm);
int __pkvm_host_donate_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu);
int __pkvm_host_relax_guest_perms(u64 gfn, enum kvm_pgtable_prot prot, struct pkvm_hyp_vcpu *vcpu);
int __pkvm_host_wrprotect_guest(u64 gfn, struct pkvm_hyp_vm *hyp_vm);
int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
u64 nr_pages, u64 *nr_shared);
int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa,
u64 nr_pages, u64 *nr_unshared);
int __pkvm_install_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
int __pkvm_remove_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa);
bool __pkvm_check_ioguard_page(struct pkvm_hyp_vcpu *hyp_vcpu);
-4
View File
@@ -374,10 +374,6 @@ static void handle_pvm_exit_hvc64(struct pkvm_hyp_vcpu *hyp_vcpu)
n = 1;
break;
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:
n = 4;
break;
+8 -4
View File
@@ -1222,12 +1222,13 @@ unlock:
return ret;
}
int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *vcpu, u64 ipa)
int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *vcpu, u64 ipa, u64 nr_pages,
u64 *nr_shared)
{
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
u64 phys, nr_pages = 1;
kvm_pte_t pte;
size_t size;
u64 phys;
int ret;
host_lock_component();
@@ -1246,6 +1247,7 @@ int __pkvm_guest_share_host(struct pkvm_hyp_vcpu *vcpu, u64 ipa)
WARN_ON(__guest_initiate_page_transition(ipa, pte, nr_pages, vcpu, PKVM_PAGE_SHARED_OWNED));
WARN_ON(__host_set_page_state_range(phys, size, PKVM_PAGE_SHARED_BORROWED));
psci_mem_protect_dec(nr_pages);
*nr_shared = nr_pages;
unlock:
guest_unlock_component(vm);
@@ -1254,12 +1256,13 @@ unlock:
return ret;
}
int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *vcpu, u64 ipa)
int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *vcpu, u64 ipa, u64 nr_pages,
u64 *nr_unshared)
{
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
u64 phys, nr_pages = 1;
kvm_pte_t pte;
size_t size;
u64 phys;
int ret;
host_lock_component();
@@ -1278,6 +1281,7 @@ int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *vcpu, u64 ipa)
WARN_ON(__guest_initiate_page_transition(ipa, pte, nr_pages, vcpu, PKVM_PAGE_OWNED));
psci_mem_protect_inc(nr_pages);
WARN_ON(host_stage2_set_owner_locked(phys, size, PKVM_ID_GUEST));
*nr_unshared = nr_pages;
unlock:
guest_unlock_component(vm);
+43 -38
View File
@@ -1342,30 +1342,6 @@ static bool pkvm_handle_psci(struct pkvm_hyp_vcpu *hyp_vcpu)
return pvm_psci_not_supported(hyp_vcpu);
}
static u64 __pkvm_memshare_page_req(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa)
{
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
u64 elr;
/* Fake up a data abort (Level 3 translation fault on write) */
vcpu->arch.fault.esr_el2 = (u32)ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT |
ESR_ELx_WNR | ESR_ELx_FSC_FAULT |
FIELD_PREP(ESR_ELx_FSC_LEVEL, 3);
/* Shuffle the IPA around into the HPFAR */
vcpu->arch.fault.hpfar_el2 = (ipa >> 8) & HPFAR_MASK;
/* This is a virtual address. 0's good. Let's go with 0. */
vcpu->arch.fault.far_el2 = 0;
/* Rewind the ELR so we return to the HVC once the IPA is mapped */
elr = read_sysreg(elr_el2);
elr -= 4;
write_sysreg(elr, elr_el2);
return ARM_EXCEPTION_TRAP;
}
static int pkvm_handle_empty_memcache(struct pkvm_hyp_vcpu *hyp_vcpu,
u64 *exit_code)
{
@@ -1387,27 +1363,43 @@ static int pkvm_handle_empty_memcache(struct pkvm_hyp_vcpu *hyp_vcpu,
static bool pkvm_memshare_call(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
{
struct pkvm_hyp_vm *hyp_vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
u64 ipa = smccc_get_arg1(vcpu);
u64 arg2 = smccc_get_arg2(vcpu);
u64 nr_pages = smccc_get_arg2(vcpu);
u64 arg3 = smccc_get_arg3(vcpu);
struct kvm_hyp_req *req;
u64 nr_shared;
int err;
if (arg2 || arg3)
/* Legacy guests have arg2 set to 0 */
if (nr_pages == 0)
nr_pages = 1;
if (arg3 || !PAGE_ALIGNED(ipa))
goto out_guest_err;
err = __pkvm_guest_share_host(hyp_vcpu, ipa);
err = __pkvm_guest_share_host(hyp_vcpu, ipa, nr_pages, &nr_shared);
switch (err) {
case 0:
/* Success! Now tell the host. */
goto out_host;
atomic64_add(nr_shared * PAGE_SIZE,
&hyp_vm->host_kvm->stat.protected_shared_mem);
smccc_set_retval(vcpu, SMCCC_RET_SUCCESS, nr_shared, 0, 0);
return true;
case -EFAULT:
req = pkvm_hyp_req_reserve(hyp_vcpu, KVM_HYP_REQ_TYPE_MAP);
if (!req)
goto out_guest_err;
req->map.guest_ipa = ipa;
req->map.size = nr_pages << PAGE_SHIFT;
/*
* Convert the exception into a data abort so that the page
* being shared is mapped into the guest next time.
* We're about to go back to the host... let's not waste time
* and check for the memcache while at it.
*/
*exit_code = __pkvm_memshare_page_req(hyp_vcpu, ipa);
goto out_host;
fallthrough;
case -ENOMEM:
if (pkvm_handle_empty_memcache(hyp_vcpu, exit_code))
goto out_guest_err;
@@ -1425,20 +1417,29 @@ out_host:
static bool pkvm_memunshare_call(struct pkvm_hyp_vcpu *hyp_vcpu)
{
struct pkvm_hyp_vm *hyp_vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
u64 ipa = smccc_get_arg1(vcpu);
u64 arg2 = smccc_get_arg2(vcpu);
u64 nr_pages = smccc_get_arg2(vcpu);
u64 arg3 = smccc_get_arg3(vcpu);
u64 nr_unshared;
int err;
if (arg2 || arg3)
/* Legacy guests have arg2 set to 0 */
if (nr_pages == 0)
nr_pages = 1;
if (arg3 || !PAGE_ALIGNED(ipa))
goto out_guest_err;
err = __pkvm_guest_unshare_host(hyp_vcpu, ipa);
err = __pkvm_guest_unshare_host(hyp_vcpu, ipa, nr_pages, &nr_unshared);
if (err)
goto out_guest_err;
return false;
atomic64_add(nr_unshared * PAGE_SIZE,
&hyp_vm->host_kvm->stat.protected_shared_mem);
smccc_set_retval(vcpu, SMCCC_RET_SUCCESS, nr_unshared, 0, 0);
return true;
out_guest_err:
smccc_set_retval(vcpu, SMCCC_RET_INVALID_PARAMETER, 0, 0, 0);
@@ -1468,11 +1469,15 @@ static bool pkvm_meminfo_call(struct pkvm_hyp_vcpu *hyp_vcpu)
u64 arg1 = smccc_get_arg1(vcpu);
u64 arg2 = smccc_get_arg2(vcpu);
u64 arg3 = smccc_get_arg3(vcpu);
bool has_range;
if (arg1 || arg2 || arg3)
goto out_guest_err;
smccc_set_retval(vcpu, PAGE_SIZE, 0, 0, 0);
has_range = smccc_get_function(vcpu) == ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID;
smccc_set_retval(vcpu, PAGE_SIZE,
has_range ? KVM_FUNC_HAS_RANGE : 0, 0, 0);
return true;
out_guest_err:
-10
View File
@@ -382,16 +382,6 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
pkvm_host_reclaim_page(vcpu->kvm, smccc_get_arg1(vcpu));
val[0] = SMCCC_RET_SUCCESS;
break;
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID:
case ARM_SMCCC_VENDOR_HYP_KVM_MEM_UNSHARE_FUNC_ID:
if (!kvm_vm_is_protected(vcpu->kvm))
break;
atomic64_add(
func_id == ARM_SMCCC_VENDOR_HYP_KVM_MEM_SHARE_FUNC_ID ?
PAGE_SIZE : -PAGE_SIZE,
&vcpu->kvm->stat.protected_shared_mem);
val[0] = SMCCC_RET_SUCCESS;
break;
case ARM_SMCCC_TRNG_VERSION:
case ARM_SMCCC_TRNG_FEATURES:
case ARM_SMCCC_TRNG_GET_UUID:
+2
View File
@@ -182,6 +182,8 @@
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
#define ARM_SMCCC_KVM_NUM_FUNCS 128
#define KVM_FUNC_HAS_RANGE BIT(0)
#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \