Index: /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 84290)
+++ /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 84291)
@@ -497,4 +497,15 @@
         else \
             return rcLock; \
+    } while (0)
+
+/**
+ * Acquires the IOMMU PDM lock (no return, only asserts on failure).
+ * This will make a long jump to ring-3 to acquire the lock if necessary.
+ */
+#define IOMMU_LOCK_NORET(a_pDevIns, a_pThis)  \
+    do { \
+        NOREF(pThis); \
+        int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo), VINF_SUCCESS); \
+        AssertRC(rcLock); \
     } while (0)
 
@@ -995,4 +1006,6 @@
     /** The 32-bit unsigned integer view.  */
     uint32_t    au32[4];
+    /** The 64-bit unsigned integer view. */
+    uint64_t    au64[2];
 } EVT_ILLEGAL_DTE_T;
 AssertCompileSize(EVT_ILLEGAL_DTE_T, 16);
@@ -1028,4 +1041,6 @@
     /** The 32-bit unsigned integer view.  */
     uint32_t    au32[4];
+    /** The 64-bit unsigned integer view. */
+    uint64_t    au64[2];
 } EVT_IO_PAGE_FAULT_T;
 AssertCompileSize(EVT_IO_PAGE_FAULT_T, 16);
@@ -1059,4 +1074,6 @@
     /** The 32-bit unsigned integer view.  */
     uint32_t    au32[4];
+    /** The 64-bit unsigned integer view. */
+    uint64_t    au64[2];
 } EVT_DEV_TAB_HW_ERROR_T;
 AssertCompileSize(EVT_DEV_TAB_HW_ERROR_T, 16);
@@ -1094,4 +1111,6 @@
     /** The 32-bit unsigned integer view. */
     uint32_t    au32[4];
+    /** The 64-bit unsigned integer view. */
+    uint64_t    au64[2];
 } EVT_PAGE_TAB_HW_ERR_T;
 AssertCompileSize(EVT_PAGE_TAB_HW_ERR_T, 16);
@@ -1100,5 +1119,4 @@
 /** Pointer to a const page table hardware error event. */
 typedef EVT_PAGE_TAB_HW_ERR_T const *PCEVT_PAGE_TAB_HW_ERR_T;
-
 
 /**
@@ -1119,4 +1137,6 @@
     /** The 32-bit unsigned integer view. */
     uint32_t    au32[4];
+    /** The 64-bit unsigned integer view. */
+    uint64_t    au64[2];
 } EVT_ILLEGAL_CMD_ERR_T;
 AssertCompileSize(EVT_ILLEGAL_CMD_ERR_T, 16);
@@ -1130,13 +1150,21 @@
     struct
     {
-        uint32_t    u32Rsvd0;           /**< Bits 31:0  - Reserved. */
-        uint32_t    u4Rsvd0 : 4;        /**< Bits 35:32 - Reserved. */
-        uint32_t    u28AddrLo : 28;     /**< Bits 63:36 - Address: SPA of the attempted access (Lo). */
-        uint32_t    u32AddrHi;          /**< Bits 95:64 - Address: SPA of the attempted access (Hi). */
+        uint32_t    u32Rsvd0;           /**< Bits 31:0   - Reserved. */
+        uint32_t    u25Rsvd1 : 25;      /**< Bits 56:32  - Reserved. */
+        uint32_t    u2Type : 2;         /**< Bits 58:57  - Type: The type of hardware error. */
+        uint32_t    u1Rsvd1 : 1;        /**< Bit  59     - Reserved. */
+        uint32_t    u4EvtCode : 4;      /**< Bits 63:60  - Event code. */
+        uint64_t    u64Addr;            /**< Bits 128:64 - Address: SPA of the attempted access. */
     } n;
     /** The 32-bit unsigned integer view. */
-    uint32_t    au32[3];
-} EVT_CMD_HW_ERROR_T;
-AssertCompileSize(EVT_CMD_HW_ERROR_T, 12);
+    uint32_t    au32[4];
+    /** The 64-bit unsigned integer view. */
+    uint64_t    au64[2];
+} EVT_CMD_HW_ERR_T;
+AssertCompileSize(EVT_CMD_HW_ERR_T, 16);
+/** Pointer to a command hardware error event. */
+typedef EVT_CMD_HW_ERR_T *PEVT_CMD_HW_ERR_T;
+/** Pointer to a const command hardware error event. */
+typedef EVT_CMD_HW_ERR_T const *PCEVT_CMD_HW_ERR_T;
 
 /**
@@ -2602,4 +2630,18 @@
 
 /**
+ * Halts command processing.
+ *
+ * @param   pDevIns     The IOMMU device instance.
+ */
+static void iommuAmdHaltCmdProcessing(PPDMDEVINS pDevIns)
+{
+    IOMMU_ASSERT_LOCKED(pDevIns);
+
+    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING);
+}
+
+
+/**
  * Wakes up the command thread if there are commands to be processed or if
  * processing is requested to be stopped by software.
@@ -3566,6 +3608,6 @@
 static void iommuAmdSetHwError(PPDMDEVINS pDevIns, PCEVT_GENERIC_T pEvent)
 {
-    /** @todo IOMMU: We should probably lock the device here */
     PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    IOMMU_LOCK_NORET(pDevIns, pThis);
     if (pThis->ExtFeat.n.u1HwErrorSup)
     {
@@ -3577,4 +3619,5 @@
         Assert(pThis->HwEvtHi.n.u4EvtCode == IOMMU_EVT_DEV_TAB_HW_ERROR);
     }
