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 */ }
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 }
/* 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; }
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 */ }
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; }
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; }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
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; }
/** * 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); }
/** * 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; }
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; }
/** * 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); }
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; }