VirtualBox

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

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

scm --update-copyright-year

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