SUPDrv-darwin.cpp revision 94eb56dfd835606c6b562f97f889be14cffdcd9a
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * VirtualBox Support Driver - Darwin Specific Code.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Copyright (C) 2006-2014 Oracle Corporation
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * available from http://www.virtualbox.org. This file is free software;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * you can redistribute it and/or modify it under the terms of the GNU
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * General Public License (GPL) as published by the Free Software
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * The contents of this file may alternatively be used under the terms
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * of the Common Development and Distribution License Version 1.0
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * VirtualBox OSE distribution, in which case the provisions of the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * CDDL are applicable instead of those of the GPL.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * You may elect to license modified versions of this file under the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * terms and conditions of either the GPL or the CDDL or both.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/*******************************************************************************
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync* Header Files *
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync*******************************************************************************/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Deal with conflicts first.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * PVM - BSD mess, that FreeBSD has correct a long time ago.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#include <IOKit/bluetooth/IOBluetoothHIDDriverTypes.h>
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/*******************************************************************************
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync* Defined Constants And Macros *
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync*******************************************************************************/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The system device node name. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The user device node name. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/*******************************************************************************
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync* Internal Functions *
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync*******************************************************************************/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic IOReturn VBoxDrvDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncstatic void vboxdrvDarwinResolveSymbols(void);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/*******************************************************************************
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync* Structures and Typedefs *
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync*******************************************************************************/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * The service class.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * This is just a formality really.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync virtual void free(void);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncOSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * An attempt at getting that clientDied() notification.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * I don't think it'll work as I cannot figure out where/what creates the correct
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * port right.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncclass org_virtualbox_SupDrvClient : public IOUserClient
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync OSDeclareDefaultStructors(org_virtualbox_SupDrvClient);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncOSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/*******************************************************************************
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync* Global Variables *
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync*******************************************************************************/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Declare the module stuff.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncextern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncextern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncKMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncDECLHIDDEN(kmod_start_func_t *) _realmain = VBoxDrvDarwinStart;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsyncDECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxDrvDarwinStop;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Device extention & session data association structure.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * The character device switch table for the driver.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /*.d_type = */0
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Major device number. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Registered devfs device handle for the system device. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Registered devfs device handle for the user device. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Spinlock protecting g_apSessionHashTab. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Hash table */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Calculates the index into g_apSessionHashTab.*/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The number of open sessions. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The notifier handle for the sleep callback handler. */
#ifdef SUPDRV_WITH_MSR_PROBER
int rc;
#ifdef DEBUG
if (g_iMajorDeviceNo >= 0)
#ifdef VBOX_WITH_HARDENING
if (g_hDevFsDeviceSys)
if (g_hDevFsDeviceUsr)
LogRel(("VBoxDrv: version " VBOX_VERSION_STRING " r%d; IOCtl version %#x; IDC version %#x; dev major=%d\n",
return KMOD_RETURN_SUCCESS;
LogRel(("VBoxDrv: devfs_make_node(makedev(%d,1),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME_USR));
LogRel(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME_SYS));
return KMOD_RETURN_FAILURE;
static void vboxdrvDarwinResolveSymbols(void)
LogRel(("VBoxDrv: failed to resolve vmx stuff: vmx_resume=%Rrc vmx_suspend=%Rrc vmx_use_count=%Rrc", rc1, rc2, rc3));
#ifdef SUPDRV_WITH_MSR_PROBER
int rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "rdmsr_carefully", (void **)&g_pfnRdMsrCarefully);
rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "rdmsr64_carefully", (void **)&g_pfnRdMsr64Carefully);
# ifdef RT_ARCH_AMD64 /* Missing 64 in name, so if implemented on 32-bit it could have different signature. */
rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "wrmsr_carefully", (void **)&g_pfnWrMsr64Carefully);
int rc;
if (g_pSleepNotifier)
#ifdef DEBUG
return KMOD_RETURN_SUCCESS;
#ifdef DEBUG_DARWIN_GIP
return EACCES;
return EIO;
if (pCred)
if (pSession)
#ifdef DEBUG_DARWIN_GIP
OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
while (pSession && (pSession->Process != Process || pSession->fUnrestricted != fUnrestricted || !pSession->fOpened))
OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#lx\n",
return EINVAL;
int rc;
&& fUnrestricted)
return rc;
static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
return EINVAL;
return EINVAL;
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
return EINVAL;
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
return rc;
return EINVAL;
return EINVAL;
if (!pHdr)
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
return ENOMEM;
if (pvPageBuf)
return rc;
return EINVAL;
if (pUser)
OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
if (pvPageBuf)
if (pUser)
if (pvPageBuf)
Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
return rc;
return VERR_INVALID_POINTER;
if (pSession)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
IOReturn VBoxDrvDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType, IOService * /* pProvider */, void * /* pvMessageArgument */, vm_size_t /* argSize */)
#ifdef VBOX_WITH_HOST_VMX
int rc;
&& g_pVmxUseCount)
if (fEnable)
host_vmxoff();
return rc;
return VERR_NOT_SUPPORTED;
#ifdef VBOX_WITH_HOST_VMX
* Note! The host_vmxon/off code is still race prone since, but this is
if ( g_pVmxUseCount
&& *g_pVmxUseCount > 0)
#ifdef VBOX_WITH_HOST_VMX
if ( fSuspended
&& g_pfnVmxResume)
if (pEntry)
int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
return VERR_NOT_SUPPORTED;
int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
return VERR_NOT_SUPPORTED;
int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
return VERR_NOT_SUPPORTED;
#ifdef SUPDRV_WITH_MSR_PROBER
typedef struct SUPDRVDARWINMSRARGS
int rc;
static DECLCALLBACK(void) supdrvDarwinMsrProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
else if (g_pfnRdMsrCarefully)
return VERR_NOT_SUPPORTED;
return rc;
return VERR_ACCESS_DENIED;
return VINF_SUCCESS;
static DECLCALLBACK(void) supdrvDarwinMsrProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
if (!g_pfnWrMsr64Carefully)
return VERR_NOT_SUPPORTED;
return rc;
return VERR_ACCESS_DENIED;
return VINF_SUCCESS;
static DECLCALLBACK(void) supdrvDarwinMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
if (!fFaster)
if (rcBefore >= 0)
if (!fFaster)
ASMReloadCR3();
ASMNopPause();
return VERR_NOT_SUPPORTED;
return VINF_SUCCESS;
static void supdrvDarwinResumeBluetoothKbd(void)
if (pDictionary)
if (pIter)
static void supdrvDarwinResumeBuiltinKbd(void)
if (pDictionary)
if (pIter)
switch (rc)
case VINF_SUCCESS: return 0;
return EPERM;
bool fRc;
fRc = false;
return fRc;
bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
if (!OwningTask)
if (m_pProvider)
if (!pCur)
Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
if (pSession)
while (pSession)
if (!pSession)
if (pThis)
LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
if (m_pSession)
terminate();
return kIOReturnSuccess;