VirtualBox

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

Last change on this file since 61583 was 61384, checked in by vboxsync, 9 years ago

VMMDev/Testing: Added a 64-byte readback register with two access areas (same context / always ring-3). Extended the NOP register handling to include odd access so we can read the whole 32-bit width in two 16-bit accesses (useful for 16-bit C code).

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