1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * VMware VMCI Driver 4 * 5 * Copyright (C) 2012 VMware, Inc. All rights reserved. 6 */ 7 8 #include <linux/vmw_vmci_defs.h> 9 #include <linux/vmw_vmci_api.h> 10 #include <linux/atomic.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/init.h> 14 15 #include "vmci_driver.h" 16 #include "vmci_event.h" 17 18 static bool vmci_disable_host; 19 module_param_named(disable_host, vmci_disable_host, bool, 0); 20 MODULE_PARM_DESC(disable_host, 21 "Disable driver host personality (default=enabled)"); 22 23 static bool vmci_disable_guest; 24 module_param_named(disable_guest, vmci_disable_guest, bool, 0); 25 MODULE_PARM_DESC(disable_guest, 26 "Disable driver guest personality (default=enabled)"); 27 28 static bool vmci_guest_personality_initialized; 29 static bool vmci_host_personality_initialized; 30 31 static DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */ 32 static vmci_vsock_cb vmci_vsock_transport_cb; 33 static bool vmci_vsock_cb_host_called; 34 35 /* 36 * vmci_get_context_id() - Gets the current context ID. 37 * 38 * Returns the current context ID. Note that since this is accessed only 39 * from code running in the host, this always returns the host context ID. 40 */ 41 u32 vmci_get_context_id(void) 42 { 43 if (vmci_guest_code_active()) 44 return vmci_get_vm_context_id(); 45 else if (vmci_host_code_active()) 46 return VMCI_HOST_CONTEXT_ID; 47 48 return VMCI_INVALID_ID; 49 } 50 EXPORT_SYMBOL_GPL(vmci_get_context_id); 51 52 /* 53 * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback. 54 * 55 * The callback will be called when the first host or guest becomes active, 56 * or if they are already active when this function is called. 57 * To unregister the callback, call this function with NULL parameter. 58 * 59 * Returns 0 on success. -EBUSY if a callback is already registered. 60 */ 61 int vmci_register_vsock_callback(vmci_vsock_cb callback) 62 { 63 int err = 0; 64 65 mutex_lock(&vmci_vsock_mutex); 66 67 if (vmci_vsock_transport_cb && callback) { 68 err = -EBUSY; 69 goto out; 70 } 71 72 vmci_vsock_transport_cb = callback; 73 74 if (!vmci_vsock_transport_cb) { 75 vmci_vsock_cb_host_called = false; 76 goto out; 77 } 78 79 if (vmci_guest_code_active()) 80 vmci_vsock_transport_cb(false); 81 82 if (vmci_host_users() > 0) { 83 vmci_vsock_cb_host_called = true; 84 vmci_vsock_transport_cb(true); 85 } 86 87 out: 88 mutex_unlock(&vmci_vsock_mutex); 89 return err; 90 } 91 EXPORT_SYMBOL_GPL(vmci_register_vsock_callback); 92 93 void vmci_call_vsock_callback(bool is_host) 94 { 95 mutex_lock(&vmci_vsock_mutex); 96 97 if (!vmci_vsock_transport_cb) 98 goto out; 99 100 /* In the host, this function could be called multiple times, 101 * but we want to register it only once. 102 */ 103 if (is_host) { 104 if (vmci_vsock_cb_host_called) 105 goto out; 106 107 vmci_vsock_cb_host_called = true; 108 } 109 110 vmci_vsock_transport_cb(is_host); 111 out: 112 mutex_unlock(&vmci_vsock_mutex); 113 } 114 115 static int __init vmci_drv_init(void) 116 { 117 int vmci_err; 118 int error; 119 120 vmci_err = vmci_event_init(); 121 if (vmci_err < VMCI_SUCCESS) { 122 pr_err("Failed to initialize VMCIEvent (result=%d)\n", 123 vmci_err); 124 return -EINVAL; 125 } 126 127 if (!vmci_disable_guest) { 128 error = vmci_guest_init(); 129 if (error) { 130 pr_warn("Failed to initialize guest personality (err=%d)\n", 131 error); 132 } else { 133 vmci_guest_personality_initialized = true; 134 pr_info("Guest personality initialized and is %s\n", 135 vmci_guest_code_active() ? 136 "active" : "inactive"); 137 } 138 } 139 140 if (!vmci_disable_host) { 141 error = vmci_host_init(); 142 if (error) { 143 pr_warn("Unable to initialize host personality (err=%d)\n", 144 error); 145 } else { 146 vmci_host_personality_initialized = true; 147 pr_info("Initialized host personality\n"); 148 } 149 } 150 151 if (!vmci_guest_personality_initialized && 152 !vmci_host_personality_initialized) { 153 vmci_event_exit(); 154 return -ENODEV; 155 } 156 157 return 0; 158 } 159 module_init(vmci_drv_init); 160 161 static void __exit vmci_drv_exit(void) 162 { 163 if (vmci_guest_personality_initialized) 164 vmci_guest_exit(); 165 166 if (vmci_host_personality_initialized) 167 vmci_host_exit(); 168 169 vmci_event_exit(); 170 } 171 module_exit(vmci_drv_exit); 172 173 MODULE_AUTHOR("VMware, Inc."); 174 MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); 175 MODULE_VERSION("1.1.6.0-k"); 176 MODULE_LICENSE("GPL v2"); 177