VBoxGuest-linux.c revision 390677f7318c5f08f4d42c65ded68a93b45f7234
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * VBoxGuest - Linux specifics.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Note. Unfortunately, the difference between this and SUPDrv-linux.c is
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * a little bit too big to be helpful.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * available from http://www.virtualbox.org. This file is free software;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * General Public License (GPL) as published by the Free Software
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * additional information or have any questions.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Some lines of code to disable the local APIC on x86_64 machines taken
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * from a Mandriva patch by Gwenole Beauchesne <gbeauchesne@mandriva.com>.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Header Files *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Defined Constants And Macros *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The device name. */
d7fe26caad92e0d13017738ab94de18e37be91b4vboxsync/** The device name for the device node open to everyone.. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync# define PCI_DEV_PUT(x) do {} while(0)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/* 2.4.x compatability macros that may or may not be defined. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Internal Functions *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic int vboxguestLinuxModInit(void);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic void vboxguestLinuxModExit(void);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic int vboxguestLinuxOpen(struct inode *pInode, struct file *pFilp);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic int vboxguestLinuxRelease(struct inode *pInode, struct file *pFilp);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic long vboxguestLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
754dd50dc28fdae60c11ade3b41cec99a027696dvboxsyncstatic int vboxguestLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic int vboxguestFAsync(int fd, struct file *pFile, int fOn);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic unsigned int vboxguestPoll(struct file *pFile, poll_table *pPt);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic ssize_t vboxguestRead(struct file *pFile, char *pbBuf, size_t cbRead, loff_t *poff);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Global Variables *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Device extention & session data association structure.
c458d2ddeb0af8a96ea6ee8f157a9731fad2ec70vboxsync/** The PCI device. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The base of the I/O port range. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The base of the MMIO range. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The size of the MMIO range as seen by PCI. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The pointer to the mapping of the MMIO range. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Wait queue used by polling. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Asynchronous notification stuff. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Whether we've create the logger or not. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile bool g_fLoggerCreated;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Release logger group settings. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Release logger flags settings. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Release logger destination settings. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Debug logger group settings. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Debug logger flags settings. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Debug logger destination settings. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Our file node major id.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Either set dynamically at run time or statically at compile time. */
196f5d54f710d2479d74f17c81a49562cc74f9a1vboxsyncstatic unsigned int g_iModuleMajor = CONFIG_VBOXGUEST_MAJOR;
bb36345fae5a2e5fec487b9c9934b64797e31ac0vboxsyncstatic unsigned int g_iModuleMajor = 0;
bb36345fae5a2e5fec487b9c9934b64797e31ac0vboxsync# error "CONFIG_VBOXADD_MAJOR -> CONFIG_VBOXGUEST_MAJOR"
bb36345fae5a2e5fec487b9c9934b64797e31ac0vboxsync/** The file_operations structure. */
c458d2ddeb0af8a96ea6ee8f157a9731fad2ec70vboxsync/** The miscdevice structure. */
f3c5829ad9f0e1ea5b425d8bba8691925295ef50vboxsync/** The file_operations structure for the user device.
f3c5829ad9f0e1ea5b425d8bba8691925295ef50vboxsync * @remarks For the time being we'll be using the same implementation as
fed0a467247ec7cd97c81935e2823f6b01c3f5b3vboxsync/** The miscdevice structure for the user device. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** PCI hotplug structure. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic const struct pci_device_id __devinitdata g_VBoxGuestPciId[] =
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* empty entry */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Converts a VBox status code to a linux error code.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @returns corresponding negative linux error code.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @param rc supdrv error code (SUPDRV_ERR_* defines).
c458d2ddeb0af8a96ea6ee8f157a9731fad2ec70vboxsync case VERR_HGCM_INVALID_CMD_ADDRESS: return -EFAULT;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync case VINF_HGCM_SAVE_STATE: return 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* No reason to return this to a guest */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync // case VERR_HGCM_SERVICE_EXISTS: return -EEXIST;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync AssertMsgFailed(("Unhandled error code %Rrc\n", rc));
dc61e6a1868aeec0d6b981e824b5cd8bf32e6b42vboxsync * Does the PCI detection and init of the device.
dc61e6a1868aeec0d6b981e824b5cd8bf32e6b42vboxsync * @returns 0 on success, negated errno on failure.
dc61e6a1868aeec0d6b981e824b5cd8bf32e6b42vboxsync pPciDev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, NULL);
c458d2ddeb0af8a96ea6ee8f157a9731fad2ec70vboxsync /* I/O Ports are mandatory, the MMIO bit is not. */
c458d2ddeb0af8a96ea6ee8f157a9731fad2ec70vboxsync * Map the register address space.
c458d2ddeb0af8a96ea6ee8f157a9731fad2ec70vboxsync if (request_mem_region(g_MMIOPhysAddr, g_cbMMIO, DEVICE_NAME) != NULL)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** @todo why aren't we requesting ownership of the I/O ports as well? */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* failure cleanup path */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync LogRel((DEVICE_NAME ": ioremap failed; MMIO Addr=%RHp cb=%#x\n", g_MMIOPhysAddr, g_cbMMIO));
g_cbMMIO = 0;
g_IOPortBase = 0;
return rc;
static void vboxguestLinuxTermPci(void)
if (pPciDev)
g_cbMMIO = 0;
int rc;
&g_DevExt);
if (rc)
return rc;
static void vboxguestLinuxTermISR(void)
int rc;
if (g_iModuleMajor > 0)
if (rc < 0)
return rc;
if (rc)
return rc;
if (rc)
if (g_iModuleMajor > 0)
return rc;
static void vboxguestLinuxTermDeviceNodes(void)
if (g_iModuleMajor > 0)
int rc;
return -EINVAL;
g_fLoggerCreated = true;
if (rc >= 0)
if (rc >= 0)
if (rc >= 0)
return rc;
RTR0Term();
return rc;
RTR0Term();
int rc;
#ifdef HAVE_UNLOCKED_IOCTL
static int vboxguestLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
void *pvBufFree;
void *pvBuf;
int rc;
Log6(("vboxguestLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
return -ENOMEM;
rc = 0;
if (cbDataReturned > 0)
Log(("vboxguestLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
if (pvBufFree)
return rc;
return fMask;
if (*poff != 0)
return -EINVAL;
&& cbRead > 0)
pbBuf[0] = 0;
#include "VBoxGuestIDC-unix.c.h"
if (g_fLoggerCreated)
if (pLogger)
if (pLogger)
if (g_fLoggerCreated)
if (pLogger)
if (pLogger)
if (g_fLoggerCreated)
if (pLogger)
if (pLogger)
module_param_call(log_flags, vboxguestLinuxParamLogFlagsSet, vboxguestLinuxParamLogFlagsGet, NULL, 0664);
module_param_call(log_dest, vboxguestLinuxParamLogDstSet, vboxguestLinuxParamLogDstGet, NULL, 0664);
# ifdef LOG_ENABLED
module_param_call(dbg_log_flags, vboxguestLinuxParamLogFlagsSet, vboxguestLinuxParamLogFlagsGet, NULL, 0664);
module_param_call(dbg_log_dest, vboxguestLinuxParamLogDstSet, vboxguestLinuxParamLogDstGet, NULL, 0664);
#ifdef MODULE_VERSION