From 705a9b5feb1ba9f207b4ae60d42645827212d370 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Mon, 12 Jun 2023 09:49:48 -0700 Subject: [PATCH] ANDROID: virt: gunyah: Sync with latest documentation and sample Sync with latest documentation and sample code from v14 of Gunyah patches: https://lore.kernel.org/all/20230613172054.3959700-1-quic_eberman@quicinc.com/ Bug: 287037804 Change-Id: I8893922e6b8096fdd5dff1b22ebce96e72cdb7c3 Signed-off-by: Elliot Berman --- .../userspace-api/ioctl/ioctl-number.rst | 2 +- Documentation/virt/gunyah/vm-manager.rst | 25 ++++----- drivers/virt/gunyah/rsc_mgr.c | 2 +- drivers/virt/gunyah/vm_mgr.c | 2 +- include/linux/gunyah_vm_mgr.h | 31 ++++++++++- samples/gunyah/gunyah_vmm.c | 52 +++++++++---------- 6 files changed, 69 insertions(+), 45 deletions(-) diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 81456c34c85d..a37f1b5a144e 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -136,7 +136,7 @@ Code Seq# Include File Comments 'F' DD video/sstfb.h conflict! 'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict! 'G' 00-0F xen/gntalloc.h, xen/gntdev.h conflict! -'G' 00-0f linux/gunyah.h conflict! +'G' 00-0F linux/gunyah.h conflict! 'H' 00-7F linux/hiddev.h conflict! 'H' 00-0F linux/hidraw.h conflict! 'H' 01 linux/mei.h conflict! diff --git a/Documentation/virt/gunyah/vm-manager.rst b/Documentation/virt/gunyah/vm-manager.rst index 87838c5b5945..415b11248e00 100644 --- a/Documentation/virt/gunyah/vm-manager.rst +++ b/Documentation/virt/gunyah/vm-manager.rst @@ -7,14 +7,12 @@ Virtual Machine Manager The Gunyah Virtual Machine Manager is a Linux driver to support launching virtual machines using Gunyah. -Except for some basic information about the location of initial binaries, -most of the configuration about a Gunyah virtual machine is described in the -VM's devicetree. The devicetree is generated by userspace. Interacting with the -virtual machine is still done via the kernel and VM configuration requires some -of the corresponding functionality to be set up in the kernel. For instance, -sharing userspace memory with a VM is done via the `GH_VM_SET_USER_MEM_REGION`_ -ioctl. The VM itself is configured to use the memory region via the -devicetree. +Configuration of a Gunyah virtual machine is done via a devicetree. When the VM +is launched, memory is provided by the host VM which contains the devictree. +Gunyah reads the devicetree to configure the memory map and create resources +such as vCPUs for the VM. Memory can be shared with the VM with +`GH_VM_SET_USER_MEM_REGION`_. Userspace can interact with the resources in Linux +by adding "functions" to the VM. Gunyah Functions ================ @@ -56,6 +54,9 @@ GH_CREATE_VM ~~~~~~~~~~~~ Creates a Gunyah VM. The argument is reserved for future use and must be 0. +A successful call will return a Gunyah VM file descriptor. See +`Gunyah VM API Descriptions`_ for list of IOCTLs that can be made on this file +file descriptor. Gunyah VM API Descriptions -------------------------- @@ -70,8 +71,8 @@ unique per virtual machine. While VMM is guest-agnostic and allows runtime addition of memory regions, Linux guest virtual machines do not support accepting memory regions at runtime. -Thus, memory regions should be provided before starting the VM and the VM must -be configured to accept these at boot-up. +Thus, for Linux guests, memory regions should be provided before starting the VM +and the VM must be configured via the devicetree to accept these at boot-up. The guest physical address is used by Linux kernel to check that the requested user regions do not overlap and to help find the corresponding memory region @@ -87,7 +88,7 @@ GH_VM_SET_DTB_CONFIG ~~~~~~~~~~~~~~~~~~~~ This ioctl sets the location of the VM's devicetree blob and is used by Gunyah -Resource Manager to allocate resources. The guest physical memory should be part +Resource Manager to allocate resources. The guest physical memory must be part of the primary memory parcel provided to the VM prior to GH_VM_START. .. kernel-doc:: include/uapi/linux/gunyah.h @@ -104,7 +105,7 @@ GH_VM_ADD_FUNCTION This ioctl registers a Gunyah VM function with the VM manager. The VM function is described with a &struct gh_fn_desc.type and some arguments for that type. Typically, the function is added before the VM starts, but the function doesn't -"operate" until the VM starts with `GH_VM_START`_. For example, vCPU ioclts will +"operate" until the VM starts with `GH_VM_START`_. For example, vCPU ioctls will all return an error until the VM starts because the vCPUs don't exist until the VM is started. This allows the VMM to set up all the kernel functions needed for the VM *before* the VM starts. diff --git a/drivers/virt/gunyah/rsc_mgr.c b/drivers/virt/gunyah/rsc_mgr.c index 2df3283f0b45..85167cca5b20 100644 --- a/drivers/virt/gunyah/rsc_mgr.c +++ b/drivers/virt/gunyah/rsc_mgr.c @@ -123,7 +123,7 @@ struct gh_rm_connection { /** * struct gh_rm - private data for communicating w/Gunyah resource manager - * @dev: pointer to device + * @dev: pointer to RM platform device * @tx_ghrsc: message queue resource to TX to RM * @rx_ghrsc: message queue resource to RX from RM * @msgq: mailbox instance of TX/RX resources above diff --git a/drivers/virt/gunyah/vm_mgr.c b/drivers/virt/gunyah/vm_mgr.c index 4e824758ddf3..8c3d029e073b 100644 --- a/drivers/virt/gunyah/vm_mgr.c +++ b/drivers/virt/gunyah/vm_mgr.c @@ -617,7 +617,7 @@ static int gh_vm_ensure_started(struct gh_vm *ghvm) if (ret) return ret; /** gh_vm_start() is guaranteed to bring status out of - * GH_RM_VM_STATUS_LOAD, thus inifitely recursive call is not + * GH_RM_VM_STATUS_LOAD, thus infinitely recursive call is not * possible */ return gh_vm_ensure_started(ghvm); diff --git a/include/linux/gunyah_vm_mgr.h b/include/linux/gunyah_vm_mgr.h index 0fa3cf6bcaca..527e94624369 100644 --- a/include/linux/gunyah_vm_mgr.h +++ b/include/linux/gunyah_vm_mgr.h @@ -21,6 +21,16 @@ int __must_check gh_vm_get(struct gh_vm *ghvm); void gh_vm_put(struct gh_vm *ghvm); struct gh_vm_function_instance; +/** + * struct gh_vm_function - Represents a function type + * @type: value from &enum gh_fn_type + * @name: friendly name for debug purposes + * @mod: owner of the function type + * @bind: Called when a new function of this type has been allocated. + * @unbind: Called when the function instance is being destroyed. + * @compare: Compare function instance @f's argument to the provided arg. + * Return true if they are equivalent. Used on GH_VM_REMOVE_FUNCTION. + */ struct gh_vm_function { u32 type; const char *name; @@ -84,9 +94,26 @@ void gh_vm_function_unregister(struct gh_vm_function *f); module_gh_vm_function(_name); \ MODULE_ALIAS_GH_VM_FUNCTION(_type, _idx) +/** + * struct gh_vm_resource_ticket - Represents a ticket to reserve exclusive access to VM resource(s) + * @vm_list: for @gh_vm->resource_tickets + * @resources: List of resource(s) associated with this ticket(members are from @gh_resource->list) + * @resource_type: Type of resource this ticket reserves + * @label: Label of the resource from resource manager this ticket reserves. + * @owner: owner of the ticket + * @populate: callback provided by the ticket owner and called when a resource is found that + * matches @resource_type and @label. Note that this callback could be called + * multiple times if userspace created mutliple resources with the same type/label. + * This callback may also have significant delay after gh_vm_add_resource_ticket() + * since gh_vm_add_resource_ticket() could be called before the VM starts. + * @unpopulate: callback provided by the ticket owner and called when the ticket owner should no + * no longer use the resource provided in the argument. When unpopulate() returns, + * the ticket owner should not be able to use the resource any more as the resource + * might being freed. + */ struct gh_vm_resource_ticket { - struct list_head vm_list; /* for gh_vm's resource tickets list */ - struct list_head resources; /* resources associated with this ticket */ + struct list_head vm_list; + struct list_head resources; enum gh_resource_type resource_type; u32 label; diff --git a/samples/gunyah/gunyah_vmm.c b/samples/gunyah/gunyah_vmm.c index d0eb49e86372..6f636ac227c6 100644 --- a/samples/gunyah/gunyah_vmm.c +++ b/samples/gunyah/gunyah_vmm.c @@ -1,6 +1,6 @@ // 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. */ #include @@ -21,6 +21,11 @@ #include +#define DEFAULT_GUEST_BASE 0x80000000 +#define DEFAULT_GUEST_SIZE 0x6400000 /* 100 MiB */ +#define DEFAULT_DTB_OFFSET 0x45f0000 /* 70MiB - 64 KiB */ +#define DEFAULT_RAMDISK_OFFSET 0x4600000 /* 70MiB */ + struct vm_config { int image_fd; int dtb_fd; @@ -29,7 +34,6 @@ struct vm_config { uint64_t guest_base; uint64_t guest_size; - uint64_t image_offset; off_t image_size; uint64_t dtb_offset; off_t dtb_size; @@ -44,7 +48,6 @@ static struct option options[] = { { "ramdisk", optional_argument, NULL, 'r' }, { "base", optional_argument, NULL, 'B' }, { "size", optional_argument, NULL, 'S' }, - { "image_offset", optional_argument, NULL, 'I' }, { "dtb_offset", optional_argument, NULL, 'D' }, { "ramdisk_offset", optional_argument, NULL, 'R' }, { } @@ -58,12 +61,12 @@ static void print_help(char *cmd) " --image, -i VM image file to load (e.g. a kernel Image) [Required]\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" - " --dtb_offset, -D Offset into guest memory to load the DTB [Default: 0]\n" - " --ramdisk_offset, -R Offset into guest memory to load a ramdisk [Default: 0x4600000]\n" - , cmd); + " --base, -B
Set the base address of guest's memory [Default: 0x%08x]\n" + " --size, -S The number of bytes large to make the guest's memory [Default: 0x%08x]\n" + " --dtb_offset, -D Offset into guest memory to load the DTB [Default: 0x%08x]\n" + " --ramdisk_offset, -R Offset into guest memory to load a ramdisk [Default: 0x%08x]\n" + , cmd, DEFAULT_GUEST_BASE, DEFAULT_GUEST_SIZE, + DEFAULT_DTB_OFFSET, DEFAULT_RAMDISK_OFFSET); } int main(int argc, char **argv) @@ -74,18 +77,19 @@ int main(int argc, char **argv) char *guest_mem; struct vm_config config = { /* Defaults good enough to boot static kernel and a basic ramdisk */ + .image_fd = -1, + .dtb_fd = -1, .ramdisk_fd = -1, - .guest_base = 0x80000000, - .guest_size = 0x6400000, /* 100 MB */ - .image_offset = 0, - .dtb_offset = 0x45f0000, - .ramdisk_offset = 0x4600000, /* put at +70MB (30MB for ramdisk) */ + .guest_base = DEFAULT_GUEST_BASE, + .guest_size = DEFAULT_GUEST_SIZE, + .dtb_offset = DEFAULT_DTB_OFFSET, + .ramdisk_offset = DEFAULT_RAMDISK_OFFSET, }; struct stat st; int opt, optidx, ret = 0; long l; - while ((opt = getopt_long(argc, argv, "hi:d:r:B:S:I:D:R:c:", options, &optidx)) != -1) { + while ((opt = getopt_long(argc, argv, "hi:d:r:B:S:D:R:c:", options, &optidx)) != -1) { switch (opt) { case 'i': config.image_fd = open(optarg, O_RDONLY | O_CLOEXEC); @@ -139,14 +143,6 @@ int main(int argc, char **argv) } config.guest_size = l; break; - case 'I': - l = strtol(optarg, NULL, 0); - if (l == LONG_MIN) { - perror("Failed to parse image offset"); - return -1; - } - config.image_offset = l; - break; case 'D': l = strtol(optarg, NULL, 0); if (l == LONG_MIN) { @@ -172,13 +168,13 @@ int main(int argc, char **argv) } } - if (!config.image_fd || !config.dtb_fd) { + if (config.image_fd == -1 || config.dtb_fd == -1) { print_help(argv[0]); return -1; } - if (config.image_offset + config.image_size > config.guest_size) { - fprintf(stderr, "Image offset and size puts it outside guest memory. Make image smaller or increase guest memory size.\n"); + if (config.image_size > config.guest_size) { + fprintf(stderr, "Image size puts it outside guest memory. Make image smaller or increase guest memory size.\n"); return -1; } @@ -222,7 +218,7 @@ int main(int argc, char **argv) return -1; } - if (read(config.image_fd, guest_mem + config.image_offset, config.image_size) < 0) { + if (read(config.image_fd, guest_mem, config.image_size) < 0) { perror("Failed to read image into guest memory"); return -1; } @@ -264,7 +260,7 @@ int main(int argc, char **argv) } while (1) - sleep(10); + pause(); return 0; }