VirtualBox

Changeset 60208 in vbox


Ignore:
Timestamp:
Mar 27, 2016 1:53:48 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
106242
Message:

bs3-cpu-basic-2: More tests.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c

    r60203 r60208  
    4040# undef MyBs3Idt
    4141# undef MY_SYS_SEL_R0_CS
     42# undef MY_SYS_SEL_R0_CS_CNF
    4243# undef MY_SYS_SEL_R0_DS
    4344# undef MY_SYS_SEL_R0_SS
    4445# if BS3_MODE_IS_16BIT_SYS(TMPL_MODE)
    45 #  define MyBs3Idt          BS3_DATA_NM(Bs3Idt16)
    46 #  define MY_SYS_SEL_R0_CS  BS3_SEL_R0_CS16
    47 #  define MY_SYS_SEL_R0_DS  BS3_SEL_R0_DS16
    48 #  define MY_SYS_SEL_R0_SS  BS3_SEL_R0_SS16
     46#  define MyBs3Idt              BS3_DATA_NM(Bs3Idt16)
     47#  define MY_SYS_SEL_R0_CS      BS3_SEL_R0_CS16
     48#  define MY_SYS_SEL_R0_CS_CNF  BS3_SEL_R0_CS16_CNF
     49#  define MY_SYS_SEL_R0_DS      BS3_SEL_R0_DS16
     50#  define MY_SYS_SEL_R0_SS      BS3_SEL_R0_SS16
    4951# elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE)
    50 #  define MyBs3Idt          BS3_DATA_NM(Bs3Idt32)
    51 #  define MY_SYS_SEL_R0_CS  BS3_SEL_R0_CS32
    52 #  define MY_SYS_SEL_R0_DS  BS3_SEL_R0_DS32
    53 #  define MY_SYS_SEL_R0_SS  BS3_SEL_R0_SS32
     52#  define MyBs3Idt              BS3_DATA_NM(Bs3Idt32)
     53#  define MY_SYS_SEL_R0_CS      BS3_SEL_R0_CS32
     54#  define MY_SYS_SEL_R0_CS_CNF  BS3_SEL_R0_CS32_CNF
     55#  define MY_SYS_SEL_R0_DS      BS3_SEL_R0_DS32
     56#  define MY_SYS_SEL_R0_SS      BS3_SEL_R0_SS32
    5457# elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
    55 #  define MyBs3Idt          BS3_DATA_NM(Bs3Idt64)
    56 #  define MY_SYS_SEL_R0_CS  BS3_SEL_R0_CS64
    57 #  define MY_SYS_SEL_R0_DS  BS3_SEL_R0_DS64
    58 #  define MY_SYS_SEL_R0_SS  BS3_SEL_R0_DS64
     58#  define MyBs3Idt              BS3_DATA_NM(Bs3Idt64)
     59#  define MY_SYS_SEL_R0_CS      BS3_SEL_R0_CS64
     60#  define MY_SYS_SEL_R0_CS_CNF  BS3_SEL_R0_CS64_CNF
     61#  define MY_SYS_SEL_R0_DS      BS3_SEL_R0_DS64
     62#  define MY_SYS_SEL_R0_SS      BS3_SEL_R0_DS64
    5963# else
    6064#  error "TMPL_MODE"
     
    97101}
    98102
     103
     104/**
     105 * Compares trap stuff.
     106 */
     107static void bs3CpuBasic2_CompareTrapCtx2(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t cbIpAdjust, uint8_t bXcpt,
     108                                         uint16_t uHandlerCs, const char *pszMode, unsigned uLine)
     109{
     110    uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
     111    CHECK_MEMBER("bXcpt",   "%#04x",    pTrapCtx->bXcpt,        bXcpt);
     112    CHECK_MEMBER("bErrCd",  "%#06RX64", pTrapCtx->uErrCd,       0);
     113    CHECK_MEMBER("uHandlerCs", "%#06x", pTrapCtx->uHandlerCs,   uHandlerCs);
     114    Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, pszMode, uLine);
     115    if (Bs3TestSubErrorCount() != cErrorsBefore)
     116    {
     117        Bs3TrapPrintFrame(pTrapCtx);
     118ASMHalt();
     119    }
     120}
     121
    99122/**
    100123 * Compares trap stuff.
     
    105128    uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
    106129    CHECK_MEMBER("bXcpt",   "%#04x",    pTrapCtx->bXcpt,        X86_XCPT_GP);
     130    CHECK_MEMBER("bErrCd",  "%#06RX64", pTrapCtx->uErrCd,       (uint64_t)uErrCd);
     131    Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 0 /*cbIpAdjust*/, 0 /*cbSpAdjust*/,
     132                         f16BitHandler ? 0 : X86_EFL_RF,
     133                         pszMode, uLine);
     134    if (Bs3TestSubErrorCount() != cErrorsBefore)
     135    {
     136        Bs3TrapPrintFrame(pTrapCtx);
     137ASMHalt();
     138    }
     139}
     140
     141/**
     142 * Compares trap stuff.
     143 */
     144static void bs3CpuBasic2_CompareNpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, bool f16BitHandler,
     145                                      const char *pszMode, unsigned uLine)
     146{
     147    uint16_t const cErrorsBefore = Bs3TestSubErrorCount();
     148    CHECK_MEMBER("bXcpt",   "%#04x",    pTrapCtx->bXcpt,        X86_XCPT_NP);
    107149    CHECK_MEMBER("bErrCd",  "%#06RX64", pTrapCtx->uErrCd,       (uint64_t)uErrCd);
    108150    Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 0 /*cbIpAdjust*/, 0 /*cbSpAdjust*/,
     
    306348    unsigned        iCtx;
    307349    unsigned        iRing;
    308     unsigned        i;
     350    unsigned        i, j, k;
    309351    unsigned        uLine;
    310352    const char     *pszMode = BS3_DATA_NM(TMPL_NM(g_szBs3ModeName));
     
    358400# endif
    359401        Bs3TrapSetJmpAndRestore(apCtx8x[iCtx], &TrapCtx);
    360         bs3CpuBasic2_CompareTrapCtx1(&TrapCtx, apCtx8x[iCtx], 2 /*int 80h*/, 0x80+iCtx /*bXcpt*/, pszMode, 10000 + iCtx);
     402        bs3CpuBasic2_CompareTrapCtx1(&TrapCtx, apCtx8x[iCtx], 2 /*int 80h*/, 0x80+iCtx /*bXcpt*/, pszMode, iCtx);
    361403    }
    362404
     
    364406     * Check that the gate DPL checks works.
    365407     */
     408    uLine = 100;
    366409    for (iRing = 0; iRing <= 3; iRing++)
    367410    {
     
    374417# endif
    375418            Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
    376             uLine = 11000 + iRing*10 + iCtx;
     419            uLine++;
    377420            if (iCtx < iRing)
    378421                bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT,
     
    385428    /*
    386429     * Modify the gate CS value and run the handler at a different CPL.
    387      */
     430     * Throw RPL variations into the mix (completely ignored) together
     431     * with gate presence.
     432     *      1. CPL <= GATE.DPL
     433     *      2. GATE.P
     434     *      3. GATE.CS.DPL <= CPL (non-conforming segments)
     435     */
     436    uLine = 1000;
    388437    for (i = 0; i <= 3; i++)
    389438    {
     
    392441            for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
    393442            {
    394                 uint16_t const uCs = (MY_SYS_SEL_R0_CS | i) + (i << BS3_SEL_RING_SHIFT);
    395                 uLine = 12000 + i*100 + iRing*10 + iCtx;
     443# if TMPL_BITS == 32
     444                BS3_DATA_NM(g_uBs3TrapEipHint) = apCtx8x[iCtx]->rip.u32;
     445# endif
     446                Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
     447                Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
     448
     449                for (j = 0; j <= 3; j++)
     450                {
     451                    uint16_t const uCs = (MY_SYS_SEL_R0_CS | j) + (i << BS3_SEL_RING_SHIFT);
     452                    for (k = 0; k < 2; k++)
     453                    {
     454                        uLine++;
     455                        /*Bs3TestPrintf("uLine=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", uLine,  iCtx,  iRing, i, uCs);*/
     456                        MyBs3Idt[0x80+iCtx].Gate.u16Sel = uCs;
     457                        MyBs3Idt[0x80+iCtx].Gate.u1Present = k;
     458                        Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
     459                        /*Bs3TrapPrintFrame(&TrapCtx);*/
     460                        if (iCtx < iRing)
     461                            bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT,
     462                                                      f16BitSys, pszMode, uLine);
     463                        else if (k == 0)
     464                            bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT,
     465                                                      f16BitSys, pszMode, uLine);
     466                        else if (i > iRing)
     467                            bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL, f16BitSys, pszMode, uLine);
     468                        else
     469                        {
     470                            uint16_t uExpectedCs = uCs & X86_SEL_MASK_OFF_RPL;
     471                            if (i <= iCtx && i <= iRing)
     472                                uExpectedCs |= i;
     473                            bs3CpuBasic2_CompareTrapCtx2(&TrapCtx, &CtxTmp, 2 /*int 8xh*/, 0x80 + iCtx /*bXcpt*/,
     474                                                         uExpectedCs, pszMode, uLine);
     475                        }
     476                    }
     477                }
     478
     479                MyBs3Idt[0x80+iCtx].Gate.u16Sel = MY_SYS_SEL_R0_CS;
     480                MyBs3Idt[0x80+iCtx].Gate.u1Present = 1;
     481            }
     482        }
     483    }
     484    BS3_ASSERT(uLine < 2000);
     485
     486    /*
     487     * Modify the gate CS value with a conforming segment.
     488     */
     489#if 0
     490    uLine = 2000;
     491    for (i = 0; i <= 3; i++)
     492    {
     493        for (iRing = 0; iRing <= 3; iRing++)
     494        {
     495            for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
     496            {
     497                uint16_t const uCs = (MY_SYS_SEL_R0_CS_CNF | i) + (i << BS3_SEL_RING_SHIFT);
     498                uLine++;
    396499                /*Bs3TestPrintf("uLine=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", uLine,  iCtx,  iRing, i, uCs);*/
    397500                Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
     
    414517        }
    415518    }
    416 
    417 
    418 #if 0
    419     /*
    420      * Check that the basic stuff works first.
    421      */
    422     Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx);
    423     bs3CpuBasic2_CompareTrapCtx1(&TrapCtx, &Ctx, 2 /*int 80h*/, 0x80 /*bXcpt*/, pszMode, __LINE__);
    424 
    425     bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, NULL, 0, f16BitSys, f16BitSys, f16BitSys, pszMode, __LINE__);
    426     bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 2, NULL, 0, f16BitSys, f16BitSys, f16BitSys, pszMode, __LINE__);
    427     bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 3, NULL, 0, f16BitSys, f16BitSys, f16BitSys, pszMode, __LINE__);
    428 
    429     /*
    430      * Check that the upper part of ESP is preserved when doing .
    431      */
    432     if ((BS3_DATA_NM(g_uBs3CpuDetected) & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
    433     {
    434         size_t const cbAltStack = _8K;
    435         uint8_t *pbAltStack = Bs3MemAllocZ(BS3MEMKIND_TILED, cbAltStack);
    436         if (pbAltStack)
     519    BS3_ASSERT(uLine < 3000);
     520#endif
     521
     522# if BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
     523    /*
     524     * The gates must be 64-bit.
     525     */
     526    uLine = 3000;
     527    for (i = 0; i <= 3; i++)
     528    {
     529        for (iRing = 0; iRing <= 3; iRing++)
    437530        {
    438             /* same ring */
    439             uLine = __LINE__;
    440             Bs3MemCpy(&Ctx2, &Ctx, sizeof(Ctx2));
    441             Ctx2.rsp.u = Bs3SelPtrToFlat(pbAltStack + 0x1980);
    442             if (Bs3TrapSetJmp(&TrapCtx))
    443                 Bs3RegCtxRestore(&Ctx2, 0); /* (does not return) */
    444             bs3CpuBasic2_CompareTrapCtx1(&TrapCtx, &Ctx2, 2 /*int 80h*/, 0x80 /*bXcpt*/, pszMode, uLine);
    445 # if TMPL_BITS == 16
    446             if ((pbTmp = (uint8_t *)ASMMemFirstNonZero(pbAltStack, cbAltStack)) != NULL)
    447                 Bs3TestFailedF("%u - %s: someone touched the alt stack (%p) with SS:ESP=%04x:%#RX32: %p=%02x\n",
    448                                uLine, pszMode, pbAltStack, Ctx2.ss, Ctx2.rsp.u32, pbTmp, *pbTmp);
     531            for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
     532            {
     533                Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
     534                Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
     535
     536                for (j = 0; j < 2; j++)
     537                {
     538                    static const uint16_t s_auCSes[2] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32 };
     539                    uint16_t uCs = (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT);
     540                    uLine++;
     541                    /*Bs3TestPrintf("uLine=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", uLine,  iCtx,  iRing, i, uCs);*/
     542                    MyBs3Idt[0x80+iCtx].Gate.u16Sel = uCs;
     543                    Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
     544                    /*Bs3TrapPrintFrame(&TrapCtx);*/
     545                    if (iCtx < iRing)
     546                        bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT,
     547                                                  f16BitSys, pszMode, uLine);
     548                    else
     549                        bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL, f16BitSys, pszMode, uLine);
     550                }
     551                MyBs3Idt[0x80+iCtx].Gate.u16Sel = MY_SYS_SEL_R0_CS;
     552            }
     553        }
     554    }
     555    BS3_ASSERT(uLine < 4000);
     556# endif
     557
     558    /*
     559     * Check invalid gate types.
     560     */
     561    uLine = 32000;
     562    for (iRing = 0; iRing <= 3; iRing++)
     563    {
     564        static const uint16_t s_auCSes[]      = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32, BS3_SEL_R0_CS64,
     565                                                  BS3_SEL_TSS16, BS3_SEL_TSS32, BS3_SEL_TSS64, 0, BS3_SEL_SPARE_1f };
     566# if BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
     567        static uint16_t const s_auInvlTypes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
     568                                                  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     569                                                  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
     570        uint16_t        const cInvTypes       = RT_ELEMENTS(s_auInvlTypes);
    449571# else
    450             if (ASMMemIsZero(pbAltStack, cbAltStack))
    451                 Bs3TestFailedF("%u - %s: alt stack wasn't used despite SS:ESP=%04x:%#RX32\n",
    452                                uLine, pszMode, Ctx2.ss, Ctx2.rsp.u32);
    453 # endif
    454 
    455             /* Different rings (load SS0:SP0 from TSS). */
    456             bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack,
    457                                                       f16BitSys, f16BitSys, f16BitSys, pszMode, __LINE__);
    458             bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 2, pbAltStack, cbAltStack,
    459                                                       f16BitSys, f16BitSys, f16BitSys, pszMode, __LINE__);
    460             bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 3, pbAltStack, cbAltStack,
    461                                                       f16BitSys, f16BitSys, f16BitSys, pszMode, __LINE__);
    462 
    463             /* Different rings but switch the SS bitness in the TSS. */
    464 # if BS3_MODE_IS_16BIT_SYS(TMPL_MODE)
    465             Bs3Tss16.ss0 = BS3_SEL_R0_SS32;
    466             bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack,
    467                                                       false, f16BitSys, f16BitSys, pszMode, __LINE__);
    468             Bs3Tss16.ss0 = BS3_SEL_R0_SS16;
    469 # else
    470             Bs3Tss32.ss0 = BS3_SEL_R0_SS16;
    471             bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack,
    472                                                       true,  f16BitSys, f16BitSys, pszMode, __LINE__);
    473             Bs3Tss32.ss0 = BS3_SEL_R0_SS32;
    474 # endif
    475 
    476             Bs3MemFree(pbAltStack, cbAltStack);
     572        static uint16_t const s_auInvlTypes[] = { 0, 1, 2, 3, 8, 9, 10, 11, 13,
     573                                                  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     574                                                  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
     575                                                  /*286:*/ 12, 14, 15 };
     576        uint16_t const        cInvTypes       = (BS3_DATA_NM(g_uBs3CpuDetected) & BS3CPU_TYPE_MASK) < BS3CPU_80386
     577                                              ? RT_ELEMENTS(s_auInvlTypes) : RT_ELEMENTS(s_auInvlTypes) - 3;
     578# endif
     579        for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++)
     580        {
     581            unsigned iType;
     582
     583            Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp));
     584            Bs3RegCtxConvertToRingX(&CtxTmp, iRing);
     585# if TMPL_BITS == 32
     586            BS3_DATA_NM(g_uBs3TrapEipHint) = CtxTmp.rip.u32;
     587# endif
     588            for (iType = 0; iType < cInvTypes; iType++)
     589            {
     590                uint8_t const bSavedType = MyBs3Idt[0x80 + iCtx].Gate.u4Type;
     591                MyBs3Idt[0x80 + iCtx].Gate.u1DescType = s_auInvlTypes[iType] >> 4;
     592                MyBs3Idt[0x80 + iCtx].Gate.u4Type     = s_auInvlTypes[iType] & 0xf;
     593
     594                for (i = 0; i < 4; i++)
     595                {
     596                    for (j = 0; j < RT_ELEMENTS(s_auCSes); j++)
     597                    {
     598                        uint16_t uCs = (unsigned)(s_auCSes[j] - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT)
     599                                     ? (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT)
     600                                     : s_auCSes[j] | i;
     601                        /*Bs3TestPrintf("uLine=%u iCtx=%u iRing=%u i=%u uCs=%04x type=%#x\n", uLine, iCtx, iRing, i, uCs, s_auInvlTypes[iType]);*/
     602                        MyBs3Idt[0x80 + iCtx].Gate.u16Sel = uCs;
     603                        Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
     604                        uLine++;
     605                        bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT,
     606                                                  f16BitSys, pszMode, uLine);
     607
     608                        /* Mark it not-present to check that invalid type takes precedence. */
     609                        MyBs3Idt[0x80 + iCtx].Gate.u1Present = 0;
     610                        Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx);
     611                        uLine++;
     612                        bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT,
     613                                                  f16BitSys, pszMode, uLine);
     614                        MyBs3Idt[0x80 + iCtx].Gate.u1Present = 1;
     615                    }
     616                }
     617
     618                MyBs3Idt[0x80 + iCtx].Gate.u16Sel     = MY_SYS_SEL_R0_CS;
     619                MyBs3Idt[0x80 + iCtx].Gate.u4Type     = bSavedType;
     620                MyBs3Idt[0x80 + iCtx].Gate.u1DescType = 0;
     621                MyBs3Idt[0x80 + iCtx].Gate.u1Present  = 1;
     622            }
    477623        }
    478         else
    479             Bs3TestPrintf("%s: Skipping ESP check, alloc failed\n", pszMode);
    480     }
    481     else
    482         Bs3TestPrintf("%s: Skipping ESP check, CPU too old\n", pszMode);
    483 #endif
     624    }
     625    BS3_ASSERT(uLine < 62000U && uLine > 32000U);
    484626
    485627#else
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