Ejemplo n.º 1
0
void
dnsproxy_answer(PNATState pData, struct socket *so, struct mbuf *m)
#endif
{
#ifndef VBOX
    char buf[MAX_BUFSPACE];
    int byte = 0;
    struct request *query = NULL;

    /* Reschedule event */
    event_add((struct event *)arg, NULL);

    /* read packet from socket */
    if ((byte = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL)) == -1) {
        LogRel(("recvfrom failed: %s\n", strerror(errno)));
        ++dropped_answers;
        return;
    }

    /* check for minimum dns packet length */
    if (byte < 12) {
        LogRel(("answer too short\n"));
        ++dropped_answers;
        return;
    }

    /* find corresponding query */
    if ((query = hash_find_request(pData, *((unsigned short *)&buf))) == NULL) {
        ++late_answers;
        return;
    }
    event_del(&query->timeout);

    hash_remove_request(pData, query);

    /* restore original query id */
    memcpy(&buf[0], &query->clientid, 2);

    if (sendto(sock_query, buf, (unsigned int)byte, 0,
                (struct sockaddr *)&query->client,
                sizeof(struct sockaddr_in)) == -1) {
        LogRel(("sendto failed: %s\n", strerror(errno)));
        ++dropped_answers;
    }
    else
        ++answered_queries;

    free(query);
#else /* VBOX */

    char *buf = NULL;
    int byte = 0;
    struct request *query = NULL;

    AssertPtr(pData);

    /* XXX: mbuf->data points to ??? */
    byte = m->m_len;
    buf = mtod(m, char *);

    /* check for minimum dns packet length */
    if (byte < 12) {
        LogRel(("NAT: Answer too short\n"));
        ++dropped_answers;
        return;
    }

    /* find corresponding query (XXX: but see below) */
    query = hash_find_request(pData, *((unsigned short *)buf));

    if (query == NULL)
    {
        /* XXX: if we haven't found anything for this request ...
         * What we are expecting later?
         */
        ++late_answers;
        so->so_expire = curtime + SO_EXPIREFAST;
        Log2(("NAT: query wasn't found\n"));
        return;
    }

    /*
     * XXX: The whole hash thing is pretty meaningless right now since
     * we use a separate socket for each request, so we already know
     * the answer.
     *
     * If the answer is not what we expect it to be, then it's
     * probably a stray or malicious reply and we'd better not free a
     * query owned by some other socket - that would cause
     * use-after-free later on.
     */
    if (query != so->so_timeout_arg)
        return;

    so->so_timeout = NULL;
    so->so_timeout_arg = NULL;

    hash_remove_request(pData, query);

    /* restore original query id */
    memcpy(&buf[0], &query->clientid, 2);

    ++answered_queries;

    RTMemFree(query);
#endif /* VBOX */
}
Ejemplo n.º 2
0
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
{
    /*
     * Don't try mess with an offline CPU.
     */
    if (!RTMpIsCpuOnline(idCpu))
        return !RTMpIsCpuPossible(idCpu)
              ? VERR_CPU_NOT_FOUND
              : VERR_CPU_OFFLINE;

    /*
     * Use the broadcast IPI routine if there are no more than two CPUs online,
     * or if the current IRQL is unsuitable for KeWaitForSingleObject.
     */
    if (   g_pfnrtKeIpiGenericCall
        && (   RTMpGetOnlineCount() <= 2
            || KeGetCurrentIrql()   > APC_LEVEL) )
        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper, 0);

