VirtualBox

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

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

ValKit/bs3-cpu-instr-2: Added shl,shr,sar,rol,ror,rcl&rcr tests (only intel data). bugref:10376

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