Index: trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32	(revision 64758)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32	(revision 64776)
@@ -30,4 +30,16 @@
 *********************************************************************************************************************************/
 #include <bs3kit.h>
+#include <iprt/asm-amd64-x86.h>
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+#define CHECK_MEMBER(a_pszMode, a_szName, a_szFmt, a_Actual, a_Expected) \
+    do { \
+        if ((a_Actual) == (a_Expected)) { /* likely */ } \
+        else Bs3TestFailedF("%u - %s: " a_szName "=" a_szFmt " expected " a_szFmt, \
+                            g_usBs3TestStep, (a_pszMode), (a_Actual), (a_Expected)); \
+    } while (0)
 
 
@@ -43,9 +55,9 @@
     uint8_t                     cbTmpl;
 } FNBS3CPUBASIC2PFTSTCODE;
+typedef FNBS3CPUBASIC2PFTSTCODE const *PCFNBS3CPUBASIC2PFTSTCODE;
 
 typedef struct BS3CPUBASIC2PFTTSTCMNMODE
 {
     uint8_t                 bMode;
-    FNBS3CPUBASIC2PFTSTCODE ExecTmpl;
     FNBS3CPUBASIC2PFTSTCODE MovLoad;
     FNBS3CPUBASIC2PFTSTCODE MovStore;
@@ -60,4 +72,6 @@
     /** The mode we're currently testing. */
     uint8_t                     bMode;
+    /** The size of a natural access. */
+    uint8_t                     cbAccess;
     /** The common mode functions. */
     PCBS3CPUBASIC2PFTTSTCMNMODE pCmnMode;
@@ -80,4 +94,6 @@
     /** Trap context frame. */
     BS3TRAPFRAME                TrapCtx;
+    /** Expected result context. */
+    BS3REGCTX                   ExpectCtx;
 
 } BS3CPUBASIC2PFSTATE;
@@ -98,5 +114,4 @@
 
 /* bs3-cpu-basic-2-template.mac: */
-FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_RaisePF_ExecTmpl_c16;
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c16;
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c16;
@@ -104,5 +119,4 @@
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16;
 
-FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_RaisePF_ExecTmpl_c32;
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c32;
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c32;
@@ -110,5 +124,4 @@
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32;
 
-FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_RaisePF_ExecTmpl_c64;
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c64;
 FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c64;
