VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 days ago

Copyright year updates by scm.

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