VBoxGuest-freebsd.c revision e1ed9baf425f4c757302ec417a815aab945fdbf0
/* $Id$ */
/** @file
* VirtualBox Guest Additions Driver for FreeBSD.
*/
/*
* Copyright (C) 2007-2015 Oracle Corporation
*
* 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.
*/
/** @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>
#ifdef PVM
#endif
#include "VBoxGuestInternal.h"
#include <iprt/initterm.h>
/** The module name. */
#define DEVICE_NAME "vboxguest"
struct VBoxGuestDeviceState
{
/** 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;
static d_poll_t VBoxGuestFreeBSDPoll;
/*
* 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);
#ifndef D_NEEDMINOR
# define D_NEEDMINOR 0
#endif
/*
* Device node entry points.
*/
static struct cdevsw g_VBoxGuestFreeBSDChrDevSW =
{
};
/** 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. */
/** Reference counter */
/** selinfo structure used for polling. */
/**
* 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;
iUnit = -1;
return;
if (iUnit >= 256)
{
return;
}
if (rc)
{
0664,
"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
*
*/
{
/*
* Close the session if it's still hanging on to the device...
*/
{
/* Don't use destroy_dev here because it may sleep resulting in a hanging user process. */
}
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;
}
{
int fEventsProcessed;
}
{
}
else
{
fEventsProcessed = 0;
}
return fEventsProcessed;
}
{
return 0;
}
{
return 0;
}
{
if (cUsers > 0)
return EBUSY;
/*
* Reverse what we did in VBoxGuestFreeBSDAttach.
*/
if (g_VBoxGuestFreeBSDEHTag != NULL)
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;
}
{
/*
* Wake up poll waiters.
*/
}
/**
* 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 | INTR_MPSAFE, 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;
cUsers = 0;
/*
* Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
*/
if (RT_FAILURE(rc))
{
LogFunc(("RTR0Init failed.\n"));
return ENXIO;
}
/*
* Allocate I/O port resource.
*/
if (pState->uIOPortBase)
{
/*
* Map the MMIO region.
*/
{
/*
* Call the common device extension initializer.
*/
#if ARCH_BITS == 64
#else
#endif
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;
/* Common code that depend on g_DevExt. */
#include "VBoxGuestIDC-unix.c.h"