/* $Id: bs3-cpu-decoding-1.c32 62410 2016-07-21 20:26:33Z vboxsync $ */ /** @file * BS3Kit - bs3-cpu-decoding-1, 32-bit C code. */ /* * Copyright (C) 2007-2016 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 #include /** * Simple test. */ typedef struct CPUDECODE1TST { uint8_t fFlags; uint8_t cbUd; uint8_t cbOpcodes; uint8_t abOpcodes[21]; } CPUDECODE1TST; typedef CPUDECODE1TST BS3_FAR *PCPUDECODE1TST; #define P_CS X86_OP_PRF_CS #define P_SS X86_OP_PRF_SS #define P_DS X86_OP_PRF_DS #define P_ES X86_OP_PRF_ES #define P_FS X86_OP_PRF_FS #define P_GS X86_OP_PRF_GS #define P_OZ X86_OP_PRF_SIZE_OP #define P_AZ X86_OP_PRF_SIZE_ADDR #define P_LK X86_OP_PRF_LOCK #define P_RZ X86_OP_PRF_REPZ #define P_RN X86_OP_PRF_REPNZ #define RM_EAX_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) #define RM_EAX_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) #define F_486 0 #define F_SSE2 1 #define F_SSE3 2 #define F_SSE42 4 #define F_MOVBE 80 CPUDECODE1TST const g_aSimpleTests[] = { /* * fFlags, cbUd, cbOpcodes, abOpcodes */ #if 1 /* Using currently undefined 0x0f 0x7a sequences. */ { 0, 3, 3, { 0x0f, 0x7a, RM_EAX_EAX, } }, { 0, 3+1, 3+1, { P_LK, 0x0f, 0x7a, RM_EAX_EAX, } }, { 0, 3+1, 3+1, { P_RN, 0x0f, 0x7a, RM_EAX_EAX, } }, { 0, 3+1, 3+1, { P_RZ, 0x0f, 0x7a, RM_EAX_EAX, } }, { 0, 3+2, 3+2, { P_LK, P_LK, 0x0f, 0x7a, RM_EAX_EAX, } }, #endif #if 0 /* The XADD instruction has empty lines for 66, f3 and f2 prefixes. AMD doesn't do anything special for XADD Ev,Gv as the intel table would indicate. */ { F_486, 99, 3, { 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 4, { P_OZ, 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 4, { P_RN, 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 5, { P_OZ, P_RN, 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 5, { P_RN, P_OZ, 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 4, { P_RZ, 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 5, { P_OZ, P_RZ, 0x0f, 0xc1, RM_EAX_EAX, } }, { F_486, 99, 5, { P_RZ, P_OZ, 0x0f, 0xc1, RM_EAX_EAX, } }, #endif #if 0 /* The movnti instruction is confined to the unprefixed lined in the intel manuals. Check how the other lines work. */ { F_SSE2, 3, 3, { 0x0f, 0xc3, RM_EAX_EAX, } }, /* invalid - reg,reg */ { F_SSE2, 99, 3, { 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, { F_SSE2, 4, 4, { P_OZ, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ { F_SSE2, 4, 4, { P_RN, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ { F_SSE2, 4, 4, { P_RZ, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ { F_SSE2, 4, 4, { P_LK, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ { F_SSE2, 5, 5, { P_RZ, P_LK, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ #endif #if 1 /* The lddqu instruction requires a 0xf2 prefix, intel only lists 0x66 and empty prefix for it. Check what they really mean by that*/ { F_SSE3, 4, 4, { P_RZ, 0x0f, 0xf0, RM_EAX_EAX, } }, /* invalid - reg, reg */ { F_SSE3, 99, 4, { P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 99, 5, { P_RZ, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 3, 3, { 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 4, 4, { P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 4, 4, { P_OZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 4, 4, { P_LK, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 5, 5, { P_RZ, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 99, 5, { P_RZ, P_OZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, // AMD,why? { F_SSE3, 5, 5, { P_RZ, P_LK, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 99, 5, { P_RN, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 99, 5, { P_OZ, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 5, 5, { P_LK, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 99, 5, { P_OZ, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, { F_SSE3, 99, 6,{ P_OZ, P_RN, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, #endif { F_SSE2, 99, 3, { 0x0f, 0x7e, RM_EAX_EAX, } }, { F_SSE2, 99, 4, { P_OZ, 0x0f, 0x7e, RM_EAX_EAX, } }, { F_SSE2, 5, 5,{ P_RZ, P_OZ, 0x0f, 0x7e, RM_EAX_EAX, } }, // WTF? { F_SSE2, 5, 5,{ P_OZ, P_RZ, 0x0f, 0x7e, RM_EAX_EAX, } }, { F_SSE2, 99, 5,{ P_RN, P_OZ, 0x0f, 0x7e, RM_EAX_EAX, } }, { F_SSE2, 99, 4, { P_RN, 0x0f, 0x7e, RM_EAX_EAX, } }, { F_SSE2, 4, 4, { P_RZ, 0x0f, 0x7e, RM_EAX_EAX, } }, /** @todo crc32 / movbe */ }; void DecodeEdgeTest(void) { /* * Allocate and initialize a page pair */ uint8_t BS3_FAR *pbPages; pbPages = Bs3MemGuardedTestPageAlloc(BS3MEMKIND_FLAT32); if (pbPages) { unsigned i; BS3REGCTX Ctx; BS3TRAPFRAME TrapFrame; Bs3MemZero(&Ctx, sizeof(Ctx)); Bs3MemZero(&TrapFrame, sizeof(TrapFrame)); ASMSetCR0((ASMGetCR0() & ~(X86_CR0_EM | X86_CR0_TS)) | X86_CR0_MP); ASMSetCR4(ASMGetCR4() | X86_CR4_OSFXSR); Bs3RegCtxSaveEx(&Ctx, BS3_MODE_CODE_32, 512); Ctx.rbx.u64 = (uintptr_t)pbPages; for (i = 0; i < RT_ELEMENTS(g_aSimpleTests); i++) { unsigned cb = g_aSimpleTests[i].cbOpcodes; while (cb >= 1) { unsigned const cErrorsBefore = Bs3TestSubErrorCount(); uint8_t BS3_FAR *pbRip = &pbPages[X86_PAGE_SIZE - cb]; Bs3MemCpy(pbRip, &g_aSimpleTests[i].abOpcodes[0], cb); Bs3RegCtxSetRipCsFromFlat(&Ctx, (uintptr_t)pbRip); Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); #if 0 Bs3TestPrintf("\ni=%d cb=%#x (cbUd=%#x cbOpcodes=%#x)\n", i, cb, g_aSimpleTests[i].cbUd, g_aSimpleTests[i].cbOpcodes); Bs3TrapPrintFrame(&TrapFrame); #endif if (cb >= g_aSimpleTests[i].cbUd) { if (TrapFrame.bXcpt != X86_XCPT_UD) Bs3TestFailedF("i=%d cb=%d cbUd=%d cbOp=%d: expected #UD got %#x at %RX32\n", i, cb, g_aSimpleTests[i].cbUd, g_aSimpleTests[i].cbOpcodes, TrapFrame.bXcpt, TrapFrame.Ctx.rip.u32); } else if (cb < g_aSimpleTests[i].cbOpcodes) { if (TrapFrame.bXcpt != X86_XCPT_PF) Bs3TestFailedF("i=%d cb=%d cbUd=%d cbOp=%d: expected #PF (on) got %#x at %RX32\n", i, cb, g_aSimpleTests[i].cbUd, g_aSimpleTests[i].cbOpcodes, TrapFrame.bXcpt, TrapFrame.Ctx.rip.u32); else if (TrapFrame.Ctx.rip.u32 != (uintptr_t)pbRip) Bs3TestFailedF("i=%d cb=%d cbUd=%d cbOp=%d: expected #PF rip of %p (on) got %#RX32\n", i, cb, g_aSimpleTests[i].cbUd, g_aSimpleTests[i].cbOpcodes, pbRip, TrapFrame.Ctx.rip.u32); } else { if (TrapFrame.bXcpt != X86_XCPT_PF) Bs3TestFailedF("i=%d cb=%d cbUd=%d cbOp=%d: expected #PF (after) got %#x at %RX32\n", i, cb, g_aSimpleTests[i].cbUd, g_aSimpleTests[i].cbOpcodes, TrapFrame.bXcpt, TrapFrame.Ctx.rip.u32); else if (TrapFrame.Ctx.rip.u32 != (uintptr_t)&pbPages[X86_PAGE_SIZE]) Bs3TestFailedF("i=%d cb=%d cbUd=%d cbOp=%d: expected #PF rip of %p (after) got %#RX32\n", i, cb, g_aSimpleTests[i].cbUd, g_aSimpleTests[i].cbOpcodes, &pbPages[X86_PAGE_SIZE], TrapFrame.Ctx.rip.u32); } if (Bs3TestSubErrorCount() != cErrorsBefore) { Bs3TestPrintf(" %.*Rhxs", cb, &g_aSimpleTests[i].abOpcodes[0]); if (cb < g_aSimpleTests[i].cbOpcodes) Bs3TestPrintf("[%.*Rhxs]", g_aSimpleTests[i].cbOpcodes - cb, &g_aSimpleTests[i].abOpcodes[cb]); Bs3TestPrintf("\n"); } /* next */ cb--; } } Bs3MemGuardedTestPageFree(pbPages); } else Bs3TestFailed("Failed to allocate two pages!\n"); /* * Test instruction sequences. */ } BS3_DECL(void) Main_pp32() { Bs3TestInit("bs3-cpu-decoding-1"); Bs3TestPrintf("g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); DecodeEdgeTest(); Bs3TestTerm(); //for (;;) ASMHalt(); }