VirtualBox

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

Last change on this file since 82781 was 81627, checked in by vboxsync, 5 years ago

VMMDev: Converted to the new PDM device style. [fixes] bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
Line 
1/* $Id: VMMDevTesting.cpp 81627 2019-11-01 21:07:06Z 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-2019 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#include "VMMDevState.h"
37#include "VMMDevTesting.h"
38
39
40#ifndef VBOX_WITHOUT_TESTING_FEATURES
41
42#define VMMDEV_TESTING_OUTPUT(a) \
43 do \
44 { \
45 LogAlways(a);\
46 LogRel(a);\
47 } while (0)
48
49/**
50 * @callback_method_impl{FNIOMMMIONEWWRITE}
51 */
52static DECLCALLBACK(VBOXSTRICTRC) vmmdevTestingMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
53{
54 RT_NOREF_PV(pvUser);
55
56 switch (off)
57 {
58 case VMMDEV_TESTING_MMIO_OFF_NOP_R3:
59#ifndef IN_RING3
60 return VINF_IOM_R3_MMIO_WRITE;
61#endif
62 case VMMDEV_TESTING_MMIO_OFF_NOP:
63 return VINF_SUCCESS;
64
65 default:
66 {
67 /*
68 * Readback register (64 bytes wide).
69 */
70 if ( ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK
71 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK + VMMDEV_TESTING_READBACK_SIZE)
72#ifndef IN_RING3
73 || ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
74 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + VMMDEV_TESTING_READBACK_SIZE)
75#endif
76 )
77 {
78 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
79 off &= VMMDEV_TESTING_READBACK_SIZE - 1;
80 switch (cb)
81 {
82 case 8: *(uint64_t *)&pThis->TestingData.abReadBack[off] = *(uint64_t const *)pv; break;
83 case 4: *(uint32_t *)&pThis->TestingData.abReadBack[off] = *(uint32_t const *)pv; break;
84 case 2: *(uint16_t *)&pThis->TestingData.abReadBack[off] = *(uint16_t const *)pv; break;
85 case 1: *(uint8_t *)&pThis->TestingData.abReadBack[off] = *(uint8_t const *)pv; break;
86 default: memcpy(&pThis->TestingData.abReadBack[off], pv, cb); break;
87 }
88 return VINF_SUCCESS;
89 }
90#ifndef IN_RING3
91 if ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
92 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
93 return VINF_IOM_R3_MMIO_WRITE;
94#endif
95
96 break;
97 }
98
99 /*
100 * Odd NOP accesses.
101 */
102 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 1:
103 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 2:
104 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 3:
105 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 4:
106 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 5:
107 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 6:
108 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 7:
109#ifndef IN_RING3
110 return VINF_IOM_R3_MMIO_WRITE;
111#endif
112 case VMMDEV_TESTING_MMIO_OFF_NOP + 1:
113 case VMMDEV_TESTING_MMIO_OFF_NOP + 2:
114 case VMMDEV_TESTING_MMIO_OFF_NOP + 3:
115 case VMMDEV_TESTING_MMIO_OFF_NOP + 4:
116 case VMMDEV_TESTING_MMIO_OFF_NOP + 5:
117 case VMMDEV_TESTING_MMIO_OFF_NOP + 6:
118 case VMMDEV_TESTING_MMIO_OFF_NOP + 7:
119 return VINF_SUCCESS;
120 }
121 return VINF_SUCCESS;
122}
123
124
125/**
126 * @callback_method_impl{FNIOMMMIONEWREAD}
127 */
128static DECLCALLBACK(VBOXSTRICTRC) vmmdevTestingMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
129{
130 RT_NOREF_PV(pvUser);
131
132 switch (off)
133 {
134 case VMMDEV_TESTING_MMIO_OFF_NOP_R3:
135#ifndef IN_RING3
136 return VINF_IOM_R3_MMIO_READ;
137#endif
138 /* fall thru. */
139 case VMMDEV_TESTING_MMIO_OFF_NOP:
140 switch (cb)
141 {
142 case 8:
143 *(uint64_t *)pv = VMMDEV_TESTING_NOP_RET | ((uint64_t)VMMDEV_TESTING_NOP_RET << 32);
144 break;
145 case 4:
146 *(uint32_t *)pv = VMMDEV_TESTING_NOP_RET;
147 break;
148 case 2:
149 *(uint16_t *)pv = RT_LO_U16(VMMDEV_TESTING_NOP_RET);
150 break;
151 case 1:
152 *(uint8_t *)pv = (uint8_t)(VMMDEV_TESTING_NOP_RET & UINT8_MAX);
153 break;
154 default:
155 AssertFailed();
156 return VERR_INTERNAL_ERROR_5;
157 }
158 return VINF_SUCCESS;
159
160
161 default:
162 {
163 /*
164 * Readback register (64 bytes wide).
165 */
166 if ( ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK
167 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK + 64)
168#ifndef IN_RING3
169 || ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
170 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
171#endif
172 )
173 {
174 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
175 off &= 0x3f;
176 switch (cb)
177 {
178 case 8: *(uint64_t *)pv = *(uint64_t const *)&pThis->TestingData.abReadBack[off]; break;
179 case 4: *(uint32_t *)pv = *(uint32_t const *)&pThis->TestingData.abReadBack[off]; break;
180 case 2: *(uint16_t *)pv = *(uint16_t const *)&pThis->TestingData.abReadBack[off]; break;
181 case 1: *(uint8_t *)pv = *(uint8_t const *)&pThis->TestingData.abReadBack[off]; break;
182 default: memcpy(pv, &pThis->TestingData.abReadBack[off], cb); break;
183 }
184 return VINF_SUCCESS;
185 }
186#ifndef IN_RING3
187 if ( off >= VMMDEV_TESTING_MMIO_OFF_READBACK_R3
188 && off + cb <= VMMDEV_TESTING_MMIO_OFF_READBACK_R3 + 64)
189 return VINF_IOM_R3_MMIO_READ;
190#endif
191 break;
192 }
193
194 /*
195 * Odd NOP accesses (for 16-bit code mainly).
196 */
197 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 1:
198 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 2:
199 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 3:
200 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 4:
201 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 5:
202 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 6:
203 case VMMDEV_TESTING_MMIO_OFF_NOP_R3 + 7:
204#ifndef IN_RING3
205 return VINF_IOM_R3_MMIO_READ;
206#endif
207 case VMMDEV_TESTING_MMIO_OFF_NOP + 1:
208 case VMMDEV_TESTING_MMIO_OFF_NOP + 2:
209 case VMMDEV_TESTING_MMIO_OFF_NOP + 3:
210 case VMMDEV_TESTING_MMIO_OFF_NOP + 4:
211 case VMMDEV_TESTING_MMIO_OFF_NOP + 5:
212 case VMMDEV_TESTING_MMIO_OFF_NOP + 6:
213 case VMMDEV_TESTING_MMIO_OFF_NOP + 7:
214 {
215 static uint8_t const s_abNopValue[8] =
216 {
217 VMMDEV_TESTING_NOP_RET & 0xff,
218 (VMMDEV_TESTING_NOP_RET >> 8) & 0xff,
219 (VMMDEV_TESTING_NOP_RET >> 16) & 0xff,
220 (VMMDEV_TESTING_NOP_RET >> 24) & 0xff,
221 VMMDEV_TESTING_NOP_RET & 0xff,
222 (VMMDEV_TESTING_NOP_RET >> 8) & 0xff,
223 (VMMDEV_TESTING_NOP_RET >> 16) & 0xff,
224 (VMMDEV_TESTING_NOP_RET >> 24) & 0xff,
225 };
226
227 memset(pv, 0xff, cb);
228 memcpy(pv, &s_abNopValue[off & 7], RT_MIN(8 - (off & 7), cb));
229 return VINF_SUCCESS;
230 }
231 }
232
233 return VINF_IOM_MMIO_UNUSED_FF;
234}
235
236#ifdef IN_RING3
237
238/**
239 * Executes the VMMDEV_TESTING_CMD_VALUE_REG command when the data is ready.
240 *
241 * @param pDevIns The PDM device instance.
242 * @param pThis The instance VMMDev data.
243 */
244static void vmmdevTestingCmdExec_ValueReg(PPDMDEVINS pDevIns, PVMMDEV pThis)
245{
246 char *pszRegNm = strchr(pThis->TestingData.String.sz, ':');
247 if (pszRegNm)
248 {
249 *pszRegNm++ = '\0';
250 pszRegNm = RTStrStrip(pszRegNm);
251 }
252 char *pszValueNm = RTStrStrip(pThis->TestingData.String.sz);
253 size_t const cchValueNm = strlen(pszValueNm);
254 if (cchValueNm && pszRegNm && *pszRegNm)
255 {
256 PUVM pUVM = PDMDevHlpGetUVM(pDevIns);
257 PVM pVM = PDMDevHlpGetVM(pDevIns);
258 VMCPUID idCpu = VMMGetCpuId(pVM);
259 uint64_t u64Value;
260 int rc2 = DBGFR3RegNmQueryU64(pUVM, idCpu, pszRegNm, &u64Value);
261 if (RT_SUCCESS(rc2))
262 {
263 const char *pszWarn = rc2 == VINF_DBGF_TRUNCATED_REGISTER ? " truncated" : "";
264#if 1 /*!RTTestValue format*/
265 char szFormat[128], szValue[128];
266 RTStrPrintf(szFormat, sizeof(szFormat), "%%VR{%s}", pszRegNm);
267 rc2 = DBGFR3RegPrintf(pUVM, idCpu, szValue, sizeof(szValue), szFormat);
268 if (RT_SUCCESS(rc2))
269 VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %16s {reg=%s}%s\n",
270 pszValueNm,
271 (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
272 szValue, pszRegNm, pszWarn));
273 else
274#endif
275 VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [0] {reg=%s}%s\n",
276 pszValueNm,
277 (ssize_t)cchValueNm - 12 > 48 ? 0 : 48 - ((ssize_t)cchValueNm - 12), "",
278 u64Value, u64Value, pszRegNm, pszWarn));
279 }
280 else
281 VMMDEV_TESTING_OUTPUT(("testing: error querying register '%s' for value '%s': %Rrc\n",
282 pszRegNm, pszValueNm, rc2));
283 }
284 else
285 VMMDEV_TESTING_OUTPUT(("testing: malformed register value '%s'/'%s'\n", pszValueNm, pszRegNm));
286}
287
288#endif /* IN_RING3 */
289
290/**
291 * @callback_method_impl{FNIOMIOPORTNEWOUT}
292 */
293static DECLCALLBACK(VBOXSTRICTRC)
294vmmdevTestingIoWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
295{
296 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
297#ifdef IN_RING3
298 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
299#endif
300 RT_NOREF_PV(pvUser);
301
302 switch (offPort)
303 {
304 /*
305 * The NOP I/O ports are used for performance measurements.
306 */
307 case VMMDEV_TESTING_IOPORT_NOP - VMMDEV_TESTING_IOPORT_BASE:
308 switch (cb)
309 {
310 case 4:
311 case 2:
312 case 1:
313 break;
314 default:
315 AssertFailed();
316 return VERR_INTERNAL_ERROR_2;
317 }
318 return VINF_SUCCESS;
319
320 case VMMDEV_TESTING_IOPORT_NOP_R3 - VMMDEV_TESTING_IOPORT_BASE:
321 switch (cb)
322 {
323 case 4:
324 case 2:
325 case 1:
326#ifndef IN_RING3
327 return VINF_IOM_R3_IOPORT_WRITE;
328#else
329 return VINF_SUCCESS;
330#endif
331 default:
332 AssertFailed();
333 return VERR_INTERNAL_ERROR_2;
334 }
335
336 /* The timestamp I/O ports are read-only. */
337 case VMMDEV_TESTING_IOPORT_TS_LOW - VMMDEV_TESTING_IOPORT_BASE:
338 case VMMDEV_TESTING_IOPORT_TS_HIGH - VMMDEV_TESTING_IOPORT_BASE:
339 break;
340
341 /*
342 * The command port (DWORD and WORD write only).
343 * (We have to allow WORD writes for 286, 186 and 8086 execution modes.)
344 */
345 case VMMDEV_TESTING_IOPORT_CMD - VMMDEV_TESTING_IOPORT_BASE:
346 if (cb == 2)
347 {
348 u32 |= VMMDEV_TESTING_CMD_MAGIC_HI_WORD;
349 cb = 4;
350 }
351 if (cb == 4)
352 {
353 pThis->u32TestingCmd = u32;
354 pThis->offTestingData = 0;
355 RT_ZERO(pThis->TestingData);
356 return VINF_SUCCESS;
357 }
358 break;
359
360 /*
361 * The data port. Used of providing data for a command.
362 */
363 case VMMDEV_TESTING_IOPORT_DATA - VMMDEV_TESTING_IOPORT_BASE:
364 {
365 uint32_t uCmd = pThis->u32TestingCmd;
366 uint32_t off = pThis->offTestingData;
367 switch (uCmd)
368 {
369 case VMMDEV_TESTING_CMD_INIT:
370 case VMMDEV_TESTING_CMD_SUB_NEW:
371 case VMMDEV_TESTING_CMD_FAILED:
372 case VMMDEV_TESTING_CMD_SKIPPED:
373 case VMMDEV_TESTING_CMD_PRINT:
374 if ( off < sizeof(pThis->TestingData.String.sz) - 1
375 && cb == 1)
376 {
377 if (u32)
378 {
379 pThis->TestingData.String.sz[off] = u32;
380 pThis->offTestingData = off + 1;
381 }
382 else
383 {
384#ifdef IN_RING3
385 pThis->TestingData.String.sz[off] = '\0';
386 switch (uCmd)
387 {
388 case VMMDEV_TESTING_CMD_INIT:
389 VMMDEV_TESTING_OUTPUT(("testing: INIT '%s'\n", pThis->TestingData.String.sz));
390 if (pThisCC->hTestingTest != NIL_RTTEST)
391 {
392 RTTestChangeName(pThisCC->hTestingTest, pThis->TestingData.String.sz);
393 RTTestBanner(pThisCC->hTestingTest);
394 }
395 break;
396 case VMMDEV_TESTING_CMD_SUB_NEW:
397 VMMDEV_TESTING_OUTPUT(("testing: SUB_NEW '%s'\n", pThis->TestingData.String.sz));
398 if (pThisCC->hTestingTest != NIL_RTTEST)
399 RTTestSub(pThisCC->hTestingTest, pThis->TestingData.String.sz);
400 break;
401 case VMMDEV_TESTING_CMD_FAILED:
402 if (pThisCC->hTestingTest != NIL_RTTEST)
403 RTTestFailed(pThisCC->hTestingTest, "%s", pThis->TestingData.String.sz);
404 VMMDEV_TESTING_OUTPUT(("testing: FAILED '%s'\n", pThis->TestingData.String.sz));
405 break;
406 case VMMDEV_TESTING_CMD_SKIPPED:
407 if (pThisCC->hTestingTest != NIL_RTTEST)
408 {
409 if (off)
410 RTTestSkipped(pThisCC->hTestingTest, "%s", pThis->TestingData.String.sz);
411 else
412 RTTestSkipped(pThisCC->hTestingTest, NULL);
413 }
414 VMMDEV_TESTING_OUTPUT(("testing: SKIPPED '%s'\n", pThis->TestingData.String.sz));
415 break;
416 case VMMDEV_TESTING_CMD_PRINT:
417 if (pThisCC->hTestingTest != NIL_RTTEST && off)
418 RTTestPrintf(pThisCC->hTestingTest, RTTESTLVL_ALWAYS, "%s", pThis->TestingData.String.sz);
419 VMMDEV_TESTING_OUTPUT(("testing: '%s'\n", pThis->TestingData.String.sz));
420 break;
421 }
422#else
423 return VINF_IOM_R3_IOPORT_WRITE;
424#endif
425 }
426 return VINF_SUCCESS;
427 }
428 break;
429
430 case VMMDEV_TESTING_CMD_TERM:
431 case VMMDEV_TESTING_CMD_SUB_DONE:
432 if (cb == 2)
433 {
434 if (off == 0)
435 {
436 pThis->TestingData.Error.c = u32;
437 pThis->offTestingData = 2;
438 break;
439 }
440 if (off == 2)
441 {
442 u32 <<= 16;
443 u32 |= pThis->TestingData.Error.c & UINT16_MAX;
444 cb = 4;
445 off = 0;
446 }
447 else
448 break;
449 }
450
451 if ( off == 0
452 && cb == 4)
453 {
454#ifdef IN_RING3
455 pThis->TestingData.Error.c = u32;
456 if (uCmd == VMMDEV_TESTING_CMD_TERM)
457 {
458 if (pThisCC->hTestingTest != NIL_RTTEST)
459 {
460 while (RTTestErrorCount(pThisCC->hTestingTest) < u32)
461 RTTestErrorInc(pThisCC->hTestingTest); /* A bit stupid, but does the trick. */
462 RTTestSubDone(pThisCC->hTestingTest);
463 RTTestSummaryAndDestroy(pThisCC->hTestingTest);
464 pThisCC->hTestingTest = NIL_RTTEST;
465 }
466 VMMDEV_TESTING_OUTPUT(("testing: TERM - %u errors\n", u32));
467 }
468 else
469 {
470 if (pThisCC->hTestingTest != NIL_RTTEST)
471 {
472 while (RTTestSubErrorCount(pThisCC->hTestingTest) < u32)
473 RTTestErrorInc(pThisCC->hTestingTest); /* A bit stupid, but does the trick. */
474 RTTestSubDone(pThisCC->hTestingTest);
475 }
476 VMMDEV_TESTING_OUTPUT(("testing: SUB_DONE - %u errors\n", u32));
477 }
478 return VINF_SUCCESS;
479#else
480 return VINF_IOM_R3_IOPORT_WRITE;
481#endif
482 }
483 break;
484
485 case VMMDEV_TESTING_CMD_VALUE:
486 if (cb == 4)
487 {
488 if (off == 0)
489 pThis->TestingData.Value.u64Value.s.Lo = u32;
490 else if (off == 4)
491 pThis->TestingData.Value.u64Value.s.Hi = u32;
492 else if (off == 8)
493 pThis->TestingData.Value.u32Unit = u32;
494 else
495 break;
496 pThis->offTestingData = off + 4;
497 return VINF_SUCCESS;
498 }
499 if (cb == 2)
500 {
501 if (off == 0)
502 pThis->TestingData.Value.u64Value.Words.w0 = (uint16_t)u32;
503 else if (off == 2)
504 pThis->TestingData.Value.u64Value.Words.w1 = (uint16_t)u32;
505 else if (off == 4)
506 pThis->TestingData.Value.u64Value.Words.w2 = (uint16_t)u32;
507 else if (off == 6)
508 pThis->TestingData.Value.u64Value.Words.w3 = (uint16_t)u32;
509 else if (off == 8)
510 pThis->TestingData.Value.u32Unit = (uint16_t)u32;
511 else if (off == 10)
512 pThis->TestingData.Value.u32Unit = u32 << 16;
513 else
514 break;
515 pThis->offTestingData = off + 2;
516 return VINF_SUCCESS;
517 }
518
519 if ( off >= 12
520 && cb == 1
521 && off - 12 < sizeof(pThis->TestingData.Value.szName) - 1)
522 {
523 if (u32)
524 {
525 pThis->TestingData.Value.szName[off - 12] = u32;
526 pThis->offTestingData = off + 1;
527 }
528 else
529 {
530#ifdef IN_RING3
531 pThis->TestingData.Value.szName[off - 12] = '\0';
532
533 RTTESTUNIT enmUnit = (RTTESTUNIT)pThis->TestingData.Value.u32Unit;
534 if (enmUnit <= RTTESTUNIT_INVALID || enmUnit >= RTTESTUNIT_END)
535 {
536 VMMDEV_TESTING_OUTPUT(("Invalid log value unit %#x\n", pThis->TestingData.Value.u32Unit));
537 enmUnit = RTTESTUNIT_NONE;
538 }
539 if (pThisCC->hTestingTest != NIL_RTTEST)
540 RTTestValue(pThisCC->hTestingTest, pThis->TestingData.Value.szName,
541 pThis->TestingData.Value.u64Value.u, enmUnit);
542
543 VMMDEV_TESTING_OUTPUT(("testing: VALUE '%s'%*s: %'9llu (%#llx) [%u]\n",
544 pThis->TestingData.Value.szName,
545 off - 12 > 48 ? 0 : 48 - (off - 12), "",
546 pThis->TestingData.Value.u64Value.u, pThis->TestingData.Value.u64Value.u,
547 pThis->TestingData.Value.u32Unit));
548#else
549 return VINF_IOM_R3_IOPORT_WRITE;
550#endif
551 }
552 return VINF_SUCCESS;
553 }
554 break;
555
556
557 /*
558 * RTTestValue with the output from DBGFR3RegNmQuery.
559 */
560 case VMMDEV_TESTING_CMD_VALUE_REG:
561 {
562 if ( off < sizeof(pThis->TestingData.String.sz) - 1
563 && cb == 1)
564 {
565 pThis->TestingData.String.sz[off] = u32;
566 if (u32)
567 pThis->offTestingData = off + 1;
568 else
569#ifdef IN_RING3
570 vmmdevTestingCmdExec_ValueReg(pDevIns, pThis);
571#else
572 return VINF_IOM_R3_IOPORT_WRITE;
573#endif
574 return VINF_SUCCESS;
575 }
576 break;
577 }
578
579 default:
580 break;
581 }
582 Log(("VMMDEV_TESTING_IOPORT_CMD: bad access; cmd=%#x off=%#x cb=%#x u32=%#x\n", uCmd, off, cb, u32));
583 return VINF_SUCCESS;
584 }
585
586 default:
587 break;
588 }
589
590 return VERR_IOM_IOPORT_UNUSED;
591}
592
593
594/**
595 * @callback_method_impl{FNIOMIOPORTNEWIN}
596 */
597static DECLCALLBACK(VBOXSTRICTRC)
598vmmdevTestingIoRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
599{
600 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
601 RT_NOREF_PV(pvUser);
602
603 switch (offPort)
604 {
605 /*
606 * The NOP I/O ports are used for performance measurements.
607 */
608 case VMMDEV_TESTING_IOPORT_NOP - VMMDEV_TESTING_IOPORT_BASE:
609 switch (cb)
610 {
611 case 4:
612 case 2:
613 case 1:
614 break;
615 default:
616 AssertFailed();
617 return VERR_INTERNAL_ERROR_2;
618 }
619 *pu32 = VMMDEV_TESTING_NOP_RET;
620 return VINF_SUCCESS;
621
622 case VMMDEV_TESTING_IOPORT_NOP_R3 - VMMDEV_TESTING_IOPORT_BASE:
623 switch (cb)
624 {
625 case 4:
626 case 2:
627 case 1:
628#ifndef IN_RING3
629 return VINF_IOM_R3_IOPORT_READ;
630#else
631 *pu32 = VMMDEV_TESTING_NOP_RET;
632 return VINF_SUCCESS;
633#endif
634 default:
635 AssertFailed();
636 return VERR_INTERNAL_ERROR_2;
637 }
638
639 /*
640 * The timestamp I/O ports are obviously used for getting a good fix
641 * on the current time (as seen by the host?).
642 *
643 * The high word is latched when reading the low, so reading low + high
644 * gives you a 64-bit timestamp value.
645 */
646 case VMMDEV_TESTING_IOPORT_TS_LOW - VMMDEV_TESTING_IOPORT_BASE:
647 if (cb == 4)
648 {
649 uint64_t NowTS = RTTimeNanoTS();
650 *pu32 = (uint32_t)NowTS;
651 pThis->u32TestingHighTimestamp = (uint32_t)(NowTS >> 32);
652 return VINF_SUCCESS;
653 }
654 break;
655
656 case VMMDEV_TESTING_IOPORT_TS_HIGH - VMMDEV_TESTING_IOPORT_BASE:
657 if (cb == 4)
658 {
659 *pu32 = pThis->u32TestingHighTimestamp;
660 return VINF_SUCCESS;
661 }
662 break;
663
664 /*
665 * The command and data registers are write-only.
666 */
667 case VMMDEV_TESTING_IOPORT_CMD - VMMDEV_TESTING_IOPORT_BASE:
668 case VMMDEV_TESTING_IOPORT_DATA - VMMDEV_TESTING_IOPORT_BASE:
669 break;
670
671 default:
672 break;
673 }
674
675 return VERR_IOM_IOPORT_UNUSED;
676}
677
678
679#ifdef IN_RING3
680
681/**
682 * Initializes the testing part of the VMMDev if enabled.
683 *
684 * @returns VBox status code.
685 * @param pDevIns The VMMDev device instance.
686 */
687void vmmdevR3TestingTerminate(PPDMDEVINS pDevIns)
688{
689 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
690 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
691 if (!pThis->fTestingEnabled)
692 return;
693
694 if (pThisCC->hTestingTest != NIL_RTTEST)
695 {
696 RTTestFailed(pThisCC->hTestingTest, "Still open at vmmdev destruction.");
697 RTTestSummaryAndDestroy(pThisCC->hTestingTest);
698 pThisCC->hTestingTest = NIL_RTTEST;
699 }
700}
701
702
703/**
704 * Initializes the testing part of the VMMDev if enabled.
705 *
706 * @returns VBox status code.
707 * @param pDevIns The VMMDev device instance.
708 */
709int vmmdevR3TestingInitialize(PPDMDEVINS pDevIns)
710{
711 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
712 PVMMDEVCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVMMDEVCC);
713 int rc;
714
715 if (!pThis->fTestingEnabled)
716 return VINF_SUCCESS;
717
718 if (pThis->fTestingMMIO)
719 {
720 /*
721 * Register a chunk of MMIO memory that we'll use for various
722 * tests interfaces. Optional, needs to be explicitly enabled.
723 */
724 rc = PDMDevHlpMmioCreateAndMap(pDevIns, VMMDEV_TESTING_MMIO_BASE, VMMDEV_TESTING_MMIO_SIZE,
725 vmmdevTestingMmioWrite, vmmdevTestingMmioRead,
726 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
727 "VMMDev Testing", &pThis->hMmioTesting);
728 AssertRCReturn(rc, rc);
729 }
730
731
732 /*
733 * Register the I/O ports used for testing.
734 */
735 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, VMMDEV_TESTING_IOPORT_BASE, VMMDEV_TESTING_IOPORT_COUNT,
736 vmmdevTestingIoWrite, vmmdevTestingIoRead, "VMMDev Testing", NULL /*paExtDescs*/,
737 &pThis->hIoPortTesting);
738 AssertRCReturn(rc, rc);
739
740 /*
741 * Open the XML output file(/pipe/whatever) if specfied.
742 */
743 rc = RTTestCreateEx("VMMDevTesting", RTTEST_C_USE_ENV | RTTEST_C_NO_TLS | RTTEST_C_XML_DELAY_TOP_TEST,
744 RTTESTLVL_INVALID, -1 /*iNativeTestPipe*/, pThisCC->pszTestingXmlOutput, &pThisCC->hTestingTest);
745 if (RT_FAILURE(rc))
746 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, "Error creating testing instance");
747
748 return VINF_SUCCESS;
749}
750
751#else /* !IN_RING3 */
752
753/**
754 * Does the ring-0/raw-mode initialization of the testing part if enabled.
755 *
756 * @returns VBox status code.
757 * @param pDevIns The VMMDev device instance.
758 */
759int vmmdevRZTestingInitialize(PPDMDEVINS pDevIns)
760{
761 PVMMDEV pThis = PDMDEVINS_2_DATA(pDevIns, PVMMDEV);
762 int rc;
763
764 if (!pThis->fTestingEnabled)
765 return VINF_SUCCESS;
766
767 if (pThis->fTestingMMIO)
768 {
769 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioTesting, vmmdevTestingMmioWrite, vmmdevTestingMmioRead, NULL);
770 AssertRCReturn(rc, rc);
771 }
772
773 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortTesting, vmmdevTestingIoWrite, vmmdevTestingIoRead, NULL);
774 AssertRCReturn(rc, rc);
775
776 return VINF_SUCCESS;
777}
778
779#endif /* !IN_RING3 */
780#endif /* !VBOX_WITHOUT_TESTING_FEATURES */
781
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use