Changeset 108873 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Apr 7, 2025 2:55:14 PM (5 weeks ago)
- svn:sync-xref-src-repo-rev:
- 168323
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/testcase/tstPGMAllGst-armv8.cpp
r108857 r108873 30 30 * Header Files * 31 31 *********************************************************************************************************************************/ 32 #include "VMInternal.h" /* createFakeVM */ 32 #include "VMInternal.h" 33 #include <VBox/vmm/cpum.h> 34 #include "../include/CPUMInternal-armv8.h" 33 35 #include "../include/PGMInternal.h" 34 36 … … 42 44 #include <VBox/err.h> 43 45 #include <VBox/log.h> 46 #include <iprt/avl.h> 44 47 #include <iprt/assert.h> 45 48 #include <iprt/initterm.h> 49 #include <iprt/json.h> 46 50 #include <iprt/message.h> 47 51 #include <iprt/mem.h> … … 49 53 #include <iprt/thread.h> 50 54 #include <iprt/test.h> 55 #include <iprt/zero.h> 56 57 58 /********************************************************************************************************************************* 59 * Structures and Typedefs * 60 *********************************************************************************************************************************/ 61 62 /** 63 * Chunk of physical memory containing data. 64 */ 65 typedef struct TSTMEMCHUNK 66 { 67 /** AVL tree code. */ 68 /** @todo Too lazy to introduce support for a ranged RT_GCPHYS based AVL tree right now, so just use uint64_t. */ 69 AVLRU64NODECORE Core; 70 /** The memory - variable in size. */ 71 uint8_t abMem[1]; 72 } TSTMEMCHUNK; 73 /** Pointer to a physical memory chunk. */ 74 typedef TSTMEMCHUNK *PTSTMEMCHUNK; 75 /** Pointer to a const physical memory chunk. */ 76 typedef const TSTMEMCHUNK *PCTSTMEMCHUNK; 77 78 79 /** 80 * The current testcase data. 81 */ 82 typedef struct TSTPGMARMV8MMU 83 { 84 /** The address space layout. */ 85 AVLRU64TREE TreeMem; 86 /** The fake VM structure. */ 87 PVM pVM; 88 /** TTBR0 value. */ 89 uint64_t u64RegTtbr0; 90 /** TTBR1 value. */ 91 uint64_t u64RegTtbr1; 92 /** The current exception level. */ 93 uint8_t bEl; 94 } TSTPGMARMV8MMU; 95 typedef TSTPGMARMV8MMU *PTSTPGMARMV8MMU; 96 typedef const TSTPGMARMV8MMU *PCTSTPGMARMV8MMU; 51 97 52 98 … … 55 101 *********************************************************************************************************************************/ 56 102 static RTTEST g_hTest; 103 /** The currently executing testcase config. */ 104 static TSTPGMARMV8MMU g_MmuCfg; 105 106 107 static int pgmPhysGCPhys2CCPtr(RTGCPHYS GCPhys, void **ppv) 108 { 109 PCTSTMEMCHUNK pChunk = (PCTSTMEMCHUNK)RTAvlrU64RangeGet(&g_MmuCfg.TreeMem, GCPhys); 110 if (!pChunk) 111 { 112 *ppv = (void *)&g_abRTZero64K[0]; /* This ASSUMES that the page table walking code will never access beyond the end of this page. */ 113 return VINF_SUCCESS; 114 } 115 116 uint64_t const off = GCPhys - pChunk->Core.Key; 117 *ppv = (void *)&pChunk->abMem[off]; 118 return VINF_SUCCESS; 119 } 57 120 58 121 … … 60 123 { 61 124 RT_NOREF(pVCpu, GCPhys, ppv); 62 AssertFailed(); 63 return VINF_SUCCESS; 125 return pgmPhysGCPhys2CCPtr(GCPhys, ppv); 64 126 } 65 127 … … 68 130 { 69 131 RT_NOREF(pVM, GCPhys, pR3Ptr); 70 AssertFailed(); 71 return VINF_SUCCESS; 132 return pgmPhysGCPhys2CCPtr(GCPhys, (void **)pR3Ptr); 72 133 } 73 134 … … 76 137 { 77 138 RT_NOREF(pVCpu); 78 AssertFailed(); 79 return 0; 139 return g_MmuCfg.bEl; 80 140 } 81 141 … … 83 143 VMM_INT_DECL(RTGCPHYS) CPUMGetEffectiveTtbr(PVMCPUCC pVCpu, RTGCPTR GCPtr) 84 144 { 85 RT_NOREF(pVCpu, GCPtr); 86 AssertFailed(); 87 return 0; 145 RT_NOREF(pVCpu); 146 return (GCPtr & RT_BIT_64(55)) 147 ? ARMV8_TTBR_EL1_AARCH64_BADDR_GET(g_MmuCfg.u64RegTtbr1) 148 : ARMV8_TTBR_EL1_AARCH64_BADDR_GET(g_MmuCfg.u64RegTtbr0); 88 149 } 89 150 … … 97 158 * 98 159 * @returns 0 on success, 1 on failure. 99 * @param ppVM Where to store Pointer to the VM. 100 * 101 * @todo Move this to VMM/VM since it's stuff done by several testcases. 160 * @param pMmuCfg The MMU config to initialize. 102 161 */ 103 static int createFakeVM(PVM *ppVM)162 static int tstMmuCfgInit(PTSTPGMARMV8MMU pMmuCfg) 104 163 { 105 164 /* … … 134 193 135 194 pUVM->pVM = pVM; 136 *ppVM = pVM;195 pMmuCfg->pVM = pVM; 137 196 return VINF_SUCCESS; 138 197 } … … 143 202 RTTestIFailed("Fatal error: RTTlsSet failed, rc=%Rrc\n", rc); 144 203 145 *ppVM = NULL;146 204 return rc; 205 } 206 207 208 static DECLCALLBACK(int) tstZeroChunk(PAVLRU64NODECORE pCore, void *pvParam) 209 { 210 RT_NOREF(pvParam); 211 PTSTMEMCHUNK pChunk = (PTSTMEMCHUNK)pCore; 212 memset(&pChunk->abMem, 0, _64K); 213 return VINF_SUCCESS; 214 } 215 216 217 static void tstMmuCfgReset(PTSTPGMARMV8MMU pMmuCfg) 218 { 219 RTAvlrU64DoWithAll(&pMmuCfg->TreeMem, true /*fFromLeft*/, tstZeroChunk, NULL); 220 } 221 222 223 static DECLCALLBACK(int) tstDestroyChunk(PAVLRU64NODECORE pCore, void *pvParam) 224 { 225 RT_NOREF(pvParam); 226 RTMemPageFree(pCore, _64K); 227 return VINF_SUCCESS; 147 228 } 148 229 … … 152 233 * 153 234 * @param pVM Pointer to the VM. 154 *155 * @todo Move this to VMM/VM since it's stuff done by several testcases.156 235 */ 157 static void destroyFakeVM(PVM pVM) 158 { 159 RT_NOREF(pVM); 236 static void tstMmuCfgDestroy(PTSTPGMARMV8MMU pMmuCfg) 237 { 238 RTMemPageFree(pMmuCfg->pVM->pUVM, sizeof(*pMmuCfg->pVM->pUVM)); 239 RTMemPageFree(pMmuCfg->pVM, sizeof(VM) + sizeof(VMCPU)); 240 RTAvlrU64Destroy(&pMmuCfg->TreeMem, tstDestroyChunk, NULL); 160 241 } 161 242 … … 166 247 * Create an fake VM structure. 167 248 */ 168 PVM pVM; 169 int rc = createFakeVM(&pVM); 249 int rc = tstMmuCfgInit(&g_MmuCfg); 170 250 if (RT_FAILURE(rc)) 171 251 return; … … 173 253 /** @todo */ 174 254 175 destroyFakeVM(pVM); 176 } 255 tstMmuCfgDestroy(&g_MmuCfg); 256 } 257 258 259 static int tstTestcaseMmuMemoryWrite(RTTEST hTest, PTSTPGMARMV8MMU pMmuCfg, uint64_t GCPhysAddr, const void *pvData, size_t cbData) 260 { 261 size_t cbLeft = cbData; 262 const uint8_t *pbData = (const uint8_t *)pvData; 263 while (cbLeft) 264 { 265 PTSTMEMCHUNK pChunk = (PTSTMEMCHUNK)RTAvlrU64RangeGet(&pMmuCfg->TreeMem, GCPhysAddr); 266 if (!pChunk) 267 { 268 /* Allocate a new chunk (64KiB chunks). */ 269 pChunk = (PTSTMEMCHUNK)RTMemPageAllocZ(_64K); 270 if (!pChunk) 271 { 272 RTTestFailed(hTest, "Failed to allocate 64KiB of memory for memory chunk at %#RX64\n", GCPhysAddr); 273 return VERR_NO_MEMORY; 274 } 275 276 pChunk->Core.Key = GCPhysAddr & ~((uint64_t)_64K - 1); 277 pChunk->Core.KeyLast = pChunk->Core.Key + _64K - 1; 278 bool fInsert = RTAvlrU64Insert(&pMmuCfg->TreeMem, &pChunk->Core); 279 AssertRelease(fInsert); 280 } 281 282 uint64_t const off = GCPhysAddr - pChunk->Core.Key; 283 size_t const cbThisCopy = RT_MIN(cbLeft, pChunk->Core.KeyLast - off + 1); 284 memcpy(&pChunk->abMem[off], pbData, cbThisCopy); 285 cbLeft -= cbThisCopy; 286 GCPhysAddr += cbThisCopy; 287 pbData += cbThisCopy; 288 } 289 return VINF_SUCCESS; 290 } 291 292 293 static int tstTestcaseMmuMemoryAdd(RTTEST hTest, PTSTPGMARMV8MMU pMmuCfg, uint64_t GCPhysAddr, RTJSONVAL hMemObj) 294 { 295 int rc; 296 RTJSONVALTYPE enmType = RTJsonValueGetType(hMemObj); 297 switch (enmType) 298 { 299 case RTJSONVALTYPE_ARRAY: 300 { 301 RTJSONIT hIt = NIL_RTJSONIT; 302 rc = RTJsonIteratorBeginArray(hMemObj, &hIt); 303 if (RT_SUCCESS(rc)) 304 { 305 for (;;) 306 { 307 RTJSONVAL hData = NIL_RTJSONVAL; 308 rc = RTJsonIteratorQueryValue(hIt, &hData, NULL /*ppszName*/); 309 if (RT_SUCCESS(rc)) 310 { 311 if (RTJsonValueGetType(hData) == RTJSONVALTYPE_INTEGER) 312 { 313 int64_t i64Data = 0; 314 rc = RTJsonValueQueryInteger(hData, &i64Data); 315 if (RT_SUCCESS(rc)) 316 { 317 if (i64Data >= 0 && i64Data <= 255) 318 { 319 uint8_t bVal = (uint8_t)i64Data; 320 rc = tstTestcaseMmuMemoryWrite(hTest, pMmuCfg, GCPhysAddr, &bVal, sizeof(bVal)); 321 } 322 else 323 { 324 RTTestFailed(hTest, "Data %#RX64 for address %#RX64 is not a valid byte value", i64Data, GCPhysAddr); 325 break; 326 } 327 } 328 else 329 { 330 RTTestFailed(hTest, "Failed to query byte value for address %#RX64", GCPhysAddr); 331 break; 332 } 333 } 334 else 335 { 336 RTTestFailed(hTest, "Data for address %#RX64 contains an invalid value", GCPhysAddr); 337 break; 338 } 339 340 RTJsonValueRelease(hData); 341 } 342 else 343 RTTestFailed(hTest, "Failed to retrieve byte value with %Rrc", rc); 344 345 rc = RTJsonIteratorNext(hIt); 346 if (RT_FAILURE(rc)) 347 break; 348 349 GCPhysAddr++; 350 } 351 if (rc == VERR_JSON_ITERATOR_END) 352 rc = VINF_SUCCESS; 353 RTJsonIteratorFree(hIt); 354 } 355 else /* An empty array is also an error */ 356 RTTestFailed(hTest, "Failed to traverse JSON array with %Rrc", rc); 357 break; 358 } 359 case RTJSONVALTYPE_INTEGER: 360 { 361 uint64_t u64Val = 0; 362 rc = RTJsonValueQueryInteger(hMemObj, (int64_t *)&u64Val); 363 if (RT_SUCCESS(rc)) 364 rc = tstTestcaseMmuMemoryWrite(hTest, pMmuCfg, GCPhysAddr, &u64Val, sizeof(u64Val)); 365 else 366 RTTestFailed(hTest, "Querying data for address %#RX64 failed with %Rrc\n", GCPhysAddr, u64Val); 367 break; 368 } 369 default: 370 RTTestFailed(hTest, "Memory object has an invalid type %d\n", enmType); 371 rc = VERR_NOT_SUPPORTED; 372 } 373 374 return rc; 375 } 376 377 378 static int tstTestcaseAddressSpacePrepare(RTTEST hTest, RTJSONVAL hTestcase) 379 { 380 /* Prepare the memory space. */ 381 RTJSONVAL hVal = NIL_RTJSONVAL; 382 int rc = RTJsonValueQueryByName(hTestcase, "AddressSpace", &hVal); 383 if (RT_SUCCESS(rc)) 384 { 385 RTJSONIT hIt = NIL_RTJSONIT; 386 rc = RTJsonIteratorBeginObject(hVal, &hIt); 387 if (RT_SUCCESS(rc)) 388 { 389 for (;;) 390 { 391 RTJSONVAL hMemObj = NIL_RTJSONVAL; 392 const char *pszAddress = NULL; 393 rc = RTJsonIteratorQueryValue(hIt, &hMemObj, &pszAddress); 394 if (RT_SUCCESS(rc)) 395 { 396 uint64_t GCPhysAddr = 0; 397 rc = RTStrToUInt64Full(pszAddress, 0, &GCPhysAddr); 398 if (rc == VINF_SUCCESS) 399 rc = tstTestcaseMmuMemoryAdd(hTest, &g_MmuCfg, GCPhysAddr, hMemObj); 400 else 401 { 402 RTTestFailed(hTest, "Address '%s' is not a valid 64-bit physical address", pszAddress); 403 break; 404 } 405 406 RTJsonValueRelease(hMemObj); 407 } 408 else 409 RTTestFailed(hTest, "Failed to retrieve memory range with %Rrc", rc); 410 411 rc = RTJsonIteratorNext(hIt); 412 if (RT_FAILURE(rc)) 413 break; 414 } 415 if (rc == VERR_JSON_ITERATOR_END) 416 rc = VINF_SUCCESS; 417 RTJsonIteratorFree(hIt); 418 } 419 else 420 RTTestFailed(hTest, "Failed to traverse JSON object with %Rrc", rc); 421 422 RTJsonValueRelease(hVal); 423 } 424 else 425 RTTestFailed(hTest, "Failed to query \"AddressSpace\" containing the address space layout %Rrc", rc); 426 427 return rc; 428 } 429 430 431 static int tstTestcaseMmuConfigPrepare(RTTEST hTest, PTSTPGMARMV8MMU pMmuCfg, RTJSONVAL hTestcase) 432 { 433 PVMCPUCC pVCpu = pMmuCfg->pVM->apCpusR3[0]; 434 435 /* Set MMU config (SCTLR, TCR, TTBR, etc.). */ 436 int64_t i64Tmp = 0; 437 int rc = RTJsonValueQueryIntegerByName(hTestcase, "SCTLR_EL1", &i64Tmp); 438 if (RT_FAILURE(rc)) 439 { 440 RTTestFailed(hTest, "Failed to query \"SCTLR_EL1\" with %Rrc", rc); 441 return rc; 442 } 443 uint64_t const u64RegSctlrEl1 = (uint64_t)i64Tmp; 444 445 rc = RTJsonValueQueryIntegerByName(hTestcase, "TCR_EL1", &i64Tmp); 446 if (RT_FAILURE(rc)) 447 { 448 RTTestFailed(hTest, "Failed to query \"TCR_EL1\" with %Rrc", rc); 449 return rc; 450 } 451 uint64_t const u64RegTcrEl1 = (uint64_t)i64Tmp; 452 453 rc = RTJsonValueQueryIntegerByName(hTestcase, "TTBR0_EL1", &i64Tmp); 454 if (RT_FAILURE(rc)) 455 { 456 RTTestFailed(hTest, "Failed to query \"TTBR0_EL1\" with %Rrc", rc); 457 return rc; 458 } 459 pVCpu->cpum.s.Guest.Ttbr0.u64 = (uint64_t)i64Tmp; 460 461 rc = RTJsonValueQueryIntegerByName(hTestcase, "TTBR1_EL1", &i64Tmp); 462 if (RT_FAILURE(rc)) 463 { 464 RTTestFailed(hTest, "Failed to query \"TTBR1_EL1\" with %Rrc", rc); 465 return rc; 466 } 467 pVCpu->cpum.s.Guest.Ttbr1.u64 = (uint64_t)i64Tmp; 468 469 470 uintptr_t const idxNewGstTtbr0 = pgmR3DeduceTypeFromTcr<ARMV8_TCR_EL1_AARCH64_T0SZ_SHIFT, ARMV8_TCR_EL1_AARCH64_TG0_SHIFT, 471 ARMV8_TCR_EL1_AARCH64_TBI0_BIT, ARMV8_TCR_EL1_AARCH64_EPD0_BIT, false> 472 (u64RegSctlrEl1, u64RegTcrEl1, &pVCpu->pgm.s.afLookupMaskTtbr0[1]); 473 uintptr_t const idxNewGstTtbr1 = pgmR3DeduceTypeFromTcr<ARMV8_TCR_EL1_AARCH64_T1SZ_SHIFT, ARMV8_TCR_EL1_AARCH64_TG1_SHIFT, 474 ARMV8_TCR_EL1_AARCH64_TBI1_BIT, ARMV8_TCR_EL1_AARCH64_EPD1_BIT, true> 475 (u64RegSctlrEl1, u64RegTcrEl1, &pVCpu->pgm.s.afLookupMaskTtbr1[1]); 476 Assert(idxNewGstTtbr0 != 0 && idxNewGstTtbr1 != 0); 477 478 /* 479 * Change the paging mode data indexes. 480 */ 481 AssertReturn(idxNewGstTtbr0 < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE); 482 AssertReturn(g_aPgmGuestModeData[idxNewGstTtbr0].uType == idxNewGstTtbr0, VERR_PGM_MODE_IPE); 483 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnGetPage, VERR_PGM_MODE_IPE); 484 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnModifyPage, VERR_PGM_MODE_IPE); 485 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnExit, VERR_PGM_MODE_IPE); 486 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnEnter, VERR_PGM_MODE_IPE); 487 488 AssertReturn(idxNewGstTtbr1 < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE); 489 AssertReturn(g_aPgmGuestModeData[idxNewGstTtbr1].uType == idxNewGstTtbr1, VERR_PGM_MODE_IPE); 490 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnGetPage, VERR_PGM_MODE_IPE); 491 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnModifyPage, VERR_PGM_MODE_IPE); 492 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnExit, VERR_PGM_MODE_IPE); 493 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnEnter, VERR_PGM_MODE_IPE); 494 495 rc = g_aPgmGuestModeData[idxNewGstTtbr0].pfnEnter(pVCpu); 496 int rc2 = g_aPgmGuestModeData[idxNewGstTtbr1].pfnEnter(pVCpu); 497 498 /* status codes. */ 499 AssertRC(rc); 500 AssertRC(rc2); 501 if (RT_SUCCESS(rc)) 502 { 503 rc = rc2; 504 if (RT_SUCCESS(rc)) /* no informational status codes. */ 505 rc = VINF_SUCCESS; 506 } 507 508 pVCpu->pgm.s.aidxGuestModeDataTtbr0[1] = idxNewGstTtbr0; 509 pVCpu->pgm.s.aidxGuestModeDataTtbr1[1] = idxNewGstTtbr1; 510 511 /* Also set the value for EL0, saves us an if condition in the hot paths later on. */ 512 pVCpu->pgm.s.aidxGuestModeDataTtbr0[0] = idxNewGstTtbr0; 513 pVCpu->pgm.s.aidxGuestModeDataTtbr1[0] = idxNewGstTtbr1; 514 515 pVCpu->pgm.s.afLookupMaskTtbr0[0] = pVCpu->pgm.s.afLookupMaskTtbr0[1]; 516 pVCpu->pgm.s.afLookupMaskTtbr1[0] = pVCpu->pgm.s.afLookupMaskTtbr1[1]; 517 518 pVCpu->pgm.s.aenmGuestMode[1] = (u64RegSctlrEl1 & ARMV8_SCTLR_EL1_M) ? PGMMODE_VMSA_V8_64 : PGMMODE_NONE; 519 return rc; 520 } 521 522 523 static void tstExecute(RTTEST hTest, PVM pVM, RTGCPTR GCPtr, RTJSONVAL hMemResult) 524 { 525 PVMCPUCC pVCpu = pVM->apCpusR3[0]; 526 527 /** @todo Incorporate EL (for nested virt and EL3 later on). */ 528 uintptr_t idx = (GCPtr & RT_BIT_64(55)) 529 ? pVCpu->pgm.s.aidxGuestModeDataTtbr1[1] 530 : pVCpu->pgm.s.aidxGuestModeDataTtbr0[1]; 531 532 PGMPTWALK Walk; 533 AssertReleaseReturnVoid(idx < RT_ELEMENTS(g_aPgmGuestModeData)); 534 AssertReleaseReturnVoid(g_aPgmGuestModeData[idx].pfnGetPage); 535 int rc = g_aPgmGuestModeData[idx].pfnGetPage(pVCpu, GCPtr, &Walk); 536 if (RT_SUCCESS(rc)) 537 { 538 RT_NOREF(hMemResult); 539 } 540 else 541 RTTestFailed(hTest, "Resolving virtual address %#RX64 to physical address failed with %Rrc", GCPtr, rc); 542 } 543 544 545 static int tstTestcaseMmuRun(RTTEST hTest, RTJSONVAL hTestcase) 546 { 547 RTJSONVAL hVal = NIL_RTJSONVAL; 548 int rc = RTJsonValueQueryByName(hTestcase, "Tests", &hVal); 549 if (RT_SUCCESS(rc)) 550 { 551 RTJSONIT hIt = NIL_RTJSONIT; 552 rc = RTJsonIteratorBeginObject(hVal, &hIt); 553 if (RT_SUCCESS(rc)) 554 { 555 for (;;) 556 { 557 RTJSONVAL hMemObj = NIL_RTJSONVAL; 558 const char *pszAddress = NULL; 559 rc = RTJsonIteratorQueryValue(hIt, &hMemObj, &pszAddress); 560 if (RT_SUCCESS(rc)) 561 { 562 uint64_t GCPtr = 0; 563 rc = RTStrToUInt64Full(pszAddress, 0, &GCPtr); 564 if (rc == VINF_SUCCESS) 565 tstExecute(hTest, g_MmuCfg.pVM, GCPtr, hMemObj); 566 else 567 { 568 RTTestFailed(hTest, "Address '%s' is not a valid 64-bit physical address", pszAddress); 569 break; 570 } 571 572 RTJsonValueRelease(hMemObj); 573 } 574 else 575 RTTestFailed(hTest, "Failed to retrieve memory range with %Rrc", rc); 576 577 rc = RTJsonIteratorNext(hIt); 578 if (RT_FAILURE(rc)) 579 break; 580 } 581 if (rc == VERR_JSON_ITERATOR_END) 582 rc = VINF_SUCCESS; 583 RTJsonIteratorFree(hIt); 584 } 585 else 586 RTTestFailed(hTest, "Failed to traverse JSON array with %Rrc", rc); 587 588 589 RTJsonValueRelease(hVal); 590 } 591 else 592 RTTestFailed(hTest, "Failed to query \"Tests\" %Rrc", rc); 593 594 return rc; 595 } 596 597 598 static void tstExecuteTestcase(RTTEST hTest, RTJSONVAL hTestcase) 599 { 600 RTJSONVAL hVal = NIL_RTJSONVAL; 601 int rc = RTJsonValueQueryByName(hTestcase, "Name", &hVal); 602 if (RT_SUCCESS(rc)) 603 { 604 const char *pszTestcaseName = RTJsonValueGetString(hVal); 605 if (pszTestcaseName) 606 { 607 RTTestSub(hTest, pszTestcaseName); 608 609 /* Reset the config for each testcase. */ 610 tstMmuCfgReset(&g_MmuCfg); 611 612 rc = tstTestcaseAddressSpacePrepare(hTest, hTestcase); 613 if (RT_SUCCESS(rc)) 614 rc = tstTestcaseMmuConfigPrepare(hTest, &g_MmuCfg, hTestcase); 615 if (RT_SUCCESS(rc)) 616 rc = tstTestcaseMmuRun(hTest, hTestcase); 617 } 618 else 619 RTTestFailed(hTest, "The testcase name is not a string"); 620 RTJsonValueRelease(hVal); 621 } 622 else 623 RTTestFailed(hTest, "Failed to query the testcase name with %Rrc", rc); 624 } 625 626 627 static void tstLoadFromFile(RTTEST hTest, const char *pszFilename) 628 { 629 int rc = tstMmuCfgInit(&g_MmuCfg); 630 if (RT_FAILURE(rc)) 631 { 632 RTTestFailed(hTest, "Failed to initialize MMU config %Rrc", rc); 633 return; 634 } 635 636 /* Load the configuration from the JSON config file. */ 637 RTERRINFOSTATIC ErrInfo; 638 RTJSONVAL hRoot = NIL_RTJSONVAL; 639 rc = RTJsonParseFromFile(&hRoot, RTJSON_PARSE_F_JSON5, pszFilename, RTErrInfoInitStatic(&ErrInfo)); 640 if (RT_SUCCESS(rc)) 641 { 642 RTJSONVALTYPE enmType = RTJsonValueGetType(hRoot); 643 if (enmType == RTJSONVALTYPE_ARRAY) 644 { 645 /* Array of testcases. */ 646 RTJSONIT hIt = NIL_RTJSONIT; 647 rc = RTJsonIteratorBeginArray(hRoot, &hIt); 648 if (RT_SUCCESS(rc)) 649 { 650 for (;;) 651 { 652 RTJSONVAL hTestcase = NIL_RTJSONVAL; 653 rc = RTJsonIteratorQueryValue(hIt, &hTestcase, NULL /*ppszName*/); 654 if (RT_SUCCESS(rc)) 655 { 656 tstExecuteTestcase(hTest, hTestcase); 657 RTJsonValueRelease(hTestcase); 658 } 659 else 660 RTTestFailed(hTest, "Failed to retrieve testcase with %Rrc", rc); 661 662 rc = RTJsonIteratorNext(hIt); 663 if (RT_FAILURE(rc)) 664 break; 665 } 666 if (rc == VERR_JSON_ITERATOR_END) 667 rc = VINF_SUCCESS; 668 RTJsonIteratorFree(hIt); 669 } 670 else /* An empty array is also an error */ 671 RTTestFailed(hTest, "Failed to traverse JSON array with %Rrc", rc); 672 } 673 else if (enmType == RTJSONVALTYPE_OBJECT) 674 { 675 /* Single testcase. */ 676 tstExecuteTestcase(hTest, hRoot); 677 } 678 else 679 RTTestFailed(hTest, "JSON root is not an array or object containing a testcase"); 680 RTJsonValueRelease(hRoot); 681 } 682 else 683 { 684 if (RTErrInfoIsSet(&ErrInfo.Core)) 685 RTTestFailed(hTest, "RTJsonParseFromFile() for \"%s\" failed with %Rrc\n%s", 686 pszFilename, rc, ErrInfo.Core.pszMsg); 687 else 688 RTTestFailed(hTest, "RTJsonParseFromFile() for \"%s\" failed with %Rrc", 689 pszFilename, rc); 690 } 691 692 tstMmuCfgDestroy(&g_MmuCfg); 693 } 694 177 695 178 696 int main(int argc, char **argv) … … 189 707 { 190 708 RTTestBanner(g_hTest); 191 tstBasic(); 709 if (argc == 2) 710 tstLoadFromFile(g_hTest, argv[1]); 711 else 712 tstBasic(); 192 713 rcExit = RTTestSummaryAndDestroy(g_hTest); 193 714 }
Note:
See TracChangeset
for help on using the changeset viewer.