Gunyah Resource Manager sets up a virtual machine based on a device tree which lives in guest memory. Resource manager requires this memory to be provided as a memory parcel for it to read and manipulate. Implement a function to construct a memory parcel from the guest's pinned memory pages. Signed-off-by: Karim Manaouil <karim.manaouil@xxxxxxxxxx> --- arch/arm64/kvm/gunyah.c | 80 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/arch/arm64/kvm/gunyah.c b/arch/arm64/kvm/gunyah.c index 7216db642174..ef0971146b56 100644 --- a/arch/arm64/kvm/gunyah.c +++ b/arch/arm64/kvm/gunyah.c @@ -634,6 +634,86 @@ static int gunyah_memory_reclaim_folio(struct gunyah_vm *ghvm, return ret; } +static int gunyah_share_memory_parcel(struct gunyah_vm *ghvm, + struct gunyah_rm_mem_parcel *parcel, gfn_t gfn, u64 nr) +{ + struct kvm *kvm = &ghvm->kvm; + struct kvm_memory_slot *memslot; + struct page **pages; + int ret; + u64 i; + + if (!nr) + return -EINVAL; + + memslot = gfn_to_memslot(kvm, gfn); + if (!memslot) + return -ENOENT; + + parcel->mem_entries = kcalloc(nr, sizeof(*parcel->mem_entries), GFP_KERNEL); + if (!parcel->mem_entries) + return -ENOMEM; + parcel->n_mem_entries = nr; + + pages = memslot->arch.pages + (gfn - memslot->base_gfn); + + for (i = 0; i < nr; i++) { + parcel->mem_entries[i].size = cpu_to_le64(PAGE_SIZE); + parcel->mem_entries[i].phys_addr = cpu_to_le64(page_to_phys(pages[i])); + } + + parcel->n_acl_entries = 1; + parcel->acl_entries = kcalloc(parcel->n_acl_entries, + sizeof(*parcel->acl_entries), GFP_KERNEL); + if (!parcel->n_acl_entries) { + ret = -ENOMEM; + goto free_entries; + } + parcel->acl_entries[0].vmid = cpu_to_le16(ghvm->vmid); + parcel->acl_entries[0].perms |= GUNYAH_RM_ACL_R; + parcel->acl_entries[0].perms |= GUNYAH_RM_ACL_W; + parcel->acl_entries[0].perms |= GUNYAH_RM_ACL_X; + parcel->mem_handle = GUNYAH_MEM_HANDLE_INVAL; + + ret = gunyah_rm_mem_share(ghvm->rm, parcel); + if (ret) + goto free_acl; + + return ret; +free_acl: + kfree(parcel->acl_entries); + parcel->acl_entries = NULL; +free_entries: + kfree(parcel->mem_entries); + parcel->mem_entries = NULL; + parcel->n_mem_entries = 0; + + return ret; +} + +static int gunyah_reclaim_memory_parcel(struct gunyah_vm *ghvm, + struct gunyah_rm_mem_parcel *parcel, gfn_t gfn, u64 nr) +{ + int ret; + + if (parcel->mem_handle != GUNYAH_MEM_HANDLE_INVAL) { + ret = gunyah_rm_mem_reclaim(ghvm->rm, parcel); + if (ret) { + dev_err(ghvm->parent, "Failed to reclaim parcel: %d\n", + ret); + /* We can't reclaim the pages -- hold onto the pages + * forever because we don't know what state the memory + * is in + */ + return ret; + } + parcel->mem_handle = GUNYAH_MEM_HANDLE_INVAL; + kfree(parcel->mem_entries); + kfree(parcel->acl_entries); + } + return 0; +} + int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) { return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE; -- 2.39.5