Inline the kernel
This commit is contained in:
parent
f9e8047d31
commit
b2b74a3f0d
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,6 +0,0 @@
|
||||
[submodule "scripts/dtc-aosp/dtc"]
|
||||
path = scripts/dtc-aosp/dtc
|
||||
url = https://github.com/xzr467706992/dtc-aosp
|
||||
[submodule "scripts/ufdt/libufdt"]
|
||||
path = scripts/ufdt/libufdt
|
||||
url = https://android.googlesource.com/platform/system/libufdt
|
@ -1649,12 +1649,6 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
|
||||
Space separated list of names of dtbs to append when
|
||||
building a concatenated Image.gz-dtb.
|
||||
|
||||
config BUILD_ARM64_EMBEDDED_DTB
|
||||
bool "Embed DTB into kernel image"
|
||||
depends on OF
|
||||
help
|
||||
Embed DTB directly into kernel image and ignore DTB from bootloader.
|
||||
|
||||
choice
|
||||
prompt "Kernel compression method"
|
||||
default BUILD_ARM64_KERNEL_COMPRESSION_GZIP
|
||||
|
@ -159,8 +159,6 @@ endif
|
||||
|
||||
KBUILD_DTBS := dtbs
|
||||
|
||||
KBUILD_DTBO_IMG := dtbo.img
|
||||
|
||||
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
|
||||
export DTC_FLAGS := -@
|
||||
endif
|
||||
@ -184,12 +182,6 @@ PHONY += dtbs dtbs_install
|
||||
dtbs: prepare scripts
|
||||
$(Q)$(MAKE) $(build)=$(boot)/dts
|
||||
|
||||
ifeq ($(CONFIG_BUILD_ARM64_EMBEDDED_DTB),y)
|
||||
$(obj)/kernel/embedded-dtb.c: dtbs dtbo.img
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(obj)/arch/arm64/boot/../kernel/embedded-dtb.c
|
||||
arch/arm64/kernel: $(obj)/kernel/embedded-dtb.c
|
||||
endif
|
||||
|
||||
dtbs_install:
|
||||
$(Q)$(MAKE) $(dtbinst)=$(boot)/dts
|
||||
|
||||
@ -199,9 +191,6 @@ Image-dtb: vmlinux scripts dtbs
|
||||
Image.gz-dtb: vmlinux scripts dtbs Image.gz
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
dtbo.img: $(boot)/dts/dtboimg.cfg dtbs
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
PHONY += vdso_install
|
||||
vdso_install:
|
||||
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
|
||||
@ -212,9 +201,6 @@ archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
$(Q)$(MAKE) $(clean)=$(boot)/dts
|
||||
|
||||
CLEAN_FILES += $(boot)/Image $(boot)/Image-dtb $(boot)/Image.* $(boot)/dtbo.img
|
||||
MRPROPER_FILES += $(boot)/Image $(boot)/Image-dtb $(boot)/Image.* $(boot)/dtbo.img
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
# We need to generate vdso-offsets.h before compiling certain files in kernel/.
|
||||
# In order to do that, we should use the archprepare target, but we can't since
|
||||
|
1
arch/arm64/boot/.gitignore
vendored
1
arch/arm64/boot/.gitignore
vendored
@ -2,4 +2,3 @@ Image
|
||||
Image-dtb
|
||||
Image.gz
|
||||
Image.gz-dtb
|
||||
dtbo.img
|
||||
|
@ -28,8 +28,6 @@ DTB_LIST := $(dtb-y)
|
||||
endif
|
||||
DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
|
||||
|
||||
DTBO_OBJS := $(shell find -L $(obj)/dts/ -name \*.dtbo)
|
||||
|
||||
# Add RTIC DTB to the DTB list if RTIC MPGen is enabled
|
||||
# Note, we keep this for compatibility with
|
||||
# BUILD_ARM64_APPENDED_DTB_IMAGE targets.
|
||||
@ -55,11 +53,6 @@ $(obj)/Image-dtb-hdr: $(obj)/Image FORCE
|
||||
$(obj)/Image-dtb: $(obj)/Image-dtb-hdr $(obj)/Image $(DTB_OBJS) FORCE
|
||||
$(call if_changed,cat)
|
||||
|
||||
quiet_cmd_overlay = OVERLAY $@
|
||||
cmd_overlay = PATH=$(srctree)/scripts/ufdt/libufdt/utils/src:$(objtree)/scripts/dtc-aosp:$(objtree)/scripts/ufdt:$(PATH) $(srctree)/$(src)/overlay.sh $@ $^ > /dev/null
|
||||
$(obj)/../kernel/embedded-dtb.c: $(obj)/dtbo.img $(DTB_OBJS) FORCE
|
||||
$(call if_changed,overlay)
|
||||
|
||||
$(obj)/Image.gz: $(obj)/Image FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
@ -75,10 +68,6 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
|
||||
$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE
|
||||
$(call if_changed,cat)
|
||||
|
||||
|
||||
$(obj)/dtbo.img: $(obj)/dts/dtboimg.cfg $(DTBO_OBJS) FORCE
|
||||
$(call if_changed,mkdtimg,4096) # align dtbo.img to 4kB
|
||||
|
||||
install:
|
||||
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
|
||||
$(obj)/Image System.map "$(INSTALL_PATH)"
|
||||
|
@ -1 +0,0 @@
|
||||
arch/arm64/boot/dts/vendor/qcom/monet-sm7250-overlay.dtbo
|
@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
|
||||
set -e
|
||||
exec 9> "$1"
|
||||
shift
|
||||
dtboimg="$1"
|
||||
shift
|
||||
|
||||
TMPDIR="$(mktemp -d -t)"
|
||||
trap 'rm -rf "$TMPDIR"' INT TERM EXIT
|
||||
|
||||
echo '/* WARNING: DO NOT EDIT - This file was generated by arch/arm64/boot/overlay.sh */' >&9
|
||||
echo '#include <linux/kernel.h>' >&9
|
||||
|
||||
total=0
|
||||
while [[ $# -gt 1 && $1 != FORCE ]]; do
|
||||
extract_dtb "$1" "$TMPDIR/soc.dtb"
|
||||
shift
|
||||
python2 $(which mkdtboimg.py) dump "$dtboimg" -b "$TMPDIR/overlay-$total.dtbo" > "$TMPDIR/dtbo-$total.info"
|
||||
for overlay in "$TMPDIR"/overlay-$total.dtbo*; do
|
||||
ufdt_apply_overlay "$TMPDIR/soc.dtb" "$overlay" "$TMPDIR/combined-$total.dtb"
|
||||
overlay_txt="$(dtc-aosp -q -O dts -o - "$overlay")"
|
||||
model="$(sed -n '/^\s*model\s*=\(.*\)$/{s//\1/p;q}' <<<"$overlay_txt")"
|
||||
compatible="$(sed -n '/^\s*compatible\s*=\(.*\)$/{s//\1/p;q}' <<<"$overlay_txt")"
|
||||
board_id="$(sed -n '/^\s*qcom,board-id\s*=\(.*\)$/{s//\1/p;q}' <<<"$overlay_txt")"
|
||||
dtc-aosp -q -O dts -o "$TMPDIR/combined-$total.dts" "$TMPDIR/combined-$total.dtb"
|
||||
sed -i "0,/^\\s*model\\s*=.*/s//model = $model/" "$TMPDIR/combined-$total.dts"
|
||||
sed -i "0,/^\\s*compatible\\s*=.*/s//compatible = $compatible/" "$TMPDIR/combined-$total.dts"
|
||||
sed -i "0,/^\\s*qcom,board-id\\s*=.*/s//qcom,board-id = $board_id/" "$TMPDIR/combined-$total.dts"
|
||||
sed -i 's/^\s*phandle = \(.*\)/\0\nlinux,phandle = \1/' "$TMPDIR/combined-$total.dts"
|
||||
dtc-aosp -q -O dtb -H both -o "$TMPDIR/combined-$total.dtb" "$TMPDIR/combined-$total.dts"
|
||||
echo "static u8 dtb_embedded_$((total + 1))[] __initdata = {" >&9
|
||||
xxd -i < "$TMPDIR/combined-$total.dtb" >&9
|
||||
echo "};" >&9
|
||||
((++total))
|
||||
done
|
||||
done
|
||||
|
||||
printf 'u8 *const dtb_embedded[] __initconst = { ' >&9
|
||||
[[ $total -eq 0 ]] || printf 'dtb_embedded_%s, ' $(seq 1 $total) >&9
|
||||
printf 'NULL };\n' >&9
|
@ -102,7 +102,6 @@ CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
# CONFIG_EFI is not set
|
||||
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
|
||||
CONFIG_BUILD_ARM64_EMBEDDED_DTB=y
|
||||
CONFIG_BUILD_ARM64_DT_OVERLAY=y
|
||||
CONFIG_COMPAT=y
|
||||
CONFIG_COMPAT_VDSO=y
|
||||
|
@ -98,7 +98,7 @@ extern void init_mem_pgprot(void);
|
||||
extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
|
||||
unsigned long virt, phys_addr_t size,
|
||||
pgprot_t prot, bool page_mappings_only);
|
||||
extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
|
||||
extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
|
||||
extern void mark_linear_text_alias_ro(void);
|
||||
#ifdef CONFIG_MEMORY_HOTPLUG
|
||||
extern void hotplug_paging(phys_addr_t start, phys_addr_t size);
|
||||
@ -108,9 +108,5 @@ extern void remove_pagetable(unsigned long start,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
|
||||
extern void select_embedded_dt(void *dt_virt) __init;
|
||||
#endif
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif
|
||||
|
@ -70,8 +70,6 @@ obj-$(CONFIG_COMPAT_VDSO) += vdso32/
|
||||
head-y := head.o
|
||||
extra-y += $(head-y) vmlinux.lds
|
||||
|
||||
obj-$(CONFIG_BUILD_ARM64_EMBEDDED_DTB) += embedded-dtb.o select-embedded-dt.o
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_EFI),y)
|
||||
AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\""
|
||||
endif
|
||||
|
@ -65,9 +65,6 @@ out:
|
||||
return default_cmdline;
|
||||
}
|
||||
|
||||
extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size,
|
||||
pgprot_t prot);
|
||||
|
||||
/*
|
||||
* This routine will be executed with the kernel mapped at its default virtual
|
||||
* address, and if it returns successfully, the kernel will be remapped, and
|
||||
@ -96,7 +93,7 @@ u64 __init kaslr_early_init(u64 dt_phys)
|
||||
* attempt at mapping the FDT in setup_machine()
|
||||
*/
|
||||
early_fixmap_init();
|
||||
fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
|
||||
fdt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
|
||||
if (!fdt)
|
||||
return 0;
|
||||
|
||||
|
@ -1,141 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
* Copyright (C) 2018-2019 Sultan Alsawaf <sultan@kerneltoast.com>.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/boot.h>
|
||||
|
||||
extern u8 *const dtb_embedded[];
|
||||
|
||||
static void __init copy_dt_node_props(void *dt_dst, int dst_node,
|
||||
const void *dt_src, int src_node)
|
||||
{
|
||||
int prop;
|
||||
|
||||
for (prop = fdt_first_property_offset(dt_src, src_node);
|
||||
prop >= 0;
|
||||
prop = fdt_next_property_offset(dt_src, prop)) {
|
||||
const char *prop_name;
|
||||
const void *prop_val;
|
||||
int prop_len;
|
||||
|
||||
prop_val = fdt_getprop_by_offset(dt_src, prop,
|
||||
&prop_name, &prop_len);
|
||||
fdt_setprop(dt_dst, dst_node, prop_name, prop_val, prop_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init __copy_entire_dt_node(void *dt_dst, const void *dt_src,
|
||||
const char *path)
|
||||
{
|
||||
int dst_node, src_node, node;
|
||||
|
||||
dst_node = fdt_path_offset(dt_dst, path);
|
||||
src_node = fdt_path_offset(dt_src, path);
|
||||
|
||||
/* Copy the current level of properties */
|
||||
copy_dt_node_props(dt_dst, dst_node, dt_src, src_node);
|
||||
|
||||
for (node = fdt_first_subnode(dt_src, src_node);
|
||||
node >= 0;
|
||||
node = fdt_next_subnode(dt_src, node)) {
|
||||
const char *name = fdt_get_name(dt_src, node, NULL);
|
||||
char full_path[SZ_1K];
|
||||
|
||||
/* Create the subnode and copy over its properties */
|
||||
fdt_add_subnode(dt_dst, dst_node, name);
|
||||
|
||||
/* Get the full path of the subnode and recurse */
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", path, name);
|
||||
__copy_entire_dt_node(dt_dst, dt_src, full_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init copy_dt_root_subnode(void *dt_dst, const void *dt_src,
|
||||
const char *path)
|
||||
{
|
||||
/*
|
||||
* Clear out the destination node first to so nothing remains from it
|
||||
* when the source node and its subnodes are copied over.
|
||||
*/
|
||||
fdt_del_node(dt_dst, fdt_path_offset(dt_dst, path));
|
||||
fdt_add_subnode(dt_dst, fdt_path_offset(dt_dst, "/"), path + 1);
|
||||
|
||||
__copy_entire_dt_node(dt_dst, dt_src, path);
|
||||
}
|
||||
|
||||
static void __init fix_embedded_dt(void *bl_dt, const void *kern_dt)
|
||||
{
|
||||
static u8 kern_dt_new[MAX_FDT_SIZE] __initdata;
|
||||
int ret;
|
||||
|
||||
ret = fdt_open_into(kern_dt, kern_dt_new, sizeof(kern_dt_new));
|
||||
if (ret) {
|
||||
pr_crit("Error: loading kernel dt failed, ret=%d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The DT modifications are considered to be error-free since both the
|
||||
* kernel and bootloader DTs are valid.
|
||||
*/
|
||||
copy_dt_root_subnode(kern_dt_new, bl_dt, "/chosen");
|
||||
copy_dt_root_subnode(kern_dt_new, bl_dt, "/firmware");
|
||||
copy_dt_root_subnode(kern_dt_new, bl_dt, "/memory");
|
||||
|
||||
ret = fdt_pack(kern_dt_new);
|
||||
if (ret) {
|
||||
pr_crit("Error: failed to pack kernel dt, ret=%d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("Using embedded DTB instead of bootloader DTB");
|
||||
memcpy(bl_dt, kern_dt_new, fdt_totalsize(kern_dt_new));
|
||||
}
|
||||
|
||||
void __init select_embedded_dt(void *bl_dt)
|
||||
{
|
||||
const char *const board_id_prop = "qcom,board-id";
|
||||
const char *const msm_id_prop = "qcom,msm-id";
|
||||
u64 real_board_id, real_msm_id;
|
||||
const u64 *prop_val;
|
||||
int i, root_node;
|
||||
|
||||
if (!bl_dt)
|
||||
return;
|
||||
|
||||
root_node = fdt_path_offset(bl_dt, "/");
|
||||
prop_val = fdt_getprop(bl_dt, root_node, board_id_prop, NULL);
|
||||
if (!prop_val) {
|
||||
pr_crit("Error: %s missing", board_id_prop);
|
||||
return;
|
||||
}
|
||||
real_board_id = *prop_val;
|
||||
|
||||
prop_val = fdt_getprop(bl_dt, root_node, msm_id_prop, NULL);
|
||||
if (!prop_val) {
|
||||
pr_crit("Error: %s missing", msm_id_prop);
|
||||
return;;
|
||||
}
|
||||
real_msm_id = *prop_val;
|
||||
|
||||
for (i = 0; dtb_embedded[i]; i++) {
|
||||
void *curr_dt = dtb_embedded[i];
|
||||
|
||||
root_node = fdt_path_offset(curr_dt, "/");
|
||||
prop_val = fdt_getprop(curr_dt, root_node, board_id_prop, NULL);
|
||||
if (!prop_val || *prop_val != real_board_id)
|
||||
continue;
|
||||
|
||||
prop_val = fdt_getprop(curr_dt, root_node, msm_id_prop, NULL);
|
||||
if (!prop_val || *prop_val != real_msm_id)
|
||||
continue;
|
||||
|
||||
fix_embedded_dt(bl_dt, curr_dt);
|
||||
break;
|
||||
}
|
||||
}
|
@ -191,12 +191,12 @@ static void __init smp_build_mpidr_hash(void)
|
||||
|
||||
static void __init setup_machine_fdt(phys_addr_t dt_phys)
|
||||
{
|
||||
void *dt_virt = fixmap_remap_fdt(dt_phys);
|
||||
int size;
|
||||
void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
|
||||
const char *name;
|
||||
|
||||
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
|
||||
select_embedded_dt(dt_virt);
|
||||
#endif
|
||||
if (dt_virt)
|
||||
memblock_reserve(dt_phys, size);
|
||||
|
||||
if (!dt_virt || !early_init_dt_scan(dt_virt)) {
|
||||
pr_crit("\n"
|
||||
@ -209,6 +209,9 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
/* Early fixups are done, map the FDT as read-only now */
|
||||
fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
|
||||
|
||||
name = of_flat_dt_get_machine_name();
|
||||
if (!name)
|
||||
return;
|
||||
|
@ -1334,7 +1334,7 @@ void __set_fixmap(enum fixed_addresses idx,
|
||||
}
|
||||
}
|
||||
|
||||
void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
|
||||
void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
|
||||
{
|
||||
const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
|
||||
int offset;
|
||||
@ -1376,13 +1376,9 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
|
||||
if (fdt_magic(dt_virt) != FDT_MAGIC)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
|
||||
*size = MAX_FDT_SIZE;
|
||||
#else
|
||||
*size = fdt_totalsize(dt_virt);
|
||||
if (*size > MAX_FDT_SIZE)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
if (offset + *size > SWAPPER_BLOCK_SIZE)
|
||||
create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
|
||||
@ -1391,18 +1387,9 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
|
||||
return dt_virt;
|
||||
}
|
||||
|
||||
void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
|
||||
int __init arch_ioremap_p4d_supported(void)
|
||||
{
|
||||
void *dt_virt;
|
||||
int size;
|
||||
|
||||
dt_virt = __fixmap_remap_fdt(dt_phys, &size,
|
||||
IS_ENABLED(CONFIG_BUILD_ARM64_EMBEDDED_DTB) ? PAGE_KERNEL : PAGE_KERNEL_RO);
|
||||
if (!dt_virt)
|
||||
return NULL;
|
||||
|
||||
memblock_reserve(dt_phys, size);
|
||||
return dt_virt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init arch_ioremap_pud_supported(void)
|
||||
|
@ -46,8 +46,7 @@ build_unifdef: $(obj)/unifdef
|
||||
subdir-$(CONFIG_MODVERSIONS) += genksyms
|
||||
subdir-y += mod
|
||||
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
|
||||
subdir-$(CONFIG_DTC) += dtc-aosp
|
||||
subdir-$(CONFIG_BUILD_ARM64_EMBEDDED_DTB) += ufdt
|
||||
subdir-$(CONFIG_DTC) += dtc
|
||||
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
|
||||
|
||||
# Let clean descend into subdirs
|
||||
|
@ -253,7 +253,10 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
|
||||
|
||||
# DTC
|
||||
# ---------------------------------------------------------------------------
|
||||
DTC ?= $(objtree)/scripts/dtc-aosp/dtc-aosp
|
||||
DTC ?= $(objtree)/scripts/dtc/dtc
|
||||
|
||||
# Silence noisy warnings
|
||||
DTC_FLAGS += -q
|
||||
|
||||
# Disable noisy checks by default
|
||||
ifeq ($(findstring 1,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),)
|
||||
@ -262,7 +265,8 @@ endif
|
||||
|
||||
ifneq ($(findstring 2,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),)
|
||||
DTC_FLAGS += -Wnode_name_chars_strict \
|
||||
-Wproperty_name_chars_strict
|
||||
-Wproperty_name_chars_strict \
|
||||
-Winterrupt_provider
|
||||
endif
|
||||
|
||||
DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
|
||||
@ -301,11 +305,6 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) FORCE
|
||||
|
||||
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
|
||||
|
||||
# mkdtimg
|
||||
#----------------------------------------------------------------------------
|
||||
quiet_cmd_mkdtimg = DTBOIMG $@
|
||||
cmd_mkdtimg = python2 $(srctree)/scripts/ufdt/libufdt/utils/src/mkdtboimg.py cfg_create $@ $<
|
||||
|
||||
# cat
|
||||
# ---------------------------------------------------------------------------
|
||||
# Concatentate multiple files together
|
||||
|
@ -1,44 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
#
|
||||
# This is based on the original scripts/dtc/Makefile, but has been revised to
|
||||
# work with an insane submodule situation.
|
||||
|
||||
hostprogs-y := dtc-aosp
|
||||
always := $(hostprogs-y)
|
||||
|
||||
dtc-aosp-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
|
||||
srcpos.o checks.o util.o
|
||||
dtc-aosp-objs += dtc-lexer.lex.o dtc-parser.tab.o
|
||||
|
||||
# We're working with a submodule, so make these all relative to that.
|
||||
dtc-aosp-objs := $(addprefix dtc/,$(dtc-aosp-objs))
|
||||
|
||||
HOSTCFLAGS_DTC := -I$(src)/dtc -I$(src)/dtc/libfdt -I$(obj)/dtc
|
||||
|
||||
HOSTCFLAGS_checks.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_data.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_dtc.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_flattree.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
|
||||
|
||||
HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC)
|
||||
HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC)
|
||||
|
||||
# Dependencies on generated files need to be listed explicitly.
|
||||
$(obj)/dtc/dtc-lexer.lex.o: $(obj)/dtc/dtc-parser.h
|
||||
|
||||
# The kernel build supports flex and bison now
|
||||
%.lex.c: %.l
|
||||
$(call if_changed,flex)
|
||||
%.tab.c: %.y
|
||||
$(call if_changed,bison)
|
||||
%.h: %.y
|
||||
$(call if_changed,bison_h)
|
||||
|
||||
# Generated files need to be cleaned explicitly.
|
||||
clean-files := dtc/dtc-lexer.lex.c dtc/dtc-parser.tab.c dtc/dtc-parser.h
|
@ -11,6 +11,13 @@ dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
|
||||
# Source files need to get at the userspace version of libfdt_env.h to compile
|
||||
HOST_EXTRACFLAGS := -I$(src)/libfdt
|
||||
|
||||
ifeq ($(wildcard /usr/include/yaml.h),)
|
||||
HOST_EXTRACFLAGS += -DNO_YAML
|
||||
else
|
||||
dtc-objs += yamltree.o
|
||||
HOSTLDLIBS_dtc := -lyaml
|
||||
endif
|
||||
|
||||
# Generated files need one more search path to include headers in source tree
|
||||
HOSTCFLAGS_dtc-lexer.lex.o := -I$(src)
|
||||
HOSTCFLAGS_dtc-parser.tab.o := -I$(src)
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Makefile.dtc
|
||||
#
|
||||
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||
@ -14,5 +15,9 @@ DTC_SRCS = \
|
||||
treesource.c \
|
||||
util.c
|
||||
|
||||
ifneq ($(NO_YAML),1)
|
||||
DTC_SRCS += yamltree.c
|
||||
endif
|
||||
|
||||
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
|
||||
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
|
||||
|
@ -1,24 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
#ifdef TRACE_CHECKS
|
||||
#define TRACE(c, ...) \
|
||||
@ -78,23 +64,56 @@ static inline void PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
char *str = NULL;
|
||||
struct srcpos *pos = NULL;
|
||||
char *file_str;
|
||||
|
||||
if ((c->warn && (quiet < 1))
|
||||
|| (c->error && (quiet < 2))) {
|
||||
fprintf(stderr, "%s: %s (%s): ",
|
||||
strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
|
||||
if (!(c->warn && (quiet < 1)) && !(c->error && (quiet < 2)))
|
||||
return;
|
||||
|
||||
if (prop && prop->srcpos)
|
||||
pos = prop->srcpos;
|
||||
else if (node && node->srcpos)
|
||||
pos = node->srcpos;
|
||||
|
||||
if (pos) {
|
||||
file_str = srcpos_string(pos);
|
||||
xasprintf(&str, "%s", file_str);
|
||||
free(file_str);
|
||||
} else if (streq(dti->outname, "-")) {
|
||||
xasprintf(&str, "<stdout>");
|
||||
} else {
|
||||
xasprintf(&str, "%s", dti->outname);
|
||||
}
|
||||
|
||||
xasprintf_append(&str, ": %s (%s): ",
|
||||
(c->error) ? "ERROR" : "Warning", c->name);
|
||||
|
||||
if (node) {
|
||||
fprintf(stderr, "%s", node->fullpath);
|
||||
if (prop)
|
||||
fprintf(stderr, ":%s", prop->name);
|
||||
fputs(": ", stderr);
|
||||
}
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
xasprintf_append(&str, "%s:%s: ", node->fullpath, prop->name);
|
||||
else
|
||||
xasprintf_append(&str, "%s: ", node->fullpath);
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
xavsprintf_append(&str, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
xasprintf_append(&str, "\n");
|
||||
|
||||
if (!prop && pos) {
|
||||
pos = node->srcpos;
|
||||
while (pos->next) {
|
||||
pos = pos->next;
|
||||
|
||||
file_str = srcpos_string(pos);
|
||||
xasprintf_append(&str, " also defined at %s\n", file_str);
|
||||
free(file_str);
|
||||
}
|
||||
}
|
||||
|
||||
fputs(str, stderr);
|
||||
}
|
||||
|
||||
#define FAIL(c, dti, node, ...) \
|
||||
@ -333,7 +352,7 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
|
||||
FAIL(c, dti, node, "node has a reg or ranges property, but no unit name");
|
||||
} else {
|
||||
if (unitname[0])
|
||||
FAIL(c, dti, node, "node has a unit name, but no reg property");
|
||||
FAIL(c, dti, node, "node has a unit name, but no reg or ranges property");
|
||||
}
|
||||
}
|
||||
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
|
||||
@ -626,6 +645,8 @@ ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
|
||||
static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
if (generate_symbols && node->labels)
|
||||
return;
|
||||
if (node->omit_if_unused && !node->is_referenced)
|
||||
delete_node(node);
|
||||
}
|
||||
@ -670,6 +691,11 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
|
||||
return;
|
||||
|
||||
for_each_property(node, prop) {
|
||||
if (streq(prop->name, "phandle")
|
||||
|| streq(prop->name, "linux,phandle")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
|
||||
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
|
||||
prop->val.val);
|
||||
@ -739,13 +765,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||||
{
|
||||
struct property *prop;
|
||||
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
|
||||
const char *ranges = c->data;
|
||||
|
||||
prop = get_property(node, "ranges");
|
||||
prop = get_property(node, ranges);
|
||||
if (!prop)
|
||||
return;
|
||||
|
||||
if (!node->parent) {
|
||||
FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property");
|
||||
FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property",
|
||||
ranges);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -757,23 +785,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
|
||||
|
||||
if (prop->val.len == 0) {
|
||||
if (p_addr_cells != c_addr_cells)
|
||||
FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its "
|
||||
FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
|
||||
"#address-cells (%d) differs from %s (%d)",
|
||||
c_addr_cells, node->parent->fullpath,
|
||||
ranges, c_addr_cells, node->parent->fullpath,
|
||||
p_addr_cells);
|
||||
if (p_size_cells != c_size_cells)
|
||||
FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its "
|
||||
FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
|
||||
"#size-cells (%d) differs from %s (%d)",
|
||||
c_size_cells, node->parent->fullpath,
|
||||
ranges, c_size_cells, node->parent->fullpath,
|
||||
p_size_cells);
|
||||
} else if ((prop->val.len % entrylen) != 0) {
|
||||
FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) "
|
||||
FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
|
||||
"(parent #address-cells == %d, child #address-cells == %d, "
|
||||
"#size-cells == %d)", prop->val.len,
|
||||
"#size-cells == %d)", ranges, prop->val.len,
|
||||
p_addr_cells, c_addr_cells, c_size_cells);
|
||||
}
|
||||
}
|
||||
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
|
||||
WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells);
|
||||
WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells);
|
||||
|
||||
static const struct bus_type pci_bus = {
|
||||
.name = "PCI",
|
||||
@ -910,7 +939,7 @@ static bool node_is_compatible(struct node *node, const char *compat)
|
||||
|
||||
for (str = prop->val.val, end = str + prop->val.len; str < end;
|
||||
str += strnlen(str, end - str) + 1) {
|
||||
if (strprefixeq(str, end - str, compat))
|
||||
if (streq(str, compat))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -921,7 +950,8 @@ static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct
|
||||
if (node_is_compatible(node, "simple-bus"))
|
||||
node->bus = &simple_bus;
|
||||
}
|
||||
WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
|
||||
WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL,
|
||||
&addr_size_cells, &compatible_is_string_list);
|
||||
|
||||
static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
|
||||
{
|
||||
@ -962,6 +992,159 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
|
||||
}
|
||||
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge);
|
||||
|
||||
static const struct bus_type i2c_bus = {
|
||||
.name = "i2c-bus",
|
||||
};
|
||||
|
||||
static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
|
||||
{
|
||||
if (strprefixeq(node->name, node->basenamelen, "i2c-bus") ||
|
||||
strprefixeq(node->name, node->basenamelen, "i2c-arb")) {
|
||||
node->bus = &i2c_bus;
|
||||
} else if (strprefixeq(node->name, node->basenamelen, "i2c")) {
|
||||
struct node *child;
|
||||
for_each_child(node, child) {
|
||||
if (strprefixeq(child->name, node->basenamelen, "i2c-bus"))
|
||||
return;
|
||||
}
|
||||
node->bus = &i2c_bus;
|
||||
} else
|
||||
return;
|
||||
|
||||
if (!node->children)
|
||||
return;
|
||||
|
||||
if (node_addr_cells(node) != 1)
|
||||
FAIL(c, dti, node, "incorrect #address-cells for I2C bus");
|
||||
if (node_size_cells(node) != 0)
|
||||
FAIL(c, dti, node, "incorrect #size-cells for I2C bus");
|
||||
|
||||
}
|
||||
WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells);
|
||||
|
||||
#define I2C_OWN_SLAVE_ADDRESS (1U << 30)
|
||||
#define I2C_TEN_BIT_ADDRESS (1U << 31)
|
||||
|
||||
static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
const char *unitname = get_unitname(node);
|
||||
char unit_addr[17];
|
||||
uint32_t reg = 0;
|
||||
int len;
|
||||
cell_t *cells = NULL;
|
||||
|
||||
if (!node->parent || (node->parent->bus != &i2c_bus))
|
||||
return;
|
||||
|
||||
prop = get_property(node, "reg");
|
||||
if (prop)
|
||||
cells = (cell_t *)prop->val.val;
|
||||
|
||||
if (!cells) {
|
||||
FAIL(c, dti, node, "missing or empty reg property");
|
||||
return;
|
||||
}
|
||||
|
||||
reg = fdt32_to_cpu(*cells);
|
||||
/* Ignore I2C_OWN_SLAVE_ADDRESS */
|
||||
reg &= ~I2C_OWN_SLAVE_ADDRESS;
|
||||
snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
|
||||
if (!streq(unitname, unit_addr))
|
||||
FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
|
||||
unit_addr);
|
||||
|
||||
for (len = prop->val.len; len > 0; len -= 4) {
|
||||
reg = fdt32_to_cpu(*(cells++));
|
||||
/* Ignore I2C_OWN_SLAVE_ADDRESS */
|
||||
reg &= ~I2C_OWN_SLAVE_ADDRESS;
|
||||
|
||||
if ((reg & I2C_TEN_BIT_ADDRESS) && ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff))
|
||||
FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
|
||||
reg);
|
||||
else if (reg > 0x7f)
|
||||
FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\". Set I2C_TEN_BIT_ADDRESS for 10 bit addresses or fix the property",
|
||||
reg);
|
||||
}
|
||||
}
|
||||
WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge);
|
||||
|
||||
static const struct bus_type spi_bus = {
|
||||
.name = "spi-bus",
|
||||
};
|
||||
|
||||
static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
|
||||
{
|
||||
int spi_addr_cells = 1;
|
||||
|
||||
if (strprefixeq(node->name, node->basenamelen, "spi")) {
|
||||
node->bus = &spi_bus;
|
||||
} else {
|
||||
/* Try to detect SPI buses which don't have proper node name */
|
||||
struct node *child;
|
||||
|
||||
if (node_addr_cells(node) != 1 || node_size_cells(node) != 0)
|
||||
return;
|
||||
|
||||
for_each_child(node, child) {
|
||||
struct property *prop;
|
||||
for_each_property(child, prop) {
|
||||
if (strprefixeq(prop->name, 4, "spi-")) {
|
||||
node->bus = &spi_bus;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (node->bus == &spi_bus)
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->bus == &spi_bus && get_property(node, "reg"))
|
||||
FAIL(c, dti, node, "node name for SPI buses should be 'spi'");
|
||||
}
|
||||
if (node->bus != &spi_bus || !node->children)
|
||||
return;
|
||||
|
||||
if (get_property(node, "spi-slave"))
|
||||
spi_addr_cells = 0;
|
||||
if (node_addr_cells(node) != spi_addr_cells)
|
||||
FAIL(c, dti, node, "incorrect #address-cells for SPI bus");
|
||||
if (node_size_cells(node) != 0)
|
||||
FAIL(c, dti, node, "incorrect #size-cells for SPI bus");
|
||||
|
||||
}
|
||||
WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells);
|
||||
|
||||
static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
const char *unitname = get_unitname(node);
|
||||
char unit_addr[9];
|
||||
uint32_t reg = 0;
|
||||
cell_t *cells = NULL;
|
||||
|
||||
if (!node->parent || (node->parent->bus != &spi_bus))
|
||||
return;
|
||||
|
||||
if (get_property(node->parent, "spi-slave"))
|
||||
return;
|
||||
|
||||
prop = get_property(node, "reg");
|
||||
if (prop)
|
||||
cells = (cell_t *)prop->val.val;
|
||||
|
||||
if (!cells) {
|
||||
FAIL(c, dti, node, "missing or empty reg property");
|
||||
return;
|
||||
}
|
||||
|
||||
reg = fdt32_to_cpu(*cells);
|
||||
snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
|
||||
if (!streq(unitname, unit_addr))
|
||||
FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"",
|
||||
unit_addr);
|
||||
}
|
||||
WARNING(spi_bus_reg, check_spi_bus_reg, NULL, ®_format, &spi_bus_bridge);
|
||||
|
||||
static void check_unit_address_format(struct check *c, struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
@ -1034,8 +1217,24 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d
|
||||
}
|
||||
WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size);
|
||||
|
||||
static void check_unique_unit_address(struct check *c, struct dt_info *dti,
|
||||
struct node *node)
|
||||
static bool node_is_disabled(struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
prop = get_property(node, "status");
|
||||
if (prop) {
|
||||
char *str = prop->val.val;
|
||||
if (streq("disabled", str))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void check_unique_unit_address_common(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node,
|
||||
bool disable_check)
|
||||
{
|
||||
struct node *childa;
|
||||
|
||||
@ -1052,18 +1251,38 @@ static void check_unique_unit_address(struct check *c, struct dt_info *dti,
|
||||
if (!strlen(addr_a))
|
||||
continue;
|
||||
|
||||
if (disable_check && node_is_disabled(childa))
|
||||
continue;
|
||||
|
||||
for_each_child(node, childb) {
|
||||
const char *addr_b = get_unitname(childb);
|
||||
if (childa == childb)
|
||||
break;
|
||||
|
||||
if (disable_check && node_is_disabled(childb))
|
||||
continue;
|
||||
|
||||
if (streq(addr_a, addr_b))
|
||||
FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_unique_unit_address(struct check *c, struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
check_unique_unit_address_common(c, dti, node, false);
|
||||
}
|
||||
WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size);
|
||||
|
||||
static void check_unique_unit_address_if_enabled(struct check *c, struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
check_unique_unit_address_common(c, dti, node, true);
|
||||
}
|
||||
CHECK_ENTRY(unique_unit_address_if_enabled, check_unique_unit_address_if_enabled,
|
||||
NULL, false, false, &avoid_default_addr_size);
|
||||
|
||||
static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
@ -1338,6 +1557,28 @@ static bool node_is_interrupt_provider(struct node *node)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void check_interrupt_provider(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
if (!node_is_interrupt_provider(node))
|
||||
return;
|
||||
|
||||
prop = get_property(node, "#interrupt-cells");
|
||||
if (!prop)
|
||||
FAIL(c, dti, node,
|
||||
"Missing #interrupt-cells in interrupt provider");
|
||||
|
||||
prop = get_property(node, "#address-cells");
|
||||
if (!prop)
|
||||
FAIL(c, dti, node,
|
||||
"Missing #address-cells in interrupt provider");
|
||||
}
|
||||
WARNING(interrupt_provider, check_interrupt_provider, NULL);
|
||||
|
||||
static void check_interrupts_property(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
@ -1364,10 +1605,14 @@ static void check_interrupts_property(struct check *c,
|
||||
prop = get_property(parent, "interrupt-parent");
|
||||
if (prop) {
|
||||
phandle = propval_cell(prop);
|
||||
/* Give up if this is an overlay with external references */
|
||||
if ((phandle == 0 || phandle == -1) &&
|
||||
(dti->dtsflags & DTSF_PLUGIN))
|
||||
if ((phandle == 0) || (phandle == -1)) {
|
||||
/* Give up if this is an overlay with
|
||||
* external references */
|
||||
if (dti->dtsflags & DTSF_PLUGIN)
|
||||
return;
|
||||
FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
|
||||
continue;
|
||||
}
|
||||
|
||||
irq_node = get_node_by_phandle(root, phandle);
|
||||
if (!irq_node) {
|
||||
@ -1391,7 +1636,7 @@ static void check_interrupts_property(struct check *c,
|
||||
|
||||
prop = get_property(irq_node, "#interrupt-cells");
|
||||
if (!prop) {
|
||||
FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent");
|
||||
/* We warn about that already in another test. */
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1536,7 +1781,7 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
|
||||
return;
|
||||
|
||||
if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
|
||||
FAIL(c, dti, node, "graph endpont node name should be 'endpoint'");
|
||||
FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'");
|
||||
|
||||
check_graph_reg(c, dti, node);
|
||||
|
||||
@ -1570,7 +1815,7 @@ static struct check *check_table[] = {
|
||||
&property_name_chars_strict,
|
||||
&node_name_chars_strict,
|
||||
|
||||
&addr_size_cells, ®_format, &ranges_format,
|
||||
&addr_size_cells, ®_format, &ranges_format, &dma_ranges_format,
|
||||
|
||||
&unit_address_vs_reg,
|
||||
&unit_address_format,
|
||||
@ -1582,9 +1827,16 @@ static struct check *check_table[] = {
|
||||
&simple_bus_bridge,
|
||||
&simple_bus_reg,
|
||||
|
||||
&i2c_bus_bridge,
|
||||
&i2c_bus_reg,
|
||||
|
||||
&spi_bus_bridge,
|
||||
&spi_bus_reg,
|
||||
|
||||
&avoid_default_addr_size,
|
||||
&avoid_unnecessary_addr_size,
|
||||
&unique_unit_address,
|
||||
&unique_unit_address_if_enabled,
|
||||
&obsolete_chosen_interrupt_controller,
|
||||
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
|
||||
|
||||
@ -1608,6 +1860,7 @@ static struct check *check_table[] = {
|
||||
&deprecated_gpio_property,
|
||||
&gpios_property,
|
||||
&interrupts_property,
|
||||
&interrupt_provider,
|
||||
|
||||
&alias_paths,
|
||||
|
||||
|
@ -1,21 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
@ -74,7 +59,8 @@ struct data data_copy_escape_string(const char *s, int len)
|
||||
struct data d;
|
||||
char *q;
|
||||
|
||||
d = data_grow_for(empty_data, len + 1);
|
||||
d = data_add_marker(empty_data, TYPE_STRING, NULL);
|
||||
d = data_grow_for(d, len + 1);
|
||||
|
||||
q = d.val;
|
||||
while (i < len) {
|
||||
@ -94,6 +80,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
|
||||
{
|
||||
struct data d = empty_data;
|
||||
|
||||
d = data_add_marker(d, TYPE_NONE, NULL);
|
||||
while (!feof(f) && (d.len < maxlen)) {
|
||||
size_t chunksize, ret;
|
||||
|
||||
|
@ -1,21 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
%option noyywrap nounput noinput never-interactive
|
||||
@ -212,14 +197,14 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
|
||||
<*>\&{LABEL} { /* label reference */
|
||||
DPRINT("Ref: %s\n", yytext+1);
|
||||
yylval.labelref = xstrdup(yytext+1);
|
||||
return DT_REF;
|
||||
return DT_LABEL_REF;
|
||||
}
|
||||
|
||||
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
|
||||
yytext[yyleng-1] = '\0';
|
||||
DPRINT("Ref: %s\n", yytext+2);
|
||||
yylval.labelref = xstrdup(yytext+2);
|
||||
return DT_REF;
|
||||
return DT_PATH_REF;
|
||||
}
|
||||
|
||||
<BYTESTRING>[0-9a-fA-F]{2} {
|
||||
|
@ -1,22 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
%locations
|
||||
|
||||
%{
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
@ -32,6 +19,8 @@ extern void yyerror(char const *s);
|
||||
treesource_error = true; \
|
||||
} while (0)
|
||||
|
||||
#define YYERROR_CALL(msg) yyerror(msg)
|
||||
|
||||
extern struct dt_info *parser_output;
|
||||
extern bool treesource_error;
|
||||
%}
|
||||
@ -70,7 +59,8 @@ extern bool treesource_error;
|
||||
%token <byte> DT_BYTE
|
||||
%token <data> DT_STRING
|
||||
%token <labelref> DT_LABEL
|
||||
%token <labelref> DT_REF
|
||||
%token <labelref> DT_LABEL_REF
|
||||
%token <labelref> DT_PATH_REF
|
||||
%token DT_INCBIN
|
||||
|
||||
%type <data> propdata
|
||||
@ -83,6 +73,7 @@ extern bool treesource_error;
|
||||
%type <data> bytestring
|
||||
%type <prop> propdef
|
||||
%type <proplist> proplist
|
||||
%type <labelref> dt_ref
|
||||
|
||||
%type <node> devicetree
|
||||
%type <node> nodedef
|
||||
@ -158,6 +149,8 @@ memreserve:
|
||||
}
|
||||
;
|
||||
|
||||
dt_ref: DT_LABEL_REF | DT_PATH_REF;
|
||||
|
||||
devicetree:
|
||||
'/' nodedef
|
||||
{
|
||||
@ -167,7 +160,7 @@ devicetree:
|
||||
{
|
||||
$$ = merge_nodes($1, $3);
|
||||
}
|
||||
| DT_REF nodedef
|
||||
| dt_ref nodedef
|
||||
{
|
||||
/*
|
||||
* We rely on the rule being always:
|
||||
@ -176,9 +169,12 @@ devicetree:
|
||||
*/
|
||||
if (!($<flags>-1 & DTSF_PLUGIN))
|
||||
ERROR(&@2, "Label or path %s not found", $1);
|
||||
$$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
|
||||
$$ = add_orphan_node(
|
||||
name_node(build_node(NULL, NULL, NULL),
|
||||
""),
|
||||
$2, $1);
|
||||
}
|
||||
| devicetree DT_LABEL DT_REF nodedef
|
||||
| devicetree DT_LABEL dt_ref nodedef
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $3);
|
||||
|
||||
@ -189,7 +185,7 @@ devicetree:
|
||||
ERROR(&@3, "Label or path %s not found", $3);
|
||||
$$ = $1;
|
||||
}
|
||||
| devicetree DT_REF nodedef
|
||||
| devicetree DT_PATH_REF nodedef
|
||||
{
|
||||
/*
|
||||
* We rely on the rule being always:
|
||||
@ -208,7 +204,26 @@ devicetree:
|
||||
}
|
||||
$$ = $1;
|
||||
}
|
||||
| devicetree DT_DEL_NODE DT_REF ';'
|
||||
| devicetree DT_LABEL_REF nodedef
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $2);
|
||||
|
||||
if (target) {
|
||||
merge_nodes(target, $3);
|
||||
} else {
|
||||
/*
|
||||
* We rely on the rule being always:
|
||||
* versioninfo plugindecl memreserves devicetree
|
||||
* so $-1 is what we want (plugindecl)
|
||||
*/
|
||||
if ($<flags>-1 & DTSF_PLUGIN)
|
||||
add_orphan_node($1, $3, $2);
|
||||
else
|
||||
ERROR(&@2, "Label or path %s not found", $2);
|
||||
}
|
||||
$$ = $1;
|
||||
}
|
||||
| devicetree DT_DEL_NODE dt_ref ';'
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $3);
|
||||
|
||||
@ -220,7 +235,7 @@ devicetree:
|
||||
|
||||
$$ = $1;
|
||||
}
|
||||
| devicetree DT_OMIT_NO_REF DT_REF ';'
|
||||
| devicetree DT_OMIT_NO_REF dt_ref ';'
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $3);
|
||||
|
||||
@ -237,7 +252,7 @@ devicetree:
|
||||
nodedef:
|
||||
'{' proplist subnodes '}' ';'
|
||||
{
|
||||
$$ = build_node($2, $3);
|
||||
$$ = build_node($2, $3, &@$);
|
||||
}
|
||||
;
|
||||
|
||||
@ -255,11 +270,11 @@ proplist:
|
||||
propdef:
|
||||
DT_PROPNODENAME '=' propdata ';'
|
||||
{
|
||||
$$ = build_property($1, $3);
|
||||
$$ = build_property($1, $3, &@$);
|
||||
}
|
||||
| DT_PROPNODENAME ';'
|
||||
{
|
||||
$$ = build_property($1, empty_data);
|
||||
$$ = build_property($1, empty_data, &@$);
|
||||
}
|
||||
| DT_DEL_PROP DT_PROPNODENAME ';'
|
||||
{
|
||||
@ -285,8 +300,9 @@ propdata:
|
||||
{
|
||||
$$ = data_merge($1, $3);
|
||||
}
|
||||
| propdataprefix DT_REF
|
||||
| propdataprefix dt_ref
|
||||
{
|
||||
$1 = data_add_marker($1, TYPE_STRING, $2);
|
||||
$$ = data_add_marker($1, REF_PATH, $2);
|
||||
}
|
||||
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
|
||||
@ -340,22 +356,27 @@ arrayprefix:
|
||||
DT_BITS DT_LITERAL '<'
|
||||
{
|
||||
unsigned long long bits;
|
||||
enum markertype type = TYPE_UINT32;
|
||||
|
||||
bits = $2;
|
||||
|
||||
if ((bits != 8) && (bits != 16) &&
|
||||
(bits != 32) && (bits != 64)) {
|
||||
switch (bits) {
|
||||
case 8: type = TYPE_UINT8; break;
|
||||
case 16: type = TYPE_UINT16; break;
|
||||
case 32: type = TYPE_UINT32; break;
|
||||
case 64: type = TYPE_UINT64; break;
|
||||
default:
|
||||
ERROR(&@2, "Array elements must be"
|
||||
" 8, 16, 32 or 64-bits");
|
||||
bits = 32;
|
||||
}
|
||||
|
||||
$$.data = empty_data;
|
||||
$$.data = data_add_marker(empty_data, type, NULL);
|
||||
$$.bits = bits;
|
||||
}
|
||||
| '<'
|
||||
{
|
||||
$$.data = empty_data;
|
||||
$$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
|
||||
$$.bits = 32;
|
||||
}
|
||||
| arrayprefix integer_prim
|
||||
@ -377,7 +398,7 @@ arrayprefix:
|
||||
|
||||
$$.data = data_append_integer($1.data, $2, $1.bits);
|
||||
}
|
||||
| arrayprefix DT_REF
|
||||
| arrayprefix dt_ref
|
||||
{
|
||||
uint64_t val = ~0ULL >> (64 - $1.bits);
|
||||
|
||||
@ -499,7 +520,7 @@ integer_unary:
|
||||
bytestring:
|
||||
/* empty */
|
||||
{
|
||||
$$ = empty_data;
|
||||
$$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
|
||||
}
|
||||
| bytestring DT_BYTE
|
||||
{
|
||||
@ -534,7 +555,7 @@ subnode:
|
||||
}
|
||||
| DT_DEL_NODE DT_PROPNODENAME ';'
|
||||
{
|
||||
$$ = name_node(build_node_delete(), $2);
|
||||
$$ = name_node(build_node_delete(&@$), $2);
|
||||
}
|
||||
| DT_OMIT_NO_REF subnode
|
||||
{
|
||||
|
@ -1,21 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
@ -35,6 +20,8 @@ int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties *
|
||||
int generate_symbols; /* enable symbols & fixup support */
|
||||
int generate_fixups; /* suppress generation of fixups on symbol support */
|
||||
int auto_label_aliases; /* auto generate labels -> aliases */
|
||||
int annotate; /* Level of annotation: 1 for input source location
|
||||
>1 for full input source location. */
|
||||
|
||||
static int is_power_of_2(int x)
|
||||
{
|
||||
@ -60,7 +47,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
|
||||
|
||||
/* Usage related data. */
|
||||
static const char usage_synopsis[] = "dtc [options] <input file>";
|
||||
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
|
||||
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv";
|
||||
static struct option const usage_long_opts[] = {
|
||||
{"quiet", no_argument, NULL, 'q'},
|
||||
{"in-format", a_argument, NULL, 'I'},
|
||||
@ -81,6 +68,7 @@ static struct option const usage_long_opts[] = {
|
||||
{"error", a_argument, NULL, 'E'},
|
||||
{"symbols", no_argument, NULL, '@'},
|
||||
{"auto-alias", no_argument, NULL, 'A'},
|
||||
{"annotate", no_argument, NULL, 'T'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{NULL, no_argument, NULL, 0x0},
|
||||
@ -95,6 +83,9 @@ static const char * const usage_opts_help[] = {
|
||||
"\n\tOutput formats are:\n"
|
||||
"\t\tdts - device tree source text\n"
|
||||
"\t\tdtb - device tree blob\n"
|
||||
#ifndef NO_YAML
|
||||
"\t\tyaml - device tree encoded as YAML\n"
|
||||
#endif
|
||||
"\t\tasm - assembler source",
|
||||
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
|
||||
"\n\tOutput dependency file",
|
||||
@ -114,6 +105,7 @@ static const char * const usage_opts_help[] = {
|
||||
"\n\tEnable/disable errors (prefix with \"no-\")",
|
||||
"\n\tEnable generation of symbols",
|
||||
"\n\tEnable auto-alias of labels",
|
||||
"\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
|
||||
"\n\tPrint this help and exit",
|
||||
"\n\tPrint version and exit",
|
||||
NULL,
|
||||
@ -128,6 +120,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
|
||||
return fallback;
|
||||
if (!strcasecmp(s, ".dts"))
|
||||
return "dts";
|
||||
if (!strcasecmp(s, ".yaml"))
|
||||
return "yaml";
|
||||
if (!strcasecmp(s, ".dtb"))
|
||||
return "dtb";
|
||||
return fallback;
|
||||
@ -259,6 +253,9 @@ int main(int argc, char *argv[])
|
||||
case 'A':
|
||||
auto_label_aliases = 1;
|
||||
break;
|
||||
case 'T':
|
||||
annotate++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(NULL);
|
||||
@ -297,6 +294,8 @@ int main(int argc, char *argv[])
|
||||
outform = "dts";
|
||||
}
|
||||
}
|
||||
if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
|
||||
die("--annotate requires -I dts -O dts\n");
|
||||
if (streq(inform, "dts"))
|
||||
dti = dt_from_source(arg);
|
||||
else if (streq(inform, "fs"))
|
||||
@ -350,6 +349,12 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (streq(outform, "dts")) {
|
||||
dt_to_source(outf, dti);
|
||||
#ifndef NO_YAML
|
||||
} else if (streq(outform, "yaml")) {
|
||||
if (!streq(inform, "dts"))
|
||||
die("YAML output format requires dts input format\n");
|
||||
dt_to_yaml(outf, dti);
|
||||
#endif
|
||||
} else if (streq(outform, "dtb")) {
|
||||
dt_to_blob(outf, dti, outversion);
|
||||
} else if (streq(outform, "asm")) {
|
||||
|
@ -1,24 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef DTC_H
|
||||
#define DTC_H
|
||||
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -58,6 +43,7 @@ extern int phandle_format; /* Use linux,phandle or phandle properties */
|
||||
extern int generate_symbols; /* generate symbols for nodes with labels */
|
||||
extern int generate_fixups; /* generate fixups */
|
||||
extern int auto_label_aliases; /* auto generate labels -> aliases */
|
||||
extern int annotate; /* annotate .dts with input source location */
|
||||
|
||||
#define PHANDLE_LEGACY 0x1
|
||||
#define PHANDLE_EPAPR 0x2
|
||||
@ -65,6 +51,37 @@ extern int auto_label_aliases; /* auto generate labels -> aliases */
|
||||
|
||||
typedef uint32_t cell_t;
|
||||
|
||||
static inline uint16_t dtb_ld16(const void *p)
|
||||
{
|
||||
const uint8_t *bp = (const uint8_t *)p;
|
||||
|
||||
return ((uint16_t)bp[0] << 8)
|
||||
| bp[1];
|
||||
}
|
||||
|
||||
static inline uint32_t dtb_ld32(const void *p)
|
||||
{
|
||||
const uint8_t *bp = (const uint8_t *)p;
|
||||
|
||||
return ((uint32_t)bp[0] << 24)
|
||||
| ((uint32_t)bp[1] << 16)
|
||||
| ((uint32_t)bp[2] << 8)
|
||||
| bp[3];
|
||||
}
|
||||
|
||||
static inline uint64_t dtb_ld64(const void *p)
|
||||
{
|
||||
const uint8_t *bp = (const uint8_t *)p;
|
||||
|
||||
return ((uint64_t)bp[0] << 56)
|
||||
| ((uint64_t)bp[1] << 48)
|
||||
| ((uint64_t)bp[2] << 40)
|
||||
| ((uint64_t)bp[3] << 32)
|
||||
| ((uint64_t)bp[4] << 24)
|
||||
| ((uint64_t)bp[5] << 16)
|
||||
| ((uint64_t)bp[6] << 8)
|
||||
| bp[7];
|
||||
}
|
||||
|
||||
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
|
||||
@ -74,10 +91,17 @@ typedef uint32_t cell_t;
|
||||
|
||||
/* Data blobs */
|
||||
enum markertype {
|
||||
TYPE_NONE,
|
||||
REF_PHANDLE,
|
||||
REF_PATH,
|
||||
LABEL,
|
||||
TYPE_UINT8,
|
||||
TYPE_UINT16,
|
||||
TYPE_UINT32,
|
||||
TYPE_UINT64,
|
||||
TYPE_STRING,
|
||||
};
|
||||
extern const char *markername(enum markertype markertype);
|
||||
|
||||
struct marker {
|
||||
enum markertype type;
|
||||
@ -101,6 +125,8 @@ struct data {
|
||||
for_each_marker(m) \
|
||||
if ((m)->type == (t))
|
||||
|
||||
size_t type_marker_length(struct marker *m);
|
||||
|
||||
void data_free(struct data d);
|
||||
|
||||
struct data data_grow_for(struct data d, int xlen);
|
||||
@ -149,6 +175,7 @@ struct property {
|
||||
struct property *next;
|
||||
|
||||
struct label *labels;
|
||||
struct srcpos *srcpos;
|
||||
};
|
||||
|
||||
struct node {
|
||||
@ -168,6 +195,7 @@ struct node {
|
||||
|
||||
struct label *labels;
|
||||
const struct bus_type *bus;
|
||||
struct srcpos *srcpos;
|
||||
|
||||
bool omit_if_unused, is_referenced;
|
||||
};
|
||||
@ -196,13 +224,15 @@ struct node {
|
||||
void add_label(struct label **labels, char *label);
|
||||
void delete_labels(struct label **labels);
|
||||
|
||||
struct property *build_property(char *name, struct data val);
|
||||
struct property *build_property(char *name, struct data val,
|
||||
struct srcpos *srcpos);
|
||||
struct property *build_property_delete(char *name);
|
||||
struct property *chain_property(struct property *first, struct property *list);
|
||||
struct property *reverse_properties(struct property *first);
|
||||
|
||||
struct node *build_node(struct property *proplist, struct node *children);
|
||||
struct node *build_node_delete(void);
|
||||
struct node *build_node(struct property *proplist, struct node *children,
|
||||
struct srcpos *srcpos);
|
||||
struct node *build_node_delete(struct srcpos *srcpos);
|
||||
struct node *name_node(struct node *node, char *name);
|
||||
struct node *omit_node_if_unused(struct node *node);
|
||||
struct node *reference_node(struct node *node);
|
||||
@ -217,7 +247,8 @@ void add_child(struct node *parent, struct node *child);
|
||||
void delete_node_by_name(struct node *parent, char *name);
|
||||
void delete_node(struct node *node);
|
||||
void append_to_property(struct node *node,
|
||||
char *name, const void *data, int len);
|
||||
char *name, const void *data, int len,
|
||||
enum markertype type);
|
||||
|
||||
const char *get_unitname(struct node *node);
|
||||
struct property *get_property(struct node *node, const char *propname);
|
||||
@ -290,6 +321,10 @@ struct dt_info *dt_from_blob(const char *fname);
|
||||
void dt_to_source(FILE *f, struct dt_info *dti);
|
||||
struct dt_info *dt_from_source(const char *f);
|
||||
|
||||
/* YAML source */
|
||||
|
||||
void dt_to_yaml(FILE *f, struct dt_info *dti);
|
||||
|
||||
/* FS trees */
|
||||
|
||||
struct dt_info *dt_from_fs(const char *dirname);
|
||||
|
@ -1,21 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
@ -171,7 +156,7 @@ static void asm_emit_data(void *e, struct data d)
|
||||
emit_offset_label(f, m->ref, m->offset);
|
||||
|
||||
while ((d.len - off) >= sizeof(uint32_t)) {
|
||||
asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
|
||||
asm_emit_cell(e, dtb_ld32(d.val + off));
|
||||
off += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
@ -393,7 +378,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
|
||||
padlen = 0;
|
||||
if (quiet < 1)
|
||||
fprintf(stderr,
|
||||
"Warning: blob size %d >= minimum size %d\n",
|
||||
"Warning: blob size %"PRIu32" >= minimum size %d\n",
|
||||
fdt32_to_cpu(fdt.totalsize), minsize);
|
||||
}
|
||||
}
|
||||
@ -525,7 +510,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
|
||||
fprintf(f, "/* Memory reserve map from source file */\n");
|
||||
|
||||
/*
|
||||
* Use .long on high and low halfs of u64s to avoid .quad
|
||||
* Use .long on high and low halves of u64s to avoid .quad
|
||||
* as it appears .quad isn't available in some assemblers.
|
||||
*/
|
||||
for (re = dti->reservelist; re; re = re->next) {
|
||||
@ -692,7 +677,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
|
||||
|
||||
val = flat_read_data(dtbuf, proplen);
|
||||
|
||||
return build_property(name, val);
|
||||
return build_property(name, val, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -750,7 +735,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
|
||||
char *flatname;
|
||||
uint32_t val;
|
||||
|
||||
node = build_node(NULL, NULL);
|
||||
node = build_node(NULL, NULL, NULL);
|
||||
|
||||
flatname = flat_read_string(dtbuf);
|
||||
|
||||
|
@ -1,21 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
@ -34,7 +19,7 @@ static struct node *read_fstree(const char *dirname)
|
||||
if (!d)
|
||||
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
|
||||
|
||||
tree = build_node(NULL, NULL);
|
||||
tree = build_node(NULL, NULL, NULL);
|
||||
|
||||
while ((de = readdir(d)) != NULL) {
|
||||
char *tmpname;
|
||||
@ -45,7 +30,7 @@ static struct node *read_fstree(const char *dirname)
|
||||
|
||||
tmpname = join_path(dirname, de->d_name);
|
||||
|
||||
if (lstat(tmpname, &st) < 0)
|
||||
if (stat(tmpname, &st) < 0)
|
||||
die("stat(%s): %s\n", tmpname, strerror(errno));
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
@ -60,7 +45,8 @@ static struct node *read_fstree(const char *dirname)
|
||||
} else {
|
||||
prop = build_property(xstrdup(de->d_name),
|
||||
data_copy_file(pfile,
|
||||
st.st_size));
|
||||
st.st_size),
|
||||
NULL);
|
||||
add_property(tree, prop);
|
||||
fclose(pfile);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
# Makefile.libfdt
|
||||
#
|
||||
# This is not a complete Makefile of itself. Instead, it is designed to
|
||||
@ -9,3 +10,9 @@ LIBFDT_VERSION = version.lds
|
||||
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
|
||||
fdt_addresses.c fdt_overlay.c
|
||||
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
|
||||
LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
|
||||
|
||||
libfdt_clean:
|
||||
@$(VECHO) CLEAN "(libfdt)"
|
||||
rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
|
||||
rm -f $(LIBFDT_dir)/$(LIBFDT_soname)
|
||||
|
@ -1,52 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
@ -55,35 +10,124 @@
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_check_header(const void *fdt)
|
||||
/*
|
||||
* Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
|
||||
* that the given buffer contains what appears to be a flattened
|
||||
* device tree with sane information in its header.
|
||||
*/
|
||||
int32_t fdt_ro_probe_(const void *fdt)
|
||||
{
|
||||
uint32_t totalsize = fdt_totalsize(fdt);
|
||||
|
||||
if (can_assume(VALID_DTB))
|
||||
return totalsize;
|
||||
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
/* Complete tree */
|
||||
if (!can_assume(LATEST)) {
|
||||
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
|
||||
if (fdt_last_comp_version(fdt) >
|
||||
FDT_LAST_SUPPORTED_VERSION)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
}
|
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||
/* Unfinished sequential-write blob */
|
||||
if (fdt_size_dt_struct(fdt) == 0)
|
||||
if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
} else {
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
}
|
||||
|
||||
if (fdt_off_dt_struct(fdt) > (UINT_MAX - fdt_size_dt_struct(fdt)))
|
||||
return FDT_ERR_BADOFFSET;
|
||||
if (totalsize < INT32_MAX)
|
||||
return totalsize;
|
||||
else
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
if (fdt_off_dt_strings(fdt) > (UINT_MAX - fdt_size_dt_strings(fdt)))
|
||||
return FDT_ERR_BADOFFSET;
|
||||
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
|
||||
{
|
||||
return (off >= hdrsize) && (off <= totalsize);
|
||||
}
|
||||
|
||||
if ((fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))
|
||||
> fdt_totalsize(fdt))
|
||||
return FDT_ERR_BADOFFSET;
|
||||
static int check_block_(uint32_t hdrsize, uint32_t totalsize,
|
||||
uint32_t base, uint32_t size)
|
||||
{
|
||||
if (!check_off_(hdrsize, totalsize, base))
|
||||
return 0; /* block start out of bounds */
|
||||
if ((base + size) < base)
|
||||
return 0; /* overflow */
|
||||
if (!check_off_(hdrsize, totalsize, base + size))
|
||||
return 0; /* block end out of bounds */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))
|
||||
> fdt_totalsize(fdt))
|
||||
return FDT_ERR_BADOFFSET;
|
||||
size_t fdt_header_size_(uint32_t version)
|
||||
{
|
||||
if (version <= 1)
|
||||
return FDT_V1_SIZE;
|
||||
else if (version <= 2)
|
||||
return FDT_V2_SIZE;
|
||||
else if (version <= 3)
|
||||
return FDT_V3_SIZE;
|
||||
else if (version <= 16)
|
||||
return FDT_V16_SIZE;
|
||||
else
|
||||
return FDT_V17_SIZE;
|
||||
}
|
||||
|
||||
size_t fdt_header_size(const void *fdt)
|
||||
{
|
||||
return can_assume(LATEST) ? FDT_V17_SIZE :
|
||||
fdt_header_size_(fdt_version(fdt));
|
||||
}
|
||||
|
||||
int fdt_check_header(const void *fdt)
|
||||
{
|
||||
size_t hdrsize;
|
||||
|
||||
if (fdt_magic(fdt) != FDT_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
if (!can_assume(LATEST)) {
|
||||
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|
||||
|| (fdt_last_comp_version(fdt) >
|
||||
FDT_LAST_SUPPORTED_VERSION))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
|
||||
return -FDT_ERR_BADVERSION;
|
||||
}
|
||||
hdrsize = fdt_header_size(fdt);
|
||||
if (!can_assume(VALID_DTB)) {
|
||||
|
||||
if ((fdt_totalsize(fdt) < hdrsize)
|
||||
|| (fdt_totalsize(fdt) > INT_MAX))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
|
||||
/* Bounds check memrsv block */
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_mem_rsvmap(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
if (!can_assume(VALID_DTB)) {
|
||||
/* Bounds check structure block */
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
|
||||
if (!check_off_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
} else {
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_struct(fdt),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
/* Bounds check strings block */
|
||||
if (!check_block_(hdrsize, fdt_totalsize(fdt),
|
||||
fdt_off_dt_strings(fdt),
|
||||
fdt_size_dt_strings(fdt)))
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -92,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|
||||
{
|
||||
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
|
||||
|
||||
if (!can_assume(VALID_INPUT))
|
||||
if ((absoffset < offset)
|
||||
|| ((absoffset + len) < absoffset)
|
||||
|| (absoffset + len) > fdt_totalsize(fdt))
|
||||
return NULL;
|
||||
|
||||
if (fdt_version(fdt) >= 0x11)
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
|
||||
if (((offset + len) < offset)
|
||||
|| ((offset + len) > fdt_size_dt_struct(fdt)))
|
||||
return NULL;
|
||||
@ -114,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
|
||||
*nextoffset = -FDT_ERR_TRUNCATED;
|
||||
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
|
||||
if (!tagp)
|
||||
if (!can_assume(VALID_DTB) && !tagp)
|
||||
return FDT_END; /* premature end */
|
||||
tag = fdt32_to_cpu(*tagp);
|
||||
offset += FDT_TAGSIZE;
|
||||
@ -126,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
do {
|
||||
p = fdt_offset_ptr(fdt, offset++, 1);
|
||||
} while (p && (*p != '\0'));
|
||||
if (!p)
|
||||
if (!can_assume(VALID_DTB) && !p)
|
||||
return FDT_END; /* premature end */
|
||||
break;
|
||||
|
||||
case FDT_PROP:
|
||||
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
|
||||
if (!lenp)
|
||||
if (!can_assume(VALID_DTB) && !lenp)
|
||||
return FDT_END; /* premature end */
|
||||
/* skip-name offset, length and value */
|
||||
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
|
||||
+ fdt32_to_cpu(*lenp);
|
||||
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
|
||||
if (!can_assume(LATEST) &&
|
||||
fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
|
||||
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
|
||||
offset += 4;
|
||||
break;
|
||||
@ -160,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
|
||||
|
||||
int fdt_check_node_offset_(const void *fdt, int offset)
|
||||
{
|
||||
if (can_assume(VALID_INPUT))
|
||||
return offset;
|
||||
if ((offset < 0) || (offset % FDT_TAGSIZE)
|
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
@ -258,7 +306,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
|
||||
|
||||
int fdt_move(const void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (fdt_totalsize(fdt) > bufsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
@ -1,55 +1,10 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef FDT_H
|
||||
#define FDT_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
@ -1,52 +1,8 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* Copyright (C) 2018 embedded brains GmbH
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
@ -55,42 +11,91 @@
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_address_cells(const void *fdt, int nodeoffset)
|
||||
static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
|
||||
{
|
||||
const fdt32_t *ac;
|
||||
int val;
|
||||
const fdt32_t *c;
|
||||
uint32_t val;
|
||||
int len;
|
||||
|
||||
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
|
||||
if (!ac)
|
||||
c = fdt_getprop(fdt, nodeoffset, name, &len);
|
||||
if (!c)
|
||||
return len;
|
||||
|
||||
if (len != sizeof(*c))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*c);
|
||||
if (val > FDT_MAX_NCELLS)
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
int fdt_address_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = fdt_cells(fdt, nodeoffset, "#address-cells");
|
||||
if (val == 0)
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
if (val == -FDT_ERR_NOTFOUND)
|
||||
return 2;
|
||||
|
||||
if (len != sizeof(*ac))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*ac);
|
||||
if ((val <= 0) || (val > FDT_MAX_NCELLS))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int fdt_size_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *sc;
|
||||
int val;
|
||||
int len;
|
||||
|
||||
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
|
||||
if (!sc)
|
||||
return 2;
|
||||
|
||||
if (len != sizeof(*sc))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*sc);
|
||||
if ((val < 0) || (val > FDT_MAX_NCELLS))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt_cells(fdt, nodeoffset, "#size-cells");
|
||||
if (val == -FDT_ERR_NOTFOUND)
|
||||
return 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* This function assumes that [address|size]_cells is 1 or 2 */
|
||||
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
|
||||
const char *name, uint64_t addr, uint64_t size)
|
||||
{
|
||||
int addr_cells, size_cells, ret;
|
||||
uint8_t data[sizeof(fdt64_t) * 2], *prop;
|
||||
|
||||
ret = fdt_address_cells(fdt, parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
addr_cells = ret;
|
||||
|
||||
ret = fdt_size_cells(fdt, parent);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
size_cells = ret;
|
||||
|
||||
/* check validity of address */
|
||||
prop = data;
|
||||
if (addr_cells == 1) {
|
||||
if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
fdt32_st(prop, (uint32_t)addr);
|
||||
} else if (addr_cells == 2) {
|
||||
fdt64_st(prop, addr);
|
||||
} else {
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
}
|
||||
|
||||
/* check validity of size */
|
||||
prop += addr_cells * sizeof(fdt32_t);
|
||||
if (size_cells == 1) {
|
||||
if (size > UINT32_MAX)
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
fdt32_st(prop, (uint32_t)size);
|
||||
} else if (size_cells == 2) {
|
||||
fdt64_st(prop, size);
|
||||
} else {
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
}
|
||||
|
||||
return fdt_appendprop(fdt, nodeoffset, name, data,
|
||||
(addr_cells + size_cells) * sizeof(fdt32_t));
|
||||
}
|
||||
|
@ -1,52 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2012 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
|
@ -1,53 +1,8 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2016 Free Electrons
|
||||
* Copyright (C) 2016 NextThing Co.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
@ -93,11 +48,11 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
|
||||
* @pathp: pointer which receives the path of the target (or NULL)
|
||||
*
|
||||
* overlay_get_target() retrieves the target offset in the base
|
||||
* device tree of a fragment, no matter how the actual targetting is
|
||||
* device tree of a fragment, no matter how the actual targeting is
|
||||
* done (through a phandle or a path)
|
||||
*
|
||||
* returns:
|
||||
* the targetted node offset in the base device tree
|
||||
* the targeted node offset in the base device tree
|
||||
* Negative error code on error
|
||||
*/
|
||||
static int overlay_get_target(const void *fdt, const void *fdto,
|
||||
@ -697,7 +652,7 @@ static int get_path_len(const void *fdt, int nodeoffset)
|
||||
int len = 0, namelen;
|
||||
const char *name;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
for (;;) {
|
||||
name = fdt_get_name(fdt, nodeoffset, &namelen);
|
||||
@ -778,26 +733,36 @@ static int overlay_symbol_update(void *fdt, void *fdto)
|
||||
/* keep end marker to avoid strlen() */
|
||||
e = path + path_len;
|
||||
|
||||
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||
|
||||
if (*path != '/')
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
/* get fragment name first */
|
||||
s = strchr(path + 1, '/');
|
||||
if (!s)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
if (!s) {
|
||||
/* Symbol refers to something that won't end
|
||||
* up in the target tree */
|
||||
continue;
|
||||
}
|
||||
|
||||
frag_name = path + 1;
|
||||
frag_name_len = s - path - 1;
|
||||
|
||||
/* verify format; safe since "s" lies in \0 terminated prop */
|
||||
len = sizeof("/__overlay__/") - 1;
|
||||
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
|
||||
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||
rel_path = s + len;
|
||||
rel_path_len = e - rel_path;
|
||||
rel_path_len = e - rel_path - 1;
|
||||
} else if ((e - s) == len
|
||||
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
|
||||
/* /<fragment-name>/__overlay__ */
|
||||
rel_path = "";
|
||||
rel_path_len = 0;
|
||||
} else {
|
||||
/* Symbol refers to something that won't end
|
||||
* up in the target tree */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find the fragment index in which the symbol lies */
|
||||
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
|
||||
@ -863,11 +828,15 @@ static int overlay_symbol_update(void *fdt, void *fdto)
|
||||
|
||||
int fdt_overlay_apply(void *fdt, void *fdto)
|
||||
{
|
||||
uint32_t delta = fdt_get_max_phandle(fdt);
|
||||
uint32_t delta;
|
||||
int ret;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_CHECK_HEADER(fdto);
|
||||
FDT_RO_PROBE(fdt);
|
||||
FDT_RO_PROBE(fdto);
|
||||
|
||||
ret = fdt_find_max_phandle(fdt, &delta);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = overlay_adjust_local_phandles(fdto, delta);
|
||||
if (ret)
|
||||
|
@ -1,52 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
@ -76,61 +31,170 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
|
||||
{
|
||||
int32_t totalsize;
|
||||
uint32_t absoffset;
|
||||
size_t len;
|
||||
int err;
|
||||
const char *s, *n;
|
||||
|
||||
if (can_assume(VALID_INPUT)) {
|
||||
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
|
||||
|
||||
if (lenp)
|
||||
*lenp = strlen(s);
|
||||
return s;
|
||||
}
|
||||
totalsize = fdt_ro_probe_(fdt);
|
||||
err = totalsize;
|
||||
if (totalsize < 0)
|
||||
goto fail;
|
||||
|
||||
err = -FDT_ERR_BADOFFSET;
|
||||
absoffset = stroffset + fdt_off_dt_strings(fdt);
|
||||
if (absoffset >= totalsize)
|
||||
goto fail;
|
||||
len = totalsize - absoffset;
|
||||
|
||||
if (fdt_magic(fdt) == FDT_MAGIC) {
|
||||
if (stroffset < 0)
|
||||
goto fail;
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||
if (stroffset >= fdt_size_dt_strings(fdt))
|
||||
goto fail;
|
||||
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
|
||||
len = fdt_size_dt_strings(fdt) - stroffset;
|
||||
}
|
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
|
||||
if ((stroffset >= 0)
|
||||
|| (stroffset < -fdt_size_dt_strings(fdt)))
|
||||
goto fail;
|
||||
if ((-stroffset) < len)
|
||||
len = -stroffset;
|
||||
} else {
|
||||
err = -FDT_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s = (const char *)fdt + absoffset;
|
||||
n = memchr(s, '\0', len);
|
||||
if (!n) {
|
||||
/* missing terminating NULL */
|
||||
err = -FDT_ERR_TRUNCATED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lenp)
|
||||
*lenp = n - s;
|
||||
return s;
|
||||
|
||||
fail:
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *fdt_string(const void *fdt, int stroffset)
|
||||
{
|
||||
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
|
||||
return fdt_get_string(fdt, stroffset, NULL);
|
||||
}
|
||||
|
||||
static int fdt_string_eq_(const void *fdt, int stroffset,
|
||||
const char *s, int len)
|
||||
{
|
||||
const char *p = fdt_string(fdt, stroffset);
|
||||
int slen;
|
||||
const char *p = fdt_get_string(fdt, stroffset, &slen);
|
||||
|
||||
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
|
||||
return p && (slen == len) && (memcmp(p, s, len) == 0);
|
||||
}
|
||||
|
||||
uint32_t fdt_get_max_phandle(const void *fdt)
|
||||
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
|
||||
{
|
||||
uint32_t max_phandle = 0;
|
||||
int offset;
|
||||
uint32_t max = 0;
|
||||
int offset = -1;
|
||||
|
||||
for (offset = fdt_next_node(fdt, -1, NULL);;
|
||||
offset = fdt_next_node(fdt, offset, NULL)) {
|
||||
uint32_t phandle;
|
||||
while (true) {
|
||||
uint32_t value;
|
||||
|
||||
offset = fdt_next_node(fdt, offset, NULL);
|
||||
if (offset < 0) {
|
||||
if (offset == -FDT_ERR_NOTFOUND)
|
||||
return max_phandle;
|
||||
break;
|
||||
|
||||
if (offset < 0)
|
||||
return (uint32_t)-1;
|
||||
|
||||
phandle = fdt_get_phandle(fdt, offset);
|
||||
if (phandle == (uint32_t)-1)
|
||||
continue;
|
||||
|
||||
if (phandle > max_phandle)
|
||||
max_phandle = phandle;
|
||||
return offset;
|
||||
}
|
||||
|
||||
value = fdt_get_phandle(fdt, offset);
|
||||
|
||||
if (value > max)
|
||||
max = value;
|
||||
}
|
||||
|
||||
if (phandle)
|
||||
*phandle = max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
|
||||
{
|
||||
uint32_t max;
|
||||
int err;
|
||||
|
||||
err = fdt_find_max_phandle(fdt, &max);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (max == FDT_MAX_PHANDLE)
|
||||
return -FDT_ERR_NOPHANDLES;
|
||||
|
||||
if (phandle)
|
||||
*phandle = max + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
|
||||
{
|
||||
int offset = n * sizeof(struct fdt_reserve_entry);
|
||||
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
|
||||
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
if (absoffset < fdt_off_mem_rsvmap(fdt))
|
||||
return NULL;
|
||||
if (absoffset > fdt_totalsize(fdt) -
|
||||
sizeof(struct fdt_reserve_entry))
|
||||
return NULL;
|
||||
}
|
||||
return fdt_mem_rsv_(fdt, n);
|
||||
}
|
||||
|
||||
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
|
||||
*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
|
||||
const struct fdt_reserve_entry *re;
|
||||
|
||||
FDT_RO_PROBE(fdt);
|
||||
re = fdt_mem_rsv(fdt, n);
|
||||
if (!can_assume(VALID_INPUT) && !re)
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
|
||||
*address = fdt64_ld(&re->address);
|
||||
*size = fdt64_ld(&re->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_num_mem_rsv(const void *fdt)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
const struct fdt_reserve_entry *re;
|
||||
|
||||
while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
|
||||
i++;
|
||||
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
|
||||
if (fdt64_ld(&re->size) == 0)
|
||||
return i;
|
||||
}
|
||||
return -FDT_ERR_TRUNCATED;
|
||||
}
|
||||
|
||||
static int nextprop_(const void *fdt, int offset)
|
||||
{
|
||||
@ -161,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
|
||||
{
|
||||
int depth;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
for (depth = 0;
|
||||
(offset >= 0) && (depth >= 0);
|
||||
@ -187,7 +251,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
|
||||
const char *p = path;
|
||||
int offset = 0;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* see if we have an alias */
|
||||
if (*path != '/') {
|
||||
@ -237,13 +301,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
||||
const char *nameptr;
|
||||
int err;
|
||||
|
||||
if (((err = fdt_check_header(fdt)) != 0)
|
||||
if (((err = fdt_ro_probe_(fdt)) < 0)
|
||||
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
|
||||
goto fail;
|
||||
|
||||
nameptr = nh->name;
|
||||
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
|
||||
/*
|
||||
* For old FDT versions, match the naming conventions of V16:
|
||||
* give only the leaf name (after all /). The actual tree
|
||||
@ -294,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
|
||||
int err;
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
|
||||
if (!can_assume(VALID_INPUT) &&
|
||||
(err = fdt_check_prop_offset_(fdt, offset)) < 0) {
|
||||
if (lenp)
|
||||
*lenp = err;
|
||||
return NULL;
|
||||
@ -303,7 +368,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
|
||||
prop = fdt_offset_ptr_(fdt, offset);
|
||||
|
||||
if (lenp)
|
||||
*lenp = fdt32_to_cpu(prop->len);
|
||||
*lenp = fdt32_ld(&prop->len);
|
||||
|
||||
return prop;
|
||||
}
|
||||
@ -315,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
|
||||
/* Prior to version 16, properties may need realignment
|
||||
* and this API does not work. fdt_getprop_*() will, however. */
|
||||
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVERSION;
|
||||
return NULL;
|
||||
@ -336,11 +401,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
|
||||
(offset = fdt_next_property_offset(fdt, offset))) {
|
||||
const struct fdt_property *prop;
|
||||
|
||||
if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
|
||||
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
|
||||
if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
|
||||
offset = -FDT_ERR_INTERNAL;
|
||||
break;
|
||||
}
|
||||
if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
|
||||
if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
|
||||
name, namelen)) {
|
||||
if (poffset)
|
||||
*poffset = offset;
|
||||
@ -361,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
|
||||
{
|
||||
/* Prior to version 16, properties may need realignment
|
||||
* and this API does not work. fdt_getprop_*() will, however. */
|
||||
if (fdt_version(fdt) < 0x10) {
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
|
||||
if (lenp)
|
||||
*lenp = -FDT_ERR_BADVERSION;
|
||||
return NULL;
|
||||
@ -392,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
return NULL;
|
||||
|
||||
/* Handle realignment */
|
||||
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
|
||||
fdt32_to_cpu(prop->len) >= 8)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
||||
(poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
|
||||
return prop->data + 4;
|
||||
return prop->data;
|
||||
}
|
||||
@ -406,12 +472,27 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
|
||||
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
if (namep)
|
||||
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
|
||||
if (namep) {
|
||||
const char *name;
|
||||
int namelen;
|
||||
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
|
||||
&namelen);
|
||||
if (!name) {
|
||||
if (lenp)
|
||||
*lenp = namelen;
|
||||
return NULL;
|
||||
}
|
||||
*namep = name;
|
||||
} else {
|
||||
*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle realignment */
|
||||
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
|
||||
fdt32_to_cpu(prop->len) >= 8)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
|
||||
(offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
|
||||
return prop->data + 4;
|
||||
return prop->data;
|
||||
}
|
||||
@ -436,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fdt32_to_cpu(*php);
|
||||
return fdt32_ld(php);
|
||||
}
|
||||
|
||||
const char *fdt_get_alias_namelen(const void *fdt,
|
||||
@ -462,7 +543,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
|
||||
int offset, depth, namelen;
|
||||
const char *name;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (buflen < 2)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
@ -514,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||
int offset, depth;
|
||||
int supernodeoffset = -FDT_ERR_INTERNAL;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (supernodedepth < 0)
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
@ -536,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
else if (offset == -FDT_ERR_BADOFFSET)
|
||||
return -FDT_ERR_BADSTRUCTURE;
|
||||
}
|
||||
|
||||
return offset; /* error from fdt_next_node() */
|
||||
}
|
||||
@ -551,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
|
||||
|
||||
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
|
||||
if (err)
|
||||
return (err < 0) ? err : -FDT_ERR_INTERNAL;
|
||||
return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
|
||||
-FDT_ERR_INTERNAL;
|
||||
return nodedepth;
|
||||
}
|
||||
|
||||
@ -573,7 +657,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
|
||||
const void *val;
|
||||
int len;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||
* property of a node in fdt_getprop(), then if that didn't
|
||||
@ -599,7 +683,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
|
||||
if ((phandle == 0) || (phandle == -1))
|
||||
return -FDT_ERR_BADPHANDLE;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we
|
||||
* potentially scan each property of a node in
|
||||
@ -752,7 +836,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
|
||||
{
|
||||
int offset, err;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
/* FIXME: The algorithm here is pretty horrible: we scan each
|
||||
* property of a node in fdt_node_check_compatible(), then if
|
||||
|
@ -1,52 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
@ -67,29 +22,31 @@ static int fdt_blocks_misordered_(const void *fdt,
|
||||
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
|
||||
}
|
||||
|
||||
static int fdt_rw_check_header_(void *fdt)
|
||||
static int fdt_rw_probe_(void *fdt)
|
||||
{
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
if (can_assume(VALID_DTB))
|
||||
return 0;
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
if (fdt_version(fdt) < 17)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) < 17)
|
||||
return -FDT_ERR_BADVERSION;
|
||||
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
|
||||
fdt_size_dt_struct(fdt)))
|
||||
return -FDT_ERR_BADLAYOUT;
|
||||
if (fdt_version(fdt) > 17)
|
||||
if (!can_assume(LATEST) && fdt_version(fdt) > 17)
|
||||
fdt_set_version(fdt, 17);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_RW_CHECK_HEADER(fdt) \
|
||||
#define FDT_RW_PROBE(fdt) \
|
||||
{ \
|
||||
int err_; \
|
||||
if ((err_ = fdt_rw_check_header_(fdt)) != 0) \
|
||||
if ((err_ = fdt_rw_probe_(fdt)) != 0) \
|
||||
return err_; \
|
||||
}
|
||||
|
||||
static inline int fdt_data_size_(void *fdt)
|
||||
static inline unsigned int fdt_data_size_(void *fdt)
|
||||
{
|
||||
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
|
||||
}
|
||||
@ -97,15 +54,16 @@ static inline int fdt_data_size_(void *fdt)
|
||||
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
|
||||
{
|
||||
char *p = splicepoint;
|
||||
char *end = (char *)fdt + fdt_data_size_(fdt);
|
||||
unsigned int dsize = fdt_data_size_(fdt);
|
||||
size_t soff = p - (char *)fdt;
|
||||
|
||||
if (((p + oldlen) < p) || ((p + oldlen) > end))
|
||||
if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
|
||||
if ((p < (char *)fdt) || (dsize + newlen < oldlen))
|
||||
return -FDT_ERR_BADOFFSET;
|
||||
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
|
||||
if (dsize - oldlen + newlen > fdt_totalsize(fdt))
|
||||
return -FDT_ERR_NOSPACE;
|
||||
memmove(p + newlen, p + oldlen, end - p - oldlen);
|
||||
memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -136,6 +94,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must only be used to roll back in case of error */
|
||||
static void fdt_del_last_string_(void *fdt, const char *s)
|
||||
{
|
||||
int newlen = strlen(s) + 1;
|
||||
|
||||
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
|
||||
}
|
||||
|
||||
static int fdt_splice_string_(void *fdt, int newlen)
|
||||
{
|
||||
void *p = (char *)fdt
|
||||
@ -149,7 +115,16 @@ static int fdt_splice_string_(void *fdt, int newlen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_find_add_string_(void *fdt, const char *s)
|
||||
/**
|
||||
* fdt_find_add_string_() - Find or allocate a string
|
||||
*
|
||||
* @fdt: pointer to the device tree to check/adjust
|
||||
* @s: string to find/add
|
||||
* @allocated: Set to 0 if the string was found, 1 if not found and so
|
||||
* allocated. Ignored if can_assume(NO_ROLLBACK)
|
||||
* @return offset of string in the string table (whether found or added)
|
||||
*/
|
||||
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
|
||||
const char *p;
|
||||
@ -157,6 +132,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
|
||||
int len = strlen(s) + 1;
|
||||
int err;
|
||||
|
||||
if (!can_assume(NO_ROLLBACK))
|
||||
*allocated = 0;
|
||||
|
||||
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
|
||||
if (p)
|
||||
/* found it */
|
||||
@ -167,6 +145,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!can_assume(NO_ROLLBACK))
|
||||
*allocated = 1;
|
||||
|
||||
memcpy(new, s, len);
|
||||
return (new - strtab);
|
||||
}
|
||||
@ -176,7 +157,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
|
||||
struct fdt_reserve_entry *re;
|
||||
int err;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
|
||||
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
|
||||
@ -192,7 +173,7 @@ int fdt_del_mem_rsv(void *fdt, int n)
|
||||
{
|
||||
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
if (n >= fdt_num_mem_rsv(fdt))
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
@ -225,11 +206,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
|
||||
int nextoffset;
|
||||
int namestroff;
|
||||
int err;
|
||||
int allocated;
|
||||
|
||||
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
|
||||
return nextoffset;
|
||||
|
||||
namestroff = fdt_find_add_string_(fdt, name);
|
||||
namestroff = fdt_find_add_string_(fdt, name, &allocated);
|
||||
if (namestroff < 0)
|
||||
return namestroff;
|
||||
|
||||
@ -237,8 +219,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
|
||||
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
|
||||
|
||||
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
|
||||
if (err)
|
||||
if (err) {
|
||||
/* Delete the string if we failed to add it */
|
||||
if (!can_assume(NO_ROLLBACK) && allocated)
|
||||
fdt_del_last_string_(fdt, name);
|
||||
return err;
|
||||
}
|
||||
|
||||
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
|
||||
(*prop)->nameoff = cpu_to_fdt32(namestroff);
|
||||
@ -252,7 +238,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
|
||||
int oldlen, newlen;
|
||||
int err;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
|
||||
if (!namep)
|
||||
@ -275,7 +261,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||
struct fdt_property *prop;
|
||||
int err;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
|
||||
if (err == -FDT_ERR_NOTFOUND)
|
||||
@ -308,7 +294,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
|
||||
struct fdt_property *prop;
|
||||
int err, oldlen, newlen;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (prop) {
|
||||
@ -334,7 +320,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||||
struct fdt_property *prop;
|
||||
int len, proplen;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (!prop)
|
||||
@ -354,7 +340,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
|
||||
uint32_t tag;
|
||||
fdt32_t *endtag;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
|
||||
if (offset >= 0)
|
||||
@ -394,7 +380,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
|
||||
{
|
||||
int endoffset;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
|
||||
if (endoffset < 0)
|
||||
@ -407,7 +393,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
|
||||
static void fdt_packblocks_(const char *old, char *new,
|
||||
int mem_rsv_size, int struct_size)
|
||||
{
|
||||
uint32_t mem_rsv_off, struct_off, strings_off;
|
||||
int mem_rsv_off, struct_off, strings_off;
|
||||
|
||||
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
|
||||
struct_off = mem_rsv_off + mem_rsv_size;
|
||||
@ -435,12 +421,12 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
const char *fdtend = fdtstart + fdt_totalsize(fdt);
|
||||
char *tmp;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_RO_PROBE(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
|
||||
if (fdt_version(fdt) >= 17) {
|
||||
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
|
||||
struct_size = fdt_size_dt_struct(fdt);
|
||||
} else {
|
||||
struct_size = 0;
|
||||
@ -450,7 +436,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
|
||||
return struct_size;
|
||||
}
|
||||
|
||||
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
|
||||
if (can_assume(LIBFDT_ORDER) ||
|
||||
!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
|
||||
/* no further work necessary */
|
||||
err = fdt_move(fdt, buf, bufsize);
|
||||
if (err)
|
||||
@ -494,7 +481,7 @@ int fdt_pack(void *fdt)
|
||||
{
|
||||
int mem_rsv_size;
|
||||
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
FDT_RW_PROBE(fdt);
|
||||
|
||||
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
|
||||
* sizeof(struct fdt_reserve_entry);
|
||||
|
@ -1,51 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
|
||||
FDT_ERRTABENT(FDT_ERR_BADVALUE),
|
||||
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
|
||||
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
|
||||
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
|
||||
};
|
||||
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
|
||||
|
||||
|
@ -1,52 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
@ -55,21 +10,87 @@
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
static int fdt_sw_check_header_(void *fdt)
|
||||
static int fdt_sw_probe_(void *fdt)
|
||||
{
|
||||
if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||
if (!can_assume(VALID_INPUT)) {
|
||||
if (fdt_magic(fdt) == FDT_MAGIC)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
|
||||
return -FDT_ERR_BADMAGIC;
|
||||
/* FIXME: should check more details about the header state */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_CHECK_HEADER(fdt) \
|
||||
#define FDT_SW_PROBE(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = fdt_sw_check_header_(fdt)) != 0) \
|
||||
if ((err = fdt_sw_probe_(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
/* 'memrsv' state: Initial state after fdt_create()
|
||||
*
|
||||
* Allowed functions:
|
||||
* fdt_add_reservemap_entry()
|
||||
* fdt_finish_reservemap() [moves to 'struct' state]
|
||||
*/
|
||||
static int fdt_sw_probe_memrsv_(void *fdt)
|
||||
{
|
||||
int err = fdt_sw_probe_(fdt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
|
||||
return -FDT_ERR_BADSTATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_PROBE_MEMRSV(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
/* 'struct' state: Enter this state after fdt_finish_reservemap()
|
||||
*
|
||||
* Allowed functions:
|
||||
* fdt_begin_node()
|
||||
* fdt_end_node()
|
||||
* fdt_property*()
|
||||
* fdt_finish() [moves to 'complete' state]
|
||||
*/
|
||||
static int fdt_sw_probe_struct_(void *fdt)
|
||||
{
|
||||
int err = fdt_sw_probe_(fdt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!can_assume(VALID_INPUT) &&
|
||||
fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
|
||||
return -FDT_ERR_BADSTATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FDT_SW_PROBE_STRUCT(fdt) \
|
||||
{ \
|
||||
int err; \
|
||||
if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
|
||||
return err; \
|
||||
}
|
||||
|
||||
static inline uint32_t sw_flags(void *fdt)
|
||||
{
|
||||
/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
|
||||
return fdt_last_comp_version(fdt);
|
||||
}
|
||||
|
||||
/* 'complete' state: Enter this state after fdt_finish()
|
||||
*
|
||||
* Allowed functions: none
|
||||
*/
|
||||
|
||||
static void *fdt_grab_space_(void *fdt, size_t len)
|
||||
{
|
||||
int offset = fdt_size_dt_struct(fdt);
|
||||
@ -85,38 +106,59 @@ static void *fdt_grab_space_(void *fdt, size_t len)
|
||||
return fdt_offset_ptr_w_(fdt, offset);
|
||||
}
|
||||
|
||||
int fdt_create(void *buf, int bufsize)
|
||||
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
|
||||
{
|
||||
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
|
||||
sizeof(struct fdt_reserve_entry));
|
||||
void *fdt = buf;
|
||||
|
||||
if (bufsize < sizeof(struct fdt_header))
|
||||
if (bufsize < hdrsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
if (flags & ~FDT_CREATE_FLAGS_ALL)
|
||||
return -FDT_ERR_BADFLAGS;
|
||||
|
||||
memset(buf, 0, bufsize);
|
||||
|
||||
/*
|
||||
* magic and last_comp_version keep intermediate state during the fdt
|
||||
* creation process, which is replaced with the proper FDT format by
|
||||
* fdt_finish().
|
||||
*
|
||||
* flags should be accessed with sw_flags().
|
||||
*/
|
||||
fdt_set_magic(fdt, FDT_SW_MAGIC);
|
||||
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
|
||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
|
||||
fdt_set_last_comp_version(fdt, flags);
|
||||
|
||||
fdt_set_totalsize(fdt, bufsize);
|
||||
|
||||
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
|
||||
sizeof(struct fdt_reserve_entry)));
|
||||
fdt_set_off_mem_rsvmap(fdt, hdrsize);
|
||||
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
|
||||
fdt_set_off_dt_strings(fdt, bufsize);
|
||||
fdt_set_off_dt_strings(fdt, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_create(void *buf, int bufsize)
|
||||
{
|
||||
return fdt_create_with_flags(buf, bufsize, 0);
|
||||
}
|
||||
|
||||
int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||
{
|
||||
size_t headsize, tailsize;
|
||||
char *oldtail, *newtail;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
FDT_SW_PROBE(fdt);
|
||||
|
||||
headsize = fdt_off_dt_struct(fdt);
|
||||
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
tailsize = fdt_size_dt_strings(fdt);
|
||||
|
||||
if (!can_assume(VALID_DTB) &&
|
||||
headsize + tailsize > fdt_totalsize(fdt))
|
||||
return -FDT_ERR_INTERNAL;
|
||||
|
||||
if ((headsize + tailsize) > bufsize)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
@ -133,8 +175,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
|
||||
memmove(buf, fdt, headsize);
|
||||
}
|
||||
|
||||
fdt_set_off_dt_strings(buf, bufsize);
|
||||
fdt_set_totalsize(buf, bufsize);
|
||||
if (fdt_off_dt_strings(buf))
|
||||
fdt_set_off_dt_strings(buf, bufsize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -144,10 +187,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
|
||||
struct fdt_reserve_entry *re;
|
||||
int offset;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
|
||||
if (fdt_size_dt_struct(fdt))
|
||||
return -FDT_ERR_BADSTATE;
|
||||
FDT_SW_PROBE_MEMRSV(fdt);
|
||||
|
||||
offset = fdt_off_dt_struct(fdt);
|
||||
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
|
||||
@ -164,16 +204,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
|
||||
|
||||
int fdt_finish_reservemap(void *fdt)
|
||||
{
|
||||
return fdt_add_reservemap_entry(fdt, 0, 0);
|
||||
int err = fdt_add_reservemap_entry(fdt, 0, 0);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_begin_node(void *fdt, const char *name)
|
||||
{
|
||||
struct fdt_node_header *nh;
|
||||
int namelen = strlen(name) + 1;
|
||||
int namelen;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
namelen = strlen(name) + 1;
|
||||
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
|
||||
if (! nh)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
@ -187,7 +234,7 @@ int fdt_end_node(void *fdt)
|
||||
{
|
||||
fdt32_t *en;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
en = fdt_grab_space_(fdt, FDT_TAGSIZE);
|
||||
if (! en)
|
||||
@ -197,19 +244,13 @@ int fdt_end_node(void *fdt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fdt_find_add_string_(void *fdt, const char *s)
|
||||
static int fdt_add_string_(void *fdt, const char *s)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||
const char *p;
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
int len = strlen(s) + 1;
|
||||
int struct_top, offset;
|
||||
|
||||
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
|
||||
if (p)
|
||||
return p - strtab;
|
||||
|
||||
/* Add it */
|
||||
offset = -strtabsize - len;
|
||||
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
|
||||
if (fdt_totalsize(fdt) + offset < struct_top)
|
||||
@ -220,20 +261,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Must only be used to roll back in case of error */
|
||||
static void fdt_del_last_string_(void *fdt, const char *s)
|
||||
{
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
int len = strlen(s) + 1;
|
||||
|
||||
fdt_set_size_dt_strings(fdt, strtabsize - len);
|
||||
}
|
||||
|
||||
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
|
||||
{
|
||||
char *strtab = (char *)fdt + fdt_totalsize(fdt);
|
||||
int strtabsize = fdt_size_dt_strings(fdt);
|
||||
const char *p;
|
||||
|
||||
*allocated = 0;
|
||||
|
||||
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
|
||||
if (p)
|
||||
return p - strtab;
|
||||
|
||||
*allocated = 1;
|
||||
|
||||
return fdt_add_string_(fdt, s);
|
||||
}
|
||||
|
||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int nameoff;
|
||||
int allocated;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
nameoff = fdt_find_add_string_(fdt, name);
|
||||
/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
|
||||
if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
|
||||
allocated = 1;
|
||||
nameoff = fdt_add_string_(fdt, name);
|
||||
} else {
|
||||
nameoff = fdt_find_add_string_(fdt, name, &allocated);
|
||||
}
|
||||
if (nameoff == 0)
|
||||
return -FDT_ERR_NOSPACE;
|
||||
|
||||
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
|
||||
if (! prop)
|
||||
if (! prop) {
|
||||
if (allocated)
|
||||
fdt_del_last_string_(fdt, name);
|
||||
return -FDT_ERR_NOSPACE;
|
||||
}
|
||||
|
||||
prop->tag = cpu_to_fdt32(FDT_PROP);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
@ -262,7 +339,7 @@ int fdt_finish(void *fdt)
|
||||
uint32_t tag;
|
||||
int offset, nextoffset;
|
||||
|
||||
FDT_SW_CHECK_HEADER(fdt);
|
||||
FDT_SW_PROBE_STRUCT(fdt);
|
||||
|
||||
/* Add terminator */
|
||||
end = fdt_grab_space_(fdt, sizeof(*end));
|
||||
@ -295,6 +372,10 @@ int fdt_finish(void *fdt)
|
||||
|
||||
/* Finally, adjust the header */
|
||||
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
|
||||
|
||||
/* And fix up fields that were keeping intermediate state. */
|
||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
|
||||
fdt_set_magic(fdt, FDT_MAGIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,52 +1,7 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
|
@ -1,59 +1,18 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef LIBFDT_H
|
||||
#define LIBFDT_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "libfdt_env.h"
|
||||
#include "fdt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FDT_FIRST_SUPPORTED_VERSION 0x02
|
||||
#define FDT_LAST_SUPPORTED_VERSION 0x11
|
||||
|
||||
@ -90,8 +49,9 @@
|
||||
|
||||
/* Error codes: codes for bad device tree blobs */
|
||||
#define FDT_ERR_TRUNCATED 8
|
||||
/* FDT_ERR_TRUNCATED: Structure block of the given device tree
|
||||
* ends without an FDT_END tag. */
|
||||
/* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
|
||||
* terminated (overflows, goes outside allowed bounds, or
|
||||
* isn't properly terminated). */
|
||||
#define FDT_ERR_BADMAGIC 9
|
||||
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
|
||||
* device tree at all - it is missing the flattened device
|
||||
@ -137,7 +97,15 @@
|
||||
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
|
||||
* phandle available anymore without causing an overflow */
|
||||
|
||||
#define FDT_ERR_MAX 17
|
||||
#define FDT_ERR_BADFLAGS 18
|
||||
/* FDT_ERR_BADFLAGS: The function was passed a flags field that
|
||||
* contains invalid flags or an invalid combination of flags. */
|
||||
|
||||
#define FDT_ERR_MAX 18
|
||||
|
||||
/* constants */
|
||||
#define FDT_MAX_PHANDLE 0xfffffffe
|
||||
/* Valid values for phandles range from 1 to 2^32-2. */
|
||||
|
||||
/**********************************************************************/
|
||||
/* Low-level functions (you probably don't need these) */
|
||||
@ -153,6 +121,61 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
||||
|
||||
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
|
||||
|
||||
/*
|
||||
* Alignment helpers:
|
||||
* These helpers access words from a device tree blob. They're
|
||||
* built to work even with unaligned pointers on platforms (ike
|
||||
* ARM) that don't like unaligned loads and stores
|
||||
*/
|
||||
|
||||
static inline uint32_t fdt32_ld(const fdt32_t *p)
|
||||
{
|
||||
const uint8_t *bp = (const uint8_t *)p;
|
||||
|
||||
return ((uint32_t)bp[0] << 24)
|
||||
| ((uint32_t)bp[1] << 16)
|
||||
| ((uint32_t)bp[2] << 8)
|
||||
| bp[3];
|
||||
}
|
||||
|
||||
static inline void fdt32_st(void *property, uint32_t value)
|
||||
{
|
||||
uint8_t *bp = (uint8_t *)property;
|
||||
|
||||
bp[0] = value >> 24;
|
||||
bp[1] = (value >> 16) & 0xff;
|
||||
bp[2] = (value >> 8) & 0xff;
|
||||
bp[3] = value & 0xff;
|
||||
}
|
||||
|
||||
static inline uint64_t fdt64_ld(const fdt64_t *p)
|
||||
{
|
||||
const uint8_t *bp = (const uint8_t *)p;
|
||||
|
||||
return ((uint64_t)bp[0] << 56)
|
||||
| ((uint64_t)bp[1] << 48)
|
||||
| ((uint64_t)bp[2] << 40)
|
||||
| ((uint64_t)bp[3] << 32)
|
||||
| ((uint64_t)bp[4] << 24)
|
||||
| ((uint64_t)bp[5] << 16)
|
||||
| ((uint64_t)bp[6] << 8)
|
||||
| bp[7];
|
||||
}
|
||||
|
||||
static inline void fdt64_st(void *property, uint64_t value)
|
||||
{
|
||||
uint8_t *bp = (uint8_t *)property;
|
||||
|
||||
bp[0] = value >> 56;
|
||||
bp[1] = (value >> 48) & 0xff;
|
||||
bp[2] = (value >> 40) & 0xff;
|
||||
bp[3] = (value >> 32) & 0xff;
|
||||
bp[4] = (value >> 24) & 0xff;
|
||||
bp[5] = (value >> 16) & 0xff;
|
||||
bp[6] = (value >> 8) & 0xff;
|
||||
bp[7] = value & 0xff;
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/* Traversal functions */
|
||||
/**********************************************************************/
|
||||
@ -195,7 +218,7 @@ int fdt_next_subnode(const void *fdt, int offset);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
|
||||
* if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
|
||||
* Error handling
|
||||
* }
|
||||
*
|
||||
@ -213,7 +236,7 @@ int fdt_next_subnode(const void *fdt, int offset);
|
||||
/* General functions */
|
||||
/**********************************************************************/
|
||||
#define fdt_get_header(fdt, field) \
|
||||
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
|
||||
(fdt32_ld(&((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))
|
||||
@ -244,18 +267,32 @@ fdt_set_hdr_(size_dt_struct);
|
||||
#undef fdt_set_hdr_
|
||||
|
||||
/**
|
||||
* fdt_check_header - sanity check a device tree or possible device tree
|
||||
* fdt_header_size - return the size of the tree's header
|
||||
* @fdt: pointer to a flattened device tree
|
||||
*/
|
||||
size_t fdt_header_size(const void *fdt);
|
||||
|
||||
/**
|
||||
* fdt_header_size_ - internal function which takes a version number
|
||||
*/
|
||||
size_t fdt_header_size_(uint32_t version);
|
||||
|
||||
/**
|
||||
* fdt_check_header - sanity check a device tree header
|
||||
|
||||
* @fdt: pointer to data which might be a flattened device tree
|
||||
*
|
||||
* fdt_check_header() checks that the given buffer contains what
|
||||
* appears to be a flattened device tree with sane information in its
|
||||
* header.
|
||||
* appears to be a flattened device tree, and that the header contains
|
||||
* valid information (to the extent that can be determined from the
|
||||
* header alone).
|
||||
*
|
||||
* returns:
|
||||
* 0, if the buffer appears to contain a valid device tree
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE, standard meanings, as above
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings, as above
|
||||
*/
|
||||
int fdt_check_header(const void *fdt);
|
||||
|
||||
@ -284,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
|
||||
/* Read-only functions */
|
||||
/**********************************************************************/
|
||||
|
||||
int fdt_check_full(const void *fdt, size_t bufsize);
|
||||
|
||||
/**
|
||||
* fdt_get_string - retrieve a string from the strings block of a device tree
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @stroffset: offset of the string within the strings block (native endian)
|
||||
* @lenp: optional pointer to return the string's length
|
||||
*
|
||||
* fdt_get_string() retrieves a pointer to a single string from the
|
||||
* strings block of the device tree blob at fdt, and optionally also
|
||||
* returns the string's length in *lenp.
|
||||
*
|
||||
* returns:
|
||||
* a pointer to the string, on success
|
||||
* NULL, if stroffset is out of bounds, or doesn't point to a valid string
|
||||
*/
|
||||
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
|
||||
|
||||
/**
|
||||
* fdt_string - retrieve a string from the strings block of a device tree
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -294,10 +349,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
|
||||
*
|
||||
* returns:
|
||||
* a pointer to the string, on success
|
||||
* NULL, if stroffset is out of bounds
|
||||
* NULL, if stroffset is out of bounds, or doesn't point to a valid string
|
||||
*/
|
||||
const char *fdt_string(const void *fdt, int stroffset);
|
||||
|
||||
/**
|
||||
* fdt_find_max_phandle - find and return the highest phandle in a tree
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @phandle: return location for the highest phandle value found in the tree
|
||||
*
|
||||
* fdt_find_max_phandle() finds the highest phandle value in the given device
|
||||
* tree. The value returned in @phandle is only valid if the function returns
|
||||
* success.
|
||||
*
|
||||
* returns:
|
||||
* 0 on success or a negative error code on failure
|
||||
*/
|
||||
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
|
||||
|
||||
/**
|
||||
* fdt_get_max_phandle - retrieves the highest phandle in a tree
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -306,12 +375,39 @@ const char *fdt_string(const void *fdt, int stroffset);
|
||||
* device tree. This will ignore badly formatted phandles, or phandles
|
||||
* with a value of 0 or -1.
|
||||
*
|
||||
* This function is deprecated in favour of fdt_find_max_phandle().
|
||||
*
|
||||
* returns:
|
||||
* the highest phandle on success
|
||||
* 0, if no phandle was found in the device tree
|
||||
* -1, if an error occurred
|
||||
*/
|
||||
uint32_t fdt_get_max_phandle(const void *fdt);
|
||||
static inline uint32_t fdt_get_max_phandle(const void *fdt)
|
||||
{
|
||||
uint32_t phandle;
|
||||
int err;
|
||||
|
||||
err = fdt_find_max_phandle(fdt, &phandle);
|
||||
if (err < 0)
|
||||
return (uint32_t)-1;
|
||||
|
||||
return phandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_generate_phandle - return a new, unused phandle for a device tree blob
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @phandle: return location for the new phandle
|
||||
*
|
||||
* Walks the device tree blob and looks for the highest phandle value. On
|
||||
* success, the new, unused phandle value (one higher than the previously
|
||||
* highest phandle value in the device tree blob) will be returned in the
|
||||
* @phandle parameter.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success or a negative error-code on failure
|
||||
*/
|
||||
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
|
||||
|
||||
/**
|
||||
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
|
||||
@ -503,7 +599,7 @@ int fdt_next_property_offset(const void *fdt, int offset);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
|
||||
* if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
|
||||
* Error handling
|
||||
* }
|
||||
*
|
||||
@ -606,7 +702,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
|
||||
/**
|
||||
* fdt_getprop_by_offset - retrieve the value of a property at a given offset
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @ffset: offset of the property to read
|
||||
* @offset: offset of the property to read
|
||||
* @namep: pointer to a string variable (will be overwritten) or NULL
|
||||
* @lenp: pointer to an integer variable (will be overwritten) or NULL
|
||||
*
|
||||
@ -1090,7 +1186,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
|
||||
*
|
||||
* returns:
|
||||
* 0 <= n < FDT_MAX_NCELLS, on success
|
||||
* 2, if the node has no #address-cells property
|
||||
* 1, if the node has no #size-cells property
|
||||
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
|
||||
* #size-cells property
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
@ -1297,7 +1393,45 @@ int fdt_nop_node(void *fdt, int nodeoffset);
|
||||
/* Sequential write functions */
|
||||
/**********************************************************************/
|
||||
|
||||
/* fdt_create_with_flags flags */
|
||||
#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
|
||||
/* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
|
||||
* names in the fdt. This can result in faster creation times, but
|
||||
* a larger fdt. */
|
||||
|
||||
#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP)
|
||||
|
||||
/**
|
||||
* fdt_create_with_flags - begin creation of a new fdt
|
||||
* @fdt: pointer to memory allocated where fdt will be created
|
||||
* @bufsize: size of the memory space at fdt
|
||||
* @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
|
||||
*
|
||||
* fdt_create_with_flags() begins the process of creating a new fdt with
|
||||
* the sequential write interface.
|
||||
*
|
||||
* fdt creation process must end with fdt_finished() to produce a valid fdt.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
|
||||
* -FDT_ERR_BADFLAGS, flags is not valid
|
||||
*/
|
||||
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
|
||||
|
||||
/**
|
||||
* fdt_create - begin creation of a new fdt
|
||||
* @fdt: pointer to memory allocated where fdt will be created
|
||||
* @bufsize: size of the memory space at fdt
|
||||
*
|
||||
* fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
|
||||
*/
|
||||
int fdt_create(void *buf, int bufsize);
|
||||
|
||||
int fdt_resize(void *fdt, void *buf, int bufsize);
|
||||
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
|
||||
int fdt_finish_reservemap(void *fdt);
|
||||
@ -1313,10 +1447,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
|
||||
fdt64_t tmp = cpu_to_fdt64(val);
|
||||
return fdt_property(fdt, name, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
#ifndef SWIG /* Not available in Python */
|
||||
static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
|
||||
{
|
||||
return fdt_property_u32(fdt, name, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* fdt_property_placeholder - add a new property and return a ptr to its value
|
||||
@ -1765,6 +1902,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
|
||||
#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
|
||||
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
|
||||
|
||||
/**
|
||||
* fdt_appendprop_addrrange - append a address range property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @parent: offset of the parent node
|
||||
* @nodeoffset: offset of the node to add a property at
|
||||
* @name: name of property
|
||||
* @addr: start address of a given range
|
||||
* @size: size of a given range
|
||||
*
|
||||
* fdt_appendprop_addrrange() appends an address range value (start
|
||||
* address and size) to the value of the named property in the given
|
||||
* node, or creates a new property with that value if it does not
|
||||
* already exist.
|
||||
* If "name" is not specified, a default "reg" is used.
|
||||
* Cell sizes are determined by parent's #address-cells and #size-cells.
|
||||
*
|
||||
* This function may insert data into the blob, and will therefore
|
||||
* change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
|
||||
* #address-cells property
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain a new property
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
|
||||
const char *name, uint64_t addr, uint64_t size);
|
||||
|
||||
/**
|
||||
* fdt_delprop - delete a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
@ -1899,4 +2073,8 @@ int fdt_overlay_apply(void *fdt, void *fdto);
|
||||
|
||||
const char *fdt_strerror(int errval);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBFDT_H */
|
||||
|
@ -1,61 +1,18 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef LIBFDT_ENV_H
|
||||
#define LIBFDT_ENV_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __CHECKER__
|
||||
#define FDT_FORCE __attribute__((force))
|
||||
|
@ -1,65 +1,21 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
|
||||
#ifndef LIBFDT_INTERNAL_H
|
||||
#define LIBFDT_INTERNAL_H
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2006 David Gibson, IBM Corporation.
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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 library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <fdt.h>
|
||||
|
||||
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
||||
|
||||
#define FDT_CHECK_HEADER(fdt) \
|
||||
int32_t fdt_ro_probe_(const void *fdt);
|
||||
#define FDT_RO_PROBE(fdt) \
|
||||
{ \
|
||||
int err_; \
|
||||
if ((err_ = fdt_check_header(fdt)) != 0) \
|
||||
return err_; \
|
||||
int32_t totalsize_; \
|
||||
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
|
||||
return totalsize_; \
|
||||
}
|
||||
|
||||
int fdt_check_node_offset_(const void *fdt, int offset);
|
||||
@ -92,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
|
||||
|
||||
#define FDT_SW_MAGIC (~FDT_MAGIC)
|
||||
|
||||
/**********************************************************************/
|
||||
/* Checking controls */
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef FDT_ASSUME_MASK
|
||||
#define FDT_ASSUME_MASK 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Defines assumptions which can be enabled. Each of these can be enabled
|
||||
* individually. For maximum safety, don't enable any assumptions!
|
||||
*
|
||||
* For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
|
||||
* You should have another method of validating the device tree, such as a
|
||||
* signature or hash check before using libfdt.
|
||||
*
|
||||
* For situations where security is not a concern it may be safe to enable
|
||||
* ASSUME_SANE.
|
||||
*/
|
||||
enum {
|
||||
/*
|
||||
* This does essentially no checks. Only the latest device-tree
|
||||
* version is correctly handled. Inconsistencies or errors in the device
|
||||
* tree may cause undefined behaviour or crashes. Invalid parameters
|
||||
* passed to libfdt may do the same.
|
||||
*
|
||||
* If an error occurs when modifying the tree it may leave the tree in
|
||||
* an intermediate (but valid) state. As an example, adding a property
|
||||
* where there is insufficient space may result in the property name
|
||||
* being added to the string table even though the property itself is
|
||||
* not added to the struct section.
|
||||
*
|
||||
* Only use this if you have a fully validated device tree with
|
||||
* the latest supported version and wish to minimise code size.
|
||||
*/
|
||||
ASSUME_PERFECT = 0xff,
|
||||
|
||||
/*
|
||||
* This assumes that the device tree is sane. i.e. header metadata
|
||||
* and basic hierarchy are correct.
|
||||
*
|
||||
* With this assumption enabled, normal device trees produced by libfdt
|
||||
* and the compiler should be handled safely. Malicious device trees and
|
||||
* complete garbage may cause libfdt to behave badly or crash. Truncated
|
||||
* device trees (e.g. those only partially loaded) can also cause
|
||||
* problems.
|
||||
*
|
||||
* Note: Only checks that relate exclusively to the device tree itself
|
||||
* (not the parameters passed to libfdt) are disabled by this
|
||||
* assumption. This includes checking headers, tags and the like.
|
||||
*/
|
||||
ASSUME_VALID_DTB = 1 << 0,
|
||||
|
||||
/*
|
||||
* This builds on ASSUME_VALID_DTB and further assumes that libfdt
|
||||
* functions are called with valid parameters, i.e. not trigger
|
||||
* FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
|
||||
* extensive checking of parameters and the device tree, making various
|
||||
* assumptions about correctness.
|
||||
*
|
||||
* It doesn't make sense to enable this assumption unless
|
||||
* ASSUME_VALID_DTB is also enabled.
|
||||
*/
|
||||
ASSUME_VALID_INPUT = 1 << 1,
|
||||
|
||||
/*
|
||||
* This disables checks for device-tree version and removes all code
|
||||
* which handles older versions.
|
||||
*
|
||||
* Only enable this if you know you have a device tree with the latest
|
||||
* version.
|
||||
*/
|
||||
ASSUME_LATEST = 1 << 2,
|
||||
|
||||
/*
|
||||
* This assumes that it is OK for a failed addition to the device tree,
|
||||
* due to lack of space or some other problem, to skip any rollback
|
||||
* steps (such as dropping the property name from the string table).
|
||||
* This is safe to enable in most circumstances, even though it may
|
||||
* leave the tree in a sub-optimal state.
|
||||
*/
|
||||
ASSUME_NO_ROLLBACK = 1 << 3,
|
||||
|
||||
/*
|
||||
* This assumes that the device tree components appear in a 'convenient'
|
||||
* order, i.e. the memory reservation block first, then the structure
|
||||
* block and finally the string block.
|
||||
*
|
||||
* This order is not specified by the device-tree specification,
|
||||
* but is expected by libfdt. The device-tree compiler always created
|
||||
* device trees with this order.
|
||||
*
|
||||
* This assumption disables a check in fdt_open_into() and removes the
|
||||
* ability to fix the problem there. This is safe if you know that the
|
||||
* device tree is correctly ordered. See fdt_blocks_misordered_().
|
||||
*/
|
||||
ASSUME_LIBFDT_ORDER = 1 << 4,
|
||||
|
||||
/*
|
||||
* This assumes that libfdt itself does not have any internal bugs. It
|
||||
* drops certain checks that should never be needed unless libfdt has an
|
||||
* undiscovered bug.
|
||||
*
|
||||
* This can generally be considered safe to enable.
|
||||
*/
|
||||
ASSUME_LIBFDT_FLAWLESS = 1 << 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* can_assume_() - check if a particular assumption is enabled
|
||||
*
|
||||
* @mask: Mask to check (ASSUME_...)
|
||||
* @return true if that assumption is enabled, else false
|
||||
*/
|
||||
static inline bool can_assume_(int mask)
|
||||
{
|
||||
return FDT_ASSUME_MASK & mask;
|
||||
}
|
||||
|
||||
/** helper macros for checking assumptions */
|
||||
#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
|
||||
|
||||
#endif /* LIBFDT_INTERNAL_H */
|
||||
|
@ -1,24 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
/*
|
||||
* Tree building functions
|
||||
@ -50,7 +36,8 @@ void delete_labels(struct label **labels)
|
||||
label->deleted = 1;
|
||||
}
|
||||
|
||||
struct property *build_property(char *name, struct data val)
|
||||
struct property *build_property(char *name, struct data val,
|
||||
struct srcpos *srcpos)
|
||||
{
|
||||
struct property *new = xmalloc(sizeof(*new));
|
||||
|
||||
@ -58,6 +45,7 @@ struct property *build_property(char *name, struct data val)
|
||||
|
||||
new->name = name;
|
||||
new->val = val;
|
||||
new->srcpos = srcpos_copy(srcpos);
|
||||
|
||||
return new;
|
||||
}
|
||||
@ -97,7 +85,8 @@ struct property *reverse_properties(struct property *first)
|
||||
return head;
|
||||
}
|
||||
|
||||
struct node *build_node(struct property *proplist, struct node *children)
|
||||
struct node *build_node(struct property *proplist, struct node *children,
|
||||
struct srcpos *srcpos)
|
||||
{
|
||||
struct node *new = xmalloc(sizeof(*new));
|
||||
struct node *child;
|
||||
@ -106,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children)
|
||||
|
||||
new->proplist = reverse_properties(proplist);
|
||||
new->children = children;
|
||||
new->srcpos = srcpos_copy(srcpos);
|
||||
|
||||
for_each_child(new, child) {
|
||||
child->parent = new;
|
||||
@ -114,13 +104,14 @@ struct node *build_node(struct property *proplist, struct node *children)
|
||||
return new;
|
||||
}
|
||||
|
||||
struct node *build_node_delete(void)
|
||||
struct node *build_node_delete(struct srcpos *srcpos)
|
||||
{
|
||||
struct node *new = xmalloc(sizeof(*new));
|
||||
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
||||
new->deleted = 1;
|
||||
new->srcpos = srcpos_copy(srcpos);
|
||||
|
||||
return new;
|
||||
}
|
||||
@ -183,6 +174,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
|
||||
|
||||
old_prop->val = new_prop->val;
|
||||
old_prop->deleted = 0;
|
||||
free(old_prop->srcpos);
|
||||
old_prop->srcpos = new_prop->srcpos;
|
||||
free(new_prop);
|
||||
new_prop = NULL;
|
||||
break;
|
||||
@ -223,6 +216,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
|
||||
add_child(old_node, new_child);
|
||||
}
|
||||
|
||||
old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
|
||||
|
||||
/* The new node contents are now merged into the old node. Free
|
||||
* the new node. */
|
||||
free(new_node);
|
||||
@ -239,20 +234,21 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
|
||||
char *name;
|
||||
|
||||
if (ref[0] == '/') {
|
||||
d = data_add_marker(d, TYPE_STRING, ref);
|
||||
d = data_append_data(d, ref, strlen(ref) + 1);
|
||||
|
||||
p = build_property("target-path", d);
|
||||
p = build_property("target-path", d, NULL);
|
||||
} else {
|
||||
d = data_add_marker(d, REF_PHANDLE, ref);
|
||||
d = data_append_integer(d, 0xffffffff, 32);
|
||||
|
||||
p = build_property("target", d);
|
||||
p = build_property("target", d, NULL);
|
||||
}
|
||||
|
||||
xasprintf(&name, "fragment@%u",
|
||||
next_orphan_fragment++);
|
||||
name_node(new_node, "__overlay__");
|
||||
node = build_node(p, new_node);
|
||||
node = build_node(p, new_node, NULL);
|
||||
name_node(node, name);
|
||||
|
||||
add_child(dt, node);
|
||||
@ -340,18 +336,21 @@ void delete_node(struct node *node)
|
||||
}
|
||||
|
||||
void append_to_property(struct node *node,
|
||||
char *name, const void *data, int len)
|
||||
char *name, const void *data, int len,
|
||||
enum markertype type)
|
||||
{
|
||||
struct data d;
|
||||
struct property *p;
|
||||
|
||||
p = get_property(node, name);
|
||||
if (p) {
|
||||
d = data_append_data(p->val, data, len);
|
||||
d = data_add_marker(p->val, type, name);
|
||||
d = data_append_data(d, data, len);
|
||||
p->val = d;
|
||||
} else {
|
||||
d = data_append_data(empty_data, data, len);
|
||||
p = build_property(name, d);
|
||||
d = data_add_marker(empty_data, type, name);
|
||||
d = data_append_data(d, data, len);
|
||||
p = build_property(name, d, NULL);
|
||||
add_property(node, p);
|
||||
}
|
||||
}
|
||||
@ -527,8 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
|
||||
p = strchr(path, '/');
|
||||
|
||||
for_each_child(tree, child) {
|
||||
if (p && (strlen(child->name) == p-path) &&
|
||||
strprefixeq(path, p - path, child->name))
|
||||
if (p && strprefixeq(path, p - path, child->name))
|
||||
return get_node_by_path(child, p+1);
|
||||
else if (!p && streq(path, child->name))
|
||||
return child;
|
||||
@ -594,6 +592,7 @@ struct node *get_node_by_ref(struct node *tree, const char *ref)
|
||||
cell_t get_node_phandle(struct node *root, struct node *node)
|
||||
{
|
||||
static cell_t phandle = 1; /* FIXME: ick, static local */
|
||||
struct data d = empty_data;
|
||||
|
||||
if ((node->phandle != 0) && (node->phandle != -1))
|
||||
return node->phandle;
|
||||
@ -603,17 +602,16 @@ cell_t get_node_phandle(struct node *root, struct node *node)
|
||||
|
||||
node->phandle = phandle;
|
||||
|
||||
d = data_add_marker(d, TYPE_UINT32, NULL);
|
||||
d = data_append_cell(d, phandle);
|
||||
|
||||
if (!get_property(node, "linux,phandle")
|
||||
&& (phandle_format & PHANDLE_LEGACY))
|
||||
add_property(node,
|
||||
build_property("linux,phandle",
|
||||
data_append_cell(empty_data, phandle)));
|
||||
add_property(node, build_property("linux,phandle", d, NULL));
|
||||
|
||||
if (!get_property(node, "phandle")
|
||||
&& (phandle_format & PHANDLE_EPAPR))
|
||||
add_property(node,
|
||||
build_property("phandle",
|
||||
data_append_cell(empty_data, phandle)));
|
||||
add_property(node, build_property("phandle", d, NULL));
|
||||
|
||||
/* If the node *does* have a phandle property, we must
|
||||
* be dealing with a self-referencing phandle, which will be
|
||||
@ -787,7 +785,7 @@ static struct node *build_and_name_child_node(struct node *parent, char *name)
|
||||
{
|
||||
struct node *node;
|
||||
|
||||
node = build_node(NULL, NULL);
|
||||
node = build_node(NULL, NULL, NULL);
|
||||
name_node(node, xstrdup(name));
|
||||
add_child(parent, node);
|
||||
|
||||
@ -848,8 +846,9 @@ static void generate_label_tree_internal(struct dt_info *dti,
|
||||
|
||||
/* insert it */
|
||||
p = build_property(l->label,
|
||||
data_copy_mem(node->fullpath,
|
||||
strlen(node->fullpath) + 1));
|
||||
data_copy_escape_string(node->fullpath,
|
||||
strlen(node->fullpath)),
|
||||
NULL);
|
||||
add_property(an, p);
|
||||
}
|
||||
|
||||
@ -899,7 +898,7 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
|
||||
|
||||
xasprintf(&entry, "%s:%s:%u",
|
||||
node->fullpath, prop->name, m->offset);
|
||||
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
|
||||
append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
|
||||
|
||||
free(entry);
|
||||
}
|
||||
@ -959,7 +958,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
|
||||
char **compp;
|
||||
int i, depth;
|
||||
|
||||
/* walk back retreiving depth */
|
||||
/* walk back retrieving depth */
|
||||
depth = 0;
|
||||
for (wn = node; wn; wn = wn->parent)
|
||||
depth++;
|
||||
@ -982,7 +981,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
|
||||
free(compp);
|
||||
|
||||
value_32 = cpu_to_fdt32(m->offset);
|
||||
append_to_property(wn, prop->name, &value_32, sizeof(value_32));
|
||||
append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
|
||||
}
|
||||
|
||||
static void generate_local_fixups_tree_internal(struct dt_info *dti,
|
||||
|
@ -1,20 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
@ -33,6 +19,9 @@ struct search_path {
|
||||
/* This is the list of directories that we search for source files */
|
||||
static struct search_path *search_path_head, **search_path_tail;
|
||||
|
||||
/* Detect infinite include recursion. */
|
||||
#define MAX_SRCFILE_DEPTH (100)
|
||||
static int srcfile_depth; /* = 0 */
|
||||
|
||||
static char *get_dirname(const char *path)
|
||||
{
|
||||
@ -51,11 +40,51 @@ static char *get_dirname(const char *path)
|
||||
|
||||
FILE *depfile; /* = NULL */
|
||||
struct srcfile_state *current_srcfile; /* = NULL */
|
||||
static char *initial_path; /* = NULL */
|
||||
static int initial_pathlen; /* = 0 */
|
||||
static bool initial_cpp = true;
|
||||
|
||||
/* Detect infinite include recursion. */
|
||||
#define MAX_SRCFILE_DEPTH (100)
|
||||
static int srcfile_depth; /* = 0 */
|
||||
static void set_initial_path(char *fname)
|
||||
{
|
||||
int i, len = strlen(fname);
|
||||
|
||||
xasprintf(&initial_path, "%s", fname);
|
||||
initial_pathlen = 0;
|
||||
for (i = 0; i != len; i++)
|
||||
if (initial_path[i] == '/')
|
||||
initial_pathlen++;
|
||||
}
|
||||
|
||||
static char *shorten_to_initial_path(char *fname)
|
||||
{
|
||||
char *p1, *p2, *prevslash1 = NULL;
|
||||
int slashes = 0;
|
||||
|
||||
for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
|
||||
if (*p1 != *p2)
|
||||
break;
|
||||
if (*p1 == '/') {
|
||||
prevslash1 = p1;
|
||||
slashes++;
|
||||
}
|
||||
}
|
||||
p1 = prevslash1 + 1;
|
||||
if (prevslash1) {
|
||||
int diff = initial_pathlen - slashes, i, j;
|
||||
int restlen = strlen(fname) - (p1 - fname);
|
||||
char *res;
|
||||
|
||||
res = xmalloc((3 * diff) + restlen + 1);
|
||||
for (i = 0, j = 0; i != diff; i++) {
|
||||
res[j++] = '.';
|
||||
res[j++] = '.';
|
||||
res[j++] = '/';
|
||||
}
|
||||
strcpy(res + j, p1);
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to open a file in a given directory.
|
||||
@ -157,6 +186,9 @@ void srcfile_push(const char *fname)
|
||||
srcfile->colno = 1;
|
||||
|
||||
current_srcfile = srcfile;
|
||||
|
||||
if (srcfile_depth == 1)
|
||||
set_initial_path(srcfile->name);
|
||||
}
|
||||
|
||||
bool srcfile_pop(void)
|
||||
@ -197,18 +229,6 @@ void srcfile_add_search_path(const char *dirname)
|
||||
search_path_tail = &node->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* The empty source position.
|
||||
*/
|
||||
|
||||
struct srcpos srcpos_empty = {
|
||||
.first_line = 0,
|
||||
.first_column = 0,
|
||||
.last_line = 0,
|
||||
.last_column = 0,
|
||||
.file = NULL,
|
||||
};
|
||||
|
||||
void srcpos_update(struct srcpos *pos, const char *text, int len)
|
||||
{
|
||||
int i;
|
||||
@ -234,13 +254,35 @@ struct srcpos *
|
||||
srcpos_copy(struct srcpos *pos)
|
||||
{
|
||||
struct srcpos *pos_new;
|
||||
struct srcfile_state *srcfile_state;
|
||||
|
||||
if (!pos)
|
||||
return NULL;
|
||||
|
||||
pos_new = xmalloc(sizeof(struct srcpos));
|
||||
assert(pos->next == NULL);
|
||||
memcpy(pos_new, pos, sizeof(struct srcpos));
|
||||
|
||||
/* allocate without free */
|
||||
srcfile_state = xmalloc(sizeof(struct srcfile_state));
|
||||
memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
|
||||
pos_new->file = srcfile_state;
|
||||
|
||||
return pos_new;
|
||||
}
|
||||
|
||||
struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
|
||||
{
|
||||
struct srcpos *p;
|
||||
|
||||
if (!pos)
|
||||
return newtail;
|
||||
|
||||
for (p = pos; p->next != NULL; p = p->next);
|
||||
p->next = newtail;
|
||||
return pos;
|
||||
}
|
||||
|
||||
char *
|
||||
srcpos_string(struct srcpos *pos)
|
||||
{
|
||||
@ -266,6 +308,68 @@ srcpos_string(struct srcpos *pos)
|
||||
return pos_str;
|
||||
}
|
||||
|
||||
static char *
|
||||
srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
|
||||
{
|
||||
char *pos_str, *fname, *first, *rest;
|
||||
bool fresh_fname = false;
|
||||
|
||||
if (!pos) {
|
||||
if (level > 1) {
|
||||
xasprintf(&pos_str, "<no-file>:<no-line>");
|
||||
return pos_str;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pos->file)
|
||||
fname = "<no-file>";
|
||||
else if (!pos->file->name)
|
||||
fname = "<no-filename>";
|
||||
else if (level > 1)
|
||||
fname = pos->file->name;
|
||||
else {
|
||||
fname = shorten_to_initial_path(pos->file->name);
|
||||
if (fname)
|
||||
fresh_fname = true;
|
||||
else
|
||||
fname = pos->file->name;
|
||||
}
|
||||
|
||||
if (level > 1)
|
||||
xasprintf(&first, "%s:%d:%d-%d:%d", fname,
|
||||
pos->first_line, pos->first_column,
|
||||
pos->last_line, pos->last_column);
|
||||
else
|
||||
xasprintf(&first, "%s:%d", fname,
|
||||
first_line ? pos->first_line : pos->last_line);
|
||||
|
||||
if (fresh_fname)
|
||||
free(fname);
|
||||
|
||||
if (pos->next != NULL) {
|
||||
rest = srcpos_string_comment(pos->next, first_line, level);
|
||||
xasprintf(&pos_str, "%s, %s", first, rest);
|
||||
free(first);
|
||||
free(rest);
|
||||
} else {
|
||||
pos_str = first;
|
||||
}
|
||||
|
||||
return pos_str;
|
||||
}
|
||||
|
||||
char *srcpos_string_first(struct srcpos *pos, int level)
|
||||
{
|
||||
return srcpos_string_comment(pos, true, level);
|
||||
}
|
||||
|
||||
char *srcpos_string_last(struct srcpos *pos, int level)
|
||||
{
|
||||
return srcpos_string_comment(pos, false, level);
|
||||
}
|
||||
|
||||
void srcpos_verror(struct srcpos *pos, const char *prefix,
|
||||
const char *fmt, va_list va)
|
||||
{
|
||||
@ -294,4 +398,9 @@ void srcpos_set_line(char *f, int l)
|
||||
{
|
||||
current_srcfile->name = f;
|
||||
current_srcfile->lineno = l;
|
||||
|
||||
if (initial_cpp) {
|
||||
initial_cpp = false;
|
||||
set_initial_path(f);
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#ifndef SRCPOS_H
|
||||
@ -74,6 +60,7 @@ struct srcpos {
|
||||
int last_line;
|
||||
int last_column;
|
||||
struct srcfile_state *file;
|
||||
struct srcpos *next;
|
||||
};
|
||||
|
||||
#define YYLTYPE struct srcpos
|
||||
@ -93,19 +80,18 @@ struct srcpos {
|
||||
YYRHSLOC(Rhs, 0).last_column; \
|
||||
(Current).file = YYRHSLOC (Rhs, 0).file; \
|
||||
} \
|
||||
(Current).next = NULL; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* Fictional source position used for IR nodes that are
|
||||
* created without otherwise knowing a true source position.
|
||||
* For example,constant definitions from the command line.
|
||||
*/
|
||||
extern struct srcpos srcpos_empty;
|
||||
|
||||
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
|
||||
extern struct srcpos *srcpos_copy(struct srcpos *pos);
|
||||
extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos,
|
||||
struct srcpos *old_srcpos);
|
||||
extern char *srcpos_string(struct srcpos *pos);
|
||||
extern char *srcpos_string_first(struct srcpos *pos, int level);
|
||||
extern char *srcpos_string_last(struct srcpos *pos, int level);
|
||||
|
||||
|
||||
extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
|
||||
const char *fmt, va_list va);
|
||||
|
@ -1,21 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include "dtc.h"
|
||||
@ -61,24 +46,18 @@ static bool isstring(char c)
|
||||
|| strchr("\a\b\t\n\v\f\r", c));
|
||||
}
|
||||
|
||||
static void write_propval_string(FILE *f, struct data val)
|
||||
static void write_propval_string(FILE *f, const char *s, size_t len)
|
||||
{
|
||||
const char *str = val.val;
|
||||
int i;
|
||||
struct marker *m = val.markers;
|
||||
const char *end = s + len - 1;
|
||||
|
||||
assert(str[val.len-1] == '\0');
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
assert(*end == '\0');
|
||||
|
||||
while (m && (m->offset == 0)) {
|
||||
if (m->type == LABEL)
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
m = m->next;
|
||||
}
|
||||
fprintf(f, "\"");
|
||||
|
||||
for (i = 0; i < (val.len-1); i++) {
|
||||
char c = str[i];
|
||||
|
||||
while (s < end) {
|
||||
char c = *s++;
|
||||
switch (c) {
|
||||
case '\a':
|
||||
fprintf(f, "\\a");
|
||||
@ -108,91 +87,80 @@ static void write_propval_string(FILE *f, struct data val)
|
||||
fprintf(f, "\\\"");
|
||||
break;
|
||||
case '\0':
|
||||
fprintf(f, "\", ");
|
||||
while (m && (m->offset <= (i + 1))) {
|
||||
if (m->type == LABEL) {
|
||||
assert(m->offset == (i+1));
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
fprintf(f, "\"");
|
||||
fprintf(f, "\\0");
|
||||
break;
|
||||
default:
|
||||
if (isprint((unsigned char)c))
|
||||
fprintf(f, "%c", c);
|
||||
else
|
||||
fprintf(f, "\\x%02hhx", c);
|
||||
fprintf(f, "\\x%02"PRIx8, c);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\"");
|
||||
|
||||
/* Wrap up any labels at the end of the value */
|
||||
for_each_marker_of_type(m, LABEL) {
|
||||
assert (m->offset == val.len);
|
||||
fprintf(f, " %s:", m->ref);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_propval_cells(FILE *f, struct data val)
|
||||
static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
|
||||
{
|
||||
void *propend = val.val + val.len;
|
||||
fdt32_t *cp = (fdt32_t *)val.val;
|
||||
struct marker *m = val.markers;
|
||||
const char *end = p + len;
|
||||
assert(len % width == 0);
|
||||
|
||||
fprintf(f, "<");
|
||||
for (;;) {
|
||||
while (m && (m->offset <= ((char *)cp - val.val))) {
|
||||
if (m->type == LABEL) {
|
||||
assert(m->offset == ((char *)cp - val.val));
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
|
||||
if ((void *)cp >= propend)
|
||||
for (; p < end; p += width) {
|
||||
switch (width) {
|
||||
case 1:
|
||||
fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
|
||||
break;
|
||||
fprintf(f, " ");
|
||||
case 2:
|
||||
fprintf(f, "0x%02"PRIx16, dtb_ld16(p));
|
||||
break;
|
||||
case 4:
|
||||
fprintf(f, "0x%02"PRIx32, dtb_ld32(p));
|
||||
break;
|
||||
case 8:
|
||||
fprintf(f, "0x%02"PRIx64, dtb_ld64(p));
|
||||
break;
|
||||
}
|
||||
if (p + width < end)
|
||||
fputc(' ', f);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wrap up any labels at the end of the value */
|
||||
for_each_marker_of_type(m, LABEL) {
|
||||
assert (m->offset == val.len);
|
||||
fprintf(f, " %s:", m->ref);
|
||||
}
|
||||
fprintf(f, ">");
|
||||
}
|
||||
|
||||
static void write_propval_bytes(FILE *f, struct data val)
|
||||
static bool has_data_type_information(struct marker *m)
|
||||
{
|
||||
void *propend = val.val + val.len;
|
||||
const char *bp = val.val;
|
||||
struct marker *m = val.markers;
|
||||
return m->type >= TYPE_UINT8;
|
||||
}
|
||||
|
||||
fprintf(f, "[");
|
||||
for (;;) {
|
||||
while (m && (m->offset == (bp-val.val))) {
|
||||
if (m->type == LABEL)
|
||||
fprintf(f, "%s: ", m->ref);
|
||||
static struct marker *next_type_marker(struct marker *m)
|
||||
{
|
||||
while (m && !has_data_type_information(m))
|
||||
m = m->next;
|
||||
return m;
|
||||
}
|
||||
|
||||
fprintf(f, "%02hhx", (unsigned char)(*bp++));
|
||||
if ((const void *)bp >= propend)
|
||||
break;
|
||||
fprintf(f, " ");
|
||||
size_t type_marker_length(struct marker *m)
|
||||
{
|
||||
struct marker *next = next_type_marker(m->next);
|
||||
|
||||
if (next)
|
||||
return next->offset - m->offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wrap up any labels at the end of the value */
|
||||
for_each_marker_of_type(m, LABEL) {
|
||||
assert (m->offset == val.len);
|
||||
fprintf(f, " %s:", m->ref);
|
||||
}
|
||||
fprintf(f, "]");
|
||||
}
|
||||
static const char *delim_start[] = {
|
||||
[TYPE_UINT8] = "[",
|
||||
[TYPE_UINT16] = "/bits/ 16 <",
|
||||
[TYPE_UINT32] = "<",
|
||||
[TYPE_UINT64] = "/bits/ 64 <",
|
||||
[TYPE_STRING] = "",
|
||||
};
|
||||
static const char *delim_end[] = {
|
||||
[TYPE_UINT8] = "]",
|
||||
[TYPE_UINT16] = ">",
|
||||
[TYPE_UINT32] = ">",
|
||||
[TYPE_UINT64] = ">",
|
||||
[TYPE_STRING] = "",
|
||||
};
|
||||
|
||||
static void write_propval(FILE *f, struct property *prop)
|
||||
static enum markertype guess_value_type(struct property *prop)
|
||||
{
|
||||
int len = prop->val.len;
|
||||
const char *p = prop->val.val;
|
||||
@ -201,11 +169,6 @@ static void write_propval(FILE *f, struct property *prop)
|
||||
int nnotstringlbl = 0, nnotcelllbl = 0;
|
||||
int i;
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(f, ";\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (! isstring(p[i]))
|
||||
nnotstring++;
|
||||
@ -220,17 +183,99 @@ static void write_propval(FILE *f, struct property *prop)
|
||||
nnotcelllbl++;
|
||||
}
|
||||
|
||||
fprintf(f, " = ");
|
||||
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
|
||||
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
|
||||
&& (nnotstringlbl == 0)) {
|
||||
write_propval_string(f, prop->val);
|
||||
return TYPE_STRING;
|
||||
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
|
||||
write_propval_cells(f, prop->val);
|
||||
} else {
|
||||
write_propval_bytes(f, prop->val);
|
||||
return TYPE_UINT32;
|
||||
}
|
||||
|
||||
fprintf(f, ";\n");
|
||||
return TYPE_UINT8;
|
||||
}
|
||||
|
||||
static void write_propval(FILE *f, struct property *prop)
|
||||
{
|
||||
size_t len = prop->val.len;
|
||||
struct marker *m = prop->val.markers;
|
||||
struct marker dummy_marker;
|
||||
enum markertype emit_type = TYPE_NONE;
|
||||
char *srcstr;
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(f, ";");
|
||||
if (annotate) {
|
||||
srcstr = srcpos_string_first(prop->srcpos, annotate);
|
||||
if (srcstr) {
|
||||
fprintf(f, " /* %s */", srcstr);
|
||||
free(srcstr);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f, " =");
|
||||
|
||||
if (!next_type_marker(m)) {
|
||||
/* data type information missing, need to guess */
|
||||
dummy_marker.type = guess_value_type(prop);
|
||||
dummy_marker.next = prop->val.markers;
|
||||
dummy_marker.offset = 0;
|
||||
dummy_marker.ref = NULL;
|
||||
m = &dummy_marker;
|
||||
}
|
||||
|
||||
for_each_marker(m) {
|
||||
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
|
||||
size_t data_len = type_marker_length(m) ? : len - m->offset;
|
||||
const char *p = &prop->val.val[m->offset];
|
||||
|
||||
if (has_data_type_information(m)) {
|
||||
emit_type = m->type;
|
||||
fprintf(f, " %s", delim_start[emit_type]);
|
||||
} else if (m->type == LABEL)
|
||||
fprintf(f, " %s:", m->ref);
|
||||
else if (m->offset)
|
||||
fputc(' ', f);
|
||||
|
||||
if (emit_type == TYPE_NONE) {
|
||||
assert(chunk_len == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(emit_type) {
|
||||
case TYPE_UINT16:
|
||||
write_propval_int(f, p, chunk_len, 2);
|
||||
break;
|
||||
case TYPE_UINT32:
|
||||
write_propval_int(f, p, chunk_len, 4);
|
||||
break;
|
||||
case TYPE_UINT64:
|
||||
write_propval_int(f, p, chunk_len, 8);
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
write_propval_string(f, p, chunk_len);
|
||||
break;
|
||||
default:
|
||||
write_propval_int(f, p, chunk_len, 1);
|
||||
}
|
||||
|
||||
if (chunk_len == data_len) {
|
||||
size_t pos = m->offset + chunk_len;
|
||||
fprintf(f, pos == len ? "%s" : "%s,",
|
||||
delim_end[emit_type] ? : "");
|
||||
emit_type = TYPE_NONE;
|
||||
}
|
||||
}
|
||||
fprintf(f, ";");
|
||||
if (annotate) {
|
||||
srcstr = srcpos_string_first(prop->srcpos, annotate);
|
||||
if (srcstr) {
|
||||
fprintf(f, " /* %s */", srcstr);
|
||||
free(srcstr);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static void write_tree_source_node(FILE *f, struct node *tree, int level)
|
||||
@ -238,14 +283,24 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
|
||||
struct property *prop;
|
||||
struct node *child;
|
||||
struct label *l;
|
||||
char *srcstr;
|
||||
|
||||
write_prefix(f, level);
|
||||
for_each_label(tree->labels, l)
|
||||
fprintf(f, "%s: ", l->label);
|
||||
if (tree->name && (*tree->name))
|
||||
fprintf(f, "%s {\n", tree->name);
|
||||
fprintf(f, "%s {", tree->name);
|
||||
else
|
||||
fprintf(f, "/ {\n");
|
||||
fprintf(f, "/ {");
|
||||
|
||||
if (annotate) {
|
||||
srcstr = srcpos_string_first(tree->srcpos, annotate);
|
||||
if (srcstr) {
|
||||
fprintf(f, " /* %s */", srcstr);
|
||||
free(srcstr);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
for_each_property(tree, prop) {
|
||||
write_prefix(f, level+1);
|
||||
@ -259,9 +314,16 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
|
||||
write_tree_source_node(f, child, level+1);
|
||||
}
|
||||
write_prefix(f, level);
|
||||
fprintf(f, "};\n");
|
||||
fprintf(f, "};");
|
||||
if (annotate) {
|
||||
srcstr = srcpos_string_last(tree->srcpos, annotate);
|
||||
if (srcstr) {
|
||||
fprintf(f, " /* %s */", srcstr);
|
||||
free(srcstr);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
|
||||
void dt_to_source(FILE *f, struct dt_info *dti)
|
||||
{
|
||||
@ -281,4 +343,3 @@ void dt_to_source(FILE *f, struct dt_info *dti)
|
||||
|
||||
write_tree_source_node(f, dti->dt, 0);
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc
|
||||
DTC_LINUX_PATH=`pwd`/scripts/dtc
|
||||
|
||||
DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
|
||||
srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \
|
||||
srcpos.h treesource.c util.c util.h version_gen.h yamltree.c Makefile.dtc \
|
||||
dtc-lexer.l dtc-parser.y"
|
||||
LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \
|
||||
fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \
|
||||
|
@ -1,24 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2011 The Chromium Authors, All Rights Reserved.
|
||||
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* util_is_printable_string contributed by
|
||||
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
@ -27,6 +13,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -46,36 +33,54 @@ char *xstrdup(const char *s)
|
||||
return d;
|
||||
}
|
||||
|
||||
/* based in part from (3) vsnprintf */
|
||||
int xasprintf(char **strp, const char *fmt, ...)
|
||||
int xavsprintf_append(char **strp, const char *fmt, va_list ap)
|
||||
{
|
||||
int n, size = 128; /* start with 128 bytes */
|
||||
int n, size = 0; /* start with 128 bytes */
|
||||
char *p;
|
||||
va_list ap;
|
||||
va_list ap_copy;
|
||||
|
||||
/* initial pointer is NULL making the fist realloc to be malloc */
|
||||
p = NULL;
|
||||
while (1) {
|
||||
p = xrealloc(p, size);
|
||||
p = *strp;
|
||||
if (p)
|
||||
size = strlen(p);
|
||||
|
||||
/* Try to print in the allocated space. */
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(p, size, fmt, ap);
|
||||
va_end(ap);
|
||||
va_copy(ap_copy, ap);
|
||||
n = vsnprintf(NULL, 0, fmt, ap_copy) + 1;
|
||||
va_end(ap_copy);
|
||||
|
||||
p = xrealloc(p, size + n);
|
||||
|
||||
n = vsnprintf(p + size, n, fmt, ap);
|
||||
|
||||
/* If that worked, return the string. */
|
||||
if (n > -1 && n < size)
|
||||
break;
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) /* glibc 2.1 */
|
||||
size = n + 1; /* precisely what is needed */
|
||||
else /* glibc 2.0 */
|
||||
size *= 2; /* twice the old size */
|
||||
}
|
||||
*strp = p;
|
||||
return strlen(p);
|
||||
}
|
||||
|
||||
int xasprintf_append(char **strp, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = xavsprintf_append(strp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int xasprintf(char **strp, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list ap;
|
||||
|
||||
*strp = NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = xavsprintf_append(strp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
char *join_path(const char *path, const char *name)
|
||||
{
|
||||
int lenp = strlen(path);
|
||||
@ -227,11 +232,11 @@ char get_escape_char(const char *s, int *i)
|
||||
return val;
|
||||
}
|
||||
|
||||
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
|
||||
int utilfdt_read_err(const char *filename, char **buffp, size_t *len)
|
||||
{
|
||||
int fd = 0; /* assume stdin */
|
||||
char *buf = NULL;
|
||||
off_t bufsize = 1024, offset = 0;
|
||||
size_t bufsize = 1024, offset = 0;
|
||||
int ret = 0;
|
||||
|
||||
*buffp = NULL;
|
||||
@ -264,20 +269,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
|
||||
free(buf);
|
||||
else
|
||||
*buffp = buf;
|
||||
if (len)
|
||||
*len = bufsize;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int utilfdt_read_err(const char *filename, char **buffp)
|
||||
{
|
||||
off_t len;
|
||||
return utilfdt_read_err_len(filename, buffp, &len);
|
||||
}
|
||||
|
||||
char *utilfdt_read_len(const char *filename, off_t *len)
|
||||
char *utilfdt_read(const char *filename, size_t *len)
|
||||
{
|
||||
char *buff;
|
||||
int ret = utilfdt_read_err_len(filename, &buff, len);
|
||||
int ret = utilfdt_read_err(filename, &buff, len);
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
|
||||
@ -288,12 +288,6 @@ char *utilfdt_read_len(const char *filename, off_t *len)
|
||||
return buff;
|
||||
}
|
||||
|
||||
char *utilfdt_read(const char *filename)
|
||||
{
|
||||
off_t len;
|
||||
return utilfdt_read_len(filename, &len);
|
||||
}
|
||||
|
||||
int utilfdt_write_err(const char *filename, const void *blob)
|
||||
{
|
||||
int fd = 1; /* assume stdout */
|
||||
@ -400,7 +394,7 @@ void utilfdt_print_data(const char *data, int len)
|
||||
|
||||
printf(" = <");
|
||||
for (i = 0, len /= 4; i < len; i++)
|
||||
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
|
||||
printf("0x%08" PRIx32 "%s", fdt32_to_cpu(cell[i]),
|
||||
i < (len - 1) ? " " : "");
|
||||
printf(">");
|
||||
} else {
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
@ -8,25 +9,14 @@
|
||||
/*
|
||||
* Copyright 2011 The Chromium Authors, All Rights Reserved.
|
||||
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
|
||||
*
|
||||
* This program 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 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifdef __clang__
|
||||
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
|
||||
#else
|
||||
#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j)))
|
||||
#endif
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define PRINTF(i, j)
|
||||
@ -72,6 +62,8 @@ static inline void *xrealloc(void *p, size_t len)
|
||||
extern char *xstrdup(const char *s);
|
||||
|
||||
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
|
||||
extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
|
||||
extern int xavsprintf_append(char **strp, const char *fmt, va_list ap);
|
||||
extern char *join_path(const char *path, const char *name);
|
||||
|
||||
/**
|
||||
@ -98,16 +90,10 @@ char get_escape_char(const char *s, int *i);
|
||||
* stderr.
|
||||
*
|
||||
* @param filename The filename to read, or - for stdin
|
||||
* @param len If non-NULL, the amount of data we managed to read
|
||||
* @return Pointer to allocated buffer containing fdt, or NULL on error
|
||||
*/
|
||||
char *utilfdt_read(const char *filename);
|
||||
|
||||
/**
|
||||
* Like utilfdt_read(), but also passes back the size of the file read.
|
||||
*
|
||||
* @param len If non-NULL, the amount of data we managed to read
|
||||
*/
|
||||
char *utilfdt_read_len(const char *filename, off_t *len);
|
||||
char *utilfdt_read(const char *filename, size_t *len);
|
||||
|
||||
/**
|
||||
* Read a device tree file into a buffer. Does not report errors, but only
|
||||
@ -116,23 +102,17 @@ char *utilfdt_read_len(const char *filename, off_t *len);
|
||||
*
|
||||
* @param filename The filename to read, or - for stdin
|
||||
* @param buffp Returns pointer to buffer containing fdt
|
||||
* @param len If non-NULL, the amount of data we managed to read
|
||||
* @return 0 if ok, else an errno value representing the error
|
||||
*/
|
||||
int utilfdt_read_err(const char *filename, char **buffp);
|
||||
|
||||
/**
|
||||
* Like utilfdt_read_err(), but also passes back the size of the file read.
|
||||
*
|
||||
* @param len If non-NULL, the amount of data we managed to read
|
||||
*/
|
||||
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len);
|
||||
int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
|
||||
|
||||
/**
|
||||
* Write a device tree buffer to a file. This will report any errors on
|
||||
* stderr.
|
||||
*
|
||||
* @param filename The filename to write, or - for stdout
|
||||
* @param blob Poiner to buffer containing fdt
|
||||
* @param blob Pointer to buffer containing fdt
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int utilfdt_write(const char *filename, const void *blob);
|
||||
@ -143,7 +123,7 @@ int utilfdt_write(const char *filename, const void *blob);
|
||||
* an error message for the user.
|
||||
*
|
||||
* @param filename The filename to write, or - for stdout
|
||||
* @param blob Poiner to buffer containing fdt
|
||||
* @param blob Pointer to buffer containing fdt
|
||||
* @return 0 if ok, else an errno value representing the error
|
||||
*/
|
||||
int utilfdt_write_err(const char *filename, const void *blob);
|
||||
|
@ -1 +1 @@
|
||||
#define DTC_VERSION "DTC 1.4.6-g84e414b0"
|
||||
#define DTC_VERSION "DTC 1.6.0-g9d7888cb"
|
||||
|
254
scripts/dtc/yamltree.c
Normal file
254
scripts/dtc/yamltree.c
Normal file
@ -0,0 +1,254 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* (C) Copyright Linaro, Ltd. 2018
|
||||
* (C) Copyright Arm Holdings. 2017
|
||||
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <yaml.h>
|
||||
#include "dtc.h"
|
||||
#include "srcpos.h"
|
||||
|
||||
char *yaml_error_name[] = {
|
||||
[YAML_NO_ERROR] = "no error",
|
||||
[YAML_MEMORY_ERROR] = "memory error",
|
||||
[YAML_READER_ERROR] = "reader error",
|
||||
[YAML_SCANNER_ERROR] = "scanner error",
|
||||
[YAML_PARSER_ERROR] = "parser error",
|
||||
[YAML_COMPOSER_ERROR] = "composer error",
|
||||
[YAML_WRITER_ERROR] = "writer error",
|
||||
[YAML_EMITTER_ERROR] = "emitter error",
|
||||
};
|
||||
|
||||
#define yaml_emitter_emit_or_die(emitter, event) ( \
|
||||
{ \
|
||||
if (!yaml_emitter_emit(emitter, event)) \
|
||||
die("yaml '%s': %s in %s, line %i\n", \
|
||||
yaml_error_name[(emitter)->error], \
|
||||
(emitter)->problem, __func__, __LINE__); \
|
||||
})
|
||||
|
||||
static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
|
||||
{
|
||||
yaml_event_t event;
|
||||
void *tag;
|
||||
int off, start_offset = markers->offset;
|
||||
|
||||
switch(width) {
|
||||
case 1: tag = "!u8"; break;
|
||||
case 2: tag = "!u16"; break;
|
||||
case 4: tag = "!u32"; break;
|
||||
case 8: tag = "!u64"; break;
|
||||
default:
|
||||
die("Invalid width %i", width);
|
||||
}
|
||||
assert(len % width == 0);
|
||||
|
||||
yaml_sequence_start_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
|
||||
for (off = 0; off < len; off += width) {
|
||||
char buf[32];
|
||||
struct marker *m;
|
||||
bool is_phandle = false;
|
||||
|
||||
switch(width) {
|
||||
case 1:
|
||||
sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
|
||||
break;
|
||||
case 2:
|
||||
sprintf(buf, "0x%"PRIx16, dtb_ld16(data + off));
|
||||
break;
|
||||
case 4:
|
||||
sprintf(buf, "0x%"PRIx32, dtb_ld32(data + off));
|
||||
m = markers;
|
||||
is_phandle = false;
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
if (m->offset == (start_offset + off)) {
|
||||
is_phandle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
sprintf(buf, "0x%"PRIx64, dtb_ld64(data + off));
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_phandle)
|
||||
yaml_scalar_event_initialize(&event, NULL,
|
||||
(yaml_char_t*)"!phandle", (yaml_char_t *)buf,
|
||||
strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
|
||||
else
|
||||
yaml_scalar_event_initialize(&event, NULL,
|
||||
(yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
|
||||
strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
}
|
||||
|
||||
yaml_sequence_end_event_initialize(&event);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
}
|
||||
|
||||
static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
|
||||
{
|
||||
yaml_event_t event;
|
||||
int i;
|
||||
|
||||
assert(str[len-1] == '\0');
|
||||
|
||||
/* Make sure the entire string is in the lower 7-bit ascii range */
|
||||
for (i = 0; i < len; i++)
|
||||
assert(isascii(str[i]));
|
||||
|
||||
yaml_scalar_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
|
||||
len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
}
|
||||
|
||||
static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
|
||||
{
|
||||
yaml_event_t event;
|
||||
int len = prop->val.len;
|
||||
struct marker *m = prop->val.markers;
|
||||
|
||||
/* Emit the property name */
|
||||
yaml_scalar_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
|
||||
strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
|
||||
/* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
|
||||
if (len == 0) {
|
||||
yaml_scalar_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)YAML_BOOL_TAG,
|
||||
(yaml_char_t*)"true",
|
||||
strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m)
|
||||
die("No markers present in property '%s' value\n", prop->name);
|
||||
|
||||
yaml_sequence_start_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
|
||||
/* Ensure we have a type marker before any phandle */
|
||||
for_each_marker(m) {
|
||||
int last_offset = 0;
|
||||
struct marker *type_m;
|
||||
|
||||
if (m->type >= TYPE_UINT8)
|
||||
last_offset = m->offset;
|
||||
|
||||
if (!(m->next && m->next->type == REF_PHANDLE &&
|
||||
last_offset < m->next->offset))
|
||||
continue;
|
||||
|
||||
type_m = xmalloc(sizeof(*type_m));
|
||||
type_m->offset = m->next->offset;
|
||||
type_m->type = TYPE_UINT32;
|
||||
type_m->ref = NULL;
|
||||
type_m->next = m->next;
|
||||
m->next = type_m;
|
||||
}
|
||||
|
||||
m = prop->val.markers;
|
||||
for_each_marker(m) {
|
||||
int chunk_len;
|
||||
char *data = &prop->val.val[m->offset];
|
||||
|
||||
if (m->type < TYPE_UINT8)
|
||||
continue;
|
||||
|
||||
chunk_len = type_marker_length(m) ? : len;
|
||||
assert(chunk_len > 0);
|
||||
len -= chunk_len;
|
||||
|
||||
switch(m->type) {
|
||||
case TYPE_UINT16:
|
||||
yaml_propval_int(emitter, m, data, chunk_len, 2);
|
||||
break;
|
||||
case TYPE_UINT32:
|
||||
yaml_propval_int(emitter, m, data, chunk_len, 4);
|
||||
break;
|
||||
case TYPE_UINT64:
|
||||
yaml_propval_int(emitter, m, data, chunk_len, 8);
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
yaml_propval_string(emitter, data, chunk_len);
|
||||
break;
|
||||
default:
|
||||
yaml_propval_int(emitter, m, data, chunk_len, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yaml_sequence_end_event_initialize(&event);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
}
|
||||
|
||||
|
||||
static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
|
||||
{
|
||||
struct property *prop;
|
||||
struct node *child;
|
||||
yaml_event_t event;
|
||||
|
||||
if (tree->deleted)
|
||||
return;
|
||||
|
||||
yaml_mapping_start_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
|
||||
for_each_property(tree, prop)
|
||||
yaml_propval(emitter, prop);
|
||||
|
||||
/* Loop over all the children, emitting them into the map */
|
||||
for_each_child(tree, child) {
|
||||
yaml_scalar_event_initialize(&event, NULL,
|
||||
(yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
|
||||
strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
yaml_tree(child, emitter);
|
||||
}
|
||||
|
||||
yaml_mapping_end_event_initialize(&event);
|
||||
yaml_emitter_emit_or_die(emitter, &event);
|
||||
}
|
||||
|
||||
void dt_to_yaml(FILE *f, struct dt_info *dti)
|
||||
{
|
||||
yaml_emitter_t emitter;
|
||||
yaml_event_t event;
|
||||
|
||||
yaml_emitter_initialize(&emitter);
|
||||
yaml_emitter_set_output_file(&emitter, f);
|
||||
yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
|
||||
yaml_emitter_emit_or_die(&emitter, &event);
|
||||
|
||||
yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
|
||||
yaml_emitter_emit_or_die(&emitter, &event);
|
||||
|
||||
yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
|
||||
yaml_emitter_emit_or_die(&emitter, &event);
|
||||
|
||||
yaml_tree(dti->dt, &emitter);
|
||||
|
||||
yaml_sequence_end_event_initialize(&event);
|
||||
yaml_emitter_emit_or_die(&emitter, &event);
|
||||
|
||||
yaml_document_end_event_initialize(&event, 0);
|
||||
yaml_emitter_emit_or_die(&emitter, &event);
|
||||
|
||||
yaml_stream_end_event_initialize(&event);
|
||||
yaml_emitter_emit_or_die(&emitter, &event);
|
||||
|
||||
yaml_emitter_delete(&emitter);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (C) 2018-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
|
||||
hostprogs-y := ufdt_apply_overlay extract_dtb
|
||||
always := $(hostprogs-y)
|
||||
|
||||
common-objects := ufdt_convert.o ufdt_node.o ufdt_node_pool.o ufdt_overlay.o ufdt_prop_dict.o tests/src/util.o sysdeps/libufdt_sysdeps_posix.o ../../dtc-aosp/dtc/libfdt/fdt.o ../../dtc-aosp/dtc/libfdt/fdt_sw.o ../../dtc-aosp/dtc/libfdt/fdt_ro.o ../../dtc-aosp/dtc/libfdt/fdt_rw.o ../../dtc-aosp/dtc/libfdt/fdt_wip.o ../../dtc-aosp/dtc/libfdt/fdt_strerror.o
|
||||
|
||||
# We're working with a submodule, so make these all relative to that.
|
||||
common-objects := $(addprefix libufdt/,$(common-objects))
|
||||
|
||||
ufdt_apply_overlay-objs := libufdt/tests/src/ufdt_overlay_test_app.o $(common-objects)
|
||||
extract_dtb-objs := libufdt/tests/src/extract_dtb.o $(common-objects)
|
||||
|
||||
HOSTCFLAGS_LIBUFDT := -I$(src)/libufdt/include -I$(src)/libufdt/sysdeps/include -std=c99 -Wno-missing-prototypes -Wno-strict-prototypes -Wno-format -I$(src)/../dtc-aosp/dtc/libfdt
|
||||
HOSTCFLAGS_ufdt_convert.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_ufdt_node.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_ufdt_node_pool.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_ufdt_overlay.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_ufdt_prop_dict.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_ufdt_overlay_test_app.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_extract_dtb.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_util.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
HOSTCFLAGS_libufdt_sysdeps_posix.o := $(HOSTCFLAGS_LIBUFDT)
|
||||
|
||||
HOSTCFLAGS_LIBFDT := -I$(src)/../dtc-aosp/dtc/libfdt
|
||||
HOSTCFLAGS_fdt.o := $(HOSTCFLAGS_LIBFDT)
|
||||
HOSTCFLAGS_fdt_sw.o := $(HOSTCFLAGS_LIBFDT)
|
||||
HOSTCFLAGS_fdt_ro.o := $(HOSTCFLAGS_LIBFDT)
|
||||
HOSTCFLAGS_fdt_rw.o := $(HOSTCFLAGS_LIBFDT)
|
||||
HOSTCFLAGS_fdt_wip.o := $(HOSTCFLAGS_LIBFDT)
|
||||
HOSTCFLAGS_fdt_strerror.o := $(HOSTCFLAGS_LIBFDT)
|
@ -1,18 +0,0 @@
|
||||
gensrcs {
|
||||
name: "qcom-audio-kernel-includes",
|
||||
cmd: "$(location headers_install.sh) `dirname $(out)` `dirname $(in)` `basename $(in)`",
|
||||
tools: ["headers_install.sh"],
|
||||
export_include_dirs: ["include/uapi"],
|
||||
srcs: [
|
||||
"include/uapi/**/*.h",
|
||||
],
|
||||
output_extension: "h",
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "qcom_audio_kernel_headers",
|
||||
generated_headers: ["qcom-audio-kernel-includes"],
|
||||
export_generated_headers: ["qcom-audio-kernel-includes"],
|
||||
vendor: true,
|
||||
recovery_available: true,
|
||||
}
|
Loading…
Reference in New Issue
Block a user