VirtualBox

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

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

ValKit/bs3-cpu-instr-2: Simple RORX test to establing whether V<>0 triggers #UD or not (it does). bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 51.3 KB
Line 
1/* $Id: bs3-cpu-instr-2-template.c 95296 2022-06-15 22:06:20Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-instr-2, C code template.
4 */
5
6/*
7 * Copyright (C) 2007-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/asm.h>
32#include <iprt/asm-amd64-x86.h>
33
34
35/*********************************************************************************************************************************
36* Structures and Typedefs *
37*********************************************************************************************************************************/
38#ifdef BS3_INSTANTIATING_CMN
39# if ARCH_BITS == 64
40typedef struct BS3CI2FSGSBASE
41{
42 const char *pszDesc;
43 bool f64BitOperand;
44 FPFNBS3FAR pfnWorker;
45 uint8_t offWorkerUd2;
46 FPFNBS3FAR pfnVerifyWorker;
47 uint8_t offVerifyWorkerUd2;
48} BS3CI2FSGSBASE;
49# endif
50#endif
51
52
53/*********************************************************************************************************************************
54* External Symbols *
55*********************************************************************************************************************************/
56#ifdef BS3_INSTANTIATING_CMN
57extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2);
58extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2);
59extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2);
60extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2);
61extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2);
62extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp);
63extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp);
64extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_L1);
65# if ARCH_BITS == 64
66extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_X1);
67# endif
68extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V1);
69extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V15);
70# if ARCH_BITS == 64
71extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2);
72extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2);
73extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2);
74extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2);
75extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2);
76extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2);
77extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2);
78extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2);
79
80extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2);
81extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2);
82extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2);
83extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2);
84
85extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2);
86extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2);
87extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2);
88extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2);
89
90extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2);
91extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2);
92extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2);
93extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2);
94# endif
95#endif
96
97
98/*********************************************************************************************************************************
99* Global Variables *
100*********************************************************************************************************************************/
101#ifdef BS3_INSTANTIATING_CMN
102# if ARCH_BITS == 64
103static BS3CI2FSGSBASE const s_aWrFsBaseWorkers[] =
104{
105 { "wrfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 13 },
106 { "wrfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 10 },
107};
108
109static BS3CI2FSGSBASE const s_aWrGsBaseWorkers[] =
110{
111 { "wrgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 13 },
112 { "wrgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 10 },
113};
114
115static BS3CI2FSGSBASE const s_aRdFsBaseWorkers[] =
116{
117 { "rdfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 13 },
118 { "rdfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 10 },
119};
120
121static BS3CI2FSGSBASE const s_aRdGsBaseWorkers[] =
122{
123 { "rdgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 13 },
124 { "rdgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 10 },
125};
126# endif
127#endif /* BS3_INSTANTIATING_CMN - global */
128
129
130/*
131 * Common code.
132 * Common code.
133 * Common code.
134 */
135#ifdef BS3_INSTANTIATING_CMN
136
137BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mul)(uint8_t bMode)
138{
139#define MUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
140#define MUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
141
142 static const struct
143 {
144 RTCCUINTREG uInAX;
145 RTCCUINTREG uInBX;
146 RTCCUINTREG uOutDX;
147 RTCCUINTREG uOutAX;
148 uint16_t fFlags;
149 } s_aTests[] =
150 {
151 { 1, 1,
152 0, 1, 0 },
153 { 2, 2,
154 0, 4, 0 },
155 { RTCCUINTREG_MAX, RTCCUINTREG_MAX,
156 RTCCUINTREG_MAX-1, 1, X86_EFL_CF | X86_EFL_OF },
157 { RTCCINTREG_MAX, RTCCINTREG_MAX,
158 RTCCINTREG_MAX / 2, 1, X86_EFL_CF | X86_EFL_OF },
159 { 1, RTCCUINTREG_MAX,
160 0, RTCCUINTREG_MAX, X86_EFL_PF | X86_EFL_SF },
161 { 1, RTCCINTREG_MAX,
162 0, RTCCINTREG_MAX, X86_EFL_PF },
163 { 2, RTCCINTREG_MAX,
164 0, RTCCUINTREG_MAX - 1, X86_EFL_SF },
165 { (RTCCUINTREG)RTCCINTREG_MAX + 1, 2,
166 1, 0, X86_EFL_PF | X86_EFL_CF | X86_EFL_OF },
167 { (RTCCUINTREG)RTCCINTREG_MAX / 2 + 1, 3,
168 0, ((RTCCUINTREG)RTCCINTREG_MAX / 2 + 1) * 3, X86_EFL_PF | X86_EFL_SF },
169 };
170
171 BS3REGCTX Ctx;
172 BS3TRAPFRAME TrapFrame;
173 unsigned i, j, k;
174
175 /* Ensure the structures are allocated before we sample the stack pointer. */
176 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
177 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
178
179 /*
180 * Create test context.
181 */
182 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
183 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2));
184 for (k = 0; k < 2; k++)
185 {
186 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
187 for (j = 0; j < 2; j++)
188 {
189 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
190 {
191 if (k == 0)
192 {
193 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
194 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
195 }
196 else
197 {
198 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
199 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
200 }
201 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
202 if (TrapFrame.bXcpt != X86_XCPT_UD)
203 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
204 else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
205 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
206 || (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
207 != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
208 {
209 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
210 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
211
212 if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
213 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
214 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
215 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
216 Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
217 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
218 if ( (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
219 != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
220 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & MUL_CHECK_EFLAGS,
221 TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO));
222 }
223 }
224 Ctx.rflags.u16 &= ~(MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO);
225 }
226 }
227
228 return 0;
229}
230
231
232BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_imul)(uint8_t bMode)
233{
234#define IMUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
235#define IMUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
236 static const struct
237 {
238 RTCCUINTREG uInAX;
239 RTCCUINTREG uInBX;
240 RTCCUINTREG uOutDX;
241 RTCCUINTREG uOutAX;
242 uint16_t fFlags;
243 } s_aTests[] =
244 {
245 /* two positive values. */
246 { 1, 1,
247 0, 1, 0 },
248 { 2, 2,
249 0, 4, 0 },
250 { RTCCINTREG_MAX, RTCCINTREG_MAX,
251 RTCCINTREG_MAX/2, 1, X86_EFL_CF | X86_EFL_OF },
252 { 1, RTCCINTREG_MAX,
253 0, RTCCINTREG_MAX, X86_EFL_PF },
254 { 2, RTCCINTREG_MAX,
255 0, RTCCUINTREG_MAX - 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF },
256 { 2, RTCCINTREG_MAX / 2,
257 0, RTCCINTREG_MAX - 1U, 0 },
258 { 2, (RTCCINTREG_MAX / 2 + 1),
259 0, (RTCCUINTREG)RTCCINTREG_MAX + 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
260 { 4, (RTCCINTREG_MAX / 2 + 1),
261 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
262
263 /* negative and positive */
264 { -4, 3,
265 -1, -12, X86_EFL_SF },
266 { 32, -127,
267 -1, -4064, X86_EFL_SF },
268 { RTCCINTREG_MIN, 1,
269 -1, RTCCINTREG_MIN, X86_EFL_SF | X86_EFL_PF },
270 { RTCCINTREG_MIN, 2,
271 -1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
272 { RTCCINTREG_MIN, 3,
273 -2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
274 { RTCCINTREG_MIN, 4,
275 -2, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
276 { RTCCINTREG_MIN, RTCCINTREG_MAX,
277 RTCCINTREG_MIN / 2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
278 { RTCCINTREG_MIN, RTCCINTREG_MAX - 1,
279 RTCCINTREG_MIN / 2 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
280
281 /* two negative values. */
282 { -4, -63,
283 0, 252, X86_EFL_PF },
284 { RTCCINTREG_MIN, RTCCINTREG_MIN,
285 RTCCUINTREG_MAX / 4 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
286 { RTCCINTREG_MIN, RTCCINTREG_MIN + 1,
287 RTCCUINTREG_MAX / 4, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF},
288 { RTCCINTREG_MIN + 1, RTCCINTREG_MIN + 1,
289 RTCCUINTREG_MAX / 4, 1, X86_EFL_CF | X86_EFL_OF },
290
291 };
292
293 BS3REGCTX Ctx;
294 BS3TRAPFRAME TrapFrame;
295 unsigned i, j, k;
296
297 /* Ensure the structures are allocated before we sample the stack pointer. */
298 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
299 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
300
301 /*
302 * Create test context.
303 */
304 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
305 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2));
306
307 for (k = 0; k < 2; k++)
308 {
309 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
310 for (j = 0; j < 2; j++)
311 {
312 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
313 {
314 if (k == 0)
315 {
316 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
317 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
318 }
319 else
320 {
321 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
322 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
323 }
324 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
325 if (TrapFrame.bXcpt != X86_XCPT_UD)
326 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
327 else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
328 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
329 || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
330 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
331 {
332 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
333 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
334
335 if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
336 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
337 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
338 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
339 Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
340 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
341 if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
342 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
343 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
344 TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
345 }
346 }
347 }
348 }
349
350 /*
351 * Repeat for the truncating two operand version.
352 */
353 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2));
354
355 for (k = 0; k < 2; k++)
356 {
357 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
358 for (j = 0; j < 2; j++)
359 {
360 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
361 {
362 if (k == 0)
363 {
364 Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
365 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
366 }
367 else
368 {
369 Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
370 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
371 }
372 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
373 if (TrapFrame.bXcpt != X86_XCPT_UD)
374 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
375 else if ( TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
376 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
377 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
378 || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
379 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
380 {
381 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
382 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
383
384 if (TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
385 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
386 s_aTests[i].uOutAX, TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS));
387 if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
388 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
389 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
390 TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
391 }
392 }
393 }
394 }
395
396 return 0;
397}
398
399
400BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_div)(uint8_t bMode)
401{
402#define DIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
403 static const struct
404 {
405 RTCCUINTREG uInDX;
406 RTCCUINTREG uInAX;
407 RTCCUINTREG uInBX;
408 RTCCUINTREG uOutAX;
409 RTCCUINTREG uOutDX;
410 uint8_t bXcpt;
411 } s_aTests[] =
412 {
413 { 0, 1, 1,
414 1, 0, X86_XCPT_UD },
415 { 0, 5, 2,
416 2, 1, X86_XCPT_UD },
417 { 0, 0, 0,
418 0, 0, X86_XCPT_DE },
419 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 0,
420 0, 0, X86_XCPT_DE },
421 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 1,
422 0, 0, X86_XCPT_DE },
423 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
424 0, 0, X86_XCPT_DE },
425 { RTCCUINTREG_MAX - 1, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
426 RTCCUINTREG_MAX, RTCCUINTREG_MAX - 1, X86_XCPT_UD },
427 };
428
429 BS3REGCTX Ctx;
430 BS3TRAPFRAME TrapFrame;
431 unsigned i, j;
432
433 /* Ensure the structures are allocated before we sample the stack pointer. */
434 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
435 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
436
437 /*
438 * Create test context.
439 */
440 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
441 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2));
442
443 /*
444 * Do the tests twice, first with all flags set, then once again with
445 * flags cleared. The flags are not touched by my intel skylake CPU.
446 */
447 Ctx.rflags.u16 |= DIV_CHECK_EFLAGS;
448 for (j = 0; j < 2; j++)
449 {
450 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
451 {
452 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
453 Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
454 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
455 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
456
457 if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
458 || ( s_aTests[i].bXcpt == X86_XCPT_UD
459 ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
460 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
461 || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS)
462 : TrapFrame.Ctx.rax.u != Ctx.rax.u
463 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
464 || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS) ) )
465 {
466 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
467 i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
468 if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
469 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
470 if (s_aTests[i].bXcpt == X86_XCPT_UD)
471 {
472 if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
473 Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
474 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
475 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
476 Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
477 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
478 if ((TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS))
479 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
480 Ctx.rflags.u16 & DIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS);
481 }
482 }
483 }
484 Ctx.rflags.u16 &= ~DIV_CHECK_EFLAGS;
485 }
486
487 return 0;
488}
489
490
491
492BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_idiv)(uint8_t bMode)
493{
494#define IDIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
495 static const struct
496 {
497 RTCCUINTREG uInDX;
498 RTCCUINTREG uInAX;
499 RTCCUINTREG uInBX;
500 RTCCUINTREG uOutAX;
501 RTCCUINTREG uOutDX;
502 uint8_t bXcpt;
503 } s_aTests[] =
504 {
505 { 0, 0, 0,
506 0, 0, X86_XCPT_DE },
507 { RTCCINTREG_MAX, RTCCINTREG_MAX, 0,
508 0, 0, X86_XCPT_DE },
509 /* two positive values. */
510 { 0, 1, 1,
511 1, 0, X86_XCPT_UD },
512 { 0, 5, 2,
513 2, 1, X86_XCPT_UD },
514 { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2, RTCCINTREG_MAX,
515 RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_UD },
516 { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2 + 1, RTCCINTREG_MAX,
517 RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_DE },
518 /* negative dividend, positive divisor. */
519 { -1, -7, 2,
520 -3, -1, X86_XCPT_UD },
521 { RTCCINTREG_MIN / 2 + 1, 0, RTCCINTREG_MAX,
522 RTCCINTREG_MIN + 2, RTCCINTREG_MIN + 2, X86_XCPT_UD },
523 { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MAX,
524 0, 0, X86_XCPT_DE },
525 /* positive dividend, negative divisor. */
526 { 0, 7, -2,
527 -3, 1, X86_XCPT_UD },
528 { RTCCINTREG_MAX / 2 + 1, RTCCINTREG_MAX, RTCCINTREG_MIN,
529 RTCCINTREG_MIN, RTCCINTREG_MAX, X86_XCPT_UD },
530 { RTCCINTREG_MAX / 2 + 1, (RTCCUINTREG)RTCCINTREG_MAX+1, RTCCINTREG_MIN,
531 0, 0, X86_XCPT_DE },
532 /* negative dividend, negative divisor. */
533 { -1, -7, -2,
534 3, -1, X86_XCPT_UD },
535 { RTCCINTREG_MIN / 2, 1, RTCCINTREG_MIN,
536 RTCCINTREG_MAX, RTCCINTREG_MIN + 1, X86_XCPT_UD },
537 { RTCCINTREG_MIN / 2, 2, RTCCINTREG_MIN,
538 RTCCINTREG_MAX, RTCCINTREG_MIN + 2, X86_XCPT_UD },
539 { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MIN,
540 0, 0, X86_XCPT_DE },
541 };
542
543 BS3REGCTX Ctx;
544 BS3TRAPFRAME TrapFrame;
545 unsigned i, j;
546
547 /* Ensure the structures are allocated before we sample the stack pointer. */
548 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
549 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
550
551 /*
552 * Create test context.
553 */
554 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
555 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2));
556
557 /*
558 * Do the tests twice, first with all flags set, then once again with
559 * flags cleared. The flags are not touched by my intel skylake CPU.
560 */
561 Ctx.rflags.u16 |= IDIV_CHECK_EFLAGS;
562 for (j = 0; j < 2; j++)
563 {
564 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
565 {
566 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
567 Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
568 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
569 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
570
571 if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
572 || ( s_aTests[i].bXcpt == X86_XCPT_UD
573 ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
574 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
575 || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS)
576 : TrapFrame.Ctx.rax.u != Ctx.rax.u
577 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
578 || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) ) )
579 {
580 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
581 i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
582 if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
583 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
584 if (s_aTests[i].bXcpt == X86_XCPT_UD)
585 {
586 if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
587 Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
588 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
589 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
590 Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
591 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
592 if ((TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS))
593 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
594 Ctx.rflags.u16 & IDIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS);
595 }
596 }
597 }
598 Ctx.rflags.u16 &= ~IDIV_CHECK_EFLAGS;
599 }
600
601 return 0;
602}
603
604
605BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rorx)(uint8_t bMode)
606{
607 static const struct
608 {
609 FPFNBS3FAR pfnWorker;
610 bool fOkay;
611 RTCCUINTXREG uIn;
612 RTCCUINTXREG uOut;
613 } s_aTests[] =
614 {
615 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp), true, // #0
616 0, /* -> */ 0 },
617 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp), true, // #1
618 ~(RTCCUINTXREG)2, /* -> */ ~(RTCCUINTXREG)0 >> 1 },
619 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp), true, // #2
620 0, /* -> */ 0 },
621 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp), true, // #3
622 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG)(~(uint32_t)0 >> 1) },
623
624 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_L1), false, // #4
625 RTCCUINTXREG_MAX, /* -> */ 0 },
626 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V1), false, // #5
627 RTCCUINTXREG_MAX, /* -> */ 0 },
628 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V15), false, // #6
629 RTCCUINTXREG_MAX, /* -> */ 0 },
630# if ARCH_BITS == 64 /* The VEX.X=0 encoding mean LES instruction in 32-bit and 16-bit mode. */
631 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_X1), true, // #7
632 UINT32_C(0xf1e2d3c5), /* -> */ (RTCCUINTXREG)UINT32_C(0x7c78b4f1) },
633# endif
634 };
635
636 BS3REGCTX Ctx;
637 BS3TRAPFRAME TrapFrame;
638 unsigned i, j;
639
640 /* Ensure the structures are allocated before we sample the stack pointer. */
641 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
642 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
643
644 /*
645 * Create test context.
646 */
647 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
648
649 /*
650 * Do the tests twice, first with all flags set, then once again with
651 * flags cleared. The flags are not supposed to be touched at all.
652 */
653 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
654 for (j = 0; j < 2; j++)
655 {
656 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
657 {
658 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && s_aTests[i].fOkay;
659 uint64_t uExpectRbx;
660 uint64_t uExpectRip;
661 Ctx.rbx.uCcXReg = RTCCUINTXREG_MAX * 1019;
662 Ctx.rdx.uCcXReg = s_aTests[i].uIn;
663 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
664 uExpectRbx = fOkay ? s_aTests[i].uOut : Ctx.rbx.u;
665 uExpectRip = Ctx.rip.u + (fOkay ? 6 : 0);
666 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
667
668 if ( TrapFrame.bXcpt != X86_XCPT_UD
669 || TrapFrame.Ctx.rip.u != uExpectRip
670 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
671 || TrapFrame.Ctx.rbx.u != uExpectRbx
672 /* check that nothing else really changed: */
673 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS)
674 || TrapFrame.Ctx.rax.u != Ctx.rax.u
675 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
676 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
677 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
678 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
679 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
680 )
681 {
682 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uIn);
683 if (TrapFrame.bXcpt != X86_XCPT_UD)
684 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", X86_XCPT_UD, TrapFrame.bXcpt);
685 if (TrapFrame.Ctx.rip.u != uExpectRip)
686 Bs3TestFailedF("Expected RIP = %#06RX16, got %#06RX16 (src)", uExpectRip, TrapFrame.Ctx.rip.u);
687 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
688 Bs3TestFailedF("Expected RDX = %#06RX16, got %#06RX16 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
689 if (TrapFrame.Ctx.rbx.u != uExpectRbx)
690 Bs3TestFailedF("Expected RBX = %#06RX16, got %#06RX16 (dst)", uExpectRbx, TrapFrame.Ctx.rbx.u);
691
692 if ((TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS))
693 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
694 Ctx.rflags.u16 & X86_EFL_STATUS_BITS, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
695 if (TrapFrame.Ctx.rax.u != Ctx.rax.u)
696 Bs3TestFailedF("Expected RAX = %#06RX16, got %#06RX16", Ctx.rax.u, TrapFrame.Ctx.rax.u);
697 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
698 Bs3TestFailedF("Expected RCX = %#06RX16, got %#06RX16", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
699 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
700 Bs3TestFailedF("Expected RSP = %#06RX16, got %#06RX16", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
701 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
702 Bs3TestFailedF("Expected RBP = %#06RX16, got %#06RX16", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
703 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
704 Bs3TestFailedF("Expected RSI = %#06RX16, got %#06RX16", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
705 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
706 Bs3TestFailedF("Expected RDI = %#06RX16, got %#06RX16", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
707 }
708 }
709 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
710 }
711
712 return 0;
713}
714
715
716# if ARCH_BITS == 64
717
718BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b)(uint8_t bMode)
719{
720 BS3REGCTX Ctx;
721 BS3REGCTX ExpectCtx;
722 BS3TRAPFRAME TrapFrame;
723 RTUINT128U au128[3];
724 PRTUINT128U pau128 = RT_ALIGN_PT(&au128[0], sizeof(RTUINT128U), PRTUINT128U);
725 bool const fSupportCX16 = RT_BOOL(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16);
726 unsigned iFlags;
727 unsigned offBuf;
728 unsigned iMatch;
729 unsigned iWorker;
730 static struct
731 {
732 bool fLocked;
733 uint8_t offUd2;
734 FNBS3FAR *pfnWorker;
735 } const s_aWorkers[] =
736 {
737 { false, 4, BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2) },
738 { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2) },
739 { false, 5, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2) },
740 { false, 5, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2) },
741 { true, 1+4, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2) },
742 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2) },
743 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2) },
744 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2) },
745 };
746
747 /* Ensure the structures are allocated before we sample the stack pointer. */
748 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
749 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
750 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
751 Bs3MemSet(pau128, 0, sizeof(pau128[0]) * 2);
752
753 /*
754 * Create test context.
755 */
756 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
757 if (!fSupportCX16)
758 Bs3TestPrintf("Note! CMPXCHG16B is not supported by the CPU!\n");
759
760 /*
761 * One loop with the normal variant and one with the locked one
762 */
763 g_usBs3TestStep = 0;
764 for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++)
765 {
766 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker);
767
768 /*
769 * One loop with all status flags set, and one with them clear.
770 */
771 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
772 for (iFlags = 0; iFlags < 2; iFlags++)
773 {
774 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
775
776 for (offBuf = 0; offBuf < sizeof(RTUINT128U); offBuf++)
777 {
778# define CX16_OLD_LO UINT64_C(0xabb6345dcc9c4bbd)
779# define CX16_OLD_HI UINT64_C(0x7b06ea35749549ab)
780# define CX16_MISMATCH_LO UINT64_C(0xbace3e3590f18981)
781# define CX16_MISMATCH_HI UINT64_C(0x9b385e8bfd5b4000)
782# define CX16_STORE_LO UINT64_C(0x5cbd27d251f6559b)
783# define CX16_STORE_HI UINT64_C(0x17ff434ed1b54963)
784
785 PRTUINT128U pBuf = (PRTUINT128U)&pau128->au8[offBuf];
786
787 ExpectCtx.rax.u = Ctx.rax.u = CX16_MISMATCH_LO;
788 ExpectCtx.rdx.u = Ctx.rdx.u = CX16_MISMATCH_HI;
789 for (iMatch = 0; iMatch < 2; iMatch++)
790 {
791 uint8_t bExpectXcpt;
792 pBuf->s.Lo = CX16_OLD_LO;
793 pBuf->s.Hi = CX16_OLD_HI;
794 ExpectCtx.rdi.u = Ctx.rdi.u = (uintptr_t)pBuf;
795 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
796 g_usBs3TestStep++;
797 //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker);
798 bExpectXcpt = X86_XCPT_UD;
799 if (fSupportCX16)
800 {
801 if (offBuf & 15)
802 {
803 bExpectXcpt = X86_XCPT_GP;
804 ExpectCtx.rip.u = Ctx.rip.u;
805 ExpectCtx.rflags.u32 = Ctx.rflags.u32;
806 }
807 else
808 {
809 ExpectCtx.rax.u = CX16_OLD_LO;
810 ExpectCtx.rdx.u = CX16_OLD_HI;
811 if (iMatch & 1)
812 ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF;
813 else
814 ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF;
815 ExpectCtx.rip.u = Ctx.rip.u + s_aWorkers[iWorker].offUd2;
816 }
817 ExpectCtx.rflags.u32 |= X86_EFL_RF;
818 }
819 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
820 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)
821 || TrapFrame.bXcpt != bExpectXcpt)
822 {
823 if (TrapFrame.bXcpt != bExpectXcpt)
824 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
825 Bs3TestFailedF("^^^ iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n", iWorker, iFlags, offBuf, iMatch);
826 ASMHalt();
827 }
828
829 ExpectCtx.rax.u = Ctx.rax.u = CX16_OLD_LO;
830 ExpectCtx.rdx.u = Ctx.rdx.u = CX16_OLD_HI;
831 }
832 }
833 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
834 }
835 }
836
837 return 0;
838}
839
840
841static void bs3CpuInstr2_fsgsbase_ExpectUD(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame)
842{
843 pCtx->rbx.u = 0;
844 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
845 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
846 pExpectCtx->rip.u = pCtx->rip.u;
847 pExpectCtx->rflags.u32 |= X86_EFL_RF;
848 if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
849 0 /*idTestStep*/)
850 || pTrapFrame->bXcpt != X86_XCPT_UD)
851 {
852 Bs3TestFailedF("Expected #UD, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
853 ASMHalt();
854 }
855}
856
857
858static bool bs3CpuInstr2_fsgsbase_VerifyWorker(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame,
859 BS3CI2FSGSBASE const *pFsGsBaseWorker, unsigned *puIter)
860{
861 bool fPassed = true;
862 unsigned iValue = 0;
863 static const struct
864 {
865 bool fGP;
866 uint64_t u64Base;
867 } s_aValues64[] =
868 {
869 { false, UINT64_C(0x0000000000000000) },
870 { false, UINT64_C(0x0000000000000001) },
871 { false, UINT64_C(0x0000000000000010) },
872 { false, UINT64_C(0x0000000000000123) },
873 { false, UINT64_C(0x0000000000001234) },
874 { false, UINT64_C(0x0000000000012345) },
875 { false, UINT64_C(0x0000000000123456) },
876 { false, UINT64_C(0x0000000001234567) },
877 { false, UINT64_C(0x0000000012345678) },
878 { false, UINT64_C(0x0000000123456789) },
879 { false, UINT64_C(0x000000123456789a) },
880 { false, UINT64_C(0x00000123456789ab) },
881 { false, UINT64_C(0x0000123456789abc) },
882 { false, UINT64_C(0x00007ffffeefefef) },
883 { false, UINT64_C(0x00007fffffffffff) },
884 { true, UINT64_C(0x0000800000000000) },
885 { true, UINT64_C(0x0000800000000000) },
886 { true, UINT64_C(0x0000800000000333) },
887 { true, UINT64_C(0x0001000000000000) },
888 { true, UINT64_C(0x0012000000000000) },
889 { true, UINT64_C(0x0123000000000000) },
890 { true, UINT64_C(0x1234000000000000) },
891 { true, UINT64_C(0xffff300000000000) },
892 { true, UINT64_C(0xffff7fffffffffff) },
893 { true, UINT64_C(0xffff7fffffffffff) },
894 { false, UINT64_C(0xffff800000000000) },
895 { false, UINT64_C(0xffffffffffeefefe) },
896 { false, UINT64_C(0xffffffffffffffff) },
897 { false, UINT64_C(0xffffffffffffffff) },
898 { false, UINT64_C(0x00000000efefefef) },
899 { false, UINT64_C(0x0000000080204060) },
900 { false, UINT64_C(0x00000000ddeeffaa) },
901 { false, UINT64_C(0x00000000fdecdbca) },
902 { false, UINT64_C(0x000000006098456b) },
903 { false, UINT64_C(0x0000000098506099) },
904 { false, UINT64_C(0x00000000206950bc) },
905 { false, UINT64_C(0x000000009740395d) },
906 { false, UINT64_C(0x0000000064a9455e) },
907 { false, UINT64_C(0x00000000d20b6eff) },
908 { false, UINT64_C(0x0000000085296d46) },
909 { false, UINT64_C(0x0000000007000039) },
910 { false, UINT64_C(0x000000000007fe00) },
911 };
912
913 Bs3RegCtxSetRipCsFromCurPtr(pCtx, pFsGsBaseWorker->pfnVerifyWorker);
914 if (pFsGsBaseWorker->f64BitOperand)
915 {
916 for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
917 {
918 bool const fGP = s_aValues64[iValue].fGP;
919
920 pCtx->rbx.u = s_aValues64[iValue].u64Base;
921 pCtx->rcx.u = 0;
922 pCtx->cr4.u |= X86_CR4_FSGSBASE;
923 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
924 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
925 pExpectCtx->rip.u = pCtx->rip.u + (!fGP ? pFsGsBaseWorker->offVerifyWorkerUd2 : 0);
926 pExpectCtx->rbx.u = !fGP ? 0 : s_aValues64[iValue].u64Base;
927 pExpectCtx->rcx.u = !fGP ? s_aValues64[iValue].u64Base : 0;
928 pExpectCtx->rflags.u32 |= X86_EFL_RF;
929 if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
930 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)
931 || (fGP && pTrapFrame->bXcpt != X86_XCPT_GP))
932 {
933 if (fGP && pTrapFrame->bXcpt != X86_XCPT_GP)
934 Bs3TestFailedF("Expected #GP, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
935 fPassed = false;
936 break;
937 }
938 }
939 }
940 else
941 {
942 for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
943 {
944 pCtx->rbx.u = s_aValues64[iValue].u64Base;
945 pCtx->rcx.u = ~s_aValues64[iValue].u64Base;
946 pCtx->cr4.u |= X86_CR4_FSGSBASE;
947 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
948 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
949 pExpectCtx->rip.u = pCtx->rip.u + pFsGsBaseWorker->offVerifyWorkerUd2;
950 pExpectCtx->rbx.u = 0;
951 pExpectCtx->rcx.u = s_aValues64[iValue].u64Base & UINT64_C(0x00000000ffffffff);
952 pExpectCtx->rflags.u32 |= X86_EFL_RF;
953 if (!Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
954 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/))
955 {
956 fPassed = false;
957 break;
958 }
959 }
960 }
961
962 *puIter = iValue;
963 return fPassed;
964}
965
966
967static void bs3CpuInstr2_rdfsbase_rdgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
968 unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
969{
970 BS3REGCTX Ctx;
971 BS3REGCTX ExpectCtx;
972 BS3TRAPFRAME TrapFrame;
973 unsigned iWorker;
974 unsigned iIter;
975 uint32_t uDummy;
976 uint32_t uStdExtFeatEbx;
977 bool fSupportsFsGsBase;
978
979 ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
980 fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
981
982 /* Ensure the structures are allocated before we sample the stack pointer. */
983 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
984 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
985 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
986
987 /*
988 * Create test context.
989 */
990 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
991
992 for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
993 {
994 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
995 if (fSupportsFsGsBase)
996 {
997 uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
998
999 /* CR4.FSGSBASE disabled -> #UD. */
1000 Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
1001 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
1002
1003 /* Read and verify existing base address. */
1004 Ctx.rbx.u = 0;
1005 Ctx.cr4.u |= X86_CR4_FSGSBASE;
1006 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
1007 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1008 ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
1009 ExpectCtx.rbx.u = uBaseAddr;
1010 ExpectCtx.rflags.u32 |= X86_EFL_RF;
1011 if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
1012 0 /*idTestStep*/))
1013 {
1014 ASMHalt();
1015 }
1016
1017 /* Write, read and verify series of base addresses. */
1018 if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
1019 {
1020 Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
1021 ASMHalt();
1022 }
1023
1024 /* Restore original base address. */
1025 ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
1026
1027 /* Clean used GPRs. */
1028 Ctx.rbx.u = 0;
1029 Ctx.rcx.u = 0;
1030 }
1031 else
1032 {
1033 /* Unsupported by CPUID -> #UD. */
1034 Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
1035 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
1036 }
1037 }
1038}
1039
1040
1041static void bs3CpuInstr2_wrfsbase_wrgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
1042 unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
1043{
1044 BS3REGCTX Ctx;
1045 BS3REGCTX ExpectCtx;
1046 BS3TRAPFRAME TrapFrame;
1047 unsigned iWorker;
1048 unsigned iIter;
1049 uint32_t uDummy;
1050 uint32_t uStdExtFeatEbx;
1051 bool fSupportsFsGsBase;
1052
1053 ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
1054 fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
1055
1056 /* Ensure the structures are allocated before we sample the stack pointer. */
1057 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1058 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
1059 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1060
1061 /*
1062 * Create test context.
1063 */
1064 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1065
1066 for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
1067 {
1068 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
1069 if (fSupportsFsGsBase)
1070 {
1071 uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
1072
1073 /* CR4.FSGSBASE disabled -> #UD. */
1074 Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
1075 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
1076
1077 /* Write a base address. */
1078 Ctx.rbx.u = 0xa0000;
1079 Ctx.cr4.u |= X86_CR4_FSGSBASE;
1080 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
1081 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1082 ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
1083 ExpectCtx.rflags.u32 |= X86_EFL_RF;
1084 if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
1085 0 /*idTestStep*/))
1086 {
1087 ASMHalt();
1088 }
1089
1090 /* Write and read back series of base addresses. */
1091 if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
1092 {
1093 Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
1094 ASMHalt();
1095 }
1096
1097 /* Restore original base address. */
1098 ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
1099
1100 /* Clean used GPRs. */
1101 Ctx.rbx.u = 0;
1102 Ctx.rcx.u = 0;
1103 }
1104 else
1105 {
1106 /* Unsupported by CPUID -> #UD. */
1107 Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
1108 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
1109 }
1110 }
1111}
1112
1113
1114BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrfsbase)(uint8_t bMode)
1115{
1116 bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrFsBaseWorkers, RT_ELEMENTS(s_aWrFsBaseWorkers), MSR_K8_FS_BASE);
1117 return 0;
1118}
1119
1120
1121BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrgsbase)(uint8_t bMode)
1122{
1123 bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrGsBaseWorkers, RT_ELEMENTS(s_aWrGsBaseWorkers), MSR_K8_GS_BASE);
1124 return 0;
1125}
1126
1127
1128BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdfsbase)(uint8_t bMode)
1129{
1130 bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdFsBaseWorkers, RT_ELEMENTS(s_aRdFsBaseWorkers), MSR_K8_FS_BASE);
1131 return 0;
1132}
1133
1134
1135BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdgsbase)(uint8_t bMode)
1136{
1137 bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdGsBaseWorkers, RT_ELEMENTS(s_aRdGsBaseWorkers), MSR_K8_GS_BASE);
1138 return 0;
1139}
1140
1141# endif /* ARCH_BITS == 64 */
1142
1143#endif /* BS3_INSTANTIATING_CMN */
1144
1145
1146
1147/*
1148 * Mode specific code.
1149 * Mode specific code.
1150 * Mode specific code.
1151 */
1152#ifdef BS3_INSTANTIATING_MODE
1153
1154
1155#endif /* BS3_INSTANTIATING_MODE */
1156
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