Index: trunk/src/VBox/Runtime/common/misc/fdt.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/misc/fdt.cpp	(revision 100007)
+++ trunk/src/VBox/Runtime/common/misc/fdt.cpp	(revision 100009)
@@ -68,5 +68,13 @@
 {
     /** Pointer to the string block. */
-    const char              *paszStrings;
+    char                    *paszStrings;
+    /** Pointer to the raw structs block. */
+    uint32_t                *pu32Structs;
+    /** Pointer to the array of memory reservation entries. */
+    PDTBFDTRSVENTRY         paMemRsv;
+    /** Number of memory reservation entries. */
+    uint32_t                cMemRsv;
+    /** The DTB header (converted to host endianess). */
+    DTBFDTHDR               DtbHdr;
 } RTFDTINT;
 /** Pointer to the internal Flattened Devicetree instance. */
@@ -118,7 +126,176 @@
  * @param   pErrInfo        Where to return additional error information.
  */
-static int rtFdtDtbHdr_Validate(PCDTBFDTHDR pDtbHdr, uint64_t cbDtb, PRTERRINFO pErrInfo)
-{
-    RT_NOREF(pDtbHdr, cbDtb, pErrInfo);
+static int rtFdtDtbHdr_Validate(PDTBFDTHDR pDtbHdr, uint64_t cbDtb, PRTERRINFO pErrInfo)
+{
+    /* Convert to host endianess first. */
+    pDtbHdr->u32Magic                   = RT_BE2H_U32(pDtbHdr->u32Magic);
+    pDtbHdr->cbFdt                      = RT_BE2H_U32(pDtbHdr->cbFdt);
+    pDtbHdr->offDtStruct                = RT_BE2H_U32(pDtbHdr->offDtStruct);
+    pDtbHdr->offDtStrings               = RT_BE2H_U32(pDtbHdr->offDtStrings);
+    pDtbHdr->offMemRsvMap               = RT_BE2H_U32(pDtbHdr->offMemRsvMap);
+    pDtbHdr->u32Version                 = RT_BE2H_U32(pDtbHdr->u32Version);
+    pDtbHdr->u32VersionLastCompatible   = RT_BE2H_U32(pDtbHdr->u32VersionLastCompatible);
+    pDtbHdr->u32CpuIdPhysBoot           = RT_BE2H_U32(pDtbHdr->u32CpuIdPhysBoot);
+    pDtbHdr->cbDtStrings                = RT_BE2H_U32(pDtbHdr->cbDtStrings);
+    pDtbHdr->cbDtStruct                 = RT_BE2H_U32(pDtbHdr->cbDtStruct);
+
+    if (pDtbHdr->u32Magic != DTBFDTHDR_MAGIC)
+        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_MAGIC_INVALID, "The magic of the DTB header is invalid (expected %#RX32, got %#RX32)",
+                             DTBFDTHDR_MAGIC, pDtbHdr->u32Magic);
+    if (pDtbHdr->u32Version != DTBFDTHDR_VERSION)
+        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_VERSION_NOT_SUPPORTED, "Version %u of the DTB is not supported (supported is %u)",
+                             pDtbHdr->u32Version, DTBFDTHDR_VERSION);
+    if (pDtbHdr->u32VersionLastCompatible != DTBFDTHDR_VERSION_LAST_COMP)
+        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_LAST_COMPAT_VERSION_INVALID, "Last compatible version %u of the DTB is invalid (expected %u)",
+                             pDtbHdr->u32VersionLastCompatible, DTBFDTHDR_VERSION_LAST_COMP);
+    if (pDtbHdr->cbFdt != cbDtb)
+        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_SIZE_INVALID, "The size of the FDT is invalid (expected %RU32, got %RU32)",
+                             cbDtb, pDtbHdr->cbFdt);
+
+    /*
+     * Check that any of the offsets is inside the bounds of the FDT and that the memory reservation block comes first,
+     * then the structs block and strings last.
+     */
+    if (   pDtbHdr->offMemRsvMap >= pDtbHdr->cbFdt
+        || pDtbHdr->offMemRsvMap < sizeof(*pDtbHdr))
+        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)",
+                             pDtbHdr->offMemRsvMap, pDtbHdr->cbFdt);
+    if (   pDtbHdr->offDtStruct >= pDtbHdr->cbFdt
+        || (pDtbHdr->cbFdt - pDtbHdr->offDtStruct < pDtbHdr->cbDtStruct)
+        || pDtbHdr->offDtStruct <= pDtbHdr->offMemRsvMap + sizeof(DTBFDTRSVENTRY))
+        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)",
+                             pDtbHdr->offDtStruct, pDtbHdr->cbDtStruct, pDtbHdr->cbFdt, pDtbHdr->offMemRsvMap);
+    if (    pDtbHdr->offDtStrings >= pDtbHdr->cbFdt
+        || (pDtbHdr->cbFdt - pDtbHdr->offDtStrings < pDtbHdr->cbDtStrings)
+        || pDtbHdr->offDtStrings < pDtbHdr->offDtStruct + pDtbHdr->cbDtStruct)
+        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)",
+                             pDtbHdr->offDtStrings, pDtbHdr->cbDtStrings, pDtbHdr->cbFdt, pDtbHdr->offDtStruct);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Fres all resources allocated for the given FDT.
+ *
+ * @param   pThis           The FDT instance to destroy.
+ */
+static void rtFdtDestroy(PRTFDTINT pThis)
+{
+    if (pThis->paszStrings)
+        RTMemFree(pThis->paszStrings);
+    if (pThis->pu32Structs)
+        RTMemFree(pThis->pu32Structs);
+    if (pThis->paMemRsv)
+        RTMemFree(pThis->paMemRsv);
+
+    pThis->paszStrings = NULL;
+    pThis->pu32Structs = NULL;
+    pThis->paMemRsv    = NULL;
+    pThis->cMemRsv     = 0;
+    RT_ZERO(pThis->DtbHdr);
+    RTMemFree(pThis);
+}
+
+
+/**
+ * Loads the memory reservation block from the underlying VFS I/O stream.
+ *
+ * @returns IPRT status code.
+ * @param   pThis           The FDT instance.
+ * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
+ * @param   pErrInfo        Where to return additional error information.
+ */
+static int rtFdtDtbMemRsvLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
+{
+    AssertReturn(pThis->DtbHdr.offMemRsvMap < pThis->DtbHdr.offDtStruct, VERR_INTERNAL_ERROR);
+
+    uint32_t cMemRsvMax = (pThis->DtbHdr.offDtStruct - pThis->DtbHdr.offMemRsvMap) / sizeof(*pThis->paMemRsv);
+    Assert(cMemRsvMax);
+
+    pThis->paMemRsv = (PDTBFDTRSVENTRY)RTMemAllocZ(cMemRsvMax * sizeof(*pThis->paMemRsv));
+    if (!pThis->paMemRsv)
+        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the memory reservation block",
+                             cMemRsvMax * sizeof(*pThis->paMemRsv));
+
+    /* Read the entries one after another until the terminator is reached. */
+    uint32_t cMemRsv = 0;
+    for (;;)
+    {
+        DTBFDTRSVENTRY MemRsv;
+        int rc = RTVfsIoStrmRead(hVfsIos, &MemRsv, sizeof(MemRsv), true /*fBlocking*/, NULL /*pcbRead*/);
+        if (RT_FAILURE(rc))
+            return RTErrInfoSetF(pErrInfo, rc, "Failed to read memory reservation entry %u from I/O stream",
+                                 cMemRsv);
+
+        /* Check whether the terminator is reached (no need to convert endianness here). */
+        if (   MemRsv.PhysAddrStart == 0
+            && MemRsv.cbArea == 0)
+            break;
+
+        /*
+         * The terminator must be included in the maximum entry count, if not
+         * the DTB is malformed and lacks a terminating entry before the start of the structs block.
+         */
+        if (cMemRsv + 1 == cMemRsvMax)
+            return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MEM_RSV_BLOCK_TERMINATOR_MISSING,
+                                 "The memory reservation block lacks a terminating entry");
+
+        pThis->paMemRsv[cMemRsv].PhysAddrStart = RT_BE2H_U64(MemRsv.PhysAddrStart);
+        pThis->paMemRsv[cMemRsv].cbArea        = RT_BE2H_U64(MemRsv.cbArea);
+        cMemRsv++;
+    }
+
+    pThis->cMemRsv = cMemRsv + 1;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Loads the structs block of the given FDT.
+ *
+ * @returns IPRT status code.
+ * @param   pThis           The FDT instance.
+ * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
+ * @param   pErrInfo        Where to return additional error information.
+ */
+static int rtFdtDtbStructsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
+{
+    pThis->pu32Structs = (uint32_t *)RTMemAllocZ(pThis->DtbHdr.cbDtStruct);
+    if (!pThis->pu32Structs)
+        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the structs block",
+                             pThis->DtbHdr.cbDtStruct);
+
+    int rc = RTVfsIoStrmRead(hVfsIos, pThis->pu32Structs, pThis->DtbHdr.cbDtStruct, true /*fBlocking*/, NULL /*pcbRead*/);
+    if (RT_FAILURE(rc))
+        return RTErrInfoSetF(pErrInfo, rc, "Failed to read structs block from I/O stream");
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Loads the strings block of the given FDT.
+ *
+ * @returns IPRT status code.
+ * @param   pThis           The FDT instance.
+ * @param   hVfsIos         The VFS I/O stream handle to load the DTB from.
+ * @param   pErrInfo        Where to return additional error information.
+ */
+static int rtFdtDtbStringsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
+{
+    pThis->paszStrings = (char *)RTMemAllocZ(pThis->DtbHdr.cbDtStrings);
+    if (!pThis->paszStrings)
+        return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the strings block",
+                             pThis->DtbHdr.cbDtStrings);
+
+    int rc = RTVfsIoStrmRead(hVfsIos, pThis->paszStrings, pThis->DtbHdr.cbDtStrings, true /*fBlocking*/, NULL /*pcbRead*/);
+    if (RT_FAILURE(rc))
+        return RTErrInfoSetF(pErrInfo, rc, "Failed to read strings block from I/O stream");
+
+    /* Verify that the strings block is terminated. */
+    if (pThis->paszStrings[pThis->DtbHdr.cbDtStrings - 1] != '\0')
+        return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRINGS_BLOCK_NOT_TERMINATED, "The strings block is not zero temrinated");
+
     return VINF_SUCCESS;
 }
