BACKPORT: ANDROID: KVM: arm64: Handle mem HYP_REQ in the host The hypervisor can use a per-VCPU shared page to fill requests for the host. Use it to fulfill the hypervisor wishes. Bug: 458241298 Signed-off-by: Vincent Donnefort <vdonnefort@google.com> Signed-off-by: Fuad Tabba <tabba@google.com> Change-Id: Id31076d511424fbf91b0e2481578bad958e35a82 (cherry picked from commit 92ba603260b542b617ab464af00b42dc98812818) [tabba@: the base's host-side hyp_alloc top-up is pkvm_hyp_topup(PKVM_TOPUP_HYP_ALLOC), not A17's __pkvm_topup_hyp_alloc; add a thin pkvm_topup_hyp_alloc() wrapper over it and call that for REQ_MEM_DEST_HYP_ALLOC. Inert until a consumer raises ARM_EXCEPTION_HYP_REQ (the FF-A back-half).] Signed-off-by: Fuad Tabba <tabba@google.com>
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index 705ebc8..c94a97d 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -25,6 +25,7 @@ enum pkvm_topup_id { unsigned long pkvm_hyp_reclaim(enum pkvm_topup_id id, unsigned long target); unsigned long pkvm_hyp_reclaimable(enum pkvm_topup_id id); +int pkvm_topup_hyp_alloc(unsigned long nr_pages); int pkvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap); int pkvm_init_host_vm(struct kvm *kvm, unsigned long type);
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index d0eaf72..f96d59a 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c
@@ -18,6 +18,7 @@ #include <asm/kvm_emulate.h> #include <asm/kvm_mmu.h> #include <asm/kvm_nested.h> +#include <asm/kvm_pkvm.h> #include <asm/debug-monitors.h> #include <asm/stacktrace/nvhe.h> #include <asm/traps.h> @@ -439,6 +440,48 @@ static int handle_trap_exceptions(struct kvm_vcpu *vcpu) return handled; } +static int handle_hyp_req_mem(struct kvm_vcpu *vcpu, + struct kvm_hyp_req *req) +{ + switch (req->mem.dest) { + case REQ_MEM_DEST_HYP_ALLOC: + return pkvm_topup_hyp_alloc(req->mem.nr_pages); + case REQ_MEM_DEST_VCPU_MEMCACHE: + return topup_hyp_memcache(&vcpu->arch.stage2_mc, + req->mem.nr_pages); + }; + + pr_warn("Unknown kvm_hyp_req mem dest: %d\n", req->mem.dest); + + return -EINVAL; +} + +static int handle_hyp_req(struct kvm_vcpu *vcpu) +{ + struct kvm_hyp_req *hyp_req = vcpu->arch.hyp_reqs; + int i, ret; + + for (i = 0; i < KVM_HYP_REQ_MAX; i++, hyp_req++) { + if (hyp_req->type == KVM_HYP_LAST_REQ) + break; + + switch (hyp_req->type) { + case KVM_HYP_REQ_TYPE_MEM: + ret = handle_hyp_req_mem(vcpu, hyp_req); + break; + default: + pr_warn("Unknown kvm_hyp_req type: %d\n", hyp_req->type); + ret = -EINVAL; + } + + if (ret) + return ret; + } + + /* handled */ + return 1; +} + /* * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on * proper exit to userspace. @@ -478,6 +521,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index) */ run->exit_reason = KVM_EXIT_FAIL_ENTRY; return -EINVAL; + case ARM_EXCEPTION_HYP_REQ: + return handle_hyp_req(vcpu); default: kvm_pr_unimpl("Unsupported exception type: %d", exception_index);
diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 356b822..4107aaf 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c
@@ -282,6 +282,11 @@ static int pkvm_hyp_topup(enum pkvm_topup_id id, unsigned long nr_pages) return res.a1; } +int pkvm_topup_hyp_alloc(unsigned long nr_pages) +{ + return pkvm_hyp_topup(PKVM_TOPUP_HYP_ALLOC, nr_pages); +} + unsigned long pkvm_hyp_reclaim(enum pkvm_topup_id id, unsigned long target) { struct kvm_hyp_memcache mc;