18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VMware VMCI Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 VMware, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/vmw_vmci_defs.h> 98c2ecf20Sopenharmony_ci#include <linux/vmw_vmci_api.h> 108c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/highmem.h> 138c2ecf20Sopenharmony_ci#include <linux/atomic.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/mutex.h> 178c2ecf20Sopenharmony_ci#include <linux/sched.h> 188c2ecf20Sopenharmony_ci#include <linux/cred.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/file.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/poll.h> 238c2ecf20Sopenharmony_ci#include <linux/pci.h> 248c2ecf20Sopenharmony_ci#include <linux/smp.h> 258c2ecf20Sopenharmony_ci#include <linux/fs.h> 268c2ecf20Sopenharmony_ci#include <linux/io.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "vmci_handle_array.h" 298c2ecf20Sopenharmony_ci#include "vmci_queue_pair.h" 308c2ecf20Sopenharmony_ci#include "vmci_datagram.h" 318c2ecf20Sopenharmony_ci#include "vmci_doorbell.h" 328c2ecf20Sopenharmony_ci#include "vmci_resource.h" 338c2ecf20Sopenharmony_ci#include "vmci_context.h" 348c2ecf20Sopenharmony_ci#include "vmci_driver.h" 358c2ecf20Sopenharmony_ci#include "vmci_event.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define VMCI_UTIL_NUM_RESOURCES 1 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cienum { 408c2ecf20Sopenharmony_ci VMCI_NOTIFY_RESOURCE_QUEUE_PAIR = 0, 418c2ecf20Sopenharmony_ci VMCI_NOTIFY_RESOURCE_DOOR_BELL = 1, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cienum { 458c2ecf20Sopenharmony_ci VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY = 0, 468c2ecf20Sopenharmony_ci VMCI_NOTIFY_RESOURCE_ACTION_CREATE = 1, 478c2ecf20Sopenharmony_ci VMCI_NOTIFY_RESOURCE_ACTION_DESTROY = 2, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * VMCI driver initialization. This block can also be used to 528c2ecf20Sopenharmony_ci * pass initial group membership etc. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistruct vmci_init_blk { 558c2ecf20Sopenharmony_ci u32 cid; 568c2ecf20Sopenharmony_ci u32 flags; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* VMCIqueue_pairAllocInfo_VMToVM */ 608c2ecf20Sopenharmony_cistruct vmci_qp_alloc_info_vmvm { 618c2ecf20Sopenharmony_ci struct vmci_handle handle; 628c2ecf20Sopenharmony_ci u32 peer; 638c2ecf20Sopenharmony_ci u32 flags; 648c2ecf20Sopenharmony_ci u64 produce_size; 658c2ecf20Sopenharmony_ci u64 consume_size; 668c2ecf20Sopenharmony_ci u64 produce_page_file; /* User VA. */ 678c2ecf20Sopenharmony_ci u64 consume_page_file; /* User VA. */ 688c2ecf20Sopenharmony_ci u64 produce_page_file_size; /* Size of the file name array. */ 698c2ecf20Sopenharmony_ci u64 consume_page_file_size; /* Size of the file name array. */ 708c2ecf20Sopenharmony_ci s32 result; 718c2ecf20Sopenharmony_ci u32 _pad; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* VMCISetNotifyInfo: Used to pass notify flag's address to the host driver. */ 758c2ecf20Sopenharmony_cistruct vmci_set_notify_info { 768c2ecf20Sopenharmony_ci u64 notify_uva; 778c2ecf20Sopenharmony_ci s32 result; 788c2ecf20Sopenharmony_ci u32 _pad; 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * Per-instance host state 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistruct vmci_host_dev { 858c2ecf20Sopenharmony_ci struct vmci_ctx *context; 868c2ecf20Sopenharmony_ci int user_version; 878c2ecf20Sopenharmony_ci enum vmci_obj_type ct_type; 888c2ecf20Sopenharmony_ci struct mutex lock; /* Mutex lock for vmci context access */ 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct vmci_ctx *host_context; 928c2ecf20Sopenharmony_cistatic bool vmci_host_device_initialized; 938c2ecf20Sopenharmony_cistatic atomic_t vmci_host_active_users = ATOMIC_INIT(0); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* 968c2ecf20Sopenharmony_ci * Determines whether the VMCI host personality is 978c2ecf20Sopenharmony_ci * available. Since the core functionality of the host driver is 988c2ecf20Sopenharmony_ci * always present, all guests could possibly use the host 998c2ecf20Sopenharmony_ci * personality. However, to minimize the deviation from the 1008c2ecf20Sopenharmony_ci * pre-unified driver state of affairs, we only consider the host 1018c2ecf20Sopenharmony_ci * device active if there is no active guest device or if there 1028c2ecf20Sopenharmony_ci * are VMX'en with active VMCI contexts using the host device. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_cibool vmci_host_code_active(void) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return vmci_host_device_initialized && 1078c2ecf20Sopenharmony_ci (!vmci_guest_code_active() || 1088c2ecf20Sopenharmony_ci atomic_read(&vmci_host_active_users) > 0); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciint vmci_host_users(void) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return atomic_read(&vmci_host_active_users); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * Called on open of /dev/vmci. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic int vmci_host_open(struct inode *inode, struct file *filp) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct vmci_host_dev *vmci_host_dev; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci vmci_host_dev = kzalloc(sizeof(struct vmci_host_dev), GFP_KERNEL); 1248c2ecf20Sopenharmony_ci if (vmci_host_dev == NULL) 1258c2ecf20Sopenharmony_ci return -ENOMEM; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci vmci_host_dev->ct_type = VMCIOBJ_NOT_SET; 1288c2ecf20Sopenharmony_ci mutex_init(&vmci_host_dev->lock); 1298c2ecf20Sopenharmony_ci filp->private_data = vmci_host_dev; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * Called on close of /dev/vmci, most often when the process 1368c2ecf20Sopenharmony_ci * exits. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_cistatic int vmci_host_close(struct inode *inode, struct file *filp) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct vmci_host_dev *vmci_host_dev = filp->private_data; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type == VMCIOBJ_CONTEXT) { 1438c2ecf20Sopenharmony_ci vmci_ctx_destroy(vmci_host_dev->context); 1448c2ecf20Sopenharmony_ci vmci_host_dev->context = NULL; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * The number of active contexts is used to track whether any 1488c2ecf20Sopenharmony_ci * VMX'en are using the host personality. It is incremented when 1498c2ecf20Sopenharmony_ci * a context is created through the IOCTL_VMCI_INIT_CONTEXT 1508c2ecf20Sopenharmony_ci * ioctl. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci atomic_dec(&vmci_host_active_users); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci vmci_host_dev->ct_type = VMCIOBJ_NOT_SET; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci kfree(vmci_host_dev); 1578c2ecf20Sopenharmony_ci filp->private_data = NULL; 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * This is used to wake up the VMX when a VMCI call arrives, or 1638c2ecf20Sopenharmony_ci * to wake up select() or poll() at the next clock tick. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistatic __poll_t vmci_host_poll(struct file *filp, poll_table *wait) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct vmci_host_dev *vmci_host_dev = filp->private_data; 1688c2ecf20Sopenharmony_ci struct vmci_ctx *context; 1698c2ecf20Sopenharmony_ci __poll_t mask = 0; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type == VMCIOBJ_CONTEXT) { 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * Read context only if ct_type == VMCIOBJ_CONTEXT to make 1748c2ecf20Sopenharmony_ci * sure that context is initialized 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci context = vmci_host_dev->context; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* Check for VMCI calls to this VM context. */ 1798c2ecf20Sopenharmony_ci if (wait) 1808c2ecf20Sopenharmony_ci poll_wait(filp, &context->host_context.wait_queue, 1818c2ecf20Sopenharmony_ci wait); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci spin_lock(&context->lock); 1848c2ecf20Sopenharmony_ci if (context->pending_datagrams > 0 || 1858c2ecf20Sopenharmony_ci vmci_handle_arr_get_size( 1868c2ecf20Sopenharmony_ci context->pending_doorbell_array) > 0) { 1878c2ecf20Sopenharmony_ci mask = EPOLLIN; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci spin_unlock(&context->lock); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci return mask; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * Copies the handles of a handle array into a user buffer, and 1968c2ecf20Sopenharmony_ci * returns the new length in userBufferSize. If the copy to the 1978c2ecf20Sopenharmony_ci * user buffer fails, the functions still returns VMCI_SUCCESS, 1988c2ecf20Sopenharmony_ci * but retval != 0. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistatic int drv_cp_harray_to_user(void __user *user_buf_uva, 2018c2ecf20Sopenharmony_ci u64 *user_buf_size, 2028c2ecf20Sopenharmony_ci struct vmci_handle_arr *handle_array, 2038c2ecf20Sopenharmony_ci int *retval) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci u32 array_size = 0; 2068c2ecf20Sopenharmony_ci struct vmci_handle *handles; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (handle_array) 2098c2ecf20Sopenharmony_ci array_size = vmci_handle_arr_get_size(handle_array); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (array_size * sizeof(*handles) > *user_buf_size) 2128c2ecf20Sopenharmony_ci return VMCI_ERROR_MORE_DATA; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci *user_buf_size = array_size * sizeof(*handles); 2158c2ecf20Sopenharmony_ci if (*user_buf_size) 2168c2ecf20Sopenharmony_ci *retval = copy_to_user(user_buf_uva, 2178c2ecf20Sopenharmony_ci vmci_handle_arr_get_handles 2188c2ecf20Sopenharmony_ci (handle_array), *user_buf_size); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return VMCI_SUCCESS; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * Sets up a given context for notify to work. Maps the notify 2258c2ecf20Sopenharmony_ci * boolean in user VA into kernel space. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic int vmci_host_setup_notify(struct vmci_ctx *context, 2288c2ecf20Sopenharmony_ci unsigned long uva) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci int retval; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (context->notify_page) { 2338c2ecf20Sopenharmony_ci pr_devel("%s: Notify mechanism is already set up\n", __func__); 2348c2ecf20Sopenharmony_ci return VMCI_ERROR_DUPLICATE_ENTRY; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * We are using 'bool' internally, but let's make sure we explicit 2398c2ecf20Sopenharmony_ci * about the size. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(bool) != sizeof(u8)); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * Lock physical page backing a given user VA. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci retval = get_user_pages_fast(uva, 1, FOLL_WRITE, &context->notify_page); 2478c2ecf20Sopenharmony_ci if (retval != 1) { 2488c2ecf20Sopenharmony_ci context->notify_page = NULL; 2498c2ecf20Sopenharmony_ci return VMCI_ERROR_GENERIC; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * Map the locked page and set up notify pointer. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci context->notify = kmap(context->notify_page) + (uva & (PAGE_SIZE - 1)); 2568c2ecf20Sopenharmony_ci vmci_ctx_check_signal_notify(context); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return VMCI_SUCCESS; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int vmci_host_get_version(struct vmci_host_dev *vmci_host_dev, 2628c2ecf20Sopenharmony_ci unsigned int cmd, void __user *uptr) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci if (cmd == IOCTL_VMCI_VERSION2) { 2658c2ecf20Sopenharmony_ci int __user *vptr = uptr; 2668c2ecf20Sopenharmony_ci if (get_user(vmci_host_dev->user_version, vptr)) 2678c2ecf20Sopenharmony_ci return -EFAULT; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * The basic logic here is: 2728c2ecf20Sopenharmony_ci * 2738c2ecf20Sopenharmony_ci * If the user sends in a version of 0 tell it our version. 2748c2ecf20Sopenharmony_ci * If the user didn't send in a version, tell it our version. 2758c2ecf20Sopenharmony_ci * If the user sent in an old version, tell it -its- version. 2768c2ecf20Sopenharmony_ci * If the user sent in an newer version, tell it our version. 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * The rationale behind telling the caller its version is that 2798c2ecf20Sopenharmony_ci * Workstation 6.5 required that VMX and VMCI kernel module were 2808c2ecf20Sopenharmony_ci * version sync'd. All new VMX users will be programmed to 2818c2ecf20Sopenharmony_ci * handle the VMCI kernel module version. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (vmci_host_dev->user_version > 0 && 2858c2ecf20Sopenharmony_ci vmci_host_dev->user_version < VMCI_VERSION_HOSTQP) { 2868c2ecf20Sopenharmony_ci return vmci_host_dev->user_version; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return VMCI_VERSION; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#define vmci_ioctl_err(fmt, ...) \ 2938c2ecf20Sopenharmony_ci pr_devel("%s: " fmt, ioctl_name, ##__VA_ARGS__) 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int vmci_host_do_init_context(struct vmci_host_dev *vmci_host_dev, 2968c2ecf20Sopenharmony_ci const char *ioctl_name, 2978c2ecf20Sopenharmony_ci void __user *uptr) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct vmci_init_blk init_block; 3008c2ecf20Sopenharmony_ci const struct cred *cred; 3018c2ecf20Sopenharmony_ci int retval; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (copy_from_user(&init_block, uptr, sizeof(init_block))) { 3048c2ecf20Sopenharmony_ci vmci_ioctl_err("error reading init block\n"); 3058c2ecf20Sopenharmony_ci return -EFAULT; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci mutex_lock(&vmci_host_dev->lock); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_NOT_SET) { 3118c2ecf20Sopenharmony_ci vmci_ioctl_err("received VMCI init on initialized handle\n"); 3128c2ecf20Sopenharmony_ci retval = -EINVAL; 3138c2ecf20Sopenharmony_ci goto out; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (init_block.flags & ~VMCI_PRIVILEGE_FLAG_RESTRICTED) { 3178c2ecf20Sopenharmony_ci vmci_ioctl_err("unsupported VMCI restriction flag\n"); 3188c2ecf20Sopenharmony_ci retval = -EINVAL; 3198c2ecf20Sopenharmony_ci goto out; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci cred = get_current_cred(); 3238c2ecf20Sopenharmony_ci vmci_host_dev->context = vmci_ctx_create(init_block.cid, 3248c2ecf20Sopenharmony_ci init_block.flags, 0, 3258c2ecf20Sopenharmony_ci vmci_host_dev->user_version, 3268c2ecf20Sopenharmony_ci cred); 3278c2ecf20Sopenharmony_ci put_cred(cred); 3288c2ecf20Sopenharmony_ci if (IS_ERR(vmci_host_dev->context)) { 3298c2ecf20Sopenharmony_ci retval = PTR_ERR(vmci_host_dev->context); 3308c2ecf20Sopenharmony_ci vmci_ioctl_err("error initializing context\n"); 3318c2ecf20Sopenharmony_ci goto out; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * Copy cid to userlevel, we do this to allow the VMX 3368c2ecf20Sopenharmony_ci * to enforce its policy on cid generation. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci init_block.cid = vmci_ctx_get_id(vmci_host_dev->context); 3398c2ecf20Sopenharmony_ci if (copy_to_user(uptr, &init_block, sizeof(init_block))) { 3408c2ecf20Sopenharmony_ci vmci_ctx_destroy(vmci_host_dev->context); 3418c2ecf20Sopenharmony_ci vmci_host_dev->context = NULL; 3428c2ecf20Sopenharmony_ci vmci_ioctl_err("error writing init block\n"); 3438c2ecf20Sopenharmony_ci retval = -EFAULT; 3448c2ecf20Sopenharmony_ci goto out; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci vmci_host_dev->ct_type = VMCIOBJ_CONTEXT; 3488c2ecf20Sopenharmony_ci atomic_inc(&vmci_host_active_users); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci vmci_call_vsock_callback(true); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci retval = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciout: 3558c2ecf20Sopenharmony_ci mutex_unlock(&vmci_host_dev->lock); 3568c2ecf20Sopenharmony_ci return retval; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int vmci_host_do_send_datagram(struct vmci_host_dev *vmci_host_dev, 3608c2ecf20Sopenharmony_ci const char *ioctl_name, 3618c2ecf20Sopenharmony_ci void __user *uptr) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct vmci_datagram_snd_rcv_info send_info; 3648c2ecf20Sopenharmony_ci struct vmci_datagram *dg = NULL; 3658c2ecf20Sopenharmony_ci u32 cid; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 3688c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 3698c2ecf20Sopenharmony_ci return -EINVAL; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (copy_from_user(&send_info, uptr, sizeof(send_info))) 3738c2ecf20Sopenharmony_ci return -EFAULT; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (send_info.len > VMCI_MAX_DG_SIZE) { 3768c2ecf20Sopenharmony_ci vmci_ioctl_err("datagram is too big (size=%d)\n", 3778c2ecf20Sopenharmony_ci send_info.len); 3788c2ecf20Sopenharmony_ci return -EINVAL; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (send_info.len < sizeof(*dg)) { 3828c2ecf20Sopenharmony_ci vmci_ioctl_err("datagram is too small (size=%d)\n", 3838c2ecf20Sopenharmony_ci send_info.len); 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci dg = memdup_user((void __user *)(uintptr_t)send_info.addr, 3888c2ecf20Sopenharmony_ci send_info.len); 3898c2ecf20Sopenharmony_ci if (IS_ERR(dg)) { 3908c2ecf20Sopenharmony_ci vmci_ioctl_err( 3918c2ecf20Sopenharmony_ci "cannot allocate memory to dispatch datagram\n"); 3928c2ecf20Sopenharmony_ci return PTR_ERR(dg); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (VMCI_DG_SIZE(dg) != send_info.len) { 3968c2ecf20Sopenharmony_ci vmci_ioctl_err("datagram size mismatch\n"); 3978c2ecf20Sopenharmony_ci kfree(dg); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci pr_devel("Datagram dst (handle=0x%x:0x%x) src (handle=0x%x:0x%x), payload (size=%llu bytes)\n", 4028c2ecf20Sopenharmony_ci dg->dst.context, dg->dst.resource, 4038c2ecf20Sopenharmony_ci dg->src.context, dg->src.resource, 4048c2ecf20Sopenharmony_ci (unsigned long long)dg->payload_size); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Get source context id. */ 4078c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 4088c2ecf20Sopenharmony_ci send_info.result = vmci_datagram_dispatch(cid, dg, true); 4098c2ecf20Sopenharmony_ci kfree(dg); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return copy_to_user(uptr, &send_info, sizeof(send_info)) ? -EFAULT : 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int vmci_host_do_receive_datagram(struct vmci_host_dev *vmci_host_dev, 4158c2ecf20Sopenharmony_ci const char *ioctl_name, 4168c2ecf20Sopenharmony_ci void __user *uptr) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct vmci_datagram_snd_rcv_info recv_info; 4198c2ecf20Sopenharmony_ci struct vmci_datagram *dg = NULL; 4208c2ecf20Sopenharmony_ci int retval; 4218c2ecf20Sopenharmony_ci size_t size; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 4248c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 4258c2ecf20Sopenharmony_ci return -EINVAL; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (copy_from_user(&recv_info, uptr, sizeof(recv_info))) 4298c2ecf20Sopenharmony_ci return -EFAULT; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci size = recv_info.len; 4328c2ecf20Sopenharmony_ci recv_info.result = vmci_ctx_dequeue_datagram(vmci_host_dev->context, 4338c2ecf20Sopenharmony_ci &size, &dg); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (recv_info.result >= VMCI_SUCCESS) { 4368c2ecf20Sopenharmony_ci void __user *ubuf = (void __user *)(uintptr_t)recv_info.addr; 4378c2ecf20Sopenharmony_ci retval = copy_to_user(ubuf, dg, VMCI_DG_SIZE(dg)); 4388c2ecf20Sopenharmony_ci kfree(dg); 4398c2ecf20Sopenharmony_ci if (retval != 0) 4408c2ecf20Sopenharmony_ci return -EFAULT; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return copy_to_user(uptr, &recv_info, sizeof(recv_info)) ? -EFAULT : 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int vmci_host_do_alloc_queuepair(struct vmci_host_dev *vmci_host_dev, 4478c2ecf20Sopenharmony_ci const char *ioctl_name, 4488c2ecf20Sopenharmony_ci void __user *uptr) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct vmci_handle handle; 4518c2ecf20Sopenharmony_ci int vmci_status; 4528c2ecf20Sopenharmony_ci int __user *retptr; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 4558c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 4568c2ecf20Sopenharmony_ci return -EINVAL; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) { 4608c2ecf20Sopenharmony_ci struct vmci_qp_alloc_info_vmvm alloc_info; 4618c2ecf20Sopenharmony_ci struct vmci_qp_alloc_info_vmvm __user *info = uptr; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (copy_from_user(&alloc_info, uptr, sizeof(alloc_info))) 4648c2ecf20Sopenharmony_ci return -EFAULT; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci handle = alloc_info.handle; 4678c2ecf20Sopenharmony_ci retptr = &info->result; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci vmci_status = vmci_qp_broker_alloc(alloc_info.handle, 4708c2ecf20Sopenharmony_ci alloc_info.peer, 4718c2ecf20Sopenharmony_ci alloc_info.flags, 4728c2ecf20Sopenharmony_ci VMCI_NO_PRIVILEGE_FLAGS, 4738c2ecf20Sopenharmony_ci alloc_info.produce_size, 4748c2ecf20Sopenharmony_ci alloc_info.consume_size, 4758c2ecf20Sopenharmony_ci NULL, 4768c2ecf20Sopenharmony_ci vmci_host_dev->context); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (vmci_status == VMCI_SUCCESS) 4798c2ecf20Sopenharmony_ci vmci_status = VMCI_SUCCESS_QUEUEPAIR_CREATE; 4808c2ecf20Sopenharmony_ci } else { 4818c2ecf20Sopenharmony_ci struct vmci_qp_alloc_info alloc_info; 4828c2ecf20Sopenharmony_ci struct vmci_qp_alloc_info __user *info = uptr; 4838c2ecf20Sopenharmony_ci struct vmci_qp_page_store page_store; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (copy_from_user(&alloc_info, uptr, sizeof(alloc_info))) 4868c2ecf20Sopenharmony_ci return -EFAULT; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci handle = alloc_info.handle; 4898c2ecf20Sopenharmony_ci retptr = &info->result; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci page_store.pages = alloc_info.ppn_va; 4928c2ecf20Sopenharmony_ci page_store.len = alloc_info.num_ppns; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci vmci_status = vmci_qp_broker_alloc(alloc_info.handle, 4958c2ecf20Sopenharmony_ci alloc_info.peer, 4968c2ecf20Sopenharmony_ci alloc_info.flags, 4978c2ecf20Sopenharmony_ci VMCI_NO_PRIVILEGE_FLAGS, 4988c2ecf20Sopenharmony_ci alloc_info.produce_size, 4998c2ecf20Sopenharmony_ci alloc_info.consume_size, 5008c2ecf20Sopenharmony_ci &page_store, 5018c2ecf20Sopenharmony_ci vmci_host_dev->context); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (put_user(vmci_status, retptr)) { 5058c2ecf20Sopenharmony_ci if (vmci_status >= VMCI_SUCCESS) { 5068c2ecf20Sopenharmony_ci vmci_status = vmci_qp_broker_detach(handle, 5078c2ecf20Sopenharmony_ci vmci_host_dev->context); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci return -EFAULT; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int vmci_host_do_queuepair_setva(struct vmci_host_dev *vmci_host_dev, 5168c2ecf20Sopenharmony_ci const char *ioctl_name, 5178c2ecf20Sopenharmony_ci void __user *uptr) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct vmci_qp_set_va_info set_va_info; 5208c2ecf20Sopenharmony_ci struct vmci_qp_set_va_info __user *info = uptr; 5218c2ecf20Sopenharmony_ci s32 result; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 5248c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 5258c2ecf20Sopenharmony_ci return -EINVAL; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) { 5298c2ecf20Sopenharmony_ci vmci_ioctl_err("is not allowed\n"); 5308c2ecf20Sopenharmony_ci return -EINVAL; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (copy_from_user(&set_va_info, uptr, sizeof(set_va_info))) 5348c2ecf20Sopenharmony_ci return -EFAULT; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (set_va_info.va) { 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * VMX is passing down a new VA for the queue 5398c2ecf20Sopenharmony_ci * pair mapping. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ci result = vmci_qp_broker_map(set_va_info.handle, 5428c2ecf20Sopenharmony_ci vmci_host_dev->context, 5438c2ecf20Sopenharmony_ci set_va_info.va); 5448c2ecf20Sopenharmony_ci } else { 5458c2ecf20Sopenharmony_ci /* 5468c2ecf20Sopenharmony_ci * The queue pair is about to be unmapped by 5478c2ecf20Sopenharmony_ci * the VMX. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci result = vmci_qp_broker_unmap(set_va_info.handle, 5508c2ecf20Sopenharmony_ci vmci_host_dev->context, 0); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return put_user(result, &info->result) ? -EFAULT : 0; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int vmci_host_do_queuepair_setpf(struct vmci_host_dev *vmci_host_dev, 5578c2ecf20Sopenharmony_ci const char *ioctl_name, 5588c2ecf20Sopenharmony_ci void __user *uptr) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct vmci_qp_page_file_info page_file_info; 5618c2ecf20Sopenharmony_ci struct vmci_qp_page_file_info __user *info = uptr; 5628c2ecf20Sopenharmony_ci s32 result; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (vmci_host_dev->user_version < VMCI_VERSION_HOSTQP || 5658c2ecf20Sopenharmony_ci vmci_host_dev->user_version >= VMCI_VERSION_NOVMVM) { 5668c2ecf20Sopenharmony_ci vmci_ioctl_err("not supported on this VMX (version=%d)\n", 5678c2ecf20Sopenharmony_ci vmci_host_dev->user_version); 5688c2ecf20Sopenharmony_ci return -EINVAL; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 5728c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 5738c2ecf20Sopenharmony_ci return -EINVAL; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (copy_from_user(&page_file_info, uptr, sizeof(*info))) 5778c2ecf20Sopenharmony_ci return -EFAULT; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * Communicate success pre-emptively to the caller. Note that the 5818c2ecf20Sopenharmony_ci * basic premise is that it is incumbent upon the caller not to look at 5828c2ecf20Sopenharmony_ci * the info.result field until after the ioctl() returns. And then, 5838c2ecf20Sopenharmony_ci * only if the ioctl() result indicates no error. We send up the 5848c2ecf20Sopenharmony_ci * SUCCESS status before calling SetPageStore() store because failing 5858c2ecf20Sopenharmony_ci * to copy up the result code means unwinding the SetPageStore(). 5868c2ecf20Sopenharmony_ci * 5878c2ecf20Sopenharmony_ci * It turns out the logic to unwind a SetPageStore() opens a can of 5888c2ecf20Sopenharmony_ci * worms. For example, if a host had created the queue_pair and a 5898c2ecf20Sopenharmony_ci * guest attaches and SetPageStore() is successful but writing success 5908c2ecf20Sopenharmony_ci * fails, then ... the host has to be stopped from writing (anymore) 5918c2ecf20Sopenharmony_ci * data into the queue_pair. That means an additional test in the 5928c2ecf20Sopenharmony_ci * VMCI_Enqueue() code path. Ugh. 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (put_user(VMCI_SUCCESS, &info->result)) { 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * In this case, we can't write a result field of the 5988c2ecf20Sopenharmony_ci * caller's info block. So, we don't even try to 5998c2ecf20Sopenharmony_ci * SetPageStore(). 6008c2ecf20Sopenharmony_ci */ 6018c2ecf20Sopenharmony_ci return -EFAULT; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci result = vmci_qp_broker_set_page_store(page_file_info.handle, 6058c2ecf20Sopenharmony_ci page_file_info.produce_va, 6068c2ecf20Sopenharmony_ci page_file_info.consume_va, 6078c2ecf20Sopenharmony_ci vmci_host_dev->context); 6088c2ecf20Sopenharmony_ci if (result < VMCI_SUCCESS) { 6098c2ecf20Sopenharmony_ci if (put_user(result, &info->result)) { 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * Note that in this case the SetPageStore() 6128c2ecf20Sopenharmony_ci * call failed but we were unable to 6138c2ecf20Sopenharmony_ci * communicate that to the caller (because the 6148c2ecf20Sopenharmony_ci * copy_to_user() call failed). So, if we 6158c2ecf20Sopenharmony_ci * simply return an error (in this case 6168c2ecf20Sopenharmony_ci * -EFAULT) then the caller will know that the 6178c2ecf20Sopenharmony_ci * SetPageStore failed even though we couldn't 6188c2ecf20Sopenharmony_ci * put the result code in the result field and 6198c2ecf20Sopenharmony_ci * indicate exactly why it failed. 6208c2ecf20Sopenharmony_ci * 6218c2ecf20Sopenharmony_ci * That says nothing about the issue where we 6228c2ecf20Sopenharmony_ci * were once able to write to the caller's info 6238c2ecf20Sopenharmony_ci * memory and now can't. Something more 6248c2ecf20Sopenharmony_ci * serious is probably going on than the fact 6258c2ecf20Sopenharmony_ci * that SetPageStore() didn't work. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci return -EFAULT; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int vmci_host_do_qp_detach(struct vmci_host_dev *vmci_host_dev, 6358c2ecf20Sopenharmony_ci const char *ioctl_name, 6368c2ecf20Sopenharmony_ci void __user *uptr) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct vmci_qp_dtch_info detach_info; 6398c2ecf20Sopenharmony_ci struct vmci_qp_dtch_info __user *info = uptr; 6408c2ecf20Sopenharmony_ci s32 result; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 6438c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (copy_from_user(&detach_info, uptr, sizeof(detach_info))) 6488c2ecf20Sopenharmony_ci return -EFAULT; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci result = vmci_qp_broker_detach(detach_info.handle, 6518c2ecf20Sopenharmony_ci vmci_host_dev->context); 6528c2ecf20Sopenharmony_ci if (result == VMCI_SUCCESS && 6538c2ecf20Sopenharmony_ci vmci_host_dev->user_version < VMCI_VERSION_NOVMVM) { 6548c2ecf20Sopenharmony_ci result = VMCI_SUCCESS_LAST_DETACH; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return put_user(result, &info->result) ? -EFAULT : 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int vmci_host_do_ctx_add_notify(struct vmci_host_dev *vmci_host_dev, 6618c2ecf20Sopenharmony_ci const char *ioctl_name, 6628c2ecf20Sopenharmony_ci void __user *uptr) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct vmci_ctx_info ar_info; 6658c2ecf20Sopenharmony_ci struct vmci_ctx_info __user *info = uptr; 6668c2ecf20Sopenharmony_ci s32 result; 6678c2ecf20Sopenharmony_ci u32 cid; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 6708c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 6718c2ecf20Sopenharmony_ci return -EINVAL; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (copy_from_user(&ar_info, uptr, sizeof(ar_info))) 6758c2ecf20Sopenharmony_ci return -EFAULT; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 6788c2ecf20Sopenharmony_ci result = vmci_ctx_add_notification(cid, ar_info.remote_cid); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return put_user(result, &info->result) ? -EFAULT : 0; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int vmci_host_do_ctx_remove_notify(struct vmci_host_dev *vmci_host_dev, 6848c2ecf20Sopenharmony_ci const char *ioctl_name, 6858c2ecf20Sopenharmony_ci void __user *uptr) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci struct vmci_ctx_info ar_info; 6888c2ecf20Sopenharmony_ci struct vmci_ctx_info __user *info = uptr; 6898c2ecf20Sopenharmony_ci u32 cid; 6908c2ecf20Sopenharmony_ci int result; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 6938c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 6948c2ecf20Sopenharmony_ci return -EINVAL; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (copy_from_user(&ar_info, uptr, sizeof(ar_info))) 6988c2ecf20Sopenharmony_ci return -EFAULT; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 7018c2ecf20Sopenharmony_ci result = vmci_ctx_remove_notification(cid, 7028c2ecf20Sopenharmony_ci ar_info.remote_cid); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return put_user(result, &info->result) ? -EFAULT : 0; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic int vmci_host_do_ctx_get_cpt_state(struct vmci_host_dev *vmci_host_dev, 7088c2ecf20Sopenharmony_ci const char *ioctl_name, 7098c2ecf20Sopenharmony_ci void __user *uptr) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct vmci_ctx_chkpt_buf_info get_info; 7128c2ecf20Sopenharmony_ci u32 cid; 7138c2ecf20Sopenharmony_ci void *cpt_buf; 7148c2ecf20Sopenharmony_ci int retval; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 7178c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 7188c2ecf20Sopenharmony_ci return -EINVAL; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (copy_from_user(&get_info, uptr, sizeof(get_info))) 7228c2ecf20Sopenharmony_ci return -EFAULT; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 7258c2ecf20Sopenharmony_ci get_info.result = vmci_ctx_get_chkpt_state(cid, get_info.cpt_type, 7268c2ecf20Sopenharmony_ci &get_info.buf_size, &cpt_buf); 7278c2ecf20Sopenharmony_ci if (get_info.result == VMCI_SUCCESS && get_info.buf_size) { 7288c2ecf20Sopenharmony_ci void __user *ubuf = (void __user *)(uintptr_t)get_info.cpt_buf; 7298c2ecf20Sopenharmony_ci retval = copy_to_user(ubuf, cpt_buf, get_info.buf_size); 7308c2ecf20Sopenharmony_ci kfree(cpt_buf); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (retval) 7338c2ecf20Sopenharmony_ci return -EFAULT; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return copy_to_user(uptr, &get_info, sizeof(get_info)) ? -EFAULT : 0; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic int vmci_host_do_ctx_set_cpt_state(struct vmci_host_dev *vmci_host_dev, 7408c2ecf20Sopenharmony_ci const char *ioctl_name, 7418c2ecf20Sopenharmony_ci void __user *uptr) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct vmci_ctx_chkpt_buf_info set_info; 7448c2ecf20Sopenharmony_ci u32 cid; 7458c2ecf20Sopenharmony_ci void *cpt_buf; 7468c2ecf20Sopenharmony_ci int retval; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 7498c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 7508c2ecf20Sopenharmony_ci return -EINVAL; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (copy_from_user(&set_info, uptr, sizeof(set_info))) 7548c2ecf20Sopenharmony_ci return -EFAULT; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci cpt_buf = memdup_user((void __user *)(uintptr_t)set_info.cpt_buf, 7578c2ecf20Sopenharmony_ci set_info.buf_size); 7588c2ecf20Sopenharmony_ci if (IS_ERR(cpt_buf)) 7598c2ecf20Sopenharmony_ci return PTR_ERR(cpt_buf); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 7628c2ecf20Sopenharmony_ci set_info.result = vmci_ctx_set_chkpt_state(cid, set_info.cpt_type, 7638c2ecf20Sopenharmony_ci set_info.buf_size, cpt_buf); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci retval = copy_to_user(uptr, &set_info, sizeof(set_info)) ? -EFAULT : 0; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci kfree(cpt_buf); 7688c2ecf20Sopenharmony_ci return retval; 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic int vmci_host_do_get_context_id(struct vmci_host_dev *vmci_host_dev, 7728c2ecf20Sopenharmony_ci const char *ioctl_name, 7738c2ecf20Sopenharmony_ci void __user *uptr) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci u32 __user *u32ptr = uptr; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return put_user(VMCI_HOST_CONTEXT_ID, u32ptr) ? -EFAULT : 0; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic int vmci_host_do_set_notify(struct vmci_host_dev *vmci_host_dev, 7818c2ecf20Sopenharmony_ci const char *ioctl_name, 7828c2ecf20Sopenharmony_ci void __user *uptr) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct vmci_set_notify_info notify_info; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 7878c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 7888c2ecf20Sopenharmony_ci return -EINVAL; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (copy_from_user(¬ify_info, uptr, sizeof(notify_info))) 7928c2ecf20Sopenharmony_ci return -EFAULT; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (notify_info.notify_uva) { 7958c2ecf20Sopenharmony_ci notify_info.result = 7968c2ecf20Sopenharmony_ci vmci_host_setup_notify(vmci_host_dev->context, 7978c2ecf20Sopenharmony_ci notify_info.notify_uva); 7988c2ecf20Sopenharmony_ci } else { 7998c2ecf20Sopenharmony_ci vmci_ctx_unset_notify(vmci_host_dev->context); 8008c2ecf20Sopenharmony_ci notify_info.result = VMCI_SUCCESS; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return copy_to_user(uptr, ¬ify_info, sizeof(notify_info)) ? 8048c2ecf20Sopenharmony_ci -EFAULT : 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int vmci_host_do_notify_resource(struct vmci_host_dev *vmci_host_dev, 8088c2ecf20Sopenharmony_ci const char *ioctl_name, 8098c2ecf20Sopenharmony_ci void __user *uptr) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct vmci_dbell_notify_resource_info info; 8128c2ecf20Sopenharmony_ci u32 cid; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (vmci_host_dev->user_version < VMCI_VERSION_NOTIFY) { 8158c2ecf20Sopenharmony_ci vmci_ioctl_err("invalid for current VMX versions\n"); 8168c2ecf20Sopenharmony_ci return -EINVAL; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 8208c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 8218c2ecf20Sopenharmony_ci return -EINVAL; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (copy_from_user(&info, uptr, sizeof(info))) 8258c2ecf20Sopenharmony_ci return -EFAULT; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci switch (info.action) { 8308c2ecf20Sopenharmony_ci case VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY: 8318c2ecf20Sopenharmony_ci if (info.resource == VMCI_NOTIFY_RESOURCE_DOOR_BELL) { 8328c2ecf20Sopenharmony_ci u32 flags = VMCI_NO_PRIVILEGE_FLAGS; 8338c2ecf20Sopenharmony_ci info.result = vmci_ctx_notify_dbell(cid, info.handle, 8348c2ecf20Sopenharmony_ci flags); 8358c2ecf20Sopenharmony_ci } else { 8368c2ecf20Sopenharmony_ci info.result = VMCI_ERROR_UNAVAILABLE; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci case VMCI_NOTIFY_RESOURCE_ACTION_CREATE: 8418c2ecf20Sopenharmony_ci info.result = vmci_ctx_dbell_create(cid, info.handle); 8428c2ecf20Sopenharmony_ci break; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci case VMCI_NOTIFY_RESOURCE_ACTION_DESTROY: 8458c2ecf20Sopenharmony_ci info.result = vmci_ctx_dbell_destroy(cid, info.handle); 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci default: 8498c2ecf20Sopenharmony_ci vmci_ioctl_err("got unknown action (action=%d)\n", 8508c2ecf20Sopenharmony_ci info.action); 8518c2ecf20Sopenharmony_ci info.result = VMCI_ERROR_INVALID_ARGS; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci return copy_to_user(uptr, &info, sizeof(info)) ? -EFAULT : 0; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int vmci_host_do_recv_notifications(struct vmci_host_dev *vmci_host_dev, 8588c2ecf20Sopenharmony_ci const char *ioctl_name, 8598c2ecf20Sopenharmony_ci void __user *uptr) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct vmci_ctx_notify_recv_info info; 8628c2ecf20Sopenharmony_ci struct vmci_handle_arr *db_handle_array; 8638c2ecf20Sopenharmony_ci struct vmci_handle_arr *qp_handle_array; 8648c2ecf20Sopenharmony_ci void __user *ubuf; 8658c2ecf20Sopenharmony_ci u32 cid; 8668c2ecf20Sopenharmony_ci int retval = 0; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (vmci_host_dev->ct_type != VMCIOBJ_CONTEXT) { 8698c2ecf20Sopenharmony_ci vmci_ioctl_err("only valid for contexts\n"); 8708c2ecf20Sopenharmony_ci return -EINVAL; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (vmci_host_dev->user_version < VMCI_VERSION_NOTIFY) { 8748c2ecf20Sopenharmony_ci vmci_ioctl_err("not supported for the current vmx version\n"); 8758c2ecf20Sopenharmony_ci return -EINVAL; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (copy_from_user(&info, uptr, sizeof(info))) 8798c2ecf20Sopenharmony_ci return -EFAULT; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if ((info.db_handle_buf_size && !info.db_handle_buf_uva) || 8828c2ecf20Sopenharmony_ci (info.qp_handle_buf_size && !info.qp_handle_buf_uva)) { 8838c2ecf20Sopenharmony_ci return -EINVAL; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci cid = vmci_ctx_get_id(vmci_host_dev->context); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci info.result = vmci_ctx_rcv_notifications_get(cid, 8898c2ecf20Sopenharmony_ci &db_handle_array, &qp_handle_array); 8908c2ecf20Sopenharmony_ci if (info.result != VMCI_SUCCESS) 8918c2ecf20Sopenharmony_ci return copy_to_user(uptr, &info, sizeof(info)) ? -EFAULT : 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci ubuf = (void __user *)(uintptr_t)info.db_handle_buf_uva; 8948c2ecf20Sopenharmony_ci info.result = drv_cp_harray_to_user(ubuf, &info.db_handle_buf_size, 8958c2ecf20Sopenharmony_ci db_handle_array, &retval); 8968c2ecf20Sopenharmony_ci if (info.result == VMCI_SUCCESS && !retval) { 8978c2ecf20Sopenharmony_ci ubuf = (void __user *)(uintptr_t)info.qp_handle_buf_uva; 8988c2ecf20Sopenharmony_ci info.result = drv_cp_harray_to_user(ubuf, 8998c2ecf20Sopenharmony_ci &info.qp_handle_buf_size, 9008c2ecf20Sopenharmony_ci qp_handle_array, &retval); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (!retval && copy_to_user(uptr, &info, sizeof(info))) 9048c2ecf20Sopenharmony_ci retval = -EFAULT; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci vmci_ctx_rcv_notifications_release(cid, 9078c2ecf20Sopenharmony_ci db_handle_array, qp_handle_array, 9088c2ecf20Sopenharmony_ci info.result == VMCI_SUCCESS && !retval); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci return retval; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic long vmci_host_unlocked_ioctl(struct file *filp, 9148c2ecf20Sopenharmony_ci unsigned int iocmd, unsigned long ioarg) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci#define VMCI_DO_IOCTL(ioctl_name, ioctl_fn) do { \ 9178c2ecf20Sopenharmony_ci char *name = __stringify(IOCTL_VMCI_ ## ioctl_name); \ 9188c2ecf20Sopenharmony_ci return vmci_host_do_ ## ioctl_fn( \ 9198c2ecf20Sopenharmony_ci vmci_host_dev, name, uptr); \ 9208c2ecf20Sopenharmony_ci } while (0) 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci struct vmci_host_dev *vmci_host_dev = filp->private_data; 9238c2ecf20Sopenharmony_ci void __user *uptr = (void __user *)ioarg; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci switch (iocmd) { 9268c2ecf20Sopenharmony_ci case IOCTL_VMCI_INIT_CONTEXT: 9278c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(INIT_CONTEXT, init_context); 9288c2ecf20Sopenharmony_ci case IOCTL_VMCI_DATAGRAM_SEND: 9298c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(DATAGRAM_SEND, send_datagram); 9308c2ecf20Sopenharmony_ci case IOCTL_VMCI_DATAGRAM_RECEIVE: 9318c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(DATAGRAM_RECEIVE, receive_datagram); 9328c2ecf20Sopenharmony_ci case IOCTL_VMCI_QUEUEPAIR_ALLOC: 9338c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(QUEUEPAIR_ALLOC, alloc_queuepair); 9348c2ecf20Sopenharmony_ci case IOCTL_VMCI_QUEUEPAIR_SETVA: 9358c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(QUEUEPAIR_SETVA, queuepair_setva); 9368c2ecf20Sopenharmony_ci case IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE: 9378c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(QUEUEPAIR_SETPAGEFILE, queuepair_setpf); 9388c2ecf20Sopenharmony_ci case IOCTL_VMCI_QUEUEPAIR_DETACH: 9398c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(QUEUEPAIR_DETACH, qp_detach); 9408c2ecf20Sopenharmony_ci case IOCTL_VMCI_CTX_ADD_NOTIFICATION: 9418c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(CTX_ADD_NOTIFICATION, ctx_add_notify); 9428c2ecf20Sopenharmony_ci case IOCTL_VMCI_CTX_REMOVE_NOTIFICATION: 9438c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(CTX_REMOVE_NOTIFICATION, ctx_remove_notify); 9448c2ecf20Sopenharmony_ci case IOCTL_VMCI_CTX_GET_CPT_STATE: 9458c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(CTX_GET_CPT_STATE, ctx_get_cpt_state); 9468c2ecf20Sopenharmony_ci case IOCTL_VMCI_CTX_SET_CPT_STATE: 9478c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(CTX_SET_CPT_STATE, ctx_set_cpt_state); 9488c2ecf20Sopenharmony_ci case IOCTL_VMCI_GET_CONTEXT_ID: 9498c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(GET_CONTEXT_ID, get_context_id); 9508c2ecf20Sopenharmony_ci case IOCTL_VMCI_SET_NOTIFY: 9518c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(SET_NOTIFY, set_notify); 9528c2ecf20Sopenharmony_ci case IOCTL_VMCI_NOTIFY_RESOURCE: 9538c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(NOTIFY_RESOURCE, notify_resource); 9548c2ecf20Sopenharmony_ci case IOCTL_VMCI_NOTIFICATIONS_RECEIVE: 9558c2ecf20Sopenharmony_ci VMCI_DO_IOCTL(NOTIFICATIONS_RECEIVE, recv_notifications); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci case IOCTL_VMCI_VERSION: 9588c2ecf20Sopenharmony_ci case IOCTL_VMCI_VERSION2: 9598c2ecf20Sopenharmony_ci return vmci_host_get_version(vmci_host_dev, iocmd, uptr); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci default: 9628c2ecf20Sopenharmony_ci pr_devel("%s: Unknown ioctl (iocmd=%d)\n", __func__, iocmd); 9638c2ecf20Sopenharmony_ci return -EINVAL; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci#undef VMCI_DO_IOCTL 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic const struct file_operations vmuser_fops = { 9708c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9718c2ecf20Sopenharmony_ci .open = vmci_host_open, 9728c2ecf20Sopenharmony_ci .release = vmci_host_close, 9738c2ecf20Sopenharmony_ci .poll = vmci_host_poll, 9748c2ecf20Sopenharmony_ci .unlocked_ioctl = vmci_host_unlocked_ioctl, 9758c2ecf20Sopenharmony_ci .compat_ioctl = compat_ptr_ioctl, 9768c2ecf20Sopenharmony_ci}; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic struct miscdevice vmci_host_miscdev = { 9798c2ecf20Sopenharmony_ci .name = "vmci", 9808c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 9818c2ecf20Sopenharmony_ci .fops = &vmuser_fops, 9828c2ecf20Sopenharmony_ci}; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ciint __init vmci_host_init(void) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci int error; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci host_context = vmci_ctx_create(VMCI_HOST_CONTEXT_ID, 9898c2ecf20Sopenharmony_ci VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS, 9908c2ecf20Sopenharmony_ci -1, VMCI_VERSION, NULL); 9918c2ecf20Sopenharmony_ci if (IS_ERR(host_context)) { 9928c2ecf20Sopenharmony_ci error = PTR_ERR(host_context); 9938c2ecf20Sopenharmony_ci pr_warn("Failed to initialize VMCIContext (error%d)\n", 9948c2ecf20Sopenharmony_ci error); 9958c2ecf20Sopenharmony_ci return error; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci error = misc_register(&vmci_host_miscdev); 9998c2ecf20Sopenharmony_ci if (error) { 10008c2ecf20Sopenharmony_ci pr_warn("Module registration error (name=%s, major=%d, minor=%d, err=%d)\n", 10018c2ecf20Sopenharmony_ci vmci_host_miscdev.name, 10028c2ecf20Sopenharmony_ci MISC_MAJOR, vmci_host_miscdev.minor, 10038c2ecf20Sopenharmony_ci error); 10048c2ecf20Sopenharmony_ci pr_warn("Unable to initialize host personality\n"); 10058c2ecf20Sopenharmony_ci vmci_ctx_destroy(host_context); 10068c2ecf20Sopenharmony_ci return error; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci pr_info("VMCI host device registered (name=%s, major=%d, minor=%d)\n", 10108c2ecf20Sopenharmony_ci vmci_host_miscdev.name, MISC_MAJOR, vmci_host_miscdev.minor); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci vmci_host_device_initialized = true; 10138c2ecf20Sopenharmony_ci return 0; 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_civoid __exit vmci_host_exit(void) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci vmci_host_device_initialized = false; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci misc_deregister(&vmci_host_miscdev); 10218c2ecf20Sopenharmony_ci vmci_ctx_destroy(host_context); 10228c2ecf20Sopenharmony_ci vmci_qp_broker_exit(); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci pr_debug("VMCI host driver module unloaded\n"); 10258c2ecf20Sopenharmony_ci} 1026