@@ -137,5 +150,4 @@
     {
         BS3_MODE_CODE_16,
-        {   bs3CpuBasic2_RaisePF_ExecTmpl_c16,      0, 3 },
         {   bs3CpuBasic2_mov_ax_ds_bx__ud2_c16,     2 },
         {   bs3CpuBasic2_mov_ds_bx_ax__ud2_c16,     2 },
@@ -145,5 +157,4 @@
     {
         BS3_MODE_CODE_32,
-        {   bs3CpuBasic2_RaisePF_ExecTmpl_c32,      0, 3  },
         {   bs3CpuBasic2_mov_ax_ds_bx__ud2_c32,     2 },
         {   bs3CpuBasic2_mov_ds_bx_ax__ud2_c32,     2 },
@@ -153,5 +164,4 @@
     {
         BS3_MODE_CODE_64,
-        {   bs3CpuBasic2_RaisePF_ExecTmpl_c64,      0, 3  },
         {   bs3CpuBasic2_mov_ax_ds_bx__ud2_c64,     2 + 1 },
         {   bs3CpuBasic2_mov_ds_bx_ax__ud2_c64,     2 + 1 },
@@ -161,5 +171,4 @@
     {
         BS3_MODE_CODE_V86,
-        {   bs3CpuBasic2_RaisePF_ExecTmpl_c16,      0, 3  },
         {   bs3CpuBasic2_mov_ax_ds_bx__ud2_c16,     2 },
         {   bs3CpuBasic2_mov_ds_bx_ax__ud2_c16,     2 },
@@ -170,11 +179,95 @@
 
 
-static void bs3CpuBasic2Pf_DoExecSubTest(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t uXcpt, uint8_t uPfErrCd,
-                                         unsigned iRing)
+/**
+ * Compares a CPU trap.
+ */
+static void bs3CpuBasic2Pf_CompareCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pExpectCtx, int cbPcAdjust,
+                                      uint8_t bXcpt, unsigned uErrCd)
+{
+    const char     *pszHint = "xxxx";
+    uint16_t const  cErrorsBefore = Bs3TestSubErrorCount();
+    uint32_t        fExtraEfl;
+
+    CHECK_MEMBER(pszHint, "bXcpt",   "%#04x",    pThis->TrapCtx.bXcpt,             bXcpt);
+    CHECK_MEMBER(pszHint, "uErrCd",  "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
+
+    fExtraEfl = X86_EFL_RF;
+    if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode))
+        fExtraEfl = 0;
+    else
+        fExtraEfl = X86_EFL_RF;
+    Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pExpectCtx, cbPcAdjust, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep);
+    if (Bs3TestSubErrorCount() != cErrorsBefore)
+    {
+        Bs3TrapPrintFrame(&pThis->TrapCtx);
+#if 1
+        Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
+        Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
+        ASMHalt();
+#endif
+    }
+}
+
+
+/**
+ * Compares a CPU trap.
+ */
+static void bs3CpuBasic2Pf_CompareSimpleCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pStartCtx, int offAddPC,
+                                            uint8_t bXcpt, unsigned uErrCd, uint64_t uCr2)
+{
+    const char     *pszHint = "xxxx";
+    uint16_t const  cErrorsBefore = Bs3TestSubErrorCount();
+    uint64_t const  uSavedCr2 = pStartCtx->cr2.u;
+    uint32_t        fExtraEfl;
+
+    CHECK_MEMBER(pszHint, "bXcpt",   "%#04x",    pThis->TrapCtx.bXcpt,             bXcpt);
+    CHECK_MEMBER(pszHint, "uErrCd",  "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
+
+    fExtraEfl = X86_EFL_RF;
+    if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode))
+        fExtraEfl = 0;
+    else
+        fExtraEfl = X86_EFL_RF;
+    pStartCtx->cr2.u = uCr2;
+    Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pStartCtx, offAddPC, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep);
+    pStartCtx->cr2.u = uSavedCr2;
+    if (Bs3TestSubErrorCount() != cErrorsBefore)
+    {
+        Bs3TrapPrintFrame(&pThis->TrapCtx);
+#if 1
+        Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
+        Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
+        ASMHalt();
+#endif
+    }
+}
+
+
+/**
+ * Checks the trap context for a simple \#PF trap.
+ */
+static void bs3CpuBasic2Pf_CompareSimplePf(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC,
+                                           unsigned uErrCd, uint64_t uCr2)
+{
+    bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_PF, uErrCd, uCr2);
+}
+
+/**
+ * Checks the trap context for a simple \#UD trap.
+ */
+static void bs3CpuBasic2Pf_CompareSimpleUd(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC)
+{
+    bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_UD, 0, pStartCtx->cr2.u);
+}
+
+
+static void bs3CpuBasic2Pf_DoExec(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd, bool fPageLevel)
 {
     uint8_t *pbOrgTest = pThis->pbOrgTest;
     unsigned off;
-    for (off = X86_PAGE_SIZE - 2; off < X86_PAGE_SIZE + 2; off++)
-    {
+
+    for (off = X86_PAGE_SIZE - 4; off < X86_PAGE_SIZE + 2; off++)
+    {
+        /* Emit a little bit of code (using the original allocation mapping) and point pCtx to it. */
         pbOrgTest[off + 0] = X86_OP_PRF_SIZE_ADDR;
         pbOrgTest[off + 1] = X86_OP_PRF_SIZE_OP;
@@ -190,7 +283,7 @@
                 break;
             case BS3_MODE_CODE_16:
-                Bs3SelSetup16BitCode(&Bs3GdteSpare01, (uintptr_t)pThis->pbTest, iRing);
+                Bs3SelSetup16BitCode(&Bs3GdteSpare01, (uintptr_t)pThis->pbTest, pCtx->bCpl);
                 pCtx->rip.u = off;
-                pCtx->cs    = BS3_SEL_SPARE_01;
+                pCtx->cs    = BS3_SEL_SPARE_01 | pCtx->bCpl;
                 break;
             case BS3_MODE_CODE_V86:
@@ -198,9 +291,439 @@
                 return;
         }
+        //Bs3TestPrintf("cs:rip=%04x:%010RX64 iRing=%d\n", pCtx->cs, pCtx->rip.u, pCtx->bCpl);
 
         Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
-        //bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
-
-    }
+        //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
+        if (bXcpt == X86_XCPT_PF)
+        {
+            unsigned offAddPC = !fPageLevel || off >= X86_PAGE_SIZE ? 0 : X86_PAGE_SIZE - off;
+            bs3CpuBasic2Pf_CompareSimplePf(pThis, pCtx, offAddPC, uPfErrCd, (uintptr_t)pThis->pbTest + offAddPC);
+        }
+        else
+            bs3CpuBasic2Pf_CompareSimpleUd(pThis, pCtx, 3);
+
+    }
+}
+
+
+static void bs3CpuBasic2Pf_SetCsEip(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, PCFNBS3CPUBASIC2PFTSTCODE pCode)
+{
+    switch (pThis->bMode & BS3_MODE_CODE_MASK)
+    {
+        default:
+            pCtx->rip.u = (uintptr_t)pCode->pfn;
+            break;
+
+        case BS3_MODE_CODE_16:
+        {
+            uint32_t uFar16 = Bs3SelFlatCodeToProtFar16((uintptr_t)pCode->pfn);
+            pCtx->rip.u = (uint16_t)uFar16;
+            pCtx->cs    = (uint16_t)(uFar16 >> 16) | pCtx->bCpl;
+            pCtx->cs   += (uint16_t)pCtx->bCpl << BS3_SEL_RING_SHIFT;
+            break;
+        }
+
+        case BS3_MODE_CODE_V86:
+        {
+            uint32_t uFar16 = Bs3SelFlatCodeToRealMode((uintptr_t)pCode->pfn);
+            pCtx->rip.u = (uint16_t)uFar16;
+            pCtx->cs    = (uint16_t)(uFar16 >> 16);
+            break;
+        }
+    }
+}
+
+
+/**
+ * Test a simple load instruction around the edges of page two.
+ *
+ * @param   pThis           The test stat data.
+ * @param   pCtx            The test context.
+ * @param   bXcpt           X86_XCPT_PF if this can cause \#PFs, otherwise
+ *                          X86_XCPT_UD.
+ * @param   uPfErrCd        The error code for \#PFs.
+ * @param   fPageLevel      Set if we're pushing PTE level bits.
+ */
+static void bs3CpuBasic2Pf_DoMovLoad(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd,
+                                     bool fPageLevel)
+{
+    static uint64_t const s_uValue = UINT64_C(0x7c4d0114428d);
+    uint64_t uExpectRax;
+    unsigned i;
+
+    /*
+     * Adjust the incoming context and calculate our expections.
+     */
+    bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovLoad);
+    Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
+    switch (pThis->bMode & BS3_MODE_CODE_MASK)
+    {
+        case BS3_MODE_CODE_16:
+        case BS3_MODE_CODE_V86:
+            uExpectRax = (uint16_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffffffff0000));
+            break;
+        case BS3_MODE_CODE_32:
+            uExpectRax = (uint32_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffff00000000));
+            break;
+        case BS3_MODE_CODE_64:
+            uExpectRax = s_uValue;
+            break;
+    }
+    if (uExpectRax == pCtx->rax.u)
+        pCtx->rax.u = ~pCtx->rax.u;
+
+    /*
+     * Make two approaches to the test page (the 2nd one):
+     *  - i=0: Start on the 1st page and edge into the 2nd.
+     *  - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        unsigned off    = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
+        unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
+        for (; off < offEnd; off++)
+        {
+            *(uint64_t *)&pThis->pbOrgTest[off] = s_uValue;
+            if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
+            else
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
+
+            Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
+            //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
+
+            if (   bXcpt != X86_XCPT_PF
+                || (fPageLevel && off >= X86_PAGE_SIZE * 2)
+                || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
+            {
+                pThis->ExpectCtx.rax.u = uExpectRax;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovLoad.offUd2, bXcpt, 0 /*uErrCd*/);
+                pThis->ExpectCtx.rax = pCtx->rax;
+            }
+            else
+            {
+                if (off < X86_PAGE_SIZE)
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
+                else
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
+                pThis->ExpectCtx.cr2 = pCtx->cr2;
+            }
+        }
+    }
+}
+
+
+/**
+ * Test a simple store instruction around the edges of page two.
+ *
+ * @param   pThis           The test stat data.
+ * @param   pCtx            The test context.
+ * @param   bXcpt           X86_XCPT_PF if this can cause \#PFs, otherwise
+ *                          X86_XCPT_UD.
+ * @param   uPfErrCd        The error code for \#PFs.
+ * @param   fPageLevel      Set if we're pushing PTE level bits.
+ */
+static void bs3CpuBasic2Pf_DoMovStore(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd,
+                                      bool fPageLevel)
+{
+    static uint64_t const s_uValue        = UINT64_C(0x3af45ead86a34a26);
+    static uint64_t const s_uValueFlipped = UINT64_C(0xc50ba152795cb5d9);
+    uint64_t const uRaxSaved = pCtx->rax.u;
+    uint64_t uExpectStored;
+    unsigned i;
+
+    /*
+     * Adjust the incoming context and calculate our expections.
+     */
+    bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovStore);
+    if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
+        pCtx->rax.u = (uint32_t)s_uValue; /* leave the upper part zero */
+    else
+        pCtx->rax.u = s_uValue;
+
+    Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
+    switch (pThis->bMode & BS3_MODE_CODE_MASK)
+    {
+        case BS3_MODE_CODE_16:
+        case BS3_MODE_CODE_V86:
+            uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
+            break;
+        case BS3_MODE_CODE_32:
+            uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
+            break;
+        case BS3_MODE_CODE_64:
+            uExpectStored = s_uValue;
+            break;
+    }
+
+    /*
+     * Make two approaches to the test page (the 2nd one):
+     *  - i=0: Start on the 1st page and edge into the 2nd.
+     *  - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        unsigned off    = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
+        unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
+        for (; off < offEnd; off++)
+        {
+            *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
+            if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
+            else
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
+
+            Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
+            //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
+
+            if (   bXcpt != X86_XCPT_PF
+                || (fPageLevel && off >= X86_PAGE_SIZE * 2)
+                || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
+            {
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovStore.offUd2, bXcpt, 0 /*uErrCd*/);
+                if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
+                    Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
+                                   g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
+            }
+            else
+            {
+                if (off < X86_PAGE_SIZE)
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
+                else
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
+                pThis->ExpectCtx.cr2 = pCtx->cr2;
+                if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
+                    Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
+                                   g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
+
+            }
+        }
+    }
+
+    pCtx->rax.u = uRaxSaved;
+}
+
+
+/**
+ * Test a xchg instruction around the edges of page two.
+ *
+ * @param   pThis           The test stat data.
+ * @param   pCtx            The test context.
+ * @param   bXcpt           X86_XCPT_PF if this can cause \#PFs, otherwise
+ *                          X86_XCPT_UD.
+ * @param   uPfErrCd        The error code for \#PFs.
+ * @param   fPageLevel      Set if we're pushing PTE level bits.
+ */
+static void bs3CpuBasic2Pf_DoXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd, bool fPageLevel)
+{
+    static uint64_t const s_uValue        = UINT64_C(0xea58699648e2f32c);
+    static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3);
+    uint64_t const uRaxSaved = pCtx->rax.u;
+    uint64_t uRaxIn;
+    uint64_t uExpectedRax;
+    uint64_t uExpectStored;
+    unsigned i;
+
+    /*
+     * Adjust the incoming context and calculate our expections.
+     */
+    bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->Xchg);
+    if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
+        uRaxIn = (uint32_t)s_uValue; /* leave the upper part zero */
+    else
+        uRaxIn = s_uValue;
+
+    Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
+    switch (pThis->bMode & BS3_MODE_CODE_MASK)
+    {
+        case BS3_MODE_CODE_16:
+        case BS3_MODE_CODE_V86:
+            uExpectedRax  = (uint16_t)s_uValueFlipped | (uRaxIn          & UINT64_C(0xffffffffffff0000));
+            uExpectStored = (uint16_t)s_uValue        | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
+            break;
+        case BS3_MODE_CODE_32:
+            uExpectedRax  = (uint32_t)s_uValueFlipped | (uRaxIn          & UINT64_C(0xffffffff00000000));
+            uExpectStored = (uint32_t)s_uValue        | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
+            break;
+        case BS3_MODE_CODE_64:
+            uExpectedRax  = s_uValueFlipped;
+            uExpectStored = s_uValue;
+            break;
+    }
+
+    /*
+     * Make two approaches to the test page (the 2nd one):
+     *  - i=0: Start on the 1st page and edge into the 2nd.
+     *  - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        unsigned off    = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
+        unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
+        for (; off < offEnd; off++)
+        {
+            *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
+            pCtx->rax.u = uRaxIn;
+            if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
+            else
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
+
+            Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
+            //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
+
+            if (   bXcpt != X86_XCPT_PF
+                || (fPageLevel && off >= X86_PAGE_SIZE * 2)
+                || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
+            {
+                pThis->ExpectCtx.rax.u = uExpectedRax;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->Xchg.offUd2, bXcpt, 0 /*uErrCd*/);
+                if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
+                    Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
+                                   g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
+            }
+            else
+            {
+                pThis->ExpectCtx.rax.u = uRaxIn;
+                if (off < X86_PAGE_SIZE)
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
+                else
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
+                pThis->ExpectCtx.cr2 = pCtx->cr2;
+                if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
+                    Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
+                                   g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
+            }
+        }
+    }
+
+    pCtx->rax.u = uRaxSaved;
+}
+
+
+/**
+ * Test a cmpxchg instruction around the edges of page two.
+ *
+ * @param   pThis           The test stat data.
+ * @param   pCtx            The test context.
+ * @param   bXcpt           X86_XCPT_PF if this can cause \#PFs, otherwise
+ *                          X86_XCPT_UD.
+ * @param   uPfErrCd        The error code for \#PFs.
+ * @param   fPageLevel      Set if we're pushing PTE level bits.
+ * @param   fMissmatch      Whether to fail and not store (@c true), or succeed
+ *                          and do the store.
+ */
+static void bs3CpuBasic2Pf_DoCmpXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd,
+                                     bool fPageLevel, bool fMissmatch)
+{
+    static uint64_t const s_uValue        = UINT64_C(0xea58699648e2f32c);
+    static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3);
+    static uint64_t const s_uValueOther   = UINT64_C(0x2171239bcb044c81);
+    uint64_t const uRaxSaved = pCtx->rax.u;
+    uint64_t const uRcxSaved = pCtx->rcx.u;
+    uint64_t uRaxIn;
+    uint64_t uExpectedRax;
+    uint32_t uExpectedFlags;
+    uint64_t uExpectStored;
+    unsigned i;
+
+    /*
+     * Adjust the incoming context and calculate our expections.
+     * Hint: CMPXCHG  [xBX],xCX     ; xAX compare and update implicit, ZF set to !fMissmatch.
+     */
+    bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->CmpXchg);
+    if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
+    {
+        uRaxIn      = (uint32_t)(fMissmatch ? s_uValueOther : s_uValueFlipped); /* leave the upper part zero */
+        pCtx->rcx.u = (uint32_t)s_uValue;                                        /* ditto */
+    }
+    else
+    {
+        uRaxIn      = fMissmatch ? s_uValueOther : s_uValueFlipped;
+        pCtx->rcx.u = s_uValue;
+    }
+    if (fMissmatch)
+        pCtx->rflags.u32 |= X86_EFL_ZF;
+    else
+        pCtx->rflags.u32 &= ~X86_EFL_ZF;
+
+    Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
+    uExpectedFlags = pCtx->rflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF | X86_EFL_ZF);
+    switch (pThis->bMode & BS3_MODE_CODE_MASK)
+    {
+        case BS3_MODE_CODE_16:
+        case BS3_MODE_CODE_V86:
+            uExpectedRax  = (uint16_t)s_uValueFlipped | (uRaxIn          & UINT64_C(0xffffffffffff0000));
+            uExpectStored = (uint16_t)s_uValue        | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
+            uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
+            break;
+        case BS3_MODE_CODE_32:
+            uExpectedRax  = (uint32_t)s_uValueFlipped | (uRaxIn          & UINT64_C(0xffffffff00000000));
+            uExpectStored = (uint32_t)s_uValue        | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
+            uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
+            break;
+        case BS3_MODE_CODE_64:
+            uExpectedRax  = s_uValueFlipped;
+            uExpectStored = s_uValue;
+            uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
+            break;
+    }
+    if (fMissmatch)
+        uExpectStored = s_uValueFlipped;
+
+    /*
+     * Make two approaches to the test page (the 2nd one):
+     *  - i=0: Start on the 1st page and edge into the 2nd.
+     *  - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        unsigned off    = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
+        unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
+        for (; off < offEnd; off++)
+        {
+            *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
+            pCtx->rax.u = uRaxIn;
+            if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
+            else
+                pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
+
+            Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
+            //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
+
+            if (   bXcpt != X86_XCPT_PF
+                || (fPageLevel && off >= X86_PAGE_SIZE * 2)
+                || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
+            {
+                pThis->ExpectCtx.rax.u = uExpectedRax;
+                pThis->ExpectCtx.rflags.u32 = uExpectedFlags;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->CmpXchg.offUd2, bXcpt, 0 /*uErrCd*/);
+                if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
+                    Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
+                                   g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
+            }
+            else
+            {
+                pThis->ExpectCtx.rax.u = uRaxIn;
+                pThis->ExpectCtx.rflags = pCtx->rflags;
+                if (off < X86_PAGE_SIZE)
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
+                else
+                    pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
+                bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
+                pThis->ExpectCtx.cr2 = pCtx->cr2;
+                if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
+                    Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
+                                   g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
+            }
+        }
+    }
+
+    pCtx->rax.u = uRaxSaved;
+    pCtx->rcx.u = uRcxSaved;
 }
 
