VirtualBox

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

Last change on this file since 62448 was 62427, checked in by vboxsync, 8 years ago

vmmdevTestingMmioRead: build fix.

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