VBoxGuest-freebsd.c revision d643ca374eb34e60b13c043ca33e2cbe7fd47361
/* $Id$ */
/** @file
* VirtualBox Guest Additions Driver for FreeBSD.
*/
/*
* Copyright (C) 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.
*/
/** @todo r=bird: This must merge with SUPDrv-freebsd.c before long. The two
* source files should only differ on prefixes and the extra bits wrt to the
* pci device. I.e. it should be diffable so that fixes to one can easily be
* applied to the other. */
#include <machine/resource.h>
#include "VBoxGuestInternal.h"
#include <iprt/initterm.h>
/** The module name. */
#define DEVICE_NAME "vboxguest"
struct VBoxGuestDeviceState
{
/** file node minor code */
unsigned uMinor;
/** Resource ID of the I/O port */
int iIOPortResId;
/** Pointer to the I/O port resource. */
struct resource *pIOPortRes;
/** Start address of the IO Port. */
/** Resource ID of the MMIO area */
int iVMMDevMemResId;
/** Pointer to the MMIO resource. */
struct resource *pVMMDevMemRes;
/** Handle of the MMIO resource. */
/** Size of the memory area. */
/** Mapping of the register space */
void *pMMIOBase;
/** IRQ number */
int iIrqResId;
/** IRQ resource handle. */
/** Pointer to the IRQ handler. */
void *pfnIrqHandler;
/** VMMDev version */
};
/*
* Character device file handlers.
*/
static d_fdopen_t VBoxGuestFreeBSDOpen;
static d_close_t VBoxGuestFreeBSDClose;
static d_ioctl_t VBoxGuestFreeBSDIOCtl;
static d_write_t VBoxGuestFreeBSDWrite;
static d_read_t VBoxGuestFreeBSDRead;
/*
* IRQ related functions.
*/
static int VBoxGuestFreeBSDISR(void *pvState);
/*
* Available functions for kernel drivers.
*/
DECLVBGL(int) VBoxGuestFreeBSDServiceCall(void *pvSession, unsigned uCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
/*
* Device node entry points.
*/
static struct cdevsw g_VBoxGuestFreeBSDChrDevSW =
{
.d_flags = D_TRACKCLOSE,
};
/** Device extention & session data association structure. */
static VBOXGUESTDEVEXT g_DevExt;
/** List of cloned device. Managed by the kernel. */
static struct clonedevs *g_pVBoxGuestFreeBSDClones;
/** The dev_clone event handler tag. */
/**
* DEVFS event handler.
*/
static void VBoxGuestFreeBSDClone(void *pvArg, struct ucred *pCred, char *pszName, int cchName, struct cdev **ppDev)
{
int iUnit;
int rc;
/*
* One device node per user, si_drv1 points to the session.
*/
if (!ppDev)
return;
return;
{
return;
}
if (rc)
{
0644,
"vboxguest%d", iUnit);
if (*ppDev)
{
Log(("VBoxGuestFreeBSDClone: Created *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n",
}
else
}
else
Log(("VBoxGuestFreeBSDClone: Existing *ppDev=%p iUnit=%d si_drv1=%p si_drv2=%p\n",
}
/**
* File open handler
*
*/
#if __FreeBSD_version >= 700000
#else
#endif
{
int rc;
/*
* Try grab it (we don't grab the giant, remember).
*/
return EBUSY;
/*
* Create a new session.
*/
if (RT_SUCCESS(rc))
{
{
Log((DEVICE_NAME ":VBoxGuestFreeBSDOpen success: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
return 0;
}
}
return RTErrConvertToErrno(rc);
}
/**
* File close handler
*
*/
{
Log(("VBoxGuestFreeBSDClose: fFile=%#x iUnit=%d pSession=%p\n", fFile, minor2unit(minor(pDev)), pSession));
/*
* Close the session if it's still hanging on to the device...
*/
{
}
else
return 0;
}
/**
* IOCTL handler
*
*/
static int VBoxGuestFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
{
int rc = 0;
/*
* Validate the input.
*/
return EINVAL;
/*
* Validate the request wrapper.
*/
{
Log((DEVICE_NAME ": VBoxGuestFreeBSDIOCtl: bad request %lu size=%lu expected=%d\n", ulCmd, IOCPARM_LEN(ulCmd), sizeof(VBGLBIGREQ)));
return ENOTTY;
}
{
Log((DEVICE_NAME ": VBoxGuestFreeBSDIOCtl: bad magic %#x; pArg=%p Cmd=%lu.\n", ReqWrap->u32Magic, pvData, ulCmd));
return EINVAL;
}
{
printf(DEVICE_NAME ": VBoxGuestFreeBSDIOCtl: bad size %#x; pArg=%p Cmd=%lu.\n", ReqWrap->cbData, pvData, ulCmd);
return EINVAL;
}
/*
* Read the request.
*/
if (RT_UNLIKELY(!pvBuf))
{
Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap->cbData));
return ENOMEM;
}
if (RT_UNLIKELY(rc))
{
Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: copyin failed; pvBuf=%p pArg=%p Cmd=%lu. rc=%d\n", pvBuf, pvData, ulCmd, rc));
return EFAULT;
}
{
return EINVAL;
}
/*
* Process the IOCtl.
*/
if (RT_SUCCESS(rc))
{
rc = 0;
{
Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap->cbData));
}
if (cbDataReturned > 0)
{
if (RT_UNLIKELY(rc))
{
Log((DEVICE_NAME ":VBoxGuestFreeBSDIOCtl: copyout failed; pvBuf=%p pArg=%p Cmd=%lu. rc=%d\n", pvBuf, pvData, ulCmd, rc));
}
}
}
else
{
}
return rc;
}
{
return 0;
}
{
return 0;
}
{
/*
* Reserve what we did in VBoxGuestFreeBSDAttach.
*/
if (pState->pVMMDevMemRes)
if (pState->pIOPortRes)
RTR0Term();
return 0;
}
/**
* Interrupt service routine.
*
* @returns Whether the interrupt was from VMMDev.
* @param pvState Opaque pointer to the device state.
*/
static int VBoxGuestFreeBSDISR(void *pvState)
{
return fOurIRQ ? 0 : 1;
}
/**
* Sets IRQ for VMMDev.
*
* @returns FreeBSD error code.
* @param pDevice Pointer to the device info structure.
* @param pvState Pointer to the state info structure.
*/
{
int iResId = 0;
int rc = 0;
#if __FreeBSD_version >= 700000
rc = bus_setup_intr(pDevice, pState->pIrqRes, INTR_TYPE_BIO, NULL, (driver_intr_t *)VBoxGuestFreeBSDISR, pState, &pState->pfnIrqHandler);
#else
rc = bus_setup_intr(pDevice, pState->pIrqRes, INTR_TYPE_BIO, (driver_intr_t *)VBoxGuestFreeBSDISR, pState, &pState->pfnIrqHandler);
#endif
if (rc)
{
return VERR_DEV_IO_ERROR;
}
return VINF_SUCCESS;
}
/**
* Removes IRQ for VMMDev.
*
* @param pDevice Pointer to the device info structure.
* @param pvState Opaque pointer to the state info structure.
*/
{
{
}
}
{
int rc = VINF_SUCCESS;
int iResId = 0;
/*
* Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
*/
if (RT_FAILURE(rc))
{
LogFunc(("RTR0Init failed.\n"));
return ENXIO;
}
if (!pState)
{
if (!pState)
return ENOMEM;
}
/*
* Allocate I/O port resource.
*/
if (pState->uIOPortBase)
{
/*
* Map the MMIO region.
*/
{
/*
* Call the common device extension initializer.
*/
if (RT_SUCCESS(rc))
{
/*
* Add IRQ of VMMDev.
*/
if (RT_SUCCESS(rc))
{
/*
* Configure device cloning.
*/
{
return 0;
}
}
else
}
else
}
else
}
else
RTR0Term();
return ENXIO;
}
{
return 0;
return ENXIO;
}
static device_method_t VBoxGuestFreeBSDMethods[] =
{
/* Device interface. */
{0,0}
};
static driver_t VBoxGuestFreeBSDDriver =
{
sizeof(struct VBoxGuestDeviceState),
};
static devclass_t VBoxGuestFreeBSDClass;
#if 0/** @todo This shouldn't be needed. if it is, that means exceptions hasn't been disabled correctly. */
int __gxx_personality_v0 = 0xdeadbeef;
#endif
/* Common code that depend on g_DevExt. */
#include "VBoxGuestIDC-unix.c.h"