VirtualBox

Ignore:
Timestamp:
May 30, 2023 9:55:31 AM (23 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
157677
Message:

Runtime/common/misc/fdt.cpp: Implement loading the blocks from the I/O stream, bugref:10401

File:
1 edited

Legend:

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

    r100007 r100009  
    6868{
    6969    /** Pointer to the string block. */
    70     const char              *paszStrings;
     70    char                    *paszStrings;
     71    /** Pointer to the raw structs block. */
     72    uint32_t                *pu32Structs;
     73    /** Pointer to the array of memory reservation entries. */
     74    PDTBFDTRSVENTRY         paMemRsv;
     75    /** Number of memory reservation entries. */
     76    uint32_t                cMemRsv;
     77    /** The DTB header (converted to host endianess). */
     78    DTBFDTHDR               DtbHdr;
    7179} RTFDTINT;
    7280/** Pointer to the internal Flattened Devicetree instance. */
     
    118126 * @param   pErrInfo        Where to return additional error information.
    119127 */
    120 static int rtFdtDtbHdr_Validate(PCDTBFDTHDR pDtbHdr, uint64_t cbDtb, PRTERRINFO pErrInfo)
    121 {
    122     RT_NOREF(pDtbHdr, cbDtb, pErrInfo);
     128static int rtFdtDtbHdr_Validate(PDTBFDTHDR pDtbHdr, uint64_t cbDtb, PRTERRINFO pErrInfo)
     129{
     130    /* Convert to host endianess first. */
     131    pDtbHdr->u32Magic                   = RT_BE2H_U32(pDtbHdr->u32Magic);
     132    pDtbHdr->cbFdt                      = RT_BE2H_U32(pDtbHdr->cbFdt);
     133    pDtbHdr->offDtStruct                = RT_BE2H_U32(pDtbHdr->offDtStruct);
     134    pDtbHdr->offDtStrings               = RT_BE2H_U32(pDtbHdr->offDtStrings);
     135    pDtbHdr->offMemRsvMap               = RT_BE2H_U32(pDtbHdr->offMemRsvMap);
     136    pDtbHdr->u32Version                 = RT_BE2H_U32(pDtbHdr->u32Version);
     137    pDtbHdr->u32VersionLastCompatible   = RT_BE2H_U32(pDtbHdr->u32VersionLastCompatible);
     138    pDtbHdr->u32CpuIdPhysBoot           = RT_BE2H_U32(pDtbHdr->u32CpuIdPhysBoot);
     139    pDtbHdr->cbDtStrings                = RT_BE2H_U32(pDtbHdr->cbDtStrings);
     140    pDtbHdr->cbDtStruct                 = RT_BE2H_U32(pDtbHdr->cbDtStruct);
     141
     142    if (pDtbHdr->u32Magic != DTBFDTHDR_MAGIC)
     143        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_MAGIC_INVALID, "The magic of the DTB header is invalid (expected %#RX32, got %#RX32)",
     144                             DTBFDTHDR_MAGIC, pDtbHdr->u32Magic);
     145    if (pDtbHdr->u32Version != DTBFDTHDR_VERSION)
     146        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_VERSION_NOT_SUPPORTED, "Version %u of the DTB is not supported (supported is %u)",
     147                             pDtbHdr->u32Version, DTBFDTHDR_VERSION);
     148    if (pDtbHdr->u32VersionLastCompatible != DTBFDTHDR_VERSION_LAST_COMP)
     149        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_LAST_COMPAT_VERSION_INVALID, "Last compatible version %u of the DTB is invalid (expected %u)",
     150                             pDtbHdr->u32VersionLastCompatible, DTBFDTHDR_VERSION_LAST_COMP);
     151    if (pDtbHdr->cbFdt != cbDtb)
     152        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_SIZE_INVALID, "The size of the FDT is invalid (expected %RU32, got %RU32)",
     153                             cbDtb, pDtbHdr->cbFdt);
     154
     155    /*
     156     * Check that any of the offsets is inside the bounds of the FDT and that the memory reservation block comes first,
     157     * then the structs block and strings last.
     158     */
     159    if (   pDtbHdr->offMemRsvMap >= pDtbHdr->cbFdt
     160        || pDtbHdr->offMemRsvMap < sizeof(*pDtbHdr))
     161        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_MEM_RSV_BLOCK_OFF_INVALID, "Memory reservation block offset is out of bounds (offMemRsvMap=%#RX32 vs. cbFdt=%#%RX32)",
     162                             pDtbHdr->offMemRsvMap, pDtbHdr->cbFdt);
     163    if (   pDtbHdr->offDtStruct >= pDtbHdr->cbFdt
     164        || (pDtbHdr->cbFdt - pDtbHdr->offDtStruct < pDtbHdr->cbDtStruct)
     165        || pDtbHdr->offDtStruct <= pDtbHdr->offMemRsvMap + sizeof(DTBFDTRSVENTRY))
     166        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)",
     167                             pDtbHdr->offDtStruct, pDtbHdr->cbDtStruct, pDtbHdr->cbFdt, pDtbHdr->offMemRsvMap);
     168    if (    pDtbHdr->offDtStrings >= pDtbHdr->cbFdt
     169        || (pDtbHdr->cbFdt - pDtbHdr->offDtStrings < pDtbHdr->cbDtStrings)
     170        || pDtbHdr->offDtStrings < pDtbHdr->offDtStruct + pDtbHdr->cbDtStruct)
     171        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_STRINGS_BLOCK_OFF_INVALID, "Strings block offset/size is out of bounds (offDtStrings=%#RX32 cbDtStrings=%#RX32 vs. cbFdt=%#%RX32 offDtStruct=%#RX32)",
     172                             pDtbHdr->offDtStrings, pDtbHdr->cbDtStrings, pDtbHdr->cbFdt, pDtbHdr->offDtStruct);
     173
     174    return VINF_SUCCESS;
     175}
     176
     177
     178/**
     179 * Fres all resources allocated for the given FDT.
     180 *
     181 * @param   pThis           The FDT instance to destroy.
     182 */
     183static void rtFdtDestroy(PRTFDTINT pThis)
     184{
     185    if (pThis->paszStrings)
     186        RTMemFree(pThis->paszStrings);
     187    if (pThis->pu32Structs)
     188        RTMemFree(pThis->pu32Structs);
     189    if (pThis->paMemRsv)
     190        RTMemFree(pThis->paMemRsv);
     191
     192    pThis->paszStrings = NULL;
     193    pThis->pu32Structs = NULL;
     194    pThis->paMemRsv    = NULL;
     195    pThis->cMemRsv     = 0;
     196    RT_ZERO(pThis->DtbHdr);
     197    RTMemFree(pThis);
     198}
     199
     200
     201/**
     202 * Loads the memory reservation block from the underlying VFS I/O stream.
     203 *
     204 * @returns IPRT status code.
     205 * @param   pThis           The FDT instance.
     206 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
     207 * @param   pErrInfo        Where to return additional error information.
     208 */
     209static int rtFdtDtbMemRsvLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     210{
     211    AssertReturn(pThis->DtbHdr.offMemRsvMap < pThis->DtbHdr.offDtStruct, VERR_INTERNAL_ERROR);
     212
     213    uint32_t cMemRsvMax = (pThis->DtbHdr.offDtStruct - pThis->DtbHdr.offMemRsvMap) / sizeof(*pThis->paMemRsv);
     214    Assert(cMemRsvMax);
     215
     216    pThis->paMemRsv = (PDTBFDTRSVENTRY)RTMemAllocZ(cMemRsvMax * sizeof(*pThis->paMemRsv));
     217    if (!pThis->paMemRsv)
     218        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the memory reservation block",
     219                             cMemRsvMax * sizeof(*pThis->paMemRsv));
     220
     221    /* Read the entries one after another until the terminator is reached. */
     222    uint32_t cMemRsv = 0;
     223    for (;;)
     224    {
     225        DTBFDTRSVENTRY MemRsv;
     226        int rc = RTVfsIoStrmRead(hVfsIos, &MemRsv, sizeof(MemRsv), true /*fBlocking*/, NULL /*pcbRead*/);
     227        if (RT_FAILURE(rc))
     228            return RTErrInfoSetF(pErrInfo, rc, "Failed to read memory reservation entry %u from I/O stream",
     229                                 cMemRsv);
     230
     231        /* Check whether the terminator is reached (no need to convert endianness here). */
     232        if (   MemRsv.PhysAddrStart == 0
     233            && MemRsv.cbArea == 0)
     234            break;
     235
     236        /*
     237         * The terminator must be included in the maximum entry count, if not
     238         * the DTB is malformed and lacks a terminating entry before the start of the structs block.
     239         */
     240        if (cMemRsv + 1 == cMemRsvMax)
     241            return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MEM_RSV_BLOCK_TERMINATOR_MISSING,
     242                                 "The memory reservation block lacks a terminating entry");
     243
     244        pThis->paMemRsv[cMemRsv].PhysAddrStart = RT_BE2H_U64(MemRsv.PhysAddrStart);
     245        pThis->paMemRsv[cMemRsv].cbArea        = RT_BE2H_U64(MemRsv.cbArea);
     246        cMemRsv++;
     247    }
     248
     249    pThis->cMemRsv = cMemRsv + 1;
     250    return VINF_SUCCESS;
     251}
     252
     253
     254/**
     255 * Loads the structs block of the given FDT.
     256 *
     257 * @returns IPRT status code.
     258 * @param   pThis           The FDT instance.
     259 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
     260 * @param   pErrInfo        Where to return additional error information.
     261 */
     262static int rtFdtDtbStructsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     263{
     264    pThis->pu32Structs = (uint32_t *)RTMemAllocZ(pThis->DtbHdr.cbDtStruct);
     265    if (!pThis->pu32Structs)
     266        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the structs block",
     267                             pThis->DtbHdr.cbDtStruct);
     268
     269    int rc = RTVfsIoStrmRead(hVfsIos, pThis->pu32Structs, pThis->DtbHdr.cbDtStruct, true /*fBlocking*/, NULL /*pcbRead*/);
     270    if (RT_FAILURE(rc))
     271        return RTErrInfoSetF(pErrInfo, rc, "Failed to read structs block from I/O stream");
     272
     273    return VINF_SUCCESS;
     274}
     275
     276
     277/**
     278 * Loads the strings block of the given FDT.
     279 *
     280 * @returns IPRT status code.
     281 * @param   pThis           The FDT instance.
     282 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
     283 * @param   pErrInfo        Where to return additional error information.
     284 */
     285static int rtFdtDtbStringsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     286{
     287    pThis->paszStrings = (char *)RTMemAllocZ(pThis->DtbHdr.cbDtStrings);
     288    if (!pThis->paszStrings)
     289        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the strings block",
     290                             pThis->DtbHdr.cbDtStrings);
     291
     292    int rc = RTVfsIoStrmRead(hVfsIos, pThis->paszStrings, pThis->DtbHdr.cbDtStrings, true /*fBlocking*/, NULL /*pcbRead*/);
     293    if (RT_FAILURE(rc))
     294        return RTErrInfoSetF(pErrInfo, rc, "Failed to read strings block from I/O stream");
     295
     296    /* Verify that the strings block is terminated. */
     297    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");
     299
    123300    return VINF_SUCCESS;
    124301}
     
    153330                if (RT_SUCCESS(rc))
    154331                {
    155                     RT_NOREF(phFdt);
     332                    PRTFDTINT pThis = (PRTFDTINT)RTMemAllocZ(sizeof(*pThis));
     333                    if (RT_LIKELY(pThis))
     334                    {
     335                        memcpy(&pThis->DtbHdr, &DtbHdr, sizeof(DtbHdr));
     336
     337                        /* Load the memory reservation block. */
     338                        rc = rtFdtDtbMemRsvLoad(pThis, hVfsIos, pErrInfo);
     339                        if (RT_SUCCESS(rc))
     340                        {
     341                            rc = rtFdtDtbStructsLoad(pThis, hVfsIos, pErrInfo);
     342                            if (RT_SUCCESS(rc))
     343                            {
     344                                rc = rtFdtDtbStringsLoad(pThis, hVfsIos, pErrInfo);
     345                                if (RT_SUCCESS(rc))
     346                                {
     347                                    *phFdt = pThis;
     348                                    return VINF_SUCCESS;
     349                                }
     350                            }
     351                        }
     352
     353                        rtFdtDestroy(pThis);
     354                    }
     355                    else
     356                        RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate memory for the FDT");
    156357                }
    157358            }
    158359            else
    159                 RTErrInfoSetF(pErrInfo, rc, "Failed to read %u bytes for the DTB header -> %Rrc\n",
    160                               sizeof(DtbHdr));
     360                RTErrInfoSetF(pErrInfo, rc, "Failed to read %u bytes for the DTB header -> %Rrc",
     361                              sizeof(DtbHdr), rc);
    161362        }
    162363        else
    163             RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MALFORMED, "DTB is too small, needs at least %u bytes, only %u available\n",
     364            RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MALFORMED, "DTB is too small, needs at least %u bytes, only %u available",
    164365                          sizeof(DtbHdr) + sizeof(DTBFDTRSVENTRY), ObjInfo.cbObject);
    165366    }
    166367    else
    167         RTErrInfoSetF(pErrInfo, rc, "Failed to query size of the DTB -> %Rrc\n", rc);
     368        RTErrInfoSetF(pErrInfo, rc, "Failed to query size of the DTB -> %Rrc", rc);
    168369
    169370    return rc;
     
    199400RTDECL(void) RTFdtDestroy(RTFDT hFdt)
    200401{
    201     RT_NOREF(hFdt);
     402    PRTFDTINT pThis = hFdt;
     403    AssertPtrReturnVoid(pThis);
     404
     405    rtFdtDestroy(pThis);
    202406}
    203407
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