VirtualBox

Changeset 108873 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Apr 7, 2025 2:55:14 PM (5 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
168323
Message:

VMM/testcase/tstPGMAllGst-armv8.cpp: Updates for the testcase, bugref:10388

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/testcase/tstPGMAllGst-armv8.cpp

    r108857 r108873  
    3030*   Header Files                                                                                                                 *
    3131*********************************************************************************************************************************/
    32 #include "VMInternal.h" /* createFakeVM */
     32#include "VMInternal.h"
     33#include <VBox/vmm/cpum.h>
     34#include "../include/CPUMInternal-armv8.h"
    3335#include "../include/PGMInternal.h"
    3436
     
    4244#include <VBox/err.h>
    4345#include <VBox/log.h>
     46#include <iprt/avl.h>
    4447#include <iprt/assert.h>
    4548#include <iprt/initterm.h>
     49#include <iprt/json.h>
    4650#include <iprt/message.h>
    4751#include <iprt/mem.h>
     
    4953#include <iprt/thread.h>
    5054#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 */
     65typedef 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. */
     74typedef TSTMEMCHUNK *PTSTMEMCHUNK;
     75/** Pointer to a const physical memory chunk. */
     76typedef const TSTMEMCHUNK *PCTSTMEMCHUNK;
     77
     78
     79/**
     80 * The current testcase data.
     81 */
     82typedef 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;
     95typedef TSTPGMARMV8MMU *PTSTPGMARMV8MMU;
     96typedef const TSTPGMARMV8MMU *PCTSTPGMARMV8MMU;
    5197
    5298
     
    55101*********************************************************************************************************************************/
    56102static RTTEST g_hTest;
     103/** The currently executing testcase config. */
     104static TSTPGMARMV8MMU g_MmuCfg;
     105
     106
     107static 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}
    57120
    58121
     
    60123{
    61124    RT_NOREF(pVCpu, GCPhys, ppv);
    62     AssertFailed();
    63     return VINF_SUCCESS;
     125    return pgmPhysGCPhys2CCPtr(GCPhys, ppv);
    64126}
    65127
     
    68130{
    69131    RT_NOREF(pVM, GCPhys, pR3Ptr);
    70     AssertFailed();
    71     return VINF_SUCCESS;
     132    return pgmPhysGCPhys2CCPtr(GCPhys, (void **)pR3Ptr);
    72133}
    73134
     
    76137{
    77138    RT_NOREF(pVCpu);
    78     AssertFailed();
    79     return 0;
     139    return g_MmuCfg.bEl;
    80140}
    81141
     
    83143VMM_INT_DECL(RTGCPHYS) CPUMGetEffectiveTtbr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
    84144{
    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);
    88149}
    89150
     
    97158 *
    98159 * @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.
    102161 */
    103 static int createFakeVM(PVM *ppVM)
     162static int tstMmuCfgInit(PTSTPGMARMV8MMU pMmuCfg)
    104163{
    105164    /*
     
    134193
    135194            pUVM->pVM = pVM;
    136             *ppVM = pVM;
     195            pMmuCfg->pVM = pVM;
    137196            return VINF_SUCCESS;
    138197        }
     
    143202        RTTestIFailed("Fatal error: RTTlsSet failed, rc=%Rrc\n", rc);
    144203
    145     *ppVM = NULL;
    146204    return rc;
     205}
     206
     207
     208static 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
     217static void tstMmuCfgReset(PTSTPGMARMV8MMU pMmuCfg)
     218{
     219    RTAvlrU64DoWithAll(&pMmuCfg->TreeMem, true /*fFromLeft*/, tstZeroChunk, NULL);
     220}
     221
     222
     223static DECLCALLBACK(int) tstDestroyChunk(PAVLRU64NODECORE pCore, void *pvParam)
     224{
     225    RT_NOREF(pvParam);
     226    RTMemPageFree(pCore, _64K);
     227    return VINF_SUCCESS;
    147228}
    148229
     
    152233 *
    153234 * @param   pVM     Pointer to the VM.
    154  *
    155  * @todo    Move this to VMM/VM since it's stuff done by several testcases.
    156235 */
    157 static void destroyFakeVM(PVM pVM)
    158 {
    159     RT_NOREF(pVM);
     236static 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);
    160241}
    161242
     
    166247     * Create an fake VM structure.
    167248     */
    168     PVM pVM;
    169     int rc = createFakeVM(&pVM);
     249    int rc = tstMmuCfgInit(&g_MmuCfg);
    170250    if (RT_FAILURE(rc))
    171251        return;
     
    173253    /** @todo */
    174254
    175     destroyFakeVM(pVM);
    176 }
     255    tstMmuCfgDestroy(&g_MmuCfg);
     256}
     257
     258
     259static 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
     293static 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
     378static 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
     431static 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
     523static 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
     545static 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
     598static 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
     627static 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
    177695
    178696int main(int argc, char **argv)
     
    189707        {
    190708            RTTestBanner(g_hTest);
    191             tstBasic();
     709            if (argc == 2)
     710                tstLoadFromFile(g_hTest, argv[1]);
     711            else
     712                tstBasic();
    192713            rcExit = RTTestSummaryAndDestroy(g_hTest);
    193714        }
Note: See TracChangeset for help on using the changeset viewer.

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