hgcmcall.c revision b357df727b216b85d4517efecf466a7b14c2e80c
/** @file
*
* vboxadd -- VirtualBox Guest Additions for Linux
* hgcmcall.c -- wrapper for hgcm calls from user space
*/
/*
* 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 */
#include "vboxmod.h"
#include "waitcompat.h"
/**
* Get the IOCTL structure from user space
*
* @returns 0 on success, Linux error code on failure
* @param cParms The number of parameters to the HGCM call
* @param pUser User space pointer to the data to be copied
* @retval hgcmR3Ret Where to store the structure allocated on success
*/
{
/* Allocate space for those call parameters. */
if (!hgcmR3)
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cannot allocate memory!\n"));
return -ENOMEM;
}
/* Get the call parameters from user space. */
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: copy_from_user failed!\n"));
return -EFAULT;
}
return 0;
}
/**
* Read the IOCTL parameters from the calling user space application and repack them into
* a structure in kernel space. This repacking is needed because the structure contains pointers
* which will no longer be valid after it is copied from user to kernel space.
*
* @returns 0 on success, or a Linux error code on failure
* @param hgcmR3 The user space ioctl structure, copied into kernel space
* @retval hgcmR0Ret The kernel space structure set up in this function
* @retval ppu8PointerDataRet A buffer storing the parameters copied from user space
*/
{
int i;
/* Allocate the structure which we will pass to the kernel space HGCM call. */
if (!hgcmR0)
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: cannot allocate memory!\n"));
return -ENOMEM;
}
/* Set up the structure header */
/* Calculate the total size of pointer space. Will normally be for a single pointer */
{
{
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
break;
break;
default:
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: unsupported or unknown parameter type\n"));
return -EINVAL;
}
}
/* Reconstruct the pointer parameter data in kernel space */
if (pu8PointerData == NULL)
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: out of memory allocating %d bytes for pointer data\n",
return -ENOMEM;
}
/* Copy and translate the parameters from the user space structure to the kernel space
structure. */
{
{
/* This pointer type means that we are sending data to the host or both
sending and reading data. */
void *pvR3LinAddr
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: copy_from_user failed!\n"));
return -EFAULT;
}
}
{
/* This type of pointer means that we are reading data from the host. */
}
else
{
/* If it is not a pointer, then it is a 32bit or 64bit value */
}
}
return 0;
}
/**
* Dump the contents of an hgcm call info structure to the back door logger
*
* @param hgcmR0 The structure to dump.
*/
{
#ifdef DEBUG_Michael
int i;
{
{
case VMMDevHGCMParmType_32bit:
Log(("VBOXGUEST_IOCTL_HGCM_CALL: parameter %d is of type 32bit: %u\n",
break;
case VMMDevHGCMParmType_64bit:
Log(("VBOXGUEST_IOCTL_HGCM_CALL: parameter %d is of type 64bit: %lu\n",
break;
Log(("VBOXGUEST_IOCTL_HGCM_CALL: parameter %d is of type LinAddr, size %u: %.*s...\n",
i,
break;
Log(("VBOXGUEST_IOCTL_HGCM_CALL: parameter %d is of type LinAddr_In, size %u: %.*s...\n",
i,
break;
Log(("VBOXGUEST_IOCTL_HGCM_CALL: parameter %d is of type LinAddr_Out, size %u: %.*s...\n",
i,
break;
default:
Log(("VBOXGUEST_IOCTL_HGCM_CALL: parameter %d is of unknown type!", i));
}
}
#endif /* defined DEBUG_Michael */
}
/**
* Copy the return parameters from the IOCTL call from kernel to user space and update the
* user space ioctl structure with the new parameter information.
*
* @returns 0 on success, a Linux error code on failure
* @param hgcmR3 The user space structure to be updated and copied back to user space, including
* the user space addresses of the buffers for the parameters
* @param hgcmR0 The kernel space structure pointing to the data to be returned
*/
{
int i;
{
{
/* We are sending data to the host or sending and reading. */
void *pvR3LinAddr
void *pvR0LinAddr
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: copy_to_user failed!\n"));
return -EFAULT;
}
}
{
/* If it is not a pointer, then it is a 32bit or 64bit value */
}
}
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: copy_to_user failed!\n"));
return -EFAULT;
}
return 0;
}
/**
* This IOCTL wrapper allows the guest to make an HGCM call from user space. The
* OS-independant part of the Guest Additions already contain code for making an
* HGCM call from the guest, but this code assumes that the call is made from the
* kernel's address space. So before calling it, we have to copy all parameters
* to the HGCM call from user space to kernel space and reconstruct the structures
* passed to the call (which include pointers to other memory) inside the kernel's
* address space.
*
* @returns 0 on success or Linux error code on failure
* @param arg User space pointer to the call data structure
*/
{
int rc;
/* Get the call header from user space to see how many call parameters there are. */
{
LogRel(("VBOXGUEST_IOCTL_HGCM_CALL: copy_from_user failed!\n"));
return -EFAULT;
}
/* Copy the ioctl structure from user to kernel space. */
if (rc != 0)
{
return rc;
}
/* Copy the ioctl parameters from user to kernel space and repack the kernel space
structure to point to the copied parameters. */
if (rc != 0)
{
return rc;
}
/* Just to make sure that all that was successful, we read through the contents
of the structure we just copied and print them to the log. */
/* Call the internal VBoxGuest ioctl interface with the ioctl structure we have just copied. */
if (VBOX_FAILURE(rc))
{
}
else
{
/* Copy the return parameters back to user space and update the user space structure. */
}
return rc;
}