VirtualBox

source: vbox/trunk/src/VBox/Devices/VMMDev/VMMDevTesting.cpp@ 90467

Last change on this file since 90467 was 90467, checked in by vboxsync, 3 years ago

VMMDev/Testing: Added VMMDEV_TESTING_LOCKED_BUSY_SUCCESS flag so we can test both regular return-to-ring-3 on contention and must-get-the-lock-no-matter-wath code paths. bugref:6695

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.9 KB
Line 
1/* $Id: VMMDevTesting.cpp 90467 2021-08-02 10:57:30Z vboxsync $ */
2/** @file
3 * VMMDev - Testing Extensions.
4 *
5 * To enable: VBoxManage setextradata vmname VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1
6 */
7
8/*
9 * Copyright (C) 2010-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_VMM
25#include <VBox/VMMDev.h>
26#include <VBox/vmm/vmapi.h>
27#include <VBox/log.h>
28#include <VBox/err.h>
29
30#include <iprt/asm.h>
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include <iprt/time.h>
34#include <iprt/test.h>
35
36#ifdef IN_RING3
37# define USING_VMM_COMMON_DEFS /* HACK ALERT! We ONLY want the EMT thread handles, so the common defs doesn't matter. */
38# include <VBox/vmm/vmcc.h>
39#endif
40
41#include "VMMDevState.h"
42#include "VMMDevTesting.h"
43
44
45#ifndef VBOX_WITHOUT_TESTING_FEATURES
46
47#define VMMDEV_TESTING_OUTPUT(a) \
48 do \
49 { \
50 LogAlways(a);\
51 LogRel(a);\
52 } while (0)
53
54/**
55 * @callback_method_impl{FNIOMMMIONEWWRITE}
56 */
57static DECLCALLBACK(VBOXSTRICTRC) vmmdevTestingMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
58{
59 RT_NOREF_PV(pvUser);
60
61 switch (off)
62 {
63 case VMMDEV_TESTING_MMIO_OFF_NOP_R3:
64#ifndef IN_RING3
65 return VINF_IOM_R3_MMIO_WRITE;
66#endif
67 case VMMDEV_TESTING_MMIO_OFF_NOP:
68 return VINF_SUCCESS;
69
70 default:
71 {
72 /*
73 * Readback register (64 bytes wide).
74 */
75 if ( ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK
76 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK + VMMDEV_TESTING_READBACK_SIZE)
77#ifndef IN_RING3
78 || ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
79 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + VMMDEV_TESTING_READBACK_SIZE)
80#endif
81 )
82 {
83 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
84 off &= VMMDEV_TESTING_READBACK_SIZE - 1;
85 switch (cb)
86 {
87 case 8: *(uint64_t *)&pThis->TestingData.abReadBack[off] = *(uint64_t const *)pv; break;
88 case 4: *(uint32_t *)&pThis->TestingData.abReadBack[off] = *(uint32_t const *)pv; break;
89 case 2: *(uint16_t *)&pThis->TestingData.abReadBack[off] = *(uint16_t const *)pv; break;
90 case 1: *(uint8_t *)&pThis->TestingData.abReadBack[off] = *(uint8_t const *)pv; break;
91 default: memcpy(&pThis->TestingData.abReadBack[off], pv, cb); break;
92 }
93 return VINF_SUCCESS;
94 }
95#ifndef IN_RING3
96 if ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
97 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
98 return VINF_IOM_R3_MMIO_WRITE;
99#endif
100
101 break;
102 }
103
104 /*
105 * Odd NOP accesses.
106 */
107 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 1:
108 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 2:
109 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 3:
110 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 4:
111 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 5:
112 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 6:
113 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 7:
114#ifndef IN_RING3
115 return VINF_IOM_R3_MMIO_WRITE;
116#endif
117 case VMMDEV_TESTING_MMIO_OFF_NOP + 1:
118 case VMMDEV_TESTING_MMIO_OFF_NOP + 2:
119 case VMMDEV_TESTING_MMIO_OFF_NOP + 3:
120 case VMMDEV_TESTING_MMIO_OFF_NOP + 4:
121 case VMMDEV_TESTING_MMIO_OFF_NOP + 5:
122 case VMMDEV_TESTING_MMIO_OFF_NOP + 6:
123 case VMMDEV_TESTING_MMIO_OFF_NOP + 7:
124 return VINF_SUCCESS;
125 }
126 return VINF_SUCCESS;
127}
128
129
130/**
131 * @callback_method_impl{FNIOMMMIONEWREAD}
132 */
133static DECLCALLBACK(VBOXSTRICTRC) vmmdevTestingMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
134{
135 RT_NOREF_PV(pvUser);
136
137 switch (off)
138 {
139 case VMMDEV_TESTING_MMIO_OFF_NOP_R3:
140#ifndef IN_RING3
141 return VINF_IOM_R3_MMIO_READ;
142#endif
143 /* fall thru. */
144 case VMMDEV_TESTING_MMIO_OFF_NOP:
145 switch (cb)
146 {
147 case 8:
148 *(uint64_t *)pv = VMMDEV_TESTING_NOP_RET | ((uint64_t)VMMDEV_TESTING_NOP_RET << 32);
149 break;
150 case 4:
151 *(uint32_t *)pv = VMMDEV_TESTING_NOP_RET;
152 break;
153 case 2:
154 *(uint16_t *)pv = RT_LO_U16(VMMDEV_TESTING_NOP_RET);
155 break;
156 case 1:
157 *(uint8_t *)pv = (uint8_t)(VMMDEV_TESTING_NOP_RET & UINT8_MAX);
158 break;
159 default:
160 AssertFailed();
161 return VERR_INTERNAL_ERROR_5;
162 }
163 return VINF_SUCCESS;
164
165
166 default:
167 {
168 /*
169 * Readback register (64 bytes wide).
170 */
171 if ( ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK
172 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK + 64)
173#ifndef IN_RING3
174 || ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
175 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
176#endif
177 )
178 {
179 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
180 off &= 0x3f;
181 switch (cb)
182 {
183 case 8: *(uint64_t *)pv = *(uint64_t const *)&pThis->TestingData.abReadBack[off]; break;
184 case 4: *(uint32_t *)pv = *(uint32_t const *)&pThis->TestingData.abReadBack[off]; break;
185 case 2: *(uint16_t *)pv = *(uint16_t const *)&pThis->TestingData.abReadBack[off]; break;
186 case 1: *(uint8_t *)pv = *(uint8_t const *)&pThis->TestingData.abReadBack[off]; break;
187 default: memcpy(pv, &pThis->TestingData.abReadBack[off], cb); break;
188 }
189 return VINF_SUCCESS;
190 }
191#ifndef IN_RING3
192 if ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
193 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
194 return VINF_IOM_R3_MMIO_READ;
195#endif
196 break;
197 }
198
199 /*
200 * Odd NOP accesses (for 16-bit code mainly).
201 */
202 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 1:
203 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 2:
204 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 3:
205 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 4:
206 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 5:
207 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 6:
208 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 7:
209#ifndef IN_RING3
210 return VINF_IOM_R3_MMIO_READ;
211#endif
212 case VMMDEV_TESTING_MMIO_OFF_NOP + 1:
213 case VMMDEV_TESTING_MMIO_OFF_NOP + 2:
214 case VMMDEV_TESTING_MMIO_OFF_NOP + 3:
215 case VMMDEV_TESTING_MMIO_OFF_NOP + 4:
216 case VMMDEV_TESTING_MMIO_OFF_NOP + 5:
217 case VMMDEV_TESTING_MMIO_OFF_NOP + 6:
218 case VMMDEV_TESTING_MMIO_OFF_NOP + 7:
219 {
220 static uint8_t const s_abNopValue[8] =
221 {
222 VMMDEV_TESTING_NOP_RET & 0xff,
223 (VMMDEV_TESTING_NOP_RET >> 8) & 0xff,
224 (VMMDEV_TESTING_NOP_RET >> 16) & 0xff,
225 (VMMDEV_TESTING_NOP_RET >> 24) & 0xff,
226 VMMDEV_TESTING_NOP_RET & 0xff,
227 (VMMDEV_TESTING_NOP_RET >> 8) & 0xff,
228 (VMMDEV_TESTING_NOP_RET >> 16) & 0xff,
229 (VMMDEV_TESTING_NOP_RET >> 24) & 0xff,
230 };
231
232 memset(pv, 0xff, cb);
233 memcpy(pv, &s_abNopValue[off & 7], RT_MIN(8 - (off & 7), cb));
234 return VINF_SUCCESS;
235 }
236 }
237
238 return VINF_IOM_MMIO_UNUSED_FF;
239}
240
241#ifdef IN_RING3
242
243/**
244 * Executes the VMMDEV_TESTING_CMD_VALUE_REG command when the data is ready.
245 *
246 * @param pDevIns The PDM device instance.
247 * @param pThis The instance VMMDev data.
248 */
249static void vmmdevTestingCmdExec_ValueReg(PPDMDEVINS pDevIns, PVMMDEV pThis)
250{
251 char *pszRegNm = strchr(pThis->TestingData.String.sz, ':');
252 if (pszRegNm)
253 {
254 *pszRegNm++ = '\0';
255 pszRegNm = RTStrStrip(pszRegNm);
256 }
257 char *pszValueNm = RTStrStrip(pThis->TestingData.String.sz);
258 size_t const cchValueNm = strlen(pszValueNm);
259 if (cchValueNm && pszRegNm && *pszRegNm)
260 {
261 PUVM pUVM = PDMDevHlpGetUVM(pDevIns);
262 PVM pVM = PDMDevHlpGetVM(pDevIns);
263 VMCPUID idCpu = VMMGetCpuId(pVM);
264 uint64_t u64Value;
265 int rc2 = DBGFR3RegNmQueryU64(pUVM, idCpu, pszRegNm, &u64Value);
266 if (RT_SUCCESS(rc2))
267 {
268 const char *pszWarn = rc2 == VINF_DBGF_TRUNCATED_REGISTER ? " truncated" : "";
269#if 1 /*!RTTestValue format*/
270 char szFormat[128], szValue[128];
271 RTStrPrintf(szFormat, sizeof(szFormat), "%%VR{%s}", pszRegNm);
272 rc2 = DBGFR3RegPrintf(pUVM, idCpu, szValue, sizeof(szValue), szFormat);
273 if (RT_SUCCESS(rc2))
274 VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %16s {reg=%s}%s\n",
275 pszValueNm,
276 (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
277 szValue, pszRegNm, pszWarn));
278 else
279#endif
280 VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [0] {reg=%s}%s\n",
281 pszValueNm,
282 (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
283 u64Value, u64Value, pszRegNm, pszWarn));
284 }
285 else
286 VMMDEV_TESTING_OUTPUT(("testing: error querying register '%s' for value '%s': %Rrc\n",
287 pszRegNm, pszValueNm, rc2));
288 }
289 else
290 VMMDEV_TESTING_OUTPUT(("testing: malformed register value '%s'/'%s'\n", pszValueNm, pszRegNm));
291}
292
293#endif /* IN_RING3 */
294
295/**
296 * @callback_method_impl{FNIOMIOPORTNEWOUT}
297 */
298static DECLCALLBACK(VBOXSTRICTRC)
299vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
300{
301 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
302#ifdef IN_RING3
303 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
304#endif
305 RT_NOREF_PV(pvUser);
306
307 switch (offPort)
308 {
309 /*
310 * The NOP I/O ports are used for performance measurements.
311 */
312 case VMMDEV_TESTING_IOPORT_NOP - VMMDEV_TESTING_IOPORT_BASE:
313 switch (cb)
314 {
315 case 4:
316 case 2:
317 case 1:
318 break;
319 default:
320 AssertFailed();
321 return VERR_INTERNAL_ERROR_2;
322 }
323 return VINF_SUCCESS;
324
325 case VMMDEV_TESTING_IOPORT_NOP_R3 - VMMDEV_TESTING_IOPORT_BASE:
326 switch (cb)
327 {
328 case 4:
329 case 2:
330 case 1:
331#ifndef IN_RING3
332 return VINF_IOM_R3_IOPORT_WRITE;
333#else
334 return VINF_SUCCESS;
335#endif
336 default:
337 AssertFailed();
338 return VERR_INTERNAL_ERROR_2;
339 }
340
341 /* The timestamp I/O ports are read-only. */
342 case VMMDEV_TESTING_IOPORT_TS_LOW - VMMDEV_TESTING_IOPORT_BASE:
343 case VMMDEV_TESTING_IOPORT_TS_HIGH - VMMDEV_TESTING_IOPORT_BASE:
344 break;
345
346 /*
347 * The command port (DWORD and WORD write only).
348 * (We have to allow WORD writes for 286, 186 and 8086 execution modes.)
349 */
350 case VMMDEV_TESTING_IOPORT_CMD - VMMDEV_TESTING_IOPORT_BASE:
351 if (cb == 2)
352 {
353 u32 |= VMMDEV_TESTING_CMD_MAGIC_HI_WORD;
354 cb = 4;
355 }
356 if (cb == 4)
357 {
358 pThis->u32TestingCmd = u32;
359 pThis->offTestingData = 0;
360 RT_ZERO(pThis->TestingData);
361 return VINF_SUCCESS;
362 }
363 break;
364
365 /*
366 * The data port. Used of providing data for a command.
367 */
368 case VMMDEV_TESTING_IOPORT_DATA - VMMDEV_TESTING_IOPORT_BASE:
369 {
370 uint32_t uCmd = pThis->u32TestingCmd;
371 uint32_t off = pThis->offTestingData;
372 switch (uCmd)
373 {
374 case VMMDEV_TESTING_CMD_INIT:
375 case VMMDEV_TESTING_CMD_SUB_NEW:
376 case VMMDEV_TESTING_CMD_FAILED:
377 case VMMDEV_TESTING_CMD_SKIPPED:
378 case VMMDEV_TESTING_CMD_PRINT:
379 if ( off < sizeof(pThis->TestingData.String.sz) - 1
380 && cb == 1)
381 {
382 if (u32)
383 {
384 pThis->TestingData.String.sz[off] = u32;
385 pThis->offTestingData = off + 1;
386 }
387 else
388 {
389#ifdef IN_RING3
390 pThis->TestingData.String.sz[off] = '\0';
391 switch (uCmd)
392 {
393 case VMMDEV_TESTING_CMD_INIT:
394 VMMDEV_TESTING_OUTPUT(("testing: INIT '%s'\n", pThis->TestingData.String.sz));
395 if (pThisCC->hTestingTest != NIL_RTTEST)
396 {
397 RTTestChangeName(pThisCC->hTestingTest, pThis->TestingData.String.sz);
398 RTTestBanner(pThisCC->hTestingTest);
399 }
400 break;
401 case VMMDEV_TESTING_CMD_SUB_NEW:
402 VMMDEV_TESTING_OUTPUT(("testing: SUB_NEW '%s'\n", pThis->TestingData.String.sz));
403 if (pThisCC->hTestingTest != NIL_RTTEST)
404 RTTestSub(pThisCC->hTestingTest, pThis->TestingData.String.sz);
405 break;
406 case VMMDEV_TESTING_CMD_FAILED:
407 if (pThisCC->hTestingTest != NIL_RTTEST)
408 RTTestFailed(pThisCC->hTestingTest, "%s", pThis->TestingData.String.sz);
409 VMMDEV_TESTING_OUTPUT(("testing: FAILED '%s'\n", pThis->TestingData.String.sz));
410 break;
411 case VMMDEV_TESTING_CMD_SKIPPED:
412 if (pThisCC->hTestingTest != NIL_RTTEST)
413 {
414 if (off)
415 RTTestSkipped(pThisCC->hTestingTest, "%s", pThis->TestingData.String.sz);
416 else
417 RTTestSkipped(pThisCC->hTestingTest, NULL);
418 }
419 VMMDEV_TESTING_OUTPUT(("testing: SKIPPED '%s'\n", pThis->TestingData.String.sz));
420 break;
421 case VMMDEV_TESTING_CMD_PRINT:
422 if (pThisCC->hTestingTest != NIL_RTTEST && off)
423 RTTestPrintf(pThisCC->hTestingTest, RTTESTLVL_ALWAYS, "%s", pThis->TestingData.String.sz);
424 VMMDEV_TESTING_OUTPUT(("testing: '%s'\n", pThis->TestingData.String.sz));
425 break;
426 }
427#else
428 return VINF_IOM_R3_IOPORT_WRITE;
429#endif
430 }
431 return VINF_SUCCESS;
432 }
433 break;
434
435 case VMMDEV_TESTING_CMD_TERM:
436 case VMMDEV_TESTING_CMD_SUB_DONE:
437 if (cb == 2)
438 {
439 if (off == 0)
440 {
441 pThis->TestingData.Error.c = u32;
442 pThis->offTestingData = 2;
443 break;
444 }
445 if (off == 2)
446 {
447 u32 <<= 16;
448 u32 |= pThis->TestingData.Error.c & UINT16_MAX;
449 cb = 4;
450 off = 0;
451 }
452 else
453 break;
454 }
455
456 if ( off == 0
457 && cb == 4)
458 {
459#ifdef IN_RING3
460 pThis->TestingData.Error.c = u32;
461 if (uCmd == VMMDEV_TESTING_CMD_TERM)
462 {
463 if (pThisCC->hTestingTest != NIL_RTTEST)
464 {
465 while (RTTestErrorCount(pThisCC->hTestingTest) < u32)
466 RTTestErrorInc(pThisCC->hTestingTest); /* A bit stupid, but does the trick. */
467 RTTestSubDone(pThisCC->hTestingTest);
468 RTTestSummaryAndDestroy(pThisCC->hTestingTest);
469 pThisCC->hTestingTest = NIL_RTTEST;
470 }
471 VMMDEV_TESTING_OUTPUT(("testing: TERM - %u errors\n", u32));
472 }
473 else
474 {
475 if (pThisCC->hTestingTest != NIL_RTTEST)
476 {
477 while (RTTestSubErrorCount(pThisCC->hTestingTest) < u32)
478 RTTestErrorInc(pThisCC->hTestingTest); /* A bit stupid, but does the trick. */
479 RTTestSubDone(pThisCC->hTestingTest);
480 }
481 VMMDEV_TESTING_OUTPUT(("testing: SUB_DONE - %u errors\n", u32));
482 }
483 return VINF_SUCCESS;
484#else
485 return VINF_IOM_R3_IOPORT_WRITE;
486#endif
487 }
488 break;
489
490 case VMMDEV_TESTING_CMD_VALUE:
491 if (cb == 4)
492 {
493 if (off == 0)
494 pThis->TestingData.Value.u64Value.s.Lo = u32;
495 else if (off == 4)
496 pThis->TestingData.Value.u64Value.s.Hi = u32;
497 else if (off == 8)
498 pThis->TestingData.Value.u32Unit = u32;
499 else
500 break;
501 pThis->offTestingData = off + 4;
502 return VINF_SUCCESS;
503 }
504 if (cb == 2)
505 {
506 if (off == 0)
507 pThis->TestingData.Value.u64Value.Words.w0 = (uint16_t)u32;
508 else if (off == 2)
509 pThis->TestingData.Value.u64Value.Words.w1 = (uint16_t)u32;
510 else if (off == 4)
511 pThis->TestingData.Value.u64Value.Words.w2 = (uint16_t)u32;
512 else if (off == 6)
513 pThis->TestingData.Value.u64Value.Words.w3 = (uint16_t)u32;
514 else if (off == 8)
515 pThis->TestingData.Value.u32Unit = (uint16_t)u32;
516 else if (off == 10)
517 pThis->TestingData.Value.u32Unit = u32 << 16;
518 else
519 break;
520 pThis->offTestingData = off + 2;
521 return VINF_SUCCESS;
522 }
523
524 if ( off >= 12
525 && cb == 1
526 && off - 12 < sizeof(pThis->TestingData.Value.szName) - 1)
527 {
528 if (u32)
529 {
530 pThis->TestingData.Value.szName[off - 12] = u32;
531 pThis->offTestingData = off + 1;
532 }
533 else
534 {
535#ifdef IN_RING3
536 pThis->TestingData.Value.szName[off - 12] = '\0';
537
538 RTTESTUNIT enmUnit = (RTTESTUNIT)pThis->TestingData.Value.u32Unit;
539 if (enmUnit <= RTTESTUNIT_INVALID || enmUnit >= RTTESTUNIT_END)
540 {
541 VMMDEV_TESTING_OUTPUT(("Invalid log value unit %#x\n", pThis->TestingData.Value.u32Unit));
542 enmUnit = RTTESTUNIT_NONE;
543 }
544 if (pThisCC->hTestingTest != NIL_RTTEST)
545 RTTestValue(pThisCC->hTestingTest, pThis->TestingData.Value.szName,
546 pThis->TestingData.Value.u64Value.u, enmUnit);
547
548 VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [%u]\n",
549 pThis->TestingData.Value.szName,
550 off - 12 > 48 ? 0 : 48 - (off - 12), "",
551 pThis->TestingData.Value.u64Value.u, pThis->TestingData.Value.u64Value.u,
552 pThis->TestingData.Value.u32Unit));
553#else
554 return VINF_IOM_R3_IOPORT_WRITE;
555#endif
556 }
557 return VINF_SUCCESS;
558 }
559 break;
560
561
562 /*
563 * RTTestValue with the output from DBGFR3RegNmQuery.
564 */
565 case VMMDEV_TESTING_CMD_VALUE_REG:
566 {
567 if ( off < sizeof(pThis->TestingData.String.sz) - 1
568 && cb == 1)
569 {
570 pThis->TestingData.String.sz[off] = u32;
571 if (u32)
572 pThis->offTestingData = off + 1;
573 else
574#ifdef IN_RING3
575 vmmdevTestingCmdExec_ValueReg(pDevIns, pThis);
576#else
577 return VINF_IOM_R3_IOPORT_WRITE;
578#endif
579 return VINF_SUCCESS;
580 }
581 break;
582 }
583
584 default:
585 break;
586 }
587 Log(("VMMDEV_TESTING_IOPORT_CMD: bad access; cmd=%#x off=%#x cb=%#x u32=%#x\n", uCmd, off, cb, u32));
588 return VINF_SUCCESS;
589 }
590
591 /*
592 * Configure the locking contention test.
593 */
594 case VMMDEV_TESTING_IOPORT_LOCKED - VMMDEV_TESTING_IOPORT_BASE:
595 switch (cb)
596 {
597 case 4:
598 case 2:
599 case 1:
600 {
601#ifndef IN_RING3
602 if (!pThis->TestingLockControl.s.fMustSucceed)
603 {
604 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
605 if (rc != VINF_SUCCESS)
606 return rc;
607 }
608 else
609#endif
610 {
611 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_SUCCESS);
612 AssertRCReturn(rc, rc);
613 }
614
615 u32 &= ~VMMDEV_TESTING_LOCKED_MBZ_MASK;
616 if (pThis->TestingLockControl.u32 != u32)
617 {
618 pThis->TestingLockControl.u32 = u32;
619 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTestingLockEvt);
620 }
621
622 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
623 return VINF_SUCCESS;
624 }
625
626 default:
627 AssertFailed();
628 return VERR_INTERNAL_ERROR_2;
629 }
630
631 default:
632 break;
633 }
634
635 return VERR_IOM_IOPORT_UNUSED;
636}
637
638
639/**
640 * @callback_method_impl{FNIOMIOPORTNEWIN}
641 */
642static DECLCALLBACK(VBOXSTRICTRC)
643vmmdevTestingIoRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
644{
645 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
646 RT_NOREF_PV(pvUser);
647
648 switch (offPort)
649 {
650 /*
651 * The NOP I/O ports are used for performance measurements.
652 */
653 case VMMDEV_TESTING_IOPORT_NOP - VMMDEV_TESTING_IOPORT_BASE:
654 switch (cb)
655 {
656 case 4:
657 case 2:
658 case 1:
659 break;
660 default:
661 AssertFailed();
662 return VERR_INTERNAL_ERROR_2;
663 }
664 *pu32 = VMMDEV_TESTING_NOP_RET;
665 return VINF_SUCCESS;
666
667 case VMMDEV_TESTING_IOPORT_NOP_R3 - VMMDEV_TESTING_IOPORT_BASE:
668 switch (cb)
669 {
670 case 4:
671 case 2:
672 case 1:
673#ifndef IN_RING3
674 return VINF_IOM_R3_IOPORT_READ;
675#else
676 *pu32 = VMMDEV_TESTING_NOP_RET;
677 return VINF_SUCCESS;
678#endif
679 default:
680 AssertFailed();
681 return VERR_INTERNAL_ERROR_2;
682 }
683
684 /*
685 * The timestamp I/O ports are obviously used for getting a good fix
686 * on the current time (as seen by the host?).
687 *
688 * The high word is latched when reading the low, so reading low + high
689 * gives you a 64-bit timestamp value.
690 */
691 case VMMDEV_TESTING_IOPORT_TS_LOW - VMMDEV_TESTING_IOPORT_BASE:
692 if (cb == 4)
693 {
694 uint64_t NowTS = RTTimeNanoTS();
695 *pu32 = (uint32_t)NowTS;
696 pThis->u32TestingHighTimestamp = (uint32_t)(NowTS >> 32);
697 return VINF_SUCCESS;
698 }
699 break;
700
701 case VMMDEV_TESTING_IOPORT_TS_HIGH - VMMDEV_TESTING_IOPORT_BASE:
702 if (cb == 4)
703 {
704 *pu32 = pThis->u32TestingHighTimestamp;
705 return VINF_SUCCESS;
706 }
707 break;
708
709 /*
710 * Just return the current locking configuration value after first
711 * acquiring the lock of course.
712 */
713 case VMMDEV_TESTING_IOPORT_LOCKED - VMMDEV_TESTING_IOPORT_BASE:
714 switch (cb)
715 {
716 case 4:
717 case 2:
718 case 1:
719 {
720#ifndef IN_RING3
721 if (!pThis->TestingLockControl.s.fMustSucceed)
722 {
723 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
724 if (rc != VINF_SUCCESS)
725 return rc;
726 }
727 else
728#endif
729 {
730 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_SUCCESS);
731 AssertRCReturn(rc, rc);
732 }
733
734 *pu32 = pThis->TestingLockControl.u32;
735
736 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
737 return VINF_SUCCESS;
738 }
739
740 default:
741 AssertFailed();
742 return VERR_INTERNAL_ERROR_2;
743 }
744
745 /*
746 * The command and data registers are write-only.
747 */
748 case VMMDEV_TESTING_IOPORT_CMD - VMMDEV_TESTING_IOPORT_BASE:
749 case VMMDEV_TESTING_IOPORT_DATA - VMMDEV_TESTING_IOPORT_BASE:
750 break;
751
752 default:
753 break;
754 }
755
756 return VERR_IOM_IOPORT_UNUSED;
757}
758
759#ifdef IN_RING3
760
761/**
762 * @callback_method_impl{FNPDMTHREADDEV}
763 */
764static DECLCALLBACK(int) vmmdevR3TestingLockingThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
765{
766 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
767 PVM pVM = PDMDevHlpGetVM(pDevIns);
768 AssertPtr(pVM);
769
770 while (RT_LIKELY(pThread->enmState == PDMTHREADSTATE_RUNNING))
771 {
772 /*
773 * Enter the critical section and
774 */
775 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_SUCCESS);
776 AssertLogRelRCReturn(rc, rc);
777
778 uint32_t cNsNextWait;
779 if (pThis->TestingLockControl.s.cUsHold)
780 {
781 PDMDevHlpSUPSemEventWaitNsRelIntr(pDevIns, pThis->hTestingLockEvt, pThis->TestingLockControl.s.cUsHold);
782 if (pThis->TestingLockControl.s.fPokeBeforeRelease)
783 VMCC_FOR_EACH_VMCPU_STMT(pVM, RTThreadPoke(pVCpu->hThread));
784 cNsNextWait = pThis->TestingLockControl.s.cUsBetween * RT_NS_1US;
785 }
786 else
787 cNsNextWait = 0;
788
789 rc = PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
790 AssertLogRelRCReturn(rc, rc);
791
792 /*
793 * Wait for the next iteration.
794 */
795 if (RT_LIKELY(pThread->enmState == PDMTHREADSTATE_RUNNING))
796 { /* likely */ }
797 else
798 break;
799 if (cNsNextWait > 0)
800 PDMDevHlpSUPSemEventWaitNsRelIntr(pDevIns, pThis->hTestingLockEvt, cNsNextWait);
801 else
802 PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hTestingLockEvt, RT_INDEFINITE_WAIT);
803 }
804
805 return VINF_SUCCESS;
806}
807
808
809/**
810 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
811 */
812static DECLCALLBACK(int) vmmdevR3TestingLockingThreadWakeup(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
813{
814 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
815 RT_NOREF(pThread);
816 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTestingLockEvt);
817}
818
819
820/**
821 * Initializes the testing part of the VMMDev if enabled.
822 *
823 * @returns VBox status code.
824 * @param pDevIns The VMMDev device instance.
825 */
826void vmmdevR3TestingTerminate(PPDMDEVINS pDevIns)
827{
828 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
829 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
830 if (!pThis->fTestingEnabled)
831 return;
832
833 if (pThisCC->hTestingTest != NIL_RTTEST)
834 {
835 RTTestFailed(pThisCC->hTestingTest, "Still open at vmmdev destruction.");
836 RTTestSummaryAndDestroy(pThisCC->hTestingTest);
837 pThisCC->hTestingTest = NIL_RTTEST;
838 }
839}
840
841
842/**
843 * Initializes the testing part of the VMMDev if enabled.
844 *
845 * @returns VBox status code.
846 * @param pDevIns The VMMDev device instance.
847 */
848int vmmdevR3TestingInitialize(PPDMDEVINS pDevIns)
849{
850 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
851 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
852 int rc;
853
854 if (!pThis->fTestingEnabled)
855 return VINF_SUCCESS;
856
857 if (pThis->fTestingMMIO)
858 {
859 /*
860 * Register a chunk of MMIO memory that we'll use for various
861 * tests interfaces. Optional, needs to be explicitly enabled.
862 */
863 rc = PDMDevHlpMmioCreateAndMap(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE,
864 vmmdevTestingMmioWrite, vmmdevTestingMmioRead,
865 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
866 "VMMDev Testing", &pThis->hMmioTesting);
867 AssertRCReturn(rc, rc);
868 }
869
870
871 /*
872 * Register the I/O ports used for testing.
873 */
874 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, VMMDEV_TESTING_IOPORT_BASE, VMMDEV_TESTING_IOPORT_COUNT,
875 vmmdevTestingIoWrite, vmmdevTestingIoRead, "VMMDev Testing", NULL /*paExtDescs*/,
876 &pThis->hIoPortTesting);
877 AssertRCReturn(rc, rc);
878
879 /*
880 * Create the locking thread.
881 */
882 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hTestingLockEvt);
883 AssertRCReturn(rc, rc);
884 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pTestingLockThread, NULL /*pvUser*/, vmmdevR3TestingLockingThread,
885 vmmdevR3TestingLockingThreadWakeup, 0 /*cbStack*/, RTTHREADTYPE_IO, "VMMLockT");
886 AssertRCReturn(rc, rc);
887
888 /*
889 * Open the XML output file(/pipe/whatever) if specfied.
890 */
891 rc = RTTestCreateEx("VMMDevTesting", RTTEST_C_USE_ENV | RTTEST_C_NO_TLS | RTTEST_C_XML_DELAY_TOP_TEST,
892 RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, pThisCC->pszTestingXmlOutput, &pThisCC->hTestingTest);
893 if (RT_FAILURE(rc))
894 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, "Error creating testing instance");
895
896 return VINF_SUCCESS;
897}
898
899#else /* !IN_RING3 */
900
901/**
902 * Does the ring-0/raw-mode initialization of the testing part if enabled.
903 *
904 * @returns VBox status code.
905 * @param pDevIns The VMMDev device instance.
906 */
907int vmmdevRZTestingInitialize(PPDMDEVINS pDevIns)
908{
909 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
910 int rc;
911
912 if (!pThis->fTestingEnabled)
913 return VINF_SUCCESS;
914
915 if (pThis->fTestingMMIO)
916 {
917 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioTesting, vmmdevTestingMmioWrite, vmmdevTestingMmioRead, NULL);
918 AssertRCReturn(rc, rc);
919 }
920
921 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortTesting, vmmdevTestingIoWrite, vmmdevTestingIoRead, NULL);
922 AssertRCReturn(rc, rc);
923
924 return VINF_SUCCESS;
925}
926
927#endif /* !IN_RING3 */
928#endif /* !VBOX_WITHOUT_TESTING_FEATURES */
929
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