VirtualBox

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

Last change on this file since 65145 was 64776, checked in by vboxsync, 8 years ago

bs3-cpu-basic-2: updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1/* $Id: bs3-cpu-basic-2-pf.c32 64776 2016-12-02 12:30:33Z 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
46/*********************************************************************************************************************************
47* Structures and Typedefs *
48*********************************************************************************************************************************/
49typedef void BS3_CALL FNBS3CPUBASIC2PFSNIPPET(void);
50
51typedef struct FNBS3CPUBASIC2PFTSTCODE
52{
53 FNBS3CPUBASIC2PFSNIPPET *pfn;
54 uint8_t offUd2;
55 uint8_t cbTmpl;
56} FNBS3CPUBASIC2PFTSTCODE;
57typedef FNBS3CPUBASIC2PFTSTCODE const *PCFNBS3CPUBASIC2PFTSTCODE;
58
59typedef struct BS3CPUBASIC2PFTTSTCMNMODE
60{
61 uint8_t bMode;
62 FNBS3CPUBASIC2PFTSTCODE MovLoad;
63 FNBS3CPUBASIC2PFTSTCODE MovStore;
64 FNBS3CPUBASIC2PFTSTCODE Xchg;
65 FNBS3CPUBASIC2PFTSTCODE CmpXchg;
66} BS3CPUBASIC2PFTTSTCMNMODE;
67typedef BS3CPUBASIC2PFTTSTCMNMODE const *PCBS3CPUBASIC2PFTTSTCMNMODE;
68
69
70typedef struct BS3CPUBASIC2PFSTATE
71{
72 /** The mode we're currently testing. */
73 uint8_t bMode;
74 /** The size of a natural access. */
75 uint8_t cbAccess;
76 /** The common mode functions. */
77 PCBS3CPUBASIC2PFTTSTCMNMODE pCmnMode;
78 /** Pointer to the test area (alias). */
79 uint8_t *pbTest;
80 /** Pointer to the orignal test area mapping. */
81 uint8_t *pbOrgTest;
82 /** The size of the test area (at least two pages). */
83 uint32_t cbTest;
84 /** 16-bit data selector for pbTest. */
85 uint16_t uSel16TestData;
86 /** 16-bit code selector for pbTest. */
87 uint16_t uSel16TestCode;
88 /** Test paging information for pbTest. */
89 BS3PAGINGINFO4ADDR PgInfo;
90
91 /** Set if we can use the INVLPG instruction. */
92 bool fUseInvlPg;
93
94 /** Trap context frame. */
95 BS3TRAPFRAME TrapCtx;
96 /** Expected result context. */
97 BS3REGCTX ExpectCtx;
98
99} BS3CPUBASIC2PFSTATE;
100/** Pointer to state for the \#PF test. */
101typedef BS3CPUBASIC2PFSTATE *PBS3CPUBASIC2PFSTATE;
102
103
104/*********************************************************************************************************************************
105* Internal Functions *
106*********************************************************************************************************************************/
107FNBS3TESTDOMODE bs3CpuBasic2_RaiseXcpt0e_c32;
108
109/* bs3-cpu-basic-2-asm.asm: */
110void BS3_CALL bs3CpuBasic2_Store_mov_c32(void *pvDst, uint32_t uValue, uint32_t uOld);
111void BS3_CALL bs3CpuBasic2_Store_xchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld);
112void BS3_CALL bs3CpuBasic2_Store_cmpxchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld);
113
114
115/* bs3-cpu-basic-2-template.mac: */
116FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c16;
117FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c16;
118FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16;
119FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16;
120
121FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c32;
122FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c32;
123FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32;
124FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32;
125
126FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c64;
127FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c64;
128FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64;
129FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64;
130
131
132/*********************************************************************************************************************************
133* Global Variables *
134*********************************************************************************************************************************/
135/** Page table access functions. */
136static const struct
137{
138 const char *pszStore;
139 void (BS3_CALL *pfnStore)(void *pvDst, uint32_t uValue, uint32_t uOld);
140} g_aStoreMethods[] =
141{
142 { "mov", bs3CpuBasic2_Store_mov_c32 },
143 { "xchg", bs3CpuBasic2_Store_xchg_c32 },
144 { "cmpxchg", bs3CpuBasic2_Store_cmpxchg_c32 },
145};
146
147
148static const BS3CPUBASIC2PFTTSTCMNMODE g_aCmnModes[] =
149{
150 {
151 BS3_MODE_CODE_16,
152 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 },
153 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 },
154 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 },
155 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 },
156 },
157 {
158 BS3_MODE_CODE_32,
159 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c32, 2 },
160 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c32, 2 },
161 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32, 2 },
162 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32, 3 },
163 },
164 {
165 BS3_MODE_CODE_64,
166 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c64, 2 + 1 },
167 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c64, 2 + 1 },
168 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64, 2 + 1 },
169 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64, 3 + 1 },
170 },
171 {
172 BS3_MODE_CODE_V86,
173 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 },
174 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 },
175 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 },
176 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 },
177 },
178};
179
180
181/**
182 * Compares a CPU trap.
183 */
184static void bs3CpuBasic2Pf_CompareCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pExpectCtx, int cbPcAdjust,
185 uint8_t bXcpt, unsigned uErrCd)
186{
187 const char *pszHint = "xxxx";
188 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
189 uint32_t fExtraEfl;
190
191 CHECK_MEMBER(pszHint, "bXcpt", "%#04x", pThis->TrapCtx.bXcpt, bXcpt);
192 CHECK_MEMBER(pszHint, "uErrCd", "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
193
194 fExtraEfl = X86_EFL_RF;
195 if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode))
196 fExtraEfl = 0;
197 else
198 fExtraEfl = X86_EFL_RF;
199 Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pExpectCtx, cbPcAdjust, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep);
200 if (Bs3TestSubErrorCount() != cErrorsBefore)
201 {
202 Bs3TrapPrintFrame(&pThis->TrapCtx);
203#if 1
204 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
205 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
206 ASMHalt();
207#endif
208 }
209}
210
211
212/**
213 * Compares a CPU trap.
214 */
215static void bs3CpuBasic2Pf_CompareSimpleCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pStartCtx, int offAddPC,
216 uint8_t bXcpt, unsigned uErrCd, uint64_t uCr2)
217{
218 const char *pszHint = "xxxx";
219 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
220 uint64_t const uSavedCr2 = pStartCtx->cr2.u;
221 uint32_t fExtraEfl;
222
223 CHECK_MEMBER(pszHint, "bXcpt", "%#04x", pThis->TrapCtx.bXcpt, bXcpt);
224 CHECK_MEMBER(pszHint, "uErrCd", "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
225
226 fExtraEfl = X86_EFL_RF;
227 if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode))
228 fExtraEfl = 0;
229 else
230 fExtraEfl = X86_EFL_RF;
231 pStartCtx->cr2.u = uCr2;
232 Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pStartCtx, offAddPC, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep);
233 pStartCtx->cr2.u = uSavedCr2;
234 if (Bs3TestSubErrorCount() != cErrorsBefore)
235 {
236 Bs3TrapPrintFrame(&pThis->TrapCtx);
237#if 1
238 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
239 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
240 ASMHalt();
241#endif
242 }
243}
244
245
246/**
247 * Checks the trap context for a simple \#PF trap.
248 */
249static void bs3CpuBasic2Pf_CompareSimplePf(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC,
250 unsigned uErrCd, uint64_t uCr2)
251{
252 bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_PF, uErrCd, uCr2);
253}
254
255/**
256 * Checks the trap context for a simple \#UD trap.
257 */
258static void bs3CpuBasic2Pf_CompareSimpleUd(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC)
259{
260 bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_UD, 0, pStartCtx->cr2.u);
261}
262
263
264static void bs3CpuBasic2Pf_DoExec(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd, bool fPageLevel)
265{
266 uint8_t *pbOrgTest = pThis->pbOrgTest;
267 unsigned off;
268
269 for (off = X86_PAGE_SIZE - 4; off < X86_PAGE_SIZE + 2; off++)
270 {
271 /* Emit a little bit of code (using the original allocation mapping) and point pCtx to it. */
272 pbOrgTest[off + 0] = X86_OP_PRF_SIZE_ADDR;
273 pbOrgTest[off + 1] = X86_OP_PRF_SIZE_OP;
274 pbOrgTest[off + 2] = 0x90; /* NOP */
275 pbOrgTest[off + 3] = 0x0f; /* UD2 */
276 pbOrgTest[off + 4] = 0x0b;
277 pbOrgTest[off + 5] = 0xeb; /* JMP $-4 */
278 pbOrgTest[off + 6] = 0xfc;
279 switch (pThis->bMode & BS3_MODE_CODE_MASK)
280 {
281 default:
282 pCtx->rip.u = (uintptr_t)&pThis->pbTest[off];
283 break;
284 case BS3_MODE_CODE_16:
285 Bs3SelSetup16BitCode(&Bs3GdteSpare01, (uintptr_t)pThis->pbTest, pCtx->bCpl);
286 pCtx->rip.u = off;
287 pCtx->cs = BS3_SEL_SPARE_01 | pCtx->bCpl;
288 break;
289 case BS3_MODE_CODE_V86:
290 /** @todo fix me. */
291 return;
292 }
293 //Bs3TestPrintf("cs:rip=%04x:%010RX64 iRing=%d\n", pCtx->cs, pCtx->rip.u, pCtx->bCpl);
294
295 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
296 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
297 if (bXcpt == X86_XCPT_PF)
298 {
299 unsigned offAddPC = !fPageLevel || off >= X86_PAGE_SIZE ? 0 : X86_PAGE_SIZE - off;
300 bs3CpuBasic2Pf_CompareSimplePf(pThis, pCtx, offAddPC, uPfErrCd, (uintptr_t)pThis->pbTest + offAddPC);
301 }
302 else
303 bs3CpuBasic2Pf_CompareSimpleUd(pThis, pCtx, 3);
304
305 }
306}
307
308
309static void bs3CpuBasic2Pf_SetCsEip(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, PCFNBS3CPUBASIC2PFTSTCODE pCode)
310{
311 switch (pThis->bMode & BS3_MODE_CODE_MASK)
312 {
313 default:
314 pCtx->rip.u = (uintptr_t)pCode->pfn;
315 break;
316
317 case BS3_MODE_CODE_16:
318 {
319 uint32_t uFar16 = Bs3SelFlatCodeToProtFar16((uintptr_t)pCode->pfn);
320 pCtx->rip.u = (uint16_t)uFar16;
321 pCtx->cs = (uint16_t)(uFar16 >> 16) | pCtx->bCpl;
322 pCtx->cs += (uint16_t)pCtx->bCpl << BS3_SEL_RING_SHIFT;
323 break;
324 }
325
326 case BS3_MODE_CODE_V86:
327 {
328 uint32_t uFar16 = Bs3SelFlatCodeToRealMode((uintptr_t)pCode->pfn);
329 pCtx->rip.u = (uint16_t)uFar16;
330 pCtx->cs = (uint16_t)(uFar16 >> 16);
331 break;
332 }
333 }
334}
335
336
337/**
338 * Test a simple load instruction around the edges of page two.
339 *
340 * @param pThis The test stat data.
341 * @param pCtx The test context.
342 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
343 * X86_XCPT_UD.
344 * @param uPfErrCd The error code for \#PFs.
345 * @param fPageLevel Set if we're pushing PTE level bits.
346 */
347static void bs3CpuBasic2Pf_DoMovLoad(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd,
348 bool fPageLevel)
349{
350 static uint64_t const s_uValue = UINT64_C(0x7c4d0114428d);
351 uint64_t uExpectRax;
352 unsigned i;
353
354 /*
355 * Adjust the incoming context and calculate our expections.
356 */
357 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovLoad);
358 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
359 switch (pThis->bMode & BS3_MODE_CODE_MASK)
360 {
361 case BS3_MODE_CODE_16:
362 case BS3_MODE_CODE_V86:
363 uExpectRax = (uint16_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffffffff0000));
364 break;
365 case BS3_MODE_CODE_32:
366 uExpectRax = (uint32_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffff00000000));
367 break;
368 case BS3_MODE_CODE_64:
369 uExpectRax = s_uValue;
370 break;
371 }
372 if (uExpectRax == pCtx->rax.u)
373 pCtx->rax.u = ~pCtx->rax.u;
374
375 /*
376 * Make two approaches to the test page (the 2nd one):
377 * - i=0: Start on the 1st page and edge into the 2nd.
378 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
379 */
380 for (i = 0; i < 2; i++)
381 {
382 unsigned off = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
383 unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
384 for (; off < offEnd; off++)
385 {
386 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValue;
387 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
388 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
389 else
390 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
391
392 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
393 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
394
395 if ( bXcpt != X86_XCPT_PF
396 || (fPageLevel && off >= X86_PAGE_SIZE * 2)
397 || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
398 {
399 pThis->ExpectCtx.rax.u = uExpectRax;
400 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovLoad.offUd2, bXcpt, 0 /*uErrCd*/);
401 pThis->ExpectCtx.rax = pCtx->rax;
402 }
403 else
404 {
405 if (off < X86_PAGE_SIZE)
406 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
407 else
408 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
409 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
410 pThis->ExpectCtx.cr2 = pCtx->cr2;
411 }
412 }
413 }
414}
415
416
417/**
418 * Test a simple store instruction around the edges of page two.
419 *
420 * @param pThis The test stat data.
421 * @param pCtx The test context.
422 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
423 * X86_XCPT_UD.
424 * @param uPfErrCd The error code for \#PFs.
425 * @param fPageLevel Set if we're pushing PTE level bits.
426 */
427static void bs3CpuBasic2Pf_DoMovStore(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd,
428 bool fPageLevel)
429{
430 static uint64_t const s_uValue = UINT64_C(0x3af45ead86a34a26);
431 static uint64_t const s_uValueFlipped = UINT64_C(0xc50ba152795cb5d9);
432 uint64_t const uRaxSaved = pCtx->rax.u;
433 uint64_t uExpectStored;
434 unsigned i;
435
436 /*
437 * Adjust the incoming context and calculate our expections.
438 */
439 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovStore);
440 if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
441 pCtx->rax.u = (uint32_t)s_uValue; /* leave the upper part zero */
442 else
443 pCtx->rax.u = s_uValue;
444
445 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
446 switch (pThis->bMode & BS3_MODE_CODE_MASK)
447 {
448 case BS3_MODE_CODE_16:
449 case BS3_MODE_CODE_V86:
450 uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
451 break;
452 case BS3_MODE_CODE_32:
453 uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
454 break;
455 case BS3_MODE_CODE_64:
456 uExpectStored = s_uValue;
457 break;
458 }
459
460 /*
461 * Make two approaches to the test page (the 2nd one):
462 * - i=0: Start on the 1st page and edge into the 2nd.
463 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
464 */
465 for (i = 0; i < 2; i++)
466 {
467 unsigned off = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
468 unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
469 for (; off < offEnd; off++)
470 {
471 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
472 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
473 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
474 else
475 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
476
477 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
478 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
479
480 if ( bXcpt != X86_XCPT_PF
481 || (fPageLevel && off >= X86_PAGE_SIZE * 2)
482 || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
483 {
484 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovStore.offUd2, bXcpt, 0 /*uErrCd*/);
485 if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
486 Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
487 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
488 }
489 else
490 {
491 if (off < X86_PAGE_SIZE)
492 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
493 else
494 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
495 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
496 pThis->ExpectCtx.cr2 = pCtx->cr2;
497 if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
498 Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
499 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
500
501 }
502 }
503 }
504
505 pCtx->rax.u = uRaxSaved;
506}
507
508
509/**
510 * Test a xchg instruction around the edges of page two.
511 *
512 * @param pThis The test stat data.
513 * @param pCtx The test context.
514 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
515 * X86_XCPT_UD.
516 * @param uPfErrCd The error code for \#PFs.
517 * @param fPageLevel Set if we're pushing PTE level bits.
518 */
519static void bs3CpuBasic2Pf_DoXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd, bool fPageLevel)
520{
521 static uint64_t const s_uValue = UINT64_C(0xea58699648e2f32c);
522 static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3);
523 uint64_t const uRaxSaved = pCtx->rax.u;
524 uint64_t uRaxIn;
525 uint64_t uExpectedRax;
526 uint64_t uExpectStored;
527 unsigned i;
528
529 /*
530 * Adjust the incoming context and calculate our expections.
531 */
532 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->Xchg);
533 if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
534 uRaxIn = (uint32_t)s_uValue; /* leave the upper part zero */
535 else
536 uRaxIn = s_uValue;
537
538 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
539 switch (pThis->bMode & BS3_MODE_CODE_MASK)
540 {
541 case BS3_MODE_CODE_16:
542 case BS3_MODE_CODE_V86:
543 uExpectedRax = (uint16_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffffffff0000));
544 uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
545 break;
546 case BS3_MODE_CODE_32:
547 uExpectedRax = (uint32_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffff00000000));
548 uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
549 break;
550 case BS3_MODE_CODE_64:
551 uExpectedRax = s_uValueFlipped;
552 uExpectStored = s_uValue;
553 break;
554 }
555
556 /*
557 * Make two approaches to the test page (the 2nd one):
558 * - i=0: Start on the 1st page and edge into the 2nd.
559 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
560 */
561 for (i = 0; i < 2; i++)
562 {
563 unsigned off = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
564 unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
565 for (; off < offEnd; off++)
566 {
567 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
568 pCtx->rax.u = uRaxIn;
569 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
570 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
571 else
572 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
573
574 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
575 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
576
577 if ( bXcpt != X86_XCPT_PF
578 || (fPageLevel && off >= X86_PAGE_SIZE * 2)
579 || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
580 {
581 pThis->ExpectCtx.rax.u = uExpectedRax;
582 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->Xchg.offUd2, bXcpt, 0 /*uErrCd*/);
583 if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
584 Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
585 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
586 }
587 else
588 {
589 pThis->ExpectCtx.rax.u = uRaxIn;
590 if (off < X86_PAGE_SIZE)
591 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
592 else
593 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
594 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
595 pThis->ExpectCtx.cr2 = pCtx->cr2;
596 if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
597 Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
598 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
599 }
600 }
601 }
602
603 pCtx->rax.u = uRaxSaved;
604}
605
606
607/**
608 * Test a cmpxchg instruction around the edges of page two.
609 *
610 * @param pThis The test stat data.
611 * @param pCtx The test context.
612 * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise
613 * X86_XCPT_UD.
614 * @param uPfErrCd The error code for \#PFs.
615 * @param fPageLevel Set if we're pushing PTE level bits.
616 * @param fMissmatch Whether to fail and not store (@c true), or succeed
617 * and do the store.
618 */
619static void bs3CpuBasic2Pf_DoCmpXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint8_t bXcpt, uint8_t uPfErrCd,
620 bool fPageLevel, bool fMissmatch)
621{
622 static uint64_t const s_uValue = UINT64_C(0xea58699648e2f32c);
623 static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3);
624 static uint64_t const s_uValueOther = UINT64_C(0x2171239bcb044c81);
625 uint64_t const uRaxSaved = pCtx->rax.u;
626 uint64_t const uRcxSaved = pCtx->rcx.u;
627 uint64_t uRaxIn;
628 uint64_t uExpectedRax;
629 uint32_t uExpectedFlags;
630 uint64_t uExpectStored;
631 unsigned i;
632
633 /*
634 * Adjust the incoming context and calculate our expections.
635 * Hint: CMPXCHG [xBX],xCX ; xAX compare and update implicit, ZF set to !fMissmatch.
636 */
637 bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->CmpXchg);
638 if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64)
639 {
640 uRaxIn = (uint32_t)(fMissmatch ? s_uValueOther : s_uValueFlipped); /* leave the upper part zero */
641 pCtx->rcx.u = (uint32_t)s_uValue; /* ditto */
642 }
643 else
644 {
645 uRaxIn = fMissmatch ? s_uValueOther : s_uValueFlipped;
646 pCtx->rcx.u = s_uValue;
647 }
648 if (fMissmatch)
649 pCtx->rflags.u32 |= X86_EFL_ZF;
650 else
651 pCtx->rflags.u32 &= ~X86_EFL_ZF;
652
653 Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx));
654 uExpectedFlags = pCtx->rflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF | X86_EFL_ZF);
655 switch (pThis->bMode & BS3_MODE_CODE_MASK)
656 {
657 case BS3_MODE_CODE_16:
658 case BS3_MODE_CODE_V86:
659 uExpectedRax = (uint16_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffffffff0000));
660 uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000));
661 uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
662 break;
663 case BS3_MODE_CODE_32:
664 uExpectedRax = (uint32_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffff00000000));
665 uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000));
666 uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
667 break;
668 case BS3_MODE_CODE_64:
669 uExpectedRax = s_uValueFlipped;
670 uExpectStored = s_uValue;
671 uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF;
672 break;
673 }
674 if (fMissmatch)
675 uExpectStored = s_uValueFlipped;
676
677 /*
678 * Make two approaches to the test page (the 2nd one):
679 * - i=0: Start on the 1st page and edge into the 2nd.
680 * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd.
681 */
682 for (i = 0; i < 2; i++)
683 {
684 unsigned off = X86_PAGE_SIZE * (i + 1) - pThis->cbAccess;
685 unsigned offEnd = X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7);
686 for (; off < offEnd; off++)
687 {
688 *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped;
689 pCtx->rax.u = uRaxIn;
690 if (BS3_MODE_IS_16BIT_CODE(pThis->bMode))
691 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off;
692 else
693 pThis->ExpectCtx.rbx.u = pCtx->rbx.u = (uintptr_t)pThis->pbTest + off;
694
695 Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx);
696 //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd);
697
698 if ( bXcpt != X86_XCPT_PF
699 || (fPageLevel && off >= X86_PAGE_SIZE * 2)
700 || (fPageLevel && off <= X86_PAGE_SIZE - pThis->cbAccess) )
701 {
702 pThis->ExpectCtx.rax.u = uExpectedRax;
703 pThis->ExpectCtx.rflags.u32 = uExpectedFlags;
704 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->CmpXchg.offUd2, bXcpt, 0 /*uErrCd*/);
705 if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored)
706 Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64",
707 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored);
708 }
709 else
710 {
711 pThis->ExpectCtx.rax.u = uRaxIn;
712 pThis->ExpectCtx.rflags = pCtx->rflags;
713 if (off < X86_PAGE_SIZE)
714 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + X86_PAGE_SIZE;
715 else
716 pThis->ExpectCtx.cr2.u = (uintptr_t)pThis->pbTest + off;
717 bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd);
718 pThis->ExpectCtx.cr2 = pCtx->cr2;
719 if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped)
720 Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64",
721 g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped);
722 }
723 }
724 }
725
726 pCtx->rax.u = uRaxSaved;
727 pCtx->rcx.u = uRcxSaved;
728}
729
730
731/**
732 * Worker for bs3CpuBasic2_RaiseXcpt0e_c32 that does the actual testing.
733 *
734 * Caller does all the cleaning up.
735 *
736 * @returns Error count.
737 * @param pThis Test state data.
738 */
739static uint8_t bs3CpuBasic2_RaiseXcpt0eWorker(PBS3CPUBASIC2PFSTATE register pThis)
740{
741 unsigned iRing;
742 BS3REGCTX aCtxts[4];
743
744 /** @todo figure out V8086 testing. */
745 if ((pThis->bMode & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86)
746 return BS3TESTDOMODE_SKIPPED;
747
748
749 /* paranoia: Touch the various big stack structures to ensure the compiler has allocated stack for them. */
750 for (iRing = 0; iRing < RT_ELEMENTS(aCtxts); iRing++)
751 Bs3MemZero(&aCtxts[iRing], sizeof(aCtxts[iRing]));
752
753 /*
754 * Set up a few contexts for testing this stuff.
755 */
756 Bs3RegCtxSaveEx(&aCtxts[0], pThis->bMode, 2048);
757 for (iRing = 1; iRing < 4; iRing++)
758 {
759 aCtxts[iRing] = aCtxts[0];
760 Bs3RegCtxConvertToRingX(&aCtxts[iRing], iRing);
761 }
762
763 if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode))
764 {
765 for (iRing = 0; iRing < 4; iRing++)
766 aCtxts[iRing].rbx.u = (uintptr_t)pThis->pbTest;
767 }
768 else
769 {
770 for (iRing = 0; iRing < 4; iRing++)
771 {
772 aCtxts[iRing].ds = pThis->uSel16TestData;
773 aCtxts[iRing].rbx.u = 0;
774 }
775 }
776
777 /*
778 * Check basic operation:
779 */
780 for (iRing = 0; iRing < 4; iRing++)
781 {
782 /* 1. we can execute the test page. */
783 bs3CpuBasic2Pf_DoExec(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
784 /* 2. we can read from the test page. */
785 bs3CpuBasic2Pf_DoMovLoad(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
786 /* 3. we can write to the test page. */
787 bs3CpuBasic2Pf_DoMovStore(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
788 /* 4. we can do locked read+write (a few variants). */
789 bs3CpuBasic2Pf_DoXchg(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/);
790 bs3CpuBasic2Pf_DoCmpXchg(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/, false /*fMissmatch*/);
791 bs3CpuBasic2Pf_DoCmpXchg(pThis, &aCtxts[iRing], X86_XCPT_UD, UINT8_MAX, true /*fPageLevel*/, true /*fMissmatch*/);
792 }
793
794 /*
795 * Check the U bit on PTE level.
796 */
797
798
799 return 0;
800}
801
802
803BS3_DECL_CALLBACK(uint8_t) bs3CpuBasic2_RaiseXcpt0e_c32(uint8_t bMode)
804{
805 void *pvTestUnaligned;
806 uint32_t cbTestUnaligned = _8M;
807 uint8_t bRet = 1;
808 int rc;
809 BS3CPUBASIC2PFSTATE State;
810
811 /*
812 * Initalize the state data.
813 */
814 Bs3MemZero(&State, sizeof(State));
815 State.bMode = bMode;
816 switch (bMode & BS3_MODE_CODE_MASK)
817 {
818 case BS3_MODE_CODE_16: State.cbAccess = sizeof(uint16_t); break;
819 case BS3_MODE_CODE_V86: State.cbAccess = sizeof(uint16_t); break;
820 case BS3_MODE_CODE_32: State.cbAccess = sizeof(uint32_t); break;
821 case BS3_MODE_CODE_64: State.cbAccess = sizeof(uint64_t); break;
822 }
823 State.pCmnMode = &g_aCmnModes[0];
824 while (State.pCmnMode->bMode != (bMode & BS3_MODE_CODE_MASK))
825 State.pCmnMode++;
826 State.fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486;
827
828 /*
829 * Allocate a some memory we can play around with, then carve a size aligned
830 * chunk out of it so we might be able to maybe play with 2/4MB pages too.
831 */
832 cbTestUnaligned = _8M * 2;
833 while ((pvTestUnaligned = Bs3MemAlloc(BS3MEMKIND_FLAT32, cbTestUnaligned)) == NULL)
834 {
835 cbTestUnaligned >>= 1;
836 if (cbTestUnaligned <= _8K)
837 {
838 Bs3TestFailed("Failed to allocate memory to play around with\n");
839 return 1;
840 }
841 }
842
843 if ((uintptr_t)pvTestUnaligned & (cbTestUnaligned - 1))
844 {
845 State.cbTest = cbTestUnaligned >> 1;
846 State.pbOrgTest = (uint8_t *)(((uintptr_t)pvTestUnaligned + State.cbTest - 1) & ~(State.cbTest - 1));
847 }
848 else
849 {
850 State.pbOrgTest = pvTestUnaligned;
851 State.cbTest = cbTestUnaligned;
852 }
853
854 /*
855 * Alias this memory far away from where our code and data lives.
856 */
857 State.pbTest = (uint8_t *)UINT32_C(0x80000000);
858 rc = Bs3PagingAlias((uintptr_t)State.pbTest, (uintptr_t)State.pbOrgTest, State.cbTest, X86_PTE_P | X86_PTE_RW | X86_PTE_US);
859 if (RT_SUCCESS(rc))
860 {
861 rc = Bs3PagingQueryAddressInfo((uintptr_t)State.pbTest, &State.PgInfo);
862 if (RT_SUCCESS(rc))
863 {
864 /*
865 * Setup a 16-bit selector for accessing the alias.
866 */
867 Bs3SelSetup16BitData(&Bs3GdteSpare00, (uintptr_t)State.pbTest);
868 State.uSel16TestData = BS3_SEL_SPARE_00 | 3;
869
870 //Bs3TestPrintf("RaiseXcpt0e_c32: bMode=%#x/%#x cbTest=%#x pbTest=%p pbAlias=%p\n",
871 // bMode, g_bBs3CurrentMode, cbTest, pbTest, pbAlias);
872
873 bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State);
874 }
875 else
876 Bs3TestFailedF("Bs3PagingQueryAddressInfo failed: %d\n", rc);
877 Bs3PagingUnalias((uintptr_t)State.pbTest, State.cbTest);
878 }
879 else
880 Bs3TestFailedF("Bs3PagingAlias failed! rc=%d\n", rc);
881 Bs3MemFree(pvTestUnaligned, cbTestUnaligned);
882 return bRet;
883}
884
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