VirtualBox

Changeset 10836 in vbox for trunk/src/VBox/HostDrivers


Ignore:
Timestamp:
Jul 23, 2008 6:37:18 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
33621
Message:

supdrv: Fixed missing session clean on the mac when more than one client was active.

Location:
trunk/src/VBox/HostDrivers/Support
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h

    r10805 r10836  
    565565     * This is NIL_RTR0PROCESS for kernel sessions and valid for user ones. */
    566566    RTR0PROCESS                 R0Process;
     567#if defined(RT_OS_DARWIN)
     568    /** Pointer to the associated org_virtualbox_SupDrvClient object. */
     569    void                       *pvSupDrvClient;
     570    /** Whether this session has been opened or not. */
     571    bool                        fOpened;
     572#endif
    567573#if defined(RT_OS_OS2)
    568574    /** The system file number of this session. */
  • trunk/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp

    r10714 r10836  
    134134    virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
    135135    virtual bool start(IOService *pProvider);
     136    static  void sessionClose(RTPROCESS Process);
    136137    virtual IOReturn clientClose(void);
    137138    virtual IOReturn clientDied(void);
     
    341342
    342343    /*
    343      * Create a new session.
    344      */
    345     rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
    346     if (RT_SUCCESS(rc))
    347     {
     344     * Find the session created by org_virtualbox_SupDrvClient, fail
     345     * if no such session, and mark it as opened. We set the uid & gid
     346     * here too, since that is more straight forward at this point.
     347     */
     348    struct ucred *pCred = proc_ucred(pProcess);
     349    if (pCred)
     350    {
     351        RTUID           Uid = pCred->cr_uid;
     352        RTGID           Gid = pCred->cr_gid;
     353        RTPROCESS       Process = RTProcSelf();
     354        unsigned        iHash = SESSION_HASH(Process);
    348355        RTSPINLOCKTMP   Tmp = RTSPINLOCKTMP_INITIALIZER;
    349         unsigned        iHash;
    350         struct ucred   *pCred = proc_ucred(pProcess);
    351         if (pCred)
    352         {
    353             pSession->Uid = pCred->cr_uid;
    354             pSession->Gid = pCred->cr_gid;
    355         }
    356 
    357         /*
    358          * Insert it into the hash table.
    359          */
    360         iHash = SESSION_HASH(pSession->Process);
    361356        RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
    362         pSession->pNextHash = g_apSessionHashTab[iHash];
    363         g_apSessionHashTab[iHash] = pSession;
    364         ASMAtomicIncS32(&g_cSessions);
     357
     358        pSession = g_apSessionHashTab[iHash];
     359        if (pSession && pSession->Process != Process)
     360        {
     361            do pSession = pSession->pNextHash;
     362            while (pSession && pSession->Process != Process);
     363        }
     364        if (pSession)
     365        {
     366            if (!pSession->fOpened)
     367            {
     368                pSession->fOpened = true;
     369                pSession->Uid = Uid;
     370                pSession->Gid = Gid;
     371            }
     372            else
     373                rc = VERR_ALREADY_LOADED;
     374        }
     375        else
     376            rc = VERR_GENERAL_FAILURE;
     377
    365378        RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
    366379    }
     380    else
     381        rc = SUPDRV_ERR_INVALID_PARAM;
    367382
    368383#ifdef DEBUG_DARWIN_GIP
     
    380395static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
    381396{
    382     RTSPINLOCKTMP   Tmp = RTSPINLOCKTMP_INITIALIZER;
    383     const RTPROCESS Process = proc_pid(pProcess);
    384     const unsigned  iHash = SESSION_HASH(Process);
    385     PSUPDRVSESSION  pSession;
    386 
    387     Log(("VBoxDrvDarwinClose: pid=%d\n", (int)Process));
    388 
    389     /*
    390      * Remove from the hash table.
     397    Log(("VBoxDrvDarwinClose: pid=%d\n", (int)RTProcSelf()));
     398    Assert(proc_pid(pProcess) == (int)RTProcSelf());
     399
     400    /*
     401     * Hand the session closing to org_virtualbox_SupDrvClient.
     402     */
     403    org_virtualbox_SupDrvClient::sessionClose(RTProcSelf());
     404    return 0;
     405}
     406
     407
     408/**
     409 * Device I/O Control entry point.
     410 *
     411 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
     412 * @param   Dev         The device number (major+minor).
     413 * @param   iCmd        The IOCtl command.
     414 * @param   pData       Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
     415 * @param   fFlags      Flag saying we're a character device (like we didn't know already).
     416 * @param   pProcess    The process issuing this request.
     417 */
     418static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
     419{
     420    RTSPINLOCKTMP       Tmp = RTSPINLOCKTMP_INITIALIZER;
     421    const RTPROCESS     Process = proc_pid(pProcess);
     422    const unsigned      iHash = SESSION_HASH(Process);
     423    PSUPDRVSESSION      pSession;
     424
     425    /*
     426     * Find the session.
    391427     */
    392428    RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
    393429    pSession = g_apSessionHashTab[iHash];
     430    if (pSession && pSession->Process != Process)
     431    {
     432        do pSession = pSession->pNextHash;
     433        while (pSession && pSession->Process != Process);
     434    }
     435    RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
     436    if (!pSession)
     437    {
     438        OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
     439                    (int)Process, iCmd));
     440        return EINVAL;
     441    }
     442
     443    /*
     444     * Deal with the two high-speed IOCtl that takes it's arguments from
     445     * the session and iCmd, and only returns a VBox status code.
     446     */
     447    if (    iCmd == SUP_IOCTL_FAST_DO_RAW_RUN
     448        ||  iCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
     449        ||  iCmd == SUP_IOCTL_FAST_DO_NOP)
     450        return supdrvIOCtlFast(iCmd, &g_DevExt, pSession);
     451    return VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
     452}
     453
     454
     455/**
     456 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
     457 *
     458 * @returns Darwin errno.
     459 *
     460 * @param pSession  The session.
     461 * @param iCmd      The IOCtl command.
     462 * @param pData     Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
     463 * @param pProcess  The calling process.
     464 */
     465static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
     466{
     467    LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
     468
     469
     470    /*
     471     * Buffered or unbuffered?
     472     */
     473    PSUPREQHDR pHdr;
     474    user_addr_t pUser = 0;
     475    void *pvPageBuf = NULL;
     476    uint32_t cbReq = IOCPARM_LEN(iCmd);
     477    if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
     478    {
     479        pHdr = (PSUPREQHDR)pData;
     480        if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
     481        {
     482            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
     483            return EINVAL;
     484        }
     485        if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
     486        {
     487            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
     488            return EINVAL;
     489        }
     490        if (RT_UNLIKELY(    RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
     491                        ||  pHdr->cbIn < sizeof(*pHdr)
     492                        ||  pHdr->cbOut < sizeof(*pHdr)))
     493        {
     494            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
     495            return EINVAL;
     496        }
     497    }
     498    else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
     499    {
     500        /*
     501         * Get the header and figure out how much we're gonna have to read.
     502         */
     503        SUPREQHDR Hdr;
     504        pUser = (user_addr_t)*(void **)pData;
     505        int rc = copyin(pUser, &Hdr, sizeof(Hdr));
     506        if (RT_UNLIKELY(rc))
     507        {
     508            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
     509            return rc;
     510        }
     511        if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
     512        {
     513            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
     514            return EINVAL;
     515        }
     516        cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
     517        if (RT_UNLIKELY(    Hdr.cbIn < sizeof(Hdr)
     518                        ||  Hdr.cbOut < sizeof(Hdr)
     519                        ||  cbReq > _1M*16))
     520        {
     521            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
     522            return EINVAL;
     523        }
     524
     525        /*
     526         * Allocate buffer and copy in the data.
     527         */
     528        pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
     529        if (!pHdr)
     530            pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
     531        if (RT_UNLIKELY(!pHdr))
     532        {
     533            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
     534            return ENOMEM;
     535        }
     536        rc = copyin(pUser, pHdr, Hdr.cbIn);
     537        if (RT_UNLIKELY(rc))
     538        {
     539            OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
     540                        (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
     541            if (pvPageBuf)
     542                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
     543            else
     544                RTMemTmpFree(pHdr);
     545            return rc;
     546        }
     547    }
     548    else
     549    {
     550        Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
     551        return EINVAL;
     552    }
     553
     554    /*
     555     * Process the IOCtl.
     556     */
     557    int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
     558    if (RT_LIKELY(!rc))
     559    {
     560        /*
     561         * If not buffered, copy back the buffer before returning.
     562         */
     563        if (pUser)
     564        {
     565            uint32_t cbOut = pHdr->cbOut;
     566            if (cbOut > cbReq)
     567            {
     568                OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
     569                cbOut = cbReq;
     570            }
     571            rc = copyout(pHdr, pUser, cbOut);
     572            if (RT_UNLIKELY(rc))
     573                OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
     574                            pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
     575
     576            /* cleanup */
     577            if (pvPageBuf)
     578                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
     579            else
     580                RTMemTmpFree(pHdr);
     581        }
     582    }
     583    else
     584    {
     585        /*
     586         * The request failed, just clean up.
     587         */
     588        if (pUser)
     589        {
     590            if (pvPageBuf)
     591                IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
     592            else
     593                RTMemTmpFree(pHdr);
     594        }
     595
     596        Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
     597        rc = EINVAL;
     598    }
     599
     600    Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
     601    return rc;
     602}
     603
     604
     605/**
     606 * The SUPDRV IDC entry point.
     607 *
     608 * @returns VBox status code, see supdrvIDC.
     609 * @param   iReq        The request code.
     610 * @param   pReq        The request.
     611 */
     612int VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
     613{
     614    PSUPDRVSESSION  pSession;
     615
     616    /*
     617     * Some quick validations.
     618     */
     619    if (RT_UNLIKELY(!VALID_PTR(pReq)))
     620        return VERR_INVALID_POINTER;
     621
     622    pSession = pReq->pSession;
     623    if (pSession)
     624    {
     625        if (RT_UNLIKELY(!VALID_PTR(pSession)))
     626            return VERR_INVALID_PARAMETER;
     627        if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
     628            return VERR_INVALID_PARAMETER;
     629    }
     630    else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
     631        return VERR_INVALID_PARAMETER;
     632
     633    /*
     634     * Do the job.
     635     */
     636    return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
     637}
     638
     639
     640/**
     641 * Initializes any OS specific object creator fields.
     642 */
     643void VBOXCALL   supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
     644{
     645    NOREF(pObj);
     646    NOREF(pSession);
     647}
     648
     649
     650/**
     651 * Checks if the session can access the object.
     652 *
     653 * @returns true if a decision has been made.
     654 * @returns false if the default access policy should be applied.
     655 *
     656 * @param   pObj        The object in question.
     657 * @param   pSession    The session wanting to access the object.
     658 * @param   pszObjName  The object name, can be NULL.
     659 * @param   prc         Where to store the result when returning true.
     660 */
     661bool VBOXCALL   supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
     662{
     663    NOREF(pObj);
     664    NOREF(pSession);
     665    NOREF(pszObjName);
     666    NOREF(prc);
     667    return false;
     668}
     669
     670
     671bool VBOXCALL   supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
     672{
     673    NOREF(pDevExt);
     674    return false;
     675}
     676
     677
     678/**
     679 * Converts a supdrv error code to a darwin error code.
     680 *
     681 * @returns corresponding darwin error code.
     682 * @param   rc  supdrv error code (SUPDRV_ERR_* defines).
     683 */
     684static int VBoxDrvDarwinErr2DarwinErr(int rc)
     685{
     686    switch (rc)
     687    {
     688        case 0:                             return 0;
     689        case SUPDRV_ERR_GENERAL_FAILURE:    return EACCES;
     690        case SUPDRV_ERR_INVALID_PARAM:      return EINVAL;
     691        case SUPDRV_ERR_INVALID_MAGIC:      return EILSEQ;
     692        case SUPDRV_ERR_INVALID_HANDLE:     return ENXIO;
     693        case SUPDRV_ERR_INVALID_POINTER:    return EFAULT;
     694        case SUPDRV_ERR_LOCK_FAILED:        return ENOLCK;
     695        case SUPDRV_ERR_ALREADY_LOADED:     return EEXIST;
     696        case SUPDRV_ERR_PERMISSION_DENIED:  return EPERM;
     697        case SUPDRV_ERR_VERSION_MISMATCH:   return ENOSYS;
     698    }
     699
     700    return EPERM;
     701}
     702
     703
     704/** @todo move this to assembly where a simple "jmp printf" will to the trick. */
     705RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
     706{
     707    va_list     args;
     708    char        szMsg[512];
     709
     710    va_start(args, pszFormat);
     711    vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
     712    va_end(args);
     713
     714    szMsg[sizeof(szMsg) - 1] = '\0';
     715    printf("%s", szMsg);
     716    return 0;
     717}
     718
     719
     720/*
     721 *
     722 * org_virtualbox_SupDrv
     723 *
     724 */
     725
     726
     727/**
     728 * Initialize the object.
     729 */
     730bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
     731{
     732    LogFlow(("org_virtualbox_SupDrv::init([%p], %p)\n", this, pDictionary));
     733    if (IOService::init(pDictionary))
     734    {
     735        /* init members. */
     736        return true;
     737    }
     738    return false;
     739}
     740
     741
     742/**
     743 * Free the object.
     744 */
     745void org_virtualbox_SupDrv::free(void)
     746{
     747    LogFlow(("IOService::free([%p])\n", this));
     748    IOService::free();
     749}
     750
     751
     752/**
     753 * Check if it's ok to start this service.
     754 * It's always ok by us, so it's up to IOService to decide really.
     755 */
     756IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
     757{
     758    LogFlow(("org_virtualbox_SupDrv::probe([%p])\n", this));
     759    return IOService::probe(pProvider, pi32Score);
     760}
     761
     762
     763/**
     764 * Start this service.
     765 */
     766bool org_virtualbox_SupDrv::start(IOService *pProvider)
     767{
     768    LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
     769
     770    if (IOService::start(pProvider))
     771    {
     772        /* register the service. */
     773        registerService();
     774        return true;
     775    }
     776    return false;
     777}
     778
     779
     780/**
     781 * Stop this service.
     782 */
     783void org_virtualbox_SupDrv::stop(IOService *pProvider)
     784{
     785    LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
     786    IOService::stop(pProvider);
     787}
     788
     789
     790/**
     791 * Termination request.
     792 *
     793 * @return  true if we're ok with shutting down now, false if we're not.
     794 * @param   fOptions        Flags.
     795 */
     796bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
     797{
     798    bool fRc;
     799    LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
     800             KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
     801    if (    KMOD_INFO_NAME.reference_count != 0
     802        ||  ASMAtomicUoReadS32(&g_cSessions))
     803        fRc = false;
     804    else
     805        fRc = IOService::terminate(fOptions);
     806    LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
     807    return fRc;
     808}
     809
     810
     811/*
     812 *
     813 * org_virtualbox_SupDrvClient
     814 *
     815 */
     816
     817
     818/**
     819 * Initializer called when the client opens the service.
     820 */
     821bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
     822{
     823    LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
     824             this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
     825    AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
     826
     827    if (!OwningTask)
     828        return false;
     829    if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
     830    {
     831        m_Task = OwningTask;
     832        m_pSession = NULL;
     833        m_pProvider = NULL;
     834        return true;
     835    }
     836    return false;
     837}
     838
     839
     840/**
     841 * Start the client service.
     842 */
     843bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
     844{
     845    LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p) (cur pid=%d proc=%p)\n",
     846             this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
     847    AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
     848                    ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
     849                    false);
     850
     851    if (IOUserClient::start(pProvider))
     852    {
     853        m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
     854        if (m_pProvider)
     855        {
     856            Assert(!m_pSession);
     857
     858            /*
     859             * Create a new session.
     860             */
     861            int rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &m_pSession);
     862            if (RT_SUCCESS(rc))
     863            {
     864                m_pSession->fOpened = false;
     865                /* The Uid and Gid fields are set on open. */
     866
     867                /*
     868                 * Insert it into the hash table, checking that there isn't
     869                 * already one for this process first.
     870                 */
     871                unsigned iHash = SESSION_HASH(m_pSession->Process);
     872                RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     873                RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
     874
     875                PSUPDRVSESSION pCur = g_apSessionHashTab[iHash];
     876                if (pCur && pCur->Process != m_pSession->Process)
     877                {
     878                    do pCur = pCur->pNextHash;
     879                    while (pCur && pCur->Process != m_pSession->Process);
     880                }
     881                if (!pCur)
     882                {
     883                    m_pSession->pNextHash = g_apSessionHashTab[iHash];
     884                    g_apSessionHashTab[iHash] = m_pSession;
     885                    m_pSession->pvSupDrvClient = this;
     886                    ASMAtomicIncS32(&g_cSessions);
     887                    rc = VINF_SUCCESS;
     888                }
     889                else
     890                    rc = VERR_ALREADY_LOADED;
     891
     892                RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
     893                if (RT_SUCCESS(rc))
     894                {
     895                    Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
     896                    return true;
     897                }
     898
     899                LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
     900                supdrvCloseSession(&g_DevExt, m_pSession);
     901            }
     902
     903            m_pSession = NULL;
     904            LogFlow(("org_virtualbox_SupDrvClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
     905        }
     906        else
     907            LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
     908    }
     909    return false;
     910}
     911
     912
     913/**
     914 * Common worker for clientClose and VBoxDrvDarwinClose.
     915 *
     916 * It will
     917 */
     918/* static */ void org_virtualbox_SupDrvClient::sessionClose(RTPROCESS Process)
     919{
     920    /*
     921     * Look for the session.
     922     */
     923    const unsigned  iHash = SESSION_HASH(Process);
     924    RTSPINLOCKTMP   Tmp = RTSPINLOCKTMP_INITIALIZER;
     925    RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
     926    PSUPDRVSESSION  pSession = g_apSessionHashTab[iHash];
    394927    if (pSession)
    395928    {
     
    423956    if (!pSession)
    424957    {
    425         OSDBGPRINT(("VBoxDrvDarwinClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
    426                     (int)Process));
    427         return EINVAL;
     958        Log(("SupDrvClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
     959        return;
     960    }
     961
     962    /*
     963     * Remove it from the client object.
     964     */
     965    org_virtualbox_SupDrvClient *pThis = (org_virtualbox_SupDrvClient *)pSession->pvSupDrvClient;
     966    pSession->pvSupDrvClient = NULL;
     967    if (pThis)
     968    {
     969        Assert(pThis->m_pSession == pSession);
     970        pThis->m_pSession = NULL;
    428971    }
    429972
     
    432975     */
    433976    supdrvCloseSession(&g_DevExt, pSession);
    434     return 0;
    435 }
    436 
    437 
    438 /**
    439  * Device I/O Control entry point.
    440  *
    441  * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
    442  * @param   Dev         The device number (major+minor).
    443  * @param   iCmd        The IOCtl command.
    444  * @param   pData       Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
    445  * @param   fFlags      Flag saying we're a character device (like we didn't know already).
    446  * @param   pProcess    The process issuing this request.
    447  */
    448 static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
    449 {
    450     RTSPINLOCKTMP       Tmp = RTSPINLOCKTMP_INITIALIZER;
    451     const RTPROCESS     Process = proc_pid(pProcess);
    452     const unsigned      iHash = SESSION_HASH(Process);
    453     PSUPDRVSESSION      pSession;
    454 
    455     /*
    456      * Find the session.
    457      */
    458     RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
    459     pSession = g_apSessionHashTab[iHash];
    460     if (pSession && pSession->Process != Process)
    461     {
    462         do pSession = pSession->pNextHash;
    463         while (pSession && pSession->Process != Process);
    464     }
    465     RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
    466     if (!pSession)
    467     {
    468         OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
    469                     (int)Process, iCmd));
    470         return EINVAL;
    471     }
    472 
    473     /*
    474      * Deal with the two high-speed IOCtl that takes it's arguments from
    475      * the session and iCmd, and only returns a VBox status code.
    476      */
    477     if (    iCmd == SUP_IOCTL_FAST_DO_RAW_RUN
    478         ||  iCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
    479         ||  iCmd == SUP_IOCTL_FAST_DO_NOP)
    480         return supdrvIOCtlFast(iCmd, &g_DevExt, pSession);
    481     return VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
    482 }
    483 
    484 
    485 /**
    486  * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
    487  *
    488  * @returns Darwin errno.
    489  *
    490  * @param pSession  The session.
    491  * @param iCmd      The IOCtl command.
    492  * @param pData     Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
    493  * @param pProcess  The calling process.
    494  */
    495 static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
    496 {
    497     LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
    498 
    499 
    500     /*
    501      * Buffered or unbuffered?
    502      */
    503     PSUPREQHDR pHdr;
    504     user_addr_t pUser = 0;
    505     void *pvPageBuf = NULL;
    506     uint32_t cbReq = IOCPARM_LEN(iCmd);
    507     if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
    508     {
    509         pHdr = (PSUPREQHDR)pData;
    510         if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
    511         {
    512             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
    513             return EINVAL;
    514         }
    515         if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
    516         {
    517             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
    518             return EINVAL;
    519         }
    520         if (RT_UNLIKELY(    RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
    521                         ||  pHdr->cbIn < sizeof(*pHdr)
    522                         ||  pHdr->cbOut < sizeof(*pHdr)))
    523         {
    524             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
    525             return EINVAL;
    526         }
    527     }
    528     else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
    529     {
    530         /*
    531          * Get the header and figure out how much we're gonna have to read.
    532          */
    533         SUPREQHDR Hdr;
    534         pUser = (user_addr_t)*(void **)pData;
    535         int rc = copyin(pUser, &Hdr, sizeof(Hdr));
    536         if (RT_UNLIKELY(rc))
    537         {
    538             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
    539             return rc;
    540         }
    541         if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
    542         {
    543             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
    544             return EINVAL;
    545         }
    546         cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
    547         if (RT_UNLIKELY(    Hdr.cbIn < sizeof(Hdr)
    548                         ||  Hdr.cbOut < sizeof(Hdr)
    549                         ||  cbReq > _1M*16))
    550         {
    551             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
    552             return EINVAL;
    553         }
    554 
    555         /*
    556          * Allocate buffer and copy in the data.
    557          */
    558         pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
    559         if (!pHdr)
    560             pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
    561         if (RT_UNLIKELY(!pHdr))
    562         {
    563             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
    564             return ENOMEM;
    565         }
    566         rc = copyin(pUser, pHdr, Hdr.cbIn);
    567         if (RT_UNLIKELY(rc))
    568         {
    569             OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
    570                         (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
    571             if (pvPageBuf)
    572                 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
    573             else
    574                 RTMemTmpFree(pHdr);
    575             return rc;
    576         }
    577     }
    578     else
    579     {
    580         Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
    581         return EINVAL;
    582     }
    583 
    584     /*
    585      * Process the IOCtl.
    586      */
    587     int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
    588     if (RT_LIKELY(!rc))
    589     {
    590         /*
    591          * If not buffered, copy back the buffer before returning.
    592          */
    593         if (pUser)
    594         {
    595             uint32_t cbOut = pHdr->cbOut;
    596             if (cbOut > cbReq)
    597             {
    598                 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
    599                 cbOut = cbReq;
    600             }
    601             rc = copyout(pHdr, pUser, cbOut);
    602             if (RT_UNLIKELY(rc))
    603                 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
    604                             pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
    605 
    606             /* cleanup */
    607             if (pvPageBuf)
    608                 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
    609             else
    610                 RTMemTmpFree(pHdr);
    611         }
    612     }
    613     else
    614     {
    615         /*
    616          * The request failed, just clean up.
    617          */
    618         if (pUser)
    619         {
    620             if (pvPageBuf)
    621                 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
    622             else
    623                 RTMemTmpFree(pHdr);
    624         }
    625 
    626         Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
    627         rc = EINVAL;
    628     }
    629 
    630     Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
    631     return rc;
    632 }
    633 
    634 
    635 /**
    636  * The SUPDRV IDC entry point.
    637  *
    638  * @returns VBox status code, see supdrvIDC.
    639  * @param   iReq        The request code.
    640  * @param   pReq        The request.
    641  */
    642 int VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
    643 {
    644     PSUPDRVSESSION  pSession;
    645 
    646     /*
    647      * Some quick validations.
    648      */
    649     if (RT_UNLIKELY(!VALID_PTR(pReq)))
    650         return VERR_INVALID_POINTER;
    651 
    652     pSession = pReq->pSession;
    653     if (pSession)
    654     {
    655         if (RT_UNLIKELY(!VALID_PTR(pSession)))
    656             return VERR_INVALID_PARAMETER;
    657         if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
    658             return VERR_INVALID_PARAMETER;
    659     }
    660     else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
    661         return VERR_INVALID_PARAMETER;
    662 
    663     /*
    664      * Do the job.
    665      */
    666     return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
    667 }
    668 
    669 
    670 /**
    671  * Initializes any OS specific object creator fields.
    672  */
    673 void VBOXCALL   supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
    674 {
    675     NOREF(pObj);
    676     NOREF(pSession);
    677 }
    678 
    679 
    680 /**
    681  * Checks if the session can access the object.
    682  *
    683  * @returns true if a decision has been made.
    684  * @returns false if the default access policy should be applied.
    685  *
    686  * @param   pObj        The object in question.
    687  * @param   pSession    The session wanting to access the object.
    688  * @param   pszObjName  The object name, can be NULL.
    689  * @param   prc         Where to store the result when returning true.
    690  */
    691 bool VBOXCALL   supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
    692 {
    693     NOREF(pObj);
    694     NOREF(pSession);
    695     NOREF(pszObjName);
    696     NOREF(prc);
    697     return false;
    698 }
    699 
    700 
    701 bool VBOXCALL   supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
    702 {
    703     NOREF(pDevExt);
    704     return false;
    705 }
    706 
    707 
    708 /**
    709  * Converts a supdrv error code to a darwin error code.
    710  *
    711  * @returns corresponding darwin error code.
    712  * @param   rc  supdrv error code (SUPDRV_ERR_* defines).
    713  */
    714 static int VBoxDrvDarwinErr2DarwinErr(int rc)
    715 {
    716     switch (rc)
    717     {
    718         case 0:                             return 0;
    719         case SUPDRV_ERR_GENERAL_FAILURE:    return EACCES;
    720         case SUPDRV_ERR_INVALID_PARAM:      return EINVAL;
    721         case SUPDRV_ERR_INVALID_MAGIC:      return EILSEQ;
    722         case SUPDRV_ERR_INVALID_HANDLE:     return ENXIO;
    723         case SUPDRV_ERR_INVALID_POINTER:    return EFAULT;
    724         case SUPDRV_ERR_LOCK_FAILED:        return ENOLCK;
    725         case SUPDRV_ERR_ALREADY_LOADED:     return EEXIST;
    726         case SUPDRV_ERR_PERMISSION_DENIED:  return EPERM;
    727         case SUPDRV_ERR_VERSION_MISMATCH:   return ENOSYS;
    728     }
    729 
    730     return EPERM;
    731 }
    732 
    733 
    734 /** @todo move this to assembly where a simple "jmp printf" will to the trick. */
    735 RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
    736 {
    737     va_list     args;
    738     char        szMsg[512];
    739 
    740     va_start(args, pszFormat);
    741     vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
    742     va_end(args);
    743 
    744     szMsg[sizeof(szMsg) - 1] = '\0';
    745     printf("%s", szMsg);
    746     return 0;
    747 }
    748 
    749 
    750 /*
    751  *
    752  * org_virtualbox_SupDrv
    753  *
    754  */
    755 
    756 
    757 /**
    758  * Initialize the object.
    759  */
    760 bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
    761 {
    762     LogFlow(("org_virtualbox_SupDrv::init([%p], %p)\n", this, pDictionary));
    763     if (IOService::init(pDictionary))
    764     {
    765         /* init members. */
    766         return true;
    767     }
    768     return false;
    769 }
    770 
    771 
    772 /**
    773  * Free the object.
    774  */
    775 void org_virtualbox_SupDrv::free(void)
    776 {
    777     LogFlow(("IOService::free([%p])\n", this));
    778     IOService::free();
    779 }
    780 
    781 
    782 /**
    783  * Check if it's ok to start this service.
    784  * It's always ok by us, so it's up to IOService to decide really.
    785  */
    786 IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
    787 {
    788     LogFlow(("org_virtualbox_SupDrv::probe([%p])\n", this));
    789     return IOService::probe(pProvider, pi32Score);
    790 }
    791 
    792 
    793 /**
    794  * Start this service.
    795  */
    796 bool org_virtualbox_SupDrv::start(IOService *pProvider)
    797 {
    798     LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
    799 
    800     if (IOService::start(pProvider))
    801     {
    802         /* register the service. */
    803         registerService();
    804         return true;
    805     }
    806     return false;
    807 }
    808 
    809 
    810 /**
    811  * Stop this service.
    812  */
    813 void org_virtualbox_SupDrv::stop(IOService *pProvider)
    814 {
    815     LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
    816     IOService::stop(pProvider);
    817 }
    818 
    819 
    820 /**
    821  * Termination request.
    822  *
    823  * @return  true if we're ok with shutting down now, false if we're not.
    824  * @param   fOptions        Flags.
    825  */
    826 bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
    827 {
    828     bool fRc;
    829     LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
    830              KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
    831     if (    KMOD_INFO_NAME.reference_count != 0
    832         ||  ASMAtomicUoReadS32(&g_cSessions))
    833         fRc = false;
    834     else
    835         fRc = IOService::terminate(fOptions);
    836     LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
    837     return fRc;
    838 }
    839 
    840 
    841 /*
    842  *
    843  * org_virtualbox_SupDrvClient
    844  *
    845  */
    846 
    847 
    848 /**
    849  * Initializer called when the client opens the service.
    850  */
    851 bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
    852 {
    853     LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x)\n", this, OwningTask, pvSecurityId, u32Type));
    854 
    855     if (!OwningTask)
    856         return false;
    857     if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
    858     {
    859         m_Task = OwningTask;
    860         m_pSession = NULL;
    861         m_pProvider = NULL;
    862         return true;
    863     }
    864     return false;
    865 }
    866 
    867 
    868 /**
    869  * Start the client service.
    870  */
    871 bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
    872 {
    873     LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p)\n", this, pProvider));
    874     if (IOUserClient::start(pProvider))
    875     {
    876         m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
    877         if (m_pProvider)
    878         {
    879             /* this is where we could create the section. */
    880             return true;
    881         }
    882         LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
    883     }
    884     return false;
    885977}
    886978
     
    891983IOReturn org_virtualbox_SupDrvClient::clientClose(void)
    892984{
    893     LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p])\n", this));
     985    LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
     986    AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
     987
     988    /*
     989     * Clean up the session if it's still around.
     990     *
     991     * We cannot rely 100% on close, and in the case of a dead client
     992     * we'll end up hanging inside vm_map_remove() if we postpone it.
     993     */
     994    if (m_pSession)
     995    {
     996        sessionClose(RTProcSelf());
     997        Assert(!m_pSession);
     998    }
    894999
    8951000    m_pProvider = NULL;
     
    9011006
    9021007/**
    903  * The client exits abnormally / forgets to do cleanups.
     1008 * The client exits abnormally / forgets to do cleanups. (logging)
    9041009 */
    9051010IOReturn org_virtualbox_SupDrvClient::clientDied(void)
     
    9081013             this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
    9091014
    910     /*
    911      * Do early session cleanup (if there is a session) so
    912      * we avoid hanging in vm_map_remove().
    913      */
    914     const RTR0PROCESS   R0Process = (RTR0PROCESS)m_Task;
    915     RTSPINLOCKTMP       Tmp = RTSPINLOCKTMP_INITIALIZER;
    916     RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
    917     for (unsigned i = 0; i < RT_ELEMENTS(g_apSessionHashTab); i++)
    918     {
    919         for (PSUPDRVSESSION pSession = g_apSessionHashTab[i]; pSession; pSession = pSession->pNextHash)
    920         {
    921             Log2(("pSession=%p R0Process=%p (=? %p)\n", pSession, pSession->R0Process, R0Process));
    922             if (pSession->R0Process == R0Process)
    923             {
    924                 /*
    925                  * It is safe to leave the spinlock here; the session shouldn't be able
    926                  * to go away while we're cleaning it up, changes to pNextHash will not
    927                  * harm us, and new sessions can't possibly be added for this process.
    928                  */
    929                 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
    930                 supdrvCleanupSession(&g_DevExt, pSession);
    931                 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
    932             }
    933         }
    934     }
    935     RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
    936 
    937     /* IOUserClient::clientDied() calls close... */
     1015    /* IOUserClient::clientDied() calls clientClose, so we'll just do the work there. */
    9381016    return IOUserClient::clientDied();
    9391017}
     
    9411019
    9421020/**
    943  * Terminate the service (initiate the destruction).
     1021 * Terminate the service (initiate the destruction). (logging)
    9441022 */
    9451023bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
     
    9511029
    9521030/**
    953  * The final stage of the client service destruction.
     1031 * The final stage of the client service destruction. (logging)
    9541032 */
    9551033bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
     
    9611039
    9621040/**
    963  * Stop the client service.
     1041 * Stop the client service. (logging)
    9641042 */
    9651043void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
  • trunk/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp

    r10256 r10836  
    7676
    7777
    78 int suplibOsInit(size_t cbReserve)
    79 {
    80     /*
    81      * Check if already initialized.
    82      */
    83     if (g_hDevice >= 0)
    84         return VINF_SUCCESS;
    85 
    86     /*
    87      * Open the IOKit client first - The first step is finding the service.
    88      */
    89     mach_port_t MasterPort;
    90     kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
    91     if (kr != kIOReturnSuccess)
    92     {
    93         LogRel(("IOMasterPort -> %d\n", kr));
    94         return VERR_GENERAL_FAILURE;
    95     }
    96 
    97     CFDictionaryRef ClassToMatch = IOServiceMatching(IOCLASS_NAME);
    98     if (!ClassToMatch)
    99     {
    100         LogRel(("IOServiceMatching(\"%s\") failed.\n", IOCLASS_NAME));
    101         return VERR_GENERAL_FAILURE;
    102     }
    103 
    104     /* Create an io_iterator_t for all instances of our drivers class that exist in the IORegistry. */
    105     io_iterator_t Iterator;
    106     kr = IOServiceGetMatchingServices(g_MasterPort, ClassToMatch, &Iterator);
    107     if (kr != kIOReturnSuccess)
    108     {
    109         LogRel(("IOServiceGetMatchingServices returned %d\n", kr));
    110         return VERR_GENERAL_FAILURE;
    111     }
    112 
    113     /* Get the first item in the iterator and release it. */
    114     io_service_t ServiceObject = IOIteratorNext(Iterator);
    115     IOObjectRelease(Iterator);
    116     if (!ServiceObject)
    117     {
    118         LogRel(("SUP: Couldn't find any matches. The kernel module is probably not loaded.\n"));
    119         return VERR_VM_DRIVER_NOT_INSTALLED;
    120     }
    121 
    122     /*
    123      * Open the service.
    124      * This will cause the user client class in SUPDrv-darwin.cpp to be instantiated.
    125      */
    126     kr = IOServiceOpen(ServiceObject, mach_task_self(), 0, &g_Connection);
    127     IOObjectRelease(ServiceObject);
    128     if (kr != kIOReturnSuccess)
    129     {
    130         LogRel(("SUP: IOServiceOpen returned %d. Driver open failed.\n", kr));
    131         return VERR_VM_DRIVER_OPEN_ERROR;
    132     }
    133 
    134     /*
    135      * Now, try open the BSD device.
     78/**
     79 * Opens the BSD device node.
     80 *
     81 * @returns VBox status code.
     82 */
     83static int suplibDarwinOpenDevice(void)
     84{
     85    /*
     86     * Open the BSD device.
     87     * This will connect to the session created when the SupDrvClient was
     88     * started, so it has to be done after opening the service (IOC v9.1+).
    13689     */
    13790    g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
     
    148101        }
    149102        LogRel(("SUP: Failed to open \"%s\", errno=%d, rc=%Vrc\n", DEVICE_NAME, errno, rc));
    150 
    151         kr = IOServiceClose(g_Connection);
    152         if (kr != kIOReturnSuccess)
    153             LogRel(("Warning: IOServiceClose(%p) returned %d\n", g_Connection, kr));
    154103        return rc;
    155104    }
     
    160109    if (fcntl(g_hDevice, F_SETFD, FD_CLOEXEC) != 0)
    161110    {
    162         int rc = errno;
    163         LogRel(("suplibOSInit: setting FD_CLOEXEC failed, errno=%d\n", rc));
     111        int err = errno;
     112        int rc = RTErrConvertFromErrno(err);
     113        LogRel(("suplibOSInit: setting FD_CLOEXEC failed, errno=%d (%Rrc)\n", err, rc));
    164114        close(g_hDevice);
    165115        g_hDevice = -1;
    166         return RTErrConvertFromErrno(rc);
    167     }
    168 
    169     /*
    170      * We're done.
    171      */
     116        return rc;
     117    }
     118
     119    return VINF_SUCCESS;
     120}
     121
     122
     123/**
     124 * Opens the IOKit service, instantiating org_virtualbox_SupDrvClient.
     125 *
     126 * @returns VBox status code.
     127 */
     128static int suplibDarwinOpenService(void)
     129{
     130    /*
     131     * Open the IOKit client first - The first step is finding the service.
     132     */
     133    mach_port_t MasterPort;
     134    kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
     135    if (kr != kIOReturnSuccess)
     136    {
     137        LogRel(("IOMasterPort -> %d\n", kr));
     138        return VERR_GENERAL_FAILURE;
     139    }
     140
     141    CFDictionaryRef ClassToMatch = IOServiceMatching(IOCLASS_NAME);
     142    if (!ClassToMatch)
     143    {
     144        LogRel(("IOServiceMatching(\"%s\") failed.\n", IOCLASS_NAME));
     145        return VERR_GENERAL_FAILURE;
     146    }
     147
     148    /* Create an io_iterator_t for all instances of our drivers class that exist in the IORegistry. */
     149    io_iterator_t Iterator;
     150    kr = IOServiceGetMatchingServices(g_MasterPort, ClassToMatch, &Iterator);
     151    if (kr != kIOReturnSuccess)
     152    {
     153        LogRel(("IOServiceGetMatchingServices returned %d\n", kr));
     154        return VERR_GENERAL_FAILURE;
     155    }
     156
     157    /* Get the first item in the iterator and release it. */
     158    io_service_t ServiceObject = IOIteratorNext(Iterator);
     159    IOObjectRelease(Iterator);
     160    if (!ServiceObject)
     161    {
     162        LogRel(("SUP: Couldn't find any matches. The kernel module is probably not loaded.\n"));
     163        return VERR_VM_DRIVER_NOT_INSTALLED;
     164    }
     165
     166    /*
     167     * Open the service.
     168     *
     169     * This will cause the user client class in SUPDrv-darwin.cpp to be
     170     * instantiated and create a session for this process.
     171     */
     172    kr = IOServiceOpen(ServiceObject, mach_task_self(), 0, &g_Connection);
     173    IOObjectRelease(ServiceObject);
     174    if (kr != kIOReturnSuccess)
     175    {
     176        LogRel(("SUP: IOServiceOpen returned %d. Driver open failed.\n", kr));
     177        return VERR_VM_DRIVER_OPEN_ERROR;
     178    }
     179
     180    return VINF_SUCCESS;
     181}
     182
     183int suplibOsInit(size_t cbReserve)
     184{
    172185    NOREF(cbReserve);
    173     return VINF_SUCCESS;
     186
     187    /*
     188     * Check if already initialized.
     189     */
     190    if (g_hDevice >= 0)
     191        return VINF_SUCCESS;
     192
     193    /*
     194     * Do the job.
     195     */
     196    int rc = suplibDarwinOpenService();
     197    if (RT_SUCCESS(rc))
     198    {
     199        rc = suplibDarwinOpenDevice();
     200        if (RT_FAILURE(rc))
     201        {
     202            kern_return_t kr = IOServiceClose(g_Connection);
     203            if (kr != kIOReturnSuccess)
     204            {
     205                LogRel(("Warning: IOServiceClose(%p) returned %d\n", g_Connection, kr));
     206                AssertFailed();
     207            }
     208            g_Connection = NULL;
     209        }
     210    }
     211
     212    return rc;
    174213}
    175214
     
    178217{
    179218    /*
    180      * Check if we're initited at all.
    181      */
    182     if (g_hDevice >= 0)
    183     {
    184         if (close(g_hDevice))
    185             AssertFailed();
    186         g_hDevice = -1;
    187     }
    188 
    189     /*
    190      * Close the connection to the IOService and destroy the connection handle.
     219     * Close the connection to the IOService.
     220     * This will cause the SUPDRVSESSION to be closed (starting IOC 9.1).
    191221     */
    192222    if (g_Connection)
     
    201231    }
    202232
     233    /*
     234     * Check if we're initited at all.
     235     */
     236    if (g_hDevice >= 0)
     237    {
     238        if (close(g_hDevice))
     239            AssertFailed();
     240        g_hDevice = -1;
     241    }
     242
    203243    return VINF_SUCCESS;
    204244}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette