VirtualBox

Changeset 10836

Show
Ignore:
Timestamp:
07/23/08 20:37:18 (3 months ago)
Author:
vboxsync
Message:

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

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • 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