summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c
new file mode 100644
index 00000000..4b4b2913
--- /dev/null
+++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c
@@ -0,0 +1,1038 @@
+/* $Id: bs3-cpu-instr-2-template.c $ */
+/** @file
+ * BS3Kit - bs3-cpu-instr-2, C code template.
+ */
+
+/*
+ * Copyright (C) 2007-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
+
+
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+#ifdef BS3_INSTANTIATING_CMN
+# if ARCH_BITS == 64
+typedef struct BS3CI2FSGSBASE
+{
+ const char *pszDesc;
+ bool f64BitOperand;
+ FPFNBS3FAR pfnWorker;
+ uint8_t offWorkerUd2;
+ FPFNBS3FAR pfnVerifyWorker;
+ uint8_t offVerifyWorkerUd2;
+} BS3CI2FSGSBASE;
+# endif
+#endif
+
+
+/*********************************************************************************************************************************
+* External Symbols *
+*********************************************************************************************************************************/
+#ifdef BS3_INSTANTIATING_CMN
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2);
+# if ARCH_BITS == 64
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2);
+
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2);
+
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2);
+
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2);
+extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2);
+# endif
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+#ifdef BS3_INSTANTIATING_CMN
+# if ARCH_BITS == 64
+static BS3CI2FSGSBASE const s_aWrFsBaseWorkers[] =
+{
+ { "wrfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 13 },
+ { "wrfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 10 },
+};
+
+static BS3CI2FSGSBASE const s_aWrGsBaseWorkers[] =
+{
+ { "wrgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 13 },
+ { "wrgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 10 },
+};
+
+static BS3CI2FSGSBASE const s_aRdFsBaseWorkers[] =
+{
+ { "rdfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 13 },
+ { "rdfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 10 },
+};
+
+static BS3CI2FSGSBASE const s_aRdGsBaseWorkers[] =
+{
+ { "rdgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 13 },
+ { "rdgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 10 },
+};
+# endif
+#endif /* BS3_INSTANTIATING_CMN - global */
+
+
+/*
+ * Common code.
+ * Common code.
+ * Common code.
+ */
+#ifdef BS3_INSTANTIATING_CMN
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mul)(uint8_t bMode)
+{
+#define MUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
+#define MUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
+
+ static const struct
+ {
+ RTCCUINTREG uInAX;
+ RTCCUINTREG uInBX;
+ RTCCUINTREG uOutDX;
+ RTCCUINTREG uOutAX;
+ uint16_t fFlags;
+ } s_aTests[] =
+ {
+ { 1, 1,
+ 0, 1, 0 },
+ { 2, 2,
+ 0, 4, 0 },
+ { RTCCUINTREG_MAX, RTCCUINTREG_MAX,
+ RTCCUINTREG_MAX-1, 1, X86_EFL_CF | X86_EFL_OF },
+ { RTCCINTREG_MAX, RTCCINTREG_MAX,
+ RTCCINTREG_MAX / 2, 1, X86_EFL_CF | X86_EFL_OF },
+ { 1, RTCCUINTREG_MAX,
+ 0, RTCCUINTREG_MAX, X86_EFL_PF | X86_EFL_SF },
+ { 1, RTCCINTREG_MAX,
+ 0, RTCCINTREG_MAX, X86_EFL_PF },
+ { 2, RTCCINTREG_MAX,
+ 0, RTCCUINTREG_MAX - 1, X86_EFL_SF },
+ { (RTCCUINTREG)RTCCINTREG_MAX + 1, 2,
+ 1, 0, X86_EFL_PF | X86_EFL_CF | X86_EFL_OF },
+ { (RTCCUINTREG)RTCCINTREG_MAX / 2 + 1, 3,
+ 0, ((RTCCUINTREG)RTCCINTREG_MAX / 2 + 1) * 3, X86_EFL_PF | X86_EFL_SF },
+ };
+
+ BS3REGCTX Ctx;
+ BS3TRAPFRAME TrapFrame;
+ unsigned i, j, k;
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2));
+ for (k = 0; k < 2; k++)
+ {
+ Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
+ for (j = 0; j < 2; j++)
+ {
+ for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ if (k == 0)
+ {
+ Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ }
+ else
+ {
+ Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ }
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+ if (TrapFrame.bXcpt != X86_XCPT_UD)
+ Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
+ else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
+ || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
+ || (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
+ != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
+ {
+ Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
+ i, s_aTests[i].uInAX, s_aTests[i].uInBX);
+
+ if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
+ Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
+ s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
+ if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
+ Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
+ s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
+ if ( (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO))
+ != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) )
+ Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & MUL_CHECK_EFLAGS,
+ TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO));
+ }
+ }
+ Ctx.rflags.u16 &= ~(MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO);
+ }
+ }
+
+ return 0;
+}
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_imul)(uint8_t bMode)
+{
+#define IMUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF)
+#define IMUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF)
+ static const struct
+ {
+ RTCCUINTREG uInAX;
+ RTCCUINTREG uInBX;
+ RTCCUINTREG uOutDX;
+ RTCCUINTREG uOutAX;
+ uint16_t fFlags;
+ } s_aTests[] =
+ {
+ /* two positive values. */
+ { 1, 1,
+ 0, 1, 0 },
+ { 2, 2,
+ 0, 4, 0 },
+ { RTCCINTREG_MAX, RTCCINTREG_MAX,
+ RTCCINTREG_MAX/2, 1, X86_EFL_CF | X86_EFL_OF },
+ { 1, RTCCINTREG_MAX,
+ 0, RTCCINTREG_MAX, X86_EFL_PF },
+ { 2, RTCCINTREG_MAX,
+ 0, RTCCUINTREG_MAX - 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF },
+ { 2, RTCCINTREG_MAX / 2,
+ 0, RTCCINTREG_MAX - 1U, 0 },
+ { 2, (RTCCINTREG_MAX / 2 + 1),
+ 0, (RTCCUINTREG)RTCCINTREG_MAX + 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
+ { 4, (RTCCINTREG_MAX / 2 + 1),
+ 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
+
+ /* negative and positive */
+ { -4, 3,
+ -1, -12, X86_EFL_SF },
+ { 32, -127,
+ -1, -4064, X86_EFL_SF },
+ { RTCCINTREG_MIN, 1,
+ -1, RTCCINTREG_MIN, X86_EFL_SF | X86_EFL_PF },
+ { RTCCINTREG_MIN, 2,
+ -1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
+ { RTCCINTREG_MIN, 3,
+ -2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
+ { RTCCINTREG_MIN, 4,
+ -2, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
+ { RTCCINTREG_MIN, RTCCINTREG_MAX,
+ RTCCINTREG_MIN / 2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF },
+ { RTCCINTREG_MIN, RTCCINTREG_MAX - 1,
+ RTCCINTREG_MIN / 2 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
+
+ /* two negative values. */
+ { -4, -63,
+ 0, 252, X86_EFL_PF },
+ { RTCCINTREG_MIN, RTCCINTREG_MIN,
+ RTCCUINTREG_MAX / 4 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF },
+ { RTCCINTREG_MIN, RTCCINTREG_MIN + 1,
+ RTCCUINTREG_MAX / 4, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF},
+ { RTCCINTREG_MIN + 1, RTCCINTREG_MIN + 1,
+ RTCCUINTREG_MAX / 4, 1, X86_EFL_CF | X86_EFL_OF },
+
+ };
+
+ BS3REGCTX Ctx;
+ BS3TRAPFRAME TrapFrame;
+ unsigned i, j, k;
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2));
+
+ for (k = 0; k < 2; k++)
+ {
+ Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
+ for (j = 0; j < 2; j++)
+ {
+ for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ if (k == 0)
+ {
+ Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ }
+ else
+ {
+ Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ }
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+ if (TrapFrame.bXcpt != X86_XCPT_UD)
+ Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
+ else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
+ || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
+ || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
+ != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
+ {
+ Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
+ i, s_aTests[i].uInAX, s_aTests[i].uInBX);
+
+ if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
+ Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
+ s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
+ if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
+ Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
+ s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
+ if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
+ != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
+ Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
+ TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
+ }
+ }
+ }
+ }
+
+ /*
+ * Repeat for the truncating two operand version.
+ */
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2));
+
+ for (k = 0; k < 2; k++)
+ {
+ Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO;
+ for (j = 0; j < 2; j++)
+ {
+ for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ if (k == 0)
+ {
+ Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ }
+ else
+ {
+ Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ }
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+ if (TrapFrame.bXcpt != X86_XCPT_UD)
+ Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt);
+ else if ( TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
+ || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
+ || TrapFrame.Ctx.rbx.u != Ctx.rbx.u
+ || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
+ != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
+ {
+ Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT,
+ i, s_aTests[i].uInAX, s_aTests[i].uInBX);
+
+ if (TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX)
+ Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS),
+ s_aTests[i].uOutAX, TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS));
+ if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO))
+ != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) )
+ Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS,
+ TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO));
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_div)(uint8_t bMode)
+{
+#define DIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
+ static const struct
+ {
+ RTCCUINTREG uInDX;
+ RTCCUINTREG uInAX;
+ RTCCUINTREG uInBX;
+ RTCCUINTREG uOutAX;
+ RTCCUINTREG uOutDX;
+ uint8_t bXcpt;
+ } s_aTests[] =
+ {
+ { 0, 1, 1,
+ 1, 0, X86_XCPT_UD },
+ { 0, 5, 2,
+ 2, 1, X86_XCPT_UD },
+ { 0, 0, 0,
+ 0, 0, X86_XCPT_DE },
+ { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 0,
+ 0, 0, X86_XCPT_DE },
+ { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 1,
+ 0, 0, X86_XCPT_DE },
+ { RTCCUINTREG_MAX, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
+ 0, 0, X86_XCPT_DE },
+ { RTCCUINTREG_MAX - 1, RTCCUINTREG_MAX, RTCCUINTREG_MAX,
+ RTCCUINTREG_MAX, RTCCUINTREG_MAX - 1, X86_XCPT_UD },
+ };
+
+ BS3REGCTX Ctx;
+ BS3TRAPFRAME TrapFrame;
+ unsigned i, j;
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2));
+
+ /*
+ * Do the tests twice, first with all flags set, then once again with
+ * flags cleared. The flags are not touched by my intel skylake CPU.
+ */
+ Ctx.rflags.u16 |= DIV_CHECK_EFLAGS;
+ for (j = 0; j < 2; j++)
+ {
+ for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+
+ if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
+ || ( s_aTests[i].bXcpt == X86_XCPT_UD
+ ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
+ || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
+ || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS)
+ : TrapFrame.Ctx.rax.u != Ctx.rax.u
+ || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
+ || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS) ) )
+ {
+ Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
+ i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
+ if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
+ Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
+ if (s_aTests[i].bXcpt == X86_XCPT_UD)
+ {
+ if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
+ Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
+ s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
+ if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
+ Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
+ s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
+ if ((TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS))
+ Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
+ Ctx.rflags.u16 & DIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS);
+ }
+ }
+ }
+ Ctx.rflags.u16 &= ~DIV_CHECK_EFLAGS;
+ }
+
+ return 0;
+}
+
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_idiv)(uint8_t bMode)
+{
+#define IDIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF)
+ static const struct
+ {
+ RTCCUINTREG uInDX;
+ RTCCUINTREG uInAX;
+ RTCCUINTREG uInBX;
+ RTCCUINTREG uOutAX;
+ RTCCUINTREG uOutDX;
+ uint8_t bXcpt;
+ } s_aTests[] =
+ {
+ { 0, 0, 0,
+ 0, 0, X86_XCPT_DE },
+ { RTCCINTREG_MAX, RTCCINTREG_MAX, 0,
+ 0, 0, X86_XCPT_DE },
+ /* two positive values. */
+ { 0, 1, 1,
+ 1, 0, X86_XCPT_UD },
+ { 0, 5, 2,
+ 2, 1, X86_XCPT_UD },
+ { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2, RTCCINTREG_MAX,
+ RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_UD },
+ { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2 + 1, RTCCINTREG_MAX,
+ RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_DE },
+ /* negative dividend, positive divisor. */
+ { -1, -7, 2,
+ -3, -1, X86_XCPT_UD },
+ { RTCCINTREG_MIN / 2 + 1, 0, RTCCINTREG_MAX,
+ RTCCINTREG_MIN + 2, RTCCINTREG_MIN + 2, X86_XCPT_UD },
+ { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MAX,
+ 0, 0, X86_XCPT_DE },
+ /* positive dividend, negative divisor. */
+ { 0, 7, -2,
+ -3, 1, X86_XCPT_UD },
+ { RTCCINTREG_MAX / 2 + 1, RTCCINTREG_MAX, RTCCINTREG_MIN,
+ RTCCINTREG_MIN, RTCCINTREG_MAX, X86_XCPT_UD },
+ { RTCCINTREG_MAX / 2 + 1, (RTCCUINTREG)RTCCINTREG_MAX+1, RTCCINTREG_MIN,
+ 0, 0, X86_XCPT_DE },
+ /* negative dividend, negative divisor. */
+ { -1, -7, -2,
+ 3, -1, X86_XCPT_UD },
+ { RTCCINTREG_MIN / 2, 1, RTCCINTREG_MIN,
+ RTCCINTREG_MAX, RTCCINTREG_MIN + 1, X86_XCPT_UD },
+ { RTCCINTREG_MIN / 2, 2, RTCCINTREG_MIN,
+ RTCCINTREG_MAX, RTCCINTREG_MIN + 2, X86_XCPT_UD },
+ { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MIN,
+ 0, 0, X86_XCPT_DE },
+ };
+
+ BS3REGCTX Ctx;
+ BS3TRAPFRAME TrapFrame;
+ unsigned i, j;
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2));
+
+ /*
+ * Do the tests twice, first with all flags set, then once again with
+ * flags cleared. The flags are not touched by my intel skylake CPU.
+ */
+ Ctx.rflags.u16 |= IDIV_CHECK_EFLAGS;
+ for (j = 0; j < 2; j++)
+ {
+ for (i = 0; i < RT_ELEMENTS(s_aTests); i++)
+ {
+ Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX;
+ Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX;
+ Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX;
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+
+ if ( TrapFrame.bXcpt != s_aTests[i].bXcpt
+ || ( s_aTests[i].bXcpt == X86_XCPT_UD
+ ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX
+ || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX
+ || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS)
+ : TrapFrame.Ctx.rax.u != Ctx.rax.u
+ || TrapFrame.Ctx.rdx.u != Ctx.rdx.u
+ || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) ) )
+ {
+ Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT,
+ i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX);
+ if (TrapFrame.bXcpt != s_aTests[i].bXcpt)
+ Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt);
+ if (s_aTests[i].bXcpt == X86_XCPT_UD)
+ {
+ if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX)
+ Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
+ s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS));
+ if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX)
+ Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT,
+ s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS));
+ if ((TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS))
+ Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16",
+ Ctx.rflags.u16 & IDIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS);
+ }
+ }
+ }
+ Ctx.rflags.u16 &= ~IDIV_CHECK_EFLAGS;
+ }
+
+ return 0;
+}
+
+
+# if ARCH_BITS == 64
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b)(uint8_t bMode)
+{
+ BS3REGCTX Ctx;
+ BS3REGCTX ExpectCtx;
+ BS3TRAPFRAME TrapFrame;
+ RTUINT128U au128[3];
+ PRTUINT128U pau128 = RT_ALIGN_PT(&au128[0], sizeof(RTUINT128U), PRTUINT128U);
+ bool const fSupportCX16 = RT_BOOL(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16);
+ unsigned iFlags;
+ unsigned offBuf;
+ unsigned iMatch;
+ unsigned iWorker;
+ static struct
+ {
+ bool fLocked;
+ uint8_t offUd2;
+ FNBS3FAR *pfnWorker;
+ } const s_aWorkers[] =
+ {
+ { false, 4, BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2) },
+ { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2) },
+ { false, 5, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2) },
+ { false, 5, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2) },
+ { true, 1+4, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2) },
+ { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2) },
+ { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2) },
+ { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2) },
+ };
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+ Bs3MemSet(pau128, 0, sizeof(pau128[0]) * 2);
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+ if (!fSupportCX16)
+ Bs3TestPrintf("Note! CMPXCHG16B is not supported by the CPU!\n");
+
+ /*
+ * One loop with the normal variant and one with the locked one
+ */
+ g_usBs3TestStep = 0;
+ for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++)
+ {
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker);
+
+ /*
+ * One loop with all status flags set, and one with them clear.
+ */
+ Ctx.rflags.u16 |= X86_EFL_STATUS_BITS;
+ for (iFlags = 0; iFlags < 2; iFlags++)
+ {
+ Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
+
+ for (offBuf = 0; offBuf < sizeof(RTUINT128U); offBuf++)
+ {
+# define CX16_OLD_LO UINT64_C(0xabb6345dcc9c4bbd)
+# define CX16_OLD_HI UINT64_C(0x7b06ea35749549ab)
+# define CX16_MISMATCH_LO UINT64_C(0xbace3e3590f18981)
+# define CX16_MISMATCH_HI UINT64_C(0x9b385e8bfd5b4000)
+# define CX16_STORE_LO UINT64_C(0x5cbd27d251f6559b)
+# define CX16_STORE_HI UINT64_C(0x17ff434ed1b54963)
+
+ PRTUINT128U pBuf = (PRTUINT128U)&pau128->au8[offBuf];
+
+ ExpectCtx.rax.u = Ctx.rax.u = CX16_MISMATCH_LO;
+ ExpectCtx.rdx.u = Ctx.rdx.u = CX16_MISMATCH_HI;
+ for (iMatch = 0; iMatch < 2; iMatch++)
+ {
+ uint8_t bExpectXcpt;
+ pBuf->s.Lo = CX16_OLD_LO;
+ pBuf->s.Hi = CX16_OLD_HI;
+ ExpectCtx.rdi.u = Ctx.rdi.u = (uintptr_t)pBuf;
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+ g_usBs3TestStep++;
+ //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker);
+ bExpectXcpt = X86_XCPT_UD;
+ if (fSupportCX16)
+ {
+ if (offBuf & 15)
+ {
+ bExpectXcpt = X86_XCPT_GP;
+ ExpectCtx.rip.u = Ctx.rip.u;
+ ExpectCtx.rflags.u32 = Ctx.rflags.u32;
+ }
+ else
+ {
+ ExpectCtx.rax.u = CX16_OLD_LO;
+ ExpectCtx.rdx.u = CX16_OLD_HI;
+ if (iMatch & 1)
+ ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF;
+ else
+ ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF;
+ ExpectCtx.rip.u = Ctx.rip.u + s_aWorkers[iWorker].offUd2;
+ }
+ ExpectCtx.rflags.u32 |= X86_EFL_RF;
+ }
+ if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
+ 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)
+ || TrapFrame.bXcpt != bExpectXcpt)
+ {
+ if (TrapFrame.bXcpt != bExpectXcpt)
+ Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd);
+ Bs3TestFailedF("^^^ iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n", iWorker, iFlags, offBuf, iMatch);
+ ASMHalt();
+ }
+
+ ExpectCtx.rax.u = Ctx.rax.u = CX16_OLD_LO;
+ ExpectCtx.rdx.u = Ctx.rdx.u = CX16_OLD_HI;
+ }
+ }
+ Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS;
+ }
+ }
+
+ return 0;
+}
+
+
+static void bs3CpuInstr2_fsgsbase_ExpectUD(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame)
+{
+ pCtx->rbx.u = 0;
+ Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
+ Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
+ pExpectCtx->rip.u = pCtx->rip.u;
+ pExpectCtx->rflags.u32 |= X86_EFL_RF;
+ if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
+ 0 /*idTestStep*/)
+ || pTrapFrame->bXcpt != X86_XCPT_UD)
+ {
+ Bs3TestFailedF("Expected #UD, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
+ ASMHalt();
+ }
+}
+
+
+static bool bs3CpuInstr2_fsgsbase_VerifyWorker(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame,
+ BS3CI2FSGSBASE const *pFsGsBaseWorker, unsigned *puIter)
+{
+ bool fPassed = true;
+ unsigned iValue = 0;
+ static const struct
+ {
+ bool fGP;
+ uint64_t u64Base;
+ } s_aValues64[] =
+ {
+ { false, UINT64_C(0x0000000000000000) },
+ { false, UINT64_C(0x0000000000000001) },
+ { false, UINT64_C(0x0000000000000010) },
+ { false, UINT64_C(0x0000000000000123) },
+ { false, UINT64_C(0x0000000000001234) },
+ { false, UINT64_C(0x0000000000012345) },
+ { false, UINT64_C(0x0000000000123456) },
+ { false, UINT64_C(0x0000000001234567) },
+ { false, UINT64_C(0x0000000012345678) },
+ { false, UINT64_C(0x0000000123456789) },
+ { false, UINT64_C(0x000000123456789a) },
+ { false, UINT64_C(0x00000123456789ab) },
+ { false, UINT64_C(0x0000123456789abc) },
+ { false, UINT64_C(0x00007ffffeefefef) },
+ { false, UINT64_C(0x00007fffffffffff) },
+ { true, UINT64_C(0x0000800000000000) },
+ { true, UINT64_C(0x0000800000000000) },
+ { true, UINT64_C(0x0000800000000333) },
+ { true, UINT64_C(0x0001000000000000) },
+ { true, UINT64_C(0x0012000000000000) },
+ { true, UINT64_C(0x0123000000000000) },
+ { true, UINT64_C(0x1234000000000000) },
+ { true, UINT64_C(0xffff300000000000) },
+ { true, UINT64_C(0xffff7fffffffffff) },
+ { true, UINT64_C(0xffff7fffffffffff) },
+ { false, UINT64_C(0xffff800000000000) },
+ { false, UINT64_C(0xffffffffffeefefe) },
+ { false, UINT64_C(0xffffffffffffffff) },
+ { false, UINT64_C(0xffffffffffffffff) },
+ { false, UINT64_C(0x00000000efefefef) },
+ { false, UINT64_C(0x0000000080204060) },
+ { false, UINT64_C(0x00000000ddeeffaa) },
+ { false, UINT64_C(0x00000000fdecdbca) },
+ { false, UINT64_C(0x000000006098456b) },
+ { false, UINT64_C(0x0000000098506099) },
+ { false, UINT64_C(0x00000000206950bc) },
+ { false, UINT64_C(0x000000009740395d) },
+ { false, UINT64_C(0x0000000064a9455e) },
+ { false, UINT64_C(0x00000000d20b6eff) },
+ { false, UINT64_C(0x0000000085296d46) },
+ { false, UINT64_C(0x0000000007000039) },
+ { false, UINT64_C(0x000000000007fe00) },
+ };
+
+ Bs3RegCtxSetRipCsFromCurPtr(pCtx, pFsGsBaseWorker->pfnVerifyWorker);
+ if (pFsGsBaseWorker->f64BitOperand)
+ {
+ for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
+ {
+ bool const fGP = s_aValues64[iValue].fGP;
+
+ pCtx->rbx.u = s_aValues64[iValue].u64Base;
+ pCtx->rcx.u = 0;
+ pCtx->cr4.u |= X86_CR4_FSGSBASE;
+ Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
+ Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
+ pExpectCtx->rip.u = pCtx->rip.u + (!fGP ? pFsGsBaseWorker->offVerifyWorkerUd2 : 0);
+ pExpectCtx->rbx.u = !fGP ? 0 : s_aValues64[iValue].u64Base;
+ pExpectCtx->rcx.u = !fGP ? s_aValues64[iValue].u64Base : 0;
+ pExpectCtx->rflags.u32 |= X86_EFL_RF;
+ if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
+ 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)
+ || (fGP && pTrapFrame->bXcpt != X86_XCPT_GP))
+ {
+ if (fGP && pTrapFrame->bXcpt != X86_XCPT_GP)
+ Bs3TestFailedF("Expected #GP, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd);
+ fPassed = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++)
+ {
+ pCtx->rbx.u = s_aValues64[iValue].u64Base;
+ pCtx->rcx.u = ~s_aValues64[iValue].u64Base;
+ pCtx->cr4.u |= X86_CR4_FSGSBASE;
+ Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx));
+ Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame);
+ pExpectCtx->rip.u = pCtx->rip.u + pFsGsBaseWorker->offVerifyWorkerUd2;
+ pExpectCtx->rbx.u = 0;
+ pExpectCtx->rcx.u = s_aValues64[iValue].u64Base & UINT64_C(0x00000000ffffffff);
+ pExpectCtx->rflags.u32 |= X86_EFL_RF;
+ if (!Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/,
+ 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/))
+ {
+ fPassed = false;
+ break;
+ }
+ }
+ }
+
+ *puIter = iValue;
+ return fPassed;
+}
+
+
+static void bs3CpuInstr2_rdfsbase_rdgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
+ unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
+{
+ BS3REGCTX Ctx;
+ BS3REGCTX ExpectCtx;
+ BS3TRAPFRAME TrapFrame;
+ unsigned iWorker;
+ unsigned iIter;
+ uint32_t uDummy;
+ uint32_t uStdExtFeatEbx;
+ bool fSupportsFsGsBase;
+
+ ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
+ fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+
+ for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
+ {
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
+ if (fSupportsFsGsBase)
+ {
+ uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
+
+ /* CR4.FSGSBASE disabled -> #UD. */
+ Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
+ bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
+
+ /* Read and verify existing base address. */
+ Ctx.rbx.u = 0;
+ Ctx.cr4.u |= X86_CR4_FSGSBASE;
+ Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+ ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
+ ExpectCtx.rbx.u = uBaseAddr;
+ ExpectCtx.rflags.u32 |= X86_EFL_RF;
+ if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
+ 0 /*idTestStep*/))
+ {
+ ASMHalt();
+ }
+
+ /* Write, read and verify series of base addresses. */
+ if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
+ {
+ Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
+ ASMHalt();
+ }
+
+ /* Restore original base address. */
+ ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
+
+ /* Clean used GPRs. */
+ Ctx.rbx.u = 0;
+ Ctx.rcx.u = 0;
+ }
+ else
+ {
+ /* Unsupported by CPUID -> #UD. */
+ Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
+ bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
+ }
+ }
+}
+
+
+static void bs3CpuInstr2_wrfsbase_wrgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers,
+ unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr)
+{
+ BS3REGCTX Ctx;
+ BS3REGCTX ExpectCtx;
+ BS3TRAPFRAME TrapFrame;
+ unsigned iWorker;
+ unsigned iIter;
+ uint32_t uDummy;
+ uint32_t uStdExtFeatEbx;
+ bool fSupportsFsGsBase;
+
+ ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy);
+ fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE);
+
+ /* Ensure the structures are allocated before we sample the stack pointer. */
+ Bs3MemSet(&Ctx, 0, sizeof(Ctx));
+ Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx));
+ Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame));
+
+ /*
+ * Create test context.
+ */
+ Bs3RegCtxSaveEx(&Ctx, bMode, 512);
+
+ for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++)
+ {
+ Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker);
+ if (fSupportsFsGsBase)
+ {
+ uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr);
+
+ /* CR4.FSGSBASE disabled -> #UD. */
+ Ctx.cr4.u &= ~X86_CR4_FSGSBASE;
+ bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
+
+ /* Write a base address. */
+ Ctx.rbx.u = 0xa0000;
+ Ctx.cr4.u |= X86_CR4_FSGSBASE;
+ Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx));
+ Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame);
+ ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2;
+ ExpectCtx.rflags.u32 |= X86_EFL_RF;
+ if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64",
+ 0 /*idTestStep*/))
+ {
+ ASMHalt();
+ }
+
+ /* Write and read back series of base addresses. */
+ if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter))
+ {
+ Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter);
+ ASMHalt();
+ }
+
+ /* Restore original base address. */
+ ASMWrMsr(idxFsGsBaseMsr, uBaseAddr);
+
+ /* Clean used GPRs. */
+ Ctx.rbx.u = 0;
+ Ctx.rcx.u = 0;
+ }
+ else
+ {
+ /* Unsupported by CPUID -> #UD. */
+ Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n");
+ bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame);
+ }
+ }
+}
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrfsbase)(uint8_t bMode)
+{
+ bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrFsBaseWorkers, RT_ELEMENTS(s_aWrFsBaseWorkers), MSR_K8_FS_BASE);
+ return 0;
+}
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrgsbase)(uint8_t bMode)
+{
+ bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrGsBaseWorkers, RT_ELEMENTS(s_aWrGsBaseWorkers), MSR_K8_GS_BASE);
+ return 0;
+}
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdfsbase)(uint8_t bMode)
+{
+ bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdFsBaseWorkers, RT_ELEMENTS(s_aRdFsBaseWorkers), MSR_K8_FS_BASE);
+ return 0;
+}
+
+
+BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdgsbase)(uint8_t bMode)
+{
+ bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdGsBaseWorkers, RT_ELEMENTS(s_aRdGsBaseWorkers), MSR_K8_GS_BASE);
+ return 0;
+}
+# endif /* ARCH_BITS == 64 */
+
+
+#endif /* BS3_INSTANTIATING_CMN */
+
+
+
+/*
+ * Mode specific code.
+ * Mode specific code.
+ * Mode specific code.
+ */
+#ifdef BS3_INSTANTIATING_MODE
+
+
+#endif /* BS3_INSTANTIATING_MODE */
+