Index: /trunk/include/VBox/VMMDevTesting.h
===================================================================
--- /trunk/include/VBox/VMMDevTesting.h	(revision 61383)
+++ /trunk/include/VBox/VMMDevTesting.h	(revision 61384)
@@ -43,8 +43,25 @@
 /** The size of the MMIO range used for testing.  */
 #define VMMDEV_TESTING_MMIO_SIZE        UINT32_C(0x00001000)
-/** The NOP MMIO register - 1248 RW. */
-#define VMMDEV_TESTING_MMIO_NOP         (VMMDEV_TESTING_MMIO_BASE + 0x000)
-/** The go-to-ring-3-NOP MMIO register - 1248 RW. */
-#define VMMDEV_TESTING_MMIO_NOP_R3      (VMMDEV_TESTING_MMIO_BASE + 0x008)
+
+/** MMIO offset: The NOP register - 1248 RW. */
+#define VMMDEV_TESTING_MMIO_OFF_NOP         (0x000)
+/** MMIO offset: The go-to-ring-3-NOP register - 1248 RW. */
+#define VMMDEV_TESTING_MMIO_OFF_NOP_R3      (0x008)
+/** MMIO offset: The readback registers - 64 bytes of read/write "memory". */
+#define VMMDEV_TESTING_MMIO_OFF_READBACK    (0x040)
+/** MMIO offset: Readback register view that always goes to ring-3. */
+#define VMMDEV_TESTING_MMIO_OFF_READBACK_R3 (0x080)
+/** The size of the MMIO readback registers. */
+#define VMMDEV_TESTING_READBACK_SIZE        (0x40)
+
+/** Default address of VMMDEV_TESTING_MMIO_OFF_NOP. */
+#define VMMDEV_TESTING_MMIO_NOP             (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP)
+/** Default address of VMMDEV_TESTING_MMIO_OFF_NOP_R3. */
+#define VMMDEV_TESTING_MMIO_NOP_R3          (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP_R3)
+/** Default address of VMMDEV_TESTING_MMIO_OFF_READBACK. */
+#define VMMDEV_TESTING_MMIO_READBACK        (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK)
+/** Default address of VMMDEV_TESTING_MMIO_OFF_READBACK_R3. */
+#define VMMDEV_TESTING_MMIO_READBACK_R3     (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK_R3)
+
 /** The real mode selector to use.
  * @remarks Requires that the A20 gate is enabled. */
@@ -52,4 +69,6 @@
 /** Calculate the real mode offset of a MMIO register. */
 #define VMMDEV_TESTING_MMIO_RM_OFF(val)  ((val) - 0xffff0)
+/** Calculate the real mode offset of a MMIO register offset. */
+#define VMMDEV_TESTING_MMIO_RM_OFF2(off) ((off) + 16 + 0x1000)
 
 /** The base port of the I/O range used for testing. */
Index: /trunk/include/VBox/VMMDevTesting.mac
===================================================================
--- /trunk/include/VBox/VMMDevTesting.mac	(revision 61383)
+++ /trunk/include/VBox/VMMDevTesting.mac	(revision 61384)
@@ -3,8 +3,16 @@
 %define VMMDEV_TESTING_MMIO_BASE        0x00101000
 %define VMMDEV_TESTING_MMIO_SIZE        0x00001000
-%define VMMDEV_TESTING_MMIO_NOP         (VMMDEV_TESTING_MMIO_BASE + 0x000)
-%define VMMDEV_TESTING_MMIO_NOP_R3      (VMMDEV_TESTING_MMIO_BASE + 0x008)
+%define VMMDEV_TESTING_MMIO_OFF_NOP         (0x000)
+%define VMMDEV_TESTING_MMIO_OFF_NOP_R3      (0x008)
+%define VMMDEV_TESTING_MMIO_OFF_READBACK    (0x040)
+%define VMMDEV_TESTING_MMIO_OFF_READBACK_R3 (0x080)
+%define VMMDEV_TESTING_READBACK_SIZE        (0x40)
+%define VMMDEV_TESTING_MMIO_NOP             (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP)
+%define VMMDEV_TESTING_MMIO_NOP_R3          (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP_R3)
+%define VMMDEV_TESTING_MMIO_READBACK        (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK)
+%define VMMDEV_TESTING_MMIO_READBACK_R3     (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK_R3)
 %define VMMDEV_TESTING_MMIO_RM_SEL       0xffff
 %define VMMDEV_TESTING_MMIO_RM_OFF(val)  ((val) - 0xffff0)
+%define VMMDEV_TESTING_MMIO_RM_OFF2(off) ((off) + 16 + 0x1000)
 %define VMMDEV_TESTING_IOPORT_BASE      0x0510
 %define VMMDEV_TESTING_IOPORT_COUNT     0x0010
Index: /trunk/src/VBox/Devices/VMMDev/VMMDevState.h
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDevState.h	(revision 61383)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDevState.h	(revision 61384)
@@ -24,4 +24,5 @@
 #ifndef VBOX_WITHOUT_TESTING_FEATURES
 # include <iprt/test.h>
+# include <VBox/VMMDevTesting.h>
 #endif
 
@@ -350,4 +351,8 @@
             char        szName[1024 - 8 - 4];
         } Value;
+
+        /** The read back register (VMMDEV_TESTING_MMIO_OFF_READBACK,
+         *  VMMDEV_TESTING_MMIO_OFF_READBACK_R3). */
+        uint8_t         abReadBack[VMMDEV_TESTING_READBACK_SIZE];
     } TestingData;
     /** The XML output file name (can be a named pipe, doesn't matter to us). */
Index: /trunk/src/VBox/Devices/VMMDev/VMMDevTesting.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDevTesting.cpp	(revision 61383)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDevTesting.cpp	(revision 61384)
@@ -55,10 +55,98 @@
     {
         case VMMDEV_TESTING_MMIO_NOP:
+        case VMMDEV_TESTING_MMIO_NOP_R3:
+#ifdef IN_RING3
+            return VINF_IOM_R3_MMIO_WRITE;
+#else
+            return VINF_SUCCESS;
+#endif
+
+        default:
+        {
+            /*
+             * Readback register (64 bytes wide).
+             */
+            uint32_t off = GCPhysAddr - VMMDEV_TESTING_MMIO_BASE;
+            if (   (   off      >= VMMDEV_TESTING_MMIO_OFF_READBACK
+                    && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK + VMMDEV_TESTING_READBACK_SIZE)
+#ifndef IN_RING3
+                || (   off      >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
+                    && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + VMMDEV_TESTING_READBACK_SIZE)
+#endif
+                    )
+            {
+                VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
+                off &= VMMDEV_TESTING_READBACK_SIZE - 1;
+                switch (cb)
+                {
+                    case 8: *(uint64_t *)&pThis->TestingData.abReadBack[off] = *(uint64_t const *)pv; break;
+                    case 4: *(uint32_t *)&pThis->TestingData.abReadBack[off] = *(uint32_t const *)pv; break;
+                    case 2: *(uint16_t *)&pThis->TestingData.abReadBack[off] = *(uint16_t const *)pv; break;
+                    case 1: *(uint8_t  *)&pThis->TestingData.abReadBack[off] = *(uint8_t  const *)pv; break;
+                    default: memcpy(&pThis->TestingData.abReadBack[off], pv, cb); break;
+                }
+                return VINF_SUCCESS;
+            }
+#ifndef IN_RING3
+            if (   off      >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
+                && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
+                return VINF_IOM_R3_MMIO_WRITE;
+#endif
+
+            break;
+        }
+
+        /*
+         * Odd NOP accesses.
+         */
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 1:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 2:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 3:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 4:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 5:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 6:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 7:
+#ifndef IN_RING3
+            return VINF_IOM_R3_MMIO_WRITE;
+#endif
+        case VMMDEV_TESTING_MMIO_NOP    + 1:
+        case VMMDEV_TESTING_MMIO_NOP    + 2:
+        case VMMDEV_TESTING_MMIO_NOP    + 3:
+        case VMMDEV_TESTING_MMIO_NOP    + 4:
+        case VMMDEV_TESTING_MMIO_NOP    + 5:
+        case VMMDEV_TESTING_MMIO_NOP    + 6:
+        case VMMDEV_TESTING_MMIO_NOP    + 7:
+            return VINF_SUCCESS;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNIOMMMIOREAD}
+ */
+PDMBOTHCBDECL(int) vmmdevTestingMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
+{
+    switch (GCPhysAddr)
+    {
+        case VMMDEV_TESTING_MMIO_NOP_R3:
+#ifndef IN_RING3
+            return VINF_IOM_R3_MMIO_READ;
+#endif
+            /* fall thru. */
+        case VMMDEV_TESTING_MMIO_NOP:
             switch (cb)
             {
                 case 8:
+                    *(uint64_t *)pv = VMMDEV_TESTING_NOP_RET | ((uint64_t)VMMDEV_TESTING_NOP_RET << 32);
+                    break;
                 case 4:
+                    *(uint32_t *)pv = VMMDEV_TESTING_NOP_RET;
+                    break;
                 case 2:
+                    *(uint16_t *)pv = (uint16_t)VMMDEV_TESTING_NOP_RET;
+                    break;
                 case 1:
+                    *(uint8_t *)pv  = (uint8_t)VMMDEV_TESTING_NOP_RET;
                     break;
                 default:
@@ -68,70 +156,76 @@
             return VINF_SUCCESS;
 
-        case VMMDEV_TESTING_MMIO_NOP_R3:
-            switch (cb)
-            {
-                case 8:
-                case 4:
-                case 2:
-                case 1:
-#ifndef IN_RING3
-                    return VINF_IOM_R3_MMIO_READ_WRITE;
-#else
-                    return VINF_SUCCESS;
-#endif
-                default:
-                    AssertFailed();
-                    return VERR_INTERNAL_ERROR_5;
-            }
 
         default:
-            break;
-    }
-    return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{FNIOMMMIOREAD}
- */
-PDMBOTHCBDECL(int) vmmdevTestingMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
-{
-    switch (GCPhysAddr)
-    {
-        case VMMDEV_TESTING_MMIO_NOP_R3:
-#ifndef IN_RING3
-            switch (cb)
-            {
-                case 8:
-                case 4:
-                case 2:
-                case 1:
-                    return VINF_IOM_R3_MMIO_READ;
-            }
-#endif
-            /* fall thru. */
-        case VMMDEV_TESTING_MMIO_NOP:
-            switch (cb)
-            {
-                case 8:
-                    *(uint64_t *)pv = VMMDEV_TESTING_NOP_RET | ((uint64_t)VMMDEV_TESTING_NOP_RET << 32);
-                    break;
-                case 4:
-                    *(uint32_t *)pv = VMMDEV_TESTING_NOP_RET;
-                    break;
-                case 2:
-                    *(uint16_t *)pv = (uint16_t)VMMDEV_TESTING_NOP_RET;
-                    break;
-                case 1:
-                    *(uint8_t *)pv  = (uint8_t)VMMDEV_TESTING_NOP_RET;
-                    break;
-                default:
-                    AssertFailed();
-                    return VERR_INTERNAL_ERROR_5;
-            }
+        {
+            /*
+             * Readback register (64 bytes wide).
+             */
+            uint32_t off = GCPhysAddr - VMMDEV_TESTING_MMIO_BASE;
+            if (   (   off      >= VMMDEV_TESTING_MMIO_OFF_READBACK
+                    && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK + 64)
+#ifndef IN_RING3
+                || (   off      >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
+                    && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
+#endif
+                    )
+            {
+                VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
+                off &= 0x3f;
+                switch (cb)
+                {
+                    case 8: *(uint64_t *)pv = *(uint64_t const *)&pThis->TestingData.abReadBack[off]; break;
+                    case 4: *(uint32_t *)pv = *(uint32_t const *)&pThis->TestingData.abReadBack[off]; break;
+                    case 2: *(uint16_t *)pv = *(uint16_t const *)&pThis->TestingData.abReadBack[off]; break;
+                    case 1: *(uint8_t  *)pv = *(uint8_t  const *)&pThis->TestingData.abReadBack[off]; break;
+                    default: memcpy(pv, &pThis->TestingData.abReadBack[off], cb); break;
+                }
+                return VINF_SUCCESS;
+            }
+#ifndef IN_RING3
+            if (   off      >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
+                && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
+                return VINF_IOM_R3_MMIO_READ;
+#endif
+            break;
+        }
+
+        /*
+         * Odd NOP accesses (for 16-bit code mainly).
+         */
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 1:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 2:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 3:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 4:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 5:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 6:
+        case VMMDEV_TESTING_MMIO_NOP_R3 + 7:
+#ifndef IN_RING3
+            return VINF_IOM_R3_MMIO_READ;
+#endif
+        case VMMDEV_TESTING_MMIO_NOP    + 1:
+        case VMMDEV_TESTING_MMIO_NOP    + 2:
+        case VMMDEV_TESTING_MMIO_NOP    + 3:
+        case VMMDEV_TESTING_MMIO_NOP    + 4:
+        case VMMDEV_TESTING_MMIO_NOP    + 5:
+        case VMMDEV_TESTING_MMIO_NOP    + 6:
+        case VMMDEV_TESTING_MMIO_NOP    + 7:
+        {
+            static uint8_t const s_abNopValue[8] =
+            {
+                 VMMDEV_TESTING_NOP_RET        & 0xff,
+                (VMMDEV_TESTING_NOP_RET >>  8) & 0xff,
+                (VMMDEV_TESTING_NOP_RET >> 16) & 0xff,
+                (VMMDEV_TESTING_NOP_RET >> 24) & 0xff,
+                VMMDEV_TESTING_NOP_RET        & 0xff,
+                (VMMDEV_TESTING_NOP_RET >>  8) & 0xff,
+                (VMMDEV_TESTING_NOP_RET >> 16) & 0xff,
+                (VMMDEV_TESTING_NOP_RET >> 24) & 0xff,
+            };
+
+            memset(pv, 0xff, cb);
+            memcpy(pv, &s_abNopValue[GCPhysAddr & 7], RT_MIN(8 - (GCPhysAddr & 7), cb));
             return VINF_SUCCESS;
-
-        default:
-            break;
+        }
     }
 
