VirtualBox

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

Last change on this file since 82844 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 148.9 KB
Line 
1/* $Id: bs3-cpu-basic-2-x0.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-basic-2, C test driver code (16-bit).
4 */
5
6/*
7 * Copyright (C) 2007-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define BS3_USE_X0_TEXT_SEG
32#include <bs3kit.h>
33#include <iprt/asm.h>
34#include <iprt/asm-amd64-x86.h>
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40#undef CHECK_MEMBER
41#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \
42 do \
43 { \
44 if ((a_Actual) == (a_Expected)) { /* likely */ } \
45 else bs3CpuBasic2_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \
46 } while (0)
47
48
49/** Indicating that we've got operand size prefix and that it matters. */
50#define BS3CB2SIDTSGDT_F_OPSIZE UINT8_C(0x01)
51/** Worker requires 386 or later. */
52#define BS3CB2SIDTSGDT_F_386PLUS UINT8_C(0x02)
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58typedef struct BS3CB2INVLDESCTYPE
59{
60 uint8_t u4Type;
61 uint8_t u1DescType;
62} BS3CB2INVLDESCTYPE;
63
64typedef struct BS3CB2SIDTSGDT
65{
66 const char *pszDesc;
67 FPFNBS3FAR fpfnWorker;
68 uint8_t cbInstr;
69 bool fSs;
70 uint8_t bMode;
71 uint8_t fFlags;
72} BS3CB2SIDTSGDT;
73
74
75/*********************************************************************************************************************************
76* External Symbols *
77*********************************************************************************************************************************/
78extern FNBS3FAR bs3CpuBasic2_Int80;
79extern FNBS3FAR bs3CpuBasic2_Int81;
80extern FNBS3FAR bs3CpuBasic2_Int82;
81extern FNBS3FAR bs3CpuBasic2_Int83;
82
83extern FNBS3FAR bs3CpuBasic2_ud2;
84#define g_bs3CpuBasic2_ud2_FlatAddr BS3_DATA_NM(g_bs3CpuBasic2_ud2_FlatAddr)
85extern uint32_t g_bs3CpuBasic2_ud2_FlatAddr;
86
87extern FNBS3FAR bs3CpuBasic2_iret;
88extern FNBS3FAR bs3CpuBasic2_iret_opsize;
89extern FNBS3FAR bs3CpuBasic2_iret_rexw;
90
91extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c16;
92extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c32;
93extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c64;
94extern FNBS3FAR bs3CpuBasic2_sidt_ss_bx_ud2_c16;
95extern FNBS3FAR bs3CpuBasic2_sidt_ss_bx_ud2_c32;
96extern FNBS3FAR bs3CpuBasic2_sidt_rexw_bx_ud2_c64;
97extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c16;
98extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c32;
99extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c64;
100extern FNBS3FAR bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c16;
101extern FNBS3FAR bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c32;
102extern FNBS3FAR bs3CpuBasic2_sidt_opsize_rexw_bx_ud2_c64;
103
104extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c16;
105extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c32;
106extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c64;
107extern FNBS3FAR bs3CpuBasic2_sgdt_ss_bx_ud2_c16;
108extern FNBS3FAR bs3CpuBasic2_sgdt_ss_bx_ud2_c32;
109extern FNBS3FAR bs3CpuBasic2_sgdt_rexw_bx_ud2_c64;
110extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c16;
111extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c32;
112extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c64;
113extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c16;
114extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c32;
115extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2_c64;
116
117extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c16;
118extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c32;
119extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c64;
120extern FNBS3FAR bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c16;
121extern FNBS3FAR bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c32;
122extern FNBS3FAR bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64;
123extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c16;
124extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2_c16;
125extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c32;
126extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c64;
127extern FNBS3FAR bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c16;
128extern FNBS3FAR bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c32;
129extern FNBS3FAR bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64;
130
131extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
132extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
133extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
134extern FNBS3FAR bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
135extern FNBS3FAR bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
136extern FNBS3FAR bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
137extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
138extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
139extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
140extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
141extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
142extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
143
144
145
146/*********************************************************************************************************************************
147* Global Variables *
148*********************************************************************************************************************************/
149static const char BS3_FAR *g_pszTestMode = (const char *)1;
150static uint8_t g_bTestMode = 1;
151static bool g_f16BitSys = 1;
152
153
154/** SIDT test workers. */
155static BS3CB2SIDTSGDT const g_aSidtWorkers[] =
156{
157 { "sidt [bx]", bs3CpuBasic2_sidt_bx_ud2_c16, 3, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
158 { "sidt [ss:bx]", bs3CpuBasic2_sidt_ss_bx_ud2_c16, 4, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
159 { "o32 sidt [bx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c16, 4, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
160 { "o32 sidt [ss:bx]", bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c16, 5, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
161 { "sidt [ebx]", bs3CpuBasic2_sidt_bx_ud2_c32, 3, false, BS3_MODE_CODE_32, 0 },
162 { "sidt [ss:ebx]", bs3CpuBasic2_sidt_ss_bx_ud2_c32, 4, true, BS3_MODE_CODE_32, 0 },
163 { "o16 sidt [ebx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c32, 4, false, BS3_MODE_CODE_32, 0 },
164 { "o16 sidt [ss:ebx]", bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c32, 5, true, BS3_MODE_CODE_32, 0 },
165 { "sidt [rbx]", bs3CpuBasic2_sidt_bx_ud2_c64, 3, false, BS3_MODE_CODE_64, 0 },
166 { "o64 sidt [rbx]", bs3CpuBasic2_sidt_rexw_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
167 { "o32 sidt [rbx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
168 { "o32 o64 sidt [rbx]", bs3CpuBasic2_sidt_opsize_rexw_bx_ud2_c64, 5, false, BS3_MODE_CODE_64, 0 },
169};
170
171/** SGDT test workers. */
172static BS3CB2SIDTSGDT const g_aSgdtWorkers[] =
173{
174 { "sgdt [bx]", bs3CpuBasic2_sgdt_bx_ud2_c16, 3, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
175 { "sgdt [ss:bx]", bs3CpuBasic2_sgdt_ss_bx_ud2_c16, 4, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
176 { "o32 sgdt [bx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c16, 4, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
177 { "o32 sgdt [ss:bx]", bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c16, 5, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
178 { "sgdt [ebx]", bs3CpuBasic2_sgdt_bx_ud2_c32, 3, false, BS3_MODE_CODE_32, 0 },
179 { "sgdt [ss:ebx]", bs3CpuBasic2_sgdt_ss_bx_ud2_c32, 4, true, BS3_MODE_CODE_32, 0 },
180 { "o16 sgdt [ebx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c32, 4, false, BS3_MODE_CODE_32, 0 },
181 { "o16 sgdt [ss:ebx]", bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c32, 5, true, BS3_MODE_CODE_32, 0 },
182 { "sgdt [rbx]", bs3CpuBasic2_sgdt_bx_ud2_c64, 3, false, BS3_MODE_CODE_64, 0 },
183 { "o64 sgdt [rbx]", bs3CpuBasic2_sgdt_rexw_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
184 { "o32 sgdt [rbx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
185 { "o32 o64 sgdt [rbx]", bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2_c64, 5, false, BS3_MODE_CODE_64, 0 },
186};
187
188/** LIDT test workers. */
189static BS3CB2SIDTSGDT const g_aLidtWorkers[] =
190{
191 { "lidt [bx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c16, 11, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
192 { "lidt [ss:bx]", bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c16, 12, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
193 { "o32 lidt [bx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c16, 12, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS },
194 { "o32 lidt [bx]; sidt32", bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2_c16, 27, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS },
195 { "o32 lidt [ss:bx]", bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c16, 13, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS },
196 { "lidt [ebx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c32, 11, false, BS3_MODE_CODE_32, 0 },
197 { "lidt [ss:ebx]", bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c32, 12, true, BS3_MODE_CODE_32, 0 },
198 { "o16 lidt [ebx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c32, 12, false, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE },
199 { "o16 lidt [ss:ebx]", bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c32, 13, true, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE },
200 { "lidt [rbx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c64, 9, false, BS3_MODE_CODE_64, 0 },
201 { "o64 lidt [rbx]", bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
202 { "o32 lidt [rbx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
203 { "o32 o64 lidt [rbx]", bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64, 11, false, BS3_MODE_CODE_64, 0 },
204};
205
206/** LGDT test workers. */
207static BS3CB2SIDTSGDT const g_aLgdtWorkers[] =
208{
209 { "lgdt [bx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 11, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
210 { "lgdt [ss:bx]", bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 12, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
211 { "o32 lgdt [bx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 12, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS },
212 { "o32 lgdt [ss:bx]", bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 13, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS },
213 { "lgdt [ebx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 11, false, BS3_MODE_CODE_32, 0 },
214 { "lgdt [ss:ebx]", bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 12, true, BS3_MODE_CODE_32, 0 },
215 { "o16 lgdt [ebx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 12, false, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE },
216 { "o16 lgdt [ss:ebx]", bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 13, true, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE },
217 { "lgdt [rbx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 9, false, BS3_MODE_CODE_64, 0 },
218 { "o64 lgdt [rbx]", bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
219 { "o32 lgdt [rbx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
220 { "o32 o64 lgdt [rbx]", bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 11, false, BS3_MODE_CODE_64, 0 },
221};
222
223
224
225#if 0
226/** Table containing invalid CS selector types. */
227static const BS3CB2INVLDESCTYPE g_aInvalidCsTypes[] =
228{
229 { X86_SEL_TYPE_RO, 1 },
230 { X86_SEL_TYPE_RO_ACC, 1 },
231 { X86_SEL_TYPE_RW, 1 },
232 { X86_SEL_TYPE_RW_ACC, 1 },
233 { X86_SEL_TYPE_RO_DOWN, 1 },
234 { X86_SEL_TYPE_RO_DOWN_ACC, 1 },
235 { X86_SEL_TYPE_RW_DOWN, 1 },
236 { X86_SEL_TYPE_RW_DOWN_ACC, 1 },
237 { 0, 0 },
238 { 1, 0 },
239 { 2, 0 },
240 { 3, 0 },
241 { 4, 0 },
242 { 5, 0 },
243 { 6, 0 },
244 { 7, 0 },
245 { 8, 0 },
246 { 9, 0 },
247 { 10, 0 },
248 { 11, 0 },
249 { 12, 0 },
250 { 13, 0 },
251 { 14, 0 },
252 { 15, 0 },
253};
254
255/** Table containing invalid SS selector types. */
256static const BS3CB2INVLDESCTYPE g_aInvalidSsTypes[] =
257{
258 { X86_SEL_TYPE_EO, 1 },
259 { X86_SEL_TYPE_EO_ACC, 1 },
260 { X86_SEL_TYPE_ER, 1 },
261 { X86_SEL_TYPE_ER_ACC, 1 },
262 { X86_SEL_TYPE_EO_CONF, 1 },
263 { X86_SEL_TYPE_EO_CONF_ACC, 1 },
264 { X86_SEL_TYPE_ER_CONF, 1 },
265 { X86_SEL_TYPE_ER_CONF_ACC, 1 },
266 { 0, 0 },
267 { 1, 0 },
268 { 2, 0 },
269 { 3, 0 },
270 { 4, 0 },
271 { 5, 0 },
272 { 6, 0 },
273 { 7, 0 },
274 { 8, 0 },
275 { 9, 0 },
276 { 10, 0 },
277 { 11, 0 },
278 { 12, 0 },
279 { 13, 0 },
280 { 14, 0 },
281 { 15, 0 },
282};
283#endif
284
285
286/**
287 * Sets globals according to the mode.
288 *
289 * @param bTestMode The test mode.
290 */
291static void bs3CpuBasic2_SetGlobals(uint8_t bTestMode)
292{
293 g_bTestMode = bTestMode;
294 g_pszTestMode = Bs3GetModeName(bTestMode);
295 g_f16BitSys = BS3_MODE_IS_16BIT_SYS(bTestMode);
296 g_usBs3TestStep = 0;
297}
298
299
300/**
301 * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep
302 * and g_pszTestMode.
303 */
304static void bs3CpuBasic2_FailedF(const char *pszFormat, ...)
305{
306 va_list va;
307
308 char szTmp[168];
309 va_start(va, pszFormat);
310 Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va);
311 va_end(va);
312
313 Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp);
314}
315
316
317#if 0
318/**
319 * Compares trap stuff.
320 */
321static void bs3CpuBasic2_CompareIntCtx1(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt)
322{
323 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
324 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
325 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
326 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 2 /*int xx*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
327 if (Bs3TestSubErrorCount() != cErrorsBefore)
328 {
329 Bs3TrapPrintFrame(pTrapCtx);
330#if 1
331 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
332 Bs3TestPrintf("Halting in CompareTrapCtx1: bXcpt=%#x\n", bXcpt);
333 ASMHalt();
334#endif
335 }
336}
337#endif
338
339
340#if 0
341/**
342 * Compares trap stuff.
343 */
344static void bs3CpuBasic2_CompareTrapCtx2(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t cbIpAdjust,
345 uint8_t bXcpt, uint16_t uHandlerCs)
346{
347 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
348 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
349 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
350 CHECK_MEMBER("uHandlerCs", "%#06x", pTrapCtx->uHandlerCs, uHandlerCs);
351 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
352 if (Bs3TestSubErrorCount() != cErrorsBefore)
353 {
354 Bs3TrapPrintFrame(pTrapCtx);
355#if 1
356 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
357 Bs3TestPrintf("Halting in CompareTrapCtx2: bXcpt=%#x\n", bXcpt);
358 ASMHalt();
359#endif
360 }
361}
362#endif
363
364/**
365 * Compares a CPU trap.
366 */
367static void bs3CpuBasic2_CompareCpuTrapCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd,
368 uint8_t bXcpt, bool f486ResumeFlagHint)
369{
370 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
371 uint32_t fExtraEfl;
372
373 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
374 CHECK_MEMBER("bErrCd", "%#06RX16", (uint16_t)pTrapCtx->uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
375
376 fExtraEfl = X86_EFL_RF;
377 if ( g_f16BitSys
378 || ( !f486ResumeFlagHint
379 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80486 ) )
380 fExtraEfl = 0;
381 else
382 fExtraEfl = X86_EFL_RF;
383#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. */
384 fExtraEfl = pTrapCtx->Ctx.rflags.u32 & X86_EFL_RF;
385#endif
386 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 0 /*cbIpAdjust*/, 0 /*cbSpAdjust*/, fExtraEfl, g_pszTestMode, g_usBs3TestStep);
387 if (Bs3TestSubErrorCount() != cErrorsBefore)
388 {
389 Bs3TrapPrintFrame(pTrapCtx);
390#if 1
391 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
392 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
393 ASMHalt();
394#endif
395 }
396}
397
398
399/**
400 * Compares \#GP trap.
401 */
402static void bs3CpuBasic2_CompareGpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
403{
404 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_GP, true /*f486ResumeFlagHint*/);
405}
406
407#if 0
408/**
409 * Compares \#NP trap.
410 */
411static void bs3CpuBasic2_CompareNpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
412{
413 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_NP, true /*f486ResumeFlagHint*/);
414}
415#endif
416
417/**
418 * Compares \#SS trap.
419 */
420static void bs3CpuBasic2_CompareSsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, bool f486ResumeFlagHint)
421{
422 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_SS, f486ResumeFlagHint);
423}
424
425#if 0
426/**
427 * Compares \#TS trap.
428 */
429static void bs3CpuBasic2_CompareTsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
430{
431 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_TS, false /*f486ResumeFlagHint*/);
432}
433#endif
434
435/**
436 * Compares \#PF trap.
437 */
438static void bs3CpuBasic2_ComparePfCtx(PCBS3TRAPFRAME pTrapCtx, PBS3REGCTX pStartCtx, uint16_t uErrCd, uint64_t uCr2Expected)
439{
440 uint64_t const uCr2Saved = pStartCtx->cr2.u;
441 pStartCtx->cr2.u = uCr2Expected;
442 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_PF, true /*f486ResumeFlagHint*/);
443 pStartCtx->cr2.u = uCr2Saved;
444}
445
446/**
447 * Compares \#UD trap.
448 */
449static void bs3CpuBasic2_CompareUdCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx)
450{
451 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*no error code*/, X86_XCPT_UD, true /*f486ResumeFlagHint*/);
452}
453
454
455#if 0 /* convert me */
456static void bs3CpuBasic2_RaiseXcpt1Common(uint16_t const uSysR0Cs, uint16_t const uSysR0CsConf, uint16_t const uSysR0Ss,
457 PX86DESC const paIdt, unsigned const cIdteShift)
458{
459 BS3TRAPFRAME TrapCtx;
460 BS3REGCTX Ctx80;
461 BS3REGCTX Ctx81;
462 BS3REGCTX Ctx82;
463 BS3REGCTX Ctx83;
464 BS3REGCTX CtxTmp;
465 BS3REGCTX CtxTmp2;
466 PBS3REGCTX apCtx8x[4];
467 unsigned iCtx;
468 unsigned iRing;
469 unsigned iDpl;
470 unsigned iRpl;
471 unsigned i, j, k;
472 uint32_t uExpected;
473 bool const f486Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486;
474# if TMPL_BITS == 16
475 bool const f386Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386;
476 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
477# else
478 bool const f286 = false;
479 bool const f386Plus = true;
480 int rc;
481 uint8_t *pbIdtCopyAlloc;
482 PX86DESC pIdtCopy;
483 const unsigned cbIdte = 1 << (3 + cIdteShift);
484 RTCCUINTXREG uCr0Saved = ASMGetCR0();
485 RTGDTR GdtrSaved;
486# endif
487 RTIDTR IdtrSaved;
488 RTIDTR Idtr;
489
490 ASMGetIDTR(&IdtrSaved);
491# if TMPL_BITS != 16
492 ASMGetGDTR(&GdtrSaved);
493# endif
494
495 /* make sure they're allocated */
496 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
497 Bs3MemZero(&Ctx80, sizeof(Ctx80));
498 Bs3MemZero(&Ctx81, sizeof(Ctx81));
499 Bs3MemZero(&Ctx82, sizeof(Ctx82));
500 Bs3MemZero(&Ctx83, sizeof(Ctx83));
501 Bs3MemZero(&CtxTmp, sizeof(CtxTmp));
502 Bs3MemZero(&CtxTmp2, sizeof(CtxTmp2));
503
504 /* Context array. */
505 apCtx8x[0] = &Ctx80;
506 apCtx8x[1] = &Ctx81;
507 apCtx8x[2] = &Ctx82;
508 apCtx8x[3] = &Ctx83;
509
510# if TMPL_BITS != 16
511 /* Allocate memory for playing around with the IDT. */
512 pbIdtCopyAlloc = NULL;
513 if (BS3_MODE_IS_PAGED(g_bTestMode))
514 pbIdtCopyAlloc = Bs3MemAlloc(BS3MEMKIND_FLAT32, 12*_1K);
515# endif
516
517 /*
518 * IDT entry 80 thru 83 are assigned DPLs according to the number.
519 * (We'll be useing more, but this'll do for now.)
520 */
521 paIdt[0x80 << cIdteShift].Gate.u2Dpl = 0;
522 paIdt[0x81 << cIdteShift].Gate.u2Dpl = 1;
523 paIdt[0x82 << cIdteShift].Gate.u2Dpl = 2;
524 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
525
526 Bs3RegCtxSave(&Ctx80);
527 Ctx80.rsp.u -= 0x300;
528 Ctx80.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int80);
529# if TMPL_BITS == 16
530 Ctx80.cs = BS3_MODE_IS_RM_OR_V86(g_bTestMode) ? BS3_SEL_TEXT16 : BS3_SEL_R0_CS16;
531# elif TMPL_BITS == 32
532 g_uBs3TrapEipHint = Ctx80.rip.u32;
533# endif
534 Bs3MemCpy(&Ctx81, &Ctx80, sizeof(Ctx80));
535 Ctx81.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int81);
536 Bs3MemCpy(&Ctx82, &Ctx80, sizeof(Ctx80));
537 Ctx82.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int82);
538 Bs3MemCpy(&Ctx83, &Ctx80, sizeof(Ctx80));
539 Ctx83.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int83);
540
541 /*
542 * Check that all the above gates work from ring-0.
543 */
544 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
545 {
546 g_usBs3TestStep = iCtx;
547# if TMPL_BITS == 32
548 g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32;
549# endif
550 Bs3TrapSetJmpAndRestore(apCtx8x[iCtx], &TrapCtx);
551 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, apCtx8x[iCtx], 0x80+iCtx /*bXcpt*/);
552 }
553
554 /*
555 * Check that the gate DPL checks works.
556 */
557 g_usBs3TestStep = 100;
558 for (iRing = 0; iRing <= 3; iRing++)
559 {
560 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
561 {
562 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
563 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
564# if TMPL_BITS == 32
565 g_uBs3TrapEipHint = CtxTmp.rip.u32;
566# endif
567 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
568 if (iCtx < iRing)
569 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
570 else
571 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
572 g_usBs3TestStep++;
573 }
574 }
575
576 /*
577 * Modify the gate CS value and run the handler at a different CPL.
578 * Throw RPL variations into the mix (completely ignored) together
579 * with gate presence.
580 * 1. CPL <= GATE.DPL
581 * 2. GATE.P
582 * 3. GATE.CS.DPL <= CPL (non-conforming segments)
583 */
584 g_usBs3TestStep = 1000;
585 for (i = 0; i <= 3; i++)
586 {
587 for (iRing = 0; iRing <= 3; iRing++)
588 {
589 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
590 {
591# if TMPL_BITS == 32
592 g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32;
593# endif
594 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
595 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
596
597 for (j = 0; j <= 3; j++)
598 {
599 uint16_t const uCs = (uSysR0Cs | j) + (i << BS3_SEL_RING_SHIFT);
600 for (k = 0; k < 2; k++)
601 {
602 g_usBs3TestStep++;
603 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
604 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
605 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = k;
606 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
607 /*Bs3TrapPrintFrame(&TrapCtx);*/
608 if (iCtx < iRing)
609 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
610 else if (k == 0)
611 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
612 else if (i > iRing)
613 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
614 else
615 {
616 uint16_t uExpectedCs = uCs & X86_SEL_MASK_OFF_RPL;
617 if (i <= iCtx && i <= iRing)
618 uExpectedCs |= i;
619 bs3CpuBasic2_CompareTrapCtx2(&TrapCtx, &CtxTmp, 2 /*int 8xh*/, 0x80 + iCtx /*bXcpt*/, uExpectedCs);
620 }
621 }
622 }
623
624 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
625 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
626 }
627 }
628 }
629 BS3_ASSERT(g_usBs3TestStep < 1600);
630
631 /*
632 * Various CS and SS related faults
633 *
634 * We temporarily reconfigure gate 80 and 83 with new CS selectors, the
635 * latter have a CS.DPL of 2 for testing ring transisions and SS loading
636 * without making it impossible to handle faults.
637 */
638 g_usBs3TestStep = 1600;
639 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
640 Bs3GdteTestPage00.Gen.u1Present = 0;
641 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
642 paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00;
643
644 /* CS.PRESENT = 0 */
645 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
646 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
647 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
648 bs3CpuBasic2_FailedF("selector was accessed");
649 g_usBs3TestStep++;
650
651 /* Check that GATE.DPL is checked before CS.PRESENT. */
652 for (iRing = 1; iRing < 4; iRing++)
653 {
654 Bs3MemCpy(&CtxTmp, &Ctx80, sizeof(CtxTmp));
655 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
656 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
657 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x80 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
658 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
659 bs3CpuBasic2_FailedF("selector was accessed");
660 g_usBs3TestStep++;
661 }
662
663 /* CS.DPL mismatch takes precedence over CS.PRESENT = 0. */
664 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
665 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
666 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
667 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
668 bs3CpuBasic2_FailedF("CS selector was accessed");
669 g_usBs3TestStep++;
670 for (iDpl = 1; iDpl < 4; iDpl++)
671 {
672 Bs3GdteTestPage00.Gen.u2Dpl = iDpl;
673 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
674 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
675 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
676 bs3CpuBasic2_FailedF("CS selector was accessed");
677 g_usBs3TestStep++;
678 }
679
680 /* 1608: Check all the invalid CS selector types alone. */
681 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
682 for (i = 0; i < RT_ELEMENTS(g_aInvalidCsTypes); i++)
683 {
684 Bs3GdteTestPage00.Gen.u4Type = g_aInvalidCsTypes[i].u4Type;
685 Bs3GdteTestPage00.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType;
686 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
687 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
688 if (Bs3GdteTestPage00.Gen.u4Type != g_aInvalidCsTypes[i].u4Type)
689 bs3CpuBasic2_FailedF("Invalid CS type %#x/%u -> %#x/%u\n",
690 g_aInvalidCsTypes[i].u4Type, g_aInvalidCsTypes[i].u1DescType,
691 Bs3GdteTestPage00.Gen.u4Type, Bs3GdteTestPage00.Gen.u1DescType);
692 g_usBs3TestStep++;
693
694 /* Incorrect CS.TYPE takes precedence over CS.PRESENT = 0. */
695 Bs3GdteTestPage00.Gen.u1Present = 0;
696 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
697 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
698 Bs3GdteTestPage00.Gen.u1Present = 1;
699 g_usBs3TestStep++;
700 }
701
702 /* Fix CS again. */
703 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
704
705 /* 1632: Test SS. */
706 if (!BS3_MODE_IS_64BIT_SYS(g_bTestMode))
707 {
708 uint16_t BS3_FAR *puTssSs2 = BS3_MODE_IS_16BIT_SYS(g_bTestMode) ? &Bs3Tss16.ss2 : &Bs3Tss32.ss2;
709 uint16_t const uSavedSs2 = *puTssSs2;
710 X86DESC const SavedGate83 = paIdt[0x83 << cIdteShift];
711
712 /* Make the handler execute in ring-2. */
713 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
714 Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
715 paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_02 | 2;
716
717 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
718 Bs3RegCtxConvertToRingX(&CtxTmp, 3); /* yeah, from 3 so SS:xSP is reloaded. */
719 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
720 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
721 if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
722 bs3CpuBasic2_FailedF("CS selector was not access");
723 g_usBs3TestStep++;
724
725 /* Create a SS.DPL=2 stack segment and check that SS2.RPL matters and
726 that we get #SS if the selector isn't present. */
727 i = 0; /* used for cycling thru invalid CS types */
728 for (k = 0; k < 10; k++)
729 {
730 /* k=0: present,
731 k=1: not-present,
732 k=2: present but very low limit,
733 k=3: not-present, low limit.
734 k=4: present, read-only.
735 k=5: not-present, read-only.
736 k=6: present, code-selector.
737 k=7: not-present, code-selector.
738 k=8: present, read-write / no access + system (=LDT).
739 k=9: not-present, read-write / no access + system (=LDT).
740 */
741 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
742 Bs3GdteTestPage03.Gen.u1Present = !(k & 1);
743 if (k >= 8)
744 {
745 Bs3GdteTestPage03.Gen.u1DescType = 0; /* system */
746 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW; /* = LDT */
747 }
748 else if (k >= 6)
749 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_ER;
750 else if (k >= 4)
751 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RO;
752 else if (k >= 2)
753 {
754 Bs3GdteTestPage03.Gen.u16LimitLow = 0x400;
755 Bs3GdteTestPage03.Gen.u4LimitHigh = 0;
756 Bs3GdteTestPage03.Gen.u1Granularity = 0;
757 }
758
759 for (iDpl = 0; iDpl < 4; iDpl++)
760 {
761 Bs3GdteTestPage03.Gen.u2Dpl = iDpl;
762
763 for (iRpl = 0; iRpl < 4; iRpl++)
764 {
765 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | iRpl;
766 //Bs3TestPrintf("k=%u iDpl=%u iRpl=%u step=%u\n", k, iDpl, iRpl, g_usBs3TestStep);
767 Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
768 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
769 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
770 if (iRpl != 2 || iRpl != iDpl || k >= 4)
771 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
772 else if (k != 0)
773 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03,
774 k == 2 /*f486ResumeFlagHint*/);
775 else
776 {
777 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
778 if (TrapCtx.uHandlerSs != (BS3_SEL_TEST_PAGE_03 | 2))
779 bs3CpuBasic2_FailedF("uHandlerSs=%#x expected %#x\n", TrapCtx.uHandlerSs, BS3_SEL_TEST_PAGE_03 | 2);
780 }
781 if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
782 bs3CpuBasic2_FailedF("CS selector was not access");
783 if ( TrapCtx.bXcpt == 0x83
784 || (TrapCtx.bXcpt == X86_XCPT_SS && k == 2) )
785 {
786 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
787 bs3CpuBasic2_FailedF("SS selector was not accessed");
788 }
789 else if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
790 bs3CpuBasic2_FailedF("SS selector was accessed");
791 g_usBs3TestStep++;
792
793 /* +1: Modify the gate DPL to check that this is checked before SS.DPL and SS.PRESENT. */
794 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 2;
795 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
796 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x83 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
797 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
798 g_usBs3TestStep++;
799
800 /* +2: Check the CS.DPL check is done before the SS ones. Restoring the
801 ring-0 INT 83 context triggers the CS.DPL < CPL check. */
802 Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx);
803 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02);
804 g_usBs3TestStep++;
805
806 /* +3: Now mark the CS selector not present and check that that also triggers before SS stuff. */
807 Bs3GdteTestPage02.Gen.u1Present = 0;
808 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
809 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02);
810 Bs3GdteTestPage02.Gen.u1Present = 1;
811 g_usBs3TestStep++;
812
813 /* +4: Make the CS selector some invalid type and check it triggers before SS stuff. */
814 Bs3GdteTestPage02.Gen.u4Type = g_aInvalidCsTypes[i].u4Type;
815 Bs3GdteTestPage02.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType;
816 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
817 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02);
818 Bs3GdteTestPage02.Gen.u4Type = X86_SEL_TYPE_ER_ACC;
819 Bs3GdteTestPage02.Gen.u1DescType = 1;
820 g_usBs3TestStep++;
821
822 /* +5: Now, make the CS selector limit too small and that it triggers after SS trouble.
823 The 286 had a simpler approach to these GP(0). */
824 Bs3GdteTestPage02.Gen.u16LimitLow = 0;
825 Bs3GdteTestPage02.Gen.u4LimitHigh = 0;
826 Bs3GdteTestPage02.Gen.u1Granularity = 0;
827 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
828 if (f286)
829 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/);
830 else if (iRpl != 2 || iRpl != iDpl || k >= 4)
831 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
832 else if (k != 0)
833 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, k == 2 /*f486ResumeFlagHint*/);
834 else
835 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/);
836 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
837 g_usBs3TestStep++;
838 }
839 }
840 }
841
842 /* Check all the invalid SS selector types alone. */
843 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
844 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
845 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2;
846 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
847 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
848 g_usBs3TestStep++;
849 for (i = 0; i < RT_ELEMENTS(g_aInvalidSsTypes); i++)
850 {
851 Bs3GdteTestPage03.Gen.u4Type = g_aInvalidSsTypes[i].u4Type;
852 Bs3GdteTestPage03.Gen.u1DescType = g_aInvalidSsTypes[i].u1DescType;
853 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
854 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
855 if (Bs3GdteTestPage03.Gen.u4Type != g_aInvalidSsTypes[i].u4Type)
856 bs3CpuBasic2_FailedF("Invalid SS type %#x/%u -> %#x/%u\n",
857 g_aInvalidSsTypes[i].u4Type, g_aInvalidSsTypes[i].u1DescType,
858 Bs3GdteTestPage03.Gen.u4Type, Bs3GdteTestPage03.Gen.u1DescType);
859 g_usBs3TestStep++;
860 }
861
862 /*
863 * Continue the SS experiments with a expand down segment. We'll use
864 * the same setup as we already have with gate 83h being DPL and
865 * having CS.DPL=2.
866 *
867 * Expand down segments are weird. The valid area is practically speaking
868 * reversed. So, a 16-bit segment with a limit of 0x6000 will have valid
869 * addresses from 0xffff thru 0x6001.
870 *
871 * So, with expand down segments we can more easily cut partially into the
872 * pushing of the iret frame and trigger more interesting behavior than
873 * with regular "expand up" segments where the whole pushing area is either
874 * all fine or not not fine.
875 */
876 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
877 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
878 Bs3GdteTestPage03.Gen.u2Dpl = 2;
879 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW_DOWN;
880 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2;
881
882 /* First test, limit = max --> no bytes accessible --> #GP */
883 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
884 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/);
885
886 /* Second test, limit = 0 --> all by zero byte accessible --> works */
887 Bs3GdteTestPage03.Gen.u16LimitLow = 0;
888 Bs3GdteTestPage03.Gen.u4LimitHigh = 0;
889 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
890 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
891
892 /* Modify the gate handler to be a dummy that immediately does UD2
893 and triggers #UD, then advance the limit down till we get the #UD. */
894 Bs3GdteTestPage03.Gen.u1Granularity = 0;
895
896 Bs3MemCpy(&CtxTmp2, &CtxTmp, sizeof(CtxTmp2)); /* #UD result context */
897 if (g_f16BitSys)
898 {
899 CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr - BS3_ADDR_BS3TEXT16;
900 Bs3Trap16SetGate(0x83, X86_SEL_TYPE_SYS_286_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u16, 0 /*cParams*/);
901 CtxTmp2.rsp.u = Bs3Tss16.sp2 - 2*5;
902 }
903 else
904 {
905 CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr;
906 Bs3Trap32SetGate(0x83, X86_SEL_TYPE_SYS_386_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u32, 0 /*cParams*/);
907 CtxTmp2.rsp.u = Bs3Tss32.esp2 - 4*5;
908 }
909 CtxTmp2.bMode = g_bTestMode; /* g_bBs3CurrentMode not changed by the UD2 handler. */
910 CtxTmp2.cs = BS3_SEL_TEST_PAGE_02 | 2;
911 CtxTmp2.ss = BS3_SEL_TEST_PAGE_03 | 2;
912 CtxTmp2.bCpl = 2;
913
914 /* test run. */
915 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
916 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
917 g_usBs3TestStep++;
918
919 /* Real run. */
920 i = (g_f16BitSys ? 2 : 4) * 6 + 1;
921 while (i-- > 0)
922 {
923 Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1;
924 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
925 if (i > 0)
926 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/);
927 else
928 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
929 g_usBs3TestStep++;
930 }
931
932 /* Do a run where we do the same-ring kind of access. */
933 Bs3RegCtxConvertToRingX(&CtxTmp, 2);
934 if (g_f16BitSys)
935 {
936 CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 2*3;
937 i = 2*3 - 1;
938 }
939 else
940 {
941 CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 4*3;
942 i = 4*3 - 1;
943 }
944 CtxTmp.ss = BS3_SEL_TEST_PAGE_03 | 2;
945 CtxTmp2.ds = CtxTmp.ds;
946 CtxTmp2.es = CtxTmp.es;
947 CtxTmp2.fs = CtxTmp.fs;
948 CtxTmp2.gs = CtxTmp.gs;
949 while (i-- > 0)
950 {
951 Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1;
952 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
953 if (i > 0)
954 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, 0 /*BS3_SEL_TEST_PAGE_03*/, true /*f486ResumeFlagHint*/);
955 else
956 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
957 g_usBs3TestStep++;
958 }
959
960 *puTssSs2 = uSavedSs2;
961 paIdt[0x83 << cIdteShift] = SavedGate83;
962 }
963 paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs;
964 BS3_ASSERT(g_usBs3TestStep < 3000);
965
966 /*
967 * Modify the gate CS value with a conforming segment.
968 */
969 g_usBs3TestStep = 3000;
970 for (i = 0; i <= 3; i++) /* cs.dpl */
971 {
972 for (iRing = 0; iRing <= 3; iRing++)
973 {
974 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
975 {
976 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
977 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
978# if TMPL_BITS == 32
979 g_uBs3TrapEipHint = CtxTmp.rip.u32;
980# endif
981
982 for (j = 0; j <= 3; j++) /* rpl */
983 {
984 uint16_t const uCs = (uSysR0CsConf | j) + (i << BS3_SEL_RING_SHIFT);
985 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
986 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
987 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
988 //Bs3TestPrintf("%u/%u/%u/%u: cs=%04x hcs=%04x xcpt=%02x\n", i, iRing, iCtx, j, uCs, TrapCtx.uHandlerCs, TrapCtx.bXcpt);
989 /*Bs3TrapPrintFrame(&TrapCtx);*/
990 g_usBs3TestStep++;
991 if (iCtx < iRing)
992 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
993 else if (i > iRing)
994 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
995 else
996 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
997 }
998 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
999 }
1000 }
1001 }
1002 BS3_ASSERT(g_usBs3TestStep < 3500);
1003
1004 /*
1005 * The gates must be 64-bit in long mode.
1006 */
1007 if (cIdteShift != 0)
1008 {
1009 g_usBs3TestStep = 3500;
1010 for (i = 0; i <= 3; i++)
1011 {
1012 for (iRing = 0; iRing <= 3; iRing++)
1013 {
1014 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1015 {
1016 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1017 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1018
1019 for (j = 0; j < 2; j++)
1020 {
1021 static const uint16_t s_auCSes[2] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32 };
1022 uint16_t uCs = (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT);
1023 g_usBs3TestStep++;
1024 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
1025 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
1026 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1027 /*Bs3TrapPrintFrame(&TrapCtx);*/
1028 if (iCtx < iRing)
1029 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1030 else
1031 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
1032 }
1033 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
1034 }
1035 }
1036 }
1037 BS3_ASSERT(g_usBs3TestStep < 4000);
1038 }
1039
1040 /*
1041 * IDT limit check. The 286 does not access X86DESCGATE::u16OffsetHigh.
1042 */
1043 g_usBs3TestStep = 5000;
1044 i = (0x80 << (cIdteShift + 3)) - 1;
1045 j = (0x82 << (cIdteShift + 3)) - (!f286 ? 1 : 3);
1046 k = (0x83 << (cIdteShift + 3)) - 1;
1047 for (; i <= k; i++, g_usBs3TestStep++)
1048 {
1049 Idtr = IdtrSaved;
1050 Idtr.cbIdt = i;
1051 ASMSetIDTR(&Idtr);
1052 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1053 if (i < j)
1054 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx81, (0x81 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1055 else
1056 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1057 }
1058 ASMSetIDTR(&IdtrSaved);
1059 BS3_ASSERT(g_usBs3TestStep < 5100);
1060
1061# if TMPL_BITS != 16 /* Only do the paging related stuff in 32-bit and 64-bit modes. */
1062
1063 /*
1064 * IDT page not present. Placing the IDT copy such that 0x80 is on the
1065 * first page and 0x81 is on the second page. We need proceed to move
1066 * it down byte by byte to check that any inaccessible byte means #PF.
1067 *
1068 * Note! We must reload the alternative IDTR for each run as any kind of
1069 * printing to the string (like error reporting) will cause a switch
1070 * to real mode and back, reloading the default IDTR.
1071 */
1072 g_usBs3TestStep = 5200;
1073 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1074 {
1075 uint32_t const uCr2Expected = Bs3SelPtrToFlat(pbIdtCopyAlloc) + _4K;
1076 for (j = 0; j < cbIdte; j++)
1077 {
1078 pIdtCopy = (PX86DESC)&pbIdtCopyAlloc[_4K - cbIdte * 0x81 - j];
1079 Bs3MemCpy(pIdtCopy, paIdt, cbIdte * 256);
1080
1081 Idtr.cbIdt = IdtrSaved.cbIdt;
1082 Idtr.pIdt = Bs3SelPtrToFlat(pIdtCopy);
1083
1084 ASMSetIDTR(&Idtr);
1085 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1086 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1087 g_usBs3TestStep++;
1088
1089 ASMSetIDTR(&Idtr);
1090 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1091 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1092 g_usBs3TestStep++;
1093
1094 rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1095 if (RT_SUCCESS(rc))
1096 {
1097 ASMSetIDTR(&Idtr);
1098 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1099 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1100 g_usBs3TestStep++;
1101
1102 ASMSetIDTR(&Idtr);
1103 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1104 if (f486Plus)
1105 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected);
1106 else
1107 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4));
1108 g_usBs3TestStep++;
1109
1110 Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1111
1112 /* Check if that the entry type is checked after the whole IDTE has been cleared for #PF. */
1113 pIdtCopy[0x80 << cIdteShift].Gate.u4Type = 0;
1114 rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1115 if (RT_SUCCESS(rc))
1116 {
1117 ASMSetIDTR(&Idtr);
1118 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1119 if (f486Plus)
1120 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected);
1121 else
1122 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4));
1123 g_usBs3TestStep++;
1124
1125 Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1126 }
1127 }
1128 else
1129 Bs3TestPrintf("Bs3PagingProtectPtr: %d\n", i);
1130
1131 ASMSetIDTR(&IdtrSaved);
1132 }
1133 }
1134
1135 /*
1136 * The read/write and user/supervisor bits the IDT PTEs are irrelevant.
1137 */
1138 g_usBs3TestStep = 5300;
1139 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1140 {
1141 Bs3MemCpy(pbIdtCopyAlloc, paIdt, cbIdte * 256);
1142 Idtr.cbIdt = IdtrSaved.cbIdt;
1143 Idtr.pIdt = Bs3SelPtrToFlat(pbIdtCopyAlloc);
1144
1145 ASMSetIDTR(&Idtr);
1146 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1147 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1148 g_usBs3TestStep++;
1149
1150 rc = Bs3PagingProtect(Idtr.pIdt, _4K, 0 /*fSet*/, X86_PTE_RW | X86_PTE_US /*fClear*/);
1151 if (RT_SUCCESS(rc))
1152 {
1153 ASMSetIDTR(&Idtr);
1154 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1155 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1156 g_usBs3TestStep++;
1157
1158 Bs3PagingProtect(Idtr.pIdt, _4K, X86_PTE_RW | X86_PTE_US /*fSet*/, 0 /*fClear*/);
1159 }
1160 ASMSetIDTR(&IdtrSaved);
1161 }
1162
1163 /*
1164 * Check that CS.u1Accessed is set to 1. Use the test page selector #0 and #3 together
1165 * with interrupt gates 80h and 83h, respectively.
1166 */
1167/** @todo Throw in SS.u1Accessed too. */
1168 g_usBs3TestStep = 5400;
1169 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1170 {
1171 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
1172 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1173 paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00;
1174
1175 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Cs + (3 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1176 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1177 paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_03; /* rpl is ignored, so leave it as zero. */
1178
1179 /* Check that the CS.A bit is being set on a general basis and that
1180 the special CS values work with out generic handler code. */
1181 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1182 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1183 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1184 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed", Bs3GdteTestPage00.Gen.u4Type);
1185 g_usBs3TestStep++;
1186
1187 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1188 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1189 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1190 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1191 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1192 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1193 if (TrapCtx.uHandlerCs != (BS3_SEL_TEST_PAGE_03 | 3))
1194 bs3CpuBasic2_FailedF("uHandlerCs=%#x, expected %#x", TrapCtx.uHandlerCs, (BS3_SEL_TEST_PAGE_03 | 3));
1195 g_usBs3TestStep++;
1196
1197 /*
1198 * Now check that setting CS.u1Access to 1 does __NOT__ trigger a page
1199 * fault due to the RW bit being zero.
1200 * (We check both with with and without the WP bit if 80486.)
1201 */
1202 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1203 ASMSetCR0(uCr0Saved | X86_CR0_WP);
1204
1205 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1206 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1207 rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_RW /*fClear*/);
1208 if (RT_SUCCESS(rc))
1209 {
1210 /* ring-0 handler */
1211 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1212 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1213 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1214 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1215 g_usBs3TestStep++;
1216
1217 /* ring-3 handler */
1218 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1219 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1220 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1221 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1222 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1223 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1224 g_usBs3TestStep++;
1225
1226 /* clear WP and repeat the above. */
1227 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1228 ASMSetCR0(uCr0Saved & ~X86_CR0_WP);
1229 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */
1230 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */
1231
1232 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1233 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1234 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1235 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1236 g_usBs3TestStep++;
1237
1238 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1239 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1240 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1241 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!n", Bs3GdteTestPage03.Gen.u4Type);
1242 g_usBs3TestStep++;
1243
1244 Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_RW /*fSet*/, 0 /*fClear*/);
1245 }
1246
1247 ASMSetCR0(uCr0Saved);
1248
1249 /*
1250 * While we're here, check that if the CS GDT entry is a non-present
1251 * page we do get a #PF with the rigth error code and CR2.
1252 */
1253 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* Just for fun, really a pointless gesture. */
1254 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1255 rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1256 if (RT_SUCCESS(rc))
1257 {
1258 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1259 if (f486Plus)
1260 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00);
1261 else
1262 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00 + 4);
1263 g_usBs3TestStep++;
1264
1265 /* Do it from ring-3 to check ErrCd, which doesn't set X86_TRAP_PF_US it turns out. */
1266 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1267 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1268 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1269
1270 if (f486Plus)
1271 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03);
1272 else
1273 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03 + 4);
1274 g_usBs3TestStep++;
1275
1276 Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1277 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
1278 bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #1", Bs3GdteTestPage00.Gen.u4Type);
1279 if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
1280 bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #2", Bs3GdteTestPage03.Gen.u4Type);
1281 }
1282
1283 /* restore */
1284 paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs;
1285 paIdt[0x83 << cIdteShift].Gate.u16Sel = uSysR0Cs;// + (3 << BS3_SEL_RING_SHIFT) + 3;
1286 }
1287
1288# endif /* 32 || 64*/
1289
1290 /*
1291 * Check broad EFLAGS effects.
1292 */
1293 g_usBs3TestStep = 5600;
1294 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1295 {
1296 for (iRing = 0; iRing < 4; iRing++)
1297 {
1298 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1299 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1300
1301 /* all set */
1302 CtxTmp.rflags.u32 &= X86_EFL_VM | X86_EFL_1;
1303 CtxTmp.rflags.u32 |= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF /* | X86_EFL_TF */ /*| X86_EFL_IF*/
1304 | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL /* | X86_EFL_NT*/;
1305 if (f486Plus)
1306 CtxTmp.rflags.u32 |= X86_EFL_AC;
1307 if (f486Plus && !g_f16BitSys)
1308 CtxTmp.rflags.u32 |= X86_EFL_RF;
1309 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1310 CtxTmp.rflags.u32 |= X86_EFL_VIF | X86_EFL_VIP;
1311 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1312 CtxTmp.rflags.u32 &= ~X86_EFL_RF;
1313
1314 if (iCtx >= iRing)
1315 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1316 else
1317 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1318 uExpected = CtxTmp.rflags.u32
1319 & ( X86_EFL_1 | X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_DF
1320 | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP
1321 | X86_EFL_ID /*| X86_EFL_TF*/ /*| X86_EFL_IF*/ /*| X86_EFL_RF*/ );
1322 if (TrapCtx.fHandlerRfl != uExpected)
1323 bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n",
1324 TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u);
1325 g_usBs3TestStep++;
1326
1327 /* all cleared */
1328 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80286)
1329 CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_RA1_MASK | UINT16_C(0xf000));
1330 else
1331 CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_VM | X86_EFL_RA1_MASK);
1332 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1333 if (iCtx >= iRing)
1334 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1335 else
1336 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1337 uExpected = CtxTmp.rflags.u32;
1338 if (TrapCtx.fHandlerRfl != uExpected)
1339 bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n",
1340 TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u);
1341 g_usBs3TestStep++;
1342 }
1343 }
1344
1345/** @todo CS.LIMIT / canonical(CS) */
1346
1347
1348 /*
1349 * Check invalid gate types.
1350 */
1351 g_usBs3TestStep = 32000;
1352 for (iRing = 0; iRing <= 3; iRing++)
1353 {
1354 static const uint16_t s_auCSes[] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32, BS3_SEL_R0_CS64,
1355 BS3_SEL_TSS16, BS3_SEL_TSS32, BS3_SEL_TSS64, 0, BS3_SEL_SPARE_1f };
1356 static uint16_t const s_auInvlTypes64[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
1357 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1358 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
1359 static uint16_t const s_auInvlTypes32[] = { 0, 1, 2, 3, 8, 9, 10, 11, 13,
1360 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1361 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1362 /*286:*/ 12, 14, 15 };
1363 uint16_t const * const pauInvTypes = cIdteShift != 0 ? s_auInvlTypes64 : s_auInvlTypes32;
1364 uint16_t const cInvTypes = cIdteShift != 0 ? RT_ELEMENTS(s_auInvlTypes64)
1365 : f386Plus ? RT_ELEMENTS(s_auInvlTypes32) - 3 : RT_ELEMENTS(s_auInvlTypes32);
1366
1367
1368 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1369 {
1370 unsigned iType;
1371
1372 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1373 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1374# if TMPL_BITS == 32
1375 g_uBs3TrapEipHint = CtxTmp.rip.u32;
1376# endif
1377 for (iType = 0; iType < cInvTypes; iType++)
1378 {
1379 uint8_t const bSavedType = paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type;
1380 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = pauInvTypes[iType] >> 4;
1381 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = pauInvTypes[iType] & 0xf;
1382
1383 for (i = 0; i < 4; i++)
1384 {
1385 for (j = 0; j < RT_ELEMENTS(s_auCSes); j++)
1386 {
1387 uint16_t uCs = (unsigned)(s_auCSes[j] - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT)
1388 ? (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT)
1389 : s_auCSes[j] | i;
1390 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x type=%#x\n", g_usBs3TestStep, iCtx, iRing, i, uCs, pauInvTypes[iType]);*/
1391 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
1392 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1393 g_usBs3TestStep++;
1394 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1395
1396 /* Mark it not-present to check that invalid type takes precedence. */
1397 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 0;
1398 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1399 g_usBs3TestStep++;
1400 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1401 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
1402 }
1403 }
1404
1405 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
1406 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = bSavedType;
1407 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = 0;
1408 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
1409 }
1410 }
1411 }
1412 BS3_ASSERT(g_usBs3TestStep < 62000U && g_usBs3TestStep > 32000U);
1413
1414
1415 /** @todo
1416 * - Run \#PF and \#GP (and others?) at CPLs other than zero.
1417 * - Quickly generate all faults.
1418 * - All the peculiarities v8086.
1419 */
1420
1421# if TMPL_BITS != 16
1422 Bs3MemFree(pbIdtCopyAlloc, 12*_1K);
1423# endif
1424}
1425#endif /* convert me */
1426
1427
1428/**
1429 * Executes one round of SIDT and SGDT tests using one assembly worker.
1430 *
1431 * This is written with driving everything from the 16-bit or 32-bit worker in
1432 * mind, i.e. not assuming the test bitcount is the same as the current.
1433 */
1434static void bs3CpuBasic2_sidt_sgdt_One(BS3CB2SIDTSGDT const BS3_FAR *pWorker, uint8_t bTestMode, uint8_t bRing,
1435 uint8_t const *pbExpected)
1436{
1437 BS3TRAPFRAME TrapCtx;
1438 BS3REGCTX Ctx;
1439 BS3REGCTX CtxUdExpected;
1440 BS3REGCTX TmpCtx;
1441 uint8_t const cbBuf = 8*2; /* test buffer area */
1442 uint8_t abBuf[8*2 + 8 + 8]; /* test buffer w/ misalignment test space and some extra guard. */
1443 uint8_t BS3_FAR *pbBuf = abBuf;
1444 uint8_t const cbIdtr = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 2+8 : 2+4;
1445 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
1446 uint8_t bFiller;
1447 int off;
1448 int off2;
1449 unsigned cb;
1450 uint8_t BS3_FAR *pbTest;
1451
1452 /* make sure they're allocated */
1453 Bs3MemZero(&Ctx, sizeof(Ctx));
1454 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
1455 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
1456 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1457 Bs3MemZero(&abBuf, sizeof(abBuf));
1458
1459 /* Create a context, give this routine some more stack space, point the context
1460 at our SIDT [xBX] + UD2 combo, and point DS:xBX at abBuf. */
1461 Bs3RegCtxSaveEx(&Ctx, bTestMode, 256 /*cbExtraStack*/);
1462 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf);
1463 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pWorker->fpfnWorker);
1464 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
1465 g_uBs3TrapEipHint = Ctx.rip.u32;
1466 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
1467 Bs3RegCtxConvertToRingX(&Ctx, bRing);
1468
1469 /* For successful SIDT attempts, we'll stop at the UD2. */
1470 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
1471 CtxUdExpected.rip.u += pWorker->cbInstr;
1472
1473 /*
1474 * Check that it works at all and that only bytes we expect gets written to.
1475 */
1476 /* First with zero buffer. */
1477 Bs3MemZero(abBuf, sizeof(abBuf));
1478 if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), 0))
1479 Bs3TestFailedF("ASMMemIsAllU8 or Bs3MemZero is busted: abBuf=%.*Rhxs\n", sizeof(abBuf), pbBuf);
1480 if (!ASMMemIsZero(abBuf, sizeof(abBuf)))
1481 Bs3TestFailedF("ASMMemIsZero or Bs3MemZero is busted: abBuf=%.*Rhxs\n", sizeof(abBuf), pbBuf);
1482 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1483 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1484 if (f286 && abBuf[cbIdtr - 1] != 0xff)
1485 Bs3TestFailedF("286: Top base byte isn't 0xff (#1): %#x\n", abBuf[cbIdtr - 1]);
1486 if (!ASMMemIsZero(&abBuf[cbIdtr], cbBuf - cbIdtr))
1487 Bs3TestFailedF("Unexpected buffer bytes set (#1): cbIdtr=%u abBuf=%.*Rhxs\n", cbIdtr, cbBuf, pbBuf);
1488 if (Bs3MemCmp(abBuf, pbExpected, cbIdtr) != 0)
1489 Bs3TestFailedF("Mismatch (%s,#1): expected %.*Rhxs, got %.*Rhxs\n", pWorker->pszDesc, cbIdtr, pbExpected, cbIdtr, abBuf);
1490 g_usBs3TestStep++;
1491
1492 /* Again with a buffer filled with a byte not occuring in the previous result. */
1493 bFiller = 0x55;
1494 while (Bs3MemChr(abBuf, bFiller, cbBuf) != NULL)
1495 bFiller++;
1496 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
1497 if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller))
1498 Bs3TestFailedF("ASMMemIsAllU8 or Bs3MemSet is busted: bFiller=%#x abBuf=%.*Rhxs\n", bFiller, sizeof(abBuf), pbBuf);
1499
1500 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1501 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1502 if (f286 && abBuf[cbIdtr - 1] != 0xff)
1503 Bs3TestFailedF("286: Top base byte isn't 0xff (#2): %#x\n", abBuf[cbIdtr - 1]);
1504 if (!ASMMemIsAllU8(&abBuf[cbIdtr], cbBuf - cbIdtr, bFiller))
1505 Bs3TestFailedF("Unexpected buffer bytes set (#2): cbIdtr=%u bFiller=%#x abBuf=%.*Rhxs\n", cbIdtr, bFiller, cbBuf, pbBuf);
1506 if (Bs3MemChr(abBuf, bFiller, cbIdtr) != NULL)
1507 Bs3TestFailedF("Not all bytes touched: cbIdtr=%u bFiller=%#x abBuf=%.*Rhxs\n", cbIdtr, bFiller, cbBuf, pbBuf);
1508 if (Bs3MemCmp(abBuf, pbExpected, cbIdtr) != 0)
1509 Bs3TestFailedF("Mismatch (%s,#2): expected %.*Rhxs, got %.*Rhxs\n", pWorker->pszDesc, cbIdtr, pbExpected, cbIdtr, abBuf);
1510 g_usBs3TestStep++;
1511
1512 /*
1513 * Slide the buffer along 8 bytes to cover misalignment.
1514 */
1515 for (off = 0; off < 8; off++)
1516 {
1517 pbBuf = &abBuf[off];
1518 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &abBuf[off]);
1519 CtxUdExpected.rbx.u = Ctx.rbx.u;
1520
1521 /* First with zero buffer. */
1522 Bs3MemZero(abBuf, sizeof(abBuf));
1523 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1524 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1525 if (off > 0 && !ASMMemIsZero(abBuf, off))
1526 Bs3TestFailedF("Unexpected buffer bytes set before (#3): cbIdtr=%u off=%u abBuf=%.*Rhxs\n",
1527 cbIdtr, off, off + cbBuf, abBuf);
1528 if (!ASMMemIsZero(&abBuf[off + cbIdtr], sizeof(abBuf) - cbIdtr - off))
1529 Bs3TestFailedF("Unexpected buffer bytes set after (#3): cbIdtr=%u off=%u abBuf=%.*Rhxs\n",
1530 cbIdtr, off, off + cbBuf, abBuf);
1531 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
1532 Bs3TestFailedF("286: Top base byte isn't 0xff (#3): %#x\n", abBuf[off + cbIdtr - 1]);
1533 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
1534 Bs3TestFailedF("Mismatch (#3): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
1535 g_usBs3TestStep++;
1536
1537 /* Again with a buffer filled with a byte not occuring in the previous result. */
1538 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
1539 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1540 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1541 if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller))
1542 Bs3TestFailedF("Unexpected buffer bytes set before (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n",
1543 cbIdtr, off, bFiller, off + cbBuf, abBuf);
1544 if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - cbIdtr - off, bFiller))
1545 Bs3TestFailedF("Unexpected buffer bytes set after (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n",
1546 cbIdtr, off, bFiller, off + cbBuf, abBuf);
1547 if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL)
1548 Bs3TestFailedF("Not all bytes touched (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n",
1549 cbIdtr, off, bFiller, off + cbBuf, abBuf);
1550 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
1551 Bs3TestFailedF("286: Top base byte isn't 0xff (#4): %#x\n", abBuf[off + cbIdtr - 1]);
1552 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
1553 Bs3TestFailedF("Mismatch (#4): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
1554 g_usBs3TestStep++;
1555 }
1556 pbBuf = abBuf;
1557 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf);
1558 CtxUdExpected.rbx.u = Ctx.rbx.u;
1559
1560 /*
1561 * Play with the selector limit if the target mode supports limit checking
1562 * We use BS3_SEL_TEST_PAGE_00 for this
1563 */
1564 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
1565 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
1566 {
1567 uint16_t cbLimit;
1568 uint32_t uFlatBuf = Bs3SelPtrToFlat(abBuf);
1569 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
1570 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
1571 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatBuf;
1572 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatBuf >> 16);
1573 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatBuf >> 24);
1574
1575 if (pWorker->fSs)
1576 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
1577 else
1578 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
1579
1580 /* Expand up (normal). */
1581 for (off = 0; off < 8; off++)
1582 {
1583 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
1584 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
1585 {
1586 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
1587 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
1588 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1589 if (off + cbIdtr <= cbLimit + 1)
1590 {
1591 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1592 if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL)
1593 Bs3TestFailedF("Not all bytes touched (#5): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1594 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1595 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
1596 Bs3TestFailedF("Mismatch (#5): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
1597 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
1598 Bs3TestFailedF("286: Top base byte isn't 0xff (#5): %#x\n", abBuf[off + cbIdtr - 1]);
1599 }
1600 else
1601 {
1602 if (pWorker->fSs)
1603 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
1604 else
1605 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1606 if (off + 2 <= cbLimit + 1)
1607 {
1608 if (Bs3MemChr(&abBuf[off], bFiller, 2) != NULL)
1609 Bs3TestFailedF("Limit bytes not touched (#6): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1610 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1611 if (Bs3MemCmp(&abBuf[off], pbExpected, 2) != 0)
1612 Bs3TestFailedF("Mismatch (#6): expected %.2Rhxs, got %.2Rhxs\n", pbExpected, &abBuf[off]);
1613 if (!ASMMemIsAllU8(&abBuf[off + 2], cbIdtr - 2, bFiller))
1614 Bs3TestFailedF("Base bytes touched on #GP (#6): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1615 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1616 }
1617 else if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller))
1618 Bs3TestFailedF("Bytes touched on #GP: cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1619 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1620 }
1621
1622 if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller))
1623 Bs3TestFailedF("Leading bytes touched (#7): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1624 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1625 if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - off - cbIdtr, bFiller))
1626 Bs3TestFailedF("Trailing bytes touched (#7): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1627 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1628
1629 g_usBs3TestStep++;
1630 }
1631 }
1632
1633 /* Expand down (weird). Inverted valid area compared to expand up,
1634 so a limit of zero give us a valid range for 0001..0ffffh (instead of
1635 a segment with one valid byte at 0000h). Whereas a limit of 0fffeh
1636 means one valid byte at 0ffffh, and a limit of 0ffffh means none
1637 (because in a normal expand up the 0ffffh means all 64KB are
1638 accessible). */
1639 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
1640 for (off = 0; off < 8; off++)
1641 {
1642 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
1643 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
1644 {
1645 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
1646 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
1647 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1648
1649 if (off > cbLimit)
1650 {
1651 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1652 if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL)
1653 Bs3TestFailedF("Not all bytes touched (#8): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1654 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1655 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
1656 Bs3TestFailedF("Mismatch (#8): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
1657 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
1658 Bs3TestFailedF("286: Top base byte isn't 0xff (#8): %#x\n", abBuf[off + cbIdtr - 1]);
1659 }
1660 else
1661 {
1662 if (pWorker->fSs)
1663 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
1664 else
1665 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1666 if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller))
1667 Bs3TestFailedF("Bytes touched on #GP: cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1668 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1669 }
1670
1671 if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller))
1672 Bs3TestFailedF("Leading bytes touched (#9): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1673 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1674 if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - off - cbIdtr, bFiller))
1675 Bs3TestFailedF("Trailing bytes touched (#9): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
1676 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
1677
1678 g_usBs3TestStep++;
1679 }
1680 }
1681
1682 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf);
1683 CtxUdExpected.rbx.u = Ctx.rbx.u;
1684 CtxUdExpected.ss = Ctx.ss;
1685 CtxUdExpected.ds = Ctx.ds;
1686 }
1687
1688 /*
1689 * Play with the paging.
1690 */
1691 if ( BS3_MODE_IS_PAGED(bTestMode)
1692 && (!pWorker->fSs || bRing == 3) /* SS.DPL == CPL, we'll get some tiled ring-3 selector here. */
1693 && (pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED)) != NULL)
1694 {
1695 RTCCUINTXREG uFlatTest = Bs3SelPtrToFlat(pbTest);
1696
1697 /*
1698 * Slide the buffer towards the trailing guard page. We'll observe the
1699 * first word being written entirely separately from the 2nd dword/qword.
1700 */
1701 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
1702 {
1703 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller, cbIdtr * 2);
1704 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
1705 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1706 if (off + cbIdtr <= X86_PAGE_SIZE)
1707 {
1708 CtxUdExpected.rbx = Ctx.rbx;
1709 CtxUdExpected.ss = Ctx.ss;
1710 CtxUdExpected.ds = Ctx.ds;
1711 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1712 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
1713 Bs3TestFailedF("Mismatch (#9): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
1714 }
1715 else
1716 {
1717 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
1718 uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
1719 if ( off <= X86_PAGE_SIZE - 2
1720 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
1721 Bs3TestFailedF("Mismatch (#10): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n",
1722 pbExpected, &pbTest[off], off);
1723 if ( off < X86_PAGE_SIZE - 2
1724 && !ASMMemIsAllU8(&pbTest[off + 2], X86_PAGE_SIZE - off - 2, bFiller))
1725 Bs3TestFailedF("Wrote partial base on #PF (#10): bFiller=%#x, got %.*Rhxs; off=%#x\n",
1726 bFiller, X86_PAGE_SIZE - off - 2, &pbTest[off + 2], off);
1727 if (off == X86_PAGE_SIZE - 1 && pbTest[off] != bFiller)
1728 Bs3TestFailedF("Wrote partial limit on #PF (#10): Expected %02x, got %02x\n", bFiller, pbTest[off]);
1729 }
1730 g_usBs3TestStep++;
1731 }
1732
1733 /*
1734 * Now, do it the other way around. It should look normal now since writing
1735 * the limit will #PF first and nothing should be written.
1736 */
1737 for (off = cbIdtr + 4; off >= -cbIdtr - 4; off--)
1738 {
1739 Bs3MemSet(pbTest, bFiller, 48);
1740 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
1741 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1742 if (off >= 0)
1743 {
1744 CtxUdExpected.rbx = Ctx.rbx;
1745 CtxUdExpected.ss = Ctx.ss;
1746 CtxUdExpected.ds = Ctx.ds;
1747 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1748 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
1749 Bs3TestFailedF("Mismatch (#11): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
1750 }
1751 else
1752 {
1753 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0), uFlatTest + off);
1754 if ( -off < cbIdtr
1755 && !ASMMemIsAllU8(pbTest, cbIdtr + off, bFiller))
1756 Bs3TestFailedF("Wrote partial content on #PF (#12): bFiller=%#x, found %.*Rhxs; off=%d\n",
1757 bFiller, cbIdtr + off, pbTest, off);
1758 }
1759 if (!ASMMemIsAllU8(&pbTest[RT_MAX(cbIdtr + off, 0)], 16, bFiller))
1760 Bs3TestFailedF("Wrote beyond expected area (#13): bFiller=%#x, found %.16Rhxs; off=%d\n",
1761 bFiller, &pbTest[RT_MAX(cbIdtr + off, 0)], off);
1762 g_usBs3TestStep++;
1763 }
1764
1765 /*
1766 * Combine paging and segment limit and check ordering.
1767 * This is kind of interesting here since it the instruction seems to
1768 * be doing two separate writes.
1769 */
1770 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
1771 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
1772 {
1773 uint16_t cbLimit;
1774
1775 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
1776 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
1777 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
1778 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
1779 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
1780
1781 if (pWorker->fSs)
1782 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
1783 else
1784 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
1785
1786 /* Expand up (normal), approaching tail guard page. */
1787 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
1788 {
1789 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
1790 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
1791 {
1792 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
1793 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller, cbIdtr * 2);
1794 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1795 if (off + cbIdtr <= cbLimit + 1)
1796 {
1797 /* No #GP, but maybe #PF. */
1798 if (off + cbIdtr <= X86_PAGE_SIZE)
1799 {
1800 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1801 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
1802 Bs3TestFailedF("Mismatch (#14): expected %.*Rhxs, got %.*Rhxs\n",
1803 cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
1804 }
1805 else
1806 {
1807 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
1808 uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
1809 if ( off <= X86_PAGE_SIZE - 2
1810 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
1811 Bs3TestFailedF("Mismatch (#15): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n",
1812 pbExpected, &pbTest[off], off);
1813 cb = X86_PAGE_SIZE - off - 2;
1814 if ( off < X86_PAGE_SIZE - 2
1815 && !ASMMemIsAllU8(&pbTest[off + 2], cb, bFiller))
1816 Bs3TestFailedF("Wrote partial base on #PF (#15): bFiller=%#x, got %.*Rhxs; off=%#x\n",
1817 bFiller, cb, &pbTest[off + 2], off);
1818 if (off == X86_PAGE_SIZE - 1 && pbTest[off] != bFiller)
1819 Bs3TestFailedF("Wrote partial limit on #PF (#15): Expected %02x, got %02x\n", bFiller, pbTest[off]);
1820 }
1821 }
1822 else if (off + 2 <= cbLimit + 1)
1823 {
1824 /* [ig]tr.limit writing does not cause #GP, but may cause #PG, if not writing the base causes #GP. */
1825 if (off <= X86_PAGE_SIZE - 2)
1826 {
1827 if (pWorker->fSs)
1828 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
1829 else
1830 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1831 if (Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
1832 Bs3TestFailedF("Mismatch (#16): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n",
1833 pbExpected, &pbTest[off], off);
1834 cb = X86_PAGE_SIZE - off - 2;
1835 if ( off < X86_PAGE_SIZE - 2
1836 && !ASMMemIsAllU8(&pbTest[off + 2], cb, bFiller))
1837 Bs3TestFailedF("Wrote partial base with limit (#16): bFiller=%#x, got %.*Rhxs; off=%#x\n",
1838 bFiller, cb, &pbTest[off + 2], off);
1839 }
1840 else
1841 {
1842 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
1843 uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
1844 if ( off < X86_PAGE_SIZE
1845 && !ASMMemIsAllU8(&pbTest[off], X86_PAGE_SIZE - off, bFiller))
1846 Bs3TestFailedF("Mismatch (#16): Partial limit write on #PF: bFiller=%#x, got %.*Rhxs\n",
1847 bFiller, X86_PAGE_SIZE - off, &pbTest[off]);
1848 }
1849 }
1850 else
1851 {
1852 /* #GP/#SS on limit. */
1853 if (pWorker->fSs)
1854 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
1855 else
1856 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1857 if ( off < X86_PAGE_SIZE
1858 && !ASMMemIsAllU8(&pbTest[off], X86_PAGE_SIZE - off, bFiller))
1859 Bs3TestFailedF("Mismatch (#17): Partial write on #GP: bFiller=%#x, got %.*Rhxs\n",
1860 bFiller, X86_PAGE_SIZE - off, &pbTest[off]);
1861 }
1862
1863 cb = RT_MIN(cbIdtr * 2, off - (X86_PAGE_SIZE - cbIdtr*2));
1864 if (!ASMMemIsAllU8(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], cb, bFiller))
1865 Bs3TestFailedF("Leading bytes touched (#18): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n",
1866 cbIdtr, off, cbLimit, bFiller, cb, pbTest[X86_PAGE_SIZE - cbIdtr * 2]);
1867
1868 g_usBs3TestStep++;
1869
1870 /* Set DS to 0 and check that we get #GP(0). */
1871 if (!pWorker->fSs)
1872 {
1873 Ctx.ds = 0;
1874 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1875 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1876 Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
1877 g_usBs3TestStep++;
1878 }
1879 }
1880 }
1881
1882 /* Expand down. */
1883 pbTest -= X86_PAGE_SIZE; /* Note! we're backing up a page to simplify things */
1884 uFlatTest -= X86_PAGE_SIZE;
1885
1886 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
1887 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
1888 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
1889 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
1890
1891 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
1892 {
1893 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
1894 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
1895 {
1896 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
1897 Bs3MemSet(&pbTest[X86_PAGE_SIZE], bFiller, cbIdtr * 2);
1898 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1899 if (cbLimit < off && off >= X86_PAGE_SIZE)
1900 {
1901 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1902 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
1903 Bs3TestFailedF("Mismatch (#19): expected %.*Rhxs, got %.*Rhxs\n",
1904 cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
1905 cb = X86_PAGE_SIZE + cbIdtr*2 - off;
1906 if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], cb, bFiller))
1907 Bs3TestFailedF("Trailing bytes touched (#20): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n",
1908 cbIdtr, off, cbLimit, bFiller, cb, pbTest[off + cbIdtr]);
1909 }
1910 else
1911 {
1912 if (cbLimit < off && off < X86_PAGE_SIZE)
1913 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
1914 uFlatTest + off);
1915 else if (pWorker->fSs)
1916 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
1917 else
1918 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1919 cb = cbIdtr*2;
1920 if (!ASMMemIsAllU8(&pbTest[X86_PAGE_SIZE], cb, bFiller))
1921 Bs3TestFailedF("Trailing bytes touched (#20): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n",
1922 cbIdtr, off, cbLimit, bFiller, cb, pbTest[X86_PAGE_SIZE]);
1923 }
1924 g_usBs3TestStep++;
1925 }
1926 }
1927
1928 pbTest += X86_PAGE_SIZE;
1929 uFlatTest += X86_PAGE_SIZE;
1930 }
1931
1932 Bs3MemGuardedTestPageFree(pbTest);
1933 }
1934
1935 /*
1936 * Check non-canonical 64-bit space.
1937 */
1938 if ( BS3_MODE_IS_64BIT_CODE(bTestMode)
1939 && (pbTest = (uint8_t BS3_FAR *)Bs3PagingSetupCanonicalTraps()) != NULL)
1940 {
1941 /* Make our references relative to the gap. */
1942 pbTest += g_cbBs3PagingOneCanonicalTrap;
1943
1944 /* Hit it from below. */
1945 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
1946 {
1947 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0x0000800000000000) + off;
1948 Bs3MemSet(&pbTest[-64], bFiller, 64*2);
1949 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1950 if (off + cbIdtr <= 0)
1951 {
1952 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1953 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
1954 Bs3TestFailedF("Mismatch (#21): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
1955 }
1956 else
1957 {
1958 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1959 if (off <= -2 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
1960 Bs3TestFailedF("Mismatch (#21): expected limit %.2Rhxs, got %.2Rhxs\n", pbExpected, &pbTest[off]);
1961 off2 = off <= -2 ? 2 : 0;
1962 cb = cbIdtr - off2;
1963 if (!ASMMemIsAllU8(&pbTest[off + off2], cb, bFiller))
1964 Bs3TestFailedF("Mismatch (#21): touched base %.*Rhxs, got %.*Rhxs\n",
1965 cb, &pbExpected[off], cb, &pbTest[off + off2]);
1966 }
1967 if (!ASMMemIsAllU8(&pbTest[off - 16], 16, bFiller))
1968 Bs3TestFailedF("Leading bytes touched (#21): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off]);
1969 if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], 16, bFiller))
1970 Bs3TestFailedF("Trailing bytes touched (#21): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off + cbIdtr]);
1971 }
1972
1973 /* Hit it from above. */
1974 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
1975 {
1976 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0xffff800000000000) + off;
1977 Bs3MemSet(&pbTest[-64], bFiller, 64*2);
1978 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1979 if (off >= 0)
1980 {
1981 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1982 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
1983 Bs3TestFailedF("Mismatch (#22): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
1984 }
1985 else
1986 {
1987 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1988 if (!ASMMemIsAllU8(&pbTest[off], cbIdtr, bFiller))
1989 Bs3TestFailedF("Mismatch (#22): touched base %.*Rhxs, got %.*Rhxs\n",
1990 cbIdtr, &pbExpected[off], cbIdtr, &pbTest[off]);
1991 }
1992 if (!ASMMemIsAllU8(&pbTest[off - 16], 16, bFiller))
1993 Bs3TestFailedF("Leading bytes touched (#22): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off]);
1994 if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], 16, bFiller))
1995 Bs3TestFailedF("Trailing bytes touched (#22): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off + cbIdtr]);
1996 }
1997
1998 }
1999}
2000
2001
2002static void bs3CpuBasic2_sidt_sgdt_Common(uint8_t bTestMode, BS3CB2SIDTSGDT const BS3_FAR *paWorkers, unsigned cWorkers,
2003 uint8_t const *pbExpected)
2004{
2005 unsigned idx;
2006 unsigned bRing;
2007 unsigned iStep = 0;
2008
2009 /* Note! We skip the SS checks for ring-0 since we badly mess up SS in the
2010 test and don't want to bother with double faults. */
2011 for (bRing = 0; bRing <= 3; bRing++)
2012 {
2013 for (idx = 0; idx < cWorkers; idx++)
2014 if ( (paWorkers[idx].bMode & (bTestMode & BS3_MODE_CODE_MASK))
2015 && (!paWorkers[idx].fSs || bRing != 0 /** @todo || BS3_MODE_IS_64BIT_SYS(bTestMode)*/ ))
2016 {
2017 g_usBs3TestStep = iStep;
2018 bs3CpuBasic2_sidt_sgdt_One(&paWorkers[idx], bTestMode, bRing, pbExpected);
2019 iStep += 1000;
2020 }
2021 if (BS3_MODE_IS_RM_OR_V86(bTestMode))
2022 break;
2023 }
2024}
2025
2026
2027BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_sidt)(uint8_t bMode)
2028{
2029 union
2030 {
2031 RTIDTR Idtr;
2032 uint8_t ab[16];
2033 } Expected;
2034
2035 //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED;
2036 bs3CpuBasic2_SetGlobals(bMode);
2037
2038 /*
2039 * Pass to common worker which is only compiled once per mode.
2040 */
2041 Bs3MemZero(&Expected, sizeof(Expected));
2042 ASMGetIDTR(&Expected.Idtr);
2043 bs3CpuBasic2_sidt_sgdt_Common(bMode, g_aSidtWorkers, RT_ELEMENTS(g_aSidtWorkers), Expected.ab);
2044
2045 /*
2046 * Re-initialize the IDT.
2047 */
2048 Bs3TrapReInit();
2049 return 0;
2050}
2051
2052
2053BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_sgdt)(uint8_t bMode)
2054{
2055 uint64_t const uOrgAddr = Bs3Lgdt_Gdt.uAddr;
2056 uint64_t uNew = 0;
2057 union
2058 {
2059 RTGDTR Gdtr;
2060 uint8_t ab[16];
2061 } Expected;
2062
2063 //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED;
2064 bs3CpuBasic2_SetGlobals(bMode);
2065
2066 /*
2067 * If paged mode, try push the GDT way up.
2068 */
2069 Bs3MemZero(&Expected, sizeof(Expected));
2070 ASMGetGDTR(&Expected.Gdtr);
2071 if (BS3_MODE_IS_PAGED(bMode))
2072 {
2073/** @todo loading non-canonical base addresses. */
2074 int rc;
2075 uNew = BS3_MODE_IS_64BIT_SYS(bMode) ? UINT64_C(0xffff80fedcb70000) : UINT64_C(0xc2d28000);
2076 uNew |= uOrgAddr & X86_PAGE_OFFSET_MASK;
2077 rc = Bs3PagingAlias(uNew, uOrgAddr, Bs3Lgdt_Gdt.cb, X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_D | X86_PTE_A);
2078 if (RT_SUCCESS(rc))
2079 {
2080 Bs3Lgdt_Gdt.uAddr = uNew;
2081 Bs3UtilSetFullGdtr(Bs3Lgdt_Gdt.cb, uNew);
2082 ASMGetGDTR(&Expected.Gdtr);
2083 if (BS3_MODE_IS_64BIT_SYS(bMode) && ARCH_BITS != 64)
2084 *(uint32_t *)&Expected.ab[6] = (uint32_t)(uNew >> 32);
2085 }
2086 }
2087
2088 /*
2089 * Pass to common worker which is only compiled once per mode.
2090 */
2091 bs3CpuBasic2_sidt_sgdt_Common(bMode, g_aSgdtWorkers, RT_ELEMENTS(g_aSgdtWorkers), Expected.ab);
2092
2093 /*
2094 * Unalias the GDT.
2095 */
2096 if (uNew != 0)
2097 {
2098 Bs3Lgdt_Gdt.uAddr = uOrgAddr;
2099 Bs3UtilSetFullGdtr(Bs3Lgdt_Gdt.cb, uOrgAddr);
2100 Bs3PagingUnalias(uNew, Bs3Lgdt_Gdt.cb);
2101 }
2102
2103 /*
2104 * Re-initialize the IDT.
2105 */
2106 Bs3TrapReInit();
2107 return 0;
2108}
2109
2110
2111
2112/*
2113 * LIDT & LGDT
2114 */
2115
2116/**
2117 * Executes one round of LIDT and LGDT tests using one assembly worker.
2118 *
2119 * This is written with driving everything from the 16-bit or 32-bit worker in
2120 * mind, i.e. not assuming the test bitcount is the same as the current.
2121 */
2122static void bs3CpuBasic2_lidt_lgdt_One(BS3CB2SIDTSGDT const BS3_FAR *pWorker, uint8_t bTestMode, uint8_t bRing,
2123 uint8_t const *pbRestore, size_t cbRestore, uint8_t const *pbExpected)
2124{
2125 static const struct
2126 {
2127 bool fGP;
2128 uint16_t cbLimit;
2129 uint64_t u64Base;
2130 } s_aValues64[] =
2131 {
2132 { false, 0x0000, UINT64_C(0x0000000000000000) },
2133 { false, 0x0001, UINT64_C(0x0000000000000001) },
2134 { false, 0x0002, UINT64_C(0x0000000000000010) },
2135 { false, 0x0003, UINT64_C(0x0000000000000123) },
2136 { false, 0x0004, UINT64_C(0x0000000000001234) },
2137 { false, 0x0005, UINT64_C(0x0000000000012345) },
2138 { false, 0x0006, UINT64_C(0x0000000000123456) },
2139 { false, 0x0007, UINT64_C(0x0000000001234567) },
2140 { false, 0x0008, UINT64_C(0x0000000012345678) },
2141 { false, 0x0009, UINT64_C(0x0000000123456789) },
2142 { false, 0x000a, UINT64_C(0x000000123456789a) },
2143 { false, 0x000b, UINT64_C(0x00000123456789ab) },
2144 { false, 0x000c, UINT64_C(0x0000123456789abc) },
2145 { false, 0x001c, UINT64_C(0x00007ffffeefefef) },
2146 { false, 0xffff, UINT64_C(0x00007fffffffffff) },
2147 { true, 0xf3f1, UINT64_C(0x0000800000000000) },
2148 { true, 0x0000, UINT64_C(0x0000800000000000) },
2149 { true, 0x0000, UINT64_C(0x0000800000000333) },
2150 { true, 0x00f0, UINT64_C(0x0001000000000000) },
2151 { true, 0x0ff0, UINT64_C(0x0012000000000000) },
2152 { true, 0x0eff, UINT64_C(0x0123000000000000) },
2153 { true, 0xe0fe, UINT64_C(0x1234000000000000) },
2154 { true, 0x00ad, UINT64_C(0xffff300000000000) },
2155 { true, 0x0000, UINT64_C(0xffff7fffffffffff) },
2156 { true, 0x00f0, UINT64_C(0xffff7fffffffffff) },
2157 { false, 0x5678, UINT64_C(0xffff800000000000) },
2158 { false, 0x2969, UINT64_C(0xffffffffffeefefe) },
2159 { false, 0x1221, UINT64_C(0xffffffffffffffff) },
2160 { false, 0x1221, UINT64_C(0xffffffffffffffff) },
2161 };
2162 static const struct
2163 {
2164 uint16_t cbLimit;
2165 uint32_t u32Base;
2166 } s_aValues32[] =
2167 {
2168 { 0xdfdf, UINT32_C(0xefefefef) },
2169 { 0x0000, UINT32_C(0x00000000) },
2170 { 0x0001, UINT32_C(0x00000001) },
2171 { 0x0002, UINT32_C(0x00000012) },
2172 { 0x0003, UINT32_C(0x00000123) },
2173 { 0x0004, UINT32_C(0x00001234) },
2174 { 0x0005, UINT32_C(0x00012345) },
2175 { 0x0006, UINT32_C(0x00123456) },
2176 { 0x0007, UINT32_C(0x01234567) },
2177 { 0x0008, UINT32_C(0x12345678) },
2178 { 0x0009, UINT32_C(0x80204060) },
2179 { 0x000a, UINT32_C(0xddeeffaa) },
2180 { 0x000b, UINT32_C(0xfdecdbca) },
2181 { 0x000c, UINT32_C(0x6098456b) },
2182 { 0x000d, UINT32_C(0x98506099) },
2183 { 0x000e, UINT32_C(0x206950bc) },
2184 { 0x000f, UINT32_C(0x9740395d) },
2185 { 0x0334, UINT32_C(0x64a9455e) },
2186 { 0xb423, UINT32_C(0xd20b6eff) },
2187 { 0x4955, UINT32_C(0x85296d46) },
2188 { 0xffff, UINT32_C(0x07000039) },
2189 { 0xefe1, UINT32_C(0x0007fe00) },
2190 };
2191
2192 BS3TRAPFRAME TrapCtx;
2193 BS3REGCTX Ctx;
2194 BS3REGCTX CtxUdExpected;
2195 BS3REGCTX TmpCtx;
2196 uint8_t abBufLoad[40]; /* Test buffer w/ misalignment test space and some (cbIdtr) extra guard. */
2197 uint8_t abBufSave[32]; /* For saving the result after loading. */
2198 uint8_t abBufRestore[24]; /* For restoring sane value (same seg as abBufSave!). */
2199 uint8_t abExpectedFilled[32]; /* Same as pbExpected, except it's filled with bFiller2 instead of zeros. */
2200 uint8_t BS3_FAR *pbBufSave; /* Correctly aligned pointer into abBufSave. */
2201 uint8_t BS3_FAR *pbBufRestore; /* Correctly aligned pointer into abBufRestore. */
2202 uint8_t const cbIdtr = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 2+8 : 2+4;
2203 uint8_t const cbBaseLoaded = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 8
2204 : BS3_MODE_IS_16BIT_CODE(bTestMode) == !(pWorker->fFlags & BS3CB2SIDTSGDT_F_OPSIZE)
2205 ? 3 : 4;
2206 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
2207 uint8_t const bTop16BitBase = f286 ? 0xff : 0x00;
2208 uint8_t bFiller1; /* For filling abBufLoad. */
2209 uint8_t bFiller2; /* For filling abBufSave and expectations. */
2210 int off;
2211 uint8_t BS3_FAR *pbTest;
2212 unsigned i;
2213
2214 /* make sure they're allocated */
2215 Bs3MemZero(&Ctx, sizeof(Ctx));
2216 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
2217 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
2218 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
2219 Bs3MemZero(abBufSave, sizeof(abBufSave));
2220 Bs3MemZero(abBufLoad, sizeof(abBufLoad));
2221 Bs3MemZero(abBufRestore, sizeof(abBufRestore));
2222
2223 /*
2224 * Create a context, giving this routine some more stack space.
2225 * - Point the context at our LIDT [xBX] + SIDT [xDI] + LIDT [xSI] + UD2 combo.
2226 * - Point DS/SS:xBX at abBufLoad.
2227 * - Point ES:xDI at abBufSave.
2228 * - Point ES:xSI at abBufRestore.
2229 */
2230 Bs3RegCtxSaveEx(&Ctx, bTestMode, 256 /*cbExtraStack*/);
2231 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pWorker->fpfnWorker);
2232 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
2233 g_uBs3TrapEipHint = Ctx.rip.u32;
2234 Ctx.rflags.u16 &= ~X86_EFL_IF;
2235 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad);
2236
2237 pbBufSave = abBufSave;
2238 if ((BS3_FP_OFF(pbBufSave) + 2) & 7)
2239 pbBufSave += 8 - ((BS3_FP_OFF(pbBufSave) + 2) & 7);
2240 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rdi, &Ctx.es, pbBufSave);
2241
2242 pbBufRestore = abBufRestore;
2243 if ((BS3_FP_OFF(pbBufRestore) + 2) & 7)
2244 pbBufRestore += 8 - ((BS3_FP_OFF(pbBufRestore) + 2) & 7);
2245 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsi, &Ctx.es, pbBufRestore);
2246 Bs3MemCpy(pbBufRestore, pbRestore, cbRestore);
2247
2248 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
2249 Bs3RegCtxConvertToRingX(&Ctx, bRing);
2250
2251 /* For successful SIDT attempts, we'll stop at the UD2. */
2252 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
2253 CtxUdExpected.rip.u += pWorker->cbInstr;
2254
2255 /*
2256 * Check that it works at all.
2257 */
2258 Bs3MemZero(abBufLoad, sizeof(abBufLoad));
2259 Bs3MemCpy(abBufLoad, pbBufRestore, cbIdtr);
2260 Bs3MemZero(abBufSave, sizeof(abBufSave));
2261 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2262 if (bRing != 0)
2263 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2264 else
2265 {
2266 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2267 if (Bs3MemCmp(pbBufSave, pbExpected, cbIdtr * 2) != 0)
2268 Bs3TestFailedF("Mismatch (%s, #1): expected %.*Rhxs, got %.*Rhxs\n",
2269 pWorker->pszDesc, cbIdtr*2, pbExpected, cbIdtr*2, pbBufSave);
2270 }
2271 g_usBs3TestStep++;
2272
2273 /* Determine two filler bytes that doesn't appear in the previous result or our expectations. */
2274 bFiller1 = ~0x55;
2275 while ( Bs3MemChr(pbBufSave, bFiller1, cbIdtr) != NULL
2276 || Bs3MemChr(pbRestore, bFiller1, cbRestore) != NULL
2277 || bFiller1 == 0xff)
2278 bFiller1++;
2279 bFiller2 = 0x33;
2280 while ( Bs3MemChr(pbBufSave, bFiller2, cbIdtr) != NULL
2281 || Bs3MemChr(pbRestore, bFiller2, cbRestore) != NULL
2282 || bFiller2 == 0xff
2283 || bFiller2 == bFiller1)
2284 bFiller2++;
2285 Bs3MemSet(abExpectedFilled, bFiller2, sizeof(abExpectedFilled));
2286 Bs3MemCpy(abExpectedFilled, pbExpected, cbIdtr);
2287
2288 /* Again with a buffer filled with a byte not occuring in the previous result. */
2289 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2290 Bs3MemCpy(abBufLoad, pbBufRestore, cbIdtr);
2291 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2292 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2293 if (bRing != 0)
2294 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2295 else
2296 {
2297 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2298 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2299 Bs3TestFailedF("Mismatch (%s, #2): expected %.*Rhxs, got %.*Rhxs\n",
2300 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2301 }
2302 g_usBs3TestStep++;
2303
2304 /*
2305 * Try loading a bunch of different limit+base value to check what happens,
2306 * especially what happens wrt the top part of the base in 16-bit mode.
2307 */
2308 if (BS3_MODE_IS_64BIT_CODE(bTestMode))
2309 {
2310 for (i = 0; i < RT_ELEMENTS(s_aValues64); i++)
2311 {
2312 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2313 Bs3MemCpy(&abBufLoad[0], &s_aValues64[i].cbLimit, 2);
2314 Bs3MemCpy(&abBufLoad[2], &s_aValues64[i].u64Base, 8);
2315 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2316 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2317 if (bRing != 0 || s_aValues64[i].fGP)
2318 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2319 else
2320 {
2321 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2322 if ( Bs3MemCmp(&pbBufSave[0], &s_aValues64[i].cbLimit, 2) != 0
2323 || Bs3MemCmp(&pbBufSave[2], &s_aValues64[i].u64Base, 8) != 0
2324 || !ASMMemIsAllU8(&pbBufSave[10], cbIdtr, bFiller2))
2325 Bs3TestFailedF("Mismatch (%s, #2): expected %04RX16:%016RX64, fillers %#x %#x, got %.*Rhxs\n",
2326 pWorker->pszDesc, s_aValues64[i].cbLimit, s_aValues64[i].u64Base,
2327 bFiller1, bFiller2, cbIdtr*2, pbBufSave);
2328 }
2329 g_usBs3TestStep++;
2330 }
2331 }
2332 else
2333 {
2334 for (i = 0; i < RT_ELEMENTS(s_aValues32); i++)
2335 {
2336 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2337 Bs3MemCpy(&abBufLoad[0], &s_aValues32[i].cbLimit, 2);
2338 Bs3MemCpy(&abBufLoad[2], &s_aValues32[i].u32Base, cbBaseLoaded);
2339 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2340 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2341 if (bRing != 0)
2342 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2343 else
2344 {
2345 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2346 if ( Bs3MemCmp(&pbBufSave[0], &s_aValues32[i].cbLimit, 2) != 0
2347 || Bs3MemCmp(&pbBufSave[2], &s_aValues32[i].u32Base, cbBaseLoaded) != 0
2348 || ( cbBaseLoaded != 4
2349 && pbBufSave[2+3] != bTop16BitBase)
2350 || !ASMMemIsAllU8(&pbBufSave[8], cbIdtr, bFiller2))
2351 Bs3TestFailedF("Mismatch (%s,#3): loaded %04RX16:%08RX32, fillers %#x %#x%s, got %.*Rhxs\n",
2352 pWorker->pszDesc, s_aValues32[i].cbLimit, s_aValues32[i].u32Base, bFiller1, bFiller2,
2353 f286 ? ", 286" : "", cbIdtr*2, pbBufSave);
2354 }
2355 g_usBs3TestStep++;
2356 }
2357 }
2358
2359 /*
2360 * Slide the buffer along 8 bytes to cover misalignment.
2361 */
2362 for (off = 0; off < 8; off++)
2363 {
2364 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &abBufLoad[off]);
2365 CtxUdExpected.rbx.u = Ctx.rbx.u;
2366
2367 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2368 Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr);
2369 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2370 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2371 if (bRing != 0)
2372 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2373 else
2374 {
2375 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2376 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2377 Bs3TestFailedF("Mismatch (%s, #4): expected %.*Rhxs, got %.*Rhxs\n",
2378 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2379 }
2380 g_usBs3TestStep++;
2381 }
2382 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad);
2383 CtxUdExpected.rbx.u = Ctx.rbx.u;
2384
2385 /*
2386 * Play with the selector limit if the target mode supports limit checking
2387 * We use BS3_SEL_TEST_PAGE_00 for this
2388 */
2389 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
2390 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
2391 {
2392 uint16_t cbLimit;
2393 uint32_t uFlatBuf = Bs3SelPtrToFlat(abBufLoad);
2394 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
2395 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
2396 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatBuf;
2397 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatBuf >> 16);
2398 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatBuf >> 24);
2399
2400 if (pWorker->fSs)
2401 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
2402 else
2403 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2404
2405 /* Expand up (normal). */
2406 for (off = 0; off < 8; off++)
2407 {
2408 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2409 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
2410 {
2411 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2412
2413 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2414 Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr);
2415 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2416 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2417 if (bRing != 0)
2418 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2419 else if (off + cbIdtr <= cbLimit + 1)
2420 {
2421 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2422 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2423 Bs3TestFailedF("Mismatch (%s, #5): expected %.*Rhxs, got %.*Rhxs\n",
2424 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2425 }
2426 else if (pWorker->fSs)
2427 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2428 else
2429 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2430 g_usBs3TestStep++;
2431
2432 /* Again with zero limit and messed up base (should trigger tripple fault if partially loaded). */
2433 abBufLoad[off] = abBufLoad[off + 1] = 0;
2434 abBufLoad[off + 2] |= 1;
2435 abBufLoad[off + cbIdtr - 2] ^= 0x5a;
2436 abBufLoad[off + cbIdtr - 1] ^= 0xa5;
2437 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2438 if (bRing != 0)
2439 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2440 else if (off + cbIdtr <= cbLimit + 1)
2441 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2442 else if (pWorker->fSs)
2443 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2444 else
2445 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2446 }
2447 }
2448
2449 /* Expand down (weird). Inverted valid area compared to expand up,
2450 so a limit of zero give us a valid range for 0001..0ffffh (instead of
2451 a segment with one valid byte at 0000h). Whereas a limit of 0fffeh
2452 means one valid byte at 0ffffh, and a limit of 0ffffh means none
2453 (because in a normal expand up the 0ffffh means all 64KB are
2454 accessible). */
2455 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
2456 for (off = 0; off < 8; off++)
2457 {
2458 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2459 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
2460 {
2461 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2462
2463 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2464 Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr);
2465 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2466 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2467 if (bRing != 0)
2468 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2469 else if (off > cbLimit)
2470 {
2471 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2472 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2473 Bs3TestFailedF("Mismatch (%s, #6): expected %.*Rhxs, got %.*Rhxs\n",
2474 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2475 }
2476 else if (pWorker->fSs)
2477 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2478 else
2479 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2480 g_usBs3TestStep++;
2481
2482 /* Again with zero limit and messed up base (should trigger triple fault if partially loaded). */
2483 abBufLoad[off] = abBufLoad[off + 1] = 0;
2484 abBufLoad[off + 2] |= 3;
2485 abBufLoad[off + cbIdtr - 2] ^= 0x55;
2486 abBufLoad[off + cbIdtr - 1] ^= 0xaa;
2487 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2488 if (bRing != 0)
2489 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2490 else if (off > cbLimit)
2491 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2492 else if (pWorker->fSs)
2493 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2494 else
2495 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2496 }
2497 }
2498
2499 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad);
2500 CtxUdExpected.rbx.u = Ctx.rbx.u;
2501 CtxUdExpected.ss = Ctx.ss;
2502 CtxUdExpected.ds = Ctx.ds;
2503 }
2504
2505 /*
2506 * Play with the paging.
2507 */
2508 if ( BS3_MODE_IS_PAGED(bTestMode)
2509 && (!pWorker->fSs || bRing == 3) /* SS.DPL == CPL, we'll get some tiled ring-3 selector here. */
2510 && (pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED)) != NULL)
2511 {
2512 RTCCUINTXREG uFlatTest = Bs3SelPtrToFlat(pbTest);
2513
2514 /*
2515 * Slide the load buffer towards the trailing guard page.
2516 */
2517 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[X86_PAGE_SIZE]);
2518 CtxUdExpected.ss = Ctx.ss;
2519 CtxUdExpected.ds = Ctx.ds;
2520 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2521 {
2522 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller1, cbIdtr*2);
2523 if (off < X86_PAGE_SIZE)
2524 Bs3MemCpy(&pbTest[off], pbBufRestore, RT_MIN(X86_PAGE_SIZE - off, cbIdtr));
2525 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
2526 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2527 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2528 if (bRing != 0)
2529 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2530 else if (off + cbIdtr <= X86_PAGE_SIZE)
2531 {
2532 CtxUdExpected.rbx = Ctx.rbx;
2533 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2534 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr*2) != 0)
2535 Bs3TestFailedF("Mismatch (%s, #7): expected %.*Rhxs, got %.*Rhxs\n",
2536 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2537 }
2538 else
2539 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
2540 g_usBs3TestStep++;
2541
2542 /* Again with zero limit and maybe messed up base as well (triple fault if buggy).
2543 The 386DX-40 here triple faults (or something) with off == 0xffe, nothing else. */
2544 if ( off < X86_PAGE_SIZE && off + cbIdtr > X86_PAGE_SIZE
2545 && ( off != X86_PAGE_SIZE - 2
2546 || (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) != BS3CPU_80386)
2547 )
2548 {
2549 pbTest[off] = 0;
2550 if (off + 1 < X86_PAGE_SIZE)
2551 pbTest[off + 1] = 0;
2552 if (off + 2 < X86_PAGE_SIZE)
2553 pbTest[off + 2] |= 7;
2554 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2555 if (bRing != 0)
2556 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2557 else
2558 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
2559 g_usBs3TestStep++;
2560 }
2561 }
2562
2563 /*
2564 * Now, do it the other way around. It should look normal now since writing
2565 * the limit will #PF first and nothing should be written.
2566 */
2567 for (off = cbIdtr + 4; off >= -cbIdtr - 4; off--)
2568 {
2569 Bs3MemSet(pbTest, bFiller1, 48);
2570 if (off >= 0)
2571 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
2572 else if (off + cbIdtr > 0)
2573 Bs3MemCpy(pbTest, &pbBufRestore[-off], cbIdtr + off);
2574 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
2575 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2576 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2577 if (bRing != 0)
2578 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2579 else if (off >= 0)
2580 {
2581 CtxUdExpected.rbx = Ctx.rbx;
2582 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2583 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr*2) != 0)
2584 Bs3TestFailedF("Mismatch (%s, #8): expected %.*Rhxs, got %.*Rhxs\n",
2585 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2586 }
2587 else
2588 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off);
2589 g_usBs3TestStep++;
2590
2591 /* Again with messed up base as well (triple fault if buggy). */
2592 if (off < 0 && off > -cbIdtr)
2593 {
2594 if (off + 2 >= 0)
2595 pbTest[off + 2] |= 15;
2596 pbTest[off + cbIdtr - 1] ^= 0xaa;
2597 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2598 if (bRing != 0)
2599 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2600 else
2601 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off);
2602 g_usBs3TestStep++;
2603 }
2604 }
2605
2606 /*
2607 * Combine paging and segment limit and check ordering.
2608 * This is kind of interesting here since it the instruction seems to
2609 * actually be doing two separate read, just like it's S[IG]DT counterpart.
2610 *
2611 * Note! My 486DX4 does a DWORD limit read when the operand size is 32-bit,
2612 * that's what f486Weirdness deals with.
2613 */
2614 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
2615 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
2616 {
2617 bool const f486Weirdness = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80486
2618 && BS3_MODE_IS_32BIT_CODE(bTestMode) == !(pWorker->fFlags & BS3CB2SIDTSGDT_F_OPSIZE);
2619 uint16_t cbLimit;
2620
2621 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
2622 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
2623 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
2624 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
2625 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
2626
2627 if (pWorker->fSs)
2628 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
2629 else
2630 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2631
2632 /* Expand up (normal), approaching tail guard page. */
2633 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2634 {
2635 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2636 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
2637 {
2638 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2639 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller1, cbIdtr * 2);
2640 if (off < X86_PAGE_SIZE)
2641 Bs3MemCpy(&pbTest[off], pbBufRestore, RT_MIN(cbIdtr, X86_PAGE_SIZE - off));
2642 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2643 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2644 if (bRing != 0)
2645 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2646 else if (off + cbIdtr <= cbLimit + 1)
2647 {
2648 /* No #GP, but maybe #PF. */
2649 if (off + cbIdtr <= X86_PAGE_SIZE)
2650 {
2651 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2652 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2653 Bs3TestFailedF("Mismatch (%s, #9): expected %.*Rhxs, got %.*Rhxs\n",
2654 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2655 }
2656 else
2657 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
2658 }
2659 /* No #GP/#SS on limit, but instead #PF? */
2660 else if ( !f486Weirdness
2661 ? off < cbLimit && off >= 0xfff
2662 : off + 2 < cbLimit && off >= 0xffd)
2663 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE));
2664 /* #GP/#SS on limit or base. */
2665 else if (pWorker->fSs)
2666 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2667 else
2668 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2669
2670 g_usBs3TestStep++;
2671
2672 /* Set DS to 0 and check that we get #GP(0). */
2673 if (!pWorker->fSs)
2674 {
2675 Ctx.ds = 0;
2676 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2677 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2678 Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2679 g_usBs3TestStep++;
2680 }
2681 }
2682 }
2683
2684 /* Expand down. */
2685 pbTest -= X86_PAGE_SIZE; /* Note! we're backing up a page to simplify things */
2686 uFlatTest -= X86_PAGE_SIZE;
2687
2688 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
2689 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
2690 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
2691 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
2692
2693 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2694 {
2695 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2696 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
2697 {
2698 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2699 Bs3MemSet(&pbTest[X86_PAGE_SIZE], bFiller1, cbIdtr * 2);
2700 if (off >= X86_PAGE_SIZE)
2701 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
2702 else if (off > X86_PAGE_SIZE - cbIdtr)
2703 Bs3MemCpy(&pbTest[X86_PAGE_SIZE], &pbBufRestore[X86_PAGE_SIZE - off], cbIdtr - (X86_PAGE_SIZE - off));
2704 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2705 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2706 if (bRing != 0)
2707 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2708 else if (cbLimit < off && off >= X86_PAGE_SIZE)
2709 {
2710 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2711 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2712 Bs3TestFailedF("Mismatch (%s, #10): expected %.*Rhxs, got %.*Rhxs\n",
2713 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2714 }
2715 else if (cbLimit < off && off < X86_PAGE_SIZE)
2716 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off);
2717 else if (pWorker->fSs)
2718 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2719 else
2720 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2721 g_usBs3TestStep++;
2722 }
2723 }
2724
2725 pbTest += X86_PAGE_SIZE;
2726 uFlatTest += X86_PAGE_SIZE;
2727 }
2728
2729 Bs3MemGuardedTestPageFree(pbTest);
2730 }
2731
2732 /*
2733 * Check non-canonical 64-bit space.
2734 */
2735 if ( BS3_MODE_IS_64BIT_CODE(bTestMode)
2736 && (pbTest = (uint8_t BS3_FAR *)Bs3PagingSetupCanonicalTraps()) != NULL)
2737 {
2738 /* Make our references relative to the gap. */
2739 pbTest += g_cbBs3PagingOneCanonicalTrap;
2740
2741 /* Hit it from below. */
2742 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
2743 {
2744 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0x0000800000000000) + off;
2745 Bs3MemSet(&pbTest[-64], bFiller1, 64*2);
2746 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
2747 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2748 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2749 if (off + cbIdtr > 0 || bRing != 0)
2750 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2751 else
2752 {
2753 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2754 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2755 Bs3TestFailedF("Mismatch (%s, #11): expected %.*Rhxs, got %.*Rhxs\n",
2756 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2757 }
2758 }
2759
2760 /* Hit it from above. */
2761 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
2762 {
2763 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0xffff800000000000) + off;
2764 Bs3MemSet(&pbTest[-64], bFiller1, 64*2);
2765 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
2766 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2767 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2768 if (off < 0 || bRing != 0)
2769 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2770 else
2771 {
2772 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2773 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2774 Bs3TestFailedF("Mismatch (%s, #19): expected %.*Rhxs, got %.*Rhxs\n",
2775 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2776 }
2777 }
2778
2779 }
2780}
2781
2782
2783static void bs3CpuBasic2_lidt_lgdt_Common(uint8_t bTestMode, BS3CB2SIDTSGDT const BS3_FAR *paWorkers, unsigned cWorkers,
2784 void const *pvRestore, size_t cbRestore, uint8_t const *pbExpected)
2785{
2786 unsigned idx;
2787 unsigned bRing;
2788 unsigned iStep = 0;
2789
2790 /* Note! We skip the SS checks for ring-0 since we badly mess up SS in the
2791 test and don't want to bother with double faults. */
2792 for (bRing = BS3_MODE_IS_V86(bTestMode) ? 3 : 0; bRing <= 3; bRing++)
2793 {
2794 for (idx = 0; idx < cWorkers; idx++)
2795 if ( (paWorkers[idx].bMode & (bTestMode & BS3_MODE_CODE_MASK))
2796 && (!paWorkers[idx].fSs || bRing != 0 /** @todo || BS3_MODE_IS_64BIT_SYS(bTestMode)*/ )
2797 && ( !(paWorkers[idx].fFlags & BS3CB2SIDTSGDT_F_386PLUS)
2798 || ( bTestMode > BS3_MODE_PE16
2799 || ( bTestMode == BS3_MODE_PE16
2800 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)) ) )
2801 {
2802 //Bs3TestPrintf("idx=%-2d fpfnWorker=%p fSs=%d cbInstr=%d\n",
2803 // idx, paWorkers[idx].fpfnWorker, paWorkers[idx].fSs, paWorkers[idx].cbInstr);
2804 g_usBs3TestStep = iStep;
2805 bs3CpuBasic2_lidt_lgdt_One(&paWorkers[idx], bTestMode, bRing, pvRestore, cbRestore, pbExpected);
2806 iStep += 1000;
2807 }
2808 if (BS3_MODE_IS_RM_SYS(bTestMode))
2809 break;
2810 }
2811}
2812
2813
2814BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_lidt)(uint8_t bMode)
2815{
2816 union
2817 {
2818 RTIDTR Idtr;
2819 uint8_t ab[32]; /* At least cbIdtr*2! */
2820 } Expected;
2821
2822 //if (bMode != BS3_MODE_LM64) return 0;
2823 bs3CpuBasic2_SetGlobals(bMode);
2824
2825 /*
2826 * Pass to common worker which is only compiled once per mode.
2827 */
2828 Bs3MemZero(&Expected, sizeof(Expected));
2829 ASMGetIDTR(&Expected.Idtr);
2830
2831 if (BS3_MODE_IS_RM_SYS(bMode))
2832 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
2833 &Bs3Lidt_Ivt, sizeof(Bs3Lidt_Ivt), Expected.ab);
2834 else if (BS3_MODE_IS_16BIT_SYS(bMode))
2835 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
2836 &Bs3Lidt_Idt16, sizeof(Bs3Lidt_Idt16), Expected.ab);
2837 else if (BS3_MODE_IS_32BIT_SYS(bMode))
2838 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
2839 &Bs3Lidt_Idt32, sizeof(Bs3Lidt_Idt32), Expected.ab);
2840 else
2841 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
2842 &Bs3Lidt_Idt64, sizeof(Bs3Lidt_Idt64), Expected.ab);
2843
2844 /*
2845 * Re-initialize the IDT.
2846 */
2847 Bs3TrapReInit();
2848 return 0;
2849}
2850
2851
2852BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_lgdt)(uint8_t bMode)
2853{
2854 union
2855 {
2856 RTGDTR Gdtr;
2857 uint8_t ab[32]; /* At least cbIdtr*2! */
2858 } Expected;
2859
2860 //if (!BS3_MODE_IS_64BIT_SYS(bMode)) return 0;
2861 bs3CpuBasic2_SetGlobals(bMode);
2862
2863 /*
2864 * Pass to common worker which is only compiled once per mode.
2865 */
2866 if (BS3_MODE_IS_RM_SYS(bMode))
2867 ASMSetGDTR((PRTGDTR)&Bs3LgdtDef_Gdt);
2868 Bs3MemZero(&Expected, sizeof(Expected));
2869 ASMGetGDTR(&Expected.Gdtr);
2870
2871 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLgdtWorkers, RT_ELEMENTS(g_aLgdtWorkers),
2872 &Bs3LgdtDef_Gdt, sizeof(Bs3LgdtDef_Gdt), Expected.ab);
2873
2874 /*
2875 * Re-initialize the IDT.
2876 */
2877 Bs3TrapReInit();
2878 return 0;
2879}
2880
2881typedef union IRETBUF
2882{
2883 uint64_t au64[6]; /* max req is 5 */
2884 uint32_t au32[12]; /* max req is 9 */
2885 uint16_t au16[24]; /* max req is 5 */
2886 uint8_t ab[48];
2887} IRETBUF;
2888typedef IRETBUF BS3_FAR *PIRETBUF;
2889
2890
2891static void iretbuf_SetupFrame(PIRETBUF pIretBuf, unsigned const cbPop,
2892 uint16_t uCS, uint64_t uPC, uint32_t fEfl, uint16_t uSS, uint64_t uSP)
2893{
2894 if (cbPop == 2)
2895 {
2896 pIretBuf->au16[0] = (uint16_t)uPC;
2897 pIretBuf->au16[1] = uCS;
2898 pIretBuf->au16[2] = (uint16_t)fEfl;
2899 pIretBuf->au16[3] = (uint16_t)uSP;
2900 pIretBuf->au16[4] = uSS;
2901 }
2902 else if (cbPop != 8)
2903 {
2904 pIretBuf->au32[0] = (uint32_t)uPC;
2905 pIretBuf->au16[1*2] = uCS;
2906 pIretBuf->au32[2] = (uint32_t)fEfl;
2907 pIretBuf->au32[3] = (uint32_t)uSP;
2908 pIretBuf->au16[4*2] = uSS;
2909 }
2910 else
2911 {
2912 pIretBuf->au64[0] = uPC;
2913 pIretBuf->au16[1*4] = uCS;
2914 pIretBuf->au64[2] = fEfl;
2915 pIretBuf->au64[3] = uSP;
2916 pIretBuf->au16[4*4] = uSS;
2917 }
2918}
2919
2920uint32_t ASMGetESP(void);
2921#pragma aux ASMGetESP = \
2922 ".386" \
2923 "mov ax, sp" \
2924 "mov edx, esp" \
2925 "shr edx, 16" \
2926 value [ax dx] \
2927 modify exact [ax dx];
2928
2929
2930static void bs3CpuBasic2_iret_Worker(uint8_t bTestMode, FPFNBS3FAR pfnIret, unsigned const cbPop,
2931 PIRETBUF pIretBuf, const char BS3_FAR *pszDesc)
2932{
2933 BS3TRAPFRAME TrapCtx;
2934 BS3REGCTX Ctx;
2935 BS3REGCTX CtxUdExpected;
2936 BS3REGCTX TmpCtx;
2937 BS3REGCTX TmpCtxExpected;
2938 uint8_t abLowUd[8];
2939 uint8_t abLowIret[8];
2940 FPFNBS3FAR pfnUdLow = (FPFNBS3FAR)abLowUd;
2941 FPFNBS3FAR pfnIretLow = (FPFNBS3FAR)abLowIret;
2942 unsigned const cbSameCplFrame = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 5*cbPop : 3*cbPop;
2943 bool const fUseLowCode = cbPop == 2 && !BS3_MODE_IS_16BIT_CODE(bTestMode);
2944 int iRingDst;
2945 int iRingSrc;
2946 uint16_t uDplSs;
2947 uint16_t uRplCs;
2948 uint16_t uRplSs;
2949// int i;
2950 uint8_t BS3_FAR *pbTest;
2951
2952 NOREF(abLowUd);
2953#define IRETBUF_SET_SEL(a_idx, a_uValue) \
2954 do { *(uint16_t)&pIretBuf->ab[a_idx * cbPop] = (a_uValue); } while (0)
2955#define IRETBUF_SET_REG(a_idx, a_uValue) \
2956 do { uint8_t const BS3_FAR *pbTmp = &pIretBuf->ab[a_idx * cbPop]; \
2957 if (cbPop == 2) *(uint16_t)pbTmp = (uint16_t)(a_uValue); \
2958 else if (cbPop != 8) *(uint32_t)pbTmp = (uint32_t)(a_uValue); \
2959 else *(uint64_t)pbTmp = (a_uValue); \
2960 } while (0)
2961
2962 /* make sure they're allocated */
2963 Bs3MemZero(&Ctx, sizeof(Ctx));
2964 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
2965 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
2966 Bs3MemZero(&TmpCtxExpected, sizeof(TmpCtxExpected));
2967 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
2968
2969 /*
2970 * When dealing with 16-bit irets in 32-bit or 64-bit mode, we must have
2971 * copies of both iret and ud in the first 64KB of memory. The stack is
2972 * below 64KB, so we'll just copy the instructions onto the stack.
2973 */
2974 Bs3MemCpy(abLowUd, bs3CpuBasic2_ud2, 4);
2975 Bs3MemCpy(abLowIret, pfnIret, 4);
2976
2977 /*
2978 * Create a context (stack is irrelevant, we'll mainly be using pIretBuf).
2979 * - Point the context at our iret instruction.
2980 * - Point SS:xSP at pIretBuf.
2981 */
2982 Bs3RegCtxSaveEx(&Ctx, bTestMode, 0);
2983 if (!fUseLowCode)
2984 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pfnIret);
2985 else
2986 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, pfnIretLow);
2987 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
2988 g_uBs3TrapEipHint = Ctx.rip.u32;
2989 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, pIretBuf);
2990
2991 /*
2992 * The first success (UD) context keeps the same code bit-count as the iret.
2993 */
2994 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
2995 if (!fUseLowCode)
2996 Bs3RegCtxSetRipCsFromLnkPtr(&CtxUdExpected, bs3CpuBasic2_ud2);
2997 else
2998 Bs3RegCtxSetRipCsFromCurPtr(&CtxUdExpected, pfnUdLow);
2999 CtxUdExpected.rsp.u += cbSameCplFrame;
3000
3001 /*
3002 * Check that it works at all.
3003 */
3004 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3005 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3006
3007 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3008 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3009 g_usBs3TestStep++;
3010
3011 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
3012 {
3013 /* Selectors are modified when switching rings, so we need to know
3014 what we're dealing with there. */
3015 if ( !BS3_SEL_IS_IN_R0_RANGE(Ctx.cs) || !BS3_SEL_IS_IN_R0_RANGE(Ctx.ss)
3016 || !BS3_SEL_IS_IN_R0_RANGE(Ctx.ds) || !BS3_SEL_IS_IN_R0_RANGE(Ctx.es))
3017 Bs3TestFailedF("Expected R0 CS, SS, DS and ES; not %#x, %#x, %#x and %#x\n", Ctx.cs, Ctx.ss, Ctx.ds, Ctx.es);
3018 if (Ctx.fs || Ctx.gs)
3019 Bs3TestFailed("Expected R0 FS and GS to be 0!\n");
3020
3021 /*
3022 * Test returning to outer rings if protected mode.
3023 */
3024 Bs3MemCpy(&TmpCtx, &Ctx, sizeof(TmpCtx));
3025 Bs3MemCpy(&TmpCtxExpected, &CtxUdExpected, sizeof(TmpCtxExpected));
3026 for (iRingDst = 3; iRingDst >= 0; iRingDst--)
3027 {
3028 Bs3RegCtxConvertToRingX(&TmpCtxExpected, iRingDst);
3029 TmpCtxExpected.ds = iRingDst ? 0 : TmpCtx.ds;
3030 TmpCtx.es = TmpCtxExpected.es;
3031 iretbuf_SetupFrame(pIretBuf, cbPop, TmpCtxExpected.cs, TmpCtxExpected.rip.u,
3032 TmpCtxExpected.rflags.u32, TmpCtxExpected.ss, TmpCtxExpected.rsp.u);
3033 Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx);
3034 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected);
3035 g_usBs3TestStep++;
3036 }
3037
3038 /*
3039 * Check CS.RPL and SS.RPL.
3040 */
3041 for (iRingDst = 3; iRingDst >= 0; iRingDst--)
3042 {
3043 uint16_t const uDstSsR0 = (CtxUdExpected.ss & BS3_SEL_RING_SUB_MASK) + BS3_SEL_R0_FIRST;
3044 Bs3MemCpy(&TmpCtxExpected, &CtxUdExpected, sizeof(TmpCtxExpected));
3045 Bs3RegCtxConvertToRingX(&TmpCtxExpected, iRingDst);
3046 for (iRingSrc = 3; iRingSrc >= 0; iRingSrc--)
3047 {
3048 Bs3MemCpy(&TmpCtx, &Ctx, sizeof(TmpCtx));
3049 Bs3RegCtxConvertToRingX(&TmpCtx, iRingSrc);
3050 TmpCtx.es = TmpCtxExpected.es;
3051 TmpCtxExpected.ds = iRingDst != iRingSrc ? 0 : TmpCtx.ds;
3052 for (uRplCs = 0; uRplCs <= 3; uRplCs++)
3053 {
3054 uint16_t const uSrcEs = TmpCtx.es;
3055 uint16_t const uDstCs = (TmpCtxExpected.cs & X86_SEL_MASK_OFF_RPL) | uRplCs;
3056 //Bs3TestPrintf("dst=%d src=%d rplCS=%d\n", iRingDst, iRingSrc, uRplCs);
3057
3058 /* CS.RPL */
3059 iretbuf_SetupFrame(pIretBuf, cbPop, uDstCs, TmpCtxExpected.rip.u, TmpCtxExpected.rflags.u32,
3060 TmpCtxExpected.ss, TmpCtxExpected.rsp.u);
3061 Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx);
3062 if (uRplCs == iRingDst && iRingDst >= iRingSrc)
3063 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected);
3064 else
3065 {
3066 if (iRingDst < iRingSrc)
3067 TmpCtx.es = 0;
3068 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstCs & X86_SEL_MASK_OFF_RPL);
3069 TmpCtx.es = uSrcEs;
3070 }
3071 g_usBs3TestStep++;
3072
3073 /* SS.RPL */
3074 if (iRingDst != iRingSrc || BS3_MODE_IS_64BIT_CODE(bTestMode))
3075 {
3076 uint16_t uSavedDstSs = TmpCtxExpected.ss;
3077 for (uRplSs = 0; uRplSs <= 3; uRplSs++)
3078 {
3079 /* SS.DPL (iRingDst == CS.DPL) */
3080 for (uDplSs = 0; uDplSs <= 3; uDplSs++)
3081 {
3082 uint16_t const uDstSs = ((uDplSs << BS3_SEL_RING_SHIFT) | uRplSs) + uDstSsR0;
3083 //Bs3TestPrintf("dst=%d src=%d rplCS=%d rplSS=%d dplSS=%d dst %04x:%08RX64 %08RX32 %04x:%08RX64\n",
3084 // iRingDst, iRingSrc, uRplCs, uRplSs, uDplSs, uDstCs, TmpCtxExpected.rip.u,
3085 // TmpCtxExpected.rflags.u32, uDstSs, TmpCtxExpected.rsp.u);
3086
3087 iretbuf_SetupFrame(pIretBuf, cbPop, uDstCs, TmpCtxExpected.rip.u,
3088 TmpCtxExpected.rflags.u32, uDstSs, TmpCtxExpected.rsp.u);
3089 Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx);
3090 if (uRplCs != iRingDst || iRingDst < iRingSrc)
3091 {
3092 if (iRingDst < iRingSrc)
3093 TmpCtx.es = 0;
3094 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstCs & X86_SEL_MASK_OFF_RPL);
3095 }
3096 else if (uRplSs != iRingDst || uDplSs != iRingDst)
3097 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstSs & X86_SEL_MASK_OFF_RPL);
3098 else
3099 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected);
3100 TmpCtx.es = uSrcEs;
3101 g_usBs3TestStep++;
3102 }
3103 }
3104
3105 TmpCtxExpected.ss = uSavedDstSs;
3106 }
3107 }
3108 }
3109 }
3110 }
3111
3112 /*
3113 * Special 64-bit checks.
3114 */
3115 if (BS3_MODE_IS_64BIT_CODE(bTestMode))
3116 {
3117 /* The VM flag is completely ignored. */
3118 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3119 CtxUdExpected.rflags.u32 | X86_EFL_VM, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3120 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3121 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3122 g_usBs3TestStep++;
3123
3124 /* The NT flag can be loaded just fine. */
3125 CtxUdExpected.rflags.u32 |= X86_EFL_NT;
3126 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3127 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3128 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3129 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3130 CtxUdExpected.rflags.u32 &= ~X86_EFL_NT;
3131 g_usBs3TestStep++;
3132
3133 /* However, we'll #GP(0) if it's already set (in RFLAGS) when executing IRET. */
3134 Ctx.rflags.u32 |= X86_EFL_NT;
3135 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3136 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3137 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3138 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3139 g_usBs3TestStep++;
3140
3141 /* The NT flag #GP(0) should trump all other exceptions - pit it against #PF. */
3142 pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED);
3143 if (pbTest != NULL)
3144 {
3145 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, &pbTest[X86_PAGE_SIZE]);
3146 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3147 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3148 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3149 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3150 g_usBs3TestStep++;
3151
3152 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, pIretBuf);
3153 Bs3MemGuardedTestPageFree(pbTest);
3154 }
3155 Ctx.rflags.u32 &= ~X86_EFL_NT;
3156 }
3157}
3158
3159
3160BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_iret)(uint8_t bMode)
3161{
3162 struct
3163 {
3164 uint8_t abExtraStack[4096]; /**< we've got ~30KB of stack, so 4KB for the trap handlers++ is not a problem. */
3165 IRETBUF IRetBuf;
3166 uint8_t abGuard[32];
3167 } uBuf;
3168 size_t cbUnused;
3169
3170 //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED;
3171 bs3CpuBasic2_SetGlobals(bMode);
3172
3173 /*
3174 * Primary instruction form.
3175 */
3176 Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf));
3177 Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard));
3178 if (BS3_MODE_IS_16BIT_CODE(bMode))
3179 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 2, &uBuf.IRetBuf, "iret");
3180 else if (BS3_MODE_IS_32BIT_CODE(bMode))
3181 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 4, &uBuf.IRetBuf, "iretd");
3182 else
3183 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_rexw, 8, &uBuf.IRetBuf, "o64 iret");
3184
3185 BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88));
3186 cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa)
3187 - (uintptr_t)uBuf.abExtraStack;
3188 if (cbUnused < 2048)
3189 Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 1);
3190
3191 /*
3192 * Secondary variation: opsize prefixed.
3193 */
3194 Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf));
3195 Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard));
3196 if (BS3_MODE_IS_16BIT_CODE(bMode) && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
3197 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 4, &uBuf.IRetBuf, "o32 iret");
3198 else if (BS3_MODE_IS_32BIT_CODE(bMode))
3199 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 2, &uBuf.IRetBuf, "o16 iret");
3200 else if (BS3_MODE_IS_64BIT_CODE(bMode))
3201 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 4, &uBuf.IRetBuf, "iretd");
3202 BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88));
3203 cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa)
3204 - (uintptr_t)uBuf.abExtraStack;
3205 if (cbUnused < 2048)
3206 Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 2);
3207
3208 /*
3209 * Third variation: 16-bit in 64-bit mode (truly unlikely)
3210 */
3211 if (BS3_MODE_IS_64BIT_CODE(bMode))
3212 {
3213 Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf));
3214 Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard));
3215 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 2, &uBuf.IRetBuf, "o16 iret");
3216 BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88));
3217 cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa)
3218 - (uintptr_t)uBuf.abExtraStack;
3219 if (cbUnused < 2048)
3220 Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 3);
3221 }
3222
3223 return 0;
3224}
3225
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