Changeset 92554 in vbox
- Timestamp:
- Nov 22, 2021 6:36:16 PM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 148435
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.c
r92530 r92554 110 110 111 111 /** 112 * Checks if we're seeing a problem with fnstenv saving zero selectors when 113 * running on the compare area. 114 * 115 * This triggers in NEM mode if the native hypervisor doesn't do a good enough 116 * job at save the FPU state for 16-bit and 32-bit guests. We have heuristics 117 * in CPUMInternal.mac (SAVE_32_OR_64_FPU) for this. 118 * 119 * @returns true if this the zero selector issue. 120 * @param pabReadback The MMIO read buffer containing the fnstenv result 121 * typically produced by IEM. 122 * @param pabCompare The buffer containing the fnstenv result typcially 123 * produced by the CPU itself. 124 */ 125 static bool TMPL_NM(bs3FpuState1_IsZeroFnStEnvSelectorsProblem)(const uint8_t BS3_FAR *pabReadback, 126 const uint8_t BS3_FAR *pabCompare) 127 { 128 unsigned const offCs = ARCH_BITS == 16 ? 8 : 16; 129 unsigned const offDs = ARCH_BITS == 16 ? 12 : 24; 130 if ( *(const uint16_t BS3_FAR *)&pabCompare[offCs] == 0 131 && *(const uint16_t BS3_FAR *)&pabCompare[offDs] == 0) 132 { 133 /* Check the stuff before the CS register: */ 134 if (Bs3MemCmp(pabReadback, pabCompare, offCs) == 0) 135 { 136 /* Check the stuff between the DS and CS registers:*/ 137 if (Bs3MemCmp(&pabReadback[offCs + 2], &pabCompare[offCs + 2], offDs - offCs - 2) == 0) 138 { 139 #if ARCH_BITS != 16 140 /* Check the stuff after the DS register if 32-bit mode: */ 141 if ( *(const uint16_t BS3_FAR *)&pabReadback[offDs + 2] 142 == *(const uint16_t BS3_FAR *)&pabCompare[offDs + 2]) 143 #endif 144 return true; 145 } 146 } 147 } 148 return false; 149 } 150 151 152 /** 112 153 * Tests for FPU state corruption. 113 154 * … … 124 165 125 166 uint8_t abBuf[sizeof(X86FXSTATE)*2 + 32]; 126 uint8_t BS3_FAR *pbTmp = &abBuf[0x10 - (((uintptr_t)abBuf) & 0x0f)];127 X86FXSTATE BS3_FAR *pExpected = (X86FXSTATE BS3_FAR *)pbTmp;128 X86FXSTATE BS3_FAR *pChecking = pExpected + 1;167 uint8_t BS3_FAR *pbTmp = &abBuf[0x10 - (((uintptr_t)abBuf) & 0x0f)]; 168 X86FXSTATE BS3_FAR *pExpected = (X86FXSTATE BS3_FAR *)pbTmp; 169 X86FXSTATE BS3_FAR *pChecking = pExpected + 1; 129 170 uint32_t iLoop; 130 171 uint32_t uStartTick; 131 172 bool fMmioReadback; 132 bool fReadBackError = false; 133 bool fReadError = false; 173 bool fReadBackError = false; 174 bool fReadError = false; 175 uint32_t cFnStEnvSelectorsZero = 0; 134 176 BS3PTRUNION MmioReg; 135 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor(); 136 bool const fSkipStorIdt = Bs3TestQueryCfgBool(VMMDEV_TESTING_CFG_IS_NEM_LINUX); 137 bool const fFastFxSaveRestore = RT_BOOL(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_FFXSR); 138 //bool const fFdpXcptOnly = (ASMCpuIdEx_EBX(7, 0) & X86_CPUID_STEXT_FEATURE_EBX_FDP_EXCPTN_ONLY) 139 // && ASMCpuId_EAX(0) >= 7; 177 BS3CPUVENDOR const enmCpuVendor = Bs3GetCpuVendor(); 178 bool const fSkipStorIdt = Bs3TestQueryCfgBool(VMMDEV_TESTING_CFG_IS_NEM_LINUX); 179 bool const fMayHaveZeroStEnvSels = Bs3TestQueryCfgBool(VMMDEV_TESTING_CFG_IS_NEM_LINUX); 180 bool const fFastFxSaveRestore = RT_BOOL(ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_FFXSR); 181 //bool const fFdpXcptOnly = (ASMCpuIdEx_EBX(7, 0) & X86_CPUID_STEXT_FEATURE_EBX_FDP_EXCPTN_ONLY) 182 // && ASMCpuId_EAX(0) >= 7; 183 RT_NOREF(bMode); 140 184 141 185 if (fSkipStorIdt) … … 143 187 144 188 # undef CHECK_STATE 145 # define CHECK_STATE(a_Instr ) \189 # define CHECK_STATE(a_Instr, a_fIsFnStEnv) \ 146 190 do { \ 147 191 TMPL_NM(bs3FpuState1_Save)(pChecking); \ … … 202 246 for (iLoop = 0; iLoop < _16M; iLoop++) 203 247 { 204 CHECK_STATE(nop );248 CHECK_STATE(nop, false); 205 249 if ( (iLoop & 0xffff) == 0xffff 206 250 && g_cBs3PitTicks - uStartTick >= 20 * 20) /* 20 seconds*/ … … 224 268 /* Macros */ 225 269 # undef CHECK_READBACK_WRITE_RUN 226 # define CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type ) \270 # define CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type, a_fIsFnStEnv) \ 227 271 do { \ 228 272 off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \ … … 234 278 a_Worker((a_Type *)&abCompare[0]); \ 235 279 Bs3MemCpy(abReadback, &MmioReg.pb[off], sizeof(a_Type)); \ 236 if (Bs3MemCmp(abReadback, abCompare, sizeof(a_Type)) != 0) \ 280 if (Bs3MemCmp(abReadback, abCompare, sizeof(a_Type)) == 0) \ 281 { /* likely */ } \ 282 else if ( (a_fIsFnStEnv) \ 283 && fMayHaveZeroStEnvSels \ 284 && TMPL_NM(bs3FpuState1_IsZeroFnStEnvSelectorsProblem)(abReadback, abCompare)) \ 285 cFnStEnvSelectorsZero += 1; \ 286 else \ 237 287 { \ 238 288 Bs3TestFailedF("Read back error for " #a_Instr " in loop #%RU32:\n%.*Rhxs expected:\n%.*Rhxs\n", \ … … 244 294 245 295 # undef CHECK_READBACK_WRITE 246 # define CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type ) \247 CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type ); \248 CHECK_STATE(a_Instr )296 # define CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type, a_fIsFnStEnv) \ 297 CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type, a_fIsFnStEnv); \ 298 CHECK_STATE(a_Instr, a_fIsFnStEnv) 249 299 # undef CHECK_READBACK_WRITE_Z 250 # define CHECK_READBACK_WRITE_Z(a_Instr, a_Worker, a_Type ) \300 # define CHECK_READBACK_WRITE_Z(a_Instr, a_Worker, a_Type, a_fIsFnStEnv) \ 251 301 do { \ 252 302 if (fMmioReadback && (!fReadBackError || iLoop == 0)) \ … … 258 308 Bs3MemZero(&MmioReg.pb[off], sizeof(a_Type)); \ 259 309 } \ 260 CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type ); \310 CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type, a_fIsFnStEnv); \ 261 311 } while (0) 262 312 … … 275 325 Bs3MemSet(&abReadback[0], 0xcc, sizeof(abReadback)); \ 276 326 CHECK_READBACK_READ_RUN(a_Instr, a_Worker, a_Type); \ 277 CHECK_STATE(a_Instr ); \327 CHECK_STATE(a_Instr, false); \ 278 328 if (!fReadError || iLoop == 0) \ 279 329 { \ … … 291 341 /* The tests. */ 292 342 if (!fSkipStorIdt) /* KVM doesn't advance RIP executing a SIDT [MMIO-memory], it seems. (Linux 5.13.1) */ 293 CHECK_READBACK_WRITE_Z(SIDT, ASMGetIDTR, RTIDTR );294 CHECK_READBACK_WRITE_Z(FNSTENV, TMPL_NM(bs3FpuState1_FNStEnv), X86FSTENV32P ); /** @todo x86.h is missing types */295 CHECK_READBACK_WRITE( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Write), X86XMMREG );343 CHECK_READBACK_WRITE_Z(SIDT, ASMGetIDTR, RTIDTR, false); 344 CHECK_READBACK_WRITE_Z(FNSTENV, TMPL_NM(bs3FpuState1_FNStEnv), X86FSTENV32P, true); /** @todo x86.h is missing types */ 345 CHECK_READBACK_WRITE( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Write), X86XMMREG, false); 296 346 CHECK_READBACK_READ( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Read), X86XMMREG); 297 CHECK_READBACK_WRITE( MOVUPS, TMPL_NM(bs3FpuState1_MovUPS_Write), X86XMMREG );347 CHECK_READBACK_WRITE( MOVUPS, TMPL_NM(bs3FpuState1_MovUPS_Write), X86XMMREG, false); 298 348 CHECK_READBACK_READ( MOVUPS, TMPL_NM(bs3FpuState1_MovUPS_Read), X86XMMREG); 299 349 … … 321 371 if (enmCpuVendor == BS3CPUVENDOR_AMD && fFastFxSaveRestore) 322 372 pExpected->FPUDP = 0; // Zen2 (3990x) 323 CHECK_STATE(FMUL );373 CHECK_STATE(FMUL, false); 324 374 325 375 /* check for timeout every now an then. */ … … 330 380 331 381 Bs3PitDisable(); 382 383 /* 384 * Warn if selectors are borked (for real VBox we'll fail and not warn). 385 */ 386 if (cFnStEnvSelectorsZero > 0) 387 Bs3TestPrintf("Warning! NEM borked the FPU selectors %u times.\n", cFnStEnvSelectorsZero); 332 388 return 0; 333 389 }
Note:
See TracChangeset
for help on using the changeset viewer.