@@ -153,17 +330,41 @@
                 if (RT_SUCCESS(rc))
                 {
-                    RT_NOREF(phFdt);
+                    PRTFDTINT pThis = (PRTFDTINT)RTMemAllocZ(sizeof(*pThis));
+                    if (RT_LIKELY(pThis))
+                    {
+                        memcpy(&pThis->DtbHdr, &DtbHdr, sizeof(DtbHdr));
+
+                        /* Load the memory reservation block. */
+                        rc = rtFdtDtbMemRsvLoad(pThis, hVfsIos, pErrInfo);
+                        if (RT_SUCCESS(rc))
+                        {
+                            rc = rtFdtDtbStructsLoad(pThis, hVfsIos, pErrInfo);
+                            if (RT_SUCCESS(rc))
+                            {
+                                rc = rtFdtDtbStringsLoad(pThis, hVfsIos, pErrInfo);
+                                if (RT_SUCCESS(rc))
+                                {
+                                    *phFdt = pThis;
+                                    return VINF_SUCCESS;
+                                }
+                            }
+                        }
+
+                        rtFdtDestroy(pThis);
+                    }
+                    else
+                        RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate memory for the FDT");
                 }
             }
             else
-                RTErrInfoSetF(pErrInfo, rc, "Failed to read %u bytes for the DTB header -> %Rrc\n",
-                              sizeof(DtbHdr));
+                RTErrInfoSetF(pErrInfo, rc, "Failed to read %u bytes for the DTB header -> %Rrc",
+                              sizeof(DtbHdr), rc);
         }
         else
-            RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MALFORMED, "DTB is too small, needs at least %u bytes, only %u available\n",
+            RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MALFORMED, "DTB is too small, needs at least %u bytes, only %u available",
                           sizeof(DtbHdr) + sizeof(DTBFDTRSVENTRY), ObjInfo.cbObject);
     }
     else
-        RTErrInfoSetF(pErrInfo, rc, "Failed to query size of the DTB -> %Rrc\n", rc);
+        RTErrInfoSetF(pErrInfo, rc, "Failed to query size of the DTB -> %Rrc", rc);
 
     return rc;
@@ -199,5 +400,8 @@
 RTDECL(void) RTFdtDestroy(RTFDT hFdt)
 {
-    RT_NOREF(hFdt);
+    PRTFDTINT pThis = hFdt;
+    AssertPtrReturnVoid(pThis);
+
+    rtFdtDestroy(pThis);
 }
 
