VirtualBox

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

Last change on this file since 107455 was 107453, checked in by vboxsync, 4 weeks ago

Runtime/common/misc/fdt.cpp: Remove unreachable code, u32Token is always DTB_FDT_TOKEN_END at this point due to the while() loop before, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.1 KB
Line 
1/* $Id: fdt.cpp 107453 2025-01-07 10:13:53Z vboxsync $ */
2/** @file
3 * IPRT - Flattened Devicetree parser and generator API.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
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/file.h>
48#include <iprt/log.h>
49#include <iprt/mem.h>
50#include <iprt/sg.h>
51#include <iprt/string.h>
52#include <iprt/vfs.h>
53#include <iprt/zero.h>
54#include <iprt/formats/dtb.h>
55
56
57/*********************************************************************************************************************************
58* Defined Constants And Macros *
59*********************************************************************************************************************************/
60
61/** Special error token to denote that the end of the structs block was reached trying to query the next token. */
62#define RTFDT_TOKEN_ERROR UINT32_MAX
63
64
65/*********************************************************************************************************************************
66* Structures and Typedefs *
67*********************************************************************************************************************************/
68
69/**
70 * Internal Flattened Devicetree instance.
71 */
72typedef struct RTFDTINT
73{
74 /** Pointer to the string block. */
75 char *paszStrings;
76 /** Pointer to the raw structs block. */
77 uint8_t *pbStruct;
78 /** Pointer to the array of memory reservation entries. */
79 PDTBFDTRSVENTRY paMemRsv;
80 /** Number of memory reservation entries. */
81 uint32_t cMemRsv;
82 /** Maximum number of memory reservation entries allocated. */
83 uint32_t cMemRsvMax;
84 /** Size of the strings block. */
85 uint32_t cbStrings;
86 /** Allocated size of the string block. */
87 uint32_t cbStringsMax;
88 /** Size of the struct block. */
89 uint32_t cbStruct;
90 /** Allocated size of the struct block. */
91 uint32_t cbStructMax;
92 /** The physical boot CPU ID. */
93 uint32_t u32CpuIdPhysBoot;
94 /** Current tree depth in the structure block. */
95 uint32_t cTreeDepth;
96 /** The next free phandle value. */
97 uint32_t idPHandle;
98} RTFDTINT;
99/** Pointer to the internal Flattened Devicetree instance. */
100typedef RTFDTINT *PRTFDTINT;
101
102
103/**
104 * DTB property dump callback.
105 *
106 * @returns IPRT status code.
107 * @param pThis Pointer to the FDT instance.
108 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
109 * @param pszProperty Property name.
110 * @param pvProperty Pointer to the raw property data.
111 * @param cbProperty Size of the property in bytes.
112 * @param pErrInfo Where to return additional error information.
113 */
114typedef DECLCALLBACKTYPE(int, FNRTFDTDTBPROPERTYDUMP,(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
115 const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo));
116/** Pointer to a DTB property dump callback. */
117typedef FNRTFDTDTBPROPERTYDUMP *PFNRTFDTDTBPROPERTYDUMP;
118
119
120/**
121 * DTB property dump descriptor.
122 */
123typedef struct RTFDTDTBPROPDUMPDESC
124{
125 /** Name of the property. */
126 const char *pszProperty;
127 /** The dump callback. */
128 PFNRTFDTDTBPROPERTYDUMP pfnDump;
129} RTFDTDTBPROPDUMPDESC;
130/** Pointer to a property dump descriptor. */
131typedef RTFDTDTBPROPDUMPDESC *PRTFDTDTBPROPDUMPDESC;
132/** Pointer to a const property dump descriptor. */
133typedef const RTFDTDTBPROPDUMPDESC *PCRTFDTDTBPROPDUMPDESC;
134
135
136/**
137 * DTB struct dump state.
138 */
139typedef struct RTFDTDTBDUMP
140{
141 /** Number of bytes left in the structs block to dump. */
142 size_t cbLeft;
143 /** Pointer to the next item in the structs block. */
144 const uint8_t *pbStructs;
145} RTFDTDTBDUMP;
146/** Pointer to a DTB struct dump state. */
147typedef RTFDTDTBDUMP *PRTFDTDTBDUMP;
148/** Pointer to a constant DTB struct dump state. */
149typedef const RTFDTDTBDUMP *PCRTFDTDTBDUMP;
150
151
152/*********************************************************************************************************************************
153* Global Variables *
154*********************************************************************************************************************************/
155
156
157/*********************************************************************************************************************************
158* Internal Functions *
159*********************************************************************************************************************************/
160#ifdef LOG_ENABLED
161
162/**
163 * Logs a FDT DTB header.
164 *
165 * @param pDtbHdr The FDT DTB header.
166 */
167static void rtFdtDtbHdr_Log(PCDTBFDTHDR pDtbHdr)
168{
169 if (LogIs2Enabled())
170 {
171 Log2(("RTFdt: Header:\n"));
172 Log2(("RTFdt: u32Magic %#RX32\n", RT_BE2H_U32(pDtbHdr->u32Magic)));
173 Log2(("RTFdt: cbFdt %#RX32\n", RT_BE2H_U32(pDtbHdr->cbFdt)));
174 Log2(("RTFdt: offDtStruct %#RX32\n", RT_BE2H_U32(pDtbHdr->offDtStruct)));
175 Log2(("RTFdt: offDtStrings %#RX32\n", RT_BE2H_U32(pDtbHdr->offDtStrings)));
176 Log2(("RTFdt: offMemRsvMap %#RX32\n", RT_BE2H_U32(pDtbHdr->offMemRsvMap)));
177 Log2(("RTFdt: u32Version %#RX32\n", RT_BE2H_U32(pDtbHdr->u32Version)));
178 Log2(("RTFdt: u32VersionLastCompatible %#RX32\n", RT_BE2H_U32(pDtbHdr->u32VersionLastCompatible)));
179 Log2(("RTFdt: u32CpuIdPhysBoot %#RX32\n", RT_BE2H_U32(pDtbHdr->u32CpuIdPhysBoot)));
180 Log2(("RTFdt: cbDtStrings %#RX32\n", RT_BE2H_U32(pDtbHdr->cbDtStrings)));
181 Log2(("RTFdt: cbDtStruct %#RX32\n", RT_BE2H_U32(pDtbHdr->cbDtStruct)));
182 }
183}
184
185#endif /* LOG_ENABLED */
186
187
188/**
189 * Validates the given header.
190 *
191 * @returns IPRT status code.
192 * @param pDtbHdr The DTB header to validate.
193 * @param cbDtb Size of the whole DTB in bytes.
194 * @param pErrInfo Where to return additional error information.
195 */
196static int rtFdtDtbHdr_Validate(PDTBFDTHDR pDtbHdr, uint64_t cbDtb, PRTERRINFO pErrInfo)
197{
198 /* Convert to host endianess first. */
199 pDtbHdr->u32Magic = RT_BE2H_U32(pDtbHdr->u32Magic);
200 pDtbHdr->cbFdt = RT_BE2H_U32(pDtbHdr->cbFdt);
201 pDtbHdr->offDtStruct = RT_BE2H_U32(pDtbHdr->offDtStruct);
202 pDtbHdr->offDtStrings = RT_BE2H_U32(pDtbHdr->offDtStrings);
203 pDtbHdr->offMemRsvMap = RT_BE2H_U32(pDtbHdr->offMemRsvMap);
204 pDtbHdr->u32Version = RT_BE2H_U32(pDtbHdr->u32Version);
205 pDtbHdr->u32VersionLastCompatible = RT_BE2H_U32(pDtbHdr->u32VersionLastCompatible);
206 pDtbHdr->u32CpuIdPhysBoot = RT_BE2H_U32(pDtbHdr->u32CpuIdPhysBoot);
207 pDtbHdr->cbDtStrings = RT_BE2H_U32(pDtbHdr->cbDtStrings);
208 pDtbHdr->cbDtStruct = RT_BE2H_U32(pDtbHdr->cbDtStruct);
209
210 if (pDtbHdr->u32Magic != DTBFDTHDR_MAGIC)
211 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_MAGIC_INVALID, "The magic of the DTB header is invalid (expected %#RX32, got %#RX32)",
212 DTBFDTHDR_MAGIC, pDtbHdr->u32Magic);
213 if (pDtbHdr->u32Version != DTBFDTHDR_VERSION)
214 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_VERSION_NOT_SUPPORTED, "Version %u of the DTB is not supported (supported is %u)",
215 pDtbHdr->u32Version, DTBFDTHDR_VERSION);
216 if (pDtbHdr->u32VersionLastCompatible != DTBFDTHDR_VERSION_LAST_COMP)
217 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_LAST_COMPAT_VERSION_INVALID, "Last compatible version %u of the DTB is invalid (expected %u)",
218 pDtbHdr->u32VersionLastCompatible, DTBFDTHDR_VERSION_LAST_COMP);
219 if (pDtbHdr->cbFdt != cbDtb)
220 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_HDR_SIZE_INVALID, "The size of the FDT is invalid (expected %RU32, got %RU32)",
221 cbDtb, pDtbHdr->cbFdt);
222
223 /*
224 * Check that any of the offsets is inside the bounds of the FDT and that the memory reservation block comes first,
225 * then the structs block and strings last.
226 */
227 if ( pDtbHdr->offMemRsvMap >= pDtbHdr->cbFdt
228 || pDtbHdr->offMemRsvMap < sizeof(*pDtbHdr))
229 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)",
230 pDtbHdr->offMemRsvMap, pDtbHdr->cbFdt);
231 if ( pDtbHdr->offDtStruct >= pDtbHdr->cbFdt
232 || (pDtbHdr->cbFdt - pDtbHdr->offDtStruct < pDtbHdr->cbDtStruct)
233 || pDtbHdr->offDtStruct < pDtbHdr->offMemRsvMap + sizeof(DTBFDTRSVENTRY))
234 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)",
235 pDtbHdr->offDtStruct, pDtbHdr->cbDtStruct, pDtbHdr->cbFdt, pDtbHdr->offMemRsvMap);
236 if ( pDtbHdr->offDtStrings >= pDtbHdr->cbFdt
237 || (pDtbHdr->cbFdt - pDtbHdr->offDtStrings < pDtbHdr->cbDtStrings)
238 || pDtbHdr->offDtStrings < pDtbHdr->offDtStruct + pDtbHdr->cbDtStruct)
239 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)",
240 pDtbHdr->offDtStrings, pDtbHdr->cbDtStrings, pDtbHdr->cbFdt, pDtbHdr->offDtStruct);
241
242 return VINF_SUCCESS;
243}
244
245
246/**
247 * Fres all resources allocated for the given FDT.
248 *
249 * @param pThis Pointer to the FDT instance to destroy.
250 */
251static void rtFdtDestroy(PRTFDTINT pThis)
252{
253 if (pThis->paszStrings)
254 RTMemFree(pThis->paszStrings);
255 if (pThis->pbStruct)
256 RTMemFree(pThis->pbStruct);
257 if (pThis->paMemRsv)
258 RTMemFree(pThis->paMemRsv);
259
260 pThis->paszStrings = NULL;
261 pThis->pbStruct = NULL;
262 pThis->paMemRsv = NULL;
263 pThis->cMemRsv = 0;
264 pThis->cMemRsvMax = 0;
265 pThis->cbStrings = 0;
266 pThis->cbStringsMax = 0;
267 pThis->cbStruct = 0;
268 pThis->cbStructMax = 0;
269 pThis->u32CpuIdPhysBoot = 0;
270 pThis->cTreeDepth = 0;
271 pThis->idPHandle = UINT32_MAX;
272 RTMemFree(pThis);
273}
274
275
276/**
277 * Loads the memory reservation block from the underlying VFS I/O stream.
278 *
279 * @returns IPRT status code.
280 * @param pThis Pointer to the FDT instance.
281 * @param pDtbHdr The DTB header.
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 rtFdtDtbMemRsvLoad(PRTFDTINT pThis, PCDTBFDTHDR pDtbHdr, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
286{
287 AssertReturn(pDtbHdr->offMemRsvMap < pDtbHdr->offDtStruct, VERR_INTERNAL_ERROR);
288
289 uint32_t cMemRsvMax = (pDtbHdr->offDtStruct - pDtbHdr->offMemRsvMap) / sizeof(*pThis->paMemRsv);
290 Assert(cMemRsvMax);
291
292 pThis->paMemRsv = (PDTBFDTRSVENTRY)RTMemAllocZ(cMemRsvMax * sizeof(*pThis->paMemRsv));
293 if (!pThis->paMemRsv)
294 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the memory reservation block",
295 cMemRsvMax * sizeof(*pThis->paMemRsv));
296
297 pThis->cMemRsvMax = cMemRsvMax;
298
299 /* Read the entries one after another until the terminator is reached. */
300 uint32_t cMemRsv = 0;
301 for (;;)
302 {
303 DTBFDTRSVENTRY MemRsv;
304 int rc = RTVfsIoStrmRead(hVfsIos, &MemRsv, sizeof(MemRsv), true /*fBlocking*/, NULL /*pcbRead*/);
305 if (RT_FAILURE(rc))
306 return RTErrInfoSetF(pErrInfo, rc, "Failed to read memory reservation entry %u from I/O stream",
307 cMemRsv);
308
309 /* Check whether the terminator is reached (no need to convert endianness here). */
310 if ( MemRsv.PhysAddrStart == 0
311 && MemRsv.cbArea == 0)
312 break;
313
314 cMemRsv++;
315
316 /*
317 * The terminator must be included in the maximum entry count, if not
318 * the DTB is malformed and lacks a terminating entry before the start of the structs block.
319 */
320 if (cMemRsv == cMemRsvMax)
321 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MEM_RSV_BLOCK_TERMINATOR_MISSING,
322 "The memory reservation block lacks a terminating entry");
323
324 pThis->paMemRsv[cMemRsv - 1].PhysAddrStart = RT_BE2H_U64(MemRsv.PhysAddrStart);
325 pThis->paMemRsv[cMemRsv - 1].cbArea = RT_BE2H_U64(MemRsv.cbArea);
326 }
327
328 pThis->cMemRsv = cMemRsv;
329 return VINF_SUCCESS;
330}
331
332
333/**
334 * Loads the structs block of the given FDT.
335 *
336 * @returns IPRT status code.
337 * @param pThis Pointer to the FDT instance.
338 * @param pDtbHdr The DTB header.
339 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
340 * @param pErrInfo Where to return additional error information.
341 */
342static int rtFdtDtbStructsLoad(PRTFDTINT pThis, PCDTBFDTHDR pDtbHdr, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
343{
344 pThis->pbStruct = (uint8_t *)RTMemAllocZ(pDtbHdr->cbDtStruct);
345 if (!pThis->pbStruct)
346 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the structs block",
347 pDtbHdr->cbDtStruct);
348
349 int rc = RTVfsIoStrmReadAt(hVfsIos, pDtbHdr->offDtStruct, pThis->pbStruct, pDtbHdr->cbDtStruct,
350 true /*fBlocking*/, NULL /*pcbRead*/);
351 if (RT_FAILURE(rc))
352 return RTErrInfoSetF(pErrInfo, rc, "Failed to read structs block from I/O stream");
353
354 return VINF_SUCCESS;
355}
356
357
358/**
359 * Loads the strings block of the given FDT.
360 *
361 * @returns IPRT status code.
362 * @param pThis Pointer to the FDT instance.
363 * @param pDtbHdr The DTB header.
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 rtFdtDtbStringsLoad(PRTFDTINT pThis, PCDTBFDTHDR pDtbHdr, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
368{
369 pThis->paszStrings = (char *)RTMemAllocZ(pDtbHdr->cbDtStrings);
370 if (!pThis->paszStrings)
371 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate %u bytes of memory for the strings block",
372 pDtbHdr->cbDtStrings);
373
374 int rc = RTVfsIoStrmReadAt(hVfsIos, pDtbHdr->offDtStrings, pThis->paszStrings, pDtbHdr->cbDtStrings,
375 true /*fBlocking*/, NULL /*pcbRead*/);
376 if (RT_FAILURE(rc))
377 return RTErrInfoSetF(pErrInfo, rc, "Failed to read strings block from I/O stream");
378
379 /* Verify that the strings block is terminated. */
380 if (pThis->paszStrings[pDtbHdr->cbDtStrings - 1] != '\0')
381 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRINGS_BLOCK_NOT_TERMINATED, "The strings block is not zero terminated");
382
383 return VINF_SUCCESS;
384}
385
386
387/**
388 * Loads the DTB from the given VFS file.
389 *
390 * @returns IPRT status code.
391 * @param phFdt Where to return the FDT handle on success.
392 * @param hVfsIos The VFS I/O stream handle to load the DTB from.
393 * @param pErrInfo Where to return additional error information.
394 */
395static int rtFdtLoadDtb(PRTFDT phFdt, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
396{
397 DTBFDTHDR DtbHdr;
398 RTFSOBJINFO ObjInfo;
399 int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
400 if (RT_SUCCESS(rc))
401 {
402 if ((uint64_t)ObjInfo.cbObject >= sizeof(DtbHdr) + sizeof(DTBFDTRSVENTRY))
403 {
404 rc = RTVfsIoStrmRead(hVfsIos, &DtbHdr, sizeof(DtbHdr), true /*fBlocking*/, NULL /*pcbRead*/);
405 if (RT_SUCCESS(rc))
406 {
407#ifdef LOG_ENABLED
408 rtFdtDtbHdr_Log(&DtbHdr);
409#endif
410
411 /* Validate the header. */
412 rc = rtFdtDtbHdr_Validate(&DtbHdr, ObjInfo.cbObject, pErrInfo);
413 if (RT_SUCCESS(rc))
414 {
415 PRTFDTINT pThis = (PRTFDTINT)RTMemAllocZ(sizeof(*pThis));
416 if (RT_LIKELY(pThis))
417 {
418 pThis->cbStrings = DtbHdr.cbDtStrings;
419 pThis->cbStruct = DtbHdr.cbDtStruct;
420 pThis->u32CpuIdPhysBoot = DtbHdr.u32CpuIdPhysBoot;
421 pThis->idPHandle = UINT32_MAX; /** @todo Would need to parse the whole tree to find the next free handle. */
422
423 /* Load the memory reservation block. */
424 rc = rtFdtDtbMemRsvLoad(pThis, &DtbHdr, hVfsIos, pErrInfo);
425 if (RT_SUCCESS(rc))
426 {
427 rc = rtFdtDtbStructsLoad(pThis, &DtbHdr, hVfsIos, pErrInfo);
428 if (RT_SUCCESS(rc))
429 {
430 rc = rtFdtDtbStringsLoad(pThis, &DtbHdr, hVfsIos, pErrInfo);
431 if (RT_SUCCESS(rc))
432 {
433 pThis->cbStringsMax = pThis->cbStrings;
434 pThis->cbStructMax = pThis->cbStruct;
435
436 *phFdt = pThis;
437 return VINF_SUCCESS;
438 }
439 }
440 }
441
442 rtFdtDestroy(pThis);
443 }
444 else
445 RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Failed to allocate memory for the FDT");
446 }
447 }
448 else
449 RTErrInfoSetF(pErrInfo, rc, "Failed to read %u bytes for the DTB header -> %Rrc",
450 sizeof(DtbHdr), rc);
451 }
452 else
453 RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_MALFORMED, "DTB is too small, needs at least %u bytes, only %u available",
454 sizeof(DtbHdr) + sizeof(DTBFDTRSVENTRY), ObjInfo.cbObject);
455 }
456 else
457 RTErrInfoSetF(pErrInfo, rc, "Failed to query size of the DTB -> %Rrc", rc);
458
459 return rc;
460}
461
462
463/**
464 * Returns the next token in the structs block from the given start returning an error
465 * if beyond the structs block.
466 *
467 * @returns Next token or RTFDT_TOKEN_ERROR if the end of the structs block is reached.
468 * @param pDump Pointer to the dump state.
469 */
470DECLINLINE(uint32_t) rtFdtStructsGetToken(PRTFDTDTBDUMP pDump)
471{
472 if (pDump->cbLeft < sizeof(uint32_t))
473 return RTFDT_TOKEN_ERROR;
474
475 uint32_t u32Token = *(const uint32_t *)pDump->pbStructs;
476 pDump->pbStructs += sizeof(uint32_t);
477 pDump->cbLeft -= sizeof(uint32_t);
478 return RT_H2BE_U32(u32Token);
479}
480
481
482#ifdef LOG_ENABLED
483/**
484 * Gets the offset inside the structs block given from the current pointer.
485 *
486 * @returns Offset in bytes from the start of the structs block.
487 * @param pThis Pointer to the FDT instance.
488 * @param pDump Pointer to the dump state.
489 */
490DECLINLINE(size_t) rtFdtStructsGetOffset(PRTFDTINT pThis, PCRTFDTDTBDUMP pDump)
491{
492 return pThis->cbStruct - pDump->cbLeft - sizeof(uint32_t);
493}
494#endif
495
496
497/**
498 * Advances the pointer inside the dump state by the given amount of bytes taking care of the alignment.
499 *
500 * @returns IPRT status code.
501 * @param pDump Pointer to the dump state.
502 * @param cbAdv How many bytes to advance.
503 * @param rcOob The status code to set if advancing goes beyond the end of the structs block.
504 */
505DECLINLINE(int) rtFdtStructsDumpAdvance(PRTFDTDTBDUMP pDump, uint32_t cbAdv, int rcOob)
506{
507 /* Align the pointer to the next 32-bit boundary. */
508 const uint8_t *pbStructsNew = RT_ALIGN_PT(pDump->pbStructs + cbAdv, sizeof(uint32_t), uint8_t *);
509 if (((uintptr_t)pbStructsNew - (uintptr_t)pDump->pbStructs) > pDump->cbLeft)
510 return rcOob;
511
512 pDump->pbStructs = pbStructsNew;
513 pDump->cbLeft -= (uintptr_t)pbStructsNew - (uintptr_t)pDump->pbStructs;
514 return VINF_SUCCESS;
515}
516
517
518/**
519 * Adds the proper indentation before a new line.
520 *
521 * @returns IPRT status code.
522 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
523 * @param uIndentLvl The level of indentation.
524 */
525static int rtFdtStructsDumpDtsIndent(RTVFSIOSTREAM hVfsIos, uint32_t uIndentLvl)
526{
527 while (uIndentLvl--)
528 {
529 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, " ");
530 if (cch != 4)
531 return cch < 0 ? -cch : VERR_BUFFER_UNDERFLOW;
532 }
533
534 return VINF_SUCCESS;
535}
536
537
538/**
539 * Queries a zero terminated ASCII string from the current location inside the structs block.
540 *
541 * @returns IPRT status code.
542 * @param pDump The dump state.
543 * @param pszString The string buffer to copy the string to.
544 * @param cchStringMax Maximum size of the string buffer in characters (including the terminator).
545 * @param pErrInfo Where to return additional error information.
546 */
547static int rtFdtStructsQueryString(PRTFDTDTBDUMP pDump, char *pszString, size_t cchStringMax, PRTERRINFO pErrInfo)
548{
549 const char *pszStrSrc = (const char *)pDump->pbStructs;
550 size_t cbLeft = pDump->cbLeft;
551
552 AssertReturn(cchStringMax, VERR_INTERNAL_ERROR);
553
554 for (;;)
555 {
556 *pszString++ = *pszStrSrc;
557 cchStringMax--;
558 cbLeft--;
559
560 if (*pszStrSrc == '\0')
561 {
562 pszStrSrc++;
563
564 int rc = rtFdtStructsDumpAdvance(pDump, (uintptr_t)pszStrSrc - (uintptr_t)pDump->pbStructs, VERR_FDT_DTB_STRUCTS_BLOCK_MALFORMED_PADDING);
565 if (RT_FAILURE(rc))
566 return RTErrInfoSetF(pErrInfo, rc, "String end + padding exceeds structs block");
567
568 return VINF_SUCCESS;
569 }
570
571 if (!cchStringMax)
572 return RTErrInfoSetF(pErrInfo, VERR_BUFFER_OVERFLOW, "Structs string too long to fit into target buffer");
573
574 pszStrSrc++;
575 if (!cbLeft)
576 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_STRING_NOT_TERMINATED, "Structs block contains an unterminated string");
577 }
578
579 /* Not reached */
580}
581
582
583/**
584 * Dumps a string list property.
585 *
586 * @returns IPRT status code.
587 * @param pThis Pointer to the FDT instance.
588 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
589 * @param pszProperty Name of the property being dumped.
590 * @param pvProperty Raw property payload.
591 * @param cbProperty Size of the property payload in bytes.
592 * @param pErrInfo Where to return additional error information.
593 */
594static DECLCALLBACK(int) rtFdtDtbPropDumpStringList(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
595 const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo)
596{
597 RT_NOREF(pThis);
598
599 const char *pszProp = (const char *)pvProperty;
600 if (pszProp[cbProperty - 1] != '\0')
601 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_STRING_NOT_TERMINATED,
602 "The string payload of property '%s' is not terminated", pszProperty);
603
604 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "\"%s\"", pszProp);
605 if (cch <= 0)
606 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
607
608 cch = strlen(pszProp) + 1;
609 cbProperty -= cch;
610 while (cbProperty)
611 {
612 pszProp += cch;
613
614 cch = RTVfsIoStrmPrintf(hVfsIos, ", \"%s\"", pszProp);
615 if (cch <= 0)
616 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
617
618 cch = strlen(pszProp) + 1;
619 cbProperty -= cch;
620 }
621
622 return VINF_SUCCESS;
623}
624
625
626/**
627 * Dumps a string property.
628 *
629 * @returns IPRT status code.
630 * @param pThis Pointer to the FDT instance.
631 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
632 * @param pszProperty Name of the property being dumped.
633 * @param pvProperty Raw property payload.
634 * @param cbProperty Size of the property payload in bytes.
635 * @param pErrInfo Where to return additional error information.
636 */
637static DECLCALLBACK(int) rtFdtDtbPropDumpString(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
638 const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo)
639{
640 RT_NOREF(pThis);
641
642 const char *pszProp = (const char *)pvProperty;
643 if (pszProp[cbProperty - 1] != '\0')
644 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_STRING_NOT_TERMINATED,
645 "The string payload of property '%s' is not terminated", pszProperty);
646
647 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "\"%s\"", pszProp);
648 if (cch <= 0)
649 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
650
651 return VINF_SUCCESS;
652}
653
654
655/**
656 * Dumps a u32 cell property.
657 *
658 * @returns IPRT status code.
659 * @param pThis Pointer to the FDT instance.
660 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
661 * @param pszProperty Name of the property being dumped.
662 * @param pvProperty Raw property payload.
663 * @param cbProperty Size of the property payload in bytes.
664 * @param pErrInfo Where to return additional error information.
665 */
666static DECLCALLBACK(int) rtFdtDtbPropDumpCellsU32(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, const char *pszProperty,
667 const void *pvProperty, size_t cbProperty, PRTERRINFO pErrInfo)
668{
669 RT_NOREF(pThis);
670
671 if (cbProperty % sizeof(uint32_t))
672 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_SIZE_MALFORMED,
673 "Property '%s' payload is not a multiple of 32-bit", pszProperty);
674
675 const uint32_t *pu32Prop = (const uint32_t *)pvProperty;
676
677 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "<");
678 if (cch == 1)
679 {
680 cch = RTVfsIoStrmPrintf(hVfsIos, "%#RX32", RT_BE2H_U32(*pu32Prop));
681 pu32Prop++;
682 if (cch > 0)
683 {
684 for (uint32_t i = 1; i < cbProperty / sizeof(uint32_t); i++)
685 {
686 cch = RTVfsIoStrmPrintf(hVfsIos, " %#RX32", RT_BE2H_U32(*pu32Prop));
687 pu32Prop++;
688 if (cch <= 0)
689 break;
690 }
691 }
692
693 if (cch > 0)
694 cch = RTVfsIoStrmPrintf(hVfsIos, ">");
695 }
696
697 if (cch <= 0)
698 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property data");
699
700 return VINF_SUCCESS;
701}
702
703
704/**
705 * The known properties to dump.
706 */
707static const RTFDTDTBPROPDUMPDESC g_aPropDump[] =
708{
709 { "compatible", rtFdtDtbPropDumpStringList }, /** @todo stringlist */
710 { "model", rtFdtDtbPropDumpString },
711 { "status", rtFdtDtbPropDumpString },
712 { "phandle", rtFdtDtbPropDumpCellsU32 },
713 { "linux,phandle", rtFdtDtbPropDumpCellsU32 },
714 { "#address-cells", rtFdtDtbPropDumpCellsU32 },
715 { "#size-cells", rtFdtDtbPropDumpCellsU32 },
716 { "reg", rtFdtDtbPropDumpCellsU32 },
717 { "virtual-reg", rtFdtDtbPropDumpCellsU32 },
718 { "ranges", rtFdtDtbPropDumpCellsU32 },
719 { "dma-ranges", rtFdtDtbPropDumpCellsU32 },
720 { "name", rtFdtDtbPropDumpString },
721 { "device_type", rtFdtDtbPropDumpString },
722 { "interrupts", rtFdtDtbPropDumpCellsU32 },
723 { "interrupt-parent", rtFdtDtbPropDumpCellsU32 },
724 { "interrupts-extended", rtFdtDtbPropDumpCellsU32 },
725 { "#interrupt-cells", rtFdtDtbPropDumpCellsU32 },
726 { "interrupt-map", rtFdtDtbPropDumpCellsU32 },
727 { "interrupt-map-mask", rtFdtDtbPropDumpCellsU32 },
728 { "serial-number", rtFdtDtbPropDumpString },
729 { "chassis-type", rtFdtDtbPropDumpString },
730 { "clock-frequency", rtFdtDtbPropDumpCellsU32 },
731 { "reg-shift", rtFdtDtbPropDumpCellsU32 },
732 { "label", rtFdtDtbPropDumpString },
733 { "clock-names", rtFdtDtbPropDumpStringList },
734 { "clock-output-names", rtFdtDtbPropDumpStringList },
735 { "stdout-path", rtFdtDtbPropDumpString },
736 { "method", rtFdtDtbPropDumpString },
737};
738
739
740/**
741 * Dumps the property as a DTS source starting at the given location inside the structs block.
742 *
743 * @returns IPRT status code.
744 * @param pThis Pointer to the FDT instance.
745 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
746 * @param pDump The dump state.
747 * @param uIndentLvl The level of indentation.
748 * @param pErrInfo Where to return additional error information.
749 */
750static int rtFdtStructsDumpPropertyAsDts(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTFDTDTBDUMP pDump, uint32_t uIndentLvl, PRTERRINFO pErrInfo)
751{
752 DTBFDTPROP Prop;
753
754 if (pDump->cbLeft < sizeof(Prop))
755 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END,
756 "Not enough space left in the structs block to read a property entry");
757
758 memcpy(&Prop, pDump->pbStructs, sizeof(Prop));
759 pDump->pbStructs += sizeof(Prop);
760 pDump->cbLeft -= sizeof(Prop);
761 Prop.offPropertyName = RT_BE2H_U32(Prop.offPropertyName);
762 Prop.cbProperty = RT_BE2H_U32(Prop.cbProperty);
763
764 if (Prop.offPropertyName >= pThis->cbStrings)
765 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_PROP_NAME_OFF_TOO_LARGE, "Property name offset points past the string block");
766
767 int rc = rtFdtStructsDumpDtsIndent(hVfsIos, uIndentLvl);
768 if (RT_FAILURE(rc))
769 return rc;
770
771 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "%s", &pThis->paszStrings[Prop.offPropertyName]);
772 if (cch <= 0)
773 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write property name: '%s'",
774 &pThis->paszStrings[Prop.offPropertyName]);
775
776 const uint8_t *pbProp = pDump->pbStructs;
777 if (Prop.cbProperty)
778 {
779 if (Prop.cbProperty > pDump->cbLeft)
780 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END, "Property '%s' data exceeds struct blocks",
781 &pThis->paszStrings[Prop.offPropertyName]);
782
783 cch = RTVfsIoStrmPrintf(hVfsIos, " = ");
784 if (cch <= 0)
785 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to output property");
786
787 rc = VERR_NOT_FOUND;
788 for (uint32_t i = 0; i < RT_ELEMENTS(g_aPropDump); i++)
789 {
790 if (!strcmp(g_aPropDump[i].pszProperty, &pThis->paszStrings[Prop.offPropertyName]))
791 {
792 rc = g_aPropDump[i].pfnDump(pThis, hVfsIos, &pThis->paszStrings[Prop.offPropertyName],
793 pbProp, Prop.cbProperty, pErrInfo);
794 break;
795 }
796 }
797
798 /* If not found use the standard U32 cells dumper. */
799 if (rc == VERR_NOT_FOUND)
800 rc = rtFdtDtbPropDumpCellsU32(pThis, hVfsIos, &pThis->paszStrings[Prop.offPropertyName],
801 pbProp, Prop.cbProperty, pErrInfo);
802 if (RT_FAILURE(rc))
803 return rc;
804
805 cch = RTVfsIoStrmPrintf(hVfsIos, ";\n");
806 if (cch <= 0)
807 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to output property");
808
809 rc = rtFdtStructsDumpAdvance(pDump, Prop.cbProperty, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END);
810 }
811 else
812 {
813 cch = RTVfsIoStrmPrintf(hVfsIos, ";\n");
814 if (cch <= 0)
815 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write newline");
816 }
817
818 return rc;
819}
820
821
822/**
823 * Dumps the node name as a DTS source starting at the given location inside the structs block.
824 *
825 * @returns IPRT status code.
826 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
827 * @param pDump The dump state.
828 * @param uIndentLvl The level of indentation.
829 * @param pErrInfo Where to return additional error information.
830 */
831static int rtFdtStructsDumpNodeAsDts(RTVFSIOSTREAM hVfsIos, PRTFDTDTBDUMP pDump, uint32_t uIndentLvl, PRTERRINFO pErrInfo)
832{
833 char szNdName[512]; /* Should be plenty. */
834
835 int rc = rtFdtStructsQueryString(pDump, &szNdName[0], sizeof(szNdName), pErrInfo);
836 if (RT_FAILURE(rc))
837 return rc;
838
839 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "\n", szNdName);
840 if (cch <= 0)
841 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS node name");
842
843 rc = rtFdtStructsDumpDtsIndent(hVfsIos, uIndentLvl);
844 if (RT_FAILURE(rc))
845 return rc;
846
847 cch = RTVfsIoStrmPrintf(hVfsIos, "%s {\n", szNdName);
848 if (cch <= 0)
849 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS node name");
850
851 return VINF_SUCCESS;
852}
853
854
855static int rtFdtStructsDumpEndNodeAsDts(RTVFSIOSTREAM hVfsIos, uint32_t uIndentLvl, PRTERRINFO pErrInfo)
856{
857 int rc = rtFdtStructsDumpDtsIndent(hVfsIos, uIndentLvl);
858 if (RT_FAILURE(rc))
859 return rc;
860
861 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "};\n");
862 if (cch <= 0)
863 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS node closing");
864
865 return VINF_SUCCESS;
866}
867
868
869/**
870 * Dumps the given FDT as DTS v1 sources from the root node.
871 *
872 * @returns IPRT status code.
873 * @param pThis Pointer to the FDT instance.
874 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
875 * @param pErrInfo Where to return additional error information.
876 */
877static int rtFdtDumpRootAsDts(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
878{
879 RTFDTDTBDUMP Dump;
880
881 Dump.cbLeft = pThis->cbStruct;
882 Dump.pbStructs = pThis->pbStruct;
883
884 /* Skip any NOP tokens. */
885 uint32_t u32Token = rtFdtStructsGetToken(&Dump);
886 while (u32Token == DTB_FDT_TOKEN_NOP)
887 u32Token = rtFdtStructsGetToken(&Dump);
888
889 /* The root node starts with a BEGIN_NODE token. */
890 if (u32Token != DTB_FDT_TOKEN_BEGIN_NODE)
891 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",
892 RT_BE2H_U32(u32Token));
893
894 /* Load the name for the root node (should be an empty string). */
895 char chNdRootName;
896 int rc = rtFdtStructsQueryString(&Dump, &chNdRootName, sizeof(chNdRootName), pErrInfo);
897 if (RT_FAILURE(rc))
898 return rc;
899
900 if (chNdRootName != '\0')
901 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_NODE_NAME_INVALID, "The root node name isn't zero terminated: %c",
902 chNdRootName);
903
904 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "/ {\n");
905 if (cch <= 0)
906 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS root node");
907
908 uint32_t uNdLvl = 1;
909 u32Token = rtFdtStructsGetToken(&Dump);
910 while (u32Token != DTB_FDT_TOKEN_END)
911 {
912 Log4(("rtFdtDumpAsDtsRoot: Token %#RX32 at offset %#zx\n", RT_BE2H_U32(u32Token), rtFdtStructsGetOffset(pThis, &Dump)));
913
914 switch (u32Token)
915 {
916 case DTB_FDT_TOKEN_BEGIN_NODE:
917 Log3(("rtFdtDumpAsDtsRoot: BEGIN_NODE token at offset %#zx\n", rtFdtStructsGetOffset(pThis, &Dump)));
918 rc = rtFdtStructsDumpNodeAsDts(hVfsIos, &Dump, uNdLvl, pErrInfo);
919 if (RT_FAILURE(rc))
920 return rc;
921
922 uNdLvl++;
923 break;
924 case DTB_FDT_TOKEN_PROPERTY:
925 Log3(("rtFdtDumpAsDtsRoot: PROP token at offset %#zx\n", rtFdtStructsGetOffset(pThis, &Dump)));
926 rc = rtFdtStructsDumpPropertyAsDts(pThis, hVfsIos, &Dump, uNdLvl, pErrInfo);
927 if (RT_FAILURE(rc))
928 return rc;
929 break;
930 case DTB_FDT_TOKEN_NOP:
931 Log3(("rtFdtDumpAsDtsRoot: NOP token at offset %#zx\n", rtFdtStructsGetOffset(pThis, &Dump)));
932 break;
933 case DTB_FDT_TOKEN_END_NODE:
934 Log3(("rtFdtDumpAsDtsRoot: END_NODE token at offset %#zx\n", rtFdtStructsGetOffset(pThis, &Dump)));
935 if (!uNdLvl)
936 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_PREMATURE_END,
937 "END_NODE token encountered at the root node");
938
939 uNdLvl--;
940 rc = rtFdtStructsDumpEndNodeAsDts(hVfsIos, uNdLvl, pErrInfo);
941 if (RT_FAILURE(rc))
942 return rc;
943 break;
944 case RTFDT_TOKEN_ERROR:
945 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_TOKEN_INVALID, "The structs block is malformed");
946 default:
947 return RTErrInfoSetF(pErrInfo, VERR_FDT_DTB_STRUCTS_BLOCK_TOKEN_INVALID, "The structs block contains an invalid/unknown token: %#RX32",
948 RT_BE2H_U32(u32Token));
949 }
950
951 u32Token = rtFdtStructsGetToken(&Dump);
952 if (u32Token == DTB_FDT_TOKEN_END)
953 Log3(("rtFdtDumpAsDtsRoot: END token at offset %#zx\n", rtFdtStructsGetOffset(pThis, &Dump)));
954 }
955
956 return VINF_SUCCESS;
957}
958
959
960/**
961 * Dumps the given FDT instance as DTS source.
962 *
963 * @returns IPRT status code.
964 * @param pThis Pointer to the FDT instance.
965 * @param hVfsIos The VFS I/O stream handle to dump the DTS to.
966 * @param pErrInfo Where to return additional error information.
967 */
968static int rtFdtDumpAsDts(PRTFDTINT pThis, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
969{
970 ssize_t cch = RTVfsIoStrmPrintf(hVfsIos, "/dts-v1/;\n");
971 if (cch <= 0)
972 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write DTS header");
973
974 /* Write memory reservations. */
975 for (uint32_t i = 0; i < pThis->cMemRsv; i++)
976 {
977 cch = RTVfsIoStrmPrintf(hVfsIos, "/memreserve/ %#RX64 %#RX64;\n", pThis->paMemRsv[i].PhysAddrStart, pThis->paMemRsv[i].cbArea);
978 if (cch <= 0)
979 return RTErrInfoSetF(pErrInfo, cch == 0 ? VERR_NO_MEMORY : -cch, "Failed to write memory reservation block %u", i);
980 }
981
982 /* Dump the tree. */
983 return rtFdtDumpRootAsDts(pThis, hVfsIos, pErrInfo);
984}
985
986
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_U64(pThis->paMemRsv[i].PhysAddrStart);
1065 MemRsv.cbArea = RT_H2BE_U64(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 uint32_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 += (uint32_t)strlen(&pThis->paszStrings[off]) + 1;
1167 }
1168
1169 /* Not found, need to insert. */
1170 uint32_t cch = (uint32_t)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 uint32_t cbNew = RT_ALIGN_32(pThis->cbStruct + cbSpaceRequired, _1K);
1195 Assert(cbNew > pThis->cbStructMax);
1196 void *pvStructNew = RTMemReallocZ(pThis->pbStruct, pThis->cbStructMax, cbNew);
1197 if (!pvStructNew)
1198 return VERR_NO_MEMORY;
1199
1200 Assert(cbNew - pThis->cbStruct >= cbSpaceRequired);
1201 pThis->pbStruct = (uint8_t *)pvStructNew;
1202 pThis->cbStructMax = cbNew;
1203 return VINF_SUCCESS;
1204}
1205
1206
1207/**
1208 * Appends the given token and payload data to the structure block taking care of aligning the data.
1209 *
1210 * @returns IPRT status code.
1211 * @param pThis Pointer to the FDT instance.
1212 * @param pSgBuf The S/G buffer to append.
1213 * @param cbAppend How many bytes to append.
1214 */
1215static int rtFdtStructAppendSg(PRTFDTINT pThis, PRTSGBUF pSgBuf, uint32_t cbAppend)
1216{
1217 uint32_t cbAppendAligned = RT_ALIGN_32(cbAppend, sizeof(uint32_t));
1218
1219 /* Ensure enough space for the token and the payload + padding. */
1220 int rc = rtFdtStructEnsureSpace(pThis, cbAppendAligned);
1221 if (RT_FAILURE(rc))
1222 return rc;
1223
1224 size_t cbCopied = RTSgBufCopyToBuf(pSgBuf, pThis->pbStruct + pThis->cbStruct, cbAppend);
1225 AssertReturn(cbCopied == cbAppend, VERR_INTERNAL_ERROR);
1226
1227 pThis->cbStruct += cbAppendAligned;
1228 return VINF_SUCCESS;
1229}
1230
1231
1232/**
1233 * Appends a token and payload data.
1234 *
1235 * @returns IPRT status code.
1236 * @param pThis Pointer to the FDT instance.
1237 * @param u32Token The token to append.
1238 * @param pvPayload Pointer to the payload data to append.
1239 * @param cbPayload Size of the payload data in bytes.
1240 */
1241static int rtFdtStructAppendTokenAndPayload(PRTFDTINT pThis, uint32_t u32Token, const void *pvPayload, size_t cbPayload)
1242{
1243 RTSGBUF SgBuf;
1244 RTSGSEG aSegs[2];
1245
1246 aSegs[0].pvSeg = &u32Token;
1247 aSegs[0].cbSeg = sizeof(u32Token);
1248 aSegs[1].pvSeg = (void *)pvPayload;
1249 aSegs[1].cbSeg = cbPayload;
1250 RTSgBufInit(&SgBuf, &aSegs[0], RT_ELEMENTS(aSegs));
1251
1252 return rtFdtStructAppendSg(pThis, &SgBuf, sizeof(u32Token) + (uint32_t)cbPayload);
1253}
1254
1255
1256/**
1257 * Appends a property.
1258 *
1259 * @returns IPRT status code.
1260 * @param pThis Pointer to the FDT instance.
1261 * @param pszProperty Name of the property.
1262 * @param pvProperty Pointer to the property data.
1263 * @param cbProperty Size of the property data in bytes.
1264 */
1265static int rtFdtStructAppendProperty(PRTFDTINT pThis, const char *pszProperty, const void *pvProperty, uint32_t cbProperty)
1266{
1267 /* Insert the property name into the strings block. */
1268 uint32_t offStr;
1269 int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
1270 if (RT_FAILURE(rc))
1271 return rc;
1272
1273 uint32_t u32Token = DTB_FDT_TOKEN_PROPERTY_BE;
1274 DTBFDTPROP Prop;
1275
1276 Prop.cbProperty = RT_H2BE_U32(cbProperty);
1277 Prop.offPropertyName = RT_H2BE_U32(offStr);
1278
1279 RTSGBUF SgBuf;
1280 RTSGSEG aSegs[3];
1281 aSegs[0].pvSeg = &u32Token;
1282 aSegs[0].cbSeg = sizeof(u32Token);
1283 aSegs[1].pvSeg = &Prop;
1284 aSegs[1].cbSeg = sizeof(Prop);
1285 if (cbProperty)
1286 {
1287 aSegs[2].pvSeg = (void *)pvProperty;
1288 aSegs[2].cbSeg = cbProperty;
1289 }
1290 RTSgBufInit(&SgBuf, &aSegs[0], cbProperty ? RT_ELEMENTS(aSegs) : 2);
1291
1292 return rtFdtStructAppendSg(pThis, &SgBuf, sizeof(u32Token) + sizeof(Prop) + cbProperty);
1293}
1294
1295
1296RTDECL(int) RTFdtCreateEmpty(PRTFDT phFdt)
1297{
1298 AssertPtrReturn(phFdt, VERR_INVALID_POINTER);
1299
1300 int rc = VINF_SUCCESS;
1301 PRTFDTINT pThis = (PRTFDTINT)RTMemAllocZ(sizeof(*pThis));
1302 if (pThis)
1303 {
1304 pThis->idPHandle = 1; /* 0 is invalid */
1305
1306 /* Add the root node. */
1307 rc = RTFdtNodeAdd(pThis, "");
1308 if (RT_SUCCESS(rc))
1309 {
1310 *phFdt = pThis;
1311 return VINF_SUCCESS;
1312 }
1313
1314 RTMemFree(pThis);
1315 }
1316 else
1317 rc = VERR_NO_MEMORY;
1318
1319 return rc;
1320}
1321
1322
1323RTDECL(int) RTFdtCreateFromVfsIoStrm(PRTFDT phFdt, RTVFSIOSTREAM hVfsIos, RTFDTTYPE enmInType, PRTERRINFO pErrInfo)
1324{
1325 AssertPtrReturn(phFdt, VERR_INVALID_POINTER);
1326 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
1327
1328 if (enmInType == RTFDTTYPE_DTB)
1329 return rtFdtLoadDtb(phFdt, hVfsIos, pErrInfo);
1330
1331 return VERR_NOT_IMPLEMENTED;
1332}
1333
1334
1335RTDECL(int) RTFdtCreateFromFile(PRTFDT phFdt, const char *pszFilename, RTFDTTYPE enmInType, PRTERRINFO pErrInfo)
1336{
1337 RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM;
1338 int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1339 &hVfsIos, NULL /*poffError*/, pErrInfo);
1340 if (RT_FAILURE(rc))
1341 return rc;
1342
1343 rc = RTFdtCreateFromVfsIoStrm(phFdt, hVfsIos, enmInType, pErrInfo);
1344 RTVfsIoStrmRelease(hVfsIos);
1345 return rc;
1346}
1347
1348
1349RTDECL(void) RTFdtDestroy(RTFDT hFdt)
1350{
1351 PRTFDTINT pThis = hFdt;
1352 AssertPtrReturnVoid(pThis);
1353
1354 rtFdtDestroy(pThis);
1355}
1356
1357
1358RTDECL(int) RTFdtFinalize(RTFDT hFdt)
1359{
1360 PRTFDTINT pThis = hFdt;
1361 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1362
1363 /* Already finalized? */
1364 if (!pThis->cTreeDepth)
1365 return VINF_SUCCESS;
1366
1367 uint32_t cbStructSpace = pThis->cTreeDepth * sizeof(uint32_t) + sizeof(uint32_t); /* One extra for the END token. */
1368 int rc = rtFdtStructEnsureSpace(pThis, cbStructSpace);
1369 if (RT_FAILURE(rc))
1370 return rc;
1371
1372 uint32_t *pu32 = (uint32_t *)(pThis->pbStruct + pThis->cbStruct);
1373 while (pThis->cTreeDepth)
1374 {
1375 *pu32++ = DTB_FDT_TOKEN_END_NODE_BE;
1376 pThis->cTreeDepth--;
1377 }
1378
1379 *pu32 = DTB_FDT_TOKEN_END_BE;
1380 pThis->cbStruct += cbStructSpace;
1381 return VINF_SUCCESS;
1382}
1383
1384
1385RTDECL(uint32_t) RTFdtPHandleAllocate(RTFDT hFdt)
1386{
1387 PRTFDTINT pThis = hFdt;
1388 AssertPtrReturn(pThis, UINT32_MAX);
1389
1390 return pThis->idPHandle++;
1391}
1392
1393
1394RTDECL(int) RTFdtDumpToVfsIoStrm(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, RTVFSIOSTREAM hVfsIos, PRTERRINFO pErrInfo)
1395{
1396 PRTFDTINT pThis = hFdt;
1397 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1398 AssertReturn(enmOutType == RTFDTTYPE_DTS || enmOutType == RTFDTTYPE_DTB, VERR_INVALID_PARAMETER);
1399 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1400
1401 if (enmOutType == RTFDTTYPE_DTS)
1402 return rtFdtDumpAsDts(pThis, hVfsIos, pErrInfo);
1403 else if (enmOutType == RTFDTTYPE_DTB)
1404 return rtFdtDumpAsDtb(pThis, hVfsIos, pErrInfo);
1405
1406 return VERR_NOT_SUPPORTED;
1407}
1408
1409
1410RTDECL(int) RTFdtDumpToFile(RTFDT hFdt, RTFDTTYPE enmOutType, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
1411{
1412 RTVFSIOSTREAM hVfsIos = NIL_RTVFSIOSTREAM;
1413 int rc = RTVfsChainOpenIoStream(pszFilename, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE,
1414 &hVfsIos, NULL /*poffError*/, pErrInfo);
1415 if (RT_FAILURE(rc))
1416 return rc;
1417
1418 rc = RTFdtDumpToVfsIoStrm(hFdt, enmOutType, fFlags, hVfsIos, pErrInfo);
1419 RTVfsIoStrmRelease(hVfsIos);
1420 return rc;
1421}
1422
1423
1424RTDECL(int) RTFdtAddMemoryReservation(RTFDT hFdt, uint64_t PhysAddrStart, uint64_t cbArea)
1425{
1426 PRTFDTINT pThis = hFdt;
1427 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1428 AssertReturn(PhysAddrStart > 0 || cbArea > 0, VERR_INVALID_PARAMETER);
1429
1430 if (pThis->cMemRsv == pThis->cMemRsvMax)
1431 {
1432 uint32_t cMemRsvMaxNew = pThis->cMemRsvMax + 10;
1433 PDTBFDTRSVENTRY paMemRsvNew = (PDTBFDTRSVENTRY)RTMemRealloc(pThis->paMemRsv, cMemRsvMaxNew * sizeof(*paMemRsvNew));
1434 if (!paMemRsvNew)
1435 return VERR_NO_MEMORY;
1436
1437 pThis->paMemRsv = paMemRsvNew;
1438 pThis->cMemRsvMax = cMemRsvMaxNew;
1439 }
1440
1441 pThis->paMemRsv[pThis->cMemRsv].PhysAddrStart = PhysAddrStart;
1442 pThis->paMemRsv[pThis->cMemRsv].cbArea = cbArea;
1443 pThis->cMemRsv++;
1444 return VINF_SUCCESS;
1445}
1446
1447
1448RTDECL(int) RTFdtSetPhysBootCpuId(RTFDT hFdt, uint32_t idPhysBootCpu)
1449{
1450 PRTFDTINT pThis = hFdt;
1451 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1452
1453 pThis->u32CpuIdPhysBoot = idPhysBootCpu;
1454 return VINF_SUCCESS;
1455}
1456
1457
1458RTDECL(int) RTFdtNodeAdd(RTFDT hFdt, const char *pszName)
1459{
1460 PRTFDTINT pThis = hFdt;
1461 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1462
1463 /** @todo Validate node name against allowed character set. */
1464 size_t cchName = strlen(pszName) + 1;
1465 int rc = rtFdtStructAppendTokenAndPayload(pThis, DTB_FDT_TOKEN_BEGIN_NODE_BE, pszName, cchName);
1466 if (RT_FAILURE(rc))
1467 return rc;
1468
1469 pThis->cTreeDepth++;
1470 return VINF_SUCCESS;
1471}
1472
1473
1474RTDECL(int) RTFdtNodeAddF(RTFDT hFdt, const char *pszNameFmt, ...)
1475{
1476 va_list va;
1477 va_start(va, pszNameFmt);
1478 int rc = RTFdtNodeAddV(hFdt, pszNameFmt, va);
1479 va_end(va);
1480 return rc;
1481}
1482
1483
1484RTDECL(int) RTFdtNodeAddV(RTFDT hFdt, const char *pszNameFmt, va_list va)
1485{
1486 char szName[512]; /* lazy developer */
1487 ssize_t cch = RTStrPrintf2V(&szName[0], sizeof(szName), pszNameFmt, va);
1488 if (cch <= 0)
1489 return VERR_BUFFER_OVERFLOW;
1490
1491 return RTFdtNodeAdd(hFdt, &szName[0]);
1492}
1493
1494
1495RTDECL(int) RTFdtNodeFinalize(RTFDT hFdt)
1496{
1497 PRTFDTINT pThis = hFdt;
1498 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1499 AssertReturn(pThis->cTreeDepth > 1, VERR_FDT_AT_ROOT_LEVEL);
1500
1501 int rc = rtFdtStructAppendTokenAndPayload(pThis, DTB_FDT_TOKEN_END_NODE_BE, NULL /*pvPayload*/, 0 /*cbPayload*/);
1502 if (RT_FAILURE(rc))
1503 return rc;
1504
1505 pThis->cTreeDepth--;
1506 return VINF_SUCCESS;
1507}
1508
1509
1510RTDECL(int) RTFdtNodePropertyAddEmpty(RTFDT hFdt, const char *pszProperty)
1511{
1512 PRTFDTINT pThis = hFdt;
1513 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1514
1515 return rtFdtStructAppendProperty(pThis, pszProperty, NULL /*pvProperty*/, 0 /*cbProperty*/);
1516}
1517
1518
1519RTDECL(int) RTFdtNodePropertyAddU32(RTFDT hFdt, const char *pszProperty, uint32_t u32)
1520{
1521 PRTFDTINT pThis = hFdt;
1522 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1523
1524 u32 = RT_H2BE_U32(u32);
1525 return rtFdtStructAppendProperty(pThis, pszProperty, &u32, sizeof(u32));
1526}
1527
1528
1529RTDECL(int) RTFdtNodePropertyAddU64(RTFDT hFdt, const char *pszProperty, uint64_t u64)
1530{
1531 PRTFDTINT pThis = hFdt;
1532 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1533
1534 uint32_t u32Low = RT_H2BE_U32((uint32_t)u64);
1535 uint32_t u32High = RT_H2BE_U32((uint32_t)(u64 >> 32));
1536 return RTFdtNodePropertyAddCellsU32(pThis, pszProperty, 2, u32High, u32Low);
1537}
1538
1539
1540RTDECL(int) RTFdtNodePropertyAddString(RTFDT hFdt, const char *pszProperty, const char *pszVal)
1541{
1542 PRTFDTINT pThis = hFdt;
1543 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1544
1545 uint32_t cchVal = (uint32_t)strlen(pszVal) + 1;
1546 return rtFdtStructAppendProperty(pThis, pszProperty, pszVal, cchVal);
1547}
1548
1549
1550RTDECL(int) RTFdtNodePropertyAddCellsU32(RTFDT hFdt, const char *pszProperty, uint32_t cCells, ...)
1551{
1552 va_list va;
1553 va_start(va, cCells);
1554 int rc = RTFdtNodePropertyAddCellsU32V(hFdt, pszProperty, cCells, va);
1555 va_end(va);
1556 return rc;
1557}
1558
1559
1560RTDECL(int) RTFdtNodePropertyAddCellsU32V(RTFDT hFdt, const char *pszProperty, uint32_t cCells, va_list va)
1561{
1562 PRTFDTINT pThis = hFdt;
1563 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1564
1565 /* Insert the property name into the strings block. */
1566 uint32_t offStr;
1567 int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
1568 if (RT_FAILURE(rc))
1569 return rc;
1570
1571 uint32_t cbProp = cCells * sizeof(uint32_t) + 3 * sizeof(uint32_t);
1572
1573 rc = rtFdtStructEnsureSpace(pThis, cbProp);
1574 if (RT_FAILURE(rc))
1575 return rc;
1576
1577 uint32_t *pu32 = (uint32_t *)(pThis->pbStruct + pThis->cbStruct);
1578 *pu32++ = DTB_FDT_TOKEN_PROPERTY_BE;
1579 *pu32++ = RT_H2BE_U32(cCells * sizeof(uint32_t));
1580 *pu32++ = RT_H2BE_U32(offStr);
1581 for (uint32_t i = 0; i < cCells; i++)
1582 {
1583 uint32_t u32 = va_arg(va, uint32_t);
1584 *pu32++ = RT_H2BE_U32(u32);
1585 }
1586
1587 pThis->cbStruct += cbProp;
1588 return VINF_SUCCESS;
1589}
1590
1591
1592RTDECL(int) RTFdtNodePropertyAddCellsU32AsArray(RTFDT hFdt, const char *pszProperty, uint32_t cCells, uint32_t *pau32Cells)
1593{
1594 PRTFDTINT pThis = hFdt;
1595 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1596
1597 /* Insert the property name into the strings block. */
1598 uint32_t offStr;
1599 int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
1600 if (RT_FAILURE(rc))
1601 return rc;
1602
1603 uint32_t cbProp = cCells * sizeof(uint32_t) + 3 * sizeof(uint32_t);
1604
1605 rc = rtFdtStructEnsureSpace(pThis, cbProp);
1606 if (RT_FAILURE(rc))
1607 return rc;
1608
1609 uint32_t *pu32 = (uint32_t *)(pThis->pbStruct + pThis->cbStruct);
1610 *pu32++ = DTB_FDT_TOKEN_PROPERTY_BE;
1611 *pu32++ = RT_H2BE_U32(cCells * sizeof(uint32_t));
1612 *pu32++ = RT_H2BE_U32(offStr);
1613 for (uint32_t i = 0; i < cCells; i++)
1614 *pu32++ = RT_H2BE_U32(pau32Cells[i]);
1615
1616 pThis->cbStruct += cbProp;
1617 return VINF_SUCCESS;
1618}
1619
1620
1621RTDECL(int) RTFdtNodePropertyAddCellsU64(RTFDT hFdt, const char *pszProperty, uint32_t cCells, ...)
1622{
1623 va_list va;
1624 va_start(va, cCells);
1625 int rc = RTFdtNodePropertyAddCellsU64V(hFdt, pszProperty, cCells, va);
1626 va_end(va);
1627 return rc;
1628}
1629
1630
1631RTDECL(int) RTFdtNodePropertyAddCellsU64V(RTFDT hFdt, const char *pszProperty, uint32_t cCells, va_list va)
1632{
1633 PRTFDTINT pThis = hFdt;
1634 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1635
1636 /* Insert the property name into the strings block. */
1637 uint32_t offStr;
1638 int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
1639 if (RT_FAILURE(rc))
1640 return rc;
1641
1642 uint32_t cbProp = cCells * 2 * sizeof(uint32_t) + 3 * sizeof(uint32_t);
1643
1644 rc = rtFdtStructEnsureSpace(pThis, cbProp);
1645 if (RT_FAILURE(rc))
1646 return rc;
1647
1648 uint32_t *pu32 = (uint32_t *)(pThis->pbStruct + pThis->cbStruct);
1649 *pu32++ = DTB_FDT_TOKEN_PROPERTY_BE;
1650 *pu32++ = RT_H2BE_U32(cCells * 2 * sizeof(uint32_t));
1651 *pu32++ = RT_H2BE_U32(offStr);
1652 for (uint32_t i = 0; i < cCells; i++)
1653 {
1654 /* First the high 32-bits of the 64-bit value are stored, then the lower ones. */
1655 uint64_t u64 = va_arg(va, uint64_t);
1656 *pu32++ = RT_H2BE_U32((uint32_t)(u64 >> 32));
1657 *pu32++ = RT_H2BE_U32((uint32_t)u64);
1658 }
1659
1660 pThis->cbStruct += cbProp;
1661 return VINF_SUCCESS;
1662}
1663
1664
1665RTDECL(int) RTFdtNodePropertyAddStringList(RTFDT hFdt, const char *pszProperty, uint32_t cStrings, ...)
1666{
1667 va_list va;
1668 va_start(va, cStrings);
1669 int rc = RTFdtNodePropertyAddStringListV(hFdt, pszProperty, cStrings, va);
1670 va_end(va);
1671 return rc;
1672}
1673
1674
1675RTDECL(int) RTFdtNodePropertyAddStringListV(RTFDT hFdt, const char *pszProperty, uint32_t cStrings, va_list va)
1676{
1677 PRTFDTINT pThis = hFdt;
1678 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1679
1680 /* Insert the property name into the strings block. */
1681 uint32_t offStr;
1682 int rc = rtFdtStringsInsertString(pThis, pszProperty, &offStr);
1683 if (RT_FAILURE(rc))
1684 return rc;
1685
1686 /* First pass, go over all strings and find out how much we have to add in total. */
1687 uint32_t cbStrings = 0;
1688 va_list vaCopy;
1689 va_copy(vaCopy, va);
1690 for (uint32_t i = 0; i < cStrings; i++)
1691 cbStrings += (uint32_t)strlen(va_arg(vaCopy, const char *)) + 1; /* Include terminator. */
1692 va_end(vaCopy);
1693
1694 uint32_t cbProp = RT_ALIGN_32(cbStrings + 3 * sizeof(uint32_t), sizeof(uint32_t)); /* Account for property token and the property data. */
1695 rc = rtFdtStructEnsureSpace(pThis, cbProp);
1696 if (RT_FAILURE(rc))
1697 return rc;
1698
1699 /* Add the data. */
1700 uint32_t *pu32 = (uint32_t *)(pThis->pbStruct + pThis->cbStruct);
1701 *pu32++ = DTB_FDT_TOKEN_PROPERTY_BE;
1702 *pu32++ = RT_H2BE_U32(cbStrings);
1703 *pu32++ = RT_H2BE_U32(offStr);
1704
1705 char *pchDst = (char *)pu32;
1706 for (uint32_t i = 0; i < cStrings; i++)
1707 {
1708 const char * const pszSrc = va_arg(va, const char *);
1709 size_t const cbStr = strlen(pszSrc) + 1;
1710 Assert(cbStrings - (size_t)(pchDst - (char *)pu32) >= cbStr);
1711 memcpy(pchDst, pszSrc, cbStr);
1712 pchDst += cbStr;
1713 }
1714
1715 pThis->cbStruct += cbProp;
1716 return VINF_SUCCESS;
1717}
Note: See TracBrowser for help on using the repository browser.

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