+    IOMMU_UNLOCK(pDevIns, pThis);
 }
 
@@ -3600,5 +3643,5 @@
     pEvtPageTabHwErr->n.u1ReadWrite        = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     pEvtPageTabHwErr->n.u1Translation      = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
-    pEvtPageTabHwErr->n.u2Type             = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT;;
+    pEvtPageTabHwErr->n.u2Type             = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT;
     pEvtPageTabHwErr->n.u4EvtCode          = IOMMU_EVT_PAGE_TAB_HW_ERROR;
     pEvtPageTabHwErr->n.u64Addr            = GCPhysPtEntity;
@@ -3627,4 +3670,41 @@
     Log((IOMMU_LOG_PFX ": Raised PAGE_TAB_HARDWARE_ERROR. uDevId=%#x uDomainId=%#x GCPhysPtEntity=%#RGp enmOp=%u enmType=%u\n",
          pEvtPageTabHwErr->n.u16DevId, pEvtPageTabHwErr->n.u16DomainOrPasidLo, pEvtPageTabHwErr->n.u64Addr, enmOp, enmEvtType));
+    NOREF(enmEvtType);
+}
+
+
+/**
+ * Initializes a COMMAND_HARDWARE_ERROR event.
+ *
+ * @param   GCPhysCmd       The system physical address of the command that caused
+ *                          the error.
+ * @param   pEvtCmdHwErr    Where to store the initialized event.
+ */
+static void iommuAmdInitCmdHwErrorEvent(RTGCPHYS GCPhysCmd, HWEVTTYPE enmHwErrType, PEVT_CMD_HW_ERR_T pEvtCmdHwErr)
+{
+    memset(pEvtCmdHwErr, 0, sizeof(*pEvtCmdHwErr));
+    pEvtCmdHwErr->n.u2Type    = enmHwErrType;
+    pEvtCmdHwErr->n.u4EvtCode = IOMMU_EVT_COMMAND_HW_ERROR;
+    pEvtCmdHwErr->n.u64Addr   = GCPhysCmd;
+}
+
+
+/**
+ * Raises a COMMAND_HARDWARE_ERROR event.
+ *
+ * @param   pDevIns         The IOMMU device instance.
+ * @param   pEvtCmdHwErr    The command hardware error event.
+ * @param   enmEvtType      The hardware error event type.
+ */
+static void iommuAmdRaiseCmdHwErrorEvent(PPDMDEVINS pDevIns, PCEVT_CMD_HW_ERR_T pEvtCmdHwErr, EVT_HW_ERR_TYPE_T enmEvtType)
+{
+    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_CMD_HW_ERR_T));
+    PCEVT_GENERIC_T pEvent = (PCEVT_GENERIC_T)pEvtCmdHwErr;
+
+    iommuAmdSetHwError(pDevIns, (PCEVT_GENERIC_T)pEvent);
+    iommuAmdWriteEvtLogEntry(pDevIns, (PCEVT_GENERIC_T)pEvent);
+    iommuAmdHaltCmdProcessing(pDevIns);
+
+    Log((IOMMU_LOG_PFX ": Raised COMMAND_HARDWARE_ERROR. GCPhysCmd=%#RGp enmType=%u\n", pEvtCmdHwErr->n.u64Addr, enmEvtType));
     NOREF(enmEvtType);
 }
@@ -4548,5 +4628,5 @@
          *        mappings and accessing them directly. */
         IOMMU_STATUS_T Status = iommuAmdGetStatus(pThis);
-        if (Status.n.u1CmdBufRunning)
+        if (Status.u64 & IOMMU_STATUS_CMD_BUF_RUNNING)
         {
             IOMMU_LOCK(pDevIns, pThis);
@@ -4583,7 +4663,8 @@
                 else
                 {
-                    /** @todo IOMMU: Raise command hardware error. */
-                    /* Stop command processing. */
-                    ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING);
+                    /* Reporting this as a "data error". Maybe target abort is more appropriate? */
+                    EVT_CMD_HW_ERR_T EvtCmdHwErr;
+                    iommuAmdInitCmdHwErrorEvent(GCPhysCmd, HWEVTTYPE_DATA_ERROR, & EvtCmdHwErr);
+                    iommuAmdRaiseCmdHwErrorEvent(pDevIns, &EvtCmdHwErr, kHwErrType_PoisonedData);
                     break;
                 }
