Index: /trunk/include/VBox/iommu-intel.h
===================================================================
--- /trunk/include/VBox/iommu-intel.h	(revision 88493)
+++ /trunk/include/VBox/iommu-intel.h	(revision 88494)
@@ -1352,4 +1352,7 @@
 /** RW: Read/write mask. */
 #define VTD_IQT_REG_RW_MASK                                     VTD_BF_IQT_REG_QT_MASK
+
+/** IQT_REG.QT: Gets the queue tail. */
+#define VTD_IQT_REG_GET_QT(a)                                   ((a) & (VTD_BF_IQT_REG_QT_MASK | VTD_BF_IQT_REG_RSVD_3_0_MASK))
 /** @} */
 
@@ -1376,4 +1379,8 @@
 #define VTD_IQA_REG_RW_MASK                                     (  VTD_BF_IQA_REG_QS_MASK | VTD_BF_IQA_REG_DW_MASK \
                                                                  | VTD_BF_IQA_REG_IQA_MASK)
+/** DW: 128-bit descriptor. */
+#define VTD_IQA_REG_DW_128_BIT                                  0
+/** DW: 256-bit descriptor. */
+#define VTD_IQA_REG_DW_256_BIT                                  1
 /** @} */
 
Index: /trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp	(revision 88493)
+++ /trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp	(revision 88494)
@@ -585,9 +585,10 @@
  * This will preserve read-only bits, mask off reserved bits and clear RW1C bits.
  *
+ * @returns The value that's actually written to the register.
  * @param   pThis   The shared DMAR device state.
  * @param   offReg  The MMIO offset of the register.
  * @param   uReg    The 64-bit value to write.
  */
-static void dmarRegWrite64(PDMAR pThis, uint16_t offReg, uint64_t uReg)
+static uint64_t dmarRegWrite64(PDMAR pThis, uint16_t offReg, uint64_t uReg)
 {
     /* Read current value from the 64-bit register. */
@@ -604,4 +605,5 @@
     /* Write new value to the 64-bit register. */
     dmarRegWriteRaw64(pThis, offReg, uNewReg);
+    return uNewReg;
 }
 
@@ -611,9 +613,10 @@
  * This will preserve read-only bits, mask off reserved bits and clear RW1C bits.
  *
+ * @returns The value that's actually written to the register.
  * @param   pThis   The shared DMAR device state.
  * @param   offReg  The MMIO offset of the register.
  * @param   uReg    The 32-bit value to write.
  */
-static void dmarRegWrite32(PDMAR pThis, uint16_t offReg, uint32_t uReg)
+static uint32_t dmarRegWrite32(PDMAR pThis, uint16_t offReg, uint32_t uReg)
 {
     /* Read current value from the 32-bit register. */
@@ -630,4 +633,5 @@
     /* Write new value to the 32-bit register. */
     dmarRegWriteRaw32(pThis, offReg, uNewReg);
+    return uNewReg;
 }
 
@@ -666,4 +670,38 @@
     NOREF(fRwMask); NOREF(fRw1cMask);
     return uCurReg;
+}
+
+
+/**
+ * Handles writes to IQT_REG.
+ *
+ * @returns Strict VBox status code.
+ * @param   pDevIns     The IOMMU device instance.
+ * @param   off         The MMIO register offset.
+ * @param   uIqtReg     The value written to IQT_REG.
+ */
+static VBOXSTRICTRC dmarIqtRegWrite(PPDMDEVINS pDevIns, uint16_t off, uint64_t uIqtReg)
+{
+    /* We only care about the low dword of VTD_MMIO_OFF_IQT_REG. */
+    PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
+    if (off == VTD_MMIO_OFF_IQT_REG)
+    {
+        /* Verify if the queue tail offset is aligned according to the descriptor width in IQA_REG. */
+        uint16_t const offQueueTail = VTD_IQT_REG_GET_QT(uIqtReg);
+        uint64_t const uIqaReg      = dmarRegRead64(pThis, VTD_MMIO_OFF_IQA_REG);
+        uint8_t const  uDw          = RT_BF_GET(uIqaReg, VTD_BF_IQA_REG_DW);
+        if (   uDw != VTD_IQA_REG_DW_256_BIT
+            || !(offQueueTail & 0x1f))
+        {
+            /** @todo IOMMU: Figure out what to do here, like waking up worker thread or
+             *        something. */
+        }
+        else
+        {
+            /* Raise invalidation queue error as queue tail not aligned to 256-bits. */
+            /** @todo IOMMU: Raise error. */
+        }
+    }
+    return VINF_SUCCESS;
 }
 
@@ -747,18 +785,19 @@
     if (DMAR_IS_MMIO_OFF_VALID(offLast))
     {
+        uint64_t const uRegWritten = cb == 8 ? dmarRegWrite64(pThis, offReg, *(uint64_t *)pv)
+                                             : dmarRegWrite32(pThis, offReg, *(uint32_t *)pv);
+        VBOXSTRICTRC rcStrict = VINF_SUCCESS;
         switch (off)
         {
-            default:
+            case VTD_MMIO_OFF_IQT_REG:
+            case VTD_MMIO_OFF_IQT_REG + 4:
             {
-                if (cb == 8)
-                    dmarRegWrite64(pThis, offReg, *(uint64_t *)pv);
-                else
-                    dmarRegWrite32(pThis, offReg, *(uint32_t *)pv);
+                rcStrict = dmarIqtRegWrite(pDevIns, offReg, uRegWritten);
                 break;
             }
         }
 
-        LogFlowFunc(("offReg=%#x\n", offReg));
-        return VINF_SUCCESS;
+        LogFlowFunc(("offReg=%#x rc=%Rrc\n", offReg, VBOXSTRICTRC_VAL(rcStrict)));
+        return rcStrict;
     }
 
