/* $Id: bs3-cmn-TestCheckExtCtx.c $ */ /** @file * BS3Kit - Bs3TestCheckExtCtx */ /* * Copyright (C) 2007-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included * in the VirtualBox 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. * * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #include "bs3kit-template-header.h" /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Field descriptors. */ static struct { uint8_t enmMethod; uint8_t cb; uint16_t off; const char BS3_FAR *pszName; } const g_aFields[] = { #define BS3EXTCTX_FIELD_ENTRY(a_enmMethod, a_Member) \ { a_enmMethod, RT_SIZEOFMEMB(BS3EXTCTX, a_Member), RT_OFFSETOF(BS3EXTCTX, a_Member), #a_Member } BS3EXTCTX_FIELD_ENTRY(BS3EXTCTXMETHOD_END, fXcr0Saved), #define BS3EXTCTX_FIELD_ENTRY_CTX(a_enmMethod, a_Member) \ { a_enmMethod, RT_SIZEOFMEMB(BS3EXTCTX, Ctx.a_Member), RT_OFFSETOF(BS3EXTCTX, Ctx.a_Member), #a_Member } BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FCW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.Dummy1), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FSW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.Dummy2), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FTW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.Dummy3), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FPUIP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.CS), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FOP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FPUOO), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.FPUOS), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[0]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[1]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[2]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[3]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[4]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[5]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[6]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_ANCIENT, Ancient.regs[7]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.FCW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.FSW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.FTW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.FOP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.FPUIP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.CS), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.Rsrvd1), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.FPUDP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.DS), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.Rsrvd2), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.MXCSR), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.MXCSR_MASK), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[0]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[1]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[2]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[3]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[4]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[5]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[6]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aRegs[7]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[0]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[1]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[2]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[3]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[4]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[5]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[6]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[7]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[8]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[9]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[10]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[11]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[12]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[13]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[14]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_FXSAVE, x87.aXMM[15]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.FCW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.FSW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.FTW), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.FOP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.FPUIP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.CS), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.Rsrvd1), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.FPUDP), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.DS), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.Rsrvd2), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.MXCSR), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.MXCSR_MASK), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[0]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[1]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[2]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[3]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[4]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[5]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[6]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aRegs[7]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[0]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[1]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[2]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[3]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[4]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[5]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[6]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[7]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[8]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[9]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[10]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[11]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[12]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[13]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[14]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.x87.aXMM[15]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.Hdr.bmXState), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.Hdr.bmXComp), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[0]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[1]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[2]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[3]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[4]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[5]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[6]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[7]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[8]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[9]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[10]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[11]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[12]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[13]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[14]), BS3EXTCTX_FIELD_ENTRY_CTX(BS3EXTCTXMETHOD_XSAVE, x.u.YmmHi.aYmmHi[15]), }; #undef Bs3TestCheckExtCtx BS3_CMN_DEF(bool, Bs3TestCheckExtCtx,(PCBS3EXTCTX pActualExtCtx, PCBS3EXTCTX pExpectedExtCtx, uint16_t fFlags, const char BS3_FAR *pszMode, uint16_t idTestStep)) { /* * Make sure the context of a similar and valid before starting. */ if (!pActualExtCtx || pActualExtCtx->u16Magic != BS3EXTCTX_MAGIC) return Bs3TestFailedF("%u - %s: invalid actual context pointer: %p", idTestStep, pszMode, pActualExtCtx); if (!pExpectedExtCtx || pExpectedExtCtx->u16Magic != BS3EXTCTX_MAGIC) return Bs3TestFailedF("%u - %s: invalid expected context pointer: %p", idTestStep, pszMode, pExpectedExtCtx); if ( pActualExtCtx->enmMethod != pExpectedExtCtx->enmMethod || pActualExtCtx->enmMethod == BS3EXTCTXMETHOD_INVALID || pActualExtCtx->enmMethod >= BS3EXTCTXMETHOD_END) return Bs3TestFailedF("%u - %s: mismatching or/and invalid context methods: %d vs %d", idTestStep, pszMode, pActualExtCtx->enmMethod, pExpectedExtCtx->enmMethod); if (pActualExtCtx->cb != pExpectedExtCtx->cb) return Bs3TestFailedF("%u - %s: mismatching context sizes: %#x vs %#x", idTestStep, pszMode, pActualExtCtx->cb, pExpectedExtCtx->cb); /* * Try get the job done quickly with a memory compare. */ if (Bs3MemCmp(pActualExtCtx, pExpectedExtCtx, pActualExtCtx->cb) == 0) return true; Bs3TestFailedF("%u - %s: context memory differs", idTestStep, pszMode); // debug { uint8_t const BS3_FAR *pb1 = (uint8_t const BS3_FAR *)pActualExtCtx; uint8_t const BS3_FAR *pb2 = (uint8_t const BS3_FAR *)pExpectedExtCtx; unsigned const cb = pActualExtCtx->cb; unsigned off; for (off = 0; off < cb; off++) if (pb1[off] != pb2[off]) { unsigned offStart = off++; const char BS3_FAR *pszName = NULL; unsigned cbDiff = 0; unsigned idxField; for (idxField = 0; idxField < RT_ELEMENTS(g_aFields); idxField++) if ( offStart - g_aFields[idxField].off < g_aFields[idxField].cb && ( g_aFields[idxField].enmMethod == BS3EXTCTXMETHOD_END || g_aFields[idxField].enmMethod == pActualExtCtx->enmMethod)) { pszName = g_aFields[idxField].pszName; cbDiff = g_aFields[idxField].cb; offStart = g_aFields[idxField].off; off = offStart + cbDiff; break; } if (!pszName) { while (off < cb && pb1[off] != pb2[off]) off++; cbDiff = off - offStart; pszName = "unknown"; } switch (cbDiff) { case 1: Bs3TestFailedF("%u - %s: Byte difference at %#x (%s): %#04x, expected %#04x", idTestStep, pszMode, offStart, pszName, pb1[offStart], pb2[offStart]); break; case 2: Bs3TestFailedF("%u - %s: Word difference at %#x (%s): %#06x, expected %#06x", idTestStep, pszMode, offStart, pszName, RT_MAKE_U16(pb1[offStart], pb1[offStart + 1]), RT_MAKE_U16(pb2[offStart], pb2[offStart + 1])); break; case 4: Bs3TestFailedF("%u - %s: DWord difference at %#x (%s): %#010RX32, expected %#010RX32", idTestStep, pszMode, offStart, pszName, RT_MAKE_U32_FROM_U8(pb1[offStart], pb1[offStart + 1], pb1[offStart + 2], pb1[offStart + 3]), RT_MAKE_U32_FROM_U8(pb2[offStart], pb2[offStart + 1], pb2[offStart + 2], pb2[offStart + 3])); break; case 8: Bs3TestFailedF("%u - %s: QWord difference at %#x (%s): %#018RX64, expected %#018RX64", idTestStep, pszMode, offStart, pszName, RT_MAKE_U64_FROM_U8(pb1[offStart], pb1[offStart + 1], pb1[offStart + 2], pb1[offStart + 3], pb1[offStart + 4], pb1[offStart + 5], pb1[offStart + 6], pb1[offStart + 7]), RT_MAKE_U64_FROM_U8(pb2[offStart], pb2[offStart + 1], pb2[offStart + 2], pb2[offStart + 3], pb2[offStart + 4], pb2[offStart + 5], pb2[offStart + 6], pb2[offStart + 7])); break; case 16: Bs3TestFailedF("%u - %s: DQword difference at %#x (%s): \n" "got %#018RX64'%#018RX64\n" "expected %#018RX64'%#018RX64", idTestStep, pszMode, offStart, pszName, RT_MAKE_U64_FROM_U8(pb1[offStart + 8], pb1[offStart + 9], pb1[offStart + 10], pb1[offStart + 11], pb1[offStart + 12], pb1[offStart + 13], pb1[offStart + 14], pb1[offStart + 15]), RT_MAKE_U64_FROM_U8(pb1[offStart], pb1[offStart + 1], pb1[offStart + 2], pb1[offStart + 3], pb1[offStart + 4], pb1[offStart + 5], pb1[offStart + 6], pb1[offStart + 7]), RT_MAKE_U64_FROM_U8(pb2[offStart + 8], pb2[offStart + 9], pb2[offStart + 10], pb2[offStart + 11], pb2[offStart + 12], pb2[offStart + 13], pb2[offStart + 14], pb2[offStart + 15]), RT_MAKE_U64_FROM_U8(pb2[offStart], pb2[offStart + 1], pb2[offStart + 2], pb2[offStart + 3], pb2[offStart + 4], pb2[offStart + 5], pb2[offStart + 6], pb2[offStart + 7]) ); break; default: Bs3TestFailedF("%u - %s: %#x..%#x differs (%s)\n" "got %.*Rhxs\n" "expected %.*Rhxs", idTestStep, pszMode, offStart, off - 1, pszName, off - offStart, &pb1[offStart], off - offStart, &pb2[offStart]); break; } } } return false; }