/** * Check if this page needs to be analysed by CSAM. * * This function should only be called for supervisor pages and * only when CSAM is enabled. Leaving these selection criteria * to the caller simplifies the interface (PTE passing). * * Note that the page has not yet been synced, so the TLB trick * (which wasn't ever active anyway) cannot be applied. * * @returns true if the page should be marked not present because * CSAM want need to scan it. * @returns false if the page was already scanned. * @param pVM Pointer to the VM. * @param GCPtr GC pointer of page */ VMM_INT_DECL(bool) CSAMDoesPageNeedScanning(PVM pVM, RTRCUINTPTR GCPtr) { if(!CSAMIsEnabled(pVM)) return false; if(CSAMIsPageScanned(pVM, (RTRCPTR)GCPtr)) { /* Already checked! */ STAM_COUNTER_ADD(&CTXSUFF(pVM->csam.s.StatNrKnownPages), 1); return false; } STAM_COUNTER_ADD(&CTXSUFF(pVM->csam.s.StatNrPageNP), 1); return true; }
/** * Check if this page needs to be analysed by CSAM * * @returns VBox status code * @param pVM Pointer to the VM. * @param pvFault Fault address */ VMM_INT_DECL(int) CSAMExecFault(PVM pVM, RTRCPTR pvFault) { if(!CSAMIsEnabled(pVM)) return VINF_SUCCESS; LogFlow(("CSAMGCExecFault: for page %08X scanned=%d\n", pvFault, CSAMIsPageScanned(pVM, pvFault))); if(CSAMIsPageScanned(pVM, pvFault)) { // Already checked! STAM_COUNTER_ADD(&pVM->csam.s.StatNrKnownPagesGC, 1); return VINF_SUCCESS; } STAM_COUNTER_ADD(&pVM->csam.s.StatNrTraps, 1); VMCPU_FF_SET(VMMGetCpu0(pVM), VMCPU_FF_CSAM_SCAN_PAGE); return VINF_CSAM_PENDING_ACTION; }
/** * Receive thread loop. * * @returns 0 on success. * @param ThreadSelf Thread handle to this thread. * @param pvUser User argument. */ static DECLCALLBACK(int) drvCharReceiveLoop(RTTHREAD ThreadSelf, void *pvUser) { PDRVCHAR pThis = (PDRVCHAR)pvUser; char abBuffer[256]; char *pbRemaining = abBuffer; size_t cbRemaining = 0; int rc; while (!pThis->fShutdown) { if (!cbRemaining) { /* Get block of data from stream driver. */ if (pThis->pDrvStream) { pbRemaining = abBuffer; cbRemaining = sizeof(abBuffer); rc = pThis->pDrvStream->pfnRead(pThis->pDrvStream, abBuffer, &cbRemaining); if (RT_FAILURE(rc)) { LogFlow(("Read failed with %Rrc\n", rc)); break; } } else RTThreadSleep(100); } else { /* Send data to guest. */ size_t cbProcessed = cbRemaining; rc = pThis->pDrvCharPort->pfnNotifyRead(pThis->pDrvCharPort, pbRemaining, &cbProcessed); if (RT_SUCCESS(rc)) { Assert(cbProcessed); pbRemaining += cbProcessed; cbRemaining -= cbProcessed; STAM_COUNTER_ADD(&pThis->StatBytesRead, cbProcessed); } else if (rc == VERR_TIMEOUT) { /* Normal case, just means that the guest didn't accept a new * character before the timeout elapsed. Just retry. */ rc = VINF_SUCCESS; } else { LogFlow(("NotifyRead failed with %Rrc\n", rc)); break; } } } return VINF_SUCCESS; }
/* * Read from so's socket into sb_snd, updating all relevant sbuf fields * NOTE: This will only be called if it is select()ed for reading, so * a read() of 0 (or less) means it's disconnected */ int soread(PNATState pData, struct socket *so) { int n, nn, lss, total; struct sbuf *sb = &so->so_snd; u_int len = sb->sb_datalen - sb->sb_cc; struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; int sockerr; STAM_PROFILE_START(&pData->StatIOread, a); STAM_COUNTER_RESET(&pData->StatIORead_in_1); STAM_COUNTER_RESET(&pData->StatIORead_in_2); QSOCKET_LOCK(tcb); SOCKET_LOCK(so); QSOCKET_UNLOCK(tcb); LogFlow(("soread: so = %R[natsock]\n", so)); Log2(("%s: so = %R[natsock] so->so_snd = %R[sbuf]\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, so, sb)); /* * No need to check if there's enough room to read. * soread wouldn't have been called if there weren't */ len = sb->sb_datalen - sb->sb_cc; iov[0].iov_base = sb->sb_wptr; iov[1].iov_base = 0; iov[1].iov_len = 0; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_rptr - sb->sb_data; if (iov[1].iov_len > len) iov[1].iov_len = len; total = iov[0].iov_len + iov[1].iov_len; if (total > mss) { lss = total % mss; if (iov[1].iov_len > lss) { iov[1].iov_len -= lss; n = 2; } else { lss -= iov[1].iov_len; iov[0].iov_len -= lss; n = 1; } } else n = 2; } else { if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } } #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); #else nn = recv(so->s, iov[0].iov_base, iov[0].iov_len, (so->so_tcpcb->t_force? MSG_OOB:0)); #endif if (nn < 0) sockerr = errno; /* save it, as it may be clobbered by logging */ else sockerr = 0; Log2(("%s: read(1) nn = %d bytes\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, nn)); Log2(("%s: so = %R[natsock] so->so_snd = %R[sbuf]\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, so, sb)); if (nn <= 0) { #ifdef RT_OS_WINDOWS /* * Windows reports ESHUTDOWN after SHUT_RD (SD_RECEIVE) * instead of just returning EOF indication. */ if (nn < 0 && sockerr == ESHUTDOWN) { nn = 0; sockerr = 0; } #endif if (nn == 0) /* XXX: should this be inside #if defined(RT_OS_WINDOWS)? */ { /* * Special case for WSAEnumNetworkEvents: If we receive 0 bytes that * _could_ mean that the connection is closed. But we will receive an * FD_CLOSE event later if the connection was _really_ closed. With * www.youtube.com I see this very often. Closing the socket too early * would be dangerous. */ int status; unsigned long pending = 0; status = ioctlsocket(so->s, FIONREAD, &pending); if (status < 0) Log(("NAT:%s: error in WSAIoctl: %d\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, errno)); if (pending != 0) { SOCKET_UNLOCK(so); STAM_PROFILE_STOP(&pData->StatIOread, a); return 0; } } if ( nn < 0 && soIgnorableErrorCode(sockerr)) { SOCKET_UNLOCK(so); STAM_PROFILE_STOP(&pData->StatIOread, a); return 0; } else { int fUninitializedTemplate = 0; int shuterr; fUninitializedTemplate = RT_BOOL(( sototcpcb(so) && ( sototcpcb(so)->t_template.ti_src.s_addr == INADDR_ANY || sototcpcb(so)->t_template.ti_dst.s_addr == INADDR_ANY))); /* nn == 0 means peer has performed an orderly shutdown */ Log2(("%s: disconnected, nn = %d, errno = %d (%s)\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, nn, sockerr, strerror(sockerr))); shuterr = sofcantrcvmore(so); if (!sockerr && !shuterr && !fUninitializedTemplate) tcp_sockclosed(pData, sototcpcb(so)); else { LogRel2(("NAT: sockerr %d, shuterr %d - %R[natsock]\n", sockerr, shuterr, so)); tcp_drop(pData, sototcpcb(so), sockerr); } SOCKET_UNLOCK(so); STAM_PROFILE_STOP(&pData->StatIOread, a); return -1; } } STAM_STATS( if (n == 1) { STAM_COUNTER_INC(&pData->StatIORead_in_1); STAM_COUNTER_ADD(&pData->StatIORead_in_1_bytes, nn); } else { STAM_COUNTER_INC(&pData->StatIORead_in_2); STAM_COUNTER_ADD(&pData->StatIORead_in_2_1st_bytes, nn); } );