VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-x0.c@ 106215

Last change on this file since 106215 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.6 KB
Line 
1/* $Id: bs3-cpu-weird-1-x0.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-weird-2, C test driver code (16-bit).
4 */
5
6/*
7 * Copyright (C) 2007-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define BS3_USE_X0_TEXT_SEG
42#include <bs3kit.h>
43#include <bs3-cmn-memory.h>
44#include <iprt/asm.h>
45#include <iprt/asm-amd64-x86.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51#undef CHECK_MEMBER
52#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \
53 do \
54 { \
55 if ((a_Actual) == (a_Expected)) { /* likely */ } \
56 else bs3CpuWeird1_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \
57 } while (0)
58
59#define BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(a_Name, a_Label) \
60 extern FNBS3FAR a_Name##_c16, a_Name##_##a_Label##_c16; \
61 extern FNBS3FAR a_Name##_c32, a_Name##_##a_Label##_c32; \
62 extern FNBS3FAR a_Name##_c64, a_Name##_##a_Label##_c64
63
64#define PROTO_ALL(a_Template) \
65 extern FNBS3FAR a_Template ## _c16, \
66 a_Template ## _c32, \
67 a_Template ## _c64
68
69#define PROTO_ALL_WITH_END(a_Template) \
70 extern FNBS3FAR a_Template ## _c16, a_Template ## _c16_EndProc, \
71 a_Template ## _c32, a_Template ## _c32_EndProc, \
72 a_Template ## _c64, a_Template ## _c64_EndProc
73
74
75/*********************************************************************************************************************************
76* External Symbols *
77*********************************************************************************************************************************/
78BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedMovSsInt80, int80);
79BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedPopSsInt80, int80);
80
81BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedMovSsInt3, int3);
82BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedPopSsInt3, int3);
83
84BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedMovSsBp, int3);
85BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedPopSsBp, int3);
86
87BS3_CPU_WEIRD_1_EXTERN_ASM_FN_VARS(bs3CpuWeird1_InhibitedMovSsSyscall, syscall);
88
89
90/*********************************************************************************************************************************
91* Global Variables *
92*********************************************************************************************************************************/
93static const char BS3_FAR *g_pszTestMode = (const char *)1;
94static BS3CPUVENDOR g_enmCpuVendor = BS3CPUVENDOR_INTEL;
95static bool g_fVME = false;
96//static uint8_t g_bTestMode = 1;
97//static bool g_f16BitSys = 1;
98
99
100
101/**
102 * Sets globals according to the mode.
103 *
104 * @param bTestMode The test mode.
105 */
106static void bs3CpuWeird1_SetGlobals(uint8_t bTestMode)
107{
108// g_bTestMode = bTestMode;
109 g_pszTestMode = Bs3GetModeName(bTestMode);
110// g_f16BitSys = BS3_MODE_IS_16BIT_SYS(bTestMode);
111 g_usBs3TestStep = 0;
112 g_enmCpuVendor = Bs3GetCpuVendor();
113 g_fVME = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486
114 && (Bs3RegGetCr4() & X86_CR4_VME);
115}
116
117
118/**
119 * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep
120 * and g_pszTestMode.
121 */
122static void bs3CpuWeird1_FailedF(const char *pszFormat, ...)
123{
124 va_list va;
125
126 char szTmp[168];
127 va_start(va, pszFormat);
128 Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va);
129 va_end(va);
130
131 Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp);
132}
133
134
135/**
136 * Compares interrupt stuff.
137 */
138static void bs3CpuWeird1_CompareDbgInhibitRingXfer(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt,
139 int8_t cbPcAdjust, int8_t cbSpAdjust, uint32_t uDr6Expected,
140 uint8_t cbIretFrame, uint64_t uHandlerRsp)
141{
142 uint32_t uDr6 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386 ? Bs3RegGetDr6() : X86_DR6_INIT_VAL;
143 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
144 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
145 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
146 CHECK_MEMBER("cbIretFrame", "%#04x", pTrapCtx->cbIretFrame, cbIretFrame);
147 CHECK_MEMBER("uHandlerRsp", "%#06RX64", pTrapCtx->uHandlerRsp, uHandlerRsp);
148 if (uDr6 != uDr6Expected)
149 bs3CpuWeird1_FailedF("dr6=%#010RX32 expected %#010RX32", uDr6, uDr6Expected);
150 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbPcAdjust, cbSpAdjust, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
151 if (Bs3TestSubErrorCount() != cErrorsBefore)
152 {
153 Bs3TrapPrintFrame(pTrapCtx);
154 Bs3TestPrintf("DR6=%#RX32; Handler: CS=%04RX16 SS:ESP=%04RX16:%08RX64 EFL=%RX64 cbIret=%#x\n",
155 uDr6, pTrapCtx->uHandlerCs, pTrapCtx->uHandlerSs, pTrapCtx->uHandlerRsp,
156 pTrapCtx->fHandlerRfl, pTrapCtx->cbIretFrame);
157#if 0
158 Bs3TestPrintf("Halting in CompareIntCtx: bXcpt=%#x\n", bXcpt);
159 ASMHalt();
160#endif
161 }
162}
163
164static uint64_t bs3CpuWeird1_GetTrapHandlerEIP(uint8_t bXcpt, uint8_t bMode, bool fV86)
165{
166 if ( BS3_MODE_IS_RM_SYS(bMode)
167 || (fV86 && BS3_MODE_IS_V86(bMode)))
168 {
169 PRTFAR16 paIvt = (PRTFAR16)Bs3XptrFlatToCurrent(0);
170 return paIvt[bXcpt].off;
171 }
172 if (BS3_MODE_IS_16BIT_SYS(bMode))
173 return Bs3Idt16[bXcpt].Gate.u16OffsetLow;
174 if (BS3_MODE_IS_32BIT_SYS(bMode))
175 return RT_MAKE_U32(Bs3Idt32[bXcpt].Gate.u16OffsetLow, Bs3Idt32[bXcpt].Gate.u16OffsetHigh);
176 return RT_MAKE_U64(RT_MAKE_U32(Bs3Idt64[bXcpt].Gate.u16OffsetLow, Bs3Idt32[bXcpt].Gate.u16OffsetHigh),
177 Bs3Idt64[bXcpt].Gate.u32OffsetTop);
178}
179
180
181static void bs3RegCtxScramble(PBS3REGCTX pCtx, uint8_t bTestMode)
182{
183 if (BS3_MODE_IS_64BIT_SYS(bTestMode))
184 {
185 pCtx->r8.au32[0] ^= UINT32_C(0x2f460cb9);
186 pCtx->r8.au32[1] ^= UINT32_C(0x2dc346ff);
187 pCtx->r9.au32[0] ^= UINT32_C(0x9c50d12e);
188 pCtx->r9.au32[1] ^= UINT32_C(0x60be8859);
189 pCtx->r10.au32[0] ^= UINT32_C(0xa45fbe73);
190 pCtx->r10.au32[1] ^= UINT32_C(0x094140bf);
191 pCtx->r11.au32[0] ^= UINT32_C(0x8200148b);
192 pCtx->r11.au32[1] ^= UINT32_C(0x95dfc457);
193 pCtx->r12.au32[0] ^= UINT32_C(0xabc885f6);
194 pCtx->r12.au32[1] ^= UINT32_C(0xb9af126a);
195 pCtx->r13.au32[0] ^= UINT32_C(0xa2c4435c);
196 pCtx->r13.au32[1] ^= UINT32_C(0x1692b52e);
197 pCtx->r14.au32[0] ^= UINT32_C(0x85a56477);
198 pCtx->r14.au32[1] ^= UINT32_C(0x31a44a04);
199 pCtx->r15.au32[0] ^= UINT32_C(0x8d5b3072);
200 pCtx->r15.au32[1] ^= UINT32_C(0xc2ffce37);
201 }
202}
203
204
205typedef enum {
206 DbgInhibitRingXferType_SoftInt,
207 DbgInhibitRingXferType_Syscall
208} DBGINHIBITRINGXFERTYPE;
209
210static int bs3CpuWeird1_DbgInhibitRingXfer_Worker(uint8_t bTestMode, uint8_t bIntGate, uint8_t cbRingInstr, int8_t cbSpAdjust,
211 FPFNBS3FAR pfnTestCode, FPFNBS3FAR pfnTestLabel, DBGINHIBITRINGXFERTYPE enmType)
212{
213 BS3REGCTX Ctx;
214 BS3TRAPFRAME TrapCtx;
215 BS3TRAPFRAME TrapExpectXfer; /* Expected registers after transfer (no #DB). */
216 BS3TRAPFRAME TrapExpectXferDb; /* Expected registers after transfer followed by some #DB. */
217 uint8_t bSavedDpl;
218 uint8_t const offTestLabel = BS3_FP_OFF(pfnTestLabel) - BS3_FP_OFF(pfnTestCode);
219 uint8_t const cbIretFrameSame = BS3_MODE_IS_16BIT_SYS(bTestMode) ? 6
220 : BS3_MODE_IS_32BIT_SYS(bTestMode) ? 12 : 40;
221 uint8_t const cbIretFrameRing = BS3_MODE_IS_16BIT_SYS(bTestMode) ? 10
222 : BS3_MODE_IS_32BIT_SYS(bTestMode) ? 20 : 40;
223 uint8_t const cbSpAdjSame = BS3_MODE_IS_64BIT_SYS(bTestMode) ? 48 : cbIretFrameSame;
224 bool const fAlwaysUd = enmType == DbgInhibitRingXferType_Syscall && bTestMode != BS3_MODE_LM64;
225 uint8_t bVmeMethod = 0;
226 uint8_t cbIretFrameDb; /* #DB before xfer */
227 uint64_t uHandlerRspDb; /* #DB before xfer */
228 BS3_XPTR_AUTO(uint32_t, StackXptr);
229
230 if (fAlwaysUd)
231 bIntGate = X86_XCPT_UD;
232
233 /* make sure they're allocated */
234 Bs3MemZero(&Ctx, sizeof(Ctx));
235 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
236 Bs3MemZero(&TrapExpectXfer, sizeof(TrapExpectXfer));
237 Bs3MemZero(&TrapExpectXferDb, sizeof(TrapExpectXferDb));
238
239 /*
240 * Make INT xx accessible from DPL 3 and create a ring-3 context that we can work with.
241 */
242 bSavedDpl = Bs3TrapSetDpl(bIntGate, 3);
243
244 Bs3RegCtxSaveEx(&Ctx, bTestMode, 1024);
245 bs3RegCtxScramble(&Ctx, bTestMode);
246 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pfnTestCode);
247 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
248 g_uBs3TrapEipHint = Ctx.rip.u32;
249 Ctx.rflags.u32 &= ~X86_EFL_RF;
250
251 /* Raw-mode enablers. */
252 Ctx.rflags.u32 |= X86_EFL_IF;
253 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
254 Ctx.cr0.u32 |= X86_CR0_WP;
255
256 /* We put the SS value on the stack so we can easily set breakpoints there. */
257 Ctx.rsp.u32 -= 8;
258 BS3_XPTR_SET_FLAT(uint32_t, StackXptr, Ctx.rsp.u32); /* ASSUMES SS.BASE == 0!! */
259
260 /* ring-3 */
261 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
262 Bs3RegCtxConvertToRingX(&Ctx, 3);
263
264 /* V8086: Set IOPL to 3. */
265 if (BS3_MODE_IS_V86(bTestMode) && enmType != DbgInhibitRingXferType_Syscall)
266 {
267 Ctx.rflags.u32 |= X86_EFL_IOPL;
268 if (g_fVME)
269 {
270 Bs3RegSetTr(BS3_SEL_TSS32_IRB);
271#if 0
272 /* SDMv3b, 20.3.3 method 5: */
273 ASMBitClear(&Bs3SharedIntRedirBm, bIntGate);
274 bVmeMethod = 5;
275#else
276 /* SDMv3b, 20.3.3 method 4 (similar to non-VME): */
277 ASMBitSet(&Bs3SharedIntRedirBm, bIntGate);
278 bVmeMethod = 4;
279 }
280#endif
281 }
282
283 /* Make BP = SP since 16-bit can't use SP for addressing. */
284 Ctx.rbp = Ctx.rsp;
285
286 /*
287 * Test #0: Test run. Calc expected delayed #DB from it.
288 */
289 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
290 {
291 Bs3RegSetDr7(0);
292 Bs3RegSetDr6(X86_DR6_INIT_VAL);
293 }
294 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
295 Bs3TrapSetJmpAndRestore(&Ctx, &TrapExpectXfer);
296 if (TrapExpectXfer.bXcpt != bIntGate)
297 {
298 Bs3TestFailedF("%u: bXcpt is %#x, expected %#x!\n", g_usBs3TestStep, TrapExpectXfer.bXcpt, bIntGate);
299 Bs3TrapPrintFrame(&TrapExpectXfer);
300 return 1;
301 }
302 Bs3MemCpy(&TrapExpectXferDb, &TrapExpectXfer, sizeof(TrapExpectXferDb));
303
304 if (!fAlwaysUd)
305 {
306 TrapExpectXferDb.Ctx.bCpl = 0;
307 TrapExpectXferDb.Ctx.cs = TrapExpectXfer.uHandlerCs;
308 TrapExpectXferDb.Ctx.ss = TrapExpectXfer.uHandlerSs;
309 TrapExpectXferDb.Ctx.rsp.u64 = TrapExpectXfer.uHandlerRsp;
310 TrapExpectXferDb.Ctx.rflags.u64 = TrapExpectXfer.fHandlerRfl;
311
312 if (enmType != DbgInhibitRingXferType_Syscall)
313 {
314 TrapExpectXferDb.cbIretFrame = TrapExpectXfer.cbIretFrame + cbIretFrameSame;
315 TrapExpectXferDb.uHandlerRsp = TrapExpectXfer.uHandlerRsp - cbSpAdjSame;
316 }
317 else
318 {
319 TrapExpectXfer.cbIretFrame = 0xff;
320 TrapExpectXferDb.cbIretFrame = cbIretFrameSame;
321 TrapExpectXfer.uHandlerRsp = Ctx.rsp.u - cbSpAdjust;
322 TrapExpectXferDb.uHandlerRsp = (TrapExpectXfer.uHandlerRsp & ~(uint64_t)15) - cbIretFrameSame;
323 }
324 if (BS3_MODE_IS_V86(bTestMode))
325 {
326 if (bVmeMethod >= 5)
327 {
328 TrapExpectXferDb.Ctx.rflags.u32 |= X86_EFL_VM;
329 TrapExpectXferDb.Ctx.bCpl = 3;
330 TrapExpectXferDb.Ctx.rip.u64 = bs3CpuWeird1_GetTrapHandlerEIP(bIntGate, bTestMode, true);
331 TrapExpectXferDb.cbIretFrame = 36;
332 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
333 TrapExpectXferDb.uHandlerRsp = Bs3Tss16.sp0 - TrapExpectXferDb.cbIretFrame;
334 else
335 TrapExpectXferDb.uHandlerRsp = Bs3Tss32.esp0 - TrapExpectXferDb.cbIretFrame;
336 }
337 else
338 {
339 TrapExpectXferDb.Ctx.ds = 0;
340 TrapExpectXferDb.Ctx.es = 0;
341 TrapExpectXferDb.Ctx.fs = 0;
342 TrapExpectXferDb.Ctx.gs = 0;
343 }
344 }
345 }
346
347 if (enmType != DbgInhibitRingXferType_Syscall)
348 {
349 cbIretFrameDb = TrapExpectXfer.cbIretFrame;
350 uHandlerRspDb = TrapExpectXfer.uHandlerRsp;
351 }
352 else
353 {
354 cbIretFrameDb = cbIretFrameRing;
355 uHandlerRspDb = BS3_ADDR_STACK_R0 - cbIretFrameRing;
356 }
357
358
359 /*
360 * Test #1: Single stepping ring-3. Ignored except for V8086 w/ VME.
361 */
362 g_usBs3TestStep++;
363 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
364 {
365 Bs3RegSetDr7(0);
366 Bs3RegSetDr6(X86_DR6_INIT_VAL);
367 }
368 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
369// Ctx.rflags.u32 |= X86_EFL_TF;
370
371 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
372 if ( !BS3_MODE_IS_V86(bTestMode)
373 || bVmeMethod < 5)
374 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, bIntGate, 0, 0, X86_DR6_INIT_VAL,
375 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
376 else
377 {
378 TrapExpectXferDb.Ctx.rflags.u32 |= X86_EFL_TF;
379 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXferDb.Ctx, X86_XCPT_DB, offTestLabel, -2,
380 X86_DR6_INIT_VAL | X86_DR6_BS,
381 TrapExpectXferDb.cbIretFrame, TrapExpectXferDb.uHandlerRsp);
382 TrapExpectXferDb.Ctx.rflags.u32 &= ~X86_EFL_TF;
383 }
384
385 Ctx.rflags.u32 &= ~X86_EFL_TF;
386 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
387 {
388 uint32_t uDr6Expect;
389
390 /*
391 * Test #2: Execution breakpoint on ring transition instruction.
392 * This hits on AMD-V (threadripper) but not on VT-x (skylake).
393 */
394 g_usBs3TestStep++;
395 Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestLabel));
396 Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE));
397 Bs3RegSetDr6(X86_DR6_INIT_VAL);
398 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
399
400 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
401 Bs3RegSetDr7(0);
402 if (g_enmCpuVendor == BS3CPUVENDOR_AMD || g_enmCpuVendor == BS3CPUVENDOR_HYGON)
403 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, offTestLabel, cbSpAdjust,
404 X86_DR6_INIT_VAL | X86_DR6_B0, TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
405 else
406 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, bIntGate, 0, 0, X86_DR6_INIT_VAL,
407 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
408
409 /*
410 * Test #3: Same as above, but with the LE and GE flags set.
411 */
412 g_usBs3TestStep++;
413 Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestLabel));
414 Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_LE | X86_DR7_GE);
415 Bs3RegSetDr6(X86_DR6_INIT_VAL);
416 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
417
418 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
419 if (g_enmCpuVendor == BS3CPUVENDOR_AMD || g_enmCpuVendor == BS3CPUVENDOR_HYGON)
420 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, offTestLabel, cbSpAdjust,
421 X86_DR6_INIT_VAL | X86_DR6_B0, TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
422 else
423 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, bIntGate, 0, 0, X86_DR6_INIT_VAL,
424 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
425
426 /*
427 * Test #4: Execution breakpoint on pop ss / mov ss. Hits.
428 *
429 * Note! In real mode AMD-V updates the stack pointer, or something else is busted. Totally weird!
430 *
431 * Update: see Test #6 update.
432 */
433 g_usBs3TestStep++;
434 Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestCode));
435 Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE));
436 Bs3RegSetDr6(X86_DR6_INIT_VAL);
437 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
438
439 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
440 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, 0, 0, X86_DR6_INIT_VAL | X86_DR6_B0, cbIretFrameDb,
441 uHandlerRspDb - (BS3_MODE_IS_RM_SYS(bTestMode) ? cbSpAdjust : 0) );
442
443 /*
444 * Test #5: Same as above, but with the LE and GE flags set.
445 */
446 g_usBs3TestStep++;
447 Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestCode));
448 Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_LE | X86_DR7_GE);
449 Bs3RegSetDr6(X86_DR6_INIT_VAL);
450 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
451
452 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
453 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, 0, 0, X86_DR6_INIT_VAL | X86_DR6_B0, cbIretFrameDb,
454 uHandlerRspDb - (BS3_MODE_IS_RM_SYS(bTestMode) ? cbSpAdjust : 0) );
455 Bs3RegSetDr7(0);
456
457 /*
458 * Test #6: Data breakpoint on SS load. The #DB is delivered after ring transition. Weird!
459 *
460 * Note! Intel loses the B0 status, probably for reasons similar to Pentium Pro errata 3. Similar
461 * erratum is seen with virtually every march since, e.g. skylake SKL009 & SKL111.
462 * Weirdly enougth, they seem to get this right in real mode. Go figure.
463 *
464 * Update: In real mode there is no ring transition, so we'll be trampling on
465 * breakpoint again (POP SS changes SP) when the INT/whatever instruction writes
466 * the return address.
467 */
468 g_usBs3TestStep++;
469 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
470 Bs3RegSetDr0(BS3_XPTR_GET_FLAT(uint32_t, StackXptr));
471 Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_WORD));
472 Bs3RegSetDr6(X86_DR6_INIT_VAL);
473
474 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
475 Bs3RegSetDr7(0);
476 TrapExpectXferDb.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme
477 Bs3RegSetDr7(0);
478 uDr6Expect = X86_DR6_INIT_VAL | X86_DR6_B0;
479 if (g_enmCpuVendor == BS3CPUVENDOR_INTEL && (bTestMode != BS3_MODE_RM || cbSpAdjust == 0))
480 uDr6Expect = X86_DR6_INIT_VAL;
481 if (!fAlwaysUd)
482 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXferDb.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect,
483 cbIretFrameSame, TrapExpectXferDb.uHandlerRsp);
484 else
485 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, X86_XCPT_UD, 0, 0, uDr6Expect,
486 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
487
488 /*
489 * Test #7: Same as above, but with the LE and GE flags set.
490 */
491 g_usBs3TestStep++;
492 *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss;
493 Bs3RegSetDr0(BS3_XPTR_GET_FLAT(uint32_t, StackXptr));
494 Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_WORD) | X86_DR7_LE | X86_DR7_GE);
495 Bs3RegSetDr6(X86_DR6_INIT_VAL);
496
497 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
498 TrapExpectXferDb.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme
499 Bs3RegSetDr7(0);
500 uDr6Expect = X86_DR6_INIT_VAL | X86_DR6_B0;
501 if (g_enmCpuVendor == BS3CPUVENDOR_INTEL && (bTestMode != BS3_MODE_RM || cbSpAdjust == 0))
502 uDr6Expect = X86_DR6_INIT_VAL;
503 if (!fAlwaysUd)
504 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXferDb.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect,
505 cbIretFrameSame, TrapExpectXferDb.uHandlerRsp);
506 else
507 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, X86_XCPT_UD, 0, 0, uDr6Expect,
508 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
509
510 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
511 {
512 /*
513 * Test #8: Data breakpoint on SS GDT entry. Half weird!
514 * Note! Intel loses the B1 status, see test #6.
515 */
516 g_usBs3TestStep++;
517 *BS3_XPTR_GET(uint32_t, StackXptr) = (Ctx.ss & X86_SEL_RPL) | BS3_SEL_SPARE_00;
518 Bs3GdteSpare00 = Bs3Gdt[Ctx.ss / sizeof(Bs3Gdt[0])];
519
520 Bs3RegSetDr1(Bs3SelPtrToFlat(&Bs3GdteSpare00));
521 Bs3RegSetDr7(X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW(1, X86_DR7_RW_RW) | X86_DR7_LEN(1, X86_DR7_LEN_DWORD));
522 Bs3RegSetDr6(X86_DR6_INIT_VAL);
523
524 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
525 TrapExpectXferDb.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme
526 Bs3RegSetDr7(0);
527 uDr6Expect = g_enmCpuVendor == BS3CPUVENDOR_INTEL ? X86_DR6_INIT_VAL : X86_DR6_INIT_VAL | X86_DR6_B1;
528 if (!fAlwaysUd)
529 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXferDb.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect,
530 cbIretFrameSame, TrapExpectXferDb.uHandlerRsp);
531 else
532 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, X86_XCPT_UD, 0, 0, uDr6Expect,
533 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
534
535 /*
536 * Test #9: Same as above, but with the LE and GE flags set.
537 */
538 g_usBs3TestStep++;
539 *BS3_XPTR_GET(uint32_t, StackXptr) = (Ctx.ss & X86_SEL_RPL) | BS3_SEL_SPARE_00;
540 Bs3GdteSpare00 = Bs3Gdt[Ctx.ss / sizeof(Bs3Gdt[0])];
541
542 Bs3RegSetDr1(Bs3SelPtrToFlat(&Bs3GdteSpare00));
543 Bs3RegSetDr7(X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW(1, X86_DR7_RW_RW) | X86_DR7_LEN(1, X86_DR7_LEN_DWORD) | X86_DR7_LE | X86_DR7_GE);
544 Bs3RegSetDr6(X86_DR6_INIT_VAL);
545
546 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
547 TrapExpectXferDb.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme
548 Bs3RegSetDr7(0);
549 uDr6Expect = g_enmCpuVendor == BS3CPUVENDOR_INTEL ? X86_DR6_INIT_VAL : X86_DR6_INIT_VAL | X86_DR6_B1;
550 if (!fAlwaysUd)
551 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXferDb.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect,
552 cbIretFrameSame, TrapExpectXferDb.uHandlerRsp);
553 else
554 bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpectXfer.Ctx, X86_XCPT_UD, 0, 0, uDr6Expect,
555 TrapExpectXfer.cbIretFrame, TrapExpectXfer.uHandlerRsp);
556 }
557
558 /*
559 * Cleanup.
560 */
561 Bs3RegSetDr0(0);
562 Bs3RegSetDr1(0);
563 Bs3RegSetDr2(0);
564 Bs3RegSetDr3(0);
565 Bs3RegSetDr6(X86_DR6_INIT_VAL);
566 Bs3RegSetDr7(0);
567 }
568 Bs3TrapSetDpl(bIntGate, bSavedDpl);
569 return 0;
570}
571
572
573BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuWeird1_DbgInhibitRingXfer)(uint8_t bMode)
574{
575 if (BS3_MODE_IS_V86(bMode))
576 switch (bMode)
577 {
578 /** @todo some busted stack stuff with the 16-bit guys. Also, if VME is
579 * enabled, we're probably not able to do any sensible testing. */
580 case BS3_MODE_PP16_V86:
581 case BS3_MODE_PE16_V86:
582 case BS3_MODE_PAE16_V86:
583 return BS3TESTDOMODE_SKIPPED;
584 }
585 //if (bMode != BS3_MODE_PE16_V86) return BS3TESTDOMODE_SKIPPED;
586 //if (bMode != BS3_MODE_PAEV86) return BS3TESTDOMODE_SKIPPED;
587
588 bs3CpuWeird1_SetGlobals(bMode);
589
590 /** @todo test sysenter and syscall too. */
591 /** @todo test INTO. */
592 /** @todo test all V8086 software INT delivery modes (currently only 4 and 1). */
593
594#define ASM_FN_ARGS(a_Name, a_Label, a_ModeSuff, a_Type) \
595 bs3CpuWeird1_##a_Name##_##a_ModeSuff, bs3CpuWeird1_##a_Name##_##a_Label##_##a_ModeSuff, DbgInhibitRingXferType_##a_Type
596
597 /* Note! Both ICEBP and BOUND has be checked cursorily and found not to be affected. */
598 if (BS3_MODE_IS_16BIT_CODE(bMode))
599 {
600 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 2, ASM_FN_ARGS(InhibitedPopSsInt80, int80, c16, SoftInt));
601 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 0, ASM_FN_ARGS(InhibitedMovSsInt80, int80, c16, SoftInt));
602 if (!BS3_MODE_IS_V86(bMode) || !g_fVME)
603 {
604 /** @todo explain why these GURU */
605 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 2, ASM_FN_ARGS(InhibitedPopSsInt3, int3, c16, SoftInt));
606 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 0, ASM_FN_ARGS(InhibitedMovSsInt3, int3, c16, SoftInt));
607 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 2, ASM_FN_ARGS(InhibitedPopSsBp, int3, c16, SoftInt));
608 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 0, ASM_FN_ARGS(InhibitedMovSsBp, int3, c16, SoftInt));
609 }
610 }
611 else if (BS3_MODE_IS_32BIT_CODE(bMode))
612 {
613 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 4, ASM_FN_ARGS(InhibitedPopSsInt80, int80, c32, SoftInt));
614 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 0, ASM_FN_ARGS(InhibitedMovSsInt80, int80, c32, SoftInt));
615 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 4, ASM_FN_ARGS(InhibitedPopSsInt3, int3, c32, SoftInt));
616 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 0, ASM_FN_ARGS(InhibitedMovSsInt3, int3, c32, SoftInt));
617 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 4, ASM_FN_ARGS(InhibitedPopSsBp, int3, c32, SoftInt));
618 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 0, ASM_FN_ARGS(InhibitedMovSsBp, int3, c32, SoftInt));
619 }
620 else
621 {
622 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 0, ASM_FN_ARGS(InhibitedMovSsInt80, int80, c64, SoftInt));
623 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 0, ASM_FN_ARGS(InhibitedMovSsInt3, int3, c64, SoftInt));
624 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 0, ASM_FN_ARGS(InhibitedMovSsBp, int3, c64, SoftInt));
625 }
626
627 /* On intel, syscall only works in long mode. */
628/** @todo test this on AMD and extend it to non-64-bit modes */
629 if (BS3_MODE_IS_64BIT_SYS(bMode))
630 {
631 uint64_t const fSavedEfer = ASMRdMsr(MSR_K6_EFER);
632 ASMWrMsr(MSR_K8_SF_MASK, X86_EFL_TF);
633 ASMWrMsr(MSR_K8_LSTAR, g_pfnBs3Syscall64GenericFlat);
634 ASMWrMsr(MSR_K8_CSTAR, g_pfnBs3Syscall64GenericCompatibilityFlat);
635 ASMWrMsr(MSR_K6_STAR, (uint64_t)BS3_SEL_R0_CS64 << MSR_K6_STAR_SYSCALL_CS_SS_SHIFT);
636 ASMWrMsr(MSR_K6_EFER, fSavedEfer | MSR_K6_EFER_SCE);
637
638 if (BS3_MODE_IS_16BIT_CODE(bMode))
639 {
640 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0xfe, 2, 0, ASM_FN_ARGS(InhibitedMovSsSyscall, syscall, c16, Syscall));
641 }
642 else if (BS3_MODE_IS_32BIT_CODE(bMode))
643 {
644 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0xfe, 2, 0, ASM_FN_ARGS(InhibitedMovSsSyscall, syscall, c32, Syscall));
645 }
646 else
647 {
648 bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0xff, 2, 0, ASM_FN_ARGS(InhibitedMovSsSyscall, syscall, c64, Syscall));
649 }
650
651 ASMWrMsr(MSR_K6_EFER, fSavedEfer);
652 ASMWrMsr(MSR_K6_STAR, 0);
653 ASMWrMsr(MSR_K8_LSTAR, 0);
654 ASMWrMsr(MSR_K8_CSTAR, 0);
655 ASMWrMsr(MSR_K8_SF_MASK, 0);
656 }
657
658 return 0;
659}
660
661
662/*********************************************************************************************************************************
663* IP / EIP Wrapping *
664*********************************************************************************************************************************/
665PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapBenign1);
666PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapBenign2);
667PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapCpuId);
668PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapIn80);
669PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapOut80);
670PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapSmsw);
671PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapRdCr0);
672PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapRdDr0);
673PROTO_ALL_WITH_END(bs3CpuWeird1_PcWrapWrDr0);
674
675typedef enum { kPcWrapSetup_None, kPcWrapSetup_ZeroRax } PCWRAPSETUP;
676
677/**
678 * Compares pc wraparound result.
679 */
680static uint8_t bs3CpuWeird1_ComparePcWrap(PCBS3TRAPFRAME pTrapCtx, PCBS3TRAPFRAME pTrapExpect)
681{
682 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
683 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, pTrapExpect->bXcpt);
684 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, pTrapExpect->uErrCd);
685 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, &pTrapExpect->Ctx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/,
686 g_pszTestMode, g_usBs3TestStep);
687 if (Bs3TestSubErrorCount() != cErrorsBefore)
688 {
689 Bs3TrapPrintFrame(pTrapCtx);
690 Bs3TestPrintf("CS=%04RX16 SS:ESP=%04RX16:%08RX64 EFL=%RX64 cbIret=%#x\n",
691 pTrapCtx->uHandlerCs, pTrapCtx->uHandlerSs, pTrapCtx->uHandlerRsp,
692 pTrapCtx->fHandlerRfl, pTrapCtx->cbIretFrame);
693#if 0
694 Bs3TestPrintf("Halting in ComparePcWrap: bXcpt=%#x\n", pTrapCtx->bXcpt);
695 ASMHalt();
696#endif
697 return 1;
698 }
699 return 0;
700}
701
702
703static uint8_t bs3CpuWeird1_PcWrapping_Worker16(uint8_t bMode, RTSEL SelCode, uint8_t BS3_FAR *pbHead,
704 uint8_t BS3_FAR *pbTail, uint8_t BS3_FAR *pbAfter,
705 void const BS3_FAR *pvTemplate, size_t cbTemplate, PCWRAPSETUP enmSetup)
706{
707 BS3TRAPFRAME TrapCtx;
708 BS3TRAPFRAME TrapExpect;
709 BS3REGCTX Ctx;
710 uint8_t bXcpt;
711
712 /* make sure they're allocated */
713 Bs3MemZero(&Ctx, sizeof(Ctx));
714 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
715 Bs3MemZero(&TrapExpect, sizeof(TrapExpect));
716
717 /*
718 * Create the expected result by first placing the code template
719 * at the start of the buffer and giving it a quick run.
720 *
721 * I cannot think of any instruction always causing #GP(0) right now, so
722 * we generate a ud2 and modify it instead.
723 */
724 Bs3MemCpy(pbHead, pvTemplate, cbTemplate);
725 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80286)
726 {
727 pbHead[cbTemplate] = 0xcc; /* int3 */
728 bXcpt = X86_XCPT_BP;
729 }
730 else
731 {
732 pbHead[cbTemplate] = 0x0f; /* ud2 */
733 pbHead[cbTemplate + 1] = 0x0b;
734 bXcpt = X86_XCPT_UD;
735 }
736
737 Bs3RegCtxSaveEx(&Ctx, bMode, 1024);
738
739 Ctx.cs = SelCode;
740 Ctx.rip.u = 0;
741 switch (enmSetup)
742 {
743 case kPcWrapSetup_None:
744 break;
745 case kPcWrapSetup_ZeroRax:
746 Ctx.rax.u = 0;
747 break;
748 }
749
750 /* V8086: Set IOPL to 3. */
751 if (BS3_MODE_IS_V86(bMode))
752 Ctx.rflags.u32 |= X86_EFL_IOPL;
753
754 Bs3TrapSetJmpAndRestore(&Ctx, &TrapExpect);
755 if (TrapExpect.bXcpt != bXcpt)
756 {
757
758 Bs3TestFailedF("%u: Setup: bXcpt is %#x, expected %#x!\n", g_usBs3TestStep, TrapExpect.bXcpt, bXcpt);
759 Bs3TrapPrintFrame(&TrapExpect);
760 return 1;
761 }
762
763 /*
764 * Adjust the contexts for the real test.
765 */
766 Ctx.cs = SelCode;
767 Ctx.rip.u = (uint32_t)_64K - cbTemplate;
768
769 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80286)
770 TrapExpect.Ctx.rip.u = 1;
771 else
772 {
773 if (BS3_MODE_IS_16BIT_SYS(bMode))
774 TrapExpect.Ctx.rip.u = 0;
775 else
776 TrapExpect.Ctx.rip.u = UINT32_C(0x10000);
777 TrapExpect.bXcpt = X86_XCPT_GP;
778 TrapExpect.uErrCd = 0;
779 }
780
781 /*
782 * Prepare the buffer for 16-bit wrap around.
783 */
784 Bs3MemSet(pbHead, 0xcc, 64); /* int3 */
785 if (bXcpt == X86_XCPT_UD)
786 {
787 pbHead[0] = 0x0f; /* ud2 */
788 pbHead[1] = 0x0b;
789 }
790 Bs3MemCpy(&pbTail[_4K - cbTemplate], pvTemplate, cbTemplate);
791 Bs3MemSet(pbAfter, 0xf1, 64); /* icebp / int1 */
792
793 /*
794 * Do a test run.
795 */
796 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
797 if (!bs3CpuWeird1_ComparePcWrap(&TrapCtx, &TrapExpect))
798 {
799#if 0 /* needs more work */
800 /*
801 * Slide the instruction template across the boundrary byte-by-byte and
802 * check that it triggers #GP on the initial instruction on 386+.
803 */
804 unsigned cbTail;
805 unsigned cbHead;
806 g_usBs3TestStep++;
807 for (cbTail = cbTemplate - 1, cbHead = 1; cbTail > 0; cbTail--, cbHead++, g_usBs3TestStep++)
808 {
809 pbTail[X86_PAGE_SIZE - cbTail - 1] = 0xcc;
810 Bs3MemCpy(&pbTail[X86_PAGE_SIZE - cbTail], pvTemplate, cbTail);
811 Bs3MemCpy(pbHead, &((uint8_t const *)pvTemplate)[cbTail], cbHead);
812 if (bXcpt == X86_XCPT_BP)
813 pbHead[cbHead] = 0xcc; /* int3 */
814 else
815 {
816 pbHead[cbHead] = 0x0f; /* ud2 */
817 pbHead[cbHead + 1] = 0x0b;
818 }
819
820 Ctx.rip.u = (uint32_t)_64K - cbTail;
821 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80286)
822 TrapExpect.Ctx.rip.u = cbHead + 1;
823 else
824 {
825 TrapExpect.Ctx.rip.u = Ctx.rip.u;
826 }
827
828 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
829 if (bs3CpuWeird1_ComparePcWrap(&TrapCtx, &TrapExpect))
830 return 1;
831 }
832#endif
833 }
834 return 0;
835}
836
837
838static uint8_t bs3CpuWeird1_PcWrapping_Worker32(uint8_t bMode, RTSEL SelCode, uint8_t BS3_FAR *pbPage1,
839 uint8_t BS3_FAR *pbPage2, uint32_t uFlatPage2,
840 void const BS3_FAR *pvTemplate, size_t cbTemplate, PCWRAPSETUP enmSetup)
841{
842 BS3TRAPFRAME TrapCtx;
843 BS3TRAPFRAME TrapExpect;
844 BS3REGCTX Ctx;
845 unsigned cbPage1;
846 unsigned cbPage2;
847
848 /* make sure they're allocated */
849 Bs3MemZero(&Ctx, sizeof(Ctx));
850 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
851 Bs3MemZero(&TrapExpect, sizeof(TrapExpect));
852
853 //Bs3TestPrintf("SelCode=%#x pbPage1=%p pbPage2=%p uFlatPage2=%RX32 pvTemplate=%p cbTemplate\n",
854 // SelCode, pbPage1, pbPage2, uFlatPage2, pvTemplate, cbTemplate);
855
856 /*
857 * Create the expected result by first placing the code template
858 * at the start of the buffer and giving it a quick run.
859 */
860 Bs3MemSet(pbPage1, 0xcc, _4K);
861 Bs3MemSet(pbPage2, 0xcc, _4K);
862 Bs3MemCpy(&pbPage1[_4K - cbTemplate], pvTemplate, cbTemplate);
863 pbPage2[0] = 0x0f; /* ud2 */
864 pbPage2[1] = 0x0b;
865
866 Bs3RegCtxSaveEx(&Ctx, bMode, 1024);
867
868 Ctx.cs = BS3_SEL_R0_CS32;
869 Ctx.rip.u = uFlatPage2 - cbTemplate;
870 switch (enmSetup)
871 {
872 case kPcWrapSetup_None:
873 break;
874 case kPcWrapSetup_ZeroRax:
875 Ctx.rax.u = 0;
876 break;
877 }
878
879 Bs3TrapSetJmpAndRestore(&Ctx, &TrapExpect);
880 if (TrapExpect.bXcpt != X86_XCPT_UD)
881 {
882
883 Bs3TestFailedF("%u: Setup: bXcpt is %#x, expected %#x!\n", g_usBs3TestStep, TrapExpect.bXcpt, X86_XCPT_UD);
884 Bs3TrapPrintFrame(&TrapExpect);
885 return 1;
886 }
887
888 /*
889 * The real test uses the special CS selector.
890 */
891 Ctx.cs = SelCode;
892 TrapExpect.Ctx.cs = SelCode;
893
894 /*
895 * Unlike 16-bit mode, the instruction may cross the wraparound boundary,
896 * so we test by advancing the template across byte-by-byte.
897 */
898 for (cbPage1 = cbTemplate, cbPage2 = 0; cbPage1 > 0; cbPage1--, cbPage2++, g_usBs3TestStep++)
899 {
900 pbPage1[X86_PAGE_SIZE - cbPage1 - 1] = 0xcc;
901 Bs3MemCpy(&pbPage1[X86_PAGE_SIZE - cbPage1], pvTemplate, cbPage1);
902 Bs3MemCpy(pbPage2, &((uint8_t const *)pvTemplate)[cbPage1], cbPage2);
903 pbPage2[cbPage2] = 0x0f; /* ud2 */
904 pbPage2[cbPage2 + 1] = 0x0b;
905
906 Ctx.rip.u = UINT32_MAX - cbPage1 + 1;
907 TrapExpect.Ctx.rip.u = cbPage2;
908
909 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
910 if (bs3CpuWeird1_ComparePcWrap(&TrapCtx, &TrapExpect))
911 return 1;
912 }
913 return 0;
914}
915
916
917static uint8_t bs3CpuWeird1_PcWrapping_Worker64(uint8_t bMode, uint8_t BS3_FAR *pbBuf, uint32_t uFlatBuf,
918 void const BS3_FAR *pvTemplate, size_t cbTemplate, PCWRAPSETUP enmSetup)
919{
920 uint8_t BS3_FAR * const pbPage1 = pbBuf; /* mapped at 0, 4G and 8G */
921 uint8_t BS3_FAR * const pbPage2 = &pbBuf[X86_PAGE_SIZE]; /* mapped at -4K, 4G-4K and 8G-4K. */
922 BS3TRAPFRAME TrapCtx;
923 BS3TRAPFRAME TrapExpect;
924 BS3REGCTX Ctx;
925 unsigned cbStart;
926 unsigned cbEnd;
927
928 /* make sure they're allocated */
929 Bs3MemZero(&Ctx, sizeof(Ctx));
930 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
931 Bs3MemZero(&TrapExpect, sizeof(TrapExpect));
932
933 /*
934 * Create the expected result by first placing the code template
935 * at the start of the buffer and giving it a quick run.
936 */
937 Bs3MemCpy(pbPage1, pvTemplate, cbTemplate);
938 pbPage1[cbTemplate] = 0x0f; /* ud2 */
939 pbPage1[cbTemplate + 1] = 0x0b;
940
941 Bs3RegCtxSaveEx(&Ctx, bMode, 1024);
942
943 Ctx.rip.u = uFlatBuf;
944 switch (enmSetup)
945 {
946 case kPcWrapSetup_None:
947 break;
948 case kPcWrapSetup_ZeroRax:
949 Ctx.rax.u = 0;
950 break;
951 }
952
953 Bs3TrapSetJmpAndRestore(&Ctx, &TrapExpect);
954 if (TrapExpect.bXcpt != X86_XCPT_UD)
955 {
956
957 Bs3TestFailedF("%u: Setup: bXcpt is %#x, expected %#x!\n", g_usBs3TestStep, TrapExpect.bXcpt, X86_XCPT_UD);
958 Bs3TrapPrintFrame(&TrapExpect);
959 return 1;
960 }
961
962 /*
963 * Unlike 16-bit mode, the instruction may cross the wraparound boundary,
964 * so we test by advancing the template across byte-by-byte.
965 *
966 * Page #1 is mapped at address zero and Page #2 as the last one.
967 */
968 Bs3MemSet(pbBuf, 0xf1, X86_PAGE_SIZE * 2);
969 for (cbStart = cbTemplate, cbEnd = 0; cbStart > 0; cbStart--, cbEnd++)
970 {
971 pbPage2[X86_PAGE_SIZE - cbStart - 1] = 0xf1;
972 Bs3MemCpy(&pbPage2[X86_PAGE_SIZE - cbStart], pvTemplate, cbStart);
973 Bs3MemCpy(pbPage1, &((uint8_t const *)pvTemplate)[cbStart], cbEnd);
974 pbPage1[cbEnd] = 0x0f; /* ud2 */
975 pbPage1[cbEnd + 1] = 0x0b;
976
977 Ctx.rip.u = UINT64_MAX - cbStart + 1;
978 TrapExpect.Ctx.rip.u = cbEnd;
979
980 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
981 if (bs3CpuWeird1_ComparePcWrap(&TrapCtx, &TrapExpect))
982 return 1;
983 g_usBs3TestStep++;
984
985 /* Also check that crossing 4G isn't buggered up in our code by
986 32-bit and 16-bit mode support.*/
987 Ctx.rip.u = _4G - cbStart;
988 TrapExpect.Ctx.rip.u = _4G + cbEnd;
989 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
990 if (bs3CpuWeird1_ComparePcWrap(&TrapCtx, &TrapExpect))
991 return 1;
992 g_usBs3TestStep++;
993
994 Ctx.rip.u = _4G*2 - cbStart;
995 TrapExpect.Ctx.rip.u = _4G*2 + cbEnd;
996 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
997 if (bs3CpuWeird1_ComparePcWrap(&TrapCtx, &TrapExpect))
998 return 1;
999 g_usBs3TestStep += 2;
1000 }
1001 return 0;
1002}
1003
1004
1005
1006BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuWeird1_PcWrapping)(uint8_t bMode)
1007{
1008 uint8_t bRet = 1;
1009 size_t i;
1010
1011 bs3CpuWeird1_SetGlobals(bMode);
1012
1013 if (BS3_MODE_IS_16BIT_CODE(bMode))
1014 {
1015 /*
1016 * For 16-bit testing, we need a 68 KB buffer.
1017 *
1018 * This is a little annoying to work with from 16-bit bit, so we use
1019 * separate pointers to each interesting bit of it.
1020 */
1021 /** @todo add api for doing this, so we don't need to include bs3-cmn-memory.h. */
1022 uint8_t BS3_FAR *pbBuf = (uint8_t BS3_FAR *)Bs3SlabAllocEx(&g_Bs3Mem4KLow.Core, 17 /*cPages*/, 0 /*fFlags*/);
1023 if (pbBuf != NULL)
1024 {
1025 uint32_t const uFlatBuf = Bs3SelPtrToFlat(pbBuf);
1026 uint8_t BS3_FAR *pbTail = Bs3XptrFlatToCurrent(uFlatBuf + 0x0f000);
1027 uint8_t BS3_FAR *pbAfter = Bs3XptrFlatToCurrent(uFlatBuf + UINT32_C(0x10000));
1028 RTSEL SelCode;
1029 uint32_t off;
1030 static struct { FPFNBS3FAR pfnStart, pfnEnd; PCWRAPSETUP enmSetup; unsigned fNoV86 : 1; }
1031 const s_aTemplates16[] =
1032 {
1033#define ENTRY16(a_Template, a_enmSetup, a_fNoV86) { a_Template ## _c16, a_Template ## _c16_EndProc, a_enmSetup, a_fNoV86 }
1034 ENTRY16(bs3CpuWeird1_PcWrapBenign1, kPcWrapSetup_None, 0),
1035 ENTRY16(bs3CpuWeird1_PcWrapBenign2, kPcWrapSetup_None, 0),
1036 ENTRY16(bs3CpuWeird1_PcWrapCpuId, kPcWrapSetup_ZeroRax, 0),
1037 ENTRY16(bs3CpuWeird1_PcWrapIn80, kPcWrapSetup_None, 0),
1038 ENTRY16(bs3CpuWeird1_PcWrapOut80, kPcWrapSetup_None, 0),
1039 ENTRY16(bs3CpuWeird1_PcWrapSmsw, kPcWrapSetup_None, 0),
1040 ENTRY16(bs3CpuWeird1_PcWrapRdCr0, kPcWrapSetup_None, 1),
1041 ENTRY16(bs3CpuWeird1_PcWrapRdDr0, kPcWrapSetup_None, 1),
1042 ENTRY16(bs3CpuWeird1_PcWrapWrDr0, kPcWrapSetup_ZeroRax, 1),
1043#undef ENTRY16
1044 };
1045
1046 /* Fill the buffer with int1 instructions: */
1047 for (off = 0; off < UINT32_C(0x11000); off += _4K)
1048 {
1049 uint8_t BS3_FAR *pbPage = Bs3XptrFlatToCurrent(uFlatBuf + off);
1050 Bs3MemSet(pbPage, 0xf1, _4K);
1051 }
1052
1053 /* Setup the CS for it. */
1054 SelCode = (uint16_t)(uFlatBuf >> 4);
1055 if (!BS3_MODE_IS_RM_OR_V86(bMode))
1056 {
1057 Bs3SelSetup16BitCode(&Bs3GdteSpare00, uFlatBuf, 0);
1058 SelCode = BS3_SEL_SPARE_00;
1059 }
1060
1061 /* Allow IN and OUT to port 80h from V8086 mode. */
1062 if (BS3_MODE_IS_V86(bMode))
1063 {
1064 Bs3RegSetTr(BS3_SEL_TSS32_IOBP_IRB);
1065 ASMBitClear(Bs3SharedIobp, 0x80);
1066 }
1067
1068 for (i = 0; i < RT_ELEMENTS(s_aTemplates16); i++)
1069 {
1070 if (!s_aTemplates16[i].fNoV86 || !BS3_MODE_IS_V86(bMode))
1071 bs3CpuWeird1_PcWrapping_Worker16(bMode, SelCode, pbBuf, pbTail, pbAfter, s_aTemplates16[i].pfnStart,
1072 (uintptr_t)s_aTemplates16[i].pfnEnd - (uintptr_t)s_aTemplates16[i].pfnStart,
1073 s_aTemplates16[i].enmSetup);
1074 g_usBs3TestStep = i * 256;
1075 }
1076
1077 if (BS3_MODE_IS_V86(bMode))
1078 ASMBitSet(Bs3SharedIobp, 0x80);
1079
1080 Bs3SlabFree(&g_Bs3Mem4KLow.Core, uFlatBuf, 17);
1081
1082 bRet = 0;
1083 }
1084 else
1085 Bs3TestFailed("Failed to allocate 17 pages (68KB)");
1086 }
1087 else
1088 {
1089 /*
1090 * For 32-bit and 64-bit mode we just need two pages.
1091 */
1092 size_t const cbBuf = X86_PAGE_SIZE * 2;
1093 uint8_t BS3_FAR *pbBuf = (uint8_t BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, cbBuf);
1094 if (pbBuf)
1095 {
1096 uint32_t const uFlatBuf = Bs3SelPtrToFlat(pbBuf);
1097 Bs3MemSet(pbBuf, 0xf1, cbBuf);
1098
1099 /*
1100 * For 32-bit we set up a CS that starts with the 2nd page and
1101 * ends with the first.
1102 */
1103 if (BS3_MODE_IS_32BIT_CODE(bMode))
1104 {
1105 static struct { FPFNBS3FAR pfnStart, pfnEnd; PCWRAPSETUP enmSetup; } const s_aTemplates32[] =
1106 {
1107#define ENTRY32(a_Template, a_enmSetup) { a_Template ## _c32, a_Template ## _c32_EndProc, a_enmSetup }
1108 ENTRY32(bs3CpuWeird1_PcWrapBenign1, kPcWrapSetup_None),
1109 ENTRY32(bs3CpuWeird1_PcWrapBenign2, kPcWrapSetup_None),
1110 ENTRY32(bs3CpuWeird1_PcWrapCpuId, kPcWrapSetup_ZeroRax),
1111 ENTRY32(bs3CpuWeird1_PcWrapIn80, kPcWrapSetup_None),
1112 ENTRY32(bs3CpuWeird1_PcWrapOut80, kPcWrapSetup_None),
1113 ENTRY32(bs3CpuWeird1_PcWrapSmsw, kPcWrapSetup_None),
1114 ENTRY32(bs3CpuWeird1_PcWrapRdCr0, kPcWrapSetup_None),
1115 ENTRY32(bs3CpuWeird1_PcWrapRdDr0, kPcWrapSetup_None),
1116 ENTRY32(bs3CpuWeird1_PcWrapWrDr0, kPcWrapSetup_ZeroRax),
1117#undef ENTRY32
1118 };
1119
1120 Bs3SelSetup32BitCode(&Bs3GdteSpare00, uFlatBuf + X86_PAGE_SIZE, UINT32_MAX, 0);
1121
1122 for (i = 0; i < RT_ELEMENTS(s_aTemplates32); i++)
1123 {
1124 //Bs3TestPrintf("pfnStart=%p pfnEnd=%p\n", s_aTemplates32[i].pfnStart, s_aTemplates32[i].pfnEnd);
1125 bs3CpuWeird1_PcWrapping_Worker32(bMode, BS3_SEL_SPARE_00, pbBuf, &pbBuf[X86_PAGE_SIZE],
1126 uFlatBuf + X86_PAGE_SIZE, Bs3SelLnkPtrToCurPtr(s_aTemplates32[i].pfnStart),
1127 (uintptr_t)s_aTemplates32[i].pfnEnd - (uintptr_t)s_aTemplates32[i].pfnStart,
1128 s_aTemplates32[i].enmSetup);
1129 g_usBs3TestStep = i * 256;
1130 }
1131
1132 bRet = 0;
1133 }
1134 /*
1135 * For 64-bit we have to alias the two buffer pages to the first and
1136 * last page in the address space. To test that the 32-bit 4G rollover
1137 * isn't incorrectly applied to LM64, we repeat this mapping for the
1138 * 4G and 8G boundaries too.
1139 *
1140 * This ASSUMES there is nothing important in page 0 when in LM64.
1141 */
1142 else
1143 {
1144 static const struct { uint64_t uDst; uint16_t off; } s_aMappings[] =
1145 {
1146 { UINT64_MAX - X86_PAGE_SIZE + 1, X86_PAGE_SIZE * 1 },
1147 { UINT64_C(0), X86_PAGE_SIZE * 0 },
1148#if 1 /* technically not required as we just repeat the same 4G address space in long mode: */
1149 { _4G - X86_PAGE_SIZE, X86_PAGE_SIZE * 1 },
1150 { _4G, X86_PAGE_SIZE * 0 },
1151 { _4G*2 - X86_PAGE_SIZE, X86_PAGE_SIZE * 1 },
1152 { _4G*2, X86_PAGE_SIZE * 0 },
1153#endif
1154 };
1155 int rc = VINF_SUCCESS;
1156 unsigned iMap;
1157 BS3_ASSERT(bMode == BS3_MODE_LM64);
1158 for (iMap = 0; iMap < RT_ELEMENTS(s_aMappings) && RT_SUCCESS(rc); iMap++)
1159 {
1160 rc = Bs3PagingAlias(s_aMappings[iMap].uDst, uFlatBuf + s_aMappings[iMap].off, X86_PAGE_SIZE,
1161 X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW);
1162 if (RT_FAILURE(rc))
1163 Bs3TestFailedF("Bs3PagingAlias(%#RX64,...) failed: %d", s_aMappings[iMap].uDst, rc);
1164 }
1165
1166 if (RT_SUCCESS(rc))
1167 {
1168 static struct { FPFNBS3FAR pfnStart, pfnEnd; PCWRAPSETUP enmSetup; } const s_aTemplates64[] =
1169 {
1170#define ENTRY64(a_Template, a_enmSetup) { a_Template ## _c64, a_Template ## _c64_EndProc, a_enmSetup }
1171 ENTRY64(bs3CpuWeird1_PcWrapBenign1, kPcWrapSetup_None),
1172 ENTRY64(bs3CpuWeird1_PcWrapBenign2, kPcWrapSetup_None),
1173 ENTRY64(bs3CpuWeird1_PcWrapCpuId, kPcWrapSetup_ZeroRax),
1174 ENTRY64(bs3CpuWeird1_PcWrapIn80, kPcWrapSetup_None),
1175 ENTRY64(bs3CpuWeird1_PcWrapOut80, kPcWrapSetup_None),
1176 ENTRY64(bs3CpuWeird1_PcWrapSmsw, kPcWrapSetup_None),
1177 ENTRY64(bs3CpuWeird1_PcWrapRdCr0, kPcWrapSetup_None),
1178 ENTRY64(bs3CpuWeird1_PcWrapRdDr0, kPcWrapSetup_None),
1179 ENTRY64(bs3CpuWeird1_PcWrapWrDr0, kPcWrapSetup_ZeroRax),
1180#undef ENTRY64
1181 };
1182
1183 for (i = 0; i < RT_ELEMENTS(s_aTemplates64); i++)
1184 {
1185 bs3CpuWeird1_PcWrapping_Worker64(bMode, pbBuf, uFlatBuf,
1186 Bs3SelLnkPtrToCurPtr(s_aTemplates64[i].pfnStart),
1187 (uintptr_t)s_aTemplates64[i].pfnEnd
1188 - (uintptr_t)s_aTemplates64[i].pfnStart,
1189 s_aTemplates64[i].enmSetup);
1190 g_usBs3TestStep = i * 256;
1191 }
1192
1193 bRet = 0;
1194
1195 Bs3PagingUnalias(UINT64_C(0), X86_PAGE_SIZE);
1196 }
1197
1198 while (iMap-- > 0)
1199 Bs3PagingUnalias(s_aMappings[iMap].uDst, X86_PAGE_SIZE);
1200 }
1201 Bs3MemFree(pbBuf, cbBuf);
1202 }
1203 else
1204 Bs3TestFailed("Failed to allocate 2-3 pages for tests.");
1205 }
1206
1207 return bRet;
1208}
1209
1210
1211/*********************************************************************************************************************************
1212* PUSH / POP *
1213*********************************************************************************************************************************/
1214PROTO_ALL(bs3CpuWeird1_Push_xSP_Ud2);
1215PROTO_ALL(bs3CpuWeird1_Push_opsize_xSP_Ud2);
1216PROTO_ALL(bs3CpuWeird1_Push_opsize_xBX_Ud2);
1217PROTO_ALL(bs3CpuWeird1_Pop_xSP_Ud2);
1218PROTO_ALL(bs3CpuWeird1_Pop_opsize_xSP_Ud2);
1219PROTO_ALL(bs3CpuWeird1_Pop_opsize_xBX_Ud2);
1220
1221
1222/**
1223 * Compares push/pop result.
1224 */
1225static uint8_t bs3CpuWeird1_ComparePushPop(PCBS3TRAPFRAME pTrapCtx, PCBS3TRAPFRAME pTrapExpect)
1226{
1227 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
1228 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, pTrapExpect->bXcpt);
1229 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, pTrapExpect->uErrCd);
1230 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, &pTrapExpect->Ctx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/,
1231 g_pszTestMode, g_usBs3TestStep);
1232 if (Bs3TestSubErrorCount() != cErrorsBefore)
1233 {
1234 Bs3TrapPrintFrame(pTrapCtx);
1235 Bs3TestPrintf("CS=%04RX16 SS:ESP=%04RX16:%08RX64 EFL=%RX64 cbIret=%#x\n",
1236 pTrapCtx->uHandlerCs, pTrapCtx->uHandlerSs, pTrapCtx->uHandlerRsp,
1237 pTrapCtx->fHandlerRfl, pTrapCtx->cbIretFrame);
1238#if 0
1239 Bs3TestPrintf("Halting in ComparePushPop: bXcpt=%#x\n", pTrapCtx->bXcpt);
1240 ASMHalt();
1241#endif
1242 return 1;
1243 }
1244 return 0;
1245}
1246
1247
1248/** Initialize the stack around the CS:RSP with fixed values. */
1249static void bs3CpuWeird1_PushPopInitStack(BS3PTRUNION PtrStack)
1250{
1251 PtrStack.pu16[-8] = UINT16_C(0x1e0f);
1252 PtrStack.pu16[-7] = UINT16_C(0x3c2d);
1253 PtrStack.pu16[-6] = UINT16_C(0x5a4b);
1254 PtrStack.pu16[-5] = UINT16_C(0x7869);
1255 PtrStack.pu16[-4] = UINT16_C(0x9687);
1256 PtrStack.pu16[-3] = UINT16_C(0xb4a5);
1257 PtrStack.pu16[-2] = UINT16_C(0xd2c3);
1258 PtrStack.pu16[-1] = UINT16_C(0xf0e1);
1259 PtrStack.pu16[0] = UINT16_C(0xfdec);
1260 PtrStack.pu16[1] = UINT16_C(0xdbca);
1261 PtrStack.pu16[2] = UINT16_C(0xb9a8);
1262 PtrStack.pu16[3] = UINT16_C(0x9786);
1263 PtrStack.pu16[4] = UINT16_C(0x7564);
1264 PtrStack.pu16[5] = UINT16_C(0x5342);
1265 PtrStack.pu16[6] = UINT16_C(0x3120);
1266}
1267
1268
1269BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuWeird1_PushPop)(uint8_t bTestMode)
1270{
1271 static struct
1272 {
1273 FPFNBS3FAR pfnStart;
1274 uint8_t cBits;
1275 bool fPush; /**< true if push, false if pop. */
1276 int8_t cbAdjSp; /**< The SP adjustment value. */
1277 uint8_t idxReg; /**< The X86_GREG_xXX value of the register in question. */
1278 uint8_t offUd2; /**< The UD2 offset into the code. */
1279 } s_aTests[] =
1280 {
1281 { bs3CpuWeird1_Push_opsize_xBX_Ud2_c16, 16, true, -4, X86_GREG_xBX, 2 },
1282 { bs3CpuWeird1_Pop_opsize_xBX_Ud2_c16, 16, false, +4, X86_GREG_xBX, 2 },
1283 { bs3CpuWeird1_Push_xSP_Ud2_c16, 16, true, -2, X86_GREG_xSP, 1 },
1284 { bs3CpuWeird1_Push_opsize_xSP_Ud2_c16, 16, true, -4, X86_GREG_xSP, 2 },
1285 { bs3CpuWeird1_Pop_xSP_Ud2_c16, 16, false, +2, X86_GREG_xSP, 1 },
1286 { bs3CpuWeird1_Pop_opsize_xSP_Ud2_c16, 16, false, +4, X86_GREG_xSP, 2 },
1287
1288 { bs3CpuWeird1_Push_opsize_xBX_Ud2_c32, 32, true, -2, X86_GREG_xBX, 2 },
1289 { bs3CpuWeird1_Pop_opsize_xBX_Ud2_c32, 32, false, +2, X86_GREG_xBX, 2 },
1290 { bs3CpuWeird1_Push_xSP_Ud2_c32, 32, true, -4, X86_GREG_xSP, 1 },
1291 { bs3CpuWeird1_Push_opsize_xSP_Ud2_c32, 32, true, -2, X86_GREG_xSP, 2 },
1292 { bs3CpuWeird1_Pop_xSP_Ud2_c32, 32, false, +4, X86_GREG_xSP, 1 },
1293 { bs3CpuWeird1_Pop_opsize_xSP_Ud2_c32, 32, false, +2, X86_GREG_xSP, 2 },
1294
1295 { bs3CpuWeird1_Push_opsize_xBX_Ud2_c64, 64, true, -2, X86_GREG_xBX, 2 },
1296 { bs3CpuWeird1_Pop_opsize_xBX_Ud2_c64, 64, false, +2, X86_GREG_xBX, 2 },
1297 { bs3CpuWeird1_Push_xSP_Ud2_c64, 64, true, -8, X86_GREG_xSP, 1 },
1298 { bs3CpuWeird1_Push_opsize_xSP_Ud2_c64, 64, true, -2, X86_GREG_xSP, 2 },
1299 { bs3CpuWeird1_Pop_xSP_Ud2_c64, 64, false, +8, X86_GREG_xSP, 1 },
1300 { bs3CpuWeird1_Pop_opsize_xSP_Ud2_c64, 64, false, +2, X86_GREG_xSP, 2 },
1301 };
1302 BS3TRAPFRAME TrapCtx;
1303 BS3TRAPFRAME TrapExpect;
1304 BS3REGCTX Ctx;
1305 uint8_t const cTestBits = BS3_MODE_IS_16BIT_CODE(bTestMode) ? 16
1306 : BS3_MODE_IS_32BIT_CODE(bTestMode) ? 32 : 64;
1307 uint8_t BS3_FAR *pbAltStack = NULL;
1308 BS3PTRUNION PtrStack;
1309 unsigned i;
1310
1311 /* make sure they're allocated */
1312 Bs3MemZero(&Ctx, sizeof(Ctx));
1313 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1314 Bs3MemZero(&TrapExpect, sizeof(TrapExpect));
1315
1316 bs3CpuWeird1_SetGlobals(bTestMode);
1317
1318 /* Construct a basic context. */
1319 Bs3RegCtxSaveEx(&Ctx, bTestMode, 1024);
1320 Ctx.rflags.u32 &= ~X86_EFL_RF;
1321 if (BS3_MODE_IS_64BIT_CODE(bTestMode))
1322 {
1323 Ctx.rbx.au32[1] ^= UINT32_C(0x12305c78);
1324 Ctx.rcx.au32[1] ^= UINT32_C(0x33447799);
1325 Ctx.rax.au32[1] ^= UINT32_C(0x9983658a);
1326 Ctx.r11.au32[1] ^= UINT32_C(0xbbeeffdd);
1327 Ctx.r12.au32[1] ^= UINT32_C(0x87272728);
1328 }
1329
1330 /* ring-3 if possible, since that'll enable automatic stack switching. */
1331 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
1332 Bs3RegCtxConvertToRingX(&Ctx, 3);
1333
1334 /* Make PtrStack == SS:xSP from Ctx. */
1335 PtrStack.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
1336
1337#if 1
1338 /* Use our own stack so we can observe the effect of ESP/RSP rolling across
1339 a 64KB boundrary when just popping SP. */
1340 if (!BS3_MODE_IS_16BIT_CODE(bTestMode)) /** @todo extend this to 16-bit code as well (except RM ofc). */
1341 {
1342 uint32_t uFlatNextSeg;
1343 pbAltStack = (uint8_t BS3_FAR *)Bs3SlabAllocEx(&g_Bs3Mem4KUpperTiled.Core, 17 /*cPages*/, 0 /*fFlags*/);
1344 if (!pbAltStack)
1345 {
1346 Bs3TestFailed("Failed to allocate 68K for alternative stack!");
1347 return 1;
1348 }
1349
1350 /* Modify RSP to be one byte under the 64KB boundrary. */
1351 uFlatNextSeg = (Bs3SelPtrToFlat(pbAltStack) + _64K) & ~UINT32_C(0xffff);
1352 Ctx.rsp.u = uFlatNextSeg - 1;
1353 //Bs3TestPrintf("uFlatNextSeg=%RX32 rsp=%RX64 ss=%RX16\n", uFlatNextSeg, Ctx.rsp.u, Ctx.ss);
1354
1355 /* Modify the PtrStack accordingly, using a spare selector for addressing it. */
1356 Bs3SelSetup16BitData(&Bs3GdteSpare00, uFlatNextSeg - _4K);
1357 PtrStack.pv = BS3_FP_MAKE(BS3_SEL_SPARE_00 | 3, _4K - 1);
1358 }
1359#endif
1360
1361 /*
1362 * Iterate the test snippets and run those relevant to the test context.
1363 */
1364 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1365 {
1366 if (s_aTests[i].cBits == cTestBits)
1367 {
1368 PBS3REG const pReg = &(&Ctx.rax)[s_aTests[i].idxReg];
1369 unsigned iRep; /**< This is to trigger native recompilation. */
1370 BS3REG SavedReg;
1371 BS3REG SavedRsp;
1372
1373 /* Save context stuff we may change: */
1374 SavedReg.u = pReg->u;
1375 SavedRsp.u = Ctx.rsp.u;
1376
1377 /* Setup the test context. */
1378 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[i].pfnStart);
1379 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
1380 g_uBs3TrapEipHint = Ctx.rip.u32;
1381
1382 if (BS3_MODE_IS_16BIT_CODE(bTestMode))
1383 Ctx.rsp.u32 |= UINT32_C(0x34560000); /* This part should be ignored, as the stack is also 16-bit. */
1384
1385 /* The basic expected trap context. */
1386 TrapExpect.bXcpt = X86_XCPT_UD;
1387 Bs3MemCpy(&TrapExpect.Ctx, &Ctx, sizeof(TrapExpect.Ctx));
1388 TrapExpect.Ctx.rsp.u += s_aTests[i].cbAdjSp;
1389 TrapExpect.Ctx.rip.u += s_aTests[i].offUd2;
1390 if (!BS3_MODE_IS_16BIT_SYS(bTestMode))
1391 TrapExpect.Ctx.rflags.u32 |= X86_EFL_RF;
1392
1393 g_usBs3TestStep = i;
1394
1395 if (s_aTests[i].cbAdjSp < 0)
1396 {
1397 /*
1398 * PUSH
1399 */
1400 RTUINT64U u64ExpectPushed;
1401 BS3PTRUNION PtrStack2;
1402 PtrStack2.pb = PtrStack.pb + s_aTests[i].cbAdjSp;
1403
1404 bs3CpuWeird1_PushPopInitStack(PtrStack);
1405 u64ExpectPushed.u = *PtrStack2.pu64;
1406 switch (s_aTests[i].cbAdjSp)
1407 {
1408 case -2: u64ExpectPushed.au16[0] = pReg->au16[0]; break;
1409 case -4: u64ExpectPushed.au32[0] = pReg->au32[0]; break;
1410 case -8: u64ExpectPushed.au64[0] = pReg->u; break;
1411 }
1412
1413 for (iRep = 0; iRep < 256; iRep++)
1414 {
1415 bs3CpuWeird1_PushPopInitStack(PtrStack);
1416 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1417 if (bs3CpuWeird1_ComparePushPop(&TrapCtx, &TrapExpect))
1418 break;
1419 if (*PtrStack2.pu64 != u64ExpectPushed.u)
1420 {
1421 Bs3TestFailedF("%u - Unexpected stack value after push: %RX64, expected %RX64",
1422 g_usBs3TestStep, *PtrStack2.pu64, u64ExpectPushed);
1423 break;
1424 }
1425 }
1426 }
1427 else
1428 {
1429 /*
1430 * POP.
1431 *
1432 * This is where it gets interesting. When popping a partial
1433 * SP and the upper part also changes, this is preserved. I.e.
1434 * the CPU first writes the updated RSP then the register or
1435 * register part that it popped.
1436 */
1437 PBS3REG const pExpectReg = &(&TrapExpect.Ctx.rax)[s_aTests[i].idxReg];
1438 RTUINT64U u64PopValue;
1439
1440 bs3CpuWeird1_PushPopInitStack(PtrStack);
1441 u64PopValue.u = *PtrStack.pu64;
1442 if (bTestMode != BS3_MODE_RM)
1443 {
1444 /* When in ring-3 we can put whatever we want on the stack, as the UD2 will cause a stack switch. */
1445 switch (s_aTests[i].cbAdjSp)
1446 {
1447 case 2: u64PopValue.au16[0] = ~pReg->au16[0] ^ UINT16_C(0xf394); break;
1448 case 4: u64PopValue.au32[0] = ~pReg->au32[0] ^ UINT32_C(0x9e501ab3); break;
1449 case 8: u64PopValue.au64[0] = ~pReg->u ^ UINT64_C(0xbf5fedd520fe9a45); break;
1450 }
1451 }
1452 else
1453 {
1454 /* In real mode we have to be a little more careful. */
1455 if (s_aTests[i].cbAdjSp == 2)
1456 u64PopValue.au16[0] = pReg->au16[0] - 382;
1457 else
1458 {
1459 u64PopValue.au16[0] = pReg->au16[0] - 258;
1460 u64PopValue.au16[1] = ~pReg->au16[1];
1461 }
1462 }
1463
1464 switch (s_aTests[i].cbAdjSp)
1465 {
1466 case 2:
1467 pExpectReg->au16[0] = u64PopValue.au16[0];
1468 break;
1469 case 4:
1470 pExpectReg->au32[0] = u64PopValue.au32[0];
1471 pExpectReg->au32[1] = 0;
1472 break;
1473 case 8:
1474 pExpectReg->u = u64PopValue.u;
1475 break;
1476 }
1477 //Bs3TestPrintf("iTest=%u/%d: %RX64 -> %RX64\n", i, s_aTests[i].cbAdjSp, pReg->u, pExpectReg->u);
1478
1479 for (iRep = 0; iRep < 256; iRep++)
1480 {
1481 bs3CpuWeird1_PushPopInitStack(PtrStack);
1482 *PtrStack.pu64 = u64PopValue.u;
1483 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1484 if (bs3CpuWeird1_ComparePushPop(&TrapCtx, &TrapExpect))
1485 break;
1486 }
1487 }
1488
1489 /* Restore context (except cs:rsp): */
1490 pReg->u = SavedReg.u;
1491 Ctx.rsp.u = SavedRsp.u;
1492 }
1493 }
1494
1495 if (pbAltStack)
1496 Bs3SlabFree(&g_Bs3Mem4KUpperTiled.Core, Bs3SelPtrToFlat(pbAltStack), 17);
1497
1498 return 0;
1499}
1500
1501
1502
1503/*********************************************************************************************************************************
1504* PUSH SREG / POP SREG *
1505*********************************************************************************************************************************/
1506PROTO_ALL(bs3CpuWeird1_Push_cs_Ud2);
1507PROTO_ALL(bs3CpuWeird1_Push_ss_Ud2);
1508PROTO_ALL(bs3CpuWeird1_Push_ds_Ud2);
1509PROTO_ALL(bs3CpuWeird1_Push_es_Ud2);
1510PROTO_ALL(bs3CpuWeird1_Push_fs_Ud2);
1511PROTO_ALL(bs3CpuWeird1_Push_gs_Ud2);
1512PROTO_ALL(bs3CpuWeird1_Pop_ss_Ud2);
1513PROTO_ALL(bs3CpuWeird1_Pop_ds_Ud2);
1514PROTO_ALL(bs3CpuWeird1_Pop_es_Ud2);
1515PROTO_ALL(bs3CpuWeird1_Pop_fs_Ud2);
1516PROTO_ALL(bs3CpuWeird1_Pop_gs_Ud2);
1517PROTO_ALL(bs3CpuWeird1_Push_opsize_cs_Ud2);
1518PROTO_ALL(bs3CpuWeird1_Push_opsize_ss_Ud2);
1519PROTO_ALL(bs3CpuWeird1_Push_opsize_ds_Ud2);
1520PROTO_ALL(bs3CpuWeird1_Push_opsize_es_Ud2);
1521PROTO_ALL(bs3CpuWeird1_Push_opsize_fs_Ud2);
1522PROTO_ALL(bs3CpuWeird1_Push_opsize_gs_Ud2);
1523PROTO_ALL(bs3CpuWeird1_Pop_opsize_ss_Ud2);
1524PROTO_ALL(bs3CpuWeird1_Pop_opsize_ds_Ud2);
1525PROTO_ALL(bs3CpuWeird1_Pop_opsize_es_Ud2);
1526PROTO_ALL(bs3CpuWeird1_Pop_opsize_fs_Ud2);
1527PROTO_ALL(bs3CpuWeird1_Pop_opsize_gs_Ud2);
1528
1529
1530BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuWeird1_PushPopSReg)(uint8_t bTestMode)
1531{
1532 static struct
1533 {
1534 FPFNBS3FAR pfnStart;
1535 uint8_t cBits;
1536 bool fPush; /**< true if push, false if pop. */
1537 int8_t cbAdjSp; /**< The SP adjustment value. */
1538 uint8_t offReg; /**< The offset of the register in BS3REGCTX. */
1539 uint8_t offUd2; /**< The UD2 offset into the code. */
1540 } s_aTests[] =
1541 {
1542 { bs3CpuWeird1_Push_cs_Ud2_c16, 16, true, -2, RT_UOFFSETOF(BS3REGCTX, cs), 1 },
1543 { bs3CpuWeird1_Push_ss_Ud2_c16, 16, true, -2, RT_UOFFSETOF(BS3REGCTX, ss), 1 },
1544 { bs3CpuWeird1_Push_ds_Ud2_c16, 16, true, -2, RT_UOFFSETOF(BS3REGCTX, ds), 1 },
1545 { bs3CpuWeird1_Push_es_Ud2_c16, 16, true, -2, RT_UOFFSETOF(BS3REGCTX, es), 1 },
1546 { bs3CpuWeird1_Push_fs_Ud2_c16, 16, true, -2, RT_UOFFSETOF(BS3REGCTX, fs), 2 },
1547 { bs3CpuWeird1_Push_gs_Ud2_c16, 16, true, -2, RT_UOFFSETOF(BS3REGCTX, gs), 2 },
1548 { bs3CpuWeird1_Pop_ss_Ud2_c16, 16, false, +2, RT_UOFFSETOF(BS3REGCTX, ss), 1 },
1549 { bs3CpuWeird1_Pop_ds_Ud2_c16, 16, false, +2, RT_UOFFSETOF(BS3REGCTX, ds), 1 },
1550 { bs3CpuWeird1_Pop_es_Ud2_c16, 16, false, +2, RT_UOFFSETOF(BS3REGCTX, es), 1 },
1551 { bs3CpuWeird1_Pop_fs_Ud2_c16, 16, false, +2, RT_UOFFSETOF(BS3REGCTX, fs), 2 },
1552 { bs3CpuWeird1_Pop_gs_Ud2_c16, 16, false, +2, RT_UOFFSETOF(BS3REGCTX, gs), 2 },
1553 { bs3CpuWeird1_Push_opsize_cs_Ud2_c16, 16, true, -4, RT_UOFFSETOF(BS3REGCTX, cs), 2 },
1554 { bs3CpuWeird1_Push_opsize_ss_Ud2_c16, 16, true, -4, RT_UOFFSETOF(BS3REGCTX, ss), 2 },
1555 { bs3CpuWeird1_Push_opsize_ds_Ud2_c16, 16, true, -4, RT_UOFFSETOF(BS3REGCTX, ds), 2 },
1556 { bs3CpuWeird1_Push_opsize_es_Ud2_c16, 16, true, -4, RT_UOFFSETOF(BS3REGCTX, es), 2 },
1557 { bs3CpuWeird1_Push_opsize_fs_Ud2_c16, 16, true, -4, RT_UOFFSETOF(BS3REGCTX, fs), 3 },
1558 { bs3CpuWeird1_Push_opsize_gs_Ud2_c16, 16, true, -4, RT_UOFFSETOF(BS3REGCTX, gs), 3 },
1559 { bs3CpuWeird1_Pop_opsize_ss_Ud2_c16, 16, false, +4, RT_UOFFSETOF(BS3REGCTX, ss), 2 },
1560 { bs3CpuWeird1_Pop_opsize_ds_Ud2_c16, 16, false, +4, RT_UOFFSETOF(BS3REGCTX, ds), 2 },
1561 { bs3CpuWeird1_Pop_opsize_es_Ud2_c16, 16, false, +4, RT_UOFFSETOF(BS3REGCTX, es), 2 },
1562 { bs3CpuWeird1_Pop_opsize_fs_Ud2_c16, 16, false, +4, RT_UOFFSETOF(BS3REGCTX, fs), 3 },
1563 { bs3CpuWeird1_Pop_opsize_gs_Ud2_c16, 16, false, +4, RT_UOFFSETOF(BS3REGCTX, gs), 3 },
1564
1565 { bs3CpuWeird1_Push_cs_Ud2_c32, 32, true, -4, RT_UOFFSETOF(BS3REGCTX, cs), 1 },
1566 { bs3CpuWeird1_Push_ss_Ud2_c32, 32, true, -4, RT_UOFFSETOF(BS3REGCTX, ss), 1 },
1567 { bs3CpuWeird1_Push_ds_Ud2_c32, 32, true, -4, RT_UOFFSETOF(BS3REGCTX, ds), 1 },
1568 { bs3CpuWeird1_Push_es_Ud2_c32, 32, true, -4, RT_UOFFSETOF(BS3REGCTX, es), 1 },
1569 { bs3CpuWeird1_Push_fs_Ud2_c32, 32, true, -4, RT_UOFFSETOF(BS3REGCTX, fs), 2 },
1570 { bs3CpuWeird1_Push_gs_Ud2_c32, 32, true, -4, RT_UOFFSETOF(BS3REGCTX, gs), 2 },
1571 { bs3CpuWeird1_Pop_ss_Ud2_c32, 32, false, +4, RT_UOFFSETOF(BS3REGCTX, ss), 1 },
1572 { bs3CpuWeird1_Pop_ds_Ud2_c32, 32, false, +4, RT_UOFFSETOF(BS3REGCTX, ds), 1 },
1573 { bs3CpuWeird1_Pop_es_Ud2_c32, 32, false, +4, RT_UOFFSETOF(BS3REGCTX, es), 1 },
1574 { bs3CpuWeird1_Pop_fs_Ud2_c32, 32, false, +4, RT_UOFFSETOF(BS3REGCTX, fs), 2 },
1575 { bs3CpuWeird1_Pop_gs_Ud2_c32, 32, false, +4, RT_UOFFSETOF(BS3REGCTX, gs), 2 },
1576 { bs3CpuWeird1_Push_opsize_cs_Ud2_c32, 32, true, -2, RT_UOFFSETOF(BS3REGCTX, cs), 2 },
1577 { bs3CpuWeird1_Push_opsize_ss_Ud2_c32, 32, true, -2, RT_UOFFSETOF(BS3REGCTX, ss), 2 },
1578 { bs3CpuWeird1_Push_opsize_ds_Ud2_c32, 32, true, -2, RT_UOFFSETOF(BS3REGCTX, ds), 2 },
1579 { bs3CpuWeird1_Push_opsize_es_Ud2_c32, 32, true, -2, RT_UOFFSETOF(BS3REGCTX, es), 2 },
1580 { bs3CpuWeird1_Push_opsize_fs_Ud2_c32, 32, true, -2, RT_UOFFSETOF(BS3REGCTX, fs), 3 },
1581 { bs3CpuWeird1_Push_opsize_gs_Ud2_c32, 32, true, -2, RT_UOFFSETOF(BS3REGCTX, gs), 3 },
1582 { bs3CpuWeird1_Pop_opsize_ss_Ud2_c32, 32, false, +2, RT_UOFFSETOF(BS3REGCTX, ss), 2 },
1583 { bs3CpuWeird1_Pop_opsize_ds_Ud2_c32, 32, false, +2, RT_UOFFSETOF(BS3REGCTX, ds), 2 },
1584 { bs3CpuWeird1_Pop_opsize_es_Ud2_c32, 32, false, +2, RT_UOFFSETOF(BS3REGCTX, es), 2 },
1585 { bs3CpuWeird1_Pop_opsize_fs_Ud2_c32, 32, false, +2, RT_UOFFSETOF(BS3REGCTX, fs), 3 },
1586 { bs3CpuWeird1_Pop_opsize_gs_Ud2_c32, 32, false, +2, RT_UOFFSETOF(BS3REGCTX, gs), 3 },
1587
1588 { bs3CpuWeird1_Push_fs_Ud2_c64, 64, true, -8, RT_UOFFSETOF(BS3REGCTX, fs), 2 },
1589 { bs3CpuWeird1_Push_gs_Ud2_c64, 64, true, -8, RT_UOFFSETOF(BS3REGCTX, gs), 2 },
1590 { bs3CpuWeird1_Pop_fs_Ud2_c64, 64, false, +8, RT_UOFFSETOF(BS3REGCTX, fs), 2 },
1591 { bs3CpuWeird1_Pop_gs_Ud2_c64, 64, false, +8, RT_UOFFSETOF(BS3REGCTX, gs), 2 },
1592 { bs3CpuWeird1_Push_opsize_fs_Ud2_c64, 64, true, -2, RT_UOFFSETOF(BS3REGCTX, fs), 3 },
1593 { bs3CpuWeird1_Push_opsize_gs_Ud2_c64, 64, true, -2, RT_UOFFSETOF(BS3REGCTX, gs), 3 },
1594 { bs3CpuWeird1_Pop_opsize_fs_Ud2_c64, 64, false, +2, RT_UOFFSETOF(BS3REGCTX, fs), 3 },
1595 { bs3CpuWeird1_Pop_opsize_gs_Ud2_c64, 64, false, +2, RT_UOFFSETOF(BS3REGCTX, gs), 3 },
1596 };
1597 BS3TRAPFRAME TrapCtx;
1598 BS3TRAPFRAME TrapExpect;
1599 BS3REGCTX Ctx;
1600 uint16_t const uInitialSel = bTestMode != BS3_MODE_RM ? BS3_SEL_R3_DS16 : 0x8080;
1601 uint16_t const uPopSel = BS3_SEL_R3_SS16;
1602 bool const fFullWrite = BS3_MODE_IS_64BIT_CODE(bTestMode) /* 64-bit mode writes are full (10980XE). */
1603 || (g_enmCpuVendor = Bs3GetCpuVendor()) != BS3CPUVENDOR_INTEL;
1604 bool const fFullRead = false /* But, 64-bit mode reads are word sized (10980XE). */
1605 || g_enmCpuVendor != BS3CPUVENDOR_INTEL;
1606 bool const fInRmWrHiEfl = true /* 10890XE writes EFLAGS[31:16] in the high word of a 'o32 PUSH FS'. */
1607 && !fFullWrite;
1608 uint8_t const cTestBits = BS3_MODE_IS_16BIT_CODE(bTestMode) ? 16
1609 : BS3_MODE_IS_32BIT_CODE(bTestMode) ? 32 : 64;
1610 unsigned const cbAltStack = 2 * X86_PAGE_SIZE;
1611 uint8_t BS3_FAR *pbAltStack = NULL;
1612 uint32_t uFlatAltStack;
1613 uint32_t uFlatAltStackAlias;
1614 BS3PTRUNION PtrStack;
1615 unsigned iVariation;
1616
1617 /* make sure they're allocated */
1618 Bs3MemZero(&Ctx, sizeof(Ctx));
1619 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1620 Bs3MemZero(&TrapExpect, sizeof(TrapExpect));
1621
1622 bs3CpuWeird1_SetGlobals(bTestMode);
1623
1624 /* Construct a basic context. */
1625 Bs3RegCtxSaveEx(&Ctx, bTestMode, 1024);
1626 Ctx.rflags.u32 &= ~X86_EFL_RF;
1627 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1628 Ctx.rflags.u32 |= X86_EFL_ID; /* Make sure it's set as it bleeds in in real-mode on my intel 10890XE. */
1629
1630 if (BS3_MODE_IS_64BIT_CODE(bTestMode))
1631 {
1632 Ctx.rbx.au32[1] ^= UINT32_C(0x12305c78);
1633 Ctx.rcx.au32[1] ^= UINT32_C(0x33447799);
1634 Ctx.rax.au32[1] ^= UINT32_C(0x9983658a);
1635 Ctx.r11.au32[1] ^= UINT32_C(0xbbeeffdd);
1636 Ctx.r12.au32[1] ^= UINT32_C(0x87272728);
1637 }
1638
1639 /* ring-3 if possible, since that'll enable automatic stack switching. */
1640 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
1641 Bs3RegCtxConvertToRingX(&Ctx, 3);
1642
1643 /* Make PtrStack == SS:xSP from Ctx. */
1644 PtrStack.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
1645
1646 /* Use our own stack so we can analyze the PUSH/POP FS behaviour using
1647 both the SS limit (except 64-bit code) and paging (when enabled).
1648 Two pages suffices here, but we allocate two more for aliasing the
1649 first to onto. */
1650 if (!BS3_MODE_IS_RM_OR_V86(bTestMode)) /** @todo test V86 mode w/ paging */
1651 {
1652 pbAltStack = (uint8_t BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, cbAltStack * 2);
1653 if (!pbAltStack)
1654 return !Bs3TestFailed("Failed to allocate 2*2 pages for an alternative stack!");
1655 uFlatAltStack = Bs3SelPtrToFlat(pbAltStack);
1656 if (uFlatAltStack & X86_PAGE_OFFSET_MASK)
1657 return !Bs3TestFailedF("Misaligned allocation: %p / %RX32!", pbAltStack, uFlatAltStack);
1658 }
1659
1660 /*
1661 * The outer loop does setup variations:
1662 * - 0: Standard push and pop w/o off default stack w/o any restrictions.
1663 * - 1: Apply segment limit as tightly as possible w/o #SS.
1664 * - 2: Apply the segment limit too tight and field #SS.
1665 * - 3: Put the segment number right next to a page that's not present.
1666 * No segment trickery.
1667 * - 4: Make the segment number word straddle a page boundrary where
1668 * the 2nd page is not present.
1669 */
1670 for (iVariation = 0; iVariation <= 4; iVariation++)
1671 {
1672 uint16_t const uSavedSs = Ctx.ss;
1673 uint64_t const uSavedRsp = Ctx.rsp.u;
1674 uint32_t uNominalEsp;
1675 unsigned iTest;
1676
1677 /* Skip variation if not supported by the test mode. */
1678 if (iVariation >= 1 && BS3_MODE_IS_RM_OR_V86(bTestMode)) /** @todo test V86 mode w/ paging */
1679 break;
1680
1681 if ((iVariation == 1 || iVariation == 2) && BS3_MODE_IS_64BIT_CODE(bTestMode))
1682 continue;
1683 if ((iVariation == 3 || iVariation == 4) && !BS3_MODE_IS_PAGED(bTestMode))
1684 continue;
1685
1686 uFlatAltStackAlias = uFlatAltStack;
1687 if (iVariation != 0)
1688 {
1689 /* Alias the two stack pages for variation #3 and #4 so we can keep
1690 accessing them via pbAltStack while testing. */
1691 if (iVariation == 3 || iVariation == 4)
1692 {
1693 int rc = Bs3PagingAlias(uFlatAltStackAlias = uFlatAltStack + X86_PAGE_SIZE * 2, uFlatAltStack, X86_PAGE_SIZE,
1694 X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | X86_PTE_US);
1695 if (RT_SUCCESS(rc))
1696 {
1697 rc = Bs3PagingAlias(uFlatAltStackAlias + X86_PAGE_SIZE, uFlatAltStack + X86_PAGE_SIZE, X86_PAGE_SIZE, 0);
1698 if (RT_FAILURE(rc))
1699 {
1700 Bs3TestFailedF("Alias of 2nd stack page failed: %d", rc);
1701 Bs3PagingUnalias(uFlatAltStackAlias, X86_PAGE_SIZE);
1702 }
1703 }
1704 else
1705 Bs3TestFailedF("Alias of 2nd stack page failed: %d", rc);
1706 if (RT_FAILURE(rc))
1707 break;
1708 }
1709
1710 if (iVariation == 1 || iVariation == 2 || BS3_MODE_IS_16BIT_CODE(bTestMode))
1711 {
1712 /* Setup a 16-bit stack with two pages and ESP pointing at the last
1713 word in the first page. The SS limit is at 4KB for variation #1
1714 (shouldn't fault unless the CPU does full dword writes), one byte
1715 lower for variation #2 (must always fault), and max limit for
1716 variations #3 and #4. */
1717 Bs3SelSetup16BitData(&Bs3GdteSpare00, uFlatAltStackAlias);
1718 if (iVariation <= 2)
1719 {
1720 Bs3GdteSpare00.Gen.u16LimitLow = _4K - 1;
1721 if (iVariation == 2)
1722 Bs3GdteSpare00.Gen.u16LimitLow -= 1;
1723 Bs3GdteSpare00.Gen.u4LimitHigh = 0;
1724 }
1725 Ctx.ss = BS3_SEL_SPARE_00 | 3;
1726 Ctx.rsp.u = _4K - sizeof(uint16_t);
1727 }
1728 else
1729 {
1730 /* Setup flat stack similar to above for variation #3 and #4. */
1731 Ctx.rsp.u = uFlatAltStackAlias + _4K - sizeof(uint16_t);
1732 }
1733
1734 /* Update the stack pointer to match the new ESP. */
1735 PtrStack.pv = &pbAltStack[_4K - sizeof(uint16_t)];
1736
1737 /* For variation #4 we move the stack position up by one byte so we'll
1738 always cross the page boundrary and hit the non-existing page. */
1739 if (iVariation == 4)
1740 {
1741 Ctx.rsp.u += 1;
1742 PtrStack.pb += 1;
1743 }
1744 }
1745 uNominalEsp = Ctx.rsp.u32;
1746 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
1747 {
1748 if (s_aTests[iTest].cBits == cTestBits)
1749 {
1750 uint16_t BS3_FAR *pRegCtx = (uint16_t BS3_FAR *)((uint8_t BS3_FAR *)&Ctx + s_aTests[iTest].offReg);
1751 uint16_t BS3_FAR *pRegExpect = (uint16_t BS3_FAR *)((uint8_t BS3_FAR *)&TrapExpect.Ctx + s_aTests[iTest].offReg);
1752 uint16_t const uSavedSel = *pRegCtx;
1753 uint8_t const cbItem = RT_ABS(s_aTests[iTest].cbAdjSp);
1754 bool const fDefaultSel = s_aTests[iTest].offReg == RT_UOFFSETOF(BS3REGCTX, ss)
1755 || s_aTests[iTest].offReg == RT_UOFFSETOF(BS3REGCTX, cs);
1756 unsigned iRep; /**< This is to trigger native recompilation. */
1757 BS3PTRUNION PtrStack2;
1758
1759 if (!fDefaultSel)
1760 *pRegCtx = uInitialSel;
1761
1762 /* Calculate the stack read/write location for this test. PtrStack
1763 ASSUMES word writes, so we have to adjust it and RSP if the CPU
1764 does full read+writes. */
1765 PtrStack2.pv = PtrStack.pv;
1766 if (cbItem != 2 && (s_aTests[iTest].cbAdjSp < 0 ? fFullWrite : fFullRead))
1767 {
1768 PtrStack2.pb -= cbItem - 2;
1769 Ctx.rsp.u32 -= cbItem - 2;
1770 }
1771
1772 /* Setup the test context. */
1773 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnStart);
1774 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
1775 g_uBs3TrapEipHint = Ctx.rip.u32;
1776
1777 /* Use the same access location for both PUSH and POP instructions (PtrStack). */
1778 if (s_aTests[iTest].cbAdjSp < 0)
1779 Ctx.rsp.u16 += -s_aTests[iTest].cbAdjSp;
1780
1781 /* The basic expected trap context. */
1782 TrapExpect.bXcpt = iVariation == 2 ? X86_XCPT_SS : iVariation == 4 ? X86_XCPT_PF : X86_XCPT_UD;
1783 TrapExpect.uErrCd = 0;
1784 Bs3MemCpy(&TrapExpect.Ctx, &Ctx, sizeof(TrapExpect.Ctx));
1785 if (TrapExpect.bXcpt == X86_XCPT_UD)
1786 {
1787 TrapExpect.Ctx.rsp.u += s_aTests[iTest].cbAdjSp;
1788 TrapExpect.Ctx.rip.u += s_aTests[iTest].offUd2;
1789 }
1790 else if (iVariation == 4)
1791 {
1792 TrapExpect.uErrCd = s_aTests[iTest].cbAdjSp < 0 ? X86_TRAP_PF_RW | X86_TRAP_PF_US : X86_TRAP_PF_US;
1793 TrapExpect.Ctx.cr2.u = uFlatAltStackAlias + X86_PAGE_SIZE;
1794 }
1795 if (!BS3_MODE_IS_16BIT_SYS(bTestMode))
1796 TrapExpect.Ctx.rflags.u32 |= X86_EFL_RF;
1797
1798 g_usBs3TestStep = iVariation * 1000 + iTest;
1799
1800 if (s_aTests[iTest].cbAdjSp < 0)
1801 {
1802#if 1
1803 /*
1804 * PUSH
1805 */
1806 RTUINT64U u64ExpectPushed;
1807
1808 bs3CpuWeird1_PushPopInitStack(PtrStack2);
1809 u64ExpectPushed.u = *PtrStack2.pu64;
1810 if (TrapExpect.bXcpt == X86_XCPT_UD)
1811 {
1812 u64ExpectPushed.au16[0] = *pRegCtx;
1813 if (s_aTests[iTest].cbAdjSp < -2)
1814 {
1815 if (fFullWrite) /* enable for CPUs that writes more than a word */
1816 {
1817 u64ExpectPushed.au16[1] = 0;
1818 if (s_aTests[iTest].cbAdjSp == -8)
1819 u64ExpectPushed.au32[1] = 0;
1820 }
1821 /* Intel 10980XE real mode: high word appears to be from EFLAGS. Weird! */
1822 else if (bTestMode == BS3_MODE_RM && fInRmWrHiEfl)
1823 u64ExpectPushed.au16[1] = Ctx.rflags.au16[1];
1824 }
1825 }
1826
1827 for (iRep = 0; iRep < 256; iRep++)
1828 {
1829 if (iVariation < 3)
1830 bs3CpuWeird1_PushPopInitStack(PtrStack2);
1831 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1832 if (bs3CpuWeird1_ComparePushPop(&TrapCtx, &TrapExpect))
1833 break;
1834
1835 if (*PtrStack2.pu64 != u64ExpectPushed.u)
1836 {
1837 Bs3TestFailedF("%u - Unexpected stack value after push: %RX64, expected %RX64",
1838 g_usBs3TestStep, *PtrStack2.pu64, u64ExpectPushed);
1839 break;
1840 }
1841 }
1842#endif
1843 }
1844 else
1845 {
1846#if 1
1847 /*
1848 * POP.
1849 */
1850 if (TrapExpect.bXcpt == X86_XCPT_UD)
1851 *pRegExpect = !fDefaultSel ? uPopSel : *pRegCtx;
1852
1853 for (iRep = 0; iRep < 256; iRep++)
1854 {
1855 bs3CpuWeird1_PushPopInitStack(PtrStack2);
1856 *PtrStack2.pu16 = !fDefaultSel ? uPopSel : *pRegCtx;
1857 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1858 if (bs3CpuWeird1_ComparePushPop(&TrapCtx, &TrapExpect))
1859 break;
1860 }
1861#endif
1862 }
1863
1864 /* Restore context (except cs:rip): */
1865 *pRegCtx = uSavedSel;
1866 Ctx.rsp.u32 = uNominalEsp;
1867 }
1868 }
1869
1870 /* Restore original SS:RSP value. */
1871 Ctx.rsp.u = uSavedRsp;
1872 Ctx.ss = uSavedSs;
1873 }
1874
1875 if (pbAltStack)
1876 Bs3MemFree(pbAltStack, cbAltStack);
1877
1878 return 0;
1879}
1880
1881
1882
1883/*********************************************************************************************************************************
1884* POPF *
1885*********************************************************************************************************************************/
1886
1887/**
1888 * Compares popf result.
1889 */
1890static uint8_t bs3CpuWeird1_ComparePopf(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pCtxExpect, uint8_t bXcpt)
1891{
1892 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
1893 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
1894 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
1895 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pCtxExpect, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/,
1896 g_pszTestMode, g_usBs3TestStep);
1897 if (Bs3TestSubErrorCount() != cErrorsBefore)
1898 {
1899 Bs3TrapPrintFrame(pTrapCtx);
1900#if 0
1901 Bs3TestPrintf("Halting in ComparePopf: bXcpt=%#x\n", pTrapCtx->bXcpt);
1902 ASMHalt();
1903#endif
1904 return 1;
1905 }
1906 return 0;
1907}
1908
1909PROTO_ALL(bs3CpuWeird1_Popf_Nop_Ud2);
1910PROTO_ALL(bs3CpuWeird1_Popf_opsize_Nop_Ud2);
1911
1912BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuWeird1_Popf)(uint8_t bTestMode)
1913{
1914 static struct
1915 {
1916 FPFNBS3FAR pfnStart;
1917 uint8_t cBits;
1918 int8_t cbAdjSp; /**< The SP adjustment value. */
1919 uint8_t offNop; /**< The NOP offset into the code. */
1920 uint8_t offUd2; /**< The UD2 offset into the code. */
1921 } const s_aTests[] =
1922 {
1923 { bs3CpuWeird1_Popf_Nop_Ud2_c16, 16, 2, 1, 2 },
1924 { bs3CpuWeird1_Popf_opsize_Nop_Ud2_c16, 16, 4, 2, 3 },
1925
1926 { bs3CpuWeird1_Popf_Nop_Ud2_c32, 32, 4, 1, 2 },
1927 { bs3CpuWeird1_Popf_opsize_Nop_Ud2_c32, 32, 2, 2, 3 },
1928
1929 { bs3CpuWeird1_Popf_Nop_Ud2_c64, 64, 8, 1, 2 },
1930 { bs3CpuWeird1_Popf_opsize_Nop_Ud2_c64, 64, 2, 2, 3 },
1931 };
1932
1933 BS3REGCTX Ctx;
1934 BS3REGCTX CtxExpect;
1935 BS3TRAPFRAME TrapCtx;
1936 BS3PTRUNION PtrStack;
1937 uint8_t const cTestBits = BS3_MODE_IS_16BIT_CODE(bTestMode) ? 16 : BS3_MODE_IS_32BIT_CODE(bTestMode) ? 32 : 64;
1938 uint32_t const fEflCpu = X86_EFL_1 | X86_EFL_STATUS_BITS | X86_EFL_DF | X86_EFL_IF | X86_EFL_TF
1939 | ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80286 ? X86_EFL_IOPL | X86_EFL_NT : 0)
1940 | ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386 ? X86_EFL_RF | X86_EFL_VM : 0)
1941 | ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486 ? X86_EFL_AC | X86_EFL_VIP | X86_EFL_VIF : 0)
1942 | (g_uBs3CpuDetected & BS3CPU_F_CPUID ? X86_EFL_ID : 0);
1943 uint32_t const fEflClear = X86_EFL_1;
1944 uint32_t const fEflSet = X86_EFL_1 | X86_EFL_STATUS_BITS
1945 | X86_EFL_DF /* safe? */
1946 | X86_EFL_IF /* safe? */
1947 | ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386 ? X86_EFL_RF : 0)
1948 | ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486 ? X86_EFL_AC | X86_EFL_VIP : 0)
1949 | (g_uBs3CpuDetected & BS3CPU_F_CPUID ? X86_EFL_ID : 0);
1950 uint32_t const fEflKeep = X86_EFL_VM;
1951 uint32_t const fXcptRf = BS3_MODE_IS_16BIT_SYS(bTestMode) ? 0 : X86_EFL_RF;
1952 bool const fVme = BS3_MODE_IS_V86(bTestMode)
1953 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486
1954 && (Bs3RegGetCr4() & X86_CR4_VME); /* Can't use Ctx.cr4 here, it's always zero. */
1955 unsigned uRing;
1956
1957 //Bs3TestPrintf("g_uBs3CpuDetected=%#RX16 fEflCpu=%#RX32 fEflSet=%#RX32\n", g_uBs3CpuDetected, fEflCpu, fEflSet);
1958 /* make sure they're allocated */
1959 Bs3MemZero(&Ctx, sizeof(Ctx));
1960 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1961
1962 bs3CpuWeird1_SetGlobals(bTestMode);
1963
1964 /* Construct a basic context. */
1965 Bs3RegCtxSaveEx(&Ctx, bTestMode, 1024);
1966 bs3RegCtxScramble(&Ctx, bTestMode);
1967 Bs3MemCpy(&CtxExpect, &Ctx, sizeof(CtxExpect));
1968
1969 /* Make PtrStack == SS:xSP from Ctx. */
1970 PtrStack.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
1971
1972 /*
1973 * The instruction works differently in different rings, so try them all.
1974 */
1975 for (uRing = BS3_MODE_IS_V86(bTestMode) ? 3 : 0; ;)
1976 {
1977 /*
1978 * We've got a couple of instruction variations with/without the opsize prefix.
1979 */
1980 unsigned iTest;
1981 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
1982 {
1983 if (s_aTests[iTest].cBits == cTestBits)
1984 {
1985 uint8_t const cbAdjSp = s_aTests[iTest].cbAdjSp;
1986 unsigned uIopl;
1987
1988 /* Setup the test context. */
1989 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnStart);
1990 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
1991 g_uBs3TrapEipHint = Ctx.rip.u32;
1992 CtxExpect.cs = Ctx.cs;
1993
1994 for (uIopl = 0; uIopl <= X86_EFL_IOPL; uIopl += 1 << X86_EFL_IOPL_SHIFT)
1995 {
1996 bool const fAlwaysUd = cbAdjSp != 2 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80286;
1997 bool const fAlwaysGp = uIopl != X86_EFL_IOPL && BS3_MODE_IS_V86(bTestMode) && (cbAdjSp == 4 || !fVme);
1998 uint8_t const bXcptNorm = fAlwaysGp ? X86_XCPT_GP : X86_XCPT_UD;
1999 uint8_t const offUd = fAlwaysGp || fAlwaysUd ? 0 : s_aTests[iTest].offUd2;
2000 uint32_t const fCleared = fAlwaysUd ? 0 : fAlwaysGp ? /* 10980xe - go figure: */ X86_EFL_RF
2001 : bTestMode == BS3_MODE_RM
2002 ? X86_EFL_RF | X86_EFL_AC | X86_EFL_VIP /** @todo figure this. iret? bs3kit bug? */
2003 : X86_EFL_RF;
2004 uint32_t fPoppable = fAlwaysGp || fAlwaysUd ? 0
2005 : uRing == 0 ? X86_EFL_POPF_BITS
2006 : uRing <= (uIopl >> X86_EFL_IOPL_SHIFT) ? X86_EFL_POPF_BITS & ~(X86_EFL_IOPL)
2007 : !fAlwaysGp ? X86_EFL_POPF_BITS & ~(X86_EFL_IOPL | X86_EFL_IF)
2008 : 0;
2009 uint8_t bXcptExpect;
2010 fPoppable &= fEflCpu;
2011 if (cbAdjSp == 2)
2012 fPoppable &= UINT16_MAX;
2013 if (bTestMode == BS3_MODE_RM && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286)
2014 fPoppable &= ~(X86_EFL_IOPL | X86_EFL_NT);
2015 //Bs3TestPrintf("uRing=%u iTest=%u uIopl=%#x fPoppable=%#RX32 fVme=%d cbAdjSp=%d\n", uRing, iTest, uIopl, fPoppable, fVme, cbAdjSp);
2016
2017 /* The first steps works with as many EFLAGS bits set as possible. */
2018 Ctx.rflags.u32 &= fEflKeep;
2019 Ctx.rflags.u32 |= fEflSet | uIopl;
2020 CtxExpect.rip.u = Ctx.rip.u + offUd;
2021 CtxExpect.rsp.u = fAlwaysGp || fAlwaysUd ? Ctx.rsp.u : Ctx.rsp.u + cbAdjSp;
2022
2023 /*
2024 * Step 1 - pop zero.
2025 */
2026 g_usBs3TestStep++;
2027 PtrStack.pu32[1] = UINT32_MAX;
2028 if (cbAdjSp >= 4)
2029 PtrStack.pu32[0] = 0;
2030 else
2031 {
2032 PtrStack.pu16[1] = UINT16_MAX;
2033 PtrStack.pu16[0] = 0;
2034 }
2035 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fPoppable & ~fCleared) | fXcptRf;
2036 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2037 if (bs3CpuWeird1_ComparePopf(&TrapCtx, &CtxExpect, bXcptNorm))
2038 break;
2039
2040 /*
2041 * Step 2 - pop 0xfffffff sans TF.
2042 */
2043 g_usBs3TestStep++;
2044 PtrStack.pu32[1] = UINT32_MAX;
2045 PtrStack.pu32[0] = UINT32_MAX & ~X86_EFL_TF;
2046 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fPoppable & ~fCleared)
2047 | (UINT32_MAX & ~X86_EFL_TF & fPoppable & ~fCleared)
2048 | fXcptRf;
2049 bXcptExpect = bXcptNorm;
2050 if (fVme && cbAdjSp == 2 && uIopl != X86_EFL_IOPL)
2051 {
2052 CtxExpect.rip.u = Ctx.rip.u;
2053 CtxExpect.rsp.u = Ctx.rsp.u;
2054 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fCleared) | fXcptRf;
2055 bXcptExpect = X86_XCPT_GP;
2056 }
2057 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2058 if (bs3CpuWeird1_ComparePopf(&TrapCtx, &CtxExpect, bXcptExpect))
2059 break;
2060
2061
2062 /* We repeat the steps with max bits cleared before the popf. */
2063 Ctx.rflags.u32 &= fEflKeep;
2064 Ctx.rflags.u32 |= fEflClear | uIopl;
2065 CtxExpect.rip.u = Ctx.rip.u + offUd;
2066 CtxExpect.rsp.u = fAlwaysGp || fAlwaysUd ? Ctx.rsp.u : Ctx.rsp.u + cbAdjSp;
2067
2068 /*
2069 * Step 3 - pop zero.
2070 */
2071 g_usBs3TestStep++;
2072 PtrStack.pu32[1] = UINT32_MAX;
2073 if (cbAdjSp >= 4)
2074 PtrStack.pu32[0] = 0;
2075 else
2076 {
2077 PtrStack.pu16[1] = UINT16_MAX;
2078 PtrStack.pu16[0] = 0;
2079 }
2080 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fPoppable & ~fCleared) | fXcptRf;
2081 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2082 if (bs3CpuWeird1_ComparePopf(&TrapCtx, &CtxExpect, bXcptNorm))
2083 break;
2084
2085 /*
2086 * Step 4 - pop 0xfffffff sans TF.
2087 */
2088 g_usBs3TestStep++;
2089 PtrStack.pu32[1] = UINT32_MAX;
2090 PtrStack.pu32[0] = UINT32_MAX & ~X86_EFL_TF;
2091 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fPoppable & ~fCleared)
2092 | (UINT32_MAX & ~X86_EFL_TF & fPoppable & ~fCleared)
2093 | fXcptRf;
2094 if (fVme && cbAdjSp == 2 && uIopl != X86_EFL_IOPL)
2095 CtxExpect.rflags.u32 |= X86_EFL_VIF;
2096 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2097 if (bs3CpuWeird1_ComparePopf(&TrapCtx, &CtxExpect, bXcptNorm))
2098 break;
2099
2100 /*
2101 * Step 5 - Pop TF and get a #DB on the following instruction.
2102 */
2103 g_usBs3TestStep++;
2104 PtrStack.pu32[1] = UINT32_MAX;
2105 PtrStack.pu32[0] = UINT32_MAX;
2106 if (cbAdjSp != 2 || !fVme || uIopl == X86_EFL_IOPL)
2107 {
2108 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fPoppable & ~fCleared)
2109 | (UINT32_MAX & fPoppable & ~fCleared)
2110 | fXcptRf;
2111 CtxExpect.rip.u = Ctx.rip.u + offUd;
2112 if (CtxExpect.rip.u != Ctx.rip.u)
2113 {
2114 bXcptExpect = X86_XCPT_DB;
2115 CtxExpect.rflags.u32 &= ~X86_EFL_RF;
2116 }
2117 else
2118 bXcptExpect = bXcptNorm;
2119 }
2120 else
2121 {
2122 CtxExpect.rflags.u32 = Ctx.rflags.u32 | fXcptRf;
2123 CtxExpect.rip.u = Ctx.rip.u;
2124 CtxExpect.rsp.u = Ctx.rsp.u;
2125 PtrStack.pu32[0] = UINT32_MAX & ~X86_EFL_IF; /* only one trigger */
2126 bXcptExpect = X86_XCPT_GP;
2127 }
2128 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2129 if (bs3CpuWeird1_ComparePopf(&TrapCtx, &CtxExpect, bXcptExpect))
2130 break;
2131
2132 /*
2133 * Step 6 - Start with TF set and pop zeros. Should #DB after POPF.
2134 */
2135 g_usBs3TestStep++;
2136 PtrStack.pu32[1] = UINT32_MAX;
2137 if (cbAdjSp >= 4)
2138 PtrStack.pu32[0] = 0;
2139 else
2140 {
2141 PtrStack.pu16[1] = UINT16_MAX;
2142 PtrStack.pu16[0] = 0;
2143 }
2144 Ctx.rflags.u32 |= X86_EFL_TF;
2145 CtxExpect.rip.u = Ctx.rip.u + offUd - !!offUd;
2146 CtxExpect.rsp.u = Ctx.rsp.u + (offUd ? cbAdjSp : 0);
2147 CtxExpect.rflags.u32 = (Ctx.rflags.u32 & ~fPoppable & ~fCleared) | fXcptRf;
2148 if (offUd)
2149 CtxExpect.rflags.u32 &= ~X86_EFL_RF;
2150
2151 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2152 if (bs3CpuWeird1_ComparePopf(&TrapCtx, &CtxExpect, offUd ? X86_XCPT_DB : bXcptNorm))
2153 break;
2154
2155 /** @todo test VIP in VME mode. */
2156 g_usBs3TestStep = (g_usBs3TestStep + 9) / 10 * 10;
2157 }
2158 g_usBs3TestStep = (g_usBs3TestStep + 99) / 100 * 100;
2159 }
2160 g_usBs3TestStep = (g_usBs3TestStep + 999) / 1000 * 1000;
2161 }
2162
2163 /*
2164 * Next ring.
2165 */
2166 if (uRing >= 3 || bTestMode == BS3_MODE_RM)
2167 break;
2168 uRing++;
2169 Bs3RegCtxConvertToRingX(&Ctx, uRing);
2170 CtxExpect.bCpl = Ctx.bCpl;
2171 CtxExpect.ss = Ctx.ss;
2172 CtxExpect.ds = Ctx.ds;
2173 CtxExpect.es = Ctx.es;
2174 CtxExpect.fs = Ctx.fs;
2175 CtxExpect.gs = Ctx.gs;
2176 g_usBs3TestStep = (g_usBs3TestStep + 9999) / 10000 * 10000;
2177 }
2178
2179 return 0;
2180}
2181
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