VirtualBox

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

Last change on this file since 97695 was 97695, checked in by vboxsync, 2 years ago

ValKit/bs3-cpu-basic-2: Simple instruction length test. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 363.9 KB
Line 
1/* $Id: bs3-cpu-basic-2-x0.c 97695 2022-11-29 00:58:11Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-basic-2, C test driver code (16-bit).
4 */
5
6/*
7 * Copyright (C) 2007-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define BS3_USE_X0_TEXT_SEG
42#include <bs3kit.h>
43#include <iprt/asm.h>
44#include <iprt/asm-amd64-x86.h>
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#undef CHECK_MEMBER
51#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \
52 do \
53 { \
54 if ((a_Actual) == (a_Expected)) { /* likely */ } \
55 else bs3CpuBasic2_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \
56 } while (0)
57
58
59/** Indicating that we've got operand size prefix and that it matters. */
60#define BS3CB2SIDTSGDT_F_OPSIZE UINT8_C(0x01)
61/** Worker requires 386 or later. */
62#define BS3CB2SIDTSGDT_F_386PLUS UINT8_C(0x02)
63
64
65/** @name MYOP_XXX - Values for FNBS3CPUBASIC2ACTSTCODE::fOp.
66 *
67 * These are flags, though we've precombined a few shortening things down.
68 *
69 * @{ */
70#define MYOP_LD 0x1 /**< The instruction loads. */
71#define MYOP_ST 0x2 /**< The instruction stores */
72#define MYOP_EFL 0x4 /**< The instruction modifies EFLAGS. */
73#define MYOP_AC_GP 0x8 /**< The instruction may cause either \#AC or \#GP (FXSAVE). */
74
75#define MYOP_LD_ST 0x3 /**< Convenience: The instruction both loads and stores. */
76#define MYOP_LD_DIV 0x5 /**< Convenience: DIV instruction - loading and modifying flags. */
77/** @} */
78
79
80/*********************************************************************************************************************************
81* Structures and Typedefs *
82*********************************************************************************************************************************/
83/** Near void pointer. */
84typedef void BS3_NEAR *NPVOID;
85
86typedef struct BS3CB2INVLDESCTYPE
87{
88 uint8_t u4Type;
89 uint8_t u1DescType;
90} BS3CB2INVLDESCTYPE;
91
92typedef struct BS3CB2SIDTSGDT
93{
94 const char *pszDesc;
95 FPFNBS3FAR fpfnWorker;
96 uint8_t cbInstr;
97 bool fSs;
98 uint8_t bMode;
99 uint8_t fFlags;
100} BS3CB2SIDTSGDT;
101
102
103typedef void BS3_CALL FNBS3CPUBASIC2ACSNIPPET(void);
104
105typedef struct FNBS3CPUBASIC2ACTSTCODE
106{
107 FNBS3CPUBASIC2ACSNIPPET BS3_FAR *pfn;
108 uint8_t fOp;
109 uint16_t cbMem;
110 uint8_t cbAlign;
111 uint8_t offFaultInstr; /**< For skipping fninit with the fld test. */
112} FNBS3CPUBASIC2ACTSTCODE;
113typedef FNBS3CPUBASIC2ACTSTCODE const *PCFNBS3CPUBASIC2ACTSTCODE;
114
115typedef struct BS3CPUBASIC2ACTTSTCMNMODE
116{
117 uint8_t bMode;
118 uint16_t cEntries;
119 PCFNBS3CPUBASIC2ACTSTCODE paEntries;
120} BS3CPUBASIC2PFTTSTCMNMODE;
121typedef BS3CPUBASIC2PFTTSTCMNMODE const *PCBS3CPUBASIC2PFTTSTCMNMODE;
122
123
124/*********************************************************************************************************************************
125* External Symbols *
126*********************************************************************************************************************************/
127extern FNBS3FAR bs3CpuBasic2_Int80;
128extern FNBS3FAR bs3CpuBasic2_Int81;
129extern FNBS3FAR bs3CpuBasic2_Int82;
130extern FNBS3FAR bs3CpuBasic2_Int83;
131
132extern FNBS3FAR bs3CpuBasic2_ud2;
133#define g_bs3CpuBasic2_ud2_FlatAddr BS3_DATA_NM(g_bs3CpuBasic2_ud2_FlatAddr)
134extern uint32_t g_bs3CpuBasic2_ud2_FlatAddr;
135
136extern FNBS3FAR bs3CpuBasic2_salc_ud2;
137extern FNBS3FAR bs3CpuBasic2_swapgs;
138
139extern FNBS3FAR bs3CpuBasic2_iret;
140extern FNBS3FAR bs3CpuBasic2_iret_opsize;
141extern FNBS3FAR bs3CpuBasic2_iret_rexw;
142
143extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c16;
144extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c32;
145extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c64;
146extern FNBS3FAR bs3CpuBasic2_sidt_ss_bx_ud2_c16;
147extern FNBS3FAR bs3CpuBasic2_sidt_ss_bx_ud2_c32;
148extern FNBS3FAR bs3CpuBasic2_sidt_rexw_bx_ud2_c64;
149extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c16;
150extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c32;
151extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c64;
152extern FNBS3FAR bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c16;
153extern FNBS3FAR bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c32;
154extern FNBS3FAR bs3CpuBasic2_sidt_opsize_rexw_bx_ud2_c64;
155
156extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c16;
157extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c32;
158extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c64;
159extern FNBS3FAR bs3CpuBasic2_sgdt_ss_bx_ud2_c16;
160extern FNBS3FAR bs3CpuBasic2_sgdt_ss_bx_ud2_c32;
161extern FNBS3FAR bs3CpuBasic2_sgdt_rexw_bx_ud2_c64;
162extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c16;
163extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c32;
164extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c64;
165extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c16;
166extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c32;
167extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2_c64;
168
169extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c16;
170extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c32;
171extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c64;
172extern FNBS3FAR bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c16;
173extern FNBS3FAR bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c32;
174extern FNBS3FAR bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64;
175extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c16;
176extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2_c16;
177extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c32;
178extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c64;
179extern FNBS3FAR bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c16;
180extern FNBS3FAR bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c32;
181extern FNBS3FAR bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64;
182
183extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
184extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
185extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
186extern FNBS3FAR bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
187extern FNBS3FAR bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
188extern FNBS3FAR bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
189extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
190extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
191extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
192extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16;
193extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32;
194extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64;
195
196
197/* bs3-cpu-basic-2-template.mac: */
198FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c16;
199FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c16;
200FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16;
201FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16;
202FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c16;
203FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fld_ds_bx__ud2_c16;
204FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fbld_ds_bx__ud2_c16;
205FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fldz_fstp_ds_bx__ud2_c16;
206FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fxsave_ds_bx__ud2_c16;
207
208FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c32;
209FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c32;
210FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32;
211FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32;
212FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c32;
213FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fld_ds_bx__ud2_c32;
214FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fbld_ds_bx__ud2_c32;
215FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fldz_fstp_ds_bx__ud2_c32;
216FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fxsave_ds_bx__ud2_c32;
217
218FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c64;
219FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c64;
220FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64;
221FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64;
222FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c64;
223FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fld_ds_bx__ud2_c64;
224FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fbld_ds_bx__ud2_c64;
225FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fninit_fldz_fstp_ds_bx__ud2_c64;
226FNBS3CPUBASIC2ACSNIPPET bs3CpuBasic2_fxsave_ds_bx__ud2_c64;
227
228
229/*********************************************************************************************************************************
230* Global Variables *
231*********************************************************************************************************************************/
232static const char BS3_FAR *g_pszTestMode = (const char *)1;
233static uint8_t g_bTestMode = 1;
234static bool g_f16BitSys = 1;
235
236
237/** SIDT test workers. */
238static BS3CB2SIDTSGDT const g_aSidtWorkers[] =
239{
240 { "sidt [bx]", bs3CpuBasic2_sidt_bx_ud2_c16, 3, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
241 { "sidt [ss:bx]", bs3CpuBasic2_sidt_ss_bx_ud2_c16, 4, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
242 { "o32 sidt [bx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c16, 4, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
243 { "o32 sidt [ss:bx]", bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c16, 5, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
244 { "sidt [ebx]", bs3CpuBasic2_sidt_bx_ud2_c32, 3, false, BS3_MODE_CODE_32, 0 },
245 { "sidt [ss:ebx]", bs3CpuBasic2_sidt_ss_bx_ud2_c32, 4, true, BS3_MODE_CODE_32, 0 },
246 { "o16 sidt [ebx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c32, 4, false, BS3_MODE_CODE_32, 0 },
247 { "o16 sidt [ss:ebx]", bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c32, 5, true, BS3_MODE_CODE_32, 0 },
248 { "sidt [rbx]", bs3CpuBasic2_sidt_bx_ud2_c64, 3, false, BS3_MODE_CODE_64, 0 },
249 { "o64 sidt [rbx]", bs3CpuBasic2_sidt_rexw_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
250 { "o32 sidt [rbx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
251 { "o32 o64 sidt [rbx]", bs3CpuBasic2_sidt_opsize_rexw_bx_ud2_c64, 5, false, BS3_MODE_CODE_64, 0 },
252};
253
254/** SGDT test workers. */
255static BS3CB2SIDTSGDT const g_aSgdtWorkers[] =
256{
257 { "sgdt [bx]", bs3CpuBasic2_sgdt_bx_ud2_c16, 3, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
258 { "sgdt [ss:bx]", bs3CpuBasic2_sgdt_ss_bx_ud2_c16, 4, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
259 { "o32 sgdt [bx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c16, 4, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
260 { "o32 sgdt [ss:bx]", bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c16, 5, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS },
261 { "sgdt [ebx]", bs3CpuBasic2_sgdt_bx_ud2_c32, 3, false, BS3_MODE_CODE_32, 0 },
262 { "sgdt [ss:ebx]", bs3CpuBasic2_sgdt_ss_bx_ud2_c32, 4, true, BS3_MODE_CODE_32, 0 },
263 { "o16 sgdt [ebx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c32, 4, false, BS3_MODE_CODE_32, 0 },
264 { "o16 sgdt [ss:ebx]", bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c32, 5, true, BS3_MODE_CODE_32, 0 },
265 { "sgdt [rbx]", bs3CpuBasic2_sgdt_bx_ud2_c64, 3, false, BS3_MODE_CODE_64, 0 },
266 { "o64 sgdt [rbx]", bs3CpuBasic2_sgdt_rexw_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
267 { "o32 sgdt [rbx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 },
268 { "o32 o64 sgdt [rbx]", bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2_c64, 5, false, BS3_MODE_CODE_64, 0 },
269};
270
271/** LIDT test workers. */
272static BS3CB2SIDTSGDT const g_aLidtWorkers[] =
273{
274 { "lidt [bx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c16, 11, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
275 { "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 },
276 { "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 },
277 { "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 },
278 { "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 },
279 { "lidt [ebx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c32, 11, false, BS3_MODE_CODE_32, 0 },
280 { "lidt [ss:ebx]", bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c32, 12, true, BS3_MODE_CODE_32, 0 },
281 { "o16 lidt [ebx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c32, 12, false, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE },
282 { "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 },
283 { "lidt [rbx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c64, 9, false, BS3_MODE_CODE_64, 0 },
284 { "o64 lidt [rbx]", bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
285 { "o32 lidt [rbx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
286 { "o32 o64 lidt [rbx]", bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64, 11, false, BS3_MODE_CODE_64, 0 },
287};
288
289/** LGDT test workers. */
290static BS3CB2SIDTSGDT const g_aLgdtWorkers[] =
291{
292 { "lgdt [bx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 11, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 },
293 { "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 },
294 { "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 },
295 { "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 },
296 { "lgdt [ebx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 11, false, BS3_MODE_CODE_32, 0 },
297 { "lgdt [ss:ebx]", bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 12, true, BS3_MODE_CODE_32, 0 },
298 { "o16 lgdt [ebx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 12, false, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE },
299 { "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 },
300 { "lgdt [rbx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 9, false, BS3_MODE_CODE_64, 0 },
301 { "o64 lgdt [rbx]", bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
302 { "o32 lgdt [rbx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 },
303 { "o32 o64 lgdt [rbx]", bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 11, false, BS3_MODE_CODE_64, 0 },
304};
305
306
307
308#if 0
309/** Table containing invalid CS selector types. */
310static const BS3CB2INVLDESCTYPE g_aInvalidCsTypes[] =
311{
312 { X86_SEL_TYPE_RO, 1 },
313 { X86_SEL_TYPE_RO_ACC, 1 },
314 { X86_SEL_TYPE_RW, 1 },
315 { X86_SEL_TYPE_RW_ACC, 1 },
316 { X86_SEL_TYPE_RO_DOWN, 1 },
317 { X86_SEL_TYPE_RO_DOWN_ACC, 1 },
318 { X86_SEL_TYPE_RW_DOWN, 1 },
319 { X86_SEL_TYPE_RW_DOWN_ACC, 1 },
320 { 0, 0 },
321 { 1, 0 },
322 { 2, 0 },
323 { 3, 0 },
324 { 4, 0 },
325 { 5, 0 },
326 { 6, 0 },
327 { 7, 0 },
328 { 8, 0 },
329 { 9, 0 },
330 { 10, 0 },
331 { 11, 0 },
332 { 12, 0 },
333 { 13, 0 },
334 { 14, 0 },
335 { 15, 0 },
336};
337
338/** Table containing invalid SS selector types. */
339static const BS3CB2INVLDESCTYPE g_aInvalidSsTypes[] =
340{
341 { X86_SEL_TYPE_EO, 1 },
342 { X86_SEL_TYPE_EO_ACC, 1 },
343 { X86_SEL_TYPE_ER, 1 },
344 { X86_SEL_TYPE_ER_ACC, 1 },
345 { X86_SEL_TYPE_EO_CONF, 1 },
346 { X86_SEL_TYPE_EO_CONF_ACC, 1 },
347 { X86_SEL_TYPE_ER_CONF, 1 },
348 { X86_SEL_TYPE_ER_CONF_ACC, 1 },
349 { 0, 0 },
350 { 1, 0 },
351 { 2, 0 },
352 { 3, 0 },
353 { 4, 0 },
354 { 5, 0 },
355 { 6, 0 },
356 { 7, 0 },
357 { 8, 0 },
358 { 9, 0 },
359 { 10, 0 },
360 { 11, 0 },
361 { 12, 0 },
362 { 13, 0 },
363 { 14, 0 },
364 { 15, 0 },
365};
366#endif
367
368
369static const FNBS3CPUBASIC2ACTSTCODE g_aCmn16[] =
370{
371 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, MYOP_LD, 2, 2 },
372 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, MYOP_ST, 2, 2 },
373 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, MYOP_LD_ST, 2, 2 },
374 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, MYOP_LD_ST | MYOP_EFL, 2, 2 },
375 { bs3CpuBasic2_div_ds_bx__ud2_c16, MYOP_LD_DIV, 2, 2 },
376 { bs3CpuBasic2_fninit_fld_ds_bx__ud2_c16, MYOP_LD, 10, 8, 2 /*fninit*/ },
377 { bs3CpuBasic2_fninit_fbld_ds_bx__ud2_c16, MYOP_LD, 10, 8, 2 /*fninit*/ },
378 { bs3CpuBasic2_fninit_fldz_fstp_ds_bx__ud2_c16, MYOP_ST, 10, 8, 4 /*fninit+fldz*/ },
379 { bs3CpuBasic2_fxsave_ds_bx__ud2_c16, MYOP_ST | MYOP_AC_GP, 512, 16 },
380};
381
382static const FNBS3CPUBASIC2ACTSTCODE g_aCmn32[] =
383{
384 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c32, MYOP_LD, 4, 4 },
385 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c32, MYOP_ST, 4, 4 },
386 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32, MYOP_LD_ST, 4, 4 },
387 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32, MYOP_LD_ST | MYOP_EFL, 4, 4 },
388 { bs3CpuBasic2_div_ds_bx__ud2_c32, MYOP_LD_DIV, 4, 4 },
389 { bs3CpuBasic2_fninit_fld_ds_bx__ud2_c32, MYOP_LD, 10, 8, 2 /*fninit*/ },
390 { bs3CpuBasic2_fninit_fbld_ds_bx__ud2_c32, MYOP_LD, 10, 8, 2 /*fninit*/ },
391 { bs3CpuBasic2_fninit_fldz_fstp_ds_bx__ud2_c32, MYOP_ST, 10, 8, 4 /*fninit+fldz*/ },
392 { bs3CpuBasic2_fxsave_ds_bx__ud2_c32, MYOP_ST | MYOP_AC_GP, 512, 16 },
393};
394
395static const FNBS3CPUBASIC2ACTSTCODE g_aCmn64[] =
396{
397 { bs3CpuBasic2_mov_ax_ds_bx__ud2_c64, MYOP_LD, 8, 8 },
398 { bs3CpuBasic2_mov_ds_bx_ax__ud2_c64, MYOP_ST, 8, 8 },
399 { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64, MYOP_LD_ST, 8, 8 },
400 { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64, MYOP_LD_ST | MYOP_EFL, 8, 8 },
401 { bs3CpuBasic2_div_ds_bx__ud2_c64, MYOP_LD_DIV, 8, 8 },
402 { bs3CpuBasic2_fninit_fld_ds_bx__ud2_c64, MYOP_LD, 10, 8, 2 /*fninit*/ },
403 { bs3CpuBasic2_fninit_fbld_ds_bx__ud2_c64, MYOP_LD, 10, 8, 2 /*fninit*/ },
404 { bs3CpuBasic2_fninit_fldz_fstp_ds_bx__ud2_c64, MYOP_ST, 10, 8, 4 /*fninit+fldz*/ },
405 { bs3CpuBasic2_fxsave_ds_bx__ud2_c64, MYOP_ST | MYOP_AC_GP, 512, 16 },
406};
407
408static const BS3CPUBASIC2PFTTSTCMNMODE g_aCmnModes[] =
409{
410 { BS3_MODE_CODE_16, RT_ELEMENTS(g_aCmn16), g_aCmn16 },
411 { BS3_MODE_CODE_V86, RT_ELEMENTS(g_aCmn16), g_aCmn16 },
412 { BS3_MODE_CODE_32, RT_ELEMENTS(g_aCmn32), g_aCmn32 },
413 { BS3_MODE_CODE_64, RT_ELEMENTS(g_aCmn64), g_aCmn64 },
414};
415
416
417/**
418 * Sets globals according to the mode.
419 *
420 * @param bTestMode The test mode.
421 */
422static void bs3CpuBasic2_SetGlobals(uint8_t bTestMode)
423{
424 g_bTestMode = bTestMode;
425 g_pszTestMode = Bs3GetModeName(bTestMode);
426 g_f16BitSys = BS3_MODE_IS_16BIT_SYS(bTestMode);
427 g_usBs3TestStep = 0;
428}
429
430
431uint32_t ASMGetESP(void);
432#pragma aux ASMGetESP = \
433 ".386" \
434 "mov ax, sp" \
435 "mov edx, esp" \
436 "shr edx, 16" \
437 value [ax dx] \
438 modify exact [ax dx];
439
440
441/**
442 * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep
443 * and g_pszTestMode.
444 */
445static void bs3CpuBasic2_FailedF(const char *pszFormat, ...)
446{
447 va_list va;
448
449 char szTmp[168];
450 va_start(va, pszFormat);
451 Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va);
452 va_end(va);
453
454 Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp);
455}
456
457
458#if 0
459/**
460 * Compares trap stuff.
461 */
462static void bs3CpuBasic2_CompareIntCtx1(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt)
463{
464 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
465 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
466 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
467 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 2 /*int xx*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
468 if (Bs3TestSubErrorCount() != cErrorsBefore)
469 {
470 Bs3TrapPrintFrame(pTrapCtx);
471#if 1
472 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
473 Bs3TestPrintf("Halting in CompareTrapCtx1: bXcpt=%#x\n", bXcpt);
474 ASMHalt();
475#endif
476 }
477}
478#endif
479
480
481#if 0
482/**
483 * Compares trap stuff.
484 */
485static void bs3CpuBasic2_CompareTrapCtx2(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t cbIpAdjust,
486 uint8_t bXcpt, uint16_t uHandlerCs)
487{
488 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
489 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
490 CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0);
491 CHECK_MEMBER("uHandlerCs", "%#06x", pTrapCtx->uHandlerCs, uHandlerCs);
492 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep);
493 if (Bs3TestSubErrorCount() != cErrorsBefore)
494 {
495 Bs3TrapPrintFrame(pTrapCtx);
496#if 1
497 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
498 Bs3TestPrintf("Halting in CompareTrapCtx2: bXcpt=%#x\n", bXcpt);
499 ASMHalt();
500#endif
501 }
502}
503#endif
504
505/**
506 * Compares a CPU trap.
507 */
508static void bs3CpuBasic2_CompareCpuTrapCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd,
509 uint8_t bXcpt, bool f486ResumeFlagHint, uint8_t cbIpAdjust)
510{
511 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
512 uint32_t fExtraEfl;
513
514 CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt);
515 CHECK_MEMBER("bErrCd", "%#06RX16", (uint16_t)pTrapCtx->uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */
516
517 if ( g_f16BitSys
518 || bXcpt == X86_XCPT_DB /* hack (10980xe)... */
519 || ( !f486ResumeFlagHint
520 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80486 ) )
521 fExtraEfl = 0;
522 else
523 fExtraEfl = X86_EFL_RF;
524#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. */
525 fExtraEfl = pTrapCtx->Ctx.rflags.u32 & X86_EFL_RF;
526#endif
527 Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, fExtraEfl, g_pszTestMode, g_usBs3TestStep);
528 if (Bs3TestSubErrorCount() != cErrorsBefore)
529 {
530 Bs3TrapPrintFrame(pTrapCtx);
531#if 1
532 Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected);
533 Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd);
534 ASMHalt();
535#endif
536 }
537}
538
539
540/**
541 * Compares \#GP trap.
542 */
543static void bs3CpuBasic2_CompareGpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
544{
545 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_GP, true /*f486ResumeFlagHint*/, 0 /*cbIpAdjust*/);
546}
547
548#if 0
549/**
550 * Compares \#NP trap.
551 */
552static void bs3CpuBasic2_CompareNpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
553{
554 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_NP, true /*f486ResumeFlagHint*/, 0 /*cbIpAdjust*/);
555}
556#endif
557
558/**
559 * Compares \#SS trap.
560 */
561static void bs3CpuBasic2_CompareSsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, bool f486ResumeFlagHint)
562{
563 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_SS, f486ResumeFlagHint, 0 /*cbIpAdjust*/);
564}
565
566#if 0
567/**
568 * Compares \#TS trap.
569 */
570static void bs3CpuBasic2_CompareTsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd)
571{
572 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_TS, false /*f486ResumeFlagHint*/, 0 /*cbIpAdjust*/);
573}
574#endif
575
576/**
577 * Compares \#PF trap.
578 */
579static void bs3CpuBasic2_ComparePfCtx(PCBS3TRAPFRAME pTrapCtx, PBS3REGCTX pStartCtx, uint16_t uErrCd,
580 uint64_t uCr2Expected, uint8_t cbIpAdjust)
581{
582 uint64_t const uCr2Saved = pStartCtx->cr2.u;
583 pStartCtx->cr2.u = uCr2Expected;
584 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_PF, true /*f486ResumeFlagHint*/, cbIpAdjust);
585 pStartCtx->cr2.u = uCr2Saved;
586}
587
588/**
589 * Compares \#UD trap.
590 */
591static void bs3CpuBasic2_CompareUdCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx)
592{
593 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*no error code*/, X86_XCPT_UD,
594 true /*f486ResumeFlagHint*/, 0 /*cbIpAdjust*/);
595}
596
597/**
598 * Compares \#AC trap.
599 */
600static void bs3CpuBasic2_CompareAcCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t cbIpAdjust)
601{
602 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*always zero*/, X86_XCPT_AC, true /*f486ResumeFlagHint*/, cbIpAdjust);
603}
604
605/**
606 * Compares \#DB trap.
607 */
608static void bs3CpuBasic2_CompareDbCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint32_t fDr6Expect)
609{
610 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
611 uint32_t const fDr6 = Bs3RegGetDr6();
612 fDr6Expect |= X86_DR6_RA1_MASK;
613 CHECK_MEMBER("dr6", "%#08RX32", fDr6, fDr6Expect);
614
615 bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*always zero*/, X86_XCPT_DB, false /*f486ResumeFlagHint?*/, 0 /*cbIpAdjust*/);
616
617 if (Bs3TestSubErrorCount() > cErrorsBefore)
618 {
619#if 0
620 Bs3TestPrintf("Halting\n");
621 ASMHalt();
622#endif
623 }
624}
625
626
627/**
628 * Checks that DR6 has the initial value, i.e. is unchanged when other exception
629 * was raised before a \#DB could occur.
630 */
631static void bs3CpuBasic2_CheckDr6InitVal(void)
632{
633 uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
634 uint32_t const fDr6 = Bs3RegGetDr6();
635 uint32_t const fDr6Expect = X86_DR6_INIT_VAL;
636 CHECK_MEMBER("dr6", "%#08RX32", fDr6, fDr6Expect);
637 if (Bs3TestSubErrorCount() > cErrorsBefore)
638 {
639 Bs3TestPrintf("Halting\n");
640 ASMHalt();
641 }
642}
643
644#if 0 /* convert me */
645static void bs3CpuBasic2_RaiseXcpt1Common(uint16_t const uSysR0Cs, uint16_t const uSysR0CsConf, uint16_t const uSysR0Ss,
646 PX86DESC const paIdt, unsigned const cIdteShift)
647{
648 BS3TRAPFRAME TrapCtx;
649 BS3REGCTX Ctx80;
650 BS3REGCTX Ctx81;
651 BS3REGCTX Ctx82;
652 BS3REGCTX Ctx83;
653 BS3REGCTX CtxTmp;
654 BS3REGCTX CtxTmp2;
655 PBS3REGCTX apCtx8x[4];
656 unsigned iCtx;
657 unsigned iRing;
658 unsigned iDpl;
659 unsigned iRpl;
660 unsigned i, j, k;
661 uint32_t uExpected;
662 bool const f486Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486;
663# if TMPL_BITS == 16
664 bool const f386Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386;
665 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
666# else
667 bool const f286 = false;
668 bool const f386Plus = true;
669 int rc;
670 uint8_t *pbIdtCopyAlloc;
671 PX86DESC pIdtCopy;
672 const unsigned cbIdte = 1 << (3 + cIdteShift);
673 RTCCUINTXREG uCr0Saved = ASMGetCR0();
674 RTGDTR GdtrSaved;
675# endif
676 RTIDTR IdtrSaved;
677 RTIDTR Idtr;
678
679 ASMGetIDTR(&IdtrSaved);
680# if TMPL_BITS != 16
681 ASMGetGDTR(&GdtrSaved);
682# endif
683
684 /* make sure they're allocated */
685 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
686 Bs3MemZero(&Ctx80, sizeof(Ctx80));
687 Bs3MemZero(&Ctx81, sizeof(Ctx81));
688 Bs3MemZero(&Ctx82, sizeof(Ctx82));
689 Bs3MemZero(&Ctx83, sizeof(Ctx83));
690 Bs3MemZero(&CtxTmp, sizeof(CtxTmp));
691 Bs3MemZero(&CtxTmp2, sizeof(CtxTmp2));
692
693 /* Context array. */
694 apCtx8x[0] = &Ctx80;
695 apCtx8x[1] = &Ctx81;
696 apCtx8x[2] = &Ctx82;
697 apCtx8x[3] = &Ctx83;
698
699# if TMPL_BITS != 16
700 /* Allocate memory for playing around with the IDT. */
701 pbIdtCopyAlloc = NULL;
702 if (BS3_MODE_IS_PAGED(g_bTestMode))
703 pbIdtCopyAlloc = Bs3MemAlloc(BS3MEMKIND_FLAT32, 12*_1K);
704# endif
705
706 /*
707 * IDT entry 80 thru 83 are assigned DPLs according to the number.
708 * (We'll be useing more, but this'll do for now.)
709 */
710 paIdt[0x80 << cIdteShift].Gate.u2Dpl = 0;
711 paIdt[0x81 << cIdteShift].Gate.u2Dpl = 1;
712 paIdt[0x82 << cIdteShift].Gate.u2Dpl = 2;
713 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
714
715 Bs3RegCtxSave(&Ctx80);
716 Ctx80.rsp.u -= 0x300;
717 Ctx80.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int80);
718# if TMPL_BITS == 16
719 Ctx80.cs = BS3_MODE_IS_RM_OR_V86(g_bTestMode) ? BS3_SEL_TEXT16 : BS3_SEL_R0_CS16;
720# elif TMPL_BITS == 32
721 g_uBs3TrapEipHint = Ctx80.rip.u32;
722# endif
723 Bs3MemCpy(&Ctx81, &Ctx80, sizeof(Ctx80));
724 Ctx81.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int81);
725 Bs3MemCpy(&Ctx82, &Ctx80, sizeof(Ctx80));
726 Ctx82.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int82);
727 Bs3MemCpy(&Ctx83, &Ctx80, sizeof(Ctx80));
728 Ctx83.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int83);
729
730 /*
731 * Check that all the above gates work from ring-0.
732 */
733 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
734 {
735 g_usBs3TestStep = iCtx;
736# if TMPL_BITS == 32
737 g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32;
738# endif
739 Bs3TrapSetJmpAndRestore(apCtx8x[iCtx], &TrapCtx);
740 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, apCtx8x[iCtx], 0x80+iCtx /*bXcpt*/);
741 }
742
743 /*
744 * Check that the gate DPL checks works.
745 */
746 g_usBs3TestStep = 100;
747 for (iRing = 0; iRing <= 3; iRing++)
748 {
749 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
750 {
751 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
752 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
753# if TMPL_BITS == 32
754 g_uBs3TrapEipHint = CtxTmp.rip.u32;
755# endif
756 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
757 if (iCtx < iRing)
758 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
759 else
760 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
761 g_usBs3TestStep++;
762 }
763 }
764
765 /*
766 * Modify the gate CS value and run the handler at a different CPL.
767 * Throw RPL variations into the mix (completely ignored) together
768 * with gate presence.
769 * 1. CPL <= GATE.DPL
770 * 2. GATE.P
771 * 3. GATE.CS.DPL <= CPL (non-conforming segments)
772 */
773 g_usBs3TestStep = 1000;
774 for (i = 0; i <= 3; i++)
775 {
776 for (iRing = 0; iRing <= 3; iRing++)
777 {
778 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
779 {
780# if TMPL_BITS == 32
781 g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32;
782# endif
783 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
784 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
785
786 for (j = 0; j <= 3; j++)
787 {
788 uint16_t const uCs = (uSysR0Cs | j) + (i << BS3_SEL_RING_SHIFT);
789 for (k = 0; k < 2; k++)
790 {
791 g_usBs3TestStep++;
792 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
793 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
794 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = k;
795 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
796 /*Bs3TrapPrintFrame(&TrapCtx);*/
797 if (iCtx < iRing)
798 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
799 else if (k == 0)
800 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
801 else if (i > iRing)
802 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
803 else
804 {
805 uint16_t uExpectedCs = uCs & X86_SEL_MASK_OFF_RPL;
806 if (i <= iCtx && i <= iRing)
807 uExpectedCs |= i;
808 bs3CpuBasic2_CompareTrapCtx2(&TrapCtx, &CtxTmp, 2 /*int 8xh*/, 0x80 + iCtx /*bXcpt*/, uExpectedCs);
809 }
810 }
811 }
812
813 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
814 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
815 }
816 }
817 }
818 BS3_ASSERT(g_usBs3TestStep < 1600);
819
820 /*
821 * Various CS and SS related faults
822 *
823 * We temporarily reconfigure gate 80 and 83 with new CS selectors, the
824 * latter have a CS.DPL of 2 for testing ring transisions and SS loading
825 * without making it impossible to handle faults.
826 */
827 g_usBs3TestStep = 1600;
828 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
829 Bs3GdteTestPage00.Gen.u1Present = 0;
830 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
831 paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00;
832
833 /* CS.PRESENT = 0 */
834 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
835 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
836 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
837 bs3CpuBasic2_FailedF("selector was accessed");
838 g_usBs3TestStep++;
839
840 /* Check that GATE.DPL is checked before CS.PRESENT. */
841 for (iRing = 1; iRing < 4; iRing++)
842 {
843 Bs3MemCpy(&CtxTmp, &Ctx80, sizeof(CtxTmp));
844 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
845 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
846 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x80 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
847 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
848 bs3CpuBasic2_FailedF("selector was accessed");
849 g_usBs3TestStep++;
850 }
851
852 /* CS.DPL mismatch takes precedence over CS.PRESENT = 0. */
853 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
854 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
855 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
856 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
857 bs3CpuBasic2_FailedF("CS selector was accessed");
858 g_usBs3TestStep++;
859 for (iDpl = 1; iDpl < 4; iDpl++)
860 {
861 Bs3GdteTestPage00.Gen.u2Dpl = iDpl;
862 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
863 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
864 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
865 bs3CpuBasic2_FailedF("CS selector was accessed");
866 g_usBs3TestStep++;
867 }
868
869 /* 1608: Check all the invalid CS selector types alone. */
870 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
871 for (i = 0; i < RT_ELEMENTS(g_aInvalidCsTypes); i++)
872 {
873 Bs3GdteTestPage00.Gen.u4Type = g_aInvalidCsTypes[i].u4Type;
874 Bs3GdteTestPage00.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType;
875 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
876 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
877 if (Bs3GdteTestPage00.Gen.u4Type != g_aInvalidCsTypes[i].u4Type)
878 bs3CpuBasic2_FailedF("Invalid CS type %#x/%u -> %#x/%u\n",
879 g_aInvalidCsTypes[i].u4Type, g_aInvalidCsTypes[i].u1DescType,
880 Bs3GdteTestPage00.Gen.u4Type, Bs3GdteTestPage00.Gen.u1DescType);
881 g_usBs3TestStep++;
882
883 /* Incorrect CS.TYPE takes precedence over CS.PRESENT = 0. */
884 Bs3GdteTestPage00.Gen.u1Present = 0;
885 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
886 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00);
887 Bs3GdteTestPage00.Gen.u1Present = 1;
888 g_usBs3TestStep++;
889 }
890
891 /* Fix CS again. */
892 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
893
894 /* 1632: Test SS. */
895 if (!BS3_MODE_IS_64BIT_SYS(g_bTestMode))
896 {
897 uint16_t BS3_FAR *puTssSs2 = BS3_MODE_IS_16BIT_SYS(g_bTestMode) ? &Bs3Tss16.ss2 : &Bs3Tss32.ss2;
898 uint16_t const uSavedSs2 = *puTssSs2;
899 X86DESC const SavedGate83 = paIdt[0x83 << cIdteShift];
900
901 /* Make the handler execute in ring-2. */
902 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
903 Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
904 paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_02 | 2;
905
906 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
907 Bs3RegCtxConvertToRingX(&CtxTmp, 3); /* yeah, from 3 so SS:xSP is reloaded. */
908 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
909 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
910 if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
911 bs3CpuBasic2_FailedF("CS selector was not access");
912 g_usBs3TestStep++;
913
914 /* Create a SS.DPL=2 stack segment and check that SS2.RPL matters and
915 that we get #SS if the selector isn't present. */
916 i = 0; /* used for cycling thru invalid CS types */
917 for (k = 0; k < 10; k++)
918 {
919 /* k=0: present,
920 k=1: not-present,
921 k=2: present but very low limit,
922 k=3: not-present, low limit.
923 k=4: present, read-only.
924 k=5: not-present, read-only.
925 k=6: present, code-selector.
926 k=7: not-present, code-selector.
927 k=8: present, read-write / no access + system (=LDT).
928 k=9: not-present, read-write / no access + system (=LDT).
929 */
930 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
931 Bs3GdteTestPage03.Gen.u1Present = !(k & 1);
932 if (k >= 8)
933 {
934 Bs3GdteTestPage03.Gen.u1DescType = 0; /* system */
935 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW; /* = LDT */
936 }
937 else if (k >= 6)
938 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_ER;
939 else if (k >= 4)
940 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RO;
941 else if (k >= 2)
942 {
943 Bs3GdteTestPage03.Gen.u16LimitLow = 0x400;
944 Bs3GdteTestPage03.Gen.u4LimitHigh = 0;
945 Bs3GdteTestPage03.Gen.u1Granularity = 0;
946 }
947
948 for (iDpl = 0; iDpl < 4; iDpl++)
949 {
950 Bs3GdteTestPage03.Gen.u2Dpl = iDpl;
951
952 for (iRpl = 0; iRpl < 4; iRpl++)
953 {
954 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | iRpl;
955 //Bs3TestPrintf("k=%u iDpl=%u iRpl=%u step=%u\n", k, iDpl, iRpl, g_usBs3TestStep);
956 Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
957 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
958 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
959 if (iRpl != 2 || iRpl != iDpl || k >= 4)
960 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
961 else if (k != 0)
962 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03,
963 k == 2 /*f486ResumeFlagHint*/);
964 else
965 {
966 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
967 if (TrapCtx.uHandlerSs != (BS3_SEL_TEST_PAGE_03 | 2))
968 bs3CpuBasic2_FailedF("uHandlerSs=%#x expected %#x\n", TrapCtx.uHandlerSs, BS3_SEL_TEST_PAGE_03 | 2);
969 }
970 if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
971 bs3CpuBasic2_FailedF("CS selector was not access");
972 if ( TrapCtx.bXcpt == 0x83
973 || (TrapCtx.bXcpt == X86_XCPT_SS && k == 2) )
974 {
975 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
976 bs3CpuBasic2_FailedF("SS selector was not accessed");
977 }
978 else if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
979 bs3CpuBasic2_FailedF("SS selector was accessed");
980 g_usBs3TestStep++;
981
982 /* +1: Modify the gate DPL to check that this is checked before SS.DPL and SS.PRESENT. */
983 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 2;
984 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
985 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x83 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
986 paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3;
987 g_usBs3TestStep++;
988
989 /* +2: Check the CS.DPL check is done before the SS ones. Restoring the
990 ring-0 INT 83 context triggers the CS.DPL < CPL check. */
991 Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx);
992 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02);
993 g_usBs3TestStep++;
994
995 /* +3: Now mark the CS selector not present and check that that also triggers before SS stuff. */
996 Bs3GdteTestPage02.Gen.u1Present = 0;
997 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
998 bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02);
999 Bs3GdteTestPage02.Gen.u1Present = 1;
1000 g_usBs3TestStep++;
1001
1002 /* +4: Make the CS selector some invalid type and check it triggers before SS stuff. */
1003 Bs3GdteTestPage02.Gen.u4Type = g_aInvalidCsTypes[i].u4Type;
1004 Bs3GdteTestPage02.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType;
1005 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1006 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02);
1007 Bs3GdteTestPage02.Gen.u4Type = X86_SEL_TYPE_ER_ACC;
1008 Bs3GdteTestPage02.Gen.u1DescType = 1;
1009 g_usBs3TestStep++;
1010
1011 /* +5: Now, make the CS selector limit too small and that it triggers after SS trouble.
1012 The 286 had a simpler approach to these GP(0). */
1013 Bs3GdteTestPage02.Gen.u16LimitLow = 0;
1014 Bs3GdteTestPage02.Gen.u4LimitHigh = 0;
1015 Bs3GdteTestPage02.Gen.u1Granularity = 0;
1016 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1017 if (f286)
1018 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/);
1019 else if (iRpl != 2 || iRpl != iDpl || k >= 4)
1020 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
1021 else if (k != 0)
1022 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, k == 2 /*f486ResumeFlagHint*/);
1023 else
1024 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/);
1025 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1026 g_usBs3TestStep++;
1027 }
1028 }
1029 }
1030
1031 /* Check all the invalid SS selector types alone. */
1032 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1033 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1034 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2;
1035 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1036 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
1037 g_usBs3TestStep++;
1038 for (i = 0; i < RT_ELEMENTS(g_aInvalidSsTypes); i++)
1039 {
1040 Bs3GdteTestPage03.Gen.u4Type = g_aInvalidSsTypes[i].u4Type;
1041 Bs3GdteTestPage03.Gen.u1DescType = g_aInvalidSsTypes[i].u1DescType;
1042 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1043 bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03);
1044 if (Bs3GdteTestPage03.Gen.u4Type != g_aInvalidSsTypes[i].u4Type)
1045 bs3CpuBasic2_FailedF("Invalid SS type %#x/%u -> %#x/%u\n",
1046 g_aInvalidSsTypes[i].u4Type, g_aInvalidSsTypes[i].u1DescType,
1047 Bs3GdteTestPage03.Gen.u4Type, Bs3GdteTestPage03.Gen.u1DescType);
1048 g_usBs3TestStep++;
1049 }
1050
1051 /*
1052 * Continue the SS experiments with a expand down segment. We'll use
1053 * the same setup as we already have with gate 83h being DPL and
1054 * having CS.DPL=2.
1055 *
1056 * Expand down segments are weird. The valid area is practically speaking
1057 * reversed. So, a 16-bit segment with a limit of 0x6000 will have valid
1058 * addresses from 0xffff thru 0x6001.
1059 *
1060 * So, with expand down segments we can more easily cut partially into the
1061 * pushing of the iret frame and trigger more interesting behavior than
1062 * with regular "expand up" segments where the whole pushing area is either
1063 * all fine or not not fine.
1064 */
1065 Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1066 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1067 Bs3GdteTestPage03.Gen.u2Dpl = 2;
1068 Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW_DOWN;
1069 *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2;
1070
1071 /* First test, limit = max --> no bytes accessible --> #GP */
1072 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1073 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/);
1074
1075 /* Second test, limit = 0 --> all by zero byte accessible --> works */
1076 Bs3GdteTestPage03.Gen.u16LimitLow = 0;
1077 Bs3GdteTestPage03.Gen.u4LimitHigh = 0;
1078 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1079 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83);
1080
1081 /* Modify the gate handler to be a dummy that immediately does UD2
1082 and triggers #UD, then advance the limit down till we get the #UD. */
1083 Bs3GdteTestPage03.Gen.u1Granularity = 0;
1084
1085 Bs3MemCpy(&CtxTmp2, &CtxTmp, sizeof(CtxTmp2)); /* #UD result context */
1086 if (g_f16BitSys)
1087 {
1088 CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr - BS3_ADDR_BS3TEXT16;
1089 Bs3Trap16SetGate(0x83, X86_SEL_TYPE_SYS_286_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u16, 0 /*cParams*/);
1090 CtxTmp2.rsp.u = Bs3Tss16.sp2 - 2*5;
1091 }
1092 else
1093 {
1094 CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr;
1095 Bs3Trap32SetGate(0x83, X86_SEL_TYPE_SYS_386_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u32, 0 /*cParams*/);
1096 CtxTmp2.rsp.u = Bs3Tss32.esp2 - 4*5;
1097 }
1098 CtxTmp2.bMode = g_bTestMode; /* g_bBs3CurrentMode not changed by the UD2 handler. */
1099 CtxTmp2.cs = BS3_SEL_TEST_PAGE_02 | 2;
1100 CtxTmp2.ss = BS3_SEL_TEST_PAGE_03 | 2;
1101 CtxTmp2.bCpl = 2;
1102
1103 /* test run. */
1104 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1105 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
1106 g_usBs3TestStep++;
1107
1108 /* Real run. */
1109 i = (g_f16BitSys ? 2 : 4) * 6 + 1;
1110 while (i-- > 0)
1111 {
1112 Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1;
1113 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1114 if (i > 0)
1115 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/);
1116 else
1117 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
1118 g_usBs3TestStep++;
1119 }
1120
1121 /* Do a run where we do the same-ring kind of access. */
1122 Bs3RegCtxConvertToRingX(&CtxTmp, 2);
1123 if (g_f16BitSys)
1124 {
1125 CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 2*3;
1126 i = 2*3 - 1;
1127 }
1128 else
1129 {
1130 CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 4*3;
1131 i = 4*3 - 1;
1132 }
1133 CtxTmp.ss = BS3_SEL_TEST_PAGE_03 | 2;
1134 CtxTmp2.ds = CtxTmp.ds;
1135 CtxTmp2.es = CtxTmp.es;
1136 CtxTmp2.fs = CtxTmp.fs;
1137 CtxTmp2.gs = CtxTmp.gs;
1138 while (i-- > 0)
1139 {
1140 Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1;
1141 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1142 if (i > 0)
1143 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, 0 /*BS3_SEL_TEST_PAGE_03*/, true /*f486ResumeFlagHint*/);
1144 else
1145 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2);
1146 g_usBs3TestStep++;
1147 }
1148
1149 *puTssSs2 = uSavedSs2;
1150 paIdt[0x83 << cIdteShift] = SavedGate83;
1151 }
1152 paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs;
1153 BS3_ASSERT(g_usBs3TestStep < 3000);
1154
1155 /*
1156 * Modify the gate CS value with a conforming segment.
1157 */
1158 g_usBs3TestStep = 3000;
1159 for (i = 0; i <= 3; i++) /* cs.dpl */
1160 {
1161 for (iRing = 0; iRing <= 3; iRing++)
1162 {
1163 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1164 {
1165 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1166 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1167# if TMPL_BITS == 32
1168 g_uBs3TrapEipHint = CtxTmp.rip.u32;
1169# endif
1170
1171 for (j = 0; j <= 3; j++) /* rpl */
1172 {
1173 uint16_t const uCs = (uSysR0CsConf | j) + (i << BS3_SEL_RING_SHIFT);
1174 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
1175 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
1176 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1177 //Bs3TestPrintf("%u/%u/%u/%u: cs=%04x hcs=%04x xcpt=%02x\n", i, iRing, iCtx, j, uCs, TrapCtx.uHandlerCs, TrapCtx.bXcpt);
1178 /*Bs3TrapPrintFrame(&TrapCtx);*/
1179 g_usBs3TestStep++;
1180 if (iCtx < iRing)
1181 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1182 else if (i > iRing)
1183 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
1184 else
1185 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1186 }
1187 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
1188 }
1189 }
1190 }
1191 BS3_ASSERT(g_usBs3TestStep < 3500);
1192
1193 /*
1194 * The gates must be 64-bit in long mode.
1195 */
1196 if (cIdteShift != 0)
1197 {
1198 g_usBs3TestStep = 3500;
1199 for (i = 0; i <= 3; i++)
1200 {
1201 for (iRing = 0; iRing <= 3; iRing++)
1202 {
1203 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1204 {
1205 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1206 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1207
1208 for (j = 0; j < 2; j++)
1209 {
1210 static const uint16_t s_auCSes[2] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32 };
1211 uint16_t uCs = (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT);
1212 g_usBs3TestStep++;
1213 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/
1214 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
1215 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1216 /*Bs3TrapPrintFrame(&TrapCtx);*/
1217 if (iCtx < iRing)
1218 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1219 else
1220 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL);
1221 }
1222 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
1223 }
1224 }
1225 }
1226 BS3_ASSERT(g_usBs3TestStep < 4000);
1227 }
1228
1229 /*
1230 * IDT limit check. The 286 does not access X86DESCGATE::u16OffsetHigh.
1231 */
1232 g_usBs3TestStep = 5000;
1233 i = (0x80 << (cIdteShift + 3)) - 1;
1234 j = (0x82 << (cIdteShift + 3)) - (!f286 ? 1 : 3);
1235 k = (0x83 << (cIdteShift + 3)) - 1;
1236 for (; i <= k; i++, g_usBs3TestStep++)
1237 {
1238 Idtr = IdtrSaved;
1239 Idtr.cbIdt = i;
1240 ASMSetIDTR(&Idtr);
1241 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1242 if (i < j)
1243 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx81, (0x81 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1244 else
1245 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1246 }
1247 ASMSetIDTR(&IdtrSaved);
1248 BS3_ASSERT(g_usBs3TestStep < 5100);
1249
1250# if TMPL_BITS != 16 /* Only do the paging related stuff in 32-bit and 64-bit modes. */
1251
1252 /*
1253 * IDT page not present. Placing the IDT copy such that 0x80 is on the
1254 * first page and 0x81 is on the second page. We need proceed to move
1255 * it down byte by byte to check that any inaccessible byte means #PF.
1256 *
1257 * Note! We must reload the alternative IDTR for each run as any kind of
1258 * printing to the string (like error reporting) will cause a switch
1259 * to real mode and back, reloading the default IDTR.
1260 */
1261 g_usBs3TestStep = 5200;
1262 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1263 {
1264 uint32_t const uCr2Expected = Bs3SelPtrToFlat(pbIdtCopyAlloc) + _4K;
1265 for (j = 0; j < cbIdte; j++)
1266 {
1267 pIdtCopy = (PX86DESC)&pbIdtCopyAlloc[_4K - cbIdte * 0x81 - j];
1268 Bs3MemCpy(pIdtCopy, paIdt, cbIdte * 256);
1269
1270 Idtr.cbIdt = IdtrSaved.cbIdt;
1271 Idtr.pIdt = Bs3SelPtrToFlat(pIdtCopy);
1272
1273 ASMSetIDTR(&Idtr);
1274 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1275 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1276 g_usBs3TestStep++;
1277
1278 ASMSetIDTR(&Idtr);
1279 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1280 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1281 g_usBs3TestStep++;
1282
1283 rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1284 if (RT_SUCCESS(rc))
1285 {
1286 ASMSetIDTR(&Idtr);
1287 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1288 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1289 g_usBs3TestStep++;
1290
1291 ASMSetIDTR(&Idtr);
1292 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1293 if (f486Plus)
1294 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected);
1295 else
1296 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4));
1297 g_usBs3TestStep++;
1298
1299 Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1300
1301 /* Check if that the entry type is checked after the whole IDTE has been cleared for #PF. */
1302 pIdtCopy[0x80 << cIdteShift].Gate.u4Type = 0;
1303 rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1304 if (RT_SUCCESS(rc))
1305 {
1306 ASMSetIDTR(&Idtr);
1307 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1308 if (f486Plus)
1309 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected);
1310 else
1311 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4));
1312 g_usBs3TestStep++;
1313
1314 Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1315 }
1316 }
1317 else
1318 Bs3TestPrintf("Bs3PagingProtectPtr: %d\n", i);
1319
1320 ASMSetIDTR(&IdtrSaved);
1321 }
1322 }
1323
1324 /*
1325 * The read/write and user/supervisor bits the IDT PTEs are irrelevant.
1326 */
1327 g_usBs3TestStep = 5300;
1328 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1329 {
1330 Bs3MemCpy(pbIdtCopyAlloc, paIdt, cbIdte * 256);
1331 Idtr.cbIdt = IdtrSaved.cbIdt;
1332 Idtr.pIdt = Bs3SelPtrToFlat(pbIdtCopyAlloc);
1333
1334 ASMSetIDTR(&Idtr);
1335 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1336 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1337 g_usBs3TestStep++;
1338
1339 rc = Bs3PagingProtect(Idtr.pIdt, _4K, 0 /*fSet*/, X86_PTE_RW | X86_PTE_US /*fClear*/);
1340 if (RT_SUCCESS(rc))
1341 {
1342 ASMSetIDTR(&Idtr);
1343 Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx);
1344 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/);
1345 g_usBs3TestStep++;
1346
1347 Bs3PagingProtect(Idtr.pIdt, _4K, X86_PTE_RW | X86_PTE_US /*fSet*/, 0 /*fClear*/);
1348 }
1349 ASMSetIDTR(&IdtrSaved);
1350 }
1351
1352 /*
1353 * Check that CS.u1Accessed is set to 1. Use the test page selector #0 and #3 together
1354 * with interrupt gates 80h and 83h, respectively.
1355 */
1356/** @todo Throw in SS.u1Accessed too. */
1357 g_usBs3TestStep = 5400;
1358 if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc)
1359 {
1360 Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT];
1361 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1362 paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00;
1363
1364 Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Cs + (3 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT];
1365 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1366 paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_03; /* rpl is ignored, so leave it as zero. */
1367
1368 /* Check that the CS.A bit is being set on a general basis and that
1369 the special CS values work with out generic handler code. */
1370 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1371 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1372 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1373 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed", Bs3GdteTestPage00.Gen.u4Type);
1374 g_usBs3TestStep++;
1375
1376 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1377 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1378 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1379 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1380 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1381 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1382 if (TrapCtx.uHandlerCs != (BS3_SEL_TEST_PAGE_03 | 3))
1383 bs3CpuBasic2_FailedF("uHandlerCs=%#x, expected %#x", TrapCtx.uHandlerCs, (BS3_SEL_TEST_PAGE_03 | 3));
1384 g_usBs3TestStep++;
1385
1386 /*
1387 * Now check that setting CS.u1Access to 1 does __NOT__ trigger a page
1388 * fault due to the RW bit being zero.
1389 * (We check both with with and without the WP bit if 80486.)
1390 */
1391 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1392 ASMSetCR0(uCr0Saved | X86_CR0_WP);
1393
1394 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1395 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1396 rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_RW /*fClear*/);
1397 if (RT_SUCCESS(rc))
1398 {
1399 /* ring-0 handler */
1400 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1401 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1402 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1403 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1404 g_usBs3TestStep++;
1405
1406 /* ring-3 handler */
1407 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1408 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1409 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1410 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1411 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1412 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1413 g_usBs3TestStep++;
1414
1415 /* clear WP and repeat the above. */
1416 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486)
1417 ASMSetCR0(uCr0Saved & ~X86_CR0_WP);
1418 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */
1419 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */
1420
1421 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1422 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/);
1423 if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1424 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type);
1425 g_usBs3TestStep++;
1426
1427 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1428 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/);
1429 if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
1430 bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!n", Bs3GdteTestPage03.Gen.u4Type);
1431 g_usBs3TestStep++;
1432
1433 Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_RW /*fSet*/, 0 /*fClear*/);
1434 }
1435
1436 ASMSetCR0(uCr0Saved);
1437
1438 /*
1439 * While we're here, check that if the CS GDT entry is a non-present
1440 * page we do get a #PF with the rigth error code and CR2.
1441 */
1442 Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* Just for fun, really a pointless gesture. */
1443 Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED;
1444 rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_P /*fClear*/);
1445 if (RT_SUCCESS(rc))
1446 {
1447 Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx);
1448 if (f486Plus)
1449 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00);
1450 else
1451 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00 + 4);
1452 g_usBs3TestStep++;
1453
1454 /* Do it from ring-3 to check ErrCd, which doesn't set X86_TRAP_PF_US it turns out. */
1455 Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp));
1456 Bs3RegCtxConvertToRingX(&CtxTmp, 3);
1457 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1458
1459 if (f486Plus)
1460 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03);
1461 else
1462 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03 + 4);
1463 g_usBs3TestStep++;
1464
1465 Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_P /*fSet*/, 0 /*fClear*/);
1466 if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
1467 bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #1", Bs3GdteTestPage00.Gen.u4Type);
1468 if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)
1469 bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #2", Bs3GdteTestPage03.Gen.u4Type);
1470 }
1471
1472 /* restore */
1473 paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs;
1474 paIdt[0x83 << cIdteShift].Gate.u16Sel = uSysR0Cs;// + (3 << BS3_SEL_RING_SHIFT) + 3;
1475 }
1476
1477# endif /* 32 || 64*/
1478
1479 /*
1480 * Check broad EFLAGS effects.
1481 */
1482 g_usBs3TestStep = 5600;
1483 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1484 {
1485 for (iRing = 0; iRing < 4; iRing++)
1486 {
1487 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1488 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1489
1490 /* all set */
1491 CtxTmp.rflags.u32 &= X86_EFL_VM | X86_EFL_1;
1492 CtxTmp.rflags.u32 |= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF /* | X86_EFL_TF */ /*| X86_EFL_IF*/
1493 | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL /* | X86_EFL_NT*/;
1494 if (f486Plus)
1495 CtxTmp.rflags.u32 |= X86_EFL_AC;
1496 if (f486Plus && !g_f16BitSys)
1497 CtxTmp.rflags.u32 |= X86_EFL_RF;
1498 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1499 CtxTmp.rflags.u32 |= X86_EFL_VIF | X86_EFL_VIP;
1500 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1501 CtxTmp.rflags.u32 &= ~X86_EFL_RF;
1502
1503 if (iCtx >= iRing)
1504 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1505 else
1506 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1507 uExpected = CtxTmp.rflags.u32
1508 & ( X86_EFL_1 | X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_DF
1509 | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP
1510 | X86_EFL_ID /*| X86_EFL_TF*/ /*| X86_EFL_IF*/ /*| X86_EFL_RF*/ );
1511 if (TrapCtx.fHandlerRfl != uExpected)
1512 bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n",
1513 TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u);
1514 g_usBs3TestStep++;
1515
1516 /* all cleared */
1517 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80286)
1518 CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_RA1_MASK | UINT16_C(0xf000));
1519 else
1520 CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_VM | X86_EFL_RA1_MASK);
1521 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1522 if (iCtx >= iRing)
1523 bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/);
1524 else
1525 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1526 uExpected = CtxTmp.rflags.u32;
1527 if (TrapCtx.fHandlerRfl != uExpected)
1528 bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n",
1529 TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u);
1530 g_usBs3TestStep++;
1531 }
1532 }
1533
1534/** @todo CS.LIMIT / canonical(CS) */
1535
1536
1537 /*
1538 * Check invalid gate types.
1539 */
1540 g_usBs3TestStep = 32000;
1541 for (iRing = 0; iRing <= 3; iRing++)
1542 {
1543 static const uint16_t s_auCSes[] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32, BS3_SEL_R0_CS64,
1544 BS3_SEL_TSS16, BS3_SEL_TSS32, BS3_SEL_TSS64, 0, BS3_SEL_SPARE_1f };
1545 static uint16_t const s_auInvlTypes64[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
1546 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1547 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
1548 static uint16_t const s_auInvlTypes32[] = { 0, 1, 2, 3, 8, 9, 10, 11, 13,
1549 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1550 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1551 /*286:*/ 12, 14, 15 };
1552 uint16_t const * const pauInvTypes = cIdteShift != 0 ? s_auInvlTypes64 : s_auInvlTypes32;
1553 uint16_t const cInvTypes = cIdteShift != 0 ? RT_ELEMENTS(s_auInvlTypes64)
1554 : f386Plus ? RT_ELEMENTS(s_auInvlTypes32) - 3 : RT_ELEMENTS(s_auInvlTypes32);
1555
1556
1557 for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
1558 {
1559 unsigned iType;
1560
1561 Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
1562 Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
1563# if TMPL_BITS == 32
1564 g_uBs3TrapEipHint = CtxTmp.rip.u32;
1565# endif
1566 for (iType = 0; iType < cInvTypes; iType++)
1567 {
1568 uint8_t const bSavedType = paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type;
1569 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = pauInvTypes[iType] >> 4;
1570 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = pauInvTypes[iType] & 0xf;
1571
1572 for (i = 0; i < 4; i++)
1573 {
1574 for (j = 0; j < RT_ELEMENTS(s_auCSes); j++)
1575 {
1576 uint16_t uCs = (unsigned)(s_auCSes[j] - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT)
1577 ? (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT)
1578 : s_auCSes[j] | i;
1579 /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x type=%#x\n", g_usBs3TestStep, iCtx, iRing, i, uCs, pauInvTypes[iType]);*/
1580 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs;
1581 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1582 g_usBs3TestStep++;
1583 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1584
1585 /* Mark it not-present to check that invalid type takes precedence. */
1586 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 0;
1587 Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
1588 g_usBs3TestStep++;
1589 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT);
1590 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
1591 }
1592 }
1593
1594 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs;
1595 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = bSavedType;
1596 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = 0;
1597 paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1;
1598 }
1599 }
1600 }
1601 BS3_ASSERT(g_usBs3TestStep < 62000U && g_usBs3TestStep > 32000U);
1602
1603
1604 /** @todo
1605 * - Run \#PF and \#GP (and others?) at CPLs other than zero.
1606 * - Quickly generate all faults.
1607 * - All the peculiarities v8086.
1608 */
1609
1610# if TMPL_BITS != 16
1611 Bs3MemFree(pbIdtCopyAlloc, 12*_1K);
1612# endif
1613}
1614#endif /* convert me */
1615
1616
1617static void bs3CpuBasic2_RaiseXcpt11Worker(uint8_t bMode, uint8_t *pbBuf, unsigned cbCacheLine, bool fAm, bool fPf,
1618 RTCCUINTXREG uFlatBufPtr, BS3CPUBASIC2PFTTSTCMNMODE const BS3_FAR *pCmn)
1619{
1620 BS3TRAPFRAME TrapCtx;
1621 BS3REGCTX Ctx;
1622 BS3REGCTX CtxUdExpected;
1623 uint8_t const cRings = bMode == BS3_MODE_RM ? 1 : 4;
1624 uint8_t iRing;
1625 uint16_t iTest;
1626
1627 /* make sure they're allocated */
1628 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1629 Bs3MemZero(&Ctx, sizeof(Ctx));
1630 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
1631
1632 /*
1633 * Test all relevant rings.
1634 *
1635 * The memory operand is ds:xBX, so point it to pbBuf.
1636 * The test snippets mostly use xAX as operand, with the div
1637 * one also using xDX, so make sure they make some sense.
1638 */
1639 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1640
1641 Ctx.cr0.u32 &= ~(X86_CR0_MP | X86_CR0_EM | X86_CR0_TS); /* so fninit + fld works */
1642
1643 for (iRing = BS3_MODE_IS_V86(bMode) ? 3 : 0; iRing < cRings; iRing++)
1644 {
1645 uint32_t uEbx;
1646 uint8_t fAc;
1647
1648 if (!BS3_MODE_IS_RM_OR_V86(bMode))
1649 Bs3RegCtxConvertToRingX(&Ctx, iRing);
1650
1651 if (!fPf || BS3_MODE_IS_32BIT_CODE(bMode) || BS3_MODE_IS_64BIT_CODE(bMode))
1652 Bs3RegCtxSetGrpDsFromCurPtr(&Ctx, &Ctx.rbx, pbBuf);
1653 else
1654 {
1655 /* Bs3RegCtxSetGrpDsFromCurPtr barfs when trying to output a sel:off address for the aliased buffer. */
1656 Ctx.ds = BS3_FP_SEG(pbBuf);
1657 Ctx.rbx.u32 = BS3_FP_OFF(pbBuf);
1658 }
1659 uEbx = Ctx.rbx.u32;
1660
1661 Ctx.rax.u = (bMode & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_64
1662 ? UINT64_C(0x80868028680386fe) : UINT32_C(0x65020686);
1663 Ctx.rdx.u = UINT32_C(0x00100100); /* careful with range due to div */
1664
1665 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
1666
1667 /*
1668 * AC flag loop.
1669 */
1670 for (fAc = 0; fAc < 2; fAc++)
1671 {
1672 if (fAc)
1673 Ctx.rflags.u32 |= X86_EFL_AC;
1674 else
1675 Ctx.rflags.u32 &= ~X86_EFL_AC;
1676
1677 /*
1678 * Loop over the test snippets.
1679 */
1680 for (iTest = 0; iTest < pCmn->cEntries; iTest++)
1681 {
1682 uint8_t const fOp = pCmn->paEntries[iTest].fOp;
1683 uint16_t const cbMem = pCmn->paEntries[iTest].cbMem;
1684 uint8_t const cbAlign = pCmn->paEntries[iTest].cbAlign;
1685 uint16_t const cbMax = cbCacheLine + cbMem;
1686 uint16_t offMem;
1687 uint8_t BS3_FAR *poffUd = (uint8_t BS3_FAR *)Bs3SelLnkPtrToCurPtr(pCmn->paEntries[iTest].pfn);
1688 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pCmn->paEntries[iTest].pfn);
1689 CtxUdExpected.rip = Ctx.rip;
1690 CtxUdExpected.rip.u = Ctx.rip.u + poffUd[-1];
1691 CtxUdExpected.cs = Ctx.cs;
1692 CtxUdExpected.rflags = Ctx.rflags;
1693 if (bMode == BS3_MODE_RM)
1694 CtxUdExpected.rflags.u32 &= ~X86_EFL_AC; /** @todo investigate. automatically cleared, or is it just our code? Observed with bs3-cpu-instr-3 too (10980xe), seems to be the CPU doing it. */
1695 CtxUdExpected.rdx = Ctx.rdx;
1696 CtxUdExpected.rax = Ctx.rax;
1697 if (fOp & MYOP_LD)
1698 {
1699 switch (cbMem)
1700 {
1701 case 2:
1702 CtxUdExpected.rax.u16 = 0x0101;
1703 break;
1704 case 4:
1705 CtxUdExpected.rax.u32 = UINT32_C(0x01010101);
1706 break;
1707 case 8:
1708 CtxUdExpected.rax.u64 = UINT64_C(0x0101010101010101);
1709 break;
1710 }
1711 }
1712
1713 /*
1714 * Buffer misalignment loop.
1715 * Note! We must make sure to cross a cache line here to make sure
1716 * to cover the split-lock scenario. (The buffer is cache
1717 * line aligned.)
1718 */
1719 for (offMem = 0; offMem < cbMax; offMem++)
1720 {
1721 bool const fMisaligned = (offMem & (cbAlign - 1)) != 0;
1722 unsigned offBuf = cbMax + cbMem * 2;
1723 while (offBuf-- > 0)
1724 pbBuf[offBuf] = 1; /* byte-by-byte to make sure it doesn't trigger AC. */
1725
1726 CtxUdExpected.rbx.u32 = Ctx.rbx.u32 = uEbx + offMem; /* ASSUMES memory in first 4GB. */
1727 if (BS3_MODE_IS_16BIT_SYS(bMode))
1728 g_uBs3TrapEipHint = Ctx.rip.u32;
1729
1730 //Bs3TestPrintf("iRing=%d iTest=%d cs:rip=%04RX16:%08RX32 ds:rbx=%04RX16:%08RX32 ss:esp=%04RX16:%08RX32 bXcpt=%#x errcd=%#x fAm=%d fAc=%d ESP=%#RX32\n",
1731 // iRing, iTest, Ctx.cs, Ctx.rip.u32, Ctx.ds, Ctx.rbx.u32, Ctx.ss, Ctx.rsp.u32, TrapCtx.bXcpt, (unsigned)TrapCtx.uErrCd, fAm, fAc, ASMGetESP());
1732
1733 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1734
1735 if ( (pCmn->paEntries[iTest].fOp & MYOP_AC_GP)
1736 && fMisaligned
1737 && (!fAm || iRing != 3 || !fAc || (offMem & 3 /* 10980XE */) == 0) )
1738 {
1739 if (fAc && bMode == BS3_MODE_RM)
1740 TrapCtx.Ctx.rflags.u32 |= X86_EFL_AC;
1741 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
1742 }
1743 else if (fPf && iRing == 3 && (!fAm || !fAc || !fMisaligned)) /* #AC beats #PF */
1744 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx,
1745 X86_TRAP_PF_P | X86_TRAP_PF_US
1746 | (pCmn->paEntries[iTest].fOp & MYOP_ST ? X86_TRAP_PF_RW : 0),
1747 uFlatBufPtr + offMem + (cbMem > 64 ? cbMem - 1 /*FXSAVE*/ : 0),
1748 pCmn->paEntries[iTest].offFaultInstr);
1749 else if (!fAm || iRing != 3 || !fAc || !fMisaligned)
1750 {
1751 if (fOp & MYOP_EFL)
1752 {
1753 CtxUdExpected.rflags.u16 &= ~X86_EFL_STATUS_BITS;
1754 CtxUdExpected.rflags.u16 |= TrapCtx.Ctx.rflags.u16 & X86_EFL_STATUS_BITS;
1755 }
1756 if (fOp == MYOP_LD_DIV)
1757 {
1758 CtxUdExpected.rax = TrapCtx.Ctx.rax;
1759 CtxUdExpected.rdx = TrapCtx.Ctx.rdx;
1760 }
1761 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1762 }
1763 else
1764 bs3CpuBasic2_CompareAcCtx(&TrapCtx, &Ctx, pCmn->paEntries[iTest].offFaultInstr);
1765
1766 g_usBs3TestStep++;
1767 }
1768 }
1769 }
1770 }
1771}
1772
1773
1774/**
1775 * Entrypoint for \#AC tests.
1776 *
1777 * @returns 0 or BS3TESTDOMODE_SKIPPED.
1778 * @param bMode The CPU mode we're testing.
1779 *
1780 * @note When testing v8086 code, we'll be running in v8086 mode. So, careful
1781 * with control registers and such.
1782 */
1783BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_RaiseXcpt11)(uint8_t bMode)
1784{
1785 unsigned cbCacheLine = 128; /** @todo detect */
1786 uint8_t BS3_FAR *pbBufAlloc;
1787 uint8_t BS3_FAR *pbBuf;
1788 unsigned idxCmnModes;
1789 uint32_t fCr0;
1790
1791 /*
1792 * Skip if 386 or older.
1793 */
1794 if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80486)
1795 {
1796 Bs3TestSkipped("#AC test requires 486 or later");
1797 return BS3TESTDOMODE_SKIPPED;
1798 }
1799
1800 bs3CpuBasic2_SetGlobals(bMode);
1801
1802 /* Get us a 64-byte aligned buffer. */
1803 pbBufAlloc = pbBuf = Bs3MemAllocZ(BS3_MODE_IS_RM_OR_V86(bMode) ? BS3MEMKIND_REAL : BS3MEMKIND_TILED, X86_PAGE_SIZE * 2);
1804 if (!pbBufAlloc)
1805 return Bs3TestFailed("Failed to allocate 2 pages of real-mode memory");
1806 if (BS3_FP_OFF(pbBuf) & (X86_PAGE_SIZE - 1))
1807 pbBuf = &pbBufAlloc[X86_PAGE_SIZE - (BS3_FP_OFF(pbBuf) & X86_PAGE_OFFSET_MASK)];
1808 BS3_ASSERT(pbBuf - pbBufAlloc <= X86_PAGE_SIZE);
1809 //Bs3TestPrintf("pbBuf=%p\n", pbBuf);
1810
1811 /* Find the g_aCmnModes entry. */
1812 idxCmnModes = 0;
1813 while (g_aCmnModes[idxCmnModes].bMode != (bMode & BS3_MODE_CODE_MASK))
1814 idxCmnModes++;
1815 //Bs3TestPrintf("idxCmnModes=%d bMode=%#x\n", idxCmnModes, bMode);
1816
1817 /* First round is w/o alignment checks enabled. */
1818 //Bs3TestPrintf("round 1\n");
1819 fCr0 = Bs3RegGetCr0();
1820 BS3_ASSERT(!(fCr0 & X86_CR0_AM));
1821 Bs3RegSetCr0(fCr0 & ~X86_CR0_AM);
1822#if 1
1823 bs3CpuBasic2_RaiseXcpt11Worker(bMode, pbBuf, cbCacheLine, false /*fAm*/, false /*fPf*/, 0, &g_aCmnModes[idxCmnModes]);
1824#endif
1825
1826 /* The second round is with aligment checks enabled. */
1827#if 1
1828 //Bs3TestPrintf("round 2\n");
1829 Bs3RegSetCr0(Bs3RegGetCr0() | X86_CR0_AM);
1830 bs3CpuBasic2_RaiseXcpt11Worker(bMode, pbBuf, cbCacheLine, true /*fAm*/, false /*fPf*/, 0, &g_aCmnModes[idxCmnModes]);
1831#endif
1832
1833#if 1
1834 /* The third and fourth round access the buffer via a page alias that's not
1835 accessible from ring-3. The third round has ACs disabled and the fourth
1836 has them enabled. */
1837 if (BS3_MODE_IS_PAGED(bMode) && !BS3_MODE_IS_V86(bMode))
1838 {
1839 /* Alias the buffer as system memory so ring-3 access with AC+AM will cause #PF: */
1840 /** @todo the aliasing is not necessary any more... */
1841 int rc;
1842 RTCCUINTXREG uFlatBufPtr = Bs3SelPtrToFlat(pbBuf);
1843 uint64_t const uAliasPgPtr = bMode & BS3_MODE_CODE_64 ? UINT64_C(0x0000648680000000) : UINT32_C(0x80000000);
1844 rc = Bs3PagingAlias(uAliasPgPtr, uFlatBufPtr & ~(uint64_t)X86_PAGE_OFFSET_MASK, X86_PAGE_SIZE * 2,
1845 X86_PTE_P | X86_PTE_RW);
1846 if (RT_SUCCESS(rc))
1847 {
1848 /* We 'misalign' the segment base here to make sure it's the final
1849 address that gets alignment checked and not just the operand value. */
1850 RTCCUINTXREG uAliasBufPtr = (RTCCUINTXREG)uAliasPgPtr + (uFlatBufPtr & X86_PAGE_OFFSET_MASK);
1851 uint8_t BS3_FAR *pbBufAlias = BS3_FP_MAKE(BS3_SEL_SPARE_00 | 3, (uFlatBufPtr & X86_PAGE_OFFSET_MASK) + 1);
1852 Bs3SelSetup16BitData(&Bs3GdteSpare00, uAliasPgPtr - 1);
1853
1854 //Bs3TestPrintf("round 3 pbBufAlias=%p\n", pbBufAlias);
1855 Bs3RegSetCr0(Bs3RegGetCr0() & ~X86_CR0_AM);
1856 bs3CpuBasic2_RaiseXcpt11Worker(bMode, pbBufAlias, cbCacheLine, false /*fAm*/,
1857 true /*fPf*/, uAliasBufPtr, &g_aCmnModes[idxCmnModes]);
1858
1859 //Bs3TestPrintf("round 4\n");
1860 Bs3RegSetCr0(Bs3RegGetCr0() | X86_CR0_AM);
1861 bs3CpuBasic2_RaiseXcpt11Worker(bMode, pbBufAlias, cbCacheLine, true /*fAm*/,
1862 true /*fPf*/, uAliasBufPtr, &g_aCmnModes[idxCmnModes]);
1863
1864 Bs3PagingUnalias(uAliasPgPtr, X86_PAGE_SIZE * 2);
1865 }
1866 else
1867 Bs3TestFailedF("Bs3PagingAlias failed with %Rrc", rc);
1868 }
1869#endif
1870
1871 Bs3MemFree(pbBufAlloc, X86_PAGE_SIZE * 2);
1872 Bs3RegSetCr0(fCr0);
1873 return 0;
1874}
1875
1876
1877/**
1878 * Executes one round of SIDT and SGDT tests using one assembly worker.
1879 *
1880 * This is written with driving everything from the 16-bit or 32-bit worker in
1881 * mind, i.e. not assuming the test bitcount is the same as the current.
1882 */
1883static void bs3CpuBasic2_sidt_sgdt_One(BS3CB2SIDTSGDT const BS3_FAR *pWorker, uint8_t bTestMode, uint8_t bRing,
1884 uint8_t const *pbExpected)
1885{
1886 BS3TRAPFRAME TrapCtx;
1887 BS3REGCTX Ctx;
1888 BS3REGCTX CtxUdExpected;
1889 BS3REGCTX TmpCtx;
1890 uint8_t const cbBuf = 8*2; /* test buffer area */
1891 uint8_t abBuf[8*2 + 8 + 8]; /* test buffer w/ misalignment test space and some extra guard. */
1892 uint8_t BS3_FAR *pbBuf = abBuf;
1893 uint8_t const cbIdtr = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 2+8 : 2+4;
1894 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
1895 uint8_t bFiller;
1896 int off;
1897 int off2;
1898 unsigned cb;
1899 uint8_t BS3_FAR *pbTest;
1900
1901 /* make sure they're allocated */
1902 Bs3MemZero(&Ctx, sizeof(Ctx));
1903 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
1904 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
1905 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
1906 Bs3MemZero(&abBuf, sizeof(abBuf));
1907
1908 /* Create a context, give this routine some more stack space, point the context
1909 at our SIDT [xBX] + UD2 combo, and point DS:xBX at abBuf. */
1910 Bs3RegCtxSaveEx(&Ctx, bTestMode, 256 /*cbExtraStack*/);
1911 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf);
1912 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pWorker->fpfnWorker);
1913 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
1914 g_uBs3TrapEipHint = Ctx.rip.u32;
1915 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
1916 Bs3RegCtxConvertToRingX(&Ctx, bRing);
1917
1918 /* For successful SIDT attempts, we'll stop at the UD2. */
1919 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
1920 CtxUdExpected.rip.u += pWorker->cbInstr;
1921
1922 /*
1923 * Check that it works at all and that only bytes we expect gets written to.
1924 */
1925 /* First with zero buffer. */
1926 Bs3MemZero(abBuf, sizeof(abBuf));
1927 if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), 0))
1928 Bs3TestFailedF("ASMMemIsAllU8 or Bs3MemZero is busted: abBuf=%.*Rhxs\n", sizeof(abBuf), pbBuf);
1929 if (!ASMMemIsZero(abBuf, sizeof(abBuf)))
1930 Bs3TestFailedF("ASMMemIsZero or Bs3MemZero is busted: abBuf=%.*Rhxs\n", sizeof(abBuf), pbBuf);
1931 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1932 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1933 if (f286 && abBuf[cbIdtr - 1] != 0xff)
1934 Bs3TestFailedF("286: Top base byte isn't 0xff (#1): %#x\n", abBuf[cbIdtr - 1]);
1935 if (!ASMMemIsZero(&abBuf[cbIdtr], cbBuf - cbIdtr))
1936 Bs3TestFailedF("Unexpected buffer bytes set (#1): cbIdtr=%u abBuf=%.*Rhxs\n", cbIdtr, cbBuf, pbBuf);
1937 if (Bs3MemCmp(abBuf, pbExpected, cbIdtr) != 0)
1938 Bs3TestFailedF("Mismatch (%s,#1): expected %.*Rhxs, got %.*Rhxs\n", pWorker->pszDesc, cbIdtr, pbExpected, cbIdtr, abBuf);
1939 g_usBs3TestStep++;
1940
1941 /* Again with a buffer filled with a byte not occuring in the previous result. */
1942 bFiller = 0x55;
1943 while (Bs3MemChr(abBuf, bFiller, cbBuf) != NULL)
1944 bFiller++;
1945 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
1946 if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller))
1947 Bs3TestFailedF("ASMMemIsAllU8 or Bs3MemSet is busted: bFiller=%#x abBuf=%.*Rhxs\n", bFiller, sizeof(abBuf), pbBuf);
1948
1949 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1950 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1951 if (f286 && abBuf[cbIdtr - 1] != 0xff)
1952 Bs3TestFailedF("286: Top base byte isn't 0xff (#2): %#x\n", abBuf[cbIdtr - 1]);
1953 if (!ASMMemIsAllU8(&abBuf[cbIdtr], cbBuf - cbIdtr, bFiller))
1954 Bs3TestFailedF("Unexpected buffer bytes set (#2): cbIdtr=%u bFiller=%#x abBuf=%.*Rhxs\n", cbIdtr, bFiller, cbBuf, pbBuf);
1955 if (Bs3MemChr(abBuf, bFiller, cbIdtr) != NULL)
1956 Bs3TestFailedF("Not all bytes touched: cbIdtr=%u bFiller=%#x abBuf=%.*Rhxs\n", cbIdtr, bFiller, cbBuf, pbBuf);
1957 if (Bs3MemCmp(abBuf, pbExpected, cbIdtr) != 0)
1958 Bs3TestFailedF("Mismatch (%s,#2): expected %.*Rhxs, got %.*Rhxs\n", pWorker->pszDesc, cbIdtr, pbExpected, cbIdtr, abBuf);
1959 g_usBs3TestStep++;
1960
1961 /*
1962 * Slide the buffer along 8 bytes to cover misalignment.
1963 */
1964 for (off = 0; off < 8; off++)
1965 {
1966 pbBuf = &abBuf[off];
1967 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &abBuf[off]);
1968 CtxUdExpected.rbx.u = Ctx.rbx.u;
1969
1970 /* First with zero buffer. */
1971 Bs3MemZero(abBuf, sizeof(abBuf));
1972 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1973 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1974 if (off > 0 && !ASMMemIsZero(abBuf, off))
1975 Bs3TestFailedF("Unexpected buffer bytes set before (#3): cbIdtr=%u off=%u abBuf=%.*Rhxs\n",
1976 cbIdtr, off, off + cbBuf, abBuf);
1977 if (!ASMMemIsZero(&abBuf[off + cbIdtr], sizeof(abBuf) - cbIdtr - off))
1978 Bs3TestFailedF("Unexpected buffer bytes set after (#3): cbIdtr=%u off=%u abBuf=%.*Rhxs\n",
1979 cbIdtr, off, off + cbBuf, abBuf);
1980 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
1981 Bs3TestFailedF("286: Top base byte isn't 0xff (#3): %#x\n", abBuf[off + cbIdtr - 1]);
1982 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
1983 Bs3TestFailedF("Mismatch (#3): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
1984 g_usBs3TestStep++;
1985
1986 /* Again with a buffer filled with a byte not occuring in the previous result. */
1987 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
1988 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
1989 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
1990 if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller))
1991 Bs3TestFailedF("Unexpected buffer bytes set before (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n",
1992 cbIdtr, off, bFiller, off + cbBuf, abBuf);
1993 if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - cbIdtr - off, bFiller))
1994 Bs3TestFailedF("Unexpected buffer bytes set after (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n",
1995 cbIdtr, off, bFiller, off + cbBuf, abBuf);
1996 if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL)
1997 Bs3TestFailedF("Not all bytes touched (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n",
1998 cbIdtr, off, bFiller, off + cbBuf, abBuf);
1999 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
2000 Bs3TestFailedF("286: Top base byte isn't 0xff (#4): %#x\n", abBuf[off + cbIdtr - 1]);
2001 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
2002 Bs3TestFailedF("Mismatch (#4): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
2003 g_usBs3TestStep++;
2004 }
2005 pbBuf = abBuf;
2006 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf);
2007 CtxUdExpected.rbx.u = Ctx.rbx.u;
2008
2009 /*
2010 * Play with the selector limit if the target mode supports limit checking
2011 * We use BS3_SEL_TEST_PAGE_00 for this
2012 */
2013 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
2014 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
2015 {
2016 uint16_t cbLimit;
2017 uint32_t uFlatBuf = Bs3SelPtrToFlat(abBuf);
2018 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
2019 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
2020 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatBuf;
2021 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatBuf >> 16);
2022 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatBuf >> 24);
2023
2024 if (pWorker->fSs)
2025 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
2026 else
2027 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2028
2029 /* Expand up (normal). */
2030 for (off = 0; off < 8; off++)
2031 {
2032 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2033 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
2034 {
2035 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2036 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
2037 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2038 if (off + cbIdtr <= cbLimit + 1)
2039 {
2040 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2041 if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL)
2042 Bs3TestFailedF("Not all bytes touched (#5): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2043 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2044 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
2045 Bs3TestFailedF("Mismatch (#5): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
2046 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
2047 Bs3TestFailedF("286: Top base byte isn't 0xff (#5): %#x\n", abBuf[off + cbIdtr - 1]);
2048 }
2049 else
2050 {
2051 if (pWorker->fSs)
2052 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2053 else
2054 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2055 if (off + 2 <= cbLimit + 1)
2056 {
2057 if (Bs3MemChr(&abBuf[off], bFiller, 2) != NULL)
2058 Bs3TestFailedF("Limit bytes not touched (#6): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2059 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2060 if (Bs3MemCmp(&abBuf[off], pbExpected, 2) != 0)
2061 Bs3TestFailedF("Mismatch (#6): expected %.2Rhxs, got %.2Rhxs\n", pbExpected, &abBuf[off]);
2062 if (!ASMMemIsAllU8(&abBuf[off + 2], cbIdtr - 2, bFiller))
2063 Bs3TestFailedF("Base bytes touched on #GP (#6): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2064 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2065 }
2066 else if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller))
2067 Bs3TestFailedF("Bytes touched on #GP: cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2068 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2069 }
2070
2071 if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller))
2072 Bs3TestFailedF("Leading bytes touched (#7): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2073 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2074 if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - off - cbIdtr, bFiller))
2075 Bs3TestFailedF("Trailing bytes touched (#7): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2076 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2077
2078 g_usBs3TestStep++;
2079 }
2080 }
2081
2082 /* Expand down (weird). Inverted valid area compared to expand up,
2083 so a limit of zero give us a valid range for 0001..0ffffh (instead of
2084 a segment with one valid byte at 0000h). Whereas a limit of 0fffeh
2085 means one valid byte at 0ffffh, and a limit of 0ffffh means none
2086 (because in a normal expand up the 0ffffh means all 64KB are
2087 accessible). */
2088 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
2089 for (off = 0; off < 8; off++)
2090 {
2091 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2092 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
2093 {
2094 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2095 Bs3MemSet(abBuf, bFiller, sizeof(abBuf));
2096 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2097
2098 if (off > cbLimit)
2099 {
2100 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2101 if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL)
2102 Bs3TestFailedF("Not all bytes touched (#8): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2103 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2104 if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0)
2105 Bs3TestFailedF("Mismatch (#8): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]);
2106 if (f286 && abBuf[off + cbIdtr - 1] != 0xff)
2107 Bs3TestFailedF("286: Top base byte isn't 0xff (#8): %#x\n", abBuf[off + cbIdtr - 1]);
2108 }
2109 else
2110 {
2111 if (pWorker->fSs)
2112 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2113 else
2114 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2115 if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller))
2116 Bs3TestFailedF("Bytes touched on #GP: cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2117 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2118 }
2119
2120 if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller))
2121 Bs3TestFailedF("Leading bytes touched (#9): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2122 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2123 if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - off - cbIdtr, bFiller))
2124 Bs3TestFailedF("Trailing bytes touched (#9): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n",
2125 cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf);
2126
2127 g_usBs3TestStep++;
2128 }
2129 }
2130
2131 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf);
2132 CtxUdExpected.rbx.u = Ctx.rbx.u;
2133 CtxUdExpected.ss = Ctx.ss;
2134 CtxUdExpected.ds = Ctx.ds;
2135 }
2136
2137 /*
2138 * Play with the paging.
2139 */
2140 if ( BS3_MODE_IS_PAGED(bTestMode)
2141 && (!pWorker->fSs || bRing == 3) /* SS.DPL == CPL, we'll get some tiled ring-3 selector here. */
2142 && (pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED)) != NULL)
2143 {
2144 RTCCUINTXREG uFlatTest = Bs3SelPtrToFlat(pbTest);
2145
2146 /*
2147 * Slide the buffer towards the trailing guard page. We'll observe the
2148 * first word being written entirely separately from the 2nd dword/qword.
2149 */
2150 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2151 {
2152 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller, cbIdtr * 2);
2153 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
2154 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2155 if (off + cbIdtr <= X86_PAGE_SIZE)
2156 {
2157 CtxUdExpected.rbx = Ctx.rbx;
2158 CtxUdExpected.ss = Ctx.ss;
2159 CtxUdExpected.ds = Ctx.ds;
2160 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2161 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
2162 Bs3TestFailedF("Mismatch (#9): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
2163 }
2164 else
2165 {
2166 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
2167 uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
2168 if ( off <= X86_PAGE_SIZE - 2
2169 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
2170 Bs3TestFailedF("Mismatch (#10): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n",
2171 pbExpected, &pbTest[off], off);
2172 if ( off < X86_PAGE_SIZE - 2
2173 && !ASMMemIsAllU8(&pbTest[off + 2], X86_PAGE_SIZE - off - 2, bFiller))
2174 Bs3TestFailedF("Wrote partial base on #PF (#10): bFiller=%#x, got %.*Rhxs; off=%#x\n",
2175 bFiller, X86_PAGE_SIZE - off - 2, &pbTest[off + 2], off);
2176 if (off == X86_PAGE_SIZE - 1 && pbTest[off] != bFiller)
2177 Bs3TestFailedF("Wrote partial limit on #PF (#10): Expected %02x, got %02x\n", bFiller, pbTest[off]);
2178 }
2179 g_usBs3TestStep++;
2180 }
2181
2182 /*
2183 * Now, do it the other way around. It should look normal now since writing
2184 * the limit will #PF first and nothing should be written.
2185 */
2186 for (off = cbIdtr + 4; off >= -cbIdtr - 4; off--)
2187 {
2188 Bs3MemSet(pbTest, bFiller, 48);
2189 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
2190 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2191 if (off >= 0)
2192 {
2193 CtxUdExpected.rbx = Ctx.rbx;
2194 CtxUdExpected.ss = Ctx.ss;
2195 CtxUdExpected.ds = Ctx.ds;
2196 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2197 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
2198 Bs3TestFailedF("Mismatch (#11): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
2199 }
2200 else
2201 {
2202 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
2203 uFlatTest + off, 0 /*cbIpAdjust*/);
2204 if ( -off < cbIdtr
2205 && !ASMMemIsAllU8(pbTest, cbIdtr + off, bFiller))
2206 Bs3TestFailedF("Wrote partial content on #PF (#12): bFiller=%#x, found %.*Rhxs; off=%d\n",
2207 bFiller, cbIdtr + off, pbTest, off);
2208 }
2209 if (!ASMMemIsAllU8(&pbTest[RT_MAX(cbIdtr + off, 0)], 16, bFiller))
2210 Bs3TestFailedF("Wrote beyond expected area (#13): bFiller=%#x, found %.16Rhxs; off=%d\n",
2211 bFiller, &pbTest[RT_MAX(cbIdtr + off, 0)], off);
2212 g_usBs3TestStep++;
2213 }
2214
2215 /*
2216 * Combine paging and segment limit and check ordering.
2217 * This is kind of interesting here since it the instruction seems to
2218 * be doing two separate writes.
2219 */
2220 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
2221 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
2222 {
2223 uint16_t cbLimit;
2224
2225 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
2226 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
2227 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
2228 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
2229 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
2230
2231 if (pWorker->fSs)
2232 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
2233 else
2234 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2235
2236 /* Expand up (normal), approaching tail guard page. */
2237 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2238 {
2239 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2240 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
2241 {
2242 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2243 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller, cbIdtr * 2);
2244 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2245 if (off + cbIdtr <= cbLimit + 1)
2246 {
2247 /* No #GP, but maybe #PF. */
2248 if (off + cbIdtr <= X86_PAGE_SIZE)
2249 {
2250 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2251 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
2252 Bs3TestFailedF("Mismatch (#14): expected %.*Rhxs, got %.*Rhxs\n",
2253 cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
2254 }
2255 else
2256 {
2257 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
2258 uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
2259 if ( off <= X86_PAGE_SIZE - 2
2260 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
2261 Bs3TestFailedF("Mismatch (#15): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n",
2262 pbExpected, &pbTest[off], off);
2263 cb = X86_PAGE_SIZE - off - 2;
2264 if ( off < X86_PAGE_SIZE - 2
2265 && !ASMMemIsAllU8(&pbTest[off + 2], cb, bFiller))
2266 Bs3TestFailedF("Wrote partial base on #PF (#15): bFiller=%#x, got %.*Rhxs; off=%#x\n",
2267 bFiller, cb, &pbTest[off + 2], off);
2268 if (off == X86_PAGE_SIZE - 1 && pbTest[off] != bFiller)
2269 Bs3TestFailedF("Wrote partial limit on #PF (#15): Expected %02x, got %02x\n", bFiller, pbTest[off]);
2270 }
2271 }
2272 else if (off + 2 <= cbLimit + 1)
2273 {
2274 /* [ig]tr.limit writing does not cause #GP, but may cause #PG, if not writing the base causes #GP. */
2275 if (off <= X86_PAGE_SIZE - 2)
2276 {
2277 if (pWorker->fSs)
2278 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2279 else
2280 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2281 if (Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
2282 Bs3TestFailedF("Mismatch (#16): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n",
2283 pbExpected, &pbTest[off], off);
2284 cb = X86_PAGE_SIZE - off - 2;
2285 if ( off < X86_PAGE_SIZE - 2
2286 && !ASMMemIsAllU8(&pbTest[off + 2], cb, bFiller))
2287 Bs3TestFailedF("Wrote partial base with limit (#16): bFiller=%#x, got %.*Rhxs; off=%#x\n",
2288 bFiller, cb, &pbTest[off + 2], off);
2289 }
2290 else
2291 {
2292 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
2293 uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
2294 if ( off < X86_PAGE_SIZE
2295 && !ASMMemIsAllU8(&pbTest[off], X86_PAGE_SIZE - off, bFiller))
2296 Bs3TestFailedF("Mismatch (#16): Partial limit write on #PF: bFiller=%#x, got %.*Rhxs\n",
2297 bFiller, X86_PAGE_SIZE - off, &pbTest[off]);
2298 }
2299 }
2300 else
2301 {
2302 /* #GP/#SS on limit. */
2303 if (pWorker->fSs)
2304 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2305 else
2306 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2307 if ( off < X86_PAGE_SIZE
2308 && !ASMMemIsAllU8(&pbTest[off], X86_PAGE_SIZE - off, bFiller))
2309 Bs3TestFailedF("Mismatch (#17): Partial write on #GP: bFiller=%#x, got %.*Rhxs\n",
2310 bFiller, X86_PAGE_SIZE - off, &pbTest[off]);
2311 }
2312
2313 cb = RT_MIN(cbIdtr * 2, off - (X86_PAGE_SIZE - cbIdtr*2));
2314 if (!ASMMemIsAllU8(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], cb, bFiller))
2315 Bs3TestFailedF("Leading bytes touched (#18): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n",
2316 cbIdtr, off, cbLimit, bFiller, cb, pbTest[X86_PAGE_SIZE - cbIdtr * 2]);
2317
2318 g_usBs3TestStep++;
2319
2320 /* Set DS to 0 and check that we get #GP(0). */
2321 if (!pWorker->fSs)
2322 {
2323 Ctx.ds = 0;
2324 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2325 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2326 Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2327 g_usBs3TestStep++;
2328 }
2329 }
2330 }
2331
2332 /* Expand down. */
2333 pbTest -= X86_PAGE_SIZE; /* Note! we're backing up a page to simplify things */
2334 uFlatTest -= X86_PAGE_SIZE;
2335
2336 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
2337 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
2338 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
2339 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
2340
2341 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2342 {
2343 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2344 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
2345 {
2346 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2347 Bs3MemSet(&pbTest[X86_PAGE_SIZE], bFiller, cbIdtr * 2);
2348 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2349 if (cbLimit < off && off >= X86_PAGE_SIZE)
2350 {
2351 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2352 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
2353 Bs3TestFailedF("Mismatch (#19): expected %.*Rhxs, got %.*Rhxs\n",
2354 cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
2355 cb = X86_PAGE_SIZE + cbIdtr*2 - off;
2356 if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], cb, bFiller))
2357 Bs3TestFailedF("Trailing bytes touched (#20): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n",
2358 cbIdtr, off, cbLimit, bFiller, cb, pbTest[off + cbIdtr]);
2359 }
2360 else
2361 {
2362 if (cbLimit < off && off < X86_PAGE_SIZE)
2363 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0),
2364 uFlatTest + off, 0 /*cbIpAdjust*/);
2365 else if (pWorker->fSs)
2366 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2367 else
2368 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2369 cb = cbIdtr*2;
2370 if (!ASMMemIsAllU8(&pbTest[X86_PAGE_SIZE], cb, bFiller))
2371 Bs3TestFailedF("Trailing bytes touched (#20): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n",
2372 cbIdtr, off, cbLimit, bFiller, cb, pbTest[X86_PAGE_SIZE]);
2373 }
2374 g_usBs3TestStep++;
2375 }
2376 }
2377
2378 pbTest += X86_PAGE_SIZE;
2379 uFlatTest += X86_PAGE_SIZE;
2380 }
2381
2382 Bs3MemGuardedTestPageFree(pbTest);
2383 }
2384
2385 /*
2386 * Check non-canonical 64-bit space.
2387 */
2388 if ( BS3_MODE_IS_64BIT_CODE(bTestMode)
2389 && (pbTest = (uint8_t BS3_FAR *)Bs3PagingSetupCanonicalTraps()) != NULL)
2390 {
2391 /* Make our references relative to the gap. */
2392 pbTest += g_cbBs3PagingOneCanonicalTrap;
2393
2394 /* Hit it from below. */
2395 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
2396 {
2397 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0x0000800000000000) + off;
2398 Bs3MemSet(&pbTest[-64], bFiller, 64*2);
2399 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2400 if (off + cbIdtr <= 0)
2401 {
2402 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2403 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
2404 Bs3TestFailedF("Mismatch (#21): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
2405 }
2406 else
2407 {
2408 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2409 if (off <= -2 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0)
2410 Bs3TestFailedF("Mismatch (#21): expected limit %.2Rhxs, got %.2Rhxs\n", pbExpected, &pbTest[off]);
2411 off2 = off <= -2 ? 2 : 0;
2412 cb = cbIdtr - off2;
2413 if (!ASMMemIsAllU8(&pbTest[off + off2], cb, bFiller))
2414 Bs3TestFailedF("Mismatch (#21): touched base %.*Rhxs, got %.*Rhxs\n",
2415 cb, &pbExpected[off], cb, &pbTest[off + off2]);
2416 }
2417 if (!ASMMemIsAllU8(&pbTest[off - 16], 16, bFiller))
2418 Bs3TestFailedF("Leading bytes touched (#21): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off]);
2419 if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], 16, bFiller))
2420 Bs3TestFailedF("Trailing bytes touched (#21): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off + cbIdtr]);
2421 }
2422
2423 /* Hit it from above. */
2424 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
2425 {
2426 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0xffff800000000000) + off;
2427 Bs3MemSet(&pbTest[-64], bFiller, 64*2);
2428 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2429 if (off >= 0)
2430 {
2431 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2432 if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0)
2433 Bs3TestFailedF("Mismatch (#22): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]);
2434 }
2435 else
2436 {
2437 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2438 if (!ASMMemIsAllU8(&pbTest[off], cbIdtr, bFiller))
2439 Bs3TestFailedF("Mismatch (#22): touched base %.*Rhxs, got %.*Rhxs\n",
2440 cbIdtr, &pbExpected[off], cbIdtr, &pbTest[off]);
2441 }
2442 if (!ASMMemIsAllU8(&pbTest[off - 16], 16, bFiller))
2443 Bs3TestFailedF("Leading bytes touched (#22): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off]);
2444 if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], 16, bFiller))
2445 Bs3TestFailedF("Trailing bytes touched (#22): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off + cbIdtr]);
2446 }
2447
2448 }
2449}
2450
2451
2452static void bs3CpuBasic2_sidt_sgdt_Common(uint8_t bTestMode, BS3CB2SIDTSGDT const BS3_FAR *paWorkers, unsigned cWorkers,
2453 uint8_t const *pbExpected)
2454{
2455 unsigned idx;
2456 unsigned bRing;
2457 unsigned iStep = 0;
2458
2459 /* Note! We skip the SS checks for ring-0 since we badly mess up SS in the
2460 test and don't want to bother with double faults. */
2461 for (bRing = 0; bRing <= 3; bRing++)
2462 {
2463 for (idx = 0; idx < cWorkers; idx++)
2464 if ( (paWorkers[idx].bMode & (bTestMode & BS3_MODE_CODE_MASK))
2465 && (!paWorkers[idx].fSs || bRing != 0 /** @todo || BS3_MODE_IS_64BIT_SYS(bTestMode)*/ ))
2466 {
2467 g_usBs3TestStep = iStep;
2468 bs3CpuBasic2_sidt_sgdt_One(&paWorkers[idx], bTestMode, bRing, pbExpected);
2469 iStep += 1000;
2470 }
2471 if (BS3_MODE_IS_RM_OR_V86(bTestMode))
2472 break;
2473 }
2474}
2475
2476
2477BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_sidt)(uint8_t bMode)
2478{
2479 union
2480 {
2481 RTIDTR Idtr;
2482 uint8_t ab[16];
2483 } Expected;
2484
2485 //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED;
2486 bs3CpuBasic2_SetGlobals(bMode);
2487
2488 /*
2489 * Pass to common worker which is only compiled once per mode.
2490 */
2491 Bs3MemZero(&Expected, sizeof(Expected));
2492 ASMGetIDTR(&Expected.Idtr);
2493 bs3CpuBasic2_sidt_sgdt_Common(bMode, g_aSidtWorkers, RT_ELEMENTS(g_aSidtWorkers), Expected.ab);
2494
2495 /*
2496 * Re-initialize the IDT.
2497 */
2498 Bs3TrapReInit();
2499 return 0;
2500}
2501
2502
2503BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_sgdt)(uint8_t bMode)
2504{
2505 uint64_t const uOrgAddr = Bs3Lgdt_Gdt.uAddr;
2506 uint64_t uNew = 0;
2507 union
2508 {
2509 RTGDTR Gdtr;
2510 uint8_t ab[16];
2511 } Expected;
2512
2513 //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED;
2514 bs3CpuBasic2_SetGlobals(bMode);
2515
2516 /*
2517 * If paged mode, try push the GDT way up.
2518 */
2519 Bs3MemZero(&Expected, sizeof(Expected));
2520 ASMGetGDTR(&Expected.Gdtr);
2521 if (BS3_MODE_IS_PAGED(bMode))
2522 {
2523/** @todo loading non-canonical base addresses. */
2524 int rc;
2525 uNew = BS3_MODE_IS_64BIT_SYS(bMode) ? UINT64_C(0xffff80fedcb70000) : UINT64_C(0xc2d28000);
2526 uNew |= uOrgAddr & X86_PAGE_OFFSET_MASK;
2527 rc = Bs3PagingAlias(uNew, uOrgAddr, Bs3Lgdt_Gdt.cb, X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_D | X86_PTE_A);
2528 if (RT_SUCCESS(rc))
2529 {
2530 Bs3Lgdt_Gdt.uAddr = uNew;
2531 Bs3UtilSetFullGdtr(Bs3Lgdt_Gdt.cb, uNew);
2532 ASMGetGDTR(&Expected.Gdtr);
2533 if (BS3_MODE_IS_64BIT_SYS(bMode) && ARCH_BITS != 64)
2534 *(uint32_t *)&Expected.ab[6] = (uint32_t)(uNew >> 32);
2535 }
2536 }
2537
2538 /*
2539 * Pass to common worker which is only compiled once per mode.
2540 */
2541 bs3CpuBasic2_sidt_sgdt_Common(bMode, g_aSgdtWorkers, RT_ELEMENTS(g_aSgdtWorkers), Expected.ab);
2542
2543 /*
2544 * Unalias the GDT.
2545 */
2546 if (uNew != 0)
2547 {
2548 Bs3Lgdt_Gdt.uAddr = uOrgAddr;
2549 Bs3UtilSetFullGdtr(Bs3Lgdt_Gdt.cb, uOrgAddr);
2550 Bs3PagingUnalias(uNew, Bs3Lgdt_Gdt.cb);
2551 }
2552
2553 /*
2554 * Re-initialize the IDT.
2555 */
2556 Bs3TrapReInit();
2557 return 0;
2558}
2559
2560
2561
2562/*
2563 * LIDT & LGDT
2564 */
2565
2566/**
2567 * Executes one round of LIDT and LGDT tests using one assembly worker.
2568 *
2569 * This is written with driving everything from the 16-bit or 32-bit worker in
2570 * mind, i.e. not assuming the test bitcount is the same as the current.
2571 */
2572static void bs3CpuBasic2_lidt_lgdt_One(BS3CB2SIDTSGDT const BS3_FAR *pWorker, uint8_t bTestMode, uint8_t bRing,
2573 uint8_t const *pbRestore, size_t cbRestore, uint8_t const *pbExpected)
2574{
2575 static const struct
2576 {
2577 bool fGP;
2578 uint16_t cbLimit;
2579 uint64_t u64Base;
2580 } s_aValues64[] =
2581 {
2582 { false, 0x0000, UINT64_C(0x0000000000000000) },
2583 { false, 0x0001, UINT64_C(0x0000000000000001) },
2584 { false, 0x0002, UINT64_C(0x0000000000000010) },
2585 { false, 0x0003, UINT64_C(0x0000000000000123) },
2586 { false, 0x0004, UINT64_C(0x0000000000001234) },
2587 { false, 0x0005, UINT64_C(0x0000000000012345) },
2588 { false, 0x0006, UINT64_C(0x0000000000123456) },
2589 { false, 0x0007, UINT64_C(0x0000000001234567) },
2590 { false, 0x0008, UINT64_C(0x0000000012345678) },
2591 { false, 0x0009, UINT64_C(0x0000000123456789) },
2592 { false, 0x000a, UINT64_C(0x000000123456789a) },
2593 { false, 0x000b, UINT64_C(0x00000123456789ab) },
2594 { false, 0x000c, UINT64_C(0x0000123456789abc) },
2595 { false, 0x001c, UINT64_C(0x00007ffffeefefef) },
2596 { false, 0xffff, UINT64_C(0x00007fffffffffff) },
2597 { true, 0xf3f1, UINT64_C(0x0000800000000000) },
2598 { true, 0x0000, UINT64_C(0x0000800000000000) },
2599 { true, 0x0000, UINT64_C(0x0000800000000333) },
2600 { true, 0x00f0, UINT64_C(0x0001000000000000) },
2601 { true, 0x0ff0, UINT64_C(0x0012000000000000) },
2602 { true, 0x0eff, UINT64_C(0x0123000000000000) },
2603 { true, 0xe0fe, UINT64_C(0x1234000000000000) },
2604 { true, 0x00ad, UINT64_C(0xffff300000000000) },
2605 { true, 0x0000, UINT64_C(0xffff7fffffffffff) },
2606 { true, 0x00f0, UINT64_C(0xffff7fffffffffff) },
2607 { false, 0x5678, UINT64_C(0xffff800000000000) },
2608 { false, 0x2969, UINT64_C(0xffffffffffeefefe) },
2609 { false, 0x1221, UINT64_C(0xffffffffffffffff) },
2610 { false, 0x1221, UINT64_C(0xffffffffffffffff) },
2611 };
2612 static const struct
2613 {
2614 uint16_t cbLimit;
2615 uint32_t u32Base;
2616 } s_aValues32[] =
2617 {
2618 { 0xdfdf, UINT32_C(0xefefefef) },
2619 { 0x0000, UINT32_C(0x00000000) },
2620 { 0x0001, UINT32_C(0x00000001) },
2621 { 0x0002, UINT32_C(0x00000012) },
2622 { 0x0003, UINT32_C(0x00000123) },
2623 { 0x0004, UINT32_C(0x00001234) },
2624 { 0x0005, UINT32_C(0x00012345) },
2625 { 0x0006, UINT32_C(0x00123456) },
2626 { 0x0007, UINT32_C(0x01234567) },
2627 { 0x0008, UINT32_C(0x12345678) },
2628 { 0x0009, UINT32_C(0x80204060) },
2629 { 0x000a, UINT32_C(0xddeeffaa) },
2630 { 0x000b, UINT32_C(0xfdecdbca) },
2631 { 0x000c, UINT32_C(0x6098456b) },
2632 { 0x000d, UINT32_C(0x98506099) },
2633 { 0x000e, UINT32_C(0x206950bc) },
2634 { 0x000f, UINT32_C(0x9740395d) },
2635 { 0x0334, UINT32_C(0x64a9455e) },
2636 { 0xb423, UINT32_C(0xd20b6eff) },
2637 { 0x4955, UINT32_C(0x85296d46) },
2638 { 0xffff, UINT32_C(0x07000039) },
2639 { 0xefe1, UINT32_C(0x0007fe00) },
2640 };
2641
2642 BS3TRAPFRAME TrapCtx;
2643 BS3REGCTX Ctx;
2644 BS3REGCTX CtxUdExpected;
2645 BS3REGCTX TmpCtx;
2646 uint8_t abBufLoad[40]; /* Test buffer w/ misalignment test space and some (cbIdtr) extra guard. */
2647 uint8_t abBufSave[32]; /* For saving the result after loading. */
2648 uint8_t abBufRestore[24]; /* For restoring sane value (same seg as abBufSave!). */
2649 uint8_t abExpectedFilled[32]; /* Same as pbExpected, except it's filled with bFiller2 instead of zeros. */
2650 uint8_t BS3_FAR *pbBufSave; /* Correctly aligned pointer into abBufSave. */
2651 uint8_t BS3_FAR *pbBufRestore; /* Correctly aligned pointer into abBufRestore. */
2652 uint8_t const cbIdtr = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 2+8 : 2+4;
2653 uint8_t const cbBaseLoaded = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 8
2654 : BS3_MODE_IS_16BIT_CODE(bTestMode) == !(pWorker->fFlags & BS3CB2SIDTSGDT_F_OPSIZE)
2655 ? 3 : 4;
2656 bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286;
2657 uint8_t const bTop16BitBase = f286 ? 0xff : 0x00;
2658 uint8_t bFiller1; /* For filling abBufLoad. */
2659 uint8_t bFiller2; /* For filling abBufSave and expectations. */
2660 int off;
2661 uint8_t BS3_FAR *pbTest;
2662 unsigned i;
2663
2664 /* make sure they're allocated */
2665 Bs3MemZero(&Ctx, sizeof(Ctx));
2666 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
2667 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
2668 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
2669 Bs3MemZero(abBufSave, sizeof(abBufSave));
2670 Bs3MemZero(abBufLoad, sizeof(abBufLoad));
2671 Bs3MemZero(abBufRestore, sizeof(abBufRestore));
2672
2673 /*
2674 * Create a context, giving this routine some more stack space.
2675 * - Point the context at our LIDT [xBX] + SIDT [xDI] + LIDT [xSI] + UD2 combo.
2676 * - Point DS/SS:xBX at abBufLoad.
2677 * - Point ES:xDI at abBufSave.
2678 * - Point ES:xSI at abBufRestore.
2679 */
2680 Bs3RegCtxSaveEx(&Ctx, bTestMode, 256 /*cbExtraStack*/);
2681 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pWorker->fpfnWorker);
2682 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
2683 g_uBs3TrapEipHint = Ctx.rip.u32;
2684 Ctx.rflags.u16 &= ~X86_EFL_IF;
2685 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad);
2686
2687 pbBufSave = abBufSave;
2688 if ((BS3_FP_OFF(pbBufSave) + 2) & 7)
2689 pbBufSave += 8 - ((BS3_FP_OFF(pbBufSave) + 2) & 7);
2690 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rdi, &Ctx.es, pbBufSave);
2691
2692 pbBufRestore = abBufRestore;
2693 if ((BS3_FP_OFF(pbBufRestore) + 2) & 7)
2694 pbBufRestore += 8 - ((BS3_FP_OFF(pbBufRestore) + 2) & 7);
2695 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsi, &Ctx.es, pbBufRestore);
2696 Bs3MemCpy(pbBufRestore, pbRestore, cbRestore);
2697
2698 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
2699 Bs3RegCtxConvertToRingX(&Ctx, bRing);
2700
2701 /* For successful SIDT attempts, we'll stop at the UD2. */
2702 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
2703 CtxUdExpected.rip.u += pWorker->cbInstr;
2704
2705 /*
2706 * Check that it works at all.
2707 */
2708 Bs3MemZero(abBufLoad, sizeof(abBufLoad));
2709 Bs3MemCpy(abBufLoad, pbBufRestore, cbIdtr);
2710 Bs3MemZero(abBufSave, sizeof(abBufSave));
2711 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2712 if (bRing != 0)
2713 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2714 else
2715 {
2716 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2717 if (Bs3MemCmp(pbBufSave, pbExpected, cbIdtr * 2) != 0)
2718 Bs3TestFailedF("Mismatch (%s, #1): expected %.*Rhxs, got %.*Rhxs\n",
2719 pWorker->pszDesc, cbIdtr*2, pbExpected, cbIdtr*2, pbBufSave);
2720 }
2721 g_usBs3TestStep++;
2722
2723 /* Determine two filler bytes that doesn't appear in the previous result or our expectations. */
2724 bFiller1 = ~0x55;
2725 while ( Bs3MemChr(pbBufSave, bFiller1, cbIdtr) != NULL
2726 || Bs3MemChr(pbRestore, bFiller1, cbRestore) != NULL
2727 || bFiller1 == 0xff)
2728 bFiller1++;
2729 bFiller2 = 0x33;
2730 while ( Bs3MemChr(pbBufSave, bFiller2, cbIdtr) != NULL
2731 || Bs3MemChr(pbRestore, bFiller2, cbRestore) != NULL
2732 || bFiller2 == 0xff
2733 || bFiller2 == bFiller1)
2734 bFiller2++;
2735 Bs3MemSet(abExpectedFilled, bFiller2, sizeof(abExpectedFilled));
2736 Bs3MemCpy(abExpectedFilled, pbExpected, cbIdtr);
2737
2738 /* Again with a buffer filled with a byte not occuring in the previous result. */
2739 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2740 Bs3MemCpy(abBufLoad, pbBufRestore, cbIdtr);
2741 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2742 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2743 if (bRing != 0)
2744 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2745 else
2746 {
2747 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2748 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2749 Bs3TestFailedF("Mismatch (%s, #2): expected %.*Rhxs, got %.*Rhxs\n",
2750 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2751 }
2752 g_usBs3TestStep++;
2753
2754 /*
2755 * Try loading a bunch of different limit+base value to check what happens,
2756 * especially what happens wrt the top part of the base in 16-bit mode.
2757 */
2758 if (BS3_MODE_IS_64BIT_CODE(bTestMode))
2759 {
2760 for (i = 0; i < RT_ELEMENTS(s_aValues64); i++)
2761 {
2762 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2763 Bs3MemCpy(&abBufLoad[0], &s_aValues64[i].cbLimit, 2);
2764 Bs3MemCpy(&abBufLoad[2], &s_aValues64[i].u64Base, 8);
2765 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2766 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2767 if (bRing != 0 || s_aValues64[i].fGP)
2768 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2769 else
2770 {
2771 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2772 if ( Bs3MemCmp(&pbBufSave[0], &s_aValues64[i].cbLimit, 2) != 0
2773 || Bs3MemCmp(&pbBufSave[2], &s_aValues64[i].u64Base, 8) != 0
2774 || !ASMMemIsAllU8(&pbBufSave[10], cbIdtr, bFiller2))
2775 Bs3TestFailedF("Mismatch (%s, #2): expected %04RX16:%016RX64, fillers %#x %#x, got %.*Rhxs\n",
2776 pWorker->pszDesc, s_aValues64[i].cbLimit, s_aValues64[i].u64Base,
2777 bFiller1, bFiller2, cbIdtr*2, pbBufSave);
2778 }
2779 g_usBs3TestStep++;
2780 }
2781 }
2782 else
2783 {
2784 for (i = 0; i < RT_ELEMENTS(s_aValues32); i++)
2785 {
2786 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2787 Bs3MemCpy(&abBufLoad[0], &s_aValues32[i].cbLimit, 2);
2788 Bs3MemCpy(&abBufLoad[2], &s_aValues32[i].u32Base, cbBaseLoaded);
2789 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2790 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2791 if (bRing != 0)
2792 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2793 else
2794 {
2795 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2796 if ( Bs3MemCmp(&pbBufSave[0], &s_aValues32[i].cbLimit, 2) != 0
2797 || Bs3MemCmp(&pbBufSave[2], &s_aValues32[i].u32Base, cbBaseLoaded) != 0
2798 || ( cbBaseLoaded != 4
2799 && pbBufSave[2+3] != bTop16BitBase)
2800 || !ASMMemIsAllU8(&pbBufSave[8], cbIdtr, bFiller2))
2801 Bs3TestFailedF("Mismatch (%s,#3): loaded %04RX16:%08RX32, fillers %#x %#x%s, got %.*Rhxs\n",
2802 pWorker->pszDesc, s_aValues32[i].cbLimit, s_aValues32[i].u32Base, bFiller1, bFiller2,
2803 f286 ? ", 286" : "", cbIdtr*2, pbBufSave);
2804 }
2805 g_usBs3TestStep++;
2806 }
2807 }
2808
2809 /*
2810 * Slide the buffer along 8 bytes to cover misalignment.
2811 */
2812 for (off = 0; off < 8; off++)
2813 {
2814 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &abBufLoad[off]);
2815 CtxUdExpected.rbx.u = Ctx.rbx.u;
2816
2817 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2818 Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr);
2819 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2820 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2821 if (bRing != 0)
2822 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2823 else
2824 {
2825 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2826 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2827 Bs3TestFailedF("Mismatch (%s, #4): expected %.*Rhxs, got %.*Rhxs\n",
2828 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2829 }
2830 g_usBs3TestStep++;
2831 }
2832 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad);
2833 CtxUdExpected.rbx.u = Ctx.rbx.u;
2834
2835 /*
2836 * Play with the selector limit if the target mode supports limit checking
2837 * We use BS3_SEL_TEST_PAGE_00 for this
2838 */
2839 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
2840 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
2841 {
2842 uint16_t cbLimit;
2843 uint32_t uFlatBuf = Bs3SelPtrToFlat(abBufLoad);
2844 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
2845 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
2846 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatBuf;
2847 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatBuf >> 16);
2848 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatBuf >> 24);
2849
2850 if (pWorker->fSs)
2851 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
2852 else
2853 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
2854
2855 /* Expand up (normal). */
2856 for (off = 0; off < 8; off++)
2857 {
2858 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2859 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
2860 {
2861 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2862
2863 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2864 Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr);
2865 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2866 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2867 if (bRing != 0)
2868 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2869 else if (off + cbIdtr <= cbLimit + 1)
2870 {
2871 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2872 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2873 Bs3TestFailedF("Mismatch (%s, #5): expected %.*Rhxs, got %.*Rhxs\n",
2874 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2875 }
2876 else if (pWorker->fSs)
2877 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2878 else
2879 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2880 g_usBs3TestStep++;
2881
2882 /* Again with zero limit and messed up base (should trigger tripple fault if partially loaded). */
2883 abBufLoad[off] = abBufLoad[off + 1] = 0;
2884 abBufLoad[off + 2] |= 1;
2885 abBufLoad[off + cbIdtr - 2] ^= 0x5a;
2886 abBufLoad[off + cbIdtr - 1] ^= 0xa5;
2887 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2888 if (bRing != 0)
2889 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2890 else if (off + cbIdtr <= cbLimit + 1)
2891 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2892 else if (pWorker->fSs)
2893 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2894 else
2895 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2896 }
2897 }
2898
2899 /* Expand down (weird). Inverted valid area compared to expand up,
2900 so a limit of zero give us a valid range for 0001..0ffffh (instead of
2901 a segment with one valid byte at 0000h). Whereas a limit of 0fffeh
2902 means one valid byte at 0ffffh, and a limit of 0ffffh means none
2903 (because in a normal expand up the 0ffffh means all 64KB are
2904 accessible). */
2905 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
2906 for (off = 0; off < 8; off++)
2907 {
2908 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
2909 for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++)
2910 {
2911 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
2912
2913 Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad));
2914 Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr);
2915 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2916 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2917 if (bRing != 0)
2918 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2919 else if (off > cbLimit)
2920 {
2921 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2922 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
2923 Bs3TestFailedF("Mismatch (%s, #6): expected %.*Rhxs, got %.*Rhxs\n",
2924 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2925 }
2926 else if (pWorker->fSs)
2927 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2928 else
2929 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2930 g_usBs3TestStep++;
2931
2932 /* Again with zero limit and messed up base (should trigger triple fault if partially loaded). */
2933 abBufLoad[off] = abBufLoad[off + 1] = 0;
2934 abBufLoad[off + 2] |= 3;
2935 abBufLoad[off + cbIdtr - 2] ^= 0x55;
2936 abBufLoad[off + cbIdtr - 1] ^= 0xaa;
2937 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2938 if (bRing != 0)
2939 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2940 else if (off > cbLimit)
2941 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2942 else if (pWorker->fSs)
2943 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
2944 else
2945 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2946 }
2947 }
2948
2949 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad);
2950 CtxUdExpected.rbx.u = Ctx.rbx.u;
2951 CtxUdExpected.ss = Ctx.ss;
2952 CtxUdExpected.ds = Ctx.ds;
2953 }
2954
2955 /*
2956 * Play with the paging.
2957 */
2958 if ( BS3_MODE_IS_PAGED(bTestMode)
2959 && (!pWorker->fSs || bRing == 3) /* SS.DPL == CPL, we'll get some tiled ring-3 selector here. */
2960 && (pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED)) != NULL)
2961 {
2962 RTCCUINTXREG uFlatTest = Bs3SelPtrToFlat(pbTest);
2963
2964 /*
2965 * Slide the load buffer towards the trailing guard page.
2966 */
2967 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[X86_PAGE_SIZE]);
2968 CtxUdExpected.ss = Ctx.ss;
2969 CtxUdExpected.ds = Ctx.ds;
2970 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
2971 {
2972 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller1, cbIdtr*2);
2973 if (off < X86_PAGE_SIZE)
2974 Bs3MemCpy(&pbTest[off], pbBufRestore, RT_MIN(X86_PAGE_SIZE - off, cbIdtr));
2975 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
2976 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
2977 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
2978 if (bRing != 0)
2979 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
2980 else if (off + cbIdtr <= X86_PAGE_SIZE)
2981 {
2982 CtxUdExpected.rbx = Ctx.rbx;
2983 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
2984 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr*2) != 0)
2985 Bs3TestFailedF("Mismatch (%s, #7): expected %.*Rhxs, got %.*Rhxs\n",
2986 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
2987 }
2988 else
2989 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
2990 g_usBs3TestStep++;
2991
2992 /* Again with zero limit and maybe messed up base as well (triple fault if buggy).
2993 The 386DX-40 here triple faults (or something) with off == 0xffe, nothing else. */
2994 if ( off < X86_PAGE_SIZE && off + cbIdtr > X86_PAGE_SIZE
2995 && ( off != X86_PAGE_SIZE - 2
2996 || (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) != BS3CPU_80386)
2997 )
2998 {
2999 pbTest[off] = 0;
3000 if (off + 1 < X86_PAGE_SIZE)
3001 pbTest[off + 1] = 0;
3002 if (off + 2 < X86_PAGE_SIZE)
3003 pbTest[off + 2] |= 7;
3004 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3005 if (bRing != 0)
3006 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3007 else
3008 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
3009 g_usBs3TestStep++;
3010 }
3011 }
3012
3013 /*
3014 * Now, do it the other way around. It should look normal now since writing
3015 * the limit will #PF first and nothing should be written.
3016 */
3017 for (off = cbIdtr + 4; off >= -cbIdtr - 4; off--)
3018 {
3019 Bs3MemSet(pbTest, bFiller1, 48);
3020 if (off >= 0)
3021 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
3022 else if (off + cbIdtr > 0)
3023 Bs3MemCpy(pbTest, &pbBufRestore[-off], cbIdtr + off);
3024 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]);
3025 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
3026 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3027 if (bRing != 0)
3028 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3029 else if (off >= 0)
3030 {
3031 CtxUdExpected.rbx = Ctx.rbx;
3032 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3033 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr*2) != 0)
3034 Bs3TestFailedF("Mismatch (%s, #8): expected %.*Rhxs, got %.*Rhxs\n",
3035 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
3036 }
3037 else
3038 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off, 0 /*cbIpAdjust*/);
3039 g_usBs3TestStep++;
3040
3041 /* Again with messed up base as well (triple fault if buggy). */
3042 if (off < 0 && off > -cbIdtr)
3043 {
3044 if (off + 2 >= 0)
3045 pbTest[off + 2] |= 15;
3046 pbTest[off + cbIdtr - 1] ^= 0xaa;
3047 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3048 if (bRing != 0)
3049 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3050 else
3051 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off, 0 /*cbIpAdjust*/);
3052 g_usBs3TestStep++;
3053 }
3054 }
3055
3056 /*
3057 * Combine paging and segment limit and check ordering.
3058 * This is kind of interesting here since it the instruction seems to
3059 * actually be doing two separate read, just like it's S[IG]DT counterpart.
3060 *
3061 * Note! My 486DX4 does a DWORD limit read when the operand size is 32-bit,
3062 * that's what f486Weirdness deals with.
3063 */
3064 if ( !BS3_MODE_IS_RM_OR_V86(bTestMode)
3065 && !BS3_MODE_IS_64BIT_CODE(bTestMode))
3066 {
3067 bool const f486Weirdness = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80486
3068 && BS3_MODE_IS_32BIT_CODE(bTestMode) == !(pWorker->fFlags & BS3CB2SIDTSGDT_F_OPSIZE);
3069 uint16_t cbLimit;
3070
3071 Bs3GdteTestPage00 = Bs3Gdte_DATA16;
3072 Bs3GdteTestPage00.Gen.u2Dpl = bRing;
3073 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
3074 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
3075 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
3076
3077 if (pWorker->fSs)
3078 CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing;
3079 else
3080 CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
3081
3082 /* Expand up (normal), approaching tail guard page. */
3083 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
3084 {
3085 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
3086 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
3087 {
3088 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
3089 Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller1, cbIdtr * 2);
3090 if (off < X86_PAGE_SIZE)
3091 Bs3MemCpy(&pbTest[off], pbBufRestore, RT_MIN(cbIdtr, X86_PAGE_SIZE - off));
3092 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
3093 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3094 if (bRing != 0)
3095 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3096 else if (off + cbIdtr <= cbLimit + 1)
3097 {
3098 /* No #GP, but maybe #PF. */
3099 if (off + cbIdtr <= X86_PAGE_SIZE)
3100 {
3101 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3102 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
3103 Bs3TestFailedF("Mismatch (%s, #9): expected %.*Rhxs, got %.*Rhxs\n",
3104 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
3105 }
3106 else
3107 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
3108 }
3109 /* No #GP/#SS on limit, but instead #PF? */
3110 else if ( !f486Weirdness
3111 ? off < cbLimit && off >= 0xfff
3112 : off + 2 < cbLimit && off >= 0xffd)
3113 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE), 0 /*cbIpAdjust*/);
3114 /* #GP/#SS on limit or base. */
3115 else if (pWorker->fSs)
3116 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
3117 else
3118 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3119
3120 g_usBs3TestStep++;
3121
3122 /* Set DS to 0 and check that we get #GP(0). */
3123 if (!pWorker->fSs)
3124 {
3125 Ctx.ds = 0;
3126 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3127 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3128 Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing;
3129 g_usBs3TestStep++;
3130 }
3131 }
3132 }
3133
3134 /* Expand down. */
3135 pbTest -= X86_PAGE_SIZE; /* Note! we're backing up a page to simplify things */
3136 uFlatTest -= X86_PAGE_SIZE;
3137
3138 Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC;
3139 Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest;
3140 Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16);
3141 Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24);
3142
3143 for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++)
3144 {
3145 CtxUdExpected.rbx.u = Ctx.rbx.u = off;
3146 for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++)
3147 {
3148 Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit;
3149 Bs3MemSet(&pbTest[X86_PAGE_SIZE], bFiller1, cbIdtr * 2);
3150 if (off >= X86_PAGE_SIZE)
3151 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
3152 else if (off > X86_PAGE_SIZE - cbIdtr)
3153 Bs3MemCpy(&pbTest[X86_PAGE_SIZE], &pbBufRestore[X86_PAGE_SIZE - off], cbIdtr - (X86_PAGE_SIZE - off));
3154 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
3155 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3156 if (bRing != 0)
3157 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3158 else if (cbLimit < off && off >= X86_PAGE_SIZE)
3159 {
3160 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3161 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
3162 Bs3TestFailedF("Mismatch (%s, #10): expected %.*Rhxs, got %.*Rhxs\n",
3163 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
3164 }
3165 else if (cbLimit < off && off < X86_PAGE_SIZE)
3166 bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off, 0 /*cbIpAdjust*/);
3167 else if (pWorker->fSs)
3168 bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/);
3169 else
3170 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3171 g_usBs3TestStep++;
3172 }
3173 }
3174
3175 pbTest += X86_PAGE_SIZE;
3176 uFlatTest += X86_PAGE_SIZE;
3177 }
3178
3179 Bs3MemGuardedTestPageFree(pbTest);
3180 }
3181
3182 /*
3183 * Check non-canonical 64-bit space.
3184 */
3185 if ( BS3_MODE_IS_64BIT_CODE(bTestMode)
3186 && (pbTest = (uint8_t BS3_FAR *)Bs3PagingSetupCanonicalTraps()) != NULL)
3187 {
3188 /* Make our references relative to the gap. */
3189 pbTest += g_cbBs3PagingOneCanonicalTrap;
3190
3191 /* Hit it from below. */
3192 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
3193 {
3194 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0x0000800000000000) + off;
3195 Bs3MemSet(&pbTest[-64], bFiller1, 64*2);
3196 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
3197 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
3198 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3199 if (off + cbIdtr > 0 || bRing != 0)
3200 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3201 else
3202 {
3203 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3204 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
3205 Bs3TestFailedF("Mismatch (%s, #11): expected %.*Rhxs, got %.*Rhxs\n",
3206 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
3207 }
3208 }
3209
3210 /* Hit it from above. */
3211 for (off = -cbIdtr - 8; off < cbIdtr + 8; off++)
3212 {
3213 Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0xffff800000000000) + off;
3214 Bs3MemSet(&pbTest[-64], bFiller1, 64*2);
3215 Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr);
3216 Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave));
3217 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3218 if (off < 0 || bRing != 0)
3219 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3220 else
3221 {
3222 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3223 if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0)
3224 Bs3TestFailedF("Mismatch (%s, #19): expected %.*Rhxs, got %.*Rhxs\n",
3225 pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave);
3226 }
3227 }
3228
3229 }
3230}
3231
3232
3233static void bs3CpuBasic2_lidt_lgdt_Common(uint8_t bTestMode, BS3CB2SIDTSGDT const BS3_FAR *paWorkers, unsigned cWorkers,
3234 void const *pvRestore, size_t cbRestore, uint8_t const *pbExpected)
3235{
3236 unsigned idx;
3237 unsigned bRing;
3238 unsigned iStep = 0;
3239
3240 /* Note! We skip the SS checks for ring-0 since we badly mess up SS in the
3241 test and don't want to bother with double faults. */
3242 for (bRing = BS3_MODE_IS_V86(bTestMode) ? 3 : 0; bRing <= 3; bRing++)
3243 {
3244 for (idx = 0; idx < cWorkers; idx++)
3245 if ( (paWorkers[idx].bMode & (bTestMode & BS3_MODE_CODE_MASK))
3246 && (!paWorkers[idx].fSs || bRing != 0 /** @todo || BS3_MODE_IS_64BIT_SYS(bTestMode)*/ )
3247 && ( !(paWorkers[idx].fFlags & BS3CB2SIDTSGDT_F_386PLUS)
3248 || ( bTestMode > BS3_MODE_PE16
3249 || ( bTestMode == BS3_MODE_PE16
3250 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)) ) )
3251 {
3252 //Bs3TestPrintf("idx=%-2d fpfnWorker=%p fSs=%d cbInstr=%d\n",
3253 // idx, paWorkers[idx].fpfnWorker, paWorkers[idx].fSs, paWorkers[idx].cbInstr);
3254 g_usBs3TestStep = iStep;
3255 bs3CpuBasic2_lidt_lgdt_One(&paWorkers[idx], bTestMode, bRing, pvRestore, cbRestore, pbExpected);
3256 iStep += 1000;
3257 }
3258 if (BS3_MODE_IS_RM_SYS(bTestMode))
3259 break;
3260 }
3261}
3262
3263
3264BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_lidt)(uint8_t bMode)
3265{
3266 union
3267 {
3268 RTIDTR Idtr;
3269 uint8_t ab[32]; /* At least cbIdtr*2! */
3270 } Expected;
3271
3272 //if (bMode != BS3_MODE_LM64) return 0;
3273 bs3CpuBasic2_SetGlobals(bMode);
3274
3275 /*
3276 * Pass to common worker which is only compiled once per mode.
3277 */
3278 Bs3MemZero(&Expected, sizeof(Expected));
3279 ASMGetIDTR(&Expected.Idtr);
3280
3281 if (BS3_MODE_IS_RM_SYS(bMode))
3282 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
3283 &Bs3Lidt_Ivt, sizeof(Bs3Lidt_Ivt), Expected.ab);
3284 else if (BS3_MODE_IS_16BIT_SYS(bMode))
3285 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
3286 &Bs3Lidt_Idt16, sizeof(Bs3Lidt_Idt16), Expected.ab);
3287 else if (BS3_MODE_IS_32BIT_SYS(bMode))
3288 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
3289 &Bs3Lidt_Idt32, sizeof(Bs3Lidt_Idt32), Expected.ab);
3290 else
3291 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers),
3292 &Bs3Lidt_Idt64, sizeof(Bs3Lidt_Idt64), Expected.ab);
3293
3294 /*
3295 * Re-initialize the IDT.
3296 */
3297 Bs3TrapReInit();
3298 return 0;
3299}
3300
3301
3302BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_lgdt)(uint8_t bMode)
3303{
3304 union
3305 {
3306 RTGDTR Gdtr;
3307 uint8_t ab[32]; /* At least cbIdtr*2! */
3308 } Expected;
3309
3310 //if (!BS3_MODE_IS_64BIT_SYS(bMode)) return 0;
3311 bs3CpuBasic2_SetGlobals(bMode);
3312
3313 /*
3314 * Pass to common worker which is only compiled once per mode.
3315 */
3316 if (BS3_MODE_IS_RM_SYS(bMode))
3317 ASMSetGDTR((PRTGDTR)&Bs3LgdtDef_Gdt);
3318 Bs3MemZero(&Expected, sizeof(Expected));
3319 ASMGetGDTR(&Expected.Gdtr);
3320
3321 bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLgdtWorkers, RT_ELEMENTS(g_aLgdtWorkers),
3322 &Bs3LgdtDef_Gdt, sizeof(Bs3LgdtDef_Gdt), Expected.ab);
3323
3324 /*
3325 * Re-initialize the IDT.
3326 */
3327 Bs3TrapReInit();
3328 return 0;
3329}
3330
3331typedef union IRETBUF
3332{
3333 uint64_t au64[6]; /* max req is 5 */
3334 uint32_t au32[12]; /* max req is 9 */
3335 uint16_t au16[24]; /* max req is 5 */
3336 uint8_t ab[48];
3337} IRETBUF;
3338typedef IRETBUF BS3_FAR *PIRETBUF;
3339
3340
3341static void iretbuf_SetupFrame(PIRETBUF pIretBuf, unsigned const cbPop,
3342 uint16_t uCS, uint64_t uPC, uint32_t fEfl, uint16_t uSS, uint64_t uSP)
3343{
3344 if (cbPop == 2)
3345 {
3346 pIretBuf->au16[0] = (uint16_t)uPC;
3347 pIretBuf->au16[1] = uCS;
3348 pIretBuf->au16[2] = (uint16_t)fEfl;
3349 pIretBuf->au16[3] = (uint16_t)uSP;
3350 pIretBuf->au16[4] = uSS;
3351 }
3352 else if (cbPop != 8)
3353 {
3354 pIretBuf->au32[0] = (uint32_t)uPC;
3355 pIretBuf->au16[1*2] = uCS;
3356 pIretBuf->au32[2] = (uint32_t)fEfl;
3357 pIretBuf->au32[3] = (uint32_t)uSP;
3358 pIretBuf->au16[4*2] = uSS;
3359 }
3360 else
3361 {
3362 pIretBuf->au64[0] = uPC;
3363 pIretBuf->au16[1*4] = uCS;
3364 pIretBuf->au64[2] = fEfl;
3365 pIretBuf->au64[3] = uSP;
3366 pIretBuf->au16[4*4] = uSS;
3367 }
3368}
3369
3370
3371static void bs3CpuBasic2_iret_Worker(uint8_t bTestMode, FPFNBS3FAR pfnIret, unsigned const cbPop,
3372 PIRETBUF pIretBuf, const char BS3_FAR *pszDesc)
3373{
3374 BS3TRAPFRAME TrapCtx;
3375 BS3REGCTX Ctx;
3376 BS3REGCTX CtxUdExpected;
3377 BS3REGCTX TmpCtx;
3378 BS3REGCTX TmpCtxExpected;
3379 uint8_t abLowUd[8];
3380 uint8_t abLowIret[8];
3381 FPFNBS3FAR pfnUdLow = (FPFNBS3FAR)abLowUd;
3382 FPFNBS3FAR pfnIretLow = (FPFNBS3FAR)abLowIret;
3383 unsigned const cbSameCplFrame = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 5*cbPop : 3*cbPop;
3384 bool const fUseLowCode = cbPop == 2 && !BS3_MODE_IS_16BIT_CODE(bTestMode);
3385 int iRingDst;
3386 int iRingSrc;
3387 uint16_t uDplSs;
3388 uint16_t uRplCs;
3389 uint16_t uRplSs;
3390// int i;
3391 uint8_t BS3_FAR *pbTest;
3392
3393 NOREF(abLowUd);
3394#define IRETBUF_SET_SEL(a_idx, a_uValue) \
3395 do { *(uint16_t)&pIretBuf->ab[a_idx * cbPop] = (a_uValue); } while (0)
3396#define IRETBUF_SET_REG(a_idx, a_uValue) \
3397 do { uint8_t const BS3_FAR *pbTmp = &pIretBuf->ab[a_idx * cbPop]; \
3398 if (cbPop == 2) *(uint16_t)pbTmp = (uint16_t)(a_uValue); \
3399 else if (cbPop != 8) *(uint32_t)pbTmp = (uint32_t)(a_uValue); \
3400 else *(uint64_t)pbTmp = (a_uValue); \
3401 } while (0)
3402
3403 /* make sure they're allocated */
3404 Bs3MemZero(&Ctx, sizeof(Ctx));
3405 Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected));
3406 Bs3MemZero(&TmpCtx, sizeof(TmpCtx));
3407 Bs3MemZero(&TmpCtxExpected, sizeof(TmpCtxExpected));
3408 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
3409
3410 /*
3411 * When dealing with 16-bit irets in 32-bit or 64-bit mode, we must have
3412 * copies of both iret and ud in the first 64KB of memory. The stack is
3413 * below 64KB, so we'll just copy the instructions onto the stack.
3414 */
3415 Bs3MemCpy(abLowUd, bs3CpuBasic2_ud2, 4);
3416 Bs3MemCpy(abLowIret, pfnIret, 4);
3417
3418 /*
3419 * Create a context (stack is irrelevant, we'll mainly be using pIretBuf).
3420 * - Point the context at our iret instruction.
3421 * - Point SS:xSP at pIretBuf.
3422 */
3423 Bs3RegCtxSaveEx(&Ctx, bTestMode, 0);
3424 if (!fUseLowCode)
3425 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pfnIret);
3426 else
3427 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, pfnIretLow);
3428 if (BS3_MODE_IS_16BIT_SYS(bTestMode))
3429 g_uBs3TrapEipHint = Ctx.rip.u32;
3430 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, pIretBuf);
3431
3432 /*
3433 * The first success (UD) context keeps the same code bit-count as the iret.
3434 */
3435 Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx));
3436 if (!fUseLowCode)
3437 Bs3RegCtxSetRipCsFromLnkPtr(&CtxUdExpected, bs3CpuBasic2_ud2);
3438 else
3439 Bs3RegCtxSetRipCsFromCurPtr(&CtxUdExpected, pfnUdLow);
3440 CtxUdExpected.rsp.u += cbSameCplFrame;
3441
3442 /*
3443 * Check that it works at all.
3444 */
3445 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3446 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3447
3448 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3449 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3450 g_usBs3TestStep++;
3451
3452 if (!BS3_MODE_IS_RM_OR_V86(bTestMode))
3453 {
3454 /* Selectors are modified when switching rings, so we need to know
3455 what we're dealing with there. */
3456 if ( !BS3_SEL_IS_IN_R0_RANGE(Ctx.cs) || !BS3_SEL_IS_IN_R0_RANGE(Ctx.ss)
3457 || !BS3_SEL_IS_IN_R0_RANGE(Ctx.ds) || !BS3_SEL_IS_IN_R0_RANGE(Ctx.es))
3458 Bs3TestFailedF("Expected R0 CS, SS, DS and ES; not %#x, %#x, %#x and %#x\n", Ctx.cs, Ctx.ss, Ctx.ds, Ctx.es);
3459 if (Ctx.fs || Ctx.gs)
3460 Bs3TestFailed("Expected R0 FS and GS to be 0!\n");
3461
3462 /*
3463 * Test returning to outer rings if protected mode.
3464 */
3465 Bs3MemCpy(&TmpCtx, &Ctx, sizeof(TmpCtx));
3466 Bs3MemCpy(&TmpCtxExpected, &CtxUdExpected, sizeof(TmpCtxExpected));
3467 for (iRingDst = 3; iRingDst >= 0; iRingDst--)
3468 {
3469 Bs3RegCtxConvertToRingX(&TmpCtxExpected, iRingDst);
3470 TmpCtxExpected.ds = iRingDst ? 0 : TmpCtx.ds;
3471 TmpCtx.es = TmpCtxExpected.es;
3472 iretbuf_SetupFrame(pIretBuf, cbPop, TmpCtxExpected.cs, TmpCtxExpected.rip.u,
3473 TmpCtxExpected.rflags.u32, TmpCtxExpected.ss, TmpCtxExpected.rsp.u);
3474 Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx);
3475 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected);
3476 g_usBs3TestStep++;
3477 }
3478
3479 /*
3480 * Check CS.RPL and SS.RPL.
3481 */
3482 for (iRingDst = 3; iRingDst >= 0; iRingDst--)
3483 {
3484 uint16_t const uDstSsR0 = (CtxUdExpected.ss & BS3_SEL_RING_SUB_MASK) + BS3_SEL_R0_FIRST;
3485 Bs3MemCpy(&TmpCtxExpected, &CtxUdExpected, sizeof(TmpCtxExpected));
3486 Bs3RegCtxConvertToRingX(&TmpCtxExpected, iRingDst);
3487 for (iRingSrc = 3; iRingSrc >= 0; iRingSrc--)
3488 {
3489 Bs3MemCpy(&TmpCtx, &Ctx, sizeof(TmpCtx));
3490 Bs3RegCtxConvertToRingX(&TmpCtx, iRingSrc);
3491 TmpCtx.es = TmpCtxExpected.es;
3492 TmpCtxExpected.ds = iRingDst != iRingSrc ? 0 : TmpCtx.ds;
3493 for (uRplCs = 0; uRplCs <= 3; uRplCs++)
3494 {
3495 uint16_t const uSrcEs = TmpCtx.es;
3496 uint16_t const uDstCs = (TmpCtxExpected.cs & X86_SEL_MASK_OFF_RPL) | uRplCs;
3497 //Bs3TestPrintf("dst=%d src=%d rplCS=%d\n", iRingDst, iRingSrc, uRplCs);
3498
3499 /* CS.RPL */
3500 iretbuf_SetupFrame(pIretBuf, cbPop, uDstCs, TmpCtxExpected.rip.u, TmpCtxExpected.rflags.u32,
3501 TmpCtxExpected.ss, TmpCtxExpected.rsp.u);
3502 Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx);
3503 if (uRplCs == iRingDst && iRingDst >= iRingSrc)
3504 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected);
3505 else
3506 {
3507 if (iRingDst < iRingSrc)
3508 TmpCtx.es = 0;
3509 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstCs & X86_SEL_MASK_OFF_RPL);
3510 TmpCtx.es = uSrcEs;
3511 }
3512 g_usBs3TestStep++;
3513
3514 /* SS.RPL */
3515 if (iRingDst != iRingSrc || BS3_MODE_IS_64BIT_CODE(bTestMode))
3516 {
3517 uint16_t uSavedDstSs = TmpCtxExpected.ss;
3518 for (uRplSs = 0; uRplSs <= 3; uRplSs++)
3519 {
3520 /* SS.DPL (iRingDst == CS.DPL) */
3521 for (uDplSs = 0; uDplSs <= 3; uDplSs++)
3522 {
3523 uint16_t const uDstSs = ((uDplSs << BS3_SEL_RING_SHIFT) | uRplSs) + uDstSsR0;
3524 //Bs3TestPrintf("dst=%d src=%d rplCS=%d rplSS=%d dplSS=%d dst %04x:%08RX64 %08RX32 %04x:%08RX64\n",
3525 // iRingDst, iRingSrc, uRplCs, uRplSs, uDplSs, uDstCs, TmpCtxExpected.rip.u,
3526 // TmpCtxExpected.rflags.u32, uDstSs, TmpCtxExpected.rsp.u);
3527
3528 iretbuf_SetupFrame(pIretBuf, cbPop, uDstCs, TmpCtxExpected.rip.u,
3529 TmpCtxExpected.rflags.u32, uDstSs, TmpCtxExpected.rsp.u);
3530 Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx);
3531 if (uRplCs != iRingDst || iRingDst < iRingSrc)
3532 {
3533 if (iRingDst < iRingSrc)
3534 TmpCtx.es = 0;
3535 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstCs & X86_SEL_MASK_OFF_RPL);
3536 }
3537 else if (uRplSs != iRingDst || uDplSs != iRingDst)
3538 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstSs & X86_SEL_MASK_OFF_RPL);
3539 else
3540 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected);
3541 TmpCtx.es = uSrcEs;
3542 g_usBs3TestStep++;
3543 }
3544 }
3545
3546 TmpCtxExpected.ss = uSavedDstSs;
3547 }
3548 }
3549 }
3550 }
3551 }
3552
3553 /*
3554 * Special 64-bit checks.
3555 */
3556 if (BS3_MODE_IS_64BIT_CODE(bTestMode))
3557 {
3558 /* The VM flag is completely ignored. */
3559 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3560 CtxUdExpected.rflags.u32 | X86_EFL_VM, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3561 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3562 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3563 g_usBs3TestStep++;
3564
3565 /* The NT flag can be loaded just fine. */
3566 CtxUdExpected.rflags.u32 |= X86_EFL_NT;
3567 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3568 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3569 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3570 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected);
3571 CtxUdExpected.rflags.u32 &= ~X86_EFL_NT;
3572 g_usBs3TestStep++;
3573
3574 /* However, we'll #GP(0) if it's already set (in RFLAGS) when executing IRET. */
3575 Ctx.rflags.u32 |= X86_EFL_NT;
3576 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3577 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3578 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3579 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3580 g_usBs3TestStep++;
3581
3582 /* The NT flag #GP(0) should trump all other exceptions - pit it against #PF. */
3583 pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED);
3584 if (pbTest != NULL)
3585 {
3586 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, &pbTest[X86_PAGE_SIZE]);
3587 iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u,
3588 CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u);
3589 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3590 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0);
3591 g_usBs3TestStep++;
3592
3593 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, pIretBuf);
3594 Bs3MemGuardedTestPageFree(pbTest);
3595 }
3596 Ctx.rflags.u32 &= ~X86_EFL_NT;
3597 }
3598}
3599
3600
3601BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_iret)(uint8_t bMode)
3602{
3603 struct
3604 {
3605 uint8_t abExtraStack[4096]; /**< we've got ~30KB of stack, so 4KB for the trap handlers++ is not a problem. */
3606 IRETBUF IRetBuf;
3607 uint8_t abGuard[32];
3608 } uBuf;
3609 size_t cbUnused;
3610
3611 //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED;
3612 bs3CpuBasic2_SetGlobals(bMode);
3613
3614 /*
3615 * Primary instruction form.
3616 */
3617 Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf));
3618 Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard));
3619 if (BS3_MODE_IS_16BIT_CODE(bMode))
3620 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 2, &uBuf.IRetBuf, "iret");
3621 else if (BS3_MODE_IS_32BIT_CODE(bMode))
3622 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 4, &uBuf.IRetBuf, "iretd");
3623 else
3624 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_rexw, 8, &uBuf.IRetBuf, "o64 iret");
3625
3626 BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88));
3627 cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa)
3628 - (uintptr_t)uBuf.abExtraStack;
3629 if (cbUnused < 2048)
3630 Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 1);
3631
3632 /*
3633 * Secondary variation: opsize prefixed.
3634 */
3635 Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf));
3636 Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard));
3637 if (BS3_MODE_IS_16BIT_CODE(bMode) && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
3638 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 4, &uBuf.IRetBuf, "o32 iret");
3639 else if (BS3_MODE_IS_32BIT_CODE(bMode))
3640 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 2, &uBuf.IRetBuf, "o16 iret");
3641 else if (BS3_MODE_IS_64BIT_CODE(bMode))
3642 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 4, &uBuf.IRetBuf, "iretd");
3643 BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88));
3644 cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa)
3645 - (uintptr_t)uBuf.abExtraStack;
3646 if (cbUnused < 2048)
3647 Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 2);
3648
3649 /*
3650 * Third variation: 16-bit in 64-bit mode (truly unlikely)
3651 */
3652 if (BS3_MODE_IS_64BIT_CODE(bMode))
3653 {
3654 Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf));
3655 Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard));
3656 bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 2, &uBuf.IRetBuf, "o16 iret");
3657 BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88));
3658 cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa)
3659 - (uintptr_t)uBuf.abExtraStack;
3660 if (cbUnused < 2048)
3661 Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 3);
3662 }
3663
3664 return 0;
3665}
3666
3667
3668
3669/*********************************************************************************************************************************
3670* Non-far JMP & CALL Tests *
3671*********************************************************************************************************************************/
3672#define PROTO_ALL(a_Template) \
3673 FNBS3FAR a_Template ## _c16, \
3674 a_Template ## _c32, \
3675 a_Template ## _c64
3676PROTO_ALL(bs3CpuBasic2_jmp_jb__ud2);
3677PROTO_ALL(bs3CpuBasic2_jmp_jb_back__ud2);
3678PROTO_ALL(bs3CpuBasic2_jmp_jv__ud2);
3679PROTO_ALL(bs3CpuBasic2_jmp_jv_back__ud2);
3680PROTO_ALL(bs3CpuBasic2_jmp_ind_mem__ud2);
3681PROTO_ALL(bs3CpuBasic2_jmp_ind_xAX__ud2);
3682PROTO_ALL(bs3CpuBasic2_jmp_ind_xDI__ud2);
3683FNBS3FAR bs3CpuBasic2_jmp_ind_r9__ud2_c64;
3684PROTO_ALL(bs3CpuBasic2_call_jv__ud2);
3685PROTO_ALL(bs3CpuBasic2_call_jv_back__ud2);
3686PROTO_ALL(bs3CpuBasic2_call_ind_mem__ud2);
3687PROTO_ALL(bs3CpuBasic2_call_ind_xAX__ud2);
3688PROTO_ALL(bs3CpuBasic2_call_ind_xDI__ud2);
3689FNBS3FAR bs3CpuBasic2_call_ind_r9__ud2_c64;
3690
3691PROTO_ALL(bs3CpuBasic2_jmp_opsize_begin);
3692PROTO_ALL(bs3CpuBasic2_jmp_jb_opsize__ud2);
3693PROTO_ALL(bs3CpuBasic2_jmp_jb_opsize_back__ud2);
3694PROTO_ALL(bs3CpuBasic2_jmp_jv_opsize__ud2);
3695PROTO_ALL(bs3CpuBasic2_jmp_jv_opsize_back__ud2);
3696PROTO_ALL(bs3CpuBasic2_jmp_ind_mem_opsize__ud2);
3697FNBS3FAR bs3CpuBasic2_jmp_ind_mem_opsize__ud2__intel_c64;
3698PROTO_ALL(bs3CpuBasic2_jmp_ind_xAX_opsize__ud2);
3699PROTO_ALL(bs3CpuBasic2_call_jv_opsize__ud2);
3700PROTO_ALL(bs3CpuBasic2_call_jv_opsize_back__ud2);
3701PROTO_ALL(bs3CpuBasic2_call_ind_mem_opsize__ud2);
3702FNBS3FAR bs3CpuBasic2_call_ind_mem_opsize__ud2__intel_c64;
3703PROTO_ALL(bs3CpuBasic2_call_ind_xAX_opsize__ud2);
3704PROTO_ALL(bs3CpuBasic2_jmp_opsize_end);
3705#undef PROTO_ALL
3706
3707FNBS3FAR bs3CpuBasic2_jmptext16_start;
3708
3709FNBS3FAR bs3CpuBasic2_jmp_target_wrap_forward;
3710FNBS3FAR bs3CpuBasic2_jmp_jb_wrap_forward__ud2;
3711FNBS3FAR bs3CpuBasic2_jmp_jb_opsize_wrap_forward__ud2;
3712FNBS3FAR bs3CpuBasic2_jmp_jv16_wrap_forward__ud2;
3713FNBS3FAR bs3CpuBasic2_jmp_jv16_opsize_wrap_forward__ud2;
3714FNBS3FAR bs3CpuBasic2_call_jv16_wrap_forward__ud2;
3715FNBS3FAR bs3CpuBasic2_call_jv16_opsize_wrap_forward__ud2;
3716
3717FNBS3FAR bs3CpuBasic2_jmp_target_wrap_backward;
3718FNBS3FAR bs3CpuBasic2_jmp_jb_wrap_backward__ud2;
3719FNBS3FAR bs3CpuBasic2_jmp_jb_opsize_wrap_backward__ud2;
3720FNBS3FAR bs3CpuBasic2_jmp_jv16_wrap_backward__ud2;
3721FNBS3FAR bs3CpuBasic2_jmp_jv16_opsize_wrap_backward__ud2;
3722FNBS3FAR bs3CpuBasic2_call_jv16_wrap_backward__ud2;
3723FNBS3FAR bs3CpuBasic2_call_jv16_opsize_wrap_backward__ud2;
3724
3725
3726
3727/**
3728 * Entrypoint for non-far JMP & CALL tests.
3729 *
3730 * @returns 0 or BS3TESTDOMODE_SKIPPED.
3731 * @param bMode The CPU mode we're testing.
3732 *
3733 * @note When testing v8086 code, we'll be running in v8086 mode. So, careful
3734 * with control registers and such.
3735 */
3736BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_jmp_call)(uint8_t bMode)
3737{
3738 BS3TRAPFRAME TrapCtx;
3739 BS3REGCTX Ctx;
3740 BS3REGCTX CtxExpected;
3741 unsigned iTest;
3742
3743 /* make sure they're allocated */
3744 Bs3MemZero(&Ctx, sizeof(Ctx));
3745 Bs3MemZero(&CtxExpected, sizeof(Ctx));
3746 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
3747
3748 bs3CpuBasic2_SetGlobals(bMode);
3749
3750 /*
3751 * Create a context.
3752 */
3753 Bs3RegCtxSaveEx(&Ctx, bMode, 768);
3754 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
3755
3756 /*
3757 * 16-bit tests.
3758 *
3759 * When opsize is 16-bit relative jumps will do 16-bit calculations and
3760 * modify IP. This means that it is not possible to trigger a segment
3761 * limit #GP(0) when the limit is set to 0xffff.
3762 */
3763 if (BS3_MODE_IS_16BIT_CODE(bMode))
3764 {
3765 static struct
3766 {
3767 int8_t iWrap;
3768 bool fOpSizePfx;
3769 int8_t iGprIndirect;
3770 bool fCall;
3771 FPFNBS3FAR pfnTest;
3772 }
3773 const s_aTests[] =
3774 {
3775 { 0, false, -1, false, bs3CpuBasic2_jmp_jb__ud2_c16, },
3776 { 0, false, -1, false, bs3CpuBasic2_jmp_jb_back__ud2_c16, },
3777 { 0, true, -1, false, bs3CpuBasic2_jmp_jb_opsize__ud2_c16, },
3778 { 0, true, -1, false, bs3CpuBasic2_jmp_jb_opsize_back__ud2_c16, },
3779 { 0, false, -1, false, bs3CpuBasic2_jmp_jv__ud2_c16, },
3780 { 0, false, -1, false, bs3CpuBasic2_jmp_jv_back__ud2_c16, },
3781 { 0, true, -1, false, bs3CpuBasic2_jmp_jv_opsize__ud2_c16, },
3782 { 0, true, -1, false, bs3CpuBasic2_jmp_jv_opsize_back__ud2_c16, },
3783 { 0, false, -1, false, bs3CpuBasic2_jmp_ind_mem__ud2_c16, },
3784 { 0, true, -1, false, bs3CpuBasic2_jmp_ind_mem_opsize__ud2_c16, },
3785 { 0, false, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX__ud2_c16, },
3786 { 0, false, X86_GREG_xDI, false, bs3CpuBasic2_jmp_ind_xDI__ud2_c16, },
3787 { 0, true, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX_opsize__ud2_c16, },
3788 { 0, false, -1, true, bs3CpuBasic2_call_jv__ud2_c16, },
3789 { 0, false, -1, true, bs3CpuBasic2_call_jv_back__ud2_c16, },
3790 { 0, true, -1, true, bs3CpuBasic2_call_jv_opsize__ud2_c16, },
3791 { 0, true, -1, true, bs3CpuBasic2_call_jv_opsize_back__ud2_c16, },
3792 { 0, false, -1, true, bs3CpuBasic2_call_ind_mem__ud2_c16, },
3793 { 0, true, -1, true, bs3CpuBasic2_call_ind_mem_opsize__ud2_c16, },
3794 { 0, false, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX__ud2_c16, },
3795 { 0, false, X86_GREG_xDI, true, bs3CpuBasic2_call_ind_xDI__ud2_c16, },
3796 { 0, true, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX_opsize__ud2_c16, },
3797
3798 { -1, false, -1, false, bs3CpuBasic2_jmp_jb_wrap_backward__ud2, },
3799 { +1, false, -1, false, bs3CpuBasic2_jmp_jb_wrap_forward__ud2, },
3800 { -1, true, -1, false, bs3CpuBasic2_jmp_jb_opsize_wrap_backward__ud2, },
3801 { +1, true, -1, false, bs3CpuBasic2_jmp_jb_opsize_wrap_forward__ud2, },
3802
3803 { -1, false, -1, false, bs3CpuBasic2_jmp_jv16_wrap_backward__ud2, },
3804 { +1, false, -1, false, bs3CpuBasic2_jmp_jv16_wrap_forward__ud2, },
3805 { -1, true, -1, false, bs3CpuBasic2_jmp_jv16_opsize_wrap_backward__ud2, },
3806 { +1, true, -1, false, bs3CpuBasic2_jmp_jv16_opsize_wrap_forward__ud2, },
3807 { -1, false, -1, true, bs3CpuBasic2_call_jv16_wrap_backward__ud2, },
3808 { +1, false, -1, true, bs3CpuBasic2_call_jv16_wrap_forward__ud2, },
3809 { -1, true, -1, true, bs3CpuBasic2_call_jv16_opsize_wrap_backward__ud2, },
3810 { +1, true, -1, true, bs3CpuBasic2_call_jv16_opsize_wrap_forward__ud2, },
3811 };
3812
3813 if (!BS3_MODE_IS_RM_OR_V86(bMode))
3814 Bs3SelSetup16BitCode(&Bs3GdteSpare03, Bs3SelLnkPtrToFlat(bs3CpuBasic2_jmptext16_start), 0);
3815
3816 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
3817 {
3818 uint64_t uGprSaved;
3819 if (s_aTests[iTest].iWrap == 0)
3820 {
3821 uint8_t const BS3_FAR *fpbCode;
3822 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
3823 fpbCode = (uint8_t const BS3_FAR *)BS3_FP_MAKE(Ctx.cs, Ctx.rip.u16);
3824 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
3825 }
3826 else
3827 {
3828 if (BS3_MODE_IS_RM_OR_V86(bMode))
3829 Ctx.cs = BS3_FP_SEG(s_aTests[iTest].pfnTest);
3830 else
3831 Ctx.cs = BS3_SEL_SPARE_03;
3832 Ctx.rip.u = BS3_FP_OFF(s_aTests[iTest].pfnTest);
3833 if (s_aTests[iTest].fOpSizePfx)
3834 CtxExpected.rip.u = Ctx.rip.u;
3835 else if (s_aTests[iTest].iWrap < 0)
3836 CtxExpected.rip.u = BS3_FP_OFF(bs3CpuBasic2_jmp_target_wrap_backward);
3837 else
3838 CtxExpected.rip.u = BS3_FP_OFF(bs3CpuBasic2_jmp_target_wrap_forward);
3839 }
3840 CtxExpected.cs = Ctx.cs;
3841 if (s_aTests[iTest].iGprIndirect >= 0)
3842 {
3843 uGprSaved = (&Ctx.rax)[s_aTests[iTest].iGprIndirect].u;
3844 (&Ctx.rax)[s_aTests[iTest].iGprIndirect].u
3845 = (&CtxExpected.rax)[s_aTests[iTest].iGprIndirect].u = CtxExpected.rip.u;
3846 }
3847 CtxExpected.rsp.u = Ctx.rsp.u;
3848 if (s_aTests[iTest].fCall && (s_aTests[iTest].iWrap == 0 || !s_aTests[iTest].fOpSizePfx))
3849 CtxExpected.rsp.u -= s_aTests[iTest].fOpSizePfx ? 4 : 2;
3850 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u);
3851
3852 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3853 if (s_aTests[iTest].iWrap == 0 || !s_aTests[iTest].fOpSizePfx)
3854 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
3855 else
3856 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, 0);
3857 g_usBs3TestStep++;
3858
3859 /* Again single stepping: */
3860 //Bs3TestPrintf("stepping...\n");
3861 Bs3RegSetDr6(0);
3862 Ctx.rflags.u16 |= X86_EFL_TF;
3863 CtxExpected.rflags.u16 = Ctx.rflags.u16;
3864 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3865 if (s_aTests[iTest].iWrap == 0 || !s_aTests[iTest].fOpSizePfx)
3866 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
3867 else
3868 {
3869 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, 0);
3870 bs3CpuBasic2_CheckDr6InitVal();
3871 }
3872 Ctx.rflags.u16 &= ~X86_EFL_TF;
3873 CtxExpected.rflags.u16 = Ctx.rflags.u16;
3874 g_usBs3TestStep++;
3875
3876 if (s_aTests[iTest].iGprIndirect >= 0)
3877 (&Ctx.rax)[s_aTests[iTest].iGprIndirect].u = (&CtxExpected.rax)[s_aTests[iTest].iGprIndirect].u = uGprSaved;
3878 }
3879
3880 /* Limit the wraparound CS segment to exclude bs3CpuBasic2_jmp_target_wrap_backward
3881 and run the backward wrapping tests. */
3882 if (!BS3_MODE_IS_RM_OR_V86(bMode))
3883 {
3884 Bs3GdteSpare03.Gen.u16LimitLow = BS3_FP_OFF(bs3CpuBasic2_jmp_target_wrap_backward) - 1;
3885 CtxExpected.cs = Ctx.cs = BS3_SEL_SPARE_03;
3886 CtxExpected.rsp.u = Ctx.rsp.u;
3887 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
3888 if (s_aTests[iTest].iWrap < 0)
3889 {
3890 CtxExpected.rip.u = Ctx.rip.u = BS3_FP_OFF(s_aTests[iTest].pfnTest);
3891 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 v1\n", Ctx.cs, Ctx.rip.u);
3892 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3893 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, 0);
3894 g_usBs3TestStep++;
3895 }
3896
3897 /* Do another round where we put the limit in the middle of the UD2
3898 instruction we're jumping to: */
3899 Bs3GdteSpare03.Gen.u16LimitLow = BS3_FP_OFF(bs3CpuBasic2_jmp_target_wrap_backward);
3900 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
3901 if (s_aTests[iTest].iWrap < 0)
3902 {
3903 Ctx.rip.u = BS3_FP_OFF(s_aTests[iTest].pfnTest);
3904 if (s_aTests[iTest].fOpSizePfx)
3905 CtxExpected.rip.u = Ctx.rip.u;
3906 else
3907 CtxExpected.rip.u = BS3_FP_OFF(bs3CpuBasic2_jmp_target_wrap_backward);
3908 CtxExpected.rsp.u = Ctx.rsp.u;
3909 if (s_aTests[iTest].fCall && (s_aTests[iTest].iWrap == 0 || !s_aTests[iTest].fOpSizePfx))
3910 CtxExpected.rsp.u -= s_aTests[iTest].fOpSizePfx ? 4 : 2;
3911 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 v2\n", Ctx.cs, Ctx.rip.u);
3912 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
3913 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, 0);
3914 g_usBs3TestStep++;
3915 }
3916 }
3917
3918 }
3919 /*
3920 * 32-bit & 64-bit tests.
3921 *
3922 * When the opsize prefix is applied here, IP is updated and bits 63:16
3923 * cleared. However in 64-bit mode, Intel ignores the opsize prefix
3924 * whereas AMD doesn't and it works like you expect.
3925 */
3926 else
3927 {
3928 static struct
3929 {
3930 uint8_t cBits;
3931 bool fOpSizePfx;
3932 bool fIgnPfx;
3933 int8_t iGprIndirect;
3934 bool fCall;
3935 FPFNBS3FAR pfnTest;
3936 }
3937 const s_aTests[] =
3938 {
3939 { 32, false, false, -1, false, bs3CpuBasic2_jmp_jb__ud2_c32, },
3940 { 32, false, false, -1, false, bs3CpuBasic2_jmp_jb_back__ud2_c32, },
3941 { 32, true, false, -1, false, bs3CpuBasic2_jmp_jb_opsize__ud2_c32, },
3942 { 32, true, false, -1, false, bs3CpuBasic2_jmp_jb_opsize_back__ud2_c32, },
3943 { 32, false, false, -1, false, bs3CpuBasic2_jmp_jv__ud2_c32, },
3944 { 32, false, false, -1, false, bs3CpuBasic2_jmp_jv_back__ud2_c32, },
3945 { 32, true, false, -1, false, bs3CpuBasic2_jmp_jv_opsize__ud2_c32, },
3946 { 32, true, false, -1, false, bs3CpuBasic2_jmp_jv_opsize_back__ud2_c32, },
3947 { 32, false, false, -1, false, bs3CpuBasic2_jmp_ind_mem__ud2_c32, },
3948 { 32, true, false, -1, false, bs3CpuBasic2_jmp_ind_mem_opsize__ud2_c32, },
3949 { 32, false, false, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX__ud2_c32, },
3950 { 32, false, false, X86_GREG_xDI, false, bs3CpuBasic2_jmp_ind_xDI__ud2_c32, },
3951 { 32, true, false, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX_opsize__ud2_c32, },
3952 { 32, false, false, -1, true, bs3CpuBasic2_call_jv__ud2_c32, },
3953 { 32, false, false, -1, true, bs3CpuBasic2_call_jv_back__ud2_c32, },
3954 { 32, true, false, -1, true, bs3CpuBasic2_call_jv_opsize__ud2_c32, },
3955 { 32, true, false, -1, true, bs3CpuBasic2_call_jv_opsize_back__ud2_c32, },
3956 { 32, false, false, -1, true, bs3CpuBasic2_call_ind_mem__ud2_c32, },
3957 { 32, true, false, -1, true, bs3CpuBasic2_call_ind_mem_opsize__ud2_c32, },
3958 { 32, false, false, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX__ud2_c32, },
3959 { 32, false, false, X86_GREG_xDI, true, bs3CpuBasic2_call_ind_xDI__ud2_c32, },
3960 { 32, true, false, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX_opsize__ud2_c32, },
3961 /* 64bit/Intel: Use the _c64 tests, which are written to ignore the o16 prefix. */
3962 { 64, false, true, -1, false, bs3CpuBasic2_jmp_jb__ud2_c64, },
3963 { 64, false, true, -1, false, bs3CpuBasic2_jmp_jb_back__ud2_c64, },
3964 { 64, true, true, -1, false, bs3CpuBasic2_jmp_jb_opsize__ud2_c64, },
3965 { 64, true, true, -1, false, bs3CpuBasic2_jmp_jb_opsize_back__ud2_c64, },
3966 { 64, false, true, -1, false, bs3CpuBasic2_jmp_jv__ud2_c64, },
3967 { 64, false, true, -1, false, bs3CpuBasic2_jmp_jv_back__ud2_c64, },
3968 { 64, true, true, -1, false, bs3CpuBasic2_jmp_jv_opsize__ud2_c64, },
3969 { 64, true, true, -1, false, bs3CpuBasic2_jmp_jv_opsize_back__ud2_c64, },
3970 { 64, false, true, -1, false, bs3CpuBasic2_jmp_ind_mem__ud2_c64, },
3971 { 64, true, true, -1, false, bs3CpuBasic2_jmp_ind_mem_opsize__ud2__intel_c64, },
3972 { 64, false, true, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX__ud2_c64, },
3973 { 64, false, true, X86_GREG_xDI, false, bs3CpuBasic2_jmp_ind_xDI__ud2_c64, },
3974 { 64, false, true, X86_GREG_x9, false, bs3CpuBasic2_jmp_ind_r9__ud2_c64, },
3975 { 64, true, true, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX_opsize__ud2_c64, }, /* no intel version needed */
3976 { 64, false, true, -1, true, bs3CpuBasic2_call_jv__ud2_c64, },
3977 { 64, false, true, -1, true, bs3CpuBasic2_call_jv_back__ud2_c64, },
3978 { 64, true, true, -1, true, bs3CpuBasic2_call_jv_opsize__ud2_c64, },
3979 { 64, true, true, -1, true, bs3CpuBasic2_call_jv_opsize_back__ud2_c64, },
3980 { 64, false, true, -1, true, bs3CpuBasic2_call_ind_mem__ud2_c64, },
3981 { 64, true, true, -1, true, bs3CpuBasic2_call_ind_mem_opsize__ud2__intel_c64,},
3982 { 64, false, true, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX__ud2_c64, },
3983 { 64, false, true, X86_GREG_xDI, true, bs3CpuBasic2_call_ind_xDI__ud2_c64, },
3984 { 64, false, true, X86_GREG_x9, true, bs3CpuBasic2_call_ind_r9__ud2_c64, },
3985 { 64, true, true, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX_opsize__ud2_c64, }, /* no intel version needed */
3986 /* 64bit/AMD: Use the _c32 tests. */
3987 { 64, false, false, -1, false, bs3CpuBasic2_jmp_jb__ud2_c32, },
3988 { 64, false, false, -1, false, bs3CpuBasic2_jmp_jb_back__ud2_c32, },
3989 { 64, true, false, -1, false, bs3CpuBasic2_jmp_jb_opsize__ud2_c32, },
3990 { 64, true, false, -1, false, bs3CpuBasic2_jmp_jb_opsize_back__ud2_c32, },
3991 { 64, false, false, -1, false, bs3CpuBasic2_jmp_jv__ud2_c32, },
3992 { 64, false, false, -1, false, bs3CpuBasic2_jmp_jv_back__ud2_c32, },
3993 { 64, true, false, -1, false, bs3CpuBasic2_jmp_jv_opsize__ud2_c32, },
3994 { 64, true, false, -1, false, bs3CpuBasic2_jmp_jv_opsize_back__ud2_c32, },
3995 { 64, false, false, -1, false, bs3CpuBasic2_jmp_ind_mem__ud2_c64, }, /* using c64 here */
3996 { 64, true, false, -1, false, bs3CpuBasic2_jmp_ind_mem_opsize__ud2_c64, }, /* ditto */
3997 { 64, false, false, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX__ud2_c64, }, /* ditto */
3998 { 64, false, false, X86_GREG_xDI, false, bs3CpuBasic2_jmp_ind_xDI__ud2_c64, }, /* ditto */
3999 { 64, false, false, X86_GREG_x9, false, bs3CpuBasic2_jmp_ind_r9__ud2_c64, }, /* ditto */
4000 { 64, true, false, X86_GREG_xAX, false, bs3CpuBasic2_jmp_ind_xAX_opsize__ud2_c64, }, /* ditto */
4001 { 64, false, false, -1, true, bs3CpuBasic2_call_jv__ud2_c32, }, /* using c32 again */
4002 { 64, false, false, -1, true, bs3CpuBasic2_call_jv_back__ud2_c32, },
4003 { 64, true, false, -1, true, bs3CpuBasic2_call_jv_opsize__ud2_c32, },
4004 { 64, true, false, -1, true, bs3CpuBasic2_call_jv_opsize_back__ud2_c32, },
4005 { 64, false, false, -1, true, bs3CpuBasic2_call_ind_mem__ud2_c64, }, /* using c64 here */
4006 { 64, true, false, -1, true, bs3CpuBasic2_call_ind_mem_opsize__ud2_c64, }, /* ditto */
4007 { 64, false, false, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX__ud2_c64, }, /* ditto */
4008 { 64, false, false, X86_GREG_xDI, true, bs3CpuBasic2_call_ind_xDI__ud2_c64, }, /* ditto */
4009 { 64, false, false, X86_GREG_x9, true, bs3CpuBasic2_call_ind_r9__ud2_c64, }, /* ditto */
4010 { 64, true, false, X86_GREG_xAX, true, bs3CpuBasic2_call_ind_xAX_opsize__ud2_c64, }, /* ditto */
4011 };
4012 uint8_t const cBits = BS3_MODE_IS_64BIT_CODE(bMode) ? 64 : 32;
4013 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor();
4014 bool const fIgnPfx = cBits == 64 && enmCpuVendor == BS3CPUVENDOR_INTEL; /** @todo what does VIA do? */
4015
4016 /* Prepare a copy of the UD2 instructions in low memory for opsize prefixed tests. */
4017 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_jmp_opsize_begin_c32);
4018 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_jmp_opsize_end_c64) - offLow;
4019 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4020 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4021 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4022 Bs3TestFailedF("Opsize overriden jumps are out of place: %#x LB %#x\n", offLow, cbLow);
4023 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4024 if (!fIgnPfx)
4025 {
4026 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4027 if (s_aTests[iTest].fOpSizePfx && s_aTests[iTest].cBits == cBits && s_aTests[iTest].fIgnPfx == fIgnPfx)
4028 {
4029 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4030 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4031 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4032 pbCode16[offUd] = 0xf1; /* replace original ud2 with icebp */
4033 pbCode16[offUd + 1] = 0xf1;
4034 pbLow[offUd] = 0x0f; /* plant ud2 in low memory */
4035 pbLow[offUd + 1] = 0x0b;
4036 }
4037 }
4038
4039 /* Run the tests. */
4040 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4041 {
4042 if (s_aTests[iTest].cBits == cBits && s_aTests[iTest].fIgnPfx == fIgnPfx)
4043 {
4044 uint64_t uGprSaved;
4045 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4046 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4047 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4048 if (s_aTests[iTest].iGprIndirect >= 0)
4049 {
4050 uGprSaved = (&Ctx.rax)[s_aTests[iTest].iGprIndirect].u;
4051 (&Ctx.rax)[s_aTests[iTest].iGprIndirect].u
4052 = (&CtxExpected.rax)[s_aTests[iTest].iGprIndirect].u = CtxExpected.rip.u;
4053 }
4054 if (s_aTests[iTest].fOpSizePfx && !fIgnPfx)
4055 CtxExpected.rip.u &= UINT16_MAX;
4056 CtxExpected.rsp.u = Ctx.rsp.u;
4057 if (s_aTests[iTest].fCall)
4058 CtxExpected.rsp.u -= s_aTests[iTest].cBits == 64 ? 8
4059 : !s_aTests[iTest].fOpSizePfx ? 4 : 2;
4060
4061 //Bs3TestPrintf("cs:rip=%04RX16:%08RX64\n", Ctx.cs, Ctx.rip.u);
4062
4063 if (BS3_MODE_IS_16BIT_SYS(bMode))
4064 g_uBs3TrapEipHint = s_aTests[iTest].fOpSizePfx ? 0 : Ctx.rip.u32;
4065 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4066
4067 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4068 g_usBs3TestStep++;
4069
4070 /* Again single stepping: */
4071 //Bs3TestPrintf("stepping...\n");
4072 Bs3RegSetDr6(0);
4073 Ctx.rflags.u16 |= X86_EFL_TF;
4074 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4075 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4076 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4077 Ctx.rflags.u16 &= ~X86_EFL_TF;
4078 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4079 g_usBs3TestStep++;
4080
4081 if (s_aTests[iTest].iGprIndirect >= 0)
4082 (&Ctx.rax)[s_aTests[iTest].iGprIndirect].u = (&CtxExpected.rax)[s_aTests[iTest].iGprIndirect].u = uGprSaved;
4083 }
4084 }
4085
4086 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4087 }
4088
4089 return 0;
4090}
4091
4092
4093/*********************************************************************************************************************************
4094* FAR JMP & FAR CALL Tests *
4095*********************************************************************************************************************************/
4096#define PROTO_ALL(a_Template) \
4097 FNBS3FAR a_Template ## _c16, \
4098 a_Template ## _c32, \
4099 a_Template ## _c64
4100PROTO_ALL(bs3CpuBasic2_far_jmp_call_opsize_begin);
4101
4102FNBS3FAR bs3CpuBasic2_jmpf_ptr_rm__ud2_c16;
4103PROTO_ALL(bs3CpuBasic2_jmpf_ptr_same_r0__ud2);
4104PROTO_ALL(bs3CpuBasic2_jmpf_ptr_same_r1__ud2);
4105PROTO_ALL(bs3CpuBasic2_jmpf_ptr_same_r2__ud2);
4106PROTO_ALL(bs3CpuBasic2_jmpf_ptr_same_r3__ud2);
4107PROTO_ALL(bs3CpuBasic2_jmpf_ptr_opsize_flipbit_r0__ud2);
4108PROTO_ALL(bs3CpuBasic2_jmpf_ptr_r0_cs64__ud2);
4109PROTO_ALL(bs3CpuBasic2_jmpf_ptr_r0_cs16l__ud2);
4110
4111FNBS3FAR bs3CpuBasic2_callf_ptr_rm__ud2_c16;
4112PROTO_ALL(bs3CpuBasic2_callf_ptr_same_r0__ud2);
4113PROTO_ALL(bs3CpuBasic2_callf_ptr_same_r1__ud2);
4114PROTO_ALL(bs3CpuBasic2_callf_ptr_same_r2__ud2);
4115PROTO_ALL(bs3CpuBasic2_callf_ptr_same_r3__ud2);
4116PROTO_ALL(bs3CpuBasic2_callf_ptr_opsize_flipbit_r0__ud2);
4117PROTO_ALL(bs3CpuBasic2_callf_ptr_r0_cs64__ud2);
4118PROTO_ALL(bs3CpuBasic2_callf_ptr_r0_cs16l__ud2);
4119
4120FNBS3FAR bs3CpuBasic2_jmpf_mem_rm__ud2_c16;
4121PROTO_ALL(bs3CpuBasic2_jmpf_mem_same_r0__ud2);
4122PROTO_ALL(bs3CpuBasic2_jmpf_mem_same_r1__ud2);
4123PROTO_ALL(bs3CpuBasic2_jmpf_mem_same_r2__ud2);
4124PROTO_ALL(bs3CpuBasic2_jmpf_mem_same_r3__ud2);
4125PROTO_ALL(bs3CpuBasic2_jmpf_mem_r0_cs16__ud2);
4126PROTO_ALL(bs3CpuBasic2_jmpf_mem_r0_cs32__ud2);
4127PROTO_ALL(bs3CpuBasic2_jmpf_mem_r0_cs64__ud2);
4128PROTO_ALL(bs3CpuBasic2_jmpf_mem_r0_cs16l__ud2);
4129
4130FNBS3FAR bs3CpuBasic2_jmpf_mem_same_r0__ud2_intel_c64;
4131FNBS3FAR bs3CpuBasic2_jmpf_mem_same_r1__ud2_intel_c64;
4132FNBS3FAR bs3CpuBasic2_jmpf_mem_same_r2__ud2_intel_c64;
4133FNBS3FAR bs3CpuBasic2_jmpf_mem_same_r3__ud2_intel_c64;
4134FNBS3FAR bs3CpuBasic2_jmpf_mem_r0_cs16__ud2_intel_c64;
4135FNBS3FAR bs3CpuBasic2_jmpf_mem_r0_cs32__ud2_intel_c64;
4136FNBS3FAR bs3CpuBasic2_jmpf_mem_r0_cs64__ud2_intel_c64;
4137FNBS3FAR bs3CpuBasic2_jmpf_mem_r0_cs16l__ud2_intel_c64;
4138
4139FNBS3FAR bs3CpuBasic2_callf_mem_rm__ud2_c16;
4140PROTO_ALL(bs3CpuBasic2_callf_mem_same_r0__ud2);
4141PROTO_ALL(bs3CpuBasic2_callf_mem_same_r1__ud2);
4142PROTO_ALL(bs3CpuBasic2_callf_mem_same_r2__ud2);
4143PROTO_ALL(bs3CpuBasic2_callf_mem_same_r3__ud2);
4144PROTO_ALL(bs3CpuBasic2_callf_mem_r0_cs16__ud2);
4145PROTO_ALL(bs3CpuBasic2_callf_mem_r0_cs32__ud2);
4146PROTO_ALL(bs3CpuBasic2_callf_mem_r0_cs64__ud2);
4147PROTO_ALL(bs3CpuBasic2_callf_mem_r0_cs16l__ud2);
4148
4149FNBS3FAR bs3CpuBasic2_callf_mem_same_r0__ud2_intel_c64;
4150FNBS3FAR bs3CpuBasic2_callf_mem_same_r1__ud2_intel_c64;
4151FNBS3FAR bs3CpuBasic2_callf_mem_same_r2__ud2_intel_c64;
4152FNBS3FAR bs3CpuBasic2_callf_mem_same_r3__ud2_intel_c64;
4153FNBS3FAR bs3CpuBasic2_callf_mem_r0_cs16__ud2_intel_c64;
4154FNBS3FAR bs3CpuBasic2_callf_mem_r0_cs32__ud2_intel_c64;
4155FNBS3FAR bs3CpuBasic2_callf_mem_r0_cs64__ud2_intel_c64;
4156FNBS3FAR bs3CpuBasic2_callf_mem_r0_cs16l__ud2_intel_c64;
4157
4158PROTO_ALL(bs3CpuBasic2_far_jmp_call_opsize_end);
4159#undef PROTO_ALL
4160
4161
4162
4163/**
4164 * Entrypoint for FAR JMP & FAR CALL tests.
4165 *
4166 * @returns 0 or BS3TESTDOMODE_SKIPPED.
4167 * @param bMode The CPU mode we're testing.
4168 *
4169 * @note When testing v8086 code, we'll be running in v8086 mode. So, careful
4170 * with control registers and such.
4171 */
4172BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_far_jmp_call)(uint8_t bMode)
4173{
4174 BS3TRAPFRAME TrapCtx;
4175 BS3REGCTX Ctx;
4176 BS3REGCTX CtxExpected;
4177 unsigned iTest;
4178
4179 /* make sure they're allocated */
4180 Bs3MemZero(&Ctx, sizeof(Ctx));
4181 Bs3MemZero(&CtxExpected, sizeof(Ctx));
4182 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
4183
4184 bs3CpuBasic2_SetGlobals(bMode);
4185
4186 /*
4187 * Create a context.
4188 */
4189 Bs3RegCtxSaveEx(&Ctx, bMode, 768);
4190 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
4191
4192 if (Ctx.rax.u8 == 0 || Ctx.rax.u8 == 0xff) /* for salc & the 64-bit detection */
4193 CtxExpected.rax.u8 = Ctx.rax.u8 = 0x42;
4194
4195 /*
4196 * Set up spare selectors.
4197 */
4198 Bs3GdteSpare00 = Bs3Gdte_CODE16;
4199 Bs3GdteSpare00.Gen.u1Long = 1;
4200
4201 /*
4202 * 16-bit tests.
4203 */
4204 if (BS3_MODE_IS_16BIT_CODE(bMode))
4205 {
4206 static struct
4207 {
4208 bool fRmOrV86;
4209 bool fCall;
4210 uint16_t uDstSel;
4211 uint8_t uDstBits;
4212 bool fOpSizePfx;
4213 FPFNBS3FAR pfnTest;
4214 }
4215 const s_aTests[] =
4216 {
4217 { true, false, BS3_SEL_TEXT16, 16, false, bs3CpuBasic2_jmpf_ptr_rm__ud2_c16, },
4218 { false, false, BS3_SEL_R0_CS16, 16, false, bs3CpuBasic2_jmpf_ptr_same_r0__ud2_c16, },
4219 { false, false, BS3_SEL_R1_CS16 | 1, 16, false, bs3CpuBasic2_jmpf_ptr_same_r1__ud2_c16, },
4220 { false, false, BS3_SEL_R2_CS16 | 2, 16, false, bs3CpuBasic2_jmpf_ptr_same_r2__ud2_c16, },
4221 { false, false, BS3_SEL_R3_CS16 | 3, 16, false, bs3CpuBasic2_jmpf_ptr_same_r3__ud2_c16, },
4222 { false, false, BS3_SEL_R0_CS32, 32, true, bs3CpuBasic2_jmpf_ptr_opsize_flipbit_r0__ud2_c16, },
4223 { false, false, BS3_SEL_R0_CS64, 64, true, bs3CpuBasic2_jmpf_ptr_r0_cs64__ud2_c16, }, /* 16-bit CS, except in LM. */
4224 { false, false, BS3_SEL_SPARE_00, 64, false, bs3CpuBasic2_jmpf_ptr_r0_cs16l__ud2_c16, }, /* 16-bit CS, except in LM. */
4225
4226 { true, true, BS3_SEL_TEXT16, 16, false, bs3CpuBasic2_callf_ptr_rm__ud2_c16, },
4227 { false, true, BS3_SEL_R0_CS16, 16, false, bs3CpuBasic2_callf_ptr_same_r0__ud2_c16, },
4228 { false, true, BS3_SEL_R1_CS16 | 1, 16, false, bs3CpuBasic2_callf_ptr_same_r1__ud2_c16, },
4229 { false, true, BS3_SEL_R2_CS16 | 2, 16, false, bs3CpuBasic2_callf_ptr_same_r2__ud2_c16, },
4230 { false, true, BS3_SEL_R3_CS16 | 3, 16, false, bs3CpuBasic2_callf_ptr_same_r3__ud2_c16, },
4231 { false, true, BS3_SEL_R0_CS32, 32, true, bs3CpuBasic2_callf_ptr_opsize_flipbit_r0__ud2_c16, },
4232 { false, true, BS3_SEL_R0_CS64, 64, true, bs3CpuBasic2_callf_ptr_r0_cs64__ud2_c16, }, /* 16-bit CS, except in LM. */
4233 { false, true, BS3_SEL_SPARE_00, 64, false, bs3CpuBasic2_callf_ptr_r0_cs16l__ud2_c16, }, /* 16-bit CS, except in LM. */
4234
4235 { true, false, BS3_SEL_TEXT16, 16, false, bs3CpuBasic2_jmpf_mem_rm__ud2_c16, },
4236 { false, false, BS3_SEL_R0_CS16, 16, false, bs3CpuBasic2_jmpf_mem_same_r0__ud2_c16, },
4237 { false, false, BS3_SEL_R1_CS16 | 1, 16, false, bs3CpuBasic2_jmpf_mem_same_r1__ud2_c16, },
4238 { false, false, BS3_SEL_R2_CS16 | 2, 16, false, bs3CpuBasic2_jmpf_mem_same_r2__ud2_c16, },
4239 { false, false, BS3_SEL_R3_CS16 | 3, 16, false, bs3CpuBasic2_jmpf_mem_same_r3__ud2_c16, },
4240 { false, false, BS3_SEL_R0_CS16, 16, false, bs3CpuBasic2_jmpf_mem_r0_cs16__ud2_c16, },
4241 { false, false, BS3_SEL_R0_CS32, 32, true, bs3CpuBasic2_jmpf_mem_r0_cs32__ud2_c16, },
4242 { false, false, BS3_SEL_R0_CS64, 64, true, bs3CpuBasic2_jmpf_mem_r0_cs64__ud2_c16, }, /* 16-bit CS, except in LM. */
4243 { false, false, BS3_SEL_SPARE_00, 64, false, bs3CpuBasic2_jmpf_mem_r0_cs16l__ud2_c16, }, /* 16-bit CS, except in LM. */
4244
4245 { true, true, BS3_SEL_TEXT16, 16, false, bs3CpuBasic2_callf_mem_rm__ud2_c16, },
4246 { false, true, BS3_SEL_R0_CS16, 16, false, bs3CpuBasic2_callf_mem_same_r0__ud2_c16, },
4247 { false, true, BS3_SEL_R1_CS16 | 1, 16, false, bs3CpuBasic2_callf_mem_same_r1__ud2_c16, },
4248 { false, true, BS3_SEL_R2_CS16 | 2, 16, false, bs3CpuBasic2_callf_mem_same_r2__ud2_c16, },
4249 { false, true, BS3_SEL_R3_CS16 | 3, 16, false, bs3CpuBasic2_callf_mem_same_r3__ud2_c16, },
4250 { false, true, BS3_SEL_R0_CS16, 16, false, bs3CpuBasic2_callf_mem_r0_cs16__ud2_c16, },
4251 { false, true, BS3_SEL_R0_CS32, 32, true, bs3CpuBasic2_callf_mem_r0_cs32__ud2_c16, },
4252 { false, true, BS3_SEL_R0_CS64, 64, true, bs3CpuBasic2_callf_mem_r0_cs64__ud2_c16, }, /* 16-bit CS, except in LM. */
4253 { false, true, BS3_SEL_SPARE_00, 64, false, bs3CpuBasic2_callf_mem_r0_cs16l__ud2_c16, }, /* 16-bit CS, except in LM. */
4254 };
4255 bool const fRmOrV86 = BS3_MODE_IS_RM_OR_V86(bMode);
4256
4257 /* Prepare a copy of the SALC & UD2 instructions in low memory for opsize
4258 prefixed tests jumping to BS3_SEL_SPARE_00 when in 64-bit mode, because
4259 it'll be a 64-bit CS then with base=0 instead of a CS16 with base=0x10000. */
4260 if (BS3_MODE_IS_64BIT_SYS(bMode))
4261 {
4262 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_far_jmp_call_opsize_begin_c16);
4263 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_far_jmp_call_opsize_end_c16) - offLow;
4264 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4265 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4266 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4267 Bs3TestFailedF("Opsize overriden jumps/calls are out of place: %#x LB %#x\n", offLow, cbLow);
4268 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4269 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4270 if (s_aTests[iTest].uDstSel == BS3_SEL_SPARE_00 && s_aTests[iTest].uDstBits == 64)
4271 {
4272 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4273 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4274 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4275 pbLow[offUd - 1] = 0xd6; /* plant salc + ud2 in low memory */
4276 pbLow[offUd] = 0x0f;
4277 pbLow[offUd + 1] = 0x0b;
4278 }
4279 }
4280
4281 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4282 if (s_aTests[iTest].fRmOrV86 == fRmOrV86)
4283 {
4284 uint64_t const uSavedRsp = Ctx.rsp.u;
4285 bool const fGp = (s_aTests[iTest].uDstSel & X86_SEL_RPL) != 0;
4286 uint8_t const BS3_FAR *fpbCode;
4287
4288 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
4289 fpbCode = (uint8_t const BS3_FAR *)BS3_FP_MAKE(Ctx.cs, Ctx.rip.u16);
4290 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4291 if ( s_aTests[iTest].uDstBits == 32
4292 || ( s_aTests[iTest].uDstBits == 64
4293 && !BS3_MODE_IS_16BIT_SYS(bMode)
4294 && s_aTests[iTest].uDstSel != BS3_SEL_SPARE_00))
4295 CtxExpected.rip.u += BS3_ADDR_BS3TEXT16;
4296 if (s_aTests[iTest].uDstSel == BS3_SEL_SPARE_00 && s_aTests[iTest].uDstBits == 64 && BS3_MODE_IS_64BIT_SYS(bMode))
4297 CtxExpected.rip.u &= UINT16_MAX;
4298 CtxExpected.cs = s_aTests[iTest].uDstSel;
4299 if (fGp)
4300 {
4301 CtxExpected.rip.u = Ctx.rip.u;
4302 CtxExpected.cs = Ctx.cs;
4303 }
4304 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4305 CtxExpected.rsp.u = Ctx.rsp.u;
4306 if (s_aTests[iTest].fCall && !fGp)
4307 CtxExpected.rsp.u -= s_aTests[iTest].fOpSizePfx ? 8 : 4;
4308 if (s_aTests[iTest].uDstBits == 64 && !fGp)
4309 {
4310 if (BS3_MODE_IS_64BIT_SYS(bMode))
4311 CtxExpected.rip.u -= 1;
4312 else
4313 CtxExpected.rax.u8 = CtxExpected.rflags.u & X86_EFL_CF ? 0xff : 0x00;
4314 }
4315 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4316 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4317 if (!fGp)
4318 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4319 else
4320 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aTests[iTest].uDstSel & X86_TRAP_ERR_SEL_MASK);
4321 Ctx.rsp.u = uSavedRsp;
4322 g_usBs3TestStep++;
4323
4324 /* Again single stepping: */
4325 //Bs3TestPrintf("stepping...\n");
4326 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4327 Ctx.rflags.u16 |= X86_EFL_TF;
4328 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4329 CtxExpected.rax.u = Ctx.rax.u;
4330 if (s_aTests[iTest].uDstBits == 64 && !fGp && !BS3_MODE_IS_64BIT_SYS(bMode))
4331 CtxExpected.rip.u -= 1;
4332 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4333 if (!fGp)
4334 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4335 else
4336 {
4337 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aTests[iTest].uDstSel & X86_TRAP_ERR_SEL_MASK);
4338 bs3CpuBasic2_CheckDr6InitVal();
4339 }
4340 Ctx.rflags.u16 &= ~X86_EFL_TF;
4341 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4342 Ctx.rsp.u = uSavedRsp;
4343 g_usBs3TestStep++;
4344 }
4345 }
4346 /*
4347 * 32-bit tests.
4348 */
4349 else if (BS3_MODE_IS_32BIT_CODE(bMode))
4350 {
4351 static struct
4352 {
4353 bool fCall;
4354 uint16_t uDstSel;
4355 uint8_t uDstBits;
4356 bool fOpSizePfx;
4357 FPFNBS3FAR pfnTest;
4358 }
4359 const s_aTests[] =
4360 {
4361 { false, BS3_SEL_R0_CS32, 32, false, bs3CpuBasic2_jmpf_ptr_same_r0__ud2_c32, },
4362 { false, BS3_SEL_R1_CS32 | 1, 32, false, bs3CpuBasic2_jmpf_ptr_same_r1__ud2_c32, },
4363 { false, BS3_SEL_R2_CS32 | 2, 32, false, bs3CpuBasic2_jmpf_ptr_same_r2__ud2_c32, },
4364 { false, BS3_SEL_R3_CS32 | 3, 32, false, bs3CpuBasic2_jmpf_ptr_same_r3__ud2_c32, },
4365 { false, BS3_SEL_R0_CS16, 16, true, bs3CpuBasic2_jmpf_ptr_opsize_flipbit_r0__ud2_c32, },
4366 { false, BS3_SEL_R0_CS64, 64, false, bs3CpuBasic2_jmpf_ptr_r0_cs64__ud2_c32, }, /* 16-bit CS, except in LM. */
4367 { false, BS3_SEL_SPARE_00, 64, true, bs3CpuBasic2_jmpf_ptr_r0_cs16l__ud2_c32, }, /* 16-bit CS, except in LM. */
4368
4369 { true, BS3_SEL_R0_CS32, 32, false, bs3CpuBasic2_callf_ptr_same_r0__ud2_c32, },
4370 { true, BS3_SEL_R1_CS32 | 1, 32, false, bs3CpuBasic2_callf_ptr_same_r1__ud2_c32, },
4371 { true, BS3_SEL_R2_CS32 | 2, 32, false, bs3CpuBasic2_callf_ptr_same_r2__ud2_c32, },
4372 { true, BS3_SEL_R3_CS32 | 3, 32, false, bs3CpuBasic2_callf_ptr_same_r3__ud2_c32, },
4373 { true, BS3_SEL_R0_CS16, 16, true, bs3CpuBasic2_callf_ptr_opsize_flipbit_r0__ud2_c32, },
4374 { true, BS3_SEL_R0_CS64, 64, false, bs3CpuBasic2_callf_ptr_r0_cs64__ud2_c32, }, /* 16-bit CS, except in LM. */
4375 { true, BS3_SEL_SPARE_00, 64, true, bs3CpuBasic2_callf_ptr_r0_cs16l__ud2_c32, }, /* 16-bit CS, except in LM. */
4376
4377 { false, BS3_SEL_R0_CS32, 32, false, bs3CpuBasic2_jmpf_mem_same_r0__ud2_c32, },
4378 { false, BS3_SEL_R1_CS32 | 1, 32, false, bs3CpuBasic2_jmpf_mem_same_r1__ud2_c32, },
4379 { false, BS3_SEL_R2_CS32 | 2, 32, false, bs3CpuBasic2_jmpf_mem_same_r2__ud2_c32, },
4380 { false, BS3_SEL_R3_CS32 | 3, 32, false, bs3CpuBasic2_jmpf_mem_same_r3__ud2_c32, },
4381 { false, BS3_SEL_R0_CS16, 16, true, bs3CpuBasic2_jmpf_mem_r0_cs16__ud2_c32, },
4382 { false, BS3_SEL_R0_CS32, 32, false, bs3CpuBasic2_jmpf_mem_r0_cs32__ud2_c32, },
4383 { false, BS3_SEL_R0_CS64, 64, false, bs3CpuBasic2_jmpf_mem_r0_cs64__ud2_c32, }, /* 16-bit CS, except in LM. */
4384 { false, BS3_SEL_SPARE_00, 64, true, bs3CpuBasic2_jmpf_mem_r0_cs16l__ud2_c32, }, /* 16-bit CS, except in LM. */
4385
4386 { true, BS3_SEL_R0_CS32, 32, false, bs3CpuBasic2_callf_mem_same_r0__ud2_c32, },
4387 { true, BS3_SEL_R1_CS32 | 1, 32, false, bs3CpuBasic2_callf_mem_same_r1__ud2_c32, },
4388 { true, BS3_SEL_R2_CS32 | 2, 32, false, bs3CpuBasic2_callf_mem_same_r2__ud2_c32, },
4389 { true, BS3_SEL_R3_CS32 | 3, 32, false, bs3CpuBasic2_callf_mem_same_r3__ud2_c32, },
4390 { true, BS3_SEL_R0_CS16, 16, true, bs3CpuBasic2_callf_mem_r0_cs16__ud2_c32, },
4391 { true, BS3_SEL_R0_CS32, 32, false, bs3CpuBasic2_callf_mem_r0_cs32__ud2_c32, },
4392 { true, BS3_SEL_R0_CS64, 64, false, bs3CpuBasic2_callf_mem_r0_cs64__ud2_c32, }, /* 16-bit CS, except in LM. */
4393 { true, BS3_SEL_SPARE_00, 64, true, bs3CpuBasic2_callf_mem_r0_cs16l__ud2_c32, }, /* 16-bit CS, except in LM. */
4394 };
4395
4396 /* Prepare a copy of the SALC & UD2 instructions in low memory for opsize
4397 prefixed tests jumping to BS3_SEL_SPARE_00 when in 64-bit mode, because
4398 it'll be a 64-bit CS then with base=0 instead of a CS16 with base=0x10000. */
4399 if (BS3_MODE_IS_64BIT_SYS(bMode))
4400 {
4401 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_far_jmp_call_opsize_begin_c32);
4402 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_far_jmp_call_opsize_end_c32) - offLow;
4403 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4404 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4405 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4406 Bs3TestFailedF("Opsize overriden jumps/calls are out of place: %#x LB %#x\n", offLow, cbLow);
4407 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4408 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4409 if (s_aTests[iTest].uDstSel == BS3_SEL_SPARE_00 && s_aTests[iTest].uDstBits == 64)
4410 {
4411 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4412 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4413 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4414 pbLow[offUd - 1] = 0xd6; /* plant salc + ud2 in low memory */
4415 pbLow[offUd] = 0x0f;
4416 pbLow[offUd + 1] = 0x0b;
4417 }
4418 }
4419 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4420 {
4421 uint64_t const uSavedRsp = Ctx.rsp.u;
4422 bool const fGp = (s_aTests[iTest].uDstSel & X86_SEL_RPL) != 0;
4423 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4424
4425 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4426 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4427 if ( s_aTests[iTest].uDstBits == 16
4428 || ( s_aTests[iTest].uDstBits == 64
4429 && ( BS3_MODE_IS_16BIT_SYS(bMode))
4430 || s_aTests[iTest].uDstSel == BS3_SEL_SPARE_00))
4431 CtxExpected.rip.u &= UINT16_MAX;
4432 CtxExpected.cs = s_aTests[iTest].uDstSel;
4433 if (fGp)
4434 {
4435 CtxExpected.rip.u = Ctx.rip.u;
4436 CtxExpected.cs = Ctx.cs;
4437 }
4438 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4439 CtxExpected.rsp.u = Ctx.rsp.u;
4440 if (s_aTests[iTest].fCall && !fGp)
4441 CtxExpected.rsp.u -= s_aTests[iTest].fOpSizePfx ? 4 : 8;
4442 if (s_aTests[iTest].uDstBits == 64 && !fGp)
4443 {
4444 if (BS3_MODE_IS_64BIT_SYS(bMode))
4445 CtxExpected.rip.u -= 1;
4446 else
4447 CtxExpected.rax.u8 = CtxExpected.rflags.u & X86_EFL_CF ? 0xff : 0x00;
4448 }
4449 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4450 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4451 if (!fGp)
4452 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4453 else
4454 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aTests[iTest].uDstSel & X86_TRAP_ERR_SEL_MASK);
4455 Ctx.rsp.u = uSavedRsp;
4456 g_usBs3TestStep++;
4457
4458 /* Again single stepping: */
4459 //Bs3TestPrintf("stepping...\n");
4460 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4461 Ctx.rflags.u16 |= X86_EFL_TF;
4462 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4463 CtxExpected.rax.u = Ctx.rax.u;
4464 if (s_aTests[iTest].uDstBits == 64 && !fGp && !BS3_MODE_IS_64BIT_SYS(bMode))
4465 CtxExpected.rip.u -= 1;
4466 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4467 if (!fGp)
4468 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4469 else
4470 {
4471 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aTests[iTest].uDstSel & X86_TRAP_ERR_SEL_MASK);
4472 bs3CpuBasic2_CheckDr6InitVal();
4473 }
4474 Ctx.rflags.u16 &= ~X86_EFL_TF;
4475 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4476 Ctx.rsp.u = uSavedRsp;
4477 g_usBs3TestStep++;
4478 }
4479 }
4480 /*
4481 * 64-bit tests.
4482 */
4483 else if (BS3_MODE_IS_64BIT_CODE(bMode))
4484 {
4485 static struct
4486 {
4487 bool fInvalid;
4488 bool fCall;
4489 uint16_t uDstSel;
4490 uint8_t uDstBits;
4491 uint8_t fOpSizePfx; /**< 0: none, 1: 066h, 2: REX.W, 3: 066h REX.W */
4492 int8_t fFix64OpSize;
4493 FPFNBS3FAR pfnTest;
4494 }
4495 const s_aTests[] =
4496 {
4497 /* invalid opcodes: */
4498 { true, false, BS3_SEL_R0_CS32, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_same_r0__ud2_c32, },
4499 { true, false, BS3_SEL_R1_CS32 | 1, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_same_r1__ud2_c32, },
4500 { true, false, BS3_SEL_R2_CS32 | 2, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_same_r2__ud2_c32, },
4501 { true, false, BS3_SEL_R3_CS32 | 3, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_same_r3__ud2_c32, },
4502 { true, false, BS3_SEL_R0_CS16, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_opsize_flipbit_r0__ud2_c32, },
4503 { true, false, BS3_SEL_R0_CS64, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_r0_cs64__ud2_c32, },
4504 { true, false, BS3_SEL_SPARE_00, 64, 0, -1, bs3CpuBasic2_jmpf_ptr_r0_cs16l__ud2_c32, },
4505
4506 { true, true, BS3_SEL_R0_CS32, 64, 0, -1, bs3CpuBasic2_callf_ptr_same_r0__ud2_c32, },
4507 { true, true, BS3_SEL_R1_CS32 | 1, 64, 0, -1, bs3CpuBasic2_callf_ptr_same_r1__ud2_c32, },
4508 { true, true, BS3_SEL_R2_CS32 | 2, 64, 0, -1, bs3CpuBasic2_callf_ptr_same_r2__ud2_c32, },
4509 { true, true, BS3_SEL_R3_CS32 | 3, 64, 0, -1, bs3CpuBasic2_callf_ptr_same_r3__ud2_c32, },
4510 { true, true, BS3_SEL_R0_CS16, 64, 0, -1, bs3CpuBasic2_callf_ptr_opsize_flipbit_r0__ud2_c32, },
4511 { true, true, BS3_SEL_R0_CS64, 64, 0, -1, bs3CpuBasic2_callf_ptr_r0_cs64__ud2_c32, },
4512 { true, true, BS3_SEL_SPARE_00, 64, 0, -1, bs3CpuBasic2_callf_ptr_r0_cs16l__ud2_c32, },
4513
4514 { false, false, BS3_SEL_R0_CS64, 64, 0, false, bs3CpuBasic2_jmpf_mem_same_r0__ud2_c64, },
4515 { false, false, BS3_SEL_R1_CS64 | 1, 64, 0, false, bs3CpuBasic2_jmpf_mem_same_r1__ud2_c64, },
4516 { false, false, BS3_SEL_R2_CS64 | 2, 64, 0, false, bs3CpuBasic2_jmpf_mem_same_r2__ud2_c64, },
4517 { false, false, BS3_SEL_R3_CS64 | 3, 64, 0, false, bs3CpuBasic2_jmpf_mem_same_r3__ud2_c64, },
4518 { false, false, BS3_SEL_R0_CS16, 16, 1, false, bs3CpuBasic2_jmpf_mem_r0_cs16__ud2_c64, },
4519 { false, false, BS3_SEL_R0_CS32, 32, 0, false, bs3CpuBasic2_jmpf_mem_r0_cs32__ud2_c64, },
4520 { false, false, BS3_SEL_R0_CS64, 64, 0, false, bs3CpuBasic2_jmpf_mem_r0_cs64__ud2_c64, }, /* 16-bit CS, except in LM. */
4521 { false, false, BS3_SEL_SPARE_00, 64, 0, false, bs3CpuBasic2_jmpf_mem_r0_cs16l__ud2_c64, }, /* 16-bit CS, except in LM. */
4522
4523 { false, false, BS3_SEL_R0_CS64, 64, 2, true, bs3CpuBasic2_jmpf_mem_same_r0__ud2_intel_c64, },
4524 { false, false, BS3_SEL_R1_CS64 | 1, 64, 2, true, bs3CpuBasic2_jmpf_mem_same_r1__ud2_intel_c64, },
4525 { false, false, BS3_SEL_R2_CS64 | 2, 64, 0, true, bs3CpuBasic2_jmpf_mem_same_r2__ud2_intel_c64, },
4526 { false, false, BS3_SEL_R3_CS64 | 3, 64, 2, true, bs3CpuBasic2_jmpf_mem_same_r3__ud2_intel_c64, },
4527 { false, false, BS3_SEL_R0_CS16, 16, 1, true, bs3CpuBasic2_jmpf_mem_r0_cs16__ud2_intel_c64, },
4528 { false, false, BS3_SEL_R0_CS32, 32, 0, true, bs3CpuBasic2_jmpf_mem_r0_cs32__ud2_intel_c64, },
4529 { false, false, BS3_SEL_R0_CS64, 64, 2, true, bs3CpuBasic2_jmpf_mem_r0_cs64__ud2_intel_c64, }, /* 16-bit CS, except in LM. */
4530 { false, false, BS3_SEL_SPARE_00, 64, 0, true, bs3CpuBasic2_jmpf_mem_r0_cs16l__ud2_intel_c64, }, /* 16-bit CS, except in LM. */
4531
4532 { false, true, BS3_SEL_R0_CS64, 64, 2, false, bs3CpuBasic2_callf_mem_same_r0__ud2_c64, },
4533 { false, true, BS3_SEL_R1_CS64 | 1, 64, 2, false, bs3CpuBasic2_callf_mem_same_r1__ud2_c64, },
4534 { false, true, BS3_SEL_R2_CS64 | 2, 64, 0, false, bs3CpuBasic2_callf_mem_same_r2__ud2_c64, },
4535 { false, true, BS3_SEL_R3_CS64 | 3, 64, 2, false, bs3CpuBasic2_callf_mem_same_r3__ud2_c64, },
4536 { false, true, BS3_SEL_R0_CS16, 16, 1, false, bs3CpuBasic2_callf_mem_r0_cs16__ud2_c64, },
4537 { false, true, BS3_SEL_R0_CS32, 32, 2, false, bs3CpuBasic2_callf_mem_r0_cs32__ud2_c64, },
4538 { false, true, BS3_SEL_R0_CS64, 64, 0, false, bs3CpuBasic2_callf_mem_r0_cs64__ud2_c64, }, /* 16-bit CS, except in LM. */
4539 { false, true, BS3_SEL_SPARE_00, 64, 0, false, bs3CpuBasic2_callf_mem_r0_cs16l__ud2_c64, }, /* 16-bit CS, except in LM. */
4540
4541 { false, true, BS3_SEL_R0_CS64, 64, 2, true, bs3CpuBasic2_callf_mem_same_r0__ud2_intel_c64, },
4542 { false, true, BS3_SEL_R1_CS64 | 1, 64, 2, true, bs3CpuBasic2_callf_mem_same_r1__ud2_intel_c64, },
4543 { false, true, BS3_SEL_R2_CS64 | 2, 64, 0, true, bs3CpuBasic2_callf_mem_same_r2__ud2_intel_c64, },
4544 { false, true, BS3_SEL_R3_CS64 | 3, 64, 2, true, bs3CpuBasic2_callf_mem_same_r3__ud2_intel_c64, },
4545 { false, true, BS3_SEL_R0_CS16, 16, 1, true, bs3CpuBasic2_callf_mem_r0_cs16__ud2_intel_c64, },
4546 { false, true, BS3_SEL_R0_CS32, 32, 0, true, bs3CpuBasic2_callf_mem_r0_cs32__ud2_intel_c64, },
4547 { false, true, BS3_SEL_R0_CS64, 64, 2, true, bs3CpuBasic2_callf_mem_r0_cs64__ud2_intel_c64, }, /* 16-bit CS, except in LM. */
4548 { false, true, BS3_SEL_SPARE_00, 64, 0, true, bs3CpuBasic2_callf_mem_r0_cs16l__ud2_intel_c64, }, /* 16-bit CS, except in LM. */
4549 };
4550 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor();
4551 bool const fFix64OpSize = enmCpuVendor == BS3CPUVENDOR_INTEL; /** @todo what does VIA do? */
4552
4553 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4554 {
4555 uint64_t const uSavedRsp = Ctx.rsp.u;
4556 bool const fUd = s_aTests[iTest].fInvalid;
4557 bool const fGp = (s_aTests[iTest].uDstSel & X86_SEL_RPL) != 0;
4558 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4559
4560 if (s_aTests[iTest].fFix64OpSize != fFix64OpSize && s_aTests[iTest].fFix64OpSize >= 0)
4561 continue;
4562
4563 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4564 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4565 CtxExpected.cs = s_aTests[iTest].uDstSel;
4566 if (s_aTests[iTest].uDstBits == 16)
4567 CtxExpected.rip.u &= UINT16_MAX;
4568 else if (s_aTests[iTest].uDstBits == 64 && fFix64OpSize && s_aTests[iTest].uDstSel != BS3_SEL_SPARE_00)
4569 CtxExpected.rip.u |= UINT64_C(0xfffff00000000000);
4570
4571 if (fGp || fUd)
4572 {
4573 CtxExpected.rip.u = Ctx.rip.u;
4574 CtxExpected.cs = Ctx.cs;
4575 }
4576 CtxExpected.rsp.u = Ctx.rsp.u;
4577 if (s_aTests[iTest].fCall && !fGp && !fUd)
4578 {
4579 CtxExpected.rsp.u -= s_aTests[iTest].fOpSizePfx == 0 ? 8
4580 : s_aTests[iTest].fOpSizePfx == 1 ? 4 : 16;
4581 //Bs3TestPrintf("cs:rsp=%04RX16:%04RX64 -> %04RX64 (fOpSizePfx=%d)\n", Ctx.ss, Ctx.rsp.u, CtxExpected.rsp.u, s_aTests[iTest].fOpSizePfx);
4582 }
4583 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4584 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4585 if (!fGp || fUd)
4586 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4587 else
4588 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aTests[iTest].uDstSel & X86_TRAP_ERR_SEL_MASK);
4589 Ctx.rsp.u = uSavedRsp;
4590 g_usBs3TestStep++;
4591
4592 /* Again single stepping: */
4593 //Bs3TestPrintf("stepping...\n");
4594 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4595 Ctx.rflags.u16 |= X86_EFL_TF;
4596 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4597 CtxExpected.rax.u = Ctx.rax.u;
4598 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4599 if (fUd)
4600 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4601 else if (!fGp)
4602 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4603 else
4604 {
4605 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aTests[iTest].uDstSel & X86_TRAP_ERR_SEL_MASK);
4606 bs3CpuBasic2_CheckDr6InitVal();
4607 }
4608 Ctx.rflags.u16 &= ~X86_EFL_TF;
4609 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4610 Ctx.rsp.u = uSavedRsp;
4611 g_usBs3TestStep++;
4612 }
4613 }
4614 else
4615 Bs3TestFailed("wtf?");
4616
4617 return 0;
4618}
4619
4620
4621/*********************************************************************************************************************************
4622* Near RET *
4623*********************************************************************************************************************************/
4624#define PROTO_ALL(a_Template) \
4625 FNBS3FAR a_Template ## _c16, \
4626 a_Template ## _c32, \
4627 a_Template ## _c64
4628PROTO_ALL(bs3CpuBasic2_retn_opsize_begin);
4629PROTO_ALL(bs3CpuBasic2_retn__ud2);
4630PROTO_ALL(bs3CpuBasic2_retn_opsize__ud2);
4631PROTO_ALL(bs3CpuBasic2_retn_i24__ud2);
4632PROTO_ALL(bs3CpuBasic2_retn_i24_opsize__ud2);
4633PROTO_ALL(bs3CpuBasic2_retn_i0__ud2);
4634PROTO_ALL(bs3CpuBasic2_retn_i0_opsize__ud2);
4635FNBS3FAR bs3CpuBasic2_retn_rexw__ud2_c64;
4636FNBS3FAR bs3CpuBasic2_retn_i24_rexw__ud2_c64;
4637FNBS3FAR bs3CpuBasic2_retn_opsize_rexw__ud2_c64;
4638FNBS3FAR bs3CpuBasic2_retn_rexw_opsize__ud2_c64;
4639FNBS3FAR bs3CpuBasic2_retn_i24_opsize_rexw__ud2_c64;
4640FNBS3FAR bs3CpuBasic2_retn_i24_rexw_opsize__ud2_c64;
4641PROTO_ALL(bs3CpuBasic2_retn_opsize_end);
4642#undef PROTO_ALL
4643
4644
4645static void bs3CpuBasic2_retn_PrepStack(BS3PTRUNION StkPtr, PCBS3REGCTX pCtxExpected, uint8_t cbAddr)
4646{
4647 StkPtr.pu32[3] = UINT32_MAX;
4648 StkPtr.pu32[2] = UINT32_MAX;
4649 StkPtr.pu32[1] = UINT32_MAX;
4650 StkPtr.pu32[0] = UINT32_MAX;
4651 StkPtr.pu32[-1] = UINT32_MAX;
4652 StkPtr.pu32[-2] = UINT32_MAX;
4653 StkPtr.pu32[-3] = UINT32_MAX;
4654 StkPtr.pu32[-4] = UINT32_MAX;
4655 if (cbAddr == 2)
4656 StkPtr.pu16[0] = pCtxExpected->rip.u16;
4657 else if (cbAddr == 4)
4658 StkPtr.pu32[0] = pCtxExpected->rip.u32;
4659 else
4660 StkPtr.pu64[0] = pCtxExpected->rip.u64;
4661}
4662
4663
4664/**
4665 * Entrypoint for NEAR RET tests.
4666 *
4667 * @returns 0 or BS3TESTDOMODE_SKIPPED.
4668 * @param bMode The CPU mode we're testing.
4669 */
4670BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_near_ret)(uint8_t bMode)
4671{
4672 BS3TRAPFRAME TrapCtx;
4673 BS3REGCTX Ctx;
4674 BS3REGCTX CtxExpected;
4675 unsigned iTest;
4676 BS3PTRUNION StkPtr;
4677
4678 /* make sure they're allocated */
4679 Bs3MemZero(&Ctx, sizeof(Ctx));
4680 Bs3MemZero(&CtxExpected, sizeof(Ctx));
4681 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
4682
4683 bs3CpuBasic2_SetGlobals(bMode);
4684
4685 /*
4686 * Create a context.
4687 *
4688 * ASSUMES we're in on the ring-0 stack in ring-0 and using less than 16KB.
4689 */
4690 Bs3RegCtxSaveEx(&Ctx, bMode, 768);
4691 Ctx.rsp.u = BS3_ADDR_STACK - _16K;
4692 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
4693
4694 StkPtr.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
4695 //Bs3TestPrintf("Stack=%p rsp=%RX64\n", StkPtr.pv, Ctx.rsp.u);
4696
4697 /*
4698 * 16-bit tests.
4699 */
4700 if (BS3_MODE_IS_16BIT_CODE(bMode))
4701 {
4702 static struct
4703 {
4704 bool fOpSizePfx;
4705 uint16_t cbImm;
4706 FPFNBS3FAR pfnTest;
4707 }
4708 const s_aTests[] =
4709 {
4710 { false, 0, bs3CpuBasic2_retn__ud2_c16, },
4711 { true, 0, bs3CpuBasic2_retn_opsize__ud2_c16, },
4712 { false, 24, bs3CpuBasic2_retn_i24__ud2_c16, },
4713 { true, 24, bs3CpuBasic2_retn_i24_opsize__ud2_c16, },
4714 { false, 0, bs3CpuBasic2_retn_i0__ud2_c16, },
4715 { true, 0, bs3CpuBasic2_retn_i0_opsize__ud2_c16, },
4716 };
4717
4718 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4719 {
4720 uint8_t const BS3_FAR *fpbCode;
4721
4722 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
4723 fpbCode = (uint8_t const BS3_FAR *)BS3_FP_MAKE(Ctx.cs, Ctx.rip.u16);
4724 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4725 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4726 CtxExpected.cs = Ctx.cs;
4727 if (!s_aTests[iTest].fOpSizePfx)
4728 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 2;
4729 else
4730 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 4;
4731 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4732 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64\n", Ctx.ss, Ctx.rsp.u);
4733 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 4 : 2);
4734 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4735 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4736 g_usBs3TestStep++;
4737
4738 /* Again single stepping: */
4739 //Bs3TestPrintf("stepping...\n");
4740 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4741 Ctx.rflags.u16 |= X86_EFL_TF;
4742 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4743 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 4 : 2);
4744 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4745 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4746 Ctx.rflags.u16 &= ~X86_EFL_TF;
4747 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4748 g_usBs3TestStep++;
4749 }
4750 }
4751 /*
4752 * 32-bit tests.
4753 */
4754 else if (BS3_MODE_IS_32BIT_CODE(bMode))
4755 {
4756 static struct
4757 {
4758 uint8_t cBits;
4759 bool fOpSizePfx;
4760 uint16_t cbImm;
4761 FPFNBS3FAR pfnTest;
4762 }
4763 const s_aTests[] =
4764 {
4765 { 32, false, 0, bs3CpuBasic2_retn__ud2_c32, },
4766 { 32, true, 0, bs3CpuBasic2_retn_opsize__ud2_c32, },
4767 { 32, false, 24, bs3CpuBasic2_retn_i24__ud2_c32, },
4768 { 32, true, 24, bs3CpuBasic2_retn_i24_opsize__ud2_c32, },
4769 { 32, false, 0, bs3CpuBasic2_retn_i0__ud2_c32, },
4770 { 32, true, 0, bs3CpuBasic2_retn_i0_opsize__ud2_c32, },
4771 };
4772
4773 /* Prepare a copy of the UD2 instructions in low memory for opsize prefixed tests. */
4774 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_begin_c32);
4775 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_end_c32) - offLow;
4776 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4777 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4778 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4779 Bs3TestFailedF("Opsize overriden jumps/calls are out of place: %#x LB %#x\n", offLow, cbLow);
4780 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4781 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4782 if (s_aTests[iTest].fOpSizePfx)
4783 {
4784 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4785 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4786 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4787 pbCode16[offUd] = 0xf1; /* replace original ud2 with icebp */
4788 pbCode16[offUd + 1] = 0xf1;
4789 pbLow[offUd] = 0x0f; /* plant ud2 in low memory */
4790 pbLow[offUd + 1] = 0x0b;
4791 }
4792
4793 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4794 {
4795 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4796
4797 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4798 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4799 CtxExpected.cs = Ctx.cs;
4800 if (!s_aTests[iTest].fOpSizePfx)
4801 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 4;
4802 else
4803 {
4804 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 2;
4805 CtxExpected.rip.u &= UINT16_MAX;
4806 }
4807 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4808 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4809 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64\n", Ctx.ss, Ctx.rsp.u);
4810 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 2 : 4);
4811 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4812 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4813 g_usBs3TestStep++;
4814
4815 /* Again single stepping: */
4816 //Bs3TestPrintf("stepping...\n");
4817 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4818 Ctx.rflags.u16 |= X86_EFL_TF;
4819 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4820 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 2 : 4);
4821 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4822 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4823 Ctx.rflags.u16 &= ~X86_EFL_TF;
4824 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4825 g_usBs3TestStep++;
4826 }
4827 }
4828 /*
4829 * 64-bit tests.
4830 */
4831 else if (BS3_MODE_IS_64BIT_CODE(bMode))
4832 {
4833 static struct
4834 {
4835 uint8_t cBits;
4836 bool fOpSizePfx;
4837 uint16_t cbImm;
4838 FPFNBS3FAR pfnTest;
4839 }
4840 const s_aTests[] =
4841 {
4842 { 32, false, 0, bs3CpuBasic2_retn__ud2_c64, },
4843 { 32, false, 0, bs3CpuBasic2_retn_rexw__ud2_c64, },
4844 { 32, true, 0, bs3CpuBasic2_retn_opsize__ud2_c64, },
4845 { 32, false, 0, bs3CpuBasic2_retn_opsize_rexw__ud2_c64, },
4846 { 32, true, 0, bs3CpuBasic2_retn_rexw_opsize__ud2_c64, },
4847 { 32, false, 24, bs3CpuBasic2_retn_i24__ud2_c64, },
4848 { 32, false, 24, bs3CpuBasic2_retn_i24_rexw__ud2_c64, },
4849 { 32, true, 24, bs3CpuBasic2_retn_i24_opsize__ud2_c64, },
4850 { 32, false, 24, bs3CpuBasic2_retn_i24_opsize_rexw__ud2_c64, },
4851 { 32, true, 24, bs3CpuBasic2_retn_i24_rexw_opsize__ud2_c64, },
4852 { 32, false, 0, bs3CpuBasic2_retn_i0__ud2_c64, },
4853 { 32, true, 0, bs3CpuBasic2_retn_i0_opsize__ud2_c64, },
4854 };
4855 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor();
4856 bool const fFix64OpSize = enmCpuVendor == BS3CPUVENDOR_INTEL; /** @todo what does VIA do? */
4857
4858 /* Prepare a copy of the UD2 instructions in low memory for opsize prefixed
4859 tests, unless we're on intel where the opsize prefix is ignored. Here we
4860 just fill low memory with int3's so we can detect non-intel behaviour. */
4861 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_begin_c64);
4862 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_end_c64) - offLow;
4863 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4864 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4865 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4866 Bs3TestFailedF("Opsize overriden jumps/calls are out of place: %#x LB %#x\n", offLow, cbLow);
4867 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4868 if (!fFix64OpSize)
4869 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4870 if (s_aTests[iTest].fOpSizePfx)
4871 {
4872 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4873 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4874 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4875 pbCode16[offUd] = 0xf1; /* replace original ud2 with icebp */
4876 pbCode16[offUd + 1] = 0xf1;
4877 pbLow[offUd] = 0x0f; /* plant ud2 in low memory */
4878 pbLow[offUd + 1] = 0x0b;
4879 }
4880
4881 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4882 {
4883 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4884
4885 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4886 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4887 CtxExpected.cs = Ctx.cs;
4888 if (!s_aTests[iTest].fOpSizePfx || fFix64OpSize)
4889 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 8;
4890 else
4891 {
4892 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 2;
4893 CtxExpected.rip.u &= UINT16_MAX;
4894 }
4895 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4896 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4897 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64\n", Ctx.ss, Ctx.rsp.u);
4898 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx && !fFix64OpSize ? 2 : 8);
4899 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4900 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4901 g_usBs3TestStep++;
4902
4903 /* Again single stepping: */
4904 //Bs3TestPrintf("stepping...\n");
4905 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4906 Ctx.rflags.u16 |= X86_EFL_TF;
4907 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4908 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx && !fFix64OpSize ? 2 : 8);
4909 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4910 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4911 Ctx.rflags.u16 &= ~X86_EFL_TF;
4912 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4913 g_usBs3TestStep++;
4914 }
4915 }
4916 else
4917 Bs3TestFailed("wtf?");
4918
4919 return 0;
4920}
4921
4922
4923/*********************************************************************************************************************************
4924* Far RET *
4925*********************************************************************************************************************************/
4926#define PROTO_ALL(a_Template) \
4927 FNBS3FAR a_Template ## _c16, \
4928 a_Template ## _c32, \
4929 a_Template ## _c64
4930PROTO_ALL(bs3CpuBasic2_retf);
4931PROTO_ALL(bs3CpuBasic2_retf_opsize);
4932FNBS3FAR bs3CpuBasic2_retf_rexw_c64;
4933FNBS3FAR bs3CpuBasic2_retf_rexw_opsize_c64;
4934FNBS3FAR bs3CpuBasic2_retf_opsize_rexw_c64;
4935PROTO_ALL(bs3CpuBasic2_retf_i32);
4936PROTO_ALL(bs3CpuBasic2_retf_i32_opsize);
4937FNBS3FAR bs3CpuBasic2_retf_i24_rexw_c64;
4938FNBS3FAR bs3CpuBasic2_retf_i24_rexw_opsize_c64;
4939FNBS3FAR bs3CpuBasic2_retf_i24_opsize_rexw_c64;
4940#undef PROTO_ALL
4941
4942
4943static void bs3CpuBasic2_retf_PrepStack(BS3PTRUNION StkPtr, uint8_t cbStkItem, RTSEL uRetCs, uint64_t uRetRip,
4944 bool fWithStack, uint16_t cbImm, RTSEL uRetSs, uint64_t uRetRsp)
4945{
4946 Bs3MemSet(&StkPtr.pu32[-4], 0xff, 96);
4947 if (cbStkItem == 2)
4948 {
4949 StkPtr.pu16[0] = (uint16_t)uRetRip;
4950 StkPtr.pu16[1] = uRetCs;
4951 if (fWithStack)
4952 {
4953 StkPtr.pb += cbImm;
4954 StkPtr.pu16[2] = (uint16_t)uRetRsp;
4955 StkPtr.pu16[3] = uRetSs;
4956 }
4957 }
4958 else if (cbStkItem == 4)
4959 {
4960 StkPtr.pu32[0] = (uint32_t)uRetRip;
4961 StkPtr.pu16[2] = uRetCs;
4962 if (fWithStack)
4963 {
4964 StkPtr.pb += cbImm;
4965 StkPtr.pu32[2] = (uint32_t)uRetRsp;
4966 StkPtr.pu16[6] = uRetSs;
4967 }
4968 }
4969 else
4970 {
4971 StkPtr.pu64[0] = uRetRip;
4972 StkPtr.pu16[4] = uRetCs;
4973 if (fWithStack)
4974 {
4975 StkPtr.pb += cbImm;
4976 StkPtr.pu64[2] = uRetRsp;
4977 StkPtr.pu16[12] = uRetSs;
4978 }
4979 }
4980}
4981
4982
4983/**
4984 * Entrypoint for FAR RET tests.
4985 *
4986 * @returns 0 or BS3TESTDOMODE_SKIPPED.
4987 * @param bMode The CPU mode we're testing.
4988 */
4989BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_far_ret)(uint8_t bMode)
4990{
4991 BS3TRAPFRAME TrapCtx;
4992 BS3REGCTX Ctx;
4993 BS3REGCTX CtxExpected;
4994 unsigned iTest;
4995 unsigned iSubTest;
4996 BS3PTRUNION StkPtr;
4997
4998#define LOW_UD_ADDR 0x0609
4999 uint8_t BS3_FAR * const pbLowUd = BS3_FP_MAKE(BS3_FP_SEG(&StkPtr), LOW_UD_ADDR);
5000#define LOW_SALC_UD_ADDR 0x0611
5001 uint8_t BS3_FAR * const pbLowSalcUd = BS3_FP_MAKE(BS3_FP_SEG(&StkPtr), LOW_SALC_UD_ADDR);
5002#define LOW_SWAPGS_ADDR 0x061d
5003 uint8_t BS3_FAR * const pbLowSwapGs = BS3_FP_MAKE(BS3_FP_SEG(&StkPtr), LOW_SWAPGS_ADDR);
5004#define BS3TEXT16_ADDR_HI (BS3_ADDR_BS3TEXT16 >> 16)
5005
5006 /* make sure they're allocated */
5007 Bs3MemZero(&Ctx, sizeof(Ctx));
5008 Bs3MemZero(&CtxExpected, sizeof(Ctx));
5009 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
5010
5011 bs3CpuBasic2_SetGlobals(bMode);
5012
5013 //if (!BS3_MODE_IS_64BIT_SYS(bMode) && bMode != BS3_MODE_PP32_16) return 0xff;
5014 //if (bMode != BS3_MODE_LM64) return 0xff;
5015
5016 /*
5017 * When dealing retf with 16-bit effective operand size to 32-bit or 64-bit
5018 * code, we're restricted to a 16-bit address. So, we plant a UD
5019 * instruction below 64KB that we can target with flat 32/64 code segments.
5020 * (Putting it on the stack would be possible too, but we'd have to create
5021 * the sub-test tables dynamically, which isn't necessary.)
5022 */
5023 Bs3MemSet(&pbLowUd[-9], 0xcc, 32);
5024 Bs3MemSet(&pbLowSalcUd[-9], 0xcc, 32);
5025 Bs3MemSet(&pbLowSwapGs[-9], 0xcc, 32);
5026
5027 pbLowUd[0] = 0x0f; /* ud2 */
5028 pbLowUd[1] = 0x0b;
5029
5030 /* A variation to detect whether we're in 64-bit or 16-bit mode when
5031 executing the code. */
5032 pbLowSalcUd[0] = 0xd6; /* salc */
5033 pbLowSalcUd[1] = 0x0f; /* ud2 */
5034 pbLowSalcUd[2] = 0x0b;
5035
5036 /* A variation to check that we're not in 64-bit mode. */
5037 pbLowSwapGs[0] = 0x0f; /* swapgs */
5038 pbLowSwapGs[1] = 0x01;
5039 pbLowSwapGs[2] = 0xf8;
5040
5041 /*
5042 * Use separate stacks for all relevant CPU exceptions so we can put
5043 * garbage in unused RSP bits w/o needing to care about where a long mode
5044 * handler will end up when accessing the whole RSP. (Not an issue with
5045 * 16-bit and 32-bit protected mode kernels, as here the weird SS based
5046 * stack pointer handling is in effect and the exception handler code
5047 * will just continue using the same SS and same portion of RSP.)
5048 *
5049 * See r154660.
5050 */
5051 if (BS3_MODE_IS_64BIT_SYS(bMode))
5052 Bs3Trap64InitEx(true);
5053
5054 /*
5055 * Create some call gates and whatnot for the UD2 code using the spare selectors.
5056 */
5057 if (BS3_MODE_IS_64BIT_SYS(bMode))
5058 for (iTest = 0; iTest < 16; iTest++)
5059 Bs3SelSetupGate64(&Bs3GdteSpare00 + iTest * 2, iTest /*bType*/, 3 /*bDpl*/,
5060 BS3_SEL_R0_CS64, BS3_FP_OFF(bs3CpuBasic2_ud2) + BS3_ADDR_BS3TEXT16);
5061 else
5062 {
5063 for (iTest = 0; iTest < 16; iTest++)
5064 {
5065 Bs3SelSetupGate(&Bs3GdteSpare00 + iTest, iTest /*bType*/, 3 /*bDpl*/,
5066 BS3_SEL_R0_CS16, BS3_FP_OFF(bs3CpuBasic2_ud2), 0);
5067 Bs3SelSetupGate(&Bs3GdteSpare00 + iTest + 16, iTest /*bType*/, 3 /*bDpl*/,
5068 BS3_SEL_R0_CS32, BS3_FP_OFF(bs3CpuBasic2_ud2) + BS3_ADDR_BS3TEXT16, 0);
5069 }
5070 }
5071
5072 /*
5073 * Create a context.
5074 *
5075 * ASSUMES we're in on the ring-0 stack in ring-0 and using less than 16KB.
5076 */
5077 Bs3RegCtxSaveEx(&Ctx, bMode, 768);
5078 Ctx.rsp.u = BS3_ADDR_STACK - _16K;
5079 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
5080
5081 StkPtr.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
5082 //Bs3TestPrintf("Stack=%p rsp=%RX64\n", StkPtr.pv, Ctx.rsp.u);
5083
5084 /*
5085 * 16-bit tests.
5086 */
5087 if (BS3_MODE_IS_16BIT_CODE(bMode))
5088 {
5089 static struct
5090 {
5091 bool fOpSizePfx;
5092 uint16_t cbImm;
5093 FPFNBS3FAR pfnTest;
5094 } const s_aTests[] =
5095 {
5096 { false, 0, bs3CpuBasic2_retf_c16, },
5097 { true, 0, bs3CpuBasic2_retf_opsize_c16, },
5098 { false, 32, bs3CpuBasic2_retf_i32_c16, },
5099 { true, 32, bs3CpuBasic2_retf_i32_opsize_c16, },
5100 };
5101
5102 static struct
5103 {
5104 bool fRmOrV86;
5105 bool fInterPriv;
5106 int8_t iXcpt;
5107 RTSEL uStartSs;
5108 uint8_t cDstBits;
5109 RTSEL uDstCs;
5110 union /* must use a union here as the compiler won't compile if uint16_t and will mess up fixups for uint32_t. */
5111 {
5112 uint32_t offDst;
5113 struct
5114 {
5115 NPVOID pv;
5116 uint16_t uHigh;
5117 } s;
5118 };
5119 RTSEL uDstSs;
5120 uint16_t uErrCd;
5121 } const s_aSubTests[] =
5122 { /* rm/v86, PriChg, Xcpt, uStartSs, => bits uDstCs offDst/pv uDstSs uErrCd */
5123 { true, false, -1, 0, 16, BS3_SEL_TEXT16, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, 0, 0 },
5124 { false, false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_TEXT16 | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5125 { false, false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5126 { false, false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5127 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, 0 },
5128 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, 0 },
5129 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS32 | 1, 0 },
5130 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS32 | 1, 0 },
5131 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5132 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5133 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS32 | 2, 0 },
5134 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS32 | 2, 0 },
5135 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5136 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5137 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS32 | 3, 0 },
5138 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS32 | 3, 0 },
5139 /* conforming stuff */
5140 { false, false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5141 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, 0 },
5142 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 1, BS3_SEL_R0_SS16 },
5143 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16_CNF | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5144 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16_CNF | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5145 { false, false, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R1_CS16_CNF },
5146 { false, false, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R1_CS16_CNF },
5147 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, 0 },
5148 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16_CNF | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5149 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16_CNF | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5150 { false, false, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R2_CS16_CNF },
5151 { false, false, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R2_CS16_CNF },
5152 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R2_CS16_CNF },
5153 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R2_CS16_CNF },
5154 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16_CNF | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5155 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16_CNF | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5156 { false, false, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R3_CS16_CNF },
5157 { false, false, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R3_CS16_CNF },
5158 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R3_CS16_CNF },
5159 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R3_CS16_CNF },
5160 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS16_CNF },
5161 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 2, BS3_SEL_R3_CS16_CNF },
5162 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16_CNF | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5163 /* returning to 32-bit code: */
5164 { false, false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5165 { false, false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS16 | 0, 0 },
5166 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5167 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
5168 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5169 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
5170 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5171 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
5172 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5173 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
5174 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5175 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
5176 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5177 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
5178 { false, false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5179 { false, false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, 0 },
5180 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5181 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
5182 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5183 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
5184 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5185 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
5186 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5187 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
5188 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5189 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
5190 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5191 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
5192 /* returning to 32-bit conforming code: */
5193 { false, false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5194 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5195 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 1, BS3_SEL_R0_SS16 },
5196 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R0_SS16 },
5197 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 1, BS3_SEL_R3_SS16 },
5198 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, BS3_SEL_R3_SS16 },
5199 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5200 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5201 { false, false, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R1_CS32_CNF },
5202 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5203 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 1, BS3_SEL_R0_SS16 },
5204 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R0_SS16 },
5205 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 1, BS3_SEL_R3_SS16 },
5206 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, BS3_SEL_R3_SS16 },
5207 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5208 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5209 { false, false, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R2_CS32_CNF },
5210 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R2_CS32_CNF },
5211 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5212 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5213 { false, false, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R3_CS32_CNF },
5214 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R3_CS32_CNF },
5215 { false, true, 42, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS32_CNF },
5216 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5217 /* returning to 64-bit code or 16-bit when not in long mode: */
5218 { false, false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5219 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5220 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5221 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5222 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_DS64 | 1, BS3_SEL_R0_DS64 },
5223 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_DS64 | 1, 0 },
5224 { false, false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5225 { false, true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5226 { false, true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5227 { false, true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5228 { false, true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5229 { false, true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5230 { false, true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5231 { false, true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R2_CS64 },
5232 { false, true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 3, BS3_SEL_R2_CS64 },
5233 { false, true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 3, BS3_SEL_R1_SS32 },
5234 { false, true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 2, BS3_SEL_R3_SS32 },
5235 /* returning to 64-bit code or 16-bit when not in long mode, conforming code variant: */
5236 { false, false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5237 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5238 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5239 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5240
5241 { false, false, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R1_CS64_CNF },
5242 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5243 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 2, BS3_SEL_R1_SS16 },
5244 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 1, BS3_SEL_R2_SS16 },
5245 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R2_SS16 },
5246 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5247 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5248
5249 { false, false, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R2_CS64_CNF },
5250 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R2_CS64_CNF },
5251 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5252 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5253
5254 { false, false, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R3_CS64_CNF },
5255 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R3_CS64_CNF },
5256 { false, true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS64_CNF },
5257 { false, true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5258
5259 /* some additional #GP variations */ /** @todo test all possible exceptions! */
5260 { false, true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS16 },
5261 { false, true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_TSS32_DF | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_TSS32_DF },
5262 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_00 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_00 },
5263 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_01 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_01 },
5264 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_02 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_02 },
5265 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_03 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_03 },
5266 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_04 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_04 },
5267 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_05 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_05 },
5268 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_06 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_06 },
5269 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_07 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_07 },
5270 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_08 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_08 },
5271 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_09 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_09 },
5272 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_0a | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_0a },
5273 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_0b | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_0b },
5274 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_0c | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_0c },
5275 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_0d | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_0d },
5276 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_0e | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_0e },
5277 { false, true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_SPARE_0f | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_0f },
5278 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_10 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_10 },
5279 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_11 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_11 },
5280 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_12 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_12 },
5281 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_13 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_13 },
5282 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_14 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_14 },
5283 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_15 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_15 },
5284 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_16 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_16 },
5285 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_17 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_17 },
5286 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_18 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_18 },
5287 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_19 | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_19 },
5288 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_1a | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_1a },
5289 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_1b | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_1b },
5290 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_1c | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_1c },
5291 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_1d | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_1d },
5292 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_1e | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_1e },
5293 { false, true, 14, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_SPARE_1f | 0, { .offDst = 0 }, BS3_SEL_R0_SS16 | 0, BS3_SEL_SPARE_1f },
5294 };
5295
5296 bool const fRmOrV86 = BS3_MODE_IS_RM_OR_V86(bMode);
5297
5298 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5299 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
5300 {
5301 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
5302
5303 for (iSubTest = 0; iSubTest < RT_ELEMENTS(s_aSubTests); iSubTest++)
5304 {
5305 g_usBs3TestStep = (iTest << 12) | (iSubTest << 4);
5306 if ( s_aSubTests[iSubTest].fRmOrV86 == fRmOrV86
5307 && (s_aSubTests[iSubTest].offDst <= UINT16_MAX || s_aTests[iTest].fOpSizePfx))
5308 {
5309 uint16_t const cbFrmDisp = s_aSubTests[iSubTest].fInterPriv ? iSubTest % 7 : 0;
5310 uint16_t const cbStkItem = s_aTests[iTest].fOpSizePfx ? 4 : 2;
5311 uint16_t const cbFrame = (s_aSubTests[iSubTest].fInterPriv ? 4 : 2) * cbStkItem;
5312 uint32_t const uFlatDst = Bs3SelFar32ToFlat32(s_aSubTests[iSubTest].offDst, s_aSubTests[iSubTest].uDstCs)
5313 + (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode));
5314 RTSEL const uDstSs = s_aSubTests[iSubTest].uDstSs;
5315 uint64_t uDstRspExpect, uDstRspPush;
5316
5317 Ctx.ss = s_aSubTests[iSubTest].uStartSs;
5318 if (Ctx.ss != BS3_SEL_R0_SS32)
5319 Ctx.rsp.u32 |= UINT32_C(0xfffe0000);
5320 else
5321 Ctx.rsp.u32 &= UINT16_MAX;
5322 uDstRspExpect = uDstRspPush = Ctx.rsp.u + s_aTests[iTest].cbImm + cbFrame + cbFrmDisp;
5323 if (s_aSubTests[iSubTest].fInterPriv)
5324 {
5325 if (s_aTests[iTest].fOpSizePfx)
5326 uDstRspPush = (uDstRspPush & UINT16_MAX) | UINT32_C(0xacdc0000);
5327 if ( uDstSs == (BS3_SEL_R1_SS32 | 1)
5328 || uDstSs == (BS3_SEL_R2_SS32 | 2)
5329 || uDstSs == (BS3_SEL_R3_SS32 | 3)
5330 || (s_aSubTests[iSubTest].cDstBits == 64 && BS3_MODE_IS_64BIT_SYS(bMode)))
5331 {
5332 if (s_aTests[iTest].fOpSizePfx)
5333 uDstRspExpect = uDstRspPush;
5334 else
5335 uDstRspExpect &= UINT16_MAX;
5336 }
5337 }
5338
5339 CtxExpected.bCpl = Ctx.bCpl;
5340 CtxExpected.cs = Ctx.cs;
5341 CtxExpected.ss = Ctx.ss;
5342 CtxExpected.ds = Ctx.ds;
5343 CtxExpected.es = Ctx.es;
5344 CtxExpected.fs = Ctx.fs;
5345 CtxExpected.gs = Ctx.gs;
5346 CtxExpected.rip.u = Ctx.rip.u;
5347 CtxExpected.rsp.u = Ctx.rsp.u;
5348 CtxExpected.rax.u = Ctx.rax.u;
5349 if (s_aSubTests[iSubTest].iXcpt < 0)
5350 {
5351 CtxExpected.cs = s_aSubTests[iSubTest].uDstCs;
5352 CtxExpected.rip.u = s_aSubTests[iSubTest].offDst;
5353 if (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5354 {
5355 CtxExpected.rip.u += 1;
5356 CtxExpected.rax.au8[0] = CtxExpected.rflags.u16 & X86_EFL_CF ? 0xff : 0;
5357 }
5358 CtxExpected.ss = uDstSs;
5359 CtxExpected.rsp.u = uDstRspExpect;
5360 if (s_aSubTests[iSubTest].fInterPriv)
5361 {
5362 uint16_t BS3_FAR *puSel = &CtxExpected.ds; /* ASSUME member order! */
5363 unsigned cSels = 4;
5364 CtxExpected.bCpl = CtxExpected.ss & X86_SEL_RPL;
5365 while (cSels-- > 0)
5366 {
5367 uint16_t uSel = *puSel;
5368 if ( (uSel & X86_SEL_MASK_OFF_RPL)
5369 && Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u2Dpl < CtxExpected.bCpl
5370 && (Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5371 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5372 *puSel = 0;
5373 puSel++;
5374 }
5375 CtxExpected.rsp.u += s_aTests[iTest].cbImm; /* arguments are dropped from both stacks. */
5376 }
5377 }
5378 g_uBs3TrapEipHint = CtxExpected.rip.u32;
5379 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
5380 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64 -> %04RX16:%04RX64 [pushed %#RX64]\n", Ctx.ss, Ctx.rsp.u, CtxExpected.ss, CtxExpected.rsp.u, uDstRspPush);
5381 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5382 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5383 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5384 //Bs3TestPrintf("%p: %04RX16 %04RX16 %04RX16 %04RX16\n", StkPtr.pu16, StkPtr.pu16[0], StkPtr.pu16[1], StkPtr.pu16[2], StkPtr.pu16[3]);
5385 //Bs3TestPrintf("%.48Rhxd\n", StkPtr.pu16);
5386 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5387 if (s_aSubTests[iSubTest].iXcpt < 0)
5388 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5389 else
5390 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5391 g_usBs3TestStep++; /* 1 */
5392
5393 /* Bad hw bp: Setup DR0-3 but use invalid length encodings (non-byte) */
5394 //Bs3TestPrintf("hw bp: bad len\n");
5395 Bs3RegSetDr0(uFlatDst);
5396 Bs3RegSetDr1(uFlatDst);
5397 Bs3RegSetDr2(uFlatDst);
5398 Bs3RegSetDr3(uFlatDst);
5399 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5400 Bs3RegSetDr7(X86_DR7_INIT_VAL
5401 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_WORD) | X86_DR7_L_G(1)
5402 | X86_DR7_RW(2, X86_DR7_RW_EO) | X86_DR7_LEN(2, X86_DR7_LEN_DWORD) | X86_DR7_L_G(2)
5403 | ( BS3_MODE_IS_64BIT_SYS(bMode)
5404 ? X86_DR7_RW(3, X86_DR7_RW_EO) | X86_DR7_LEN(3, X86_DR7_LEN_QWORD) | X86_DR7_L_G(3) : 0) );
5405 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5406 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5407 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5408 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5409 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5410 if (s_aSubTests[iSubTest].iXcpt < 0)
5411 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5412 else
5413 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5414 bs3CpuBasic2_CheckDr6InitVal();
5415 g_usBs3TestStep++; /* 2 */
5416
5417 /* Bad hw bp: setup DR0-3 but don't enable them */
5418 //Bs3TestPrintf("hw bp: disabled\n");
5419 //Bs3RegSetDr0(uFlatDst);
5420 //Bs3RegSetDr1(uFlatDst);
5421 //Bs3RegSetDr2(uFlatDst);
5422 //Bs3RegSetDr3(uFlatDst);
5423 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5424 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5425 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5426 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5427 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5428 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5429 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5430 if (s_aSubTests[iSubTest].iXcpt < 0)
5431 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5432 else
5433 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5434 bs3CpuBasic2_CheckDr6InitVal();
5435 g_usBs3TestStep++; /* 3 */
5436
5437 /* Bad hw bp: Points at 2nd byte in the UD2. Docs says it only works when pointing at first byte. */
5438 //Bs3TestPrintf("hw bp: byte 2\n");
5439 Bs3RegSetDr0(uFlatDst + 1);
5440 Bs3RegSetDr1(uFlatDst + 1);
5441 //Bs3RegSetDr2(uFlatDst);
5442 //Bs3RegSetDr3(uFlatDst);
5443 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5444 Bs3RegSetDr7(X86_DR7_INIT_VAL
5445 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_L_G(0)
5446 | X86_DR7_RW(1, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1));
5447 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5448 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5449 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5450 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5451 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5452 if (s_aSubTests[iSubTest].iXcpt < 0)
5453 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5454 else
5455 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5456 bs3CpuBasic2_CheckDr6InitVal();
5457 g_usBs3TestStep++; /* 4 */
5458
5459 /* Again with two correctly hardware breakpoints and a disabled one that just matches the address: */
5460 //Bs3TestPrintf("bp 1 + 3...\n");
5461 Bs3RegSetDr0(uFlatDst);
5462 Bs3RegSetDr1(uFlatDst);
5463 Bs3RegSetDr2(0);
5464 Bs3RegSetDr3(uFlatDst);
5465 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5466 Bs3RegSetDr7(X86_DR7_INIT_VAL
5467 | X86_DR7_RW(1, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1)
5468 | X86_DR7_RW(3, X86_DR7_RW_EO) | X86_DR7_LEN(3, X86_DR7_LEN_BYTE) | X86_DR7_L_G(3) );
5469 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5470 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5471 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5472 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5473 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5474 if (s_aSubTests[iSubTest].iXcpt < 0)
5475 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B3);
5476 else
5477 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5478 g_usBs3TestStep++; /* 5 */
5479
5480 /* Again with a single locally enabled breakpoint. */
5481 //Bs3TestPrintf("bp 0/l...\n");
5482 Bs3RegSetDr0(uFlatDst);
5483 Bs3RegSetDr1(0);
5484 Bs3RegSetDr2(0);
5485 Bs3RegSetDr3(0);
5486 Bs3RegSetDr6(X86_DR6_INIT_VAL | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BS);
5487 Bs3RegSetDr7(X86_DR7_INIT_VAL
5488 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_L(0));
5489 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5490 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5491 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5492 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5493 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5494 if (s_aSubTests[iSubTest].iXcpt < 0)
5495 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_B0 | X86_DR6_BS); /* B0-B3 set, BS preserved */
5496 else
5497 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5498 g_usBs3TestStep++; /* 6 */
5499
5500 /* Again with a single globally enabled breakpoint and serveral other types of breakpoints configured but not enabled. */
5501 //Bs3TestPrintf("bp 2/g+...\n");
5502 Bs3RegSetDr0(uFlatDst);
5503 Bs3RegSetDr1(uFlatDst);
5504 Bs3RegSetDr2(uFlatDst);
5505 Bs3RegSetDr3(uFlatDst);
5506 Bs3RegSetDr6(X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BD | X86_DR6_BT | X86_DR6_B2);
5507 Bs3RegSetDr7(X86_DR7_INIT_VAL
5508 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE)
5509 | X86_DR7_RW(1, X86_DR7_RW_RW) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1)
5510 | X86_DR7_RW(2, X86_DR7_RW_EO) | X86_DR7_LEN(2, X86_DR7_LEN_BYTE) | X86_DR7_G(2)
5511 | X86_DR7_RW(3, X86_DR7_RW_WO) | X86_DR7_LEN(3, X86_DR7_LEN_BYTE) | X86_DR7_G(3)
5512 );
5513 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5514 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5515 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5516 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5517 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5518 if (s_aSubTests[iSubTest].iXcpt < 0)
5519 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_B2 | X86_DR6_BS | X86_DR6_BD | X86_DR6_BT);
5520 else
5521 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5522 g_usBs3TestStep++; /* 7 */
5523
5524 /* Now do single stepping: */
5525 //Bs3TestPrintf("stepping...\n");
5526 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5527 Ctx.rflags.u16 |= X86_EFL_TF;
5528 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5529 if (s_aSubTests[iSubTest].iXcpt < 0 && s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5530 {
5531 CtxExpected.rip.u -= 1;
5532 CtxExpected.rax.u = Ctx.rax.u;
5533 }
5534 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5535 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5536 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5537 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5538 if (s_aSubTests[iSubTest].iXcpt < 0)
5539 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
5540 else
5541 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5542 Ctx.rflags.u16 &= ~X86_EFL_TF;
5543 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5544 g_usBs3TestStep++; /* 8 */
5545
5546 /* Single step with B0-B3 set to check that they're not preserved
5547 and with BD & BT to check that they are (checked on Intel 6700K): */
5548 //Bs3TestPrintf("stepping b0-b3+bd+bt=1...\n");
5549 Bs3RegSetDr6(X86_DR6_INIT_VAL | X86_DR6_B_MASK | X86_DR6_BD | X86_DR6_BT);
5550 Ctx.rflags.u16 |= X86_EFL_TF;
5551 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5552 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5553 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5554 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5555 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5556 if (s_aSubTests[iSubTest].iXcpt < 0)
5557 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS | X86_DR6_BD | X86_DR6_BT);
5558 else
5559 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5560 Ctx.rflags.u16 &= ~X86_EFL_TF;
5561 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5562 g_usBs3TestStep++; /* 9 */
5563
5564 }
5565 }
5566 }
5567 }
5568 /*
5569 * 32-bit tests.
5570 */
5571 else if (BS3_MODE_IS_32BIT_CODE(bMode))
5572 {
5573 static struct
5574 {
5575 bool fOpSizePfx;
5576 uint16_t cbImm;
5577 FPFNBS3FAR pfnTest;
5578 } const s_aTests[] =
5579 {
5580 { false, 0, bs3CpuBasic2_retf_c32, },
5581 { true, 0, bs3CpuBasic2_retf_opsize_c32, },
5582 { false, 32, bs3CpuBasic2_retf_i32_c32, },
5583 { true, 32, bs3CpuBasic2_retf_i32_opsize_c32, },
5584 };
5585
5586 static struct
5587 {
5588 bool fInterPriv;
5589 int8_t iXcpt;
5590 RTSEL uStartSs;
5591 uint8_t cDstBits;
5592 RTSEL uDstCs;
5593 union /* must use a union here as the compiler won't compile if uint16_t and will mess up fixups for uint32_t. */
5594 {
5595 uint32_t offDst;
5596 struct
5597 {
5598 NPVOID pv;
5599 uint16_t uHigh;
5600 } s;
5601 };
5602 RTSEL uDstSs;
5603 uint16_t uErrCd;
5604 } const s_aSubTests[] =
5605 { /* PriChg, Xcpt, uStartSs, => bits uDstCs offDst/pv uDstSs uErrCd */
5606 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5607 { false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5608 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5609 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5610 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5611 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5612 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5613 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5614 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5615 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5616 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5617 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5618 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5619 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5620 /* same with 32-bit wide target addresses: */
5621 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, 0 },
5622 { false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, 0 },
5623 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
5624 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
5625 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
5626 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
5627 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
5628 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
5629 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
5630 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
5631 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
5632 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
5633 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
5634 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
5635 /* conforming stuff */
5636 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5637 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5638 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
5639 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5640 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5641 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R1_CS32_CNF },
5642 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R1_CS32_CNF },
5643 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5644 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5645 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5646 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS32_CNF },
5647 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS32_CNF },
5648 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS32_CNF },
5649 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS32_CNF },
5650 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5651 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5652 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS32_CNF },
5653 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS32_CNF },
5654 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS32_CNF },
5655 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS32_CNF },
5656 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, BS3_SEL_R3_CS32_CNF },
5657 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 2, BS3_SEL_R3_CS32_CNF },
5658 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5659 /* returning to 16-bit code: */
5660 { false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, 0 },
5661 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
5662 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
5663 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5664 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
5665 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5666 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
5667 { false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS16 | 0, 0 },
5668 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
5669 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
5670 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
5671 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5672 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
5673 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5674 /* returning to 16-bit conforming code: */
5675 { false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, 0 },
5676 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
5677 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
5678 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R0_SS32 },
5679 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 1, BS3_SEL_R3_SS32 },
5680 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R3_SS32 },
5681 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
5682 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5683 { false, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R1_CS16_CNF },
5684 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
5685 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
5686 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R0_SS32 },
5687 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 1, BS3_SEL_R3_SS32 },
5688 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R3_SS32 },
5689 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5690 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5691 { false, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS16_CNF },
5692 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS16_CNF },
5693 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5694 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
5695 { false, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS16_CNF },
5696 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS16_CNF },
5697 { true, 42, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, BS3_SEL_R3_CS16_CNF },
5698 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5699 /* returning to 64-bit code or 16-bit when not in long mode: */
5700 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5701 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5702 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5703 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5704 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_DS64 | 1, BS3_SEL_R0_DS64 },
5705 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_DS64 | 1, 0 },
5706 { false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5707 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5708 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5709 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5710 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5711 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5712 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5713 { true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R2_CS64 },
5714 { true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 3, BS3_SEL_R2_CS64 },
5715 { true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 3, BS3_SEL_R1_SS32 },
5716 { true, 14, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 2, BS3_SEL_R3_SS32 },
5717 /* returning to 64-bit code or 16-bit when not in long mode, conforming code variant: */
5718 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5719 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5720 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5721 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5722
5723 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R1_CS64_CNF },
5724 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5725 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 2, BS3_SEL_R1_SS16 },
5726 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 1, BS3_SEL_R2_SS16 },
5727 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R2_SS16 },
5728 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5729 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5730
5731 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R2_CS64_CNF },
5732 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R2_CS64_CNF },
5733 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5734 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5735
5736 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, BS3_SEL_R3_CS64_CNF },
5737 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, BS3_SEL_R3_CS64_CNF },
5738 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS64_CNF },
5739 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5740
5741 /* some additional #GP variations */ /** @todo test all possible exceptions! */
5742 { true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS16 },
5743 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_00 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_00 },
5744 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_01 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_01 },
5745 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_02 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_02 },
5746 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_03 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_03 },
5747 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_04 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_04 },
5748 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_05 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_05 },
5749 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_06 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_06 },
5750 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_07 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_07 },
5751 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_08 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_08 },
5752 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_09 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_09 },
5753 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0a },
5754 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0b | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0b },
5755 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0c },
5756 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0d | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0d },
5757 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0e },
5758 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0f | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0f },
5759 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_10 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_10 },
5760 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_11 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_11 },
5761 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_12 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_12 },
5762 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_13 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_13 },
5763 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_14 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_14 },
5764 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_15 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_15 },
5765 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_16 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_16 },
5766 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_17 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_17 },
5767 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_18 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_18 },
5768 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_19 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_19 },
5769 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1a },
5770 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1b | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1b },
5771 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1c },
5772 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1d | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1d },
5773 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1e },
5774 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1f | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1f },
5775 };
5776
5777 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
5778 {
5779 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
5780 //Bs3TestPrintf("-------------- #%u: cs:eip=%04RX16:%08RX64 imm=%u%s\n",
5781 // iTest, Ctx.cs, Ctx.rip.u, s_aTests[iTest].cbImm, s_aTests[iTest].fOpSizePfx ? " o16" : "");
5782
5783 for (iSubTest = 0; iSubTest < RT_ELEMENTS(s_aSubTests); iSubTest++)
5784 {
5785 g_usBs3TestStep = (iTest << 12) | (iSubTest << 1);
5786 if (!s_aTests[iTest].fOpSizePfx || s_aSubTests[iSubTest].offDst <= UINT16_MAX)
5787 {
5788 uint16_t const cbFrmDisp = s_aSubTests[iSubTest].fInterPriv ? iSubTest % 7 : 0;
5789 uint16_t const cbStkItem = s_aTests[iTest].fOpSizePfx ? 2 : 4;
5790 uint16_t const cbFrame = (s_aSubTests[iSubTest].fInterPriv ? 4 : 2) * cbStkItem;
5791 RTSEL const uDstSs = s_aSubTests[iSubTest].uDstSs;
5792 uint64_t uDstRspExpect, uDstRspPush;
5793 //Bs3TestPrintf(" #%u: %s %d %#04RX16 -> %u %#04RX16:%#04RX32 %#04RX16 %#RX16\n", iSubTest, s_aSubTests[iSubTest].fInterPriv ? "priv" : "same", s_aSubTests[iSubTest].iXcpt, s_aSubTests[iSubTest].uStartSs,
5794 // s_aSubTests[iSubTest].cDstBits, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst, s_aSubTests[iSubTest].uDstSs, s_aSubTests[iSubTest].uErrCd);
5795
5796 Ctx.ss = s_aSubTests[iSubTest].uStartSs;
5797 if (Ctx.ss != BS3_SEL_R0_SS32)
5798 Ctx.rsp.u32 |= UINT32_C(0xfffe0000);
5799 else
5800 Ctx.rsp.u32 &= UINT16_MAX;
5801 uDstRspExpect = uDstRspPush = Ctx.rsp.u + s_aTests[iTest].cbImm + cbFrame + cbFrmDisp;
5802 if (s_aSubTests[iSubTest].fInterPriv)
5803 {
5804 if (!s_aTests[iTest].fOpSizePfx)
5805 uDstRspPush = (uDstRspPush & UINT16_MAX) | UINT32_C(0xacdc0000);
5806 if ( uDstSs == (BS3_SEL_R1_SS32 | 1)
5807 || uDstSs == (BS3_SEL_R2_SS32 | 2)
5808 || uDstSs == (BS3_SEL_R3_SS32 | 3)
5809 || (s_aSubTests[iSubTest].cDstBits == 64 && BS3_MODE_IS_64BIT_SYS(bMode)))
5810 {
5811 if (!s_aTests[iTest].fOpSizePfx)
5812 uDstRspExpect = uDstRspPush;
5813 else
5814 uDstRspExpect &= UINT16_MAX;
5815 }
5816 }
5817
5818 CtxExpected.bCpl = Ctx.bCpl;
5819 CtxExpected.cs = Ctx.cs;
5820 CtxExpected.ss = Ctx.ss;
5821 CtxExpected.ds = Ctx.ds;
5822 CtxExpected.es = Ctx.es;
5823 CtxExpected.fs = Ctx.fs;
5824 CtxExpected.gs = Ctx.gs;
5825 CtxExpected.rip.u = Ctx.rip.u;
5826 CtxExpected.rsp.u = Ctx.rsp.u;
5827 CtxExpected.rax.u = Ctx.rax.u;
5828 if (s_aSubTests[iSubTest].iXcpt < 0)
5829 {
5830 CtxExpected.cs = s_aSubTests[iSubTest].uDstCs;
5831 CtxExpected.rip.u = s_aSubTests[iSubTest].offDst;
5832 if (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5833 {
5834 CtxExpected.rip.u += 1;
5835 CtxExpected.rax.au8[0] = CtxExpected.rflags.u16 & X86_EFL_CF ? 0xff : 0;
5836 }
5837 CtxExpected.ss = uDstSs;
5838 CtxExpected.rsp.u = uDstRspExpect;
5839 if (s_aSubTests[iSubTest].fInterPriv)
5840 {
5841 uint16_t BS3_FAR *puSel = &CtxExpected.ds; /* ASSUME member order! */
5842 unsigned cSels = 4;
5843 CtxExpected.bCpl = CtxExpected.ss & X86_SEL_RPL;
5844 while (cSels-- > 0)
5845 {
5846 uint16_t uSel = *puSel;
5847 if ( (uSel & X86_SEL_MASK_OFF_RPL)
5848 && Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u2Dpl < CtxExpected.bCpl
5849 && (Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5850 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5851 *puSel = 0;
5852 puSel++;
5853 }
5854 CtxExpected.rsp.u += s_aTests[iTest].cbImm; /* arguments are dropped from both stacks. */
5855 }
5856 }
5857 g_uBs3TrapEipHint = CtxExpected.rip.u32;
5858 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64 -> %04RX16:%04RX64 [pushed %#RX64]; %04RX16:%04RX64\n",Ctx.ss, Ctx.rsp.u,
5859 // CtxExpected.ss, CtxExpected.rsp.u, uDstRspPush, CtxExpected.cs, CtxExpected.rip.u);
5860 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5861 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5862 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5863 //Bs3TestPrintf("%p: %04RX16 %04RX16 %04RX16 %04RX16\n", StkPtr.pu16, StkPtr.pu16[0], StkPtr.pu16[1], StkPtr.pu16[2], StkPtr.pu16[3]);
5864 //Bs3TestPrintf("%.48Rhxd\n", StkPtr.pu16);
5865 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5866 if (s_aSubTests[iSubTest].iXcpt < 0)
5867 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5868 else
5869 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5870 g_usBs3TestStep++;
5871
5872 /* Again single stepping: */
5873 //Bs3TestPrintf("stepping...\n");
5874 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5875 Ctx.rflags.u16 |= X86_EFL_TF;
5876 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5877 if (s_aSubTests[iSubTest].iXcpt < 0 && s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5878 {
5879 CtxExpected.rip.u -= 1;
5880 CtxExpected.rax.u = Ctx.rax.u;
5881 }
5882 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5883 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5884 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5885 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5886 if (s_aSubTests[iSubTest].iXcpt < 0)
5887 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
5888 else
5889 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5890 Ctx.rflags.u16 &= ~X86_EFL_TF;
5891 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5892 g_usBs3TestStep++;
5893 }
5894 }
5895 }
5896 }
5897 /*
5898 * 64-bit tests.
5899 */
5900 else if (BS3_MODE_IS_64BIT_CODE(bMode))
5901 {
5902 static struct
5903 {
5904 uint8_t fOpSizePfx; /**< 0: none, 1: 066h, 2: REX.W; Effective op size prefix. */
5905 uint16_t cbImm;
5906 FPFNBS3FAR pfnTest;
5907 } const s_aTests[] =
5908 {
5909 { 0, 0, bs3CpuBasic2_retf_c64, },
5910 { 1, 0, bs3CpuBasic2_retf_opsize_c64, },
5911 { 0, 32, bs3CpuBasic2_retf_i32_c64, },
5912 { 1, 32, bs3CpuBasic2_retf_i32_opsize_c64, },
5913 { 2, 0, bs3CpuBasic2_retf_rexw_c64, },
5914 { 2, 0, bs3CpuBasic2_retf_opsize_rexw_c64, },
5915 { 1, 0, bs3CpuBasic2_retf_rexw_opsize_c64, },
5916 { 2, 24, bs3CpuBasic2_retf_i24_rexw_c64, },
5917 { 2, 24, bs3CpuBasic2_retf_i24_opsize_rexw_c64, },
5918 { 1, 24, bs3CpuBasic2_retf_i24_rexw_opsize_c64, },
5919 };
5920
5921 static struct
5922 {
5923 bool fInterPriv;
5924 int8_t iXcpt;
5925 RTSEL uStartSs;
5926 uint8_t cDstBits;
5927 RTSEL uDstCs;
5928 union /* must use a union here as the compiler won't compile if uint16_t and will mess up fixups for uint32_t. */
5929 {
5930 uint32_t offDst;
5931 struct
5932 {
5933 NPVOID pv;
5934 uint16_t uHigh;
5935 } s;
5936 };
5937 RTSEL uDstSs;
5938 uint16_t uErrCd;
5939 } const s_aSubTests[] =
5940 { /* PriChg, Xcpt, uStartSs, => bits uDstCs offDst/pv uDstSs uErrCd */
5941 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5942 { false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5943 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5944 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5945 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5946 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5947 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5948 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5949 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5950 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5951 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5952 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5953 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5954 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5955 /* same with 32-bit wide target addresses: */
5956 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64 | 0, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, 0 },
5957 { false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64 | 0, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, 0 },
5958 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
5959 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
5960 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
5961 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
5962 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
5963 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
5964 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
5965 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
5966 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
5967 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
5968 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
5969 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .s = {(NPVOID)bs3CpuBasic2_salc_ud2, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
5970 /* conforming stuff */
5971 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5972 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5973 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
5974 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5975 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5976 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R1_CS64_CNF },
5977 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R1_CS64_CNF },
5978 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5979 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5980 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5981 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS64_CNF },
5982 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS64_CNF },
5983 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS64_CNF },
5984 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS64_CNF },
5985 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5986 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5987 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS64_CNF },
5988 { false, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS64_CNF },
5989 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS64_CNF },
5990 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS64_CNF },
5991 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, BS3_SEL_R3_CS64_CNF },
5992 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 2, BS3_SEL_R3_CS64_CNF },
5993 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64_CNF | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5994 /* returning to 16-bit code: */
5995 { false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, 0 },
5996 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
5997 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
5998 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5999 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
6000 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6001 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
6002 { false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS16 | 0, 0 },
6003 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
6004 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
6005 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
6006 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
6007 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
6008 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6009 /* returning to 16-bit conforming code: */
6010 { false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, 0 },
6011 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
6012 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
6013 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R0_SS32 },
6014 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 1, BS3_SEL_R3_SS32 },
6015 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R3_SS32 },
6016 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
6017 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6018 { false, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R1_CS16_CNF },
6019 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
6020 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
6021 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R0_SS32 },
6022 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 1, BS3_SEL_R3_SS32 },
6023 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R3_SS32 },
6024 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
6025 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6026 { false, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS16_CNF },
6027 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS16_CNF },
6028 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
6029 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
6030 { false, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS16_CNF },
6031 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS16_CNF },
6032 { true, 42, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, BS3_SEL_R3_CS16_CNF },
6033 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6034 /* returning to 32-bit code - narrow 16-bit target address: */
6035 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
6036 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
6037 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
6038 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
6039 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
6040 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
6041 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
6042 { false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
6043 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
6044 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
6045 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
6046 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
6047 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
6048 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
6049 /* returning to 32-bit code - wider 32-bit target address: */
6050 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
6051 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
6052 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
6053 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
6054 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
6055 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
6056 { false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS16 | 0, 0 },
6057 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
6058 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
6059 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
6060 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
6061 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
6062 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
6063 /* returning to 32-bit conforming code: */
6064 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, 0 },
6065 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, 0 },
6066 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
6067 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R0_SS32 },
6068 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 1, BS3_SEL_R3_SS32 },
6069 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R3_SS32 },
6070 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS16 | 2, 0 },
6071 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
6072 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R1_CS32_CNF },
6073 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS16 | 1, 0 },
6074 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 1, BS3_SEL_R0_SS32 },
6075 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R0_SS32 },
6076 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 1, BS3_SEL_R3_SS32 },
6077 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, BS3_SEL_R3_SS32 },
6078 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, 0 },
6079 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
6080 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R2_CS32_CNF },
6081 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R2_CS32_CNF },
6082 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
6083 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS16 | 3, 0 },
6084 { false, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R0_SS32 | 0, BS3_SEL_R3_CS32_CNF },
6085 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R1_SS32 | 1, BS3_SEL_R3_CS32_CNF },
6086 { true, 42, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R2_SS32 | 2, BS3_SEL_R3_CS32_CNF },
6087 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, BS3TEXT16_ADDR_HI } }, BS3_SEL_R3_SS32 | 3, 0 },
6088
6089 /* some additional #GP variations */ /** @todo test all possible exceptions! */
6090 { true, 14, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, BS3_SEL_R3_CS16 },
6091
6092 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_00 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_00 },
6093 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_02 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_02 },
6094 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_04 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_04 },
6095 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_06 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_06 },
6096 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_08 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_08 },
6097 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_0a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0a },
6098 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_0c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0c },
6099 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_0e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0e },
6100 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_10 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_10 },
6101 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_12 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_12 },
6102 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_14 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_14 },
6103 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_16 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_16 },
6104 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_18 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_18 },
6105 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_1a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1a },
6106 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_1c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1c },
6107 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_1e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1e },
6108 };
6109
6110 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
6111 {
6112 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
6113 //Bs3TestPrintf("-------------- #%u: cs:eip=%04RX16:%08RX64 imm=%u%s\n", iTest, Ctx.cs, Ctx.rip.u, s_aTests[iTest].cbImm,
6114 // s_aTests[iTest].fOpSizePfx == 1 ? " o16" : s_aTests[iTest].fOpSizePfx == 2 ? " o64" : "");
6115
6116 for (iSubTest = 0; iSubTest < RT_ELEMENTS(s_aSubTests); iSubTest++)
6117 {
6118 g_usBs3TestStep = (iTest << 12) | (iSubTest << 1);
6119 if (s_aTests[iTest].fOpSizePfx != 1 || s_aSubTests[iSubTest].offDst <= UINT16_MAX)
6120 {
6121 uint16_t const cbFrmDisp = s_aSubTests[iSubTest].fInterPriv ? iSubTest % 7 : 0;
6122 uint16_t const cbStkItem = s_aTests[iTest].fOpSizePfx == 2 ? 8 : s_aTests[iTest].fOpSizePfx == 0 ? 4 : 2;
6123 uint16_t const cbFrame = (s_aSubTests[iSubTest].fInterPriv ? 4 : 2) * cbStkItem;
6124 RTSEL const uDstSs = s_aSubTests[iSubTest].uDstSs;
6125 uint64_t uDstRspExpect, uDstRspPush;
6126 //Bs3TestPrintf(" #%u: %s %d %#04RX16 -> %u %#04RX16:%#04RX32 %#04RX16 %#RX16\n", iSubTest, s_aSubTests[iSubTest].fInterPriv ? "priv" : "same", s_aSubTests[iSubTest].iXcpt, s_aSubTests[iSubTest].uStartSs,
6127 // s_aSubTests[iSubTest].cDstBits, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst, s_aSubTests[iSubTest].uDstSs, s_aSubTests[iSubTest].uErrCd);
6128
6129 Ctx.ss = s_aSubTests[iSubTest].uStartSs;
6130 uDstRspExpect = uDstRspPush = Ctx.rsp.u + s_aTests[iTest].cbImm + cbFrame + cbFrmDisp;
6131 if (s_aSubTests[iSubTest].fInterPriv)
6132 {
6133 if (s_aTests[iTest].fOpSizePfx != 1)
6134 {
6135 if (s_aTests[iTest].fOpSizePfx == 2)
6136 uDstRspPush |= UINT64_C(0xf00dfaceacdc0000);
6137 else
6138 uDstRspPush |= UINT32_C(0xacdc0000);
6139 if (s_aSubTests[iSubTest].cDstBits == 64)
6140 uDstRspExpect = uDstRspPush;
6141 else if (!BS3_SEL_IS_SS16(uDstSs))
6142 uDstRspExpect = (uint32_t)uDstRspPush;
6143 }
6144 }
6145
6146 CtxExpected.bCpl = Ctx.bCpl;
6147 CtxExpected.cs = Ctx.cs;
6148 CtxExpected.ss = Ctx.ss;
6149 CtxExpected.ds = Ctx.ds;
6150 CtxExpected.es = Ctx.es;
6151 CtxExpected.fs = Ctx.fs;
6152 CtxExpected.gs = Ctx.gs;
6153 CtxExpected.rip.u = Ctx.rip.u;
6154 CtxExpected.rsp.u = Ctx.rsp.u;
6155 CtxExpected.rax.u = Ctx.rax.u;
6156 if (s_aSubTests[iSubTest].iXcpt < 0)
6157 {
6158 CtxExpected.cs = s_aSubTests[iSubTest].uDstCs;
6159 CtxExpected.rip.u = s_aSubTests[iSubTest].offDst;
6160 if (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
6161 {
6162 CtxExpected.rip.u += 1;
6163 CtxExpected.rax.au8[0] = CtxExpected.rflags.u16 & X86_EFL_CF ? 0xff : 0;
6164 }
6165 CtxExpected.ss = uDstSs;
6166 CtxExpected.rsp.u = uDstRspExpect;
6167 if (s_aSubTests[iSubTest].fInterPriv)
6168 {
6169 uint16_t BS3_FAR *puSel = &CtxExpected.ds; /* ASSUME member order! */
6170 unsigned cSels = 4;
6171 CtxExpected.bCpl = CtxExpected.ss & X86_SEL_RPL;
6172 while (cSels-- > 0)
6173 {
6174 uint16_t uSel = *puSel;
6175 if ( (uSel & X86_SEL_MASK_OFF_RPL)
6176 && Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u2Dpl < CtxExpected.bCpl
6177 && (Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
6178 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
6179 *puSel = 0;
6180 puSel++;
6181 }
6182 CtxExpected.rsp.u += s_aTests[iTest].cbImm; /* arguments are dropped from both stacks. */
6183 }
6184 }
6185 g_uBs3TrapEipHint = CtxExpected.rip.u32;
6186 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64 -> %04RX16:%04RX64 [pushed %#RX64]; %04RX16:%04RX64\n",Ctx.ss, Ctx.rsp.u,
6187 // CtxExpected.ss, CtxExpected.rsp.u, uDstRspPush, CtxExpected.cs, CtxExpected.rip.u);
6188 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
6189 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
6190 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
6191 //Bs3TestPrintf("%p: %04RX16 %04RX16 %04RX16 %04RX16\n", StkPtr.pu16, StkPtr.pu16[0], StkPtr.pu16[1], StkPtr.pu16[2], StkPtr.pu16[3]);
6192 //Bs3TestPrintf("%.48Rhxd\n", StkPtr.pu16);
6193 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
6194 if (s_aSubTests[iSubTest].iXcpt < 0)
6195 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
6196 else
6197 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
6198 g_usBs3TestStep++;
6199
6200 /* Again single stepping: */
6201 //Bs3TestPrintf("stepping...\n");
6202 Bs3RegSetDr6(X86_DR6_INIT_VAL);
6203 Ctx.rflags.u16 |= X86_EFL_TF;
6204 CtxExpected.rflags.u16 = Ctx.rflags.u16;
6205 if (s_aSubTests[iSubTest].iXcpt < 0 && s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
6206 {
6207 CtxExpected.rip.u -= 1;
6208 CtxExpected.rax.u = Ctx.rax.u;
6209 }
6210 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
6211 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
6212 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
6213 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
6214 if (s_aSubTests[iSubTest].iXcpt < 0)
6215 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
6216 else
6217 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
6218 Ctx.rflags.u16 &= ~X86_EFL_TF;
6219 CtxExpected.rflags.u16 = Ctx.rflags.u16;
6220 g_usBs3TestStep++;
6221 }
6222 }
6223 }
6224 }
6225 else
6226 Bs3TestFailed("wtf?");
6227
6228 if (BS3_MODE_IS_64BIT_SYS(bMode))
6229 Bs3TrapReInit();
6230 return 0;
6231}
6232
6233
6234
6235/*********************************************************************************************************************************
6236* Instruction Length *
6237*********************************************************************************************************************************/
6238
6239
6240static uint8_t bs3CpuBasic2_instr_len_Worker(uint8_t bMode, uint8_t BS3_FAR *pbCodeBuf)
6241{
6242 BS3TRAPFRAME TrapCtx;
6243 BS3REGCTX Ctx;
6244 BS3REGCTX CtxExpected;
6245 uint32_t uEipBase;
6246 unsigned cbInstr;
6247 unsigned off;
6248
6249 /* Make sure they're allocated and all zeroed. */
6250 Bs3MemZero(&Ctx, sizeof(Ctx));
6251 Bs3MemZero(&CtxExpected, sizeof(Ctx));
6252 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
6253
6254 /*
6255 * Create a context.
6256 *
6257 * ASSUMES we're in on the ring-0 stack in ring-0 and using less than 16KB.
6258 */
6259 Bs3RegCtxSaveEx(&Ctx, bMode, 768);
6260 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, (FPFNBS3FAR)pbCodeBuf);
6261 uEipBase = Ctx.rip.u32;
6262
6263 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
6264
6265 /*
6266 * Simple stuff crossing the page.
6267 */
6268 for (off = X86_PAGE_SIZE - 32; off <= X86_PAGE_SIZE + 16; off++)
6269 {
6270 Ctx.rip.u32 = uEipBase + off;
6271 for (cbInstr = 0; cbInstr < 24; cbInstr++)
6272 {
6273 /*
6274 * Generate the instructions:
6275 * [es] nop
6276 * ud2
6277 */
6278 if (cbInstr > 0)
6279 {
6280 Bs3MemSet(&pbCodeBuf[off], 0x26 /* es */, cbInstr);
6281 pbCodeBuf[off + cbInstr - 1] = 0x90; /* nop */
6282 }
6283 pbCodeBuf[off + cbInstr + 0] = 0x0f; /* ud2 */
6284 pbCodeBuf[off + cbInstr + 1] = 0x0b;
6285
6286 /*
6287 * Test it.
6288 */
6289 if (cbInstr < 16)
6290 CtxExpected.rip.u32 = Ctx.rip.u32 + cbInstr;
6291 else
6292 CtxExpected.rip.u32 = Ctx.rip.u32;
6293 g_uBs3TrapEipHint = CtxExpected.rip.u32;
6294 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
6295 if (cbInstr < 16)
6296 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
6297 else
6298 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, 0);
6299 }
6300 pbCodeBuf[off] = 0xf1; /* icebp */
6301 }
6302
6303 /*
6304 * Pit instruction length violations against the segment limit (#GP).
6305 */
6306 if (!BS3_MODE_IS_RM_OR_V86(bMode) && bMode != BS3_MODE_LM64)
6307 {
6308 /** @todo */
6309 }
6310
6311 /*
6312 * Pit instruction length violations against an invalid page (#PF).
6313 */
6314 if (BS3_MODE_IS_PAGED(bMode))
6315 {
6316 /** @todo */
6317 }
6318
6319 return 0;
6320}
6321
6322
6323/**
6324 * Entrypoint for FAR RET tests.
6325 *
6326 * @returns 0 or BS3TESTDOMODE_SKIPPED.
6327 * @param bMode The CPU mode we're testing.
6328 */
6329BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_instr_len)(uint8_t bMode)
6330{
6331 /*
6332 * Allocate three pages so we can straddle an instruction across the
6333 * boundrary for testing special IEM cases, with the last page being
6334 * made in accessible and useful for pitting #PF against #GP.
6335 */
6336 uint8_t BS3_FAR * const pbCodeBuf = (uint8_t BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_REAL, X86_PAGE_SIZE * 3);
6337 //Bs3TestPrintf("pbCodeBuf=%p\n", pbCodeBuf);
6338 if (pbCodeBuf)
6339 {
6340 Bs3MemSet(pbCodeBuf, 0xf1, X86_PAGE_SIZE * 3);
6341 bs3CpuBasic2_SetGlobals(bMode);
6342
6343 if (!BS3_MODE_IS_PAGED(bMode))
6344 bs3CpuBasic2_instr_len_Worker(bMode, pbCodeBuf);
6345 else
6346 {
6347 uint32_t const uFlatLastPg = Bs3SelPtrToFlat(pbCodeBuf) + X86_PAGE_SIZE * 2;
6348 int rc = Bs3PagingProtect(uFlatLastPg, X86_PAGE_SIZE, 0, X86_PTE_P);
6349 if (RT_SUCCESS(rc))
6350 {
6351 bs3CpuBasic2_instr_len_Worker(bMode, pbCodeBuf);
6352 Bs3PagingProtect(uFlatLastPg, X86_PAGE_SIZE, X86_PTE_P, 0);
6353 }
6354 else
6355 Bs3TestFailed("Failed to allocate 3 code pages");
6356 }
6357
6358 Bs3MemFree(pbCodeBuf, X86_PAGE_SIZE * 3);
6359 }
6360 else
6361 Bs3TestFailed("Failed to allocate 3 code pages");
6362 return 0;
6363}
6364
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette