vboxmod.c revision eb0398a29ff0e9c8456afeef89fbffca86a626e8
/** @file
* vboxadd -- VirtualBox Guest Additions for Linux
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#include "the-linux-kernel.h"
#include "version-generated.h"
/* #define IRQ_DEBUG */
/* #define IOCTL_DEBUG */
#ifdef IOCTL_DEBUG
do { \
} while(0)
do { \
} while(0)
#else
#endif
#ifdef IOCTL_LOG_DEBUG
# define IOCTL_LOG_ENTRY(arg) \
do { \
} while(0)
# define IOCTL_LOG_EXIT(arg) \
do { \
} while(0)
#else
# define IOCTL_LOG_ENTRY(arg) do { } while(0)
# define IOCTL_LOG_EXIT(arg) do { } while(0)
#endif
#ifdef IOCTL_VMM_DEBUG
# define IOCTL_VMM_ENTRY(arg) \
do { \
} while(0)
# define IOCTL_VMM_EXIT(arg) \
do { \
} while(0)
#else
# define IOCTL_VMM_ENTRY(arg) do { } while(0)
# define IOCTL_VMM_EXIT(arg) do { } while(0)
#endif
#include "vboxmod.h"
#include "waitcompat.h"
#include <linux/miscdevice.h>
#define str(s) #s
MODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
MODULE_AUTHOR("Sun Microsystems, Inc.");
MODULE_LICENSE("GPL");
#ifdef MODULE_VERSION
#endif
/** device extension structure (we only support one device instance) */
/** our file node major id (set dynamically) */
#ifdef CONFIG_VBOXADD_MAJOR
static unsigned int vbox_major = CONFIG_VBOXADD_MAJOR;
#else
static unsigned int vbox_major = 0;
#endif
DECLVBGL (void *) vboxadd_cmc_open (void)
{
return vboxDev;
}
{
(void) opaque;
}
#define MAX_HGCM_CONNECTIONS 1024
/**
* Structure for keeping track of HGCM connections owned by user space processes, so that
* we can close the connection if a process does not clean up properly (for example if it
* was terminated too abruptly).
*/
/* We just define a fixed number of these so far. This can be changed if it ever becomes
a problem. */
static struct
{
/** Open file structure that this connection handle is associated with */
/** HGCM connection ID */
=
{
{ 0 }
};
/**
* This function converts a VBox result code into a Linux error number.
* Note that we return 0 (success) for all informational values, as Linux
* has no such concept.
*/
static int vboxadd_convert_result(int vbox_err)
{
if ( vbox_err > -1000
&& vbox_err < 1000)
return RTErrConvertToErrno(vbox_err);
switch (vbox_err)
{
case VERR_HGCM_SERVICE_NOT_FOUND: return ESRCH;
case VINF_HGCM_CLIENT_REJECTED: return 0;
case VERR_HGCM_INVALID_CMD_ADDRESS: return EFAULT;
case VINF_HGCM_ASYNC_EXECUTE: return 0;
case VERR_HGCM_INTERNAL: return EPROTO;
case VERR_HGCM_INVALID_CLIENT_ID: return EINVAL;
case VINF_HGCM_SAVE_STATE: return 0;
/* No reason to return this to a guest */
// case VERR_HGCM_SERVICE_EXISTS: return EEXIST;
}
}
/**
* Register an HGCM connection as being connected with a given file descriptor, so that it
* will be closed automatically when that file descriptor is.
*
* @returns 0 on success or Linux kernel error number
* @param clientID the client ID of the HGCM connection
* @param filep the file structure that the connection is to be associated with
*/
{
int i;
bool found = false;
for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i)
{
}
for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i)
{
{
found = true;
}
}
}
/**
* Unregister an HGCM connection associated with a given file descriptor without closing
* the connection.
*
* @returns 0 on success or Linux kernel error number
* @param clientID the client ID of the HGCM connection
*/
{
int i;
bool found = false;
for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i)
{
{
hgcm_connections[i].client_id = 0;
found = true;
}
}
for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i)
{
}
}
/**
* Unregister all HGCM connections associated with a given file descriptor, closing
* the connections in the process. This should be called when a file descriptor is
* closed.
*
* @returns 0 on success or Linux kernel error number
* @param clientID the client ID of the HGCM connection
*/
{
int i;
for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i)
{
{
hgcm_connections[i].client_id = 0;
}
}
return 0;
}
/**
* File open handler
*
*/
{
/* no checks required */
return 0;
}
static void
{
long timeleft;
{
);
{
}
if (timeleft < 0)
{
}
if (timeleft == 0)
{
}
}
else
{
)
)
{
}
}
}
/**
* IOCtl handler - wait for an event from the host.
*
* @returns Linux kernel return code
* @param ptr User space pointer to a structure describing the event
*/
static int vboxadd_wait_event(void *ptr)
{
int rc = 0;
{
LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not get event info\n"));
}
if (0 == rc)
{
{
LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not put out_mask\n"));
}
}
return 0;
}
/**
* IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
* succeeds, it will be associated with the file structure used to open it, so that it will be
* automatically shut down again if the file descriptor is closed.
*
* @returns 0 on success, or a Linux kernel errno value
* @param filp the file structure with which the application opened the driver
* @param userspace_info userspace pointer to the hgcm connection information
* (VBoxGuestHGCMConnectInfo structure)
* @retval userspace_info userspace pointer to the hgcm connection information
*/
{
int rc = 0;
sizeof (info)) != 0)
{
LogFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: can not get connection info\n"));
}
info.u32ClientID = 0;
if (rc >= 0)
{
&info);
if (rc < 0)
LogFunc(("hgcm connection failed. internal ioctl result %Rrc, hgcm result %Rrc\n",
}
if (rc >= 0)
{
/* Register that the connection is associated with this file pointer. */
if (rc < 0)
LogFunc(("failed to register the HGCM connection\n"));
}
if ( rc >= 0
sizeof(info)) != 0)
{
LogFunc (("failed to return the connection structure\n"));
}
/* Unregister again, as we didn't get as far as informing userspace. */
{
/* Disconnect the hgcm connection again, as we told userspace it failed. */
}
return rc;
}
/**
* IOCTL handler. Disconnect a specific HGCM connection.
*
* @returns 0 on success, or a Linux kernel errno value
* @param filp the file structure with which the application opened the driver
* @param userspace_info userspace pointer to the hgcm connection information
* (VBoxGuestHGCMConnectInfo structure)
* @retval userspace_info userspace pointer to the hgcm connection information
*/
{
{
LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: can not get info\n"));
}
if (rc >= 0)
{
if (rc < 0)
}
if ( rc >= 0
{
LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: failed to return the connection structure\n"));
}
return rc;
}
/** Bounce buffer structure for hcgm guest-host data copies. */
typedef struct hgcm_bounce_buffer
{
/** Kernel memory address. */
void *pKernel;
/** User memory address. */
void *pUser;
/** Buffer size. */
/** Create a bounce buffer in kernel space for user space memory. */
{
int rc = 0;
/* Empty buffers are allowed, but then the user pointer should be NULL. */
-EINVAL);
if (rc >= 0)
{
if (cb > 0)
{
if ( rc >= 0
&& copy
}
else
/* We definitely don't want to copy anything from an empty
* buffer. */
}
if (rc >= 0)
{
}
else
{
}
return rc;
}
/** Free a kernel space bounce buffer for user space memory. */
{
int rc = 0;
&& copy
if (rc < 0)
return rc;
}
/** Lock down R3 memory as needed for the HGCM call. Copied from
* HGCMInternal.cpp and SysHlp.cpp */
{
int rc = 0;
unsigned iParm;
if (cbParms)
{
/* Lock user buffers. */
{
{
break;
break;
break;
{
if (rc >= 0)
{
}
else
break;
}
default:
/* make gcc happy */
break;
}
if (rc < 0)
break;
}
}
return rc;
}
/** Unlock R3 memory after the HGCM call. Copied from HGCMInternal.cpp and
* SysHlp.cpp */
{
int rc = 0;
unsigned iParm;
/* Unlock user buffers. */
{
{
{
}
}
else
{
{
AssertFailed();
* we can see where it's coming from. */
}
}
}
return rc;
}
/**
* IOCTL handler. Make an HGCM call.
*
* @returns 0 on success, or a Linux kernel errno value
* @param userspace_info userspace pointer to the hgcm connection information
* (VBoxGuestHGCMConnectInfo structure). This will be
* updated on success.
* @param u32Size the size of the userspace structure
*/
{
void *apvCtx[VBOX_HGCM_MAX_PARMS];
unsigned haveParms = 0;
int rc = 0;
if ( rc >= 0
{
LogRelFunc (("can not get info from user space\n"));
}
if ( rc >= 0
{
LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
u32Size));
}
if (rc >= 0)
{
haveParms = 1;
}
if (rc >= 0)
{
int vrc;
if (rc < 0)
if ( rc >= 0
u32Size))
{
LogRelFunc (("failed to return the information to user space\n"));
}
}
if (haveParms)
{
}
return rc;
}
/**
* IOCTL handler. Make an HGCM call with timeout.
*
* @returns 0 on success, or a Linux kernel errno value
* @param userspace_info userspace pointer to the hgcm connection information
* (VBoxGuestHGCMConnectInfo structure). This will be
* updated on success.
* @param u32Size the size of the userspace structure
*/
static int vboxadd_hgcm_call_timed(unsigned long userspace_info,
{
void *apvCtx[VBOX_HGCM_MAX_PARMS];
unsigned haveParms = 0;
int rc = 0;
if ( rc >= 0
{
LogRelFunc (("can not get info from user space\n"));
}
if ( rc >= 0
{
LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
u32Size));
}
if (rc >= 0)
{
haveParms = 1;
}
if (rc >= 0)
{
int vrc;
if (rc < 0)
if ( rc >= 0
{
LogRelFunc (("failed to return the information to user space\n"));
}
}
if (haveParms)
{
}
return rc;
}
/**
* IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
* we know how to handle.
*
* @returns iprt status code
* @param pInfo kernel space pointer to the filter mask change info
*/
{
LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
if (RT_FAILURE(rc))
Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
else
{
}
if (RT_FAILURE(rc))
{
Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
}
if (pReq)
return rc;
}
/**
* IOCTL handler for vboxadd
*/
{
int rc = 0;
/* Deal with variable size ioctls first. */
{
char *pszMessage;
if (NULL == pszMessage)
{
LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
}
if ( (0 == rc)
{
LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
}
if (0 == rc)
{
}
if (NULL != pszMessage)
{
}
}
else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
{
size_t cbRequestSize = 0;
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
}
if (0 == rc)
{
/* get the request size */
if (!cbVanillaRequestSize)
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
}
}
if (0 == rc)
{
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
}
}
if (0 == rc)
{
/* request storage for the full request */
if (RT_FAILURE(rc))
{
}
}
if (0 == rc)
{
/* now get the full request */
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
}
}
/* now issue the request */
if (0 == rc)
{
/* asynchronous processing? */
if (rrc == VINF_HGCM_ASYNC_EXECUTE)
{
}
/* failed? */
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
}
else
{
/* success, copy the result data to user space */
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
}
}
}
}
else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
{
/* Do the HGCM call using the Vbgl bits */
}
else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
{
/* Do the HGCM call using the Vbgl bits */
}
else
{
switch (cmd)
{
break;
break;
break;
break;
{
{
LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
break;
}
break;
}
default:
break;
}
}
return rc;
}
/**
* IOCTL handler for vboxuser
* @todo currently this is just a copy of vboxadd_ioctl. We should
* decide if we wish to restrict this. If we do, we should remove
* the more general ioctls (HGCM call, VMM device request) and
* replace them with specific ones. If not, then we should just
* make vboxadd world readable and writable or something.
*/
{
int rc = 0;
/* Deal with variable size ioctls first. */
{
char *pszMessage;
if (NULL == pszMessage)
{
LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
}
if ( (0 == rc)
{
LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
}
if (0 == rc)
/* This only produces output in debug builds */
if (NULL != pszMessage)
{
}
}
else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
{
size_t cbRequestSize = 0;
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
}
if (0 == rc)
{
/* get the request size */
if (!cbVanillaRequestSize)
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
}
}
if (0 == rc)
{
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
}
}
if (0 == rc)
{
/* request storage for the full request */
if (RT_FAILURE(rc))
{
}
}
if (0 == rc)
{
/* now get the full request */
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
}
}
/* now issue the request */
if (0 == rc)
{
/* asynchronous processing? */
if (rrc == VINF_HGCM_ASYNC_EXECUTE)
{
}
/* failed? */
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
}
else
{
/* success, copy the result data to user space */
{
LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
}
}
}
}
else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
{
/* Do the HGCM call using the Vbgl bits */
}
else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
{
/* Do the HGCM call using the Vbgl bits */
}
else
{
switch (cmd)
{
break;
break;
break;
break;
{
{
LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
break;
}
break;
}
default:
break;
}
}
return rc;
}
/**
* Poll function. This returns "ready to read" if the guest is in absolute
* mouse pointer mode and the pointer position has changed since the last
* poll.
*/
unsigned int
{
int result = 0;
return result;
}
/** Asynchronous notification activation method. */
static int
{
}
/**
* Dummy read function - we only supply this because we implement poll and
* fasync.
*/
static ssize_t
{
{
return -EINVAL;
}
buf[0] = 0;
return 1;
}
/**
* File close handler for vboxadd. Clean up any HGCM connections associated
* with the open file which might still be open.
*/
{
/* Deactivate our asynchronous queue. */
return 0;
}
/**
* File close handler for vboxuser. Clean up any HGCM connections associated
* with the open file which might still be open.
*/
{
return 0;
}
/** file operations for the vboxadd device */
static struct file_operations vboxadd_fops =
{
.owner = THIS_MODULE,
.open = vboxadd_open,
.ioctl = vboxadd_ioctl,
.poll = vboxadd_poll,
.fasync = vboxadd_fasync,
.read = vboxadd_read,
};
/** Miscellaneous device allocation for vboxadd */
static struct miscdevice gMiscVBoxAdd =
{
};
/** file operations for the vboxuser device */
static struct file_operations vboxuser_fops =
{
.owner = THIS_MODULE,
.open = vboxadd_open,
.ioctl = vboxuser_ioctl,
};
/** Miscellaneous device allocation for vboxuser */
static struct miscdevice gMiscVBoxUser =
{
};
#ifndef IRQ_RETVAL
/* interrupt handlers in 2.4 kernels don't return anything */
# define irqreturn_t void
# define IRQ_RETVAL(n)
#endif
/**
* vboxadd_irq_handler
*
* Interrupt handler
*
* @returns scsi error code
* @param irq Irq number
* @param dev_id Irq handler parameter
* @param regs Regs
*
*/
#else
#endif
{
int fIRQTaken = 0;
int rcVBox;
#ifdef IRQ_DEBUG
Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
#endif
/* check if IRQ was asserted by VBox */
{
#ifdef IRQ_DEBUG
Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
#endif
/* make a copy of the event mask */
{
{
}
}
else
{
/* impossible... */
LogRelFunc(("IRQ was not acknowledged! rc = %Rrc, header.rc = %Rrc\n",
BUG ();
}
/* it was ours! */
fIRQTaken = 1;
}
#ifdef IRQ_DEBUG
else
{
/* we might be attached to a shared interrupt together with another device. */
Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
}
#endif
/* it was ours */
return IRQ_RETVAL(fIRQTaken);
}
/**
* Helper function to reserve a fixed kernel address space window
* and tell the VMM that it can safely put its hypervisor there.
* This function might fail which is not a critical error.
*/
static int vboxadd_reserve_hypervisor(void)
{
int rcVBox;
/* allocate request structure */
(VMMDevRequestHeader**)&req,
sizeof(VMMDevReqHypervisorInfo),
);
if (RT_FAILURE(rcVBox))
{
goto bail_out;
}
/* query the hypervisor information */
{
/* are we supposed to make a reservation? */
if (req->hypervisorSize)
{
/** @todo repeat this several times until we get an address the host likes */
void *hypervisorArea;
/* reserve another 4MB because the start needs to be 4MB aligned */
/* perform a fictive IO space mapping */
if (hypervisorArea)
{
/* communicate result to VMM, align at 4MB */
{
/* store mapping for future unmapping */
}
else
{
LogRelFunc(("failed to set hypervisor region! rc = %Rrc, header.rc = %Rrc\n",
goto bail_out;
}
}
else
{
goto bail_out;
}
}
}
else
{
LogRelFunc(("failed to query hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
goto bail_out;
}
/* successful return */
return 0;
/* error return */
if (req)
return 1;
}
/**
* Helper function to free the hypervisor address window
*
*/
static int vboxadd_free_hypervisor(void)
{
int rcVBox;
/* allocate request structure */
(VMMDevRequestHeader**)&req,
sizeof(VMMDevReqHypervisorInfo),
);
if (RT_FAILURE(rcVBox))
{
goto bail_out;
}
/* reset the hypervisor information */
req->hypervisorStart = 0;
req->hypervisorSize = 0;
{
/* now we can free the associated IO space mapping */
vboxDev->hypervisorStart = 0;
}
else
{
LogRelFunc(("failed to reset hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
goto bail_out;
}
return 0;
if (req)
return 1;
}
/**
* Helper to free resources
*
*/
static void free_resources(void)
{
if (vboxDev)
{
{
/* Unregister notifications when the host absolute pointer
* position changes. */
}
/* Detach from IRQ before cleaning up! */
if (vboxDev->hypervisorStart)
if (vboxDev->irqAckRequest)
{
}
if (vboxDev->pVMMDevMemory)
}
}
#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
#define PCI_DEV_PUT(x) pci_dev_put(x)
#else
#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
#define PCI_DEV_PUT(x) do {} while(0)
#endif
/**
* Module initialization
*
*/
{
rcVBox = vboxadd_cmc_init();
if (RT_FAILURE(rcVBox))
{
}
/* Detect PCI device */
if (!rc)
{
if (!pcidev)
{
}
}
if (!rc)
{
if (rc)
}
if (!rc)
LogRel(("Starting VirtualBox version %s Guest Additions\n",
/* Register vboxadd */
{
if (rc) /* As we pass a non-zero major, rc should be zero on success. */
LogRel(("vboxadd: register_chrdev failed: vbox_major: %d, err = %d\n",
vbox_major, rc));
}
else if (!rc) /* Register as a miscellaneous device otherwise */
{
if (rc)
LogRel(("vboxadd: misc_register failed for %s (rc=%d)\n",
VBOXADD_NAME, rc));
}
if (!rc)
fHaveVBoxAdd = true;
/* Register our user session device */
if (!rc)
{
if (rc)
LogRel(("vboxadd: misc_register failed for %s (rc=%d)\n",
VBOXUSER_NAME, rc));
}
if (!rc)
fHaveVBoxUser = true;
/* allocate and initialize device extension */
if (!rc)
{
if (vboxDev)
else
{
LogRel(("vboxadd: could not allocate private device structure\n"));
}
}
if (!rc)
{
/* get the IO port region */
/* get the memory region */
/* all resources found? */
{
LogRel(("vboxadd: did not find expected hardware resources\n"));
}
}
/* request ownership of adapter memory */
{
LogRel(("vboxadd: failed to obtain adapter memory\n"));
}
/* map adapter memory into kernel address space and check version */
if (!rc)
{
if (!vboxDev->pVMMDevMemory)
{
LogRel(("vboxadd: ioremap failed\n"));
}
}
{
LogRel(("vboxadd: invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
}
/* initialize ring 0 guest library */
if (!rc)
{
if (RT_FAILURE(rcVBox))
{
LogRel(("vboxadd: could not initialize VBGL subsystem: %Rrc\n",
rcVBox));
}
}
if (!rc)
fHaveGuestLib = true;
/* report guest information to host, this must be done as the very first request */
if (!rc)
{
sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
if (RT_FAILURE(rcVBox))
{
}
/* report guest version to host, the VMMDev requires that to be done
* before any other VMMDev operations. */
if (infoReq)
{
#else
#endif
}
if ( infoReq
&& ( RT_FAILURE(rcVBox)
{
LogRel(("vboxadd: error reporting guest information to host: %Rrc, header: %Rrc\n",
}
if (infoReq)
}
/** @todo check the error code once we bump the additions version.
For now we ignore it for compatibility with older hosts. */
if (!rc)
{
sizeof(VMMDevReqGuestCapabilities2),
if (RT_FAILURE(rcVBox))
{
LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
rcVBox));
}
else
{
vmmreqGuestCaps->u32OrMask = 0;
if (RT_FAILURE(rcVBox))
{
LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
rcVBox));
}
}
}
/* perform hypervisor address space reservation */
if (!rc && vboxadd_reserve_hypervisor())
{
/* we just ignore the error, no address window reservation, non fatal */
}
/* allocate a VMM request structure for use in the ISR */
if (!rc)
{
sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
if (RT_FAILURE(rcVBox))
{
LogRel(("vboxadd: could not allocate request structure: %Rrc\n",
rcVBox));
}
}
/* get ISR */
if (!rc)
{
#else
#endif
if (rc)
else
}
if (!rc)
{
/* Register for notification when the host absolute pointer position
* changes. */
info.u32NotMask = 0;
if (RT_FAILURE(rcVBox))
{
LogRel(("vboxadd: failed to register for VMMDEV_EVENT_MOUSE_POSITION_CHANGED events: %Rrc\n",
rcVBox));
}
}
if (!rc)
{
/* some useful information for the user but don't show this on the console */
LogRel(("VirtualBox device settings: major %d, IRQ %d, "
"I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
"hypervisor window at 0x%p (size 0x%x)\n",
}
else /* Clean up on failure */
{
if (fHaveGuestLib)
if (vboxDev)
if (fHaveVBoxUser)
if (fHaveVBoxAdd && vbox_major > 0)
else if (fHaveVBoxAdd)
}
/* We always release this. Presumably because we no longer need to do
* anything with the device structure. */
if (pcidev)
return rc;
}
/**
* Module termination
*
*/
{
if (vbox_major > 0)
else
vboxadd_cmc_fini ();
}
/* PCI hotplug structure */
{
{
},
{
/* empty entry */
}
};
/*
* Local Variables:
* c-mode: bsd
* indent-tabs-mode: nil
* c-plusplus: evil
* End:
*/