diff --git a/arch/arm64/include/asm/gunyah.h b/arch/arm64/include/asm/gunyah.h index a8b368f53bab..c83d983b0f4e 100644 --- a/arch/arm64/include/asm/gunyah.h +++ b/arch/arm64/include/asm/gunyah.h @@ -1,9 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ -#ifndef __ASM_GUNYAH_H_ -#define __ASM_GUNYAH_H_ +#ifndef _ASM_GUNYAH_H +#define _ASM_GUNYAH_H #include #include diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile index efda8f732f8a..63ca11e74796 100644 --- a/drivers/virt/gunyah/Makefile +++ b/drivers/virt/gunyah/Makefile @@ -3,8 +3,8 @@ obj-$(CONFIG_GUNYAH_PLATFORM_HOOKS) += gunyah_platform_hooks.o obj-$(CONFIG_GUNYAH_QCOM_PLATFORM) += gunyah_qcom.o -gunyah_rsc_mgr-y += rsc_mgr.o rsc_mgr_rpc.o vm_mgr.o vm_mgr_mm.o -obj-$(CONFIG_GUNYAH) += gunyah_rsc_mgr.o +gunyah-y += rsc_mgr.o rsc_mgr_rpc.o vm_mgr.o vm_mgr_mm.o +obj-$(CONFIG_GUNYAH) += gunyah.o obj-$(CONFIG_GUNYAH_VCPU) += gunyah_vcpu.o obj-$(CONFIG_GUNYAH_IRQFD) += gunyah_irqfd.o diff --git a/drivers/virt/gunyah/gunyah_irqfd.c b/drivers/virt/gunyah/gunyah_irqfd.c index 1b7f0c5073da..3e954ebd2029 100644 --- a/drivers/virt/gunyah/gunyah_irqfd.c +++ b/drivers/virt/gunyah/gunyah_irqfd.c @@ -176,5 +176,5 @@ static bool gh_irqfd_compare(const struct gh_vm_function_instance *f, DECLARE_GH_VM_FUNCTION_INIT(irqfd, GH_FN_IRQFD, 2, gh_irqfd_bind, gh_irqfd_unbind, gh_irqfd_compare); -MODULE_DESCRIPTION("Gunyah irqfds"); +MODULE_DESCRIPTION("Gunyah irqfd VM Function"); MODULE_LICENSE("GPL"); diff --git a/drivers/virt/gunyah/gunyah_vcpu.c b/drivers/virt/gunyah/gunyah_vcpu.c index 455ed4425121..4f0bbd58a205 100644 --- a/drivers/virt/gunyah/gunyah_vcpu.c +++ b/drivers/virt/gunyah/gunyah_vcpu.c @@ -68,6 +68,9 @@ static bool gh_handle_mmio(struct gh_vcpu *vcpu, len = vcpu_run_resp->state_data[1], data = vcpu_run_resp->state_data[2]; + if (WARN_ON(len > sizeof(u64))) + len = sizeof(u64); + if (vcpu_run_resp->state == GH_VCPU_ADDRSPACE_VMMIO_READ) { vcpu->vcpu_run->mmio.is_write = 0; /* Record that we need to give vCPU user's supplied value next gh_vcpu_run() */ @@ -175,6 +178,8 @@ static int gh_vcpu_run(struct gh_vcpu *vcpu) vcpu->state = GH_VCPU_READY; break; case GH_VCPU_MMIO_READ: + if (unlikely(vcpu->mmio_read_len > sizeof(state_data[0]))) + vcpu->mmio_read_len = sizeof(state_data[0]); memcpy(&state_data[0], vcpu->vcpu_run->mmio.data, vcpu->mmio_read_len); vcpu->state = GH_VCPU_READY; break; @@ -387,15 +392,9 @@ static long gh_vcpu_bind(struct gh_vm_function_instance *f) if (r) goto err_destroy_page; - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) { - r = fd; - goto err_remove_vcpu; - } - if (!gh_vm_get(f->ghvm)) { r = -ENODEV; - goto err_put_fd; + goto err_remove_resource_ticket; } vcpu->ghvm = f->ghvm; @@ -409,23 +408,30 @@ static long gh_vcpu_bind(struct gh_vm_function_instance *f) goto err_put_gh_vm; kref_get(&vcpu->kref); - snprintf(name, sizeof(name), "gh-vcpu:%d", vcpu->ticket.label); + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + r = fd; + goto err_notifier; + } + + snprintf(name, sizeof(name), "gh-vcpu:%u", vcpu->ticket.label); file = anon_inode_getfile(name, &gh_vcpu_fops, vcpu, O_RDWR); if (IS_ERR(file)) { r = PTR_ERR(file); - goto err_notifier; + goto err_put_fd; } fd_install(fd, file); return fd; +err_put_fd: + put_unused_fd(fd); err_notifier: gh_rm_notifier_unregister(f->rm, &vcpu->nb); err_put_gh_vm: gh_vm_put(vcpu->ghvm); -err_put_fd: - put_unused_fd(fd); -err_remove_vcpu: +err_remove_resource_ticket: gh_vm_remove_resource_ticket(f->ghvm, &vcpu->ticket); err_destroy_page: free_page((unsigned long)vcpu->vcpu_run); @@ -458,5 +464,5 @@ static bool gh_vcpu_compare(const struct gh_vm_function_instance *f, } DECLARE_GH_VM_FUNCTION_INIT(vcpu, GH_FN_VCPU, 1, gh_vcpu_bind, gh_vcpu_unbind, gh_vcpu_compare); -MODULE_DESCRIPTION("Gunyah vCPU Driver"); +MODULE_DESCRIPTION("Gunyah vCPU Function"); MODULE_LICENSE("GPL"); diff --git a/drivers/virt/gunyah/rsc_mgr.c b/drivers/virt/gunyah/rsc_mgr.c index 10cc8db37d30..5571540311af 100644 --- a/drivers/virt/gunyah/rsc_mgr.c +++ b/drivers/virt/gunyah/rsc_mgr.c @@ -126,7 +126,8 @@ struct gh_rm_connection { * @dev: pointer to device * @tx_ghrsc: message queue resource to TX to RM * @rx_ghrsc: message queue resource to RX from RM - * @msgq: mailbox instance of above + * @msgq: mailbox instance of TX/RX resources above + * @msgq_client: mailbox client of above msgq * @active_rx_connection: ongoing gh_rm_connection for which we're receiving fragments * @last_tx_ret: return value of last mailbox tx * @call_xarray: xarray to allocate & lookup sequence IDs for Request/Response flows @@ -160,7 +161,7 @@ struct gh_rm { /** * gh_rm_remap_error() - Remap Gunyah resource manager errors into a Linux error code - * @gh_error: "Standard" return value from Gunyah resource manager + * @rm_error: "Standard" return value from Gunyah resource manager */ static inline int gh_rm_remap_error(enum gh_rm_error rm_error) { @@ -378,7 +379,7 @@ static void gh_rm_notif_work(struct work_struct *work) notification.work); struct gh_rm *rm = connection->notification.rm; - blocking_notifier_call_chain(&rm->nh, connection->msg_id, connection->payload); + blocking_notifier_call_chain(&rm->nh, le32_to_cpu(connection->msg_id), connection->payload); put_device(rm->dev); kfree(connection->payload); diff --git a/drivers/virt/gunyah/rsc_mgr_rpc.c b/drivers/virt/gunyah/rsc_mgr_rpc.c index 4a8f94a34cf2..f48e7df2dbef 100644 --- a/drivers/virt/gunyah/rsc_mgr_rpc.c +++ b/drivers/virt/gunyah/rsc_mgr_rpc.c @@ -308,7 +308,7 @@ int gh_rm_mem_reclaim(struct gh_rm *rm, struct gh_rm_mem_parcel *parcel) int ret; ret = gh_rm_call(rm, GH_RM_RPC_MEM_RECLAIM, &req, sizeof(req), NULL, NULL); - /* Do not call platform mem reclaim hooks: the reclaim didn't happen*/ + /* Only call the platform mem reclaim hooks if we reclaimed the memory */ if (ret) return ret; @@ -348,7 +348,7 @@ EXPORT_SYMBOL_GPL(gh_rm_vm_set_firmware_mem); int gh_rm_alloc_vmid(struct gh_rm *rm, u16 vmid) { struct gh_rm_vm_common_vmid_req req_payload = { - .vmid = vmid, + .vmid = cpu_to_le16(vmid), }; struct gh_rm_vm_alloc_vmid_resp *resp_payload; size_t resp_size; diff --git a/drivers/virt/gunyah/vm_mgr.c b/drivers/virt/gunyah/vm_mgr.c index 1ff96c35af56..4e824758ddf3 100644 --- a/drivers/virt/gunyah/vm_mgr.c +++ b/drivers/virt/gunyah/vm_mgr.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -385,7 +386,7 @@ static int gh_vm_rm_notification_status(struct gh_vm *ghvm, void *data) { struct gh_rm_vm_status_payload *payload = data; - if (payload->vmid != ghvm->vmid) + if (le16_to_cpu(payload->vmid) != ghvm->vmid) return NOTIFY_OK; /* All other state transitions are synchronous to a corresponding RM call */ @@ -403,7 +404,7 @@ static int gh_vm_rm_notification_exited(struct gh_vm *ghvm, void *data) { struct gh_rm_vm_exited_payload *payload = data; - if (payload->vmid != ghvm->vmid) + if (le16_to_cpu(payload->vmid) != ghvm->vmid) return NOTIFY_OK; down_write(&ghvm->status_lock); @@ -413,6 +414,7 @@ static int gh_vm_rm_notification_exited(struct gh_vm *ghvm, void *data) memcpy(&ghvm->exit_info.reason, payload->exit_reason, min(GH_VM_MAX_EXIT_REASON_SIZE, ghvm->exit_info.reason_size)); up_write(&ghvm->status_lock); + wake_up(&ghvm->vm_status_wait); return NOTIFY_DONE; } @@ -441,9 +443,9 @@ static void gh_vm_stop(struct gh_vm *ghvm) if (ret) dev_warn(ghvm->parent, "Failed to stop VM: %d\n", ret); } - - ghvm->vm_status = GH_RM_VM_STATUS_EXITED; up_write(&ghvm->status_lock); + + wait_event(ghvm->vm_status_wait, ghvm->vm_status == GH_RM_VM_STATUS_EXITED); } static __must_check struct gh_vm *gh_vm_alloc(struct gh_rm *rm) @@ -663,9 +665,13 @@ static long gh_vm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_from_user(&dtb_config, argp, sizeof(dtb_config))) return -EFAULT; - if (dtb_config.guest_phys_addr + dtb_config.size < dtb_config.guest_phys_addr) + if (overflows_type(dtb_config.guest_phys_addr + dtb_config.size, u64)) return -EOVERFLOW; + /* Gunyah requires that dtb_config is page aligned */ + if (!PAGE_ALIGNED(dtb_config.guest_phys_addr) || !PAGE_ALIGNED(dtb_config.size)) + return -EINVAL; + ghvm->dtb_config = dtb_config; r = 0; diff --git a/drivers/virt/gunyah/vm_mgr.h b/drivers/virt/gunyah/vm_mgr.h index 9fc4e30129a7..6b88ba64e07d 100644 --- a/drivers/virt/gunyah/vm_mgr.h +++ b/drivers/virt/gunyah/vm_mgr.h @@ -3,8 +3,8 @@ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ -#ifndef _GH_PRIV_VM_MGR_H -#define _GH_PRIV_VM_MGR_H +#ifndef _GH_VM_MGR_H +#define _GH_VM_MGR_H #include #include diff --git a/drivers/virt/gunyah/vm_mgr_mm.c b/drivers/virt/gunyah/vm_mgr_mm.c index 952cc85e5d4b..3157d5317843 100644 --- a/drivers/virt/gunyah/vm_mgr_mm.c +++ b/drivers/virt/gunyah/vm_mgr_mm.c @@ -119,14 +119,12 @@ int gh_vm_mem_alloc(struct gh_vm *ghvm, struct gh_userspace_memory_region *regio if (ret) return ret; - /* Check label is unique */ mapping = __gh_vm_mem_find_by_label(ghvm, region->label); if (mapping) { ret = -EEXIST; goto unlock; } - /* Check for overlap */ list_for_each_entry(tmp_mapping, &ghvm->memory_mappings, list) { if (gh_vm_mem_overlap(tmp_mapping, region->guest_phys_addr, region->memory_size)) { @@ -235,7 +233,6 @@ int gh_vm_mem_alloc(struct gh_vm *ghvm, struct gh_userspace_memory_region *regio } else { parcel->mem_entries[j].size = cpu_to_le64(entry_size); j++; - BUG_ON(j >= parcel->n_mem_entries); parcel->mem_entries[j].ipa_base = cpu_to_le64(page_to_phys(curr_page)); entry_size = PAGE_SIZE; diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h index 2a16219fad18..1f1685518bf3 100644 --- a/include/linux/gunyah.h +++ b/include/linux/gunyah.h @@ -14,13 +14,13 @@ #include #include -/* Follows resource manager's resource types for VM_GET_HYP_RESOURCES */ +/* Matches resource manager's resource types for VM_GET_HYP_RESOURCES RPC */ enum gh_resource_type { GH_RESOURCE_TYPE_BELL_TX = 0, GH_RESOURCE_TYPE_BELL_RX = 1, GH_RESOURCE_TYPE_MSGQ_TX = 2, GH_RESOURCE_TYPE_MSGQ_RX = 3, - GH_RESOURCE_TYPE_VCPU = 4, + GH_RESOURCE_TYPE_VCPU = 4, }; struct gh_resource { @@ -28,7 +28,6 @@ struct gh_resource { u64 capid; unsigned int irq; - /* To help allocator in vm manager */ struct list_head list; u32 rm_label; }; @@ -37,7 +36,7 @@ struct gh_resource { * Gunyah Message Queues */ -#define GH_MSGQ_MAX_MSG_SIZE 240 +#define GH_MSGQ_MAX_MSG_SIZE 240 struct gh_msgq_tx_data { size_t length; @@ -144,16 +143,17 @@ static inline int gh_error_remap(enum gh_error gh_error) } enum gh_api_feature { - GH_FEATURE_DOORBELL = 1, - GH_FEATURE_MSGQUEUE = 2, - GH_FEATURE_VCPU = 5, - GH_FEATURE_MEMEXTENT = 6, + GH_FEATURE_DOORBELL = 1, + GH_FEATURE_MSGQUEUE = 2, + GH_FEATURE_VCPU = 5, + GH_FEATURE_MEMEXTENT = 6, }; bool arch_is_gh_guest(void); #define GH_API_V1 1 +/* Other bits reserved for future use and will be zero */ #define GH_API_INFO_API_VERSION_MASK GENMASK_ULL(13, 0) #define GH_API_INFO_BIG_ENDIAN BIT_ULL(14) #define GH_API_INFO_IS_64BIT BIT_ULL(15) diff --git a/include/linux/gunyah_rsc_mgr.h b/include/linux/gunyah_rsc_mgr.h index 27283c881ecb..f73371bd8f7c 100644 --- a/include/linux/gunyah_rsc_mgr.h +++ b/include/linux/gunyah_rsc_mgr.h @@ -10,7 +10,7 @@ #include #include -#define GH_VMID_INVAL U16_MAX +#define GH_VMID_INVAL U16_MAX #define GH_MEM_HANDLE_INVAL U32_MAX struct gh_rm; @@ -31,12 +31,6 @@ struct gh_rm_vm_exited_payload { #define GH_RM_NOTIFICATION_VM_EXITED 0x56100001 enum gh_rm_vm_status { - /** - * RM doesn't have a state where load partially failed because - * only Linux - */ - GH_RM_VM_STATUS_LOAD_FAILED = -1, - GH_RM_VM_STATUS_NO_STATE = 0, GH_RM_VM_STATUS_INIT = 1, GH_RM_VM_STATUS_READY = 2, diff --git a/samples/gunyah/gunyah_vmm.c b/samples/gunyah/gunyah_vmm.c index d0ba9c20cb13..d0eb49e86372 100644 --- a/samples/gunyah/gunyah_vmm.c +++ b/samples/gunyah/gunyah_vmm.c @@ -56,8 +56,8 @@ static void print_help(char *cmd) "Usage: %s \n" " --help, -h this menu\n" " --image, -i VM image file to load (e.g. a kernel Image) [Required]\n" - " --dtb, -d Devicetree to load [Required]\n" - " --ramdisk, -r Ramdisk to load\n" + " --dtb, -d Devicetree file to load [Required]\n" + " --ramdisk, -r Ramdisk file to load\n" " --base, -B
Set the base address of guest's memory [Default: 0x80000000]\n" " --size, -S The number of bytes large to make the guest's memory [Default: 0x6400000 (100 MB)]\n" " --image_offset, -I Offset into guest memory to load the VM image file [Default: 0x10000]\n"