vboxmod.c revision 5509d287ac416c6cb44a7a87b560c8a1b7115cf2
/** @file
*
* vboxadd -- VirtualBox Guest Additions for Linux
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* 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 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.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
#include "the-linux-kernel.h"
/* #define IRQ_DEBUG */
#include "vboxmod.h"
#include "waitcompat.h"
#define VERSION "0.5"
MODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
MODULE_AUTHOR("InnoTek Systemberatung GmbH");
MODULE_LICENSE("GPL");
/* Runtime assert implementation for Linux ring 0 */
const char *pszFile, const char *pszFunction)
{
elog ("!!Assertion Failed!!\n"
"Expression: %s\n"
"Location : %s(%d) %s\n",
}
/* Runtime assert implementation for Linux ring 0 */
{
char msg[256];
}
/* Backdoor logging function, needed by the runtime */
{
char msg[256];
size_t n;
return n;
}
/** 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;
}
/**
* File open handler
*
*/
{
/* no checks required */
return 0;
}
/**
* File close handler
*
*/
{
/* no action required */
return 0;
}
/**
* Wait for event
*
*/
static void
{
BUG ();
}
static void
{
long timeout;
&info->u32EventFlagsOut);
}
/**
* IOCTL handler
*
*/
{
switch (cmd)
{
{
{
return -EFAULT;
}
{
return -EFAULT;
}
return 0;
}
{
int rc;
{
return -EINVAL;
}
{
return -EFAULT;
}
/* get the request size */
if (!cbVanillaRequestSize)
{
return -EINVAL;
}
{
"vboxadd_ioctl: invalid request size: %d min: %d type: %d\n",
return -EINVAL;
}
/* request storage for the full request */
if (VBOX_FAILURE(rc))
{
"vboxadd_ioctl: could not allocate request structure! rc = %d\n", rc);
return -EFAULT;
}
/* now get the full request */
{
"vboxadd_ioctl: failed to fetch full request from user space!\n");
return -EFAULT;
}
/* now issue the request */
/* failed? */
{
return -EFAULT;
}
else
{
/* success, copy the result data to user space */
{
"vboxadd_ioctl: error copying request result to user space!\n");
return -EFAULT;
}
}
break;
}
{
int i, rc;
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_from_user failed!\n");
return -EFAULT;
}
if (!hgcmR3)
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: cannot allocate memory!\n");
return -ENOMEM;
}
* sizeof(HGCMFunctionParameter)))
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_from_user failed!\n");
return -EFAULT;
}
if (!hgcmR0)
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: cannot allocate memory!\n");
return -ENOMEM;
}
/* Calculate the total size of pointer space. Will normally be for a single pointer */
for (i = 0; i < callHeader.cParms; ++i)
{
{
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
break;
break;
default:
elog("IOCTL_VBOXGUEST_HGCM_CALL: unsupported or unknown parameter type\n");
return -EINVAL;
}
}
/* Reconstruct the pointer parameter data in kernel space */
if (pu8PointerData == NULL)
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: out of memory allocating %d bytes for pointer data\n",
return -ENOMEM;
}
for (i = 0; i < callHeader.cParms; ++i)
{
{
/* We are sending data to the host or sending and reading. */
void *pvR3LinAddr
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_from_user failed!\n");
goto hgcm_exit;
}
}
{
/* We are reading data from the host */
}
else
{
/* If it is not a pointer, then it is a 32bit or 64bit value */
}
}
/* Internal VBoxGuest IOCTL interface */
if (rc != VINF_SUCCESS)
{
/** @todo We need a function to convert VBox error codes back to Linux. */
goto hgcm_exit;
}
for (i = 0; i < callHeader.cParms; ++i)
{
{
/* We are sending data to the host or sending and reading. */
void *pvR3LinAddr
void *pvR0LinAddr
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_to_user failed!\n");
goto hgcm_exit;
}
}
{
/* If it is not a pointer, then it is a 32bit or 64bit value */
}
}
{
elog("IOCTL_VBOXGUEST_HGCM_CALL: copy_to_user failed!\n");
goto hgcm_exit;
}
return rc;
}
default:
{
return -EINVAL;
}
}
return 0;
}
#ifdef DEBUG
static ssize_t
{
{
return -EINVAL;
}
*loff += 8;
return 8;
}
#endif
/** strategy handlers (file operations) */
static struct file_operations vbox_fops =
{
.owner = THIS_MODULE,
.open = vboxadd_open,
.ioctl = vboxadd_ioctl,
#ifdef DEBUG
.read = vboxadd_read,
#endif
};
#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
printk ("%s: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
#endif
/* check if IRQ was asserted by VBox */
{
#ifdef IRQ_DEBUG
#endif
/* make a copy of the event mask */
{
{
}
}
else
{
/* impossible... */
"vboxadd: failed acknowledging IRQ! rc = %x, header.rc = %d\n",
BUG ();
}
/* it was ours! */
fIRQTaken = 1;
}
#ifdef IRQ_DEBUG
else
{
printk ("vboxadd: 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 (VBOX_FAILURE(rcVBox))
{
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
{
"rc = %d, header.rc = %d\n",
goto bail_out;
}
}
else
{
goto bail_out;
}
}
}
else
{
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 (VBOX_FAILURE(rcVBox))
{
"vboxadd: failed to allocate hypervisor info structure! rc = %d\n", 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
{
goto bail_out;
}
return 0;
if (req)
return 1;
}
/**
* Helper to free resources
*
*/
static void free_resources(void)
{
if (vboxDev)
{
if (vboxDev->hypervisorStart)
{
}
if (vboxDev->irqAckRequest)
{
}
if (vboxDev->pVMMDevMemory)
}
}
/**
* Module initialization
*
*/
{
int err;
int rcVBox;
if (vboxadd_cmc_init ())
{
return -ENODEV;
}
/*
* Detect PCI device
*/
if (!pcidev)
{
return -ENODEV;
}
if (err)
{
return -ENODEV;
}
/* register a character device */
{
vbox_major, err);
return -ENODEV;
}
/* if no major code was set, take the return value */
if (!vbox_major)
vbox_major = err;
/* allocate and initialize device extension */
if (!vboxDev)
{
goto fail;
}
/* get the IO port region */
/* get the memory region */
/* and size */
/* all resources found? */
{
goto fail;
}
/* request ownership of adapter memory */
{
goto fail;
}
/* map adapter memory into kernel address space and check version */
);
if (!vboxDev->pVMMDevMemory)
{
goto fail;
}
{
"vboxadd: invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
goto fail;
}
/* initialize VBGL subsystem */
if (VBOX_FAILURE(rcVBox))
{
goto fail;
}
/* report guest information to host, this must be done as the very first request */
sizeof(VMMDevReportGuestInfo),
);
if (VBOX_FAILURE(rcVBox))
{
goto fail;
}
/* report guest version to host, the VMMDev requires that to be done first */
#else
#endif
{
"vboxadd: error reporting guest info to host! rc = %d, header.rc = %d\n",
goto fail;
}
/* perform hypervisor address space reservation */
if (vboxadd_reserve_hypervisor())
{
/* we just ignore the error, no address window reservation, non fatal */
}
/* allocate a VMM request structure for use in the ISR */
sizeof(VMMDevEvents),
);
if (VBOX_FAILURE(rcVBox))
{
goto fail;
}
/* get ISR */
if (err)
{
goto fail;
}
/* some useful information for the user */
"vboxadd: major code: %d, "
"using irq %d, "
"io port 0x%x, memory at 0x%x (size %d bytes), "
"hypervisor window at 0x%p (size 0x%x bytes)\n",
/* successful return */
return 0;
fail:
return err;
}
/**
* Module termination
*
*/
{
vboxadd_cmc_fini ();
}
/* PCI hotplug structure */
{
{
},
{
/* empty entry */
}
};
int __gxx_personality_v0 = 0xdeadbeef;
/*
* Local Variables:
* c-mode: bsd
* indent-tabs-mode: nil
* c-plusplus: evil
* End:
*/