mirror of https://github.com/wolfSSL/wolfBoot.git
218 lines
8.7 KiB
C
218 lines
8.7 KiB
C
/* fdt.h
|
|
*
|
|
* Functions to help with flattened device tree (DTB) parsing
|
|
*
|
|
*
|
|
* Copyright (C) 2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfBoot.
|
|
*
|
|
* wolfBoot is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfBoot is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#ifndef FDT_H
|
|
#define FDT_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
|
|
#define FDT_MAGIC 0xD00DFEEDUL
|
|
#define FDT_SW_MAGIC (uint32_t)(~FDT_MAGIC) /* marker for run-time creation/edit of FDT */
|
|
|
|
struct fdt_header {
|
|
uint32_t magic;
|
|
uint32_t totalsize;
|
|
uint32_t off_dt_struct;
|
|
uint32_t off_dt_strings;
|
|
uint32_t off_mem_rsvmap;
|
|
uint32_t version;
|
|
uint32_t last_comp_version;
|
|
uint32_t boot_cpuid_phys;
|
|
uint32_t size_dt_strings;
|
|
uint32_t size_dt_struct;
|
|
};
|
|
|
|
struct fdt_reserve_entry {
|
|
uint64_t address;
|
|
uint64_t size;
|
|
};
|
|
|
|
struct fdt_prop {
|
|
uint32_t len;
|
|
uint32_t nameoff;
|
|
};
|
|
|
|
struct fdt_node_header {
|
|
uint32_t tag;
|
|
char name[0];
|
|
};
|
|
|
|
struct fdt_property {
|
|
uint32_t tag;
|
|
uint32_t len;
|
|
uint32_t nameoff;
|
|
char data[0];
|
|
};
|
|
|
|
#define FDT_TAGSIZE sizeof(uint32_t)
|
|
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
|
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
|
|
|
#define FDT_FIRST_SUPPORTED_VERSION 0x10
|
|
#define FDT_LAST_SUPPORTED_VERSION 0x11
|
|
|
|
#define FDT_BEGIN_NODE 0x00000001UL
|
|
#define FDT_END_NODE 0x00000002UL
|
|
#define FDT_PROP 0x00000003UL
|
|
#define FDT_NOP 0x00000004UL
|
|
#define FDT_END 0x00000009UL
|
|
|
|
#define FDT_ERR_BADMAGIC 1
|
|
#define FDT_ERR_BADVERSION 2
|
|
#define FDT_ERR_BADSTRUCTURE 3
|
|
#define FDT_ERR_BADOFFSET 4
|
|
#define FDT_ERR_BADSTATE 5
|
|
#define FDT_ERR_NOTFOUND 6
|
|
#define FDT_ERR_NOSPACE 7
|
|
#define FDT_ERR_TRUNCATED 8
|
|
#define FDT_ERR_INTERNAL 9
|
|
#define FDT_ERR_EXISTS 10
|
|
|
|
#define FDT_PCI_PREFETCH (0x40000000)
|
|
#define FDT_PCI_MEM32 (0x02000000)
|
|
#define FDT_PCI_IO (0x01000000)
|
|
#define FDT_PCI_MEM64 (0x03000000)
|
|
|
|
uint32_t cpu_to_fdt32(uint32_t x);
|
|
uint64_t cpu_to_fdt64(uint64_t x);
|
|
uint32_t fdt32_to_cpu(uint32_t x);
|
|
uint64_t fdt64_to_cpu(uint64_t x);
|
|
|
|
#define fdt_get_header(fdt, field) (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
|
|
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
|
|
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
|
|
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
|
|
#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
|
|
#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
|
|
#define fdt_version(fdt) (fdt_get_header(fdt, version))
|
|
#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
|
|
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
|
|
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
|
|
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
|
|
|
|
#define fdt_set_header(fdt, field, val) (((struct fdt_header *)fdt)->field = cpu_to_fdt32(val))
|
|
#define fdt_set_magic(fdt, val) (fdt_set_header(fdt, magic, (val)))
|
|
#define fdt_set_totalsize(fdt, val) (fdt_set_header(fdt, totalsize, (val)))
|
|
#define fdt_set_off_dt_struct(fdt, val) (fdt_set_header(fdt, off_dt_struct, (val)))
|
|
#define fdt_set_off_dt_strings(fdt, val) (fdt_set_header(fdt, off_dt_strings, (val)))
|
|
#define fdt_set_off_mem_rsvmap(fdt, val) (fdt_set_header(fdt, off_mem_rsvmap, (val)))
|
|
#define fdt_set_version(fdt, val) (fdt_set_header(fdt, version, (val)))
|
|
#define fdt_set_last_comp_version(fdt, val) (fdt_set_header(fdt, last_comp_version, (val)))
|
|
#define fdt_set_boot_cpuid_phys(fdt, val) (fdt_set_header(fdt, boot_cpuid_phys, (val)))
|
|
#define fdt_set_size_dt_strings(fdt, val) (fdt_set_header(fdt, size_dt_strings, (val)))
|
|
#define fdt_set_size_dt_struct(fdt, val) (fdt_set_header(fdt, size_dt_struct, (val)))
|
|
|
|
/* Headroom (bytes) appended to fdt_totalsize() before wolfBoot inserts
|
|
* /chosen properties. Sized to comfortably hold a full LINUX_BOOTARGS
|
|
* plus, when WOLFBOOT_FIT_RAMDISK is enabled, two 64-bit
|
|
* linux,initrd-{start,end} cells with property-name overhead. A target
|
|
* whose hal_dts_fixup() inserts more chosen entries can override this
|
|
* with -DWOLFBOOT_FDT_FIXUP_HEADROOM=<bytes>. */
|
|
#ifndef WOLFBOOT_FDT_FIXUP_HEADROOM
|
|
#define WOLFBOOT_FDT_FIXUP_HEADROOM 768
|
|
#endif
|
|
|
|
int fdt_check_header(const void *fdt);
|
|
int fdt_next_node(const void *fdt, int offset, int *depth);
|
|
int fdt_first_property_offset(const void *fdt, int nodeoffset);
|
|
int fdt_next_property_offset(const void *fdt, int offset);
|
|
const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp);
|
|
|
|
const char* fdt_get_name(const void *fdt, int nodeoffset, int *len);
|
|
const char* fdt_get_string(const void *fdt, int stroffset, int *lenp);
|
|
|
|
const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp);
|
|
int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len);
|
|
|
|
void* fdt_getprop_address(const void *fdt, int nodeoffset, const char *name);
|
|
|
|
int fdt_find_node_offset(void* fdt, int startoff, const char* nodename);
|
|
int fdt_find_prop_offset(void* fdt, int startoff, const char* propname, const char* propval);
|
|
|
|
int fdt_find_devtype(void* fdt, int startoff, const char* node);
|
|
int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible);
|
|
int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible);
|
|
int fdt_add_subnode(void* fdt, int parentoff, const char* name);
|
|
int fdt_del_node(void *fdt, int nodeoffset);
|
|
|
|
/* helpers to fix/append a property to a node */
|
|
int fdt_fixup_str(void* fdt, int off, const char* node, const char* name, const char* str);
|
|
int fdt_fixup_val(void* fdt, int off, const char* node, const char* name, uint32_t val);
|
|
int fdt_fixup_val64(void* fdt, int off, const char* node, const char* name, uint64_t val);
|
|
|
|
int fdt_shrink(void* fdt);
|
|
int fdt_add_mem_rsv(void* fdt, uint64_t address, uint64_t size);
|
|
|
|
/* FIT */
|
|
const char* fit_find_images(void* fdt, const char** pkernel, const char** pflat_dt,
|
|
const char** pramdisk, const char** pfpga);
|
|
/* Return a pointer to a subimage's "compatible" property, or NULL if
|
|
* absent. NOTE: "compatible" is a devicetree string-list (one or more
|
|
* NUL-separated strings); this returns a pointer to the raw property
|
|
* data, i.e. the FIRST string only. Callers that must inspect every
|
|
* entry (e.g. to detect "partial") have to obtain the property length
|
|
* via fdt_getprop() and scan the whole buffer - fit_load_fpga() does
|
|
* this internally rather than relying on this helper. */
|
|
const char* fit_get_compatible(void* fdt, const char* image);
|
|
void* fit_load_image(void* fdt, const char* image, int* lenp);
|
|
void* fit_load_image_ex(void* fdt, const char* image, int* lenp, uint32_t out_max);
|
|
/* Load (and, if compressed, decompress) a FIT subimage directly to a
|
|
* caller-supplied destination buffer. Overrides the FIT image's
|
|
* `load` and `entry` properties - dst is both the destination and the
|
|
* value returned. dst_max bounds the decompressed size. */
|
|
void* fit_load_image_to(void* fdt, const char* image, void* dst,
|
|
uint32_t dst_max, int* lenp);
|
|
|
|
/* FDT initrd fixup: writes /chosen/linux,initrd-{start,end} as 64-bit
|
|
* big-endian properties. Creates /chosen if missing. Returns 0 on success
|
|
* or a negative FDT_ERR_*. */
|
|
int fdt_fixup_initrd(void* fdt, uint64_t start, uint64_t size);
|
|
|
|
#ifdef WOLFBOOT_FIT_RAMDISK
|
|
/* Load a FIT ramdisk subimage (optionally relocated to
|
|
* WOLFBOOT_LOAD_RAMDISK_ADDRESS) and patch /chosen/linux,initrd-*
|
|
* in the supplied DTB. Returns 0 on success, -1 on load failure.
|
|
* Callers typically ignore the return value (log-and-continue). */
|
|
int fit_load_ramdisk(void* fit, const char* ramdisk_node, void* dts_addr);
|
|
#endif
|
|
|
|
#ifdef WOLFBOOT_FPGA_BITSTREAM
|
|
/* Locate a FIT fpga subimage, stage it to its `load` address (or use
|
|
* the in-FIT data pointer) and program the PL via hal_fpga_load().
|
|
* Returns 0 on success (including when fpga_node is NULL), negative on
|
|
* failure. When WOLFBOOT_FPGA_NONFATAL is defined a programming failure
|
|
* is logged and 0 is returned instead. */
|
|
int fit_load_fpga(void* fdt, const char* fpga_node);
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* !FDT_H */
|