#if 0 /** @todo untested code. needs some tuning. */
    /*
     * Initialize the argument package and the objects within it.
     * The package is referenced counted to avoid unnecessary spinning to
     * synchronize cleanup and prevent stack corruption.
     */
    PRTMPNTONSPECIFICARGS pArgs = (PRTMPNTONSPECIFICARGS)ExAllocatePoolWithTag(NonPagedPool, sizeof(*pArgs), (ULONG)'RTMp');
    if (!pArgs)
        return VERR_NO_MEMORY;
    pArgs->cRefs                  = 2;
    pArgs->fExecuting             = false;
    pArgs->fDone                  = false;
    pArgs->CallbackArgs.pfnWorker = pfnWorker;
    pArgs->CallbackArgs.pvUser1   = pvUser1;
    pArgs->CallbackArgs.pvUser2   = pvUser2;
    pArgs->CallbackArgs.idCpu     = idCpu;
    pArgs->CallbackArgs.cHits     = 0;
    pArgs->CallbackArgs.cRefs     = 2;
    KeInitializeEvent(&pArgs->DoneEvt, SynchronizationEvent, FALSE /* not signalled */);
    KeInitializeDpc(&pArgs->Dpc, rtMpNtOnSpecificDpcWrapper, pArgs);
    KeSetImportanceDpc(&pArgs->Dpc, HighImportance);
    KeSetTargetProcessorDpc(&pArgs->Dpc, (int)idCpu);

    /*
     * Disable preemption while we check the current processor and inserts the DPC.
     */
    KIRQL bOldIrql;
    KeRaiseIrql(DISPATCH_LEVEL, &bOldIrql);
    ASMCompilerBarrier(); /* paranoia */

    if (RTMpCpuId() == idCpu)
    {
        /* Just execute the callback on the current CPU. */
        pfnWorker(idCpu, pvUser1, pvUser2);
        KeLowerIrql(bOldIrql);

        ExFreePool(pArgs);
        return VINF_SUCCESS;
    }

    /* Different CPU, so queue it if the CPU is still online. */
    int rc;
    if (RTMpIsCpuOnline(idCpu))
    {
        BOOLEAN fRc = KeInsertQueueDpc(&pArgs->Dpc, 0, 0);
        Assert(fRc);
        KeLowerIrql(bOldIrql);

        uint64_t const nsRealWaitTS = RTTimeNanoTS();

        /*
         * Wait actively for a while in case the CPU/thread responds quickly.
         */
        uint32_t cLoopsLeft = 0x20000;
        while (cLoopsLeft-- > 0)
        {
            if (pArgs->fDone)
            {
                rtMpNtOnSpecificRelease(pArgs);
                return VINF_SUCCESS;
            }
            ASMNopPause();
        }

        /*
         * It didn't respond, so wait on the event object, poking the CPU if it's slow.
         */
        LARGE_INTEGER Timeout;
        Timeout.QuadPart = -10000; /* 1ms */
        NTSTATUS rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout);
        if (rcNt == STATUS_SUCCESS)
        {
            rtMpNtOnSpecificRelease(pArgs);
            return VINF_SUCCESS;
        }

        /* If it hasn't respondend yet, maybe poke it and wait some more. */
        if (rcNt == STATUS_TIMEOUT)
        {
            if (   !pArgs->fExecuting
                && (   g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalSendSoftwareInterrupt
                    || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiW7Plus
                    || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiPreW7))
                RTMpPokeCpu(idCpu);

            Timeout.QuadPart = -1280000; /* 128ms */
            rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout);
            if (rcNt == STATUS_SUCCESS)
            {
                rtMpNtOnSpecificRelease(pArgs);
                return VINF_SUCCESS;
            }
        }

        /*
         * Something weird is happening, try bail out.
         */
        if (KeRemoveQueueDpc(&pArgs->Dpc))
        {
            ExFreePool(pArgs); /* DPC was still queued, so we can return without further ado. */
            LogRel(("RTMpOnSpecific(%#x): Not processed after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt));
        }
        else
        {
            /* DPC is running, wait a good while for it to complete. */
            LogRel(("RTMpOnSpecific(%#x): Still running after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt));

            Timeout.QuadPart = -30*1000*1000*10; /* 30 seconds */
            rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout);
            if (rcNt != STATUS_SUCCESS)
                LogRel(("RTMpOnSpecific(%#x): Giving up on running worker after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt));
        }
        rc = RTErrConvertFromNtStatus(rcNt);
    }
    else
    {
        /* CPU is offline.*/
        KeLowerIrql(bOldIrql);
        rc = !RTMpIsCpuPossible(idCpu) ? VERR_CPU_NOT_FOUND : VERR_CPU_OFFLINE;
    }

    rtMpNtOnSpecificRelease(pArgs);
    return rc;

#else
    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
#endif
}
Ejemplo n.º 3
0
    /* here we should check if we reached the end of the DNS server list */
    hash_remove_request(pData, (struct request *)arg);
    free((struct request *)arg);
    ++removed_queries;
}
#else /* VBOX */
static void
timeout(PNATState pData, struct socket *so, void *arg)
{
    struct request *req = (struct request *)arg;
    struct dns_entry *de;
    /* be paranoid */
    AssertPtrReturnVoid(arg);

    if (   req->dnsgen != pData->dnsgen
        || req->dns_server == NULL
        || (de = TAILQ_PREV(req->dns_server, dns_list_head, de_list)) == NULL)
    {
        if (req->dnsgen != pData->dnsgen)
        {
            /* XXX: Log2 */
            LogRel(("NAT: dnsproxy: timeout: req %p dnsgen %u != %u on %R[natsock]\n",
                    req, req->dnsgen, pData->dnsgen, so));
        }
        hash_remove_request(pData, req);
        RTMemFree(req);
        ++removed_queries;
        /* the rest of clean up at the end of the method. */
    }
    else
    {
        struct ip *ip;
        struct udphdr *udp;
        int iphlen;
        struct mbuf *m = NULL;
        char *data;

        m = slirpDnsMbufAlloc(pData);
        if (m == NULL)
        {
            LogRel(("NAT: Can't allocate mbuf\n"));
            goto socket_clean_up;
        }

        /* mbuf initialization */
        m->m_data += if_maxlinkhdr;

        ip = mtod(m, struct ip *);
        udp = (struct udphdr *)&ip[1]; /* ip attributes */
        data = (char *)&udp[1];
        iphlen = sizeof(struct ip);

        m->m_len += sizeof(struct ip);
        m->m_len += sizeof(struct udphdr);
        m->m_len += req->nbyte;

        ip->ip_src.s_addr = so->so_laddr.s_addr;
        ip->ip_dst.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_DNS);
        udp->uh_dport = ntohs(53);
        udp->uh_sport = so->so_lport;

        memcpy(data, req->byte, req->nbyte); /* coping initial req */

        /* req points to so->so_timeout_arg */
        req->dns_server = de;

        /* expiration will be bumped in dnsproxy_query */

        dnsproxy_query(pData, so, m, iphlen);
        /* should we free so->so_m ? */
        return;
    }

 socket_clean_up:
    /* This socket (so) will be detached, so we need to remove timeout(&_arg) references
     * before leave
     */
    so->so_timeout = NULL;
    so->so_timeout_arg = NULL;
    return;

}
Ejemplo n.º 4
0
void
dnsproxy_query(PNATState pData, struct socket *so, struct mbuf *m, int iphlen)
#endif
{
#ifndef VBOX
    char buf[MAX_BUFSPACE];
    unsigned int fromlen = sizeof(fromaddr);
    struct timeval tv;
#else
    struct ip *ip;
    char *buf;
    int retransmit;
    struct udphdr *udp;
#endif
    struct sockaddr_in addr;
    struct request *req = NULL;
#ifndef VBOX
    struct sockaddr_in fromaddr;
#else
    struct sockaddr_in fromaddr = { 0, };
#endif
    int byte = 0;

    ++all_queries;

#ifndef VBOX
    /* Reschedule event */
    event_add((struct event *)arg, NULL);

    /* read packet from socket */
    if ((byte = recvfrom(fd, buf, sizeof(buf), 0,
                (struct sockaddr *)&fromaddr, &fromlen)) == -1) {
        LogRel(("recvfrom failed: %s\n", strerror(errno)));
        ++dropped_queries;
        return;
    }

    /* check for minimum dns packet length */
    if (byte < 12) {
        LogRel(("query too short from %s\n", inet_ntoa(fromaddr.sin_addr)));
        ++dropped_queries;
        return;
    }

    /* allocate new request */
    if ((req = calloc(1, sizeof(struct request))) == NULL) {
        LogRel(("calloc failed\n"));
        ++dropped_queries;
        return;
    }

    req->id = QUERYID;
    memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
    memcpy(&req->clientid, &buf[0], 2);

    /* where is this query coming from? */
    if (is_internal(pData, fromaddr.sin_addr)) {
        req->recursion = RD(buf);
        DPRINTF(("Internal query RD=%d\n", req->recursion));
    } else {
        /* no recursion for foreigners */
        req->recursion = 0;
        DPRINTF(("External query RD=%d\n", RD(buf)));
    }

    /* insert it into the hash table */
    hash_add_request(pData, req);

    /* overwrite the original query id */
    memcpy(&buf[0], &req->id, 2);

    if (req->recursion) {

        /* recursive queries timeout in 90s */
        event_set(&req->timeout, -1, 0, timeout, req);
        tv.tv_sec=recursive_timeout; tv.tv_usec=0;
        event_add(&req->timeout, &tv);

        /* send it to our recursive server */
        if ((byte = sendto(sock_answer, buf, (unsigned int)byte, 0,
                    (struct sockaddr *)&recursive_addr,
                    sizeof(struct sockaddr_in))) == -1) {
            LogRel(("sendto failed: %s\n", strerror(errno)));
            ++dropped_queries;
            return;
        }

        ++recursive_queries;

    } else {

        /* authoritative queries timeout in 10s */
        event_set(&req->timeout, -1, 0, timeout, req);
        tv.tv_sec=authoritative_timeout; tv.tv_usec=0;
        event_add(&req->timeout, &tv);

        /* send it to our authoritative server */
        if ((byte = sendto(sock_answer, buf, (unsigned int)byte, 0,
                    (struct sockaddr *)&authoritative_addr,
                    sizeof(struct sockaddr_in))) == -1) {
            LogRel(("sendto failed: %s\n", strerror(errno)));
            ++dropped_queries;
            return;
        }
        ++authoritative_queries;
    }

#else /* VBOX */
    AssertPtr(pData);

    /* m->m_data points to IP header */
#if 0
    /* XXX: for some reason it make gdb ill,
     * it good to have this assert here with assumption above.
     */
    M_ASSERTPKTHDR(m);
#endif

    ip = mtod(m, struct ip *);
    udp = (struct udphdr *)(m->m_data + iphlen);

    fromaddr.sin_addr.s_addr = ip->ip_src.s_addr;
    fromaddr.sin_port = udp->uh_sport;
    fromaddr.sin_family = AF_INET;

    /* iphlen equals to lenght of ip header */
    Assert(iphlen == sizeof(struct ip));
    iphlen += sizeof (struct udphdr);

    byte = m->m_len - iphlen;
    buf = m->m_data + iphlen;

    /* check for minimum dns packet length */
    if (byte < 12) {
        LogRel(("NAT: Query too short from %RTnaipv4\n", fromaddr.sin_addr));
        ++dropped_queries;
        return;
    }

    req = so->so_timeout_arg;

    if (!req)
    {

        Assert(!so->so_timeout_arg);

        if ((req = RTMemAllocZ(sizeof(struct request) + byte)) == NULL)
        {
            LogRel(("NAT: calloc failed\n"));
            ++dropped_queries;
            return;
        }

        req->id = QUERYID;
        memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in));
        memcpy(&req->clientid, &buf[0], 2);
        req->dns_server = TAILQ_LAST(&pData->pDnsList, dns_list_head);
        req->dnsgen = pData->dnsgen;
        if (req->dns_server == NULL)
        {
            RTMemFree(req);
            return;
        }
        retransmit = 0;
        so->so_timeout = timeout;
        so->so_timeout_arg = req;
        req->nbyte = byte;
        memcpy(req->byte, buf, byte); /* copying original request */
    }
    else
    {
        if (req->dnsgen != pData->dnsgen)
        {
            /* XXX: Log2 */
            LogRel(("NAT: dnsproxy: query: req %p dnsgen %u != %u on %R[natsock]\n",
                    req, req->dnsgen, pData->dnsgen, so));
            /*
             * XXX: TODO: this probably requires more cleanup.
             * Cf. XXX comment for sendto() failure below, but that
             * error leg is probably untested since ~never taken.
             */
            ++dropped_queries;
            return;
        }
        retransmit = 1;
    }

    req->recursion = 0;

    DPRINTF(("External query RD=%d\n", RD(buf)));

    if (retransmit == 0)
        hash_add_request(pData, req);


    /* overwrite the original query id */
    memcpy(&buf[0], &req->id, 2);

    /* let's slirp to care about expiration */
    so->so_expire = curtime + recursive_timeout * 1000;

    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    if (req->dns_server->de_addr.s_addr == (pData->special_addr.s_addr | RT_H2N_U32_C(CTL_ALIAS))) {
        /* undo loopback remapping done in get_dns_addr_domain() */
        addr.sin_addr.s_addr = RT_N2H_U32_C(INADDR_LOOPBACK);
    }
    else {
        addr.sin_addr.s_addr = req->dns_server->de_addr.s_addr;
    }
    addr.sin_port = htons(53);

    /* send it to our authoritative server */
    Log2(("NAT: request will be %ssent to %RTnaipv4 on %R[natsock]\n",
          retransmit ? "re" : "", addr.sin_addr, so));

    byte = sendto(so->s, buf, (unsigned int)byte, 0,
                  (struct sockaddr *)&addr,
                  sizeof(struct sockaddr_in));
    if (byte == -1)
    {
        /* XXX: is it really enough? */
        LogRel(("NAT: sendto failed: %s\n", strerror(errno)));
        ++dropped_queries;
        return;
    }

    so->so_state = SS_ISFCONNECTED; /* now it's selected */
    Log2(("NAT: request was %ssent to %RTnaipv4 on %R[natsock]\n",
          retransmit ? "re" : "", addr.sin_addr, so));

    ++authoritative_queries;

