VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c@ 60527

Last change on this file since 60527 was 60527, checked in by vboxsync, 9 years ago

bs3kit: Far updates.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.1 KB
Line 
1/* $Id: bs3-cpu-basic-2-template.c 60527 2016-04-18 09:11:04Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-basic-2, C code template.
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#ifdef BS3_INSTANTIATING_MODE
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#include <iprt/asm.h>
34#include <iprt/asm-amd64-x86.h>
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40# undef MyBs3Idt
41# undef MY_SYS_SEL_R0_CS
42# undef MY_SYS_SEL_R0_CS_CNF
43# undef MY_SYS_SEL_R0_DS
44# undef MY_SYS_SEL_R0_SS
45# if BS3_MODE_IS_16BIT_SYS(TMPL_MODE)
46# define MyBs3Idt Bs3Idt16
47# define MY_SYS_SEL_R0_CS BS3_SEL_R0_CS16
48# define MY_SYS_SEL_R0_CS_CNF BS3_SEL_R0_CS16_CNF
49# define MY_SYS_SEL_R0_DS BS3_SEL_R0_DS16
50# define MY_SYS_SEL_R0_SS BS3_SEL_R0_SS16
51# elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE)
52# define MyBs3Idt Bs3Idt32
53# define MY_SYS_SEL_R0_CS BS3_SEL_R0_CS32
54# define MY_SYS_SEL_R0_CS_CNF BS3_SEL_R0_CS32_CNF
55# define MY_SYS_SEL_R0_DS BS3_SEL_R0_DS32
56# define MY_SYS_SEL_R0_SS BS3_SEL_R0_SS32
57# elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
58# define MyBs3Idt Bs3Idt64
59# define MY_SYS_SEL_R0_CS BS3_SEL_R0_CS64
60# define MY_SYS_SEL_R0_CS_CNF BS3_SEL_R0_CS64_CNF
61# define MY_SYS_SEL_R0_DS BS3_SEL_R0_DS64
62# define MY_SYS_SEL_R0_SS BS3_SEL_R0_DS64
63# else
64# error "TMPL_MODE"
65# endif
66#undef CHECK_MEMBER
67#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \
68 do \
69 { \
70 if ((a_Actual) == (a_Expected)) { /* likely */ } \
71 else bs3CpuBasic2_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \
72 } while (0)
73
74
75/*********************************************************************************************************************************
76* Structures and Typedefs *
77*********************************************************************************************************************************/
78#ifndef DONE_MODE_TYPES
79#define DONE_MODE_TYPES
80typedef struct BS3CB2INVLDESCTYPE
81{
82 uint8_t u4Type;
83 uint8_t u1DescType;
84} BS3CB2INVLDESCTYPE;
85#endif
86
87
88/*********************************************************************************************************************************
89* External Symbols *
90*********************************************************************************************************************************/
91extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_Int80)(void);
92extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_Int81)(void);
93extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_Int82)(void);
94extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_Int83)(void);
95extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_ud2)(void);
96extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_sidt_bx_ud2)(void);
97extern BS3_DECL(void) TMPL_NM(bs3CpuBasic2_lidt_bx_ud2)(void);
98#ifndef DOXYGEN_RUNNING
99# define g_bs3CpuBasic2_ud2_FlatAddr BS3_DATA_NM(g_bs3CpuBasic2_ud2_FlatAddr)
100#endif
101extern uint32_t g_bs3CpuBasic2_ud2_FlatAddr;
102
103
104/*********************************************************************************************************************************
105* Global Variables *
106*********************************************************************************************************************************/
107#if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16_32 || TMPL_MODE == BS3_MODE_LM64
108#define g_pszTestMode BS3_CMN_NM(g_pszTestMode)
109static const char BS3_FAR *g_pszTestMode = (const char *)1;
110#define g_bTestMode BS3_CMN_NM(g_bTestMode)
111static uint8_t g_bTestMode = 1;
112#define g_f16BitSys BS3_CMN_NM(g_f16BitSys)
113static bool g_f16BitSys = 1;
114
115/** Table containing invalid CS selector types. */
116static const BS3CB2INVLDESCTYPE g_aInvalidCsTypes[] =
117{
118 { X86_SEL_TYPE_RO, 1 },
119 { X86_SEL_TYPE_RO_ACC, 1 },
120 { X86_SEL_TYPE_RW, 1 },
121 { X86_SEL_TYPE_RW_ACC, 1 },
122 { X86_SEL_TYPE_RO_DOWN, 1 },
123 { X86_SEL_TYPE_RO_DOWN_ACC, 1 },
124 { X86_SEL_TYPE_RW_DOWN, 1 },
125 { X86_SEL_TYPE_RW_DOWN_ACC, 1 },
126 { 0, 0 },
127 { 1, 0 },
128 { 2, 0 },
129 { 3, 0 },
130 { 4, 0 },
131 { 5, 0 },
132 { 6, 0 },
133 { 7, 0 },
134 { 8, 0 },
135 { 9, 0 },
136 { 10, 0 },
137 { 11, 0 },
138 { 12, 0 },
139 { 13, 0 },
140 { 14, 0 },
141 { 15, 0 },
142};
143
144/** Table containing invalid SS selector types. */
145static const BS3CB2INVLDESCTYPE g_aInvalidSsTypes[] =
146{
147 { X86_SEL_TYPE_EO, 1 },
148 { X86_SEL_TYPE_EO_ACC, 1 },
149 { X86_SEL_TYPE_ER, 1 },
150 { X86_SEL_TYPE_ER_ACC, 1 },
151 { X86_SEL_TYPE_EO_CONF, 1 },
152 { X86_SEL_TYPE_EO_CONF_ACC, 1 },
153 { X86_SEL_TYPE_ER_CONF, 1 },
154 { X86_SEL_TYPE_ER_CONF_ACC, 1 },
155 { 0, 0 },
156 { 1, 0 },
157 { 2, 0 },
158 { 3, 0 },
159 { 4, 0 },
160 { 5, 0 },
161 { 6, 0 },
162 { 7, 0 },
163 { 8, 0 },
164 { 9, 0 },
165 { 10, 0 },
166 { 11, 0 },
167 { 12, 0 },
168 { 13, 0 },
169 { 14, 0 },
170 { 15, 0 },
171};
172
173#endif
174
175#if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16_32 || TMPL_MODE == BS3_MODE_LM64
176
177/**
178 * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep
179 * and g_pszTestMode.
180 */
181#define bs3CpuBasic2_FailedF BS3_CMN_NM(bs3CpuBasic2_FailedF)
182void bs3CpuBasic2_FailedF(const char *pszFormat, ...)
183{
184 va_list va;
185
186 char szTmp[168];
187 va_start(va, pszFormat);
188 Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va);
189 va_end(va);
190
191 Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp);
192}
193
194
195/**
196 * Compares trap stuff.
197 */
198#define bs3CpuBasic2_CompareIntCtx1 BS3_CMN_NM(bs3CpuBasic2_CompareIntCtx1)
199void bs3CpuBasic2_CompareIntCtx1(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt)
200{
201 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
202 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
203 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
204 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 2 /*int xx*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
205 if (Bs3TestSubErrorCount() != cErrorsBefore)
206 {
207 Bs3TrapPrintFrame(pTrapCtx);
208#if 1
209 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
210 Bs3TestPrintf("Halting in CompareTrapCtx1: bXcpt=%#x\n", bXcpt);
211 ASMHalt();
212#endif
213 }
214}
215
216
217/**
218 * Compares trap stuff.
219 */
220#define bs3CpuBasic2_CompareTrapCtx2 BS3_CMN_NM(bs3CpuBasic2_CompareTrapCtx2)
221void bs3CpuBasic2_CompareTrapCtx2(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t cbIpAdjust, uint8_t bXcpt,
222 uint16_t uHandlerCs)
223{
224 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
225 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
226 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
227 CHECK_MEMBER("uHandlerCs", "%#06x", pTrapCtx->uHandlerCs, uHandlerCs);
228 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
229 if (Bs3TestSubErrorCount() != cErrorsBefore)
230 {
231 Bs3TrapPrintFrame(pTrapCtx);
232#if 1
233 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
234 Bs3TestPrintf("Halting in CompareTrapCtx2: bXcpt=%#x\n", bXcpt);
235 ASMHalt();
236#endif
237 }
238}
239
240/**
241 * Compares a CPU trap.
242 */
243#define bs3CpuBasic2_CompareCpuTrapCtx BS3_CMN_NM(bs3CpuBasic2_CompareCpuTrapCtx)
244BS3_DECL(void) bs3CpuBasic2_CompareCpuTrapCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, uint8_t bXcpt,
245 bool f486ResumeFlagHint)
246{
247 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
248 uint32_t fExtraEfl;
249
250 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
251 CHECK_MEMBER("bErrCd", "%#06RX16", (uint16_t)pTrapCtx->uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
252
253 fExtraEfl = X86_EFL_RF;
254 if ( g_f16BitSys
255 || ( !f486ResumeFlagHint
256 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80486 ) )
257 fExtraEfl = 0;
258 else
259 fExtraEfl = X86_EFL_RF;
260 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 0 /*cbIpAdjust*/, 0 /*cbSpAdjust*/, fExtraEfl, g_pszTestMode, g_usBs3TestStep);
261 if (Bs3TestSubErrorCount() != cErrorsBefore)
262 {
263 Bs3TrapPrintFrame(pTrapCtx);
264#if 1
265 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
266 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
267 ASMHalt();
268#endif
269 }
270}
271
272
273/**
274 * Compares \#GP trap.
275 */
276#define bs3CpuBasic2_CompareGpCtx BS3_CMN_NM(bs3CpuBasic2_CompareGpCtx)
277void bs3CpuBasic2_CompareGpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
278{
279 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_GP, true /*f486ResumeFlagHint*/);
280}
281
282/**
283 * Compares \#NP trap.
284 */
285#define bs3CpuBasic2_CompareNpCtx BS3_CMN_NM(bs3CpuBasic2_CompareNpCtx)
286void bs3CpuBasic2_CompareNpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
287{
288 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_NP, true /*f486ResumeFlagHint*/);
289}
290
291/**
292 * Compares \#SS trap.
293 */
294#define bs3CpuBasic2_CompareSsCtx BS3_CMN_NM(bs3CpuBasic2_CompareSsCtx)
295void bs3CpuBasic2_CompareSsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, bool f486ResumeFlagHint)
296{
297 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_SS, f486ResumeFlagHint);
298}
299
300/**
301 * Compares \#TS trap.
302 */
303#define bs3CpuBasic2_CompareTsCtx BS3_CMN_NM(bs3CpuBasic2_CompareTsCtx)
304void bs3CpuBasic2_CompareTsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
305{
306 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_TS, false /*f486ResumeFlagHint*/);
307}
308
309/**
310 * Compares \#PF trap.
311 */
312#define bs3CpuBasic2_ComparePfCtx BS3_CMN_NM(bs3CpuBasic2_ComparePfCtx)
313void bs3CpuBasic2_ComparePfCtx(PCBS3TRAPFRAME pTrapCtx, PBS3REGCTX pStartCtx, uint16_t uErrCd, uint64_t uCr2Expected)
314{
315 uint64_t const uCr2Saved = pStartCtx->cr2.u;
316 pStartCtx->cr2.u = uCr2Expected;
317 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_PF, true /*f486ResumeFlagHint*/);
318 pStartCtx->cr2.u = uCr2Saved;
319}
320
321/**
322 * Compares \#UD trap.
323 */
324#define bs3CpuBasic2_CompareUdCtx BS3_CMN_NM(bs3CpuBasic2_CompareUdCtx)
325void bs3CpuBasic2_CompareUdCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx)
326{
327 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*no error code*/, X86_XCPT_UD, true /*f486ResumeFlagHint*/);
328}
329
330
331#define bs3CpuBasic2_RaiseXcpt1Common BS3_CMN_NM(bs3CpuBasic2_RaiseXcpt1Common)
332static void bs3CpuBasic2_RaiseXcpt1Common(bool const g_f16BitSys,
333 uint16_t const uSysR0Cs, uint16_t const uSysR0CsConf, uint16_t const uSysR0Ss,
334 PX86DESC const paIdt, unsigned const cIdteShift)
335{
336 BS3TRAPFRAME TrapCtx;
337 BS3REGCTX Ctx80;
338 BS3REGCTX Ctx81;
339 BS3REGCTX Ctx82;
340 BS3REGCTX Ctx83;
341 BS3REGCTX CtxTmp;
342 BS3REGCTX CtxTmp2;
343 PBS3REGCTX apCtx8x[4];
344 unsigned iCtx;
345 unsigned iRing;
346 unsigned iDpl;
347 unsigned iRpl;
348 unsigned i, j, k;
349 uint32_t uExpected;
350 bool const f486Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486;
351# if TMPL_BITS == 16
352 bool const f386Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386;
353 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
354# else
355 bool const f286 = false;
356 bool const f386Plus = true;
357 int rc;
358 uint8_t *pbIdtCopyAlloc;
359 PX86DESC pIdtCopy;
360 const unsigned cbIdte = 1 << (3 + cIdteShift);
361 RTCCUINTXREG uCr0Saved = ASMGetCR0();
362 RTGDTR GdtrSaved;
363# endif
364 RTIDTR IdtrSaved;
365 RTIDTR Idtr;
366
367 ASMGetIDTR(&IdtrSaved);
368# if TMPL_BITS != 16
369 ASMGetGDTR(&GdtrSaved);
370# endif
371
372 /* make sure they're allocated */
373 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
374 Bs3MemZero(&Ctx80, sizeof(Ctx80));
375 Bs3MemZero(&Ctx81, sizeof(Ctx81));
376 Bs3MemZero(&Ctx82, sizeof(Ctx82));
377 Bs3MemZero(&Ctx83, sizeof(Ctx83));
378 Bs3MemZero(&CtxTmp, sizeof(CtxTmp));
379 Bs3MemZero(&CtxTmp2, sizeof(CtxTmp2));
380
381 /* Context array. */
382 apCtx8x[0] = &Ctx80;
383 apCtx8x[1] = &Ctx81;
384 apCtx8x[2] = &Ctx82;
385 apCtx8x[3] = &Ctx83;
386
387# if TMPL_BITS != 16
388 /* Allocate memory for playing around with the IDT. */
389 pbIdtCopyAlloc = NULL;
390 if (BS3_MODE_IS_PAGED(g_bTestMode))
391 pbIdtCopyAlloc = Bs3MemAlloc(BS3MEMKIND_FLAT32, 12*_1K);
392# endif
393
394 /*
395 * IDT entry 80 thru 83 are assigned DPLs according to the number.
396 * (We'll be useing more, but this'll do for now.)
397 */
398 paIdt[0x80 << cIdteShift].Gate.u2Dpl = 0;
399 paIdt[0x81 << cIdteShift].Gate.u2Dpl = 1;
400 paIdt[0x82 << cIdteShift].Gate.u2Dpl = 2;
401 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
402
403 Bs3RegCtxSave(&Ctx80);
404 Ctx80.rsp.u -= 0x300;
405 Ctx80.rip.u = (uintptr_t)BS3_FP_OFF(&TMPL_NM(bs3CpuBasic2_Int80));
406# if TMPL_BITS == 32
407 g_uBs3TrapEipHint = Ctx80.rip.u32;
408# endif
409 Bs3MemCpy(&Ctx81, &Ctx80, sizeof(Ctx80));
410 Ctx81.rip.u = (uintptr_t)BS3_FP_OFF(&TMPL_NM(bs3CpuBasic2_Int81));
411 Bs3MemCpy(&Ctx82, &Ctx80, sizeof(Ctx80));
412 Ctx82.rip.u = (uintptr_t)BS3_FP_OFF(&TMPL_NM(bs3CpuBasic2_Int82));
413 Bs3MemCpy(&Ctx83, &Ctx80, sizeof(Ctx80));
414 Ctx83.rip.u = (uintptr_t)BS3_FP_OFF(&TMPL_NM(bs3CpuBasic2_Int83));
415
416 /*
417 * Check that all the above gates work from ring-0.
418 */
419 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
420 {
421 g_usBs3TestStep = iCtx;
422# if TMPL_BITS == 32
423 g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32;
424# endif
425 Bs3TrapSetJmpAndRestore(apCtx8x[iCtx], &TrapCtx);
426 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, apCtx8x[iCtx], 0x80+iCtx /*bXcpt*/);
427 }
428
429 /*
430 * Check that the gate DPL checks works.
431 */
432 g_usBs3TestStep = 100;
433 for (iRing = 0; iRing <= 3; iRing++)
434 {
435 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
436 {
437 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
438 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
439# if TMPL_BITS == 32
440 g_uBs3TrapEipHint = CtxTmp.rip.u32;
441# endif
442 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
443 if (iCtx < iRing)
444 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
445 else
446 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
447 g_usBs3TestStep++;
448 }
449 }
450
451 /*
452 * Modify the gate CS value and run the handler at a different CPL.
453 * Throw RPL variations into the mix (completely ignored) together
454 * with gate presence.
455 * 1. CPL <= GATE.DPL
456 * 2. GATE.P
457 * 3. GATE.CS.DPL <= CPL (non-conforming segments)
458 */
459 g_usBs3TestStep = 1000;
460 for (i = 0; i <= 3; i++)
461 {
462 for (iRing = 0; iRing <= 3; iRing++)
463 {
464 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
465 {
466# if TMPL_BITS == 32
467 g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32;
468# endif
469 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
470 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
471
472 for (j = 0; j <= 3; j++)
473 {
474 uint16_t const uCs = (uSysR0Cs | j) + (i << BS3_SEL_RING_SHIFT);
475 for (k = 0; k < 2; k++)
476 {
477 g_usBs3TestStep++;
478 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
479 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
480 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = k;
481 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
482 /*Bs3TrapPrintFrame(&TrapCtx);*/
483 if (iCtx < iRing)
484 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
485 else if (k == 0)
486 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
487 else if (i > iRing)
488 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
489 else
490 {
491 uint16_t uExpectedCs = uCs & X86_SEL_MASK_OFF_RPL;
492 if (i <= iCtx && i <= iRing)
493 uExpectedCs |= i;
494 bs3CpuBasic2_CompareTrapCtx2(&TrapCtx, &CtxTmp, 2 /*int 8xh*/, 0x80 + iCtx /*bXcpt*/, uExpectedCs);
495 }
496 }
497 }
498
499 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
500 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
501 }
502 }
503 }
504 BS3_ASSERT(g_usBs3TestStep < 1600);
505
506 /*
507 * Various CS and SS related faults
508 *
509 * We temporarily reconfigure gate 80 and 83 with new CS selectors, the
510 * latter have a CS.DPL of 2 for testing ring transisions and SS loading
511 * without making it impossible to handle faults.
512 */
513 g_usBs3TestStep = 1600;
514 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
515 Bs3GdteTestPage00.Gen.u1Present = 0;
516 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
517 paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00;
518
519 /* CS.PRESENT = 0 */
520 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
521 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
522 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
523 bs3CpuBasic2_FailedF("selector was accessed");
524 g_usBs3TestStep++;
525
526 /* Check that GATE.DPL is checked before CS.PRESENT. */
527 for (iRing = 1; iRing < 4; iRing++)
528 {
529 Bs3MemCpy(&CtxTmp, &Ctx80, sizeof(CtxTmp));
530 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
531 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
532 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x80 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
533 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
534 bs3CpuBasic2_FailedF("selector was accessed");
535 g_usBs3TestStep++;
536 }
537
538 /* CS.DPL mismatch takes precedence over CS.PRESENT = 0. */
539 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
540 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
541 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
542 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
543 bs3CpuBasic2_FailedF("CS selector was accessed");
544 g_usBs3TestStep++;
545 for (iDpl = 1; iDpl < 4; iDpl++)
546 {
547 Bs3GdteTestPage00.Gen.u2Dpl = iDpl;
548 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
549 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
550 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
551 bs3CpuBasic2_FailedF("CS selector was accessed");
552 g_usBs3TestStep++;
553 }
554
555 /* 1608: Check all the invalid CS selector types alone. */
556 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
557 for (i = 0; i < RT_ELEMENTS(g_aInvalidCsTypes); i++)
558 {
559 Bs3GdteTestPage00.Gen.u4Type = g_aInvalidCsTypes[i].u4Type;
560 Bs3GdteTestPage00.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType;
561 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
562 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
563 if (Bs3GdteTestPage00.Gen.u4Type != g_aInvalidCsTypes[i].u4Type)
564 bs3CpuBasic2_FailedF("Invalid CS type %#x/%u -> %#x/%u\n",
565 g_aInvalidCsTypes[i].u4Type, g_aInvalidCsTypes[i].u1DescType,
566 Bs3GdteTestPage00.Gen.u4Type, Bs3GdteTestPage00.Gen.u1DescType);
567 g_usBs3TestStep++;
568
569 /* Incorrect CS.TYPE takes precedence over CS.PRESENT = 0. */
570 Bs3GdteTestPage00.Gen.u1Present = 0;
571 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
572 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
573 Bs3GdteTestPage00.Gen.u1Present = 1;
574 g_usBs3TestStep++;
575 }
576
577 /* Fix CS again. */
578 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
579
580 /* 1632: Test SS. */
581 if (!BS3_MODE_IS_64BIT_SYS(g_bTestMode))
582 {
583 uint16_t BS3_FAR *puTssSs2 = BS3_MODE_IS_16BIT_SYS(g_bTestMode) ? &Bs3Tss16.ss2 : &Bs3Tss32.ss2;
584 uint16_t const uSavedSs2 = *puTssSs2;
585 X86DESC const SavedGate83 = paIdt[0x83 << cIdteShift];
586
587 /* Make the handler execute in ring-2. */
588 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
589 Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
590 paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_02 | 2;
591
592 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
593 Bs3RegCtxConvertToRingX(&CtxTmp, 3); /* yeah, from 3 so SS:xSP is reloaded. */
594 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
595 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
596 if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
597 bs3CpuBasic2_FailedF("CS selector was not access");
598 g_usBs3TestStep++;
599
600 /* Create a SS.DPL=2 stack segment and check that SS2.RPL matters and
601 that we get #SS if the selector isn't present. */
602 i = 0; /* used for cycling thru invalid CS types */
603 for (k = 0; k < 10; k++)
604 {
605 /* k=0: present,
606 k=1: not-present,
607 k=2: present but very low limit,
608 k=3: not-present, low limit.
609 k=4: present, read-only.
610 k=5: not-present, read-only.
611 k=6: present, code-selector.
612 k=7: not-present, code-selector.
613 k=8: present, read-write / no access + system (=LDT).
614 k=9: not-present, read-write / no access + system (=LDT).
615 */
616 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
617 Bs3GdteTestPage03.Gen.u1Present = !(k & 1);
618 if (k >= 8)
619 {
620 Bs3GdteTestPage03.Gen.u1DescType = 0; /* system */
621 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW; /* = LDT */
622 }
623 else if (k >= 6)
624 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_ER;
625 else if (k >= 4)
626 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RO;
627 else if (k >= 2)
628 {
629 Bs3GdteTestPage03.Gen.u16LimitLow = 0x400;
630 Bs3GdteTestPage03.Gen.u4LimitHigh = 0;
631 Bs3GdteTestPage03.Gen.u1Granularity = 0;
632 }
633
634 for (iDpl = 0; iDpl < 4; iDpl++)
635 {
636 Bs3GdteTestPage03.Gen.u2Dpl = iDpl;
637
638 for (iRpl = 0; iRpl < 4; iRpl++)
639 {
640 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | iRpl;
641 //Bs3TestPrintf("k=%u iDpl=%u iRpl=%u step=%u\n", k, iDpl, iRpl, g_usBs3TestStep);
642 Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
643 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
644 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
645 if (iRpl != 2 || iRpl != iDpl || k >= 4)
646 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
647 else if (k != 0)
648 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03,
649 k == 2 /*f486ResumeFlagHint*/);
650 else
651 {
652 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
653 if (TrapCtx.uHandlerSs != (BS3_SEL_TEST_PAGE_03 | 2))
654 bs3CpuBasic2_FailedF("uHandlerSs=%#x expected %#x\n", TrapCtx.uHandlerSs, BS3_SEL_TEST_PAGE_03 | 2);
655 }
656 if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
657 bs3CpuBasic2_FailedF("CS selector was not access");
658 if ( TrapCtx.bXcpt == 0x83
659 || (TrapCtx.bXcpt == X86_XCPT_SS && k == 2) )
660 {
661 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
662 bs3CpuBasic2_FailedF("SS selector was not accessed");
663 }
664 else if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
665 bs3CpuBasic2_FailedF("SS selector was accessed");
666 g_usBs3TestStep++;
667
668 /* +1: Modify the gate DPL to check that this is checked before SS.DPL and SS.PRESENT. */
669 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 2;
670 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
671 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x83 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
672 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
673 g_usBs3TestStep++;
674
675 /* +2: Check the the CS.DPL check is done before the SS ones. Restoring the
676 ring-0 INT 83 context triggers the CS.DPL < CPL check. */
677 Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx);
678 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02);
679 g_usBs3TestStep++;
680
681 /* +3: Now mark the CS selector not present and check that that also triggers before SS stuff. */
682 Bs3GdteTestPage02.Gen.u1Present = 0;
683 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
684 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02);
685 Bs3GdteTestPage02.Gen.u1Present = 1;
686 g_usBs3TestStep++;
687
688 /* +4: Make the CS selector some invalid type and check it triggers before SS stuff. */
689 Bs3GdteTestPage02.Gen.u4Type = g_aInvalidCsTypes[i].u4Type;
690 Bs3GdteTestPage02.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType;
691 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
692 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02);
693 Bs3GdteTestPage02.Gen.u4Type = X86_SEL_TYPE_ER_ACC;
694 Bs3GdteTestPage02.Gen.u1DescType = 1;
695 g_usBs3TestStep++;
696
697 /* +5: Now, make the CS selector limit too small and that it triggers after SS trouble.
698 The 286 had a simpler approach to these GP(0). */
699 Bs3GdteTestPage02.Gen.u16LimitLow = 0;
700 Bs3GdteTestPage02.Gen.u4LimitHigh = 0;
701 Bs3GdteTestPage02.Gen.u1Granularity = 0;
702 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
703 if (f286)
704 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/);
705 else if (iRpl != 2 || iRpl != iDpl || k >= 4)
706 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
707 else if (k != 0)
708 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, k == 2 /*f486ResumeFlagHint*/);
709 else
710 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/);
711 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
712 g_usBs3TestStep++;
713 }
714 }
715 }
716
717 /* Check all the invalid SS selector types alone. */
718 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
719 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
720 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2;
721 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
722 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
723 g_usBs3TestStep++;
724 for (i = 0; i < RT_ELEMENTS(g_aInvalidSsTypes); i++)
725 {
726 Bs3GdteTestPage03.Gen.u4Type = g_aInvalidSsTypes[i].u4Type;
727 Bs3GdteTestPage03.Gen.u1DescType = g_aInvalidSsTypes[i].u1DescType;
728 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
729 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
730 if (Bs3GdteTestPage03.Gen.u4Type != g_aInvalidSsTypes[i].u4Type)
731 bs3CpuBasic2_FailedF("Invalid SS type %#x/%u -> %#x/%u\n",
732 g_aInvalidSsTypes[i].u4Type, g_aInvalidSsTypes[i].u1DescType,
733 Bs3GdteTestPage03.Gen.u4Type, Bs3GdteTestPage03.Gen.u1DescType);
734 g_usBs3TestStep++;
735 }
736
737 /*
738 * Continue the SS experiments with a expand down segment. We'll use
739 * the same setup as we already have with gate 83h being DPL and
740 * having CS.DPL=2.
741 *
742 * Expand down segments are weird. The valid area is practically speaking
743 * reversed. So, a 16-bit segment with a limit of 0x6000 will have valid
744 * addresses from 0xffff thru 0x6001.
745 *
746 * So, with expand down segments we can more easily cut partially into the
747 * pushing of the iret frame and trigger more interesting behavior than
748 * with regular "expand up" segments where the whole pushing area is either
749 * all fine or not not fine.
750 */
751 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
752 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
753 Bs3GdteTestPage03.Gen.u2Dpl = 2;
754 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW_DOWN;
755 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2;
756
757 /* First test, limit = max --> no bytes accessible --> #GP */
758 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
759 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/);
760
761 /* Second test, limit = 0 --> all by zero byte accessible --> works */
762 Bs3GdteTestPage03.Gen.u16LimitLow = 0;
763 Bs3GdteTestPage03.Gen.u4LimitHigh = 0;
764 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
765 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
766
767 /* Modify the gate handler to be a dummy that immediately does UD2
768 and triggers #UD, then advance the limit down till we get the #UD. */
769 Bs3GdteTestPage03.Gen.u1Granularity = 0;
770
771 Bs3MemCpy(&CtxTmp2, &CtxTmp, sizeof(CtxTmp2)); /* #UD result context */
772 if (g_f16BitSys)
773 {
774 CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr - BS3_ADDR_BS3TEXT16;
775 Bs3Trap16SetGate(0x83, X86_SEL_TYPE_SYS_286_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u16, 0 /*cParams*/);
776 CtxTmp2.rsp.u = Bs3Tss16.sp2 - 2*5;
777 }
778 else
779 {
780 CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr;
781 Bs3Trap32SetGate(0x83, X86_SEL_TYPE_SYS_386_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u32, 0 /*cParams*/);
782 CtxTmp2.rsp.u = Bs3Tss32.esp2 - 4*5;
783 }
784 CtxTmp2.bMode = g_bTestMode; /* g_bBs3CurrentMode not changed by the UD2 handler. */
785 CtxTmp2.cs = BS3_SEL_TEST_PAGE_02 | 2;
786 CtxTmp2.ss = BS3_SEL_TEST_PAGE_03 | 2;
787 CtxTmp2.bCpl = 2;
788
789 /* test run. */
790 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
791 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
792 g_usBs3TestStep++;
793
794 /* Real run. */
795 i = (g_f16BitSys ? 2 : 4) * 6 + 1;
796 while (i-- > 0)
797 {
798 Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1;
799 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
800 if (i > 0)
801 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/);
802 else
803 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
804 g_usBs3TestStep++;
805 }
806
807 /* Do a run where we do the same-ring kind of access. */
808 Bs3RegCtxConvertToRingX(&CtxTmp, 2);
809 if (g_f16BitSys)
810 {
811 CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 2*3;
812 i = 2*3 - 1;
813 }
814 else
815 {
816 CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 4*3;
817 i = 4*3 - 1;
818 }
819 CtxTmp.ss = BS3_SEL_TEST_PAGE_03 | 2;
820 CtxTmp2.ds = CtxTmp.ds;
821 CtxTmp2.es = CtxTmp.es;
822 CtxTmp2.fs = CtxTmp.fs;
823 CtxTmp2.gs = CtxTmp.gs;
824 while (i-- > 0)
825 {
826 Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1;
827 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
828 if (i > 0)
829 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, 0 /*BS3_SEL_TEST_PAGE_03*/, true /*f486ResumeFlagHint*/);
830 else
831 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
832 g_usBs3TestStep++;
833 }
834
835 *puTssSs2 = uSavedSs2;
836 paIdt[0x83 << cIdteShift] = SavedGate83;
837 }
838 paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs;
839 BS3_ASSERT(g_usBs3TestStep < 3000);
840
841 /*
842 * Modify the gate CS value with a conforming segment.
843 */
844 g_usBs3TestStep = 3000;
845 for (i = 0; i <= 3; i++) /* cs.dpl */
846 {
847 for (iRing = 0; iRing <= 3; iRing++)
848 {
849 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
850 {
851 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
852 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
853# if TMPL_BITS == 32
854 g_uBs3TrapEipHint = CtxTmp.rip.u32;
855# endif
856
857 for (j = 0; j <= 3; j++) /* rpl */
858 {
859 uint16_t const uCs = (uSysR0CsConf | j) + (i << BS3_SEL_RING_SHIFT);
860 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
861 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
862 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
863 //Bs3TestPrintf("%u/%u/%u/%u: cs=%04x hcs=%04x xcpt=%02x\n", i, iRing, iCtx, j, uCs, TrapCtx.uHandlerCs, TrapCtx.bXcpt);
864 /*Bs3TrapPrintFrame(&TrapCtx);*/
865 g_usBs3TestStep++;
866 if (iCtx < iRing)
867 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
868 else if (i > iRing)
869 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
870 else
871 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
872 }
873 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
874 }
875 }
876 }
877 BS3_ASSERT(g_usBs3TestStep < 3500);
878
879 /*
880 * The gates must be 64-bit in long mode.
881 */
882 if (cIdteShift != 0)
883 {
884 g_usBs3TestStep = 3500;
885 for (i = 0; i <= 3; i++)
886 {
887 for (iRing = 0; iRing <= 3; iRing++)
888 {
889 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
890 {
891 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
892 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
893
894 for (j = 0; j < 2; j++)
895 {
896 static const uint16_t s_auCSes[2] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32 };
897 uint16_t uCs = (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT);
898 g_usBs3TestStep++;
899 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
900 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
901 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
902 /*Bs3TrapPrintFrame(&TrapCtx);*/
903 if (iCtx < iRing)
904 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
905 else
906 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
907 }
908 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
909 }
910 }
911 }
912 BS3_ASSERT(g_usBs3TestStep < 4000);
913 }
914
915 /*
916 * IDT limit check. The 286 does not access X86DESCGATE::u16OffsetHigh.
917 */
918 g_usBs3TestStep = 5000;
919 i = (0x80 << (cIdteShift + 3)) - 1;
920 j = (0x82 << (cIdteShift + 3)) - (!f286 ? 1 : 3);
921 k = (0x83 << (cIdteShift + 3)) - 1;
922 for (; i <= k; i++, g_usBs3TestStep++)
923 {
924 Idtr = IdtrSaved;
925 Idtr.cbIdt = i;
926 ASMSetIDTR(&Idtr);
927 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
928 if (i < j)
929 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx81, (0x81 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
930 else
931 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
932 }
933 ASMSetIDTR(&IdtrSaved);
934 BS3_ASSERT(g_usBs3TestStep < 5100);
935
936# if TMPL_BITS != 16 /* Only do the paging related stuff in 32-bit and 64-bit modes. */
937
938 /*
939 * IDT page not present. Placing the IDT copy such that 0x80 is on the
940 * first page and 0x81 is on the second page. We need proceed to move
941 * it down byte by byte to check that any inaccessible byte means #PF.
942 *
943 * Note! We must reload the alternative IDTR for each run as any kind of
944 * printing to the string (like error reporting) will cause a switch
945 * to real mode and back, reloading the default IDTR.
946 */
947 g_usBs3TestStep = 5200;
948 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
949 {
950 uint32_t const uCr2Expected = Bs3SelPtrToFlat(pbIdtCopyAlloc) + _4K;
951 for (j = 0; j < cbIdte; j++)
952 {
953 pIdtCopy = (PX86DESC)&pbIdtCopyAlloc[_4K - cbIdte * 0x81 - j];
954 Bs3MemCpy(pIdtCopy, paIdt, cbIdte * 256);
955
956 Idtr.cbIdt = IdtrSaved.cbIdt;
957 Idtr.pIdt = Bs3SelPtrToFlat(pIdtCopy);
958
959 ASMSetIDTR(&Idtr);
960 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
961 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
962 g_usBs3TestStep++;
963
964 ASMSetIDTR(&Idtr);
965 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
966 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
967 g_usBs3TestStep++;
968
969 rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/);
970 if (RT_SUCCESS(rc))
971 {
972 ASMSetIDTR(&Idtr);
973 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
974 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
975 g_usBs3TestStep++;
976
977 ASMSetIDTR(&Idtr);
978 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
979 if (f486Plus)
980 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected);
981 else
982 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4));
983 g_usBs3TestStep++;
984
985 Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/);
986
987 /* Check if that the entry type is checked after the whole IDTE has been cleared for #PF. */
988 pIdtCopy[0x80 << cIdteShift].Gate.u4Type = 0;
989 rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/);
990 if (RT_SUCCESS(rc))
991 {
992 ASMSetIDTR(&Idtr);
993 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
994 if (f486Plus)
995 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected);
996 else
997 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4));
998 g_usBs3TestStep++;
999
1000 Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1001 }
1002 }
1003 else
1004 Bs3TestPrintf("Bs3PagingProtectPtr: %d\n", i);
1005
1006 ASMSetIDTR(&IdtrSaved);
1007 }
1008 }
1009
1010 /*
1011 * The read/write and user/supervisor bits the IDT PTEs are irrelevant.
1012 */
1013 g_usBs3TestStep = 5300;
1014 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1015 {
1016 Bs3MemCpy(pbIdtCopyAlloc, paIdt, cbIdte * 256);
1017 Idtr.cbIdt = IdtrSaved.cbIdt;
1018 Idtr.pIdt = Bs3SelPtrToFlat(pbIdtCopyAlloc);
1019
1020 ASMSetIDTR(&Idtr);
1021 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1022 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1023 g_usBs3TestStep++;
1024
1025 rc = Bs3PagingProtect(Idtr.pIdt, _4K, 0 /*fSet*/, X86_PTE_RW | X86_PTE_US /*fClear*/);
1026 if (RT_SUCCESS(rc))
1027 {
1028 ASMSetIDTR(&Idtr);
1029 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1030 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1031 g_usBs3TestStep++;
1032
1033 Bs3PagingProtect(Idtr.pIdt, _4K, X86_PTE_RW | X86_PTE_US /*fSet*/, 0 /*fClear*/);
1034 }
1035 ASMSetIDTR(&IdtrSaved);
1036 }
1037
1038 /*
1039 * Check that CS.u1Accessed is set to 1. Use the test page selector #0 and #3 together
1040 * with interrupt gates 80h and 83h, respectively.
1041 */
1042/** @todo Throw in SS.u1Accessed too. */
1043 g_usBs3TestStep = 5400;
1044 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1045 {
1046 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
1047 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1048 paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00;
1049
1050 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Cs + (3 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1051 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1052 paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_03; /* rpl is ignored, so leave it as zero. */
1053
1054 /* Check that the CS.A bit is being set on a general basis and that
1055 the special CS values work with out generic handler code. */
1056 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1057 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1058 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1059 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed", Bs3GdteTestPage00.Gen.u4Type);
1060 g_usBs3TestStep++;
1061
1062 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1063 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1064 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1065 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1066 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1067 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1068 if (TrapCtx.uHandlerCs != (BS3_SEL_TEST_PAGE_03 | 3))
1069 bs3CpuBasic2_FailedF("uHandlerCs=%#x, expected %#x", TrapCtx.uHandlerCs, (BS3_SEL_TEST_PAGE_03 | 3));
1070 g_usBs3TestStep++;
1071
1072 /*
1073 * Now check that setting CS.u1Access to 1 does __NOT__ trigger a page
1074 * fault due to the RW bit being zero.
1075 * (We check both with with and without the WP bit if 80486.)
1076 */
1077 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1078 ASMSetCR0(uCr0Saved | X86_CR0_WP);
1079
1080 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1081 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1082 rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_RW /*fClear*/);
1083 if (RT_SUCCESS(rc))
1084 {
1085 /* ring-0 handler */
1086 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1087 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1088 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1089 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1090 g_usBs3TestStep++;
1091
1092 /* ring-3 handler */
1093 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1094 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1095 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1096 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1097 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1098 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1099 g_usBs3TestStep++;
1100
1101 /* clear WP and repeat the above. */
1102 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1103 ASMSetCR0(uCr0Saved & ~X86_CR0_WP);
1104 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */
1105 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */
1106
1107 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1108 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1109 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1110 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1111 g_usBs3TestStep++;
1112
1113 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1114 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1115 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1116 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!n", Bs3GdteTestPage03.Gen.u4Type);
1117 g_usBs3TestStep++;
1118
1119 Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_RW /*fSet*/, 0 /*fClear*/);
1120 }
1121
1122 ASMSetCR0(uCr0Saved);
1123
1124 /*
1125 * While we're here, check that if the CS GDT entry is a non-present
1126 * page we do get a #PF with the rigth error code and CR2.
1127 */
1128 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* Just for fun, really a pointless gesture. */
1129 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1130 rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1131 if (RT_SUCCESS(rc))
1132 {
1133 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1134 if (f486Plus)
1135 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00);
1136 else
1137 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00 + 4);
1138 g_usBs3TestStep++;
1139
1140 /* Do it from ring-3 to check ErrCd, which doesn't set X86_TRAP_PF_US it turns out. */
1141 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1142 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1143 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1144
1145 if (f486Plus)
1146 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03);
1147 else
1148 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03 + 4);
1149 g_usBs3TestStep++;
1150
1151 Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1152 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
1153 bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #1", Bs3GdteTestPage00.Gen.u4Type);
1154 if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
1155 bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #2", Bs3GdteTestPage03.Gen.u4Type);
1156 }
1157
1158 /* restore */
1159 paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs;
1160 paIdt[0x83 << cIdteShift].Gate.u16Sel = uSysR0Cs;// + (3 << BS3_SEL_RING_SHIFT) + 3;
1161 }
1162
1163# endif /* 32 || 64*/
1164
1165 /*
1166 * Check broad EFLAGS effects.
1167 */
1168 g_usBs3TestStep = 5600;
1169 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1170 {
1171 for (iRing = 0; iRing < 4; iRing++)
1172 {
1173 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1174 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1175
1176 /* all set */
1177 CtxTmp.rflags.u32 &= X86_EFL_VM | X86_EFL_1;
1178 CtxTmp.rflags.u32 |= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF /* | X86_EFL_TF */ /*| X86_EFL_IF*/
1179 | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL /* | X86_EFL_NT*/;
1180 if (f486Plus)
1181 CtxTmp.rflags.u32 |= X86_EFL_AC;
1182 if (f486Plus && !g_f16BitSys)
1183 CtxTmp.rflags.u32 |= X86_EFL_RF;
1184 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1185 CtxTmp.rflags.u32 |= X86_EFL_VIF | X86_EFL_VIP;
1186 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1187 CtxTmp.rflags.u32 &= ~X86_EFL_RF;
1188
1189 if (iCtx >= iRing)
1190 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1191 else
1192 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1193 uExpected = CtxTmp.rflags.u32
1194 & ( X86_EFL_1 | X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_DF
1195 | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP
1196 | X86_EFL_ID /*| X86_EFL_TF*/ /*| X86_EFL_IF*/ /*| X86_EFL_RF*/ );
1197 if (TrapCtx.fHandlerRfl != uExpected)
1198 bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n",
1199 TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u);
1200 g_usBs3TestStep++;
1201
1202 /* all cleared */
1203 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80286)
1204 CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_RA1_MASK | UINT16_C(0xf000));
1205 else
1206 CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_VM | X86_EFL_RA1_MASK);
1207 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1208 if (iCtx >= iRing)
1209 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1210 else
1211 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1212 uExpected = CtxTmp.rflags.u32;
1213 if (TrapCtx.fHandlerRfl != uExpected)
1214 bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n",
1215 TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u);
1216 g_usBs3TestStep++;
1217 }
1218 }
1219
1220/** @todo CS.LIMIT / canonical(CS) */
1221
1222
1223 /*
1224 * Check invalid gate types.
1225 */
1226 g_usBs3TestStep = 32000;
1227 for (iRing = 0; iRing <= 3; iRing++)
1228 {
1229 static const uint16_t s_auCSes[] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32, BS3_SEL_R0_CS64,
1230 BS3_SEL_TSS16, BS3_SEL_TSS32, BS3_SEL_TSS64, 0, BS3_SEL_SPARE_1f };
1231 static uint16_t const s_auInvlTypes64[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
1232 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1233 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
1234 static uint16_t const s_auInvlTypes32[] = { 0, 1, 2, 3, 8, 9, 10, 11, 13,
1235 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1236 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1237 /*286:*/ 12, 14, 15 };
1238 uint16_t const * const pauInvTypes = cIdteShift != 0 ? s_auInvlTypes64 : s_auInvlTypes32;
1239 uint16_t const cInvTypes = cIdteShift != 0 ? RT_ELEMENTS(s_auInvlTypes64)
1240 : f386Plus ? RT_ELEMENTS(s_auInvlTypes32) - 3 : RT_ELEMENTS(s_auInvlTypes32);
1241
1242
1243 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1244 {
1245 unsigned iType;
1246
1247 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1248 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1249# if TMPL_BITS == 32
1250 g_uBs3TrapEipHint = CtxTmp.rip.u32;
1251# endif
1252 for (iType = 0; iType < cInvTypes; iType++)
1253 {
1254 uint8_t const bSavedType = paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type;
1255 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = pauInvTypes[iType] >> 4;
1256 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = pauInvTypes[iType] & 0xf;
1257
1258 for (i = 0; i < 4; i++)
1259 {
1260 for (j = 0; j < RT_ELEMENTS(s_auCSes); j++)
1261 {
1262 uint16_t uCs = (unsigned)(s_auCSes[j] - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT)
1263 ? (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT)
1264 : s_auCSes[j] | i;
1265 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x type=%#x\n", g_usBs3TestStep, iCtx, iRing, i, uCs, pauInvTypes[iType]);*/
1266 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
1267 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1268 g_usBs3TestStep++;
1269 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1270
1271 /* Mark it not-present to check that invalid type takes precedence. */
1272 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 0;
1273 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1274 g_usBs3TestStep++;
1275 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1276 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
1277 }
1278 }
1279
1280 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = MY_SYS_SEL_R0_CS;
1281 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = bSavedType;
1282 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = 0;
1283 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
1284 }
1285 }
1286 }
1287 BS3_ASSERT(g_usBs3TestStep < 62000U && g_usBs3TestStep > 32000U);
1288
1289
1290 /** @todo
1291 * - Run \#PF and \#GP (and others?) at CPLs other than zero.
1292 * - Quickly generate all faults.
1293 * - All the peculiarities v8086.
1294 */
1295
1296# if TMPL_BITS != 16
1297 Bs3MemFree(pbIdtCopyAlloc, 12*_1K);
1298# endif
1299}
1300
1301
1302#define bs3CpuBasic2_sidt_Common BS3_CMN_NM(bs3CpuBasic2_sidt_Common)
1303void bs3CpuBasic2_sidt_Common(void)
1304{
1305 BS3TRAPFRAME TrapCtx;
1306 BS3REGCTX Ctx;
1307 BS3REGCTX TmpCtx;
1308 uint8_t abBuf[16];
1309 uint8_t BS3_FAR *pbBuf = abBuf;
1310
1311 /* make sure they're allocated */
1312 Bs3MemZero(&Ctx, sizeof(Ctx));
1313 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
1314 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1315 Bs3MemZero(&abBuf, sizeof(abBuf));
1316
1317 /* Create a context, give this routine some more stack space, point the context
1318 at our SIDT [xBX] + UD2 combo, and point DS:xBX at abBuf. */
1319 Bs3RegCtxSave(&Ctx);
1320 Ctx.rsp.u -= 0x80;
1321 Ctx.rip.u = (uintptr_t)BS3_FP_OFF(&TMPL_NM(bs3CpuBasic2_sidt_bx_ud2));
1322# if TMPL_BITS == 32
1323 g_uBs3TrapEipHint = Ctx.rip.u32;
1324# endif
1325 Ctx.rbx.u = BS3_FP_OFF(pbBuf);
1326# if TMPL_BITS == 16
1327 Ctx.ds = BS3_FP_SEG(pbBuf);
1328# endif
1329
1330 /*
1331 * Check that it works at all.
1332 */
1333 Bs3MemZero(&abBuf, sizeof(abBuf));
1334 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1335 g_usBs3TestStep = 0;
1336 //bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx, 0x80 /*bXcpt*/);
1337
1338}
1339
1340#endif /* once for each bitcount */
1341
1342
1343#if TMPL_MODE == BS3_MODE_PE16 || TMPL_MODE == BS3_MODE_PE16_32
1344
1345/**
1346 * Worker for bs3CpuBasic2_TssGateEsp that tests the INT 80 from outer rings.
1347 */
1348#define bs3CpuBasic2_TssGateEsp_AltStackOuterRing BS3_CMN_NM(bs3CpuBasic2_TssGateEsp_AltStackOuterRing)
1349void bs3CpuBasic2_TssGateEsp_AltStackOuterRing(PCBS3REGCTX pCtx, uint8_t bRing, uint8_t *pbAltStack, size_t cbAltStack,
1350 bool f16BitStack, bool f16BitTss, bool f16BitHandler, unsigned uLine)
1351{
1352 uint8_t const cbIretFrame = f16BitHandler ? 5*2 : 5*4;
1353 BS3REGCTX Ctx2;
1354 BS3TRAPFRAME TrapCtx;
1355 uint8_t *pbTmp;
1356 g_usBs3TestStep = uLine;
1357
1358 Bs3MemCpy(&Ctx2, pCtx, sizeof(Ctx2));
1359 Bs3RegCtxConvertToRingX(&Ctx2, bRing);
1360
1361 if (pbAltStack)
1362 {
1363 Ctx2.rsp.u = Bs3SelPtrToFlat(pbAltStack + 0x1980);
1364 Bs3MemZero(pbAltStack, cbAltStack);
1365 }
1366
1367 Bs3TrapSetJmpAndRestore(&Ctx2, &TrapCtx);
1368
1369 if (!f16BitStack && f16BitTss)
1370 Ctx2.rsp.u &= UINT16_MAX;
1371
1372 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx2, 0x80 /*bXcpt*/);
1373 CHECK_MEMBER("bCpl", "%u", TrapCtx.Ctx.bCpl, bRing);
1374 CHECK_MEMBER("cbIretFrame", "%#x", TrapCtx.cbIretFrame, cbIretFrame);
1375
1376 if (pbAltStack)
1377 {
1378 uint64_t uExpectedRsp = (f16BitTss ? Bs3Tss16.sp0 : Bs3Tss32.esp0) - cbIretFrame;
1379 if (f16BitStack)
1380 {
1381 uExpectedRsp &= UINT16_MAX;
1382 uExpectedRsp |= Ctx2.rsp.u & ~(uint64_t)UINT16_MAX;
1383 }
1384 if ( TrapCtx.uHandlerRsp != uExpectedRsp
1385 || TrapCtx.uHandlerSs != (f16BitTss ? Bs3Tss16.ss0 : Bs3Tss32.ss0))
1386 bs3CpuBasic2_FailedF("handler SS:ESP=%04x:%08RX64, expected %04x:%08RX16",
1387 TrapCtx.uHandlerSs, TrapCtx.uHandlerRsp, Bs3Tss16.ss0, uExpectedRsp);
1388
1389 pbTmp = (uint8_t *)ASMMemFirstNonZero(pbAltStack, cbAltStack);
1390 if ((f16BitStack || TrapCtx.uHandlerRsp <= UINT16_MAX) && pbTmp != NULL)
1391 bs3CpuBasic2_FailedF("someone touched the alt stack (%p) with SS:ESP=%04x:%#RX32: %p=%02x",
1392 pbAltStack, Ctx2.ss, Ctx2.rsp.u32, pbTmp, *pbTmp);
1393 else if (!f16BitStack && TrapCtx.uHandlerRsp > UINT16_MAX && pbTmp == NULL)
1394 bs3CpuBasic2_FailedF("the alt stack (%p) was not used SS:ESP=%04x:%#RX32\n", pbAltStack, Ctx2.ss, Ctx2.rsp.u32);
1395 }
1396}
1397
1398#define bs3CpuBasic2_TssGateEspCommon BS3_CMN_NM(bs3CpuBasic2_TssGateEspCommon)
1399void bs3CpuBasic2_TssGateEspCommon(bool const g_f16BitSys, PX86DESC const paIdt, unsigned const cIdteShift)
1400{
1401 BS3TRAPFRAME TrapCtx;
1402 BS3REGCTX Ctx;
1403 BS3REGCTX Ctx2;
1404# if TMPL_BITS == 16
1405 uint8_t *pbTmp;
1406# endif
1407
1408 /* make sure they're allocated */
1409 Bs3MemZero(&Ctx, sizeof(Ctx));
1410 Bs3MemZero(&Ctx2, sizeof(Ctx2));
1411 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1412
1413 Bs3RegCtxSave(&Ctx);
1414 Ctx.rsp.u -= 0x80;
1415 Ctx.rip.u = (uintptr_t)BS3_FP_OFF(&TMPL_NM(bs3CpuBasic2_Int80));
1416# if TMPL_BITS == 32
1417 g_uBs3TrapEipHint = Ctx.rip.u32;
1418# endif
1419
1420 /*
1421 * We'll be using IDT entry 80 and 81 here. The first one will be
1422 * accessible from all DPLs, the latter not. So, start with setting
1423 * the DPLs.
1424 */
1425 paIdt[0x80 << cIdteShift].Gate.u2Dpl = 3;
1426 paIdt[0x81 << cIdteShift].Gate.u2Dpl = 0;
1427
1428 /*
1429 * Check that the basic stuff works first.
1430 */
1431 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1432 g_usBs3TestStep = __LINE__;
1433 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx, 0x80 /*bXcpt*/);
1434
1435 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, NULL, 0, g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__);
1436 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 2, NULL, 0, g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__);
1437 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 3, NULL, 0, g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__);
1438
1439 /*
1440 * Check that the upper part of ESP is preserved when doing .
1441 */
1442 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
1443 {
1444 size_t const cbAltStack = _8K;
1445 uint8_t *pbAltStack = Bs3MemAllocZ(BS3MEMKIND_TILED, cbAltStack);
1446 if (pbAltStack)
1447 {
1448 /* same ring */
1449 g_usBs3TestStep = __LINE__;
1450 Bs3MemCpy(&Ctx2, &Ctx, sizeof(Ctx2));
1451 Ctx2.rsp.u = Bs3SelPtrToFlat(pbAltStack + 0x1980);
1452 if (Bs3TrapSetJmp(&TrapCtx))
1453 Bs3RegCtxRestore(&Ctx2, 0); /* (does not return) */
1454 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx2, 0x80 /*bXcpt*/);
1455# if TMPL_BITS == 16
1456 if ((pbTmp = (uint8_t *)ASMMemFirstNonZero(pbAltStack, cbAltStack)) != NULL)
1457 bs3CpuBasic2_FailedF("someone touched the alt stack (%p) with SS:ESP=%04x:%#RX32: %p=%02x\n",
1458 pbAltStack, Ctx2.ss, Ctx2.rsp.u32, pbTmp, *pbTmp);
1459# else
1460 if (ASMMemIsZero(pbAltStack, cbAltStack))
1461 bs3CpuBasic2_FailedF("alt stack wasn't used despite SS:ESP=%04x:%#RX32\n", Ctx2.ss, Ctx2.rsp.u32);
1462# endif
1463
1464 /* Different rings (load SS0:SP0 from TSS). */
1465 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack,
1466 g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__);
1467 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 2, pbAltStack, cbAltStack,
1468 g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__);
1469 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 3, pbAltStack, cbAltStack,
1470 g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__);
1471
1472 /* Different rings but switch the SS bitness in the TSS. */
1473 if (g_f16BitSys)
1474 {
1475 Bs3Tss16.ss0 = BS3_SEL_R0_SS32;
1476 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack,
1477 false, g_f16BitSys, g_f16BitSys, __LINE__);
1478 Bs3Tss16.ss0 = BS3_SEL_R0_SS16;
1479 }
1480 else
1481 {
1482 Bs3Tss32.ss0 = BS3_SEL_R0_SS16;
1483 bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack,
1484 true, g_f16BitSys, g_f16BitSys, __LINE__);
1485 Bs3Tss32.ss0 = BS3_SEL_R0_SS32;
1486 }
1487
1488 Bs3MemFree(pbAltStack, cbAltStack);
1489 }
1490 else
1491 Bs3TestPrintf("%s: Skipping ESP check, alloc failed\n", g_pszTestMode);
1492 }
1493 else
1494 Bs3TestPrintf("%s: Skipping ESP check, CPU too old\n", g_pszTestMode);
1495}
1496
1497#endif /* PE16 || PE32 */
1498
1499
1500BS3_DECL(uint8_t) TMPL_NM(bs3CpuBasic2_TssGateEsp)(uint8_t bMode)
1501{
1502 uint8_t bRet = 0;
1503
1504 g_pszTestMode = TMPL_NM(g_szBs3ModeName);
1505 g_bTestMode = bMode;
1506 g_f16BitSys = BS3_MODE_IS_16BIT_SYS(TMPL_MODE);
1507
1508#if TMPL_MODE == BS3_MODE_PE16 \
1509 || TMPL_MODE == BS3_MODE_PE16_32 \
1510 || TMPL_MODE == BS3_MODE_PP16 \
1511 || TMPL_MODE == BS3_MODE_PP16_32 \
1512 || TMPL_MODE == BS3_MODE_PAE16 \
1513 || TMPL_MODE == BS3_MODE_PAE16_32 \
1514 || TMPL_MODE == BS3_MODE_PE32
1515 bs3CpuBasic2_TssGateEspCommon(BS3_MODE_IS_16BIT_SYS(TMPL_MODE),
1516 (PX86DESC)MyBs3Idt,
1517 BS3_MODE_IS_64BIT_SYS(TMPL_MODE) ? 1 : 0);
1518#else
1519 bRet = BS3TESTDOMODE_SKIPPED;
1520#endif
1521
1522 /*
1523 * Re-initialize the IDT.
1524 */
1525 TMPL_NM(Bs3TrapInit)();
1526 return bRet;
1527}
1528
1529
1530BS3_DECL(uint8_t) TMPL_NM(bs3CpuBasic2_RaiseXcpt1)(uint8_t bMode)
1531{
1532 g_pszTestMode = TMPL_NM(g_szBs3ModeName);
1533 g_bTestMode = bMode;
1534 g_f16BitSys = BS3_MODE_IS_16BIT_SYS(TMPL_MODE);
1535
1536#if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE)
1537
1538 /*
1539 * Pass to common worker which is only compiled once per mode.
1540 */
1541 bs3CpuBasic2_RaiseXcpt1Common(BS3_MODE_IS_16BIT_SYS(TMPL_MODE),
1542 MY_SYS_SEL_R0_CS,
1543 MY_SYS_SEL_R0_CS_CNF,
1544 MY_SYS_SEL_R0_SS,
1545 (PX86DESC)MyBs3Idt,
1546 BS3_MODE_IS_64BIT_SYS(TMPL_MODE) ? 1 : 0);
1547
1548 /*
1549 * Re-initialize the IDT.
1550 */
1551 TMPL_NM(Bs3TrapInit)();
1552 return 0;
1553#elif TMPL_MODE == BS3_MODE_RM
1554
1555 /*
1556 * Check
1557 */
1558 /** @todo check */
1559 return BS3TESTDOMODE_SKIPPED;
1560
1561#else
1562 return BS3TESTDOMODE_SKIPPED;
1563#endif
1564}
1565
1566
1567BS3_DECL(uint8_t) TMPL_NM(bs3CpuBasic2_iret)(uint8_t bMode)
1568{
1569 g_pszTestMode = TMPL_NM(g_szBs3ModeName);
1570 g_bTestMode = bMode;
1571 g_f16BitSys = BS3_MODE_IS_16BIT_SYS(TMPL_MODE);
1572
1573 Bs3PrintStrN(RT_STR_TUPLE("Hello world!\n"));
1574#if !BS3_MODE_IS_V86(TMPL_MODE)
1575 Bs3TestPrintf(RT_STR_TUPLE("Hi there!\n"));
1576#endif
1577 return BS3TESTDOMODE_SKIPPED;
1578}
1579
1580
1581BS3_DECL(uint8_t) TMPL_NM(bs3CpuBasic2_sidt)(uint8_t bMode)
1582{
1583 g_pszTestMode = TMPL_NM(g_szBs3ModeName);
1584 g_bTestMode = bMode;
1585 g_f16BitSys = BS3_MODE_IS_16BIT_SYS(TMPL_MODE);
1586
1587 BS3_ASSERT(bMode == TMPL_MODE);
1588
1589 /*
1590 * Pass to common worker which is only compiled once per mode.
1591 */
1592 bs3CpuBasic2_sidt_Common();
1593
1594 /*
1595 * Re-initialize the IDT.
1596 */
1597 TMPL_NM(Bs3TrapInit)();
1598 return 0;
1599}
1600
1601
1602#endif /* BS3_INSTANTIATING_MODE */
1603
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