mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
ANDROID: KVM: arm64: Donate pages to protected guests
Now that we have all the infrastructure in place to allow guest-to-host sharing of pages in protected mode, let's stop sharing the pages from the host on guest memory aborts and switch to a proper donation instead. Signed-off-by Quentin Perret <qperret@google.com> Bug: 209580772 Change-Id: Ib37625172e24950cd74913a20bff8ce29a72f45b Signed-off-by: Will Deacon <willdeacon@google.com>
This commit is contained in:
committed by
Will Deacon
parent
0b7e337baf
commit
f85c26161b
@@ -64,7 +64,7 @@ enum __kvm_host_smccc_func {
|
||||
/* Hypercalls available after pKVM finalisation */
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_host_unshare_hyp,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_host_share_guest,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_host_donate_guest,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_vcpu_run,
|
||||
__KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,
|
||||
|
||||
@@ -63,6 +63,7 @@ int __pkvm_host_unshare_hyp(u64 pfn);
|
||||
int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages);
|
||||
int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages);
|
||||
int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct kvm_vcpu *vcpu);
|
||||
int __pkvm_host_donate_guest(u64 pfn, u64 gfn, struct kvm_vcpu *vcpu);
|
||||
int __pkvm_guest_share_host(struct kvm_vcpu *vcpu, u64 ipa);
|
||||
int __pkvm_guest_unshare_host(struct kvm_vcpu *vcpu, u64 ipa);
|
||||
|
||||
|
||||
@@ -594,7 +594,7 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
|
||||
cpu_reg(host_ctxt, 1) = ret;
|
||||
}
|
||||
|
||||
static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
|
||||
static void handle___pkvm_host_donate_guest(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
DECLARE_REG(u64, pfn, host_ctxt, 1);
|
||||
DECLARE_REG(u64, gfn, host_ctxt, 2);
|
||||
@@ -616,7 +616,7 @@ static void handle___pkvm_host_share_guest(struct kvm_cpu_context *host_ctxt)
|
||||
ret = refill_memcache(&state->vcpu->arch.pkvm_memcache, nr_pages,
|
||||
&vcpu->arch.pkvm_memcache);
|
||||
if (!ret)
|
||||
ret = __pkvm_host_share_guest(pfn, gfn, state->vcpu);
|
||||
ret = __pkvm_host_donate_guest(pfn, gfn, state->vcpu);
|
||||
out:
|
||||
cpu_reg(host_ctxt, 1) = ret;
|
||||
}
|
||||
@@ -860,7 +860,7 @@ static const hcall_t host_hcall[] = {
|
||||
|
||||
HANDLE_FUNC(__pkvm_host_share_hyp),
|
||||
HANDLE_FUNC(__pkvm_host_unshare_hyp),
|
||||
HANDLE_FUNC(__pkvm_host_share_guest),
|
||||
HANDLE_FUNC(__pkvm_host_donate_guest),
|
||||
HANDLE_FUNC(__kvm_adjust_pc),
|
||||
HANDLE_FUNC(__kvm_vcpu_run),
|
||||
HANDLE_FUNC(__kvm_flush_vm_context),
|
||||
|
||||
@@ -1034,6 +1034,14 @@ static int guest_ack_share(u64 addr, const struct pkvm_mem_transition *tx,
|
||||
size, PKVM_NOPAGE);
|
||||
}
|
||||
|
||||
static int guest_ack_donation(u64 addr, const struct pkvm_mem_transition *tx)
|
||||
{
|
||||
u64 size = tx->nr_pages * PAGE_SIZE;
|
||||
|
||||
return __guest_check_page_state_range(tx->completer.guest.vcpu, addr,
|
||||
size, PKVM_NOPAGE);
|
||||
}
|
||||
|
||||
static int guest_complete_share(u64 addr, const struct pkvm_mem_transition *tx,
|
||||
enum kvm_pgtable_prot perms)
|
||||
{
|
||||
@@ -1047,6 +1055,17 @@ static int guest_complete_share(u64 addr, const struct pkvm_mem_transition *tx,
|
||||
prot, &vcpu->arch.pkvm_memcache);
|
||||
}
|
||||
|
||||
static int guest_complete_donation(u64 addr, const struct pkvm_mem_transition *tx)
|
||||
{
|
||||
enum kvm_pgtable_prot prot = pkvm_mkstate(KVM_PGTABLE_PROT_RWX, PKVM_PAGE_OWNED);
|
||||
struct kvm_vcpu *vcpu = tx->completer.guest.vcpu;
|
||||
struct kvm_shadow_vm *vm = vcpu->arch.pkvm.shadow_vm;
|
||||
u64 size = tx->nr_pages * PAGE_SIZE;
|
||||
|
||||
return kvm_pgtable_stage2_map(&vm->pgt, addr, size, tx->completer.guest.phys,
|
||||
prot, &vcpu->arch.pkvm_memcache);
|
||||
}
|
||||
|
||||
static int __guest_get_completer_addr(u64 *completer_addr, phys_addr_t phys,
|
||||
const struct pkvm_mem_transition *tx)
|
||||
{
|
||||
@@ -1372,6 +1391,9 @@ static int check_donation(struct pkvm_mem_donation *donation)
|
||||
case PKVM_ID_HYP:
|
||||
ret = hyp_ack_donation(completer_addr, tx);
|
||||
break;
|
||||
case PKVM_ID_GUEST:
|
||||
ret = guest_ack_donation(completer_addr, tx);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@@ -1406,6 +1428,9 @@ static int __do_donate(struct pkvm_mem_donation *donation)
|
||||
case PKVM_ID_HYP:
|
||||
ret = hyp_complete_donation(completer_addr, tx);
|
||||
break;
|
||||
case PKVM_ID_GUEST:
|
||||
ret = guest_complete_donation(completer_addr, tx);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@@ -1706,3 +1731,39 @@ int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct kvm_vcpu *vcpu)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __pkvm_host_donate_guest(u64 pfn, u64 gfn, struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
u64 host_addr = hyp_pfn_to_phys(pfn);
|
||||
u64 guest_addr = hyp_pfn_to_phys(gfn);
|
||||
struct pkvm_mem_donation donation = {
|
||||
.tx = {
|
||||
.nr_pages = 1,
|
||||
.initiator = {
|
||||
.id = PKVM_ID_HOST,
|
||||
.addr = host_addr,
|
||||
.host = {
|
||||
.completer_addr = guest_addr,
|
||||
},
|
||||
},
|
||||
.completer = {
|
||||
.id = PKVM_ID_GUEST,
|
||||
.guest = {
|
||||
.vcpu = vcpu,
|
||||
.phys = host_addr,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
host_lock_component();
|
||||
guest_lock_component(vcpu);
|
||||
|
||||
ret = do_donate(&donation);
|
||||
|
||||
guest_unlock_component(vcpu);
|
||||
host_unlock_component();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1125,17 +1125,17 @@ static int sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pkvm_host_share_guest(u64 pfn, u64 gfn, struct kvm_vcpu *vcpu)
|
||||
static int pkvm_host_donate_guest(u64 pfn, u64 gfn, struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
|
||||
arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__pkvm_host_share_guest),
|
||||
arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__pkvm_host_donate_guest),
|
||||
pfn, gfn, vcpu, &res);
|
||||
WARN_ON(res.a0 != SMCCC_RET_SUCCESS);
|
||||
|
||||
/*
|
||||
* Getting -EPERM at this point implies that the pfn has already been
|
||||
* shared. This should only ever happen when two vCPUs faulted on the
|
||||
* donated. This should only ever happen when two vCPUs faulted on the
|
||||
* same page, and the current one lost the race to do the donation.
|
||||
*/
|
||||
return (res.a1 == -EPERM) ? -EAGAIN : res.a1;
|
||||
@@ -1182,7 +1182,7 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
}
|
||||
|
||||
pfn = page_to_pfn(page);
|
||||
ret = pkvm_host_share_guest(pfn, fault_ipa >> PAGE_SHIFT, vcpu);
|
||||
ret = pkvm_host_donate_guest(pfn, fault_ipa >> PAGE_SHIFT, vcpu);
|
||||
if (ret) {
|
||||
if (ret == -EAGAIN)
|
||||
ret = 0;
|
||||
|
||||
Reference in New Issue
Block a user