162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * VMware VMCI Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 VMware, Inc. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/vmw_vmci_defs.h> 962306a36Sopenharmony_ci#include <linux/vmw_vmci_api.h> 1062306a36Sopenharmony_ci#include <linux/atomic.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "vmci_driver.h" 1662306a36Sopenharmony_ci#include "vmci_event.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic bool vmci_disable_host; 1962306a36Sopenharmony_cimodule_param_named(disable_host, vmci_disable_host, bool, 0); 2062306a36Sopenharmony_ciMODULE_PARM_DESC(disable_host, 2162306a36Sopenharmony_ci "Disable driver host personality (default=enabled)"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic bool vmci_disable_guest; 2462306a36Sopenharmony_cimodule_param_named(disable_guest, vmci_disable_guest, bool, 0); 2562306a36Sopenharmony_ciMODULE_PARM_DESC(disable_guest, 2662306a36Sopenharmony_ci "Disable driver guest personality (default=enabled)"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic bool vmci_guest_personality_initialized; 2962306a36Sopenharmony_cistatic bool vmci_host_personality_initialized; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */ 3262306a36Sopenharmony_cistatic vmci_vsock_cb vmci_vsock_transport_cb; 3362306a36Sopenharmony_cistatic bool vmci_vsock_cb_host_called; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * vmci_get_context_id() - Gets the current context ID. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Returns the current context ID. Note that since this is accessed only 3962306a36Sopenharmony_ci * from code running in the host, this always returns the host context ID. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ciu32 vmci_get_context_id(void) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci if (vmci_guest_code_active()) 4462306a36Sopenharmony_ci return vmci_get_vm_context_id(); 4562306a36Sopenharmony_ci else if (vmci_host_code_active()) 4662306a36Sopenharmony_ci return VMCI_HOST_CONTEXT_ID; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci return VMCI_INVALID_ID; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_get_context_id); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback. 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * The callback will be called when the first host or guest becomes active, 5662306a36Sopenharmony_ci * or if they are already active when this function is called. 5762306a36Sopenharmony_ci * To unregister the callback, call this function with NULL parameter. 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Returns 0 on success. -EBUSY if a callback is already registered. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ciint vmci_register_vsock_callback(vmci_vsock_cb callback) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci int err = 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci mutex_lock(&vmci_vsock_mutex); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (vmci_vsock_transport_cb && callback) { 6862306a36Sopenharmony_ci err = -EBUSY; 6962306a36Sopenharmony_ci goto out; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci vmci_vsock_transport_cb = callback; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!vmci_vsock_transport_cb) { 7562306a36Sopenharmony_ci vmci_vsock_cb_host_called = false; 7662306a36Sopenharmony_ci goto out; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (vmci_guest_code_active()) 8062306a36Sopenharmony_ci vmci_vsock_transport_cb(false); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (vmci_host_users() > 0) { 8362306a36Sopenharmony_ci vmci_vsock_cb_host_called = true; 8462306a36Sopenharmony_ci vmci_vsock_transport_cb(true); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciout: 8862306a36Sopenharmony_ci mutex_unlock(&vmci_vsock_mutex); 8962306a36Sopenharmony_ci return err; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_register_vsock_callback); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_civoid vmci_call_vsock_callback(bool is_host) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci mutex_lock(&vmci_vsock_mutex); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (!vmci_vsock_transport_cb) 9862306a36Sopenharmony_ci goto out; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* In the host, this function could be called multiple times, 10162306a36Sopenharmony_ci * but we want to register it only once. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci if (is_host) { 10462306a36Sopenharmony_ci if (vmci_vsock_cb_host_called) 10562306a36Sopenharmony_ci goto out; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci vmci_vsock_cb_host_called = true; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci vmci_vsock_transport_cb(is_host); 11162306a36Sopenharmony_ciout: 11262306a36Sopenharmony_ci mutex_unlock(&vmci_vsock_mutex); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int __init vmci_drv_init(void) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int vmci_err; 11862306a36Sopenharmony_ci int error; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci vmci_err = vmci_event_init(); 12162306a36Sopenharmony_ci if (vmci_err < VMCI_SUCCESS) { 12262306a36Sopenharmony_ci pr_err("Failed to initialize VMCIEvent (result=%d)\n", 12362306a36Sopenharmony_ci vmci_err); 12462306a36Sopenharmony_ci return -EINVAL; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (!vmci_disable_guest) { 12862306a36Sopenharmony_ci error = vmci_guest_init(); 12962306a36Sopenharmony_ci if (error) { 13062306a36Sopenharmony_ci pr_warn("Failed to initialize guest personality (err=%d)\n", 13162306a36Sopenharmony_ci error); 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci vmci_guest_personality_initialized = true; 13462306a36Sopenharmony_ci pr_info("Guest personality initialized and is %s\n", 13562306a36Sopenharmony_ci vmci_guest_code_active() ? 13662306a36Sopenharmony_ci "active" : "inactive"); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (!vmci_disable_host) { 14162306a36Sopenharmony_ci error = vmci_host_init(); 14262306a36Sopenharmony_ci if (error) { 14362306a36Sopenharmony_ci pr_warn("Unable to initialize host personality (err=%d)\n", 14462306a36Sopenharmony_ci error); 14562306a36Sopenharmony_ci } else { 14662306a36Sopenharmony_ci vmci_host_personality_initialized = true; 14762306a36Sopenharmony_ci pr_info("Initialized host personality\n"); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!vmci_guest_personality_initialized && 15262306a36Sopenharmony_ci !vmci_host_personality_initialized) { 15362306a36Sopenharmony_ci vmci_event_exit(); 15462306a36Sopenharmony_ci return -ENODEV; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_cimodule_init(vmci_drv_init); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void __exit vmci_drv_exit(void) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci if (vmci_guest_personality_initialized) 16462306a36Sopenharmony_ci vmci_guest_exit(); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (vmci_host_personality_initialized) 16762306a36Sopenharmony_ci vmci_host_exit(); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci vmci_event_exit(); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_cimodule_exit(vmci_drv_exit); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciMODULE_AUTHOR("VMware, Inc."); 17462306a36Sopenharmony_ciMODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); 17562306a36Sopenharmony_ciMODULE_VERSION("1.1.6.0-k"); 17662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 177