VirtualBox

source: vbox/trunk/src/VBox/Devices/testcase/tstDevice.cpp@ 82891

Last change on this file since 82891 was 82883, checked in by vboxsync, 5 years ago

Devices/testcase: Restarted work on the device testbench/fuzzing work (#9006), adjusting to the interface changes in 6.1 dropping the VMM stub library which is not required anymore (yay), work in progress

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.7 KB
Line 
1/* $Id: tstDevice.cpp 82883 2020-01-27 18:20:21Z vboxsync $ */
2/** @file
3 * tstDevice - Test framework for PDM devices/drivers
4 */
5
6/*
7 * Copyright (C) 2017-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEFAULT /** @todo */
23#include <VBox/types.h>
24#include <VBox/sup.h>
25#include <VBox/version.h>
26#include <iprt/assert.h>
27#include <iprt/ctype.h>
28#include <iprt/getopt.h>
29#include <iprt/initterm.h>
30#include <iprt/ldr.h>
31#include <iprt/log.h>
32#include <iprt/list.h>
33#include <iprt/mem.h>
34#include <iprt/once.h>
35#include <iprt/path.h>
36#include <iprt/string.h>
37#include <iprt/stream.h>
38#include <iprt/trace.h>
39
40#include "tstDeviceInternal.h"
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51
52
53/**
54 * Testcase plugin descriptor.
55 */
56typedef struct TSTDEVPLUGIN
57{
58 /** Node for the plugin list. */
59 RTLISTNODE NdPlugins;
60 /** Copy of the filename. */
61 char *pszFilename;
62 /** Loader handle. */
63 RTLDRMOD hMod;
64 /** Number of references to this plugin. */
65 volatile uint32_t cRefs;
66} TSTDEVPLUGIN;
67/** Pointer to a device plugin descriptor. */
68typedef TSTDEVPLUGIN *PTSTDEVPLUGIN;
69/** Pointer to a const plugin descriptor. */
70typedef const TSTDEVPLUGIN *PCTSTDEVPLUGIN;
71
72
73/**
74 * Testcase descriptor.
75 */
76typedef struct TSTDEVTESTCASE
77{
78 /** Node for the list of registered testcases. */
79 RTLISTNODE NdTestcases;
80 /** Pointer to the plugin the testcase belongs to. */
81 PCTSTDEVPLUGIN pPlugin;
82 /** Pointer to the testcase descriptor. */
83 PCTSTDEVTESTCASEREG pTestcaseReg;
84} TSTDEVTESTCASE;
85/** Pointer to a testcase descriptor. */
86typedef TSTDEVTESTCASE *PTSTDEVTESTCASE;
87/** Pointer to a constant testcase descriptor. */
88typedef const TSTDEVTESTCASE *PCTSTDEVTESTCASE;
89
90
91/**
92 * PDM R0/RC module trampoline descriptor.
93 */
94#pragma pack(1)
95typedef struct TSTDEVPDMMODTRAMPOLINE
96{
97 /** Jump instruction. */
98 uint8_t abJmp[6];
99 /** Address to jump to. */
100 uintptr_t AddrTarget;
101 /** Padding to get a 16byte aligned structure. */
102 uint8_t abPadding[HC_ARCH_BITS == 64 ? 2 : 5];
103} TSTDEVPDMMODTRAMPOLINE;
104#pragma pack()
105AssertCompileSize(TSTDEVPDMMODTRAMPOLINE, 16);
106/** Pointer to a trampoline descriptor. */
107typedef TSTDEVPDMMODTRAMPOLINE *PTSTDEVPDMMODTRAMPOLINE;
108
109/**
110 * PDM module descriptor.
111 */
112typedef struct TSTDEVPDMMOD
113{
114 /** Node for the module list. */
115 RTLISTNODE NdPdmMods;
116 /** Type of module (R3/R0/RC). */
117 TSTDEVPDMMODTYPE enmType;
118 /** Copy of the filename. */
119 char *pszFilename;
120 /** Loader handle. */
121 RTLDRMOD hLdrMod;
122 /** Number of references to this plugin. */
123 volatile uint32_t cRefs;
124 /** R0/RC Module type dependent data. */
125 struct
126 {
127 /** The exectuable image bits. */
128 void *pvBits;
129 /** Size of the memory buffer. */
130 size_t cbBits;
131 /** Pointer to the executable memory containing the trampoline code. */
132 uint8_t *pbTrampoline;
133 /** Number of trampoline entries supported. */
134 uint32_t cTrampolinesMax;
135 /** Number of trampoline entries used. */
136 uint32_t cTrampolines;
137 /** Pointer to the next unused trampoline entry. */
138 PTSTDEVPDMMODTRAMPOLINE pTrampolineNext;
139 } R0Rc;
140} TSTDEVPDMMOD;
141/** Pointer to a PDM module descriptor. */
142typedef TSTDEVPDMMOD *PTSTDEVPDMMOD;
143/** Pointer to a const PDM module descriptor. */
144typedef const TSTDEVPDMMOD *PCTSTDEVPDMMOD;
145
146/**
147 * PDM device descriptor.
148 */
149typedef struct TSTDEVPDMDEV
150{
151 /** Node for the known device list. */
152 RTLISTNODE NdPdmDevs;
153 /** Pointer to the PDM module containing the device. */
154 PCTSTDEVPDMMOD pPdmMod;
155 /** Device registration structure. */
156 const PDMDEVREG *pReg;
157} TSTDEVPDMDEV;
158/** Pointer to a PDM device descriptor .*/
159typedef TSTDEVPDMDEV *PTSTDEVPDMDEV;
160/** Pointer to a constant PDM device descriptor .*/
161typedef const TSTDEVPDMDEV *PCTSTDEVPDMDEV;
162
163
164/**
165 * Internal callback structure pointer.
166 * The main purpose is to define the extra data we associate
167 * with PDMDEVREGCB so we can find the plugin the device is associated with etc.
168 */
169typedef struct TSTDEVPDMDEVREGCBINT
170{
171 /** The callback structure. */
172 PDMDEVREGCB Core;
173 /** A bit of padding. */
174 uint32_t u32[4];
175 /** Pointer to plugin. */
176 PTSTDEVPDMMOD pMod;
177} TSTDEVPDMDEVREGCBINT;
178/** Pointer to a PDMDEVREGCBINT structure. */
179typedef TSTDEVPDMDEVREGCBINT *PTSTDEVPDMDEVREGCBINT;
180/** Pointer to a const PDMDEVREGCBINT structure. */
181typedef const TSTDEVPDMDEVREGCBINT *PCTSTDEVPDMDEVREGCBINT;
182
183
184typedef struct TSTDEVPDMR0IMPORTS
185{
186 /** The symbol name. */
187 const char *pszSymbol;
188 /** The pointer. */
189 PFNRT pfn;
190} TSTDEVPDMR0IMPORTS;
191typedef const TSTDEVPDMR0IMPORTS *PCTSTDEVPDMR0IMPORTS;
192
193
194/*********************************************************************************************************************************
195* Global Variables *
196*********************************************************************************************************************************/
197/** List of registered testcase plugins. */
198RTLISTANCHOR g_LstPlugins;
199/** List of registered testcases. */
200RTLISTANCHOR g_LstTestcases;
201/** List of registered PDM modules. */
202RTLISTANCHOR g_LstPdmMods;
203/** List of registered PDM devices. */
204RTLISTANCHOR g_LstPdmDevs;
205
206/**
207 * PDM R0 imports we implement.
208 */
209static const TSTDEVPDMR0IMPORTS g_aPdmR0Imports[] =
210{
211#if 0
212 {"IOMMMIOMapMMIO2Page", (PFNRT)IOMMMIOMapMMIO2Page},
213 {"IOMMMIOResetRegion", (PFNRT)IOMMMIOResetRegion},
214 {"IntNetR0IfSend", (PFNRT)/*IntNetR0IfSend*/NULL},
215 {"IntNetR0IfSetPromiscuousMode", (PFNRT)/*IntNetR0IfSetPromiscuousMode*/NULL},
216 {"PDMCritSectEnterDebug", (PFNRT)PDMCritSectEnterDebug},
217 {"PDMCritSectIsOwner", (PFNRT)PDMCritSectIsOwner},
218 {"PDMCritSectLeave", (PFNRT)PDMCritSectLeave},
219 {"PDMCritSectTryEnterDebug", (PFNRT)PDMCritSectTryEnterDebug},
220 {"PDMHCCritSectScheduleExitEvent", (PFNRT)PDMHCCritSectScheduleExitEvent},
221 {"PDMNsAllocateBandwidth", (PFNRT)PDMNsAllocateBandwidth},
222 {"PDMQueueAlloc", (PFNRT)PDMQueueAlloc},
223 {"PDMQueueInsert", (PFNRT)PDMQueueInsert},
224 {"PGMHandlerPhysicalPageTempOff", (PFNRT)PGMHandlerPhysicalPageTempOff},
225 {"PGMShwMakePageWritable", (PFNRT)PGMShwMakePageWritable},
226 {"RTAssertMsg1Weak", (PFNRT)RTAssertMsg1Weak},
227 {"RTAssertMsg2Weak", (PFNRT)RTAssertMsg2Weak},
228 {"RTAssertShouldPanic", (PFNRT)RTAssertShouldPanic},
229 {"RTLogDefaultInstanceEx", (PFNRT)RTLogDefaultInstanceEx},
230 {"RTLogLoggerEx", (PFNRT)RTLogLoggerEx},
231 {"RTLogRelGetDefaultInstanceEx", (PFNRT)RTLogRelGetDefaultInstanceEx},
232 {"RTOnceSlow", (PFNRT)RTOnceSlow},
233 {"RTR0AssertPanicSystem", (PFNRT)0x10101010},
234 {"RTThreadSleep", (PFNRT)RTThreadSleep},
235 {"RTTimeMilliTS", (PFNRT)RTTimeMilliTS},
236 {"RTTimeNanoTS", (PFNRT)RTTimeNanoTS},
237 {"RTTraceBufAddMsgF", (PFNRT)RTTraceBufAddMsgF},
238 {"SUPSemEventSignal", (PFNRT)SUPSemEventSignal},
239 {"TMTimerGet", (PFNRT)TMTimerGet},
240 {"TMTimerGetFreq", (PFNRT)TMTimerGetFreq},
241 {"TMTimerIsActive", (PFNRT)TMTimerIsActive},
242 {"TMTimerIsLockOwner", (PFNRT)TMTimerIsLockOwner},
243 {"TMTimerLock", (PFNRT)TMTimerLock},
244 {"TMTimerSet", (PFNRT)TMTimerSet},
245 {"TMTimerSetFrequencyHint", (PFNRT)TMTimerSetFrequencyHint},
246 {"TMTimerSetMicro", (PFNRT)TMTimerSetMicro},
247 {"TMTimerSetMillies", (PFNRT)TMTimerSetMillies},
248 {"TMTimerSetNano", (PFNRT)TMTimerSetNano},
249 {"TMTimerStop", (PFNRT)TMTimerStop},
250 {"TMTimerUnlock", (PFNRT)TMTimerUnlock},
251 {"nocrt_memcmp", (PFNRT)memcmp},
252 {"nocrt_memcpy", (PFNRT)memcpy},
253 {"nocrt_memmove", (PFNRT)memmove},
254 {"nocrt_memset", (PFNRT)memset},
255 {"nocrt_strlen", (PFNRT)strlen},
256#else
257 { NULL, NULL }
258#endif
259};
260
261
262/*********************************************************************************************************************************
263* Internal Functions *
264*********************************************************************************************************************************/
265
266#if 0
267/**
268 * Parses the options given to the testcase.
269 *
270 * @returns Process status code.
271 * @param cArgs Number of arguments given.
272 * @param paszArgs Pointer to the argument vector.
273 */
274static RTEXITCODE tstDevParseOptions(int cArgs, char *paszArgs[])
275{
276 static RTGETOPTDEF const s_aOptions[] =
277 {
278 };
279
280
281 int ch;
282 RTGETOPTUNION Value;
283 RTGETOPTSTATE GetState;
284 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0 /* fFlags */);
285 while ((ch = RTGetOpt(&GetState, &Value)))
286 {
287 switch (ch)
288 {
289 default:
290 return RTGetOptPrintError(ch, &Value);
291 }
292 }
293}
294#endif
295
296
297/**
298 * Checks whether the given testcase name is already existing.
299 *
300 * @returns Pointer to existing testcase, NULL if not found.
301 * @param pszFilename The filename to check.
302 */
303static PCTSTDEVTESTCASE tstDevTestcaseFind(const char *pszName)
304{
305 PCTSTDEVTESTCASE pIt;
306 RTListForEach(&g_LstTestcases, pIt, TSTDEVTESTCASE, NdTestcases)
307 {
308 if (!RTStrCmp(pIt->pTestcaseReg->szName, pszName))
309 return pIt;
310 }
311
312 return NULL;
313}
314
315
316/**
317 * @interface_method_impl{TSTDEVPLUGINREGISTER,pfnRegisterTestcase}
318 */
319static DECLCALLBACK(int) tstDevRegisterTestcase(void *pvUser, PCTSTDEVTESTCASEREG pTestcaseReg)
320{
321 int rc = VINF_SUCCESS;
322 PTSTDEVPLUGIN pPlugin = (PTSTDEVPLUGIN)pvUser;
323
324 /* Try to find a testcase with the name first. */
325 if (!tstDevTestcaseFind(pTestcaseReg->szName))
326 {
327 PTSTDEVTESTCASE pTestcase = (PTSTDEVTESTCASE)RTMemAllocZ(sizeof(TSTDEVPLUGIN));
328 if (RT_LIKELY(pTestcase))
329 {
330 pTestcase->pPlugin = pPlugin;
331 pPlugin->cRefs++;
332 pTestcase->pTestcaseReg = pTestcaseReg;
333 RTListAppend(&g_LstTestcases, &pTestcase->NdTestcases);
334 return VINF_SUCCESS;
335 }
336 else
337 rc = VERR_NO_MEMORY;
338 }
339 else
340 rc = VERR_ALREADY_EXISTS;
341
342 return rc;
343}
344
345
346/**
347 * Checks whether the given plugin filename was already loaded.
348 *
349 * @returns Pointer to already loaded plugin, NULL if not found.
350 * @param pszFilename The filename to check.
351 */
352static PCTSTDEVPLUGIN tstDevPluginFind(const char *pszFilename)
353{
354 PCTSTDEVPLUGIN pIt;
355 RTListForEach(&g_LstPlugins, pIt, TSTDEVPLUGIN, NdPlugins)
356 {
357 if (!RTStrCmp(pIt->pszFilename, pszFilename))
358 return pIt;
359 }
360
361 return NULL;
362}
363
364
365/**
366 * Tries to loads the given plugin.
367 *
368 * @returns VBox status code.
369 * @param pszFilename The filename to load.
370 */
371static int tstDevLoadPlugin(const char *pszFilename)
372{
373 int rc = VINF_SUCCESS;
374
375 /* Check whether the plugin is loaded first. */
376 if (!tstDevPluginFind(pszFilename))
377 {
378 PTSTDEVPLUGIN pPlugin = (PTSTDEVPLUGIN)RTMemAllocZ(sizeof(TSTDEVPLUGIN));
379 if (RT_LIKELY(pPlugin))
380 {
381 pPlugin->pszFilename = RTStrDup(pszFilename);
382 pPlugin->cRefs = 1;
383 rc = RTLdrLoad(pszFilename, &pPlugin->hMod);
384 if (RT_SUCCESS(rc))
385 {
386 TSTDEVPLUGINREGISTER TestcaseRegister;
387 PFNTSTDEVPLUGINLOAD pfnPluginLoad = NULL;
388
389 TestcaseRegister.pfnRegisterTestcase = tstDevRegisterTestcase;
390
391 rc = RTLdrGetSymbol(pPlugin->hMod, TSTDEV_PLUGIN_LOAD_NAME, (void**)&pfnPluginLoad);
392 if (RT_FAILURE(rc) || !pfnPluginLoad)
393 {
394 LogFunc(("error resolving the entry point %s in plugin %s, rc=%Rrc, pfnPluginLoad=%#p\n",
395 TSTDEV_PLUGIN_LOAD_NAME, pszFilename, rc, pfnPluginLoad));
396 if (RT_SUCCESS(rc))
397 rc = VERR_SYMBOL_NOT_FOUND;
398 }
399
400 if (RT_SUCCESS(rc))
401 {
402 /* Get the function table. */
403 rc = pfnPluginLoad(pPlugin, &TestcaseRegister);
404 }
405 else
406 LogFunc(("ignored plugin '%s': rc=%Rrc\n", pszFilename, rc));
407
408 /* Create a plugin entry on success. */
409 if (RT_SUCCESS(rc))
410 {
411 RTListAppend(&g_LstPlugins, &pPlugin->NdPlugins);
412 return VINF_SUCCESS;
413 }
414 else
415 RTLdrClose(pPlugin->hMod);
416 }
417
418 RTMemFree(pPlugin);
419 }
420 else
421 rc = VERR_NO_MEMORY;
422 }
423
424 return rc;
425}
426
427
428/**
429 * Checks whether the given testcase name is already existing.
430 *
431 * @returns Pointer to already loaded plugin, NULL if not found.
432 * @param pszFilename The filename to check.
433 */
434static PCTSTDEVPDMDEV tstDevPdmDeviceFind(const char *pszName)
435{
436 PCTSTDEVPDMDEV pIt;
437 RTListForEach(&g_LstPdmDevs, pIt, TSTDEVPDMDEV, NdPdmDevs)
438 {
439 if (!RTStrCmp(pIt->pReg->szName, pszName))
440 return pIt;
441 }
442
443 return NULL;
444}
445
446
447/**
448 * Checks that a PDMDRVREG::szName, PDMDEVREG::szName or PDMUSBREG::szName
449 * field contains only a limited set of ASCII characters.
450 *
451 * @returns true / false.
452 * @param pszName The name to validate.
453 */
454bool tstDevPdmR3IsValidName(const char *pszName)
455{
456 char ch;
457 while ( (ch = *pszName) != '\0'
458 && ( RT_C_IS_ALNUM(ch)
459 || ch == '-'
460 || ch == ' ' /** @todo disallow this! */
461 || ch == '_') )
462 pszName++;
463 return ch == '\0';
464}
465
466
467/**
468 * @interface_method_impl{PDMDEVREGCB,pfnRegister}
469 */
470static DECLCALLBACK(int) tstDevPdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)
471{
472 /*
473 * Validate the registration structure (mostly copy and paste from PDMDevice.cpp).
474 */
475 Assert(pReg);
476 AssertMsgReturn(pReg->u32Version == PDM_DEVREG_VERSION,
477 ("Unknown struct version %#x!\n", pReg->u32Version),
478 VERR_PDM_UNKNOWN_DEVREG_VERSION);
479
480 AssertMsgReturn( pReg->szName[0]
481 && strlen(pReg->szName) < sizeof(pReg->szName)
482 && tstDevPdmR3IsValidName(pReg->szName),
483 ("Invalid name '%.*s'\n", sizeof(pReg->szName), pReg->szName),
484 VERR_PDM_INVALID_DEVICE_REGISTRATION);
485 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) == PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT,
486 ("Invalid host bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
487 VERR_PDM_INVALID_DEVICE_HOST_BITS);
488 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK),
489 ("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
490 VERR_PDM_INVALID_DEVICE_REGISTRATION);
491 AssertMsgReturn(pReg->fClass,
492 ("No class! (Device %s)\n", pReg->szName),
493 VERR_PDM_INVALID_DEVICE_REGISTRATION);
494 AssertMsgReturn(pReg->cMaxInstances > 0,
495 ("Max instances %u! (Device %s)\n", pReg->cMaxInstances, pReg->szName),
496 VERR_PDM_INVALID_DEVICE_REGISTRATION);
497 AssertMsgReturn(pReg->cbInstanceCC <= (uint32_t)(pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0) ? 96 * _1K : _1M),
498 ("Instance size %d bytes! (Device %s)\n", pReg->cbInstanceCC, pReg->szName),
499 VERR_PDM_INVALID_DEVICE_REGISTRATION);
500 AssertMsgReturn(pReg->pfnConstruct,
501 ("No constructor! (Device %s)\n", pReg->szName),
502 VERR_PDM_INVALID_DEVICE_REGISTRATION);
503 AssertLogRelMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK) == PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
504 ("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pReg->szName),
505 VERR_PDM_INVALID_DEVICE_GUEST_BITS);
506 AssertLogRelMsg(pReg->u32VersionEnd == PDM_DEVREG_VERSION,
507 ("u32VersionEnd=%#x, expected %#x. (szName=%s)\n",
508 pReg->u32VersionEnd, PDM_DEVREG_VERSION, pReg->szName));
509
510 /*
511 * Check for duplicates.
512 */
513 int rc = VINF_SUCCESS;
514 PCTSTDEVPDMDEVREGCBINT pRegCB = (PCTSTDEVPDMDEVREGCBINT)pCallbacks;
515 if (!tstDevPdmDeviceFind(pReg->szName))
516 {
517 PTSTDEVPDMDEV pPdmDev = (PTSTDEVPDMDEV)RTMemAllocZ(sizeof(TSTDEVPDMDEV));
518 if (RT_LIKELY(pPdmDev))
519 {
520 pPdmDev->pPdmMod = pRegCB->pMod;
521 pRegCB->pMod->cRefs++;
522 pPdmDev->pReg = pReg;
523 RTListAppend(&g_LstPdmDevs, &pPdmDev->NdPdmDevs);
524 return VINF_SUCCESS;
525 }
526 else
527 rc = VERR_NO_MEMORY;
528 }
529 else
530 rc = VERR_PDM_DEVICE_NAME_CLASH;
531
532 return rc;
533}
534
535
536/**
537 * Checks whether the given PDM module filename was already loaded.
538 *
539 * @returns Pointer to already loaded plugin, NULL if not found.
540 * @param pszFilename The filename to check.
541 */
542static PCTSTDEVPDMMOD tstDevPdmModFind(const char *pszFilename)
543{
544 PCTSTDEVPDMMOD pIt;
545 RTListForEach(&g_LstPdmMods, pIt, TSTDEVPDMMOD, NdPdmMods)
546 {
547 if (!RTStrCmp(pIt->pszFilename, pszFilename))
548 return pIt;
549 }
550
551 return NULL;
552}
553
554
555/**
556 * Resolve an external symbol during RTLdrGetBits().
557 *
558 * @returns iprt status code.
559 * @param hLdrMod The loader module handle.
560 * @param pszModule Module name.
561 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
562 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
563 * @param pValue Where to store the symbol value (address).
564 * @param pvUser User argument.
565 */
566static DECLCALLBACK(int) tstDevPdmLoadR0RcModGetImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
567 unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
568{
569 RT_NOREF(hLdrMod, uSymbol, pszModule);
570 PTSTDEVPDMMOD pMod = (PTSTDEVPDMMOD)pvUser;
571
572 /* Resolve the import. */
573 PCTSTDEVPDMR0IMPORTS pImpDesc = NULL;
574 bool fFound = false;
575 for (uint32_t i = 0; i < RT_ELEMENTS(g_aPdmR0Imports); i++)
576 {
577 pImpDesc = &g_aPdmR0Imports[i];
578 if (!strcmp(pszSymbol, pImpDesc->pszSymbol))
579 {
580 fFound = true;
581 break;
582 }
583 }
584
585 int rc = VERR_SYMBOL_NOT_FOUND;
586 if (fFound)
587 {
588 /* Check whether the symbol has a trampoline already. */
589 PTSTDEVPDMMODTRAMPOLINE pTrampoline = (PTSTDEVPDMMODTRAMPOLINE)pMod->R0Rc.pbTrampoline;
590 for (uint32_t i = 0; i < pMod->R0Rc.cTrampolines; i++)
591 {
592 if (pTrampoline->AddrTarget == (uintptr_t)pImpDesc->pfn)
593 break;
594 pTrampoline++;
595 }
596
597 /* Create new trampoline if not found. */
598 if (pTrampoline->AddrTarget != (uintptr_t)pImpDesc->pfn)
599 {
600 if (pMod->R0Rc.cTrampolines < pMod->R0Rc.cTrampolinesMax)
601 {
602 pTrampoline = pMod->R0Rc.pTrampolineNext;
603 pMod->R0Rc.pTrampolineNext++;
604 pMod->R0Rc.cTrampolines++;
605 pTrampoline->abJmp[0] = 0xff; /* jmp */
606 pTrampoline->abJmp[1] = 0x25; /* rip */
607 pTrampoline->abJmp[2] = 0x00; /* offset */
608 pTrampoline->abJmp[3] = 0x00;
609 pTrampoline->abJmp[4] = 0x00;
610 pTrampoline->abJmp[5] = 0x00;
611 pTrampoline->AddrTarget = (uintptr_t)pImpDesc->pfn;
612 rc = VINF_SUCCESS;
613 }
614 else
615 {
616 rc = VERR_SYMBOL_NOT_FOUND;
617 AssertFailed();
618 }
619 }
620 else
621 rc = VINF_SUCCESS;
622
623 if (RT_SUCCESS(rc))
624 *pValue = (RTUINTPTR)pTrampoline;
625 }
626 else
627 AssertFailed();
628
629 return rc;
630}
631
632
633/**
634 * Loads a new R0 modules given by the filename.
635 *
636 * @returns VBox status code.
637 * @param pMod Pointer to module structure.
638 */
639static int tstDevPdmLoadR0RcMod(PTSTDEVPDMMOD pMod)
640{
641 int rc = VINF_SUCCESS;
642 const char *pszFile = RTPathFilename(pMod->pszFilename);
643
644 /* Check whether the plugin is loaded first. */
645 if (!tstDevPdmModFind(pszFile))
646 {
647 /*
648 * R0 modules need special treatment as these are relocatable images
649 * which are supposed to run in ring 0.
650 */
651 rc = RTLdrOpen(pMod->pszFilename, 0, RTLDRARCH_HOST, &pMod->hLdrMod);
652 if (RT_SUCCESS(rc))
653 {
654 size_t cb = RTLdrSize(pMod->hLdrMod) + 1024 * sizeof(TSTDEVPDMMODTRAMPOLINE);
655
656 /* Allocate bits. */
657 uint32_t fFlags = RTMEMALLOCEX_FLAGS_EXEC;
658#ifdef RT_OS_LINUX
659 /*
660 * amd64 ELF binaries support only a 2GB code segment everything must be in
661 * (X86_64_PC32 relocation) so we have to use a trampoline to the final destination
662 * which is kept close to the imported module.
663 */
664 fFlags |= RTMEMALLOCEX_FLAGS_32BIT_REACH;
665#endif
666 rc = RTMemAllocEx(cb, 0, fFlags, (void **)&pMod->R0Rc.pbTrampoline);
667 pMod->R0Rc.cbBits = cb;
668 if (RT_SUCCESS(rc))
669 {
670 pMod->R0Rc.pvBits = pMod->R0Rc.pbTrampoline + 1024 * sizeof(TSTDEVPDMMODTRAMPOLINE);
671 pMod->R0Rc.cTrampolinesMax = 1024;
672 pMod->R0Rc.cTrampolines = 0;
673 pMod->R0Rc.pTrampolineNext = (PTSTDEVPDMMODTRAMPOLINE)pMod->R0Rc.pbTrampoline;
674 /* Get the bits. */
675 rc = RTLdrGetBits(pMod->hLdrMod, pMod->R0Rc.pvBits, (uintptr_t)pMod->R0Rc.pvBits,
676 tstDevPdmLoadR0RcModGetImport, pMod);
677 if (RT_FAILURE(rc))
678 RTMemFreeEx(pMod->R0Rc.pbTrampoline, pMod->R0Rc.cbBits);
679 }
680
681 if (RT_FAILURE(rc))
682 RTLdrClose(pMod->hLdrMod);
683 }
684 }
685
686 return rc;
687}
688
689
690/**
691 * Loads the given
692 */
693static int tstDevPdmLoadR3Mod(PTSTDEVPDMMOD pMod)
694{
695 int rc = RTLdrLoad(pMod->pszFilename, &pMod->hLdrMod);
696 if (RT_SUCCESS(rc))
697 {
698 FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
699 rc = RTLdrGetSymbol(pMod->hLdrMod, "VBoxDevicesRegister", (void**)&pfnVBoxDevicesRegister);
700 if (RT_FAILURE(rc) || !pfnVBoxDevicesRegister)
701 {
702 LogFunc(("error resolving the entry point %s in plugin %s, rc=%Rrc, pfnPluginLoad=%#p\n",
703 "VBoxDevicesRegister", pMod->pszFilename, rc, pfnVBoxDevicesRegister));
704 if (RT_SUCCESS(rc))
705 rc = VERR_SYMBOL_NOT_FOUND;
706 }
707
708 if (RT_SUCCESS(rc))
709 {
710 TSTDEVPDMDEVREGCBINT RegCB;
711 RegCB.Core.u32Version = PDM_DEVREG_CB_VERSION;
712 RegCB.Core.pfnRegister = tstDevPdmR3DevReg_Register;
713 RegCB.pMod = pMod;
714 rc = pfnVBoxDevicesRegister(&RegCB.Core, VBOX_VERSION);
715 }
716 else
717 LogFunc(("ignored plugin '%s': rc=%Rrc\n", pMod->pszFilename, rc));
718
719 if (RT_FAILURE(rc))
720 RTLdrClose(pMod->hLdrMod);
721 }
722
723 return rc;
724}
725
726
727/**
728 * Tries to loads the given PDM module.
729 *
730 * @returns VBox status code.
731 * @param pszFilename The filename to load.
732 * @param enmModType The module type.
733 */
734static int tstDevPdmLoadMod(const char *pszFilename, TSTDEVPDMMODTYPE enmModType)
735{
736 int rc = VINF_SUCCESS;
737
738 /* Check whether the plugin is loaded first. */
739 if (!tstDevPdmModFind(pszFilename))
740 {
741 PTSTDEVPDMMOD pMod = (PTSTDEVPDMMOD)RTMemAllocZ(sizeof(TSTDEVPDMMOD));
742 if (RT_LIKELY(pMod))
743 {
744 pMod->pszFilename = RTStrDup(pszFilename);
745 pMod->cRefs = 1;
746 pMod->enmType = enmModType;
747
748 if (enmModType == TSTDEVPDMMODTYPE_R3)
749 rc = tstDevPdmLoadR3Mod(pMod);
750 else if (enmModType == TSTDEVPDMMODTYPE_RC || enmModType == TSTDEVPDMMODTYPE_R0)
751 rc = tstDevPdmLoadR0RcMod(pMod);
752
753 if (RT_SUCCESS(rc))
754 RTListAppend(&g_LstPdmMods, &pMod->NdPdmMods);
755 else
756 RTMemFree(pMod);
757 }
758 else
759 rc = VERR_NO_MEMORY;
760 }
761
762 return rc;
763}
764
765
766/**
767 * Tries to resolve the given symbol from the module given.
768 *
769 * @returns VBox status code.
770 * @param pThis The device under test instance.
771 * @param pszMod The module name.
772 * @param enmModType The module type if the module needs to be loaded.
773 * @param pszSymbol The symbol to resolve.
774 * @param ppfn Where to store the value on success.
775 */
776DECLHIDDEN(int) tstDevPdmLdrGetSymbol(PTSTDEVDUTINT pThis, const char *pszMod, TSTDEVPDMMODTYPE enmModType,
777 const char *pszSymbol, PFNRT *ppfn)
778{
779 RT_NOREF(pThis);
780
781 int rc = VINF_SUCCESS;
782 PCTSTDEVPDMMOD pMod = tstDevPdmModFind(pszMod);
783 if (!pMod)
784 {
785 /* Try to load the module. */
786 rc = tstDevPdmLoadMod(pszMod, enmModType);
787 if (RT_SUCCESS(rc))
788 {
789 pMod = tstDevPdmModFind(pszMod);
790 AssertPtr(pMod);
791 }
792 }
793
794 if (RT_SUCCESS(rc))
795 {
796 if (pMod->enmType == TSTDEVPDMMODTYPE_R0 || pMod->enmType == TSTDEVPDMMODTYPE_RC)
797 rc = RTLdrGetSymbolEx(pMod->hLdrMod, pMod->R0Rc.pvBits, (uintptr_t)pMod->R0Rc.pvBits,
798 UINT32_MAX, pszSymbol, (PRTLDRADDR)ppfn);
799 else
800 rc = RTLdrGetSymbol(pMod->hLdrMod, pszSymbol, (void **)ppfn);
801 }
802
803 return rc;
804}
805
806
807static TSTDEVCFGITEM s_aTestcaseCfg[] =
808{
809 {"CtrlMemBufSize", TSTDEVCFGITEMTYPE_INTEGER, "0" },
810 {NULL, TSTDEVCFGITEMTYPE_INVALID, NULL }
811};
812
813static TSTDEVTESTCASEREG s_TestcaseDef =
814{
815 "test",
816 "Testcase during implementation",
817 "nvme",
818 0,
819 &s_aTestcaseCfg[0],
820 NULL,
821};
822
823/**
824 * Create a new PDM device with default config.
825 *
826 * @returns VBox status code.
827 * @param pszName Name of the device to create.
828 */
829static int tstDevPdmDevCreate(const char *pszName)
830{
831 int rc = VINF_SUCCESS;
832 PCTSTDEVPDMDEV pPdmDev = tstDevPdmDeviceFind(pszName);
833 if (RT_LIKELY(pPdmDev))
834 {
835 TSTDEVDUTINT Dut;
836 Dut.pTestcaseReg = &s_TestcaseDef;
837 Dut.enmCtx = TSTDEVDUTCTX_R3;
838 Dut.pVm = NULL;
839 Dut.SupSession.pDut = &Dut;
840 RTListInit(&Dut.LstIoPorts);
841 RTListInit(&Dut.LstTimers);
842 RTListInit(&Dut.LstMmHeap);
843 RTListInit(&Dut.LstPdmThreads);
844 RTListInit(&Dut.SupSession.LstSupSem);
845 CFGMNODE Cfg;
846 Cfg.pDut = &Dut;
847
848 rc = RTCritSectRwInit(&Dut.CritSectLists);
849 AssertRC(rc);
850
851 PPDMDEVINS pDevIns = (PPDMDEVINS)RTMemAllocZ(RT_UOFFSETOF_DYN(PDMDEVINS, achInstanceData[pPdmDev->pReg->cbInstanceCC]));
852 pDevIns->u32Version = PDM_DEVINS_VERSION;
853 pDevIns->iInstance = 0;
854 pDevIns->pReg = pPdmDev->pReg;
855 pDevIns->pvInstanceDataR3 = &pDevIns->achInstanceData[0];
856 pDevIns->pHlpR3 = &g_tstDevPdmDevHlpR3;
857 pDevIns->pCfg = &Cfg;
858 pDevIns->Internal.s.pDut = &Dut;
859 rc = pPdmDev->pReg->pfnConstruct(pDevIns, 0, &Cfg);
860 if (RT_SUCCESS(rc))
861 {
862 PRTDEVDUTIOPORT pIoPort = RTListGetFirst(&Dut.LstIoPorts, RTDEVDUTIOPORT, NdIoPorts);
863 uint32_t uVal = 0;
864 /*PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);*/
865 pIoPort->pfnInR0(pDevIns, pIoPort->pvUserR0, pIoPort->PortStart, &uVal, sizeof(uint8_t));
866 /*PDMCritSectLeave(pDevIns->pCritSectRoR3);*/
867 }
868 }
869 else
870 rc = VERR_NOT_FOUND;
871
872 return rc;
873}
874
875int main(int argc, char *argv[])
876{
877 /*
878 * Init the runtime and parse the arguments.
879 */
880 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
881 int rc = RTR3InitExe(argc, &argv, 0);
882 if (RT_SUCCESS(rc))
883 {
884 RTListInit(&g_LstPlugins);
885 RTListInit(&g_LstTestcases);
886 RTListInit(&g_LstPdmMods);
887 RTListInit(&g_LstPdmDevs);
888
889 rc = tstDevLoadPlugin("TSTDevTestcases");
890 if (RT_SUCCESS(rc) || true)
891 {
892 rc = tstDevPdmLoadMod(argv[1], TSTDEVPDMMODTYPE_R3);
893 if (RT_SUCCESS(rc))
894 rc = tstDevPdmDevCreate("nvme");
895 else
896 rcExit = RTEXITCODE_FAILURE;
897 }
898 else
899 rcExit = RTEXITCODE_FAILURE;
900
901 //rcExit = tstDevParseOptions(argc, argv);
902 }
903 else
904 rcExit = RTEXITCODE_FAILURE;
905
906 return rcExit;
907}
908
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