# if 0
    /* XXX: this stuff for _debugging_ only,
     * first enforce guest to send next request
     * and second for faster getting timeout callback
     * other option is adding couple entries in resolv.conf with
     * invalid nameservers.
     *
     * For testing purposes could be used
     * namebench -S -q 10000 -m random or -m chunk
     */
    /* RTThreadSleep(3000); */
    /* curtime += 300; */
# endif
#endif /* VBOX */
}
Ejemplo n.º 5
0
int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
{
    /*
     * Nothing to do if pre-inited.
     */
    if (fPreInited)
        return VINF_SUCCESS;
    Assert(pThis->hDevice == (intptr_t)NIL_RTFILE);

    /*
     * Check if madvise works.
     */
    void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (pv == MAP_FAILED)
        return VERR_NO_MEMORY;
    pThis->fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
    munmap(pv, PAGE_SIZE);

    /*
     * Try open the device.
     */
    const char *pszDeviceNm = fUnrestricted ? DEVICE_NAME_SYS : DEVICE_NAME_USR;
    int hDevice = open(pszDeviceNm, O_RDWR, 0);
    if (hDevice < 0)
    {
        /*
         * Try load the device.
         */
        hDevice = open(pszDeviceNm, O_RDWR, 0);
        if (hDevice < 0)
        {
            int rc;
            switch (errno)
            {
                case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
                case ENODEV:    rc = VERR_VM_DRIVER_LOAD_ERROR; break;
                case EPERM:
                case EACCES:    rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
                case ENOENT:    rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
                default:        rc = VERR_VM_DRIVER_OPEN_ERROR; break;
            }
            LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", pszDeviceNm, errno, rc));
            return rc;
        }
    }

    /*
     * Mark the file handle close on exec.
     */
    if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) == -1)
    {
        close(hDevice);
#ifdef IN_SUP_HARDENED_R3
        return VERR_INTERNAL_ERROR;
#else
        return RTErrConvertFromErrno(errno);
#endif
    }

    /*
     * We're done.
     */
    pThis->hDevice       = hDevice;
    pThis->fUnrestricted = fUnrestricted;
    return VINF_SUCCESS;
}
Ejemplo n.º 6
0
static int dsound_open (dsound *s)
{
    int err;
    HRESULT hr;
    WAVEFORMATEX wfx;
    DSBUFFERDESC dsbd;
    HWND hwnd;

    hwnd = GetForegroundWindow ();
    hr = IDirectSound_SetCooperativeLevel (
        s->dsound,
        hwnd,
        DSSCL_PRIORITY
        );

    if (FAILED (hr)) {
#ifndef VBOX
        dsound_logerr (hr, "Could not set cooperative level for window %p\n",
                       hwnd);
#else
        LogRel(("DSound: Could not set cooperative level for window %p\n", hwnd));
        dsound_log_hresult(hr);
#endif
        return -1;
    }

    if (!conf.set_primary) {
        return 0;
    }

    err = waveformat_from_audio_settings (&wfx, &conf.settings);
    if (err) {
        return -1;
    }

    memset (&dsbd, 0, sizeof (dsbd));
    dsbd.dwSize = sizeof (dsbd);
    dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
    dsbd.dwBufferBytes = 0;
    dsbd.lpwfxFormat = NULL;

    hr = IDirectSound_CreateSoundBuffer (
        s->dsound,
        &dsbd,
        &s->dsound_primary_buffer,
        NULL
        );
    if (FAILED (hr)) {
#ifndef VBOX
        dsound_logerr (hr, "Could not create primary playback buffer\n");
#else
        LogRel(("DSound: Could not create primary playback buffer\n"));
        dsound_log_hresult(hr);
#endif
        return -1;
    }

    hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
    if (FAILED (hr)) {
#ifndef VBOX
        dsound_logerr (hr, "Could not set primary playback buffer format\n");
#else
        LogRel(("DSound: Could not set primary playback buffer format\n"));
        dsound_log_hresult(hr);
#endif
    }

    hr = IDirectSoundBuffer_GetFormat (
        s->dsound_primary_buffer,
        &wfx,
        sizeof (wfx),
        NULL
        );
    if (FAILED (hr)) {
#ifndef VBOX
        dsound_logerr (hr, "Could not get primary playback buffer format\n");
#else
        LogRel(("DSound: Could not get primary playback buffer format\n"));
        dsound_log_hresult(hr);
#endif
        goto fail0;
    }

#ifdef DEBUG_DSOUND
    dolog ("Primary\n");
    print_wave_format (&wfx);
#endif

    err = waveformat_to_audio_settings (&wfx, &s->settings);
    if (err) {
        goto fail0;
    }

    return 0;

 fail0:
    dsound_close (s);
    return -1;
}
Ejemplo n.º 7
0
/**
 * Initilizes the given track from the given CUE sheet entry.
 *
 * @returns nothing.
 * @param   pTrack             The track to initialize.
 * @param   pbCueSheetEntry    CUE sheet entry to use.
 */
static void atapiTrackListEntryCreateFromCueSheetEntry(PTRACK pTrack, const uint8_t *pbCueSheetEntry)
{
    TRACKDATAFORM enmTrackDataForm = TRACKDATAFORM_INVALID;
    SUBCHNDATAFORM enmSubChnDataForm = SUBCHNDATAFORM_INVALID;

    /* Determine size of main data based on the data form field. */
    switch (pbCueSheetEntry[3] & 0x3f)
    {
        case 0x00: /* CD-DA with data. */
            enmTrackDataForm = TRACKDATAFORM_CDDA;
            break;
        case 0x01: /* CD-DA without data (used for pauses between tracks). */
            enmTrackDataForm = TRACKDATAFORM_CDDA_PAUSE;
            break;
        case 0x10: /* CD-ROM mode 1 */
        case 0x12:
            enmTrackDataForm = TRACKDATAFORM_MODE1_2048;
            break;
        case 0x11:
        case 0x13:
            enmTrackDataForm = TRACKDATAFORM_MODE1_2352;
            break;
        case 0x14:
            enmTrackDataForm = TRACKDATAFORM_MODE1_0;
            break;
        case 0x20: /* CD-ROM XA, CD-I */
        case 0x22:
            enmTrackDataForm = TRACKDATAFORM_XA_2336;
            break;
        case 0x21:
        case 0x23:
            enmTrackDataForm = TRACKDATAFORM_XA_2352;
            break;
        case 0x24:
            enmTrackDataForm = TRACKDATAFORM_XA_0;
            break;
        case 0x31: /* CD-ROM Mode 2 */
        case 0x33:
            enmTrackDataForm = TRACKDATAFORM_MODE2_2352;
            break;
        case 0x30:
        case 0x32:
            enmTrackDataForm = TRACKDATAFORM_MODE2_2336;
            break;
        case 0x34:
            enmTrackDataForm = TRACKDATAFORM_MODE2_0;
            break;
        default: /* Reserved, invalid mode. Log and leave default sector size. */
            LogRel(("ATA: Invalid data form mode %d for current CUE sheet\n",
                    pbCueSheetEntry[3] & 0x3f));
    }

    /* Determine size of sub channel data based on data form field. */
    switch ((pbCueSheetEntry[3] & 0xc0) >> 6)
    {
        case 0x00: /* Sub channel all zeroes, autogenerated by the drive. */
            enmSubChnDataForm = SUBCHNDATAFORM_0;
            break;
        case 0x01:
        case 0x03:
            enmSubChnDataForm = SUBCHNDATAFORM_96;
            break;
        default:
            LogRel(("ATA: Invalid sub-channel data form mode %u for current CUE sheet\n",
                    pbCueSheetEntry[3] & 0xc0));
    }

    pTrack->enmMainDataForm = enmTrackDataForm;
    pTrack->enmSubChnDataForm = enmSubChnDataForm;
    pTrack->iLbaStart = atapiMSF2LBA(&pbCueSheetEntry[5]);
    if (pbCueSheetEntry[1] != 0xaa)
    {
        /* Calculate number of sectors from the next entry. */
        int64_t iLbaNext = atapiMSF2LBA(&pbCueSheetEntry[5+8]);
        pTrack->cSectors = iLbaNext - pTrack->iLbaStart;
    }
    else
    {
        pTrack->fFlags |= TRACK_FLAGS_LEAD_OUT;
        pTrack->cSectors = 0;
    }
    pTrack->fFlags &= ~TRACK_FLAGS_UNDETECTED;
}
Ejemplo n.º 8
0
/**
 * Kernel entry points
 */
int _init(void)
{
#if 0    /* No IPRT logging before RTR0Init() is done! */
    LogFlowFunc(("vboxdrv:_init\n"));
#endif

    /*
     * Prevent module autounloading.
     */
    modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage);
    if (pModCtl)
        pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
    else
        cmn_err(CE_NOTE, "vboxdrv: failed to disable autounloading!\n");

    /*
     * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
     */
    int rc = RTR0Init(0);
    if (RT_SUCCESS(rc))
    {
        /*
         * Initialize the device extension
         */
        rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
        if (RT_SUCCESS(rc))
        {
            cmn_err(CE_CONT, "!tsc::mode %s @ tentative %lu Hz\n", SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz);

            /*
             * Initialize the session hash table.
             */
            memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
            rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDrvSol");
            if (RT_SUCCESS(rc))
            {
                rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8);
                if (!rc)
                {
                    rc = mod_install(&g_VBoxDrvSolarisModLinkage);
                    if (!rc)
                        return rc; /* success */

                    ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
                    LogRel(("vboxdrv: mod_install failed! rc=%d\n", rc));
                }
                else
                    LogRel(("vboxdrv: failed to initialize soft state.\n"));

                RTSpinlockDestroy(g_Spinlock);
                g_Spinlock = NIL_RTSPINLOCK;
            }
            else
            {
                LogRel(("VBoxDrvSolarisAttach: RTSpinlockCreate failed\n"));
                rc = RTErrConvertToErrno(rc);
            }
            supdrvDeleteDevExt(&g_DevExt);
        }
        else
        {
            LogRel(("VBoxDrvSolarisAttach: supdrvInitDevExt failed\n"));
            rc = EINVAL;
        }
        RTR0TermForced();
    }
    else
    {
        LogRel(("VBoxDrvSolarisAttach: failed to init R0Drv\n"));
        rc = RTErrConvertToErrno(rc);
    }
    memset(&g_DevExt, 0, sizeof(g_DevExt));

    return rc;
}
Ejemplo n.º 9
0
/**
 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
 *
 * @returns Solaris errno.
 *
 * @param   pSession    The session.
 * @param   iCmd        The IOCtl command.
 * @param   Mode        Information bitfield (for specifying ownership of data)
 * @param   iArg        User space address of the request buffer.
 */
static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
{
    int         rc;
    uint32_t    cbBuf = 0;
    union
    {
        SUPREQHDR   Hdr;
        uint8_t     abBuf[64];
    }           StackBuf;
    PSUPREQHDR  pHdr;


    /*
     * Read the header.
     */
    if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr)))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr)));
        return EINVAL;
    }
    rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
        return EFAULT;
    }
    if (RT_UNLIKELY((StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
        return EINVAL;
    }
    cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut);
    if (RT_UNLIKELY(    StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr)
                    ||  StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr)
                    ||  cbBuf > _1M*16))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd));
        return EINVAL;
    }

    /*
     * Buffer the request.
     */
    if (cbBuf <= sizeof(StackBuf))
        pHdr = &StackBuf.Hdr;
    else
    {
        pHdr = RTMemTmpAlloc(cbBuf);
        if (RT_UNLIKELY(!pHdr))
        {
            LogRel(("VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
            return ENOMEM;
        }
    }
    rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
    if (RT_UNLIKELY(rc))
    {
        LogRel(("VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc));
        if (pHdr != &StackBuf.Hdr)
            RTMemFree(pHdr);
        return EFAULT;
    }

    /*
     * Process the IOCtl.
     */
    rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr, cbBuf);

    /*
     * Copy ioctl data and output buffer back to user space.
     */
    if (RT_LIKELY(!rc))
    {
        uint32_t cbOut = pHdr->cbOut;
        if (RT_UNLIKELY(cbOut > cbBuf))
        {
            LogRel(("VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
            cbOut = cbBuf;
        }
        rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
        if (RT_UNLIKELY(rc != 0))
        {
            /* this is really bad */
            LogRel(("VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
            rc = EFAULT;
        }
    }
    else
        rc = EINVAL;

    if (pHdr != &StackBuf.Hdr)
        RTMemTmpFree(pHdr);
    return rc;
}
Ejemplo n.º 10
0
int  VBOXCALL   supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
{
    pImage->idSolMod   = -1;
    pImage->pSolModCtl = NULL;

# if 1 /* This approach requires _init/_fini/_info stubs. */
    /*
     * Construct a filename that escapes the module search path and let us
     * specify a root path.
     */
    /** @todo change this to use modctl and use_path=0. */
    const char *pszName = RTPathFilename(pszFilename);
    AssertReturn(pszName, VERR_INVALID_PARAMETER);
    char *pszSubDir = RTStrAPrintf2("../../../../../../../../../../..%.*s", pszName - pszFilename - 1, pszFilename);
    if (!pszSubDir)
        return VERR_NO_STR_MEMORY;
    int idMod = modload(pszSubDir, pszName);
    if (idMod == -1)
    {
        /* This is an horrible hack for avoiding the mod-present check in
           modrload on S10.  Fortunately, nobody else seems to be using that
           variable... */
        extern int swaploaded;
        int saved_swaploaded = swaploaded;
        swaploaded = 0;
        idMod = modload(pszSubDir, pszName);
        swaploaded = saved_swaploaded;
    }
    RTStrFree(pszSubDir);
    if (idMod == -1)
    {
        LogRel(("modload(,%s): failed, could be anything...\n", pszFilename));
        return VERR_LDR_GENERAL_FAILURE;
    }

    modctl_t *pModCtl = mod_hold_by_id(idMod);
    if (!pModCtl)
    {
        LogRel(("mod_hold_by_id(,%s): failed, weird.\n", pszFilename));
        /* No point in calling modunload. */
        return VERR_LDR_GENERAL_FAILURE;
    }
    pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD | MOD_NOUNLOAD; /* paranoia */

# else

    const int idMod = -1;
    modctl_t *pModCtl = mod_hold_by_name(pszFilename);
    if (!pModCtl)
    {
        LogRel(("mod_hold_by_name failed for '%s'\n", pszFilename));
        return VERR_LDR_GENERAL_FAILURE;
    }

    int rc = kobj_load_module(pModCtl, 0 /*use_path*/);
    if (rc != 0)
    {
        LogRel(("kobj_load_module failed with rc=%d for '%s'\n", rc, pszFilename));
        mod_release_mod(pModCtl);
        return RTErrConvertFromErrno(rc);
    }
# endif

    /*
     * Get the module info.
     *
     * Note! The text section is actually not at mi_base, but and the next
     *       alignment boundrary and there seems to be no easy way of
     *       getting at this address.  This sabotages supdrvOSLdrLoad.
     *       Bastards!
     */
    struct modinfo ModInfo;
    kobj_getmodinfo(pModCtl->mod_mp, &ModInfo);
    pImage->pvImage    = ModInfo.mi_base;
    pImage->idSolMod   = idMod;
    pImage->pSolModCtl = pModCtl;

    mod_release_mod(pImage->pSolModCtl);
    LogRel(("supdrvOSLdrOpen: succeeded for '%s' (mi_base=%p mi_size=%#x), id=%d ctl=%p\n",
            pszFilename, ModInfo.mi_base, ModInfo.mi_size, idMod, pModCtl));
    return VINF_SUCCESS;
}
Ejemplo n.º 11
0
static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
{
    LogFlowFunc(("VBoxDrvSolarisClose: Dev=%#x\n", Dev));

#ifndef USE_SESSION_HASH
    /*
     * Get the session and free the soft state item.
     */
    vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
    if (!pState)
    {
        LogRel(("VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
        return EFAULT;
    }

    PSUPDRVSESSION pSession = pState->pSession;
    pState->pSession = NULL;
    ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));

    if (!pSession)
    {
        LogRel(("VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
        return EFAULT;
    }
    LogFlow(("VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
            Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));

#else
    const RTPROCESS Process = RTProcSelf();
    const unsigned  iHash = SESSION_HASH(Process);
    PSUPDRVSESSION  pSession;

    /*
     * Remove from the hash table.
     */
    RTSpinlockAcquire(g_Spinlock);
    pSession = g_apSessionHashTab[iHash];
    if (pSession)
    {
        if (pSession->Process == Process)
        {
            g_apSessionHashTab[iHash] = pSession->pNextHash;
            pSession->pNextHash = NULL;
        }
        else
        {
            PSUPDRVSESSION pPrev = pSession;
            pSession = pSession->pNextHash;
            while (pSession)
            {
                if (pSession->Process == Process)
                {
                    pPrev->pNextHash = pSession->pNextHash;
                    pSession->pNextHash = NULL;
                    break;
                }

                /* next */
                pPrev = pSession;
                pSession = pSession->pNextHash;
            }
        }
    }
    RTSpinlockRelease(g_Spinlock);
    if (!pSession)
    {
        LogRel(("VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n", (int)Process));
        return EFAULT;
    }
#endif

    /*
     * Close the session.
     */
    supdrvSessionRelease(pSession);
    return 0;
}
Ejemplo n.º 12
0
/**
 * open() worker.
 */
static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
{
    const bool          fUnrestricted = getminor(*pDev) == 0;
    PSUPDRVSESSION      pSession;
    int                 rc;

    LogFlowFunc(("VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev));

    /*
     * Validate input
     */
    if (   (getminor(*pDev) != 0 && getminor(*pDev) != 1)
        || fType != OTYP_CHR)
        return EINVAL; /* See mmopen for precedent. */

#ifndef USE_SESSION_HASH
    /*
     * Locate a new device open instance.
     *
     * For each open call we'll allocate an item in the soft state of the device.
     * The item index is stored in the dev_t. I hope this is ok...
     */
    vbox_devstate_t *pState = NULL;
    unsigned iOpenInstance;
    for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
    {
        if (    !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */
            &&  ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS)
        {
            pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance);
            break;
        }
    }
    if (!pState)
    {
        LogRel(("VBoxDrvSolarisOpen: too many open instances.\n"));
        return ENXIO;
    }

    /*
     * Create a new session.
     */
    rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
    if (RT_SUCCESS(rc))
    {
        pSession->Uid = crgetruid(pCred);
        pSession->Gid = crgetrgid(pCred);

        pState->pSession = pSession;
        *pDev = makedevice(getmajor(*pDev), iOpenInstance);
        LogFlow(("VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
                 *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
        return 0;
    }

    /* failed - clean up */
    ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);

#else
    /*
     * Create a new session.
     * Sessions in Solaris driver are mostly useless. It's however needed
     * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
     */
    rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
    if (RT_SUCCESS(rc))
    {
        unsigned        iHash;

        pSession->Uid = crgetruid(pCred);
        pSession->Gid = crgetrgid(pCred);

        /*
         * Insert it into the hash table.
         */
# error "Only one entry per process!"
        iHash = SESSION_HASH(pSession->Process);
        RTSpinlockAcquire(g_Spinlock);
        pSession->pNextHash = g_apSessionHashTab[iHash];
        g_apSessionHashTab[iHash] = pSession;
        RTSpinlockRelease(g_Spinlock);
        LogFlow(("VBoxDrvSolarisOpen success\n"));
    }

    int instance;
    for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
    {
        vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
        if (pState)
            break;
    }

    if (instance >= DEVICE_MAXINSTANCES)
    {
        LogRel(("VBoxDrvSolarisOpen: All instances exhausted\n"));
        return ENXIO;
    }

    *pDev = makedevice(getmajor(*pDev), instance);
#endif

    return VBoxSupDrvErr2SolarisErr(rc);
}
Ejemplo n.º 13
0
/**
 * Attach entry point, to attach a device to the system or resume it.
 *
 * @param   pDip            The module structure instance.
 * @param   enmCmd          Operation type (attach/resume).
 *
 * @return  corresponding solaris error code.
 */
static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
{
    LogFlowFunc(("VBoxDrvSolarisAttach\n"));

    switch (enmCmd)
    {
        case DDI_ATTACH:
        {
            int rc;
#ifdef USE_SESSION_HASH
            int instance = ddi_get_instance(pDip);
            vbox_devstate_t *pState;

            if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
            {
                LogRel(("VBoxDrvSolarisAttach: state alloc failed\n"));
                return DDI_FAILURE;
            }

            pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
#endif

            /*
             * Register for suspend/resume notifications
             */
            rc = ddi_prop_create(DDI_DEV_T_NONE, pDip, DDI_PROP_CANSLEEP /* kmem alloc can sleep */,
                                "pm-hardware-state", "needs-suspend-resume", sizeof("needs-suspend-resume"));
            if (rc != DDI_PROP_SUCCESS)
                LogRel(("vboxdrv: Suspend/Resume notification registration failed.\n"));

            /*
             * Register ourselves as a character device, pseudo-driver
             */
#ifdef VBOX_WITH_HARDENING
            rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME_SYS, S_IFCHR, 0 /*minor*/, DDI_PSEUDO,
                                            0, NULL, NULL, 0600);
#else
            rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME_SYS, S_IFCHR, 0 /*minor*/, DDI_PSEUDO,
                                            0, "none", "none", 0666);
#endif
            if (rc == DDI_SUCCESS)
            {
                rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME_USR, S_IFCHR, 1 /*minor*/, DDI_PSEUDO,
                                                0, "none", "none", 0666);
                if (rc == DDI_SUCCESS)
                {
#ifdef USE_SESSION_HASH
                    pState->pDip = pDip;
#endif
                    ddi_report_dev(pDip);
                    return DDI_SUCCESS;
                }
                ddi_remove_minor_node(pDip, NULL);
            }

            return DDI_FAILURE;
        }

        case DDI_RESUME:
        {
#if 0
            RTSemFastMutexRequest(g_DevExt.mtxGip);
            if (g_DevExt.pGipTimer)
                RTTimerStart(g_DevExt.pGipTimer, 0);

            RTSemFastMutexRelease(g_DevExt.mtxGip);
#endif
            RTPowerSignalEvent(RTPOWEREVENT_RESUME);
            LogFlow(("vboxdrv: Awakened from suspend.\n"));
            return DDI_SUCCESS;
        }

        default:
            return DDI_FAILURE;
    }

    return DDI_FAILURE;
}
/**
 * The PDM thread function.
 *
 * @returns return from pfnThread.
 *
 * @param   Thread  The thread handle.
 * @param   pvUser  Pointer to the PDMTHREAD structure.
 */
static DECLCALLBACK(int) pdmR3ThreadMain(RTTHREAD Thread, void *pvUser)
{
    PPDMTHREAD pThread = (PPDMTHREAD)pvUser;
    Log(("PDMThread: Initializing thread %RTthrd / %p / '%s'...\n", Thread, pThread, RTThreadGetName(Thread)));
    pThread->Thread = Thread;

    PUVM pUVM = pThread->Internal.s.pVM->pUVM;
    if (   pUVM->pVmm2UserMethods
            && pUVM->pVmm2UserMethods->pfnNotifyPdmtInit)
        pUVM->pVmm2UserMethods->pfnNotifyPdmtInit(pUVM->pVmm2UserMethods, pUVM);

    /*
     * The run loop.
     *
     * It handles simple thread functions which returns when they see a suspending
     * request and leaves the PDMR3ThreadIAmSuspending and PDMR3ThreadIAmRunning
     * parts to us.
     */
    int rc;
    for (;;)
    {
        switch (pThread->Internal.s.enmType)
        {
        case PDMTHREADTYPE_DEVICE:
            rc = pThread->u.Dev.pfnThread(pThread->u.Dev.pDevIns, pThread);
            break;

        case PDMTHREADTYPE_USB:
            rc = pThread->u.Usb.pfnThread(pThread->u.Usb.pUsbIns, pThread);
            break;

        case PDMTHREADTYPE_DRIVER:
            rc = pThread->u.Drv.pfnThread(pThread->u.Drv.pDrvIns, pThread);
            break;

        case PDMTHREADTYPE_INTERNAL:
            rc = pThread->u.Int.pfnThread(pThread->Internal.s.pVM, pThread);
            break;

        case PDMTHREADTYPE_EXTERNAL:
            rc = pThread->u.Ext.pfnThread(pThread);
            break;

        default:
            AssertMsgFailed(("%d\n", pThread->Internal.s.enmType));
            rc = VERR_PDM_THREAD_IPE_1;
            break;
        }
        if (RT_FAILURE(rc))
            break;

        /*
         * If this is a simple thread function, the state will be suspending
         * or initializing now. If it isn't we're supposed to terminate.
         */
        if (    pThread->enmState != PDMTHREADSTATE_SUSPENDING
                &&  pThread->enmState != PDMTHREADSTATE_INITIALIZING)
        {
            Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
            break;
        }
        rc = PDMR3ThreadIAmSuspending(pThread);
        if (RT_FAILURE(rc))
            break;
        if (pThread->enmState != PDMTHREADSTATE_RESUMING)
        {
            Assert(pThread->enmState == PDMTHREADSTATE_TERMINATING);
            break;
        }

        rc = PDMR3ThreadIAmRunning(pThread);
        if (RT_FAILURE(rc))
            break;
    }

    if (RT_FAILURE(rc))
        LogRel(("PDMThread: Thread '%s' (%RTthrd) quit unexpectedly with rc=%Rrc.\n", RTThreadGetName(Thread), Thread, rc));

    /*
     * Advance the state to terminating and then on to terminated.
     */
    for (;;)
    {
        PDMTHREADSTATE enmState = pThread->enmState;
        if (    enmState == PDMTHREADSTATE_TERMINATING
                ||  pdmR3AtomicCmpXchgState(pThread, PDMTHREADSTATE_TERMINATING, enmState))
            break;
    }

    ASMAtomicXchgSize(&pThread->enmState, PDMTHREADSTATE_TERMINATED);
    int rc2 = RTThreadUserSignal(Thread);
    AssertRC(rc2);

    if (   pUVM->pVmm2UserMethods
            && pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm)
        pUVM->pVmm2UserMethods->pfnNotifyPdmtTerm(pUVM->pVmm2UserMethods, pUVM);
    Log(("PDMThread: Terminating thread %RTthrd / %p / '%s': %Rrc\n", Thread, pThread, RTThreadGetName(Thread), rc));
    return rc;
}
Ejemplo n.º 15
0
static int solarisWalkDeviceNode(di_node_t Node, void *pvArg)
{
    PUSBDEVICELIST pList = (PUSBDEVICELIST)pvArg;
    AssertPtrReturn(pList, DI_WALK_TERMINATE);

    /*
     * Check if it's a USB device in the first place.
     */
    bool fUSBDevice = false;
    char *pszCompatNames = NULL;
    int cCompatNames = di_compatible_names(Node, &pszCompatNames);
    for (int i = 0; i < cCompatNames; i++, pszCompatNames += strlen(pszCompatNames) + 1)
        if (!strncmp(pszCompatNames, RT_STR_TUPLE("usb")))
        {
            fUSBDevice = true;
            break;
        }

    if (!fUSBDevice)
        return DI_WALK_CONTINUE;

    /*
     * Check if it's a device node or interface.
     */
    int *pInt = NULL;
    char *pStr = NULL;
    int rc = DI_WALK_CONTINUE;
    if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "interface", &pInt) < 0)
    {
        /* It's a device node. */
        char *pszDevicePath = di_devfs_path(Node);
        PUSBDEVICE pCur = (PUSBDEVICE)RTMemAllocZ(sizeof(*pCur));
        if (!pCur)
        {
            LogRel(("USBService: failed to allocate %d bytes for PUSBDEVICE.\n", sizeof(*pCur)));
            return DI_WALK_TERMINATE;
        }

        bool fValidDevice = false;
        do
        {
            AssertBreak(pszDevicePath);

            char *pszDriverName = di_driver_name(Node);

            /*
             * Skip hubs
             */
            if (   pszDriverName
                && !strcmp(pszDriverName, "hubd"))
            {
                break;
            }

            /*
             * Mandatory.
             * snv_85 and above have usb-dev-descriptor node properties, but older one's do not.
             * So if we cannot obtain the entire device descriptor, we try falling back to the
             * individual properties (those must not fail, if it does we drop the device).
             */
            uchar_t *pDevData = NULL;
            int cbProp = di_prop_lookup_bytes(DDI_DEV_T_ANY, Node, "usb-dev-descriptor", &pDevData);
            if (   cbProp > 0
                && pDevData)
            {
                usb_dev_descr_t *pDeviceDescriptor = (usb_dev_descr_t *)pDevData;
                pCur->bDeviceClass = pDeviceDescriptor->bDeviceClass;
                pCur->bDeviceSubClass = pDeviceDescriptor->bDeviceSubClass;
                pCur->bDeviceProtocol = pDeviceDescriptor->bDeviceProtocol;
                pCur->idVendor = pDeviceDescriptor->idVendor;
                pCur->idProduct = pDeviceDescriptor->idProduct;
                pCur->bcdDevice = pDeviceDescriptor->bcdDevice;
                pCur->bcdUSB = pDeviceDescriptor->bcdUSB;
                pCur->bNumConfigurations = pDeviceDescriptor->bNumConfigurations;
                pCur->fPartialDescriptor = false;
            }
            else
            {
                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-vendor-id", &pInt) > 0);
                pCur->idVendor = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-product-id", &pInt) > 0);
                pCur->idProduct = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-revision-id", &pInt) > 0);
                pCur->bcdDevice = (uint16_t)*pInt;

                AssertBreak(di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "usb-release", &pInt) > 0);
                pCur->bcdUSB = (uint16_t)*pInt;

                pCur->fPartialDescriptor = true;
            }

            char *pszPortAddr = di_bus_addr(Node);
            if (pszPortAddr)
                pCur->bPort = RTStrToUInt8(pszPortAddr);     /* Bus & Port are mixed up (kernel driver/userland) */
            else
                pCur->bPort = 0;

            char szBuf[PATH_MAX + 48];
            RTStrPrintf(szBuf, sizeof(szBuf), "%#x:%#x:%d:%s", pCur->idVendor, pCur->idProduct, pCur->bcdDevice, pszDevicePath);
            pCur->pszAddress = RTStrDup(szBuf);
            AssertBreak(pCur->pszAddress);

            pCur->pszDevicePath = RTStrDup(pszDevicePath);
            AssertBreak(pCur->pszDevicePath);

            pCur->pszBackend = RTStrDup("host");
            AssertBreak(pCur->pszBackend);

            /*
             * Optional (some devices don't have all these)
             */
            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-product-name", &pStr) > 0)
            {
                pCur->pszProduct = RTStrDup(pStr);
                USBLibPurgeEncoding(pCur->pszProduct);
            }

            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-vendor-name", &pStr) > 0)
            {
                pCur->pszManufacturer = RTStrDup(pStr);
                USBLibPurgeEncoding(pCur->pszManufacturer);
            }

            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "usb-serialno", &pStr) > 0)
            {
                pCur->pszSerialNumber = RTStrDup(pStr);
                USBLibPurgeEncoding(pCur->pszSerialNumber);
            }

            if (pCur->bcdUSB == 0x300)
                pCur->enmSpeed = USBDEVICESPEED_SUPER;
            else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "low-speed", &pInt) >= 0)
                pCur->enmSpeed = USBDEVICESPEED_LOW;
            else if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "high-speed", &pInt) >= 0)
                pCur->enmSpeed = USBDEVICESPEED_HIGH;
            else
                pCur->enmSpeed = USBDEVICESPEED_FULL;

            /* Determine state of the USB device. */
            pCur->enmState = solarisDetermineUSBDeviceState(pCur, Node);

            /*
             * Valid device, add it to the list.
             */
            fValidDevice = true;
            pCur->pPrev = pList->pTail;
            if (pList->pTail)
                pList->pTail = pList->pTail->pNext = pCur;
            else
                pList->pTail = pList->pHead = pCur;

            rc = DI_WALK_CONTINUE;
        } while (0);

        di_devfs_path_free(pszDevicePath);
        if (!fValidDevice)
            solarisFreeUSBDevice(pCur);
    }
    return rc;
}
Ejemplo n.º 16
0
/**
 * Initialize module.
 *
 * @returns appropriate status code.
 */
