VirtualBox

source: vbox/trunk/src/VBox/VMM/testcase/tstPGMAllGst-armv8.cpp@ 108886

Last change on this file since 108886 was 108886, checked in by vboxsync, 4 weeks ago

VMM/testcase/tstPGMAllGst-armv8: Updates to the testcase, add support for naming and setting individual bitfields for registers, bugref:10388

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.3 KB
Line 
1/* $Id: tstPGMAllGst-armv8.cpp 108886 2025-04-08 11:59:40Z vboxsync $ */
2/** @file
3 * PGM page table walking testcase - ARMv8 variant.
4 */
5
6/*
7 * Copyright (C) 2025 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "VMInternal.h"
33#include <VBox/vmm/cpum.h>
34#include "../include/CPUMInternal-armv8.h"
35#include "../include/PGMInternal.h"
36
37#include <VBox/vmm/vm.h>
38#include <VBox/vmm/uvm.h>
39#include <VBox/vmm/vmm.h>
40#include <VBox/vmm/pgm.h>
41#include <VBox/vmm/mm.h>
42#include <VBox/vmm/stam.h>
43
44#include <VBox/err.h>
45#include <VBox/log.h>
46#include <iprt/avl.h>
47#include <iprt/assert.h>
48#include <iprt/initterm.h>
49#include <iprt/json.h>
50#include <iprt/message.h>
51#include <iprt/mem.h>
52#include <iprt/string.h>
53#include <iprt/thread.h>
54#include <iprt/test.h>
55#include <iprt/zero.h>
56
57#include "tstPGMAllGst-armv8-tests.h"
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63
64/**
65 * Named value.
66 */
67typedef struct TSTCFGNAMEDVALUE
68{
69 /** The name of the value. */
70 const char *pszName;
71 /** The integer value. */
72 uint64_t u64Val;
73} TSTCFGNAMEDVALUE;
74typedef TSTCFGNAMEDVALUE *PTSTCFGNAMEDVALUE;
75typedef const TSTCFGNAMEDVALUE *PCTSTCFGNAMEDVALUE;
76
77
78/**
79 * A config bitfield.
80 */
81typedef struct TSTCFGBITFIELD
82{
83 /** The bitfield name. */
84 const char *pszName;
85 /** The bitfield offset. */
86 uint8_t offBitfield;
87 /** Number of bits for the bitfield. */
88 uint8_t cBits;
89 /** Optional array of named values. */
90 PCTSTCFGNAMEDVALUE paNamedValues;
91} TSTCFGBITFIELD;
92typedef TSTCFGBITFIELD *PTSTCFGBITFIELD;
93typedef const TSTCFGBITFIELD *PCTSTCFGBITFIELD;
94
95
96/**
97 * Chunk of physical memory containing data.
98 */
99typedef struct TSTMEMCHUNK
100{
101 /** AVL tree code. */
102 /** @todo Too lazy to introduce support for a ranged RT_GCPHYS based AVL tree right now, so just use uint64_t. */
103 AVLRU64NODECORE Core;
104 /** The memory - variable in size. */
105 uint8_t abMem[1];
106} TSTMEMCHUNK;
107/** Pointer to a physical memory chunk. */
108typedef TSTMEMCHUNK *PTSTMEMCHUNK;
109/** Pointer to a const physical memory chunk. */
110typedef const TSTMEMCHUNK *PCTSTMEMCHUNK;
111
112
113/**
114 * The current testcase data.
115 */
116typedef struct TSTPGMARMV8MMU
117{
118 /** The address space layout. */
119 AVLRU64TREE TreeMem;
120 /** The fake VM structure. */
121 PVM pVM;
122 /** TTBR0 value. */
123 uint64_t u64RegTtbr0;
124 /** TTBR1 value. */
125 uint64_t u64RegTtbr1;
126 /** The current exception level. */
127 uint8_t bEl;
128} TSTPGMARMV8MMU;
129typedef TSTPGMARMV8MMU *PTSTPGMARMV8MMU;
130typedef const TSTPGMARMV8MMU *PCTSTPGMARMV8MMU;
131
132
133/*********************************************************************************************************************************
134* Global Variables *
135*********************************************************************************************************************************/
136static RTTEST g_hTest;
137/** The currently executing testcase config. */
138static TSTPGMARMV8MMU g_MmuCfg;
139
140
141static int pgmPhysGCPhys2CCPtr(RTGCPHYS GCPhys, void **ppv)
142{
143 PCTSTMEMCHUNK pChunk = (PCTSTMEMCHUNK)RTAvlrU64RangeGet(&g_MmuCfg.TreeMem, GCPhys);
144 if (!pChunk)
145 {
146 *ppv = (void *)&g_abRTZero64K[0]; /* This ASSUMES that the page table walking code will never access beyond the end of this page. */
147 return VINF_SUCCESS;
148 }
149
150 uint64_t const off = GCPhys - pChunk->Core.Key;
151 *ppv = (void *)&pChunk->abMem[off];
152 return VINF_SUCCESS;
153}
154
155
156int pgmPhysGCPhys2CCPtrLockless(PVMCPUCC pVCpu, RTGCPHYS GCPhys, void **ppv)
157{
158 RT_NOREF(pVCpu, GCPhys, ppv);
159 return pgmPhysGCPhys2CCPtr(GCPhys, ppv);
160}
161
162
163int pgmPhysGCPhys2R3Ptr(PVMCC pVM, RTGCPHYS GCPhys, PRTR3PTR pR3Ptr)
164{
165 RT_NOREF(pVM, GCPhys, pR3Ptr);
166 return pgmPhysGCPhys2CCPtr(GCPhys, (void **)pR3Ptr);
167}
168
169
170VMM_INT_DECL(uint8_t) CPUMGetGuestEL(PVMCPUCC pVCpu)
171{
172 RT_NOREF(pVCpu);
173 return g_MmuCfg.bEl;
174}
175
176
177VMM_INT_DECL(RTGCPHYS) CPUMGetEffectiveTtbr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
178{
179 RT_NOREF(pVCpu);
180 return (GCPtr & RT_BIT_64(55))
181 ? ARMV8_TTBR_EL1_AARCH64_BADDR_GET(g_MmuCfg.u64RegTtbr1)
182 : ARMV8_TTBR_EL1_AARCH64_BADDR_GET(g_MmuCfg.u64RegTtbr0);
183}
184
185
186/** Include and instantiate the page table walking code. */
187#include "../VMMAll/PGMAllGst-armv8.cpp.h"
188
189
190/**
191 * Creates a mockup VM structure for testing SSM.
192 *
193 * @returns 0 on success, 1 on failure.
194 * @param pMmuCfg The MMU config to initialize.
195 */
196static int tstMmuCfgInit(PTSTPGMARMV8MMU pMmuCfg)
197{
198 /*
199 * Allocate and init the UVM structure.
200 */
201 PUVM pUVM = (PUVM)RTMemPageAllocZ(sizeof(*pUVM));
202 AssertReturn(pUVM, 1);
203 pUVM->u32Magic = UVM_MAGIC;
204 pUVM->vm.s.idxTLS = RTTlsAlloc();
205 int rc = RTTlsSet(pUVM->vm.s.idxTLS, &pUVM->aCpus[0]);
206 if (RT_SUCCESS(rc))
207 {
208 pUVM->aCpus[0].pUVM = pUVM;
209 pUVM->aCpus[0].vm.s.NativeThreadEMT = RTThreadNativeSelf();
210
211 /*
212 * Allocate and init the VM structure.
213 */
214 PVM pVM = (PVM)RTMemPageAllocZ(sizeof(VM) + sizeof(VMCPU));
215 rc = pVM ? VINF_SUCCESS : VERR_NO_PAGE_MEMORY;
216 if (RT_SUCCESS(rc))
217 {
218 pVM->enmVMState = VMSTATE_CREATED;
219 pVM->pVMR3 = pVM;
220 pVM->pUVM = pUVM;
221 pVM->cCpus = 1;
222
223 PVMCPU pVCpu = (PVMCPU)(pVM + 1);
224 pVCpu->pVMR3 = pVM;
225 pVCpu->hNativeThread = RTThreadNativeSelf();
226 pVM->apCpusR3[0] = pVCpu;
227
228 pUVM->pVM = pVM;
229 pMmuCfg->pVM = pVM;
230 return VINF_SUCCESS;
231 }
232
233 RTTestIFailed("Fatal error: failed to allocated pages for the VM structure, rc=%Rrc\n", rc);
234 }
235 else
236 RTTestIFailed("Fatal error: RTTlsSet failed, rc=%Rrc\n", rc);
237
238 return rc;
239}
240
241
242static int tstMmuCfgReadBitfieldU64(RTTEST hTest, RTJSONVAL hObj, PCTSTCFGBITFIELD paBitfields, uint64_t *pu64Result)
243{
244 uint64_t u64 = 0;
245
246 uint32_t idx = 0;
247 while (paBitfields[idx].pszName)
248 {
249 RTJSONVAL hValue = NIL_RTJSONVAL;
250 int rc = RTJsonValueQueryByName(hObj, paBitfields[idx].pszName, &hValue);
251 if (rc == VERR_NOT_FOUND)
252 {
253 idx++;
254 continue;
255 }
256 if (RT_FAILURE(rc))
257 {
258 RTTestFailed(hTest, "Failed to query \"%s\" with %Rrc", paBitfields[idx].pszName, rc);
259 return rc;
260 }
261
262 RTJSONVALTYPE enmType = RTJsonValueGetType(hValue);
263 switch (enmType)
264 {
265 case RTJSONVALTYPE_INTEGER:
266 {
267 int64_t i64Tmp = 0;
268 rc = RTJsonValueQueryInteger(hValue, &i64Tmp);
269 if (RT_FAILURE(rc))
270 {
271 RTTestFailed(hTest, "Failed to query \"%s\" as an integer with %Rrc", paBitfields[idx].pszName, rc);
272 break;
273 }
274 else if ( i64Tmp < 0
275 || (uint64_t)i64Tmp > (RT_BIT_64(paBitfields[idx].cBits) - 1))
276 {
277 RTTestFailed(hTest, "Value of \"%s\" is out of bounds, got %#RX64, maximum is %#RX64",
278 paBitfields[idx].pszName, (uint64_t)i64Tmp, (RT_BIT_64(paBitfields[idx].cBits) - 1));
279 rc = VERR_INVALID_PARAMETER;
280 }
281 else
282 u64 |= ((uint64_t)i64Tmp) << paBitfields[idx].offBitfield;
283 break;
284 }
285 case RTJSONVALTYPE_STRING:
286 {
287 if (paBitfields[idx].paNamedValues)
288 {
289 const char *pszNamedValue = RTJsonValueGetString(hValue);
290 PCTSTCFGNAMEDVALUE pNamedValue = &paBitfields[idx].paNamedValues[0];
291 while (pNamedValue->pszName)
292 {
293 if (!RTStrICmp(pszNamedValue, pNamedValue->pszName))
294 {
295 u64 |= pNamedValue->u64Val << paBitfields[idx].offBitfield;
296 break;
297 }
298 pNamedValue++;
299 }
300 if (!pNamedValue->pszName)
301 {
302 RTTestFailed(hTest, "\"%s\" ist not a known named value for bitfield '%s'", pszNamedValue, paBitfields[idx].pszName);
303 rc = VERR_NOT_FOUND;
304 }
305 }
306 else
307 {
308 RTTestFailed(hTest, "Bitfield \"%s\" doesn't support named values", paBitfields[idx].pszName);
309 rc = VERR_NOT_SUPPORTED;
310 }
311 break;
312 }
313 default:
314 rc = VERR_NOT_SUPPORTED;
315 RTTestFailed(hTest, "JSON value type %d is not supported\n", enmType);
316 break;
317 }
318 RTJsonValueRelease(hValue);
319
320 if (RT_FAILURE(rc))
321 return rc;
322
323 idx++;
324 }
325
326 *pu64Result = u64;
327 return VINF_SUCCESS;
328}
329
330
331static int tstMmuCfgReadU64(RTTEST hTest, RTJSONVAL hObj, const char *pszName, PCTSTCFGBITFIELD paBitfields, uint64_t *pu64Result)
332{
333 RTJSONVAL hValue = NIL_RTJSONVAL;
334 int rc = RTJsonValueQueryByName(hObj, pszName, &hValue);
335 if (RT_FAILURE(rc))
336 {
337 RTTestFailed(hTest, "Failed to query \"%s\" with %Rrc", pszName, rc);
338 return rc;
339 }
340
341 RTJSONVALTYPE enmType = RTJsonValueGetType(hValue);
342 switch (enmType)
343 {
344 case RTJSONVALTYPE_INTEGER:
345 rc = RTJsonValueQueryInteger(hValue, (int64_t *)pu64Result);
346 break;
347 case RTJSONVALTYPE_OBJECT:
348 rc = tstMmuCfgReadBitfieldU64(hTest, hValue, paBitfields, pu64Result);
349 break;
350 default:
351 rc = VERR_NOT_SUPPORTED;
352 RTTestFailed(hTest, "JSON value type %d is not supported\n", enmType);
353 break;
354 }
355
356 RTJsonValueRelease(hValue);
357 return rc;
358}
359
360
361static DECLCALLBACK(int) tstZeroChunk(PAVLRU64NODECORE pCore, void *pvParam)
362{
363 RT_NOREF(pvParam);
364 PTSTMEMCHUNK pChunk = (PTSTMEMCHUNK)pCore;
365 memset(&pChunk->abMem, 0, _64K);
366 return VINF_SUCCESS;
367}
368
369
370static void tstMmuCfgReset(PTSTPGMARMV8MMU pMmuCfg)
371{
372 RTAvlrU64DoWithAll(&pMmuCfg->TreeMem, true /*fFromLeft*/, tstZeroChunk, NULL);
373}
374
375
376static DECLCALLBACK(int) tstDestroyChunk(PAVLRU64NODECORE pCore, void *pvParam)
377{
378 RT_NOREF(pvParam);
379 RTMemPageFree(pCore, _64K);
380 return VINF_SUCCESS;
381}
382
383
384static void tstMmuCfgDestroy(PTSTPGMARMV8MMU pMmuCfg)
385{
386 RTMemPageFree(pMmuCfg->pVM->pUVM, sizeof(*pMmuCfg->pVM->pUVM));
387 RTMemPageFree(pMmuCfg->pVM, sizeof(VM) + sizeof(VMCPU));
388 RTAvlrU64Destroy(&pMmuCfg->TreeMem, tstDestroyChunk, NULL);
389}
390
391
392static int tstTestcaseMmuMemoryWrite(RTTEST hTest, PTSTPGMARMV8MMU pMmuCfg, uint64_t GCPhysAddr, const void *pvData, size_t cbData)
393{
394 size_t cbLeft = cbData;
395 const uint8_t *pbData = (const uint8_t *)pvData;
396 while (cbLeft)
397 {
398 PTSTMEMCHUNK pChunk = (PTSTMEMCHUNK)RTAvlrU64RangeGet(&pMmuCfg->TreeMem, GCPhysAddr);
399 if (!pChunk)
400 {
401 /* Allocate a new chunk (64KiB chunks). */
402 pChunk = (PTSTMEMCHUNK)RTMemPageAllocZ(_64K);
403 if (!pChunk)
404 {
405 RTTestFailed(hTest, "Failed to allocate 64KiB of memory for memory chunk at %#RX64\n", GCPhysAddr);
406 return VERR_NO_MEMORY;
407 }
408
409 pChunk->Core.Key = GCPhysAddr & ~((uint64_t)_64K - 1);
410 pChunk->Core.KeyLast = pChunk->Core.Key + _64K - 1;
411 bool fInsert = RTAvlrU64Insert(&pMmuCfg->TreeMem, &pChunk->Core);
412 AssertRelease(fInsert);
413 }
414
415 uint64_t const off = GCPhysAddr - pChunk->Core.Key;
416 size_t const cbThisCopy = RT_MIN(cbLeft, pChunk->Core.KeyLast - off + 1);
417 memcpy(&pChunk->abMem[off], pbData, cbThisCopy);
418 cbLeft -= cbThisCopy;
419 GCPhysAddr += cbThisCopy;
420 pbData += cbThisCopy;
421 }
422 return VINF_SUCCESS;
423}
424
425
426static int tstTestcaseMmuMemoryAdd(RTTEST hTest, PTSTPGMARMV8MMU pMmuCfg, uint64_t GCPhysAddr, RTJSONVAL hMemObj)
427{
428 int rc;
429 RTJSONVALTYPE enmType = RTJsonValueGetType(hMemObj);
430 switch (enmType)
431 {
432 case RTJSONVALTYPE_ARRAY:
433 {
434 RTJSONIT hIt = NIL_RTJSONIT;
435 rc = RTJsonIteratorBeginArray(hMemObj, &hIt);
436 if (RT_SUCCESS(rc))
437 {
438 for (;;)
439 {
440 RTJSONVAL hData = NIL_RTJSONVAL;
441 rc = RTJsonIteratorQueryValue(hIt, &hData, NULL /*ppszName*/);
442 if (RT_SUCCESS(rc))
443 {
444 if (RTJsonValueGetType(hData) == RTJSONVALTYPE_INTEGER)
445 {
446 int64_t i64Data = 0;
447 rc = RTJsonValueQueryInteger(hData, &i64Data);
448 if (RT_SUCCESS(rc))
449 {
450 if (i64Data >= 0 && i64Data <= 255)
451 {
452 uint8_t bVal = (uint8_t)i64Data;
453 rc = tstTestcaseMmuMemoryWrite(hTest, pMmuCfg, GCPhysAddr, &bVal, sizeof(bVal));
454 }
455 else
456 {
457 RTTestFailed(hTest, "Data %#RX64 for address %#RX64 is not a valid byte value", i64Data, GCPhysAddr);
458 break;
459 }
460 }
461 else
462 {
463 RTTestFailed(hTest, "Failed to query byte value for address %#RX64", GCPhysAddr);
464 break;
465 }
466 }
467 else
468 {
469 RTTestFailed(hTest, "Data for address %#RX64 contains an invalid value", GCPhysAddr);
470 break;
471 }
472
473 RTJsonValueRelease(hData);
474 }
475 else
476 RTTestFailed(hTest, "Failed to retrieve byte value with %Rrc", rc);
477
478 rc = RTJsonIteratorNext(hIt);
479 if (RT_FAILURE(rc))
480 break;
481
482 GCPhysAddr++;
483 }
484 if (rc == VERR_JSON_ITERATOR_END)
485 rc = VINF_SUCCESS;
486 RTJsonIteratorFree(hIt);
487 }
488 else /* An empty array is also an error */
489 RTTestFailed(hTest, "Failed to traverse JSON array with %Rrc", rc);
490 break;
491 }
492 case RTJSONVALTYPE_INTEGER:
493 {
494 uint64_t u64Val = 0;
495 rc = RTJsonValueQueryInteger(hMemObj, (int64_t *)&u64Val);
496 if (RT_SUCCESS(rc))
497 rc = tstTestcaseMmuMemoryWrite(hTest, pMmuCfg, GCPhysAddr, &u64Val, sizeof(u64Val));
498 else
499 RTTestFailed(hTest, "Querying data for address %#RX64 failed with %Rrc\n", GCPhysAddr, u64Val);
500 break;
501 }
502 default:
503 RTTestFailed(hTest, "Memory object has an invalid type %d\n", enmType);
504 rc = VERR_NOT_SUPPORTED;
505 }
506
507 return rc;
508}
509
510
511static int tstTestcaseAddressSpacePrepare(RTTEST hTest, RTJSONVAL hTestcase)
512{
513 /* Prepare the memory space. */
514 RTJSONVAL hVal = NIL_RTJSONVAL;
515 int rc = RTJsonValueQueryByName(hTestcase, "AddressSpace", &hVal);
516 if (RT_SUCCESS(rc))
517 {
518 RTJSONIT hIt = NIL_RTJSONIT;
519 rc = RTJsonIteratorBeginObject(hVal, &hIt);
520 if (RT_SUCCESS(rc))
521 {
522 for (;;)
523 {
524 RTJSONVAL hMemObj = NIL_RTJSONVAL;
525 const char *pszAddress = NULL;
526 rc = RTJsonIteratorQueryValue(hIt, &hMemObj, &pszAddress);
527 if (RT_SUCCESS(rc))
528 {
529 uint64_t GCPhysAddr = 0;
530 rc = RTStrToUInt64Full(pszAddress, 0, &GCPhysAddr);
531 if (rc == VINF_SUCCESS)
532 rc = tstTestcaseMmuMemoryAdd(hTest, &g_MmuCfg, GCPhysAddr, hMemObj);
533 else
534 {
535 RTTestFailed(hTest, "Address '%s' is not a valid 64-bit physical address", pszAddress);
536 break;
537 }
538
539 RTJsonValueRelease(hMemObj);
540 }
541 else
542 RTTestFailed(hTest, "Failed to retrieve memory range with %Rrc", rc);
543
544 rc = RTJsonIteratorNext(hIt);
545 if (RT_FAILURE(rc))
546 break;
547 }
548 if (rc == VERR_JSON_ITERATOR_END)
549 rc = VINF_SUCCESS;
550 RTJsonIteratorFree(hIt);
551 }
552 else if (rc == VERR_JSON_IS_EMPTY) /* Empty address space is valid. */
553 rc = VINF_SUCCESS;
554 else
555 RTTestFailed(hTest, "Failed to traverse JSON object with %Rrc", rc);
556
557 RTJsonValueRelease(hVal);
558 }
559 else
560 RTTestFailed(hTest, "Failed to query \"AddressSpace\" containing the address space layout %Rrc", rc);
561
562 return rc;
563}
564
565
566static int tstTestcaseMmuConfigPrepare(RTTEST hTest, PTSTPGMARMV8MMU pMmuCfg, RTJSONVAL hTestcase)
567{
568 PVMCPUCC pVCpu = pMmuCfg->pVM->apCpusR3[0];
569
570 /* Set MMU config (SCTLR, TCR, TTBR, etc.). */
571 uint64_t u64RegSctlrEl1 = 0;
572 int rc = tstMmuCfgReadU64(hTest, hTestcase, "SCTLR_EL1", NULL, &u64RegSctlrEl1);
573 if (RT_FAILURE(rc))
574 return rc;
575
576 uint64_t u64RegTcrEl1 = 0;
577 static const TSTCFGNAMEDVALUE s_aTgSizes[] =
578 {
579 { "4K", 0 },
580 { "64K", 1 },
581 { "16K", 2 },
582 { NULL, 0 }
583 };
584 static const TSTCFGNAMEDVALUE s_aIpsSizes[] =
585 {
586 { "4G", 0 },
587 { "64G", 1 },
588 { "1T", 2 },
589 { "4T", 3 },
590 { "16T", 4 },
591 { "256T", 5 },
592 { "4P", 6 },
593 { "64P", 7 },
594
595 { NULL, 0 }
596 };
597 static const TSTCFGBITFIELD s_aTcrEl1Bitfields[] =
598 {
599#define BITFIELD_CREATE_BOOL(a_Name, a_offBit) \
600 { a_Name, a_offBit, 1, NULL }
601
602 BITFIELD_CREATE_BOOL("MTX1", 61),
603 BITFIELD_CREATE_BOOL("MTX0", 60),
604 BITFIELD_CREATE_BOOL("DS", 59),
605 BITFIELD_CREATE_BOOL("TCMA1", 58),
606 BITFIELD_CREATE_BOOL("TCMA0", 57),
607 BITFIELD_CREATE_BOOL("E0PD1", 56),
608 BITFIELD_CREATE_BOOL("E0PD0", 55),
609 BITFIELD_CREATE_BOOL("NFD1", 54),
610 BITFIELD_CREATE_BOOL("NFD0", 53),
611 BITFIELD_CREATE_BOOL("TBID1", 52),
612 BITFIELD_CREATE_BOOL("TBID0", 51),
613 BITFIELD_CREATE_BOOL("HWU162", 50),
614 BITFIELD_CREATE_BOOL("HWU161", 49),
615 BITFIELD_CREATE_BOOL("HWU160", 48),
616 BITFIELD_CREATE_BOOL("HWU159", 47),
617 BITFIELD_CREATE_BOOL("HWU062", 46),
618 BITFIELD_CREATE_BOOL("HWU061", 45),
619 BITFIELD_CREATE_BOOL("HWU060", 44),
620 BITFIELD_CREATE_BOOL("HWU059", 43),
621 BITFIELD_CREATE_BOOL("HPD1", 42),
622 BITFIELD_CREATE_BOOL("HPD0", 41),
623 BITFIELD_CREATE_BOOL("HD", 40),
624 BITFIELD_CREATE_BOOL("HA", 39),
625 BITFIELD_CREATE_BOOL("TBI1", 38),
626 BITFIELD_CREATE_BOOL("TBI0", 37),
627 { "IPS", 32, 3, &s_aIpsSizes[0] },
628 { "TG1", 30, 2, &s_aTgSizes[0] },
629 { "SH1", 28, 2, NULL },
630 { "ORGN1", 26, 2, NULL },
631 { "IRGN1", 24, 2, NULL },
632 BITFIELD_CREATE_BOOL("EPD1", 33),
633 BITFIELD_CREATE_BOOL("A1", 22),
634 { "T1SZ", 16, 6, NULL },
635
636 { "TG0", 14, 2, &s_aTgSizes[0] },
637 { "SH0", 12, 2, NULL },
638 { "ORGN0", 10, 2, NULL },
639 { "IRGN0", 8, 2, NULL },
640 BITFIELD_CREATE_BOOL("EPD0", 7),
641 { "T0SZ", 0, 6, NULL },
642 { NULL, 0, 0, NULL }
643
644#undef BITFIELD_CREATE_BOOL
645 };
646 rc = tstMmuCfgReadU64(hTest, hTestcase, "TCR_EL1", &s_aTcrEl1Bitfields[0], &u64RegTcrEl1);
647 if (RT_FAILURE(rc))
648 return rc;
649
650 rc = tstMmuCfgReadU64(hTest, hTestcase, "TTBR0_EL1", NULL, &pVCpu->cpum.s.Guest.Ttbr0.u64);
651 if (RT_FAILURE(rc))
652 return rc;
653
654 rc = tstMmuCfgReadU64(hTest, hTestcase, "TTBR1_EL1", NULL, &pVCpu->cpum.s.Guest.Ttbr1.u64);
655 if (RT_FAILURE(rc))
656 return rc;
657
658 uintptr_t const idxNewGstTtbr0 = pgmR3DeduceTypeFromTcr<ARMV8_TCR_EL1_AARCH64_T0SZ_SHIFT, ARMV8_TCR_EL1_AARCH64_TG0_SHIFT,
659 ARMV8_TCR_EL1_AARCH64_TBI0_BIT, ARMV8_TCR_EL1_AARCH64_EPD0_BIT, false>
660 (u64RegSctlrEl1, u64RegTcrEl1, &pVCpu->pgm.s.afLookupMaskTtbr0[1]);
661 uintptr_t const idxNewGstTtbr1 = pgmR3DeduceTypeFromTcr<ARMV8_TCR_EL1_AARCH64_T1SZ_SHIFT, ARMV8_TCR_EL1_AARCH64_TG1_SHIFT,
662 ARMV8_TCR_EL1_AARCH64_TBI1_BIT, ARMV8_TCR_EL1_AARCH64_EPD1_BIT, true>
663 (u64RegSctlrEl1, u64RegTcrEl1, &pVCpu->pgm.s.afLookupMaskTtbr1[1]);
664 Assert(idxNewGstTtbr0 != 0 && idxNewGstTtbr1 != 0);
665
666 /*
667 * Change the paging mode data indexes.
668 */
669 AssertReturn(idxNewGstTtbr0 < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE);
670 AssertReturn(g_aPgmGuestModeData[idxNewGstTtbr0].uType == idxNewGstTtbr0, VERR_PGM_MODE_IPE);
671 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnGetPage, VERR_PGM_MODE_IPE);
672 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnModifyPage, VERR_PGM_MODE_IPE);
673 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnExit, VERR_PGM_MODE_IPE);
674 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr0].pfnEnter, VERR_PGM_MODE_IPE);
675
676 AssertReturn(idxNewGstTtbr1 < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE);
677 AssertReturn(g_aPgmGuestModeData[idxNewGstTtbr1].uType == idxNewGstTtbr1, VERR_PGM_MODE_IPE);
678 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnGetPage, VERR_PGM_MODE_IPE);
679 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnModifyPage, VERR_PGM_MODE_IPE);
680 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnExit, VERR_PGM_MODE_IPE);
681 AssertPtrReturn(g_aPgmGuestModeData[idxNewGstTtbr1].pfnEnter, VERR_PGM_MODE_IPE);
682
683 rc = g_aPgmGuestModeData[idxNewGstTtbr0].pfnEnter(pVCpu);
684 int rc2 = g_aPgmGuestModeData[idxNewGstTtbr1].pfnEnter(pVCpu);
685
686 /* status codes. */
687 AssertRC(rc);
688 AssertRC(rc2);
689 if (RT_SUCCESS(rc))
690 {
691 rc = rc2;
692 if (RT_SUCCESS(rc)) /* no informational status codes. */
693 rc = VINF_SUCCESS;
694 }
695
696 pVCpu->pgm.s.aidxGuestModeDataTtbr0[1] = idxNewGstTtbr0;
697 pVCpu->pgm.s.aidxGuestModeDataTtbr1[1] = idxNewGstTtbr1;
698
699 /* Also set the value for EL0, saves us an if condition in the hot paths later on. */
700 pVCpu->pgm.s.aidxGuestModeDataTtbr0[0] = idxNewGstTtbr0;
701 pVCpu->pgm.s.aidxGuestModeDataTtbr1[0] = idxNewGstTtbr1;
702
703 pVCpu->pgm.s.afLookupMaskTtbr0[0] = pVCpu->pgm.s.afLookupMaskTtbr0[1];
704 pVCpu->pgm.s.afLookupMaskTtbr1[0] = pVCpu->pgm.s.afLookupMaskTtbr1[1];
705
706 pVCpu->pgm.s.aenmGuestMode[1] = (u64RegSctlrEl1 & ARMV8_SCTLR_EL1_M) ? PGMMODE_VMSA_V8_64 : PGMMODE_NONE;
707 return rc;
708}
709
710
711DECLINLINE(int) tstResultQueryBoolDef(RTTEST hTest, RTJSONVAL hMemResult, const char *pszName, bool *pf, bool fDef)
712{
713 int rc = RTJsonValueQueryBooleanByName(hMemResult, pszName, pf);
714 if (rc == VERR_NOT_FOUND)
715 {
716 *pf = fDef;
717 rc = VINF_SUCCESS;
718 }
719 else if (RT_FAILURE(rc))
720 RTTestFailed(hTest, "Querying '%s' failed with %Rrc", pszName, rc);
721
722 return rc;
723}
724
725
726DECLINLINE(int) tstResultQueryGCPhysDef(RTTEST hTest, RTJSONVAL hMemResult, const char *pszName, RTGCPHYS *pGCPhys, RTGCPHYS GCPhysDef)
727{
728 int64_t i64 = 0;
729 int rc = RTJsonValueQueryIntegerByName(hMemResult, pszName, &i64);
730 if (rc == VERR_NOT_FOUND)
731 {
732 *pGCPhys = GCPhysDef;
733 rc = VINF_SUCCESS;
734 }
735 else if (RT_FAILURE(rc))
736 RTTestFailed(hTest, "Querying '%s' failed with %Rrc", pszName, rc);
737 else
738 *pGCPhys = (RTGCPHYS)i64;
739
740 return rc;
741}
742
743
744DECLINLINE(int) tstResultQueryGCPhys(RTTEST hTest, RTJSONVAL hMemResult, const char *pszName, RTGCPHYS *pGCPhys)
745{
746 int64_t i64 = 0;
747 int rc = RTJsonValueQueryIntegerByName(hMemResult, pszName, &i64);
748 if (RT_FAILURE(rc))
749 RTTestFailed(hTest, "Querying '%s' failed with %Rrc", pszName, rc);
750 else
751 *pGCPhys = (RTGCPHYS)i64;
752
753 return rc;
754}
755
756
757DECLINLINE(int) tstResultQueryU8(RTTEST hTest, RTJSONVAL hMemResult, const char *pszName, uint8_t *pu8)
758{
759 int64_t i64 = 0;
760 int rc = RTJsonValueQueryIntegerByName(hMemResult, pszName, &i64);
761 if (RT_FAILURE(rc))
762 RTTestFailed(hTest, "Querying '%s' failed with %Rrc", pszName, rc);
763 else if (i64 < 0 || i64 > UINT8_MAX)
764 RTTestFailed(hTest, "Value %#RI64 for '%s' is out of bounds", i64, pszName);
765 else
766 *pu8 = (uint8_t)i64;
767
768 return rc;
769}
770
771
772DECLINLINE(int) tstResultQueryU32(RTTEST hTest, RTJSONVAL hMemResult, const char *pszName, uint32_t *pu32)
773{
774 int64_t i64 = 0;
775 int rc = RTJsonValueQueryIntegerByName(hMemResult, pszName, &i64);
776 if (RT_FAILURE(rc))
777 RTTestFailed(hTest, "Querying '%s' failed with %Rrc", pszName, rc);
778 else if (i64 < 0 || i64 > UINT32_MAX)
779 RTTestFailed(hTest, "Value %#RI64 for '%s' is out of bounds", i64, pszName);
780 else
781 *pu32 = (uint32_t)i64;
782
783 return rc;
784}
785
786
787DECLINLINE(int) tstResultQueryU64(RTTEST hTest, RTJSONVAL hMemResult, const char *pszName, uint64_t *pu64)
788{
789 int64_t i64 = 0;
790 int rc = RTJsonValueQueryIntegerByName(hMemResult, pszName, &i64);
791 if (RT_FAILURE(rc))
792 RTTestFailed(hTest, "Querying '%s' failed with %Rrc", pszName, rc);
793 else
794 *pu64 = (uint64_t)i64;
795
796 return rc;
797}
798
799
800static int tstResultInit(RTTEST hTest, RTJSONVAL hMemResult, PPGMPTWALK pWalkResult)
801{
802 int rc = tstResultQueryBoolDef(hTest, hMemResult, "Succeeded", &pWalkResult->fSucceeded, true);
803 if (RT_SUCCESS(rc))
804 rc = tstResultQueryBoolDef(hTest, hMemResult, "IsSlat", &pWalkResult->fIsSlat, false);
805 if (RT_SUCCESS(rc))
806 rc = tstResultQueryBoolDef(hTest, hMemResult, "IsLinearAddrValid", &pWalkResult->fIsLinearAddrValid, false);
807 if (RT_SUCCESS(rc))
808 rc = tstResultQueryBoolDef(hTest, hMemResult, "NotPresent", &pWalkResult->fNotPresent, false);
809 if (RT_SUCCESS(rc))
810 rc = tstResultQueryBoolDef(hTest, hMemResult, "BadPhysAddr", &pWalkResult->fBadPhysAddr, false);
811 if (RT_SUCCESS(rc))
812 rc = tstResultQueryBoolDef(hTest, hMemResult, "RsvdError", &pWalkResult->fRsvdError, false);
813 if (RT_SUCCESS(rc))
814 rc = tstResultQueryBoolDef(hTest, hMemResult, "BigPage", &pWalkResult->fBigPage, false);
815 if (RT_SUCCESS(rc))
816 rc = tstResultQueryBoolDef(hTest, hMemResult, "GigantPage", &pWalkResult->fGigantPage, false);
817 if (RT_SUCCESS(rc))
818 rc = tstResultQueryGCPhys(hTest, hMemResult, "GCPhys", &pWalkResult->GCPhys);
819 if (RT_SUCCESS(rc))
820 rc = tstResultQueryGCPhysDef(hTest, hMemResult, "GCPhysNested", &pWalkResult->GCPhysNested, 0);
821 if (RT_SUCCESS(rc))
822 rc = tstResultQueryU8(hTest, hMemResult, "Level", &pWalkResult->uLevel);
823 if (RT_SUCCESS(rc))
824 rc = tstResultQueryU32(hTest, hMemResult, "fFailed", &pWalkResult->fFailed);
825 if (RT_SUCCESS(rc))
826 rc = tstResultQueryU64(hTest, hMemResult, "Effective", &pWalkResult->fEffective);
827
828 return rc;
829}
830
831
832static void tstExecute(RTTEST hTest, PVM pVM, RTGCPTR GCPtr, RTJSONVAL hMemResult)
833{
834 PVMCPUCC pVCpu = pVM->apCpusR3[0];
835
836 /** @todo Incorporate EL (for nested virt and EL3 later on). */
837 uintptr_t idx = (GCPtr & RT_BIT_64(55))
838 ? pVCpu->pgm.s.aidxGuestModeDataTtbr1[1]
839 : pVCpu->pgm.s.aidxGuestModeDataTtbr0[1];
840
841 PGMPTWALK Walk; RT_ZERO(Walk);
842 AssertReleaseReturnVoid(idx < RT_ELEMENTS(g_aPgmGuestModeData));
843 AssertReleaseReturnVoid(g_aPgmGuestModeData[idx].pfnGetPage);
844 int rc = g_aPgmGuestModeData[idx].pfnGetPage(pVCpu, GCPtr, &Walk);
845 if (RT_SUCCESS(rc))
846 {
847 PGMPTWALK WalkResult; RT_ZERO(WalkResult);
848 WalkResult.GCPtr = GCPtr;
849
850 rc = tstResultInit(hTest, hMemResult, &WalkResult);
851 if (RT_SUCCESS(rc))
852 {
853 if (memcmp(&Walk, &WalkResult, sizeof(Walk)))
854 {
855 if (Walk.GCPtr != WalkResult.GCPtr)
856 RTTestFailed(hTest, "Result GCPtr=%RGv != Expected GCPtr=%RGv", Walk.GCPtr, WalkResult.GCPtr);
857 if (Walk.GCPhysNested != WalkResult.GCPhysNested)
858 RTTestFailed(hTest, "Result GCPhysNested=%RGp != Expected GCPhysNested=%RGp", Walk.GCPhysNested, WalkResult.GCPhysNested);
859 if (Walk.GCPhys != WalkResult.GCPhys)
860 RTTestFailed(hTest, "Result GCPhys=%RGp != Expected GCPhys=%RGp", Walk.GCPhys, WalkResult.GCPhys);
861 if (Walk.fSucceeded != WalkResult.fSucceeded)
862 RTTestFailed(hTest, "Result fSucceeded=%RTbool != Expected fSucceeded=%RTbool", Walk.fSucceeded, WalkResult.fSucceeded);
863 if (Walk.fIsSlat != WalkResult.fIsSlat)
864 RTTestFailed(hTest, "Result fIsSlat=%RTbool != Expected fIsSlat=%RTbool", Walk.fIsSlat, WalkResult.fIsSlat);
865 if (Walk.fIsLinearAddrValid != WalkResult.fIsLinearAddrValid)
866 RTTestFailed(hTest, "Result fIsLinearAddrValid=%RTbool != Expected fIsLinearAddrValid=%RTbool", Walk.fIsLinearAddrValid, WalkResult.fIsLinearAddrValid);
867 if (Walk.uLevel != WalkResult.uLevel)
868 RTTestFailed(hTest, "Result uLevel=%RU8 != Expected uLevel=%RU8", Walk.uLevel, WalkResult.uLevel);
869 if (Walk.fNotPresent != WalkResult.fNotPresent)
870 RTTestFailed(hTest, "Result fNotPresent=%RTbool != Expected fNotPresent=%RTbool", Walk.fNotPresent, WalkResult.fNotPresent);
871 if (Walk.fBadPhysAddr != WalkResult.fBadPhysAddr)
872 RTTestFailed(hTest, "Result fBadPhysAddr=%RTbool != Expected fBadPhysAddr=%RTbool", Walk.fBadPhysAddr, WalkResult.fBadPhysAddr);
873 if (Walk.fRsvdError != WalkResult.fRsvdError)
874 RTTestFailed(hTest, "Result fRsvdError=%RTbool != Expected fRsvdError=%RTbool", Walk.fRsvdError, WalkResult.fRsvdError);
875 if (Walk.fBigPage != WalkResult.fBigPage)
876 RTTestFailed(hTest, "Result fBigPage=%RTbool != Expected fBigPage=%RTbool", Walk.fBigPage, WalkResult.fBigPage);
877 if (Walk.fGigantPage != WalkResult.fGigantPage)
878 RTTestFailed(hTest, "Result fGigantPage=%RTbool != Expected fGigantPage=%RTbool", Walk.fGigantPage, WalkResult.fGigantPage);
879 if (Walk.fFailed != WalkResult.fFailed)
880 RTTestFailed(hTest, "Result fFailed=%#RX32 != Expected fFailed=%#RX32", Walk.fFailed, WalkResult.fFailed);
881 if (Walk.fEffective != WalkResult.fEffective)
882 RTTestFailed(hTest, "Result fEffective=%#RX64 != Expected fEffective=%#RX64", Walk.fEffective, WalkResult.fEffective);
883 }
884 }
885 }
886 else
887 RTTestFailed(hTest, "Resolving virtual address %#RX64 to physical address failed with %Rrc", GCPtr, rc);
888}
889
890
891static int tstTestcaseMmuRun(RTTEST hTest, RTJSONVAL hTestcase)
892{
893 RTJSONVAL hVal = NIL_RTJSONVAL;
894 int rc = RTJsonValueQueryByName(hTestcase, "Tests", &hVal);
895 if (RT_SUCCESS(rc))
896 {
897 RTJSONIT hIt = NIL_RTJSONIT;
898 rc = RTJsonIteratorBeginObject(hVal, &hIt);
899 if (RT_SUCCESS(rc))
900 {
901 for (;;)
902 {
903 RTJSONVAL hMemObj = NIL_RTJSONVAL;
904 const char *pszAddress = NULL;
905 rc = RTJsonIteratorQueryValue(hIt, &hMemObj, &pszAddress);
906 if (RT_SUCCESS(rc))
907 {
908 uint64_t GCPtr = 0;
909 rc = RTStrToUInt64Full(pszAddress, 0, &GCPtr);
910 if (rc == VINF_SUCCESS)
911 tstExecute(hTest, g_MmuCfg.pVM, GCPtr, hMemObj);
912 else
913 {
914 RTTestFailed(hTest, "Address '%s' is not a valid 64-bit physical address", pszAddress);
915 break;
916 }
917
918 RTJsonValueRelease(hMemObj);
919 }
920 else
921 RTTestFailed(hTest, "Failed to retrieve memory range with %Rrc", rc);
922
923 rc = RTJsonIteratorNext(hIt);
924 if (RT_FAILURE(rc))
925 break;
926 }
927 if (rc == VERR_JSON_ITERATOR_END)
928 rc = VINF_SUCCESS;
929 RTJsonIteratorFree(hIt);
930 }
931 else
932 RTTestFailed(hTest, "Failed to traverse JSON array with %Rrc", rc);
933
934
935 RTJsonValueRelease(hVal);
936 }
937 else
938 RTTestFailed(hTest, "Failed to query \"Tests\" %Rrc", rc);
939
940 return rc;
941}
942
943
944static void tstExecuteTestcase(RTTEST hTest, RTJSONVAL hTestcase)
945{
946 RTJSONVAL hVal = NIL_RTJSONVAL;
947 int rc = RTJsonValueQueryByName(hTestcase, "Name", &hVal);
948 if (RT_SUCCESS(rc))
949 {
950 const char *pszTestcaseName = RTJsonValueGetString(hVal);
951 if (pszTestcaseName)
952 {
953 RTTestSub(hTest, pszTestcaseName);
954
955 /* Reset the config for each testcase. */
956 tstMmuCfgReset(&g_MmuCfg);
957
958 rc = tstTestcaseAddressSpacePrepare(hTest, hTestcase);
959 if (RT_SUCCESS(rc))
960 rc = tstTestcaseMmuConfigPrepare(hTest, &g_MmuCfg, hTestcase);
961 if (RT_SUCCESS(rc))
962 rc = tstTestcaseMmuRun(hTest, hTestcase);
963 }
964 else
965 RTTestFailed(hTest, "The testcase name is not a string");
966 RTJsonValueRelease(hVal);
967 }
968 else
969 RTTestFailed(hTest, "Failed to query the testcase name with %Rrc", rc);
970}
971
972
973static void tstLoadAndRun(RTTEST hTest, RTJSONVAL hRoot)
974{
975 int rc = tstMmuCfgInit(&g_MmuCfg);
976 if (RT_FAILURE(rc))
977 {
978 RTTestFailed(hTest, "Failed to initialize MMU config %Rrc", rc);
979 return;
980 }
981
982 RTJSONVALTYPE enmType = RTJsonValueGetType(hRoot);
983 if (enmType == RTJSONVALTYPE_ARRAY)
984 {
985 /* Array of testcases. */
986 RTJSONIT hIt = NIL_RTJSONIT;
987 rc = RTJsonIteratorBeginArray(hRoot, &hIt);
988 if (RT_SUCCESS(rc))
989 {
990 for (;;)
991 {
992 RTJSONVAL hTestcase = NIL_RTJSONVAL;
993 rc = RTJsonIteratorQueryValue(hIt, &hTestcase, NULL /*ppszName*/);
994 if (RT_SUCCESS(rc))
995 {
996 tstExecuteTestcase(hTest, hTestcase);
997 RTJsonValueRelease(hTestcase);
998 }
999 else
1000 RTTestFailed(hTest, "Failed to retrieve testcase with %Rrc", rc);
1001
1002 rc = RTJsonIteratorNext(hIt);
1003 if (RT_FAILURE(rc))
1004 break;
1005 }
1006 if (rc == VERR_JSON_ITERATOR_END)
1007 rc = VINF_SUCCESS;
1008 RTJsonIteratorFree(hIt);
1009 }
1010 else /* An empty array is also an error */
1011 RTTestFailed(hTest, "Failed to traverse JSON array with %Rrc", rc);
1012 }
1013 else if (enmType == RTJSONVALTYPE_OBJECT)
1014 {
1015 /* Single testcase. */
1016 tstExecuteTestcase(hTest, hRoot);
1017 }
1018 else
1019 RTTestFailed(hTest, "JSON root is not an array or object containing a testcase");
1020 RTJsonValueRelease(hRoot);
1021 tstMmuCfgDestroy(&g_MmuCfg);
1022}
1023
1024
1025static void tstLoadFromFile(RTTEST hTest, const char *pszFilename)
1026{
1027 /* Load the configuration from the JSON config file. */
1028 RTERRINFOSTATIC ErrInfo;
1029 RTJSONVAL hRoot = NIL_RTJSONVAL;
1030 int rc = RTJsonParseFromFile(&hRoot, RTJSON_PARSE_F_JSON5, pszFilename, RTErrInfoInitStatic(&ErrInfo));
1031 if (RT_SUCCESS(rc))
1032 tstLoadAndRun(hTest, hRoot);
1033 else
1034 {
1035 if (RTErrInfoIsSet(&ErrInfo.Core))
1036 RTTestFailed(hTest, "RTJsonParseFromFile() for \"%s\" failed with %Rrc\n%s",
1037 pszFilename, rc, ErrInfo.Core.pszMsg);
1038 else
1039 RTTestFailed(hTest, "RTJsonParseFromFile() for \"%s\" failed with %Rrc",
1040 pszFilename, rc);
1041 }
1042}
1043
1044
1045static void tstBasic(RTTEST hTest)
1046{
1047 RTERRINFOSTATIC ErrInfo;
1048 RTJSONVAL hRoot = NIL_RTJSONVAL;
1049 int rc = RTJsonParseFromBuf(&hRoot, RTJSON_PARSE_F_JSON5,
1050 g_abtstPGMAllGst_armv8_1, g_cbtstPGMAllGst_armv8_1,
1051 RTErrInfoInitStatic(&ErrInfo));
1052 if (RT_SUCCESS(rc))
1053 tstLoadAndRun(hTest, hRoot);
1054 else
1055 {
1056 if (RTErrInfoIsSet(&ErrInfo.Core))
1057 RTTestFailed(hTest, "RTJsonParseFromBuf() failed with %Rrc\n%s", rc, ErrInfo.Core.pszMsg);
1058 else
1059 RTTestFailed(hTest, "RTJsonParseFromBuf() failed with %Rrc", rc);
1060 }
1061}
1062
1063
1064int main(int argc, char **argv)
1065{
1066 /*
1067 * We run the VMM in driverless mode to avoid needing to hardened the testcase
1068 */
1069 RTEXITCODE rcExit;
1070 int rc = RTR3InitExe(argc, &argv, SUPR3INIT_F_DRIVERLESS << RTR3INIT_FLAGS_SUPLIB_SHIFT);
1071 if (RT_SUCCESS(rc))
1072 {
1073 rc = RTTestCreate("tstPGMAllGst-armv8", &g_hTest);
1074 if (RT_SUCCESS(rc))
1075 {
1076 RTTestBanner(g_hTest);
1077 if (argc == 2)
1078 tstLoadFromFile(g_hTest, argv[1]);
1079 else
1080 tstBasic(g_hTest);
1081 rcExit = RTTestSummaryAndDestroy(g_hTest);
1082 }
1083 else
1084 rcExit = RTMsgErrorExitFailure("RTTestCreate failed: %Rrc", rc);
1085 }
1086 else
1087 rcExit = RTMsgInitFailure(rc);
1088 return rcExit;
1089}
1090
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette