VirtualBox

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