@@ -219,4 +742,9 @@
     BS3REGCTX           aCtxts[4];
 
+    /** @todo figure out V8086 testing. */
+    if ((pThis->bMode & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86)
+        return BS3TESTDOMODE_SKIPPED;
+
+
     /* paranoia: Touch the various big stack structures to ensure the compiler has allocated stack for them. */
     for (iRing = 0; iRing < RT_ELEMENTS(aCtxts); iRing++)
@@ -247,15 +775,24 @@
     }
 
-
-    /*
-     * Check basic operation.
+    /*
+     * Check basic operation:
      */
     for (iRing = 0; iRing < 4; iRing++)
     {
-        /* we can execute the test page. */
-        bs3CpuBasic2Pf_DoExecSubTest(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, iRing);
-    }
-
-
+        /* 1. we can execute the test page. */
+        bs3CpuBasic2Pf_DoExec(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
+        /* 2. we can read from the test page. */
+        bs3CpuBasic2Pf_DoMovLoad(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
+        /* 3. we can write to the test page. */
+        bs3CpuBasic2Pf_DoMovStore(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
+        /* 4. we can do locked read+write (a few variants). */
+        bs3CpuBasic2Pf_DoXchg(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
+        bs3CpuBasic2Pf_DoCmpXchg(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/, false /*fMissmatch*/);
+        bs3CpuBasic2Pf_DoCmpXchg(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/, true  /*fMissmatch*/);
+    }
+
+    /*
+     * Check the U bit on PTE level.
+     */
 
 
@@ -277,4 +814,11 @@
     Bs3MemZero(&State, sizeof(State));
     State.bMode = bMode;
+    switch (bMode & BS3_MODE_CODE_MASK)
+    {
+        case BS3_MODE_CODE_16:  State.cbAccess = sizeof(uint16_t); break;
+        case BS3_MODE_CODE_V86: State.cbAccess = sizeof(uint16_t); break;
+        case BS3_MODE_CODE_32:  State.cbAccess = sizeof(uint32_t); break;
+        case BS3_MODE_CODE_64:  State.cbAccess = sizeof(uint64_t); break;
+    }
     State.pCmnMode = &g_aCmnModes[0];
     while (State.pCmnMode->bMode != (bMode & BS3_MODE_CODE_MASK))
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac	(revision 64758)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac	(revision 64776)
@@ -321,11 +321,4 @@
 ;
 
-; For testing exec access.
-BS3_PROC_BEGIN_CMN bs3CpuBasic2_RaisePF_ExecTmpl, BS3_PBC_NEAR
-.again: ud2
-        jmp     .again
-BS3_PROC_END_CMN   bs3CpuBasic2_RaisePF_ExecTmpl
-
-
 ; For testing read access.
 BS3_PROC_BEGIN_CMN bs3CpuBasic2_mov_ax_ds_bx__ud2, BS3_PBC_NEAR
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c	(revision 64758)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c	(revision 64776)
@@ -77,6 +77,8 @@
      */
     NOREF(g_aModeTest); NOREF(g_aModeByOneTests); /* for when commenting out bits */
+#if 0
     Bs3TestDoModes_rm(g_aModeTest, RT_ELEMENTS(g_aModeTest));
     Bs3TestDoModesByOne_rm(g_aModeByOneTests, RT_ELEMENTS(g_aModeByOneTests), 0);
+#endif
 
     /*
@@ -86,5 +88,5 @@
 
     Bs3TestTerm();
-for (;;) { ASMHalt(); }
+//for (;;) { ASMHalt(); }
 }
 
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c	(revision 64758)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c	(revision 64776)
@@ -70,7 +70,7 @@
                 if (!pPgInfo->u.Pae.pPml4e->n.u1Present)
                     rc = VERR_PAGE_NOT_PRESENT;
-                else if (pPgInfo->u.Pae.pPml4e->u <= uMaxAddr)
+                else if ((pPgInfo->u.Pae.pPml4e->u & X86_PML4E_PG_MASK) <= uMaxAddr)
                 {
-                    pPgInfo->u.Pae.pPdpe  = (X86PDPE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPml4e->u & X86_PAGE_BASE_MASK);
+                    pPgInfo->u.Pae.pPdpe  = (X86PDPE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPml4e->u & X86_PML4E_PG_MASK);
                     pPgInfo->u.Pae.pPdpe += (uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
                     if (!pPgInfo->u.Pae.pPdpe->n.u1Present)
@@ -96,8 +96,8 @@
             /* Common code for the PD and PT levels. */
             if (   rc == VINF_TRY_AGAIN
-                && pPgInfo->u.Pae.pPdpe->u <= uMaxAddr)
+                && (pPgInfo->u.Pae.pPdpe->u & X86_PDPE_PG_MASK) <= uMaxAddr)
             {
                 rc = VERR_OUT_OF_RANGE;
-                pPgInfo->u.Pae.pPde  = (X86PDEPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPdpe->u & X86_PAGE_BASE_MASK);
+                pPgInfo->u.Pae.pPde  = (X86PDEPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPdpe->u & X86_PDPE_PG_MASK);
                 pPgInfo->u.Pae.pPde += (uFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
                 if (!pPgInfo->u.Pae.pPde->n.u1Present)
@@ -105,8 +105,8 @@
                 else if (pPgInfo->u.Pae.pPde->b.u1Size)
                     rc = VINF_SUCCESS;
-                else if (pPgInfo->u.Pae.pPde->u <= uMaxAddr)
+                else if ((pPgInfo->u.Pae.pPde->u & X86_PDE_PAE_PG_MASK) <= uMaxAddr)
                 {
-                    pPgInfo->u.Pae.pPte  = (X86PTEPAE BS3_FAR *)Bs3XptrFlatToCurrent(  pPgInfo->u.Pae.pPde->u
-                                                                                     & X86_PAGE_BASE_MASK);
+                    pPgInfo->u.Pae.pPte = (X86PTEPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPde->u & X86_PDE_PAE_PG_MASK);
+                    rc = VINF_SUCCESS;
                 }
             }
@@ -136,6 +136,5 @@
             else if (pPgInfo->u.Legacy.pPde->u <= uMaxAddr)
             {
-                pPgInfo->u.Legacy.pPte  = (X86PTE BS3_FAR *)Bs3XptrFlatToCurrent(  pPgInfo->u.Legacy.pPde->u
-                                                                                 & X86_PAGE_BASE_MASK_32);
+                pPgInfo->u.Legacy.pPte  = (X86PTE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Legacy.pPde->u & X86_PDE_PG_MASK);
                 pPgInfo->u.Legacy.pPte += ((uint32_t)uFlat >> X86_PT_SHIFT) & X86_PT_MASK;
                 if (pPgInfo->u.Legacy.pPte->n.u1Present)
