summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/USB
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/USB')
-rw-r--r--src/VBox/Devices/USB/DevEHCI.cpp41
-rw-r--r--src/VBox/Devices/USB/DrvVUSBRootHub.cpp13
-rw-r--r--src/VBox/Devices/USB/VUSBInternal.h2
-rw-r--r--src/VBox/Devices/USB/VUSBUrb.cpp2
-rw-r--r--src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp37
5 files changed, 71 insertions, 24 deletions
diff --git a/src/VBox/Devices/USB/DevEHCI.cpp b/src/VBox/Devices/USB/DevEHCI.cpp
index 1ca85af3..48659563 100644
--- a/src/VBox/Devices/USB/DevEHCI.cpp
+++ b/src/VBox/Devices/USB/DevEHCI.cpp
@@ -161,7 +161,7 @@ typedef struct VUSBURBHCITDINT
/** The address of the TD. */
RTGCPHYS TdAddr;
/** A copy of the TD. */
- uint32_t TdCopy[16];
+ uint32_t TdCopy[18];
} VUSBURBHCITDINT;
/**
@@ -526,19 +526,25 @@ typedef const EHCI_ITD *PEHCI_CITD;
AssertCompileSize(EHCI_ITD, 0x40);
/** @} */
-/* ITD with extra padding to add 8th 'Buffer' entry. The PG member of
+/* ITD with extra padding to add 8th and 9th 'Buffer' entry. The PG member of
* EHCI_ITD_TRANSACTION can contain values in the 0-7 range, but only values
* 0-6 are valid. The extra padding is added to avoid cluttering the code
* with range checks; ehciR3ReadItd() initializes the pad with a safe value.
* The EHCI 1.0 specification explicitly says using PG value of 7 yields
- * undefined behavior.
+ * undefined behavior. Two pad entries are needed because initial PG value
+ * of 7 (already 'wrong') can cross to the next page (8).
*/
typedef struct
{
- EHCI_ITD itd;
- EHCI_BUFFER_PTR pad;
+ EHCI_TD_PTR Next;
+ EHCI_ITD_TRANSACTION Transaction[EHCI_NUM_ITD_TRANSACTIONS];
+ union
+ {
+ EHCI_ITD_MISC Misc;
+ EHCI_BUFFER_PTR Buffer[EHCI_NUM_ITD_PAGES + 2];
+ } Buffer;
} EHCI_ITD_PAD, *PEHCI_ITD_PAD;
-AssertCompileSize(EHCI_ITD_PAD, 0x44);
+AssertCompileSize(EHCI_ITD_PAD, 0x48);
/** @name Split Transaction Isochronous Transfer Descriptor (siTD)
* @{ */
@@ -1471,7 +1477,8 @@ DECLINLINE(void) ehciR3ReadTDPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, EHCI_TD_PT
DECLINLINE(void) ehciR3ReadItd(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_ITD_PAD pPItd)
{
ehciGetDWords(pDevIns, GCPhys, (uint32_t *)pPItd, sizeof(EHCI_ITD) >> 2);
- pPItd->pad.Pointer = 0xFFFFF; /* Direct accesses at the last page under 4GB (ROM). */
+ pPItd->Buffer.Buffer[7].Pointer = 0xFFFFF; /* Direct ill-defined accesses to the last page under 4GB (ROM). */
+ pPItd->Buffer.Buffer[8].Pointer = 0xFFFFF;
}
DECLINLINE(void) ehciR3ReadSitd(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_SITD pSitd)
@@ -1479,7 +1486,7 @@ DECLINLINE(void) ehciR3ReadSitd(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_SITD
ehciGetDWords(pDevIns, GCPhys, (uint32_t *)pSitd, sizeof(*pSitd) >> 2);
}
-DECLINLINE(void) ehciR3WriteItd(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_ITD pItd)
+DECLINLINE(void) ehciR3WriteItd(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_ITD_PAD pItd)
{
/** @todo might need to be careful about write order in async io thread */
/*
@@ -1490,7 +1497,7 @@ DECLINLINE(void) ehciR3WriteItd(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_ITD p
uint32_t offDWordsWrite = offWrite / sizeof(uint32_t);
Assert(!(offWrite % sizeof(uint32_t)));
- ehciPutDWords(pDevIns, GCPhys + offWrite, (uint32_t *)pItd + offDWordsWrite, (sizeof(*pItd) >> 2) - offDWordsWrite);
+ ehciPutDWords(pDevIns, GCPhys + offWrite, (uint32_t *)pItd + offDWordsWrite, (sizeof(EHCI_ITD) >> 2) - offDWordsWrite);
}
DECLINLINE(void) ehciR3ReadQHD(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PEHCI_QHD pQHD)
@@ -1758,7 +1765,7 @@ DECLINLINE(void) ehciR3DumpITD(PPDMDEVINS pDevIns, RTGCPHYS GCPhysHead, bool fLi
/* Read the whole ITD */
EHCI_ITD_PAD PaddedItd;
- PEHCI_ITD pItd = &PaddedItd.itd;
+ PEHCI_ITD_PAD pItd = &PaddedItd;
ehciR3ReadItd(pDevIns, GCPhys, &PaddedItd);
Log2(("Addr=%x EndPt=%x Dir=%s MaxSize=%x Mult=%d}\n", pItd->Buffer.Misc.DeviceAddress, pItd->Buffer.Misc.EndPt, (pItd->Buffer.Misc.DirectionIn) ? "in" : "out", pItd->Buffer.Misc.MaxPacket, pItd->Buffer.Misc.Multi));
@@ -2028,7 +2035,7 @@ static int ehciR3InFlightRemoveUrb(PEHCI pThis, PEHCICC pThisCC, PVUSBURB pUrb)
* @param pUrb The URB in question.
* @param pItd The ITD pointer.
*/
-static bool ehciR3ItdHasUrbBeenCanceled(PEHCICC pThisCC, PVUSBURB pUrb, PEHCI_ITD pItd)
+static bool ehciR3ItdHasUrbBeenCanceled(PEHCICC pThisCC, PVUSBURB pUrb, PEHCI_ITD_PAD pItd)
{
RT_NOREF(pThisCC);
Assert(pItd);
@@ -2252,7 +2259,7 @@ static void ehciR3RhXferCompleteITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pTh
{
/* Read the whole ITD */
EHCI_ITD_PAD PaddedItd;
- PEHCI_ITD pItd = &PaddedItd.itd;
+ PEHCI_ITD_PAD pItd = &PaddedItd;
ehciR3ReadItd(pDevIns, pUrb->paTds[0].TdAddr, &PaddedItd);
/*
@@ -2323,7 +2330,7 @@ static void ehciR3RhXferCompleteITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pTh
ehciPhysWrite(pDevIns, GCPhysBuf, pb, cb1);
if ((pg + 1) >= EHCI_NUM_ITD_PAGES)
- LogRelMax(10, ("EHCI: Crossing to undefined page %d in iTD at %RGp on completion.\n", pg + 1, pUrb->paTds[0].TdAddr));
+ LogRelMax(10, ("EHCI: Crossing to nonstandard page %d in iTD at %RGp on completion.\n", pg + 1, pUrb->paTds[0].TdAddr));
GCPhysBuf = (RTGCPHYS)pItd->Buffer.Buffer[pg + 1].Pointer << EHCI_BUFFER_PTR_SHIFT;
ehciPhysWrite(pDevIns, GCPhysBuf, pb + cb1, cb2);
@@ -2790,7 +2797,7 @@ static bool ehciR3SubmitQTD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC, RT
* @returns false on failure to submit.
*/
static bool ehciR3SubmitITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
- PEHCI_ITD pItd, RTGCPHYS ITdAddr, const unsigned iFrame)
+ PEHCI_ITD_PAD pItd, RTGCPHYS ITdAddr, const unsigned iFrame)
{
/*
* Determine the endpoint direction.
@@ -2875,7 +2882,7 @@ static bool ehciR3SubmitITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
ehciPhysRead(pDevIns, GCPhysBuf, &pUrb->abData[curOffset], cb1);
if ((pg + 1) >= EHCI_NUM_ITD_PAGES)
- LogRelMax(10, ("EHCI: Crossing to undefined page %d in iTD at %RGp on submit.\n", pg + 1, pUrb->paTds[0].TdAddr));
+ LogRelMax(10, ("EHCI: Crossing to nonstandard page %d in iTD at %RGp on submit.\n", pg + 1, pUrb->paTds[0].TdAddr));
GCPhysBuf = (RTGCPHYS)pItd->Buffer.Buffer[pg + 1].Pointer << EHCI_BUFFER_PTR_SHIFT;
ehciPhysRead(pDevIns, GCPhysBuf, &pUrb->abData[curOffset + cb1], cb2);
@@ -2932,7 +2939,7 @@ static void ehciR3ServiceITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
RT_NOREF(enmServiceType);
bool fAnyActive = false;
EHCI_ITD_PAD PaddedItd;
- PEHCI_ITD pItd = &PaddedItd.itd;
+ PEHCI_ITD_PAD pItd = &PaddedItd;
if (ehciR3IsTdInFlight(pThisCC, GCPhys))
return;
@@ -2953,7 +2960,7 @@ static void ehciR3ServiceITD(PPDMDEVINS pDevIns, PEHCI pThis, PEHCICC pThisCC,
/* Using out of range PG value (7) yields undefined behavior. We will attempt
* the last page below 4GB (which is ROM, not writable).
*/
- LogRelMax(10, ("EHCI: Illegal page value %d in iTD at %RGp.\n", pItd->Transaction[i].PG, (RTGCPHYS)GCPhys));
+ LogRelMax(10, ("EHCI: Nonstandard page value %d in iTD at %RGp.\n", pItd->Transaction[i].PG, (RTGCPHYS)GCPhys));
}
Log2((" T%d Len=%x Offset=%x PG=%d IOC=%d Buffer=%x\n", i, pItd->Transaction[i].Length, pItd->Transaction[i].Offset, pItd->Transaction[i].PG, pItd->Transaction[i].IOC,
diff --git a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
index c1d5ab9d..81a4b08d 100644
--- a/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
+++ b/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
@@ -703,7 +703,8 @@ DECLHIDDEN(uint64_t) vusbRhR3ProcessFrame(PVUSBROOTHUB pThis, bool fCallback)
uint64_t tsNanoStart = RTTimeNanoTS();
/* Don't do anything if we are not supposed to process anything (EHCI and XHCI). */
- if (!pThis->uFrameRateDefault)
+ if ( !pThis->uFrameRateDefault
+ || ASMAtomicReadBool(&pThis->fSavingState))
return 0;
if (ASMAtomicXchgBool(&pThis->fFrameProcessing, true))
@@ -1348,15 +1349,16 @@ static DECLCALLBACK(int) vusbR3RhSavePrep(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
LogFlow(("vusbR3RhSavePrep:\n"));
RT_NOREF(pSSM);
+ ASMAtomicXchgBool(&pThis->fSavingState, true);
+
/*
* Detach all proxied devices.
*/
- RTCritSectEnter(&pThis->CritSectDevices);
/** @todo we a) can't tell which are proxied, and b) this won't work well when continuing after saving! */
for (unsigned i = 0; i < RT_ELEMENTS(pThis->apDevByPort); i++)
{
- PVUSBDEV pDev = pThis->apDevByPort[i];
+ PVUSBDEV pDev = vusbR3RhGetVUsbDevByPortRetain(pThis, i, "SavePrep");
if (pDev)
{
if (!VUSBIDevIsSavedStateSupported(&pDev->IDevice))
@@ -1369,13 +1371,13 @@ static DECLCALLBACK(int) vusbR3RhSavePrep(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
* This will work fine even if the save fails since the Done handler is
* called unconditionally if the Prep handler was called.
*/
+ Assert(!pThis->apDevByPort[i]);
pThis->apDevByPort[i] = pDev;
+ vusbDevRelease(pDev, "SavePrep");
}
}
}
- RTCritSectLeave(&pThis->CritSectDevices);
-
/*
* Kill old load data which might be hanging around.
*/
@@ -1423,6 +1425,7 @@ static DECLCALLBACK(int) vusbR3RhSaveDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
vusbHubAttach(pThis, pDev);
}
+ ASMAtomicXchgBool(&pThis->fSavingState, false);
return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/USB/VUSBInternal.h b/src/VBox/Devices/USB/VUSBInternal.h
index e82c4ce4..4a482ca5 100644
--- a/src/VBox/Devices/USB/VUSBInternal.h
+++ b/src/VBox/Devices/USB/VUSBInternal.h
@@ -421,6 +421,8 @@ typedef struct VUSBROOTHUB
/** Flag whether a frame is currently being processed. */
volatile bool fFrameProcessing;
+ /** Flag whether we are in the middle of saving the VM state. */
+ volatile bool fSavingState;
#if HC_ARCH_BITS == 32
uint32_t Alignment1;
diff --git a/src/VBox/Devices/USB/VUSBUrb.cpp b/src/VBox/Devices/USB/VUSBUrb.cpp
index 595277f9..f55e8746 100644
--- a/src/VBox/Devices/USB/VUSBUrb.cpp
+++ b/src/VBox/Devices/USB/VUSBUrb.cpp
@@ -231,7 +231,7 @@ static void vusbMsgCompletion(PVUSBURB pUrb)
int vusbUrbErrorRhEx(PVUSBROOTHUB pRh, PVUSBURB pUrb)
{
PVUSBDEV pDev = pUrb->pVUsb->pDev;
- LogFlow(("%s: vusbUrbErrorRh: pDev=%p[%s] rh=%p\n", pUrb->pszDesc, pDev, pDev->pUsbIns ? pDev->pUsbIns->pszName : "", pRh));
+ LogFlow(("%s: vusbUrbErrorRh: pDev=%p[%s] rh=%p\n", pUrb->pszDesc, pDev, pDev && pDev->pUsbIns ? pDev->pUsbIns->pszName : "", pRh));
RT_NOREF(pDev);
return pRh->pIRhPort->pfnXferError(pRh->pIRhPort, pUrb);
}
diff --git a/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp b/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp
index e76eb5f8..f3b568f7 100644
--- a/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp
+++ b/src/VBox/Devices/USB/darwin/USBProxyDevice-darwin.cpp
@@ -50,6 +50,7 @@
#include <iprt/assert.h>
#include <iprt/critsect.h>
+#include <iprt/ldr.h>
#include <iprt/list.h>
#include <iprt/mem.h>
#include <iprt/once.h>
@@ -74,6 +75,17 @@
typedef struct USBPROXYIFOSX *PUSBPROXYIFOSX;
+/** @name IOKitLib declarations and definitions for IOServiceAuthorize() which is not available in all SDKs.
+ * @{ */
+/** IOServiceAuthorize in IOKit. */
+typedef kern_return_t (* PFNIOSERVICEAUTHORIZE)(io_service_t, uint32_t options);
+
+#ifndef kIOServiceInteractionAllowed
+# define kIOServiceInteractionAllowed 0x00000001
+#endif
+/** @} */
+
+
/**
* A low latency isochronous buffer.
*
@@ -278,6 +290,8 @@ static CFStringRef g_pRunLoopMode = NULL;
/** The IO Master Port.
* Not worth cleaning up. */
static mach_port_t g_MasterPort = MACH_PORT_NULL;
+/** Pointer to the IOServiceAuthorize() method. */
+static PFNIOSERVICEAUTHORIZE g_pfnIOServiceAuthorize = NULL;
/**
@@ -291,7 +305,17 @@ static DECLCALLBACK(int32_t) usbProxyDarwinInitOnce(void *pvUser1)
{
RT_NOREF(pvUser1);
- int rc;
+ RTLDRMOD hMod = NIL_RTLDRMOD;
+ int rc = RTLdrLoadEx("/System/Library/Frameworks/IOKit.framework/Versions/Current/IOKit", &hMod, RTLDRLOAD_FLAGS_NO_SUFFIX | RTLDRLOAD_FLAGS_NO_UNLOAD,
+ NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTLdrGetSymbol(hMod, "IOServiceAuthorize", (void **)&g_pfnIOServiceAuthorize);
+ if (RT_FAILURE(rc))
+ LogRel(("USB: Failed to resolve IOServiceAuthorize(), capturing USB devices might not work (%Rrc)\n", rc));
+ RTLdrClose(hMod);
+ }
+
kern_return_t krc = IOMasterPort(MACH_PORT_NULL, &g_MasterPort);
if (krc == KERN_SUCCESS)
{
@@ -1215,6 +1239,17 @@ static DECLCALLBACK(int) usbProxyDarwinOpen(PUSBPROXYDEV pProxyDev, const char *
}
/*
+ * Ask for authorization (which only works with the com.apple.vm.device-access entitlement).
+ */
+ if (g_pfnIOServiceAuthorize)
+ {
+ irc = g_pfnIOServiceAuthorize(USBDevice, kIOServiceInteractionAllowed);
+ if (irc != kIOReturnSuccess)
+ LogRel(("USB: Failed to get authorization for device '%s', capturing the device might not work: irc=%#x\n",
+ pszAddress, irc));
+ }
+
+ /*
* Create a plugin interface for the device and query its IOUSBDeviceInterface.
*/
SInt32 Score = 0;