VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.c@ 77807

Last change on this file since 77807 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1/* $Id: bs3-fpustate-1-template.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-fpustate-1, C code template.
4 */
5
6/*
7 * Copyright (C) 2007-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/asm.h>
32#include <iprt/asm-amd64-x86.h>
33#include <VBox/VMMDevTesting.h>
34
35
36/*********************************************************************************************************************************
37* Defined Constants And Macros *
38*********************************************************************************************************************************/
39
40
41#ifdef BS3_INSTANTIATING_CMN
42
43/**
44 * Displays the differences between the two states.
45 */
46# define bs3FpuState1_Diff BS3_CMN_NM(bs3FpuState1_Diff)
47BS3_DECL_NEAR(void) bs3FpuState1_Diff(X86FXSTATE const BS3_FAR *pExpected, X86FXSTATE const BS3_FAR *pChecking)
48{
49 unsigned i;
50
51# define CHECK(a_Member, a_Fmt) \
52 if (pExpected->a_Member != pChecking->a_Member) \
53 Bs3TestPrintf(" " #a_Member ": " a_Fmt ", expected " a_Fmt "\n", pChecking->a_Member, pExpected->a_Member); \
54 else do { } while (0)
55 CHECK(FCW, "%#RX16");
56 CHECK(FSW, "%#RX16");
57 CHECK(FTW, "%#RX16");
58 CHECK(FOP, "%#RX16");
59 CHECK(FPUIP, "%#RX32");
60 CHECK(CS, "%#RX16");
61 CHECK(Rsrvd1, "%#RX16");
62 CHECK(FPUDP, "%#RX32");
63 CHECK(DS, "%#RX16");
64 CHECK(Rsrvd2, "%#RX16");
65 CHECK(MXCSR, "%#RX32");
66 CHECK(MXCSR_MASK, "%#RX32");
67# undef CHECK
68 for (i = 0; i < RT_ELEMENTS(pExpected->aRegs); i++)
69 if ( pChecking->aRegs[i].au64[0] != pExpected->aRegs[i].au64[0]
70 || pChecking->aRegs[i].au64[1] != pExpected->aRegs[i].au64[1])
71 Bs3TestPrintf("st%u: %.16Rhxs\n"
72 "exp: %.16Rhxs\n",
73 i, &pChecking->aRegs[i], &pExpected->aRegs[i]);
74 for (i = 0; i < RT_ELEMENTS(pExpected->aXMM); i++)
75 if ( pChecking->aXMM[i].au64[0] != pExpected->aXMM[i].au64[0]
76 || pChecking->aXMM[i].au64[1] != pExpected->aXMM[i].au64[1])
77 Bs3TestPrintf("xmm%u: %.16Rhxs\n"
78 " %sexp: %.16Rhxs\n",
79 i, &pChecking->aRegs[i], &pExpected->aRegs[i], i >= 10 ? " " : "");
80}
81
82
83#endif /* BS3_INSTANTIATING_CMN */
84
85
86/*
87 * Mode specific code.
88 * Mode specific code.
89 * Mode specific code.
90 */
91#ifdef BS3_INSTANTIATING_MODE
92# if TMPL_MODE == BS3_MODE_PE32 \
93 || TMPL_MODE == BS3_MODE_PP32 \
94 || TMPL_MODE == BS3_MODE_PAE32 \
95 || TMPL_MODE == BS3_MODE_LM64 \
96 || TMPL_MODE == BS3_MODE_RM
97
98/* Assembly helpers: */
99BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_InitState)(X86FXSTATE BS3_FAR *pFxState, void BS3_FAR *pvMmioReg);
100BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_Restore)(X86FXSTATE const BS3_FAR *pFxState);
101BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_Save)(X86FXSTATE BS3_FAR *pFxState);
102
103BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_FNStEnv)(void BS3_FAR *pvMmioReg);
104BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_MovDQU_Read)(void BS3_FAR *pvMmioReg);
105BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_MovDQU_Write)(void BS3_FAR *pvMmioReg);
106BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_FMul)(void BS3_FAR *pvMmioReg);
107
108
109/**
110 * Tests for FPU state corruption.
111 *
112 * First we don't do anything to quit guest context for a while.
113 * Then we start testing weird MMIO accesses, some which amonger other things
114 * forces the use of the FPU state or host FPU to do the emulation. Both are a
115 * little complicated in raw-mode and ring-0 contexts.
116 *
117 * We ASSUME FXSAVE/FXRSTOR support here.
118 */
119BS3_DECL_FAR(uint8_t) TMPL_NM(bs3FpuState1_Corruption)(uint8_t bMode)
120{
121 /* We don't need to test that many modes, probably. */
122
123 uint8_t abBuf[sizeof(X86FXSTATE)*2 + 32];
124 uint8_t BS3_FAR *pbTmp = &abBuf[0x10 - (((uintptr_t)abBuf) & 0x0f)];
125 X86FXSTATE BS3_FAR *pExpected = (X86FXSTATE BS3_FAR *)pbTmp;
126 X86FXSTATE BS3_FAR *pChecking = pExpected + 1;
127 uint32_t iLoop;
128 uint32_t uStartTick;
129 bool fMmioReadback;
130 bool fReadBackError = false;
131 BS3PTRUNION MmioReg;
132
133
134# undef CHECK_STATE
135# define CHECK_STATE(a_Instr) \
136 do { \
137 TMPL_NM(bs3FpuState1_Save)(pChecking); \
138 if (Bs3MemCmp(pExpected, pChecking, sizeof(*pExpected)) != 0) \
139 { \
140 Bs3TestFailedF("State differs after " #a_Instr " (write) in loop #%RU32\n", iLoop); \
141 bs3FpuState1_Diff(pExpected, pChecking); \
142 Bs3PitDisable(); \
143 return 1; \
144 } \
145 } while (0)
146
147 /*
148 * Setup the test.
149 */
150
151 /* Make this code executable in raw-mode. A bit tricky. */
152 ASMSetCR0(ASMGetCR0() | X86_CR0_WP);
153 Bs3PitSetupAndEnablePeriodTimer(20);
154 ASMIntEnable();
155# if ARCH_BITS != 64
156 ASMHalt();
157# endif
158
159 /* Figure out which MMIO region we'll be using so we can correctly initialize FPUDS. */
160# if BS3_MODE_IS_RM_OR_V86(TMPL_MODE)
161 MmioReg.pv = BS3_FP_MAKE(0xffff, VMMDEV_TESTING_MMIO_BASE - _1M + 16);
162# elif BS3_MODE_IS_16BIT_CODE(TMPL_MODE)
163 MmioReg.pv = BS3_FP_MAKE(BS3_SEL_VMMDEV_MMIO16, VMMDEV_TESTING_MMIO_BASE - _1M);
164# else
165 MmioReg.pv = (uint8_t *)VMMDEV_TESTING_MMIO_BASE;
166# endif
167 if (MmioReg.pu32[VMMDEV_TESTING_MMIO_OFF_NOP / sizeof(uint32_t)] == VMMDEV_TESTING_NOP_RET)
168 {
169 fMmioReadback = true;
170 MmioReg.pb += VMMDEV_TESTING_MMIO_OFF_READBACK;
171 }
172 else
173 {
174 Bs3TestPrintf("VMMDev MMIO not found, using VGA instead\n");
175 fMmioReadback = false;
176 MmioReg.pv = Bs3XptrFlatToCurrent(0xa7800);
177 }
178
179 /* Make 100% sure we don't trap accessing the FPU state and that we can use fxsave/fxrstor. */
180 g_usBs3TestStep = 1;
181 ASMSetCR0((ASMGetCR0() & ~(X86_CR0_TS | X86_CR0_EM)) | X86_CR0_MP);
182 ASMSetCR4(ASMGetCR4() | X86_CR4_OSFXSR /*| X86_CR4_OSXMMEEXCPT*/);
183
184 /* Come up with a distinct state. We do that from assembly (will do FPU in R0/RC). */
185 g_usBs3TestStep = 2;
186 Bs3MemSet(abBuf, 0x42, sizeof(abBuf));
187 TMPL_NM(bs3FpuState1_InitState)(pExpected, MmioReg.pb);
188
189
190 /*
191 * Test #1: Check that we can keep it consistent for a while.
192 */
193 g_usBs3TestStep = 3;
194 uStartTick = g_cBs3PitTicks;
195 for (iLoop = 0; iLoop < _16M; iLoop++)
196 {
197 CHECK_STATE(nop);
198 if ( (iLoop & 0xffff) == 0xffff
199 && g_cBs3PitTicks - uStartTick >= 20 * 20) /* 20 seconds*/
200 break;
201 }
202
203 /*
204 * Test #2: Use various FPU, SSE and weird instructions to do MMIO writes.
205 *
206 * We'll use the VMMDev readback register if possible, but make do
207 * with VGA if not configured.
208 */
209 g_usBs3TestStep = 4;
210 uStartTick = g_cBs3PitTicks;
211 for (iLoop = 0; iLoop < _1M; iLoop++)
212 {
213 unsigned off;
214 uint8_t abCompare[64];
215 uint8_t abReadback[64];
216
217 /* Macros */
218# undef CHECK_READBACK_WRITE_RUN
219# define CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type) \
220 do { \
221 off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \
222 if (off + sizeof(a_Type) > VMMDEV_TESTING_READBACK_SIZE) \
223 off = VMMDEV_TESTING_READBACK_SIZE - sizeof(a_Type); \
224 a_Worker((a_Type *)&MmioReg.pb[off]); \
225 if (fMmioReadback && (!fReadBackError || iLoop == 0)) \
226 { \
227 a_Worker((a_Type *)&abCompare[0]); \
228 Bs3MemCpy(abReadback, &MmioReg.pb[off], sizeof(a_Type)); \
229 if (Bs3MemCmp(abReadback, abCompare, sizeof(a_Type)) != 0) \
230 { \
231 Bs3TestFailedF("Read back error for " #a_Instr " in loop #%RU32:\n%.*Rhxs expected:\n%.*Rhxs\n", \
232 iLoop, sizeof(a_Type), abReadback, sizeof(a_Type), abCompare); \
233 fReadBackError = true; \
234 } \
235 } \
236 } while (0)
237
238# undef CHECK_READBACK_WRITE
239# define CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type) \
240 CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type); \
241 CHECK_STATE(a_Instr)
242# undef CHECK_READBACK_WRITE_Z
243# define CHECK_READBACK_WRITE_Z(a_Instr, a_Worker, a_Type) \
244 do { \
245 if (fMmioReadback && (!fReadBackError || iLoop == 0)) \
246 { \
247 Bs3MemZero(&abCompare[0], sizeof(a_Type)); \
248 off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \
249 if (off + sizeof(a_Type) > VMMDEV_TESTING_READBACK_SIZE) \
250 off = VMMDEV_TESTING_READBACK_SIZE - sizeof(a_Type); \
251 Bs3MemZero(&MmioReg.pb[off], sizeof(a_Type)); \
252 } \
253 CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type); \
254 } while (0)
255
256# undef CHECK_READBACK_READ_RUN
257# define CHECK_READBACK_READ_RUN(a_Instr, a_Worker, a_Type) \
258 do { \
259 off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \
260 if (off + sizeof(a_Type) > VMMDEV_TESTING_READBACK_SIZE) \
261 off = VMMDEV_TESTING_READBACK_SIZE - sizeof(a_Type); \
262 a_Worker((a_Type *)&MmioReg.pb[off]); \
263 TMPL_NM(bs3FpuState1_Save)(pChecking); \
264 } while (0)
265# undef CHECK_READBACK_READ
266# define CHECK_READBACK_READ(a_Instr, a_Worker, a_Type) \
267 CHECK_READBACK_READ_RUN(a_Instr, a_Worker, a_Type); \
268 CHECK_STATE(a_Instr)
269
270
271 /* The tests. */
272 CHECK_READBACK_WRITE_Z(SIDT, ASMGetIDTR, RTIDTR);
273 CHECK_READBACK_WRITE_Z(FNSTENV, TMPL_NM(bs3FpuState1_FNStEnv), X86FSTENV32P); /** @todo x86.h is missing types */
274 CHECK_READBACK_WRITE( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Write), X86XMMREG);
275 CHECK_READBACK_READ( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Read), X86XMMREG);
276
277 /* Using the FPU is a little complicated, but we really need to check these things. */
278 CHECK_READBACK_READ_RUN(FMUL, TMPL_NM(bs3FpuState1_FMul), uint64_t);
279 pExpected->FOP = 0x7dc;
280# if ARCH_BITS == 64
281 pExpected->FPUDP = (uint32_t) (uintptr_t)&MmioReg.pb[off];
282 pExpected->DS = (uint16_t)((uintptr_t)&MmioReg.pb[off] >> 32);
283 pExpected->Rsrvd2 = (uint16_t)((uintptr_t)&MmioReg.pb[off] >> 48);
284# elif BS3_MODE_IS_RM_OR_V86(TMPL_MODE)
285 pExpected->FPUDP = Bs3SelPtrToFlat(&MmioReg.pb[off]);
286# else
287 pExpected->FPUDP = BS3_FP_OFF(&MmioReg.pb[off]);
288# endif
289 CHECK_STATE(FMUL);
290
291 /* check for timeout every now an then. */
292 if ( (iLoop & 0xfff) == 0xfff
293 && g_cBs3PitTicks - uStartTick >= 20 * 20) /* 20 seconds*/
294 break;
295 }
296
297 Bs3PitDisable();
298 return 0;
299}
300# endif
301#endif /* BS3_INSTANTIATING_MODE */
302
Note: See TracBrowser for help on using the repository browser.

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