VirtualBox

Changeset 100022 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
May 31, 2023 8:40:43 AM (18 months ago)
Author:
vboxsync
Message:

Runtime/RTFdt: Implement parsing Devicetree blobs (DTB) and output a DTS, bugref:10401

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/misc/fdt.cpp

    r100009 r100022  
    5656*   Defined Constants And Macros                                                                                                 *
    5757*********************************************************************************************************************************/
     58
     59/** Special error token to denote that the end of the structs block was reached trying to query the next token. */
     60#define RTFDT_TOKEN_ERROR                       UINT32_MAX
    5861
    5962
     
    8083/** Pointer to the internal Flattened Devicetree instance. */
    8184typedef RTFDTINT *PRTFDTINT;
     85
     86
     87/**
     88 * DTB property dump callback.
     89 *
     90 * @returns IPRT status code.
     91 * @param   pThis           Pointer to the FDT instance.
     92 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
     93 * @param   pszProperty     Property name.
     94 * @param   pvProperty      Pointer to the raw property data.
     95 * @param   cbProperty      Size of the property in bytes.
     96 * @param   pErrInfo        Where to return additional error information.
     97 */
     98typedef DECLCALLBACKTYPE(int, FNRTFDTDTBPROPERTYDUMP,(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
     99                                                      const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo));
     100/** Pointer to a DTB property dump callback. */
     101typedef FNRTFDTDTBPROPERTYDUMP *PFNRTFDTDTBPROPERTYDUMP;
     102
     103
     104/**
     105 * DTB property dump descriptor.
     106 */
     107typedef struct RTFDTDTBPROPDUMPDESC
     108{
     109    /** Name of the property. */
     110    const char              *pszProperty;
     111    /** The dump callback. */
     112    PFNRTFDTDTBPROPERTYDUMP pfnDump;
     113} RTFDTDTBPROPDUMPDESC;
     114/** Pointer to a property dump descriptor. */
     115typedef RTFDTDTBPROPDUMPDESC *PRTFDTDTBPROPDUMPDESC;
     116/** Pointer to a const property dump descriptor. */
     117typedef const RTFDTDTBPROPDUMPDESC *PCRTFDTDTBPROPDUMPDESC;
     118
     119
     120/**
     121 * DTB struct dump state.
     122 */
     123typedef struct RTFDTDTBDUMP
     124{
     125    /** Number of bytes left in the structs block to dump. */
     126    size_t                  cbLeft;
     127    /** Pointer to the next item in the structs block. */
     128    const uint8_t           *pbStructs;
     129} RTFDTDTBDUMP;
     130/** Pointer to a DTB struct dump state. */
     131typedef RTFDTDTBDUMP *PRTFDTDTBDUMP;
     132/** Pointer to a constant DTB struct dump state. */
     133typedef const RTFDTDTBDUMP *PCRTFDTDTBDUMP;
    82134
    83135
     
    163215    if (   pDtbHdr->offDtStruct >= pDtbHdr->cbFdt
    164216        || (pDtbHdr->cbFdt - pDtbHdr->offDtStruct < pDtbHdr->cbDtStruct)
    165         || pDtbHdr->offDtStruct <= pDtbHdr->offMemRsvMap + sizeof(DTBFDTRSVENTRY))
     217        || pDtbHdr->offDtStruct < pDtbHdr->offMemRsvMap + sizeof(DTBFDTRSVENTRY))
    166218        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_STRUCT_BLOCK_OFF_INVALID, "Structs block offset/size is out of bounds (offDtStruct=%#RX32 cbDtStruct=%#RX32 vs. cbFdt=%#RX32 offMemRsvMap=%#RX32)",
    167219                             pDtbHdr->offDtStruct, pDtbHdr->cbDtStruct, pDtbHdr->cbFdt, pDtbHdr->offMemRsvMap);
     
    179231 * Fres all resources allocated for the given FDT.
    180232 *
    181  * @param   pThis           The FDT instance to destroy.
     233 * @param   pThis           Pointer to the FDT instance to destroy.
    182234 */
    183235static void rtFdtDestroy(PRTFDTINT pThis)
     
    203255 *
    204256 * @returns IPRT status code.
    205  * @param   pThis           The FDT instance.
     257 * @param   pThis           Pointer to the FDT instance.
    206258 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
    207259 * @param   pErrInfo        Where to return additional error information.
     
    234286            break;
    235287
     288        cMemRsv++;
     289
    236290        /*
    237291         * The terminator must be included in the maximum entry count, if not
    238292         * the DTB is malformed and lacks a terminating entry before the start of the structs block.
    239293         */
    240         if (cMemRsv + 1 == cMemRsvMax)
     294        if (cMemRsv == cMemRsvMax)
    241295            return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MEM_RSV_BLOCK_TERMINATOR_MISSING,
    242296                                 "The memory reservation block lacks a terminating entry");
    243297
    244         pThis->paMemRsv[cMemRsv].PhysAddrStart = RT_BE2H_U64(MemRsv.PhysAddrStart);
    245         pThis->paMemRsv[cMemRsv].cbArea        = RT_BE2H_U64(MemRsv.cbArea);
    246         cMemRsv++;
     298        pThis->paMemRsv[cMemRsv - 1].PhysAddrStart = RT_BE2H_U64(MemRsv.PhysAddrStart);
     299        pThis->paMemRsv[cMemRsv - 1].cbArea        = RT_BE2H_U64(MemRsv.cbArea);
    247300    }
    248301
    249     pThis->cMemRsv = cMemRsv + 1;
     302    pThis->cMemRsv = cMemRsv;
    250303    return VINF_SUCCESS;
    251304}
     
    256309 *
    257310 * @returns IPRT status code.
    258  * @param   pThis           The FDT instance.
     311 * @param   pThis           Pointer to the FDT instance.
    259312 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
    260313 * @param   pErrInfo        Where to return additional error information.
     
    267320                             pThis->DtbHdr.cbDtStruct);
    268321
    269     int rc = RTVfsIoStrmRead(hVfsIos, pThis->pu32Structs, pThis->DtbHdr.cbDtStruct, true /*fBlocking*/, NULL /*pcbRead*/);
     322    int rc = RTVfsIoStrmReadAt(hVfsIos, pThis->DtbHdr.offDtStruct, pThis->pu32Structs, pThis->DtbHdr.cbDtStruct,
     323                               true /*fBlocking*/, NULL /*pcbRead*/);
    270324    if (RT_FAILURE(rc))
    271325        return RTErrInfoSetF(pErrInfo, rc, "Failed to read structs block from I/O stream");
     
    279333 *
    280334 * @returns IPRT status code.
    281  * @param   pThis           The FDT instance.
     335 * @param   pThis           Pointer to the FDT instance.
    282336 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
    283337 * @param   pErrInfo        Where to return additional error information.
     
    290344                             pThis->DtbHdr.cbDtStrings);
    291345
    292     int rc = RTVfsIoStrmRead(hVfsIos, pThis->paszStrings, pThis->DtbHdr.cbDtStrings, true /*fBlocking*/, NULL /*pcbRead*/);
     346    int rc = RTVfsIoStrmReadAt(hVfsIos, pThis->DtbHdr.offDtStrings, pThis->paszStrings, pThis->DtbHdr.cbDtStrings,
     347                               true /*fBlocking*/, NULL /*pcbRead*/);
    293348    if (RT_FAILURE(rc))
    294349        return RTErrInfoSetF(pErrInfo, rc, "Failed to read strings block from I/O stream");
     
    296351    /* Verify that the strings block is terminated. */
    297352    if (pThis->paszStrings[pThis->DtbHdr.cbDtStrings - 1] != '\0')
    298         return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRINGS_BLOCK_NOT_TERMINATED, "The strings block is not zero temrinated");
     353        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRINGS_BLOCK_NOT_TERMINATED, "The strings block is not zero terminated");
    299354
    300355    return VINF_SUCCESS;
     
    372427
    373428
     429/**
     430 * Returns the next token in the structs block from the given start returning an error
     431 * if beyond the structs block.
     432 *
     433 * @returns Next token or RTFDT_TOKEN_ERROR if the end of the structs block is reached.
     434 * @param   pDump           Pointer to the dump state.
     435 */
     436DECLINLINE(uint32_t) rtFdtStructsGetToken(PRTFDTDTBDUMP pDump)
     437{
     438    if (pDump->cbLeft < sizeof(uint32_t))
     439        return RTFDT_TOKEN_ERROR;
     440
     441    uint32_t u32Token = *(const uint32_t *)pDump->pbStructs;
     442    pDump->pbStructs += sizeof(uint32_t);
     443    pDump->cbLeft    -= sizeof(uint32_t);
     444    return u32Token;
     445}
     446
     447
     448/**
     449 * Gets the offset inside the structs block given from the current pointer.
     450 *
     451 * @returns Offset in bytes from the start of the structs block.
     452 * @param   pThis           Pointer to the FDT instance.
     453 * @param   pDump           Pointer to the dump state.
     454 */
     455DECLINLINE(uint32_t) rtFdtStructsGetOffset(PRTFDTINT pThis, PCRTFDTDTBDUMP pDump)
     456{
     457    return pThis->DtbHdr.cbDtStruct - pDump->cbLeft - sizeof(uint32_t);
     458}
     459
     460
     461/**
     462 * Advances the pointer inside the dump state by the given amount of bytes taking care of the alignment.
     463 *
     464 * @returns IPRT status code.
     465 * @param   pDump           Pointer to the dump state.
     466 * @param   cbAdv           How many bytes to advance.
     467 * @param   rcOob           The status code to set if advancing goes beyond the end of the structs block.
     468 */
     469DECLINLINE(int) rtFdtStructsDumpAdvance(PRTFDTDTBDUMP pDump, uint32_t cbAdv, int rcOob)
     470{
     471    /* Align the pointer to the next 32-bit boundary. */
     472    const uint8_t *pbStructsNew = RT_ALIGN_PT(pDump->pbStructs + cbAdv, sizeof(uint32_t), uint8_t *);
     473    if (((uintptr_t)pbStructsNew - (uintptr_t)pDump->pbStructs) > pDump->cbLeft)
     474        return rcOob;
     475
     476    pDump->pbStructs = pbStructsNew;
     477    pDump->cbLeft   -= (uintptr_t)pbStructsNew - (uintptr_t)pDump->pbStructs;
     478    return VINF_SUCCESS;
     479}
     480
     481
     482/**
     483 * Adds the proper indentation before a new line.
     484 *
     485 * @returns IPRT status code.
     486 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     487 * @param   uIndentLvl      The level of indentation.
     488 */
     489static int rtFdtStructsDumpDtsIndent(RTVFSIOSTREAM hVfsIos, uint32_t uIndentLvl)
     490{
     491    while (uIndentLvl--)
     492    {
     493        ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "    ");
     494        if (cch != 4)
     495            return cch < 0 ? -cch : VERR_BUFFER_UNDERFLOW;
     496    }
     497
     498    return VINF_SUCCESS;
     499}
     500
     501
     502/**
     503 * Queries a zero terminated ASCII string from the current location inside the structs block.
     504 *
     505 * @returns IPRT status code.
     506 * @param   pDump           The dump state.
     507 * @param   pszString       The string buffer to copy the string to.
     508 * @param   cchStringMax    Maximum size of the string buffer in characters (including the terminator).
     509 * @param   pErrInfo        Where to return additional error information.
     510 */
     511static int rtFdtStructsQueryString(PRTFDTDTBDUMP pDump, char *pszString, size_t cchStringMax, PRTERRINFO pErrInfo)
     512{
     513    const char *pszStrSrc = (const char *)pDump->pbStructs;
     514    size_t cbLeft = pDump->cbLeft;
     515
     516    AssertReturn(cchStringMax, VERR_INTERNAL_ERROR);
     517
     518    for (;;)
     519    {
     520        *pszString++ = *pszStrSrc;
     521        cchStringMax--;
     522        cbLeft--;
     523
     524        if (*pszStrSrc == '\0')
     525        {
     526            pszStrSrc++;
     527
     528            int rc = rtFdtStructsDumpAdvance(pDump, (uintptr_t)pszStrSrc - (uintptr_t)pDump->pbStructs, VERR_FDT_DTB_STRUCTS_BLOCK_MALFORMED_PADDING);
     529            if (RT_FAILURE(rc))
     530                return RTErrInfoSetF(pErrInfo, rc, "String end + padding exceeds structs block");
     531
     532            return VINF_SUCCESS;
     533        }
     534
     535        if (!cchStringMax)
     536            return RTErrInfoSetF(pErrInfo, VERR_BUFFER_OVERFLOW, "Structs string too long to fit into target buffer");
     537
     538        *pszStrSrc++;
     539        if (!cbLeft)
     540            return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_STRING_NOT_TERMINATED, "Structs block contains an unterminated string");
     541    }
     542
     543    /* Not reached */
     544    return VERR_INTERNAL_ERROR;
     545}
     546
     547
     548/**
     549 * Dumps a string list property.
     550 *
     551 * @returns IPRT status code.
     552 * @param   pThis           Pointer to the FDT instance.
     553 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     554 * @param   pszProperty     Name of the property being dumped.
     555 * @param   pvProperty      Raw property payload.
     556 * @param   cbProperty      Size of the property payload in bytes.
     557 * @param   pErrInfo        Where to return additional error information.
     558 */
     559static DECLCALLBACK(int) rtFdtDtbPropDumpStringList(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
     560                                                    const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo)
     561{
     562    RT_NOREF(pThis);
     563
     564    const char *pszProp = (const char *)pvProperty;
     565    if (pszProp[cbProperty - 1] != '\0')
     566        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_STRING_NOT_TERMINATED,
     567                             "The string payload of property '%s' is not terminated", pszProperty);
     568
     569    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "\"%s\"", pszProp);
     570    if (cch <= 0)
     571        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
     572
     573    cch = strlen(pszProp) + 1;
     574    cbProperty -= cch;
     575    while (cbProperty)
     576    {
     577        pszProp += cch;
     578
     579        cch = RTVfsIoStrmPrintf(hVfsIos, ", \"%s\"", pszProp);
     580        if (cch <= 0)
     581            return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
     582
     583        cch = strlen(pszProp) + 1;
     584        cbProperty -= cch;
     585    }
     586
     587    return VINF_SUCCESS;
     588}
     589
     590
     591/**
     592 * Dumps a string property.
     593 *
     594 * @returns IPRT status code.
     595 * @param   pThis           Pointer to the FDT instance.
     596 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     597 * @param   pszProperty     Name of the property being dumped.
     598 * @param   pvProperty      Raw property payload.
     599 * @param   cbProperty      Size of the property payload in bytes.
     600 * @param   pErrInfo        Where to return additional error information.
     601 */
     602static DECLCALLBACK(int) rtFdtDtbPropDumpString(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
     603                                                const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo)
     604{
     605    RT_NOREF(pThis);
     606
     607    const char *pszProp = (const char *)pvProperty;
     608    if (pszProp[cbProperty - 1] != '\0')
     609        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_STRING_NOT_TERMINATED,
     610                             "The string payload of property '%s' is not terminated", pszProperty);
     611
     612    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "\"%s\"", pszProp);
     613    if (cch <= 0)
     614        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
     615
     616    return VINF_SUCCESS;
     617}
     618
     619
     620/**
     621 * Dumps a <u32> cell property.
     622 *
     623 * @returns IPRT status code.
     624 * @param   pThis           Pointer to the FDT instance.
     625 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     626 * @param   pszProperty     Name of the property being dumped.
     627 * @param   pvProperty      Raw property payload.
     628 * @param   cbProperty      Size of the property payload in bytes.
     629 * @param   pErrInfo        Where to return additional error information.
     630 */
     631static DECLCALLBACK(int) rtFdtDtbPropDumpCellsU32(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
     632                                                  const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo)
     633{
     634    RT_NOREF(pThis);
     635
     636    if (cbProperty % sizeof(uint32_t))
     637        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_SIZE_MALFORMED,
     638                             "Property '%s' payload is not a multiple of 32-bit", pszProperty);
     639
     640    const uint32_t *pu32Prop = (const uint32_t *)pvProperty;
     641
     642    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "<");
     643    if (cch == 1)
     644    {
     645        cch = RTVfsIoStrmPrintf(hVfsIos, "%#RX32", RT_BE2H_U32(*pu32Prop));
     646        pu32Prop++;
     647        if (cch > 0)
     648        {
     649            for (uint32_t i = 1; i < cbProperty / sizeof(uint32_t); i++)
     650            {
     651                cch = RTVfsIoStrmPrintf(hVfsIos, " %#RX32", RT_BE2H_U32(*pu32Prop));
     652                pu32Prop++;
     653                if (cch <= 0)
     654                    break;
     655            }
     656        }
     657
     658        if (cch > 0)
     659            cch = RTVfsIoStrmPrintf(hVfsIos, ">");
     660    }
     661
     662    if (cch <= 0)
     663        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
     664
     665    return VINF_SUCCESS;
     666}
     667
     668
     669/**
     670 * The known properties to dump.
     671 */
     672static const RTFDTDTBPROPDUMPDESC g_aPropDump[] =
     673{
     674    { "compatible",             rtFdtDtbPropDumpStringList  }, /** @todo stringlist */
     675    { "model",                  rtFdtDtbPropDumpString      },
     676    { "status",                 rtFdtDtbPropDumpString      },
     677    { "phandle",                rtFdtDtbPropDumpCellsU32    },
     678    { "linux,phandle",          rtFdtDtbPropDumpCellsU32    },
     679    { "#address-cells",         rtFdtDtbPropDumpCellsU32    },
     680    { "#size-cells",            rtFdtDtbPropDumpCellsU32    },
     681    { "reg",                    rtFdtDtbPropDumpCellsU32    },
     682    { "virtual-reg",            rtFdtDtbPropDumpCellsU32    },
     683    { "ranges",                 rtFdtDtbPropDumpCellsU32    },
     684    { "dma-ranges",             rtFdtDtbPropDumpCellsU32    },
     685    { "name",                   rtFdtDtbPropDumpString      },
     686    { "device_type",            rtFdtDtbPropDumpString      },
     687    { "interrupts",             rtFdtDtbPropDumpCellsU32    },
     688    { "interrupt-parent",       rtFdtDtbPropDumpCellsU32    },
     689    { "interrupts-extended",    rtFdtDtbPropDumpCellsU32    },
     690    { "#interrupt-cells",       rtFdtDtbPropDumpCellsU32    },
     691    { "interrupt-map",          rtFdtDtbPropDumpCellsU32    },
     692    { "interrupt-map-mask",     rtFdtDtbPropDumpCellsU32    },
     693    { "serial-number",          rtFdtDtbPropDumpString      },
     694    { "chassis-type",           rtFdtDtbPropDumpString      },
     695    { "clock-frequency",        rtFdtDtbPropDumpCellsU32    },
     696    { "reg-shift",              rtFdtDtbPropDumpCellsU32    },
     697    { "label",                  rtFdtDtbPropDumpString      },
     698    { "clock-names",            rtFdtDtbPropDumpStringList  },
     699    { "clock-output-names",     rtFdtDtbPropDumpStringList  },
     700    { "stdout-path",            rtFdtDtbPropDumpString      },
     701    { "method",                 rtFdtDtbPropDumpString      },
     702};
     703
     704
     705/**
     706 * Dumps the property as a DTS source starting at the given location inside the structs block.
     707 *
     708 * @returns IPRT status code.
     709 * @param   pThis           Pointer to the FDT instance.
     710 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     711 * @param   pDump           The dump state.
     712 * @param   uIndentLvl      The level of indentation.
     713 * @param   pErrInfo        Where to return additional error information.
     714 */
     715static int rtFdtStructsDumpPropertyAsDts(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTFDTDTBDUMP pDump, uint32_t uIndentLvl, PRTERRINFO pErrInfo)
     716{
     717    DTBFDTPROP Prop;
     718
     719    if (pDump->cbLeft < sizeof(Prop))
     720        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END,
     721                             "Not enough space left in the structs block to read a property entry");
     722
     723    memcpy(&Prop, pDump->pbStructs, sizeof(Prop));
     724    pDump->pbStructs += sizeof(Prop);
     725    pDump->cbLeft    -= sizeof(Prop);
     726    Prop.offPropertyName = RT_BE2H_U32(Prop.offPropertyName);
     727    Prop.cbProperty      = RT_BE2H_U32(Prop.cbProperty);
     728
     729    if (Prop.offPropertyName >= pThis->DtbHdr.cbDtStrings)
     730        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_NAME_OFF_TOO_LARGE, "Property name offset points past the string block");
     731
     732    int rc = rtFdtStructsDumpDtsIndent(hVfsIos, uIndentLvl);
     733    if (RT_FAILURE(rc))
     734        return rc;
     735
     736    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "%s", &pThis->paszStrings[Prop.offPropertyName]);
     737    if (cch <= 0)
     738        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property name: '%s'",
     739                             &pThis->paszStrings[Prop.offPropertyName]);
     740
     741    const uint8_t *pbProp = pDump->pbStructs;
     742    if (Prop.cbProperty)
     743    {
     744        if (Prop.cbProperty > pDump->cbLeft)
     745            return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END, "Property '%s' data exceeds struct blocks",
     746                                 &pThis->paszStrings[Prop.offPropertyName]);
     747
     748        cch = RTVfsIoStrmPrintf(hVfsIos, " = ");
     749        if (cch <= 0)
     750            return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to output property");
     751
     752        rc = VERR_NOT_FOUND;
     753        for (uint32_t i = 0; i < RT_ELEMENTS(g_aPropDump); i++)
     754        {
     755            if (!strcmp(g_aPropDump[i].pszProperty, &pThis->paszStrings[Prop.offPropertyName]))
     756            {
     757                rc = g_aPropDump[i].pfnDump(pThis, hVfsIos, &pThis->paszStrings[Prop.offPropertyName],
     758                                            pbProp, Prop.cbProperty, pErrInfo);
     759                break;
     760            }
     761        }
     762
     763        /* If not found use the standard U32 cells dumper. */
     764        if (rc == VERR_NOT_FOUND)
     765            rc = rtFdtDtbPropDumpCellsU32(pThis, hVfsIos, &pThis->paszStrings[Prop.offPropertyName],
     766                                          pbProp, Prop.cbProperty, pErrInfo);
     767        if (RT_FAILURE(rc))
     768            return rc;
     769
     770        cch = RTVfsIoStrmPrintf(hVfsIos, ";\n");
     771        if (cch <= 0)
     772            return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to output property");
     773
     774        rc = rtFdtStructsDumpAdvance(pDump, Prop.cbProperty, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END);
     775    }
     776    else
     777    {
     778        cch = RTVfsIoStrmPrintf(hVfsIos, ";\n");
     779        if (cch <= 0)
     780            return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write newline");
     781    }
     782
     783    return rc;
     784}
     785
     786
     787/**
     788 * Dumps the node name as a DTS source starting at the given location inside the structs block.
     789 *
     790 * @returns IPRT status code.
     791 * @param   pThis           Pointer to the FDT instance.
     792 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     793 * @param   pDump           The dump state.
     794 * @param   uIndentLvl      The level of indentation.
     795 * @param   pErrInfo        Where to return additional error information.
     796 */
     797static int rtFdtStructsDumpNodeAsDts(RTVFSIOSTREAM hVfsIos, PRTFDTDTBDUMP pDump, uint32_t uIndentLvl, PRTERRINFO pErrInfo)
     798{
     799    char szNdName[512]; /* Should be plenty. */
     800
     801    int rc = rtFdtStructsQueryString(pDump, &szNdName[0], sizeof(szNdName), pErrInfo);
     802    if (RT_FAILURE(rc))
     803        return rc;
     804
     805    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "\n", szNdName);
     806    if (cch <= 0)
     807        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS node name");
     808
     809    rc = rtFdtStructsDumpDtsIndent(hVfsIos, uIndentLvl);
     810    if (RT_FAILURE(rc))
     811        return rc;
     812
     813    cch = RTVfsIoStrmPrintf(hVfsIos, "%s {\n", szNdName);
     814    if (cch <= 0)
     815        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS node name");
     816
     817    return VINF_SUCCESS;
     818}
     819
     820
     821static int rtFdtStructsDumpEndNodeAsDts(RTVFSIOSTREAM hVfsIos, uint32_t uIndentLvl, PRTERRINFO pErrInfo)
     822{
     823    int rc = rtFdtStructsDumpDtsIndent(hVfsIos, uIndentLvl);
     824    if (RT_FAILURE(rc))
     825        return rc;
     826
     827    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "};\n");
     828    if (cch <= 0)
     829        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS node closing");
     830
     831    return VINF_SUCCESS;
     832}
     833
     834
     835/**
     836 * Dumps the given FDT as DTS v1 sources from the root node.
     837 *
     838 * @returns IPRT status code.
     839 * @param   pThis           Pointer to the FDT instance.
     840 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     841 * @param   pErrInfo        Where to return additional error information.
     842 */
     843static int rtFdtDumpRootAsDts(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     844{
     845    RTFDTDTBDUMP Dump;
     846
     847    Dump.cbLeft    = pThis->DtbHdr.cbDtStruct;
     848    Dump.pbStructs = (const uint8_t *)pThis->pu32Structs;
     849
     850    /* Skip any NOP tokens. */
     851    uint32_t u32Token = rtFdtStructsGetToken(&Dump);
     852    while (u32Token == DTB_FDT_TOKEN_NOP_BE)
     853        u32Token = rtFdtStructsGetToken(&Dump);
     854
     855    /* The root node starts with a BEGIN_NODE token. */
     856    if (u32Token != DTB_FDT_TOKEN_BEGIN_NODE_BE)
     857        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_TOKEN_INVALID, "The structs block doesn't start with the BEGIN_NODE token for the root node: %#RX32",
     858                             RT_BE2H_U32(u32Token));
     859
     860    /* Load the name for the root node (should be an empty string). */
     861    char chNdRootName;
     862    int rc = rtFdtStructsQueryString(&Dump, &chNdRootName, sizeof(chNdRootName), pErrInfo);
     863    if (RT_FAILURE(rc))
     864        return rc;
     865
     866    if (chNdRootName != '\0')
     867        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_NODE_NAME_INVALID, "The root node name isn't zero terminated: %c",
     868                             chNdRootName);
     869
     870    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "/ {\n");
     871    if (cch <= 0)
     872        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS root node");
     873
     874    uint32_t uNdLvl = 1;
     875    u32Token = rtFdtStructsGetToken(&Dump);
     876    while (u32Token != DTB_FDT_TOKEN_END_BE)
     877    {
     878        Log4(("rtFdtDumpAsDtsRoot: Token %#RX32 at offset %#RX32\n", RT_BE2H_U32(u32Token), rtFdtStructsGetOffset(pThis, &Dump)));
     879
     880        switch (u32Token)
     881        {
     882            case DTB_FDT_TOKEN_BEGIN_NODE_BE:
     883                Log3(("rtFdtDumpAsDtsRoot: BEGIN_NODE token at offset %#RX32\n", rtFdtStructsGetOffset(pThis, &Dump)));
     884                rc = rtFdtStructsDumpNodeAsDts(hVfsIos, &Dump, uNdLvl, pErrInfo);
     885                if (RT_FAILURE(rc))
     886                    return rc;
     887
     888                uNdLvl++;
     889                break;
     890            case DTB_FDT_TOKEN_PROPERTY_BE:
     891                Log3(("rtFdtDumpAsDtsRoot: PROP token at offset %#RX32\n", rtFdtStructsGetOffset(pThis, &Dump)));
     892                rc = rtFdtStructsDumpPropertyAsDts(pThis, hVfsIos, &Dump, uNdLvl, pErrInfo);
     893                if (RT_FAILURE(rc))
     894                    return rc;
     895                break;
     896            case DTB_FDT_TOKEN_NOP_BE:
     897                Log3(("rtFdtDumpAsDtsRoot: NOP token at offset %#RX32\n", rtFdtStructsGetOffset(pThis, &Dump)));
     898                break;
     899            case DTB_FDT_TOKEN_END_NODE_BE:
     900                Log3(("rtFdtDumpAsDtsRoot: END_NODE token at offset %#RX32\n", rtFdtStructsGetOffset(pThis, &Dump)));
     901                if (!uNdLvl)
     902                    return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END,
     903                                         "END_NODE token encountered at the root node");
     904
     905                uNdLvl--;
     906                rc = rtFdtStructsDumpEndNodeAsDts(hVfsIos, uNdLvl, pErrInfo);
     907                if (RT_FAILURE(rc))
     908                    return rc;
     909                break;
     910            case RTFDT_TOKEN_ERROR:
     911                return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_TOKEN_INVALID, "The structs block is malformed");
     912            default:
     913                return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_TOKEN_INVALID, "The structs block contains an invalid/unknown token: %#RX32",
     914                                     RT_BE2H_U32(u32Token));
     915        }
     916
     917        u32Token = rtFdtStructsGetToken(&Dump);
     918        if (u32Token == DTB_FDT_TOKEN_END_BE)
     919            Log3(("rtFdtDumpAsDtsRoot: END token at offset %#RX32\n", rtFdtStructsGetOffset(pThis, &Dump)));
     920    }
     921
     922    /* Need to end on an END token. */
     923    if (u32Token != DTB_FDT_TOKEN_END_BE)
     924        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_TOKEN_INVALID, "The structs block doesn't end with an END token (got %#RX32, expected %#RX32)",
     925                             RT_BE2H_U32(u32Token), DTB_FDT_TOKEN_END);
     926
     927    return VINF_SUCCESS;
     928}
     929
     930
     931/**
     932 * Dumps the given FDT instance as DTS source.
     933 *
     934 * @returns IPRT status code.
     935 * @param   pThis           Pointer to the FDT instance.
     936 * @param   hVfsIos         The VFS I/O stream handle to dump the DTS to.
     937 * @param   pErrInfo        Where to return additional error information.
     938 */
     939static int rtFdtDumpAsDts(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     940{
     941    ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "/dts-v1/;\n");
     942    if (cch <= 0)
     943        return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS header");
     944
     945    /* Write memory reservations. */
     946    for (uint32_t i = 0; i < pThis->cMemRsv; i++)
     947    {
     948        cch = RTVfsIoStrmPrintf(hVfsIos, "/memreserve/ %#RX64 %#RX64;\n", pThis->paMemRsv[i].PhysAddrStart, pThis->paMemRsv[i].cbArea);
     949        if (cch <= 0)
     950            return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write memory reervation block %u", i);
     951    }
     952
     953    /* Dump the tree. */
     954    return rtFdtDumpRootAsDts(pThis, hVfsIos, pErrInfo);
     955}
     956
     957
    374958RTDECL(int) RTFdtCreateEmpty(PRTFDT phFdt)
    375959{
     
    407991
    408992
    409 RTDECL(int) RTFdtDumpToVfsIoStrm(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, RTVFSIOSTREAM hVfsIos)
    410 {
    411     RT_NOREF(hFdt, enmOutType, fFlags, hVfsIos);
     993RTDECL(int) RTFdtDumpToVfsIoStrm(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     994{
     995    PRTFDTINT pThis = hFdt;
     996    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     997
     998    RT_NOREF(fFlags);
     999    if (enmOutType == RTFDTTYPE_DTS)
     1000        return rtFdtDumpAsDts(pThis, hVfsIos, pErrInfo);
     1001
    4121002    return VERR_NOT_IMPLEMENTED;
    4131003}
    4141004
    4151005
    416 RTDECL(int) RTFdtDumpToFile(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, const char *pszFilename)
    417 {
    418     RT_NOREF(hFdt, enmOutType, fFlags, pszFilename);
     1006RTDECL(int) RTFdtDumpToFile(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
     1007{
     1008    RT_NOREF(hFdt, enmOutType, fFlags, pszFilename, pErrInfo);
    4191009    return VERR_NOT_IMPLEMENTED;
    4201010}
  • trunk/src/VBox/Runtime/tools/RTDtc.cpp

    r100006 r100022  
    206206        if (RT_SUCCESS(rc))
    207207        {
    208             rc = RTFdtDumpToVfsIoStrm(hFdt, pOpts->enmOutType, 0 /*fFlags*/, hVfsIosDst);
    209             if (RT_FAILURE(rc))
     208            rc = RTFdtDumpToVfsIoStrm(hFdt, pOpts->enmOutType, 0 /*fFlags*/, hVfsIosDst, RTErrInfoInitStatic(&ErrInfo));
     209            if (RT_FAILURE(rc) && RTErrInfoIsSet(&ErrInfo.Core))
     210                rc =  RTMsgErrorRc(rc, "Writing the devicetree failed: %Rrc - %s", rc, ErrInfo.Core.pszMsg);
     211            else if (RT_FAILURE(rc))
    210212                rc = RTMsgErrorRc(rc, "Writing the devicetree failed: %Rrc\n", rc);
    211213            RTVfsIoStrmRelease(hVfsIosDst);
    212214        }
    213215        RTFdtDestroy(hFdt);
     216    }
     217    else
     218    {
     219        if (RTErrInfoIsSet(&ErrInfo.Core))
     220            rc = RTMsgErrorRc(rc, "Loading the devicetree blob failed: %Rrc - %s", rc, ErrInfo.Core.pszMsg);
     221        else
     222            rc = RTMsgErrorRc(rc, "Loading the devicetree blob failed: %Rrc\n", rc);
    214223    }
    215224
     
    275284                    if (rcExit2 != RTEXITCODE_SUCCESS)
    276285                        rcExit = rcExit2;
     286                    fContinue = false;
    277287                    break;
    278288                }
     
    287297                    break;
    288298
     299                case 'o':
     300                    Opts.pszOutFile = ValueUnion.psz;
     301                    break;
     302
    289303                case 'O':
    290304                    Opts.enmOutType = rtCmdDtcParseOutputType(ValueUnion.psz);
Note: See TracChangeset for help on using the changeset viewer.

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