VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32@ 65444

Last change on this file since 65444 was 65408, checked in by vboxsync, 8 years ago

bs3-cpu-basic-2: more

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.7 KB
Line 
1/* $Id: bs3-cpu-basic-2-pf.c32 65408 2017-01-23 16:03:35Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-basic-2, 32-bit C code.
4 */
5
6/*
7 * Copyright (C) 2007-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <bs3kit.h>
32#include <iprt/asm-amd64-x86.h>
33
34
35/*********************************************************************************************************************************
36* Defined Constants And Macros *
37*********************************************************************************************************************************/
38#define CHECK_MEMBER(a_pszMode, a_szName, a_szFmt, a_Actual, a_Expected) \
39 do { \
40 if ((a_Actual) == (a_Expected)) { /* likely */ } \
41 else Bs3TestFailedF("%u - %s: " a_szName "=" a_szFmt " expected " a_szFmt, \
42 g_usBs3TestStep, (a_pszMode), (a_Actual), (a_Expected)); \
43 } while (0)
44
45#define BS3CPUBASIC2PF_HALT(pThis) \
46 do { \
47 Bs3TestPrintf("Halting: pteworker=%s store=%s accessor=%s\n", \
48 pThis->pszPteWorker, pThis->pszStore, pThis->pszAccessor); \
49 ASMHalt(); \
50 } while (0)
51
52
53/** @def BS3CPUBASIC2PF_FASTER
54 * This is useful for IEM execution. */
55#define BS3CPUBASIC2PF_FASTER
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61typedef void BS3_CALL FNBS3CPUBASIC2PFSNIPPET(void);
62
63typedef struct FNBS3CPUBASIC2PFTSTCODE
64{
65 FNBS3CPUBASIC2PFSNIPPET *pfn;
66 uint8_t offUd2;
67
68} FNBS3CPUBASIC2PFTSTCODE;
69typedef FNBS3CPUBASIC2PFTSTCODE const *PCFNBS3CPUBASIC2PFTSTCODE;
70
71typedef struct BS3CPUBASIC2PFTTSTCMNMODE
72{
73 uint8_t bMode;
74 FNBS3CPUBASIC2PFTSTCODE MovLoad;
75 FNBS3CPUBASIC2PFTSTCODE MovStore;
76 FNBS3CPUBASIC2PFTSTCODE Xchg;
77 FNBS3CPUBASIC2PFTSTCODE CmpXchg;
78 FNBS3CPUBASIC2PFTSTCODE DivMem;
79} BS3CPUBASIC2PFTTSTCMNMODE;
80typedef BS3CPUBASIC2PFTTSTCMNMODE const *PCBS3CPUBASIC2PFTTSTCMNMODE;
81
82
83typedef struct BS3CPUBASIC2PFSTATE
84{
85 /** The mode we're currently testing. */
86 uint8_t bMode;
87 /** The size of a natural access. */
88 uint8_t cbAccess;
89 /** The common mode functions. */
90 PCBS3CPUBASIC2PFTTSTCMNMODE pCmnMode;
91 /** Pointer to the test area (alias). */
92 uint8_t *pbTest;
93 /** Pointer to the orignal test area mapping. */
94 uint8_t *pbOrgTest;
95 /** The size of the test area (at least two pages). */
96 uint32_t cbTest;
97 /** cbTest expressed as a page count. */
98 uint16_t cTestPages;
99 /** The number of PTEs in the first PTE, i.e. what we can
100 * safely access via PgInfo.u.Pae.pPte/PgInfo.u.Legacy.pPte. */
101 uint16_t cTest1stPtes;
102 /** The number of PDEs for cTestPages. */
103 uint16_t cTestPdes;
104 /** 16-bit data selector for pbTest. */
105 uint16_t uSel16TestData;
106 /** 16-bit code selector for pbTest. */
107 uint16_t uSel16TestCode;
108 /** The size of the PDE backup. */
109 uint16_t cbPdeBackup;
110 /** The size of the PTE backup. */
111 uint16_t cbPteBackup;
112 /** Test paging information for pbTest. */
113 BS3PAGINGINFO4ADDR PgInfo;
114
115 /** Set if we can use the INVLPG instruction. */
116 bool fUseInvlPg;
117 /** Physical addressing width. */
118 uint8_t cBitsPhysWidth;
119
120 /** Reflects CR0.WP. */
121 bool fWp;
122 /** Reflects EFER.NXE & CR4.PAE. */
123 bool fNxe;
124
125 const char *pszAccessor;
126 const char *pszPteWorker;
127 const char *pszStore;
128
129 /** Trap context frame. */
130 BS3TRAPFRAME TrapCtx;
131 /** Expected result context. */
132 BS3REGCTX ExpectCtx;
133
134 /** The PML4E backup. */
135 uint64_t u64Pml4eBackup;
136 /** The PDPTE backup. */
137 uint64_t u64PdpteBackup;
138 /** The PDE backup. */
139 uint64_t au64PdeBackup[16];
140 /** The PTE backup. */
141 union
142 {
143 uint32_t Legacy[X86_PG_ENTRIES];
144 uint64_t Pae[X86_PG_PAE_ENTRIES];
145 } PteBackup;
146
147} BS3CPUBASIC2PFSTATE;
148/** Pointer to state for the \#PF test. */
149typedef BS3CPUBASIC2PFSTATE *PBS3CPUBASIC2PFSTATE;
150
151
152/**
153 * Paging modification worker.
154 */
155typedef struct BS3CPUBASIC2PFMODPT
156{
157 const char *pszName;
158 uint32_t fPresent : 1;
159 uint32_t fUser : 1;
160 uint32_t fWriteable : 1;
161 uint32_t fNoExecute : 1;
162 uint32_t fReserved : 1;
163 uint32_t uModifyArg : 24;
164 void (*pfnModify)(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, struct BS3CPUBASIC2PFMODPT const *pEntry,
165 uint32_t fClearMask, uint32_t fSetMask);
166 bool (*pfnApplicable)(PBS3CPUBASIC2PFSTATE pThis, struct BS3CPUBASIC2PFMODPT const *pEntry);
167} BS3CPUBASIC2PFMODPT;
168typedef BS3CPUBASIC2PFMODPT const *PCBS3CPUBASIC2PFMODPT;
169
170/** Page level protection. Alternative is page directory or higher level. */
171#define BS3CB2PFACC_F_PAGE_LEVEL RT_BIT(0)
172/** Directly access the boobytrapped page, no edging on or off it. */
173#define BS3CB2PFACC_F_DIRECT RT_BIT(1)
174
175/**
176 * Memory accessor.
177 */
178typedef struct BS3CPUBASIC2PFACCESSOR
179{
180 /** Accessor name. */
181 const char *pszName;
182 /** The accessor. */
183 void (*pfnAccessor)(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd);
184 /** The X86_TRAP_PF_XXX access flags this access sets. */
185 uint32_t fAccess;
186 /** The exception when things are fine. */
187 uint8_t bOkayXcpt;
188} BS3CPUBASIC2PFACCESSOR;
189typedef const BS3CPUBASIC2PFACCESSOR *PCBS3CPUBASIC2PFACCESSOR;
190
191
192/*********************************************************************************************************************************
193* Internal Functions *
194*********************************************************************************************************************************/
195FNBS3TESTDOMODE bs3CpuBasic2_RaiseXcpt0e_c32;
196
197/* bs3-cpu-basic-2-asm.asm: */
198void BS3_CALL bs3CpuBasic2_Store_mov_c32(void *pvDst, uint32_t uValue, uint32_t uOld);
199void BS3_CALL bs3CpuBasic2_Store_xchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld);
200void BS3_CALL bs3CpuBasic2_Store_cmpxchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld);
201
202
203/* bs3-cpu-basic-2-template.mac: */
204FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c16;
205FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c16;
206FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16;
207FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16;
208FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c16;
209
210FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c32;
211FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c32;
212FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32;
213FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32;
214FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c32;
215
216FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c64;
217FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c64;
218FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64;
219FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64;
220FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c64;
221
222
223/*********************************************************************************************************************************
224* Global Variables *
225*********************************************************************************************************************************/
226/** Page table access functions. */
227static const struct
228{
229 const char *pszName;
230 void (BS3_CALL *pfnStore)(void *pvDst, uint32_t uValue, uint32_t uOld);
231} g_aStoreMethods[] =
232{
233 { "mov", bs3CpuBasic2_Store_mov_c32 },
234 { "xchg", bs3CpuBasic2_Store_xchg_c32 },
235 { "cmpxchg", bs3CpuBasic2_Store_cmpxchg_c32 },
236};
237
238
239static const BS3CPUBASIC2PFTTSTCMNMODE g_aCmnModes[] =
240{
241 {
242 BS3_MODE_CODE_16,
243 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 },
244 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 },
245 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 },
246 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 },
247 { bs3CpuBasic2_div_ds_bx__ud2_c16, 2 },
248 },
249 {
250 BS3_MODE_CODE_32,
251 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c32, 2 },
252 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c32, 2 },
253 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32, 2 },
254 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32, 3 },
255 { bs3CpuBasic2_div_ds_bx__ud2_c32, 2 },
256 },
257 {
258 BS3_MODE_CODE_64,
259 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c64, 2 + 1 },
260 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c64, 2 + 1 },
261 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64, 2 + 1 },
262 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64, 3 + 1 },
263 { bs3CpuBasic2_div_ds_bx__ud2_c64, 2 + 1 },
264 },
265 {
266 BS3_MODE_CODE_V86,
267 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 },
268 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 },
269 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 },
270 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 },
271 { bs3CpuBasic2_div_ds_bx__ud2_c16, 2 },
272 },
273};
274
275
276/**
277 * Compares a CPU trap.
278 */
279static void bs3CpuBasic2Pf_CompareCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pExpectCtx, int cbPcAdjust,
280 uint8_t bXcpt, unsigned uErrCd)
281{
282 const char *pszHint = "xxxx";
283 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
284 uint32_t fExtraEfl;
285
286 CHECK_MEMBER(pszHint, "bXcpt", "%#04x", pThis->TrapCtx.bXcpt, bXcpt);
287 CHECK_MEMBER(pszHint, "uErrCd", "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
288
289 fExtraEfl = X86_EFL_RF;
290 if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode))
291 fExtraEfl = 0;
292 else
293 fExtraEfl = X86_EFL_RF;
294 Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pExpectCtx, cbPcAdjust, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep);
295 if (Bs3TestSubErrorCount() != cErrorsBefore)
296 {
297 Bs3TrapPrintFrame(&pThis->TrapCtx);
298#if 1
299 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
300 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
301 BS3CPUBASIC2PF_HALT(pThis);
302#endif
303 }
304}
305
306
307/**
308 * Compares a CPU trap.
309 */
310static void bs3CpuBasic2Pf_CompareSimpleCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pStartCtx, int offAddPC,
311 uint8_t bXcpt, unsigned uErrCd, uint64_t uCr2)
312{
313 const char *pszHint = "xxxx";
314 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
315 uint64_t const uSavedCr2 = pStartCtx->cr2.u;
316 uint32_t fExtraEfl;
317
318 CHECK_MEMBER(pszHint, "bXcpt", "%#04x", pThis->TrapCtx.bXcpt, bXcpt);
319 CHECK_MEMBER(pszHint, "uErrCd", "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
320
321 fExtraEfl = X86_EFL_RF;
322 if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode))
323 fExtraEfl = 0;
324 else
325 fExtraEfl = X86_EFL_RF;
326 pStartCtx->cr2.u = uCr2;
327 Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pStartCtx, offAddPC, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep);
328 pStartCtx->cr2.u = uSavedCr2;
329 if (Bs3TestSubErrorCount() != cErrorsBefore)
330 {
331 Bs3TrapPrintFrame(&pThis->TrapCtx);
332#if 1
333 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
334 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
335 BS3CPUBASIC2PF_HALT(pThis);
336#endif
337 }
338}
339
340
341/**
342 * Checks the trap context for a simple \#PF trap.
343 */
344static void bs3CpuBasic2Pf_CompareSimplePf(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC,
345 unsigned uErrCd, uint64_t uCr2)
346{
347 bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_PF, uErrCd, uCr2);
348}
349
350/**
351 * Checks the trap context for a simple \#UD trap.
352 */
353static void bs3CpuBasic2Pf_CompareSimpleUd(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC)
354{
355 bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_UD, 0, pStartCtx->cr2.u);
356}
357
358
359/**
360 * Restores all the paging entries from backup and flushes everything.
361 */
362static void bs3CpuBasic2Pf_FlushAll(void)
363{
364 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
365 {
366 uint32_t uCr4 = ASMGetCR4();
367 if (uCr4 & (X86_CR4_PGE | X86_CR4_PCIDE))
368 {
369 ASMSetCR4(uCr4 & ~(X86_CR4_PGE | X86_CR4_PCIDE));
370 ASMSetCR4(uCr4);
371 return;
372 }
373 }
374
375 ASMReloadCR3();
376}
377
378
379/**
380 * Restores all the paging entries from backup and flushes everything.
381 *
382 * @param pThis Test state data.
383 */
384static void bs3CpuBasic2Pf_RestoreFromBackups(PBS3CPUBASIC2PFSTATE pThis)
385{
386 Bs3MemCpy(pThis->PgInfo.u.Legacy.pPte, &pThis->PteBackup, pThis->cbPteBackup);
387 Bs3MemCpy(pThis->PgInfo.u.Legacy.pPde, pThis->au64PdeBackup, pThis->cbPdeBackup);
388 if (pThis->PgInfo.cEntries > 2)
389 pThis->PgInfo.u.Pae.pPdpe->u = pThis->u64PdpteBackup;
390 if (pThis->PgInfo.cEntries > 3)
391 pThis->PgInfo.u.Pae.pPml4e->u = pThis->u64Pml4eBackup;
392 bs3CpuBasic2Pf_FlushAll();
393}
394
395
396/** @name BS3CPUBASIC2PFACCESSOR::pfnAccessor Implementations
397 * @{ */
398
399static void bs3CpuBasic2Pf_DoExec(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd)
400{
401 uint8_t *pbOrgTest = pThis->pbOrgTest;
402 unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE + 1 : X86_PAGE_SIZE + 2;
403 unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? offEnd - 1 : X86_PAGE_SIZE - 5;
404
405 for (; off < offEnd; off++)
406 {
407 /* Emit a little bit of code (using the original allocation mapping) and point pCtx to it. */
408 pbOrgTest[off + 0] = X86_OP_PRF_SIZE_ADDR;
409 pbOrgTest[off + 1] = X86_OP_PRF_SIZE_OP;
410 pbOrgTest[off + 2] = 0x90; /* NOP */
411 pbOrgTest[off + 3] = 0x0f; /* UD2 */
412 pbOrgTest[off + 4] = 0x0b;
413 pbOrgTest[off + 5] = 0xeb; /* JMP $-4 */
414 pbOrgTest[off + 6] = 0xfc;
415 switch (pThis->bMode & BS3_MODE_CODE_MASK)
416 {
417 default:
418 pCtx->rip.u = (uintptr_t)&pThis->pbTest[off];
419 break;
420 case BS3_MODE_CODE_16:
421 Bs3SelSetup16BitCode(&Bs3GdteSpare01, (uintptr_t)pThis->pbTest, pCtx->bCpl);
422 pCtx->rip.u = off;
423 pCtx->cs = BS3_SEL_SPARE_01 | pCtx->bCpl;
424 break;
425 case BS3_MODE_CODE_V86:
426 /** @todo fix me. */
427 return;
428 }
429 //Bs3TestPrintf("cs:rip=%04x:%010RX64 iRing=%d\n", pCtx->cs, pCtx->rip.u, pCtx->bCpl);
430
431 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
432 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
433 if ( bXcpt != X86_XCPT_PF
434 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off < X86_PAGE_SIZE - 4))
435 bs3CpuBasic2Pf_CompareSimpleUd(pThis, pCtx, 3);
436 else if (!(fFlags & BS3CB2PFACC_F_PAGE_LEVEL) || off >= X86_PAGE_SIZE)
437 bs3CpuBasic2Pf_CompareSimplePf(pThis, pCtx, 0, uPfErrCd, (uintptr_t)pThis->pbTest + off);
438 else
439 bs3CpuBasic2Pf_CompareSimplePf(pThis, pCtx,
440 off + 3 == X86_PAGE_SIZE || off + 4 == X86_PAGE_SIZE
441 ? RT_MIN(X86_PAGE_SIZE, off + 3) - off : 0,
442 uPfErrCd, (uintptr_t)pThis->pbTest + RT_MIN(X86_PAGE_SIZE, off + 4));
443 }
444}
445
446
447static void bs3CpuBasic2Pf_SetCsEip(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, PCFNBS3CPUBASIC2PFTSTCODE pCode)
448{
449 switch (pThis->bMode & BS3_MODE_CODE_MASK)
450 {
451 default:
452 pCtx->rip.u = (uintptr_t)pCode->pfn;
453 break;
454
455 case BS3_MODE_CODE_16:
456 {
457 uint32_t uFar16 = Bs3SelFlatCodeToProtFar16((uintptr_t)pCode->pfn);
458 pCtx->rip.u = (uint16_t)uFar16;
459 pCtx->cs = (uint16_t)(uFar16 >> 16) | pCtx->bCpl;
460 pCtx->cs += (uint16_t)pCtx->bCpl << BS3_SEL_RING_SHIFT;
461 break;
462 }
463
464 case BS3_MODE_CODE_V86:
465 {
466 uint32_t uFar16 = Bs3SelFlatCodeToRealMode((uintptr_t)pCode->pfn);
467 pCtx->rip.u = (uint16_t)uFar16;
468 pCtx->cs = (uint16_t)(uFar16 >> 16);
469 break;
470 }
471 }
472}
473
474
475/**
476 * Test a simple load instruction around the edges of page two.
477 *
478 * @param pThis The test stat data.
479 * @param pCtx The test context.
480 * @param fFlags BS3CB2PFACC_F_XXX.
481 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
482 * X86_XCPT_UD.
483 * @param uPfErrCd The error code for \#PFs.
484 */
485static void bs3CpuBasic2Pf_DoMovLoad(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd)
486{
487 static uint64_t const s_uValue = UINT64_C(0x7c4d0114428d);
488 uint64_t uExpectRax;
489 unsigned i;
490
491 /*
492 * Adjust the incoming context and calculate our expections.
493 */
494 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovLoad);
495 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
496 switch (pThis->bMode & BS3_MODE_CODE_MASK)
497 {
498 case BS3_MODE_CODE_16:
499 case BS3_MODE_CODE_V86:
500 uExpectRax = (uint16_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffffffff0000));
501 break;
502 case BS3_MODE_CODE_32:
503 uExpectRax = (uint32_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffff00000000));
504 break;
505 case BS3_MODE_CODE_64:
506 uExpectRax = s_uValue;
507 break;
508 }
509 if (uExpectRax == pCtx->rax.u)
510 pCtx->rax.u = ~pCtx->rax.u;
511
512 /*
513 * Make two approaches to the test page (the 2nd one):
514 * - i=0: Start on the 1st page and edge into the 2nd.
515 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
516 */
517 for (i = 0; i < 2; i++)
518 {
519 unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
520 unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
521
522 for (; off < offEnd; off++)
523 {
524 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValue;
525 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
526 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
527 else
528 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
529
530 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
531 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
532
533 if ( bXcpt != X86_XCPT_PF
534 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2)
535 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) )
536 {
537 pThis->ExpectCtx.rax.u = uExpectRax;
538 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovLoad.offUd2, X86_XCPT_UD, 0 /*uErrCd*/);
539 pThis->ExpectCtx.rax = pCtx->rax;
540 }
541 else
542 {
543 if (off < X86_PAGE_SIZE)
544 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
545 else
546 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
547 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
548 pThis->ExpectCtx.cr2 = pCtx->cr2;
549 }
550 }
551
552 if (fFlags & BS3CB2PFACC_F_DIRECT)
553 break;
554 }
555}
556
557
558/**
559 * Test a simple store instruction around the edges of page two.
560 *
561 * @param pThis The test stat data.
562 * @param pCtx The test context.
563 * @param fFlags BS3CB2PFACC_F_XXX.
564 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
565 * X86_XCPT_UD.
566 * @param uPfErrCd The error code for \#PFs.
567 */
568static void bs3CpuBasic2Pf_DoMovStore(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags,
569 uint8_t bXcpt, uint8_t uPfErrCd)
570{
571 static uint64_t const s_uValue = UINT64_C(0x3af45ead86a34a26);
572 static uint64_t const s_uValueFlipped = UINT64_C(0xc50ba152795cb5d9);
573 uint64_t const uRaxSaved = pCtx->rax.u;
574 uint64_t uExpectStored;
575 unsigned i;
576
577 /*
578 * Adjust the incoming context and calculate our expections.
579 */
580 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovStore);
581 if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
582 pCtx->rax.u = (uint32_t)s_uValue; /* leave the upper part zero */
583 else
584 pCtx->rax.u = s_uValue;
585
586 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
587 switch (pThis->bMode & BS3_MODE_CODE_MASK)
588 {
589 case BS3_MODE_CODE_16:
590 case BS3_MODE_CODE_V86:
591 uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
592 break;
593 case BS3_MODE_CODE_32:
594 uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
595 break;
596 case BS3_MODE_CODE_64:
597 uExpectStored = s_uValue;
598 break;
599 }
600
601 /*
602 * Make two approaches to the test page (the 2nd one):
603 * - i=0: Start on the 1st page and edge into the 2nd.
604 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
605 */
606 for (i = 0; i < 2; i++)
607 {
608 unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
609 unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
610 for (; off < offEnd; off++)
611 {
612 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
613 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
614 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
615 else
616 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
617
618 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
619 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
620
621 if ( bXcpt != X86_XCPT_PF
622 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2)
623 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) )
624 {
625 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovStore.offUd2, X86_XCPT_UD, 0 /*uErrCd*/);
626 if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
627 Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
628 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
629 }
630 else
631 {
632 if (off < X86_PAGE_SIZE)
633 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
634 else
635 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
636 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
637 pThis->ExpectCtx.cr2 = pCtx->cr2;
638 if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
639 Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
640 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
641
642 }
643 }
644
645 if (fFlags & BS3CB2PFACC_F_DIRECT)
646 break;
647 }
648
649 pCtx->rax.u = uRaxSaved;
650}
651
652
653/**
654 * Test a xchg instruction around the edges of page two.
655 *
656 * @param pThis The test stat data.
657 * @param pCtx The test context.
658 * @param fFlags BS3CB2PFACC_F_XXX.
659 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
660 * X86_XCPT_UD.
661 * @param uPfErrCd The error code for \#PFs.
662 */
663static void bs3CpuBasic2Pf_DoXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd)
664{
665 static uint64_t const s_uValue = UINT64_C(0xea58699648e2f32c);
666 static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3);
667 uint64_t const uRaxSaved = pCtx->rax.u;
668 uint64_t uRaxIn;
669 uint64_t uExpectedRax;
670 uint64_t uExpectStored;
671 unsigned i;
672
673 /*
674 * Adjust the incoming context and calculate our expections.
675 */
676 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->Xchg);
677 if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
678 uRaxIn = (uint32_t)s_uValue; /* leave the upper part zero */
679 else
680 uRaxIn = s_uValue;
681
682 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
683 switch (pThis->bMode & BS3_MODE_CODE_MASK)
684 {
685 case BS3_MODE_CODE_16:
686 case BS3_MODE_CODE_V86:
687 uExpectedRax = (uint16_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffffffff0000));
688 uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
689 break;
690 case BS3_MODE_CODE_32:
691 uExpectedRax = (uint32_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffff00000000));
692 uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
693 break;
694 case BS3_MODE_CODE_64:
695 uExpectedRax = s_uValueFlipped;
696 uExpectStored = s_uValue;
697 break;
698 }
699
700 /*
701 * Make two approaches to the test page (the 2nd one):
702 * - i=0: Start on the 1st page and edge into the 2nd.
703 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
704 */
705 for (i = 0; i < 2; i++)
706 {
707 unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
708 unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
709 for (; off < offEnd; off++)
710 {
711 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
712 pCtx->rax.u = uRaxIn;
713 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
714 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
715 else
716 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
717
718 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
719 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
720
721 if ( bXcpt != X86_XCPT_PF
722 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2)
723 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) )
724 {
725 pThis->ExpectCtx.rax.u = uExpectedRax;
726 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->Xchg.offUd2, X86_XCPT_UD, 0 /*uErrCd*/);
727 if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
728 Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
729 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
730 }
731 else
732 {
733 pThis->ExpectCtx.rax.u = uRaxIn;
734 if (off < X86_PAGE_SIZE)
735 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
736 else
737 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
738 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
739 pThis->ExpectCtx.cr2 = pCtx->cr2;
740 if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
741 Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
742 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
743 }
744 }
745
746 if (fFlags & BS3CB2PFACC_F_DIRECT)
747 break;
748 }
749
750 pCtx->rax.u = uRaxSaved;
751}
752
753
754/**
755 * Test a cmpxchg instruction around the edges of page two.
756 *
757 * @param pThis The test stat data.
758 * @param pCtx The test context.
759 * @param fFlags BS3CB2PFACC_F_XXX.
760 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
761 * X86_XCPT_UD.
762 * @param uPfErrCd The error code for \#PFs.
763 * @param fMissmatch Whether to fail and not store (@c true), or succeed
764 * and do the store.
765 */
766static void bs3CpuBasic2Pf_DoCmpXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags,
767 uint8_t bXcpt, uint8_t uPfErrCd, bool fMissmatch)
768{
769 static uint64_t const s_uValue = UINT64_C(0xea58699648e2f32c);
770 static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3);
771 static uint64_t const s_uValueOther = UINT64_C(0x2171239bcb044c81);
772 uint64_t const uRaxSaved = pCtx->rax.u;
773 uint64_t const uRcxSaved = pCtx->rcx.u;
774 uint64_t uRaxIn;
775 uint64_t uExpectedRax;
776 uint32_t uExpectedFlags;
777 uint64_t uExpectStored;
778 unsigned i;
779
780 /*
781 * Adjust the incoming context and calculate our expections.
782 * Hint: CMPXCHG [xBX],xCX ; xAX compare and update implicit, ZF set to !fMissmatch.
783 */
784 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->CmpXchg);
785 if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
786 {
787 uRaxIn = (uint32_t)(fMissmatch ? s_uValueOther : s_uValueFlipped); /* leave the upper part zero */
788 pCtx->rcx.u = (uint32_t)s_uValue; /* ditto */
789 }
790 else
791 {
792 uRaxIn = fMissmatch ? s_uValueOther : s_uValueFlipped;
793 pCtx->rcx.u = s_uValue;
794 }
795 if (fMissmatch)
796 pCtx->rflags.u32 |= X86_EFL_ZF;
797 else
798 pCtx->rflags.u32 &= ~X86_EFL_ZF;
799
800 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
801 uExpectedFlags = pCtx->rflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF | X86_EFL_ZF);
802 switch (pThis->bMode & BS3_MODE_CODE_MASK)
803 {
804 case BS3_MODE_CODE_16:
805 case BS3_MODE_CODE_V86:
806 uExpectedRax = (uint16_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffffffff0000));
807 uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
808 uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
809 break;
810 case BS3_MODE_CODE_32:
811 uExpectedRax = (uint32_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffff00000000));
812 uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
813 uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
814 break;
815 case BS3_MODE_CODE_64:
816 uExpectedRax = s_uValueFlipped;
817 uExpectStored = s_uValue;
818 uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
819 break;
820 }
821 if (fMissmatch)
822 uExpectStored = s_uValueFlipped;
823
824 /*
825 * Make two approaches to the test page (the 2nd one):
826 * - i=0: Start on the 1st page and edge into the 2nd.
827 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
828 */
829 for (i = 0; i < 2; i++)
830 {
831 unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
832 unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
833 for (; off < offEnd; off++)
834 {
835 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
836 pCtx->rax.u = uRaxIn;
837 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
838 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
839 else
840 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
841
842 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
843 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
844
845 if ( bXcpt != X86_XCPT_PF
846 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2)
847 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) )
848 {
849 pThis->ExpectCtx.rax.u = uExpectedRax;
850 pThis->ExpectCtx.rflags.u32 = uExpectedFlags;
851 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->CmpXchg.offUd2, X86_XCPT_UD, 0 /*uErrCd*/);
852 if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
853 Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
854 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
855 }
856 else
857 {
858 pThis->ExpectCtx.rax.u = uRaxIn;
859 pThis->ExpectCtx.rflags = pCtx->rflags;
860 if (off < X86_PAGE_SIZE)
861 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
862 else
863 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
864 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
865 pThis->ExpectCtx.cr2 = pCtx->cr2;
866 if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
867 Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
868 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
869 }
870 }
871
872 if (fFlags & BS3CB2PFACC_F_DIRECT)
873 break;
874 }
875
876 pCtx->rax.u = uRaxSaved;
877 pCtx->rcx.u = uRcxSaved;
878}
879
880
881static void bs3CpuBasic2Pf_DoCmpXchgMiss(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags,
882 uint8_t bXcpt, uint8_t uPfErrCd)
883{
884 bs3CpuBasic2Pf_DoCmpXchg(pThis, pCtx, fFlags, bXcpt, uPfErrCd, true /*fMissmatch*/ );
885}
886
887
888static void bs3CpuBasic2Pf_DoCmpXchgMatch(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags,
889 uint8_t bXcpt, uint8_t uPfErrCd)
890{
891 bs3CpuBasic2Pf_DoCmpXchg(pThis, pCtx, fFlags, bXcpt, uPfErrCd , false /*fMissmatch*/ );
892}
893
894
895/**
896 * @interface_method_impl{BS3CPUBASIC2PFACCESSOR,pfnAccessor,
897 * DIV [MEM=0] for checking the accessed bit}
898 */
899static void bs3CpuBasic2Pf_DoDivByZero(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags,
900 uint8_t bXcpt, uint8_t uPfErrCd)
901{
902 static uint64_t const s_uFiller = UINT64_C(0x9856703711f4069e);
903 uint64_t uZeroAndFill;
904 unsigned i;
905
906 /*
907 * Adjust the incoming context and calculate our expections.
908 */
909 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->DivMem);
910
911 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
912 switch (pThis->bMode & BS3_MODE_CODE_MASK)
913 {
914 case BS3_MODE_CODE_16:
915 case BS3_MODE_CODE_V86:
916 uZeroAndFill = s_uFiller & UINT64_C(0xffffffffffff0000);
917 break;
918 case BS3_MODE_CODE_32:
919 uZeroAndFill = s_uFiller & UINT64_C(0xffffffff00000000);
920 break;
921 case BS3_MODE_CODE_64:
922 uZeroAndFill = 0;
923 break;
924 }
925
926 /*
927 * Make two approaches to the test page (the 2nd one):
928 * - i=0: Start on the 1st page and edge into the 2nd.
929 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
930 */
931 for (i = 0; i < 2; i++)
932 {
933 unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
934 unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
935 for (; off < offEnd; off++)
936 {
937 *(uint64_t *)&pThis->pbOrgTest[off] = uZeroAndFill;
938 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
939 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
940 else
941 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
942
943 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
944 //if (pThis->bMode == BS3_MODE_PP16_32) Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
945
946 if ( bXcpt != X86_XCPT_PF
947 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2)
948 || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) )
949 {
950 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, X86_XCPT_DE, 0 /*uErrCd*/);
951 if (*(uint64_t *)&pThis->pbOrgTest[off] != uZeroAndFill)
952 Bs3TestFailedF("%u - %s: Modified source op: %#RX64, expected %#RX64",
953 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uZeroAndFill);
954 }
955 else
956 {
957 if (off < X86_PAGE_SIZE)
958 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
959 else
960 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
961 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
962 pThis->ExpectCtx.cr2 = pCtx->cr2;
963 if (*(uint64_t *)&pThis->pbOrgTest[off] != uZeroAndFill)
964 Bs3TestFailedF("%u - %s: Modified source op: %#RX64, expected %#RX64",
965 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uZeroAndFill);
966 }
967 }
968
969 if (fFlags & BS3CB2PFACC_F_DIRECT)
970 break;
971 }
972}
973
974
975static BS3CPUBASIC2PFACCESSOR const g_aAccessors[] =
976{
977 { "DoExec", bs3CpuBasic2Pf_DoExec, X86_TRAP_PF_ID, X86_XCPT_UD },
978 { "DoMovLoad", bs3CpuBasic2Pf_DoMovLoad, 0, X86_XCPT_UD },
979 { "DoMovStore", bs3CpuBasic2Pf_DoMovStore, X86_TRAP_PF_RW, X86_XCPT_UD },
980 { "DoXchg", bs3CpuBasic2Pf_DoXchg, X86_TRAP_PF_RW, X86_XCPT_UD },
981 { "DoCmpXchgMiss", bs3CpuBasic2Pf_DoCmpXchgMiss, X86_TRAP_PF_RW, X86_XCPT_UD },
982 { "DoCmpXhcgMatch", bs3CpuBasic2Pf_DoCmpXchgMatch, X86_TRAP_PF_RW, X86_XCPT_UD },
983 { "DoDivByZero", bs3CpuBasic2Pf_DoDivByZero, 0, X86_XCPT_DE },
984};
985
986/** @} */
987
988
989/** @name BS3CPUBASIC2PFMODPT::pfnModify implementations.
990 * @{ */
991
992
993static void bs3CpuBasic2Pf_ClearMask(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, PCBS3CPUBASIC2PFMODPT pEntry,
994 uint32_t fClearMask, uint32_t fSetMask)
995{
996 if (pThis->PgInfo.cbEntry == 4)
997 {
998 uint32_t const uOrg = pThis->PteBackup.Legacy[1];
999 uint32_t uNew = ((uOrg & ~fClearMask) | fSetMask) & ~(uint32_t)pEntry->uModifyArg;
1000 uint32_t const uOld = pThis->PgInfo.u.Legacy.pPte[1].u;
1001 g_aStoreMethods[iStore].pfnStore(pThis->PgInfo.u.Legacy.pPte + 1, uNew, uOld);
1002 }
1003 else
1004 {
1005 uint64_t const uOrg = pThis->PteBackup.Pae[1];
1006 uint64_t uNew = ((uOrg & ~(uint64_t)fClearMask) | fSetMask) & ~(uint64_t)pEntry->uModifyArg;
1007 uint64_t const uOld = pThis->PgInfo.u.Pae.pPte[1].u;
1008
1009 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[0], (uint32_t)uNew, (uint32_t)uOld);
1010 if ((uint32_t)(uNew >> 32) != (uint32_t)(uOld >> 32))
1011 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[1],
1012 (uint32_t)(uNew >> 32), (uint32_t)(uOld >> 32));
1013 }
1014}
1015
1016static void bs3CpuBasic2Pf_SetBit(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, PCBS3CPUBASIC2PFMODPT pEntry,
1017 uint32_t fClearMask, uint32_t fSetMask)
1018{
1019 if (pThis->PgInfo.cbEntry == 4)
1020 {
1021 uint32_t const uOrg = pThis->PteBackup.Legacy[1];
1022 uint32_t uNew = (uOrg & ~fClearMask) | fSetMask | RT_BIT_32(pEntry->uModifyArg);
1023 uint32_t const uOld = pThis->PgInfo.u.Legacy.pPte[1].u;
1024 g_aStoreMethods[iStore].pfnStore(pThis->PgInfo.u.Legacy.pPte + 1, uNew, uOld);
1025 }
1026 else
1027 {
1028 uint64_t const uOrg = pThis->PteBackup.Pae[1];
1029 uint64_t uNew = ((uOrg & ~(uint64_t)fClearMask) | fSetMask) | RT_BIT_64(pEntry->uModifyArg);
1030 uint64_t const uOld = pThis->PgInfo.u.Pae.pPte[1].u;
1031
1032 if (pEntry->uModifyArg < 32 || (uint32_t)uNew != (uint32_t)uOld)
1033 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[0], (uint32_t)uNew, (uint32_t)uOld);
1034 if (pEntry->uModifyArg >= 32 || (uint32_t)(uNew >> 32) != (uint32_t)(uOld >> 32))
1035 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[1],
1036 (uint32_t)(uNew >> 32), (uint32_t)(uOld >> 32));
1037 }
1038}
1039
1040static void bs3CpuBasic2Pf_NoChange(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, PCBS3CPUBASIC2PFMODPT pEntry,
1041 uint32_t fClearMask, uint32_t fSetMask)
1042{
1043 if (pThis->PgInfo.cbEntry == 4)
1044 {
1045 uint32_t const uOrg = pThis->PteBackup.Legacy[1];
1046 uint32_t uNew = (uOrg & ~fClearMask) | fSetMask;
1047 uint32_t const uOld = pThis->PgInfo.u.Legacy.pPte[1].u;
1048 if (uNew != uOld)
1049 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Legacy.pPte[1], uNew, uOld);
1050 }
1051 else
1052 {
1053 uint64_t const uOrg = pThis->PteBackup.Pae[1];
1054 uint64_t uNew = (uOrg & ~(uint64_t)fClearMask) | fSetMask;
1055 uint64_t const uOld = pThis->PgInfo.u.Pae.pPte[1].u;
1056 if (uNew != uOld)
1057 {
1058 if ((uint32_t)uNew != (uint32_t)uOld)
1059 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[0], (uint32_t)uNew, (uint32_t)uOld);
1060 if ((uint32_t)(uNew >> 32) != (uint32_t)(uOld >> 32))
1061 g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[1],
1062 (uint32_t)(uNew >> 32), (uint32_t)(uOld >> 32));
1063 }
1064 }
1065}
1066
1067/** @} */
1068
1069
1070/** @name BS3CPUBASIC2PFMODPT::pfnApplicable implementations.
1071 * @{ */
1072
1073static bool bs3CpuBasic2Pf_IsPteBitReserved(PBS3CPUBASIC2PFSTATE pThis, PCBS3CPUBASIC2PFMODPT pEntry)
1074{
1075 if (pThis->PgInfo.cbEntry == 8)
1076 {
1077 /* Bits 52..63 or 62 (NXE=1). */
1078 if (pThis->PgInfo.cEntries == 3)
1079 {
1080 if ((uint32_t)(pEntry->uModifyArg - 52U) < (uint32_t)(12 - pThis->fNxe))
1081 return true;
1082 }
1083 else if (pEntry->uModifyArg == 63 && !pThis->fNxe)
1084 return true;
1085
1086 /* Reserved physical address bits. */
1087 if (pEntry->uModifyArg < 52)
1088 {
1089 if ((uint32_t)pEntry->uModifyArg >= (uint32_t)pThis->cBitsPhysWidth)
1090 return true;
1091 }
1092 }
1093 return false;
1094}
1095
1096static bool bs3CpuBasic2Pf_IsPteBitSoftwareUsable(PBS3CPUBASIC2PFSTATE pThis, PCBS3CPUBASIC2PFMODPT pEntry)
1097{
1098 if (pThis->PgInfo.cbEntry == 8)
1099 {
1100 if (pThis->PgInfo.cEntries != 3)
1101 {
1102 if ((uint32_t)(pEntry->uModifyArg - 52U) < (uint32_t)11)
1103 return true;
1104 }
1105 }
1106 return false;
1107}
1108
1109
1110static bool bs3CpuBasic2Pf_IsNxe(PBS3CPUBASIC2PFSTATE pThis, PCBS3CPUBASIC2PFMODPT pEntry)
1111{
1112 return pThis->fNxe && pThis->PgInfo.cbEntry == 8;
1113}
1114
1115/** @} */
1116
1117
1118static const BS3CPUBASIC2PFMODPT g_aPteWorkers[] =
1119{
1120/* { pszName, P U W NX RSV ModiyfArg pfnModify, pfnApplicable }, */
1121 { "org", 1, 1, 1, 0, 0, 0, bs3CpuBasic2Pf_NoChange, NULL },
1122 { "!US", 1, 0, 1, 0, 0, X86_PTE_US, bs3CpuBasic2Pf_ClearMask, NULL },
1123 { "!RW", 1, 1, 0, 0, 0, X86_PTE_RW, bs3CpuBasic2Pf_ClearMask, NULL },
1124 { "!RW+!US", 1, 0, 0, 0, 0, X86_PTE_RW | X86_PTE_US, bs3CpuBasic2Pf_ClearMask, NULL },
1125 { "!P", 0, 0, 0, 0, 0, X86_PTE_P, bs3CpuBasic2Pf_ClearMask, NULL },
1126 { "NX", 1, 1, 1, 1, 0, 63, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsNxe },
1127 { "RSVPH[32]", 0, 0, 0, 0, 1, 32, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1128 { "RSVPH[33]", 0, 0, 0, 0, 1, 33, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1129 { "RSVPH[34]", 0, 0, 0, 0, 1, 34, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1130 { "RSVPH[35]", 0, 0, 0, 0, 1, 35, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1131 { "RSVPH[36]", 0, 0, 0, 0, 1, 36, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1132 { "RSVPH[37]", 0, 0, 0, 0, 1, 37, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1133 { "RSVPH[38]", 0, 0, 0, 0, 1, 38, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1134 { "RSVPH[39]", 0, 0, 0, 0, 1, 39, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1135 { "RSVPH[40]", 0, 0, 0, 0, 1, 40, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1136 { "RSVPH[41]", 0, 0, 0, 0, 1, 41, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1137 { "RSVPH[42]", 0, 0, 0, 0, 1, 42, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1138 { "RSVPH[43]", 0, 0, 0, 0, 1, 43, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1139 { "RSVPH[44]", 0, 0, 0, 0, 1, 44, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1140 { "RSVPH[45]", 0, 0, 0, 0, 1, 45, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1141 { "RSVPH[46]", 0, 0, 0, 0, 1, 46, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1142 { "RSVPH[47]", 0, 0, 0, 0, 1, 47, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1143 { "RSVPH[48]", 0, 0, 0, 0, 1, 48, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1144 { "RSVPH[49]", 0, 0, 0, 0, 1, 49, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1145 { "RSVPH[50]", 0, 0, 0, 0, 1, 50, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1146 { "RSVPH[51]", 0, 0, 0, 0, 1, 51, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1147 { "RSV[52]", 0, 0, 0, 0, 1, 52, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1148 { "RSV[53]", 0, 0, 0, 0, 1, 53, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1149 { "RSV[54]", 0, 0, 0, 0, 1, 54, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1150 { "RSV[55]", 0, 0, 0, 0, 1, 55, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1151 { "RSV[56]", 0, 0, 0, 0, 1, 56, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1152 { "RSV[57]", 0, 0, 0, 0, 1, 57, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1153 { "RSV[58]", 0, 0, 0, 0, 1, 58, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1154 { "RSV[59]", 0, 0, 0, 0, 1, 59, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1155 { "RSV[60]", 0, 0, 0, 0, 1, 60, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1156 { "RSV[61]", 0, 0, 0, 0, 1, 61, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1157 { "RSV[62]", 0, 0, 0, 0, 1, 62, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1158 { "RSV[62]", 0, 0, 0, 0, 1, 62, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1159 { "RSV[63]", 0, 0, 0, 0, 1, 63, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved },
1160 { "!RSV[52]", 1, 1, 1, 0, 0, 52, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1161 { "!RSV[53]", 1, 1, 1, 0, 0, 53, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1162 { "!RSV[54]", 1, 1, 1, 0, 0, 54, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1163 { "!RSV[55]", 1, 1, 1, 0, 0, 55, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1164 { "!RSV[56]", 1, 1, 1, 0, 0, 56, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1165 { "!RSV[57]", 1, 1, 1, 0, 0, 57, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1166 { "!RSV[58]", 1, 1, 1, 0, 0, 58, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1167 { "!RSV[59]", 1, 1, 1, 0, 0, 59, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1168 { "!RSV[60]", 1, 1, 1, 0, 0, 60, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1169 { "!RSV[61]", 1, 1, 1, 0, 0, 61, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1170 { "!RSV[62]", 1, 1, 1, 0, 0, 62, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable },
1171
1172};
1173
1174
1175/**
1176 * Worker for bs3CpuBasic2_RaiseXcpt0e_c32 that does the actual testing.
1177 *
1178 * Caller does all the cleaning up.
1179 *
1180 * @returns Error count.
1181 * @param pThis Test state data.
1182 * @param fNxe Whether NX is enabled.
1183 */
1184static uint8_t bs3CpuBasic2_RaiseXcpt0eWorker(PBS3CPUBASIC2PFSTATE register pThis, bool const fWp, bool const fNxe)
1185{
1186 unsigned iRing;
1187 unsigned iStore;
1188 unsigned iAccessor;
1189 unsigned iOuter;
1190 uint32_t const fPfIdMask = fNxe ? UINT32_MAX : ~X86_TRAP_PF_ID;
1191 BS3REGCTX aCtxts[4];
1192
1193 pThis->fWp = fWp;
1194 pThis->fNxe = fNxe;
1195
1196 /** @todo figure out V8086 testing. */
1197 if ((pThis->bMode & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86)
1198 return BS3TESTDOMODE_SKIPPED;
1199
1200
1201 /* paranoia: Touch the various big stack structures to ensure the compiler has allocated stack for them. */
1202 for (iRing = 0; iRing < RT_ELEMENTS(aCtxts); iRing++)
1203 Bs3MemZero(&aCtxts[iRing], sizeof(aCtxts[iRing]));
1204
1205 /*
1206 * Set up a few contexts for testing this stuff.
1207 */
1208 Bs3RegCtxSaveEx(&aCtxts[0], pThis->bMode, 2048);
1209 for (iRing = 1; iRing < 4; iRing++)
1210 {
1211 aCtxts[iRing] = aCtxts[0];
1212 Bs3RegCtxConvertToRingX(&aCtxts[iRing], iRing);
1213 }
1214
1215 if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode))
1216 {
1217 for (iRing = 0; iRing < 4; iRing++)
1218 aCtxts[iRing].rbx.u = (uintptr_t)pThis->pbTest;
1219 }
1220 else
1221 {
1222 for (iRing = 0; iRing < 4; iRing++)
1223 {
1224 aCtxts[iRing].ds = pThis->uSel16TestData;
1225 aCtxts[iRing].rbx.u = 0;
1226 }
1227 }
1228
1229 /*
1230 * Check basic operation:
1231 */
1232 for (iRing = 0; iRing < 4; iRing++)
1233 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1234 g_aAccessors[iAccessor].pfnAccessor(pThis, &aCtxts[iRing], BS3CB2PFACC_F_PAGE_LEVEL, X86_XCPT_UD, UINT8_MAX);
1235
1236 /*
1237 * Check the U bit on PTE level. We only mess with the 2nd page.
1238 */
1239 for (iOuter = 0; iOuter < 2; iOuter++)
1240 {
1241 uint32_t const fAccessor = (iOuter == 0 ? BS3CB2PFACC_F_DIRECT : 0) | BS3CB2PFACC_F_PAGE_LEVEL;
1242 bool const fWp = RT_BOOL(ASMGetCR0() & X86_CR0_WP);
1243 unsigned iPteWrk;
1244
1245 bs3CpuBasic2Pf_FlushAll();
1246 for (iPteWrk = 0; iPteWrk < RT_ELEMENTS(g_aPteWorkers); iPteWrk++)
1247 {
1248 BS3CPUBASIC2PFMODPT EffWrk;
1249 const BS3CPUBASIC2PFMODPT *pPteWrk = &g_aPteWorkers[iPteWrk];
1250 if (pPteWrk->pfnApplicable && !pPteWrk->pfnApplicable(pThis, pPteWrk))
1251 continue;
1252
1253 pThis->pszPteWorker = pPteWrk->pszName;
1254
1255 EffWrk = *pPteWrk;
1256
1257#if 1
1258 /*
1259 * Do the modification once, then test all different accesses
1260 * without flushing the TLB or anything in-between.
1261 */
1262 for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++)
1263 {
1264 pThis->pszStore = g_aStoreMethods[iStore].pszName;
1265 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0);
1266
1267 for (iRing = 0; iRing < 4; iRing++)
1268 {
1269 PBS3REGCTX const pCtx = &aCtxts[iRing];
1270 if ( EffWrk.fReserved
1271 || !EffWrk.fPresent
1272 || (!EffWrk.fUser && iRing == 3))
1273 {
1274 uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD
1275 : EffWrk.fPresent ? X86_TRAP_PF_P : 0)
1276 | (iRing == 3 ? X86_TRAP_PF_US : 0);
1277 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1278 {
1279 pThis->pszAccessor = g_aAccessors[iAccessor].pszName;
1280 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF,
1281 fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask));
1282 }
1283 }
1284 else
1285 {
1286 uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0);
1287 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1288 {
1289 pThis->pszAccessor = g_aAccessors[iAccessor].pszName;
1290 if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID)
1291 && EffWrk.fNoExecute)
1292 || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW)
1293 && !EffWrk.fWriteable
1294 && (fWp || iRing == 3)) )
1295 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF,
1296 fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask));
1297 else
1298 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1299 }
1300 }
1301 }
1302
1303 /* Reset the paging + full flush. */
1304 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1305 }
1306#endif
1307
1308#define CHECK_AD_BITS(a_fExpectedAD) \
1309 do { \
1310 uint32_t fActualAD = ( pThis->PgInfo.cbEntry == 8 \
1311 ? pThis->PgInfo.u.Pae.pPte[1].au32[0] : pThis->PgInfo.u.Legacy.pPte[1].au32[0]) \
1312 & (X86_PTE_A | X86_PTE_D); \
1313 if (fActualAD != (a_fExpectedAD)) \
1314 { \
1315 Bs3TestFailedF("%u - %s/%u: unexpected A/D bits: %#x, expected %#x\n", \
1316 g_usBs3TestStep, "xxxx", __LINE__, fActualAD, a_fExpectedAD); \
1317 BS3CPUBASIC2PF_HALT(pThis); \
1318 } \
1319 } while (0)
1320
1321 /*
1322 * Again, but redoing everything for each accessor.
1323 */
1324 for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++)
1325 {
1326 pThis->pszStore = g_aStoreMethods[iStore].pszName;
1327
1328 for (iRing = 0; iRing < 4; iRing++)
1329 {
1330 PBS3REGCTX const pCtx = &aCtxts[iRing];
1331
1332 if ( EffWrk.fReserved
1333 || !EffWrk.fPresent
1334 || (!EffWrk.fUser && iRing == 3))
1335 {
1336 uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD
1337 : EffWrk.fPresent ? X86_TRAP_PF_P : 0)
1338 | (iRing == 3 ? X86_TRAP_PF_US : 0);
1339 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1340 {
1341 pThis->pszAccessor = g_aAccessors[iAccessor].pszName;
1342
1343 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0);
1344 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF,
1345 fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask));
1346 CHECK_AD_BITS(0);
1347 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1348
1349 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0);
1350 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF,
1351 fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask));
1352 CHECK_AD_BITS(0);
1353 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1354 }
1355 }
1356 else
1357 {
1358 uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0);
1359 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1360 {
1361 pThis->pszAccessor = g_aAccessors[iAccessor].pszName;
1362 if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID)
1363 && EffWrk.fNoExecute)
1364 || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW)
1365 && !EffWrk.fWriteable
1366 && (fWp || iRing == 3)) )
1367 {
1368 uint32_t const fErrCd = fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask);
1369
1370 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0);
1371 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1372 CHECK_AD_BITS(0);
1373 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1374
1375 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D);
1376 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1377 CHECK_AD_BITS(X86_PTE_A | X86_PTE_D);
1378 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1379
1380 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D);
1381 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1382 CHECK_AD_BITS(X86_PTE_D);
1383 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1384
1385 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A);
1386 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1387 CHECK_AD_BITS(X86_PTE_A);
1388 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1389 }
1390 else
1391 {
1392 uint32_t const fExpectedAD = (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW)
1393 ? X86_PTE_A | X86_PTE_D : X86_PTE_A;
1394
1395 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0);
1396 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1397 CHECK_AD_BITS(fExpectedAD);
1398 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1399
1400 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D);
1401 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1402 CHECK_AD_BITS(X86_PTE_A | X86_PTE_D);
1403 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1404
1405 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D);
1406 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1407 CHECK_AD_BITS(fExpectedAD | X86_PTE_D);
1408 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1409
1410 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A);
1411 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1412 CHECK_AD_BITS(fExpectedAD | X86_PTE_A);
1413 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1414 }
1415 }
1416 }
1417 }
1418 }
1419
1420 /*
1421 * Again, but using invalidate page.
1422 */
1423 if (pThis->fUseInvlPg)
1424 {
1425 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1426
1427 for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++)
1428 {
1429 pThis->pszStore = g_aStoreMethods[iStore].pszName;
1430
1431 for (iRing = 0; iRing < 4; iRing++)
1432 {
1433 PBS3REGCTX const pCtx = &aCtxts[iRing];
1434
1435 if ( EffWrk.fReserved
1436 || !EffWrk.fPresent
1437 || (!EffWrk.fUser && iRing == 3))
1438 {
1439 uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD
1440 : EffWrk.fPresent ? X86_TRAP_PF_P : 0)
1441 | (iRing == 3 ? X86_TRAP_PF_US : 0);
1442 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1443 {
1444 pThis->pszAccessor = g_aAccessors[iAccessor].pszName;
1445
1446 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0);
1447 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1448 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF,
1449 fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask));
1450 CHECK_AD_BITS(0);
1451
1452 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0);
1453 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1454 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF,
1455 fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask));
1456 CHECK_AD_BITS(0);
1457 }
1458 }
1459 else
1460 {
1461 uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0);
1462 for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++)
1463 {
1464 pThis->pszAccessor = g_aAccessors[iAccessor].pszName;
1465 if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID)
1466 && EffWrk.fNoExecute)
1467 || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW)
1468 && !EffWrk.fWriteable
1469 && (fWp || iRing == 3)) )
1470 {
1471 uint32_t const fErrCd = fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask);
1472
1473 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0);
1474 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1475 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1476 CHECK_AD_BITS(0);
1477
1478 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D);
1479 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1480 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1481 CHECK_AD_BITS(X86_PTE_A | X86_PTE_D);
1482
1483 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D);
1484 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1485 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1486 CHECK_AD_BITS(X86_PTE_D);
1487
1488 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A);
1489 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1490 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd);
1491 CHECK_AD_BITS(X86_PTE_A);
1492 }
1493 else
1494 {
1495 uint32_t const fExpectedAD = (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW)
1496 ? X86_PTE_A | X86_PTE_D : X86_PTE_A;
1497
1498 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0);
1499 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1500 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1501 CHECK_AD_BITS(fExpectedAD);
1502
1503 pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D);
1504 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1505 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1506 CHECK_AD_BITS(X86_PTE_A | X86_PTE_D);
1507
1508 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D);
1509 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1510 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1511 CHECK_AD_BITS(fExpectedAD | X86_PTE_D);
1512
1513 pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A);
1514 ASMInvalidatePage((uintptr_t)pThis->pbTest + X86_PAGE_SIZE);
1515 g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX);
1516 CHECK_AD_BITS(fExpectedAD | X86_PTE_A);
1517 }
1518 }
1519 }
1520 }
1521 }
1522
1523 bs3CpuBasic2Pf_RestoreFromBackups(pThis);
1524 }
1525 }
1526 }
1527
1528 return 0;
1529}
1530
1531
1532BS3_DECL_CALLBACK(uint8_t) bs3CpuBasic2_RaiseXcpt0e_c32(uint8_t bMode)
1533{
1534 void *pvTestUnaligned;
1535 uint32_t cbTestUnaligned = _8M;
1536 uint8_t bRet = 1;
1537 int rc;
1538 BS3CPUBASIC2PFSTATE State;
1539
1540 /*
1541 * Initalize the state data.
1542 */
1543 Bs3MemZero(&State, sizeof(State));
1544 State.bMode = bMode;
1545 switch (bMode & BS3_MODE_CODE_MASK)
1546 {
1547 case BS3_MODE_CODE_16: State.cbAccess = sizeof(uint16_t); break;
1548 case BS3_MODE_CODE_V86: State.cbAccess = sizeof(uint16_t); break;
1549 case BS3_MODE_CODE_32: State.cbAccess = sizeof(uint32_t); break;
1550 case BS3_MODE_CODE_64: State.cbAccess = sizeof(uint64_t); break;
1551 }
1552 State.pCmnMode = &g_aCmnModes[0];
1553 while (State.pCmnMode->bMode != (bMode & BS3_MODE_CODE_MASK))
1554 State.pCmnMode++;
1555 State.fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486;
1556
1557 /* Figure physical addressing width. */
1558 State.cBitsPhysWidth = 32;
1559 if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1560 && (ASMCpuId_EDX(1) & (X86_CPUID_FEATURE_EDX_PSE36 | X86_CPUID_FEATURE_EDX_PAE)) )
1561 State.cBitsPhysWidth = 36;
1562
1563 if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID_EXT_LEAVES)
1564 && ASMCpuId_EAX(0x80000000) >= 0x80000008)
1565 {
1566 uint8_t cBits = (uint8_t)ASMCpuId_EAX(0x80000008);
1567 if (cBits >= 32 && cBits <= 52)
1568 State.cBitsPhysWidth = cBits;
1569 else
1570 Bs3TestPrintf("CPUID 0x80000008: Physical bitcount out of range: %u\n", cBits);
1571 }
1572 //Bs3TestPrintf("Physical bitcount: %u\n", State.cBitsPhysWidth);
1573
1574 /*
1575 * Allocate a some memory we can play around with, then carve a size aligned
1576 * chunk out of it so we might be able to maybe play with 2/4MB pages too.
1577 */
1578 cbTestUnaligned = _8M * 2;
1579 while ((pvTestUnaligned = Bs3MemAlloc(BS3MEMKIND_FLAT32, cbTestUnaligned)) == NULL)
1580 {
1581 cbTestUnaligned >>= 1;
1582 if (cbTestUnaligned <= _16K)
1583 {
1584 Bs3TestFailed("Failed to allocate memory to play around with\n");
1585 return 1;
1586 }
1587 }
1588
1589 /* align. */
1590 if ((uintptr_t)pvTestUnaligned & (cbTestUnaligned - 1))
1591 {
1592 State.cbTest = cbTestUnaligned >> 1;
1593 State.pbOrgTest = (uint8_t *)(((uintptr_t)pvTestUnaligned + State.cbTest - 1) & ~(State.cbTest - 1));
1594 }
1595 else
1596 {
1597 State.pbOrgTest = pvTestUnaligned;
1598 State.cbTest = cbTestUnaligned;
1599 }
1600 State.cTestPages = State.cbTest >> X86_PAGE_SHIFT;
1601
1602 /*
1603 * Alias this memory far away from where our code and data lives.
1604 */
1605 State.pbTest = (uint8_t *)UINT32_C(0x80000000);
1606 rc = Bs3PagingAlias((uintptr_t)State.pbTest, (uintptr_t)State.pbOrgTest, State.cbTest, X86_PTE_P | X86_PTE_RW | X86_PTE_US);
1607 if (RT_SUCCESS(rc))
1608 {
1609 rc = Bs3PagingQueryAddressInfo((uintptr_t)State.pbTest, &State.PgInfo);
1610 if (RT_SUCCESS(rc))
1611 {
1612 /* Set values that derives from the test memory size and paging info. */
1613 if (State.PgInfo.cEntries == 2)
1614 {
1615 State.cTestPdes = (State.cTestPages + X86_PG_ENTRIES - 1) / X86_PG_ENTRIES;
1616 State.cTest1stPtes = RT_MIN(State.cTestPages, X86_PG_ENTRIES);
1617 State.cbPdeBackup = State.cTestPdes * (X86_PAGE_SIZE / X86_PG_ENTRIES);
1618 State.cbPteBackup = State.cTest1stPtes * (X86_PAGE_SIZE / X86_PG_ENTRIES);
1619 }
1620 else
1621 {
1622 State.cTestPdes = (State.cTestPages + X86_PG_PAE_ENTRIES - 1) / X86_PG_PAE_ENTRIES;
1623 State.cTest1stPtes = RT_MIN(State.cTestPages, X86_PG_PAE_ENTRIES);
1624 State.cbPdeBackup = State.cTestPdes * (X86_PAGE_SIZE / X86_PG_PAE_ENTRIES);
1625 State.cbPteBackup = State.cTest1stPtes * (X86_PAGE_SIZE / X86_PG_PAE_ENTRIES);
1626 }
1627#ifdef BS3CPUBASIC2PF_FASTER
1628 State.cbPteBackup = State.PgInfo.cbEntry * 4;
1629#endif
1630 if (State.cTestPdes <= RT_ELEMENTS(State.au64PdeBackup))
1631 {
1632 uint32_t cr0 = ASMGetCR0();
1633
1634 /* Back up the structures. */
1635 Bs3MemCpy(&State.PteBackup, State.PgInfo.u.Legacy.pPte, State.cbPteBackup);
1636 Bs3MemCpy(State.au64PdeBackup, State.PgInfo.u.Legacy.pPde, State.cbPdeBackup);
1637 if (State.PgInfo.cEntries > 2)
1638 State.u64PdpteBackup = State.PgInfo.u.Pae.pPdpe->u;
1639 if (State.PgInfo.cEntries > 3)
1640 State.u64Pml4eBackup = State.PgInfo.u.Pae.pPml4e->u;
1641
1642 /*
1643 * Setup a 16-bit selector for accessing the alias.
1644 */
1645 Bs3SelSetup16BitData(&Bs3GdteSpare00, (uintptr_t)State.pbTest);
1646 State.uSel16TestData = BS3_SEL_SPARE_00 | 3;
1647
1648 /*
1649 * Do the testing.
1650 */
1651 ASMSetCR0(ASMGetCR0() & ~X86_CR0_WP);
1652 bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, false /*fWp*/, false /*fNxe*/);
1653 if (bRet == 0 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1654 {
1655 ASMSetCR0(ASMGetCR0() | X86_CR0_WP);
1656 bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, true /*fWp*/, false /*fNxe*/);
1657 }
1658
1659 /* Do again with NX enabled. */
1660 if (bRet == 0 && (g_uBs3CpuDetected & BS3CPU_F_NX))
1661 {
1662 ASMWrMsr(MSR_K6_EFER, ASMRdMsr(MSR_K6_EFER) | MSR_K6_EFER_NXE);
1663 ASMSetCR0(ASMGetCR0() & ~X86_CR0_WP);
1664 bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, false /*fWp*/, State.PgInfo.cbEntry == 8 /*fNxe*/);
1665 ASMSetCR0(ASMGetCR0() | X86_CR0_WP);
1666 bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, true /*fWp*/, State.PgInfo.cbEntry == 8 /*fNxe*/);
1667 ASMWrMsr(MSR_K6_EFER, ASMRdMsr(MSR_K6_EFER) & ~MSR_K6_EFER_NXE);
1668 }
1669 bs3CpuBasic2Pf_RestoreFromBackups(&State);
1670 ASMSetCR0((ASMGetCR0() & ~X86_CR0_WP) | (cr0 & X86_CR0_WP));
1671 }
1672 else
1673 Bs3TestFailedF("cTestPdes=%u!\n", State.cTestPdes);
1674 }
1675 else
1676 Bs3TestFailedF("Bs3PagingQueryAddressInfo failed: %d\n", rc);
1677 Bs3PagingUnalias((uintptr_t)State.pbTest, State.cbTest);
1678 }
1679 else
1680 Bs3TestFailedF("Bs3PagingAlias failed! rc=%d\n", rc);
1681 Bs3MemFree(pvTestUnaligned, cbTestUnaligned);
1682 return bRet;
1683}
1684
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette