VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 366.1 KB
Line 
1/* $Id: bs3-cpu-basic-2-x0.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-basic-2, C test driver code (16-bit).
4 */
5
6/*
7 * Copyright (C) 2007-2023 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_i760__ud2);
4634PROTO_ALL(bs3CpuBasic2_retn_i0__ud2);
4635PROTO_ALL(bs3CpuBasic2_retn_i0_opsize__ud2);
4636FNBS3FAR bs3CpuBasic2_retn_rexw__ud2_c64;
4637FNBS3FAR bs3CpuBasic2_retn_i24_rexw__ud2_c64;
4638FNBS3FAR bs3CpuBasic2_retn_opsize_rexw__ud2_c64;
4639FNBS3FAR bs3CpuBasic2_retn_rexw_opsize__ud2_c64;
4640FNBS3FAR bs3CpuBasic2_retn_i24_opsize_rexw__ud2_c64;
4641FNBS3FAR bs3CpuBasic2_retn_i24_rexw_opsize__ud2_c64;
4642PROTO_ALL(bs3CpuBasic2_retn_opsize_end);
4643#undef PROTO_ALL
4644
4645
4646static void bs3CpuBasic2_retn_PrepStack(BS3PTRUNION StkPtr, PCBS3REGCTX pCtxExpected, uint8_t cbAddr)
4647{
4648 StkPtr.pu32[3] = UINT32_MAX;
4649 StkPtr.pu32[2] = UINT32_MAX;
4650 StkPtr.pu32[1] = UINT32_MAX;
4651 StkPtr.pu32[0] = UINT32_MAX;
4652 StkPtr.pu32[-1] = UINT32_MAX;
4653 StkPtr.pu32[-2] = UINT32_MAX;
4654 StkPtr.pu32[-3] = UINT32_MAX;
4655 StkPtr.pu32[-4] = UINT32_MAX;
4656 if (cbAddr == 2)
4657 StkPtr.pu16[0] = pCtxExpected->rip.u16;
4658 else if (cbAddr == 4)
4659 StkPtr.pu32[0] = pCtxExpected->rip.u32;
4660 else
4661 StkPtr.pu64[0] = pCtxExpected->rip.u64;
4662}
4663
4664
4665/**
4666 * Entrypoint for NEAR RET tests.
4667 *
4668 * @returns 0 or BS3TESTDOMODE_SKIPPED.
4669 * @param bMode The CPU mode we're testing.
4670 */
4671BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_near_ret)(uint8_t bMode)
4672{
4673 BS3TRAPFRAME TrapCtx;
4674 BS3REGCTX Ctx;
4675 BS3REGCTX CtxExpected;
4676 unsigned iTest;
4677 BS3PTRUNION StkPtr;
4678
4679 /* make sure they're allocated */
4680 Bs3MemZero(&Ctx, sizeof(Ctx));
4681 Bs3MemZero(&CtxExpected, sizeof(Ctx));
4682 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
4683
4684 bs3CpuBasic2_SetGlobals(bMode);
4685
4686 /*
4687 * Create a context.
4688 *
4689 * ASSUMES we're in on the ring-0 stack in ring-0 and using less than 16KB.
4690 */
4691 Bs3RegCtxSaveEx(&Ctx, bMode, 1664);
4692 Ctx.rsp.u = BS3_ADDR_STACK - _16K;
4693 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
4694
4695 StkPtr.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
4696 //Bs3TestPrintf("Stack=%p rsp=%RX64\n", StkPtr.pv, Ctx.rsp.u);
4697
4698 /*
4699 * 16-bit tests.
4700 */
4701 if (BS3_MODE_IS_16BIT_CODE(bMode))
4702 {
4703 static struct
4704 {
4705 bool fOpSizePfx;
4706 uint16_t cbImm;
4707 FPFNBS3FAR pfnTest;
4708 }
4709 const s_aTests[] =
4710 {
4711 { false, 0, bs3CpuBasic2_retn__ud2_c16, },
4712 { true, 0, bs3CpuBasic2_retn_opsize__ud2_c16, },
4713 { false, 24, bs3CpuBasic2_retn_i24__ud2_c16, },
4714 { true, 24, bs3CpuBasic2_retn_i24_opsize__ud2_c16, },
4715 { false, 0, bs3CpuBasic2_retn_i0__ud2_c16, },
4716 { true, 0, bs3CpuBasic2_retn_i0_opsize__ud2_c16, },
4717 { false,760, bs3CpuBasic2_retn_i760__ud2_c16, },
4718 };
4719
4720 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4721 {
4722 uint8_t const BS3_FAR *fpbCode;
4723
4724 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
4725 fpbCode = (uint8_t const BS3_FAR *)BS3_FP_MAKE(Ctx.cs, Ctx.rip.u16);
4726 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4727 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4728 CtxExpected.cs = Ctx.cs;
4729 if (!s_aTests[iTest].fOpSizePfx)
4730 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 2;
4731 else
4732 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 4;
4733 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4734 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64\n", Ctx.ss, Ctx.rsp.u);
4735 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 4 : 2);
4736 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4737 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4738 g_usBs3TestStep++;
4739
4740 /* Again single stepping: */
4741 //Bs3TestPrintf("stepping...\n");
4742 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4743 Ctx.rflags.u16 |= X86_EFL_TF;
4744 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4745 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 4 : 2);
4746 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4747 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4748 Ctx.rflags.u16 &= ~X86_EFL_TF;
4749 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4750 g_usBs3TestStep++;
4751 }
4752 }
4753 /*
4754 * 32-bit tests.
4755 */
4756 else if (BS3_MODE_IS_32BIT_CODE(bMode))
4757 {
4758 static struct
4759 {
4760 uint8_t cBits;
4761 bool fOpSizePfx;
4762 uint16_t cbImm;
4763 FPFNBS3FAR pfnTest;
4764 }
4765 const s_aTests[] =
4766 {
4767 { 32, false, 0, bs3CpuBasic2_retn__ud2_c32, },
4768 { 32, true, 0, bs3CpuBasic2_retn_opsize__ud2_c32, },
4769 { 32, false, 24, bs3CpuBasic2_retn_i24__ud2_c32, },
4770 { 32, true, 24, bs3CpuBasic2_retn_i24_opsize__ud2_c32, },
4771 { 32, false, 0, bs3CpuBasic2_retn_i0__ud2_c32, },
4772 { 32, true, 0, bs3CpuBasic2_retn_i0_opsize__ud2_c32, },
4773 { 32, false,760, bs3CpuBasic2_retn_i760__ud2_c32, },
4774 };
4775
4776 /* Prepare a copy of the UD2 instructions in low memory for opsize prefixed tests. */
4777 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_begin_c32);
4778 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_end_c32) - offLow;
4779 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4780 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4781 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4782 Bs3TestFailedF("Opsize overriden jumps/calls are out of place: %#x LB %#x\n", offLow, cbLow);
4783 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4784 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4785 if (s_aTests[iTest].fOpSizePfx)
4786 {
4787 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4788 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4789 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4790 pbCode16[offUd] = 0xf1; /* replace original ud2 with icebp */
4791 pbCode16[offUd + 1] = 0xf1;
4792 pbLow[offUd] = 0x0f; /* plant ud2 in low memory */
4793 pbLow[offUd + 1] = 0x0b;
4794 }
4795
4796 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4797 {
4798 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4799
4800 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4801 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4802 CtxExpected.cs = Ctx.cs;
4803 if (!s_aTests[iTest].fOpSizePfx)
4804 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 4;
4805 else
4806 {
4807 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 2;
4808 CtxExpected.rip.u &= UINT16_MAX;
4809 }
4810 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4811 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4812 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64\n", Ctx.ss, Ctx.rsp.u);
4813 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 2 : 4);
4814 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4815 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4816 g_usBs3TestStep++;
4817
4818 /* Again single stepping: */
4819 //Bs3TestPrintf("stepping...\n");
4820 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4821 Ctx.rflags.u16 |= X86_EFL_TF;
4822 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4823 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx ? 2 : 4);
4824 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4825 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4826 Ctx.rflags.u16 &= ~X86_EFL_TF;
4827 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4828 g_usBs3TestStep++;
4829 }
4830 }
4831 /*
4832 * 64-bit tests.
4833 */
4834 else if (BS3_MODE_IS_64BIT_CODE(bMode))
4835 {
4836 static struct
4837 {
4838 uint8_t cBits;
4839 bool fOpSizePfx;
4840 uint16_t cbImm;
4841 FPFNBS3FAR pfnTest;
4842 }
4843 const s_aTests[] =
4844 {
4845 { 32, false, 0, bs3CpuBasic2_retn__ud2_c64, },
4846 { 32, false, 0, bs3CpuBasic2_retn_rexw__ud2_c64, },
4847 { 32, true, 0, bs3CpuBasic2_retn_opsize__ud2_c64, },
4848 { 32, false, 0, bs3CpuBasic2_retn_opsize_rexw__ud2_c64, },
4849 { 32, true, 0, bs3CpuBasic2_retn_rexw_opsize__ud2_c64, },
4850 { 32, false, 24, bs3CpuBasic2_retn_i24__ud2_c64, },
4851 { 32, false, 24, bs3CpuBasic2_retn_i24_rexw__ud2_c64, },
4852 { 32, true, 24, bs3CpuBasic2_retn_i24_opsize__ud2_c64, },
4853 { 32, false, 24, bs3CpuBasic2_retn_i24_opsize_rexw__ud2_c64, },
4854 { 32, true, 24, bs3CpuBasic2_retn_i24_rexw_opsize__ud2_c64, },
4855 { 32, false, 0, bs3CpuBasic2_retn_i0__ud2_c64, },
4856 { 32, true, 0, bs3CpuBasic2_retn_i0_opsize__ud2_c64, },
4857 { 32, false,760, bs3CpuBasic2_retn_i760__ud2_c64, },
4858 };
4859 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor();
4860 bool const fFix64OpSize = enmCpuVendor == BS3CPUVENDOR_INTEL; /** @todo what does VIA do? */
4861
4862 /* Prepare a copy of the UD2 instructions in low memory for opsize prefixed
4863 tests, unless we're on intel where the opsize prefix is ignored. Here we
4864 just fill low memory with int3's so we can detect non-intel behaviour. */
4865 uint16_t const offLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_begin_c64);
4866 uint16_t const cbLow = BS3_FP_OFF(bs3CpuBasic2_retn_opsize_end_c64) - offLow;
4867 uint8_t BS3_FAR * const pbLow = BS3_FP_MAKE(BS3_SEL_TILED_R0, 0);
4868 uint8_t BS3_FAR * const pbCode16 = BS3_MAKE_PROT_R0PTR_FROM_FLAT(BS3_ADDR_BS3TEXT16);
4869 if (offLow < 0x600 || offLow + cbLow >= BS3_ADDR_STACK_R2)
4870 Bs3TestFailedF("Opsize overriden jumps/calls are out of place: %#x LB %#x\n", offLow, cbLow);
4871 Bs3MemSet(&pbLow[offLow], 0xcc /*int3*/, cbLow);
4872 if (!fFix64OpSize)
4873 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4874 if (s_aTests[iTest].fOpSizePfx)
4875 {
4876 uint16_t const offFn = BS3_FP_OFF(s_aTests[iTest].pfnTest);
4877 uint16_t const offUd = offFn + (int16_t)(int8_t)pbCode16[offFn - 1];
4878 BS3_ASSERT(offUd - offLow + 1 < cbLow);
4879 pbCode16[offUd] = 0xf1; /* replace original ud2 with icebp */
4880 pbCode16[offUd + 1] = 0xf1;
4881 pbLow[offUd] = 0x0f; /* plant ud2 in low memory */
4882 pbLow[offUd + 1] = 0x0b;
4883 }
4884
4885 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
4886 {
4887 uint8_t const BS3_FAR *fpbCode = Bs3SelLnkPtrToCurPtr(s_aTests[iTest].pfnTest);
4888
4889 Ctx.rip.u = Bs3SelLnkPtrToFlat(s_aTests[iTest].pfnTest);
4890 CtxExpected.rip.u = Ctx.rip.u + (int64_t)(int8_t)fpbCode[-1];
4891 CtxExpected.cs = Ctx.cs;
4892 if (!s_aTests[iTest].fOpSizePfx || fFix64OpSize)
4893 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 8;
4894 else
4895 {
4896 CtxExpected.rsp.u = Ctx.rsp.u + s_aTests[iTest].cbImm + 2;
4897 CtxExpected.rip.u &= UINT16_MAX;
4898 }
4899 g_uBs3TrapEipHint = CtxExpected.rip.u32;
4900 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
4901 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64\n", Ctx.ss, Ctx.rsp.u);
4902 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx && !fFix64OpSize ? 2 : 8);
4903 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4904 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
4905 g_usBs3TestStep++;
4906
4907 /* Again single stepping: */
4908 //Bs3TestPrintf("stepping...\n");
4909 Bs3RegSetDr6(X86_DR6_INIT_VAL);
4910 Ctx.rflags.u16 |= X86_EFL_TF;
4911 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4912 bs3CpuBasic2_retn_PrepStack(StkPtr, &CtxExpected, s_aTests[iTest].fOpSizePfx && !fFix64OpSize ? 2 : 8);
4913 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
4914 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
4915 Ctx.rflags.u16 &= ~X86_EFL_TF;
4916 CtxExpected.rflags.u16 = Ctx.rflags.u16;
4917 g_usBs3TestStep++;
4918 }
4919 }
4920 else
4921 Bs3TestFailed("wtf?");
4922
4923 return 0;
4924}
4925
4926
4927/*********************************************************************************************************************************
4928* Far RET *
4929*********************************************************************************************************************************/
4930#define PROTO_ALL(a_Template) \
4931 FNBS3FAR a_Template ## _c16, \
4932 a_Template ## _c32, \
4933 a_Template ## _c64
4934PROTO_ALL(bs3CpuBasic2_retf);
4935PROTO_ALL(bs3CpuBasic2_retf_opsize);
4936FNBS3FAR bs3CpuBasic2_retf_rexw_c64;
4937FNBS3FAR bs3CpuBasic2_retf_rexw_opsize_c64;
4938FNBS3FAR bs3CpuBasic2_retf_opsize_rexw_c64;
4939PROTO_ALL(bs3CpuBasic2_retf_i32);
4940PROTO_ALL(bs3CpuBasic2_retf_i32_opsize);
4941FNBS3FAR bs3CpuBasic2_retf_i24_rexw_c64;
4942FNBS3FAR bs3CpuBasic2_retf_i24_rexw_opsize_c64;
4943FNBS3FAR bs3CpuBasic2_retf_i24_opsize_rexw_c64;
4944PROTO_ALL(bs3CpuBasic2_retf_i888);
4945#undef PROTO_ALL
4946
4947
4948static void bs3CpuBasic2_retf_PrepStack(BS3PTRUNION StkPtr, uint8_t cbStkItem, RTSEL uRetCs, uint64_t uRetRip,
4949 bool fWithStack, uint16_t cbImm, RTSEL uRetSs, uint64_t uRetRsp)
4950{
4951 Bs3MemSet(&StkPtr.pu32[-4], 0xff, 96);
4952 if (cbStkItem == 2)
4953 {
4954 StkPtr.pu16[0] = (uint16_t)uRetRip;
4955 StkPtr.pu16[1] = uRetCs;
4956 if (fWithStack)
4957 {
4958 StkPtr.pb += cbImm;
4959 StkPtr.pu16[2] = (uint16_t)uRetRsp;
4960 StkPtr.pu16[3] = uRetSs;
4961 }
4962 }
4963 else if (cbStkItem == 4)
4964 {
4965 StkPtr.pu32[0] = (uint32_t)uRetRip;
4966 StkPtr.pu16[2] = uRetCs;
4967 if (fWithStack)
4968 {
4969 StkPtr.pb += cbImm;
4970 StkPtr.pu32[2] = (uint32_t)uRetRsp;
4971 StkPtr.pu16[6] = uRetSs;
4972 }
4973 }
4974 else
4975 {
4976 StkPtr.pu64[0] = uRetRip;
4977 StkPtr.pu16[4] = uRetCs;
4978 if (fWithStack)
4979 {
4980 StkPtr.pb += cbImm;
4981 StkPtr.pu64[2] = uRetRsp;
4982 StkPtr.pu16[12] = uRetSs;
4983 }
4984 }
4985}
4986
4987
4988/**
4989 * Entrypoint for FAR RET tests.
4990 *
4991 * @returns 0 or BS3TESTDOMODE_SKIPPED.
4992 * @param bMode The CPU mode we're testing.
4993 */
4994BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_far_ret)(uint8_t bMode)
4995{
4996 BS3TRAPFRAME TrapCtx;
4997 BS3REGCTX Ctx;
4998 BS3REGCTX Ctx2;
4999 BS3REGCTX CtxExpected;
5000 unsigned iTest;
5001 unsigned iSubTest;
5002 BS3PTRUNION StkPtr;
5003
5004#define LOW_UD_ADDR 0x0609
5005 uint8_t BS3_FAR * const pbLowUd = BS3_FP_MAKE(BS3_FP_SEG(&StkPtr), LOW_UD_ADDR);
5006#define LOW_SALC_UD_ADDR 0x0611
5007 uint8_t BS3_FAR * const pbLowSalcUd = BS3_FP_MAKE(BS3_FP_SEG(&StkPtr), LOW_SALC_UD_ADDR);
5008#define LOW_SWAPGS_ADDR 0x061d
5009 uint8_t BS3_FAR * const pbLowSwapGs = BS3_FP_MAKE(BS3_FP_SEG(&StkPtr), LOW_SWAPGS_ADDR);
5010#define BS3TEXT16_ADDR_HI (BS3_ADDR_BS3TEXT16 >> 16)
5011
5012 /* make sure they're allocated */
5013 Bs3MemZero(&Ctx, sizeof(Ctx));
5014 Bs3MemZero(&Ctx2, sizeof(Ctx2));
5015 Bs3MemZero(&CtxExpected, sizeof(CtxExpected));
5016 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
5017
5018 bs3CpuBasic2_SetGlobals(bMode);
5019
5020 //if (!BS3_MODE_IS_64BIT_SYS(bMode) && bMode != BS3_MODE_PP32_16) return 0xff;
5021 //if (bMode != BS3_MODE_PE32_16) return 0xff;
5022
5023 /*
5024 * When dealing retf with 16-bit effective operand size to 32-bit or 64-bit
5025 * code, we're restricted to a 16-bit address. So, we plant a UD
5026 * instruction below 64KB that we can target with flat 32/64 code segments.
5027 * (Putting it on the stack would be possible too, but we'd have to create
5028 * the sub-test tables dynamically, which isn't necessary.)
5029 */
5030 Bs3MemSet(&pbLowUd[-9], 0xcc, 32);
5031 Bs3MemSet(&pbLowSalcUd[-9], 0xcc, 32);
5032 Bs3MemSet(&pbLowSwapGs[-9], 0xcc, 32);
5033
5034 pbLowUd[0] = 0x0f; /* ud2 */
5035 pbLowUd[1] = 0x0b;
5036
5037 /* A variation to detect whether we're in 64-bit or 16-bit mode when
5038 executing the code. */
5039 pbLowSalcUd[0] = 0xd6; /* salc */
5040 pbLowSalcUd[1] = 0x0f; /* ud2 */
5041 pbLowSalcUd[2] = 0x0b;
5042
5043 /* A variation to check that we're not in 64-bit mode. */
5044 pbLowSwapGs[0] = 0x0f; /* swapgs */
5045 pbLowSwapGs[1] = 0x01;
5046 pbLowSwapGs[2] = 0xf8;
5047
5048 /*
5049 * Use separate stacks for all relevant CPU exceptions so we can put
5050 * garbage in unused RSP bits w/o needing to care about where a long mode
5051 * handler will end up when accessing the whole RSP. (Not an issue with
5052 * 16-bit and 32-bit protected mode kernels, as here the weird SS based
5053 * stack pointer handling is in effect and the exception handler code
5054 * will just continue using the same SS and same portion of RSP.)
5055 *
5056 * See r154660.
5057 */
5058 if (BS3_MODE_IS_64BIT_SYS(bMode))
5059 Bs3Trap64InitEx(true);
5060
5061 /*
5062 * Create some call gates and whatnot for the UD2 code using the spare selectors.
5063 */
5064 if (BS3_MODE_IS_64BIT_SYS(bMode))
5065 for (iTest = 0; iTest < 16; iTest++)
5066 Bs3SelSetupGate64(&Bs3GdteSpare00 + iTest * 2, iTest /*bType*/, 3 /*bDpl*/,
5067 BS3_SEL_R0_CS64, BS3_FP_OFF(bs3CpuBasic2_ud2) + BS3_ADDR_BS3TEXT16);
5068 else
5069 {
5070 for (iTest = 0; iTest < 16; iTest++)
5071 {
5072 Bs3SelSetupGate(&Bs3GdteSpare00 + iTest, iTest /*bType*/, 3 /*bDpl*/,
5073 BS3_SEL_R0_CS16, BS3_FP_OFF(bs3CpuBasic2_ud2), 0);
5074 Bs3SelSetupGate(&Bs3GdteSpare00 + iTest + 16, iTest /*bType*/, 3 /*bDpl*/,
5075 BS3_SEL_R0_CS32, BS3_FP_OFF(bs3CpuBasic2_ud2) + BS3_ADDR_BS3TEXT16, 0);
5076 }
5077 }
5078
5079 /*
5080 * Create a context.
5081 *
5082 * ASSUMES we're in on the ring-0 stack in ring-0 and using less than 16KB.
5083 */
5084 Bs3RegCtxSaveEx(&Ctx, bMode, 1728);
5085 Ctx.rsp.u = BS3_ADDR_STACK - _16K;
5086 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
5087
5088 StkPtr.pv = Bs3RegCtxGetRspSsAsCurPtr(&Ctx);
5089 //Bs3TestPrintf("Stack=%p rsp=%RX64\n", StkPtr.pv, Ctx.rsp.u);
5090
5091 /*
5092 * 16-bit tests.
5093 */
5094 if (BS3_MODE_IS_16BIT_CODE(bMode))
5095 {
5096 static struct
5097 {
5098 bool fOpSizePfx;
5099 uint16_t cbImm;
5100 FPFNBS3FAR pfnTest;
5101 } const s_aTests[] =
5102 {
5103 { false, 0, bs3CpuBasic2_retf_c16, },
5104 { true, 0, bs3CpuBasic2_retf_opsize_c16, },
5105 { false, 32, bs3CpuBasic2_retf_i32_c16, },
5106 { true, 32, bs3CpuBasic2_retf_i32_opsize_c16, },
5107 { false,888, bs3CpuBasic2_retf_i888_c16, },
5108 };
5109
5110 static struct
5111 {
5112 bool fRmOrV86;
5113 bool fInterPriv;
5114 int8_t iXcpt;
5115 RTSEL uStartSs;
5116 uint8_t cDstBits;
5117 RTSEL uDstCs;
5118 union /* must use a union here as the compiler won't compile if uint16_t and will mess up fixups for uint32_t. */
5119 {
5120 uint32_t offDst;
5121 struct
5122 {
5123 NPVOID pv;
5124 uint16_t uHigh;
5125 } s;
5126 };
5127 RTSEL uDstSs;
5128 uint16_t uErrCd;
5129 } const s_aSubTests[] =
5130 { /* rm/v86, PriChg, Xcpt, uStartSs, => bits uDstCs offDst/pv uDstSs uErrCd */
5131 { true, false, -1, 0, 16, BS3_SEL_TEXT16, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, 0, 0 },
5132 { false, false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_TEXT16 | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5133 { false, false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5134 { false, false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R0_SS16 | 0, 0 },
5135 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, 0 },
5136 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS16 | 1, 0 },
5137 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS32 | 1, 0 },
5138 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R1_SS32 | 1, 0 },
5139 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5140 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS16 | 2, 0 },
5141 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS32 | 2, 0 },
5142 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R2_SS32 | 2, 0 },
5143 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5144 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS16 | 3, 0 },
5145 { false, true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS32 | 3, 0 },
5146 { false, true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = { (NPVOID)bs3CpuBasic2_ud2 } }, BS3_SEL_R3_SS32 | 3, 0 },
5147 /* conforming stuff */
5148 { 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 },
5149 { 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 },
5150 { 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 },
5151 { 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 },
5152 { 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 },
5153 { 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 },
5154 { 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 },
5155 { 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 },
5156 { 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 },
5157 { 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 },
5158 { 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 },
5159 { 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 },
5160 { 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 },
5161 { 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 },
5162 { 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 },
5163 { 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 },
5164 { 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 },
5165 { 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 },
5166 { 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 },
5167 { 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 },
5168 { 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 },
5169 { 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 },
5170 { 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 },
5171 /* returning to 32-bit code: */
5172 { false, false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5173 { 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 },
5174 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5175 { 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 },
5176 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5177 { 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 },
5178 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5179 { 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 },
5180 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5181 { 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 },
5182 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5183 { 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 },
5184 { false, true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5185 { 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 },
5186 { false, false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5187 { 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 },
5188 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5189 { 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 },
5190 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5191 { 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 },
5192 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5193 { 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 },
5194 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5195 { 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 },
5196 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5197 { 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 },
5198 { false, true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5199 { 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 },
5200 /* returning to 32-bit conforming code: */
5201 { 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 },
5202 { 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 },
5203 { 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 },
5204 { 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 },
5205 { 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 },
5206 { 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 },
5207 { 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 },
5208 { 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 },
5209 { 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 },
5210 { 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 },
5211 { 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 },
5212 { 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 },
5213 { 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 },
5214 { 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 },
5215 { 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 },
5216 { 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 },
5217 { 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 },
5218 { 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 },
5219 { 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 },
5220 { 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 },
5221 { 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 },
5222 { 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 },
5223 { 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 },
5224 { 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 },
5225 /* returning to 64-bit code or 16-bit when not in long mode: */
5226 { 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 },
5227 { 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 },
5228 { 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 },
5229 { 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 },
5230 { 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 },
5231 { 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 },
5232 { 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 },
5233 { 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 },
5234 { 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 },
5235 { 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 },
5236 { 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 },
5237 { 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 },
5238 { 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 },
5239 { 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 },
5240 { 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 },
5241 { 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 },
5242 { 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 },
5243 /* returning to 64-bit code or 16-bit when not in long mode, conforming code variant: */
5244 { 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 },
5245 { 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 },
5246 { 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 },
5247 { 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 },
5248
5249 { 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 },
5250 { 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 },
5251 { 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 },
5252 { 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 },
5253 { 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 },
5254 { 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 },
5255 { 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 },
5256
5257 { 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 },
5258 { 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 },
5259 { 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 },
5260 { 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 },
5261
5262 { 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 },
5263 { 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 },
5264 { 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 },
5265 { 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 },
5266
5267 /* some additional #GP variations */ /** @todo test all possible exceptions! */
5268 { 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 },
5269 { 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 },
5270 { 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 },
5271 { 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 },
5272 { 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 },
5273 { 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 },
5274 { 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 },
5275 { 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 },
5276 { 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 },
5277 { 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 },
5278 { 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 },
5279 { 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 },
5280 { 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 },
5281 { 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 },
5282 { 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 },
5283 { 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 },
5284 { 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 },
5285 { 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 },
5286 { 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 },
5287 { 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 },
5288 { 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 },
5289 { 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 },
5290 { 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 },
5291 { 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 },
5292 { 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 },
5293 { 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 },
5294 { 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 },
5295 { 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 },
5296 { 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 },
5297 { 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 },
5298 { 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 },
5299 { 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 },
5300 { 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 },
5301 { 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 },
5302 };
5303
5304 bool const fRmOrV86 = BS3_MODE_IS_RM_OR_V86(bMode);
5305 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor();
5306
5307 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5308 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
5309 {
5310 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
5311
5312 for (iSubTest = 0; iSubTest < RT_ELEMENTS(s_aSubTests); iSubTest++)
5313 {
5314 g_usBs3TestStep = (iTest << 12) | (iSubTest << 4);
5315 if ( s_aSubTests[iSubTest].fRmOrV86 == fRmOrV86
5316 && (s_aSubTests[iSubTest].offDst <= UINT16_MAX || s_aTests[iTest].fOpSizePfx))
5317 {
5318 uint16_t const cbFrmDisp = s_aSubTests[iSubTest].fInterPriv ? iSubTest % 7 : 0;
5319 uint16_t const cbStkItem = s_aTests[iTest].fOpSizePfx ? 4 : 2;
5320 uint16_t const cbFrame = (s_aSubTests[iSubTest].fInterPriv ? 4 : 2) * cbStkItem;
5321 uint32_t const uFlatDst = Bs3SelFar32ToFlat32(s_aSubTests[iSubTest].offDst, s_aSubTests[iSubTest].uDstCs)
5322 + (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode));
5323 RTSEL const uDstSs = s_aSubTests[iSubTest].uDstSs;
5324 uint64_t uDstRspExpect, uDstRspPush;
5325 uint16_t cErrors;
5326
5327 Ctx.ss = s_aSubTests[iSubTest].uStartSs;
5328 if (Ctx.ss != BS3_SEL_R0_SS32)
5329 Ctx.rsp.u32 |= UINT32_C(0xfffe0000);
5330 else
5331 Ctx.rsp.u32 &= UINT16_MAX;
5332 uDstRspExpect = uDstRspPush = Ctx.rsp.u + s_aTests[iTest].cbImm + cbFrame + cbFrmDisp;
5333 if (s_aSubTests[iSubTest].fInterPriv)
5334 {
5335 if (s_aTests[iTest].fOpSizePfx)
5336 uDstRspPush = (uDstRspPush & UINT16_MAX) | UINT32_C(0xacdc0000);
5337 if ( uDstSs == (BS3_SEL_R1_SS32 | 1)
5338 || uDstSs == (BS3_SEL_R2_SS32 | 2)
5339 || uDstSs == (BS3_SEL_R3_SS32 | 3)
5340 || (s_aSubTests[iSubTest].cDstBits == 64 && BS3_MODE_IS_64BIT_SYS(bMode)))
5341 {
5342 if (s_aTests[iTest].fOpSizePfx)
5343 uDstRspExpect = uDstRspPush;
5344 else
5345 uDstRspExpect &= UINT16_MAX;
5346 }
5347 }
5348
5349 CtxExpected.bCpl = Ctx.bCpl;
5350 CtxExpected.cs = Ctx.cs;
5351 CtxExpected.ss = Ctx.ss;
5352 CtxExpected.ds = Ctx.ds;
5353 CtxExpected.es = Ctx.es;
5354 CtxExpected.fs = Ctx.fs;
5355 CtxExpected.gs = Ctx.gs;
5356 CtxExpected.rip.u = Ctx.rip.u;
5357 CtxExpected.rsp.u = Ctx.rsp.u;
5358 CtxExpected.rax.u = Ctx.rax.u;
5359 if (s_aSubTests[iSubTest].iXcpt < 0)
5360 {
5361 CtxExpected.cs = s_aSubTests[iSubTest].uDstCs;
5362 CtxExpected.rip.u = s_aSubTests[iSubTest].offDst;
5363 if (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5364 {
5365 CtxExpected.rip.u += 1;
5366 CtxExpected.rax.au8[0] = CtxExpected.rflags.u16 & X86_EFL_CF ? 0xff : 0;
5367 }
5368 CtxExpected.ss = uDstSs;
5369 CtxExpected.rsp.u = uDstRspExpect;
5370 if (s_aSubTests[iSubTest].fInterPriv)
5371 {
5372 uint16_t BS3_FAR *puSel = &CtxExpected.ds; /* ASSUME member order! */
5373 unsigned cSels = 4;
5374 CtxExpected.bCpl = CtxExpected.ss & X86_SEL_RPL;
5375 while (cSels-- > 0)
5376 {
5377 uint16_t uSel = *puSel;
5378 if ( (uSel & X86_SEL_MASK_OFF_RPL)
5379 && Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u2Dpl < CtxExpected.bCpl
5380 && (Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5381 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5382 *puSel = 0;
5383 puSel++;
5384 }
5385 CtxExpected.rsp.u += s_aTests[iTest].cbImm; /* arguments are dropped from both stacks. */
5386 }
5387 }
5388 g_uBs3TrapEipHint = CtxExpected.rip.u32;
5389 //Bs3TestPrintf("cs:rip=%04RX16:%04RX64 -> %04RX16:%04RX64\n", Ctx.cs, Ctx.rip.u, CtxExpected.cs, CtxExpected.rip.u);
5390 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64 -> %04RX16:%04RX64 [pushed %#RX64]\n", Ctx.ss, Ctx.rsp.u, CtxExpected.ss, CtxExpected.rsp.u, uDstRspPush);
5391 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5392 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5393 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5394 //Bs3TestPrintf("%p: %04RX16 %04RX16 %04RX16 %04RX16\n", StkPtr.pu16, StkPtr.pu16[0], StkPtr.pu16[1], StkPtr.pu16[2], StkPtr.pu16[3]);
5395 //Bs3TestPrintf("%.48Rhxd\n", StkPtr.pu16);
5396 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5397 if (s_aSubTests[iSubTest].iXcpt < 0)
5398 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5399 else
5400 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5401 g_usBs3TestStep++; /* 1 */
5402
5403 /* Bad hw bp: Setup DR0-3 but use invalid length encodings (non-byte) */
5404 //Bs3TestPrintf("hw bp: bad len\n");
5405 Bs3RegSetDr0(uFlatDst);
5406 Bs3RegSetDr1(uFlatDst);
5407 Bs3RegSetDr2(uFlatDst);
5408 Bs3RegSetDr3(uFlatDst);
5409 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5410 Bs3RegSetDr7(X86_DR7_INIT_VAL
5411 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_WORD) | X86_DR7_L_G(1)
5412 | X86_DR7_RW(2, X86_DR7_RW_EO) | X86_DR7_LEN(2, X86_DR7_LEN_DWORD) | X86_DR7_L_G(2)
5413 | ( BS3_MODE_IS_64BIT_SYS(bMode)
5414 ? X86_DR7_RW(3, X86_DR7_RW_EO) | X86_DR7_LEN(3, X86_DR7_LEN_QWORD) | X86_DR7_L_G(3) : 0) );
5415 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5416 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5417 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5418 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5419 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5420 if (s_aSubTests[iSubTest].iXcpt < 0)
5421 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5422 else
5423 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5424 bs3CpuBasic2_CheckDr6InitVal();
5425 g_usBs3TestStep++; /* 2 */
5426
5427 /* Bad hw bp: setup DR0-3 but don't enable them */
5428 //Bs3TestPrintf("hw bp: disabled\n");
5429 //Bs3RegSetDr0(uFlatDst);
5430 //Bs3RegSetDr1(uFlatDst);
5431 //Bs3RegSetDr2(uFlatDst);
5432 //Bs3RegSetDr3(uFlatDst);
5433 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5434 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5435 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5436 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5437 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5438 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5439 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5440 if (s_aSubTests[iSubTest].iXcpt < 0)
5441 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5442 else
5443 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5444 bs3CpuBasic2_CheckDr6InitVal();
5445 g_usBs3TestStep++; /* 3 */
5446
5447 /* Bad hw bp: Points at 2nd byte in the UD2. Docs says it only works when pointing at first byte. */
5448 //Bs3TestPrintf("hw bp: byte 2\n");
5449 Bs3RegSetDr0(uFlatDst + 1);
5450 Bs3RegSetDr1(uFlatDst + 1);
5451 //Bs3RegSetDr2(uFlatDst);
5452 //Bs3RegSetDr3(uFlatDst);
5453 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5454 Bs3RegSetDr7(X86_DR7_INIT_VAL
5455 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_L_G(0)
5456 | X86_DR7_RW(1, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1));
5457 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5458 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5459 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5460 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5461 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5462 if (s_aSubTests[iSubTest].iXcpt < 0)
5463 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5464 else
5465 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5466 bs3CpuBasic2_CheckDr6InitVal();
5467 g_usBs3TestStep++; /* 4 */
5468
5469 /* Again with two correctly hardware breakpoints and a disabled one that just matches the address: */
5470 //Bs3TestPrintf("bp 1 + 3...\n");
5471 Bs3RegSetDr0(uFlatDst);
5472 Bs3RegSetDr1(uFlatDst);
5473 Bs3RegSetDr2(0);
5474 Bs3RegSetDr3(uFlatDst);
5475 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5476 Bs3RegSetDr7(X86_DR7_INIT_VAL
5477 | X86_DR7_RW(1, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1)
5478 | X86_DR7_RW(3, X86_DR7_RW_EO) | X86_DR7_LEN(3, X86_DR7_LEN_BYTE) | X86_DR7_L_G(3) );
5479 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5480 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5481 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5482 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5483 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5484 if (s_aSubTests[iSubTest].iXcpt < 0)
5485 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected,
5486 enmCpuVendor == BS3CPUVENDOR_AMD ? X86_DR6_B1 | X86_DR6_B3 /* 3990x */
5487 : X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B3);
5488 else
5489 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5490 g_usBs3TestStep++; /* 5 */
5491
5492 /* Again with a single locally enabled breakpoint. */
5493 //Bs3TestPrintf("bp 0/l...\n");
5494 Bs3RegSetDr0(uFlatDst);
5495 Bs3RegSetDr1(0);
5496 Bs3RegSetDr2(0);
5497 Bs3RegSetDr3(0);
5498 Bs3RegSetDr6(X86_DR6_INIT_VAL | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BS);
5499 Bs3RegSetDr7(X86_DR7_INIT_VAL
5500 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_L(0));
5501 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5502 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5503 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5504 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5505 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5506 if (s_aSubTests[iSubTest].iXcpt < 0)
5507 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_B0 | X86_DR6_BS); /* B0-B3 set, BS preserved */
5508 else
5509 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5510 g_usBs3TestStep++; /* 6 */
5511
5512 /* Again with a single globally enabled breakpoint and serveral other types of breakpoints
5513 configured but not enabled. */
5514 //Bs3TestPrintf("bp 2/g+...\n");
5515 cErrors = Bs3TestSubErrorCount();
5516 Bs3RegSetDr0(uFlatDst);
5517 Bs3RegSetDr1(uFlatDst);
5518 Bs3RegSetDr2(uFlatDst);
5519 Bs3RegSetDr3(uFlatDst);
5520 Bs3RegSetDr6(X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BD | X86_DR6_BT | X86_DR6_B2);
5521 Bs3RegSetDr7(X86_DR7_INIT_VAL
5522 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE)
5523 | X86_DR7_RW(1, X86_DR7_RW_RW) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1)
5524 | X86_DR7_RW(2, X86_DR7_RW_EO) | X86_DR7_LEN(2, X86_DR7_LEN_BYTE) | X86_DR7_G(2)
5525 | X86_DR7_RW(3, X86_DR7_RW_WO) | X86_DR7_LEN(3, X86_DR7_LEN_BYTE) | X86_DR7_G(3)
5526 );
5527 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5528 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5529 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5530 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5531 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5532 if (s_aSubTests[iSubTest].iXcpt < 0)
5533 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_B2 | X86_DR6_BS | X86_DR6_BD | X86_DR6_BT);
5534 else
5535 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5536 g_usBs3TestStep++; /* 7 */
5537
5538 /* Now resume it with lots of execution breakpoints configured. */
5539 if (s_aSubTests[iSubTest].iXcpt < 0 && Bs3TestSubErrorCount() == cErrors)
5540 {
5541 Bs3MemCpy(&Ctx2, &TrapCtx.Ctx, sizeof(Ctx2));
5542 Ctx2.rflags.u32 |= X86_EFL_RF;
5543 //Bs3TestPrintf("bp 3/g+rf %04RX16:%04RX64 efl=%RX32 ds=%04RX16...\n", Ctx2.cs, Ctx2.rip.u, Ctx2.rflags.u32, Ctx2.ds);
5544 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5545 Bs3RegSetDr7(X86_DR7_INIT_VAL
5546 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE)
5547 | X86_DR7_RW(1, X86_DR7_RW_EO) | X86_DR7_LEN(1, X86_DR7_LEN_BYTE) | X86_DR7_L_G(1)
5548 | X86_DR7_RW(2, X86_DR7_RW_EO) | X86_DR7_LEN(2, X86_DR7_LEN_BYTE) | X86_DR7_G(2)
5549 | X86_DR7_RW(3, X86_DR7_RW_EO) | X86_DR7_LEN(3, X86_DR7_LEN_BYTE) | X86_DR7_G(3)
5550 );
5551 Bs3TrapSetJmpAndRestore(&Ctx2, &TrapCtx);
5552 Bs3RegSetDr7(X86_DR7_INIT_VAL);
5553 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5554 bs3CpuBasic2_CheckDr6InitVal();
5555 }
5556 g_usBs3TestStep++; /* 8 */
5557
5558 /* Now do single stepping: */
5559 //Bs3TestPrintf("stepping...\n");
5560 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5561 Ctx.rflags.u16 |= X86_EFL_TF;
5562 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5563 if (s_aSubTests[iSubTest].iXcpt < 0 && s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5564 {
5565 CtxExpected.rip.u -= 1;
5566 CtxExpected.rax.u = Ctx.rax.u;
5567 }
5568 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5569 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5570 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5571 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5572 if (s_aSubTests[iSubTest].iXcpt < 0)
5573 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
5574 else
5575 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5576 Ctx.rflags.u16 &= ~X86_EFL_TF;
5577 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5578 g_usBs3TestStep++; /* 9 */
5579
5580 /* Single step with B0-B3 set to check that they're not preserved
5581 and with BD & BT to check that they are (checked on Intel 6700K): */
5582 //Bs3TestPrintf("stepping b0-b3+bd+bt=1...\n");
5583 Bs3RegSetDr6(X86_DR6_INIT_VAL | X86_DR6_B_MASK | X86_DR6_BD | X86_DR6_BT);
5584 Ctx.rflags.u16 |= X86_EFL_TF;
5585 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5586 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5587 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5588 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5589 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5590 if (s_aSubTests[iSubTest].iXcpt < 0)
5591 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS | X86_DR6_BD | X86_DR6_BT);
5592 else
5593 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5594 Ctx.rflags.u16 &= ~X86_EFL_TF;
5595 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5596 g_usBs3TestStep++; /* 10 */
5597
5598 }
5599 }
5600 }
5601 }
5602 /*
5603 * 32-bit tests.
5604 */
5605 else if (BS3_MODE_IS_32BIT_CODE(bMode))
5606 {
5607 static struct
5608 {
5609 bool fOpSizePfx;
5610 uint16_t cbImm;
5611 FPFNBS3FAR pfnTest;
5612 } const s_aTests[] =
5613 {
5614 { false, 0, bs3CpuBasic2_retf_c32, },
5615 { true, 0, bs3CpuBasic2_retf_opsize_c32, },
5616 { false, 32, bs3CpuBasic2_retf_i32_c32, },
5617 { true, 32, bs3CpuBasic2_retf_i32_opsize_c32, },
5618 { false,888, bs3CpuBasic2_retf_i888_c32, },
5619 };
5620
5621 static struct
5622 {
5623 bool fInterPriv;
5624 int8_t iXcpt;
5625 RTSEL uStartSs;
5626 uint8_t cDstBits;
5627 RTSEL uDstCs;
5628 union /* must use a union here as the compiler won't compile if uint16_t and will mess up fixups for uint32_t. */
5629 {
5630 uint32_t offDst;
5631 struct
5632 {
5633 NPVOID pv;
5634 uint16_t uHigh;
5635 } s;
5636 };
5637 RTSEL uDstSs;
5638 uint16_t uErrCd;
5639 } const s_aSubTests[] =
5640 { /* PriChg, Xcpt, uStartSs, => bits uDstCs offDst/pv uDstSs uErrCd */
5641 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5642 { false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5643 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5644 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5645 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5646 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5647 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5648 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5649 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5650 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5651 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5652 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5653 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5654 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5655 /* same with 32-bit wide target addresses: */
5656 { 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 },
5657 { 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 },
5658 { 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 },
5659 { 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 },
5660 { 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 },
5661 { 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 },
5662 { 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 },
5663 { 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 },
5664 { 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 },
5665 { 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 },
5666 { 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 },
5667 { 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 },
5668 { 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 },
5669 { 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 },
5670 /* conforming stuff */
5671 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 0, { .offDst = LOW_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5672 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5673 { 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 },
5674 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5675 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5676 { 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 },
5677 { 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 },
5678 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 1, { .offDst = LOW_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5679 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5680 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5681 { 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 },
5682 { 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 },
5683 { 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 },
5684 { 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 },
5685 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 2, { .offDst = LOW_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5686 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5687 { 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 },
5688 { 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 },
5689 { 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 },
5690 { 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 },
5691 { 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 },
5692 { 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 },
5693 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32_CNF | 3, { .offDst = LOW_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5694 /* returning to 16-bit code: */
5695 { false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS32 | 0, 0 },
5696 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
5697 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
5698 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5699 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
5700 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5701 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
5702 { false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R0_SS16 | 0, 0 },
5703 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
5704 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
5705 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
5706 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
5707 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
5708 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_ud2, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
5709 /* returning to 16-bit conforming code: */
5710 { 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 },
5711 { 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 },
5712 { 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 },
5713 { 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 },
5714 { 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 },
5715 { 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 },
5716 { 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 },
5717 { 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 },
5718 { 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 },
5719 { 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 },
5720 { 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 },
5721 { 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 },
5722 { 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 },
5723 { 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 },
5724 { 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 },
5725 { 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 },
5726 { 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 },
5727 { 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 },
5728 { 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 },
5729 { 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 },
5730 { 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 },
5731 { 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 },
5732 { 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 },
5733 { 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 },
5734 /* returning to 64-bit code or 16-bit when not in long mode: */
5735 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
5736 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5737 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5738 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5739 { 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 },
5740 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_DS64 | 1, 0 },
5741 { false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5742 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5743 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5744 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5745 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5746 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5747 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5748 { 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 },
5749 { 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 },
5750 { 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 },
5751 { 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 },
5752 /* returning to 64-bit code or 16-bit when not in long mode, conforming code variant: */
5753 { 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 },
5754 { 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 },
5755 { 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 },
5756 { 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 },
5757
5758 { 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 },
5759 { 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 },
5760 { 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 },
5761 { 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 },
5762 { 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 },
5763 { 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 },
5764 { 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 },
5765
5766 { 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 },
5767 { 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 },
5768 { 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 },
5769 { 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 },
5770
5771 { 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 },
5772 { 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 },
5773 { 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 },
5774 { 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 },
5775
5776 /* some additional #GP variations */ /** @todo test all possible exceptions! */
5777 { 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 },
5778 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_00 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_00 },
5779 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_01 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_01 },
5780 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_02 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_02 },
5781 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_03 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_03 },
5782 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_04 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_04 },
5783 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_05 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_05 },
5784 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_06 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_06 },
5785 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_07 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_07 },
5786 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_08 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_08 },
5787 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_09 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_09 },
5788 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0a },
5789 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0b | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0b },
5790 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0c },
5791 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0d | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0d },
5792 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0e },
5793 { true, 14, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_SPARE_0f | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0f },
5794 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_10 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_10 },
5795 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_11 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_11 },
5796 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_12 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_12 },
5797 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_13 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_13 },
5798 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_14 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_14 },
5799 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_15 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_15 },
5800 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_16 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_16 },
5801 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_17 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_17 },
5802 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_18 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_18 },
5803 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_19 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_19 },
5804 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1a },
5805 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1b | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1b },
5806 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1c },
5807 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1d | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1d },
5808 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1e },
5809 { true, 14, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_SPARE_1f | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1f },
5810 };
5811
5812 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
5813 {
5814 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
5815 //Bs3TestPrintf("-------------- #%u: cs:eip=%04RX16:%08RX64 imm=%u%s\n",
5816 // iTest, Ctx.cs, Ctx.rip.u, s_aTests[iTest].cbImm, s_aTests[iTest].fOpSizePfx ? " o16" : "");
5817
5818 for (iSubTest = 0; iSubTest < RT_ELEMENTS(s_aSubTests); iSubTest++)
5819 {
5820 g_usBs3TestStep = (iTest << 12) | (iSubTest << 1);
5821 if (!s_aTests[iTest].fOpSizePfx || s_aSubTests[iSubTest].offDst <= UINT16_MAX)
5822 {
5823 uint16_t const cbFrmDisp = s_aSubTests[iSubTest].fInterPriv ? iSubTest % 7 : 0;
5824 uint16_t const cbStkItem = s_aTests[iTest].fOpSizePfx ? 2 : 4;
5825 uint16_t const cbFrame = (s_aSubTests[iSubTest].fInterPriv ? 4 : 2) * cbStkItem;
5826 RTSEL const uDstSs = s_aSubTests[iSubTest].uDstSs;
5827 uint64_t uDstRspExpect, uDstRspPush;
5828 //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,
5829 // s_aSubTests[iSubTest].cDstBits, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst, s_aSubTests[iSubTest].uDstSs, s_aSubTests[iSubTest].uErrCd);
5830
5831 Ctx.ss = s_aSubTests[iSubTest].uStartSs;
5832 if (Ctx.ss != BS3_SEL_R0_SS32)
5833 Ctx.rsp.u32 |= UINT32_C(0xfffe0000);
5834 else
5835 Ctx.rsp.u32 &= UINT16_MAX;
5836 uDstRspExpect = uDstRspPush = Ctx.rsp.u + s_aTests[iTest].cbImm + cbFrame + cbFrmDisp;
5837 if (s_aSubTests[iSubTest].fInterPriv)
5838 {
5839 if (!s_aTests[iTest].fOpSizePfx)
5840 uDstRspPush = (uDstRspPush & UINT16_MAX) | UINT32_C(0xacdc0000);
5841 if ( uDstSs == (BS3_SEL_R1_SS32 | 1)
5842 || uDstSs == (BS3_SEL_R2_SS32 | 2)
5843 || uDstSs == (BS3_SEL_R3_SS32 | 3)
5844 || (s_aSubTests[iSubTest].cDstBits == 64 && BS3_MODE_IS_64BIT_SYS(bMode)))
5845 {
5846 if (!s_aTests[iTest].fOpSizePfx)
5847 uDstRspExpect = uDstRspPush;
5848 else
5849 uDstRspExpect &= UINT16_MAX;
5850 }
5851 }
5852
5853 CtxExpected.bCpl = Ctx.bCpl;
5854 CtxExpected.cs = Ctx.cs;
5855 CtxExpected.ss = Ctx.ss;
5856 CtxExpected.ds = Ctx.ds;
5857 CtxExpected.es = Ctx.es;
5858 CtxExpected.fs = Ctx.fs;
5859 CtxExpected.gs = Ctx.gs;
5860 CtxExpected.rip.u = Ctx.rip.u;
5861 CtxExpected.rsp.u = Ctx.rsp.u;
5862 CtxExpected.rax.u = Ctx.rax.u;
5863 if (s_aSubTests[iSubTest].iXcpt < 0)
5864 {
5865 CtxExpected.cs = s_aSubTests[iSubTest].uDstCs;
5866 CtxExpected.rip.u = s_aSubTests[iSubTest].offDst;
5867 if (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5868 {
5869 CtxExpected.rip.u += 1;
5870 CtxExpected.rax.au8[0] = CtxExpected.rflags.u16 & X86_EFL_CF ? 0xff : 0;
5871 }
5872 CtxExpected.ss = uDstSs;
5873 CtxExpected.rsp.u = uDstRspExpect;
5874 if (s_aSubTests[iSubTest].fInterPriv)
5875 {
5876 uint16_t BS3_FAR *puSel = &CtxExpected.ds; /* ASSUME member order! */
5877 unsigned cSels = 4;
5878 CtxExpected.bCpl = CtxExpected.ss & X86_SEL_RPL;
5879 while (cSels-- > 0)
5880 {
5881 uint16_t uSel = *puSel;
5882 if ( (uSel & X86_SEL_MASK_OFF_RPL)
5883 && Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u2Dpl < CtxExpected.bCpl
5884 && (Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5885 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
5886 *puSel = 0;
5887 puSel++;
5888 }
5889 CtxExpected.rsp.u += s_aTests[iTest].cbImm; /* arguments are dropped from both stacks. */
5890 }
5891 }
5892 g_uBs3TrapEipHint = CtxExpected.rip.u32;
5893 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64 -> %04RX16:%04RX64 [pushed %#RX64]; %04RX16:%04RX64\n",Ctx.ss, Ctx.rsp.u,
5894 // CtxExpected.ss, CtxExpected.rsp.u, uDstRspPush, CtxExpected.cs, CtxExpected.rip.u);
5895 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5896 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5897 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5898 //Bs3TestPrintf("%p: %04RX16 %04RX16 %04RX16 %04RX16\n", StkPtr.pu16, StkPtr.pu16[0], StkPtr.pu16[1], StkPtr.pu16[2], StkPtr.pu16[3]);
5899 //Bs3TestPrintf("%.48Rhxd\n", StkPtr.pu16);
5900 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5901 if (s_aSubTests[iSubTest].iXcpt < 0)
5902 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
5903 else
5904 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5905 g_usBs3TestStep++;
5906
5907 /* Again single stepping: */
5908 //Bs3TestPrintf("stepping...\n");
5909 Bs3RegSetDr6(X86_DR6_INIT_VAL);
5910 Ctx.rflags.u16 |= X86_EFL_TF;
5911 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5912 if (s_aSubTests[iSubTest].iXcpt < 0 && s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
5913 {
5914 CtxExpected.rip.u -= 1;
5915 CtxExpected.rax.u = Ctx.rax.u;
5916 }
5917 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
5918 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
5919 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
5920 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
5921 if (s_aSubTests[iSubTest].iXcpt < 0)
5922 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
5923 else
5924 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
5925 Ctx.rflags.u16 &= ~X86_EFL_TF;
5926 CtxExpected.rflags.u16 = Ctx.rflags.u16;
5927 g_usBs3TestStep++;
5928 }
5929 }
5930 }
5931 }
5932 /*
5933 * 64-bit tests.
5934 */
5935 else if (BS3_MODE_IS_64BIT_CODE(bMode))
5936 {
5937 static struct
5938 {
5939 uint8_t fOpSizePfx; /**< 0: none, 1: 066h, 2: REX.W; Effective op size prefix. */
5940 uint16_t cbImm;
5941 FPFNBS3FAR pfnTest;
5942 } const s_aTests[] =
5943 {
5944 { 0, 0, bs3CpuBasic2_retf_c64, },
5945 { 1, 0, bs3CpuBasic2_retf_opsize_c64, },
5946 { 0, 32, bs3CpuBasic2_retf_i32_c64, },
5947 { 1, 32, bs3CpuBasic2_retf_i32_opsize_c64, },
5948 { 2, 0, bs3CpuBasic2_retf_rexw_c64, },
5949 { 2, 0, bs3CpuBasic2_retf_opsize_rexw_c64, },
5950 { 1, 0, bs3CpuBasic2_retf_rexw_opsize_c64, },
5951 { 2, 24, bs3CpuBasic2_retf_i24_rexw_c64, },
5952 { 2, 24, bs3CpuBasic2_retf_i24_opsize_rexw_c64, },
5953 { 1, 24, bs3CpuBasic2_retf_i24_rexw_opsize_c64, },
5954 { 0,888, bs3CpuBasic2_retf_i888_c64, },
5955 };
5956
5957 static struct
5958 {
5959 bool fInterPriv;
5960 int8_t iXcpt;
5961 RTSEL uStartSs;
5962 uint8_t cDstBits;
5963 RTSEL uDstCs;
5964 union /* must use a union here as the compiler won't compile if uint16_t and will mess up fixups for uint32_t. */
5965 {
5966 uint32_t offDst;
5967 struct
5968 {
5969 NPVOID pv;
5970 uint16_t uHigh;
5971 } s;
5972 };
5973 RTSEL uDstSs;
5974 uint16_t uErrCd;
5975 } const s_aSubTests[] =
5976 { /* PriChg, Xcpt, uStartSs, => bits uDstCs offDst/pv uDstSs uErrCd */
5977 { false, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5978 { false, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R0_CS64 | 0, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
5979 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5980 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
5981 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5982 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R1_CS64 | 1, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
5983 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5984 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
5985 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5986 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R2_CS64 | 2, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
5987 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5988 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
5989 { true, -1, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5990 { true, -1, BS3_SEL_R0_SS16 | 0, 64, BS3_SEL_R3_CS64 | 3, { .offDst = LOW_SALC_UD_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
5991 /* same with 32-bit wide target addresses: */
5992 { 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 },
5993 { 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 },
5994 { 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 },
5995 { 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 },
5996 { 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 },
5997 { 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 },
5998 { 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 },
5999 { 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 },
6000 { 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 },
6001 { 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 },
6002 { 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 },
6003 { 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 },
6004 { 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 },
6005 { 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 },
6006 /* conforming stuff */
6007 { 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 },
6008 { 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 },
6009 { 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 },
6010 { 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 },
6011 { 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 },
6012 { 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 },
6013 { 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 },
6014 { 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 },
6015 { 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 },
6016 { 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 },
6017 { 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 },
6018 { 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 },
6019 { 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 },
6020 { 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 },
6021 { 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 },
6022 { 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 },
6023 { 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 },
6024 { 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 },
6025 { 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 },
6026 { 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 },
6027 { 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 },
6028 { 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 },
6029 { 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 },
6030 /* returning to 16-bit code: */
6031 { false, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS32 | 0, 0 },
6032 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
6033 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
6034 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
6035 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
6036 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6037 { true, -1, BS3_SEL_R0_SS32 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
6038 { false, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R0_CS16 | 0, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R0_SS16 | 0, 0 },
6039 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS16 | 1, 0 },
6040 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R1_CS16 | 1, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R1_SS32 | 1, 0 },
6041 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS16 | 2, 0 },
6042 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R2_CS16 | 2, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R2_SS32 | 2, 0 },
6043 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS16 | 3, 0 },
6044 { true, -1, BS3_SEL_R0_SS16 | 0, 16, BS3_SEL_R3_CS16 | 3, { .s = {(NPVOID)bs3CpuBasic2_swapgs, 0 } }, BS3_SEL_R3_SS32 | 3, 0 },
6045 /* returning to 16-bit conforming code: */
6046 { 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 },
6047 { 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 },
6048 { 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 },
6049 { 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 },
6050 { 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 },
6051 { 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 },
6052 { 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 },
6053 { 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 },
6054 { 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 },
6055 { 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 },
6056 { 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 },
6057 { 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 },
6058 { 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 },
6059 { 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 },
6060 { 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 },
6061 { 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 },
6062 { 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 },
6063 { 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 },
6064 { 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 },
6065 { 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 },
6066 { 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 },
6067 { 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 },
6068 { 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 },
6069 { 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 },
6070 /* returning to 32-bit code - narrow 16-bit target address: */
6071 { false, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R0_SS32 | 0, 0 },
6072 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
6073 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
6074 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
6075 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
6076 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
6077 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
6078 { false, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R0_CS32 | 0, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R0_SS16 | 0, 0 },
6079 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS16 | 1, 0 },
6080 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R1_CS32 | 1, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R1_SS32 | 1, 0 },
6081 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS16 | 2, 0 },
6082 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R2_CS32 | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
6083 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS16 | 3, 0 },
6084 { true, -1, BS3_SEL_R0_SS16 | 0, 32, BS3_SEL_R3_CS32 | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
6085 /* returning to 32-bit code - wider 32-bit target address: */
6086 { 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 },
6087 { 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 },
6088 { 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 },
6089 { 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 },
6090 { 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 },
6091 { 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 },
6092 { 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 },
6093 { 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 },
6094 { 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 },
6095 { 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 },
6096 { 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 },
6097 { 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 },
6098 { 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 },
6099 /* returning to 32-bit conforming code: */
6100 { 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 },
6101 { 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 },
6102 { 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 },
6103 { 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 },
6104 { 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 },
6105 { 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 },
6106 { 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 },
6107 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R0_CS32_CNF | 3, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R3_SS32 | 3, 0 },
6108 { 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 },
6109 { 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 },
6110 { 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 },
6111 { 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 },
6112 { 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 },
6113 { 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 },
6114 { 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 },
6115 { 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 },
6116 { 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 },
6117 { 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 },
6118 { true, -1, BS3_SEL_R0_SS32 | 0, 32, BS3_SEL_R2_CS32_CNF | 2, { .offDst = LOW_SWAPGS_ADDR }, BS3_SEL_R2_SS32 | 2, 0 },
6119 { 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 },
6120 { 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 },
6121 { 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 },
6122 { 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 },
6123 { 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 },
6124
6125 /* some additional #GP variations */ /** @todo test all possible exceptions! */
6126 { 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 },
6127
6128 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_00 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_00 },
6129 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_02 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_02 },
6130 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_04 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_04 },
6131 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_06 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_06 },
6132 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_08 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_08 },
6133 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_0a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0a },
6134 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_0c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0c },
6135 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_0e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_0e },
6136 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_10 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_10 },
6137 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_12 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_12 },
6138 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_14 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_14 },
6139 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_16 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_16 },
6140 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_18 | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_18 },
6141 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_1a | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1a },
6142 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_1c | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1c },
6143 { true, 14, BS3_SEL_R0_SS32 | 0, 64, BS3_SEL_SPARE_1e | 0, { .offDst = 0 }, BS3_SEL_R0_SS32 | 0, BS3_SEL_SPARE_1e },
6144 };
6145
6146 for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++)
6147 {
6148 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, s_aTests[iTest].pfnTest);
6149 //Bs3TestPrintf("-------------- #%u: cs:eip=%04RX16:%08RX64 imm=%u%s\n", iTest, Ctx.cs, Ctx.rip.u, s_aTests[iTest].cbImm,
6150 // s_aTests[iTest].fOpSizePfx == 1 ? " o16" : s_aTests[iTest].fOpSizePfx == 2 ? " o64" : "");
6151
6152 for (iSubTest = 0; iSubTest < RT_ELEMENTS(s_aSubTests); iSubTest++)
6153 {
6154 g_usBs3TestStep = (iTest << 12) | (iSubTest << 1);
6155 if (s_aTests[iTest].fOpSizePfx != 1 || s_aSubTests[iSubTest].offDst <= UINT16_MAX)
6156 {
6157 uint16_t const cbFrmDisp = s_aSubTests[iSubTest].fInterPriv ? iSubTest % 7 : 0;
6158 uint16_t const cbStkItem = s_aTests[iTest].fOpSizePfx == 2 ? 8 : s_aTests[iTest].fOpSizePfx == 0 ? 4 : 2;
6159 uint16_t const cbFrame = (s_aSubTests[iSubTest].fInterPriv ? 4 : 2) * cbStkItem;
6160 RTSEL const uDstSs = s_aSubTests[iSubTest].uDstSs;
6161 uint64_t uDstRspExpect, uDstRspPush;
6162 //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,
6163 // s_aSubTests[iSubTest].cDstBits, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst, s_aSubTests[iSubTest].uDstSs, s_aSubTests[iSubTest].uErrCd);
6164
6165 Ctx.ss = s_aSubTests[iSubTest].uStartSs;
6166 uDstRspExpect = uDstRspPush = Ctx.rsp.u + s_aTests[iTest].cbImm + cbFrame + cbFrmDisp;
6167 if (s_aSubTests[iSubTest].fInterPriv)
6168 {
6169 if (s_aTests[iTest].fOpSizePfx != 1)
6170 {
6171 if (s_aTests[iTest].fOpSizePfx == 2)
6172 uDstRspPush |= UINT64_C(0xf00dfaceacdc0000);
6173 else
6174 uDstRspPush |= UINT32_C(0xacdc0000);
6175 if (s_aSubTests[iSubTest].cDstBits == 64)
6176 uDstRspExpect = uDstRspPush;
6177 else if (!BS3_SEL_IS_SS16(uDstSs))
6178 uDstRspExpect = (uint32_t)uDstRspPush;
6179 }
6180 }
6181
6182 CtxExpected.bCpl = Ctx.bCpl;
6183 CtxExpected.cs = Ctx.cs;
6184 CtxExpected.ss = Ctx.ss;
6185 CtxExpected.ds = Ctx.ds;
6186 CtxExpected.es = Ctx.es;
6187 CtxExpected.fs = Ctx.fs;
6188 CtxExpected.gs = Ctx.gs;
6189 CtxExpected.rip.u = Ctx.rip.u;
6190 CtxExpected.rsp.u = Ctx.rsp.u;
6191 CtxExpected.rax.u = Ctx.rax.u;
6192 if (s_aSubTests[iSubTest].iXcpt < 0)
6193 {
6194 CtxExpected.cs = s_aSubTests[iSubTest].uDstCs;
6195 CtxExpected.rip.u = s_aSubTests[iSubTest].offDst;
6196 if (s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
6197 {
6198 CtxExpected.rip.u += 1;
6199 CtxExpected.rax.au8[0] = CtxExpected.rflags.u16 & X86_EFL_CF ? 0xff : 0;
6200 }
6201 CtxExpected.ss = uDstSs;
6202 CtxExpected.rsp.u = uDstRspExpect;
6203 if (s_aSubTests[iSubTest].fInterPriv)
6204 {
6205 uint16_t BS3_FAR *puSel = &CtxExpected.ds; /* ASSUME member order! */
6206 unsigned cSels = 4;
6207 CtxExpected.bCpl = CtxExpected.ss & X86_SEL_RPL;
6208 while (cSels-- > 0)
6209 {
6210 uint16_t uSel = *puSel;
6211 if ( (uSel & X86_SEL_MASK_OFF_RPL)
6212 && Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u2Dpl < CtxExpected.bCpl
6213 && (Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
6214 != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
6215 *puSel = 0;
6216 puSel++;
6217 }
6218 CtxExpected.rsp.u += s_aTests[iTest].cbImm; /* arguments are dropped from both stacks. */
6219 }
6220 }
6221 g_uBs3TrapEipHint = CtxExpected.rip.u32;
6222 //Bs3TestPrintf("ss:rsp=%04RX16:%04RX64 -> %04RX16:%04RX64 [pushed %#RX64]; %04RX16:%04RX64\n",Ctx.ss, Ctx.rsp.u,
6223 // CtxExpected.ss, CtxExpected.rsp.u, uDstRspPush, CtxExpected.cs, CtxExpected.rip.u);
6224 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
6225 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
6226 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
6227 //Bs3TestPrintf("%p: %04RX16 %04RX16 %04RX16 %04RX16\n", StkPtr.pu16, StkPtr.pu16[0], StkPtr.pu16[1], StkPtr.pu16[2], StkPtr.pu16[3]);
6228 //Bs3TestPrintf("%.48Rhxd\n", StkPtr.pu16);
6229 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
6230 if (s_aSubTests[iSubTest].iXcpt < 0)
6231 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
6232 else
6233 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
6234 g_usBs3TestStep++;
6235
6236 /* Again single stepping: */
6237 //Bs3TestPrintf("stepping...\n");
6238 Bs3RegSetDr6(X86_DR6_INIT_VAL);
6239 Ctx.rflags.u16 |= X86_EFL_TF;
6240 CtxExpected.rflags.u16 = Ctx.rflags.u16;
6241 if (s_aSubTests[iSubTest].iXcpt < 0 && s_aSubTests[iSubTest].cDstBits == 64 && !BS3_MODE_IS_64BIT_SYS(bMode))
6242 {
6243 CtxExpected.rip.u -= 1;
6244 CtxExpected.rax.u = Ctx.rax.u;
6245 }
6246 bs3CpuBasic2_retf_PrepStack(StkPtr, cbStkItem, s_aSubTests[iSubTest].uDstCs, s_aSubTests[iSubTest].offDst,
6247 s_aSubTests[iSubTest].fInterPriv, s_aTests[iTest].cbImm,
6248 s_aSubTests[iSubTest].uDstSs, uDstRspPush);
6249 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
6250 if (s_aSubTests[iSubTest].iXcpt < 0)
6251 bs3CpuBasic2_CompareDbCtx(&TrapCtx, &CtxExpected, X86_DR6_BS);
6252 else
6253 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, s_aSubTests[iSubTest].uErrCd);
6254 Ctx.rflags.u16 &= ~X86_EFL_TF;
6255 CtxExpected.rflags.u16 = Ctx.rflags.u16;
6256 g_usBs3TestStep++;
6257 }
6258 }
6259 }
6260 }
6261 else
6262 Bs3TestFailed("wtf?");
6263
6264 if (BS3_MODE_IS_64BIT_SYS(bMode))
6265 Bs3TrapReInit();
6266 return 0;
6267}
6268
6269
6270
6271/*********************************************************************************************************************************
6272* Instruction Length *
6273*********************************************************************************************************************************/
6274
6275
6276static uint8_t bs3CpuBasic2_instr_len_Worker(uint8_t bMode, uint8_t BS3_FAR *pbCodeBuf)
6277{
6278 BS3TRAPFRAME TrapCtx;
6279 BS3REGCTX Ctx;
6280 BS3REGCTX CtxExpected;
6281 uint32_t uEipBase;
6282 unsigned cbInstr;
6283 unsigned off;
6284
6285 /* Make sure they're allocated and all zeroed. */
6286 Bs3MemZero(&Ctx, sizeof(Ctx));
6287 Bs3MemZero(&CtxExpected, sizeof(Ctx));
6288 Bs3MemZero(&TrapCtx, sizeof(TrapCtx));
6289
6290 /*
6291 * Create a context.
6292 *
6293 * ASSUMES we're in on the ring-0 stack in ring-0 and using less than 16KB.
6294 */
6295 Bs3RegCtxSaveEx(&Ctx, bMode, 768);
6296 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, (FPFNBS3FAR)pbCodeBuf);
6297 uEipBase = Ctx.rip.u32;
6298
6299 Bs3MemCpy(&CtxExpected, &Ctx, sizeof(CtxExpected));
6300
6301 /*
6302 * Simple stuff crossing the page.
6303 */
6304 for (off = X86_PAGE_SIZE - 32; off <= X86_PAGE_SIZE + 16; off++)
6305 {
6306 Ctx.rip.u32 = uEipBase + off;
6307 for (cbInstr = 0; cbInstr < 24; cbInstr++)
6308 {
6309 /*
6310 * Generate the instructions:
6311 * [es] nop
6312 * ud2
6313 */
6314 if (cbInstr > 0)
6315 {
6316 Bs3MemSet(&pbCodeBuf[off], 0x26 /* es */, cbInstr);
6317 pbCodeBuf[off + cbInstr - 1] = 0x90; /* nop */
6318 }
6319 pbCodeBuf[off + cbInstr + 0] = 0x0f; /* ud2 */
6320 pbCodeBuf[off + cbInstr + 1] = 0x0b;
6321
6322 /*
6323 * Test it.
6324 */
6325 if (cbInstr < 16)
6326 CtxExpected.rip.u32 = Ctx.rip.u32 + cbInstr;
6327 else
6328 CtxExpected.rip.u32 = Ctx.rip.u32;
6329 g_uBs3TrapEipHint = CtxExpected.rip.u32;
6330 Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
6331 if (cbInstr < 16)
6332 bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxExpected);
6333 else
6334 bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxExpected, 0);
6335 }
6336 pbCodeBuf[off] = 0xf1; /* icebp */
6337 }
6338
6339 /*
6340 * Pit instruction length violations against the segment limit (#GP).
6341 */
6342 if (!BS3_MODE_IS_RM_OR_V86(bMode) && bMode != BS3_MODE_LM64)
6343 {
6344 /** @todo */
6345 }
6346
6347 /*
6348 * Pit instruction length violations against an invalid page (#PF).
6349 */
6350 if (BS3_MODE_IS_PAGED(bMode))
6351 {
6352 /** @todo */
6353 }
6354
6355 return 0;
6356}
6357
6358
6359/**
6360 * Entrypoint for FAR RET tests.
6361 *
6362 * @returns 0 or BS3TESTDOMODE_SKIPPED.
6363 * @param bMode The CPU mode we're testing.
6364 */
6365BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_instr_len)(uint8_t bMode)
6366{
6367 /*
6368 * Allocate three pages so we can straddle an instruction across the
6369 * boundrary for testing special IEM cases, with the last page being
6370 * made in accessible and useful for pitting #PF against #GP.
6371 */
6372 uint8_t BS3_FAR * const pbCodeBuf = (uint8_t BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_REAL, X86_PAGE_SIZE * 3);
6373 //Bs3TestPrintf("pbCodeBuf=%p\n", pbCodeBuf);
6374 if (pbCodeBuf)
6375 {
6376 Bs3MemSet(pbCodeBuf, 0xf1, X86_PAGE_SIZE * 3);
6377 bs3CpuBasic2_SetGlobals(bMode);
6378
6379 if (!BS3_MODE_IS_PAGED(bMode))
6380 bs3CpuBasic2_instr_len_Worker(bMode, pbCodeBuf);
6381 else
6382 {
6383 uint32_t const uFlatLastPg = Bs3SelPtrToFlat(pbCodeBuf) + X86_PAGE_SIZE * 2;
6384 int rc = Bs3PagingProtect(uFlatLastPg, X86_PAGE_SIZE, 0, X86_PTE_P);
6385 if (RT_SUCCESS(rc))
6386 {
6387 bs3CpuBasic2_instr_len_Worker(bMode, pbCodeBuf);
6388 Bs3PagingProtect(uFlatLastPg, X86_PAGE_SIZE, X86_PTE_P, 0);
6389 }
6390 else
6391 Bs3TestFailed("Failed to allocate 3 code pages");
6392 }
6393
6394 Bs3MemFree(pbCodeBuf, X86_PAGE_SIZE * 3);
6395 }
6396 else
6397 Bs3TestFailed("Failed to allocate 3 code pages");
6398 return 0;
6399}
6400
Note: See TracBrowser for help on using the repository browser.

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