VirtualBox

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

Last change on this file since 104008 was 104008, checked in by vboxsync, 14 months ago

ValKit/bs3-cpu-instr-2: Use the amd specific test data for shift/rotate tests. bugref:10376

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 246.1 KB
Line 
1/* $Id: bs3-cpu-instr-2-template.c 104008 2024-03-22 23:53:44Z 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.215389.xyz.
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 ? BS3_THRESHOLD_NATIVE_RECOMPILER + cTestData : 1; \
973 unsigned const cMaxRecompInner= cBitsImm != 8 ? 1 : BS3_THRESHOLD_NATIVE_RECOMPILER; \
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 if (fIntelIbProblem && cBitsImm == 8 && !paTests[iTest].fDstMem) \
1024 { /* Intel 10890xe: 'ROL reg,imm8' and 'ROR reg,imm8' produces different OF values. \
1025 stored in bit 3 of the output. */ \
1026 CtxExpect.rflags.u16 &= ~X86_EFL_OF; \
1027 CtxExpect.rflags.u16 |= (paTestData[iTestData].fEflOut & RT_BIT_32(BS3CPUINSTR2SHIFT_EFL_IB_OVERFLOW_OUT_BIT)) \
1028 << (X86_EFL_OF_BIT - BS3CPUINSTR2SHIFT_EFL_IB_OVERFLOW_OUT_BIT); \
1029 } \
1030 \
1031 /* Inner recompiler trigger loop, for instructions with immediates that we modify. */ \
1032 cRecompInner = 0; \
1033 do \
1034 { \
1035 if (paTests[iTest].fDstMem) \
1036 *puCtxDst = paTestData[iTestData].uSrc1; \
1037 \
1038 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); \
1039 \
1040 if (fUndefEfl) /* When executing tests for the other CPU vendor. */ \
1041 CtxExpect.rflags.u16 = (CtxExpect.rflags.u16 & ~fUndefEfl) | (TrapFrame.Ctx.rflags.u16 & fUndefEfl); \
1042 /* Alternative overflow flag workaround: else if (fIntelIbProblem && cBitsImm == 8 && !paTests[iTest].fDstMem) \
1043 { \
1044 Bs3TestPrintf("tweaked in=%#x out=%#x exp=%#x\n", Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16, CtxExpect.rflags.u16); \
1045 CtxExpect.rflags.u16 = (CtxExpect.rflags.u16 & ~X86_EFL_OF) | (TrapFrame.Ctx.rflags.u16 & X86_EFL_OF); \
1046 } else if (cBitsImm == 8) Bs3TestPrintf("as is\n"); */\
1047 \
1048 if (TrapFrame.bXcpt != X86_XCPT_UD) \
1049 { \
1050 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt); \
1051 Bs3TrapPrintFrame(&TrapFrame); \
1052 } \
1053 else if (Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &CtxExpect, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, \
1054 0 /*fExtraEfl*/, "mode", (iTest << 8) | (iTestData & 0xff))) \
1055 { \
1056 if (puMemPtrReg && paTests[iTest].fDstMem && Buf.uData != uMemExpect) \
1057 Bs3TestPrintf("Wrong memory result: %" a_szFmt ", expected %" a_szFmt "\n", Buf.uData, uMemExpect); \
1058 else \
1059 { \
1060 cRecompInner++; \
1061 continue; \
1062 } \
1063 } \
1064 /*else { Bs3RegCtxPrint(&Ctx); Bs3TrapPrintFrame(&TrapFrame); }*/ \
1065 Bs3TestPrintf(#a_cBits ": iTest=%u iData=%u inner=%u: uSrc1=%" a_szFmt "%s uSrc2=%RX8 (%s) fEfl=%RX16 -> %" a_szFmt " fEfl=%RX16\n", \
1066 iTest, iTestData, cRecompInner, \
1067 paTestData[iTestData].uSrc1, paTests[iTest].fDstMem ? " mem" : "", \
1068 paTestData[iTestData].uSrc2, cBitsImm == 0 ? "cl" : cBitsImm == 1 ? "1" : "Ib", \
1069 (uint16_t)(paTestData[iTestData].fEflIn & X86_EFL_STATUS_BITS), \
1070 paTestData[iTestData].uResult, paTestData[iTestData].fEflOut & X86_EFL_STATUS_BITS); \
1071 Bs3RegCtxPrint(&Ctx); Bs3TrapPrintFrame(&TrapFrame); \
1072 ASMHalt(); \
1073 } while (cRecompInner < cMaxRecompInner); \
1074 } \
1075 } \
1076 \
1077 /* Restore modified context registers (except EFLAGS). */ \
1078 CtxExpect.ds = Ctx.ds = SavedDs; \
1079 (&CtxExpect.rax)[idxDstReg & 15].u = (&Ctx.rax)[idxDstReg & 15].u = SavedDst.u; \
1080 CtxExpect.rcx.u = Ctx.rcx.u = SavedRcx.u; \
1081 } \
1082 \
1083 return 0; \
1084}
1085
1086BS3CPUINSTR2_COMMON_SHIFT_U(8, uint8_t, "RX8")
1087BS3CPUINSTR2_COMMON_SHIFT_U(16, uint16_t, "RX16")
1088BS3CPUINSTR2_COMMON_SHIFT_U(32, uint32_t, "RX32")
1089#if ARCH_BITS == 64
1090BS3CPUINSTR2_COMMON_SHIFT_U(64, uint64_t, "RX64")
1091#endif
1092
1093
1094#define BS3CPUINSTR2_SHIFT_INSTR_NOT_64(a_Ins, a_fEflUndef, a_fIntelIbProblem) \
1095 { \
1096 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests8[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_8(a_Ins) }; \
1097 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests16[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_16(a_Ins) }; \
1098 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests32[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_32(a_Ins) }; \
1099 uint16_t const fEflUndefIntel = bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_INTEL, a_fEflUndef); \
1100 uint16_t const fEflUndefAmd = bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_AMD, a_fEflUndef); \
1101 bs3CpuInstr2_CommonShiftU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), \
1102 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU8, \
1103 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU8, \
1104 fEflUndefIntel, a_fIntelIbProblem); \
1105 bs3CpuInstr2_CommonShiftU8(bMode, s_aTests8, RT_ELEMENTS(s_aTests8), \
1106 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU8, \
1107 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU8, \
1108 fEflUndefAmd, false); \
1109 bs3CpuInstr2_CommonShiftU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), \
1110 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU16, \
1111 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU16, \
1112 fEflUndefIntel, a_fIntelIbProblem); \
1113 bs3CpuInstr2_CommonShiftU16(bMode, s_aTests16, RT_ELEMENTS(s_aTests16), \
1114 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU16, \
1115 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU16, \
1116 fEflUndefAmd, false); \
1117 bs3CpuInstr2_CommonShiftU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), \
1118 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU32, \
1119 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU32, \
1120 fEflUndefIntel, a_fIntelIbProblem); \
1121 bs3CpuInstr2_CommonShiftU32(bMode, s_aTests32, RT_ELEMENTS(s_aTests32), \
1122 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU32, \
1123 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU32, \
1124 fEflUndefAmd, false); \
1125 } (void)0
1126#if ARCH_BITS == 64
1127# define BS3CPUINSTR2_SHIFT_INSTR_ONLY64(a_Ins, a_fEflUndef, a_fIntelIbProblem) \
1128 { \
1129 static const BS3CPUINSTR2CMNSHIFTTEST s_aTests64[] = { BS3CPUINSTR2CMNSHIFTTEST_ENTRIES_64(a_Ins) }; \
1130 bs3CpuInstr2_CommonShiftU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), \
1131 g_aBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU64, \
1132 g_cBs3CpuInstr2_ ## a_Ins ## _intel_TestDataU64, \
1133 bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_INTEL, a_fEflUndef), a_fIntelIbProblem); \
1134 bs3CpuInstr2_CommonShiftU64(bMode, s_aTests64, RT_ELEMENTS(s_aTests64), \
1135 g_aBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU64, \
1136 g_cBs3CpuInstr2_ ## a_Ins ## _amd_TestDataU64, \
1137 bs3CpuInstr2_UndefEflByCpuVendor(BS3CPUVENDOR_AMD, a_fEflUndef), false); \
1138 } (void)0
1139#else
1140# define BS3CPUINSTR2_SHIFT_INSTR_ONLY64(a_Ins, a_fEflUndef, a_fIntelIbProblem) (void)0
1141#endif
1142
1143
1144BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shl)(uint8_t bMode)
1145{
1146 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(shl, X86_EFL_AF | X86_EFL_OF, false);
1147 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(shl, X86_EFL_AF | X86_EFL_OF, false);
1148 return 0;
1149}
1150
1151
1152BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shr)(uint8_t bMode)
1153{
1154 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(shr, X86_EFL_AF | X86_EFL_OF, false);
1155 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(shr, X86_EFL_AF | X86_EFL_OF, false);
1156 return 0;
1157}
1158
1159
1160BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_sar)(uint8_t bMode)
1161{
1162 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(sar, X86_EFL_AF | X86_EFL_OF, false);
1163 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(sar, X86_EFL_AF | X86_EFL_OF, false);
1164 return 0;
1165}
1166
1167
1168BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rol)(uint8_t bMode)
1169{
1170 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(rol, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1171 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(rol, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1172 return 0;
1173}
1174
1175
1176BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_ror)(uint8_t bMode)
1177{
1178 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(ror, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1179 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(ror, X86_EFL_OF | X86_EFL_CF, true /*fIntelIbProblem*/);
1180 return 0;
1181}
1182
1183
1184BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rcl)(uint8_t bMode)
1185{
1186 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(rcl, X86_EFL_OF, false);
1187 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(rcl, X86_EFL_OF, false);
1188 return 0;
1189}
1190
1191
1192BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rcr)(uint8_t bMode)
1193{
1194 BS3CPUINSTR2_SHIFT_INSTR_NOT_64(rcr, X86_EFL_OF, false);
1195 BS3CPUINSTR2_SHIFT_INSTR_ONLY64(rcr, X86_EFL_OF, false);
1196 return 0;
1197}
1198
1199
1200
1201
1202
1203/*
1204 * Multiplication
1205 */
1206
1207BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mul)(uint8_t bMode)
1208{
1209#define MUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
1210#define MUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
1211
1212 static const struct
1213 {
1214 RTCCUINTREG uInAX;
1215 RTCCUINTREG uInBX;
1216 RTCCUINTREG uOutDX;
1217 RTCCUINTREG uOutAX;
1218 uint16_t fFlags;
1219 } s_aTests[] =
1220 {
1221 { 1, 1,
1222 0, 1, 0 },
1223 { 2, 2,
1224 0, 4, 0 },
1225 { RTCCUINTREG_MAX, RTCCUINTREG_MAX,
1226 RTCCUINTREG_MAX-1, 1, X86_EFL_CF | X86_EFL_OF },
1227 { RTCCINTREG_MAX, RTCCINTREG_MAX,
1228 RTCCINTREG_MAX / 2, 1, X86_EFL_CF | X86_EFL_OF },
1229 { 1, RTCCUINTREG_MAX,
1230 0, RTCCUINTREG_MAX, X86_EFL_PF | X86_EFL_SF },
1231 { 1, RTCCINTREG_MAX,
1232 0, RTCCINTREG_MAX, X86_EFL_PF },
1233 { 2, RTCCINTREG_MAX,
1234 0, RTCCUINTREG_MAX - 1, X86_EFL_SF },
1235 { (RTCCUINTREG)RTCCINTREG_MAX + 1, 2,
1236 1, 0, X86_EFL_PF | X86_EFL_CF | X86_EFL_OF },
1237 { (RTCCUINTREG)RTCCINTREG_MAX / 2 + 1, 3,
1238 0, ((RTCCUINTREG)RTCCINTREG_MAX / 2 + 1) * 3, X86_EFL_PF | X86_EFL_SF },
1239 };
1240
1241 BS3REGCTX Ctx;
1242 BS3TRAPFRAME TrapFrame;
1243 unsigned i, j, k;
1244
1245 /* Ensure the structures are allocated before we sample the stack pointer. */
1246 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1247 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1248
1249 /*
1250 * Create test context.
1251 */
1252 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1253 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2));
1254 for (k = 0; k < 2; k++)
1255 {
1256 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
1257 for (j = 0; j < 2; j++)
1258 {
1259 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1260 {
1261 if (k == 0)
1262 {
1263 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1264 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1265 }
1266 else
1267 {
1268 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1269 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1270 }
1271 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1272 if (TrapFrame.bXcpt != X86_XCPT_UD)
1273 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
1274 else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1275 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1276 || (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
1277 != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
1278 {
1279 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
1280 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
1281
1282 if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
1283 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1284 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1285 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1286 Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1287 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1288 if ( (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
1289 != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
1290 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & MUL_CHECK_EFLAGS,
1291 TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO));
1292 }
1293 }
1294 Ctx.rflags.u16 &= ~(MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO);
1295 }
1296 }
1297
1298 return 0;
1299}
1300
1301
1302BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_imul)(uint8_t bMode)
1303{
1304#define IMUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
1305#define IMUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
1306 static const struct
1307 {
1308 RTCCUINTREG uInAX;
1309 RTCCUINTREG uInBX;
1310 RTCCUINTREG uOutDX;
1311 RTCCUINTREG uOutAX;
1312 uint16_t fFlags;
1313 } s_aTests[] =
1314 {
1315 /* two positive values. */
1316 { 1, 1,
1317 0, 1, 0 },
1318 { 2, 2,
1319 0, 4, 0 },
1320 { RTCCINTREG_MAX, RTCCINTREG_MAX,
1321 RTCCINTREG_MAX/2, 1, X86_EFL_CF | X86_EFL_OF },
1322 { 1, RTCCINTREG_MAX,
1323 0, RTCCINTREG_MAX, X86_EFL_PF },
1324 { 2, RTCCINTREG_MAX,
1325 0, RTCCUINTREG_MAX - 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF },
1326 { 2, RTCCINTREG_MAX / 2,
1327 0, RTCCINTREG_MAX - 1U, 0 },
1328 { 2, (RTCCINTREG_MAX / 2 + 1),
1329 0, (RTCCUINTREG)RTCCINTREG_MAX + 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
1330 { 4, (RTCCINTREG_MAX / 2 + 1),
1331 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1332
1333 /* negative and positive */
1334 { -4, 3,
1335 -1, -12, X86_EFL_SF },
1336 { 32, -127,
1337 -1, -4064, X86_EFL_SF },
1338 { RTCCINTREG_MIN, 1,
1339 -1, RTCCINTREG_MIN, X86_EFL_SF | X86_EFL_PF },
1340 { RTCCINTREG_MIN, 2,
1341 -1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1342 { RTCCINTREG_MIN, 3,
1343 -2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
1344 { RTCCINTREG_MIN, 4,
1345 -2, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1346 { RTCCINTREG_MIN, RTCCINTREG_MAX,
1347 RTCCINTREG_MIN / 2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
1348 { RTCCINTREG_MIN, RTCCINTREG_MAX - 1,
1349 RTCCINTREG_MIN / 2 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1350
1351 /* two negative values. */
1352 { -4, -63,
1353 0, 252, X86_EFL_PF },
1354 { RTCCINTREG_MIN, RTCCINTREG_MIN,
1355 RTCCUINTREG_MAX / 4 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
1356 { RTCCINTREG_MIN, RTCCINTREG_MIN + 1,
1357 RTCCUINTREG_MAX / 4, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF},
1358 { RTCCINTREG_MIN + 1, RTCCINTREG_MIN + 1,
1359 RTCCUINTREG_MAX / 4, 1, X86_EFL_CF | X86_EFL_OF },
1360
1361 };
1362
1363 BS3REGCTX Ctx;
1364 BS3TRAPFRAME TrapFrame;
1365 unsigned i, j, k;
1366
1367 /* Ensure the structures are allocated before we sample the stack pointer. */
1368 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1369 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1370
1371 /*
1372 * Create test context.
1373 */
1374 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1375 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2));
1376
1377 for (k = 0; k < 2; k++)
1378 {
1379 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
1380 for (j = 0; j < 2; j++)
1381 {
1382 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1383 {
1384 if (k == 0)
1385 {
1386 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1387 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1388 }
1389 else
1390 {
1391 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1392 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1393 }
1394 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1395 if (TrapFrame.bXcpt != X86_XCPT_UD)
1396 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
1397 else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1398 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1399 || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1400 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1401 {
1402 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
1403 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
1404
1405 if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
1406 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1407 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1408 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1409 Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1410 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1411 if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1412 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1413 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
1414 TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
1415 }
1416 }
1417 }
1418 }
1419
1420 /*
1421 * Repeat for the truncating two operand version.
1422 */
1423 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2));
1424
1425 for (k = 0; k < 2; k++)
1426 {
1427 Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
1428 for (j = 0; j < 2; j++)
1429 {
1430 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1431 {
1432 if (k == 0)
1433 {
1434 Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1435 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1436 }
1437 else
1438 {
1439 Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1440 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1441 }
1442 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1443 if (TrapFrame.bXcpt != X86_XCPT_UD)
1444 Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
1445 else if ( TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1446 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1447 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
1448 || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1449 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1450 {
1451 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
1452 i, s_aTests[i].uInAX, s_aTests[i].uInBX);
1453
1454 if (TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
1455 Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
1456 s_aTests[i].uOutAX, TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS));
1457 if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
1458 != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
1459 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
1460 TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
1461 }
1462 }
1463 }
1464 }
1465
1466 return 0;
1467}
1468
1469
1470BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_div)(uint8_t bMode)
1471{
1472#define DIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
1473 static const struct
1474 {
1475 RTCCUINTREG uInDX;
1476 RTCCUINTREG uInAX;
1477 RTCCUINTREG uInBX;
1478 RTCCUINTREG uOutAX;
1479 RTCCUINTREG uOutDX;
1480 uint8_t bXcpt;
1481 } s_aTests[] =
1482 {
1483 { 0, 1, 1,
1484 1, 0, X86_XCPT_UD },
1485 { 0, 5, 2,
1486 2, 1, X86_XCPT_UD },
1487 { 0, 0, 0,
1488 0, 0, X86_XCPT_DE },
1489 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 0,
1490 0, 0, X86_XCPT_DE },
1491 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 1,
1492 0, 0, X86_XCPT_DE },
1493 { RTCCUINTREG_MAX, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
1494 0, 0, X86_XCPT_DE },
1495 { RTCCUINTREG_MAX - 1, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
1496 RTCCUINTREG_MAX, RTCCUINTREG_MAX - 1, X86_XCPT_UD },
1497 };
1498
1499 BS3REGCTX Ctx;
1500 BS3TRAPFRAME TrapFrame;
1501 unsigned i, j;
1502
1503 /* Ensure the structures are allocated before we sample the stack pointer. */
1504 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1505 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1506
1507 /*
1508 * Create test context.
1509 */
1510 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1511 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2));
1512
1513 /*
1514 * Do the tests twice, first with all flags set, then once again with
1515 * flags cleared. The flags are not touched by my intel skylake CPU.
1516 */
1517 Ctx.rflags.u16 |= DIV_CHECK_EFLAGS;
1518 for (j = 0; j < 2; j++)
1519 {
1520 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1521 {
1522 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1523 Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
1524 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1525 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1526
1527 if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
1528 || ( s_aTests[i].bXcpt == X86_XCPT_UD
1529 ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1530 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1531 || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS)
1532 : TrapFrame.Ctx.rax.u != Ctx.rax.u
1533 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1534 || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS) ) )
1535 {
1536 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
1537 i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
1538 if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
1539 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
1540 if (s_aTests[i].bXcpt == X86_XCPT_UD)
1541 {
1542 if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
1543 Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1544 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1545 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1546 Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1547 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1548 if ((TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS))
1549 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
1550 Ctx.rflags.u16 & DIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS);
1551 }
1552 }
1553 }
1554 Ctx.rflags.u16 &= ~DIV_CHECK_EFLAGS;
1555 }
1556
1557 return 0;
1558}
1559
1560
1561
1562BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_idiv)(uint8_t bMode)
1563{
1564#define IDIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
1565 static const struct
1566 {
1567 RTCCUINTREG uInDX;
1568 RTCCUINTREG uInAX;
1569 RTCCUINTREG uInBX;
1570 RTCCUINTREG uOutAX;
1571 RTCCUINTREG uOutDX;
1572 uint8_t bXcpt;
1573 } s_aTests[] =
1574 {
1575 { 0, 0, 0,
1576 0, 0, X86_XCPT_DE },
1577 { RTCCINTREG_MAX, RTCCINTREG_MAX, 0,
1578 0, 0, X86_XCPT_DE },
1579 /* two positive values. */
1580 { 0, 1, 1,
1581 1, 0, X86_XCPT_UD },
1582 { 0, 5, 2,
1583 2, 1, X86_XCPT_UD },
1584 { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2, RTCCINTREG_MAX,
1585 RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_UD },
1586 { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2 + 1, RTCCINTREG_MAX,
1587 RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_DE },
1588 /* negative dividend, positive divisor. */
1589 { -1, -7, 2,
1590 -3, -1, X86_XCPT_UD },
1591 { RTCCINTREG_MIN / 2 + 1, 0, RTCCINTREG_MAX,
1592 RTCCINTREG_MIN + 2, RTCCINTREG_MIN + 2, X86_XCPT_UD },
1593 { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MAX,
1594 0, 0, X86_XCPT_DE },
1595 /* positive dividend, negative divisor. */
1596 { 0, 7, -2,
1597 -3, 1, X86_XCPT_UD },
1598 { RTCCINTREG_MAX / 2 + 1, RTCCINTREG_MAX, RTCCINTREG_MIN,
1599 RTCCINTREG_MIN, RTCCINTREG_MAX, X86_XCPT_UD },
1600 { RTCCINTREG_MAX / 2 + 1, (RTCCUINTREG)RTCCINTREG_MAX+1, RTCCINTREG_MIN,
1601 0, 0, X86_XCPT_DE },
1602 /* negative dividend, negative divisor. */
1603 { -1, -7, -2,
1604 3, -1, X86_XCPT_UD },
1605 { RTCCINTREG_MIN / 2, 1, RTCCINTREG_MIN,
1606 RTCCINTREG_MAX, RTCCINTREG_MIN + 1, X86_XCPT_UD },
1607 { RTCCINTREG_MIN / 2, 2, RTCCINTREG_MIN,
1608 RTCCINTREG_MAX, RTCCINTREG_MIN + 2, X86_XCPT_UD },
1609 { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MIN,
1610 0, 0, X86_XCPT_DE },
1611 };
1612
1613 BS3REGCTX Ctx;
1614 BS3TRAPFRAME TrapFrame;
1615 unsigned i, j;
1616
1617 /* Ensure the structures are allocated before we sample the stack pointer. */
1618 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1619 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1620
1621 /*
1622 * Create test context.
1623 */
1624 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1625 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2));
1626
1627 /*
1628 * Do the tests twice, first with all flags set, then once again with
1629 * flags cleared. The flags are not touched by my intel skylake CPU.
1630 */
1631 Ctx.rflags.u16 |= IDIV_CHECK_EFLAGS;
1632 for (j = 0; j < 2; j++)
1633 {
1634 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
1635 {
1636 Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
1637 Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
1638 Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
1639 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1640
1641 if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
1642 || ( s_aTests[i].bXcpt == X86_XCPT_UD
1643 ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
1644 || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
1645 || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS)
1646 : TrapFrame.Ctx.rax.u != Ctx.rax.u
1647 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1648 || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) ) )
1649 {
1650 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
1651 i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
1652 if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
1653 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
1654 if (s_aTests[i].bXcpt == X86_XCPT_UD)
1655 {
1656 if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
1657 Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1658 s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
1659 if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
1660 Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
1661 s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
1662 if ((TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS))
1663 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
1664 Ctx.rflags.u16 & IDIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS);
1665 }
1666 }
1667 }
1668 Ctx.rflags.u16 &= ~IDIV_CHECK_EFLAGS;
1669 }
1670
1671 return 0;
1672}
1673
1674
1675/*
1676 * BSF/BSR (386+) & TZCNT/LZCNT (BMI1,ABM)
1677 */
1678
1679typedef struct BS3CPUINSTR2_SUBTEST_BITSCAN_T
1680{
1681 RTCCUINTXREG uSrc;
1682 RTCCUINTXREG uOut;
1683 bool fOutNotSet;
1684 uint16_t fEflOut;
1685} BS3CPUINSTR2_SUBTEST_BITSCAN_T;
1686
1687typedef struct BS3CPUINSTR2_TEST_BITSCAN_T
1688{
1689 FPFNBS3FAR pfnWorker;
1690 bool fMemSrc;
1691 uint8_t cbInstr;
1692 uint8_t cOpBits;
1693 uint16_t fEflCheck;
1694 uint8_t cSubTests;
1695 BS3CPUINSTR2_SUBTEST_BITSCAN_T const *paSubTests;
1696} BS3CPUINSTR2_TEST_BITSCAN_T;
1697
1698static uint8_t bs3CpuInstr2_BitScan(uint8_t bMode, BS3CPUINSTR2_TEST_BITSCAN_T const *paTests, unsigned cTests)
1699{
1700 BS3REGCTX Ctx;
1701 BS3TRAPFRAME TrapFrame;
1702 unsigned i, j, k;
1703
1704 /* Ensure the structures are allocated before we sample the stack pointer. */
1705 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
1706 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
1707
1708 /*
1709 * Create test context.
1710 */
1711 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
1712
1713 /*
1714 * Do the tests twice, first with all flags set, then once again with
1715 * flags cleared. The flags are not supposed to be touched at all.
1716 */
1717 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
1718 for (j = 0; j < 2; j++)
1719 {
1720 for (i = 0; i < cTests; i++)
1721 {
1722 for (k = 0; k < paTests[i].cSubTests; k++)
1723 {
1724 uint64_t uExpectRax, uExpectRip;
1725 RTCCUINTXREG uMemSrc, uMemSrcExpect;
1726
1727 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
1728 if (!paTests[i].fMemSrc)
1729 {
1730 Ctx.rbx.uCcXReg = paTests[i].paSubTests[k].uSrc;
1731 uMemSrcExpect = uMemSrc = ~paTests[i].paSubTests[k].uSrc;
1732 }
1733 else
1734 {
1735 uMemSrcExpect = uMemSrc = paTests[i].paSubTests[k].uSrc;
1736 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
1737 }
1738 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paTests[i].pfnWorker);
1739 if (paTests[i].paSubTests[k].fOutNotSet)
1740 uExpectRax = Ctx.rax.u;
1741 else if (paTests[i].cOpBits != 16)
1742 uExpectRax = paTests[i].paSubTests[k].uOut;
1743 else
1744 uExpectRax = paTests[i].paSubTests[k].uOut | (Ctx.rax.u & UINT64_C(0xffffffffffff0000));
1745 uExpectRip = Ctx.rip.u + paTests[i].cbInstr;
1746 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
1747
1748 if ( TrapFrame.bXcpt != X86_XCPT_UD
1749 || TrapFrame.Ctx.rip.u != uExpectRip
1750 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
1751 || TrapFrame.Ctx.rax.u != uExpectRax
1752 || (TrapFrame.Ctx.rflags.u16 & paTests[i].fEflCheck)
1753 != (paTests[i].paSubTests[k].fEflOut & paTests[i].fEflCheck)
1754 /* check that nothing else really changed: */
1755 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
1756 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
1757 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
1758 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
1759 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
1760 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
1761 || uMemSrc != uMemSrcExpect
1762 )
1763 {
1764 Bs3TestFailedF("test #%i/%i failed: input %#" RTCCUINTXREG_XFMT,
1765 i, k, paTests[i].paSubTests[k].uSrc);
1766 if (TrapFrame.bXcpt != X86_XCPT_UD)
1767 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", X86_XCPT_UD, TrapFrame.bXcpt);
1768 if (TrapFrame.Ctx.rip.u != uExpectRip)
1769 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
1770 if (TrapFrame.Ctx.rax.u != uExpectRax)
1771 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
1772 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
1773 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
1774 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
1775 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
1776 if ( (TrapFrame.Ctx.rflags.u16 & paTests[i].fEflCheck)
1777 != (paTests[i].paSubTests[k].fEflOut & paTests[i].fEflCheck))
1778 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
1779 paTests[i].paSubTests[k].fEflOut & paTests[i].fEflCheck,
1780 TrapFrame.Ctx.rflags.u16 & paTests[i].fEflCheck);
1781
1782 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
1783 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
1784 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
1785 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
1786 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
1787 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
1788 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
1789 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
1790 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
1791 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
1792 if (uMemSrc != uMemSrcExpect)
1793 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
1794 }
1795 }
1796 }
1797 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
1798 }
1799
1800 return 0;
1801}
1802
1803
1804BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bsf_tzcnt)(uint8_t bMode)
1805{
1806 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsf16[] =
1807 {
1808 { 0, /* -> */ 0, true, X86_EFL_ZF },
1809 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 0, true, X86_EFL_ZF },
1810 { ~(RTCCUINTXREG)0, /* -> */ 0, false, 0 },
1811 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1812 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1813 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1814 };
1815 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsTzCnt16[] =
1816 {
1817 { 0, /* -> */ 16, false, X86_EFL_CF },
1818 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 16, false, X86_EFL_CF },
1819 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1820 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1821 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1822 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1823 };
1824 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsf32[] =
1825 {
1826 { 0, /* -> */ 0, true, X86_EFL_ZF },
1827#if ARCH_BITS == 64
1828 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 0, true, X86_EFL_ZF },
1829#endif
1830 { ~(RTCCUINTXREG)0, /* -> */ 0, false, 0 },
1831 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1832 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1833 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1834 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1835 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1836 };
1837 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsTzCnt32[] =
1838 {
1839 { 0, /* -> */ 32, false, X86_EFL_CF },
1840#if ARCH_BITS == 64
1841 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 32, false, X86_EFL_CF },
1842#endif
1843 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1844 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1845 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1846 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1847 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1848 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1849 };
1850#if ARCH_BITS == 64
1851 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsf64[] =
1852 {
1853 { 0, /* -> */ 0, true, X86_EFL_ZF },
1854 { ~(RTCCUINTXREG)0, /* -> */ 0, false, 0 },
1855 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1856 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1857 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1858 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1859 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1860 { UINT64_C(0x8000000000000000), /* -> */ 63, false, 0 },
1861 { UINT64_C(0x4560000000000000), /* -> */ 53, false, 0 },
1862 };
1863 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsTzCnt64[] =
1864 {
1865 { 0, /* -> */ 64, false, X86_EFL_CF },
1866 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1867 { ~(RTCCUINTXREG)1, /* -> */ 1, false, 0 },
1868 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
1869 { UINT16_C(0x4560), /* -> */ 5, false, 0 },
1870 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
1871 { UINT32_C(0x45600000), /* -> */ 21, false, 0 },
1872 { UINT64_C(0x8000000000000000), /* -> */ 63, false, 0 },
1873 { UINT64_C(0x4560000000000000), /* -> */ 53, false, 0 },
1874 };
1875#endif
1876 static BS3CPUINSTR2_TEST_BITSCAN_T s_aTests[] =
1877 {
1878 { BS3_CMN_NM(bs3CpuInstr2_bsf_AX_BX_ud2), false, 3 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1879 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1880 { BS3_CMN_NM(bs3CpuInstr2_bsf_AX_FSxBX_ud2), true, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1881 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1882 { BS3_CMN_NM(bs3CpuInstr2_bsf_EAX_EBX_ud2), false, 3 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1883 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1884 { BS3_CMN_NM(bs3CpuInstr2_bsf_EAX_FSxBX_ud2), true, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1885 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1886#if ARCH_BITS == 64
1887 { BS3_CMN_NM(bs3CpuInstr2_bsf_RAX_RBX_ud2), false, 4, 64, X86_EFL_ZF,
1888 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1889 { BS3_CMN_NM(bs3CpuInstr2_bsf_RAX_FSxBX_ud2), true, 5, 64, X86_EFL_ZF,
1890 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1891#endif
1892 /* f2 prefixed variant: */
1893 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1894 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1895 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
1896 RT_ELEMENTS(s_aSubTestsBsf16), s_aSubTestsBsf16 },
1897 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1898 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1899 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
1900 RT_ELEMENTS(s_aSubTestsBsf32), s_aSubTestsBsf32 },
1901#if ARCH_BITS == 64
1902 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF,
1903 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1904 { BS3_CMN_NM(bs3CpuInstr2_f2_bsf_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF,
1905 RT_ELEMENTS(s_aSubTestsBsf64), s_aSubTestsBsf64 },
1906#endif
1907
1908 /* tzcnt: */
1909 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1910 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1911 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1912 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1913 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1914 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1915 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1916 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1917#if ARCH_BITS == 64
1918 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF | X86_EFL_CF,
1919 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1920 { BS3_CMN_NM(bs3CpuInstr2_tzcnt_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF | X86_EFL_CF,
1921 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1922#endif
1923 /* f2 prefixed tzcnt variant (last prefix (f3) should prevail): */
1924 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_AX_BX_ud2), false, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1925 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1926 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_AX_FSxBX_ud2), true, 6 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
1927 RT_ELEMENTS(s_aSubTestsTzCnt16), s_aSubTestsTzCnt16 },
1928 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_EAX_EBX_ud2), false, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1929 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1930 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_EAX_FSxBX_ud2),true, 6 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
1931 RT_ELEMENTS(s_aSubTestsTzCnt32), s_aSubTestsTzCnt32 },
1932#if ARCH_BITS == 64
1933 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_RAX_RBX_ud2), false, 6, 64, X86_EFL_ZF | X86_EFL_CF,
1934 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1935 { BS3_CMN_NM(bs3CpuInstr2_f2_tzcnt_RAX_FSxBX_ud2),true, 7, 64, X86_EFL_ZF | X86_EFL_CF,
1936 RT_ELEMENTS(s_aSubTestsTzCnt64), s_aSubTestsTzCnt64 },
1937#endif
1938 };
1939
1940 uint32_t uStdExtFeatEbx = 0;
1941 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
1942 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
1943 if (!(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI1))
1944 {
1945 unsigned i = RT_ELEMENTS(s_aTests);
1946 while (i-- > 0)
1947 if (s_aTests[i].fEflCheck & X86_EFL_CF)
1948 {
1949 s_aTests[i].fEflCheck = X86_EFL_ZF;
1950 switch (s_aTests[i].cOpBits)
1951 {
1952 case 16:
1953 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsf16);
1954 s_aTests[i].paSubTests = s_aSubTestsBsf16;
1955 break;
1956 case 32:
1957 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsf32);
1958 s_aTests[i].paSubTests = s_aSubTestsBsf32;
1959 break;
1960#if ARCH_BITS == 64
1961 case 64:
1962 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsf64);
1963 s_aTests[i].paSubTests = s_aSubTestsBsf64;
1964 break;
1965#endif
1966 }
1967 }
1968 Bs3TestPrintf("tzcnt not supported\n");
1969 }
1970
1971 return bs3CpuInstr2_BitScan(bMode, s_aTests, RT_ELEMENTS(s_aTests));
1972}
1973
1974
1975BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bsr_lzcnt)(uint8_t bMode)
1976{
1977 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsr16[] =
1978 {
1979 { 0, /* -> */ 0, true, X86_EFL_ZF },
1980 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 0, true, X86_EFL_ZF },
1981 { ~(RTCCUINTXREG)0, /* -> */ 15, false, 0 },
1982 { ~(RTCCUINTXREG)1, /* -> */ 15, false, 0 },
1983 { UINT16_C(0x0001), /* -> */ 0, false, 0 },
1984 { UINT16_C(0x0002), /* -> */ 1, false, 0 },
1985 { UINT16_C(0x4560), /* -> */ 14, false, 0 },
1986 };
1987 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsLzCnt16[] =
1988 {
1989 { 0, /* -> */ 16, false, X86_EFL_CF },
1990 { ~(RTCCUINTXREG)UINT16_MAX, /* -> */ 16, false, X86_EFL_CF },
1991 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
1992 { ~(RTCCUINTXREG)1, /* -> */ 0, false, X86_EFL_ZF },
1993 { UINT16_C(0x8000), /* -> */ 0, false, X86_EFL_ZF },
1994 { UINT16_C(0x4560), /* -> */ 1, false, 0 },
1995 { UINT16_C(0x003f), /* -> */ 10, false, 0 },
1996 { UINT16_C(0x0001), /* -> */ 15, false, 0 },
1997 };
1998 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsr32[] =
1999 {
2000 { 0, /* -> */ 0, true, X86_EFL_ZF },
2001#if ARCH_BITS == 64
2002 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 0, true, X86_EFL_ZF },
2003#endif
2004 { ~(RTCCUINTXREG)0, /* -> */ 31, false, 0 },
2005 { ~(RTCCUINTXREG)1, /* -> */ 31, false, 0 },
2006 { 1, /* -> */ 0, false, 0 },
2007 { 2, /* -> */ 1, false, 0 },
2008 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
2009 { UINT16_C(0x4560), /* -> */ 14, false, 0 },
2010 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
2011 { UINT32_C(0x45600000), /* -> */ 30, false, 0 },
2012 };
2013 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsLzCnt32[] =
2014 {
2015 { 0, /* -> */ 32, false, X86_EFL_CF },
2016#if ARCH_BITS == 64
2017 { ~(RTCCUINTXREG)UINT32_MAX, /* -> */ 32, false, X86_EFL_CF },
2018#endif
2019 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
2020 { ~(RTCCUINTXREG)1, /* -> */ 0, false, X86_EFL_ZF },
2021 { 1, /* -> */ 31, false, 0 },
2022 { 2, /* -> */ 30, false, 0},
2023 { UINT16_C(0x8000), /* -> */ 16, false, 0 },
2024 { UINT16_C(0x4560), /* -> */ 17, false, 0 },
2025 { UINT32_C(0x80000000), /* -> */ 0, false, X86_EFL_ZF },
2026 { UINT32_C(0x45600000), /* -> */ 1, false, 0 },
2027 { UINT32_C(0x0000ffff), /* -> */ 16, false, 0 },
2028 };
2029#if ARCH_BITS == 64
2030 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsBsr64[] =
2031 {
2032 { 0, /* -> */ 0, true, X86_EFL_ZF },
2033 { ~(RTCCUINTXREG)0, /* -> */ 63, false, 0 },
2034 { ~(RTCCUINTXREG)1, /* -> */ 63, false, 0 },
2035 { 1, /* -> */ 0, false, 0 },
2036 { 2, /* -> */ 1, false, 0 },
2037 { UINT16_C(0x8000), /* -> */ 15, false, 0 },
2038 { UINT16_C(0x4560), /* -> */ 14, false, 0 },
2039 { UINT32_C(0x80000000), /* -> */ 31, false, 0 },
2040 { UINT32_C(0x45600000), /* -> */ 30, false, 0 },
2041 { UINT64_C(0x8000000000000000), /* -> */ 63, false, 0 },
2042 { UINT64_C(0x0045600000000000), /* -> */ 54, false, 0 },
2043 };
2044 static BS3CPUINSTR2_SUBTEST_BITSCAN_T const s_aSubTestsLzCnt64[] =
2045 {
2046 { 0, /* -> */ 64, false, X86_EFL_CF },
2047 { ~(RTCCUINTXREG)0, /* -> */ 0, false, X86_EFL_ZF },
2048 { ~(RTCCUINTXREG)1, /* -> */ 0, false, X86_EFL_ZF },
2049 { 1, /* -> */ 63, false, 0 },
2050 { 2, /* -> */ 62, false, 0 },
2051 { UINT16_C(0x8000), /* -> */ 48, false, 0 },
2052 { UINT16_C(0x4560), /* -> */ 49, false, 0 },
2053 { UINT32_C(0x80000000), /* -> */ 32, false, 0 },
2054 { UINT32_C(0x45600000), /* -> */ 33, false, 0 },
2055 { UINT64_C(0x8000000000000000), /* -> */ 0, false, X86_EFL_ZF },
2056 { UINT64_C(0x4560000000000000), /* -> */ 1, false, 0 },
2057 { UINT64_C(0x0045600000000000), /* -> */ 9, false, 0 },
2058 };
2059#endif
2060 static BS3CPUINSTR2_TEST_BITSCAN_T s_aTests[] =
2061 {
2062 { BS3_CMN_NM(bs3CpuInstr2_bsr_AX_BX_ud2), false, 3 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2063 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2064 { BS3_CMN_NM(bs3CpuInstr2_bsr_AX_FSxBX_ud2), true, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2065 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2066 { BS3_CMN_NM(bs3CpuInstr2_bsr_EAX_EBX_ud2), false, 3 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2067 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2068 { BS3_CMN_NM(bs3CpuInstr2_bsr_EAX_FSxBX_ud2), true, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2069 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2070#if ARCH_BITS == 64
2071 { BS3_CMN_NM(bs3CpuInstr2_bsr_RAX_RBX_ud2), false, 4, 64, X86_EFL_ZF,
2072 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2073 { BS3_CMN_NM(bs3CpuInstr2_bsr_RAX_FSxBX_ud2), true, 5, 64, X86_EFL_ZF,
2074 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2075#endif
2076 /* f2 prefixed variant: */
2077 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2078 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2079 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF,
2080 RT_ELEMENTS(s_aSubTestsBsr16), s_aSubTestsBsr16 },
2081 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2082 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2083 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF,
2084 RT_ELEMENTS(s_aSubTestsBsr32), s_aSubTestsBsr32 },
2085#if ARCH_BITS == 64
2086 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF,
2087 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2088 { BS3_CMN_NM(bs3CpuInstr2_f2_bsr_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF,
2089 RT_ELEMENTS(s_aSubTestsBsr64), s_aSubTestsBsr64 },
2090#endif
2091
2092 /* lzcnt: */
2093 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_AX_BX_ud2), false, 4 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2094 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2095 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_AX_FSxBX_ud2), true, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2096 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2097 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_EAX_EBX_ud2), false, 4 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2098 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2099 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_EAX_FSxBX_ud2), true, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2100 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2101#if ARCH_BITS == 64
2102 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_RAX_RBX_ud2), false, 5, 64, X86_EFL_ZF | X86_EFL_CF,
2103 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2104 { BS3_CMN_NM(bs3CpuInstr2_lzcnt_RAX_FSxBX_ud2), true, 6, 64, X86_EFL_ZF | X86_EFL_CF,
2105 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2106#endif
2107 /* f2 prefixed lzcnt variant (last prefix (f3) should prevail): */
2108 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_AX_BX_ud2), false, 5 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2109 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2110 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_AX_FSxBX_ud2), true, 6 + (ARCH_BITS != 16), 16, X86_EFL_ZF | X86_EFL_CF,
2111 RT_ELEMENTS(s_aSubTestsLzCnt16), s_aSubTestsLzCnt16 },
2112 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_EAX_EBX_ud2), false, 5 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2113 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2114 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_EAX_FSxBX_ud2),true, 6 + (ARCH_BITS == 16), 32, X86_EFL_ZF | X86_EFL_CF,
2115 RT_ELEMENTS(s_aSubTestsLzCnt32), s_aSubTestsLzCnt32 },
2116#if ARCH_BITS == 64
2117 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_RAX_RBX_ud2), false, 6, 64, X86_EFL_ZF | X86_EFL_CF,
2118 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2119 { BS3_CMN_NM(bs3CpuInstr2_f2_lzcnt_RAX_FSxBX_ud2),true, 7, 64, X86_EFL_ZF | X86_EFL_CF,
2120 RT_ELEMENTS(s_aSubTestsLzCnt64), s_aSubTestsLzCnt64 },
2121#endif
2122 };
2123
2124 uint32_t uExtFeatEcx = 0;
2125 if (g_uBs3CpuDetected & BS3CPU_F_CPUID_EXT_LEAVES)
2126 ASMCpuIdExSlow(UINT32_C(0x80000001), 0, 0, 0, NULL, NULL, &uExtFeatEcx, NULL);
2127 if (!(uExtFeatEcx & X86_CPUID_AMD_FEATURE_ECX_ABM))
2128 {
2129 unsigned i = RT_ELEMENTS(s_aTests);
2130 while (i-- > 0)
2131 if (s_aTests[i].fEflCheck & X86_EFL_CF)
2132 {
2133 s_aTests[i].fEflCheck = X86_EFL_ZF;
2134 switch (s_aTests[i].cOpBits)
2135 {
2136 case 16:
2137 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsr16);
2138 s_aTests[i].paSubTests = s_aSubTestsBsr16;
2139 break;
2140 case 32:
2141 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsr32);
2142 s_aTests[i].paSubTests = s_aSubTestsBsr32;
2143 break;
2144#if ARCH_BITS == 64
2145 case 64:
2146 s_aTests[i].cSubTests = RT_ELEMENTS(s_aSubTestsBsr64);
2147 s_aTests[i].paSubTests = s_aSubTestsBsr64;
2148 break;
2149#endif
2150 }
2151 }
2152 Bs3TestPrintf("lzcnt not supported\n");
2153 }
2154
2155 return bs3CpuInstr2_BitScan(bMode, s_aTests, RT_ELEMENTS(s_aTests));
2156}
2157
2158
2159/**
2160 * RORX
2161 */
2162BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rorx)(uint8_t bMode)
2163{
2164 static const struct
2165 {
2166 FPFNBS3FAR pfnWorker;
2167 bool fMemSrc;
2168 bool fOkay;
2169 RTCCUINTXREG uIn;
2170 RTCCUINTXREG uOut;
2171 } s_aTests[] =
2172 {
2173 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2174 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp), false, true, // #0
2175 0, /* -> */ 0 },
2176 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_RDX_2_icebp), false, true, // #1
2177 ~(RTCCUINTXREG)2, /* -> */ ~(RTCCUINTXREG)0 >> 1 },
2178 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_DSxDI_68_icebp), true, true, // #2
2179 0, /* -> */ 0 },
2180 { BS3_CMN_NM(bs3CpuInstr2_rorx_RBX_DSxDI_68_icebp), true, true, // #3
2181 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG_MAX >> 4) | (~(RTCCUINTXREG)2 << (sizeof(RTCCUINTXREG) * 8 - 4)) },
2182
2183 /* 32 bits register width: */
2184 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp), false, true, // #4
2185 0, /* -> */ 0 },
2186 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp), false, true, // #5
2187 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG)(~(uint32_t)0 >> 1) },
2188 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_DSxDI_36_icebp), true, true, // #6
2189 0, /* -> */ 0 },
2190 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_DSxDI_36_icebp), true, true, // #7
2191 ~(RTCCUINTXREG)2, /* -> */ (RTCCUINTXREG)UINT32_C(0xdfffffff) },
2192
2193 /* encoding tests: */
2194 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_L1), false, false, // #8
2195 RTCCUINTXREG_MAX, /* -> */ 0 },
2196 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V1), false, false, // #9
2197 RTCCUINTXREG_MAX, /* -> */ 0 },
2198 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_V15), false, false, // #10
2199 RTCCUINTXREG_MAX, /* -> */ 0 },
2200# if ARCH_BITS == 64 /* The VEX.X=0 encoding mean LES instruction in 32-bit and 16-bit mode. */
2201 { BS3_CMN_NM(bs3CpuInstr2_rorx_EBX_EDX_2_icebp_X1), false, true, // #11
2202 UINT32_C(0xf1e2d3c5), /* -> */ (RTCCUINTXREG)UINT32_C(0x7c78b4f1) },
2203# endif
2204 };
2205
2206 BS3REGCTX Ctx;
2207 BS3TRAPFRAME TrapFrame;
2208 unsigned i, j;
2209 uint32_t uStdExtFeatEbx = 0;
2210 bool fSupportsRorX;
2211
2212 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2213 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2214 fSupportsRorX = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI2);
2215
2216 /* Ensure the structures are allocated before we sample the stack pointer. */
2217 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2218 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2219
2220 /*
2221 * Create test context.
2222 */
2223 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2224
2225 /*
2226 * Do the tests twice, first with all flags set, then once again with
2227 * flags cleared. The flags are not supposed to be touched at all.
2228 */
2229 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2230 for (j = 0; j < 2; j++)
2231 {
2232 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
2233 {
2234 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && s_aTests[i].fOkay && fSupportsRorX;
2235 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2236 uint64_t uExpectRbx, uExpectRip;
2237 RTCCUINTXREG uMemSrc, uMemSrcExpect;
2238 Ctx.rbx.uCcXReg = RTCCUINTXREG_MAX * 1019;
2239 if (!s_aTests[i].fMemSrc)
2240 {
2241 Ctx.rdx.uCcXReg = s_aTests[i].uIn;
2242 uMemSrcExpect = uMemSrc = ~s_aTests[i].uIn;
2243 }
2244 else
2245 {
2246 Ctx.rdx.uCcXReg = ~s_aTests[i].uIn;
2247 uMemSrcExpect = uMemSrc = s_aTests[i].uIn;
2248 Bs3RegCtxSetGrpDsFromCurPtr(&Ctx, &Ctx.rdi, &uMemSrc);
2249 }
2250 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
2251 uExpectRbx = fOkay ? s_aTests[i].uOut : Ctx.rbx.u;
2252 uExpectRip = Ctx.rip.u + (fOkay ? 6 + 1 : 0);
2253 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2254
2255 if ( TrapFrame.bXcpt != bExpectXcpt
2256 || TrapFrame.Ctx.rip.u != uExpectRip
2257 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2258 || TrapFrame.Ctx.rbx.u != uExpectRbx
2259 /* check that nothing else really changed: */
2260 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS)
2261 || TrapFrame.Ctx.rax.u != Ctx.rax.u
2262 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2263 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2264 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2265 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2266 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2267 || uMemSrc != uMemSrcExpect
2268 )
2269 {
2270 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uIn);
2271 if (TrapFrame.bXcpt != bExpectXcpt)
2272 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2273 if (TrapFrame.Ctx.rip.u != uExpectRip)
2274 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2275 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2276 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2277 if (TrapFrame.Ctx.rbx.u != uExpectRbx)
2278 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", uExpectRbx, TrapFrame.Ctx.rbx.u);
2279
2280 if ((TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS))
2281 Bs3TestFailedF("Expected EFLAGS = %#06RX64, got %#06RX64",
2282 Ctx.rflags.u16 & X86_EFL_STATUS_BITS, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
2283 if (TrapFrame.Ctx.rax.u != Ctx.rax.u)
2284 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", Ctx.rax.u, TrapFrame.Ctx.rax.u);
2285 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2286 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2287 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2288 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2289 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2290 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2291 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2292 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2293 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2294 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2295 if (uMemSrc != uMemSrcExpect)
2296 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
2297 }
2298 }
2299 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2300 }
2301
2302 return 0;
2303}
2304
2305
2306BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_andn)(uint8_t bMode)
2307{
2308#define ANDN_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_ZF | X86_EFL_OF | X86_EFL_SF)
2309#define ANDN_IGNORE_EFLAGS (uint16_t)(X86_EFL_AF | X86_EFL_PF) /* undefined, ignoring for now */
2310 static const struct
2311 {
2312 FPFNBS3FAR pfnWorker;
2313 bool fMemSrc;
2314 uint8_t cbInstr;
2315 RTCCUINTXREG uSrc1;
2316 RTCCUINTXREG uSrc2;
2317 RTCCUINTXREG uOut;
2318 uint16_t fEFlags;
2319 } s_aTests[] =
2320 {
2321 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2322 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_RBX_icebp), false, 5, // #0
2323 0, 0, /* -> */ 0, X86_EFL_ZF },
2324 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_RBX_icebp), false, 5, // #1
2325 2, ~(RTCCUINTXREG)3, /* -> */ ~(RTCCUINTXREG)3, X86_EFL_SF },
2326 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_FSxBX_icebp), true, 6, // #2
2327 0, 0, /* -> */ 0, X86_EFL_ZF },
2328 { BS3_CMN_NM(bs3CpuInstr2_andn_RAX_RCX_FSxBX_icebp), true, 6, // #3
2329 2, ~(RTCCUINTXREG)3, /* -> */ ~(RTCCUINTXREG)3, X86_EFL_SF },
2330
2331 /* 32-bit register width */
2332 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_EBX_icebp), false, 5, // #4
2333 0, 0, /* -> */ 0, X86_EFL_ZF },
2334 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_EBX_icebp), false, 5, // #5
2335 2, ~(RTCCUINTXREG)7, /* -> */ ~(uint32_t)7, X86_EFL_SF },
2336 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_FSxBX_icebp), true, 6, // #6
2337 0, 0, /* -> */ 0, X86_EFL_ZF },
2338 { BS3_CMN_NM(bs3CpuInstr2_andn_EAX_ECX_FSxBX_icebp), true, 6, // #7
2339 2, ~(RTCCUINTXREG)7, /* -> */ ~(uint32_t)7, X86_EFL_SF },
2340
2341 };
2342
2343 BS3REGCTX Ctx;
2344 BS3TRAPFRAME TrapFrame;
2345 unsigned i, j;
2346 uint32_t uStdExtFeatEbx = 0;
2347 bool fSupportsAndN;
2348
2349 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2350 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2351 fSupportsAndN = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI1);
2352
2353 /* Ensure the structures are allocated before we sample the stack pointer. */
2354 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2355 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2356
2357 /*
2358 * Create test context.
2359 */
2360 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2361
2362 /*
2363 * Do the tests twice, first with all flags set, then once again with
2364 * flags cleared. The flags are not supposed to be touched at all.
2365 */
2366 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2367 for (j = 0; j < 2; j++)
2368 {
2369 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
2370 {
2371 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsAndN;
2372 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2373 uint64_t uExpectRax, uExpectRip;
2374 RTCCUINTXREG uMemSrc2, uMemSrc2Expect;
2375
2376 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
2377 Ctx.rcx.uCcXReg = s_aTests[i].uSrc1;
2378 if (!s_aTests[i].fMemSrc)
2379 {
2380 Ctx.rbx.uCcXReg = s_aTests[i].uSrc2;
2381 uMemSrc2Expect = uMemSrc2 = ~s_aTests[i].uSrc2;
2382 }
2383 else
2384 {
2385 uMemSrc2Expect = uMemSrc2 = s_aTests[i].uSrc2;
2386 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc2);
2387 }
2388 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
2389 uExpectRax = fOkay ? s_aTests[i].uOut : Ctx.rax.u;
2390 uExpectRip = Ctx.rip.u + (fOkay ? s_aTests[i].cbInstr + 1 : 0);
2391 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2392
2393 if ( TrapFrame.bXcpt != bExpectXcpt
2394 || TrapFrame.Ctx.rip.u != uExpectRip
2395 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2396 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
2397 || TrapFrame.Ctx.rax.u != uExpectRax
2398 /* check that nothing else really changed: */
2399 || (TrapFrame.Ctx.rflags.u16 & ANDN_CHECK_EFLAGS)
2400 != ((fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16) & ANDN_CHECK_EFLAGS)
2401 || (TrapFrame.Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS)
2402 != (Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS)
2403 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2404 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2405 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2406 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2407 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2408 || uMemSrc2 != uMemSrc2Expect
2409 )
2410 {
2411 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT ", %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uSrc1, s_aTests[i].uSrc2);
2412 if (TrapFrame.bXcpt != bExpectXcpt)
2413 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2414 if (TrapFrame.Ctx.rip.u != uExpectRip)
2415 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2416 if (TrapFrame.Ctx.rax.u != uExpectRax)
2417 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
2418 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2419 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2420 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
2421 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
2422 if ( (TrapFrame.Ctx.rflags.u16 & ANDN_CHECK_EFLAGS)
2423 != ((fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16) & ANDN_CHECK_EFLAGS))
2424 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
2425 (fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16) & ANDN_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & ANDN_CHECK_EFLAGS);
2426 if ( (TrapFrame.Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS)
2427 != (Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS))
2428 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
2429 Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS,
2430 TrapFrame.Ctx.rflags.u16 & ~(ANDN_CHECK_EFLAGS | ANDN_IGNORE_EFLAGS) & X86_EFL_STATUS_BITS);
2431
2432 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2433 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2434 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2435 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2436 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2437 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2438 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2439 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2440 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2441 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2442 if (uMemSrc2 != uMemSrc2Expect)
2443 Bs3TestFailedF("Expected uMemSrc2 = %#06RX64, got %#06RX64", (uint64_t)uMemSrc2Expect, (uint64_t)uMemSrc2);
2444 }
2445 }
2446 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2447 }
2448
2449 return 0;
2450}
2451
2452/*
2453 * For testing BEXTR, SHLX SARX & SHRX.
2454 */
2455typedef struct BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T
2456{
2457 RTCCUINTXREG uSrc1;
2458 RTCCUINTXREG uSrc2;
2459 RTCCUINTXREG uOut;
2460 uint16_t fEflOut;
2461} BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T;
2462
2463typedef struct BS3CPUINSTR2_TEST_Gy_Ey_By_T
2464{
2465 FPFNBS3FAR pfnWorker;
2466 bool fMemSrc;
2467 uint8_t cbInstr;
2468 uint8_t cSubTests;
2469 BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const *paSubTests;
2470} BS3CPUINSTR2_TEST_Gy_Ey_By_T;
2471
2472static uint8_t bs3CpuInstr2_Common_Gy_Ey_By(uint8_t bMode, BS3CPUINSTR2_TEST_Gy_Ey_By_T const *paTests, unsigned cTests,
2473 uint32_t fStdExtFeatEbx, uint16_t fEflCheck, uint16_t fEflIgnore)
2474{
2475 BS3REGCTX Ctx;
2476 BS3TRAPFRAME TrapFrame;
2477 unsigned i, j, k;
2478 uint32_t uStdExtFeatEbx = 0;
2479 bool fSupportsInstr;
2480
2481 fEflCheck &= ~fEflIgnore;
2482
2483 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2484 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2485 fSupportsInstr = RT_BOOL(uStdExtFeatEbx & fStdExtFeatEbx);
2486
2487 /* Ensure the structures are allocated before we sample the stack pointer. */
2488 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2489 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2490
2491 /*
2492 * Create test context.
2493 */
2494 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2495
2496 /*
2497 * Do the tests twice, first with all flags set, then once again with
2498 * flags cleared. The flags are not supposed to be touched at all.
2499 */
2500 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2501 for (j = 0; j < 2; j++)
2502 {
2503 for (i = 0; i < cTests; i++)
2504 {
2505 for (k = 0; k < paTests[i].cSubTests; k++)
2506 {
2507 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsInstr;
2508 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2509 uint64_t uExpectRax, uExpectRip;
2510 RTCCUINTXREG uMemSrc1, uMemSrc1Expect;
2511
2512 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
2513 Ctx.rcx.uCcXReg = paTests[i].paSubTests[k].uSrc2;
2514 if (!paTests[i].fMemSrc)
2515 {
2516 Ctx.rbx.uCcXReg = paTests[i].paSubTests[k].uSrc1;
2517 uMemSrc1Expect = uMemSrc1 = ~paTests[i].paSubTests[k].uSrc1;
2518 }
2519 else
2520 {
2521 uMemSrc1Expect = uMemSrc1 = paTests[i].paSubTests[k].uSrc1;
2522 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc1);
2523 }
2524 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paTests[i].pfnWorker);
2525 uExpectRax = fOkay ? paTests[i].paSubTests[k].uOut : Ctx.rax.u;
2526 uExpectRip = Ctx.rip.u + (fOkay ? paTests[i].cbInstr + 1 : 0);
2527 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2528
2529 if ( TrapFrame.bXcpt != bExpectXcpt
2530 || TrapFrame.Ctx.rip.u != uExpectRip
2531 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2532 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
2533 || TrapFrame.Ctx.rax.u != uExpectRax
2534 /* check that nothing else really changed: */
2535 || (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2536 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck)
2537 || (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2538 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2539 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2540 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2541 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2542 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2543 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2544 || uMemSrc1 != uMemSrc1Expect
2545 )
2546 {
2547 Bs3TestFailedF("test #%i/%i failed: input %#" RTCCUINTXREG_XFMT ", %#" RTCCUINTXREG_XFMT,
2548 i, k, paTests[i].paSubTests[k].uSrc1, paTests[i].paSubTests[k].uSrc2);
2549 if (TrapFrame.bXcpt != bExpectXcpt)
2550 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2551 if (TrapFrame.Ctx.rip.u != uExpectRip)
2552 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2553 if (TrapFrame.Ctx.rax.u != uExpectRax)
2554 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
2555 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2556 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2557 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
2558 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
2559 if ( (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2560 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck))
2561 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
2562 (fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck,
2563 TrapFrame.Ctx.rflags.u16 & fEflCheck);
2564 if ( (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2565 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS))
2566 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
2567 Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS,
2568 TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS);
2569
2570 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2571 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2572 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2573 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2574 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2575 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2576 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2577 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2578 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2579 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2580 if (uMemSrc1 != uMemSrc1Expect)
2581 Bs3TestFailedF("Expected uMemSrc1 = %#06RX64, got %#06RX64", (uint64_t)uMemSrc1Expect, (uint64_t)uMemSrc1);
2582 }
2583 }
2584 }
2585 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2586 }
2587
2588 return 0;
2589}
2590
2591
2592BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bextr)(uint8_t bMode)
2593{
2594 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2595 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2596 {
2597 { 0, RT_MAKE_U16(0, 0), /* -> */ 0, X86_EFL_ZF },
2598 { 0, RT_MAKE_U16(16, 33), /* -> */ 0, X86_EFL_ZF },
2599 { ~(RTCCUINTXREG)7, RT_MAKE_U16(2, 4), /* -> */ 0xe, 0},
2600 { ~(RTCCUINTXREG)7, RT_MAKE_U16(40, 8), /* -> */ ARCH_BITS == 64 ? 0xff : 0x00, ARCH_BITS == 64 ? 0 : X86_EFL_ZF },
2601 };
2602
2603 /* 32-bit register width */
2604 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2605 {
2606 { 0, RT_MAKE_U16(0, 0), /* -> */ 0, X86_EFL_ZF },
2607 { 0, RT_MAKE_U16(16, 18), /* -> */ 0, X86_EFL_ZF },
2608 { ~(RTCCUINTXREG)7, RT_MAKE_U16(2, 4), /* -> */ 0xe, 0 },
2609 { ~(RTCCUINTXREG)7, RT_MAKE_U16(24, 8), /* -> */ 0xff, 0 },
2610 { ~(RTCCUINTXREG)7, RT_MAKE_U16(31, 9), /* -> */ 1, 0 },
2611 { ~(RTCCUINTXREG)7, RT_MAKE_U16(42, 8), /* -> */ 0, X86_EFL_ZF },
2612 };
2613
2614 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2615 {
2616 { BS3_CMN_NM(bs3CpuInstr2_bextr_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2617 { BS3_CMN_NM(bs3CpuInstr2_bextr_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2618 { BS3_CMN_NM(bs3CpuInstr2_bextr_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2619 { BS3_CMN_NM(bs3CpuInstr2_bextr_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2620 };
2621 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2622 X86_EFL_STATUS_BITS, X86_EFL_AF | X86_EFL_SF | X86_EFL_PF);
2623}
2624
2625
2626BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_bzhi)(uint8_t bMode)
2627{
2628 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2629 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2630 {
2631 { 0, 0, /* -> */ 0, X86_EFL_ZF },
2632 { 0, ~(RTCCUINTXREG)255, /* -> */ 0, X86_EFL_ZF },
2633 { 0, 64, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
2634 { ~(RTCCUINTXREG)0, 64, /* -> */ ~(RTCCUINTXREG)0, X86_EFL_CF | X86_EFL_SF },
2635 { ~(RTCCUINTXREG)0, 63,
2636 /* -> */ ARCH_BITS >= 64 ? ~(RTCCUINTXREG)0 >> 1 : ~(RTCCUINTXREG)0, ARCH_BITS >= 64 ? 0 : X86_EFL_CF | X86_EFL_SF },
2637 { ~(RTCCUINTXREG)0 << 31 | UINT32_C(0x63849607), 24, /* -> */ UINT32_C(0x00849607), 0 },
2638 { ~(RTCCUINTXREG)0 << 31 | UINT32_C(0x63849607), 33,
2639 /* -> */ ARCH_BITS >= 64 ? UINT64_C(0x1e3849607) : UINT32_C(0xe3849607), ARCH_BITS >= 64 ? 0 : X86_EFL_CF | X86_EFL_SF },
2640 };
2641
2642 /* 32-bit register width */
2643 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2644 {
2645 { 0, 0, /* -> */ 0, X86_EFL_ZF },
2646 { 0, ~(RTCCUINTXREG)255, /* -> */ 0, X86_EFL_ZF },
2647 { 0, 32, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
2648 { ~(RTCCUINTXREG)0, 32, /* -> */ UINT32_MAX, X86_EFL_CF | X86_EFL_SF },
2649 { ~(RTCCUINTXREG)0, 31, /* -> */ UINT32_MAX >> 1, 0 },
2650 { UINT32_C(0x1230fd34), 15, /* -> */ UINT32_C(0x00007d34), 0 },
2651 };
2652
2653 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2654 {
2655 { BS3_CMN_NM(bs3CpuInstr2_bzhi_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2656 { BS3_CMN_NM(bs3CpuInstr2_bzhi_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2657 { BS3_CMN_NM(bs3CpuInstr2_bzhi_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2658 { BS3_CMN_NM(bs3CpuInstr2_bzhi_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2659 };
2660 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI2,
2661 X86_EFL_STATUS_BITS, 0);
2662}
2663
2664
2665/** @note This is a Gy_By_Ey format instruction, so we're switching the two
2666 * source registers around when calling bs3CpuInstr2_Common_Gy_Ey_By.
2667 * Sorry for the confusion, but it saves some unnecessary code dup. */
2668BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_pdep)(uint8_t bMode)
2669{
2670 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2671 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2672 { /* Mask (RBX/[FS:xBX]), source=RCX */
2673 { 0, 0, /* -> */ 0, 0 },
2674 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2675 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2676 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)0, 0 },
2677#if ARCH_BITS >= 64
2678 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)0, /* -> */ UINT64_C(0x3586049947589201), 0 },
2679 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)7, /* -> */ UINT64_C(0x3586049947588000), 0 },
2680#endif
2681 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x47589201), 0 },
2682 { UINT32_C(0x47589201), ~(RTCCUINTXREG)7, /* -> */ UINT32_C(0x47588000), 0 },
2683 };
2684
2685 /* 32-bit register width */
2686 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2687 { /* Mask (EBX/[FS:xBX]), source=ECX */
2688 { 0, 0, /* -> */ 0, 0 },
2689 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2690 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2691 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ UINT32_MAX, 0 },
2692 { UINT32_C(0x01010101), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x01010101), 0 },
2693 { UINT32_C(0x01010101), ~(RTCCUINTXREG)3, /* -> */ UINT32_C(0x01010000), 0 },
2694 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x47589201), 0 },
2695 };
2696
2697 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2698 {
2699 { BS3_CMN_NM(bs3CpuInstr2_pdep_RAX_RCX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2700 { BS3_CMN_NM(bs3CpuInstr2_pdep_RAX_RCX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2701 { BS3_CMN_NM(bs3CpuInstr2_pdep_EAX_ECX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2702 { BS3_CMN_NM(bs3CpuInstr2_pdep_EAX_ECX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2703 };
2704 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI2, 0, 0);
2705}
2706
2707
2708/** @note Same note as for bs3CpuInstr2_pdep */
2709BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_pext)(uint8_t bMode)
2710{
2711 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2712 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2713 { /* Mask (RBX/[FS:xBX]), source=RCX */
2714 { 0, 0, /* -> */ 0, 0 },
2715 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2716 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2717 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)0, 0 },
2718#if ARCH_BITS >= 64
2719 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)0, /* -> */ UINT64_C(0x00000000007fffff), 0 },
2720 { UINT64_C(0x3586049947589201), ~(RTCCUINTXREG)7, /* -> */ UINT64_C(0x00000000007ffffe), 0 },
2721#endif
2722 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x000007ff), 0 },
2723 { UINT32_C(0x47589201), ~(RTCCUINTXREG)7, /* -> */ UINT32_C(0x000007fe), 0 },
2724 };
2725
2726 /* 32-bit register width */
2727 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2728 { /* Mask (EBX/[FS:xBX]), source=ECX */
2729 { 0, 0, /* -> */ 0, 0 },
2730 { 0, ~(RTCCUINTXREG)0, /* -> */ 0, 0 },
2731 { ~(RTCCUINTXREG)0, 0, /* -> */ 0, 0 },
2732 { ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ UINT32_MAX, 0 },
2733 { UINT32_C(0x01010101), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x0000000f), 0 },
2734 { UINT32_C(0x01010101), ~(RTCCUINTXREG)3, /* -> */ UINT32_C(0x0000000e), 0 },
2735 { UINT32_C(0x47589201), ~(RTCCUINTXREG)0, /* -> */ UINT32_C(0x000007ff), 0 },
2736 { UINT32_C(0x47589201), ~(RTCCUINTXREG)7, /* -> */ UINT32_C(0x000007fe), 0 },
2737 };
2738
2739 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2740 {
2741 { BS3_CMN_NM(bs3CpuInstr2_pext_RAX_RCX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2742 { BS3_CMN_NM(bs3CpuInstr2_pext_RAX_RCX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2743 { BS3_CMN_NM(bs3CpuInstr2_pext_EAX_ECX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2744 { BS3_CMN_NM(bs3CpuInstr2_pext_EAX_ECX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2745 };
2746 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI2, 0, 0);
2747}
2748
2749
2750BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shlx)(uint8_t bMode)
2751{
2752 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2753 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2754 {
2755 { 0, 0, /* -> */ 0, 0 },
2756 { 0, ~(RTCCUINTXREG)3, /* -> */ 0, 0 },
2757 { ~(RTCCUINTXREG)7, 8, /* -> */ ~(RTCCUINTXREG)0x7ff, 0},
2758 { ~(RTCCUINTXREG)7, 40, /* -> */ ~(RTCCUINTXREG)7 << (ARCH_BITS == 64 ? 40 : 8), 0 },
2759 { ~(RTCCUINTXREG)7, 72, /* -> */ ~(RTCCUINTXREG)7 << 8, 0 },
2760 };
2761
2762 /* 32-bit register width */
2763 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2764 {
2765 { 0, 0, /* -> */ 0, 0 },
2766 { 0, ~(RTCCUINTXREG)9, /* -> */ 0, 0 },
2767 { ~(RTCCUINTXREG)7, 8, /* -> */ UINT32_C(0xfffff800), 0 },
2768 { ~(RTCCUINTXREG)7, 8, /* -> */ UINT32_C(0xfffff800), 0 },
2769 };
2770
2771 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2772 {
2773 { BS3_CMN_NM(bs3CpuInstr2_shlx_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2774 { BS3_CMN_NM(bs3CpuInstr2_shlx_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2775 { BS3_CMN_NM(bs3CpuInstr2_shlx_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2776 { BS3_CMN_NM(bs3CpuInstr2_shlx_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2777 };
2778 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2779 0, 0);
2780}
2781
2782
2783BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_sarx)(uint8_t bMode)
2784{
2785 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2786 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2787 {
2788 { 0, 0, /* -> */ 0, 0 },
2789 { 0, ~(RTCCUINTXREG)3, /* -> */ 0, 0 },
2790 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1, /* -> */ ~(RTCCUINTXREG)0, 0 },
2791 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1 + 64, /* -> */ ~(RTCCUINTXREG)0, 0 },
2792 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3, /* -> */ 2, 0 },
2793 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3 + 64, /* -> */ 2, 0 },
2794 };
2795
2796 /* 32-bit register width */
2797 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2798 {
2799 { 0, 0, /* -> */ 0, 0 },
2800 { 0, ~(RTCCUINTXREG)9, /* -> */ 0, 0 },
2801 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24, /* -> */ UINT32_C(0xffffff80), 0 },
2802 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24+32, /* -> */ UINT32_C(0xffffff80), 0 },
2803 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24, /* -> */ UINT32_C(0x40), 0 },
2804 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24+32, /* -> */ UINT32_C(0x40), 0 },
2805 };
2806
2807 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2808 {
2809 { BS3_CMN_NM(bs3CpuInstr2_sarx_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2810 { BS3_CMN_NM(bs3CpuInstr2_sarx_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2811 { BS3_CMN_NM(bs3CpuInstr2_sarx_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2812 { BS3_CMN_NM(bs3CpuInstr2_sarx_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2813 };
2814 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2815 0, 0);
2816}
2817
2818
2819BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_shrx)(uint8_t bMode)
2820{
2821 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2822 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests64[] =
2823 {
2824 { 0, 0, /* -> */ 0, 0 },
2825 { 0, ~(RTCCUINTXREG)3, /* -> */ 0, 0 },
2826 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1, /* -> */ 1, 0 },
2827 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 1), RTCCINTXREG_BITS - 1 + 64, /* -> */ 1, 0 },
2828 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3, /* -> */ 2, 0 },
2829 { (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), RTCCINTXREG_BITS - 3 + 64, /* -> */ 2, 0 },
2830 };
2831
2832 /* 32-bit register width */
2833 static BS3CPUINSTR2_SUBTEST_Gy_Ey_By_T const s_aSubTests32[] =
2834 {
2835 { 0, 0, /* -> */ 0, 0 },
2836 { 0, ~(RTCCUINTXREG)9, /* -> */ 0, 0 },
2837 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24, /* -> */ UINT32_C(0x80), 0 },
2838 { ~(RTCCUINTXREG)UINT32_C(0x7fffffff), 24+32, /* -> */ UINT32_C(0x80), 0 },
2839 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24, /* -> */ UINT32_C(0x40), 0 },
2840 { ~(RTCCUINTXREG)UINT32_C(0xbfffffff), 24+32, /* -> */ UINT32_C(0x40), 0 },
2841 };
2842
2843 static BS3CPUINSTR2_TEST_Gy_Ey_By_T const s_aTests[] =
2844 {
2845 { BS3_CMN_NM(bs3CpuInstr2_shrx_RAX_RBX_RCX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2846 { BS3_CMN_NM(bs3CpuInstr2_shrx_RAX_FSxBX_RCX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
2847 { BS3_CMN_NM(bs3CpuInstr2_shrx_EAX_EBX_ECX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2848 { BS3_CMN_NM(bs3CpuInstr2_shrx_EAX_FSxBX_ECX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
2849 };
2850 return bs3CpuInstr2_Common_Gy_Ey_By(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
2851 0, 0);
2852}
2853
2854
2855/*
2856 * For testing BLSR, BLSMSK, and BLSI.
2857 */
2858typedef struct BS3CPUINSTR2_SUBTEST_By_Ey_T
2859{
2860 RTCCUINTXREG uSrc;
2861 RTCCUINTXREG uDst;
2862 uint16_t fEflOut;
2863} BS3CPUINSTR2_SUBTEST_By_Ey_T;
2864
2865typedef struct BS3CPUINSTR2_TEST_By_Ey_T
2866{
2867 FPFNBS3FAR pfnWorker;
2868 bool fMemSrc;
2869 uint8_t cbInstr;
2870 uint8_t cSubTests;
2871 BS3CPUINSTR2_SUBTEST_By_Ey_T const *paSubTests;
2872} BS3CPUINSTR2_TEST_By_Ey_T;
2873
2874static uint8_t bs3CpuInstr2_Common_By_Ey(uint8_t bMode, BS3CPUINSTR2_TEST_By_Ey_T const *paTests, unsigned cTests,
2875 uint32_t fStdExtFeatEbx, uint16_t fEflCheck, uint16_t fEflIgnore)
2876{
2877 BS3REGCTX Ctx;
2878 BS3TRAPFRAME TrapFrame;
2879 unsigned i, j, k;
2880 uint32_t uStdExtFeatEbx = 0;
2881 bool fSupportsInstr;
2882
2883 fEflCheck &= ~fEflIgnore;
2884
2885 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
2886 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
2887 fSupportsInstr = RT_BOOL(uStdExtFeatEbx & fStdExtFeatEbx);
2888
2889 /* Ensure the structures are allocated before we sample the stack pointer. */
2890 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
2891 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
2892
2893 /*
2894 * Create test context.
2895 */
2896 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
2897
2898 /*
2899 * Do the tests twice, first with all flags set, then once again with
2900 * flags cleared. The flags are not supposed to be touched at all.
2901 */
2902 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
2903 for (j = 0; j < 2; j++)
2904 {
2905 for (i = 0; i < cTests; i++)
2906 {
2907 for (k = 0; k < paTests[i].cSubTests; k++)
2908 {
2909 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsInstr;
2910 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
2911 uint64_t uExpectRax, uExpectRip;
2912 RTCCUINTXREG uMemSrc, uMemSrcExpect;
2913
2914 Ctx.rax.uCcXReg = ~paTests[i].paSubTests[k].uSrc ^ 0x593e7591;
2915 if (!paTests[i].fMemSrc)
2916 {
2917 Ctx.rbx.uCcXReg = paTests[i].paSubTests[k].uSrc;
2918 uMemSrcExpect = uMemSrc = ~paTests[i].paSubTests[k].uSrc;
2919 }
2920 else
2921 {
2922 uMemSrcExpect = uMemSrc = paTests[i].paSubTests[k].uSrc;
2923 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
2924 }
2925 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paTests[i].pfnWorker);
2926 uExpectRax = fOkay ? paTests[i].paSubTests[k].uDst : Ctx.rax.u;
2927 uExpectRip = Ctx.rip.u + (fOkay ? paTests[i].cbInstr + 1 : 0);
2928 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
2929
2930 if ( TrapFrame.bXcpt != bExpectXcpt
2931 || TrapFrame.Ctx.rip.u != uExpectRip
2932 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
2933 || TrapFrame.Ctx.rax.u != uExpectRax
2934 /* check that nothing else really changed: */
2935 || (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2936 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck)
2937 || (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2938 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2939 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
2940 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
2941 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
2942 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
2943 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
2944 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
2945 || uMemSrc != uMemSrcExpect
2946 )
2947 {
2948 Bs3TestFailedF("test #%i/%i failed: input %#" RTCCUINTXREG_XFMT,
2949 i, k, paTests[i].paSubTests[k].uSrc);
2950 if (TrapFrame.bXcpt != bExpectXcpt)
2951 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
2952 if (TrapFrame.Ctx.rip.u != uExpectRip)
2953 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
2954 if (TrapFrame.Ctx.rax.u != uExpectRax)
2955 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
2956 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
2957 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
2958 if ( (TrapFrame.Ctx.rflags.u16 & fEflCheck)
2959 != ((fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck))
2960 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (output)",
2961 (fOkay ? paTests[i].paSubTests[k].fEflOut : Ctx.rflags.u16) & fEflCheck,
2962 TrapFrame.Ctx.rflags.u16 & fEflCheck);
2963 if ( (TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS)
2964 != (Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS))
2965 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
2966 Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS,
2967 TrapFrame.Ctx.rflags.u16 & ~(fEflCheck | fEflIgnore) & X86_EFL_STATUS_BITS);
2968
2969 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
2970 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
2971 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
2972 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
2973 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
2974 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
2975 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
2976 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
2977 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
2978 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
2979 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
2980 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
2981 if (uMemSrc != uMemSrcExpect)
2982 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
2983 }
2984 }
2985 }
2986 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
2987 }
2988
2989 return 0;
2990}
2991
2992
2993BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_blsr)(uint8_t bMode)
2994{
2995 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
2996 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests64[] =
2997 {
2998 { 0, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
2999 { 1, /* -> */ 0, X86_EFL_ZF },
3000 { 2, /* -> */ 0, X86_EFL_ZF },
3001 { 3, /* -> */ 2, 0 },
3002 { 5, /* -> */ 4, 0 },
3003 { 6, /* -> */ 4, 0 },
3004 { 7, /* -> */ 6, 0 },
3005 { 9, /* -> */ 8, 0 },
3006 { 10, /* -> */ 8, 0 },
3007 { ~(RTCCUINTXREG)1, /* -> */ ~(RTCCUINTXREG)3, X86_EFL_SF },
3008 { (RTCCUINTXREG)3 << (RTCCINTXREG_BITS - 2), /* -> */ (RTCCUINTXREG)2 << (RTCCINTXREG_BITS - 2), X86_EFL_SF },
3009 };
3010
3011 /* 32-bit register width */
3012 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests32[] =
3013 {
3014 { 0, /* -> */ 0, X86_EFL_ZF | X86_EFL_CF },
3015 { 1, /* -> */ 0, X86_EFL_ZF },
3016 { ~(RTCCUINTXREG)1, /* -> */ UINT32_C(0xfffffffc), X86_EFL_SF },
3017 { ~(RTCCUINTXREG)0 << 30, /* -> */ UINT32_C(0x80000000), X86_EFL_SF },
3018 };
3019
3020 static BS3CPUINSTR2_TEST_By_Ey_T const s_aTests[] =
3021 {
3022 { BS3_CMN_NM(bs3CpuInstr2_blsr_RAX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3023 { BS3_CMN_NM(bs3CpuInstr2_blsr_RAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3024 { BS3_CMN_NM(bs3CpuInstr2_blsr_EAX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3025 { BS3_CMN_NM(bs3CpuInstr2_blsr_EAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3026 };
3027 return bs3CpuInstr2_Common_By_Ey(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
3028 X86_EFL_STATUS_BITS, 0);
3029}
3030
3031
3032BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_blsmsk)(uint8_t bMode)
3033{
3034 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
3035 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests64[] =
3036 {
3037 { 0, /* -> */ ~(RTCCUINTXREG)0, X86_EFL_CF | X86_EFL_SF },
3038 { 1, /* -> */ 1, 0 },
3039 { ~(RTCCUINTXREG)1, /* -> */ 3, 0 },
3040 { (RTCCUINTXREG)3 << (RTCCINTXREG_BITS - 2), /* -> */ ~((RTCCUINTXREG)2 << (RTCCINTXREG_BITS - 2)), 0 },
3041 };
3042
3043 /* 32-bit register width */
3044 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests32[] =
3045 {
3046 { 0, /* -> */ UINT32_MAX, X86_EFL_CF | X86_EFL_SF },
3047 { 1, /* -> */ 1, 0 },
3048 { ~(RTCCUINTXREG)1, /* -> */ 3, 0 },
3049 { ~(RTCCUINTXREG)0 << 30, /* -> */ UINT32_C(0x7fffffff), 0},
3050 };
3051
3052 static BS3CPUINSTR2_TEST_By_Ey_T const s_aTests[] =
3053 {
3054 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_RAX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3055 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_RAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3056 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_EAX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3057 { BS3_CMN_NM(bs3CpuInstr2_blsmsk_EAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3058 };
3059 return bs3CpuInstr2_Common_By_Ey(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
3060 X86_EFL_STATUS_BITS, 0);
3061}
3062
3063
3064BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_blsi)(uint8_t bMode)
3065{
3066 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
3067 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests64[] =
3068 {
3069 { 0, /* -> */ 0, X86_EFL_ZF },
3070 { 1, /* -> */ 1, X86_EFL_CF },
3071 { ~(RTCCUINTXREG)1, /* -> */ 2, X86_EFL_CF },
3072 { (RTCCUINTXREG)3 << (RTCCINTXREG_BITS - 2), /* -> */ (RTCCUINTXREG)1 << (RTCCINTXREG_BITS - 2), X86_EFL_CF },
3073 };
3074
3075 /* 32-bit register width */
3076 static BS3CPUINSTR2_SUBTEST_By_Ey_T const s_aSubTests32[] =
3077 {
3078 { 0, /* -> */ 0, X86_EFL_ZF },
3079 { 1, /* -> */ 1, X86_EFL_CF },
3080 { ~(RTCCUINTXREG)1, /* -> */ 2, X86_EFL_CF },
3081 { ~(RTCCUINTXREG)0 << 30, /* -> */ UINT32_C(0x40000000), X86_EFL_CF },
3082 };
3083
3084 static BS3CPUINSTR2_TEST_By_Ey_T const s_aTests[] =
3085 {
3086 { BS3_CMN_NM(bs3CpuInstr2_blsi_RAX_RBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3087 { BS3_CMN_NM(bs3CpuInstr2_blsi_RAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests64), s_aSubTests64 },
3088 { BS3_CMN_NM(bs3CpuInstr2_blsi_EAX_EBX_icebp), false, 5, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3089 { BS3_CMN_NM(bs3CpuInstr2_blsi_EAX_FSxBX_icebp), true, 6, RT_ELEMENTS(s_aSubTests32), s_aSubTests32 },
3090 };
3091 return bs3CpuInstr2_Common_By_Ey(bMode, s_aTests, RT_ELEMENTS(s_aTests), X86_CPUID_STEXT_FEATURE_EBX_BMI1,
3092 X86_EFL_STATUS_BITS, 0);
3093}
3094
3095
3096/*
3097 * MULX (BMI2) - destination registers (/r & vvvv) = r/m * rDX
3098 */
3099BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mulx)(uint8_t bMode)
3100{
3101 static const struct
3102 {
3103 FPFNBS3FAR pfnWorker;
3104 bool fMemSrc;
3105 bool fSameDst;
3106 uint8_t cbInstr;
3107 RTCCUINTXREG uSrc1;
3108 RTCCUINTXREG uSrc2;
3109 RTCCUINTXREG uDst1;
3110 RTCCUINTXREG uDst2;
3111 } s_aTests[] =
3112 {
3113 /* 64 bits register width (32 bits in 32- and 16-bit modes): */
3114 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #0
3115 0, 0, /* -> */ 0, 0 },
3116 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #1
3117 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)1, 1 },
3118 { BS3_CMN_NM(bs3CpuInstr2_mulx_RCX_RCX_RBX_RDX_icebp), false, true, 5, // #2
3119 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)1, ~(RTCCUINTXREG)1 },
3120 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #3
3121 2, 2, /* -> */ 0, 4 },
3122 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_RBX_RDX_icebp), false, false, 5, // #4
3123 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(RTCCUINTXREG)41 },
3124
3125 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_FSxBX_RDX_icebp), true, false, 6, // #5
3126 0, 0, /* -> */ 0, 0 },
3127 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_FSxBX_RDX_icebp), true, false, 6, // #6
3128 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(RTCCUINTXREG)1, 1 },
3129 { BS3_CMN_NM(bs3CpuInstr2_mulx_RAX_RCX_FSxBX_RDX_icebp), true, false, 6, // #7
3130 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(RTCCUINTXREG)41 },
3131
3132 /* 32-bit register width */
3133 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #8
3134 0, 0, /* -> */ 0, 0 },
3135 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #9
3136 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(uint32_t)1, 1 },
3137 { BS3_CMN_NM(bs3CpuInstr2_mulx_ECX_ECX_EBX_EDX_icebp), false, true, 5, // #10
3138 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(uint32_t)1, ~(uint32_t)1 },
3139 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #11
3140 2, 2, /* -> */ 0, 4 },
3141 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_EBX_EDX_icebp), false, false, 5, // #12
3142 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(uint32_t)41 },
3143
3144 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_FSxBX_EDX_icebp), true, false, 6, // #13
3145 0, 0, /* -> */ 0, 0 },
3146 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_FSxBX_EDX_icebp), true, false, 6, // #14
3147 ~(RTCCUINTXREG)0, ~(RTCCUINTXREG)0, /* -> */ ~(uint32_t)1, 1 },
3148 { BS3_CMN_NM(bs3CpuInstr2_mulx_EAX_ECX_FSxBX_EDX_icebp), true, false, 6, // #15
3149 ~(RTCCUINTXREG)0, 42, /* -> */ 0x29, ~(uint32_t)41 },
3150 };
3151
3152 BS3REGCTX Ctx;
3153 BS3TRAPFRAME TrapFrame;
3154 unsigned i, j;
3155 uint32_t uStdExtFeatEbx = 0;
3156 bool fSupportsAndN;
3157
3158 if (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3159 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &uStdExtFeatEbx, NULL, NULL);
3160 fSupportsAndN = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_BMI2);
3161
3162 /* Ensure the structures are allocated before we sample the stack pointer. */
3163 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3164 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3165
3166 /*
3167 * Create test context.
3168 */
3169 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3170
3171 /*
3172 * Do the tests twice, first with all flags set, then once again with
3173 * flags cleared. The flags are not supposed to be touched at all.
3174 */
3175 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3176 for (j = 0; j < 2; j++)
3177 {
3178 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3179 {
3180 bool const fOkay = !BS3_MODE_IS_RM_OR_V86(bMode) && fSupportsAndN;
3181 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3182 uint64_t uExpectRax, uExpectRcx, uExpectRip;
3183 RTCCUINTXREG uMemSrc1, uMemSrc1Expect;
3184
3185 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
3186 Ctx.rcx.uCcXReg = RTCCUINTXREG_MAX * 4095;
3187 Ctx.rdx.uCcXReg = s_aTests[i].uSrc2;
3188 if (!s_aTests[i].fMemSrc)
3189 {
3190 Ctx.rbx.uCcXReg = s_aTests[i].uSrc1;
3191 uMemSrc1Expect = uMemSrc1 = ~s_aTests[i].uSrc1;
3192 }
3193 else
3194 {
3195 uMemSrc1Expect = uMemSrc1 = s_aTests[i].uSrc1;
3196 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc1);
3197 }
3198 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3199 uExpectRax = fOkay && !s_aTests[i].fSameDst ? s_aTests[i].uDst1 : Ctx.rax.u;
3200 uExpectRcx = fOkay ? s_aTests[i].uDst2 : Ctx.rcx.u;
3201 uExpectRip = Ctx.rip.u + (fOkay ? s_aTests[i].cbInstr + 1 : 0);
3202 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3203
3204 if ( TrapFrame.bXcpt != bExpectXcpt
3205 || TrapFrame.Ctx.rip.u != uExpectRip
3206 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3207 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3208 || TrapFrame.Ctx.rax.u != uExpectRax
3209 || TrapFrame.Ctx.rcx.u != uExpectRcx
3210 /* check that nothing else really changed: */
3211 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS)
3212 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3213 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3214 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3215 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3216 || uMemSrc1 != uMemSrc1Expect
3217 )
3218 {
3219 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT ", %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uSrc1, s_aTests[i].uSrc2);
3220 if (TrapFrame.bXcpt != bExpectXcpt)
3221 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3222 if (TrapFrame.Ctx.rip.u != uExpectRip)
3223 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3224 if (TrapFrame.Ctx.rax.u != uExpectRax)
3225 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3226 if (TrapFrame.Ctx.rcx.u != uExpectRcx)
3227 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", uExpectRcx, TrapFrame.Ctx.rcx.u);
3228 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3229 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3230 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3231 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3232
3233 if ( (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (Ctx.rflags.u16 & X86_EFL_STATUS_BITS))
3234 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32 (immutable)",
3235 Ctx.rflags.u16 & X86_EFL_STATUS_BITS, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
3236 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3237 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3238 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3239 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3240 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3241 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3242 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3243 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3244 if (uMemSrc1 != uMemSrc1Expect)
3245 Bs3TestFailedF("Expected uMemSrc1 = %#06RX64, got %#06RX64", (uint64_t)uMemSrc1Expect, (uint64_t)uMemSrc1);
3246 }
3247 }
3248 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3249 }
3250
3251 return 0;
3252}
3253
3254
3255/*
3256 * POPCNT - Intel: POPCNT; AMD: ABM.
3257 */
3258BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_popcnt)(uint8_t bMode)
3259{
3260 static const struct
3261 {
3262 FPFNBS3FAR pfnWorker;
3263 bool fMemSrc;
3264 uint8_t cWidth;
3265 uint8_t cbInstr;
3266 RTCCUINTXREG uSrc;
3267 RTCCUINTXREG uDst;
3268 uint16_t fEFlags;
3269 } s_aTests[] =
3270 {
3271 /* 16-bit register width */
3272 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #0
3273 0, /* -> */ 0, X86_EFL_ZF },
3274 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #1
3275 ~(RTCCUINTXREG)0, /* -> */ 16, 0 },
3276 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #2
3277 UINT16_C(0xffff), /* -> */ 16, 0 },
3278 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_BX_icebp), false, 16, 4 + (ARCH_BITS != 16), // #3
3279 UINT16_C(0x0304), /* -> */ 3, 0 },
3280 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_FSxBX_icebp), true, 16, 5 + (ARCH_BITS != 16), // #4
3281 UINT16_C(0xd569), /* -> */ 9, 0},
3282 { BS3_CMN_NM(bs3CpuInstr2_popcnt_AX_FSxBX_icebp), true, 16, 5 + (ARCH_BITS != 16), // #5
3283 0, /* -> */ 0, X86_EFL_ZF },
3284
3285 /* 32-bit register width */
3286 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_EBX_icebp), false, 32, 4 + (ARCH_BITS == 16), // #6
3287 0, /* -> */ 0, X86_EFL_ZF },
3288 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_EBX_icebp), false, 32, 4 + (ARCH_BITS == 16), // #7
3289 ~(RTCCUINTXREG)0, /* -> */ 32, 0},
3290 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_EBX_icebp), false, 32, 4 + (ARCH_BITS == 16), // #8
3291 UINT32_C(0x01020304), /* -> */ 5, 0},
3292 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_FSxBX_icebp), true, 32, 5 + (ARCH_BITS == 16), // #9
3293 0, /* -> */ 0, X86_EFL_ZF },
3294 { BS3_CMN_NM(bs3CpuInstr2_popcnt_EAX_FSxBX_icebp), true, 32, 5 + (ARCH_BITS == 16), // #10
3295 UINT32_C(0x49760948), /* -> */ 12, 0 },
3296
3297#if ARCH_BITS == 64
3298 /* 64-bit register width */
3299 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_RBX_icebp), false, 64, 5, // #11
3300 0, /* -> */ 0, X86_EFL_ZF },
3301 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_RBX_icebp), false, 64, 5, // #12
3302 ~(RTCCUINTXREG)0, /* -> */ 64, 0 },
3303 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_RBX_icebp), false, 64, 5, // #13
3304 UINT64_C(0x1234123412341234), /* -> */ 5*4, 0 },
3305 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_FSxBX_icebp), true, 64, 6, // #14
3306 0, /* -> */ 0, X86_EFL_ZF },
3307 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_FSxBX_icebp), true, 64, 6, // #15
3308 ~(RTCCUINTXREG)0, /* -> */ 64, 0 },
3309 { BS3_CMN_NM(bs3CpuInstr2_popcnt_RAX_FSxBX_icebp), true, 64, 6, // #16
3310 UINT64_C(0x5908760293769087), /* -> */ 26, 0 },
3311#endif
3312 };
3313
3314 BS3REGCTX Ctx;
3315 BS3TRAPFRAME TrapFrame;
3316 unsigned i, j;
3317 bool const fSupportsPopCnt = (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3318 && (ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_POPCNT);
3319
3320 /* Ensure the structures are allocated before we sample the stack pointer. */
3321 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3322 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3323
3324 /*
3325 * Create test context.
3326 */
3327 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3328
3329 /*
3330 * Do the tests twice, first with all flags set, then once again with
3331 * flags cleared. The flags are not supposed to be touched at all.
3332 */
3333 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3334 for (j = 0; j < 2; j++)
3335 {
3336 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3337 {
3338 bool const fOkay = fSupportsPopCnt;
3339 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3340 uint64_t uExpectRax, uExpectRip;
3341 RTCCUINTXREG uMemSrc, uMemSrcExpect;
3342
3343 Ctx.rax.uCcXReg = RTCCUINTXREG_MAX * 1019;
3344 if (!s_aTests[i].fMemSrc)
3345 {
3346 Ctx.rbx.uCcXReg = s_aTests[i].uSrc;
3347 uMemSrcExpect = uMemSrc = ~s_aTests[i].uSrc;
3348 }
3349 else
3350 {
3351 uMemSrcExpect = uMemSrc = s_aTests[i].uSrc;
3352 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
3353 }
3354 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3355 uExpectRax = fOkay ? s_aTests[i].uDst : Ctx.rax.u;
3356 if (s_aTests[i].cWidth == 16)
3357 uExpectRax = (uExpectRax & UINT16_MAX) | (Ctx.rax.u & ~(uint64_t)UINT16_MAX);
3358
3359 uExpectRip = Ctx.rip.u + (fOkay ? s_aTests[i].cbInstr + 1 : 0);
3360 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3361
3362 if ( TrapFrame.bXcpt != bExpectXcpt
3363 || TrapFrame.Ctx.rip.u != uExpectRip
3364 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3365 || TrapFrame.Ctx.rax.u != uExpectRax
3366 || (TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16)
3367 /* check that nothing else really changed: */
3368 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
3369 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3370 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3371 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3372 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3373 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3374 || uMemSrc != uMemSrcExpect
3375 )
3376 {
3377 Bs3TestFailedF("test #%i failed: input %#" RTCCUINTXREG_XFMT, i, s_aTests[i].uSrc);
3378 if (TrapFrame.bXcpt != bExpectXcpt)
3379 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3380 if (TrapFrame.Ctx.rip.u != uExpectRip)
3381 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3382 if (TrapFrame.Ctx.rax.u != uExpectRax)
3383 Bs3TestFailedF("Expected RAX = %#06RX64, got %#06RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3384 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3385 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3386 if ((TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS) != (fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16))
3387 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32",
3388 fOkay ? s_aTests[i].fEFlags : Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16 & X86_EFL_STATUS_BITS);
3389
3390 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
3391 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
3392 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3393 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3394 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3395 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3396 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3397 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3398 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3399 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3400 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3401 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3402 if (uMemSrc != uMemSrcExpect)
3403 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
3404 }
3405 }
3406 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3407 }
3408
3409 return 0;
3410}
3411
3412/*
3413 * CRC32 - SSE4.2
3414 */
3415BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_crc32)(uint8_t bMode)
3416{
3417 typedef struct BS3CPUINSTR2_CRC32_VALUES_T
3418 {
3419 uint32_t uDstIn;
3420 uint32_t uDstOut;
3421 uint64_t uSrc;
3422 } BS3CPUINSTR2_CRC32_VALUES_T;
3423 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues1[] =
3424 {
3425 { UINT32_C(0000000000), UINT32_C(0000000000), UINT8_C(0000) },
3426 { UINT32_C(0xffffffff), UINT32_C(0x25502c8c), UINT8_C(0xea) },
3427 { UINT32_C(0x25502c8c), UINT32_C(0x474224a6), UINT8_C(0xea) },
3428 { UINT32_C(0x474224a6), UINT32_C(0x0c7f9048), UINT8_C(0xea) },
3429 { UINT32_C(0x0c7f9048), UINT32_C(0x39c5b9e0), UINT8_C(0x01) },
3430 { UINT32_C(0x39c5b9e0), UINT32_C(0x2493fabc), UINT8_C(0x04) },
3431 { UINT32_C(0x2493fabc), UINT32_C(0x0b05c4d6), UINT8_C(0x27) },
3432 { UINT32_C(0x0b05c4d6), UINT32_C(0xbe26a561), UINT8_C(0x2a) },
3433 { UINT32_C(0xbe26a561), UINT32_C(0xe1855652), UINT8_C(0x63) },
3434 { UINT32_C(0xe1855652), UINT32_C(0xc67efe3f), UINT8_C(0xa7) },
3435 { UINT32_C(0xc67efe3f), UINT32_C(0x227028cd), UINT8_C(0xfd) },
3436 { UINT32_C(0x227028cd), UINT32_C(0xf4559a1d), UINT8_C(0xea) },
3437 };
3438 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues2[] =
3439 {
3440 { UINT32_C(0000000000), UINT32_C(0000000000), UINT16_C(000000) },
3441 { UINT32_C(0xffffffff), UINT32_C(0xd550e2a0), UINT16_C(0x04d2) },
3442 { UINT32_C(0xd550e2a0), UINT32_C(0x38e07a0a), UINT16_C(0xe8cc) },
3443 { UINT32_C(0x38e07a0a), UINT32_C(0x60ebd519), UINT16_C(0x82a2) },
3444 { UINT32_C(0x60ebd519), UINT32_C(0xaaa127b5), UINT16_C(0x0fff) },
3445 { UINT32_C(0xaaa127b5), UINT32_C(0xb13175c6), UINT16_C(0x00ff) },
3446 { UINT32_C(0xb13175c6), UINT32_C(0x3a226f1b), UINT16_C(0x0300) },
3447 { UINT32_C(0x3a226f1b), UINT32_C(0xbaedef0c), UINT16_C(0x270f) },
3448 { UINT32_C(0xbaedef0c), UINT32_C(0x2d18866e), UINT16_C(0x3ff6) },
3449 { UINT32_C(0x2d18866e), UINT32_C(0x07e2e954), UINT16_C(0x9316) },
3450 { UINT32_C(0x07e2e954), UINT32_C(0x95f82acb), UINT16_C(0xa59c) },
3451 };
3452 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues4[] =
3453 {
3454 { UINT32_C(0000000000), UINT32_C(0000000000), UINT32_C(0000000000) },
3455 { UINT32_C(0xffffffff), UINT32_C(0xc9a7250e), UINT32_C(0x0270fa68) },
3456 { UINT32_C(0xc9a7250e), UINT32_C(0x7340d175), UINT32_C(0x23729736) },
3457 { UINT32_C(0x7340d175), UINT32_C(0x7e17b67d), UINT32_C(0x8bc75d35) },
3458 { UINT32_C(0x7e17b67d), UINT32_C(0x5028eb71), UINT32_C(0x0e9bebf2) },
3459 { UINT32_C(0x5028eb71), UINT32_C(0xc0a7f45a), UINT32_C(0x000001bc) },
3460 { UINT32_C(0xc0a7f45a), UINT32_C(0xa96f4012), UINT32_C(0x0034ba02) },
3461 { UINT32_C(0xa96f4012), UINT32_C(0xb27c0718), UINT32_C(0x0000002a) },
3462 { UINT32_C(0xb27c0718), UINT32_C(0x79fb2d35), UINT32_C(0x0153158e) },
3463 { UINT32_C(0x79fb2d35), UINT32_C(0x23434fc9), UINT32_C(0x02594882) },
3464 { UINT32_C(0x23434fc9), UINT32_C(0x354bf3b6), UINT32_C(0xb230b8f3) },
3465 };
3466#if ARCH_BITS >= 64
3467 static const BS3CPUINSTR2_CRC32_VALUES_T s_aValues8[] =
3468 {
3469 { UINT32_C(0000000000), UINT32_C(0000000000), UINT64_C(000000000000000000) },
3470 { UINT32_C(0xffffffff), UINT32_C(0xadc36834), UINT64_C(0x02b0b5e2a975c1cc) },
3471 { UINT32_C(0xadc36834), UINT32_C(0xf0e893c9), UINT64_C(0x823d386bf7517583) },
3472 { UINT32_C(0xf0e893c9), UINT32_C(0x1a22a837), UINT64_C(0x0481f5311fa061d0) },
3473 { UINT32_C(0x1a22a837), UINT32_C(0xcf8b6d61), UINT64_C(0x13fa70f64d52a92d) },
3474 { UINT32_C(0xcf8b6d61), UINT32_C(0xc7dde203), UINT64_C(0x3ccc8b035903d3e1) },
3475 { UINT32_C(0xc7dde203), UINT32_C(0xd42b5823), UINT64_C(0x0000011850ec2fac) },
3476 { UINT32_C(0xd42b5823), UINT32_C(0x8b1ce49e), UINT64_C(0x0000000000001364) },
3477 { UINT32_C(0x8b1ce49e), UINT32_C(0x1af31710), UINT64_C(0x000000057840205a) },
3478 { UINT32_C(0x1af31710), UINT32_C(0xdea35e8b), UINT64_C(0x2e5d93688d9a0bfa) },
3479 { UINT32_C(0xdea35e8b), UINT32_C(0x594c013a), UINT64_C(0x8ac7230489e7ffff) },
3480 { UINT32_C(0x594c013a), UINT32_C(0x27b061e5), UINT64_C(0x6bf037ae325f1c71) },
3481 { UINT32_C(0x27b061e5), UINT32_C(0x3120b5f7), UINT64_C(0x0fffffff34503556) },
3482 };
3483#endif
3484 static const struct
3485 {
3486 FPFNBS3FAR pfnWorker;
3487 bool fMemSrc;
3488 uint8_t cbOp;
3489 uint8_t cValues;
3490 BS3CPUINSTR2_CRC32_VALUES_T const BS3_FAR *paValues;
3491 } s_aTests[] =
3492 {
3493 /* 8-bit register width */
3494 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_BL_icebp), false, 1, RT_ELEMENTS(s_aValues1), s_aValues1 },
3495 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_byte_FSxBX_icebp), true, 1, RT_ELEMENTS(s_aValues1), s_aValues1 },
3496
3497 /* 16-bit register width */
3498 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_BX_icebp), false, 2, RT_ELEMENTS(s_aValues2), s_aValues2 },
3499 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_word_FSxBX_icebp), true, 2, RT_ELEMENTS(s_aValues2), s_aValues2 },
3500
3501 /* 32-bit register width */
3502 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_EBX_icebp), false, 4, RT_ELEMENTS(s_aValues4), s_aValues4 },
3503 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_dword_FSxBX_icebp), true, 4, RT_ELEMENTS(s_aValues4), s_aValues4 },
3504#if ARCH_BITS >= 64
3505 /* 32-bit register width */
3506 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_RBX_icebp), false, 8, RT_ELEMENTS(s_aValues8), s_aValues8 },
3507 { BS3_CMN_NM(bs3CpuInstr2_crc32_EAX_qword_FSxBX_icebp), true, 8, RT_ELEMENTS(s_aValues8), s_aValues8 },
3508#endif
3509 };
3510
3511 BS3REGCTX Ctx;
3512 BS3TRAPFRAME TrapFrame;
3513 unsigned i, j;
3514 bool const fSupportsCrc32 = (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3515 && (ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_SSE4_2);
3516
3517 /* Ensure the structures are allocated before we sample the stack pointer. */
3518 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3519 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3520
3521 /*
3522 * Create test context.
3523 */
3524 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3525
3526 /*
3527 * Do the tests twice, first with all flags set, then once again with
3528 * flags cleared. The flags are not supposed to be touched at all.
3529 */
3530 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3531 for (j = 0; j < 2; j++)
3532 {
3533 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3534 {
3535 uint8_t const cbOp = s_aTests[i].cbOp;
3536 unsigned const cValues = s_aTests[i].cValues;
3537 BS3CPUINSTR2_CRC32_VALUES_T const BS3_FAR *paValues = s_aTests[i].paValues;
3538 unsigned iValue;
3539 bool const fOkay = fSupportsCrc32;
3540 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3541 uint64_t const uSrcGarbage = ( cbOp == 1 ? UINT64_C(0x03948314d0f03400)
3542 : cbOp == 2 ? UINT64_C(0x03948314d0f00000)
3543 : cbOp == 4 ? UINT64_C(0x0394831000000000) : 0)
3544 & (ARCH_BITS >= 64 ? UINT64_MAX : UINT32_MAX);
3545 uint64_t uExpectRip;
3546
3547 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3548 uExpectRip = Ctx.rip.u + (fOkay ? ((uint8_t const BS3_FAR *)s_aTests[i].pfnWorker)[-1] + 1 : 0);
3549
3550 for (iValue = 0; iValue < cValues; iValue++)
3551 {
3552 uint64_t const uExpectRax = fOkay ? paValues[iValue].uDstOut : paValues[iValue].uDstIn;
3553 uint64_t uMemSrc, uMemSrcExpect;
3554
3555 Ctx.rax.uCcXReg = paValues[iValue].uDstIn;
3556 if (!s_aTests[i].fMemSrc)
3557 {
3558 Ctx.rbx.u64 = paValues[iValue].uSrc | uSrcGarbage;
3559 uMemSrcExpect = uMemSrc = ~(paValues[iValue].uSrc | uSrcGarbage);
3560 }
3561 else
3562 {
3563 uMemSrcExpect = uMemSrc = paValues[iValue].uSrc | uSrcGarbage;
3564 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
3565 }
3566
3567 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3568
3569 if ( TrapFrame.bXcpt != bExpectXcpt
3570 || TrapFrame.Ctx.rip.u != uExpectRip
3571 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3572 || TrapFrame.Ctx.rax.u != uExpectRax
3573 /* check that nothing else really changed: */
3574 || TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16
3575 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
3576 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3577 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3578 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3579 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3580 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3581 || uMemSrc != uMemSrcExpect
3582 )
3583 {
3584 Bs3TestFailedF("test #%i value #%i failed: input %#RX32, %#RX64",
3585 i, iValue, paValues[iValue].uDstIn, paValues[iValue].uSrc);
3586 if (TrapFrame.bXcpt != bExpectXcpt)
3587 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3588 if (TrapFrame.Ctx.rip.u != uExpectRip)
3589 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3590 if (TrapFrame.Ctx.rax.u != uExpectRax)
3591 Bs3TestFailedF("Expected RAX = %#010RX64, got %#010RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3592 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3593 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3594
3595 if (TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16)
3596 Bs3TestFailedF("Expected EFLAGS = %#06RX32, got %#06RX32", Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16);
3597 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
3598 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
3599 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3600 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3601 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3602 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3603 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3604 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3605 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3606 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3607 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3608 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3609 if (uMemSrc != uMemSrcExpect)
3610 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
3611 }
3612 }
3613 }
3614 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3615 }
3616
3617 return 0;
3618}
3619
3620#if 0 /* Program for generating CRC32 value sets: */
3621#include <stdio.h>
3622#include <stdint.h>
3623#include <stdlib.h>
3624
3625int main(int argc, char **argv)
3626{
3627 int cbOp = atoi(argv[1]);
3628 uint32_t uBefore = atoi(argv[2]);
3629 int i = 3;
3630 while (i < argc)
3631 {
3632 unsigned long long uValue = strtoull(argv[i], NULL, 0);
3633 uint32_t uAfter = uBefore;
3634 switch (cbOp)
3635 {
3636 case 1:
3637 __asm__ __volatile__("crc32b %2, %0" : "=r" (uAfter) : "0" (uAfter), "r" ((uint8_t)uValue));
3638 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT8_C(%#04x) },\n",
3639 uBefore, uAfter, (unsigned)(uint8_t)uValue);
3640 break;
3641 case 2:
3642 __asm__ __volatile__("crc32w %2, %0" : "=r" (uAfter) : "0" (uAfter), "r" ((uint16_t)uValue));
3643 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT16_C(%#06x) },\n",
3644 uBefore, uAfter, (unsigned)(uint16_t)uValue);
3645 break;
3646 case 4:
3647 __asm__ __volatile__("crc32l %2, %0" : "=r" (uAfter) : "0" (uAfter), "r" ((uint32_t)uValue));
3648 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT32_C(%#010x) },\n",
3649 uBefore, uAfter, (uint32_t)uValue);
3650 break;
3651 case 8:
3652 {
3653 uint64_t u64After = uBefore;
3654 __asm__ __volatile__("crc32q %2, %0" : "=r" (u64After) : "0" (u64After), "r" (uValue));
3655 uAfter = (uint32_t)u64After;
3656 printf(" { UINT32_C(%#010x), UINT32_C(%#010x), UINT64_C(%#018llx) },\n", uBefore, uAfter, uValue);
3657 break;
3658 }
3659 }
3660
3661 /* next */
3662 uBefore = uAfter;
3663 i++;
3664 }
3665 return 0;
3666}
3667#endif
3668
3669
3670/*
3671 * ADCX/ADOX - ADX
3672 */
3673BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_adcx_adox)(uint8_t bMode)
3674{
3675 typedef struct BS3CPUINSTR2_ADX_VALUES_T
3676 {
3677 uint64_t uDstOut;
3678 uint64_t uDstIn;
3679 uint64_t uSrc;
3680 bool fFlagIn;
3681 bool fFlagOut;
3682 } BS3CPUINSTR2_ADX_VALUES_T;
3683 static const BS3CPUINSTR2_ADX_VALUES_T s_aValues4[] =
3684 {
3685 { UINT32_C(0000000000), UINT32_C(0000000000), UINT32_C(0000000000), false, false },
3686 { UINT32_C(0000000001), UINT32_C(0000000000), UINT32_C(0000000000), true, false },
3687
3688 { UINT32_C(0xfffffffe), UINT32_MAX / 2, UINT32_MAX / 2, false, false },
3689 { UINT32_C(0xffffffff), UINT32_MAX / 2, UINT32_MAX / 2, true, false },
3690
3691 { UINT32_C(0x7ffffffe), UINT32_MAX, UINT32_MAX / 2, false, true },
3692 { UINT32_C(0x7fffffff), UINT32_MAX, UINT32_MAX / 2, true, true },
3693
3694 { UINT32_C(0x7ffffffe), UINT32_MAX / 2, UINT32_MAX, false, true },
3695 { UINT32_C(0x7fffffff), UINT32_MAX / 2, UINT32_MAX, true, true },
3696
3697 { UINT32_C(0xfffffffe), UINT32_MAX, UINT32_MAX, false, true },
3698 { UINT32_C(0xffffffff), UINT32_MAX, UINT32_MAX, true, true },
3699 };
3700#if ARCH_BITS >= 64
3701 static const BS3CPUINSTR2_ADX_VALUES_T s_aValues8[] =
3702 {
3703 { UINT64_C(00000000000000000000), UINT64_C(00000000000000000000), UINT64_C(00000000000000000000), false, false },
3704 { UINT64_C(00000000000000000001), UINT64_C(00000000000000000000), UINT64_C(00000000000000000000), true, false },
3705
3706 { UINT64_C(0xfffffffffffffffe), UINT64_MAX / 2, UINT64_MAX / 2, false, false },
3707 { UINT64_C(0xffffffffffffffff), UINT64_MAX / 2, UINT64_MAX / 2, true, false },
3708
3709 { UINT64_C(0x7ffffffffffffffe), UINT64_MAX, UINT64_MAX / 2, false, true },
3710 { UINT64_C(0x7fffffffffffffff), UINT64_MAX, UINT64_MAX / 2, true, true },
3711
3712 { UINT64_C(0x7ffffffffffffffe), UINT64_MAX / 2, UINT64_MAX, false, true },
3713 { UINT64_C(0x7fffffffffffffff), UINT64_MAX / 2, UINT64_MAX, true, true },
3714
3715 { UINT64_C(0xfffffffffffffffe), UINT64_MAX, UINT64_MAX, false, true },
3716 { UINT64_C(0xffffffffffffffff), UINT64_MAX, UINT64_MAX, true, true },
3717 };
3718#endif
3719 static const struct
3720 {
3721 FPFNBS3FAR pfnWorker;
3722 bool fMemSrc;
3723 uint8_t cbOp;
3724 uint8_t cValues;
3725 BS3CPUINSTR2_ADX_VALUES_T const BS3_FAR *paValues;
3726 uint32_t fEFlagsMod;
3727 } s_aTests[] =
3728 {
3729 /* 32-bit register width */
3730 { BS3_CMN_NM(bs3CpuInstr2_adcx_EAX_EBX_icebp), false, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_CF },
3731 { BS3_CMN_NM(bs3CpuInstr2_adcx_EAX_dword_FSxBX_icebp), true, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_CF },
3732
3733 { BS3_CMN_NM(bs3CpuInstr2_adox_EAX_EBX_icebp), false, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_OF },
3734 { BS3_CMN_NM(bs3CpuInstr2_adox_EAX_dword_FSxBX_icebp), true, 4, RT_ELEMENTS(s_aValues4), s_aValues4, X86_EFL_OF },
3735#if ARCH_BITS >= 64
3736 /* 64-bit register width */
3737 { BS3_CMN_NM(bs3CpuInstr2_adcx_RAX_RBX_icebp), false, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_CF },
3738 { BS3_CMN_NM(bs3CpuInstr2_adcx_RAX_qword_FSxBX_icebp), true, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_CF },
3739
3740 { BS3_CMN_NM(bs3CpuInstr2_adox_RAX_RBX_icebp), false, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_OF },
3741 { BS3_CMN_NM(bs3CpuInstr2_adox_RAX_qword_FSxBX_icebp), true, 8, RT_ELEMENTS(s_aValues8), s_aValues8, X86_EFL_OF },
3742#endif
3743 };
3744
3745 BS3REGCTX Ctx;
3746 BS3TRAPFRAME TrapFrame;
3747 unsigned i, j;
3748 bool fSupportsAdx = false;
3749
3750 if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3751 && ASMCpuId_EAX(0) >= 7)
3752 {
3753 uint32_t fEbx = 0;
3754 ASMCpuIdExSlow(7, 0, 0, 0, NULL, &fEbx, NULL, NULL);
3755 fSupportsAdx = RT_BOOL(fEbx & X86_CPUID_STEXT_FEATURE_EBX_ADX);
3756 }
3757
3758 /* Ensure the structures are allocated before we sample the stack pointer. */
3759 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3760 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3761
3762 /*
3763 * Create test context.
3764 */
3765 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3766
3767 /*
3768 * Do the tests twice, first with all flags set, then once again with
3769 * flags cleared. The flags are not supposed to be touched at all except for the one indicated (CF or OF).
3770 */
3771 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
3772 for (j = 0; j < 2; j++)
3773 {
3774 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3775 {
3776 uint8_t const cbOp = s_aTests[i].cbOp;
3777 unsigned const cValues = s_aTests[i].cValues;
3778 BS3CPUINSTR2_ADX_VALUES_T const BS3_FAR *paValues = s_aTests[i].paValues;
3779 uint32_t const fEFlagsMod = s_aTests[i].fEFlagsMod;
3780 unsigned iValue;
3781 bool const fOkay = fSupportsAdx;
3782 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3783 uint64_t const uSrcGarbage = ( cbOp == 4 ? UINT64_C(0x0394831000000000) : 0)
3784 & (ARCH_BITS >= 64 ? UINT64_MAX : UINT32_MAX);
3785 uint64_t uExpectRip;
3786
3787 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3788 uExpectRip = Ctx.rip.u + (fOkay ? ((uint8_t const BS3_FAR *)s_aTests[i].pfnWorker)[-1] + 1 : 0);
3789
3790 for (iValue = 0; iValue < cValues; iValue++)
3791 {
3792 uint64_t const uExpectRax = fOkay ? paValues[iValue].uDstOut : paValues[iValue].uDstIn;
3793 uint64_t uMemSrc, uMemSrcExpect;
3794
3795 Ctx.rax.uCcXReg = paValues[iValue].uDstIn;
3796 if (!s_aTests[i].fMemSrc)
3797 {
3798 Ctx.rbx.u64 = paValues[iValue].uSrc | uSrcGarbage;
3799 uMemSrcExpect = uMemSrc = ~(paValues[iValue].uSrc | uSrcGarbage);
3800 }
3801 else
3802 {
3803 uMemSrcExpect = uMemSrc = paValues[iValue].uSrc | uSrcGarbage;
3804 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMemSrc);
3805 }
3806
3807 Ctx.rflags.u16 &= ~fEFlagsMod;
3808 if (paValues[iValue].fFlagIn)
3809 Ctx.rflags.u16 |= fEFlagsMod;
3810
3811 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3812
3813 if (fOkay)
3814 {
3815 Ctx.rflags.u16 &= ~fEFlagsMod;
3816 if (paValues[iValue].fFlagOut)
3817 Ctx.rflags.u16 |= fEFlagsMod;
3818 }
3819
3820 if ( TrapFrame.bXcpt != bExpectXcpt
3821 || TrapFrame.Ctx.rip.u != uExpectRip
3822 || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
3823 || TrapFrame.Ctx.rax.u != uExpectRax
3824 /* check that nothing else really changed: */
3825 || TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16
3826 || TrapFrame.Ctx.rcx.u != Ctx.rcx.u
3827 || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
3828 || TrapFrame.Ctx.rsp.u != Ctx.rsp.u
3829 || TrapFrame.Ctx.rbp.u != Ctx.rbp.u
3830 || TrapFrame.Ctx.rsi.u != Ctx.rsi.u
3831 || TrapFrame.Ctx.rdi.u != Ctx.rdi.u
3832 || uMemSrc != uMemSrcExpect
3833 )
3834 {
3835 Bs3TestFailedF("test #%i value #%i failed: input %#RX64, %#RX64",
3836 i, iValue, paValues[iValue].uDstIn, paValues[iValue].uSrc);
3837 if (TrapFrame.bXcpt != bExpectXcpt)
3838 Bs3TestFailedF("Expected bXcpt = %#x, got %#x", bExpectXcpt, TrapFrame.bXcpt);
3839 if (TrapFrame.Ctx.rip.u != uExpectRip)
3840 Bs3TestFailedF("Expected RIP = %#06RX64, got %#06RX64", uExpectRip, TrapFrame.Ctx.rip.u);
3841 if (TrapFrame.Ctx.rax.u != uExpectRax)
3842 Bs3TestFailedF("Expected RAX = %#010RX64, got %#010RX64", uExpectRax, TrapFrame.Ctx.rax.u);
3843 if (TrapFrame.Ctx.rbx.u != Ctx.rbx.u)
3844 Bs3TestFailedF("Expected RBX = %#06RX64, got %#06RX64 (dst)", Ctx.rbx.u, TrapFrame.Ctx.rbx.u);
3845
3846 if (TrapFrame.Ctx.rflags.u16 != Ctx.rflags.u16)
3847 Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", Ctx.rflags.u16, TrapFrame.Ctx.rflags.u16);
3848 if (TrapFrame.Ctx.rcx.u != Ctx.rcx.u)
3849 Bs3TestFailedF("Expected RCX = %#06RX64, got %#06RX64", Ctx.rcx.u, TrapFrame.Ctx.rcx.u);
3850 if (TrapFrame.Ctx.rdx.u != Ctx.rdx.u)
3851 Bs3TestFailedF("Expected RDX = %#06RX64, got %#06RX64 (src)", Ctx.rdx.u, TrapFrame.Ctx.rdx.u);
3852 if (TrapFrame.Ctx.rsp.u != Ctx.rsp.u)
3853 Bs3TestFailedF("Expected RSP = %#06RX64, got %#06RX64", Ctx.rsp.u, TrapFrame.Ctx.rsp.u);
3854 if (TrapFrame.Ctx.rbp.u != Ctx.rbp.u)
3855 Bs3TestFailedF("Expected RBP = %#06RX64, got %#06RX64", Ctx.rbp.u, TrapFrame.Ctx.rbp.u);
3856 if (TrapFrame.Ctx.rsi.u != Ctx.rsi.u)
3857 Bs3TestFailedF("Expected RSI = %#06RX64, got %#06RX64", Ctx.rsi.u, TrapFrame.Ctx.rsi.u);
3858 if (TrapFrame.Ctx.rdi.u != Ctx.rdi.u)
3859 Bs3TestFailedF("Expected RDI = %#06RX64, got %#06RX64", Ctx.rdi.u, TrapFrame.Ctx.rdi.u);
3860 if (uMemSrc != uMemSrcExpect)
3861 Bs3TestFailedF("Expected uMemSrc = %#06RX64, got %#06RX64", (uint64_t)uMemSrcExpect, (uint64_t)uMemSrc);
3862 }
3863 }
3864 }
3865 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
3866 }
3867
3868 return 0;
3869}
3870
3871
3872
3873/*
3874 * MOVBE
3875 */
3876BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_movbe)(uint8_t bMode)
3877{
3878 const char BS3_FAR * const pszMode = Bs3GetModeName(bMode);
3879
3880 typedef struct BS3CPUINSTR2_MOVBE_VALUES_T
3881 {
3882 RTCCUINTXREG uDstOut;
3883 RTCCUINTXREG uDstIn;
3884 RTCCUINTXREG uSrc;
3885 } BS3CPUINSTR2_MOVBE_VALUES_T;
3886 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues2[] =
3887 {
3888 { UINT64_C(0xc0dedeaddead3412), UINT64_C(0xc0dedeaddeadc0de), UINT16_C(0x1234) }
3889 };
3890 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues4MemSrc[] =
3891 {
3892 { UINT64_C(0x78563412), UINT64_C(0xc0dedeaddeadc0de), UINT32_C(0x12345678) }
3893 };
3894 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues4MemDst[] =
3895 {
3896 { UINT64_C(0xc0dedead78563412), UINT64_C(0xc0dedeaddeadc0de), UINT32_C(0x12345678) }
3897 };
3898#if ARCH_BITS >= 64
3899 static const BS3CPUINSTR2_MOVBE_VALUES_T s_aValues8[] =
3900 {
3901 { UINT64_C(0xf0debc9a78563412), UINT64_C(0xc0dedeaddeadc0de), UINT64_C(0x123456789abcdef0) }
3902 };
3903#endif
3904 static const struct
3905 {
3906 FPFNBS3FAR pfnWorker;
3907 bool fMemSrc;
3908 uint8_t offIcebp;
3909 uint8_t cValues;
3910 BS3CPUINSTR2_MOVBE_VALUES_T const BS3_FAR *paValues;
3911 } s_aTests[] =
3912 {
3913 /* 16-bit register width */
3914 { BS3_CMN_NM(bs3CpuInstr2_movbe_AX_word_FSxBX_icebp), true, 6 + (ARCH_BITS != 16), RT_ELEMENTS(s_aValues2), s_aValues2 },
3915 { BS3_CMN_NM(bs3CpuInstr2_movbe_word_FSxBX_AX_icebp), false, 6 + (ARCH_BITS != 16), RT_ELEMENTS(s_aValues2), s_aValues2 },
3916 /* 32-bit register width */
3917 { BS3_CMN_NM(bs3CpuInstr2_movbe_EAX_dword_FSxBX_icebp), true, 6 + (ARCH_BITS == 16), RT_ELEMENTS(s_aValues4MemSrc), s_aValues4MemSrc },
3918 { BS3_CMN_NM(bs3CpuInstr2_movbe_dword_FSxBX_EAX_icebp), false, 6 + (ARCH_BITS == 16), RT_ELEMENTS(s_aValues4MemDst), s_aValues4MemDst },
3919#if ARCH_BITS >= 64
3920 /* 64-bit register width */
3921 { BS3_CMN_NM(bs3CpuInstr2_movbe_RAX_qword_FSxBX_icebp), true, 7, RT_ELEMENTS(s_aValues8), s_aValues8 },
3922 { BS3_CMN_NM(bs3CpuInstr2_movbe_qword_FSxBX_RAX_icebp), false, 7, RT_ELEMENTS(s_aValues8), s_aValues8 },
3923#endif
3924 };
3925
3926 BS3REGCTX Ctx;
3927 BS3REGCTX ExpectCtx;
3928 BS3TRAPFRAME TrapFrame;
3929 unsigned i, j;
3930 bool fSupportsMovBe = false;
3931
3932 if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID)
3933 && ASMCpuId_EAX(0) >= 1)
3934 {
3935 uint32_t fEcx = 0;
3936 ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, &fEcx, NULL);
3937 fSupportsMovBe = RT_BOOL(fEcx & X86_CPUID_FEATURE_ECX_MOVBE);
3938 }
3939
3940 /* Ensure the structures are allocated before we sample the stack pointer. */
3941 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
3942 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
3943 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
3944
3945 /*
3946 * Create test context.
3947 */
3948 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
3949
3950 /*
3951 * Do the tests twice, first with all flags set, then once again with
3952 * flags cleared. The flags are not supposed to be touched at all.
3953 */
3954 g_usBs3TestStep = 0;
3955 for (j = 0; j < 2; j++)
3956 {
3957 for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
3958 {
3959 unsigned const cValues = s_aTests[i].cValues;
3960 BS3CPUINSTR2_MOVBE_VALUES_T const BS3_FAR *paValues = s_aTests[i].paValues;
3961 unsigned iValue;
3962 bool const fOkay = fSupportsMovBe;
3963 uint8_t const bExpectXcpt = fOkay ? X86_XCPT_DB : X86_XCPT_UD;
3964 uint64_t uExpectRip;
3965
3966 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aTests[i].pfnWorker);
3967 uExpectRip = Ctx.rip.u + (fOkay ? ((uint8_t const BS3_FAR *)s_aTests[i].pfnWorker)[-1] + 1 : 0);
3968
3969 for (iValue = 0; iValue < cValues; iValue++)
3970 {
3971 //uint64_t const uExpectRax = fOkay ? paValues[iValue].uDstOut : paValues[iValue].uDstIn;
3972 uint64_t uMem, uMemExpect;
3973
3974 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
3975
3976 if (!s_aTests[i].fMemSrc)
3977 {
3978 /* Memory is destination */
3979 Ctx.rax.u64 = paValues[iValue].uSrc;
3980 ExpectCtx.rax.u64 = paValues[iValue].uSrc;
3981 uMem = paValues[iValue].uDstIn;
3982 uMemExpect = paValues[iValue].uDstOut;
3983 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMem);
3984 Bs3RegCtxSetGrpSegFromCurPtr(&ExpectCtx, &ExpectCtx.rbx, &ExpectCtx.fs, &uMem);
3985 }
3986 else
3987 {
3988 /* Memory is source */
3989 uMemExpect = uMem = paValues[iValue].uSrc;
3990 Ctx.rax.u64 = paValues[iValue].uDstIn;
3991 ExpectCtx.rax.u64 = paValues[iValue].uDstOut;
3992 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, &Ctx.fs, &uMem);
3993 Bs3RegCtxSetGrpSegFromCurPtr(&ExpectCtx, &ExpectCtx.rbx, &ExpectCtx.fs, &uMem);
3994 }
3995
3996 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
3997 g_usBs3TestStep++;
3998
3999 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, bExpectXcpt == X86_XCPT_DB ? s_aTests[i].offIcebp : 0 /*cbPcAdjust*/,
4000 0 /*cbSpAcjust*/, 0 /*fExtraEfl*/, pszMode, g_usBs3TestStep)
4001 || TrapFrame.bXcpt != bExpectXcpt
4002 || uMem != uMemExpect
4003 )
4004 {
4005 if (TrapFrame.bXcpt != bExpectXcpt)
4006 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
4007 if (uMem != uMemExpect)
4008 Bs3TestFailedF("Expected uMem = %#06RX64, got %#06RX64", (uint64_t)uMemExpect, (uint64_t)uMem);
4009 Bs3TestFailedF("^^^ iCfg=%u iWorker=%d iValue=%d\n",
4010 j, i, iValue);
4011 }
4012 }
4013 }
4014 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
4015 }
4016
4017 return 0;
4018}
4019
4020
4021
4022/*
4023 * CMPXCHG8B
4024 */
4025BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg8b)(uint8_t bMode)
4026{
4027
4028 BS3REGCTX Ctx;
4029 BS3REGCTX ExpectCtx;
4030 BS3TRAPFRAME TrapFrame;
4031 RTUINT64U au64[3];
4032 PRTUINT64U pau64 = RT_ALIGN_PT(&au64[0], sizeof(RTUINT64U), PRTUINT64U);
4033 bool const fSupportCX8 = RT_BOOL(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_CX8);
4034 const char BS3_FAR * const pszMode = Bs3GetModeName(bMode);
4035 uint8_t bRing = BS3_MODE_IS_V86(bMode) ? 3 : 0;
4036 unsigned iFlags;
4037 unsigned offBuf;
4038 unsigned iMatch;
4039 unsigned iWorker;
4040 static struct
4041 {
4042 bool fLocked;
4043 uint8_t offIcebp;
4044 FNBS3FAR *pfnWorker;
4045 } const s_aWorkers[] =
4046 {
4047 { false, 5, BS3_CMN_NM(bs3CpuInstr2_cmpxchg8b_FSxDI_icebp) },
4048#if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PP16
4049 { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg8b_FSxDI_icebp) },
4050#else
4051 { false, 6, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg8b_FSxDI_icebp) },
4052#endif
4053 { false, 6, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg8b_FSxDI_icebp) },
4054 { false, 6, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg8b_FSxDI_icebp) },
4055 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg8b_FSxDI_icebp) },
4056 { true, 1+6, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg8b_FSxDI_icebp) },
4057 { true, 1+6, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg8b_FSxDI_icebp) },
4058 { true, 1+6, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg8b_FSxDI_icebp) },
4059 };
4060
4061 /* Ensure the structures are allocated before we sample the stack pointer. */
4062 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4063 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4064 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4065 Bs3MemSet(pau64, 0, sizeof(pau64[0]) * 2);
4066
4067 /*
4068 * Create test context.
4069 */
4070 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4071 if (!fSupportCX8)
4072 Bs3TestPrintf("Note! CMPXCHG8B is not supported by the CPU!\n");
4073
4074 /*
4075 * Run the tests in all rings since alignment issues may behave
4076 * differently in ring-3 compared to ring-0.
4077 */
4078 for (;;)
4079 {
4080 /*
4081 * One loop with alignment checks disabled and one with enabled.
4082 */
4083 unsigned iCfg;
4084 for (iCfg = 0; iCfg < 2; iCfg++)
4085 {
4086 if (iCfg)
4087 {
4088 Ctx.rflags.u32 |= X86_EFL_AC;
4089 Ctx.cr0.u32 |= X86_CR0_AM;
4090 }
4091 else
4092 {
4093 Ctx.rflags.u32 &= ~X86_EFL_AC;
4094 Ctx.cr0.u32 &= ~X86_CR0_AM;
4095 }
4096
4097 /*
4098 * One loop with the normal variant and one with the locked one
4099 */
4100 g_usBs3TestStep = 0;
4101 for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++)
4102 {
4103 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker);
4104
4105 /*
4106 * One loop with all status flags set, and one with them clear.
4107 */
4108 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
4109 for (iFlags = 0; iFlags < 2; iFlags++)
4110 {
4111 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4112
4113 for (offBuf = 0; offBuf < sizeof(RTUINT64U); offBuf++)
4114 {
4115# define CX8_OLD_LO UINT32_C(0xcc9c4bbd)
4116# define CX8_OLD_HI UINT32_C(0x749549ab)
4117# define CX8_MISMATCH_LO UINT32_C(0x90f18981)
4118# define CX8_MISMATCH_HI UINT32_C(0xfd5b4000)
4119# define CX8_STORE_LO UINT32_C(0x51f6559b)
4120# define CX8_STORE_HI UINT32_C(0xd1b54963)
4121
4122 PRTUINT64U pBuf = (PRTUINT64U)&pau64->au8[offBuf];
4123
4124 ExpectCtx.rax.u = Ctx.rax.u = CX8_MISMATCH_LO;
4125 ExpectCtx.rdx.u = Ctx.rdx.u = CX8_MISMATCH_HI;
4126
4127 Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rdi, &Ctx.fs, pBuf);
4128 Bs3RegCtxSetGrpSegFromCurPtr(&ExpectCtx, &ExpectCtx.rdi, &ExpectCtx.fs, pBuf);
4129
4130 for (iMatch = 0; iMatch < 2; iMatch++)
4131 {
4132 uint8_t bExpectXcpt;
4133 pBuf->s.Lo = CX8_OLD_LO;
4134 pBuf->s.Hi = CX8_OLD_HI;
4135
4136 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4137 g_usBs3TestStep++;
4138 //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker);
4139 bExpectXcpt = X86_XCPT_UD;
4140 if (fSupportCX8)
4141 {
4142 if ( offBuf
4143 && bRing == 3
4144 && bMode != BS3_MODE_RM
4145 && !BS3_MODE_IS_V86(bMode)
4146 && iCfg)
4147 {
4148 bExpectXcpt = X86_XCPT_AC;
4149 ExpectCtx.rflags.u32 = Ctx.rflags.u32;
4150 }
4151 else
4152 {
4153 bExpectXcpt = X86_XCPT_DB;
4154
4155 ExpectCtx.rax.u = CX8_OLD_LO;
4156 ExpectCtx.rdx.u = CX8_OLD_HI;
4157
4158 if (iMatch & 1)
4159 ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF;
4160 else
4161 ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF;
4162 }
4163
4164 /* Kludge! Looks like EFLAGS.AC is cleared when raising #GP in real mode on an i7-6700K. WEIRD! */
4165 if (bMode == BS3_MODE_RM && (Ctx.rflags.u32 & X86_EFL_AC))
4166 {
4167 if (TrapFrame.Ctx.rflags.u32 & X86_EFL_AC)
4168 Bs3TestFailedF("Expected EFLAGS.AC to be cleared (bXcpt=%d)", TrapFrame.bXcpt);
4169 TrapFrame.Ctx.rflags.u32 |= X86_EFL_AC;
4170 }
4171 }
4172
4173 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, bExpectXcpt == X86_XCPT_DB ? s_aWorkers[iWorker].offIcebp : 0, 0 /*cbSpAdjust*/,
4174 bExpectXcpt == X86_XCPT_DB || BS3_MODE_IS_16BIT_SYS(bMode) ? 0 : X86_EFL_RF, pszMode, g_usBs3TestStep)
4175 || TrapFrame.bXcpt != bExpectXcpt)
4176 {
4177 if (TrapFrame.bXcpt != bExpectXcpt)
4178 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
4179 Bs3TestFailedF("^^^ bRing=%u iCfg=%d iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n",
4180 bRing, iCfg, iWorker, iFlags, offBuf, iMatch);
4181 ASMHalt();
4182 }
4183
4184 ExpectCtx.rax.u = Ctx.rax.u = CX8_OLD_LO;
4185 ExpectCtx.rdx.u = Ctx.rdx.u = CX8_OLD_HI;
4186 }
4187 }
4188 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
4189 }
4190 }
4191 } /* for each test config. */
4192
4193 /*
4194 * Next ring.
4195 */
4196 bRing++;
4197 if (bRing > 3 || bMode == BS3_MODE_RM)
4198 break;
4199 Bs3RegCtxConvertToRingX(&Ctx, bRing);
4200 }
4201
4202 return 0;
4203}
4204
4205
4206
4207/*
4208 *
4209 */
4210# if ARCH_BITS == 64
4211
4212BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b)(uint8_t bMode)
4213{
4214 BS3REGCTX Ctx;
4215 BS3REGCTX ExpectCtx;
4216 BS3TRAPFRAME TrapFrame;
4217 RTUINT128U au128[3];
4218 PRTUINT128U pau128 = RT_ALIGN_PT(&au128[0], sizeof(RTUINT128U), PRTUINT128U);
4219 bool const fSupportCX16 = RT_BOOL(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16);
4220 const char BS3_FAR * const pszMode = Bs3GetModeName(bMode);
4221 uint8_t bRing = BS3_MODE_IS_V86(bMode) ? 3 : 0;
4222 unsigned iFlags;
4223 unsigned offBuf;
4224 unsigned iMatch;
4225 unsigned iWorker;
4226 static struct
4227 {
4228 bool fLocked;
4229 uint8_t offUd2;
4230 FNBS3FAR *pfnWorker;
4231 } const s_aWorkers[] =
4232 {
4233 { false, 4, BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2) },
4234 { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2) },
4235 { false, 5, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2) },
4236 { false, 5, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2) },
4237 { true, 1+4, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2) },
4238 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2) },
4239 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2) },
4240 { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2) },
4241 };
4242
4243 /* Ensure the structures are allocated before we sample the stack pointer. */
4244 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4245 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4246 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4247 Bs3MemSet(pau128, 0, sizeof(pau128[0]) * 2);
4248
4249 /*
4250 * Create test context.
4251 */
4252 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4253 if (!fSupportCX16)
4254 Bs3TestPrintf("Note! CMPXCHG16B is not supported by the CPU!\n");
4255
4256
4257 /*
4258 * Run the tests in all rings since alignment issues may behave
4259 * differently in ring-3 compared to ring-0.
4260 */
4261 for (;;)
4262 {
4263 /*
4264 * One loop with alignment checks disabled and one with enabled.
4265 */
4266 unsigned iCfg;
4267 for (iCfg = 0; iCfg < 2; iCfg++)
4268 {
4269 if (iCfg)
4270 {
4271 Ctx.rflags.u32 |= X86_EFL_AC;
4272 Ctx.cr0.u32 |= X86_CR0_AM;
4273 }
4274 else
4275 {
4276 Ctx.rflags.u32 &= ~X86_EFL_AC;
4277 Ctx.cr0.u32 &= ~X86_CR0_AM;
4278 }
4279
4280 /*
4281 * One loop with the normal variant and one with the locked one
4282 */
4283 g_usBs3TestStep = 0;
4284 for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++)
4285 {
4286 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker);
4287
4288 /*
4289 * One loop with all status flags set, and one with them clear.
4290 */
4291 Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
4292 for (iFlags = 0; iFlags < 2; iFlags++)
4293 {
4294 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4295
4296 for (offBuf = 0; offBuf < sizeof(RTUINT128U); offBuf++)
4297 {
4298# define CX16_OLD_LO UINT64_C(0xabb6345dcc9c4bbd)
4299# define CX16_OLD_HI UINT64_C(0x7b06ea35749549ab)
4300# define CX16_MISMATCH_LO UINT64_C(0xbace3e3590f18981)
4301# define CX16_MISMATCH_HI UINT64_C(0x9b385e8bfd5b4000)
4302# define CX16_STORE_LO UINT64_C(0x5cbd27d251f6559b)
4303# define CX16_STORE_HI UINT64_C(0x17ff434ed1b54963)
4304
4305 PRTUINT128U pBuf = (PRTUINT128U)&pau128->au8[offBuf];
4306
4307 ExpectCtx.rax.u = Ctx.rax.u = CX16_MISMATCH_LO;
4308 ExpectCtx.rdx.u = Ctx.rdx.u = CX16_MISMATCH_HI;
4309 for (iMatch = 0; iMatch < 2; iMatch++)
4310 {
4311 uint8_t bExpectXcpt;
4312 pBuf->s.Lo = CX16_OLD_LO;
4313 pBuf->s.Hi = CX16_OLD_HI;
4314 ExpectCtx.rdi.u = Ctx.rdi.u = (uintptr_t)pBuf;
4315 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4316 g_usBs3TestStep++;
4317 //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker);
4318 bExpectXcpt = X86_XCPT_UD;
4319 if (fSupportCX16)
4320 {
4321 if (offBuf & 15)
4322 {
4323 bExpectXcpt = X86_XCPT_GP;
4324 ExpectCtx.rip.u = Ctx.rip.u;
4325 ExpectCtx.rflags.u32 = Ctx.rflags.u32;
4326 }
4327 else
4328 {
4329 ExpectCtx.rax.u = CX16_OLD_LO;
4330 ExpectCtx.rdx.u = CX16_OLD_HI;
4331 if (iMatch & 1)
4332 ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF;
4333 else
4334 ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF;
4335 ExpectCtx.rip.u = Ctx.rip.u + s_aWorkers[iWorker].offUd2;
4336 }
4337 ExpectCtx.rflags.u32 |= X86_EFL_RF;
4338 }
4339 if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
4340 0 /*fExtraEfl*/, pszMode, 0 /*idTestStep*/)
4341 || TrapFrame.bXcpt != bExpectXcpt)
4342 {
4343 if (TrapFrame.bXcpt != bExpectXcpt)
4344 Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
4345 Bs3TestFailedF("^^^bRing=%d iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n", bRing, iWorker, iFlags, offBuf, iMatch);
4346 ASMHalt();
4347 }
4348
4349 ExpectCtx.rax.u = Ctx.rax.u = CX16_OLD_LO;
4350 ExpectCtx.rdx.u = Ctx.rdx.u = CX16_OLD_HI;
4351 }
4352 }
4353 Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
4354 }
4355 }
4356 } /* for each test config. */
4357
4358 /*
4359 * Next ring.
4360 */
4361 bRing++;
4362 if (bRing > 3 || bMode == BS3_MODE_RM)
4363 break;
4364 Bs3RegCtxConvertToRingX(&Ctx, bRing);
4365 }
4366
4367 return 0;
4368}
4369
4370
4371static void bs3CpuInstr2_fsgsbase_ExpectUD(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame)
4372{
4373 pCtx->rbx.u = 0;
4374 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
4375 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
4376 pExpectCtx->rip.u = pCtx->rip.u;
4377 pExpectCtx->rflags.u32 |= X86_EFL_RF;
4378 if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
4379 0 /*idTestStep*/)
4380 || pTrapFrame->bXcpt != X86_XCPT_UD)
4381 {
4382 Bs3TestFailedF("Expected #UD, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
4383 ASMHalt();
4384 }
4385}
4386
4387
4388static bool bs3CpuInstr2_fsgsbase_VerifyWorker(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame,
4389 BS3CI2FSGSBASE const *pFsGsBaseWorker, unsigned *puIter)
4390{
4391 bool fPassed = true;
4392 unsigned iValue = 0;
4393 static const struct
4394 {
4395 bool fGP;
4396 uint64_t u64Base;
4397 } s_aValues64[] =
4398 {
4399 { false, UINT64_C(0x0000000000000000) },
4400 { false, UINT64_C(0x0000000000000001) },
4401 { false, UINT64_C(0x0000000000000010) },
4402 { false, UINT64_C(0x0000000000000123) },
4403 { false, UINT64_C(0x0000000000001234) },
4404 { false, UINT64_C(0x0000000000012345) },
4405 { false, UINT64_C(0x0000000000123456) },
4406 { false, UINT64_C(0x0000000001234567) },
4407 { false, UINT64_C(0x0000000012345678) },
4408 { false, UINT64_C(0x0000000123456789) },
4409 { false, UINT64_C(0x000000123456789a) },
4410 { false, UINT64_C(0x00000123456789ab) },
4411 { false, UINT64_C(0x0000123456789abc) },
4412 { false, UINT64_C(0x00007ffffeefefef) },
4413 { false, UINT64_C(0x00007fffffffffff) },
4414 { true, UINT64_C(0x0000800000000000) },
4415 { true, UINT64_C(0x0000800000000000) },
4416 { true, UINT64_C(0x0000800000000333) },
4417 { true, UINT64_C(0x0001000000000000) },
4418 { true, UINT64_C(0x0012000000000000) },
4419 { true, UINT64_C(0x0123000000000000) },
4420 { true, UINT64_C(0x1234000000000000) },
4421 { true, UINT64_C(0xffff300000000000) },
4422 { true, UINT64_C(0xffff7fffffffffff) },
4423 { true, UINT64_C(0xffff7fffffffffff) },
4424 { false, UINT64_C(0xffff800000000000) },
4425 { false, UINT64_C(0xffffffffffeefefe) },
4426 { false, UINT64_C(0xffffffffffffffff) },
4427 { false, UINT64_C(0xffffffffffffffff) },
4428 { false, UINT64_C(0x00000000efefefef) },
4429 { false, UINT64_C(0x0000000080204060) },
4430 { false, UINT64_C(0x00000000ddeeffaa) },
4431 { false, UINT64_C(0x00000000fdecdbca) },
4432 { false, UINT64_C(0x000000006098456b) },
4433 { false, UINT64_C(0x0000000098506099) },
4434 { false, UINT64_C(0x00000000206950bc) },
4435 { false, UINT64_C(0x000000009740395d) },
4436 { false, UINT64_C(0x0000000064a9455e) },
4437 { false, UINT64_C(0x00000000d20b6eff) },
4438 { false, UINT64_C(0x0000000085296d46) },
4439 { false, UINT64_C(0x0000000007000039) },
4440 { false, UINT64_C(0x000000000007fe00) },
4441 };
4442
4443 Bs3RegCtxSetRipCsFromCurPtr(pCtx, pFsGsBaseWorker->pfnVerifyWorker);
4444 if (pFsGsBaseWorker->f64BitOperand)
4445 {
4446 for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
4447 {
4448 bool const fGP = s_aValues64[iValue].fGP;
4449
4450 pCtx->rbx.u = s_aValues64[iValue].u64Base;
4451 pCtx->rcx.u = 0;
4452 pCtx->cr4.u |= X86_CR4_FSGSBASE;
4453 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
4454 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
4455 pExpectCtx->rip.u = pCtx->rip.u + (!fGP ? pFsGsBaseWorker->offVerifyWorkerUd2 : 0);
4456 pExpectCtx->rbx.u = !fGP ? 0 : s_aValues64[iValue].u64Base;
4457 pExpectCtx->rcx.u = !fGP ? s_aValues64[iValue].u64Base : 0;
4458 pExpectCtx->rflags.u32 |= X86_EFL_RF;
4459 if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
4460 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)
4461 || (fGP && pTrapFrame->bXcpt != X86_XCPT_GP))
4462 {
4463 if (fGP && pTrapFrame->bXcpt != X86_XCPT_GP)
4464 Bs3TestFailedF("Expected #GP, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
4465 else
4466 Bs3TestFailedF("iValue=%u\n", iValue);
4467 fPassed = false;
4468 break;
4469 }
4470 }
4471 }
4472 else
4473 {
4474 for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
4475 {
4476 pCtx->rbx.u = s_aValues64[iValue].u64Base;
4477 pCtx->rcx.u = ~s_aValues64[iValue].u64Base;
4478 pCtx->cr4.u |= X86_CR4_FSGSBASE;
4479 Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
4480 Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
4481 pExpectCtx->rip.u = pCtx->rip.u + pFsGsBaseWorker->offVerifyWorkerUd2;
4482 pExpectCtx->rbx.u = 0;
4483 pExpectCtx->rcx.u = s_aValues64[iValue].u64Base & UINT64_C(0x00000000ffffffff);
4484 pExpectCtx->rflags.u32 |= X86_EFL_RF;
4485 if (!Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
4486 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/))
4487 {
4488 Bs3TestFailedF("iValue=%u\n", iValue);
4489 fPassed = false;
4490 break;
4491 }
4492 }
4493 }
4494
4495 *puIter = iValue;
4496 return fPassed;
4497}
4498
4499
4500static void bs3CpuInstr2_rdfsbase_rdgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
4501 unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
4502{
4503 BS3REGCTX Ctx;
4504 BS3REGCTX ExpectCtx;
4505 BS3TRAPFRAME TrapFrame;
4506 unsigned iWorker;
4507 unsigned iIter;
4508 uint32_t uDummy;
4509 uint32_t uStdExtFeatEbx;
4510 bool fSupportsFsGsBase;
4511
4512 ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
4513 fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
4514
4515 /* Ensure the structures are allocated before we sample the stack pointer. */
4516 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4517 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4518 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4519
4520 /*
4521 * Create test context.
4522 */
4523 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4524
4525 for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
4526 {
4527 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
4528 if (fSupportsFsGsBase)
4529 {
4530 uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
4531
4532 /* CR4.FSGSBASE disabled -> #UD. */
4533 Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
4534 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4535
4536 /* Read and verify existing base address. */
4537 Ctx.rbx.u = 0;
4538 Ctx.cr4.u |= X86_CR4_FSGSBASE;
4539 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4540 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4541 ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
4542 ExpectCtx.rbx.u = uBaseAddr;
4543 ExpectCtx.rflags.u32 |= X86_EFL_RF;
4544 if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
4545 0 /*idTestStep*/))
4546 {
4547 ASMHalt();
4548 }
4549
4550 /* Write, read and verify series of base addresses. */
4551 if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
4552 {
4553 Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
4554 ASMHalt();
4555 }
4556
4557 /* Restore original base address. */
4558 ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
4559
4560 /* Clean used GPRs. */
4561 Ctx.rbx.u = 0;
4562 Ctx.rcx.u = 0;
4563 }
4564 else
4565 {
4566 /* Unsupported by CPUID -> #UD. */
4567 Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
4568 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4569 }
4570 }
4571}
4572
4573
4574static void bs3CpuInstr2_wrfsbase_wrgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
4575 unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
4576{
4577 BS3REGCTX Ctx;
4578 BS3REGCTX ExpectCtx;
4579 BS3TRAPFRAME TrapFrame;
4580 unsigned iWorker;
4581 unsigned iIter;
4582 uint32_t uDummy;
4583 uint32_t uStdExtFeatEbx;
4584 bool fSupportsFsGsBase;
4585
4586 ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
4587 fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
4588
4589 /* Ensure the structures are allocated before we sample the stack pointer. */
4590 Bs3MemSet(&Ctx, 0, sizeof(Ctx));
4591 Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
4592 Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
4593
4594 /*
4595 * Create test context.
4596 */
4597 Bs3RegCtxSaveEx(&Ctx, bMode, 512);
4598
4599 for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
4600 {
4601 Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
4602 if (fSupportsFsGsBase)
4603 {
4604 uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
4605
4606 /* CR4.FSGSBASE disabled -> #UD. */
4607 Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
4608 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4609
4610 /* Write a base address. */
4611 Ctx.rbx.u = 0xa0000;
4612 Ctx.cr4.u |= X86_CR4_FSGSBASE;
4613 Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
4614 Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
4615 ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
4616 ExpectCtx.rflags.u32 |= X86_EFL_RF;
4617 if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
4618 0 /*idTestStep*/))
4619 {
4620 ASMHalt();
4621 }
4622
4623 /* Write and read back series of base addresses. */
4624 if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
4625 {
4626 Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
4627 ASMHalt();
4628 }
4629
4630 /* Restore original base address. */
4631 ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
4632
4633 /* Clean used GPRs. */
4634 Ctx.rbx.u = 0;
4635 Ctx.rcx.u = 0;
4636 }
4637 else
4638 {
4639 /* Unsupported by CPUID -> #UD. */
4640 Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
4641 bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
4642 }
4643 }
4644}
4645
4646
4647BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrfsbase)(uint8_t bMode)
4648{
4649 bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrFsBaseWorkers, RT_ELEMENTS(s_aWrFsBaseWorkers), MSR_K8_FS_BASE);
4650 return 0;
4651}
4652
4653
4654BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrgsbase)(uint8_t bMode)
4655{
4656 bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrGsBaseWorkers, RT_ELEMENTS(s_aWrGsBaseWorkers), MSR_K8_GS_BASE);
4657 return 0;
4658}
4659
4660
4661BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdfsbase)(uint8_t bMode)
4662{
4663 bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdFsBaseWorkers, RT_ELEMENTS(s_aRdFsBaseWorkers), MSR_K8_FS_BASE);
4664 return 0;
4665}
4666
4667
4668BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdgsbase)(uint8_t bMode)
4669{
4670 bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdGsBaseWorkers, RT_ELEMENTS(s_aRdGsBaseWorkers), MSR_K8_GS_BASE);
4671 return 0;
4672}
4673
4674# endif /* ARCH_BITS == 64 */
4675
4676#endif /* BS3_INSTANTIATING_CMN */
4677
4678
4679
4680/*
4681 * Mode specific code.
4682 * Mode specific code.
4683 * Mode specific code.
4684 */
4685#ifdef BS3_INSTANTIATING_MODE
4686
4687
4688#endif /* BS3_INSTANTIATING_MODE */
4689
Note: See TracBrowser for help on using the repository browser.

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