VirtualBox

Changeset 100029 in vbox for trunk/src/VBox/Runtime/common


Ignore:
Timestamp:
Jun 1, 2023 11:06:25 AM (20 months ago)
Author:
vboxsync
Message:

Runtime/RTFdt: Some untested generator API + implementation, bugref:10401

File:
1 edited

Legend:

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

    r100024 r100029  
    4747#include <iprt/log.h>
    4848#include <iprt/mem.h>
    49 #include <iprt/strcache.h>
     49#include <iprt/sg.h>
    5050#include <iprt/string.h>
    5151#include <iprt/vfs.h>
     52#include <iprt/zero.h>
    5253#include <iprt/formats/dtb.h>
    5354
     
    7374    char                    *paszStrings;
    7475    /** Pointer to the raw structs block. */
    75     uint32_t                *pu32Structs;
     76    uint8_t                 *pbStruct;
    7677    /** Pointer to the array of memory reservation entries. */
    7778    PDTBFDTRSVENTRY         paMemRsv;
    7879    /** Number of memory reservation entries. */
    7980    uint32_t                cMemRsv;
    80     /** The DTB header (converted to host endianess). */
    81     DTBFDTHDR               DtbHdr;
     81    /** Maximum number of memory reservation entries allocated. */
     82    uint32_t                cMemRsvMax;
     83    /** Size of the strings block. */
     84    uint32_t                cbStrings;
     85    /** Allocated size of the string block. */
     86    uint32_t                cbStringsMax;
     87    /** Size of the struct block. */
     88    uint32_t                cbStruct;
     89    /** Allocated size of the struct block. */
     90    uint32_t                cbStructMax;
     91    /** The physical boot CPU ID. */
     92    uint32_t                u32CpuIdPhysBoot;
     93    /** Current tree depth in the structure block. */
     94    uint32_t                cTreeDepth;
    8295} RTFDTINT;
    8396/** Pointer to the internal Flattened Devicetree instance. */
     
    237250    if (pThis->paszStrings)
    238251        RTMemFree(pThis->paszStrings);
    239     if (pThis->pu32Structs)
    240         RTMemFree(pThis->pu32Structs);
     252    if (pThis->pbStruct)
     253        RTMemFree(pThis->pbStruct);
    241254    if (pThis->paMemRsv)
    242255        RTMemFree(pThis->paMemRsv);
    243256
    244     pThis->paszStrings = NULL;
    245     pThis->pu32Structs = NULL;
    246     pThis->paMemRsv    = NULL;
    247     pThis->cMemRsv     = 0;
    248     RT_ZERO(pThis->DtbHdr);
     257    pThis->paszStrings      = NULL;
     258    pThis->pbStruct         = NULL;
     259    pThis->paMemRsv         = NULL;
     260    pThis->cMemRsv          = 0;
     261    pThis->cMemRsvMax       = 0;
     262    pThis->cbStrings        = 0;
     263    pThis->cbStringsMax     = 0;
     264    pThis->cbStruct         = 0;
     265    pThis->cbStructMax      = 0;
     266    pThis->u32CpuIdPhysBoot = 0;
     267    pThis->cTreeDepth       = 0;
    249268    RTMemFree(pThis);
    250269}
     
    256275 * @returns IPRT status code.
    257276 * @param   pThis           Pointer to the FDT instance.
     277 * @param   pDtbHdr         The DTB header.
    258278 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
    259279 * @param   pErrInfo        Where to return additional error information.
    260280 */
    261 static int rtFdtDtbMemRsvLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
    262 {
    263     AssertReturn(pThis->DtbHdr.offMemRsvMap < pThis->DtbHdr.offDtStruct, VERR_INTERNAL_ERROR);
    264 
    265     uint32_t cMemRsvMax = (pThis->DtbHdr.offDtStruct - pThis->DtbHdr.offMemRsvMap) / sizeof(*pThis->paMemRsv);
     281static int rtFdtDtbMemRsvLoad(PRTFDTINT pThis, PCDTBFDTHDR pDtbHdr, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     282{
     283    AssertReturn(pDtbHdr->offMemRsvMap < pDtbHdr->offDtStruct, VERR_INTERNAL_ERROR);
     284
     285    uint32_t cMemRsvMax = (pDtbHdr->offDtStruct - pDtbHdr->offMemRsvMap) / sizeof(*pThis->paMemRsv);
    266286    Assert(cMemRsvMax);
    267287
     
    270290        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the memory reservation block",
    271291                             cMemRsvMax * sizeof(*pThis->paMemRsv));
     292
     293    pThis->cMemRsvMax = cMemRsvMax;
    272294
    273295    /* Read the entries one after another until the terminator is reached. */
     
    310332 * @returns IPRT status code.
    311333 * @param   pThis           Pointer to the FDT instance.
     334 * @param   pDtbHdr         The DTB header.
    312335 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
    313336 * @param   pErrInfo        Where to return additional error information.
    314337 */
    315 static int rtFdtDtbStructsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
    316 {
    317     pThis->pu32Structs = (uint32_t *)RTMemAllocZ(pThis->DtbHdr.cbDtStruct);
    318     if (!pThis->pu32Structs)
     338static int rtFdtDtbStructsLoad(PRTFDTINT pThis, PCDTBFDTHDR pDtbHdr, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     339{
     340    pThis->pbStruct = (uint8_t *)RTMemAllocZ(pDtbHdr->cbDtStruct);
     341    if (!pThis->pbStruct)
    319342        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the structs block",
    320                              pThis->DtbHdr.cbDtStruct);
    321 
    322     int rc = RTVfsIoStrmReadAt(hVfsIos, pThis->DtbHdr.offDtStruct, pThis->pu32Structs, pThis->DtbHdr.cbDtStruct,
     343                             pDtbHdr->cbDtStruct);
     344
     345    int rc = RTVfsIoStrmReadAt(hVfsIos, pDtbHdr->offDtStruct, pThis->pbStruct, pDtbHdr->cbDtStruct,
    323346                               true /*fBlocking*/, NULL /*pcbRead*/);
    324347    if (RT_FAILURE(rc))
     
    334357 * @returns IPRT status code.
    335358 * @param   pThis           Pointer to the FDT instance.
     359 * @param   pDtbHdr         The DTB header.
    336360 * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
    337361 * @param   pErrInfo        Where to return additional error information.
    338362 */
    339 static int rtFdtDtbStringsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
    340 {
    341     pThis->paszStrings = (char *)RTMemAllocZ(pThis->DtbHdr.cbDtStrings);
     363static int rtFdtDtbStringsLoad(PRTFDTINT pThis, PCDTBFDTHDR pDtbHdr, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     364{
     365    pThis->paszStrings = (char *)RTMemAllocZ(pDtbHdr->cbDtStrings);
    342366    if (!pThis->paszStrings)
    343367        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the strings block",
    344                              pThis->DtbHdr.cbDtStrings);
    345 
    346     int rc = RTVfsIoStrmReadAt(hVfsIos, pThis->DtbHdr.offDtStrings, pThis->paszStrings, pThis->DtbHdr.cbDtStrings,
     368                             pDtbHdr->cbDtStrings);
     369
     370    int rc = RTVfsIoStrmReadAt(hVfsIos, pDtbHdr->offDtStrings, pThis->paszStrings, pDtbHdr->cbDtStrings,
    347371                               true /*fBlocking*/, NULL /*pcbRead*/);
    348372    if (RT_FAILURE(rc))
     
    350374
    351375    /* Verify that the strings block is terminated. */
    352     if (pThis->paszStrings[pThis->DtbHdr.cbDtStrings - 1] != '\0')
     376    if (pThis->paszStrings[pDtbHdr->cbDtStrings - 1] != '\0')
    353377        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRINGS_BLOCK_NOT_TERMINATED, "The strings block is not zero terminated");
    354378
     
    388412                    if (RT_LIKELY(pThis))
    389413                    {
    390                         memcpy(&pThis->DtbHdr, &DtbHdr, sizeof(DtbHdr));
     414                        pThis->cbStrings        = DtbHdr.cbDtStrings;
     415                        pThis->cbStruct         = DtbHdr.cbDtStruct;
     416                        pThis->u32CpuIdPhysBoot = DtbHdr.u32CpuIdPhysBoot;
    391417
    392418                        /* Load the memory reservation block. */
    393                         rc = rtFdtDtbMemRsvLoad(pThis, hVfsIos, pErrInfo);
     419                        rc = rtFdtDtbMemRsvLoad(pThis, &DtbHdr, hVfsIos, pErrInfo);
    394420                        if (RT_SUCCESS(rc))
    395421                        {
    396                             rc = rtFdtDtbStructsLoad(pThis, hVfsIos, pErrInfo);
     422                            rc = rtFdtDtbStructsLoad(pThis, &DtbHdr, hVfsIos, pErrInfo);
    397423                            if (RT_SUCCESS(rc))
    398424                            {
    399                                 rc = rtFdtDtbStringsLoad(pThis, hVfsIos, pErrInfo);
     425                                rc = rtFdtDtbStringsLoad(pThis, &DtbHdr, hVfsIos, pErrInfo);
    400426                                if (RT_SUCCESS(rc))
    401427                                {
     428                                    pThis->cbStringsMax = pThis->cbStrings;
     429                                    pThis->cbStructMax  = pThis->cbStruct;
     430
    402431                                    *phFdt = pThis;
    403432                                    return VINF_SUCCESS;
     
    456485DECLINLINE(size_t) rtFdtStructsGetOffset(PRTFDTINT pThis, PCRTFDTDTBDUMP pDump)
    457486{
    458     return pThis->DtbHdr.cbDtStruct - pDump->cbLeft - sizeof(uint32_t);
     487    return pThis->cbStruct - pDump->cbLeft - sizeof(uint32_t);
    459488}
    460489#endif
     
    728757    Prop.cbProperty      = RT_BE2H_U32(Prop.cbProperty);
    729758
    730     if (Prop.offPropertyName >= pThis->DtbHdr.cbDtStrings)
     759    if (Prop.offPropertyName >= pThis->cbStrings)
    731760        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_NAME_OFF_TOO_LARGE, "Property name offset points past the string block");
    732761
     
    845874    RTFDTDTBDUMP Dump;
    846875
    847     Dump.cbLeft    = pThis->DtbHdr.cbDtStruct;
    848     Dump.pbStructs = (const uint8_t *)pThis->pu32Structs;
     876    Dump.cbLeft    = pThis->cbStruct;
     877    Dump.pbStructs = pThis->pbStruct;
    849878
    850879    /* Skip any NOP tokens. */
     
    948977        cch = RTVfsIoStrmPrintf(hVfsIos, "/memreserve/ %#RX64 %#RX64;\n", pThis->paMemRsv[i].PhysAddrStart, pThis->paMemRsv[i].cbArea);
    949978        if (cch <= 0)
    950             return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write memory reervation block %u", i);
     979            return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write memory reservation block %u", i);
    951980    }
    952981
     
    956985
    957986
     987/**
     988 * Adds the zero padding to align the next block properly.
     989 *
     990 * @returns IPRT status code.
     991 * @param   hVfsIos         The VFS I/O stream handle to dump the DTB to.
     992 * @param   cbPad           How many bytes to pad.
     993 */
     994static int rtFdtDumpAsDtbPad(RTVFSIOSTREAM hVfsIos, uint32_t cbPad)
     995{
     996    if (!cbPad)
     997        return VINF_SUCCESS;
     998
     999    while (cbPad)
     1000    {
     1001        uint32_t cbThisPad = RT_MIN(cbPad, _4K);
     1002        int rc = RTVfsIoStrmWrite(hVfsIos, &g_abRTZero4K[0], cbThisPad, true /*fBlocking*/, NULL /*pcbWritten*/);
     1003        if (RT_FAILURE(rc))
     1004            return rc;
     1005
     1006        cbPad -= cbThisPad;
     1007    }
     1008
     1009    return VINF_SUCCESS;
     1010}
     1011
     1012
     1013/**
     1014 * Dumps the given FDT instance as a DTB (Devicetree blob).
     1015 *
     1016 * @returns IPRT status code.
     1017 * @param   pThis           Pointer to the FDT instance.
     1018 * @param   hVfsIos         The VFS I/O stream handle to dump the DTB to.
     1019 * @param   pErrInfo        Where to return additional error information.
     1020 */
     1021static int rtFdtDumpAsDtb(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     1022{
     1023    DTBFDTHDR Hdr;
     1024
     1025    /* ensure the FDT is finalized. */
     1026    int rc = RTFdtFinalize(pThis);
     1027    if (RT_FAILURE(rc))
     1028        return rc;
     1029
     1030    uint32_t offMemRsvMap = RT_ALIGN_32(sizeof(Hdr), sizeof(uint64_t));
     1031    uint32_t offDtStruct  = RT_ALIGN_32(offMemRsvMap + (pThis->cMemRsv + 1) * sizeof(DTBFDTRSVENTRY), sizeof(uint32_t));
     1032    uint32_t offDtStrings = offDtStruct + pThis->cbStruct;
     1033    uint32_t cbFdt        = offDtStrings + pThis->cbStrings;
     1034    uint32_t cbCur        = 0;
     1035
     1036    Hdr.u32Magic                 = RT_H2BE_U32(DTBFDTHDR_MAGIC);
     1037    Hdr.cbFdt                    = RT_H2BE_U32(cbFdt);
     1038    Hdr.offDtStruct              = RT_H2BE_U32(offDtStruct);
     1039    Hdr.offDtStrings             = RT_H2BE_U32(offDtStrings);
     1040    Hdr.offMemRsvMap             = RT_H2BE_U32(offMemRsvMap);
     1041    Hdr.u32Version               = RT_H2BE_U32(DTBFDTHDR_VERSION);
     1042    Hdr.u32VersionLastCompatible = RT_H2BE_U32(DTBFDTHDR_VERSION_LAST_COMP);
     1043    Hdr.u32CpuIdPhysBoot         = RT_H2BE_U32(pThis->u32CpuIdPhysBoot);
     1044    Hdr.cbDtStrings              = RT_H2BE_U32(pThis->cbStrings);
     1045    Hdr.cbDtStruct               = RT_H2BE_U32(pThis->cbStruct);
     1046
     1047    /* Write out header, memory reservation block, struct block and strings block all with appropriate padding. */
     1048    rc = RTVfsIoStrmWrite(hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, NULL /*pcbWritten*/);
     1049    if (RT_FAILURE(rc))
     1050        return RTErrInfoSetF(pErrInfo, rc, "Failed to write DTB header (%u bytes) to I/O stream", sizeof(Hdr));
     1051
     1052    cbCur += sizeof(Hdr);
     1053    rc = rtFdtDumpAsDtbPad(hVfsIos, offMemRsvMap - cbCur);
     1054    if (RT_FAILURE(rc))
     1055        return RTErrInfoSetF(pErrInfo, rc, "Failed to write padding after DTB header (%u bytes) to I/O stream",
     1056                             offMemRsvMap - cbCur);
     1057    cbCur += offMemRsvMap - cbCur;
     1058
     1059    /* Write memory reservation blocks. */
     1060    for (uint32_t i = 0; i < pThis->cMemRsv; i++)
     1061    {
     1062        DTBFDTRSVENTRY MemRsv;
     1063
     1064        MemRsv.PhysAddrStart = RT_H2BE_U32(pThis->paMemRsv[i].PhysAddrStart);
     1065        MemRsv.cbArea        = RT_H2BE_U32(pThis->paMemRsv[i].cbArea);
     1066        rc = RTVfsIoStrmWrite(hVfsIos, &MemRsv, sizeof(MemRsv), true /*fBlocking*/, NULL /*pcbWritten*/);
     1067        if (RT_FAILURE(rc))
     1068            return RTErrInfoSetF(pErrInfo, rc, "Failed to write memory reservation entry %u (%u bytes) to I/O stream",
     1069                                 i, sizeof(MemRsv));
     1070        cbCur += sizeof(MemRsv);
     1071    }
     1072
     1073    /* Always write terminating entry. */
     1074    DTBFDTRSVENTRY RsvTerm;
     1075    RsvTerm.PhysAddrStart = RT_H2BE_U32(0); /* Yeah, pretty useful endianess conversion I know */
     1076    RsvTerm.cbArea        = RT_H2BE_U32(0);
     1077    rc = RTVfsIoStrmWrite(hVfsIos, &RsvTerm, sizeof(RsvTerm), true /*fBlocking*/, NULL /*pcbWritten*/);
     1078    if (RT_FAILURE(rc))
     1079        return RTErrInfoSetF(pErrInfo, rc, "Failed to write terminating memory reservation entry (%u bytes) to I/O stream",
     1080                             sizeof(RsvTerm));
     1081    cbCur += sizeof(RsvTerm);
     1082
     1083    rc = rtFdtDumpAsDtbPad(hVfsIos, offDtStruct - cbCur);
     1084    if (RT_FAILURE(rc))
     1085        return RTErrInfoSetF(pErrInfo, rc, "Failed to write padding after memory reservation block (%u bytes) to I/O stream",
     1086                             offDtStruct - cbCur);
     1087    cbCur += offDtStruct - cbCur;
     1088
     1089    /* Write struct block. */
     1090    rc = RTVfsIoStrmWrite(hVfsIos, pThis->pbStruct, pThis->cbStruct, true /*fBlocking*/, NULL /*pcbWritten*/);
     1091    if (RT_FAILURE(rc))
     1092        return RTErrInfoSetF(pErrInfo, rc, "Failed to write struct block (%u bytes) to I/O stream",
     1093                             pThis->cbStruct);
     1094    cbCur += pThis->cbStruct;
     1095
     1096    rc = rtFdtDumpAsDtbPad(hVfsIos, offDtStrings - cbCur);
     1097    if (RT_FAILURE(rc))
     1098        return RTErrInfoSetF(pErrInfo, rc, "Failed to write padding after structs block (%u bytes) to I/O stream",
     1099                             offDtStrings - cbCur);
     1100    cbCur += offDtStrings - cbCur;
     1101
     1102    /* Write strings block. */
     1103    rc = RTVfsIoStrmWrite(hVfsIos, pThis->paszStrings, pThis->cbStrings, true /*fBlocking*/, NULL /*pcbWritten*/);
     1104    if (RT_FAILURE(rc))
     1105        return RTErrInfoSetF(pErrInfo, rc, "Failed to write strings block (%u bytes) to I/O stream",
     1106                             pThis->cbStrings);
     1107    cbCur += pThis->cbStrings;
     1108
     1109    rc = rtFdtDumpAsDtbPad(hVfsIos, cbFdt - cbCur);
     1110    if (RT_FAILURE(rc))
     1111        return RTErrInfoSetF(pErrInfo, rc, "Failed to write padding after strings block (%u bytes) to I/O stream",
     1112                             cbFdt - cbCur);
     1113    cbCur += cbFdt - cbCur;
     1114
     1115    Assert(cbCur == cbFdt);
     1116    return VINF_SUCCESS;
     1117}
     1118
     1119
     1120/**
     1121 * Ensures there is enough space in the structure block, allocating more if required.
     1122 *
     1123 * @returns IPRT status code.
     1124 * @param   pThis           Pointer to the FDT instance.
     1125 * @param   cch             Number of characters required, including the zero terminator.
     1126 */
     1127static int rtFdtStringsEnsureSpace(PRTFDTINT pThis, uint32_t cch)
     1128{
     1129    if (pThis->cbStringsMax - pThis->cbStrings >= cch)
     1130        return VINF_SUCCESS;
     1131
     1132    size_t cbNew = RT_ALIGN_32(pThis->cbStrings + cch, 256);
     1133    void *pvStringsNew = RTMemReallocZ(pThis->paszStrings, pThis->cbStringsMax, cbNew);
     1134    if (!pvStringsNew)
     1135        return VERR_NO_MEMORY;
     1136
     1137    Assert(cbNew - pThis->cbStrings >= cch);
     1138    pThis->paszStrings = (char *)pvStringsNew;
     1139    pThis->cbStringsMax = cbNew;
     1140    return VINF_SUCCESS;
     1141}
     1142
     1143
     1144/**
     1145 * Looks for the given string in the strings block appending it if not found, returning
     1146 * the offset of the occurrence.
     1147 *
     1148 * @returns IPRT status code.
     1149 * @param   pThis           Pointer to the FDT instance.
     1150 * @param   psz             The string to insert.
     1151 * @param   poffStr         Where to store the offset of the start of string from the beginning
     1152 *                          of the strings block on success.
     1153 */
     1154static int rtFdtStringsInsertString(PRTFDTINT pThis, const char *psz, uint32_t *poffStr)
     1155{
     1156    uint32_t off = 0;
     1157    while (off < pThis->cbStrings)
     1158    {
     1159        if (!RTStrCmp(psz, &pThis->paszStrings[off]))
     1160        {
     1161            *poffStr = off;
     1162            return VINF_SUCCESS;
     1163        }
     1164
     1165        /** @todo Optimize? The strings block is not very large though so probably not worth the effort. */
     1166        off += strlen(&pThis->paszStrings[off]) + 1;
     1167    }
     1168
     1169    /* Not found, need to insert. */
     1170    size_t cch = strlen(psz) + 1;
     1171    int rc = rtFdtStringsEnsureSpace(pThis, cch);
     1172    if (RT_FAILURE(rc))
     1173        return rc;
     1174
     1175    memcpy(&pThis->paszStrings[off], psz, cch);
     1176    pThis->cbStrings += cch;
     1177    *poffStr = off;
     1178    return VINF_SUCCESS;
     1179}
     1180
     1181
     1182/**
     1183 * Ensures there is enough space in the structure block, allocating more if required.
     1184 *
     1185 * @returns IPRT status code.
     1186 * @param   pThis           Pointer to the FDT instance.
     1187 * @param   cbSpaceRequired Number of bytes required.
     1188 */
     1189static int rtFdtStructEnsureSpace(PRTFDTINT pThis, uint32_t cbSpaceRequired)
     1190{
     1191    if (pThis->cbStructMax - pThis->cbStruct >= cbSpaceRequired)
     1192        return VINF_SUCCESS;
     1193
     1194    size_t cbNew = RT_ALIGN_32(pThis->cbStruct + cbSpaceRequired, _1K);
     1195    void *pvStructNew = RTMemReallocZ(pThis->pbStruct, pThis->cbStructMax, cbNew);
     1196    if (!pvStructNew)
     1197        return VERR_NO_MEMORY;
     1198
     1199    Assert(cbNew - pThis->cbStruct >= cbSpaceRequired);
     1200    pThis->pbStruct    = (uint8_t *)pvStructNew;
     1201    pThis->cbStructMax = cbNew;
     1202    return VINF_SUCCESS;
     1203}
     1204
     1205
     1206/**
     1207 * Appends the given token and payload data to the structure block taking care of aligning the data.
     1208 *
     1209 * @returns IPRT status code.
     1210 * @param   pThis           Pointer to the FDT instance.
     1211 * @param   pSgBuf          The S/G buffer to append.
     1212 * @param   cbAppend        How many bytes to append.
     1213 */
     1214static int rtFdtStructAppendSg(PRTFDTINT pThis, PRTSGBUF pSgBuf, uint32_t cbAppend)
     1215{
     1216    uint32_t cbAppendAligned = RT_ALIGN_32(cbAppend, sizeof(uint32_t));
     1217
     1218    /* Ensure enough space for the token and the payload + padding. */
     1219    int rc = rtFdtStructEnsureSpace(pThis, cbAppendAligned);
     1220    if (RT_FAILURE(rc))
     1221        return rc;
     1222
     1223    size_t cbCopied = RTSgBufCopyToBuf(pSgBuf, pThis->pbStruct + pThis->cbStruct, cbAppend);
     1224    AssertReturn(cbCopied == cbAppend, VERR_INTERNAL_ERROR);
     1225
     1226    pThis->cbStruct += cbAppendAligned;
     1227    return VINF_SUCCESS;
     1228}
     1229
     1230
     1231/**
     1232 * Appends a token and payload data.
     1233 *
     1234 * @returns IPRT status code.
     1235 * @param   pThis           Pointer to the FDT instance.
     1236 * @param   u32Token        The token to append.
     1237 * @param   pvPayload       Pointer to the payload data to append.
     1238 * @param   cbPayload       Size of the payload data in bytes.
     1239 */
     1240static int rtFdtStructAppendTokenAndPayload(PRTFDTINT pThis, uint32_t u32Token, const void *pvPayload, size_t cbPayload)
     1241{
     1242    RTSGBUF SgBuf;
     1243    RTSGSEG aSegs[2];
     1244
     1245    aSegs[0].pvSeg = &u32Token;
     1246    aSegs[0].cbSeg = sizeof(u32Token);
     1247    aSegs[1].pvSeg = (void *)pvPayload;
     1248    aSegs[1].cbSeg = cbPayload;
     1249    RTSgBufInit(&SgBuf, &aSegs[0], RT_ELEMENTS(aSegs));
     1250
     1251    return rtFdtStructAppendSg(pThis, &SgBuf, sizeof(u32Token) + cbPayload);
     1252}
     1253
     1254
     1255/**
     1256 * Appends a property.
     1257 *
     1258 * @returns IPRT status code.
     1259 * @param   pThis           Pointer to the FDT instance.
     1260 * @param   pszProperty     Name of the property.
     1261 * @param   pvProperty      Pointer to the property data.
     1262 * @param   cbProperty      Size of the property data in bytes.
     1263 */
     1264static int rtFdtStructAppendProperty(PRTFDTINT pThis, const char *pszProperty, const void *pvProperty, uint32_t cbProperty)
     1265{
     1266    /* Insert the property name into the strings block. */
     1267    uint32_t offStr;
     1268    int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
     1269    if (RT_FAILURE(rc))
     1270        return rc;
     1271
     1272    uint32_t u32Token = DTB_FDT_TOKEN_PROPERTY_BE;
     1273    DTBFDTPROP Prop;
     1274
     1275    Prop.cbProperty      = RT_H2BE_U32(cbProperty);
     1276    Prop.offPropertyName = RT_H2BE_U32(offStr);
     1277
     1278    RTSGBUF SgBuf;
     1279    RTSGSEG aSegs[3];
     1280    aSegs[0].pvSeg = &u32Token;
     1281    aSegs[0].cbSeg = sizeof(u32Token);
     1282    aSegs[1].pvSeg = &Prop;
     1283    aSegs[1].cbSeg = sizeof(Prop);
     1284    if (cbProperty)
     1285    {
     1286        aSegs[2].pvSeg = (void *)pvProperty;
     1287        aSegs[2].cbSeg = cbProperty;
     1288    }
     1289    RTSgBufInit(&SgBuf, &aSegs[0], cbProperty ? RT_ELEMENTS(aSegs) : 2);
     1290
     1291    return rtFdtStructAppendSg(pThis, &SgBuf, sizeof(u32Token) + sizeof(Prop) + cbProperty);
     1292}
     1293
     1294
    9581295RTDECL(int) RTFdtCreateEmpty(PRTFDT phFdt)
    9591296{
    960     RT_NOREF(phFdt);
    961     return VERR_NOT_IMPLEMENTED;
     1297    AssertPtrReturn(phFdt, VERR_INVALID_POINTER);
     1298
     1299    int rc = VINF_SUCCESS;
     1300    PRTFDTINT pThis = (PRTFDTINT)RTMemAllocZ(sizeof(*pThis));
     1301    if (pThis)
     1302    {
     1303        /* Add the root node. */
     1304        rc = RTFdtNodeAdd(pThis, "");
     1305        if (RT_SUCCESS(rc))
     1306        {
     1307            *phFdt = pThis;
     1308            return VINF_SUCCESS;
     1309        }
     1310
     1311        RTMemFree(pThis);
     1312    }
     1313    else
     1314        rc = VERR_NO_MEMORY;
     1315
     1316    return rc;
    9621317}
    9631318
     
    9911346
    9921347
    993 RTDECL(int) RTFdtDumpToVfsIoStrm(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     1348RTDECL(int) RTFdtFinalize(RTFDT hFdt)
    9941349{
    9951350    PRTFDTINT pThis = hFdt;
    9961351    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    9971352
    998     RT_NOREF(fFlags);
     1353    /* Already finalized? */
     1354    if (!pThis->cTreeDepth)
     1355        return VINF_SUCCESS;
     1356
     1357    uint32_t cbStructSpace = pThis->cTreeDepth * sizeof(uint32_t) + sizeof(uint32_t); /* One extra for the END token. */
     1358    int rc = rtFdtStructEnsureSpace(pThis, cbStructSpace);
     1359    if (RT_FAILURE(rc))
     1360        return rc;
     1361
     1362    uint32_t *pu32 = (uint32_t *)pThis->pbStruct;
     1363    while (pThis->cTreeDepth--)
     1364        *pu32++ = DTB_FDT_TOKEN_END_NODE_BE;
     1365
     1366    *pu32 = DTB_FDT_TOKEN_END_BE;
     1367    pThis->cbStruct += cbStructSpace;
     1368    return VINF_SUCCESS;
     1369}
     1370
     1371
     1372RTDECL(int) RTFdtDumpToVfsIoStrm(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
     1373{
     1374    PRTFDTINT pThis = hFdt;
     1375    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1376    AssertReturn(enmOutType == RTFDTTYPE_DTS || enmOutType == RTFDTTYPE_DTB, VERR_INVALID_PARAMETER);
     1377    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
     1378
    9991379    if (enmOutType == RTFDTTYPE_DTS)
    10001380        return rtFdtDumpAsDts(pThis, hVfsIos, pErrInfo);
    1001 
    1002     return VERR_NOT_IMPLEMENTED;
     1381    else if (enmOutType == RTFDTTYPE_DTB)
     1382        return rtFdtDumpAsDtb(pThis, hVfsIos, pErrInfo);
     1383
     1384    return VERR_NOT_SUPPORTED;
    10031385}
    10041386
     
    10091391    return VERR_NOT_IMPLEMENTED;
    10101392}
     1393
     1394
     1395RTDECL(int) RTFdtAddMemoryReservation(RTFDT hFdt, uint64_t PhysAddrStart, uint64_t cbArea)
     1396{
     1397    PRTFDTINT pThis = hFdt;
     1398    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1399    AssertReturn(PhysAddrStart > 0 || cbArea > 0, VERR_INVALID_PARAMETER);
     1400
     1401    if (pThis->cMemRsv == pThis->cMemRsvMax)
     1402    {
     1403        uint32_t cMemRsvMaxNew = pThis->cMemRsvMax + 10;
     1404        PDTBFDTRSVENTRY paMemRsvNew = (PDTBFDTRSVENTRY)RTMemRealloc(pThis->paMemRsv, cMemRsvMaxNew * sizeof(*paMemRsvNew));
     1405        if (!paMemRsvNew)
     1406            return VERR_NO_MEMORY;
     1407
     1408        pThis->paMemRsv   = paMemRsvNew;
     1409        pThis->cMemRsvMax = cMemRsvMaxNew;
     1410    }
     1411
     1412    pThis->paMemRsv[pThis->cMemRsv].PhysAddrStart = PhysAddrStart;
     1413    pThis->paMemRsv[pThis->cMemRsv].cbArea        = cbArea;
     1414    pThis->cMemRsv++;
     1415    return VINF_SUCCESS;
     1416}
     1417
     1418
     1419RTDECL(int) RTFdtSetPhysBootCpuId(RTFDT hFdt, uint32_t idPhysBootCpu)
     1420{
     1421    PRTFDTINT pThis = hFdt;
     1422    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1423
     1424    pThis->u32CpuIdPhysBoot = idPhysBootCpu;
     1425    return VINF_SUCCESS;
     1426}
     1427
     1428
     1429RTDECL(int) RTFdtNodeAdd(RTFDT hFdt, const char *pszName)
     1430{
     1431    PRTFDTINT pThis = hFdt;
     1432    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1433
     1434    /** @todo Validate node name against allowed character set. */
     1435    size_t cchName = strlen(pszName) + 1;
     1436    int rc = rtFdtStructAppendTokenAndPayload(pThis, DTB_FDT_TOKEN_BEGIN_NODE_BE, pszName, cchName);
     1437    if (RT_FAILURE(rc))
     1438        return rc;
     1439
     1440    pThis->cTreeDepth++;
     1441    return VINF_SUCCESS;
     1442}
     1443
     1444
     1445RTDECL(int) RTFdtNodeAddF(RTFDT hFdt, const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3)
     1446{
     1447    va_list va;
     1448    va_start(va, pszNameFmt);
     1449    int rc = RTFdtNodeAddV(hFdt, pszNameFmt, va);
     1450    va_end(va);
     1451    return rc;
     1452}
     1453
     1454
     1455RTDECL(int) RTFdtNodeAddV(RTFDT hFdt, const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)
     1456{
     1457    char szName[512]; /* lazy developer */
     1458    ssize_t cch = RTStrPrintf2V(&szName[0], sizeof(szName), pszNameFmt, va);
     1459    if (cch <= 0)
     1460        return VERR_BUFFER_OVERFLOW;
     1461
     1462    return RTFdtNodeAdd(hFdt, &szName[0]);
     1463}
     1464
     1465
     1466RTDECL(int) RTFdtNodeFinalize(RTFDT hFdt)
     1467{
     1468    PRTFDTINT pThis = hFdt;
     1469    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1470    AssertReturn(pThis->cTreeDepth > 1, VERR_FDT_AT_ROOT_LEVEL);
     1471
     1472    int rc = rtFdtStructAppendTokenAndPayload(pThis, DTB_FDT_TOKEN_END_NODE_BE, NULL /*pvPayload*/, 0 /*cbPayload*/);
     1473    if (RT_FAILURE(rc))
     1474        return rc;
     1475
     1476    pThis->cTreeDepth--;
     1477    return VINF_SUCCESS;
     1478}
     1479
     1480
     1481RTDECL(int) RTFdtNodePropertyAddEmpty(RTFDT hFdt, const char *pszProperty)
     1482{
     1483    PRTFDTINT pThis = hFdt;
     1484    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1485
     1486    return rtFdtStructAppendProperty(pThis, pszProperty, NULL /*pvProperty*/, 0 /*cbProperty*/);
     1487}
     1488
     1489
     1490RTDECL(int) RTFdtNodePropertyAddU32(RTFDT hFdt, const char *pszProperty, uint32_t u32)
     1491{
     1492    PRTFDTINT pThis = hFdt;
     1493    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1494
     1495    RT_H2BE_U32(u32);
     1496    return rtFdtStructAppendProperty(pThis, pszProperty, &u32, sizeof(u32));
     1497}
     1498
     1499
     1500RTDECL(int) RTFdtNodePropertyAddString(RTFDT hFdt, const char *pszProperty, const char *pszVal)
     1501{
     1502    PRTFDTINT pThis = hFdt;
     1503    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1504
     1505    uint32_t cchVal = (uint32_t)strlen(pszVal) + 1;
     1506    return rtFdtStructAppendProperty(pThis, pszProperty, pszVal, cchVal);
     1507}
     1508
     1509
     1510RTDECL(int) RTFdtNodePropertyAddCellsU32(RTFDT hFdt, const char *pszProperty, uint32_t cCells, ...)
     1511{
     1512    va_list va;
     1513    va_start(va, cCells);
     1514    int rc = RTFdtNodePropertyAddCellsU32V(hFdt, pszProperty, cCells, va);
     1515    va_end(va);
     1516    return rc;
     1517}
     1518
     1519
     1520RTDECL(int) RTFdtNodePropertyAddCellsU32V(RTFDT hFdt, const char *pszProperty, uint32_t cCells, va_list va)
     1521{
     1522    PRTFDTINT pThis = hFdt;
     1523    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1524
     1525    /* Insert the property name into the strings block. */
     1526    uint32_t offStr;
     1527    int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
     1528    if (RT_FAILURE(rc))
     1529        return rc;
     1530
     1531    uint32_t cbPropAligned = RT_ALIGN_32(cCells * sizeof(uint32_t) + 3 * sizeof(uint32_t), sizeof(uint32_t));
     1532
     1533    rc = rtFdtStructEnsureSpace(pThis, cbPropAligned);
     1534    if (RT_FAILURE(rc))
     1535        return rc;
     1536
     1537    uint32_t *pu32 = (uint32_t *)(pThis->pbStruct + pThis->cbStruct);
     1538    *pu32++ = DTB_FDT_TOKEN_PROPERTY_BE;
     1539    *pu32++ = RT_H2BE_U32(cCells * sizeof(uint32_t));
     1540    *pu32++ = RT_H2BE_U32(offStr);
     1541    for (uint32_t i = 0; i < cCells; i++)
     1542        *pu32++ = va_arg(va, uint32_t);
     1543
     1544    pThis->cbStruct += cbPropAligned;
     1545    return VINF_SUCCESS;
     1546}
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