VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/fdt.cpp@ 100022

Last change on this file since 100022 was 100022, checked in by vboxsync, 2 years ago

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.3 KB
Line 
1/* $Id: fdt.cpp 100022 2023-05-31 08:40:43Z vboxsync $ */
2/** @file
3 * IPRT - Flattened Devicetree parser and generator API.
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_FDT
42#include <iprt/fdt.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/err.h>
47#include <iprt/log.h>
48#include <iprt/mem.h>
49#include <iprt/strcache.h>
50#include <iprt/string.h>
51#include <iprt/vfs.h>
52#include <iprt/formats/dtb.h>
53
54
55/*********************************************************************************************************************************
56* Defined Constants And Macros *
57*********************************************************************************************************************************/
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
61
62
63/*********************************************************************************************************************************
64* Structures and Typedefs *
65*********************************************************************************************************************************/
66
67/**
68 * Internal Flattened Devicetree instance.
69 */
70typedef struct RTFDTINT
71{
72 /** Pointer to the string block. */
73 char *paszStrings;
74 /** Pointer to the raw structs block. */
75 uint32_t *pu32Structs;
76 /** Pointer to the array of memory reservation entries. */
77 PDTBFDTRSVENTRY paMemRsv;
78 /** Number of memory reservation entries. */
79 uint32_t cMemRsv;
80 /** The DTB header (converted to host endianess). */
81 DTBFDTHDR DtbHdr;
82} RTFDTINT;
83/** Pointer to the internal Flattened Devicetree instance. */
84typedef 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;
134
135
136/*********************************************************************************************************************************
137* Global Variables *
138*********************************************************************************************************************************/
139
140
141/*********************************************************************************************************************************
142* Internal Functions *
143*********************************************************************************************************************************/
144#ifdef LOG_ENABLED
145
146/**
147 * Logs a FDT DTB header.
148 *
149 * @param pDtbHdr The FDT DTB header.
150 */
151static void rtFdtDtbHdr_Log(PCDTBFDTHDR pDtbHdr)
152{
153 if (LogIs2Enabled())
154 {
155 Log2(("RTFdt: Header:\n"));
156 Log2(("RTFdt: u32Magic %#RX32\n", RT_BE2H_U32(pDtbHdr->u32Magic)));
157 Log2(("RTFdt: cbFdt %#RX32\n", RT_BE2H_U32(pDtbHdr->cbFdt)));
158 Log2(("RTFdt: offDtStruct %#RX32\n", RT_BE2H_U32(pDtbHdr->offDtStruct)));
159 Log2(("RTFdt: offDtStrings %#RX32\n", RT_BE2H_U32(pDtbHdr->offDtStrings)));
160 Log2(("RTFdt: offMemRsvMap %#RX32\n", RT_BE2H_U32(pDtbHdr->offMemRsvMap)));
161 Log2(("RTFdt: u32Version %#RX32\n", RT_BE2H_U32(pDtbHdr->u32Version)));
162 Log2(("RTFdt: u32VersionLastCompatible %#RX32\n", RT_BE2H_U32(pDtbHdr->u32VersionLastCompatible)));
163 Log2(("RTFdt: u32CpuIdPhysBoot %#RX32\n", RT_BE2H_U32(pDtbHdr->u32CpuIdPhysBoot)));
164 Log2(("RTFdt: cbDtStrings %#RX32\n", RT_BE2H_U32(pDtbHdr->cbDtStrings)));
165 Log2(("RTFdt: cbDtStruct %#RX32\n", RT_BE2H_U32(pDtbHdr->cbDtStruct)));
166 }
167}
168
169#endif /* LOG_ENABLED */
170
171
172/**
173 * Validates the given header.
174 *
175 * @returns IPRT status code.
176 * @param pDtbHdr The DTB header to validate.
177 * @param cbDtb Size of the whole DTB in bytes.
178 * @param pErrInfo Where to return additional error information.
179 */
180static int rtFdtDtbHdr_Validate(PDTBFDTHDR pDtbHdr, uint64_t cbDtb, PRTERRINFO pErrInfo)
181{
182 /* Convert to host endianess first. */
183 pDtbHdr->u32Magic = RT_BE2H_U32(pDtbHdr->u32Magic);
184 pDtbHdr->cbFdt = RT_BE2H_U32(pDtbHdr->cbFdt);
185 pDtbHdr->offDtStruct = RT_BE2H_U32(pDtbHdr->offDtStruct);
186 pDtbHdr->offDtStrings = RT_BE2H_U32(pDtbHdr->offDtStrings);
187 pDtbHdr->offMemRsvMap = RT_BE2H_U32(pDtbHdr->offMemRsvMap);
188 pDtbHdr->u32Version = RT_BE2H_U32(pDtbHdr->u32Version);
189 pDtbHdr->u32VersionLastCompatible = RT_BE2H_U32(pDtbHdr->u32VersionLastCompatible);
190 pDtbHdr->u32CpuIdPhysBoot = RT_BE2H_U32(pDtbHdr->u32CpuIdPhysBoot);
191 pDtbHdr->cbDtStrings = RT_BE2H_U32(pDtbHdr->cbDtStrings);
192 pDtbHdr->cbDtStruct = RT_BE2H_U32(pDtbHdr->cbDtStruct);
193
194 if (pDtbHdr->u32Magic != DTBFDTHDR_MAGIC)
195 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_MAGIC_INVALID, "The magic of the DTB header is invalid (expected %#RX32, got %#RX32)",
196 DTBFDTHDR_MAGIC, pDtbHdr->u32Magic);
197 if (pDtbHdr->u32Version != DTBFDTHDR_VERSION)
198 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_VERSION_NOT_SUPPORTED, "Version %u of the DTB is not supported (supported is %u)",
199 pDtbHdr->u32Version, DTBFDTHDR_VERSION);
200 if (pDtbHdr->u32VersionLastCompatible != DTBFDTHDR_VERSION_LAST_COMP)
201 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_LAST_COMPAT_VERSION_INVALID, "Last compatible version %u of the DTB is invalid (expected %u)",
202 pDtbHdr->u32VersionLastCompatible, DTBFDTHDR_VERSION_LAST_COMP);
203 if (pDtbHdr->cbFdt != cbDtb)
204 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_SIZE_INVALID, "The size of the FDT is invalid (expected %RU32, got %RU32)",
205 cbDtb, pDtbHdr->cbFdt);
206
207 /*
208 * Check that any of the offsets is inside the bounds of the FDT and that the memory reservation block comes first,
209 * then the structs block and strings last.
210 */
211 if ( pDtbHdr->offMemRsvMap >= pDtbHdr->cbFdt
212 || pDtbHdr->offMemRsvMap < sizeof(*pDtbHdr))
213 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)",
214 pDtbHdr->offMemRsvMap, pDtbHdr->cbFdt);
215 if ( pDtbHdr->offDtStruct >= pDtbHdr->cbFdt
216 || (pDtbHdr->cbFdt - pDtbHdr->offDtStruct < pDtbHdr->cbDtStruct)
217 || pDtbHdr->offDtStruct < pDtbHdr->offMemRsvMap + sizeof(DTBFDTRSVENTRY))
218 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)",
219 pDtbHdr->offDtStruct, pDtbHdr->cbDtStruct, pDtbHdr->cbFdt, pDtbHdr->offMemRsvMap);
220 if ( pDtbHdr->offDtStrings >= pDtbHdr->cbFdt
221 || (pDtbHdr->cbFdt - pDtbHdr->offDtStrings < pDtbHdr->cbDtStrings)
222 || pDtbHdr->offDtStrings < pDtbHdr->offDtStruct + pDtbHdr->cbDtStruct)
223 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)",
224 pDtbHdr->offDtStrings, pDtbHdr->cbDtStrings, pDtbHdr->cbFdt, pDtbHdr->offDtStruct);
225
226 return VINF_SUCCESS;
227}
228
229
230/**
231 * Fres all resources allocated for the given FDT.
232 *
233 * @param pThis Pointer to the FDT instance to destroy.
234 */
235static void rtFdtDestroy(PRTFDTINT pThis)
236{
237 if (pThis->paszStrings)
238 RTMemFree(pThis->paszStrings);
239 if (pThis->pu32Structs)
240 RTMemFree(pThis->pu32Structs);
241 if (pThis->paMemRsv)
242 RTMemFree(pThis->paMemRsv);
243
244 pThis->paszStrings = NULL;
245 pThis->pu32Structs = NULL;
246 pThis->paMemRsv = NULL;
247 pThis->cMemRsv = 0;
248 RT_ZERO(pThis->DtbHdr);
249 RTMemFree(pThis);
250}
251
252
253/**
254 * Loads the memory reservation block from the underlying VFS I/O stream.
255 *
256 * @returns IPRT status code.
257 * @param pThis Pointer to the FDT instance.
258 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
259 * @param pErrInfo Where to return additional error information.
260 */
261static 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);
266 Assert(cMemRsvMax);
267
268 pThis->paMemRsv = (PDTBFDTRSVENTRY)RTMemAllocZ(cMemRsvMax * sizeof(*pThis->paMemRsv));
269 if (!pThis->paMemRsv)
270 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the memory reservation block",
271 cMemRsvMax * sizeof(*pThis->paMemRsv));
272
273 /* Read the entries one after another until the terminator is reached. */
274 uint32_t cMemRsv = 0;
275 for (;;)
276 {
277 DTBFDTRSVENTRY MemRsv;
278 int rc = RTVfsIoStrmRead(hVfsIos, &MemRsv, sizeof(MemRsv), true /*fBlocking*/, NULL /*pcbRead*/);
279 if (RT_FAILURE(rc))
280 return RTErrInfoSetF(pErrInfo, rc, "Failed to read memory reservation entry %u from I/O stream",
281 cMemRsv);
282
283 /* Check whether the terminator is reached (no need to convert endianness here). */
284 if ( MemRsv.PhysAddrStart == 0
285 && MemRsv.cbArea == 0)
286 break;
287
288 cMemRsv++;
289
290 /*
291 * The terminator must be included in the maximum entry count, if not
292 * the DTB is malformed and lacks a terminating entry before the start of the structs block.
293 */
294 if (cMemRsv == cMemRsvMax)
295 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MEM_RSV_BLOCK_TERMINATOR_MISSING,
296 "The memory reservation block lacks a terminating entry");
297
298 pThis->paMemRsv[cMemRsv - 1].PhysAddrStart = RT_BE2H_U64(MemRsv.PhysAddrStart);
299 pThis->paMemRsv[cMemRsv - 1].cbArea = RT_BE2H_U64(MemRsv.cbArea);
300 }
301
302 pThis->cMemRsv = cMemRsv;
303 return VINF_SUCCESS;
304}
305
306
307/**
308 * Loads the structs block of the given FDT.
309 *
310 * @returns IPRT status code.
311 * @param pThis Pointer to the FDT instance.
312 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
313 * @param pErrInfo Where to return additional error information.
314 */
315static int rtFdtDtbStructsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
316{
317 pThis->pu32Structs = (uint32_t *)RTMemAllocZ(pThis->DtbHdr.cbDtStruct);
318 if (!pThis->pu32Structs)
319 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,
323 true /*fBlocking*/, NULL /*pcbRead*/);
324 if (RT_FAILURE(rc))
325 return RTErrInfoSetF(pErrInfo, rc, "Failed to read structs block from I/O stream");
326
327 return VINF_SUCCESS;
328}
329
330
331/**
332 * Loads the strings block of the given FDT.
333 *
334 * @returns IPRT status code.
335 * @param pThis Pointer to the FDT instance.
336 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
337 * @param pErrInfo Where to return additional error information.
338 */
339static int rtFdtDtbStringsLoad(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
340{
341 pThis->paszStrings = (char *)RTMemAllocZ(pThis->DtbHdr.cbDtStrings);
342 if (!pThis->paszStrings)
343 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,
347 true /*fBlocking*/, NULL /*pcbRead*/);
348 if (RT_FAILURE(rc))
349 return RTErrInfoSetF(pErrInfo, rc, "Failed to read strings block from I/O stream");
350
351 /* Verify that the strings block is terminated. */
352 if (pThis->paszStrings[pThis->DtbHdr.cbDtStrings - 1] != '\0')
353 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRINGS_BLOCK_NOT_TERMINATED, "The strings block is not zero terminated");
354
355 return VINF_SUCCESS;
356}
357
358
359/**
360 * Loads the DTB from the given VFS file.
361 *
362 * @returns IPRT status code.
363 * @param phFdt Where to return the FDT handle on success.
364 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
365 * @param pErrInfo Where to return additional error information.
366 */
367static int rtFdtLoadDtb(PRTFDT phFdt, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
368{
369 DTBFDTHDR DtbHdr;
370 RTFSOBJINFO ObjInfo;
371 int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
372 if (RT_SUCCESS(rc))
373 {
374 if ((uint64_t)ObjInfo.cbObject >= sizeof(DtbHdr) + sizeof(DTBFDTRSVENTRY))
375 {
376 rc = RTVfsIoStrmRead(hVfsIos, &DtbHdr, sizeof(DtbHdr), true /*fBlocking*/, NULL /*pcbRead*/);
377 if (RT_SUCCESS(rc))
378 {
379#ifdef LOG_ENABLED
380 rtFdtDtbHdr_Log(&DtbHdr);
381#endif
382
383 /* Validate the header. */
384 rc = rtFdtDtbHdr_Validate(&DtbHdr, ObjInfo.cbObject, pErrInfo);
385 if (RT_SUCCESS(rc))
386 {
387 PRTFDTINT pThis = (PRTFDTINT)RTMemAllocZ(sizeof(*pThis));
388 if (RT_LIKELY(pThis))
389 {
390 memcpy(&pThis->DtbHdr, &DtbHdr, sizeof(DtbHdr));
391
392 /* Load the memory reservation block. */
393 rc = rtFdtDtbMemRsvLoad(pThis, hVfsIos, pErrInfo);
394 if (RT_SUCCESS(rc))
395 {
396 rc = rtFdtDtbStructsLoad(pThis, hVfsIos, pErrInfo);
397 if (RT_SUCCESS(rc))
398 {
399 rc = rtFdtDtbStringsLoad(pThis, hVfsIos, pErrInfo);
400 if (RT_SUCCESS(rc))
401 {
402 *phFdt = pThis;
403 return VINF_SUCCESS;
404 }
405 }
406 }
407
408 rtFdtDestroy(pThis);
409 }
410 else
411 RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate memory for the FDT");
412 }
413 }
414 else
415 RTErrInfoSetF(pErrInfo, rc, "Failed to read %u bytes for the DTB header -> %Rrc",
416 sizeof(DtbHdr), rc);
417 }
418 else
419 RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MALFORMED, "DTB is too small, needs at least %u bytes, only %u available",
420 sizeof(DtbHdr) + sizeof(DTBFDTRSVENTRY), ObjInfo.cbObject);
421 }
422 else
423 RTErrInfoSetF(pErrInfo, rc, "Failed to query size of the DTB -> %Rrc", rc);
424
425 return rc;
426}
427
428
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
958RTDECL(int) RTFdtCreateEmpty(PRTFDT phFdt)
959{
960 RT_NOREF(phFdt);
961 return VERR_NOT_IMPLEMENTED;
962}
963
964
965RTDECL(int) RTFdtCreateFromVfsIoStrm(PRTFDT phFdt, RTVFSIOSTREAM hVfsIos, RTFDTTYPE enmInType, PRTERRINFO pErrInfo)
966{
967 AssertPtrReturn(phFdt, VERR_INVALID_POINTER);
968 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
969
970 if (enmInType == RTFDTTYPE_DTB)
971 return rtFdtLoadDtb(phFdt, hVfsIos, pErrInfo);
972
973 return VERR_NOT_IMPLEMENTED;
974}
975
976
977RTDECL(int) RTFdtCreateFromFile(PRTFDT phFdt, const char *pszFilename, RTFDTTYPE enmInType, PRTERRINFO pErrInfo)
978{
979 RT_NOREF(phFdt, pszFilename, enmInType, pErrInfo);
980 return VERR_NOT_IMPLEMENTED;
981}
982
983
984RTDECL(void) RTFdtDestroy(RTFDT hFdt)
985{
986 PRTFDTINT pThis = hFdt;
987 AssertPtrReturnVoid(pThis);
988
989 rtFdtDestroy(pThis);
990}
991
992
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
1002 return VERR_NOT_IMPLEMENTED;
1003}
1004
1005
1006RTDECL(int) RTFdtDumpToFile(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
1007{
1008 RT_NOREF(hFdt, enmOutType, fFlags, pszFilename, pErrInfo);
1009 return VERR_NOT_IMPLEMENTED;
1010}
Note: See TracBrowser for help on using the repository browser.

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