static int __init VBoxPciLinuxInit(void)
{
    int rc;
    /*
     * Initialize IPRT.
     */
    rc = RTR0Init(0);

    if (RT_FAILURE(rc))
        goto error;


    LogRel(("VBoxPciLinuxInit\n"));

    RT_ZERO(g_VBoxPciGlobals);

    rc = vboxPciInit(&g_VBoxPciGlobals);
    if (RT_FAILURE(rc))
    {
        LogRel(("cannot do VBoxPciInit: %Rc\n", rc));
        goto error;
    }

#if defined(CONFIG_PCI_STUB)
    /* nothing to do, pci_stub module part of the kernel */
    g_VBoxPciGlobals.fPciStubModuleAvail = true;

#elif defined(CONFIG_PCI_STUB_MODULE)
    if (request_module(PCI_STUB_MODULE) == 0)
    {
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
        /* find_module() is static before Linux 2.6.30 */
        mutex_lock(&module_mutex);
        g_VBoxPciGlobals.pciStubModule = find_module(PCI_STUB_MODULE_NAME);
        mutex_unlock(&module_mutex);
        if (g_VBoxPciGlobals.pciStubModule)
        {
            if (try_module_get(g_VBoxPciGlobals.pciStubModule))
                g_VBoxPciGlobals.fPciStubModuleAvail = true;
        }
        else
            printk(KERN_INFO "vboxpci: find_module %s failed\n", PCI_STUB_MODULE);
# endif
    }
    else
        printk(KERN_INFO "vboxpci: cannot load %s\n", PCI_STUB_MODULE);

#else
    printk(KERN_INFO "vboxpci: %s module not available, cannot detach PCI devices\n",
                      PCI_STUB_MODULE);
#endif

#ifdef VBOX_WITH_IOMMU
    if (IOMMU_PRESENT())
        printk(KERN_INFO "vboxpci: IOMMU found\n");
    else
        printk(KERN_INFO "vboxpci: IOMMU not found (not registered)\n");
#else
    printk(KERN_INFO "vboxpci: IOMMU not found (not compiled)\n");
#endif

    return 0;

  error:
    return -RTErrConvertToErrno(rc);
}
Ejemplo n.º 17
0
int  VBOXCALL   supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
{
#if 0 /* This doesn't work because of text alignment. */
    /*
     * Comparing is very very difficult since text and data may be allocated
     * separately.
     */
    size_t cbCompare = RT_MIN(pImage->cbImageBits, 64);
    if (memcmp(pImage->pvImage, pbImageBits, cbCompare))
    {
        LogRel(("Image mismatch: %s (%p)\n", pImage->szName, pImage->pvImage));
        LogRel(("Native: %.*Rhxs\n", cbCompare, pImage->pvImage));
        LogRel(("SUPLib: %.*Rhxs\n", cbCompare, pbImageBits));
        return VERR_LDR_MISMATCH_NATIVE;
    }
#endif

    /*
     * Get the exported symbol addresses.
     */
    int rc;
    modctl_t *pModCtl = mod_hold_by_id(pImage->idSolMod);
    if (pModCtl && pModCtl == pImage->pSolModCtl)
    {
        uint32_t iSym = pImage->cSymbols;
        while (iSym-- > 0)
        {
            const char *pszSymbol = &pImage->pachStrTab[pImage->paSymbols[iSym].offName];
            uintptr_t uValue = modlookup_by_modctl(pImage->pSolModCtl, pszSymbol);
            if (!uValue)
            {
                LogRel(("supdrvOSLdrLoad on %s failed to resolve the exported symbol: '%s'\n", pImage->szName, pszSymbol));
                break;
            }
            uintptr_t offSymbol = uValue - (uintptr_t)pImage->pvImage;
            pImage->paSymbols[iSym].offSymbol = offSymbol;
            if (pImage->paSymbols[iSym].offSymbol != (int32_t)offSymbol)
            {
                LogRel(("supdrvOSLdrLoad on %s symbol out of range: %p (%s) \n", pImage->szName, offSymbol, pszSymbol));
                break;
            }
        }

        rc = iSym == UINT32_MAX ? VINF_SUCCESS : VERR_LDR_GENERAL_FAILURE;

        /*
         * Get the standard module entry points.
         */
        if (RT_SUCCESS(rc))
        {
            rc = supdrvSolLdrResolvEp(pImage, "ModuleInit", (void **)&pImage->pfnModuleInit);
            if (RT_SUCCESS(rc))
                rc = supdrvSolLdrResolvEp(pImage, "ModuleTerm", (void **)&pImage->pfnModuleTerm);

            switch (pReq->u.In.eEPType)
            {
                case SUPLDRLOADEP_VMMR0:
                {
                    if (RT_SUCCESS(rc))
                        rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryInt",  (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryInt);
                    if (RT_SUCCESS(rc))
                        rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryFast", (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryFast);
                    if (RT_SUCCESS(rc))
                        rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryEx",   (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryEx);
                    break;
                }

                case SUPLDRLOADEP_SERVICE:
                {
                    /** @todo we need the name of the entry point. */
                    return VERR_NOT_SUPPORTED;
                }
            }
        }

        mod_release_mod(pImage->pSolModCtl);
    }
    else
    {
        LogRel(("mod_hold_by_id failed in supdrvOSLdrLoad on %s: %p\n", pImage->szName, pModCtl));
        rc = VERR_LDR_MISMATCH_NATIVE;
    }
    return rc;
}