VirtualBox

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

Last change on this file since 105686 was 104066, checked in by vboxsync, 8 months ago

ValKit/bootsectors: Added a g_cBs3ThresholdNativeRecompiler variable that can be used instead of BS3_THRESHOLD_NATIVE_RECOMPILER, initializing it with the VMMDEV_TESTING_CFG_THRESHOLD_NATIVE_RECOMPILER value from the host if available. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 245.6 KB
Line 
1/* $Id: bs3-cpu-instr-2-template.c 104066 2024-03-26 16:06:07Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-cpu-instr-2, C code template.
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#include <iprt/asm.h>
42#include <iprt/asm-amd64-x86.h>
43#include "bs3-cpu-instr-2.h"
44#include "bs3-cpu-instr-2-data.h"
45#include "bs3-cpu-instr-2-asm-auto.h"
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51#ifdef BS3_INSTANTIATING_CMN
52# if ARCH_BITS == 64
53typedef struct BS3CI2FSGSBASE
54{
55 const char *pszDesc;
56 bool f64BitOperand;
57 FPFNBS3FAR pfnWorker;
58 uint8_t offWorkerUd2;
59 FPFNBS3FAR pfnVerifyWorker;
60 uint8_t offVerifyWorkerUd2;
61} BS3CI2FSGSBASE;
62# endif
63#endif
64
65
66/*********************************************************************************************************************************
67* Global Variables *
68*********************************************************************************************************************************/
69#ifdef BS3_INSTANTIATING_CMN
70# if ARCH_BITS == 64
71static BS3CI2FSGSBASE const s_aWrFsBaseWorkers[] =
72{
73 { "wrfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 15 },
74 { "wrfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 13 },
75};
76
77static BS3CI2FSGSBASE const s_aWrGsBaseWorkers[] =
78{
79 { "wrgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 15 },
80 { "wrgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 13 },
81};
82
83static BS3CI2FSGSBASE const s_aRdFsBaseWorkers[] =
84{
85 { "rdfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 15 },
86 { "rdfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 13 },
87};
88
89static BS3CI2FSGSBASE const s_aRdGsBaseWorkers[] =
90{
91 { "rdgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 15 },
92 { "rdgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 13 },
93};
94# endif
95#endif /* BS3_INSTANTIATING_CMN - global */
96
97
98/*
99 * Common code.
100 * Common code.
101 * Common code.
102 */
103#ifdef BS3_INSTANTIATING_CMN
104
105/*
106 * Basic binary arithmetic tests.
107 */
108
109# if ARCH_BITS == 64 /* fDstMem cBitsImm */
110# define BS3CPUINSTR2CMNBINTEST_ENTRIES_8_64BIT(a_Ins) \
111 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _sil_dil), X86_GREG_xSI, X86_GREG_xDI, false, false, 0 }, \
112 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9b_r8b), X86_GREG_x9, X86_GREG_x8, false, false, 0 }, \
113 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _al_r13b), X86_GREG_xAX, X86_GREG_x13, false, false, 0 }, \
114 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx14_r11b), X86_GREG_x14, X86_GREG_x11, true, false, 0 },
115# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8_64BIT(a_Ins) \
116 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8b_Ib), X86_GREG_x8, X86_GREG_x15, false, false, 8 }, \
117 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r14b_Ib), X86_GREG_x14, X86_GREG_x15, false, false, 8 }, \
118 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx13_Ib), X86_GREG_x13, X86_GREG_x15, true, false, 8 },
119# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8_64BIT(a_Ins) \
120 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _dl_r14b), X86_GREG_xDX, X86_GREG_x14, false, false, 0 }, \
121 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _r8b_bl), X86_GREG_x8, X86_GREG_xBX, false, false, 0 }, \
122 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r11b_DSx12), X86_GREG_x11, X86_GREG_x12, false, true, 0 },
123# define BS3CPUINSTR2CMNBINTEST_ENTRIES_16_64BIT(a_Ins) \
124 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8w_cx), X86_GREG_x8, X86_GREG_xCX, false, false, 0 }, \
125 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r15w_r10w), X86_GREG_x15, X86_GREG_x10, false, false, 0 }, \
126 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx15_r12w), X86_GREG_x15, X86_GREG_x12, true, false, 0 },
127# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B_64BIT(a_Ins) \
128 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8w_Ib), X86_GREG_x8, X86_GREG_xBX, false, false, 8 }, \
129 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r12w_Ib), X86_GREG_x12, X86_GREG_xBX, false, false, 8 }, \
130 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSx14_Ib), X86_GREG_x14, X86_GREG_xBX, true, false, 8 },
131# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W_64BIT(a_Ins) \
132 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8w_Iw), X86_GREG_x8, X86_GREG_xBX, false, false, 16 }, \
133 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r13w_Iw), X86_GREG_x13, X86_GREG_xBX, false, false, 16 }, \
134 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx11_Iw), X86_GREG_x11, X86_GREG_xBX, true, false, 16 },
135# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16_64BIT(a_Ins) \
136 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _r13w_ax), X86_GREG_x13, X86_GREG_xAX, false, false, 0 }, \
137 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _si_r9w), X86_GREG_xSI, X86_GREG_x9, false, false, 0 }, \
138 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9w_DSx8), X86_GREG_x9, X86_GREG_x8, false, true, 0 },
139# define BS3CPUINSTR2CMNBINTEST_ENTRIES_32_64BIT(a_Ins) \
140 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _eax_r8d), X86_GREG_xAX, X86_GREG_x8, false, false, 0 }, \
141 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9d_ecx), X86_GREG_x9, X86_GREG_xCX, false, false, 0 }, \
142 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r13d_r14d), X86_GREG_x13, X86_GREG_x14, false, false, 0 }, \
143 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx10_r11d), X86_GREG_x10, X86_GREG_x11, true, false, 0 },
144# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B_64BIT(a_Ins) \
145 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8d_Ib), X86_GREG_x8, X86_GREG_xBX, false, false, 8 }, \
146 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r11d_Ib), X86_GREG_x11, X86_GREG_xBX, false, false, 8 }, \
147 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSx15_Ib), X86_GREG_x15, X86_GREG_xBX, true, false, 8 },
148# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW_64BIT(a_Ins) \
149 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8d_Id), X86_GREG_x8, X86_GREG_xBX, false, false, 32 }, \
150 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r14d_Id), X86_GREG_x14, X86_GREG_xBX, false, false, 32 }, \
151 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx12_Id), X86_GREG_x12, X86_GREG_xBX, true, false, 32 },
152# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32_64BIT(a_Ins) \
153 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _r15d_esi), X86_GREG_x15, X86_GREG_xSI, false, false, 0 }, \
154 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _eax_r10d), X86_GREG_xAX, X86_GREG_x10, false, false, 0 }, \
155 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r14d_DSx12), X86_GREG_x14, X86_GREG_x12, false, true, 0 },
156
157# define BS3CPUINSTR2CMNBINTEST_ENTRIES_64(a_Ins) \
158 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rax_rbx), X86_GREG_xAX, X86_GREG_xBX, false, false, 0 }, \
159 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8_rax), X86_GREG_x8, X86_GREG_xAX, false, false, 0 }, \
160 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rdx_r10), X86_GREG_xDX, X86_GREG_x10, false, false, 0 }, \
161 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxBX_rax), X86_GREG_xBX, X86_GREG_xAX, true, false, 0 }, \
162 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSx12_r8), X86_GREG_x12, X86_GREG_x8, true, false, 0 },
163# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(a_Ins) \
164 BS3CPUINSTR2CMNBINTEST_ENTRIES_64(a_Ins) \
165 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _r15_rsi), X86_GREG_x15, X86_GREG_xSI, false, false, 0 }, \
166 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _rbx_r14), X86_GREG_xBX, X86_GREG_x14, false, false, 0 }, \
167 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rax_DSxBX), X86_GREG_xAX, X86_GREG_xBX, false, true, 0 }, \
168 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8_DSx12), X86_GREG_x8, X86_GREG_x12, false, true, 0 },
169
170# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(a_Ins) \
171 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rax_Ib), X86_GREG_xAX, X86_GREG_x15, false, false, 8 }, \
172 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rbp_Ib), X86_GREG_xBP, X86_GREG_x15, false, false, 8 }, \
173 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8_Ib), X86_GREG_x8, X86_GREG_x15, false, false, 8 }, \
174 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r11_Ib), X86_GREG_x11, X86_GREG_x15, false, false, 8 }, \
175 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSxSI_Ib), X86_GREG_xSI, X86_GREG_x15, true, false, 8 }, \
176 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSx8_Ib), X86_GREG_x8, X86_GREG_x15, true, false, 8 },
177
178# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(a_Ins) \
179 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rax_Id), X86_GREG_xAX, X86_GREG_x15, false, false, 32 }, \
180 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8_Id), X86_GREG_x8, X86_GREG_x15, false, false, 32 }, \
181 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rbx_Id), X86_GREG_xBX, X86_GREG_x15, false, false, 32 }, \
182 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r14_Id), X86_GREG_x14, X86_GREG_x15, false, false, 32 }, \
183 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSx12_Id), X86_GREG_x12, X86_GREG_x15, true, false, 32 },
184
185# else
186# define BS3CPUINSTR2CMNBINTEST_ENTRIES_8_64BIT(aIns)
187# define BS3CPUINSTR2CMNBINTEST_ENTRIES_16_64BIT(aIns)
188# define BS3CPUINSTR2CMNBINTEST_ENTRIES_32_64BIT(aIns)
189# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8_64BIT(aIns)
190# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B_64BIT(aIns)
191# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W_64BIT(aIns)
192# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B_64BIT(aIns)
193# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW_64BIT(aIns)
194# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8_64BIT(aIns)
195# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16_64BIT(aIns)
196# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32_64BIT(aIns)
197# endif
198
199# define BS3CPUINSTR2CMNBINTEST_ENTRIES_8(a_Ins) \
200 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _al_dl), X86_GREG_xAX, X86_GREG_xDX, false, false, 0 }, \
201 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ch_bh), X86_GREG_xCX+16, X86_GREG_xBX+16, false, false, 0 }, \
202 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dl_ah), X86_GREG_xDX, X86_GREG_xAX+16, false, false, 0 }, \
203 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxBX_ah), X86_GREG_xBX, X86_GREG_xAX+16, true, false, 0 }, \
204 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxDI_bl), X86_GREG_xDI, X86_GREG_xBX, true, false, 0 }, \
205 BS3CPUINSTR2CMNBINTEST_ENTRIES_8_64BIT(a_Ins)
206# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(a_Ins) \
207 BS3CPUINSTR2CMNBINTEST_ENTRIES_8(a_Ins) \
208 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _dh_cl), X86_GREG_xDX+16, X86_GREG_xCX, false, false, 0 }, \
209 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dl_DSxBX), X86_GREG_xDX, X86_GREG_xBX, false, true, 0 }, \
210 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ch_DSxBX), X86_GREG_xCX+16, X86_GREG_xBX, false, true, 0 }, \
211 BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8_64BIT(a_Ins)
212
213# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(a_Ins) \
214 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _al_Ib), X86_GREG_xAX, X86_GREG_x15, false, false, 8 }, \
215 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _cl_Ib), X86_GREG_xCX, X86_GREG_x15, false, false, 8 }, \
216 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dh_Ib), X86_GREG_xDX+16, X86_GREG_x15, false, false, 8 }, \
217 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxDI_Ib), X86_GREG_xDI, X86_GREG_x15, true, false, 8 }, \
218 BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8_64BIT(a_Ins)
219
220# define BS3CPUINSTR2CMNBINTEST_ENTRIES_16(a_Ins) \
221 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _di_si), X86_GREG_xDI, X86_GREG_xSI, false, false, 0 }, \
222 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _cx_bp), X86_GREG_xCX, X86_GREG_xBP, false, false, 0 }, \
223 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxDI_si), X86_GREG_xDI, X86_GREG_xSI, true, false, 0 }, \
224 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxBX_ax), X86_GREG_xBX, X86_GREG_xAX, true, false, 0 }, \
225 BS3CPUINSTR2CMNBINTEST_ENTRIES_16_64BIT(a_Ins)
226# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(a_Ins) \
227 BS3CPUINSTR2CMNBINTEST_ENTRIES_16(a_Ins) \
228 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _bp_bx), X86_GREG_xBP, X86_GREG_xBX, false, false, 0 }, \
229 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _si_DSxDI), X86_GREG_xSI, X86_GREG_xDI, false, true, 0 }, \
230 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ax_DSxBX), X86_GREG_xAX, X86_GREG_xBX, false, true, 0 }, \
231 BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16_64BIT(a_Ins)
232
233# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(a_Ins) \
234 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ax_Ib), X86_GREG_xAX, X86_GREG_x15, false, false, 8 }, \
235 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _si_Ib), X86_GREG_xSI, X86_GREG_x15, false, false, 8 }, \
236 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSxDI_Ib), X86_GREG_xDI, X86_GREG_x15, true, false, 8 }, \
237 BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B_64BIT(a_Ins)
238
239# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(a_Ins) \
240 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ax_Iw), X86_GREG_xAX, X86_GREG_x15, false, false, 16 }, \
241 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bx_Iw), X86_GREG_xBX, X86_GREG_x15, false, false, 16 }, \
242 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxBX_Iw), X86_GREG_xBX, X86_GREG_x15, true, false, 16 }, \
243 BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W_64BIT(a_Ins)
244
245
246# define BS3CPUINSTR2CMNBINTEST_ENTRIES_32(a_Ins) \
247 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _eax_ebx), X86_GREG_xAX, X86_GREG_xBX, false, false, 0 }, \
248 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ecx_ebp), X86_GREG_xCX, X86_GREG_xBP, false, false, 0 }, \
249 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _edx_edi), X86_GREG_xDX, X86_GREG_xDI, false, false, 0 }, \
250 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxDI_esi), X86_GREG_xDI, X86_GREG_xSI, true, false, 0 }, \
251 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxBX_eax), X86_GREG_xBX, X86_GREG_xAX, true, false, 0 }, \
252 BS3CPUINSTR2CMNBINTEST_ENTRIES_32_64BIT(a_Ins)
253# define BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(a_Ins) \
254 BS3CPUINSTR2CMNBINTEST_ENTRIES_32(a_Ins) \
255 { BS3_CMN_NM(bs3CpuInstr2_alt_ ## a_Ins ## _edi_esi), X86_GREG_xDI, X86_GREG_xSI, false, false, 0 }, \
256 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _eax_DSxBX), X86_GREG_xAX, X86_GREG_xBX, false, true, 0 }, \
257 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ebp_DSxDI), X86_GREG_xBP, X86_GREG_xDI, false, true, 0 }, \
258 BS3CPUINSTR2CMNBINTEST_ENTRIES_32_64BIT(a_Ins)
259
260# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(a_Ins) \
261 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _eax_Ib), X86_GREG_xAX, X86_GREG_x15, false, false, 8 }, \
262 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ecx_Ib), X86_GREG_xCX, X86_GREG_x15, false, false, 8 }, \
263 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSxDI_Ib), X86_GREG_xDI, X86_GREG_x15, true, false, 8 }, \
264 BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B_64BIT(a_Ins)
265
266# define BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(a_Ins) \
267 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _eax_Id), X86_GREG_xAX, X86_GREG_x15, false, false, 32 }, \
268 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ebp_Id), X86_GREG_xBP, X86_GREG_x15, false, false, 32 }, \
269 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _DSxSI_Id), X86_GREG_xSI, X86_GREG_x15, true, false, 32 }, \
270 BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW_64BIT(a_Ins)
271
272
273typedef struct BS3CPUINSTR2CMNBINTEST
274{
275 FPFNBS3FAR pfnWorker;
276 uint8_t idxDstReg;
277 uint8_t idxSrcReg;
278 bool fDstMem : 1;
279 bool fSrcMem : 1;
280 uint8_t cBitsImm;
281} BS3CPUINSTR2CMNBINTEST;
282typedef BS3CPUINSTR2CMNBINTEST const BS3_FAR_DATA *PCBS3CPUINSTR2CMNBINTEST;
283
284
285static uint16_t const g_auEflStatusBitsVars[] =
286{
287 0,
288 X86_EFL_STATUS_BITS,
289 X86_EFL_CF,
290 X86_EFL_PF,
291 X86_EFL_AF,
292 X86_EFL_ZF,
293 X86_EFL_SF,
294 X86_EFL_OF,
295 X86_EFL_PF | X86_EFL_AF,
296};
297
298
299DECLINLINE(void RT_FAR *) Code2RwPtr(void RT_FAR *pfn)
300{
301#if ARCH_BITS == 16
302 if (!BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode))
303 pfn = BS3_FP_MAKE(BS3_SEL_TILED + 8, BS3_FP_OFF(pfn)); /* ASSUMES CS */
304#endif
305 return pfn;
306}
307
308#define BS3CPUINSTR2_COMMON_BINARY_U(a_cBits, a_UIntType, a_UIntImmType, a_szFmt) \
309static uint8_t \
310RT_CONCAT(bs3CpuInstr2_CommonBinaryU,a_cBits)(uint8_t bMode, PCBS3CPUINSTR2CMNBINTEST paTests, unsigned cTests, uint16_t fPassthruEfl, \
311 RT_CONCAT(PCBS3CPUINSTR2BIN,a_cBits) paTestData, unsigned cTestData, bool fCarryIn, \
312 bool fMaskSrcWhenMemDst, bool fReadOnly) \
313{ \
314 BS3REGCTX Ctx; \
315 BS3REGCTX CtxExpect; \
316 BS3TRAPFRAME TrapFrame; \
317 unsigned iTest; \
318 struct \
319 { \
320 char achPreGuard[8]; \
321 a_UIntType uData; \
322 char achPostGuard[8]; \
323 } Buf = { { '0','1','2','3','4','5','6','7' }, 0, { '8','9','a','b','c','d','e','f'} }; \
324 a_UIntType uMemExpect = 0; \
325 a_UIntType uMemDummy = 0; \
326 \
327 /* Ensure the structures are allocated before we sample the stack pointer. */ \
328 Bs3MemSet(&Ctx, 0, sizeof(Ctx)); \
329 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); \
330 \
331 /* \
332 * Create test context. \
333 */ \
334 Bs3RegCtxSaveEx(&Ctx, bMode, 640); \
335 Ctx.rflags.u32 &= ~X86_EFL_RF; \
336 if (ARCH_BITS == 64) \
337 for (iTest = 0; iTest < 16; iTest++) \
338 if (iTest != X86_GREG_xSP) \
339 (&Ctx.rax)[iTest].au32[1] = UINT32_C(0x8572ade) << (iTest & 7); \
340 Bs3MemCpy(&CtxExpect, &Ctx, sizeof(CtxExpect)); \
341 if (!BS3_MODE_IS_16BIT_SYS(bMode)) \
342 CtxExpect.rflags.u32 |= X86_EFL_RF; \
343 \
344 /* \
345 * Each test worker. \
346 */ \
347 for (iTest = 0; iTest < cTests; iTest++) \
348 { \
349 uint8_t const cbInstr = ((uint8_t BS3_FAR *)paTests[iTest].pfnWorker)[-1]; /* the function is prefixed by the length */ \
350 uint8_t RT_FAR * const pbImm = (uint8_t BS3_FAR *)Code2RwPtr(&((uint8_t BS3_FAR *)paTests[iTest].pfnWorker)[cbInstr - 1]); \
351 a_UIntImmType RT_FAR * const puImm = (a_UIntImmType RT_FAR *)Code2RwPtr(&((uint8_t BS3_FAR *)paTests[iTest].pfnWorker)[cbInstr - sizeof(a_UIntImmType)]); \
352 unsigned const idxDstReg = paTests[iTest].idxDstReg; \
353 unsigned const idxSrcReg = paTests[iTest].idxSrcReg; \
354 uint16_t const SavedDs = Ctx.ds; \
355 BS3REG const SavedDst = (&Ctx.rax)[idxDstReg & 15]; /* saves memptr too */ \
356 BS3REG const SavedSrc = (&Ctx.rax)[idxSrcReg & 15]; /* ditto */ \
357 a_UIntType RT_FAR * const puCtxDst = paTests[iTest].fDstMem ? &Buf.uData \
358 : &(&Ctx.rax)[idxDstReg & 15].RT_CONCAT(au,a_cBits)[idxDstReg >> 4]; \
359 a_UIntType RT_FAR * const puCtxSrc = paTests[iTest].fSrcMem ? &Buf.uData \
360 : paTests[iTest].cBitsImm == 0 \
361 ? &(&Ctx.rax)[idxSrcReg & 15].RT_CONCAT(au,a_cBits)[idxSrcReg >> 4] \
362 : &uMemDummy; \
363 a_UIntType RT_FAR * const puCtxExpectDst = paTests[iTest].fDstMem ? &uMemExpect \
364 : &(&CtxExpect.rax)[idxDstReg & 15].RT_CONCAT(au,a_cBits)[idxDstReg >> 4]; \
365 a_UIntType RT_FAR * const puCtxExpectSrc = paTests[iTest].fSrcMem ? &uMemExpect \
366 : paTests[iTest].cBitsImm == 0 \
367 ? &(&CtxExpect.rax)[idxSrcReg & 15].RT_CONCAT(au,a_cBits)[idxSrcReg >> 4] \
368 : &uMemDummy; \
369 uint64_t RT_FAR * const puMemPtrReg = paTests[iTest].fDstMem ? &(&Ctx.rax)[idxDstReg & 15].u \
370 : paTests[iTest].fSrcMem ? &(&Ctx.rax)[idxSrcReg & 15].u : NULL; \
371 uint64_t RT_FAR * const puMemPtrRegExpt= paTests[iTest].fDstMem ? &(&CtxExpect.rax)[idxDstReg & 15].u \
372 : paTests[iTest].fSrcMem ? &(&CtxExpect.rax)[idxSrcReg & 15].u : NULL; \
373 unsigned iTestData; \
374 /*Bs3TestPrintf("pfnWorker=%p\n", paTests[iTest].pfnWorker);*/ \
375 \
376 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, paTests[iTest].pfnWorker); \
377 CtxExpect.rip.u = Ctx.rip.u + cbInstr; \
378 CtxExpect.cs = Ctx.cs; \
379 \
380 if (puMemPtrReg) \
381 CtxExpect.ds = Ctx.ds = Ctx.ss; \
382 \
383 /* \
384 * Loop over the test data and feed it to the worker. \
385 */\
386 for (iTestData = 0; iTestData < cTestData; iTestData++) \
387 { \
388 unsigned iRecompiler; \
389 a_UIntType const uSrc = !fMaskSrcWhenMemDst | !paTests[iTest].fDstMem \
390 ? paTestData[iTestData].uSrc2 : paTestData[iTestData].uSrc2 & (a_cBits - 1); \
391 if (!paTests[iTest].cBitsImm) \
392 { \
393 *puCtxSrc = uSrc; \
394 *puCtxExpectSrc = uSrc; \
395 } \
396 else if (paTests[iTest].cBitsImm == 8) \
397 { \
398 if ((int8_t)uSrc == (int##a_cBits##_t)uSrc) \
399 *pbImm = (uint8_t)uSrc; \
400 else continue; \
401 } \
402 else if (sizeof(*puImm) == sizeof(*puCtxSrc) || (int32_t)uSrc == (int64_t)uSrc) \
403 *puImm = (a_UIntImmType)uSrc; \
404 else continue; \
405 \
406 *puCtxDst = paTestData[iTestData].uSrc1; \
407 *puCtxExpectDst = paTestData[iTestData].uResult; \
408 if (a_cBits == 32 && !fReadOnly && !paTests[iTest].fDstMem) \
409 puCtxExpectDst[1] = 0; \
410 \
411 if (puMemPtrReg) \
412 { \
413 *puMemPtrReg = BS3_FP_OFF(&Buf.uData); \
414 *puMemPtrRegExpt = BS3_FP_OFF(&Buf.uData); \
415 } \
416 \
417 CtxExpect.rflags.u16 &= ~X86_EFL_STATUS_BITS; \
418 CtxExpect.rflags.u16 |= paTestData[iTestData].fEflOut & X86_EFL_STATUS_BITS; \
419 \
420 /* \
421 * Do input the eight EFLAGS variations three times, so we're sure to trigger \
422 * native recompilation of the test worker code. \
423 */ \
424 for (iRecompiler = 0; iRecompiler < 2; iRecompiler++) \
425 { \
426 unsigned iEflVar = 0; \
427 for (iEflVar = 0; iEflVar < RT_ELEMENTS(g_auEflStatusBitsVars); iEflVar++) \
428 { \
429 if (paTests[iTest].fDstMem) \
430 *puCtxDst = paTestData[iTestData].uSrc1; \
431 \
432 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS; \
433 if (!fCarryIn) \
434 Ctx.rflags.u16 |= g_auEflStatusBitsVars[iEflVar]; \
435 else \
436 Ctx.rflags.u16 |= (g_auEflStatusBitsVars[iEflVar] & ~X86_EFL_CF) \
437 | (paTestData[iTestData].fEflOut >> BS3CPUINSTR2BIN_EFL_CARRY_IN_BIT) & X86_EFL_CF; \
438 if (fPassthruEfl) \
439 CtxExpect.rflags.u16 = (CtxExpect.rflags.u16 & ~fPassthruEfl) | (Ctx.rflags.u16 & fPassthruEfl); \
440 \
441 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); \
442 if (TrapFrame.bXcpt != X86_XCPT_UD) \
443 { \
444 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt); \
445 Bs3TrapPrintFrame(&TrapFrame); \
446 } \
447 else if (Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &CtxExpect, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, \
448 0 /*fExtraEfl*/, "mode", (iTest << 8) | (iTestData & 0xff))) \
449 { \
450 if (!puMemPtrReg) \
451 continue; \
452 if (paTests[iTest].fDstMem && Buf.uData != uMemExpect) \
453 Bs3TestPrintf("Wrong memory result: %" a_szFmt ", expected %" a_szFmt "\n", Buf.uData, uMemExpect); \
454 else if (!paTests[iTest].fDstMem && Buf.uData != uSrc) \
455 Bs3TestPrintf("Memory input result modified: %" a_szFmt ", expected %" a_szFmt "\n", Buf.uData, uSrc); \
456 else \
457 continue; \
458 } \
459 /*else { Bs3RegCtxPrint(&Ctx); Bs3TrapPrintFrame(&TrapFrame); }*/ \
460 Bs3TestPrintf(#a_cBits ": iTest=%u iData=%u: uSrc1=%" a_szFmt "%s uSrc2=%" a_szFmt "%s %s-> %" a_szFmt "\n", \
461 iTest, iTestData, paTestData[iTestData].uSrc1, paTests[iTest].fDstMem ? " mem" : "", \
462 paTestData[iTestData].uSrc2, paTests[iTest].fSrcMem ? " mem" : "", \
463 !fCarryIn ? "" : Ctx.rflags.u16 & X86_EFL_CF ? "CF " : "NC ", \
464 paTestData[iTestData].uResult); \
465 Bs3RegCtxPrint(&Ctx); Bs3TrapPrintFrame(&TrapFrame); \
466 ASMHalt(); \
467 iRecompiler = ~0U - 1; \
468 break; \
469 } \
470 } \
471 } \
472 \
473 /* Restore modified context registers (except EFLAGS). */ \
474 CtxExpect.ds = Ctx.ds = SavedDs; \
475 (&CtxExpect.rax)[idxDstReg & 15].u = (&Ctx.rax)[idxDstReg & 15].u = SavedDst.u; \
476 (&CtxExpect.rax)[idxSrcReg & 15].u = (&Ctx.rax)[idxSrcReg & 15].u = SavedSrc.u; \
477 } \
478 \
479 return 0; \
480}
481
482BS3CPUINSTR2_COMMON_BINARY_U(8, uint8_t, uint8_t, "RX8")
483BS3CPUINSTR2_COMMON_BINARY_U(16, uint16_t, uint16_t, "RX16")
484BS3CPUINSTR2_COMMON_BINARY_U(32, uint32_t, uint32_t, "RX32")
485#if ARCH_BITS == 64
486BS3CPUINSTR2_COMMON_BINARY_U(64, uint64_t, uint32_t, "RX64")
487#endif
488
489
490BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_and)(uint8_t bMode)
491{
492 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(and) };
493 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(and) };
494 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(and) };
495#if ARCH_BITS == 64
496 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(and) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(and) };
497#endif
498 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
499 g_aBs3CpuInstr2_and_TestDataU8, g_cBs3CpuInstr2_and_TestDataU8,
500 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
501 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
502 g_aBs3CpuInstr2_and_TestDataU16, g_cBs3CpuInstr2_and_TestDataU16,
503 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
504 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
505 g_aBs3CpuInstr2_and_TestDataU32, g_cBs3CpuInstr2_and_TestDataU32,
506 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
507#if ARCH_BITS == 64
508 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
509 g_aBs3CpuInstr2_and_TestDataU64, g_cBs3CpuInstr2_and_TestDataU64,
510 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
511#endif
512 return 0;
513}
514
515
516BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_or)(uint8_t bMode)
517{
518 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(or) };
519 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(or) };
520 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(or) };
521#if ARCH_BITS == 64
522 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(or) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(or) };
523#endif
524 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
525 g_aBs3CpuInstr2_or_TestDataU8, g_cBs3CpuInstr2_or_TestDataU8,
526 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
527 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
528 g_aBs3CpuInstr2_or_TestDataU16, g_cBs3CpuInstr2_or_TestDataU16,
529 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
530 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
531 g_aBs3CpuInstr2_or_TestDataU32, g_cBs3CpuInstr2_or_TestDataU32,
532 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
533#if ARCH_BITS == 64
534 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
535 g_aBs3CpuInstr2_or_TestDataU64, g_cBs3CpuInstr2_or_TestDataU64,
536 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
537#endif
538 return 0;
539}
540
541
542BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_xor)(uint8_t bMode)
543{
544 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(xor) };
545 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(xor) };
546 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(xor) };
547#if ARCH_BITS == 64
548 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(xor) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(xor) };
549#endif
550 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
551 g_aBs3CpuInstr2_xor_TestDataU8, g_cBs3CpuInstr2_xor_TestDataU8,
552 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
553 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
554 g_aBs3CpuInstr2_xor_TestDataU16, g_cBs3CpuInstr2_xor_TestDataU16,
555 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
556 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
557 g_aBs3CpuInstr2_xor_TestDataU32, g_cBs3CpuInstr2_xor_TestDataU32,
558 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
559#if ARCH_BITS == 64
560 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
561 g_aBs3CpuInstr2_xor_TestDataU64, g_cBs3CpuInstr2_xor_TestDataU64,
562 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
563#endif
564 return 0;
565}
566
567
568BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_test)(uint8_t bMode)
569{
570 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_8(test) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(test) };
571 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_16(test) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(test) };
572 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_32(test) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(test) };
573#if ARCH_BITS == 64
574 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_64(test) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(test) };
575#endif
576 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
577 g_aBs3CpuInstr2_test_TestDataU8, g_cBs3CpuInstr2_test_TestDataU8,
578 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
579 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
580 g_aBs3CpuInstr2_test_TestDataU16, g_cBs3CpuInstr2_test_TestDataU16,
581 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
582 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
583 g_aBs3CpuInstr2_test_TestDataU32, g_cBs3CpuInstr2_test_TestDataU32,
584 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
585#if ARCH_BITS == 64
586 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
587 g_aBs3CpuInstr2_test_TestDataU64, g_cBs3CpuInstr2_test_TestDataU64,
588 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
589#endif
590 return 0;
591}
592
593
594BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_add)(uint8_t bMode)
595{
596 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(add) };
597 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(add) };
598 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(add) };
599#if ARCH_BITS == 64
600 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(add) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(add) };
601#endif
602 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
603 g_aBs3CpuInstr2_add_TestDataU8, g_cBs3CpuInstr2_add_TestDataU8,
604 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
605 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
606 g_aBs3CpuInstr2_add_TestDataU16, g_cBs3CpuInstr2_add_TestDataU16,
607 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
608 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
609 g_aBs3CpuInstr2_add_TestDataU32, g_cBs3CpuInstr2_add_TestDataU32,
610 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
611#if ARCH_BITS == 64
612 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
613 g_aBs3CpuInstr2_add_TestDataU64, g_cBs3CpuInstr2_add_TestDataU64,
614 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
615#endif
616 return 0;
617}
618
619
620BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_adc)(uint8_t bMode)
621{
622 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(adc) };
623 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(adc) };
624 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(adc) };
625#if ARCH_BITS == 64
626 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(adc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(adc) };
627#endif
628 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
629 g_aBs3CpuInstr2_adc_TestDataU8, g_cBs3CpuInstr2_adc_TestDataU8,
630 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
631 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
632 g_aBs3CpuInstr2_adc_TestDataU16, g_cBs3CpuInstr2_adc_TestDataU16,
633 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
634 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
635 g_aBs3CpuInstr2_adc_TestDataU32, g_cBs3CpuInstr2_adc_TestDataU32,
636 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
637#if ARCH_BITS == 64
638 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
639 g_aBs3CpuInstr2_adc_TestDataU64, g_cBs3CpuInstr2_adc_TestDataU64,
640 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
641#endif
642 return 0;
643}
644
645
646BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_sub)(uint8_t bMode)
647{
648 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(sub) };
649 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(sub) };
650 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(sub) };
651#if ARCH_BITS == 64
652 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(sub) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(sub) };
653#endif
654 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
655 g_aBs3CpuInstr2_sub_TestDataU8, g_cBs3CpuInstr2_sub_TestDataU8,
656 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
657 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
658 g_aBs3CpuInstr2_sub_TestDataU16, g_cBs3CpuInstr2_sub_TestDataU16,
659 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
660 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
661 g_aBs3CpuInstr2_sub_TestDataU32, g_cBs3CpuInstr2_sub_TestDataU32,
662 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
663#if ARCH_BITS == 64
664 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
665 g_aBs3CpuInstr2_sub_TestDataU64, g_cBs3CpuInstr2_sub_TestDataU64,
666 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
667#endif
668 return 0;
669}
670
671
672BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_sbb)(uint8_t bMode)
673{
674 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(sbb) };
675 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(sbb) };
676 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(sbb) };
677#if ARCH_BITS == 64
678 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(sbb) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(sbb) };
679#endif
680 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
681 g_aBs3CpuInstr2_sbb_TestDataU8, g_cBs3CpuInstr2_sbb_TestDataU8,
682 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
683 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
684 g_aBs3CpuInstr2_sbb_TestDataU16, g_cBs3CpuInstr2_sbb_TestDataU16,
685 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
686 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
687 g_aBs3CpuInstr2_sbb_TestDataU32, g_cBs3CpuInstr2_sbb_TestDataU32,
688 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
689#if ARCH_BITS == 64
690 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
691 g_aBs3CpuInstr2_sbb_TestDataU64, g_cBs3CpuInstr2_sbb_TestDataU64,
692 true /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
693#endif
694 return 0;
695}
696
697
698BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmp)(uint8_t bMode)
699{
700 static const BS3CPUINSTR2CMNBINTEST s_aTests8[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_8(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_8(cmp) };
701 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_16(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16W(cmp) };
702 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_32(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32DW(cmp) };
703#if ARCH_BITS == 64
704 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_ALT_64(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(cmp) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64DW(cmp) };
705#endif
706 bs3CpuInstr2_CommonBinaryU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), 0 /*fPassthruEfl*/,
707 g_aBs3CpuInstr2_cmp_TestDataU8, g_cBs3CpuInstr2_cmp_TestDataU8,
708 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
709 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), 0 /*fPassthruEfl*/,
710 g_aBs3CpuInstr2_cmp_TestDataU16, g_cBs3CpuInstr2_cmp_TestDataU16,
711 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
712 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), 0 /*fPassthruEfl*/,
713 g_aBs3CpuInstr2_cmp_TestDataU32, g_cBs3CpuInstr2_cmp_TestDataU32,
714 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
715#if ARCH_BITS == 64
716 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), 0 /*fPassthruEfl*/,
717 g_aBs3CpuInstr2_cmp_TestDataU64, g_cBs3CpuInstr2_cmp_TestDataU64,
718 false /*fCarryIn*/, false /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
719#endif
720 return 0;
721}
722
723
724#define BS3CPUINSTR2_BTx_PASSTHRU_EFL (X86_EFL_ZF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF)
725
726BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bt)(uint8_t bMode)
727{
728 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_16(bt) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(bt) };
729 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_32(bt) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(bt) };
730#if ARCH_BITS == 64
731 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_64(bt) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(bt) };
732#endif
733 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
734 g_aBs3CpuInstr2_bt_TestDataU16, g_cBs3CpuInstr2_bt_TestDataU16,
735 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
736 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
737 g_aBs3CpuInstr2_bt_TestDataU32, g_cBs3CpuInstr2_bt_TestDataU32,
738 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
739#if ARCH_BITS == 64
740 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
741 g_aBs3CpuInstr2_bt_TestDataU64, g_cBs3CpuInstr2_bt_TestDataU64,
742 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, true /*fReadOnly*/);
743#endif
744 return 0;
745}
746
747
748BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_btc)(uint8_t bMode)
749{
750 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_16(btc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(btc) };
751 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_32(btc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(btc) };
752#if ARCH_BITS == 64
753 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_64(btc) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(btc) };
754#endif
755 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
756 g_aBs3CpuInstr2_btc_TestDataU16, g_cBs3CpuInstr2_btc_TestDataU16,
757 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
758 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
759 g_aBs3CpuInstr2_btc_TestDataU32, g_cBs3CpuInstr2_btc_TestDataU32,
760 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
761#if ARCH_BITS == 64
762 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
763 g_aBs3CpuInstr2_btc_TestDataU64, g_cBs3CpuInstr2_btc_TestDataU64,
764 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
765#endif
766 return 0;
767}
768
769
770BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_btr)(uint8_t bMode)
771{
772 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_16(btr) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(btr) };
773 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_32(btr) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(btr) };
774#if ARCH_BITS == 64
775 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_64(btr) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(btr) };
776#endif
777 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
778 g_aBs3CpuInstr2_btr_TestDataU16, g_cBs3CpuInstr2_btr_TestDataU16,
779 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
780 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
781 g_aBs3CpuInstr2_btr_TestDataU32, g_cBs3CpuInstr2_btr_TestDataU32,
782 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
783#if ARCH_BITS == 64
784 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
785 g_aBs3CpuInstr2_btr_TestDataU64, g_cBs3CpuInstr2_btr_TestDataU64,
786 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
787#endif
788 return 0;
789}
790
791
792BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bts)(uint8_t bMode)
793{
794 static const BS3CPUINSTR2CMNBINTEST s_aTests16[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_16(bts) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_16B(bts) };
795 static const BS3CPUINSTR2CMNBINTEST s_aTests32[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_32(bts) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_32B(bts) };
796#if ARCH_BITS == 64
797 static const BS3CPUINSTR2CMNBINTEST s_aTests64[] = { BS3CPUINSTR2CMNBINTEST_ENTRIES_64(bts) BS3CPUINSTR2CMNBINTEST_ENTRIES_IMM_64B(bts) };
798#endif
799 bs3CpuInstr2_CommonBinaryU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
800 g_aBs3CpuInstr2_bts_TestDataU16, g_cBs3CpuInstr2_bts_TestDataU16,
801 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
802 bs3CpuInstr2_CommonBinaryU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
803 g_aBs3CpuInstr2_bts_TestDataU32, g_cBs3CpuInstr2_bts_TestDataU32,
804 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
805#if ARCH_BITS == 64
806 bs3CpuInstr2_CommonBinaryU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), BS3CPUINSTR2_BTx_PASSTHRU_EFL,
807 g_aBs3CpuInstr2_bts_TestDataU64, g_cBs3CpuInstr2_bts_TestDataU64,
808 false /*fCarryIn*/, true /*fMaskSrcWhenMemDst*/, false /*fReadOnly*/);
809#endif
810 return 0;
811}
812
813
814
815/*
816 * Basic shift & rotate tests.
817 */
818
819# if ARCH_BITS == 64 /* fDstMem cBitsImm */
820# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_8_64BIT(a_Ins) \
821 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _sil_1), X86_GREG_xSI, 1, false }, \
822 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9b_Ib), X86_GREG_x9, 8, false }, \
823 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r13b_cl), X86_GREG_x13, 0, false }, \
824 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bDSx14_1), X86_GREG_x14, 1, true }, \
825 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bDSxAX_Ib), X86_GREG_xAX, 8, true }, \
826 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bDSx9_cl), X86_GREG_x9, 0, true },
827
828# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_16_64BIT(a_Ins) \
829 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8w_1), X86_GREG_x8, 1, false }, \
830 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9w_Ib), X86_GREG_x9, 8, false }, \
831 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r13w_cl), X86_GREG_x13, 0, false }, \
832 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSx14_1), X86_GREG_x14, 1, true }, \
833 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSxBP_Ib), X86_GREG_xBP, 8, true }, \
834 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSx9_cl), X86_GREG_x9, 0, true },
835
836# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_32_64BIT(a_Ins) \
837 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8d_1), X86_GREG_x8, 1, false }, \
838 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9d_Ib), X86_GREG_x9, 8, false }, \
839 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r13d_cl), X86_GREG_x13, 0, false }, \
840 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSx14_1), X86_GREG_x14, 1, true }, \
841 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSxBP_Ib), X86_GREG_xBP, 8, true }, \
842 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSx9_cl), X86_GREG_x9, 0, true },
843
844# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_64(a_Ins) \
845 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rdi_1), X86_GREG_xDI, 1, false }, \
846 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rcx_Ib), X86_GREG_xCX, 8, false }, \
847 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _rbp_cl), X86_GREG_xBP, 0, false }, \
848 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSxSI_1), X86_GREG_xSI, 1, true }, \
849 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSxBX_Ib), X86_GREG_xBX, 8, true }, \
850 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSxDI_cl), X86_GREG_xDI, 0, true }, \
851 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r8_1), X86_GREG_x8, 1, false }, \
852 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r9_Ib), X86_GREG_x9, 8, false }, \
853 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _r13_cl), X86_GREG_x13, 0, false }, \
854 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSx14_1), X86_GREG_x14, 1, true }, \
855 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSxBP_Ib), X86_GREG_xBP, 8, true }, \
856 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _qwDSx9_cl), X86_GREG_x9, 0, true },
857
858# else
859# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_8_64BIT(aIns)
860# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_16_64BIT(aIns)
861# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_32_64BIT(aIns)
862# endif
863
864# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_8(a_Ins) \
865 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _al_1), X86_GREG_xAX, 1, false }, \
866 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dl_Ib), X86_GREG_xDX, 8, false }, \
867 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ch_cl), X86_GREG_xCX+16, 0, false }, \
868 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bDSxBX_1), X86_GREG_xBX, 1, true }, \
869 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bDSxDI_Ib), X86_GREG_xDI, 8, true }, \
870 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bDSxSI_cl), X86_GREG_xSI, 0, true }, \
871 BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_8_64BIT(a_Ins)
872
873# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_16(a_Ins) \
874 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _di_1), X86_GREG_xDI, 1, false }, \
875 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _cx_Ib), X86_GREG_xCX, 8, false }, \
876 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _bp_cl), X86_GREG_xBP, 0, false }, \
877 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSxSI_1), X86_GREG_xSI, 1, true }, \
878 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSxDI_Ib), X86_GREG_xDI, 8, true }, \
879 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _wDSxBX_cl), X86_GREG_xBX, 0, true }, \
880 BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_16_64BIT(a_Ins)
881
882# define BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_32(a_Ins) \
883 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _edi_1), X86_GREG_xDI, 1, false }, \
884 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ecx_Ib), X86_GREG_xCX, 8, false }, \
885 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _ebp_cl), X86_GREG_xBP, 0, false }, \
886 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSxSI_1), X86_GREG_xSI, 1, true }, \
887 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSxBX_Ib), X86_GREG_xBX, 8, true }, \
888 { BS3_CMN_NM(bs3CpuInstr2_ ## a_Ins ## _dwDSxDI_cl), X86_GREG_xDI, 0, true }, \
889 BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_32_64BIT(a_Ins)
890
891
892typedef struct BS3CPUINSTR2CMNSHIFTTEST
893{
894 FPFNBS3FAR pfnWorker;
895 uint8_t idxDstReg;
896 uint8_t cBitsImm; /**< 0 for CL; 1 for single shift w/o immediate; 8 for 8-bit immediate. */
897 bool fDstMem;
898} BS3CPUINSTR2CMNSHIFTTEST;
899typedef BS3CPUINSTR2CMNSHIFTTEST const BS3_FAR_DATA *PCBS3CPUINSTR2CMNSHIFTTEST;
900
901
902DECLINLINE(uint16_t) bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR enmDataVendor, uint16_t fUndefEfl)
903{
904 BS3CPUVENDOR enmVendor = Bs3GetCpuVendor();
905 return enmDataVendor == enmVendor
906 || (enmDataVendor == BS3CPUVENDOR_INTEL) == (enmVendor != BS3CPUVENDOR_AMD && enmVendor != BS3CPUVENDOR_HYGON)
907 ? 0 : fUndefEfl;
908}
909
910
911#define BS3CPUINSTR2_COMMON_SHIFT_U(a_cBits, a_UIntType, a_szFmt) \
912static uint8_t \
913RT_CONCAT(bs3CpuInstr2_CommonShiftU,a_cBits)(uint8_t bMode, PCBS3CPUINSTR2CMNSHIFTTEST paTests, unsigned cTests, \
914 RT_CONCAT(PCBS3CPUINSTR2SHIFT,a_cBits) paTestData, unsigned cTestData, \
915 uint16_t fUndefEfl, bool fIntelIbProblem) \
916{ \
917 BS3REGCTX Ctx; \
918 BS3REGCTX CtxExpect; \
919 BS3TRAPFRAME TrapFrame; \
920 unsigned iTest; \
921 struct \
922 { \
923 char achPreGuard[8]; \
924 a_UIntType uData; \
925 char achPostGuard[8]; \
926 } Buf = { { '0','1','2','3','4','5','6','7' }, 0, { '8','9','a','b','c','d','e','f'} }; \
927 a_UIntType uMemExpect = 0; \
928 uint8_t bMemDummy = 0; \
929 \
930 /* May have no test data for a CPU vendor*/ \
931 if (!cTestData) \
932 return 0; \
933 \
934 /* Ensure the structures are allocated before we sample the stack pointer. */ \
935 Bs3MemSet(&Ctx, 0, sizeof(Ctx)); \
936 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); \
937 \
938 /* \
939 * Create test context. \
940 */ \
941 Bs3RegCtxSaveEx(&Ctx, bMode, 640); \
942 Ctx.rflags.u32 &= ~X86_EFL_RF; \
943 if (ARCH_BITS == 64) \
944 for (iTest = 0; iTest < 16; iTest++) \
945 if (iTest != X86_GREG_xSP) \
946 (&Ctx.rax)[iTest].au32[1] = UINT32_C(0x8572ade) << (iTest & 7); \
947 Bs3MemCpy(&CtxExpect, &Ctx, sizeof(CtxExpect)); \
948 if (!BS3_MODE_IS_16BIT_SYS(bMode)) \
949 CtxExpect.rflags.u32 |= X86_EFL_RF; \
950 \
951 /* \
952 * Each test worker. \
953 */ \
954 for (iTest = 0; iTest < cTests; iTest++) \
955 { \
956 uint8_t const cbInstr = ((uint8_t BS3_FAR *)paTests[iTest].pfnWorker)[-1]; /* the function is prefixed by the length */ \
957 uint8_t RT_FAR * const pbImm = (uint8_t BS3_FAR *)Code2RwPtr(&((uint8_t BS3_FAR *)paTests[iTest].pfnWorker)[cbInstr - 1]); \
958 uint8_t const idxDstReg = paTests[iTest].idxDstReg; \
959 uint8_t const cBitsImm = paTests[iTest].cBitsImm; \
960 uint16_t const SavedDs = Ctx.ds; \
961 BS3REG const SavedDst = (&Ctx.rax)[idxDstReg & 15]; /* saves memptr too */ \
962 BS3REG const SavedRcx = Ctx.rcx; \
963 a_UIntType RT_FAR * const puCtxDst = paTests[iTest].fDstMem ? &Buf.uData \
964 : &(&Ctx.rax)[idxDstReg & 15].RT_CONCAT(au,a_cBits)[idxDstReg >> 4]; \
965 uint8_t RT_FAR * const puCtxSrc = cBitsImm == 0 ? &Ctx.rcx.au8[0] : &bMemDummy; \
966 a_UIntType RT_FAR * const puCtxExpectDst = paTests[iTest].fDstMem ? &uMemExpect \
967 : &(&CtxExpect.rax)[idxDstReg & 15].RT_CONCAT(au,a_cBits)[idxDstReg >> 4]; \
968 uint8_t RT_FAR * const puCtxExpectSrc = cBitsImm == 0 ? &CtxExpect.rcx.au8[0] : &bMemDummy; \
969 uint64_t RT_FAR * const puMemPtrReg = paTests[iTest].fDstMem ? &(&Ctx.rax)[idxDstReg & 15].u : NULL; \
970 uint64_t RT_FAR * const puMemPtrRegExpt= paTests[iTest].fDstMem ? &(&CtxExpect.rax)[idxDstReg & 15].u : NULL; \
971 unsigned cRecompOuter = 0; \
972 unsigned const cMaxRecompOuter= cBitsImm != 8 ? g_cBs3ThresholdNativeRecompiler + cTestData : 1; \
973 unsigned const cMaxRecompInner= cBitsImm != 8 ? 1 : g_cBs3ThresholdNativeRecompiler; \
974 /*Bs3TestPrintf("\n"#a_cBits ": pfnWorker=%p cBitsImm=%d (%d)\n", paTests[iTest].pfnWorker, cBitsImm, paTests[iTest].cBitsImm);*/ \
975 \
976 Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, paTests[iTest].pfnWorker); \
977 CtxExpect.rip.u = Ctx.rip.u + cbInstr; \
978 CtxExpect.cs = Ctx.cs; \
979 \
980 if (puMemPtrReg) \
981 CtxExpect.ds = Ctx.ds = Ctx.ss; \
982 \
983 /* \
984 * Iterate twice or more over the input data to ensure that the recompiler kicks in. \
985 * For instructions with an immediate byte, we do this in the inner loop below. \
986 */ \
987 while (cRecompOuter < cMaxRecompOuter) \
988 { \
989 /* \
990 * Loop over the test data and feed it to the worker. \
991 */\
992 unsigned iTestData; \
993 for (iTestData = 0; iTestData < cTestData; iTestData++) \
994 { \
995 unsigned cRecompInner; \
996 uint8_t const uSrc2 = paTestData[iTestData].uSrc2; \
997 if (cBitsImm == 0) \
998 { \
999 *puCtxSrc = uSrc2; \
1000 *puCtxExpectSrc = uSrc2; \
1001 } \
1002 else if (cBitsImm == 8) \
1003 *pbImm = uSrc2; \
1004 else if ((uSrc2 & RT_MAX(a_cBits - 1, 31)) != 1) \
1005 continue; \
1006 cRecompOuter++; \
1007 \
1008 *puCtxDst = paTestData[iTestData].uSrc1; \
1009 *puCtxExpectDst = paTestData[iTestData].uResult; \
1010 if (a_cBits == 32 && !paTests[iTest].fDstMem) \
1011 puCtxExpectDst[1] = 0; \
1012 \
1013 if (puMemPtrReg) \
1014 { \
1015 *puMemPtrReg = BS3_FP_OFF(&Buf.uData); \
1016 *puMemPtrRegExpt = BS3_FP_OFF(&Buf.uData); \
1017 } \
1018 \
1019 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS; \
1020 Ctx.rflags.u16 |= paTestData[iTestData].fEflIn & X86_EFL_STATUS_BITS; \
1021 CtxExpect.rflags.u16 &= ~X86_EFL_STATUS_BITS; \
1022 CtxExpect.rflags.u16 |= paTestData[iTestData].fEflOut & X86_EFL_STATUS_BITS; \
1023 /* Intel: 'ROL reg,imm8' and 'ROR reg,imm8' produces different OF values. \
1024 stored in bit 3 of the output. Observed on 8700B, 9980HK, 10980xe, \
1025 1260p, ++. */ \
1026 if (fIntelIbProblem && cBitsImm == 8 && !paTests[iTest].fDstMem) \
1027 { \
1028 CtxExpect.rflags.u16 &= ~X86_EFL_OF; \
1029 CtxExpect.rflags.u16 |= (paTestData[iTestData].fEflOut & RT_BIT_32(BS3CPUINSTR2SHIFT_EFL_IB_OVERFLOW_OUT_BIT)) \
1030 << (X86_EFL_OF_BIT - BS3CPUINSTR2SHIFT_EFL_IB_OVERFLOW_OUT_BIT); \
1031 } \
1032 \
1033 /* Inner recompiler trigger loop, for instructions with immediates that we modify. */ \
1034 cRecompInner = 0; \
1035 do \
1036 { \
1037 if (paTests[iTest].fDstMem) \
1038 *puCtxDst = paTestData[iTestData].uSrc1; \
1039 \
1040 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); \
1041 \
1042 if (fUndefEfl) /* When executing tests for the other CPU vendor. */ \
1043 CtxExpect.rflags.u16 = (CtxExpect.rflags.u16 & ~fUndefEfl) | (TrapFrame.Ctx.rflags.u16 & fUndefEfl); \
1044 \
1045 if (TrapFrame.bXcpt != X86_XCPT_UD) \
1046 { \
1047 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt); \
1048 Bs3TrapPrintFrame(&TrapFrame); \
1049 } \
1050 else if (Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &CtxExpect, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, \
1051 0 /*fExtraEfl*/, "mode", (iTest << 8) | (iTestData & 0xff))) \
1052 { \
1053 if (puMemPtrReg && paTests[iTest].fDstMem && Buf.uData != uMemExpect) \
1054 Bs3TestPrintf("Wrong memory result: %" a_szFmt ", expected %" a_szFmt "\n", Buf.uData, uMemExpect); \
1055 else \
1056 { \
1057 cRecompInner++; \
1058 continue; \
1059 } \
1060 } \
1061 /*else { Bs3RegCtxPrint(&Ctx); Bs3TrapPrintFrame(&TrapFrame); }*/ \
1062 Bs3TestPrintf(#a_cBits ": iTest=%u iData=%u inner=%u: uSrc1=%" a_szFmt "%s uSrc2=%RX8 (%s) fEfl=%RX16 -> %" a_szFmt " fEfl=%RX16\n", \
1063 iTest, iTestData, cRecompInner, \
1064 paTestData[iTestData].uSrc1, paTests[iTest].fDstMem ? " mem" : "", \
1065 paTestData[iTestData].uSrc2, cBitsImm == 0 ? "cl" : cBitsImm == 1 ? "1" : "Ib", \
1066 (uint16_t)(paTestData[iTestData].fEflIn & X86_EFL_STATUS_BITS), \
1067 paTestData[iTestData].uResult, paTestData[iTestData].fEflOut & X86_EFL_STATUS_BITS); \
1068 Bs3RegCtxPrint(&Ctx); Bs3TrapPrintFrame(&TrapFrame); \
1069 ASMHalt(); \
1070 } while (cRecompInner < cMaxRecompInner); \
1071 } \
1072 } \
1073 \
1074 /* Restore modified context registers (except EFLAGS). */ \
1075 CtxExpect.ds = Ctx.ds = SavedDs; \
1076 (&CtxExpect.rax)[idxDstReg & 15].u = (&Ctx.rax)[idxDstReg & 15].u = SavedDst.u; \
1077 CtxExpect.rcx.u = Ctx.rcx.u = SavedRcx.u; \
1078 } \
1079 \
1080 return 0; \
1081}
1082
1083BS3CPUINSTR2_COMMON_SHIFT_U(8, uint8_t, "RX8")
1084BS3CPUINSTR2_COMMON_SHIFT_U(16, uint16_t, "RX16")
1085BS3CPUINSTR2_COMMON_SHIFT_U(32, uint32_t, "RX32")
1086#if ARCH_BITS == 64
1087BS3CPUINSTR2_COMMON_SHIFT_U(64, uint64_t, "RX64")
1088#endif
1089
1090
1091#define BS3CPUINSTR2_SHIFT_INSTR_NOT_64(a_Ins, a_fEflUndef, a_fIntelIbProblem) \
1092 { \
1093 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests8[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_8(a_Ins) }; \
1094 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests16[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_16(a_Ins) }; \
1095 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests32[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_32(a_Ins) }; \
1096 uint16_t const fEflUndefIntel = bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_INTEL, a_fEflUndef); \
1097 uint16_t const fEflUndefAmd = bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_AMD, a_fEflUndef); \
1098 bs3CpuInstr2_CommonShiftU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), \
1099 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU8, \
1100 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU8, \
1101 fEflUndefIntel, a_fIntelIbProblem); \
1102 bs3CpuInstr2_CommonShiftU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), \
1103 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU8, \
1104 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU8, \
1105 fEflUndefAmd, false); \
1106 bs3CpuInstr2_CommonShiftU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), \
1107 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU16, \
1108 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU16, \
1109 fEflUndefIntel, a_fIntelIbProblem); \
1110 bs3CpuInstr2_CommonShiftU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), \
1111 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU16, \
1112 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU16, \
1113 fEflUndefAmd, false); \
1114 bs3CpuInstr2_CommonShiftU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), \
1115 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU32, \
1116 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU32, \
1117 fEflUndefIntel, a_fIntelIbProblem); \
1118 bs3CpuInstr2_CommonShiftU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), \
1119 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU32, \
1120 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU32, \
1121 fEflUndefAmd, false); \
1122 } (void)0
1123#if ARCH_BITS == 64
1124# define BS3CPUINSTR2_SHIFT_INSTR_ONLY64(a_Ins, a_fEflUndef, a_fIntelIbProblem) \
1125 { \
1126 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests64[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_64(a_Ins) }; \
1127 bs3CpuInstr2_CommonShiftU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), \
1128 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU64, \
1129 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU64, \
1130 bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_INTEL, a_fEflUndef), a_fIntelIbProblem); \
1131 bs3CpuInstr2_CommonShiftU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), \
1132 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU64, \
1133 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU64, \
1134 bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_AMD, a_fEflUndef), false); \
1135 } (void)0
1136#else
1137# define BS3CPUINSTR2_SHIFT_INSTR_ONLY64(a_Ins, a_fEflUndef, a_fIntelIbProblem) (void)0
1138#endif
1139
1140
1141BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shl)(uint8_t bMode)
1142{
1143 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(shl, X86_EFL_AF | X86_EFL_OF, false);
1144 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(shl, X86_EFL_AF | X86_EFL_OF, false);
1145 return 0;
1146}
1147
1148
1149BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shr)(uint8_t bMode)
1150{
1151 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(shr, X86_EFL_AF | X86_EFL_OF, false);
1152 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(shr, X86_EFL_AF | X86_EFL_OF, false);
1153 return 0;
1154}
1155
1156
1157BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_sar)(uint8_t bMode)
1158{
1159 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(sar, X86_EFL_AF | X86_EFL_OF, false);
1160 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(sar, X86_EFL_AF | X86_EFL_OF, false);
1161 return 0;
1162}
1163
1164
1165BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rol)(uint8_t bMode)
1166{
1167 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(rol, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1168 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(rol, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1169 return 0;
1170}
1171
1172
1173BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_ror)(uint8_t bMode)
1174{
1175 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(ror, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1176 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(ror, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1177 return 0;
1178}
1179
1180
1181BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rcl)(uint8_t bMode)
1182{
1183 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(rcl, X86_EFL_OF, false);
1184 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(rcl, X86_EFL_OF, false);
1185 return 0;
1186}
1187
1188
1189BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rcr)(uint8_t bMode)
1190{
1191 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(rcr, X86_EFL_OF, false);
1192 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(rcr, X86_EFL_OF, false);
1193 return 0;
1194}
1195
1196
1197
1198
1199
1200/*
1201 * Multiplication
1202 */
1203
1204BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mul)(uint8_t bMode)
1205{
1206#define MUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
1207#define MUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
1208
1209 static const struct
1210 {
1211 RTCCUINTREG uInAX;
1212 RTCCUINTREG uInBX;
1213 RTCCUINTREG uOutDX;
1214 RTCCUINTREG uOutAX;
1215 uint16_t fFlags;
1216 } s_aTests[] =
1217 {
1218 { 1, 1,
1219 0, 1, 0 },
1220 { 2, 2,
1221 0, 4, 0 },
1222 { RTCCUINTREG_MAX, RTCCUINTREG_MAX,
1223 RTCCUINTREG_MAX-1, 1, X86_EFL_CF | X86_EFL_OF },
1224 { RTCCINTREG_MAX, RTCCINTREG_MAX,
1225 RTCCINTREG_MAX / 2, 1, X86_EFL_CF | X86_EFL_OF },
1226 { 1, RTCCUINTREG_MAX,
1227 0, RTCCUINTREG_MAX, X86_EFL_PF | X86_EFL_SF },
1228 { 1, RTCCINTREG_MAX,
1229 0, RTCCINTREG_MAX, X86_EFL_PF },
1230 { 2, RTCCINTREG_MAX,
1231 0, RTCCUINTREG_MAX - 1, X86_EFL_SF },
1232 { (RTCCUINTREG)RTCCINTREG_MAX + 1, 2,
1233 1, 0, X86_EFL_PF | X86_EFL_CF | X86_EFL_OF },
1234 { (RTCCUINTREG)RTCCINTREG_MAX / 2 + 1, 3,
1235 0, ((RTCCUINTREG)RTCCINTREG_MAX / 2 + 1) * 3, X86_EFL_PF | X86_EFL_SF },
1236 };
1237
1238 BS3REGCTX Ctx;
1239 BS3TRAPFRAME TrapFrame;
1240 unsigned i, j, k;
1241
1242 /* Ensure the structures are allocated before we sample the stack pointer. */
1243 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1244 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1245
1246 /*
1247 * Create test context.
1248 */
1249 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1250 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2));
1251 for (k = 0; k < 2; k++)
1252 {
1253 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
1254 for (j = 0; j < 2; j++)
1255 {
1256 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1257 {
1258 if (k == 0)
1259 {
1260 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1261 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1262 }
1263 else
1264 {
1265 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1266 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1267 }
1268 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1269 if (TrapFrame.bXcpt != X86_XCPT_UD)
1270 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
1271 else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1272 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1273 || (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
1274 != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
1275 {
1276 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
1277 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
1278
1279 if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
1280 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1281 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1282 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1283 Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1284 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1285 if ( (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
1286 != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
1287 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & MUL_CHECK_EFLAGS,
1288 TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO));
1289 }
1290 }
1291 Ctx.rflags.u16 &= ~(MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO);
1292 }
1293 }
1294
1295 return 0;
1296}
1297
1298
1299BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_imul)(uint8_t bMode)
1300{
1301#define IMUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
1302#define IMUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
1303 static const struct
1304 {
1305 RTCCUINTREG uInAX;
1306 RTCCUINTREG uInBX;
1307 RTCCUINTREG uOutDX;
1308 RTCCUINTREG uOutAX;
1309 uint16_t fFlags;
1310 } s_aTests[] =
1311 {
1312 /* two positive values. */
1313 { 1, 1,
1314 0, 1, 0 },
1315 { 2, 2,
1316 0, 4, 0 },
1317 { RTCCINTREG_MAX, RTCCINTREG_MAX,
1318 RTCCINTREG_MAX/2, 1, X86_EFL_CF | X86_EFL_OF },
1319 { 1, RTCCINTREG_MAX,
1320 0, RTCCINTREG_MAX, X86_EFL_PF },
1321 { 2, RTCCINTREG_MAX,
1322 0, RTCCUINTREG_MAX - 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF },
1323 { 2, RTCCINTREG_MAX / 2,
1324 0, RTCCINTREG_MAX - 1U, 0 },
1325 { 2, (RTCCINTREG_MAX / 2 + 1),
1326 0, (RTCCUINTREG)RTCCINTREG_MAX + 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
1327 { 4, (RTCCINTREG_MAX / 2 + 1),
1328 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1329
1330 /* negative and positive */
1331 { -4, 3,
1332 -1, -12, X86_EFL_SF },
1333 { 32, -127,
1334 -1, -4064, X86_EFL_SF },
1335 { RTCCINTREG_MIN, 1,
1336 -1, RTCCINTREG_MIN, X86_EFL_SF | X86_EFL_PF },
1337 { RTCCINTREG_MIN, 2,
1338 -1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1339 { RTCCINTREG_MIN, 3,
1340 -2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
1341 { RTCCINTREG_MIN, 4,
1342 -2, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1343 { RTCCINTREG_MIN, RTCCINTREG_MAX,
1344 RTCCINTREG_MIN / 2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
1345 { RTCCINTREG_MIN, RTCCINTREG_MAX - 1,
1346 RTCCINTREG_MIN / 2 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1347
1348 /* two negative values. */
1349 { -4, -63,
1350 0, 252, X86_EFL_PF },
1351 { RTCCINTREG_MIN, RTCCINTREG_MIN,
1352 RTCCUINTREG_MAX / 4 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1353 { RTCCINTREG_MIN, RTCCINTREG_MIN + 1,
1354 RTCCUINTREG_MAX / 4, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF},
1355 { RTCCINTREG_MIN + 1, RTCCINTREG_MIN + 1,
1356 RTCCUINTREG_MAX / 4, 1, X86_EFL_CF | X86_EFL_OF },
1357
1358 };
1359
1360 BS3REGCTX Ctx;
1361 BS3TRAPFRAME TrapFrame;
1362 unsigned i, j, k;
1363
1364 /* Ensure the structures are allocated before we sample the stack pointer. */
1365 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1366 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1367
1368 /*
1369 * Create test context.
1370 */
1371 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1372 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2));
1373
1374 for (k = 0; k < 2; k++)
1375 {
1376 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
1377 for (j = 0; j < 2; j++)
1378 {
1379 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1380 {
1381 if (k == 0)
1382 {
1383 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1384 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1385 }
1386 else
1387 {
1388 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1389 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1390 }
1391 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1392 if (TrapFrame.bXcpt != X86_XCPT_UD)
1393 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
1394 else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1395 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1396 || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1397 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1398 {
1399 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
1400 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
1401
1402 if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
1403 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1404 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1405 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1406 Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1407 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1408 if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1409 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1410 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
1411 TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
1412 }
1413 }
1414 }
1415 }
1416
1417 /*
1418 * Repeat for the truncating two operand version.
1419 */
1420 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2));
1421
1422 for (k = 0; k < 2; k++)
1423 {
1424 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
1425 for (j = 0; j < 2; j++)
1426 {
1427 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1428 {
1429 if (k == 0)
1430 {
1431 Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1432 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1433 }
1434 else
1435 {
1436 Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1437 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1438 }
1439 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1440 if (TrapFrame.bXcpt != X86_XCPT_UD)
1441 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
1442 else if ( TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1443 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1444 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
1445 || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1446 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1447 {
1448 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
1449 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
1450
1451 if (TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
1452 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1453 s_aTests[i].uOutAX, TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS));
1454 if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1455 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1456 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
1457 TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
1458 }
1459 }
1460 }
1461 }
1462
1463 return 0;
1464}
1465
1466
1467BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_div)(uint8_t bMode)
1468{
1469#define DIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
1470 static const struct
1471 {
1472 RTCCUINTREG uInDX;
1473 RTCCUINTREG uInAX;
1474 RTCCUINTREG uInBX;
1475 RTCCUINTREG uOutAX;
1476 RTCCUINTREG uOutDX;
1477 uint8_t bXcpt;
1478 } s_aTests[] =
1479 {
1480 { 0, 1, 1,
1481 1, 0, X86_XCPT_UD },
1482 { 0, 5, 2,
1483 2, 1, X86_XCPT_UD },
1484 { 0, 0, 0,
1485 0, 0, X86_XCPT_DE },
1486 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 0,
1487 0, 0, X86_XCPT_DE },
1488 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 1,
1489 0, 0, X86_XCPT_DE },
1490 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
1491 0, 0, X86_XCPT_DE },
1492 { RTCCUINTREG_MAX - 1, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
1493 RTCCUINTREG_MAX, RTCCUINTREG_MAX - 1, X86_XCPT_UD },
1494 };
1495
1496 BS3REGCTX Ctx;
1497 BS3TRAPFRAME TrapFrame;
1498 unsigned i, j;
1499
1500 /* Ensure the structures are allocated before we sample the stack pointer. */
1501 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1502 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1503
1504 /*
1505 * Create test context.
1506 */
1507 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1508 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2));
1509
1510 /*
1511 * Do the tests twice, first with all flags set, then once again with
1512 * flags cleared. The flags are not touched by my intel skylake CPU.
1513 */
1514 Ctx.rflags.u16 |= DIV_CHECK_EFLAGS;
1515 for (j = 0; j < 2; j++)
1516 {
1517 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1518 {
1519 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1520 Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
1521 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1522 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1523
1524 if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
1525 || ( s_aTests[i].bXcpt == X86_XCPT_UD
1526 ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1527 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1528 || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS)
1529 : TrapFrame.Ctx.rax.u != Ctx.rax.u
1530 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1531 || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS) ) )
1532 {
1533 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
1534 i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
1535 if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
1536 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
1537 if (s_aTests[i].bXcpt == X86_XCPT_UD)
1538 {
1539 if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
1540 Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1541 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1542 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1543 Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1544 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1545 if ((TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS))
1546 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
1547 Ctx.rflags.u16 & DIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS);
1548 }
1549 }
1550 }
1551 Ctx.rflags.u16 &= ~DIV_CHECK_EFLAGS;
1552 }
1553
1554 return 0;
1555}
1556
1557
1558
1559BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_idiv)(uint8_t bMode)
1560{
1561#define IDIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
1562 static const struct
1563 {
1564 RTCCUINTREG uInDX;
1565 RTCCUINTREG uInAX;
1566 RTCCUINTREG uInBX;
1567 RTCCUINTREG uOutAX;
1568 RTCCUINTREG uOutDX;
1569 uint8_t bXcpt;
1570 } s_aTests[] =
1571 {
1572 { 0, 0, 0,
1573 0, 0, X86_XCPT_DE },
1574 { RTCCINTREG_MAX, RTCCINTREG_MAX, 0,
1575 0, 0, X86_XCPT_DE },
1576 /* two positive values. */
1577 { 0, 1, 1,
1578 1, 0, X86_XCPT_UD },
1579 { 0, 5, 2,
1580 2, 1, X86_XCPT_UD },
1581 { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2, RTCCINTREG_MAX,
1582 RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_UD },
1583 { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2 + 1, RTCCINTREG_MAX,
1584 RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_DE },
1585 /* negative dividend, positive divisor. */
1586 { -1, -7, 2,
1587 -3, -1, X86_XCPT_UD },
1588 { RTCCINTREG_MIN / 2 + 1, 0, RTCCINTREG_MAX,
1589 RTCCINTREG_MIN + 2, RTCCINTREG_MIN + 2, X86_XCPT_UD },
1590 { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MAX,
1591 0, 0, X86_XCPT_DE },
1592 /* positive dividend, negative divisor. */
1593 { 0, 7, -2,
1594 -3, 1, X86_XCPT_UD },
1595 { RTCCINTREG_MAX / 2 + 1, RTCCINTREG_MAX, RTCCINTREG_MIN,
1596 RTCCINTREG_MIN, RTCCINTREG_MAX, X86_XCPT_UD },
1597 { RTCCINTREG_MAX / 2 + 1, (RTCCUINTREG)RTCCINTREG_MAX+1, RTCCINTREG_MIN,
1598 0, 0, X86_XCPT_DE },
1599 /* negative dividend, negative divisor. */
1600 { -1, -7, -2,
1601 3, -1, X86_XCPT_UD },
1602 { RTCCINTREG_MIN / 2, 1, RTCCINTREG_MIN,
1603 RTCCINTREG_MAX, RTCCINTREG_MIN + 1, X86_XCPT_UD },
1604 { RTCCINTREG_MIN / 2, 2, RTCCINTREG_MIN,
1605 RTCCINTREG_MAX, RTCCINTREG_MIN + 2, X86_XCPT_UD },
1606 { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MIN,
1607 0, 0, X86_XCPT_DE },
1608 };
1609
1610 BS3REGCTX Ctx;
1611 BS3TRAPFRAME TrapFrame;
1612 unsigned i, j;
1613
1614 /* Ensure the structures are allocated before we sample the stack pointer. */
1615 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1616 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1617
1618 /*
1619 * Create test context.
1620 */
1621 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1622 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2));
1623
1624 /*
1625 * Do the tests twice, first with all flags set, then once again with
1626 * flags cleared. The flags are not touched by my intel skylake CPU.
1627 */
1628 Ctx.rflags.u16 |= IDIV_CHECK_EFLAGS;
1629 for (j = 0; j < 2; j++)
1630 {
1631 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1632 {
1633 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1634 Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
1635 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1636 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1637
1638 if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
1639 || ( s_aTests[i].bXcpt == X86_XCPT_UD
1640 ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1641 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1642 || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS)
1643 : TrapFrame.Ctx.rax.u != Ctx.rax.u
1644 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1645 || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) ) )
1646 {
1647 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
1648 i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
1649 if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
1650 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
1651 if (s_aTests[i].bXcpt == X86_XCPT_UD)
1652 {
1653 if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
1654 Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1655 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1656 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1657 Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1658 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1659 if ((TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS))
1660 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
1661 Ctx.rflags.u16 & IDIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS);
1662 }
1663 }
1664 }
1665 Ctx.rflags.u16 &= ~IDIV_CHECK_EFLAGS;
1666 }
1667
1668 return 0;
1669}
1670
1671
1672/*
1673 * BSF/BSR (386+) & TZCNT/LZCNT (BMI1,ABM)
1674 */
1675
1676typedef struct BS3CPUINSTR2_SUBTEST_BITSCAN_T
1677{
1678 RTCCUINTXREG uSrc;
1679 RTCCUINTXREG uOut;
1680 bool fOutNotSet;
1681 uint16_t fEflOut;
1682} BS3CPUINSTR2_SUBTEST_BITSCAN_T;
1683
1684typedef struct BS3CPUINSTR2_TEST_BITSCAN_T
1685{
1686 FPFNBS3FAR pfnWorker;
1687 bool fMemSrc;
1688 uint8_t cbInstr;
1689 uint8_t cOpBits;
1690 uint16_t fEflCheck;
1691 uint8_t cSubTests;
1692 BS3CPUINSTR2_SUBTEST_BITSCAN_T const *paSubTests;
1693} BS3CPUINSTR2_TEST_BITSCAN_T;
1694
1695static uint8_t bs3CpuInstr2_BitScan(uint8_t bMode, BS3CPUINSTR2_TEST_BITSCAN_T const *paTests, unsigned cTests)
1696{
1697 BS3REGCTX Ctx;
1698 BS3TRAPFRAME TrapFrame;
1699 unsigned i, j, k;
1700
1701 /* Ensure the structures are allocated before we sample the stack pointer. */
1702 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1703 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1704
1705 /*
1706 * Create test context.
1707 */
1708 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1709
1710 /*
1711 * Do the tests twice, first with all flags set, then once again with
1712 * flags cleared. The flags are not supposed to be touched at all.
1713 */
1714 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
1715 for (j = 0; j < 2; j++)
1716 {
1717 for (i = 0; i < cTests; i++)
1718 {
1719 for (k = 0; k < paTests[i].cSubTests; k++)
1720 {
1721 uint64_t uExpectRax, uExpectRip;
1722 RTCCUINTXREG uMemSrc, uMemSrcExpect;
1723
1724 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
1725 if (!paTests[i].fMemSrc)
1726 {
1727 Ctx.rbx.uCcXReg = paTests[i].paSubTests[k].uSrc;
1728 uMemSrcExpect = uMemSrc = ~paTests[i].paSubTests[k].uSrc;
1729 }
1730 else
1731 {
1732 uMemSrcExpect = uMemSrc = paTests[i].paSubTests[k].uSrc;
1733 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
1734 }
1735 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paTests[i].pfnWorker);
1736 if (paTests[i].paSubTests[k].fOutNotSet)
1737 uExpectRax = Ctx.rax.u;
1738 else if (paTests[i].cOpBits != 16)
1739 uExpectRax = paTests[i].paSubTests[k].uOut;
1740 else
1741 uExpectRax = paTests[i].paSubTests[k].uOut | (Ctx.rax.u & UINT64_C(0xffffffffffff0000));
1742 uExpectRip = Ctx.rip.u + paTests[i].cbInstr;
1743 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1744
1745 if ( TrapFrame.bXcpt != X86_XCPT_UD
1746 || TrapFrame.Ctx.rip.u != uExpectRip
1747 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
1748 || TrapFrame.Ctx.rax.u != uExpectRax
1749 || (TrapFrame.Ctx.rflags.u16 & paTests[i].fEflCheck)
1750 != (paTests[i].paSubTests[k].fEflOut & paTests[i].fEflCheck)
1751 /* check that nothing else really changed: */
1752 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
1753 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1754 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
1755 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
1756 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
1757 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
1758 || uMemSrc != uMemSrcExpect
1759 )
1760 {
1761 Bs3TestFailedF("test #%i/%i failed: input %#" RTCCUINTXREG_XFMT,
1762 i, k, paTests[i].paSubTests[k].uSrc);
1763 if (TrapFrame.bXcpt != X86_XCPT_UD)
1764 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", X86_XCPT_UD, TrapFrame.bXcpt);
1765 if (TrapFrame.Ctx.rip.u != uExpectRip)
1766 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
1767 if (TrapFrame.Ctx.rax.u != uExpectRax)
1768 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
1769 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
1770 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
1771 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
1772 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
1773 if ( (TrapFrame.Ctx.rflags.u16 & paTests[i].fEflCheck)
1774 != (paTests[i].paSubTests[k].fEflOut & paTests[i].fEflCheck))
1775 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
1776 paTests[i].paSubTests[k].fEflOut & paTests[i].fEflCheck,
1777 TrapFrame.Ctx.rflags.u16 & paTests[i].fEflCheck);
1778
1779 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
1780 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
1781 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
1782 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
1783 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
1784 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
1785 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
1786 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
1787 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
1788 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
1789 if (uMemSrc != uMemSrcExpect)
1790 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
1791 }
1792 }
1793 }
1794 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
1795 }
1796
1797 return 0;
1798}
1799
1800
1801BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bsf_tzcnt)(uint8_t bMode)
1802{
1803 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsf16[] =
1804 {
1805 { 0, /* -> */ 0, true, X86_EFL_ZF },
1806 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 0, true, X86_EFL_ZF },
1807 { ~(RTCCUINTXREG)0, /* -> */ 0, false, 0 },
1808 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1809 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1810 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1811 };
1812 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsTzCnt16[] =
1813 {
1814 { 0, /* -> */ 16, false, X86_EFL_CF },
1815 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 16, false, X86_EFL_CF },
1816 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1817 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1818 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1819 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1820 };
1821 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsf32[] =
1822 {
1823 { 0, /* -> */ 0, true, X86_EFL_ZF },
1824#if ARCH_BITS == 64
1825 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 0, true, X86_EFL_ZF },
1826#endif
1827 { ~(RTCCUINTXREG)0, /* -> */ 0, false, 0 },
1828 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1829 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1830 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1831 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1832 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1833 };
1834 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsTzCnt32[] =
1835 {
1836 { 0, /* -> */ 32, false, X86_EFL_CF },
1837#if ARCH_BITS == 64
1838 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 32, false, X86_EFL_CF },
1839#endif
1840 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1841 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1842 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1843 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1844 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1845 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1846 };
1847#if ARCH_BITS == 64
1848 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsf64[] =
1849 {
1850 { 0, /* -> */ 0, true, X86_EFL_ZF },
1851 { ~(RTCCUINTXREG)0, /* -> */ 0, false, 0 },
1852 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1853 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1854 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1855 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1856 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1857 { UINT64_C(0x8000000000000000), /* -> */ 63, false, 0 },
1858 { UINT64_C(0x4560000000000000), /* -> */ 53, false, 0 },
1859 };
1860 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsTzCnt64[] =
1861 {
1862 { 0, /* -> */ 64, false, X86_EFL_CF },
1863 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1864 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1865 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1866 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1867 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1868 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1869 { UINT64_C(0x8000000000000000), /* -> */ 63, false, 0 },
1870 { UINT64_C(0x4560000000000000), /* -> */ 53, false, 0 },
1871 };
1872#endif
1873 static BS3CPUINSTR2_TEST_BITSCAN_T s_aTests[] =
1874 {
1875 { BS3_CMN_NM(bs3CpuInstr2_bsf_AX_BX_ud2), false, 3 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1876 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1877 { BS3_CMN_NM(bs3CpuInstr2_bsf_AX_FSxBX_ud2), true, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1878 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1879 { BS3_CMN_NM(bs3CpuInstr2_bsf_EAX_EBX_ud2), false, 3 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1880 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1881 { BS3_CMN_NM(bs3CpuInstr2_bsf_EAX_FSxBX_ud2), true, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1882 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1883#if ARCH_BITS == 64
1884 { BS3_CMN_NM(bs3CpuInstr2_bsf_RAX_RBX_ud2), false, 4, 64, X86_EFL_ZF,
1885 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1886 { BS3_CMN_NM(bs3CpuInstr2_bsf_RAX_FSxBX_ud2), true, 5, 64, X86_EFL_ZF,
1887 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1888#endif
1889 /* f2 prefixed variant: */
1890 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1891 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1892 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1893 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1894 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1895 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1896 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1897 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1898#if ARCH_BITS == 64
1899 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF,
1900 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1901 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF,
1902 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1903#endif
1904
1905 /* tzcnt: */
1906 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1907 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1908 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1909 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1910 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1911 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1912 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1913 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1914#if ARCH_BITS == 64
1915 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF | X86_EFL_CF,
1916 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1917 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF | X86_EFL_CF,
1918 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1919#endif
1920 /* f2 prefixed tzcnt variant (last prefix (f3) should prevail): */
1921 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_AX_BX_ud2), false, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1922 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1923 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_AX_FSxBX_ud2), true, 6 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1924 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1925 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_EAX_EBX_ud2), false, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1926 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1927 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_EAX_FSxBX_ud2),true, 6 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1928 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1929#if ARCH_BITS == 64
1930 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_RAX_RBX_ud2), false, 6, 64, X86_EFL_ZF | X86_EFL_CF,
1931 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1932 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_RAX_FSxBX_ud2),true, 7, 64, X86_EFL_ZF | X86_EFL_CF,
1933 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1934#endif
1935 };
1936
1937 uint32_t uStdExtFeatEbx = 0;
1938 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1939 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
1940 if (!(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI1))
1941 {
1942 unsigned i = RT_ELEMENTS(s_aTests);
1943 while (i-- > 0)
1944 if (s_aTests[i].fEflCheck & X86_EFL_CF)
1945 {
1946 s_aTests[i].fEflCheck = X86_EFL_ZF;
1947 switch (s_aTests[i].cOpBits)
1948 {
1949 case 16:
1950 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsf16);
1951 s_aTests[i].paSubTests = s_aSubTestsBsf16;
1952 break;
1953 case 32:
1954 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsf32);
1955 s_aTests[i].paSubTests = s_aSubTestsBsf32;
1956 break;
1957#if ARCH_BITS == 64
1958 case 64:
1959 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsf64);
1960 s_aTests[i].paSubTests = s_aSubTestsBsf64;
1961 break;
1962#endif
1963 }
1964 }
1965 Bs3TestPrintf("tzcnt not supported\n");
1966 }
1967
1968 return bs3CpuInstr2_BitScan(bMode, s_aTests, RT_ELEMENTS(s_aTests));
1969}
1970
1971
1972BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bsr_lzcnt)(uint8_t bMode)
1973{
1974 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsr16[] =
1975 {
1976 { 0, /* -> */ 0, true, X86_EFL_ZF },
1977 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 0, true, X86_EFL_ZF },
1978 { ~(RTCCUINTXREG)0, /* -> */ 15, false, 0 },
1979 { ~(RTCCUINTXREG)1, /* -> */ 15, false, 0 },
1980 { UINT16_C(0x0001), /* -> */ 0, false, 0 },
1981 { UINT16_C(0x0002), /* -> */ 1, false, 0 },
1982 { UINT16_C(0x4560), /* -> */ 14, false, 0 },
1983 };
1984 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsLzCnt16[] =
1985 {
1986 { 0, /* -> */ 16, false, X86_EFL_CF },
1987 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 16, false, X86_EFL_CF },
1988 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1989 { ~(RTCCUINTXREG)1, /* -> */ 0, false, X86_EFL_ZF },
1990 { UINT16_C(0x8000), /* -> */ 0, false, X86_EFL_ZF },
1991 { UINT16_C(0x4560), /* -> */ 1, false, 0 },
1992 { UINT16_C(0x003f), /* -> */ 10, false, 0 },
1993 { UINT16_C(0x0001), /* -> */ 15, false, 0 },
1994 };
1995 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsr32[] =
1996 {
1997 { 0, /* -> */ 0, true, X86_EFL_ZF },
1998#if ARCH_BITS == 64
1999 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 0, true, X86_EFL_ZF },
2000#endif
2001 { ~(RTCCUINTXREG)0, /* -> */ 31, false, 0 },
2002 { ~(RTCCUINTXREG)1, /* -> */ 31, false, 0 },
2003 { 1, /* -> */ 0, false, 0 },
2004 { 2, /* -> */ 1, false, 0 },
2005 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
2006 { UINT16_C(0x4560), /* -> */ 14, false, 0 },
2007 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
2008 { UINT32_C(0x45600000), /* -> */ 30, false, 0 },
2009 };
2010 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsLzCnt32[] =
2011 {
2012 { 0, /* -> */ 32, false, X86_EFL_CF },
2013#if ARCH_BITS == 64
2014 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 32, false, X86_EFL_CF },
2015#endif
2016 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
2017 { ~(RTCCUINTXREG)1, /* -> */ 0, false, X86_EFL_ZF },
2018 { 1, /* -> */ 31, false, 0 },
2019 { 2, /* -> */ 30, false, 0},
2020 { UINT16_C(0x8000), /* -> */ 16, false, 0 },
2021 { UINT16_C(0x4560), /* -> */ 17, false, 0 },
2022 { UINT32_C(0x80000000), /* -> */ 0, false, X86_EFL_ZF },
2023 { UINT32_C(0x45600000), /* -> */ 1, false, 0 },
2024 { UINT32_C(0x0000ffff), /* -> */ 16, false, 0 },
2025 };
2026#if ARCH_BITS == 64
2027 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsr64[] =
2028 {
2029 { 0, /* -> */ 0, true, X86_EFL_ZF },
2030 { ~(RTCCUINTXREG)0, /* -> */ 63, false, 0 },
2031 { ~(RTCCUINTXREG)1, /* -> */ 63, false, 0 },
2032 { 1, /* -> */ 0, false, 0 },
2033 { 2, /* -> */ 1, false, 0 },
2034 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
2035 { UINT16_C(0x4560), /* -> */ 14, false, 0 },
2036 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
2037 { UINT32_C(0x45600000), /* -> */ 30, false, 0 },
2038 { UINT64_C(0x8000000000000000), /* -> */ 63, false, 0 },
2039 { UINT64_C(0x0045600000000000), /* -> */ 54, false, 0 },
2040 };
2041 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsLzCnt64[] =
2042 {
2043 { 0, /* -> */ 64, false, X86_EFL_CF },
2044 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
2045 { ~(RTCCUINTXREG)1, /* -> */ 0, false, X86_EFL_ZF },
2046 { 1, /* -> */ 63, false, 0 },
2047 { 2, /* -> */ 62, false, 0 },
2048 { UINT16_C(0x8000), /* -> */ 48, false, 0 },
2049 { UINT16_C(0x4560), /* -> */ 49, false, 0 },
2050 { UINT32_C(0x80000000), /* -> */ 32, false, 0 },
2051 { UINT32_C(0x45600000), /* -> */ 33, false, 0 },
2052 { UINT64_C(0x8000000000000000), /* -> */ 0, false, X86_EFL_ZF },
2053 { UINT64_C(0x4560000000000000), /* -> */ 1, false, 0 },
2054 { UINT64_C(0x0045600000000000), /* -> */ 9, false, 0 },
2055 };
2056#endif
2057 static BS3CPUINSTR2_TEST_BITSCAN_T s_aTests[] =
2058 {
2059 { BS3_CMN_NM(bs3CpuInstr2_bsr_AX_BX_ud2), false, 3 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2060 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2061 { BS3_CMN_NM(bs3CpuInstr2_bsr_AX_FSxBX_ud2), true, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2062 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2063 { BS3_CMN_NM(bs3CpuInstr2_bsr_EAX_EBX_ud2), false, 3 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2064 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2065 { BS3_CMN_NM(bs3CpuInstr2_bsr_EAX_FSxBX_ud2), true, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2066 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2067#if ARCH_BITS == 64
2068 { BS3_CMN_NM(bs3CpuInstr2_bsr_RAX_RBX_ud2), false, 4, 64, X86_EFL_ZF,
2069 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2070 { BS3_CMN_NM(bs3CpuInstr2_bsr_RAX_FSxBX_ud2), true, 5, 64, X86_EFL_ZF,
2071 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2072#endif
2073 /* f2 prefixed variant: */
2074 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2075 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2076 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2077 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2078 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2079 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2080 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2081 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2082#if ARCH_BITS == 64
2083 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF,
2084 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2085 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF,
2086 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2087#endif
2088
2089 /* lzcnt: */
2090 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2091 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2092 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2093 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2094 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2095 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2096 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2097 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2098#if ARCH_BITS == 64
2099 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF | X86_EFL_CF,
2100 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2101 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF | X86_EFL_CF,
2102 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2103#endif
2104 /* f2 prefixed lzcnt variant (last prefix (f3) should prevail): */
2105 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_AX_BX_ud2), false, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2106 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2107 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_AX_FSxBX_ud2), true, 6 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2108 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2109 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_EAX_EBX_ud2), false, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2110 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2111 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_EAX_FSxBX_ud2),true, 6 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2112 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2113#if ARCH_BITS == 64
2114 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_RAX_RBX_ud2), false, 6, 64, X86_EFL_ZF | X86_EFL_CF,
2115 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2116 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_RAX_FSxBX_ud2),true, 7, 64, X86_EFL_ZF | X86_EFL_CF,
2117 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2118#endif
2119 };
2120
2121 uint32_t uExtFeatEcx = 0;
2122 if (g_uBs3CpuDetected & BS3CPU_F_CPUID_EXT_LEAVES)
2123 ASMCpuIdExSlow(UINT32_C(0x80000001), 0, 0, 0, NULL, NULL, &uExtFeatEcx, NULL);
2124 if (!(uExtFeatEcx & X86_CPUID_AMD_FEATURE_ECX_ABM))
2125 {
2126 unsigned i = RT_ELEMENTS(s_aTests);
2127 while (i-- > 0)
2128 if (s_aTests[i].fEflCheck & X86_EFL_CF)
2129 {
2130 s_aTests[i].fEflCheck = X86_EFL_ZF;
2131 switch (s_aTests[i].cOpBits)
2132 {
2133 case 16:
2134 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsr16);
2135 s_aTests[i].paSubTests = s_aSubTestsBsr16;
2136 break;
2137 case 32:
2138 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsr32);
2139 s_aTests[i].paSubTests = s_aSubTestsBsr32;
2140 break;
2141#if ARCH_BITS == 64
2142 case 64:
2143 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsr64);
2144 s_aTests[i].paSubTests = s_aSubTestsBsr64;
2145 break;
2146#endif
2147 }
2148 }
2149 Bs3TestPrintf("lzcnt not supported\n");
2150 }
2151
2152 return bs3CpuInstr2_BitScan(bMode, s_aTests, RT_ELEMENTS(s_aTests));
2153}
2154
2155
2156/**
2157 * RORX
2158 */
2159BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rorx)(uint8_t bMode)
2160{
2161 static const struct
2162 {
2163 FPFNBS3FAR pfnWorker;
2164 bool fMemSrc;
2165 bool fOkay;
2166 RTCCUINTXREG uIn;
2167 RTCCUINTXREG uOut;
2168 } s_aTests[] =
2169 {
2170 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2171 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp), false, true, // #0
2172 0, /* -> */ 0 },
2173 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp), false, true, // #1
2174 ~(RTCCUINTXREG)2, /* -> */ ~(RTCCUINTXREG)0 >> 1 },
2175 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_DSxDI_68_icebp), true, true, // #2
2176 0, /* -> */ 0 },
2177 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_DSxDI_68_icebp), true, true, // #3
2178 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG_MAX >> 4) | (~(RTCCUINTXREG)2 << (sizeof(RTCCUINTXREG) * 8 - 4)) },
2179
2180 /* 32 bits register width: */
2181 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp), false, true, // #4
2182 0, /* -> */ 0 },
2183 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp), false, true, // #5
2184 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG)(~(uint32_t)0 >> 1) },
2185 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_DSxDI_36_icebp), true, true, // #6
2186 0, /* -> */ 0 },
2187 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_DSxDI_36_icebp), true, true, // #7
2188 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG)UINT32_C(0xdfffffff) },
2189
2190 /* encoding tests: */
2191 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_L1), false, false, // #8
2192 RTCCUINTXREG_MAX, /* -> */ 0 },
2193 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V1), false, false, // #9
2194 RTCCUINTXREG_MAX, /* -> */ 0 },
2195 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V15), false, false, // #10
2196 RTCCUINTXREG_MAX, /* -> */ 0 },
2197# if ARCH_BITS == 64 /* The VEX.X=0 encoding mean LES instruction in 32-bit and 16-bit mode. */
2198 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_X1), false, true, // #11
2199 UINT32_C(0xf1e2d3c5), /* -> */ (RTCCUINTXREG)UINT32_C(0x7c78b4f1) },
2200# endif
2201 };
2202
2203 BS3REGCTX Ctx;
2204 BS3TRAPFRAME TrapFrame;
2205 unsigned i, j;
2206 uint32_t uStdExtFeatEbx = 0;
2207 bool fSupportsRorX;
2208
2209 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2210 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2211 fSupportsRorX = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI2);
2212
2213 /* Ensure the structures are allocated before we sample the stack pointer. */
2214 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2215 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2216
2217 /*
2218 * Create test context.
2219 */
2220 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2221
2222 /*
2223 * Do the tests twice, first with all flags set, then once again with
2224 * flags cleared. The flags are not supposed to be touched at all.
2225 */
2226 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2227 for (j = 0; j < 2; j++)
2228 {
2229 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
2230 {
2231 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && s_aTests[i].fOkay && fSupportsRorX;
2232 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2233 uint64_t uExpectRbx, uExpectRip;
2234 RTCCUINTXREG uMemSrc, uMemSrcExpect;
2235 Ctx.rbx.uCcXReg = RTCCUINTXREG_MAX * 1019;
2236 if (!s_aTests[i].fMemSrc)
2237 {
2238 Ctx.rdx.uCcXReg = s_aTests[i].uIn;
2239 uMemSrcExpect = uMemSrc = ~s_aTests[i].uIn;
2240 }
2241 else
2242 {
2243 Ctx.rdx.uCcXReg = ~s_aTests[i].uIn;
2244 uMemSrcExpect = uMemSrc = s_aTests[i].uIn;
2245 Bs3RegCtxSetGrpDsFromCurPtr(&Ctx, &Ctx.rdi, &uMemSrc);
2246 }
2247 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
2248 uExpectRbx = fOkay ? s_aTests[i].uOut : Ctx.rbx.u;
2249 uExpectRip = Ctx.rip.u + (fOkay ? 6 + 1 : 0);
2250 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2251
2252 if ( TrapFrame.bXcpt != bExpectXcpt
2253 || TrapFrame.Ctx.rip.u != uExpectRip
2254 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2255 || TrapFrame.Ctx.rbx.u != uExpectRbx
2256 /* check that nothing else really changed: */
2257 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS)
2258 || TrapFrame.Ctx.rax.u != Ctx.rax.u
2259 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2260 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2261 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2262 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2263 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2264 || uMemSrc != uMemSrcExpect
2265 )
2266 {
2267 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uIn);
2268 if (TrapFrame.bXcpt != bExpectXcpt)
2269 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2270 if (TrapFrame.Ctx.rip.u != uExpectRip)
2271 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2272 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2273 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2274 if (TrapFrame.Ctx.rbx.u != uExpectRbx)
2275 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", uExpectRbx, TrapFrame.Ctx.rbx.u);
2276
2277 if ((TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS))
2278 Bs3TestFailedF("Expected EFLAGS = %#06RX64, got %#06RX64",
2279 Ctx.rflags.u16 & X86_EFL_STATUS_BITS, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
2280 if (TrapFrame.Ctx.rax.u != Ctx.rax.u)
2281 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", Ctx.rax.u, TrapFrame.Ctx.rax.u);
2282 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2283 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2284 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2285 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2286 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2287 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2288 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2289 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2290 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2291 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2292 if (uMemSrc != uMemSrcExpect)
2293 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
2294 }
2295 }
2296 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2297 }
2298
2299 return 0;
2300}
2301
2302
2303BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_andn)(uint8_t bMode)
2304{
2305#define ANDN_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_ZF | X86_EFL_OF | X86_EFL_SF)
2306#define ANDN_IGNORE_EFLAGS (uint16_t)(X86_EFL_AF | X86_EFL_PF) /* undefined, ignoring for now */
2307 static const struct
2308 {
2309 FPFNBS3FAR pfnWorker;
2310 bool fMemSrc;
2311 uint8_t cbInstr;
2312 RTCCUINTXREG uSrc1;
2313 RTCCUINTXREG uSrc2;
2314 RTCCUINTXREG uOut;
2315 uint16_t fEFlags;
2316 } s_aTests[] =
2317 {
2318 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2319 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_RBX_icebp), false, 5, // #0
2320 0, 0, /* -> */ 0, X86_EFL_ZF },
2321 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_RBX_icebp), false, 5, // #1
2322 2, ~(RTCCUINTXREG)3, /* -> */ ~(RTCCUINTXREG)3, X86_EFL_SF },
2323 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_FSxBX_icebp), true, 6, // #2
2324 0, 0, /* -> */ 0, X86_EFL_ZF },
2325 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_FSxBX_icebp), true, 6, // #3
2326 2, ~(RTCCUINTXREG)3, /* -> */ ~(RTCCUINTXREG)3, X86_EFL_SF },
2327
2328 /* 32-bit register width */
2329 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_EBX_icebp), false, 5, // #4
2330 0, 0, /* -> */ 0, X86_EFL_ZF },
2331 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_EBX_icebp), false, 5, // #5
2332 2, ~(RTCCUINTXREG)7, /* -> */ ~(uint32_t)7, X86_EFL_SF },
2333 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_FSxBX_icebp), true, 6, // #6
2334 0, 0, /* -> */ 0, X86_EFL_ZF },
2335 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_FSxBX_icebp), true, 6, // #7
2336 2, ~(RTCCUINTXREG)7, /* -> */ ~(uint32_t)7, X86_EFL_SF },
2337
2338 };
2339
2340 BS3REGCTX Ctx;
2341 BS3TRAPFRAME TrapFrame;
2342 unsigned i, j;
2343 uint32_t uStdExtFeatEbx = 0;
2344 bool fSupportsAndN;
2345
2346 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2347 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2348 fSupportsAndN = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI1);
2349
2350 /* Ensure the structures are allocated before we sample the stack pointer. */
2351 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2352 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2353
2354 /*
2355 * Create test context.
2356 */
2357 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2358
2359 /*
2360 * Do the tests twice, first with all flags set, then once again with
2361 * flags cleared. The flags are not supposed to be touched at all.
2362 */
2363 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2364 for (j = 0; j < 2; j++)
2365 {
2366 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
2367 {
2368 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsAndN;
2369 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2370 uint64_t uExpectRax, uExpectRip;
2371 RTCCUINTXREG uMemSrc2, uMemSrc2Expect;
2372
2373 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
2374 Ctx.rcx.uCcXReg = s_aTests[i].uSrc1;
2375 if (!s_aTests[i].fMemSrc)
2376 {
2377 Ctx.rbx.uCcXReg = s_aTests[i].uSrc2;
2378 uMemSrc2Expect = uMemSrc2 = ~s_aTests[i].uSrc2;
2379 }
2380 else
2381 {
2382 uMemSrc2Expect = uMemSrc2 = s_aTests[i].uSrc2;
2383 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc2);
2384 }
2385 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
2386 uExpectRax = fOkay ? s_aTests[i].uOut : Ctx.rax.u;
2387 uExpectRip = Ctx.rip.u + (fOkay ? s_aTests[i].cbInstr + 1 : 0);
2388 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2389
2390 if ( TrapFrame.bXcpt != bExpectXcpt
2391 || TrapFrame.Ctx.rip.u != uExpectRip
2392 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2393 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
2394 || TrapFrame.Ctx.rax.u != uExpectRax
2395 /* check that nothing else really changed: */
2396 || (TrapFrame.Ctx.rflags.u16 & ANDN_CHECK_EFLAGS)
2397 != ((fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16) & ANDN_CHECK_EFLAGS)
2398 || (TrapFrame.Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS)
2399 != (Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS)
2400 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2401 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2402 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2403 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2404 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2405 || uMemSrc2 != uMemSrc2Expect
2406 )
2407 {
2408 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT ", %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uSrc1, s_aTests[i].uSrc2);
2409 if (TrapFrame.bXcpt != bExpectXcpt)
2410 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2411 if (TrapFrame.Ctx.rip.u != uExpectRip)
2412 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2413 if (TrapFrame.Ctx.rax.u != uExpectRax)
2414 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
2415 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2416 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2417 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
2418 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
2419 if ( (TrapFrame.Ctx.rflags.u16 & ANDN_CHECK_EFLAGS)
2420 != ((fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16) & ANDN_CHECK_EFLAGS))
2421 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
2422 (fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16) & ANDN_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & ANDN_CHECK_EFLAGS);
2423 if ( (TrapFrame.Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS)
2424 != (Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS))
2425 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
2426 Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS,
2427 TrapFrame.Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS);
2428
2429 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2430 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2431 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2432 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2433 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2434 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2435 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2436 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2437 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2438 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2439 if (uMemSrc2 != uMemSrc2Expect)
2440 Bs3TestFailedF("Expected uMemSrc2 = %#06RX64, got %#06RX64", (uint64_t)uMemSrc2Expect, (uint64_t)uMemSrc2);
2441 }
2442 }
2443 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2444 }
2445
2446 return 0;
2447}
2448
2449/*
2450 * For testing BEXTR, SHLX SARX & SHRX.
2451 */
2452typedef struct BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T
2453{
2454 RTCCUINTXREG uSrc1;
2455 RTCCUINTXREG uSrc2;
2456 RTCCUINTXREG uOut;
2457 uint16_t fEflOut;
2458} BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T;
2459
2460typedef struct BS3CPUINSTR2_TEST_Gy_Ey_By_T
2461{
2462 FPFNBS3FAR pfnWorker;
2463 bool fMemSrc;
2464 uint8_t cbInstr;
2465 uint8_t cSubTests;
2466 BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const *paSubTests;
2467} BS3CPUINSTR2_TEST_Gy_Ey_By_T;
2468
2469static uint8_t bs3CpuInstr2_Common_Gy_Ey_By(uint8_t bMode, BS3CPUINSTR2_TEST_Gy_Ey_By_T const *paTests, unsigned cTests,
2470 uint32_t fStdExtFeatEbx, uint16_t fEflCheck, uint16_t fEflIgnore)
2471{
2472 BS3REGCTX Ctx;
2473 BS3TRAPFRAME TrapFrame;
2474 unsigned i, j, k;
2475 uint32_t uStdExtFeatEbx = 0;
2476 bool fSupportsInstr;
2477
2478 fEflCheck &= ~fEflIgnore;
2479
2480 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2481 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2482 fSupportsInstr = RT_BOOL(uStdExtFeatEbx & fStdExtFeatEbx);
2483
2484 /* Ensure the structures are allocated before we sample the stack pointer. */
2485 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2486 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2487
2488 /*
2489 * Create test context.
2490 */
2491 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2492
2493 /*
2494 * Do the tests twice, first with all flags set, then once again with
2495 * flags cleared. The flags are not supposed to be touched at all.
2496 */
2497 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2498 for (j = 0; j < 2; j++)
2499 {
2500 for (i = 0; i < cTests; i++)
2501 {
2502 for (k = 0; k < paTests[i].cSubTests; k++)
2503 {
2504 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsInstr;
2505 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2506 uint64_t uExpectRax, uExpectRip;
2507 RTCCUINTXREG uMemSrc1, uMemSrc1Expect;
2508
2509 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
2510 Ctx.rcx.uCcXReg = paTests[i].paSubTests[k].uSrc2;
2511 if (!paTests[i].fMemSrc)
2512 {
2513 Ctx.rbx.uCcXReg = paTests[i].paSubTests[k].uSrc1;
2514 uMemSrc1Expect = uMemSrc1 = ~paTests[i].paSubTests[k].uSrc1;
2515 }
2516 else
2517 {
2518 uMemSrc1Expect = uMemSrc1 = paTests[i].paSubTests[k].uSrc1;
2519 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc1);
2520 }
2521 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paTests[i].pfnWorker);
2522 uExpectRax = fOkay ? paTests[i].paSubTests[k].uOut : Ctx.rax.u;
2523 uExpectRip = Ctx.rip.u + (fOkay ? paTests[i].cbInstr + 1 : 0);
2524 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2525
2526 if ( TrapFrame.bXcpt != bExpectXcpt
2527 || TrapFrame.Ctx.rip.u != uExpectRip
2528 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2529 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
2530 || TrapFrame.Ctx.rax.u != uExpectRax
2531 /* check that nothing else really changed: */
2532 || (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2533 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck)
2534 || (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2535 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2536 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2537 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2538 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2539 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2540 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2541 || uMemSrc1 != uMemSrc1Expect
2542 )
2543 {
2544 Bs3TestFailedF("test #%i/%i failed: input %#" RTCCUINTXREG_XFMT ", %#" RTCCUINTXREG_XFMT,
2545 i, k, paTests[i].paSubTests[k].uSrc1, paTests[i].paSubTests[k].uSrc2);
2546 if (TrapFrame.bXcpt != bExpectXcpt)
2547 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2548 if (TrapFrame.Ctx.rip.u != uExpectRip)
2549 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2550 if (TrapFrame.Ctx.rax.u != uExpectRax)
2551 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
2552 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2553 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2554 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
2555 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
2556 if ( (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2557 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck))
2558 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
2559 (fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck,
2560 TrapFrame.Ctx.rflags.u16 & fEflCheck);
2561 if ( (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2562 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS))
2563 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
2564 Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS,
2565 TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS);
2566
2567 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2568 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2569 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2570 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2571 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2572 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2573 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2574 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2575 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2576 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2577 if (uMemSrc1 != uMemSrc1Expect)
2578 Bs3TestFailedF("Expected uMemSrc1 = %#06RX64, got %#06RX64", (uint64_t)uMemSrc1Expect, (uint64_t)uMemSrc1);
2579 }
2580 }
2581 }
2582 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2583 }
2584
2585 return 0;
2586}
2587
2588
2589BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bextr)(uint8_t bMode)
2590{
2591 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2592 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2593 {
2594 { 0, RT_MAKE_U16(0, 0), /* -> */ 0, X86_EFL_ZF },
2595 { 0, RT_MAKE_U16(16, 33), /* -> */ 0, X86_EFL_ZF },
2596 { ~(RTCCUINTXREG)7, RT_MAKE_U16(2, 4), /* -> */ 0xe, 0},
2597 { ~(RTCCUINTXREG)7, RT_MAKE_U16(40, 8), /* -> */ ARCH_BITS == 64 ? 0xff : 0x00, ARCH_BITS == 64 ? 0 : X86_EFL_ZF },
2598 };
2599
2600 /* 32-bit register width */
2601 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2602 {
2603 { 0, RT_MAKE_U16(0, 0), /* -> */ 0, X86_EFL_ZF },
2604 { 0, RT_MAKE_U16(16, 18), /* -> */ 0, X86_EFL_ZF },
2605 { ~(RTCCUINTXREG)7, RT_MAKE_U16(2, 4), /* -> */ 0xe, 0 },
2606 { ~(RTCCUINTXREG)7, RT_MAKE_U16(24, 8), /* -> */ 0xff, 0 },
2607 { ~(RTCCUINTXREG)7, RT_MAKE_U16(31, 9), /* -> */ 1, 0 },
2608 { ~(RTCCUINTXREG)7, RT_MAKE_U16(42, 8), /* -> */ 0, X86_EFL_ZF },
2609 };
2610
2611 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2612 {
2613 { BS3_CMN_NM(bs3CpuInstr2_bextr_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2614 { BS3_CMN_NM(bs3CpuInstr2_bextr_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2615 { BS3_CMN_NM(bs3CpuInstr2_bextr_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2616 { BS3_CMN_NM(bs3CpuInstr2_bextr_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2617 };
2618 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2619 X86_EFL_STATUS_BITS, X86_EFL_AF | X86_EFL_SF | X86_EFL_PF);
2620}
2621
2622
2623BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bzhi)(uint8_t bMode)
2624{
2625 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2626 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2627 {
2628 { 0, 0, /* -> */ 0, X86_EFL_ZF },
2629 { 0, ~(RTCCUINTXREG)255, /* -> */ 0, X86_EFL_ZF },
2630 { 0, 64, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
2631 { ~(RTCCUINTXREG)0, 64, /* -> */ ~(RTCCUINTXREG)0, X86_EFL_CF | X86_EFL_SF },
2632 { ~(RTCCUINTXREG)0, 63,
2633 /* -> */ ARCH_BITS >= 64 ? ~(RTCCUINTXREG)0 >> 1 : ~(RTCCUINTXREG)0, ARCH_BITS >= 64 ? 0 : X86_EFL_CF | X86_EFL_SF },
2634 { ~(RTCCUINTXREG)0 << 31 | UINT32_C(0x63849607), 24, /* -> */ UINT32_C(0x00849607), 0 },
2635 { ~(RTCCUINTXREG)0 << 31 | UINT32_C(0x63849607), 33,
2636 /* -> */ ARCH_BITS >= 64 ? UINT64_C(0x1e3849607) : UINT32_C(0xe3849607), ARCH_BITS >= 64 ? 0 : X86_EFL_CF | X86_EFL_SF },
2637 };
2638
2639 /* 32-bit register width */
2640 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2641 {
2642 { 0, 0, /* -> */ 0, X86_EFL_ZF },
2643 { 0, ~(RTCCUINTXREG)255, /* -> */ 0, X86_EFL_ZF },
2644 { 0, 32, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
2645 { ~(RTCCUINTXREG)0, 32, /* -> */ UINT32_MAX, X86_EFL_CF | X86_EFL_SF },
2646 { ~(RTCCUINTXREG)0, 31, /* -> */ UINT32_MAX >> 1, 0 },
2647 { UINT32_C(0x1230fd34), 15, /* -> */ UINT32_C(0x00007d34), 0 },
2648 };
2649
2650 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2651 {
2652 { BS3_CMN_NM(bs3CpuInstr2_bzhi_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2653 { BS3_CMN_NM(bs3CpuInstr2_bzhi_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2654 { BS3_CMN_NM(bs3CpuInstr2_bzhi_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2655 { BS3_CMN_NM(bs3CpuInstr2_bzhi_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2656 };
2657 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI2,
2658 X86_EFL_STATUS_BITS, 0);
2659}
2660
2661
2662/** @note This is a Gy_By_Ey format instruction, so we're switching the two
2663 * source registers around when calling bs3CpuInstr2_Common_Gy_Ey_By.
2664 * Sorry for the confusion, but it saves some unnecessary code dup. */
2665BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_pdep)(uint8_t bMode)
2666{
2667 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2668 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2669 { /* Mask (RBX/[FS:xBX]), source=RCX */
2670 { 0, 0, /* -> */ 0, 0 },
2671 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2672 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2673 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)0, 0 },
2674#if ARCH_BITS >= 64
2675 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)0, /* -> */ UINT64_C(0x3586049947589201), 0 },
2676 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)7, /* -> */ UINT64_C(0x3586049947588000), 0 },
2677#endif
2678 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x47589201), 0 },
2679 { UINT32_C(0x47589201), ~(RTCCUINTXREG)7, /* -> */ UINT32_C(0x47588000), 0 },
2680 };
2681
2682 /* 32-bit register width */
2683 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2684 { /* Mask (EBX/[FS:xBX]), source=ECX */
2685 { 0, 0, /* -> */ 0, 0 },
2686 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2687 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2688 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ UINT32_MAX, 0 },
2689 { UINT32_C(0x01010101), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x01010101), 0 },
2690 { UINT32_C(0x01010101), ~(RTCCUINTXREG)3, /* -> */ UINT32_C(0x01010000), 0 },
2691 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x47589201), 0 },
2692 };
2693
2694 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2695 {
2696 { BS3_CMN_NM(bs3CpuInstr2_pdep_RAX_RCX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2697 { BS3_CMN_NM(bs3CpuInstr2_pdep_RAX_RCX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2698 { BS3_CMN_NM(bs3CpuInstr2_pdep_EAX_ECX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2699 { BS3_CMN_NM(bs3CpuInstr2_pdep_EAX_ECX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2700 };
2701 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI2, 0, 0);
2702}
2703
2704
2705/** @note Same note as for bs3CpuInstr2_pdep */
2706BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_pext)(uint8_t bMode)
2707{
2708 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2709 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2710 { /* Mask (RBX/[FS:xBX]), source=RCX */
2711 { 0, 0, /* -> */ 0, 0 },
2712 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2713 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2714 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)0, 0 },
2715#if ARCH_BITS >= 64
2716 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)0, /* -> */ UINT64_C(0x00000000007fffff), 0 },
2717 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)7, /* -> */ UINT64_C(0x00000000007ffffe), 0 },
2718#endif
2719 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x000007ff), 0 },
2720 { UINT32_C(0x47589201), ~(RTCCUINTXREG)7, /* -> */ UINT32_C(0x000007fe), 0 },
2721 };
2722
2723 /* 32-bit register width */
2724 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2725 { /* Mask (EBX/[FS:xBX]), source=ECX */
2726 { 0, 0, /* -> */ 0, 0 },
2727 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2728 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2729 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ UINT32_MAX, 0 },
2730 { UINT32_C(0x01010101), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x0000000f), 0 },
2731 { UINT32_C(0x01010101), ~(RTCCUINTXREG)3, /* -> */ UINT32_C(0x0000000e), 0 },
2732 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x000007ff), 0 },
2733 { UINT32_C(0x47589201), ~(RTCCUINTXREG)7, /* -> */ UINT32_C(0x000007fe), 0 },
2734 };
2735
2736 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2737 {
2738 { BS3_CMN_NM(bs3CpuInstr2_pext_RAX_RCX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2739 { BS3_CMN_NM(bs3CpuInstr2_pext_RAX_RCX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2740 { BS3_CMN_NM(bs3CpuInstr2_pext_EAX_ECX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2741 { BS3_CMN_NM(bs3CpuInstr2_pext_EAX_ECX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2742 };
2743 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI2, 0, 0);
2744}
2745
2746
2747BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shlx)(uint8_t bMode)
2748{
2749 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2750 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2751 {
2752 { 0, 0, /* -> */ 0, 0 },
2753 { 0, ~(RTCCUINTXREG)3, /* -> */ 0, 0 },
2754 { ~(RTCCUINTXREG)7, 8, /* -> */ ~(RTCCUINTXREG)0x7ff, 0},
2755 { ~(RTCCUINTXREG)7, 40, /* -> */ ~(RTCCUINTXREG)7 << (ARCH_BITS == 64 ? 40 : 8), 0 },
2756 { ~(RTCCUINTXREG)7, 72, /* -> */ ~(RTCCUINTXREG)7 << 8, 0 },
2757 };
2758
2759 /* 32-bit register width */
2760 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2761 {
2762 { 0, 0, /* -> */ 0, 0 },
2763 { 0, ~(RTCCUINTXREG)9, /* -> */ 0, 0 },
2764 { ~(RTCCUINTXREG)7, 8, /* -> */ UINT32_C(0xfffff800), 0 },
2765 { ~(RTCCUINTXREG)7, 8, /* -> */ UINT32_C(0xfffff800), 0 },
2766 };
2767
2768 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2769 {
2770 { BS3_CMN_NM(bs3CpuInstr2_shlx_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2771 { BS3_CMN_NM(bs3CpuInstr2_shlx_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2772 { BS3_CMN_NM(bs3CpuInstr2_shlx_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2773 { BS3_CMN_NM(bs3CpuInstr2_shlx_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2774 };
2775 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2776 0, 0);
2777}
2778
2779
2780BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_sarx)(uint8_t bMode)
2781{
2782 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2783 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2784 {
2785 { 0, 0, /* -> */ 0, 0 },
2786 { 0, ~(RTCCUINTXREG)3, /* -> */ 0, 0 },
2787 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1, /* -> */ ~(RTCCUINTXREG)0, 0 },
2788 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1 + 64, /* -> */ ~(RTCCUINTXREG)0, 0 },
2789 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3, /* -> */ 2, 0 },
2790 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3 + 64, /* -> */ 2, 0 },
2791 };
2792
2793 /* 32-bit register width */
2794 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2795 {
2796 { 0, 0, /* -> */ 0, 0 },
2797 { 0, ~(RTCCUINTXREG)9, /* -> */ 0, 0 },
2798 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24, /* -> */ UINT32_C(0xffffff80), 0 },
2799 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24+32, /* -> */ UINT32_C(0xffffff80), 0 },
2800 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24, /* -> */ UINT32_C(0x40), 0 },
2801 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24+32, /* -> */ UINT32_C(0x40), 0 },
2802 };
2803
2804 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2805 {
2806 { BS3_CMN_NM(bs3CpuInstr2_sarx_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2807 { BS3_CMN_NM(bs3CpuInstr2_sarx_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2808 { BS3_CMN_NM(bs3CpuInstr2_sarx_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2809 { BS3_CMN_NM(bs3CpuInstr2_sarx_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2810 };
2811 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2812 0, 0);
2813}
2814
2815
2816BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shrx)(uint8_t bMode)
2817{
2818 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2819 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2820 {
2821 { 0, 0, /* -> */ 0, 0 },
2822 { 0, ~(RTCCUINTXREG)3, /* -> */ 0, 0 },
2823 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1, /* -> */ 1, 0 },
2824 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1 + 64, /* -> */ 1, 0 },
2825 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3, /* -> */ 2, 0 },
2826 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3 + 64, /* -> */ 2, 0 },
2827 };
2828
2829 /* 32-bit register width */
2830 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2831 {
2832 { 0, 0, /* -> */ 0, 0 },
2833 { 0, ~(RTCCUINTXREG)9, /* -> */ 0, 0 },
2834 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24, /* -> */ UINT32_C(0x80), 0 },
2835 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24+32, /* -> */ UINT32_C(0x80), 0 },
2836 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24, /* -> */ UINT32_C(0x40), 0 },
2837 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24+32, /* -> */ UINT32_C(0x40), 0 },
2838 };
2839
2840 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2841 {
2842 { BS3_CMN_NM(bs3CpuInstr2_shrx_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2843 { BS3_CMN_NM(bs3CpuInstr2_shrx_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2844 { BS3_CMN_NM(bs3CpuInstr2_shrx_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2845 { BS3_CMN_NM(bs3CpuInstr2_shrx_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2846 };
2847 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2848 0, 0);
2849}
2850
2851
2852/*
2853 * For testing BLSR, BLSMSK, and BLSI.
2854 */
2855typedef struct BS3CPUINSTR2_SUBTEST_By_Ey_T
2856{
2857 RTCCUINTXREG uSrc;
2858 RTCCUINTXREG uDst;
2859 uint16_t fEflOut;
2860} BS3CPUINSTR2_SUBTEST_By_Ey_T;
2861
2862typedef struct BS3CPUINSTR2_TEST_By_Ey_T
2863{
2864 FPFNBS3FAR pfnWorker;
2865 bool fMemSrc;
2866 uint8_t cbInstr;
2867 uint8_t cSubTests;
2868 BS3CPUINSTR2_SUBTEST_By_Ey_T const *paSubTests;
2869} BS3CPUINSTR2_TEST_By_Ey_T;
2870
2871static uint8_t bs3CpuInstr2_Common_By_Ey(uint8_t bMode, BS3CPUINSTR2_TEST_By_Ey_T const *paTests, unsigned cTests,
2872 uint32_t fStdExtFeatEbx, uint16_t fEflCheck, uint16_t fEflIgnore)
2873{
2874 BS3REGCTX Ctx;
2875 BS3TRAPFRAME TrapFrame;
2876 unsigned i, j, k;
2877 uint32_t uStdExtFeatEbx = 0;
2878 bool fSupportsInstr;
2879
2880 fEflCheck &= ~fEflIgnore;
2881
2882 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2883 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2884 fSupportsInstr = RT_BOOL(uStdExtFeatEbx & fStdExtFeatEbx);
2885
2886 /* Ensure the structures are allocated before we sample the stack pointer. */
2887 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2888 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2889
2890 /*
2891 * Create test context.
2892 */
2893 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2894
2895 /*
2896 * Do the tests twice, first with all flags set, then once again with
2897 * flags cleared. The flags are not supposed to be touched at all.
2898 */
2899 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2900 for (j = 0; j < 2; j++)
2901 {
2902 for (i = 0; i < cTests; i++)
2903 {
2904 for (k = 0; k < paTests[i].cSubTests; k++)
2905 {
2906 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsInstr;
2907 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2908 uint64_t uExpectRax, uExpectRip;
2909 RTCCUINTXREG uMemSrc, uMemSrcExpect;
2910
2911 Ctx.rax.uCcXReg = ~paTests[i].paSubTests[k].uSrc ^ 0x593e7591;
2912 if (!paTests[i].fMemSrc)
2913 {
2914 Ctx.rbx.uCcXReg = paTests[i].paSubTests[k].uSrc;
2915 uMemSrcExpect = uMemSrc = ~paTests[i].paSubTests[k].uSrc;
2916 }
2917 else
2918 {
2919 uMemSrcExpect = uMemSrc = paTests[i].paSubTests[k].uSrc;
2920 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
2921 }
2922 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paTests[i].pfnWorker);
2923 uExpectRax = fOkay ? paTests[i].paSubTests[k].uDst : Ctx.rax.u;
2924 uExpectRip = Ctx.rip.u + (fOkay ? paTests[i].cbInstr + 1 : 0);
2925 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2926
2927 if ( TrapFrame.bXcpt != bExpectXcpt
2928 || TrapFrame.Ctx.rip.u != uExpectRip
2929 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
2930 || TrapFrame.Ctx.rax.u != uExpectRax
2931 /* check that nothing else really changed: */
2932 || (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2933 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck)
2934 || (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2935 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2936 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2937 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2938 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2939 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2940 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2941 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2942 || uMemSrc != uMemSrcExpect
2943 )
2944 {
2945 Bs3TestFailedF("test #%i/%i failed: input %#" RTCCUINTXREG_XFMT,
2946 i, k, paTests[i].paSubTests[k].uSrc);
2947 if (TrapFrame.bXcpt != bExpectXcpt)
2948 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2949 if (TrapFrame.Ctx.rip.u != uExpectRip)
2950 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2951 if (TrapFrame.Ctx.rax.u != uExpectRax)
2952 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
2953 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
2954 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
2955 if ( (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2956 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck))
2957 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
2958 (fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck,
2959 TrapFrame.Ctx.rflags.u16 & fEflCheck);
2960 if ( (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2961 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS))
2962 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
2963 Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS,
2964 TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS);
2965
2966 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2967 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2968 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2969 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2970 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2971 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2972 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2973 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2974 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2975 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2976 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2977 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2978 if (uMemSrc != uMemSrcExpect)
2979 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
2980 }
2981 }
2982 }
2983 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2984 }
2985
2986 return 0;
2987}
2988
2989
2990BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_blsr)(uint8_t bMode)
2991{
2992 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2993 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests64[] =
2994 {
2995 { 0, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
2996 { 1, /* -> */ 0, X86_EFL_ZF },
2997 { 2, /* -> */ 0, X86_EFL_ZF },
2998 { 3, /* -> */ 2, 0 },
2999 { 5, /* -> */ 4, 0 },
3000 { 6, /* -> */ 4, 0 },
3001 { 7, /* -> */ 6, 0 },
3002 { 9, /* -> */ 8, 0 },
3003 { 10, /* -> */ 8, 0 },
3004 { ~(RTCCUINTXREG)1, /* -> */ ~(RTCCUINTXREG)3, X86_EFL_SF },
3005 { (RTCCUINTXREG)3 << (RTCCINTXREG_BITS - 2), /* -> */ (RTCCUINTXREG)2 << (RTCCINTXREG_BITS - 2), X86_EFL_SF },
3006 };
3007
3008 /* 32-bit register width */
3009 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests32[] =
3010 {
3011 { 0, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
3012 { 1, /* -> */ 0, X86_EFL_ZF },
3013 { ~(RTCCUINTXREG)1, /* -> */ UINT32_C(0xfffffffc), X86_EFL_SF },
3014 { ~(RTCCUINTXREG)0 << 30, /* -> */ UINT32_C(0x80000000), X86_EFL_SF },
3015 };
3016
3017 static BS3CPUINSTR2_TEST_By_Ey_T const s_aTests[] =
3018 {
3019 { BS3_CMN_NM(bs3CpuInstr2_blsr_RAX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3020 { BS3_CMN_NM(bs3CpuInstr2_blsr_RAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3021 { BS3_CMN_NM(bs3CpuInstr2_blsr_EAX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3022 { BS3_CMN_NM(bs3CpuInstr2_blsr_EAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3023 };
3024 return bs3CpuInstr2_Common_By_Ey(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
3025 X86_EFL_STATUS_BITS, 0);
3026}
3027
3028
3029BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_blsmsk)(uint8_t bMode)
3030{
3031 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
3032 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests64[] =
3033 {
3034 { 0, /* -> */ ~(RTCCUINTXREG)0, X86_EFL_CF | X86_EFL_SF },
3035 { 1, /* -> */ 1, 0 },
3036 { ~(RTCCUINTXREG)1, /* -> */ 3, 0 },
3037 { (RTCCUINTXREG)3 << (RTCCINTXREG_BITS - 2), /* -> */ ~((RTCCUINTXREG)2 << (RTCCINTXREG_BITS - 2)), 0 },
3038 };
3039
3040 /* 32-bit register width */
3041 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests32[] =
3042 {
3043 { 0, /* -> */ UINT32_MAX, X86_EFL_CF | X86_EFL_SF },
3044 { 1, /* -> */ 1, 0 },
3045 { ~(RTCCUINTXREG)1, /* -> */ 3, 0 },
3046 { ~(RTCCUINTXREG)0 << 30, /* -> */ UINT32_C(0x7fffffff), 0},
3047 };
3048
3049 static BS3CPUINSTR2_TEST_By_Ey_T const s_aTests[] =
3050 {
3051 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_RAX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3052 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_RAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3053 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_EAX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3054 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_EAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3055 };
3056 return bs3CpuInstr2_Common_By_Ey(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
3057 X86_EFL_STATUS_BITS, 0);
3058}
3059
3060
3061BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_blsi)(uint8_t bMode)
3062{
3063 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
3064 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests64[] =
3065 {
3066 { 0, /* -> */ 0, X86_EFL_ZF },
3067 { 1, /* -> */ 1, X86_EFL_CF },
3068 { ~(RTCCUINTXREG)1, /* -> */ 2, X86_EFL_CF },
3069 { (RTCCUINTXREG)3 << (RTCCINTXREG_BITS - 2), /* -> */ (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), X86_EFL_CF },
3070 };
3071
3072 /* 32-bit register width */
3073 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests32[] =
3074 {
3075 { 0, /* -> */ 0, X86_EFL_ZF },
3076 { 1, /* -> */ 1, X86_EFL_CF },
3077 { ~(RTCCUINTXREG)1, /* -> */ 2, X86_EFL_CF },
3078 { ~(RTCCUINTXREG)0 << 30, /* -> */ UINT32_C(0x40000000), X86_EFL_CF },
3079 };
3080
3081 static BS3CPUINSTR2_TEST_By_Ey_T const s_aTests[] =
3082 {
3083 { BS3_CMN_NM(bs3CpuInstr2_blsi_RAX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3084 { BS3_CMN_NM(bs3CpuInstr2_blsi_RAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3085 { BS3_CMN_NM(bs3CpuInstr2_blsi_EAX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3086 { BS3_CMN_NM(bs3CpuInstr2_blsi_EAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3087 };
3088 return bs3CpuInstr2_Common_By_Ey(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
3089 X86_EFL_STATUS_BITS, 0);
3090}
3091
3092
3093/*
3094 * MULX (BMI2) - destination registers (/r & vvvv) = r/m * rDX
3095 */
3096BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mulx)(uint8_t bMode)
3097{
3098 static const struct
3099 {
3100 FPFNBS3FAR pfnWorker;
3101 bool fMemSrc;
3102 bool fSameDst;
3103 uint8_t cbInstr;
3104 RTCCUINTXREG uSrc1;
3105 RTCCUINTXREG uSrc2;
3106 RTCCUINTXREG uDst1;
3107 RTCCUINTXREG uDst2;
3108 } s_aTests[] =
3109 {
3110 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
3111 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #0
3112 0, 0, /* -> */ 0, 0 },
3113 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #1
3114 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)1, 1 },
3115 { BS3_CMN_NM(bs3CpuInstr2_mulx_RCX_RCX_RBX_RDX_icebp), false, true, 5, // #2
3116 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)1, ~(RTCCUINTXREG)1 },
3117 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #3
3118 2, 2, /* -> */ 0, 4 },
3119 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #4
3120 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(RTCCUINTXREG)41 },
3121
3122 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_FSxBX_RDX_icebp), true, false, 6, // #5
3123 0, 0, /* -> */ 0, 0 },
3124 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_FSxBX_RDX_icebp), true, false, 6, // #6
3125 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)1, 1 },
3126 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_FSxBX_RDX_icebp), true, false, 6, // #7
3127 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(RTCCUINTXREG)41 },
3128
3129 /* 32-bit register width */
3130 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #8
3131 0, 0, /* -> */ 0, 0 },
3132 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #9
3133 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(uint32_t)1, 1 },
3134 { BS3_CMN_NM(bs3CpuInstr2_mulx_ECX_ECX_EBX_EDX_icebp), false, true, 5, // #10
3135 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(uint32_t)1, ~(uint32_t)1 },
3136 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #11
3137 2, 2, /* -> */ 0, 4 },
3138 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #12
3139 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(uint32_t)41 },
3140
3141 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_FSxBX_EDX_icebp), true, false, 6, // #13
3142 0, 0, /* -> */ 0, 0 },
3143 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_FSxBX_EDX_icebp), true, false, 6, // #14
3144 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(uint32_t)1, 1 },
3145 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_FSxBX_EDX_icebp), true, false, 6, // #15
3146 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(uint32_t)41 },
3147 };
3148
3149 BS3REGCTX Ctx;
3150 BS3TRAPFRAME TrapFrame;
3151 unsigned i, j;
3152 uint32_t uStdExtFeatEbx = 0;
3153 bool fSupportsAndN;
3154
3155 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3156 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
3157 fSupportsAndN = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI2);
3158
3159 /* Ensure the structures are allocated before we sample the stack pointer. */
3160 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3161 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3162
3163 /*
3164 * Create test context.
3165 */
3166 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3167
3168 /*
3169 * Do the tests twice, first with all flags set, then once again with
3170 * flags cleared. The flags are not supposed to be touched at all.
3171 */
3172 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3173 for (j = 0; j < 2; j++)
3174 {
3175 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3176 {
3177 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsAndN;
3178 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3179 uint64_t uExpectRax, uExpectRcx, uExpectRip;
3180 RTCCUINTXREG uMemSrc1, uMemSrc1Expect;
3181
3182 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
3183 Ctx.rcx.uCcXReg = RTCCUINTXREG_MAX * 4095;
3184 Ctx.rdx.uCcXReg = s_aTests[i].uSrc2;
3185 if (!s_aTests[i].fMemSrc)
3186 {
3187 Ctx.rbx.uCcXReg = s_aTests[i].uSrc1;
3188 uMemSrc1Expect = uMemSrc1 = ~s_aTests[i].uSrc1;
3189 }
3190 else
3191 {
3192 uMemSrc1Expect = uMemSrc1 = s_aTests[i].uSrc1;
3193 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc1);
3194 }
3195 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3196 uExpectRax = fOkay && !s_aTests[i].fSameDst ? s_aTests[i].uDst1 : Ctx.rax.u;
3197 uExpectRcx = fOkay ? s_aTests[i].uDst2 : Ctx.rcx.u;
3198 uExpectRip = Ctx.rip.u + (fOkay ? s_aTests[i].cbInstr + 1 : 0);
3199 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3200
3201 if ( TrapFrame.bXcpt != bExpectXcpt
3202 || TrapFrame.Ctx.rip.u != uExpectRip
3203 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3204 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3205 || TrapFrame.Ctx.rax.u != uExpectRax
3206 || TrapFrame.Ctx.rcx.u != uExpectRcx
3207 /* check that nothing else really changed: */
3208 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS)
3209 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3210 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3211 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3212 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3213 || uMemSrc1 != uMemSrc1Expect
3214 )
3215 {
3216 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT ", %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uSrc1, s_aTests[i].uSrc2);
3217 if (TrapFrame.bXcpt != bExpectXcpt)
3218 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3219 if (TrapFrame.Ctx.rip.u != uExpectRip)
3220 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3221 if (TrapFrame.Ctx.rax.u != uExpectRax)
3222 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3223 if (TrapFrame.Ctx.rcx.u != uExpectRcx)
3224 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", uExpectRcx, TrapFrame.Ctx.rcx.u);
3225 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3226 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3227 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3228 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3229
3230 if ( (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS))
3231 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
3232 Ctx.rflags.u16 & X86_EFL_STATUS_BITS, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
3233 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3234 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3235 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3236 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3237 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3238 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3239 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3240 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3241 if (uMemSrc1 != uMemSrc1Expect)
3242 Bs3TestFailedF("Expected uMemSrc1 = %#06RX64, got %#06RX64", (uint64_t)uMemSrc1Expect, (uint64_t)uMemSrc1);
3243 }
3244 }
3245 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3246 }
3247
3248 return 0;
3249}
3250
3251
3252/*
3253 * POPCNT - Intel: POPCNT; AMD: ABM.
3254 */
3255BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_popcnt)(uint8_t bMode)
3256{
3257 static const struct
3258 {
3259 FPFNBS3FAR pfnWorker;
3260 bool fMemSrc;
3261 uint8_t cWidth;
3262 uint8_t cbInstr;
3263 RTCCUINTXREG uSrc;
3264 RTCCUINTXREG uDst;
3265 uint16_t fEFlags;
3266 } s_aTests[] =
3267 {
3268 /* 16-bit register width */
3269 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #0
3270 0, /* -> */ 0, X86_EFL_ZF },
3271 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #1
3272 ~(RTCCUINTXREG)0, /* -> */ 16, 0 },
3273 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #2
3274 UINT16_C(0xffff), /* -> */ 16, 0 },
3275 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #3
3276 UINT16_C(0x0304), /* -> */ 3, 0 },
3277 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_FSxBX_icebp), true, 16, 5 + (ARCH_BITS != 16), // #4
3278 UINT16_C(0xd569), /* -> */ 9, 0},
3279 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_FSxBX_icebp), true, 16, 5 + (ARCH_BITS != 16), // #5
3280 0, /* -> */ 0, X86_EFL_ZF },
3281
3282 /* 32-bit register width */
3283 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_EBX_icebp), false, 32, 4 + (ARCH_BITS == 16), // #6
3284 0, /* -> */ 0, X86_EFL_ZF },
3285 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_EBX_icebp), false, 32, 4 + (ARCH_BITS == 16), // #7
3286 ~(RTCCUINTXREG)0, /* -> */ 32, 0},
3287 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_EBX_icebp), false, 32, 4 + (ARCH_BITS == 16), // #8
3288 UINT32_C(0x01020304), /* -> */ 5, 0},
3289 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_FSxBX_icebp), true, 32, 5 + (ARCH_BITS == 16), // #9
3290 0, /* -> */ 0, X86_EFL_ZF },
3291 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_FSxBX_icebp), true, 32, 5 + (ARCH_BITS == 16), // #10
3292 UINT32_C(0x49760948), /* -> */ 12, 0 },
3293
3294#if ARCH_BITS == 64
3295 /* 64-bit register width */
3296 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_RBX_icebp), false, 64, 5, // #11
3297 0, /* -> */ 0, X86_EFL_ZF },
3298 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_RBX_icebp), false, 64, 5, // #12
3299 ~(RTCCUINTXREG)0, /* -> */ 64, 0 },
3300 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_RBX_icebp), false, 64, 5, // #13
3301 UINT64_C(0x1234123412341234), /* -> */ 5*4, 0 },
3302 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_FSxBX_icebp), true, 64, 6, // #14
3303 0, /* -> */ 0, X86_EFL_ZF },
3304 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_FSxBX_icebp), true, 64, 6, // #15
3305 ~(RTCCUINTXREG)0, /* -> */ 64, 0 },
3306 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_FSxBX_icebp), true, 64, 6, // #16
3307 UINT64_C(0x5908760293769087), /* -> */ 26, 0 },
3308#endif
3309 };
3310
3311 BS3REGCTX Ctx;
3312 BS3TRAPFRAME TrapFrame;
3313 unsigned i, j;
3314 bool const fSupportsPopCnt = (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3315 && (ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_POPCNT);
3316
3317 /* Ensure the structures are allocated before we sample the stack pointer. */
3318 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3319 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3320
3321 /*
3322 * Create test context.
3323 */
3324 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3325
3326 /*
3327 * Do the tests twice, first with all flags set, then once again with
3328 * flags cleared. The flags are not supposed to be touched at all.
3329 */
3330 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3331 for (j = 0; j < 2; j++)
3332 {
3333 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3334 {
3335 bool const fOkay = fSupportsPopCnt;
3336 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3337 uint64_t uExpectRax, uExpectRip;
3338 RTCCUINTXREG uMemSrc, uMemSrcExpect;
3339
3340 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
3341 if (!s_aTests[i].fMemSrc)
3342 {
3343 Ctx.rbx.uCcXReg = s_aTests[i].uSrc;
3344 uMemSrcExpect = uMemSrc = ~s_aTests[i].uSrc;
3345 }
3346 else
3347 {
3348 uMemSrcExpect = uMemSrc = s_aTests[i].uSrc;
3349 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
3350 }
3351 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3352 uExpectRax = fOkay ? s_aTests[i].uDst : Ctx.rax.u;
3353 if (s_aTests[i].cWidth == 16)
3354 uExpectRax = (uExpectRax & UINT16_MAX) | (Ctx.rax.u & ~(uint64_t)UINT16_MAX);
3355
3356 uExpectRip = Ctx.rip.u + (fOkay ? s_aTests[i].cbInstr + 1 : 0);
3357 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3358
3359 if ( TrapFrame.bXcpt != bExpectXcpt
3360 || TrapFrame.Ctx.rip.u != uExpectRip
3361 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3362 || TrapFrame.Ctx.rax.u != uExpectRax
3363 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16)
3364 /* check that nothing else really changed: */
3365 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
3366 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3367 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3368 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3369 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3370 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3371 || uMemSrc != uMemSrcExpect
3372 )
3373 {
3374 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uSrc);
3375 if (TrapFrame.bXcpt != bExpectXcpt)
3376 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3377 if (TrapFrame.Ctx.rip.u != uExpectRip)
3378 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3379 if (TrapFrame.Ctx.rax.u != uExpectRax)
3380 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3381 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3382 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3383 if ((TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16))
3384 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32",
3385 fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
3386
3387 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
3388 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
3389 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3390 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3391 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3392 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3393 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3394 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3395 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3396 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3397 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3398 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3399 if (uMemSrc != uMemSrcExpect)
3400 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
3401 }
3402 }
3403 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3404 }
3405
3406 return 0;
3407}
3408
3409/*
3410 * CRC32 - SSE4.2
3411 */
3412BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_crc32)(uint8_t bMode)
3413{
3414 typedef struct BS3CPUINSTR2_CRC32_VALUES_T
3415 {
3416 uint32_t uDstIn;
3417 uint32_t uDstOut;
3418 uint64_t uSrc;
3419 } BS3CPUINSTR2_CRC32_VALUES_T;
3420 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues1[] =
3421 {
3422 { UINT32_C(0000000000), UINT32_C(0000000000), UINT8_C(0000) },
3423 { UINT32_C(0xffffffff), UINT32_C(0x25502c8c), UINT8_C(0xea) },
3424 { UINT32_C(0x25502c8c), UINT32_C(0x474224a6), UINT8_C(0xea) },
3425 { UINT32_C(0x474224a6), UINT32_C(0x0c7f9048), UINT8_C(0xea) },
3426 { UINT32_C(0x0c7f9048), UINT32_C(0x39c5b9e0), UINT8_C(0x01) },
3427 { UINT32_C(0x39c5b9e0), UINT32_C(0x2493fabc), UINT8_C(0x04) },
3428 { UINT32_C(0x2493fabc), UINT32_C(0x0b05c4d6), UINT8_C(0x27) },
3429 { UINT32_C(0x0b05c4d6), UINT32_C(0xbe26a561), UINT8_C(0x2a) },
3430 { UINT32_C(0xbe26a561), UINT32_C(0xe1855652), UINT8_C(0x63) },
3431 { UINT32_C(0xe1855652), UINT32_C(0xc67efe3f), UINT8_C(0xa7) },
3432 { UINT32_C(0xc67efe3f), UINT32_C(0x227028cd), UINT8_C(0xfd) },
3433 { UINT32_C(0x227028cd), UINT32_C(0xf4559a1d), UINT8_C(0xea) },
3434 };
3435 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues2[] =
3436 {
3437 { UINT32_C(0000000000), UINT32_C(0000000000), UINT16_C(000000) },
3438 { UINT32_C(0xffffffff), UINT32_C(0xd550e2a0), UINT16_C(0x04d2) },
3439 { UINT32_C(0xd550e2a0), UINT32_C(0x38e07a0a), UINT16_C(0xe8cc) },
3440 { UINT32_C(0x38e07a0a), UINT32_C(0x60ebd519), UINT16_C(0x82a2) },
3441 { UINT32_C(0x60ebd519), UINT32_C(0xaaa127b5), UINT16_C(0x0fff) },
3442 { UINT32_C(0xaaa127b5), UINT32_C(0xb13175c6), UINT16_C(0x00ff) },
3443 { UINT32_C(0xb13175c6), UINT32_C(0x3a226f1b), UINT16_C(0x0300) },
3444 { UINT32_C(0x3a226f1b), UINT32_C(0xbaedef0c), UINT16_C(0x270f) },
3445 { UINT32_C(0xbaedef0c), UINT32_C(0x2d18866e), UINT16_C(0x3ff6) },
3446 { UINT32_C(0x2d18866e), UINT32_C(0x07e2e954), UINT16_C(0x9316) },
3447 { UINT32_C(0x07e2e954), UINT32_C(0x95f82acb), UINT16_C(0xa59c) },
3448 };
3449 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues4[] =
3450 {
3451 { UINT32_C(0000000000), UINT32_C(0000000000), UINT32_C(0000000000) },
3452 { UINT32_C(0xffffffff), UINT32_C(0xc9a7250e), UINT32_C(0x0270fa68) },
3453 { UINT32_C(0xc9a7250e), UINT32_C(0x7340d175), UINT32_C(0x23729736) },
3454 { UINT32_C(0x7340d175), UINT32_C(0x7e17b67d), UINT32_C(0x8bc75d35) },
3455 { UINT32_C(0x7e17b67d), UINT32_C(0x5028eb71), UINT32_C(0x0e9bebf2) },
3456 { UINT32_C(0x5028eb71), UINT32_C(0xc0a7f45a), UINT32_C(0x000001bc) },
3457 { UINT32_C(0xc0a7f45a), UINT32_C(0xa96f4012), UINT32_C(0x0034ba02) },
3458 { UINT32_C(0xa96f4012), UINT32_C(0xb27c0718), UINT32_C(0x0000002a) },
3459 { UINT32_C(0xb27c0718), UINT32_C(0x79fb2d35), UINT32_C(0x0153158e) },
3460 { UINT32_C(0x79fb2d35), UINT32_C(0x23434fc9), UINT32_C(0x02594882) },
3461 { UINT32_C(0x23434fc9), UINT32_C(0x354bf3b6), UINT32_C(0xb230b8f3) },
3462 };
3463#if ARCH_BITS >= 64
3464 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues8[] =
3465 {
3466 { UINT32_C(0000000000), UINT32_C(0000000000), UINT64_C(000000000000000000) },
3467 { UINT32_C(0xffffffff), UINT32_C(0xadc36834), UINT64_C(0x02b0b5e2a975c1cc) },
3468 { UINT32_C(0xadc36834), UINT32_C(0xf0e893c9), UINT64_C(0x823d386bf7517583) },
3469 { UINT32_C(0xf0e893c9), UINT32_C(0x1a22a837), UINT64_C(0x0481f5311fa061d0) },
3470 { UINT32_C(0x1a22a837), UINT32_C(0xcf8b6d61), UINT64_C(0x13fa70f64d52a92d) },
3471 { UINT32_C(0xcf8b6d61), UINT32_C(0xc7dde203), UINT64_C(0x3ccc8b035903d3e1) },
3472 { UINT32_C(0xc7dde203), UINT32_C(0xd42b5823), UINT64_C(0x0000011850ec2fac) },
3473 { UINT32_C(0xd42b5823), UINT32_C(0x8b1ce49e), UINT64_C(0x0000000000001364) },
3474 { UINT32_C(0x8b1ce49e), UINT32_C(0x1af31710), UINT64_C(0x000000057840205a) },
3475 { UINT32_C(0x1af31710), UINT32_C(0xdea35e8b), UINT64_C(0x2e5d93688d9a0bfa) },
3476 { UINT32_C(0xdea35e8b), UINT32_C(0x594c013a), UINT64_C(0x8ac7230489e7ffff) },
3477 { UINT32_C(0x594c013a), UINT32_C(0x27b061e5), UINT64_C(0x6bf037ae325f1c71) },
3478 { UINT32_C(0x27b061e5), UINT32_C(0x3120b5f7), UINT64_C(0x0fffffff34503556) },
3479 };
3480#endif
3481 static const struct
3482 {
3483 FPFNBS3FAR pfnWorker;
3484 bool fMemSrc;
3485 uint8_t cbOp;
3486 uint8_t cValues;
3487 BS3CPUINSTR2_CRC32_VALUES_T const BS3_FAR *paValues;
3488 } s_aTests[] =
3489 {
3490 /* 8-bit register width */
3491 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_BL_icebp), false, 1, RT_ELEMENTS(s_aValues1), s_aValues1 },
3492 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_byte_FSxBX_icebp), true, 1, RT_ELEMENTS(s_aValues1), s_aValues1 },
3493
3494 /* 16-bit register width */
3495 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_BX_icebp), false, 2, RT_ELEMENTS(s_aValues2), s_aValues2 },
3496 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_word_FSxBX_icebp), true, 2, RT_ELEMENTS(s_aValues2), s_aValues2 },
3497
3498 /* 32-bit register width */
3499 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_EBX_icebp), false, 4, RT_ELEMENTS(s_aValues4), s_aValues4 },
3500 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_dword_FSxBX_icebp), true, 4, RT_ELEMENTS(s_aValues4), s_aValues4 },
3501#if ARCH_BITS >= 64
3502 /* 32-bit register width */
3503 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_RBX_icebp), false, 8, RT_ELEMENTS(s_aValues8), s_aValues8 },
3504 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_qword_FSxBX_icebp), true, 8, RT_ELEMENTS(s_aValues8), s_aValues8 },
3505#endif
3506 };
3507
3508 BS3REGCTX Ctx;
3509 BS3TRAPFRAME TrapFrame;
3510 unsigned i, j;
3511 bool const fSupportsCrc32 = (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3512 && (ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_SSE4_2);
3513
3514 /* Ensure the structures are allocated before we sample the stack pointer. */
3515 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3516 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3517
3518 /*
3519 * Create test context.
3520 */
3521 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3522
3523 /*
3524 * Do the tests twice, first with all flags set, then once again with
3525 * flags cleared. The flags are not supposed to be touched at all.
3526 */
3527 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3528 for (j = 0; j < 2; j++)
3529 {
3530 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3531 {
3532 uint8_t const cbOp = s_aTests[i].cbOp;
3533 unsigned const cValues = s_aTests[i].cValues;
3534 BS3CPUINSTR2_CRC32_VALUES_T const BS3_FAR *paValues = s_aTests[i].paValues;
3535 unsigned iValue;
3536 bool const fOkay = fSupportsCrc32;
3537 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3538 uint64_t const uSrcGarbage = ( cbOp == 1 ? UINT64_C(0x03948314d0f03400)
3539 : cbOp == 2 ? UINT64_C(0x03948314d0f00000)
3540 : cbOp == 4 ? UINT64_C(0x0394831000000000) : 0)
3541 & (ARCH_BITS >= 64 ? UINT64_MAX : UINT32_MAX);
3542 uint64_t uExpectRip;
3543
3544 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3545 uExpectRip = Ctx.rip.u + (fOkay ? ((uint8_t const BS3_FAR *)s_aTests[i].pfnWorker)[-1] + 1 : 0);
3546
3547 for (iValue = 0; iValue < cValues; iValue++)
3548 {
3549 uint64_t const uExpectRax = fOkay ? paValues[iValue].uDstOut : paValues[iValue].uDstIn;
3550 uint64_t uMemSrc, uMemSrcExpect;
3551
3552 Ctx.rax.uCcXReg = paValues[iValue].uDstIn;
3553 if (!s_aTests[i].fMemSrc)
3554 {
3555 Ctx.rbx.u64 = paValues[iValue].uSrc | uSrcGarbage;
3556 uMemSrcExpect = uMemSrc = ~(paValues[iValue].uSrc | uSrcGarbage);
3557 }
3558 else
3559 {
3560 uMemSrcExpect = uMemSrc = paValues[iValue].uSrc | uSrcGarbage;
3561 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
3562 }
3563
3564 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3565
3566 if ( TrapFrame.bXcpt != bExpectXcpt
3567 || TrapFrame.Ctx.rip.u != uExpectRip
3568 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3569 || TrapFrame.Ctx.rax.u != uExpectRax
3570 /* check that nothing else really changed: */
3571 || TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16
3572 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
3573 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3574 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3575 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3576 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3577 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3578 || uMemSrc != uMemSrcExpect
3579 )
3580 {
3581 Bs3TestFailedF("test #%i value #%i failed: input %#RX32, %#RX64",
3582 i, iValue, paValues[iValue].uDstIn, paValues[iValue].uSrc);
3583 if (TrapFrame.bXcpt != bExpectXcpt)
3584 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3585 if (TrapFrame.Ctx.rip.u != uExpectRip)
3586 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3587 if (TrapFrame.Ctx.rax.u != uExpectRax)
3588 Bs3TestFailedF("Expected RAX = %#010RX64, got %#010RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3589 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3590 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3591
3592 if (TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16)
3593 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32", Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16);
3594 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
3595 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
3596 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3597 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3598 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3599 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3600 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3601 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3602 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3603 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3604 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3605 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3606 if (uMemSrc != uMemSrcExpect)
3607 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
3608 }
3609 }
3610 }
3611 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3612 }
3613
3614 return 0;
3615}
3616
3617#if 0 /* Program for generating CRC32 value sets: */
3618#include <stdio.h>
3619#include <stdint.h>
3620#include <stdlib.h>
3621
3622int main(int argc, char **argv)
3623{
3624 int cbOp = atoi(argv[1]);
3625 uint32_t uBefore = atoi(argv[2]);
3626 int i = 3;
3627 while (i < argc)
3628 {
3629 unsigned long long uValue = strtoull(argv[i], NULL, 0);
3630 uint32_t uAfter = uBefore;
3631 switch (cbOp)
3632 {
3633 case 1:
3634 __asm__ __volatile__("crc32b %2, %0" : "=r" (uAfter) : "0" (uAfter), "r" ((uint8_t)uValue));
3635 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT8_C(%#04x) },\n",
3636 uBefore, uAfter, (unsigned)(uint8_t)uValue);
3637 break;
3638 case 2:
3639 __asm__ __volatile__("crc32w %2, %0" : "=r" (uAfter) : "0" (uAfter), "r" ((uint16_t)uValue));
3640 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT16_C(%#06x) },\n",
3641 uBefore, uAfter, (unsigned)(uint16_t)uValue);
3642 break;
3643 case 4:
3644 __asm__ __volatile__("crc32l %2, %0" : "=r" (uAfter) : "0" (uAfter), "r" ((uint32_t)uValue));
3645 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT32_C(%#010x) },\n",
3646 uBefore, uAfter, (uint32_t)uValue);
3647 break;
3648 case 8:
3649 {
3650 uint64_t u64After = uBefore;
3651 __asm__ __volatile__("crc32q %2, %0" : "=r" (u64After) : "0" (u64After), "r" (uValue));
3652 uAfter = (uint32_t)u64After;
3653 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT64_C(%#018llx) },\n", uBefore, uAfter, uValue);
3654 break;
3655 }
3656 }
3657
3658 /* next */
3659 uBefore = uAfter;
3660 i++;
3661 }
3662 return 0;
3663}
3664#endif
3665
3666
3667/*
3668 * ADCX/ADOX - ADX
3669 */
3670BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_adcx_adox)(uint8_t bMode)
3671{
3672 typedef struct BS3CPUINSTR2_ADX_VALUES_T
3673 {
3674 uint64_t uDstOut;
3675 uint64_t uDstIn;
3676 uint64_t uSrc;
3677 bool fFlagIn;
3678 bool fFlagOut;
3679 } BS3CPUINSTR2_ADX_VALUES_T;
3680 static const BS3CPUINSTR2_ADX_VALUES_T s_aValues4[] =
3681 {
3682 { UINT32_C(0000000000), UINT32_C(0000000000), UINT32_C(0000000000), false, false },
3683 { UINT32_C(0000000001), UINT32_C(0000000000), UINT32_C(0000000000), true, false },
3684
3685 { UINT32_C(0xfffffffe), UINT32_MAX / 2, UINT32_MAX / 2, false, false },
3686 { UINT32_C(0xffffffff), UINT32_MAX / 2, UINT32_MAX / 2, true, false },
3687
3688 { UINT32_C(0x7ffffffe), UINT32_MAX, UINT32_MAX / 2, false, true },
3689 { UINT32_C(0x7fffffff), UINT32_MAX, UINT32_MAX / 2, true, true },
3690
3691 { UINT32_C(0x7ffffffe), UINT32_MAX / 2, UINT32_MAX, false, true },
3692 { UINT32_C(0x7fffffff), UINT32_MAX / 2, UINT32_MAX, true, true },
3693
3694 { UINT32_C(0xfffffffe), UINT32_MAX, UINT32_MAX, false, true },
3695 { UINT32_C(0xffffffff), UINT32_MAX, UINT32_MAX, true, true },
3696 };
3697#if ARCH_BITS >= 64
3698 static const BS3CPUINSTR2_ADX_VALUES_T s_aValues8[] =
3699 {
3700 { UINT64_C(00000000000000000000), UINT64_C(00000000000000000000), UINT64_C(00000000000000000000), false, false },
3701 { UINT64_C(00000000000000000001), UINT64_C(00000000000000000000), UINT64_C(00000000000000000000), true, false },
3702
3703 { UINT64_C(0xfffffffffffffffe), UINT64_MAX / 2, UINT64_MAX / 2, false, false },
3704 { UINT64_C(0xffffffffffffffff), UINT64_MAX / 2, UINT64_MAX / 2, true, false },
3705
3706 { UINT64_C(0x7ffffffffffffffe), UINT64_MAX, UINT64_MAX / 2, false, true },
3707 { UINT64_C(0x7fffffffffffffff), UINT64_MAX, UINT64_MAX / 2, true, true },
3708
3709 { UINT64_C(0x7ffffffffffffffe), UINT64_MAX / 2, UINT64_MAX, false, true },
3710 { UINT64_C(0x7fffffffffffffff), UINT64_MAX / 2, UINT64_MAX, true, true },
3711
3712 { UINT64_C(0xfffffffffffffffe), UINT64_MAX, UINT64_MAX, false, true },
3713 { UINT64_C(0xffffffffffffffff), UINT64_MAX, UINT64_MAX, true, true },
3714 };
3715#endif
3716 static const struct
3717 {
3718 FPFNBS3FAR pfnWorker;
3719 bool fMemSrc;
3720 uint8_t cbOp;
3721 uint8_t cValues;
3722 BS3CPUINSTR2_ADX_VALUES_T const BS3_FAR *paValues;
3723 uint32_t fEFlagsMod;
3724 } s_aTests[] =
3725 {
3726 /* 32-bit register width */
3727 { BS3_CMN_NM(bs3CpuInstr2_adcx_EAX_EBX_icebp), false, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_CF },
3728 { BS3_CMN_NM(bs3CpuInstr2_adcx_EAX_dword_FSxBX_icebp), true, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_CF },
3729
3730 { BS3_CMN_NM(bs3CpuInstr2_adox_EAX_EBX_icebp), false, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_OF },
3731 { BS3_CMN_NM(bs3CpuInstr2_adox_EAX_dword_FSxBX_icebp), true, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_OF },
3732#if ARCH_BITS >= 64
3733 /* 64-bit register width */
3734 { BS3_CMN_NM(bs3CpuInstr2_adcx_RAX_RBX_icebp), false, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_CF },
3735 { BS3_CMN_NM(bs3CpuInstr2_adcx_RAX_qword_FSxBX_icebp), true, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_CF },
3736
3737 { BS3_CMN_NM(bs3CpuInstr2_adox_RAX_RBX_icebp), false, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_OF },
3738 { BS3_CMN_NM(bs3CpuInstr2_adox_RAX_qword_FSxBX_icebp), true, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_OF },
3739#endif
3740 };
3741
3742 BS3REGCTX Ctx;
3743 BS3TRAPFRAME TrapFrame;
3744 unsigned i, j;
3745 bool fSupportsAdx = false;
3746
3747 if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3748 && ASMCpuId_EAX(0) >= 7)
3749 {
3750 uint32_t fEbx = 0;
3751 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &fEbx, NULL, NULL);
3752 fSupportsAdx = RT_BOOL(fEbx & X86_CPUID_STEXT_FEATURE_EBX_ADX);
3753 }
3754
3755 /* Ensure the structures are allocated before we sample the stack pointer. */
3756 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3757 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3758
3759 /*
3760 * Create test context.
3761 */
3762 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3763
3764 /*
3765 * Do the tests twice, first with all flags set, then once again with
3766 * flags cleared. The flags are not supposed to be touched at all except for the one indicated (CF or OF).
3767 */
3768 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3769 for (j = 0; j < 2; j++)
3770 {
3771 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3772 {
3773 uint8_t const cbOp = s_aTests[i].cbOp;
3774 unsigned const cValues = s_aTests[i].cValues;
3775 BS3CPUINSTR2_ADX_VALUES_T const BS3_FAR *paValues = s_aTests[i].paValues;
3776 uint32_t const fEFlagsMod = s_aTests[i].fEFlagsMod;
3777 unsigned iValue;
3778 bool const fOkay = fSupportsAdx;
3779 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3780 uint64_t const uSrcGarbage = ( cbOp == 4 ? UINT64_C(0x0394831000000000) : 0)
3781 & (ARCH_BITS >= 64 ? UINT64_MAX : UINT32_MAX);
3782 uint64_t uExpectRip;
3783
3784 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3785 uExpectRip = Ctx.rip.u + (fOkay ? ((uint8_t const BS3_FAR *)s_aTests[i].pfnWorker)[-1] + 1 : 0);
3786
3787 for (iValue = 0; iValue < cValues; iValue++)
3788 {
3789 uint64_t const uExpectRax = fOkay ? paValues[iValue].uDstOut : paValues[iValue].uDstIn;
3790 uint64_t uMemSrc, uMemSrcExpect;
3791
3792 Ctx.rax.uCcXReg = paValues[iValue].uDstIn;
3793 if (!s_aTests[i].fMemSrc)
3794 {
3795 Ctx.rbx.u64 = paValues[iValue].uSrc | uSrcGarbage;
3796 uMemSrcExpect = uMemSrc = ~(paValues[iValue].uSrc | uSrcGarbage);
3797 }
3798 else
3799 {
3800 uMemSrcExpect = uMemSrc = paValues[iValue].uSrc | uSrcGarbage;
3801 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
3802 }
3803
3804 Ctx.rflags.u16 &= ~fEFlagsMod;
3805 if (paValues[iValue].fFlagIn)
3806 Ctx.rflags.u16 |= fEFlagsMod;
3807
3808 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3809
3810 if (fOkay)
3811 {
3812 Ctx.rflags.u16 &= ~fEFlagsMod;
3813 if (paValues[iValue].fFlagOut)
3814 Ctx.rflags.u16 |= fEFlagsMod;
3815 }
3816
3817 if ( TrapFrame.bXcpt != bExpectXcpt
3818 || TrapFrame.Ctx.rip.u != uExpectRip
3819 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3820 || TrapFrame.Ctx.rax.u != uExpectRax
3821 /* check that nothing else really changed: */
3822 || TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16
3823 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
3824 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3825 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3826 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3827 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3828 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3829 || uMemSrc != uMemSrcExpect
3830 )
3831 {
3832 Bs3TestFailedF("test #%i value #%i failed: input %#RX64, %#RX64",
3833 i, iValue, paValues[iValue].uDstIn, paValues[iValue].uSrc);
3834 if (TrapFrame.bXcpt != bExpectXcpt)
3835 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3836 if (TrapFrame.Ctx.rip.u != uExpectRip)
3837 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3838 if (TrapFrame.Ctx.rax.u != uExpectRax)
3839 Bs3TestFailedF("Expected RAX = %#010RX64, got %#010RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3840 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3841 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3842
3843 if (TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16)
3844 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16);
3845 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
3846 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
3847 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3848 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3849 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3850 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3851 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3852 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3853 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3854 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3855 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3856 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3857 if (uMemSrc != uMemSrcExpect)
3858 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
3859 }
3860 }
3861 }
3862 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3863 }
3864
3865 return 0;
3866}
3867
3868
3869
3870/*
3871 * MOVBE
3872 */
3873BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_movbe)(uint8_t bMode)
3874{
3875 const char BS3_FAR * const pszMode = Bs3GetModeName(bMode);
3876
3877 typedef struct BS3CPUINSTR2_MOVBE_VALUES_T
3878 {
3879 RTCCUINTXREG uDstOut;
3880 RTCCUINTXREG uDstIn;
3881 RTCCUINTXREG uSrc;
3882 } BS3CPUINSTR2_MOVBE_VALUES_T;
3883 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues2[] =
3884 {
3885 { UINT64_C(0xc0dedeaddead3412), UINT64_C(0xc0dedeaddeadc0de), UINT16_C(0x1234) }
3886 };
3887 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues4MemSrc[] =
3888 {
3889 { UINT64_C(0x78563412), UINT64_C(0xc0dedeaddeadc0de), UINT32_C(0x12345678) }
3890 };
3891 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues4MemDst[] =
3892 {
3893 { UINT64_C(0xc0dedead78563412), UINT64_C(0xc0dedeaddeadc0de), UINT32_C(0x12345678) }
3894 };
3895#if ARCH_BITS >= 64
3896 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues8[] =
3897 {
3898 { UINT64_C(0xf0debc9a78563412), UINT64_C(0xc0dedeaddeadc0de), UINT64_C(0x123456789abcdef0) }
3899 };
3900#endif
3901 static const struct
3902 {
3903 FPFNBS3FAR pfnWorker;
3904 bool fMemSrc;
3905 uint8_t offIcebp;
3906 uint8_t cValues;
3907 BS3CPUINSTR2_MOVBE_VALUES_T const BS3_FAR *paValues;
3908 } s_aTests[] =
3909 {
3910 /* 16-bit register width */
3911 { BS3_CMN_NM(bs3CpuInstr2_movbe_AX_word_FSxBX_icebp), true, 6 + (ARCH_BITS != 16), RT_ELEMENTS(s_aValues2), s_aValues2 },
3912 { BS3_CMN_NM(bs3CpuInstr2_movbe_word_FSxBX_AX_icebp), false, 6 + (ARCH_BITS != 16), RT_ELEMENTS(s_aValues2), s_aValues2 },
3913 /* 32-bit register width */
3914 { BS3_CMN_NM(bs3CpuInstr2_movbe_EAX_dword_FSxBX_icebp), true, 6 + (ARCH_BITS == 16), RT_ELEMENTS(s_aValues4MemSrc), s_aValues4MemSrc },
3915 { BS3_CMN_NM(bs3CpuInstr2_movbe_dword_FSxBX_EAX_icebp), false, 6 + (ARCH_BITS == 16), RT_ELEMENTS(s_aValues4MemDst), s_aValues4MemDst },
3916#if ARCH_BITS >= 64
3917 /* 64-bit register width */
3918 { BS3_CMN_NM(bs3CpuInstr2_movbe_RAX_qword_FSxBX_icebp), true, 7, RT_ELEMENTS(s_aValues8), s_aValues8 },
3919 { BS3_CMN_NM(bs3CpuInstr2_movbe_qword_FSxBX_RAX_icebp), false, 7, RT_ELEMENTS(s_aValues8), s_aValues8 },
3920#endif
3921 };
3922
3923 BS3REGCTX Ctx;
3924 BS3REGCTX ExpectCtx;
3925 BS3TRAPFRAME TrapFrame;
3926 unsigned i, j;
3927 bool fSupportsMovBe = false;
3928
3929 if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3930 && ASMCpuId_EAX(0) >= 1)
3931 {
3932 uint32_t fEcx = 0;
3933 ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, &fEcx, NULL);
3934 fSupportsMovBe = RT_BOOL(fEcx & X86_CPUID_FEATURE_ECX_MOVBE);
3935 }
3936
3937 /* Ensure the structures are allocated before we sample the stack pointer. */
3938 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3939 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3940 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
3941
3942 /*
3943 * Create test context.
3944 */
3945 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3946
3947 /*
3948 * Do the tests twice, first with all flags set, then once again with
3949 * flags cleared. The flags are not supposed to be touched at all.
3950 */
3951 g_usBs3TestStep = 0;
3952 for (j = 0; j < 2; j++)
3953 {
3954 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3955 {
3956 unsigned const cValues = s_aTests[i].cValues;
3957 BS3CPUINSTR2_MOVBE_VALUES_T const BS3_FAR *paValues = s_aTests[i].paValues;
3958 unsigned iValue;
3959 bool const fOkay = fSupportsMovBe;
3960 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3961 uint64_t uExpectRip;
3962
3963 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3964 uExpectRip = Ctx.rip.u + (fOkay ? ((uint8_t const BS3_FAR *)s_aTests[i].pfnWorker)[-1] + 1 : 0);
3965
3966 for (iValue = 0; iValue < cValues; iValue++)
3967 {
3968 //uint64_t const uExpectRax = fOkay ? paValues[iValue].uDstOut : paValues[iValue].uDstIn;
3969 uint64_t uMem, uMemExpect;
3970
3971 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
3972
3973 if (!s_aTests[i].fMemSrc)
3974 {
3975 /* Memory is destination */
3976 Ctx.rax.u64 = paValues[iValue].uSrc;
3977 ExpectCtx.rax.u64 = paValues[iValue].uSrc;
3978 uMem = paValues[iValue].uDstIn;
3979 uMemExpect = paValues[iValue].uDstOut;
3980 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMem);
3981 Bs3RegCtxSetGrpSegFromCurPtr(&ExpectCtx, &ExpectCtx.rbx, &ExpectCtx.fs, &uMem);
3982 }
3983 else
3984 {
3985 /* Memory is source */
3986 uMemExpect = uMem = paValues[iValue].uSrc;
3987 Ctx.rax.u64 = paValues[iValue].uDstIn;
3988 ExpectCtx.rax.u64 = paValues[iValue].uDstOut;
3989 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMem);
3990 Bs3RegCtxSetGrpSegFromCurPtr(&ExpectCtx, &ExpectCtx.rbx, &ExpectCtx.fs, &uMem);
3991 }
3992
3993 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3994 g_usBs3TestStep++;
3995
3996 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, bExpectXcpt == X86_XCPT_DB ? s_aTests[i].offIcebp : 0 /*cbPcAdjust*/,
3997 0 /*cbSpAcjust*/, 0 /*fExtraEfl*/, pszMode, g_usBs3TestStep)
3998 || TrapFrame.bXcpt != bExpectXcpt
3999 || uMem != uMemExpect
4000 )
4001 {
4002 if (TrapFrame.bXcpt != bExpectXcpt)
4003 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
4004 if (uMem != uMemExpect)
4005 Bs3TestFailedF("Expected uMem = %#06RX64, got %#06RX64", (uint64_t)uMemExpect, (uint64_t)uMem);
4006 Bs3TestFailedF("^^^ iCfg=%u iWorker=%d iValue=%d\n",
4007 j, i, iValue);
4008 }
4009 }
4010 }
4011 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
4012 }
4013
4014 return 0;
4015}
4016
4017
4018
4019/*
4020 * CMPXCHG8B
4021 */
4022BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg8b)(uint8_t bMode)
4023{
4024
4025 BS3REGCTX Ctx;
4026 BS3REGCTX ExpectCtx;
4027 BS3TRAPFRAME TrapFrame;
4028 RTUINT64U au64[3];
4029 PRTUINT64U pau64 = RT_ALIGN_PT(&au64[0], sizeof(RTUINT64U), PRTUINT64U);
4030 bool const fSupportCX8 = RT_BOOL(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_CX8);
4031 const char BS3_FAR * const pszMode = Bs3GetModeName(bMode);
4032 uint8_t bRing = BS3_MODE_IS_V86(bMode) ? 3 : 0;
4033 unsigned iFlags;
4034 unsigned offBuf;
4035 unsigned iMatch;
4036 unsigned iWorker;
4037 static struct
4038 {
4039 bool fLocked;
4040 uint8_t offIcebp;
4041 FNBS3FAR *pfnWorker;
4042 } const s_aWorkers[] =
4043 {
4044 { false, 5, BS3_CMN_NM(bs3CpuInstr2_cmpxchg8b_FSxDI_icebp) },
4045#if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PP16
4046 { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg8b_FSxDI_icebp) },
4047#else
4048 { false, 6, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg8b_FSxDI_icebp) },
4049#endif
4050 { false, 6, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg8b_FSxDI_icebp) },
4051 { false, 6, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg8b_FSxDI_icebp) },
4052 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg8b_FSxDI_icebp) },
4053 { true, 1+6, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg8b_FSxDI_icebp) },
4054 { true, 1+6, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg8b_FSxDI_icebp) },
4055 { true, 1+6, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg8b_FSxDI_icebp) },
4056 };
4057
4058 /* Ensure the structures are allocated before we sample the stack pointer. */
4059 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4060 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4061 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4062 Bs3MemSet(pau64, 0, sizeof(pau64[0]) * 2);
4063
4064 /*
4065 * Create test context.
4066 */
4067 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4068 if (!fSupportCX8)
4069 Bs3TestPrintf("Note! CMPXCHG8B is not supported by the CPU!\n");
4070
4071 /*
4072 * Run the tests in all rings since alignment issues may behave
4073 * differently in ring-3 compared to ring-0.
4074 */
4075 for (;;)
4076 {
4077 /*
4078 * One loop with alignment checks disabled and one with enabled.
4079 */
4080 unsigned iCfg;
4081 for (iCfg = 0; iCfg < 2; iCfg++)
4082 {
4083 if (iCfg)
4084 {
4085 Ctx.rflags.u32 |= X86_EFL_AC;
4086 Ctx.cr0.u32 |= X86_CR0_AM;
4087 }
4088 else
4089 {
4090 Ctx.rflags.u32 &= ~X86_EFL_AC;
4091 Ctx.cr0.u32 &= ~X86_CR0_AM;
4092 }
4093
4094 /*
4095 * One loop with the normal variant and one with the locked one
4096 */
4097 g_usBs3TestStep = 0;
4098 for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++)
4099 {
4100 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker);
4101
4102 /*
4103 * One loop with all status flags set, and one with them clear.
4104 */
4105 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
4106 for (iFlags = 0; iFlags < 2; iFlags++)
4107 {
4108 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4109
4110 for (offBuf = 0; offBuf < sizeof(RTUINT64U); offBuf++)
4111 {
4112# define CX8_OLD_LO UINT32_C(0xcc9c4bbd)
4113# define CX8_OLD_HI UINT32_C(0x749549ab)
4114# define CX8_MISMATCH_LO UINT32_C(0x90f18981)
4115# define CX8_MISMATCH_HI UINT32_C(0xfd5b4000)
4116# define CX8_STORE_LO UINT32_C(0x51f6559b)
4117# define CX8_STORE_HI UINT32_C(0xd1b54963)
4118
4119 PRTUINT64U pBuf = (PRTUINT64U)&pau64->au8[offBuf];
4120
4121 ExpectCtx.rax.u = Ctx.rax.u = CX8_MISMATCH_LO;
4122 ExpectCtx.rdx.u = Ctx.rdx.u = CX8_MISMATCH_HI;
4123
4124 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rdi, &Ctx.fs, pBuf);
4125 Bs3RegCtxSetGrpSegFromCurPtr(&ExpectCtx, &ExpectCtx.rdi, &ExpectCtx.fs, pBuf);
4126
4127 for (iMatch = 0; iMatch < 2; iMatch++)
4128 {
4129 uint8_t bExpectXcpt;
4130 pBuf->s.Lo = CX8_OLD_LO;
4131 pBuf->s.Hi = CX8_OLD_HI;
4132
4133 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4134 g_usBs3TestStep++;
4135 //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker);
4136 bExpectXcpt = X86_XCPT_UD;
4137 if (fSupportCX8)
4138 {
4139 if ( offBuf
4140 && bRing == 3
4141 && bMode != BS3_MODE_RM
4142 && !BS3_MODE_IS_V86(bMode)
4143 && iCfg)
4144 {
4145 bExpectXcpt = X86_XCPT_AC;
4146 ExpectCtx.rflags.u32 = Ctx.rflags.u32;
4147 }
4148 else
4149 {
4150 bExpectXcpt = X86_XCPT_DB;
4151
4152 ExpectCtx.rax.u = CX8_OLD_LO;
4153 ExpectCtx.rdx.u = CX8_OLD_HI;
4154
4155 if (iMatch & 1)
4156 ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF;
4157 else
4158 ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF;
4159 }
4160
4161 /* Kludge! Looks like EFLAGS.AC is cleared when raising #GP in real mode on an i7-6700K. WEIRD! */
4162 if (bMode == BS3_MODE_RM && (Ctx.rflags.u32 & X86_EFL_AC))
4163 {
4164 if (TrapFrame.Ctx.rflags.u32 & X86_EFL_AC)
4165 Bs3TestFailedF("Expected EFLAGS.AC to be cleared (bXcpt=%d)", TrapFrame.bXcpt);
4166 TrapFrame.Ctx.rflags.u32 |= X86_EFL_AC;
4167 }
4168 }
4169
4170 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, bExpectXcpt == X86_XCPT_DB ? s_aWorkers[iWorker].offIcebp : 0, 0 /*cbSpAdjust*/,
4171 bExpectXcpt == X86_XCPT_DB || BS3_MODE_IS_16BIT_SYS(bMode) ? 0 : X86_EFL_RF, pszMode, g_usBs3TestStep)
4172 || TrapFrame.bXcpt != bExpectXcpt)
4173 {
4174 if (TrapFrame.bXcpt != bExpectXcpt)
4175 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
4176 Bs3TestFailedF("^^^ bRing=%u iCfg=%d iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n",
4177 bRing, iCfg, iWorker, iFlags, offBuf, iMatch);
4178 ASMHalt();
4179 }
4180
4181 ExpectCtx.rax.u = Ctx.rax.u = CX8_OLD_LO;
4182 ExpectCtx.rdx.u = Ctx.rdx.u = CX8_OLD_HI;
4183 }
4184 }
4185 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
4186 }
4187 }
4188 } /* for each test config. */
4189
4190 /*
4191 * Next ring.
4192 */
4193 bRing++;
4194 if (bRing > 3 || bMode == BS3_MODE_RM)
4195 break;
4196 Bs3RegCtxConvertToRingX(&Ctx, bRing);
4197 }
4198
4199 return 0;
4200}
4201
4202
4203
4204/*
4205 *
4206 */
4207# if ARCH_BITS == 64
4208
4209BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b)(uint8_t bMode)
4210{
4211 BS3REGCTX Ctx;
4212 BS3REGCTX ExpectCtx;
4213 BS3TRAPFRAME TrapFrame;
4214 RTUINT128U au128[3];
4215 PRTUINT128U pau128 = RT_ALIGN_PT(&au128[0], sizeof(RTUINT128U), PRTUINT128U);
4216 bool const fSupportCX16 = RT_BOOL(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16);
4217 const char BS3_FAR * const pszMode = Bs3GetModeName(bMode);
4218 uint8_t bRing = BS3_MODE_IS_V86(bMode) ? 3 : 0;
4219 unsigned iFlags;
4220 unsigned offBuf;
4221 unsigned iMatch;
4222 unsigned iWorker;
4223 static struct
4224 {
4225 bool fLocked;
4226 uint8_t offUd2;
4227 FNBS3FAR *pfnWorker;
4228 } const s_aWorkers[] =
4229 {
4230 { false, 4, BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2) },
4231 { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2) },
4232 { false, 5, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2) },
4233 { false, 5, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2) },
4234 { true, 1+4, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2) },
4235 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2) },
4236 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2) },
4237 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2) },
4238 };
4239
4240 /* Ensure the structures are allocated before we sample the stack pointer. */
4241 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4242 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4243 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4244 Bs3MemSet(pau128, 0, sizeof(pau128[0]) * 2);
4245
4246 /*
4247 * Create test context.
4248 */
4249 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4250 if (!fSupportCX16)
4251 Bs3TestPrintf("Note! CMPXCHG16B is not supported by the CPU!\n");
4252
4253
4254 /*
4255 * Run the tests in all rings since alignment issues may behave
4256 * differently in ring-3 compared to ring-0.
4257 */
4258 for (;;)
4259 {
4260 /*
4261 * One loop with alignment checks disabled and one with enabled.
4262 */
4263 unsigned iCfg;
4264 for (iCfg = 0; iCfg < 2; iCfg++)
4265 {
4266 if (iCfg)
4267 {
4268 Ctx.rflags.u32 |= X86_EFL_AC;
4269 Ctx.cr0.u32 |= X86_CR0_AM;
4270 }
4271 else
4272 {
4273 Ctx.rflags.u32 &= ~X86_EFL_AC;
4274 Ctx.cr0.u32 &= ~X86_CR0_AM;
4275 }
4276
4277 /*
4278 * One loop with the normal variant and one with the locked one
4279 */
4280 g_usBs3TestStep = 0;
4281 for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++)
4282 {
4283 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker);
4284
4285 /*
4286 * One loop with all status flags set, and one with them clear.
4287 */
4288 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
4289 for (iFlags = 0; iFlags < 2; iFlags++)
4290 {
4291 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4292
4293 for (offBuf = 0; offBuf < sizeof(RTUINT128U); offBuf++)
4294 {
4295# define CX16_OLD_LO UINT64_C(0xabb6345dcc9c4bbd)
4296# define CX16_OLD_HI UINT64_C(0x7b06ea35749549ab)
4297# define CX16_MISMATCH_LO UINT64_C(0xbace3e3590f18981)
4298# define CX16_MISMATCH_HI UINT64_C(0x9b385e8bfd5b4000)
4299# define CX16_STORE_LO UINT64_C(0x5cbd27d251f6559b)
4300# define CX16_STORE_HI UINT64_C(0x17ff434ed1b54963)
4301
4302 PRTUINT128U pBuf = (PRTUINT128U)&pau128->au8[offBuf];
4303
4304 ExpectCtx.rax.u = Ctx.rax.u = CX16_MISMATCH_LO;
4305 ExpectCtx.rdx.u = Ctx.rdx.u = CX16_MISMATCH_HI;
4306 for (iMatch = 0; iMatch < 2; iMatch++)
4307 {
4308 uint8_t bExpectXcpt;
4309 pBuf->s.Lo = CX16_OLD_LO;
4310 pBuf->s.Hi = CX16_OLD_HI;
4311 ExpectCtx.rdi.u = Ctx.rdi.u = (uintptr_t)pBuf;
4312 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4313 g_usBs3TestStep++;
4314 //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker);
4315 bExpectXcpt = X86_XCPT_UD;
4316 if (fSupportCX16)
4317 {
4318 if (offBuf & 15)
4319 {
4320 bExpectXcpt = X86_XCPT_GP;
4321 ExpectCtx.rip.u = Ctx.rip.u;
4322 ExpectCtx.rflags.u32 = Ctx.rflags.u32;
4323 }
4324 else
4325 {
4326 ExpectCtx.rax.u = CX16_OLD_LO;
4327 ExpectCtx.rdx.u = CX16_OLD_HI;
4328 if (iMatch & 1)
4329 ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF;
4330 else
4331 ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF;
4332 ExpectCtx.rip.u = Ctx.rip.u + s_aWorkers[iWorker].offUd2;
4333 }
4334 ExpectCtx.rflags.u32 |= X86_EFL_RF;
4335 }
4336 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
4337 0 /*fExtraEfl*/, pszMode, 0 /*idTestStep*/)
4338 || TrapFrame.bXcpt != bExpectXcpt)
4339 {
4340 if (TrapFrame.bXcpt != bExpectXcpt)
4341 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
4342 Bs3TestFailedF("^^^bRing=%d iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n", bRing, iWorker, iFlags, offBuf, iMatch);
4343 ASMHalt();
4344 }
4345
4346 ExpectCtx.rax.u = Ctx.rax.u = CX16_OLD_LO;
4347 ExpectCtx.rdx.u = Ctx.rdx.u = CX16_OLD_HI;
4348 }
4349 }
4350 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
4351 }
4352 }
4353 } /* for each test config. */
4354
4355 /*
4356 * Next ring.
4357 */
4358 bRing++;
4359 if (bRing > 3 || bMode == BS3_MODE_RM)
4360 break;
4361 Bs3RegCtxConvertToRingX(&Ctx, bRing);
4362 }
4363
4364 return 0;
4365}
4366
4367
4368static void bs3CpuInstr2_fsgsbase_ExpectUD(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame)
4369{
4370 pCtx->rbx.u = 0;
4371 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
4372 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
4373 pExpectCtx->rip.u = pCtx->rip.u;
4374 pExpectCtx->rflags.u32 |= X86_EFL_RF;
4375 if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
4376 0 /*idTestStep*/)
4377 || pTrapFrame->bXcpt != X86_XCPT_UD)
4378 {
4379 Bs3TestFailedF("Expected #UD, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
4380 ASMHalt();
4381 }
4382}
4383
4384
4385static bool bs3CpuInstr2_fsgsbase_VerifyWorker(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame,
4386 BS3CI2FSGSBASE const *pFsGsBaseWorker, unsigned *puIter)
4387{
4388 bool fPassed = true;
4389 unsigned iValue = 0;
4390 static const struct
4391 {
4392 bool fGP;
4393 uint64_t u64Base;
4394 } s_aValues64[] =
4395 {
4396 { false, UINT64_C(0x0000000000000000) },
4397 { false, UINT64_C(0x0000000000000001) },
4398 { false, UINT64_C(0x0000000000000010) },
4399 { false, UINT64_C(0x0000000000000123) },
4400 { false, UINT64_C(0x0000000000001234) },
4401 { false, UINT64_C(0x0000000000012345) },
4402 { false, UINT64_C(0x0000000000123456) },
4403 { false, UINT64_C(0x0000000001234567) },
4404 { false, UINT64_C(0x0000000012345678) },
4405 { false, UINT64_C(0x0000000123456789) },
4406 { false, UINT64_C(0x000000123456789a) },
4407 { false, UINT64_C(0x00000123456789ab) },
4408 { false, UINT64_C(0x0000123456789abc) },
4409 { false, UINT64_C(0x00007ffffeefefef) },
4410 { false, UINT64_C(0x00007fffffffffff) },
4411 { true, UINT64_C(0x0000800000000000) },
4412 { true, UINT64_C(0x0000800000000000) },
4413 { true, UINT64_C(0x0000800000000333) },
4414 { true, UINT64_C(0x0001000000000000) },
4415 { true, UINT64_C(0x0012000000000000) },
4416 { true, UINT64_C(0x0123000000000000) },
4417 { true, UINT64_C(0x1234000000000000) },
4418 { true, UINT64_C(0xffff300000000000) },
4419 { true, UINT64_C(0xffff7fffffffffff) },
4420 { true, UINT64_C(0xffff7fffffffffff) },
4421 { false, UINT64_C(0xffff800000000000) },
4422 { false, UINT64_C(0xffffffffffeefefe) },
4423 { false, UINT64_C(0xffffffffffffffff) },
4424 { false, UINT64_C(0xffffffffffffffff) },
4425 { false, UINT64_C(0x00000000efefefef) },
4426 { false, UINT64_C(0x0000000080204060) },
4427 { false, UINT64_C(0x00000000ddeeffaa) },
4428 { false, UINT64_C(0x00000000fdecdbca) },
4429 { false, UINT64_C(0x000000006098456b) },
4430 { false, UINT64_C(0x0000000098506099) },
4431 { false, UINT64_C(0x00000000206950bc) },
4432 { false, UINT64_C(0x000000009740395d) },
4433 { false, UINT64_C(0x0000000064a9455e) },
4434 { false, UINT64_C(0x00000000d20b6eff) },
4435 { false, UINT64_C(0x0000000085296d46) },
4436 { false, UINT64_C(0x0000000007000039) },
4437 { false, UINT64_C(0x000000000007fe00) },
4438 };
4439
4440 Bs3RegCtxSetRipCsFromCurPtr(pCtx, pFsGsBaseWorker->pfnVerifyWorker);
4441 if (pFsGsBaseWorker->f64BitOperand)
4442 {
4443 for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
4444 {
4445 bool const fGP = s_aValues64[iValue].fGP;
4446
4447 pCtx->rbx.u = s_aValues64[iValue].u64Base;
4448 pCtx->rcx.u = 0;
4449 pCtx->cr4.u |= X86_CR4_FSGSBASE;
4450 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
4451 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
4452 pExpectCtx->rip.u = pCtx->rip.u + (!fGP ? pFsGsBaseWorker->offVerifyWorkerUd2 : 0);
4453 pExpectCtx->rbx.u = !fGP ? 0 : s_aValues64[iValue].u64Base;
4454 pExpectCtx->rcx.u = !fGP ? s_aValues64[iValue].u64Base : 0;
4455 pExpectCtx->rflags.u32 |= X86_EFL_RF;
4456 if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
4457 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)
4458 || (fGP && pTrapFrame->bXcpt != X86_XCPT_GP))
4459 {
4460 if (fGP && pTrapFrame->bXcpt != X86_XCPT_GP)
4461 Bs3TestFailedF("Expected #GP, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
4462 else
4463 Bs3TestFailedF("iValue=%u\n", iValue);
4464 fPassed = false;
4465 break;
4466 }
4467 }
4468 }
4469 else
4470 {
4471 for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
4472 {
4473 pCtx->rbx.u = s_aValues64[iValue].u64Base;
4474 pCtx->rcx.u = ~s_aValues64[iValue].u64Base;
4475 pCtx->cr4.u |= X86_CR4_FSGSBASE;
4476 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
4477 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
4478 pExpectCtx->rip.u = pCtx->rip.u + pFsGsBaseWorker->offVerifyWorkerUd2;
4479 pExpectCtx->rbx.u = 0;
4480 pExpectCtx->rcx.u = s_aValues64[iValue].u64Base & UINT64_C(0x00000000ffffffff);
4481 pExpectCtx->rflags.u32 |= X86_EFL_RF;
4482 if (!Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
4483 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/))
4484 {
4485 Bs3TestFailedF("iValue=%u\n", iValue);
4486 fPassed = false;
4487 break;
4488 }
4489 }
4490 }
4491
4492 *puIter = iValue;
4493 return fPassed;
4494}
4495
4496
4497static void bs3CpuInstr2_rdfsbase_rdgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
4498 unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
4499{
4500 BS3REGCTX Ctx;
4501 BS3REGCTX ExpectCtx;
4502 BS3TRAPFRAME TrapFrame;
4503 unsigned iWorker;
4504 unsigned iIter;
4505 uint32_t uDummy;
4506 uint32_t uStdExtFeatEbx;
4507 bool fSupportsFsGsBase;
4508
4509 ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
4510 fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
4511
4512 /* Ensure the structures are allocated before we sample the stack pointer. */
4513 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4514 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4515 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4516
4517 /*
4518 * Create test context.
4519 */
4520 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4521
4522 for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
4523 {
4524 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
4525 if (fSupportsFsGsBase)
4526 {
4527 uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
4528
4529 /* CR4.FSGSBASE disabled -> #UD. */
4530 Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
4531 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4532
4533 /* Read and verify existing base address. */
4534 Ctx.rbx.u = 0;
4535 Ctx.cr4.u |= X86_CR4_FSGSBASE;
4536 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4537 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4538 ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
4539 ExpectCtx.rbx.u = uBaseAddr;
4540 ExpectCtx.rflags.u32 |= X86_EFL_RF;
4541 if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
4542 0 /*idTestStep*/))
4543 {
4544 ASMHalt();
4545 }
4546
4547 /* Write, read and verify series of base addresses. */
4548 if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
4549 {
4550 Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
4551 ASMHalt();
4552 }
4553
4554 /* Restore original base address. */
4555 ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
4556
4557 /* Clean used GPRs. */
4558 Ctx.rbx.u = 0;
4559 Ctx.rcx.u = 0;
4560 }
4561 else
4562 {
4563 /* Unsupported by CPUID -> #UD. */
4564 Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
4565 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4566 }
4567 }
4568}
4569
4570
4571static void bs3CpuInstr2_wrfsbase_wrgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
4572 unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
4573{
4574 BS3REGCTX Ctx;
4575 BS3REGCTX ExpectCtx;
4576 BS3TRAPFRAME TrapFrame;
4577 unsigned iWorker;
4578 unsigned iIter;
4579 uint32_t uDummy;
4580 uint32_t uStdExtFeatEbx;
4581 bool fSupportsFsGsBase;
4582
4583 ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
4584 fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
4585
4586 /* Ensure the structures are allocated before we sample the stack pointer. */
4587 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4588 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4589 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4590
4591 /*
4592 * Create test context.
4593 */
4594 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4595
4596 for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
4597 {
4598 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
4599 if (fSupportsFsGsBase)
4600 {
4601 uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
4602
4603 /* CR4.FSGSBASE disabled -> #UD. */
4604 Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
4605 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4606
4607 /* Write a base address. */
4608 Ctx.rbx.u = 0xa0000;
4609 Ctx.cr4.u |= X86_CR4_FSGSBASE;
4610 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4611 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4612 ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
4613 ExpectCtx.rflags.u32 |= X86_EFL_RF;
4614 if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
4615 0 /*idTestStep*/))
4616 {
4617 ASMHalt();
4618 }
4619
4620 /* Write and read back series of base addresses. */
4621 if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
4622 {
4623 Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
4624 ASMHalt();
4625 }
4626
4627 /* Restore original base address. */
4628 ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
4629
4630 /* Clean used GPRs. */
4631 Ctx.rbx.u = 0;
4632 Ctx.rcx.u = 0;
4633 }
4634 else
4635 {
4636 /* Unsupported by CPUID -> #UD. */
4637 Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
4638 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4639 }
4640 }
4641}
4642
4643
4644BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrfsbase)(uint8_t bMode)
4645{
4646 bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrFsBaseWorkers, RT_ELEMENTS(s_aWrFsBaseWorkers), MSR_K8_FS_BASE);
4647 return 0;
4648}
4649
4650
4651BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrgsbase)(uint8_t bMode)
4652{
4653 bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrGsBaseWorkers, RT_ELEMENTS(s_aWrGsBaseWorkers), MSR_K8_GS_BASE);
4654 return 0;
4655}
4656
4657
4658BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdfsbase)(uint8_t bMode)
4659{
4660 bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdFsBaseWorkers, RT_ELEMENTS(s_aRdFsBaseWorkers), MSR_K8_FS_BASE);
4661 return 0;
4662}
4663
4664
4665BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdgsbase)(uint8_t bMode)
4666{
4667 bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdGsBaseWorkers, RT_ELEMENTS(s_aRdGsBaseWorkers), MSR_K8_GS_BASE);
4668 return 0;
4669}
4670
4671# endif /* ARCH_BITS == 64 */
4672
4673#endif /* BS3_INSTANTIATING_CMN */
4674
4675
4676
4677/*
4678 * Mode specific code.
4679 * Mode specific code.
4680 * Mode specific code.
4681 */
4682#ifdef BS3_INSTANTIATING_MODE
4683
4684
4685#endif /* BS3_INSTANTIATING_MODE */
4686
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