Inline the kernel

This commit is contained in:
mikairyuu 2021-12-24 12:10:41 +10:00
parent f9e8047d31
commit b2b74a3f0d
52 changed files with 2174 additions and 1645 deletions

6
.gitmodules vendored
View File

@ -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

View File

@ -1649,12 +1649,6 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
Space separated list of names of dtbs to append when Space separated list of names of dtbs to append when
building a concatenated Image.gz-dtb. 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 choice
prompt "Kernel compression method" prompt "Kernel compression method"
default BUILD_ARM64_KERNEL_COMPRESSION_GZIP default BUILD_ARM64_KERNEL_COMPRESSION_GZIP

View File

@ -159,8 +159,6 @@ endif
KBUILD_DTBS := dtbs KBUILD_DTBS := dtbs
KBUILD_DTBO_IMG := dtbo.img
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
export DTC_FLAGS := -@ export DTC_FLAGS := -@
endif endif
@ -184,12 +182,6 @@ PHONY += dtbs dtbs_install
dtbs: prepare scripts dtbs: prepare scripts
$(Q)$(MAKE) $(build)=$(boot)/dts $(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: dtbs_install:
$(Q)$(MAKE) $(dtbinst)=$(boot)/dts $(Q)$(MAKE) $(dtbinst)=$(boot)/dts
@ -199,9 +191,6 @@ Image-dtb: vmlinux scripts dtbs
Image.gz-dtb: vmlinux scripts dtbs Image.gz Image.gz-dtb: vmlinux scripts dtbs Image.gz
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
dtbo.img: $(boot)/dts/dtboimg.cfg dtbs
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
PHONY += vdso_install PHONY += vdso_install
vdso_install: vdso_install:
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
@ -212,9 +201,6 @@ archclean:
$(Q)$(MAKE) $(clean)=$(boot) $(Q)$(MAKE) $(clean)=$(boot)
$(Q)$(MAKE) $(clean)=$(boot)/dts $(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),) ifeq ($(KBUILD_EXTMOD),)
# We need to generate vdso-offsets.h before compiling certain files in kernel/. # 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 # In order to do that, we should use the archprepare target, but we can't since

View File

@ -2,4 +2,3 @@ Image
Image-dtb Image-dtb
Image.gz Image.gz
Image.gz-dtb Image.gz-dtb
dtbo.img

View File

@ -28,8 +28,6 @@ DTB_LIST := $(dtb-y)
endif endif
DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb) 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 # Add RTIC DTB to the DTB list if RTIC MPGen is enabled
# Note, we keep this for compatibility with # Note, we keep this for compatibility with
# BUILD_ARM64_APPENDED_DTB_IMAGE targets. # 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 $(obj)/Image-dtb: $(obj)/Image-dtb-hdr $(obj)/Image $(DTB_OBJS) FORCE
$(call if_changed,cat) $(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 $(obj)/Image.gz: $(obj)/Image FORCE
$(call if_changed,gzip) $(call if_changed,gzip)
@ -75,10 +68,6 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE $(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE
$(call if_changed,cat) $(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: install:
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
$(obj)/Image System.map "$(INSTALL_PATH)" $(obj)/Image System.map "$(INSTALL_PATH)"

View File

@ -1 +0,0 @@
arch/arm64/boot/dts/vendor/qcom/monet-sm7250-overlay.dtbo

View File

@ -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

View File

@ -102,7 +102,6 @@ CONFIG_SETEND_EMULATION=y
CONFIG_RANDOMIZE_BASE=y CONFIG_RANDOMIZE_BASE=y
# CONFIG_EFI is not set # CONFIG_EFI is not set
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
CONFIG_BUILD_ARM64_EMBEDDED_DTB=y
CONFIG_BUILD_ARM64_DT_OVERLAY=y CONFIG_BUILD_ARM64_DT_OVERLAY=y
CONFIG_COMPAT=y CONFIG_COMPAT=y
CONFIG_COMPAT_VDSO=y CONFIG_COMPAT_VDSO=y

View File

@ -98,7 +98,7 @@ extern void init_mem_pgprot(void);
extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
unsigned long virt, phys_addr_t size, unsigned long virt, phys_addr_t size,
pgprot_t prot, bool page_mappings_only); 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); extern void mark_linear_text_alias_ro(void);
#ifdef CONFIG_MEMORY_HOTPLUG #ifdef CONFIG_MEMORY_HOTPLUG
extern void hotplug_paging(phys_addr_t start, phys_addr_t size); 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
#endif #endif
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
extern void select_embedded_dt(void *dt_virt) __init;
#endif
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
#endif #endif

View File

@ -70,8 +70,6 @@ obj-$(CONFIG_COMPAT_VDSO) += vdso32/
head-y := head.o head-y := head.o
extra-y += $(head-y) vmlinux.lds extra-y += $(head-y) vmlinux.lds
obj-$(CONFIG_BUILD_ARM64_EMBEDDED_DTB) += embedded-dtb.o select-embedded-dt.o
ifeq ($(CONFIG_DEBUG_EFI),y) ifeq ($(CONFIG_DEBUG_EFI),y)
AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\"" AFLAGS_head.o += -DVMLINUX_PATH="\"$(realpath $(objtree)/vmlinux)\""
endif endif

View File

@ -65,9 +65,6 @@ out:
return default_cmdline; 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 * 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 * 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() * attempt at mapping the FDT in setup_machine()
*/ */
early_fixmap_init(); early_fixmap_init();
fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL); fdt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
if (!fdt) if (!fdt)
return 0; return 0;

View File

@ -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;
}
}

View File

@ -191,12 +191,12 @@ static void __init smp_build_mpidr_hash(void)
static void __init setup_machine_fdt(phys_addr_t dt_phys) 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; const char *name;
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB if (dt_virt)
select_embedded_dt(dt_virt); memblock_reserve(dt_phys, size);
#endif
if (!dt_virt || !early_init_dt_scan(dt_virt)) { if (!dt_virt || !early_init_dt_scan(dt_virt)) {
pr_crit("\n" pr_crit("\n"
@ -209,6 +209,9 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
cpu_relax(); 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(); name = of_flat_dt_get_machine_name();
if (!name) if (!name)
return; return;

View File

@ -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); const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
int offset; 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) if (fdt_magic(dt_virt) != FDT_MAGIC)
return NULL; return NULL;
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
*size = MAX_FDT_SIZE;
#else
*size = fdt_totalsize(dt_virt); *size = fdt_totalsize(dt_virt);
if (*size > MAX_FDT_SIZE) if (*size > MAX_FDT_SIZE)
return NULL; return NULL;
#endif
if (offset + *size > SWAPPER_BLOCK_SIZE) if (offset + *size > SWAPPER_BLOCK_SIZE)
create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base, 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; return dt_virt;
} }
void *__init fixmap_remap_fdt(phys_addr_t dt_phys) int __init arch_ioremap_p4d_supported(void)
{ {
void *dt_virt; return 0;
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;
} }
int __init arch_ioremap_pud_supported(void) int __init arch_ioremap_pud_supported(void)

View File

@ -46,8 +46,7 @@ build_unifdef: $(obj)/unifdef
subdir-$(CONFIG_MODVERSIONS) += genksyms subdir-$(CONFIG_MODVERSIONS) += genksyms
subdir-y += mod subdir-y += mod
subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_DTC) += dtc-aosp subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_BUILD_ARM64_EMBEDDED_DTB) += ufdt
subdir-$(CONFIG_GDB_SCRIPTS) += gdb subdir-$(CONFIG_GDB_SCRIPTS) += gdb
# Let clean descend into subdirs # Let clean descend into subdirs

View File

@ -253,7 +253,10 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
# DTC # DTC
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
DTC ?= $(objtree)/scripts/dtc-aosp/dtc-aosp DTC ?= $(objtree)/scripts/dtc/dtc
# Silence noisy warnings
DTC_FLAGS += -q
# Disable noisy checks by default # Disable noisy checks by default
ifeq ($(findstring 1,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),) ifeq ($(findstring 1,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),)
@ -262,7 +265,8 @@ endif
ifneq ($(findstring 2,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),) ifneq ($(findstring 2,$(KBUILD_ENABLE_EXTRA_GCC_CHECKS)),)
DTC_FLAGS += -Wnode_name_chars_strict \ DTC_FLAGS += -Wnode_name_chars_strict \
-Wproperty_name_chars_strict -Wproperty_name_chars_strict \
-Winterrupt_provider
endif endif
DTC_FLAGS += $(DTC_FLAGS_$(basetarget)) DTC_FLAGS += $(DTC_FLAGS_$(basetarget))
@ -301,11 +305,6 @@ $(obj)/%.dtb: $(src)/%.dts $(DTC) FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) 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 # cat
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Concatentate multiple files together # Concatentate multiple files together

View File

@ -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

View File

@ -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 # Source files need to get at the userspace version of libfdt_env.h to compile
HOST_EXTRACFLAGS := -I$(src)/libfdt 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 # Generated files need one more search path to include headers in source tree
HOSTCFLAGS_dtc-lexer.lex.o := -I$(src) HOSTCFLAGS_dtc-lexer.lex.o := -I$(src)
HOSTCFLAGS_dtc-parser.tab.o := -I$(src) HOSTCFLAGS_dtc-parser.tab.o := -I$(src)

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Makefile.dtc # Makefile.dtc
# #
# This is not a complete Makefile of itself. Instead, it is designed to # This is not a complete Makefile of itself. Instead, it is designed to
@ -14,5 +15,9 @@ DTC_SRCS = \
treesource.c \ treesource.c \
util.c util.c
ifneq ($(NO_YAML),1)
DTC_SRCS += yamltree.c
endif
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)

View File

@ -1,24 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007. * (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 "dtc.h"
#include "srcpos.h"
#ifdef TRACE_CHECKS #ifdef TRACE_CHECKS
#define TRACE(c, ...) \ #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, ...) const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); char *str = NULL;
struct srcpos *pos = NULL;
char *file_str;
if ((c->warn && (quiet < 1)) if (!(c->warn && (quiet < 1)) && !(c->error && (quiet < 2)))
|| (c->error && (quiet < 2))) { return;
fprintf(stderr, "%s: %s (%s): ",
strcmp(dti->outname, "-") ? dti->outname : "<stdout>", if (prop && prop->srcpos)
(c->error) ? "ERROR" : "Warning", c->name); pos = prop->srcpos;
if (node) { else if (node && node->srcpos)
fprintf(stderr, "%s", node->fullpath); pos = node->srcpos;
if (prop)
fprintf(stderr, ":%s", prop->name); if (pos) {
fputs(": ", stderr); file_str = srcpos_string(pos);
} xasprintf(&str, "%s", file_str);
vfprintf(stderr, fmt, ap); free(file_str);
fprintf(stderr, "\n"); } 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) {
if (prop)
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); 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, ...) \ #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"); FAIL(c, dti, node, "node has a reg or ranges property, but no unit name");
} else { } else {
if (unitname[0]) 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); 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, static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
struct node *node) struct node *node)
{ {
if (generate_symbols && node->labels)
return;
if (node->omit_if_unused && !node->is_referenced) if (node->omit_if_unused && !node->is_referenced)
delete_node(node); delete_node(node);
} }
@ -670,6 +691,11 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
return; return;
for_each_property(node, prop) { 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)) { 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)", FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val); prop->val.val);
@ -739,13 +765,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
{ {
struct property *prop; struct property *prop;
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; 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) if (!prop)
return; return;
if (!node->parent) { 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; return;
} }
@ -757,23 +785,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
if (prop->val.len == 0) { if (prop->val.len == 0) {
if (p_addr_cells != c_addr_cells) 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)", "#address-cells (%d) differs from %s (%d)",
c_addr_cells, node->parent->fullpath, ranges, c_addr_cells, node->parent->fullpath,
p_addr_cells); p_addr_cells);
if (p_size_cells != c_size_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)", "#size-cells (%d) differs from %s (%d)",
c_size_cells, node->parent->fullpath, ranges, c_size_cells, node->parent->fullpath,
p_size_cells); p_size_cells);
} else if ((prop->val.len % entrylen) != 0) { } 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, " "(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); 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 = { static const struct bus_type pci_bus = {
.name = "PCI", .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; for (str = prop->val.val, end = str + prop->val.len; str < end;
str += strnlen(str, end - str) + 1) { str += strnlen(str, end - str) + 1) {
if (strprefixeq(str, end - str, compat)) if (streq(str, compat))
return true; return true;
} }
return false; 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")) if (node_is_compatible(node, "simple-bus"))
node->bus = &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) 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, &reg_format, &simple_bus_bridge); WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_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, &reg_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, &reg_format, &spi_bus_bridge);
static void check_unit_address_format(struct check *c, struct dt_info *dti, static void check_unit_address_format(struct check *c, struct dt_info *dti,
struct node *node) 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); 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, static bool node_is_disabled(struct node *node)
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; struct node *childa;
@ -1052,18 +1251,38 @@ static void check_unique_unit_address(struct check *c, struct dt_info *dti,
if (!strlen(addr_a)) if (!strlen(addr_a))
continue; continue;
if (disable_check && node_is_disabled(childa))
continue;
for_each_child(node, childb) { for_each_child(node, childb) {
const char *addr_b = get_unitname(childb); const char *addr_b = get_unitname(childb);
if (childa == childb) if (childa == childb)
break; break;
if (disable_check && node_is_disabled(childb))
continue;
if (streq(addr_a, addr_b)) if (streq(addr_a, addr_b))
FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath); 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); 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, static void check_obsolete_chosen_interrupt_controller(struct check *c,
struct dt_info *dti, struct dt_info *dti,
struct node *node) struct node *node)
@ -1338,6 +1557,28 @@ static bool node_is_interrupt_provider(struct node *node)
return false; 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, static void check_interrupts_property(struct check *c,
struct dt_info *dti, struct dt_info *dti,
struct node *node) struct node *node)
@ -1364,10 +1605,14 @@ static void check_interrupts_property(struct check *c,
prop = get_property(parent, "interrupt-parent"); prop = get_property(parent, "interrupt-parent");
if (prop) { if (prop) {
phandle = propval_cell(prop); phandle = propval_cell(prop);
/* Give up if this is an overlay with external references */ if ((phandle == 0) || (phandle == -1)) {
if ((phandle == 0 || phandle == -1) && /* Give up if this is an overlay with
(dti->dtsflags & DTSF_PLUGIN)) * external references */
if (dti->dtsflags & DTSF_PLUGIN)
return; return;
FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
continue;
}
irq_node = get_node_by_phandle(root, phandle); irq_node = get_node_by_phandle(root, phandle);
if (!irq_node) { if (!irq_node) {
@ -1391,7 +1636,7 @@ static void check_interrupts_property(struct check *c,
prop = get_property(irq_node, "#interrupt-cells"); prop = get_property(irq_node, "#interrupt-cells");
if (!prop) { if (!prop) {
FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent"); /* We warn about that already in another test. */
return; return;
} }
@ -1536,7 +1781,7 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
return; return;
if (!strprefixeq(node->name, node->basenamelen, "endpoint")) 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); check_graph_reg(c, dti, node);
@ -1570,7 +1815,7 @@ static struct check *check_table[] = {
&property_name_chars_strict, &property_name_chars_strict,
&node_name_chars_strict, &node_name_chars_strict,
&addr_size_cells, &reg_format, &ranges_format, &addr_size_cells, &reg_format, &ranges_format, &dma_ranges_format,
&unit_address_vs_reg, &unit_address_vs_reg,
&unit_address_format, &unit_address_format,
@ -1582,9 +1827,16 @@ static struct check *check_table[] = {
&simple_bus_bridge, &simple_bus_bridge,
&simple_bus_reg, &simple_bus_reg,
&i2c_bus_bridge,
&i2c_bus_reg,
&spi_bus_bridge,
&spi_bus_reg,
&avoid_default_addr_size, &avoid_default_addr_size,
&avoid_unnecessary_addr_size, &avoid_unnecessary_addr_size,
&unique_unit_address, &unique_unit_address,
&unique_unit_address_if_enabled,
&obsolete_chosen_interrupt_controller, &obsolete_chosen_interrupt_controller,
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
@ -1608,6 +1860,7 @@ static struct check *check_table[] = {
&deprecated_gpio_property, &deprecated_gpio_property,
&gpios_property, &gpios_property,
&interrupts_property, &interrupts_property,
&interrupt_provider,
&alias_paths, &alias_paths,

View File

@ -1,21 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 "dtc.h"
@ -74,7 +59,8 @@ struct data data_copy_escape_string(const char *s, int len)
struct data d; struct data d;
char *q; 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; q = d.val;
while (i < len) { while (i < len) {
@ -94,6 +80,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{ {
struct data d = empty_data; struct data d = empty_data;
d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) { while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret; size_t chunksize, ret;

View File

@ -1,21 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 %option noyywrap nounput noinput never-interactive
@ -212,14 +197,14 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
<*>\&{LABEL} { /* label reference */ <*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1); DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1); yylval.labelref = xstrdup(yytext+1);
return DT_REF; return DT_LABEL_REF;
} }
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */ <*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0'; yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2); DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2); yylval.labelref = xstrdup(yytext+2);
return DT_REF; return DT_PATH_REF;
} }
<BYTESTRING>[0-9a-fA-F]{2} { <BYTESTRING>[0-9a-fA-F]{2} {

View File

@ -1,22 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 <stdio.h>
#include <inttypes.h> #include <inttypes.h>
@ -32,6 +19,8 @@ extern void yyerror(char const *s);
treesource_error = true; \ treesource_error = true; \
} while (0) } while (0)
#define YYERROR_CALL(msg) yyerror(msg)
extern struct dt_info *parser_output; extern struct dt_info *parser_output;
extern bool treesource_error; extern bool treesource_error;
%} %}
@ -70,7 +59,8 @@ extern bool treesource_error;
%token <byte> DT_BYTE %token <byte> DT_BYTE
%token <data> DT_STRING %token <data> DT_STRING
%token <labelref> DT_LABEL %token <labelref> DT_LABEL
%token <labelref> DT_REF %token <labelref> DT_LABEL_REF
%token <labelref> DT_PATH_REF
%token DT_INCBIN %token DT_INCBIN
%type <data> propdata %type <data> propdata
@ -83,6 +73,7 @@ extern bool treesource_error;
%type <data> bytestring %type <data> bytestring
%type <prop> propdef %type <prop> propdef
%type <proplist> proplist %type <proplist> proplist
%type <labelref> dt_ref
%type <node> devicetree %type <node> devicetree
%type <node> nodedef %type <node> nodedef
@ -158,6 +149,8 @@ memreserve:
} }
; ;
dt_ref: DT_LABEL_REF | DT_PATH_REF;
devicetree: devicetree:
'/' nodedef '/' nodedef
{ {
@ -167,7 +160,7 @@ devicetree:
{ {
$$ = merge_nodes($1, $3); $$ = merge_nodes($1, $3);
} }
| DT_REF nodedef | dt_ref nodedef
{ {
/* /*
* We rely on the rule being always: * We rely on the rule being always:
@ -176,9 +169,12 @@ devicetree:
*/ */
if (!($<flags>-1 & DTSF_PLUGIN)) if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1); 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); struct node *target = get_node_by_ref($1, $3);
@ -189,7 +185,7 @@ devicetree:
ERROR(&@3, "Label or path %s not found", $3); ERROR(&@3, "Label or path %s not found", $3);
$$ = $1; $$ = $1;
} }
| devicetree DT_REF nodedef | devicetree DT_PATH_REF nodedef
{ {
/* /*
* We rely on the rule being always: * We rely on the rule being always:
@ -208,7 +204,26 @@ devicetree:
} }
$$ = $1; $$ = $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); struct node *target = get_node_by_ref($1, $3);
@ -220,7 +235,7 @@ devicetree:
$$ = $1; $$ = $1;
} }
| devicetree DT_OMIT_NO_REF DT_REF ';' | devicetree DT_OMIT_NO_REF dt_ref ';'
{ {
struct node *target = get_node_by_ref($1, $3); struct node *target = get_node_by_ref($1, $3);
@ -237,7 +252,7 @@ devicetree:
nodedef: nodedef:
'{' proplist subnodes '}' ';' '{' proplist subnodes '}' ';'
{ {
$$ = build_node($2, $3); $$ = build_node($2, $3, &@$);
} }
; ;
@ -255,11 +270,11 @@ proplist:
propdef: propdef:
DT_PROPNODENAME '=' propdata ';' DT_PROPNODENAME '=' propdata ';'
{ {
$$ = build_property($1, $3); $$ = build_property($1, $3, &@$);
} }
| DT_PROPNODENAME ';' | DT_PROPNODENAME ';'
{ {
$$ = build_property($1, empty_data); $$ = build_property($1, empty_data, &@$);
} }
| DT_DEL_PROP DT_PROPNODENAME ';' | DT_DEL_PROP DT_PROPNODENAME ';'
{ {
@ -285,8 +300,9 @@ propdata:
{ {
$$ = data_merge($1, $3); $$ = 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); $$ = data_add_marker($1, REF_PATH, $2);
} }
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@ -340,22 +356,27 @@ arrayprefix:
DT_BITS DT_LITERAL '<' DT_BITS DT_LITERAL '<'
{ {
unsigned long long bits; unsigned long long bits;
enum markertype type = TYPE_UINT32;
bits = $2; bits = $2;
if ((bits != 8) && (bits != 16) && switch (bits) {
(bits != 32) && (bits != 64)) { 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" ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits"); " 8, 16, 32 or 64-bits");
bits = 32; bits = 32;
} }
$$.data = empty_data; $$.data = data_add_marker(empty_data, type, NULL);
$$.bits = bits; $$.bits = bits;
} }
| '<' | '<'
{ {
$$.data = empty_data; $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
$$.bits = 32; $$.bits = 32;
} }
| arrayprefix integer_prim | arrayprefix integer_prim
@ -377,7 +398,7 @@ arrayprefix:
$$.data = data_append_integer($1.data, $2, $1.bits); $$.data = data_append_integer($1.data, $2, $1.bits);
} }
| arrayprefix DT_REF | arrayprefix dt_ref
{ {
uint64_t val = ~0ULL >> (64 - $1.bits); uint64_t val = ~0ULL >> (64 - $1.bits);
@ -499,7 +520,7 @@ integer_unary:
bytestring: bytestring:
/* empty */ /* empty */
{ {
$$ = empty_data; $$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
} }
| bytestring DT_BYTE | bytestring DT_BYTE
{ {
@ -534,7 +555,7 @@ subnode:
} }
| DT_DEL_NODE DT_PROPNODENAME ';' | DT_DEL_NODE DT_PROPNODENAME ';'
{ {
$$ = name_node(build_node_delete(), $2); $$ = name_node(build_node_delete(&@$), $2);
} }
| DT_OMIT_NO_REF subnode | DT_OMIT_NO_REF subnode
{ {

View File

@ -1,21 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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> #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_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */ int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */ 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) 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. */ /* Usage related data. */
static const char usage_synopsis[] = "dtc [options] <input file>"; 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[] = { static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'}, {"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'}, {"in-format", a_argument, NULL, 'I'},
@ -81,6 +68,7 @@ static struct option const usage_long_opts[] = {
{"error", a_argument, NULL, 'E'}, {"error", a_argument, NULL, 'E'},
{"symbols", no_argument, NULL, '@'}, {"symbols", no_argument, NULL, '@'},
{"auto-alias", no_argument, NULL, 'A'}, {"auto-alias", no_argument, NULL, 'A'},
{"annotate", no_argument, NULL, 'T'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0}, {NULL, no_argument, NULL, 0x0},
@ -95,6 +83,9 @@ static const char * const usage_opts_help[] = {
"\n\tOutput formats are:\n" "\n\tOutput formats are:\n"
"\t\tdts - device tree source text\n" "\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n" "\t\tdtb - device tree blob\n"
#ifndef NO_YAML
"\t\tyaml - device tree encoded as YAML\n"
#endif
"\t\tasm - assembler source", "\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)", "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file", "\n\tOutput dependency file",
@ -114,6 +105,7 @@ static const char * const usage_opts_help[] = {
"\n\tEnable/disable errors (prefix with \"no-\")", "\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tEnable generation of symbols", "\n\tEnable generation of symbols",
"\n\tEnable auto-alias of labels", "\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 this help and exit",
"\n\tPrint version and exit", "\n\tPrint version and exit",
NULL, NULL,
@ -128,6 +120,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
return fallback; return fallback;
if (!strcasecmp(s, ".dts")) if (!strcasecmp(s, ".dts"))
return "dts"; return "dts";
if (!strcasecmp(s, ".yaml"))
return "yaml";
if (!strcasecmp(s, ".dtb")) if (!strcasecmp(s, ".dtb"))
return "dtb"; return "dtb";
return fallback; return fallback;
@ -259,6 +253,9 @@ int main(int argc, char *argv[])
case 'A': case 'A':
auto_label_aliases = 1; auto_label_aliases = 1;
break; break;
case 'T':
annotate++;
break;
case 'h': case 'h':
usage(NULL); usage(NULL);
@ -297,6 +294,8 @@ int main(int argc, char *argv[])
outform = "dts"; outform = "dts";
} }
} }
if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
die("--annotate requires -I dts -O dts\n");
if (streq(inform, "dts")) if (streq(inform, "dts"))
dti = dt_from_source(arg); dti = dt_from_source(arg);
else if (streq(inform, "fs")) else if (streq(inform, "fs"))
@ -350,6 +349,12 @@ int main(int argc, char *argv[])
if (streq(outform, "dts")) { if (streq(outform, "dts")) {
dt_to_source(outf, dti); 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")) { } else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion); dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) { } else if (streq(outform, "asm")) {

View File

@ -1,24 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef DTC_H #ifndef DTC_H
#define DTC_H #define DTC_H
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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> #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_symbols; /* generate symbols for nodes with labels */
extern int generate_fixups; /* generate fixups */ extern int generate_fixups; /* generate fixups */
extern int auto_label_aliases; /* auto generate labels -> aliases */ extern int auto_label_aliases; /* auto generate labels -> aliases */
extern int annotate; /* annotate .dts with input source location */
#define PHANDLE_LEGACY 0x1 #define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2 #define PHANDLE_EPAPR 0x2
@ -65,6 +51,37 @@ extern int auto_label_aliases; /* auto generate labels -> aliases */
typedef uint32_t cell_t; 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 streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0) #define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
@ -74,10 +91,17 @@ typedef uint32_t cell_t;
/* Data blobs */ /* Data blobs */
enum markertype { enum markertype {
TYPE_NONE,
REF_PHANDLE, REF_PHANDLE,
REF_PATH, REF_PATH,
LABEL, LABEL,
TYPE_UINT8,
TYPE_UINT16,
TYPE_UINT32,
TYPE_UINT64,
TYPE_STRING,
}; };
extern const char *markername(enum markertype markertype);
struct marker { struct marker {
enum markertype type; enum markertype type;
@ -101,6 +125,8 @@ struct data {
for_each_marker(m) \ for_each_marker(m) \
if ((m)->type == (t)) if ((m)->type == (t))
size_t type_marker_length(struct marker *m);
void data_free(struct data d); void data_free(struct data d);
struct data data_grow_for(struct data d, int xlen); struct data data_grow_for(struct data d, int xlen);
@ -149,6 +175,7 @@ struct property {
struct property *next; struct property *next;
struct label *labels; struct label *labels;
struct srcpos *srcpos;
}; };
struct node { struct node {
@ -168,6 +195,7 @@ struct node {
struct label *labels; struct label *labels;
const struct bus_type *bus; const struct bus_type *bus;
struct srcpos *srcpos;
bool omit_if_unused, is_referenced; bool omit_if_unused, is_referenced;
}; };
@ -196,13 +224,15 @@ struct node {
void add_label(struct label **labels, char *label); void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels); 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 *build_property_delete(char *name);
struct property *chain_property(struct property *first, struct property *list); struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first); struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children); struct node *build_node(struct property *proplist, struct node *children,
struct node *build_node_delete(void); struct srcpos *srcpos);
struct node *build_node_delete(struct srcpos *srcpos);
struct node *name_node(struct node *node, char *name); struct node *name_node(struct node *node, char *name);
struct node *omit_node_if_unused(struct node *node); struct node *omit_node_if_unused(struct node *node);
struct node *reference_node(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_by_name(struct node *parent, char *name);
void delete_node(struct node *node); void delete_node(struct node *node);
void append_to_property(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); const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname); 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); void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f); struct dt_info *dt_from_source(const char *f);
/* YAML source */
void dt_to_yaml(FILE *f, struct dt_info *dti);
/* FS trees */ /* FS trees */
struct dt_info *dt_from_fs(const char *dirname); struct dt_info *dt_from_fs(const char *dirname);

View File

@ -1,21 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 "dtc.h"
@ -171,7 +156,7 @@ static void asm_emit_data(void *e, struct data d)
emit_offset_label(f, m->ref, m->offset); emit_offset_label(f, m->ref, m->offset);
while ((d.len - off) >= sizeof(uint32_t)) { 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); off += sizeof(uint32_t);
} }
@ -393,7 +378,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
padlen = 0; padlen = 0;
if (quiet < 1) if (quiet < 1)
fprintf(stderr, fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n", "Warning: blob size %"PRIu32" >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize); 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"); 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. * as it appears .quad isn't available in some assemblers.
*/ */
for (re = dti->reservelist; re; re = re->next) { 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); 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; char *flatname;
uint32_t val; uint32_t val;
node = build_node(NULL, NULL); node = build_node(NULL, NULL, NULL);
flatname = flat_read_string(dtbuf); flatname = flat_read_string(dtbuf);

View File

@ -1,21 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 "dtc.h"
@ -34,7 +19,7 @@ static struct node *read_fstree(const char *dirname)
if (!d) if (!d)
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno)); 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) { while ((de = readdir(d)) != NULL) {
char *tmpname; char *tmpname;
@ -45,7 +30,7 @@ static struct node *read_fstree(const char *dirname)
tmpname = join_path(dirname, de->d_name); 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)); die("stat(%s): %s\n", tmpname, strerror(errno));
if (S_ISREG(st.st_mode)) { if (S_ISREG(st.st_mode)) {
@ -60,7 +45,8 @@ static struct node *read_fstree(const char *dirname)
} else { } else {
prop = build_property(xstrdup(de->d_name), prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile, data_copy_file(pfile,
st.st_size)); st.st_size),
NULL);
add_property(tree, prop); add_property(tree, prop);
fclose(pfile); fclose(pfile);
} }

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
# Makefile.libfdt # Makefile.libfdt
# #
# This is not a complete Makefile of itself. Instead, it is designed to # 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 \ 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 fdt_addresses.c fdt_overlay.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) 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)

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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 "libfdt_env.h"
@ -55,35 +10,124 @@
#include "libfdt_internal.h" #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) { if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */ /* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) if (!can_assume(LATEST)) {
return -FDT_ERR_BADVERSION; if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION;
return -FDT_ERR_BADVERSION; if (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */ /* 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; return -FDT_ERR_BADSTATE;
} else { } else {
return -FDT_ERR_BADMAGIC; return -FDT_ERR_BADMAGIC;
} }
if (fdt_off_dt_struct(fdt) > (UINT_MAX - fdt_size_dt_struct(fdt))) if (totalsize < INT32_MAX)
return FDT_ERR_BADOFFSET; return totalsize;
else
return -FDT_ERR_TRUNCATED;
}
if (fdt_off_dt_strings(fdt) > (UINT_MAX - fdt_size_dt_strings(fdt))) static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
return FDT_ERR_BADOFFSET; {
return (off >= hdrsize) && (off <= totalsize);
}
if ((fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt)) static int check_block_(uint32_t hdrsize, uint32_t totalsize,
> fdt_totalsize(fdt)) uint32_t base, uint32_t size)
return FDT_ERR_BADOFFSET; {
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)) size_t fdt_header_size_(uint32_t version)
> fdt_totalsize(fdt)) {
return FDT_ERR_BADOFFSET; 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; 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); unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if ((absoffset < offset) if (!can_assume(VALID_INPUT))
|| ((absoffset + len) < absoffset) if ((absoffset < offset)
|| (absoffset + len) > fdt_totalsize(fdt)) || ((absoffset + len) < absoffset)
return NULL; || (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (fdt_version(fdt) >= 0x11) if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
if (((offset + len) < offset) if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt))) || ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL; return NULL;
@ -114,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED; *nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!tagp) if (!can_assume(VALID_DTB) && !tagp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp); tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE; offset += FDT_TAGSIZE;
@ -126,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do { do {
p = fdt_offset_ptr(fdt, offset++, 1); p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0')); } while (p && (*p != '\0'));
if (!p) if (!can_assume(VALID_DTB) && !p)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
break; break;
case FDT_PROP: case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!lenp) if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */ return FDT_END; /* premature end */
/* skip-name offset, length and value */ /* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp); + 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 - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4; offset += 4;
break; 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) int fdt_check_node_offset_(const void *fdt, int offset)
{ {
if (can_assume(VALID_INPUT))
return offset;
if ((offset < 0) || (offset % FDT_TAGSIZE) if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
return -FDT_ERR_BADOFFSET; 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) int fdt_move(const void *fdt, void *buf, int bufsize)
{ {
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize) if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;

View File

@ -1,55 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef FDT_H #ifndef FDT_H
#define FDT_H #define FDT_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor. * 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__ #ifndef __ASSEMBLY__

View File

@ -1,52 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
* * Copyright (C) 2018 embedded brains GmbH
* 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 "libfdt_env.h"
@ -55,42 +11,91 @@
#include "libfdt_internal.h" #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; const fdt32_t *c;
int val; uint32_t val;
int len; int len;
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); c = fdt_getprop(fdt, nodeoffset, name, &len);
if (!ac) 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; 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; return val;
} }
int fdt_size_cells(const void *fdt, int nodeoffset) int fdt_size_cells(const void *fdt, int nodeoffset)
{ {
const fdt32_t *sc;
int val; 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; 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));
}

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation. * 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" #include "libfdt_env.h"

View File

@ -1,53 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2016 Free Electrons * Copyright (C) 2016 Free Electrons
* Copyright (C) 2016 NextThing Co. * 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" #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) * @pathp: pointer which receives the path of the target (or NULL)
* *
* overlay_get_target() retrieves the target offset in the base * 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) * done (through a phandle or a path)
* *
* returns: * returns:
* the targetted node offset in the base device tree * the targeted node offset in the base device tree
* Negative error code on error * Negative error code on error
*/ */
static int overlay_get_target(const void *fdt, const void *fdto, 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; int len = 0, namelen;
const char *name; const char *name;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
for (;;) { for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen); 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() */ /* keep end marker to avoid strlen() */
e = path + path_len; e = path + path_len;
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
if (*path != '/') if (*path != '/')
return -FDT_ERR_BADVALUE; return -FDT_ERR_BADVALUE;
/* get fragment name first */ /* get fragment name first */
s = strchr(path + 1, '/'); s = strchr(path + 1, '/');
if (!s) if (!s) {
return -FDT_ERR_BADOVERLAY; /* Symbol refers to something that won't end
* up in the target tree */
continue;
}
frag_name = path + 1; frag_name = path + 1;
frag_name_len = s - path - 1; frag_name_len = s - path - 1;
/* verify format; safe since "s" lies in \0 terminated prop */ /* verify format; safe since "s" lies in \0 terminated prop */
len = sizeof("/__overlay__/") - 1; len = sizeof("/__overlay__/") - 1;
if ((e - s) < len || memcmp(s, "/__overlay__/", len)) if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
return -FDT_ERR_BADOVERLAY; /* /<fragment-name>/__overlay__/<relative-subnode-path> */
rel_path = s + len;
rel_path = s + len; rel_path_len = e - rel_path - 1;
rel_path_len = e - rel_path; } 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 */ /* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 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) int fdt_overlay_apply(void *fdt, void *fdto)
{ {
uint32_t delta = fdt_get_max_phandle(fdt); uint32_t delta;
int ret; int ret;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
FDT_CHECK_HEADER(fdto); FDT_RO_PROBE(fdto);
ret = fdt_find_max_phandle(fdt, &delta);
if (ret)
goto err;
ret = overlay_adjust_local_phandles(fdto, delta); ret = overlay_adjust_local_phandles(fdto, delta);
if (ret) if (ret)

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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 "libfdt_env.h"
@ -76,60 +31,169 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
return 0; 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) 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, static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len) 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; uint32_t max = 0;
int offset; int offset = -1;
for (offset = fdt_next_node(fdt, -1, NULL);; while (true) {
offset = fdt_next_node(fdt, offset, NULL)) { uint32_t value;
uint32_t phandle;
if (offset == -FDT_ERR_NOTFOUND) offset = fdt_next_node(fdt, offset, NULL);
return max_phandle; if (offset < 0) {
if (offset == -FDT_ERR_NOTFOUND)
break;
if (offset < 0) return offset;
return (uint32_t)-1; }
phandle = fdt_get_phandle(fdt, offset); value = fdt_get_phandle(fdt, offset);
if (phandle == (uint32_t)-1)
continue;
if (phandle > max_phandle) if (value > max)
max_phandle = phandle; max = value;
} }
if (phandle)
*phandle = max;
return 0; 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) int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{ {
FDT_CHECK_HEADER(fdt); const struct fdt_reserve_entry *re;
*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); 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; return 0;
} }
int fdt_num_mem_rsv(const void *fdt) 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) for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
i++; if (fdt64_ld(&re->size) == 0)
return i; return i;
}
return -FDT_ERR_TRUNCATED;
} }
static int nextprop_(const void *fdt, int offset) static int nextprop_(const void *fdt, int offset)
@ -161,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{ {
int depth; int depth;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
for (depth = 0; for (depth = 0;
(offset >= 0) && (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; const char *p = path;
int offset = 0; int offset = 0;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* see if we have an alias */ /* see if we have an alias */
if (*path != '/') { if (*path != '/') {
@ -237,13 +301,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr; const char *nameptr;
int err; int err;
if (((err = fdt_check_header(fdt)) != 0) if (((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail; goto fail;
nameptr = nh->name; 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: * For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree * 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; int err;
const struct fdt_property *prop; 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) if (lenp)
*lenp = err; *lenp = err;
return NULL; 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); prop = fdt_offset_ptr_(fdt, offset);
if (lenp) if (lenp)
*lenp = fdt32_to_cpu(prop->len); *lenp = fdt32_ld(&prop->len);
return prop; 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 /* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */ * 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) if (lenp)
*lenp = -FDT_ERR_BADVERSION; *lenp = -FDT_ERR_BADVERSION;
return NULL; 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))) { (offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop; 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; offset = -FDT_ERR_INTERNAL;
break; break;
} }
if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) { name, namelen)) {
if (poffset) if (poffset)
*poffset = offset; *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 /* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */ * 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) if (lenp)
*lenp = -FDT_ERR_BADVERSION; *lenp = -FDT_ERR_BADVERSION;
return NULL; return NULL;
@ -392,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL; return NULL;
/* Handle realignment */ /* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
fdt32_to_cpu(prop->len) >= 8) (poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4; return prop->data + 4;
return prop->data; 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); prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop) if (!prop)
return NULL; return NULL;
if (namep) if (namep) {
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 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 */ /* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
fdt32_to_cpu(prop->len) >= 8) (offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4; return prop->data + 4;
return prop->data; return prop->data;
} }
@ -436,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0; return 0;
} }
return fdt32_to_cpu(*php); return fdt32_ld(php);
} }
const char *fdt_get_alias_namelen(const void *fdt, 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; int offset, depth, namelen;
const char *name; const char *name;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (buflen < 2) if (buflen < 2)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -514,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth; int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL; int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (supernodedepth < 0) if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
@ -536,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
} }
} }
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) if (!can_assume(VALID_INPUT)) {
return -FDT_ERR_BADOFFSET; if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADOFFSET;
return -FDT_ERR_BADSTRUCTURE; else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}
return offset; /* error from fdt_next_node() */ 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); err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err) if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL; return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
-FDT_ERR_INTERNAL;
return nodedepth; return nodedepth;
} }
@ -573,7 +657,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val; const void *val;
int len; int len;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't * 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)) if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE; return -FDT_ERR_BADPHANDLE;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we /* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in * 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; int offset, err;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if * property of a node in fdt_node_check_compatible(), then if

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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 "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))); (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; return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt))) fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT; return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17) if (!can_assume(LATEST) && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17); fdt_set_version(fdt, 17);
return 0; return 0;
} }
#define FDT_RW_CHECK_HEADER(fdt) \ #define FDT_RW_PROBE(fdt) \
{ \ { \
int err_; \ int err_; \
if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ if ((err_ = fdt_rw_probe_(fdt)) != 0) \
return err_; \ 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); 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) static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{ {
char *p = splicepoint; 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; return -FDT_ERR_BADOFFSET;
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) if ((p < (char *)fdt) || (dsize + newlen < oldlen))
return -FDT_ERR_BADOFFSET; return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) if (dsize - oldlen + newlen > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen); memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
return 0; return 0;
} }
@ -136,6 +94,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
return 0; 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) static int fdt_splice_string_(void *fdt, int newlen)
{ {
void *p = (char *)fdt void *p = (char *)fdt
@ -149,7 +115,16 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0; 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); char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p; const char *p;
@ -157,6 +132,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
int len = strlen(s) + 1; int len = strlen(s) + 1;
int err; int err;
if (!can_assume(NO_ROLLBACK))
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p) if (p)
/* found it */ /* found it */
@ -167,6 +145,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
if (err) if (err)
return err; return err;
if (!can_assume(NO_ROLLBACK))
*allocated = 1;
memcpy(new, s, len); memcpy(new, s, len);
return (new - strtab); 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; struct fdt_reserve_entry *re;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = fdt_splice_mem_rsv_(fdt, re, 0, 1); 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); 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)) if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
@ -225,11 +206,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int nextoffset; int nextoffset;
int namestroff; int namestroff;
int err; int err;
int allocated;
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset; return nextoffset;
namestroff = fdt_find_add_string_(fdt, name); namestroff = fdt_find_add_string_(fdt, name, &allocated);
if (namestroff < 0) if (namestroff < 0)
return namestroff; return namestroff;
@ -237,8 +219,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
proplen = sizeof(**prop) + FDT_TAGALIGN(len); proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = fdt_splice_struct_(fdt, *prop, 0, proplen); 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; return err;
}
(*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff); (*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 oldlen, newlen;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep) if (!namep)
@ -275,7 +261,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop; struct fdt_property *prop;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND) if (err == -FDT_ERR_NOTFOUND)
@ -308,7 +294,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop; struct fdt_property *prop;
int err, oldlen, newlen; int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) { if (prop) {
@ -334,7 +320,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop; struct fdt_property *prop;
int len, proplen; int len, proplen;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len); prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop) if (!prop)
@ -354,7 +340,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag; uint32_t tag;
fdt32_t *endtag; fdt32_t *endtag;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0) if (offset >= 0)
@ -394,7 +380,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
{ {
int endoffset; int endoffset;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
endoffset = fdt_node_end_offset_(fdt, nodeoffset); endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0) if (endoffset < 0)
@ -407,7 +393,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
static void fdt_packblocks_(const char *old, char *new, static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size, int struct_size) 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); mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size; 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); const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp; char *tmp;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * 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); struct_size = fdt_size_dt_struct(fdt);
} else { } else {
struct_size = 0; struct_size = 0;
@ -450,7 +436,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size; 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 */ /* no further work necessary */
err = fdt_move(fdt, buf, bufsize); err = fdt_move(fdt, buf, bufsize);
if (err) if (err)
@ -494,7 +481,7 @@ int fdt_pack(void *fdt)
{ {
int mem_rsv_size; int mem_rsv_size;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * sizeof(struct fdt_reserve_entry);

View File

@ -1,51 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libfdt_env.h" #include "libfdt_env.h"
@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVALUE), FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES), FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
}; };
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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 "libfdt_env.h"
@ -55,21 +10,87 @@
#include "libfdt_internal.h" #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)) {
return -FDT_ERR_BADMAGIC; if (fdt_magic(fdt) == FDT_MAGIC)
/* FIXME: should check more details about the header state */ return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
}
return 0; return 0;
} }
#define FDT_SW_CHECK_HEADER(fdt) \ #define FDT_SW_PROBE(fdt) \
{ \ { \
int err; \ int err; \
if ((err = fdt_sw_check_header_(fdt)) != 0) \ if ((err = fdt_sw_probe_(fdt)) != 0) \
return err; \ 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) static void *fdt_grab_space_(void *fdt, size_t len)
{ {
int offset = fdt_size_dt_struct(fdt); 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); 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; void *fdt = buf;
if (bufsize < sizeof(struct fdt_header)) if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
if (flags & ~FDT_CREATE_FLAGS_ALL)
return -FDT_ERR_BADFLAGS;
memset(buf, 0, bufsize); 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_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); 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_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), fdt_set_off_mem_rsvmap(fdt, hdrsize);
sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 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; 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) int fdt_resize(void *fdt, void *buf, int bufsize)
{ {
size_t headsize, tailsize; size_t headsize, tailsize;
char *oldtail, *newtail; 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); tailsize = fdt_size_dt_strings(fdt);
if (!can_assume(VALID_DTB) &&
headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize) if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -133,8 +175,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
memmove(buf, fdt, headsize); memmove(buf, fdt, headsize);
} }
fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize); fdt_set_totalsize(buf, bufsize);
if (fdt_off_dt_strings(buf))
fdt_set_off_dt_strings(buf, bufsize);
return 0; return 0;
} }
@ -144,10 +187,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
struct fdt_reserve_entry *re; struct fdt_reserve_entry *re;
int offset; int offset;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_MEMRSV(fdt);
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
offset = fdt_off_dt_struct(fdt); offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(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) 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) int fdt_begin_node(void *fdt, const char *name)
{ {
struct fdt_node_header *nh; 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)); nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh) if (! nh)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
@ -187,7 +234,7 @@ int fdt_end_node(void *fdt)
{ {
fdt32_t *en; fdt32_t *en;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
en = fdt_grab_space_(fdt, FDT_TAGSIZE); en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en) if (! en)
@ -197,19 +244,13 @@ int fdt_end_node(void *fdt)
return 0; 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); char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt); int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1; int len = strlen(s) + 1;
int struct_top, offset; int struct_top, offset;
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len; offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top) if (fdt_totalsize(fdt) + offset < struct_top)
@ -220,20 +261,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
return offset; 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) int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{ {
struct fdt_property *prop; struct fdt_property *prop;
int nameoff; 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) if (nameoff == 0)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); 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; return -FDT_ERR_NOSPACE;
}
prop->tag = cpu_to_fdt32(FDT_PROP); prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff); prop->nameoff = cpu_to_fdt32(nameoff);
@ -262,7 +339,7 @@ int fdt_finish(void *fdt)
uint32_t tag; uint32_t tag;
int offset, nextoffset; int offset, nextoffset;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
/* Add terminator */ /* Add terminator */
end = fdt_grab_space_(fdt, sizeof(*end)); end = fdt_grab_space_(fdt, sizeof(*end));
@ -295,6 +372,10 @@ int fdt_finish(void *fdt)
/* Finally, adjust the header */ /* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); 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); fdt_set_magic(fdt, FDT_MAGIC);
return 0; return 0;
} }

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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 "libfdt_env.h"

View File

@ -1,59 +1,18 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_H #ifndef LIBFDT_H
#define LIBFDT_H #define LIBFDT_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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 "libfdt_env.h"
#include "fdt.h" #include "fdt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FDT_FIRST_SUPPORTED_VERSION 0x02 #define FDT_FIRST_SUPPORTED_VERSION 0x02
#define FDT_LAST_SUPPORTED_VERSION 0x11 #define FDT_LAST_SUPPORTED_VERSION 0x11
@ -90,8 +49,9 @@
/* Error codes: codes for bad device tree blobs */ /* Error codes: codes for bad device tree blobs */
#define FDT_ERR_TRUNCATED 8 #define FDT_ERR_TRUNCATED 8
/* FDT_ERR_TRUNCATED: Structure block of the given device tree /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
* ends without an FDT_END tag. */ * terminated (overflows, goes outside allowed bounds, or
* isn't properly terminated). */
#define FDT_ERR_BADMAGIC 9 #define FDT_ERR_BADMAGIC 9
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
* device tree at all - it is missing the flattened device * device tree at all - it is missing the flattened device
@ -137,7 +97,15 @@
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any /* FDT_ERR_NOPHANDLES: The device tree doesn't have any
* phandle available anymore without causing an overflow */ * 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) */ /* 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); 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 */ /* 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 * Error handling
* } * }
* *
@ -213,7 +236,7 @@ int fdt_next_subnode(const void *fdt, int offset);
/* General functions */ /* General functions */
/**********************************************************************/ /**********************************************************************/
#define fdt_get_header(fdt, field) \ #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_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
@ -244,18 +267,32 @@ fdt_set_hdr_(size_dt_struct);
#undef fdt_set_hdr_ #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: pointer to data which might be a flattened device tree
* *
* fdt_check_header() checks that the given buffer contains what * fdt_check_header() checks that the given buffer contains what
* appears to be a flattened device tree with sane information in its * appears to be a flattened device tree, and that the header contains
* header. * valid information (to the extent that can be determined from the
* header alone).
* *
* returns: * returns:
* 0, if the buffer appears to contain a valid device tree * 0, if the buffer appears to contain a valid device tree
* -FDT_ERR_BADMAGIC, * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION, * -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); int fdt_check_header(const void *fdt);
@ -284,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/* Read-only functions */ /* 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_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
@ -294,10 +349,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
* *
* returns: * returns:
* a pointer to the string, on success * 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); 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_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob * @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 * device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1. * with a value of 0 or -1.
* *
* This function is deprecated in favour of fdt_find_max_phandle().
*
* returns: * returns:
* the highest phandle on success * the highest phandle on success
* 0, if no phandle was found in the device tree * 0, if no phandle was found in the device tree
* -1, if an error occurred * -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 * 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 * 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_getprop_by_offset - retrieve the value of a property at a given offset
* @fdt: pointer to the device tree blob * @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 * @namep: pointer to a string variable (will be overwritten) or NULL
* @lenp: pointer to an integer 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: * returns:
* 0 <= n < FDT_MAX_NCELLS, on success * 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 * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property * #size-cells property
* -FDT_ERR_BADMAGIC, * -FDT_ERR_BADMAGIC,
@ -1297,7 +1393,45 @@ int fdt_nop_node(void *fdt, int nodeoffset);
/* Sequential write functions */ /* 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_create(void *buf, int bufsize);
int fdt_resize(void *fdt, 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_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
int fdt_finish_reservemap(void *fdt); 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); fdt64_t tmp = cpu_to_fdt64(val);
return fdt_property(fdt, name, &tmp, sizeof(tmp)); 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) static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
{ {
return fdt_property_u32(fdt, name, val); return fdt_property_u32(fdt, name, val);
} }
#endif
/** /**
* fdt_property_placeholder - add a new property and return a ptr to its value * 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) \ #define fdt_appendprop_string(fdt, nodeoffset, name, str) \
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) 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_delprop - delete a property
* @fdt: pointer to the device tree blob * @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); const char *fdt_strerror(int errval);
#ifdef __cplusplus
}
#endif
#endif /* LIBFDT_H */ #endif /* LIBFDT_H */

View File

@ -1,61 +1,18 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_ENV_H #ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H #define LIBFDT_ENV_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor. * 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 <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#ifdef __CHECKER__ #ifdef __CHECKER__
#define FDT_FORCE __attribute__((force)) #define FDT_FORCE __attribute__((force))

View File

@ -1,65 +1,21 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_INTERNAL_H #ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H #define LIBFDT_INTERNAL_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * 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> #include <fdt.h>
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #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) \ int32_t totalsize_; \
return err_; \ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
return totalsize_; \
} }
int fdt_check_node_offset_(const void *fdt, int offset); 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) #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 */ #endif /* LIBFDT_INTERNAL_H */

View File

@ -1,24 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 "dtc.h"
#include "srcpos.h"
/* /*
* Tree building functions * Tree building functions
@ -50,7 +36,8 @@ void delete_labels(struct label **labels)
label->deleted = 1; 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)); struct property *new = xmalloc(sizeof(*new));
@ -58,6 +45,7 @@ struct property *build_property(char *name, struct data val)
new->name = name; new->name = name;
new->val = val; new->val = val;
new->srcpos = srcpos_copy(srcpos);
return new; return new;
} }
@ -97,7 +85,8 @@ struct property *reverse_properties(struct property *first)
return head; 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 *new = xmalloc(sizeof(*new));
struct node *child; struct node *child;
@ -106,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children)
new->proplist = reverse_properties(proplist); new->proplist = reverse_properties(proplist);
new->children = children; new->children = children;
new->srcpos = srcpos_copy(srcpos);
for_each_child(new, child) { for_each_child(new, child) {
child->parent = new; child->parent = new;
@ -114,13 +104,14 @@ struct node *build_node(struct property *proplist, struct node *children)
return new; return new;
} }
struct node *build_node_delete(void) struct node *build_node_delete(struct srcpos *srcpos)
{ {
struct node *new = xmalloc(sizeof(*new)); struct node *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new)); memset(new, 0, sizeof(*new));
new->deleted = 1; new->deleted = 1;
new->srcpos = srcpos_copy(srcpos);
return new; 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->val = new_prop->val;
old_prop->deleted = 0; old_prop->deleted = 0;
free(old_prop->srcpos);
old_prop->srcpos = new_prop->srcpos;
free(new_prop); free(new_prop);
new_prop = NULL; new_prop = NULL;
break; break;
@ -223,6 +216,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
add_child(old_node, new_child); 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 contents are now merged into the old node. Free
* the new node. */ * the new node. */
free(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; char *name;
if (ref[0] == '/') { if (ref[0] == '/') {
d = data_add_marker(d, TYPE_STRING, ref);
d = data_append_data(d, ref, strlen(ref) + 1); d = data_append_data(d, ref, strlen(ref) + 1);
p = build_property("target-path", d); p = build_property("target-path", d, NULL);
} else { } else {
d = data_add_marker(d, REF_PHANDLE, ref); d = data_add_marker(d, REF_PHANDLE, ref);
d = data_append_integer(d, 0xffffffff, 32); d = data_append_integer(d, 0xffffffff, 32);
p = build_property("target", d); p = build_property("target", d, NULL);
} }
xasprintf(&name, "fragment@%u", xasprintf(&name, "fragment@%u",
next_orphan_fragment++); next_orphan_fragment++);
name_node(new_node, "__overlay__"); name_node(new_node, "__overlay__");
node = build_node(p, new_node); node = build_node(p, new_node, NULL);
name_node(node, name); name_node(node, name);
add_child(dt, node); add_child(dt, node);
@ -340,18 +336,21 @@ void delete_node(struct node *node)
} }
void append_to_property(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 data d;
struct property *p; struct property *p;
p = get_property(node, name); p = get_property(node, name);
if (p) { 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; p->val = d;
} else { } else {
d = data_append_data(empty_data, data, len); d = data_add_marker(empty_data, type, name);
p = build_property(name, d); d = data_append_data(d, data, len);
p = build_property(name, d, NULL);
add_property(node, p); add_property(node, p);
} }
} }
@ -527,8 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/'); p = strchr(path, '/');
for_each_child(tree, child) { for_each_child(tree, child) {
if (p && (strlen(child->name) == p-path) && if (p && strprefixeq(path, p - path, child->name))
strprefixeq(path, p - path, child->name))
return get_node_by_path(child, p+1); return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name)) else if (!p && streq(path, child->name))
return child; 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) cell_t get_node_phandle(struct node *root, struct node *node)
{ {
static cell_t phandle = 1; /* FIXME: ick, static local */ static cell_t phandle = 1; /* FIXME: ick, static local */
struct data d = empty_data;
if ((node->phandle != 0) && (node->phandle != -1)) if ((node->phandle != 0) && (node->phandle != -1))
return node->phandle; return node->phandle;
@ -603,17 +602,16 @@ cell_t get_node_phandle(struct node *root, struct node *node)
node->phandle = phandle; node->phandle = phandle;
d = data_add_marker(d, TYPE_UINT32, NULL);
d = data_append_cell(d, phandle);
if (!get_property(node, "linux,phandle") if (!get_property(node, "linux,phandle")
&& (phandle_format & PHANDLE_LEGACY)) && (phandle_format & PHANDLE_LEGACY))
add_property(node, add_property(node, build_property("linux,phandle", d, NULL));
build_property("linux,phandle",
data_append_cell(empty_data, phandle)));
if (!get_property(node, "phandle") if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR)) && (phandle_format & PHANDLE_EPAPR))
add_property(node, add_property(node, build_property("phandle", d, NULL));
build_property("phandle",
data_append_cell(empty_data, phandle)));
/* If the node *does* have a phandle property, we must /* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be * 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; struct node *node;
node = build_node(NULL, NULL); node = build_node(NULL, NULL, NULL);
name_node(node, xstrdup(name)); name_node(node, xstrdup(name));
add_child(parent, node); add_child(parent, node);
@ -848,8 +846,9 @@ static void generate_label_tree_internal(struct dt_info *dti,
/* insert it */ /* insert it */
p = build_property(l->label, p = build_property(l->label,
data_copy_mem(node->fullpath, data_copy_escape_string(node->fullpath,
strlen(node->fullpath) + 1)); strlen(node->fullpath)),
NULL);
add_property(an, p); 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", xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset); 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); free(entry);
} }
@ -959,7 +958,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
char **compp; char **compp;
int i, depth; int i, depth;
/* walk back retreiving depth */ /* walk back retrieving depth */
depth = 0; depth = 0;
for (wn = node; wn; wn = wn->parent) for (wn = node; wn; wn = wn->parent)
depth++; depth++;
@ -982,7 +981,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
free(compp); free(compp);
value_32 = cpu_to_fdt32(m->offset); 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, static void generate_local_fixups_tree_internal(struct dt_info *dti,

View File

@ -1,20 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc. * 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 #define _GNU_SOURCE
@ -33,6 +19,9 @@ struct search_path {
/* This is the list of directories that we search for source files */ /* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail; 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) static char *get_dirname(const char *path)
{ {
@ -51,11 +40,51 @@ static char *get_dirname(const char *path)
FILE *depfile; /* = NULL */ FILE *depfile; /* = NULL */
struct srcfile_state *current_srcfile; /* = 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. */ static void set_initial_path(char *fname)
#define MAX_SRCFILE_DEPTH (100) {
static int srcfile_depth; /* = 0 */ 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. * Try to open a file in a given directory.
@ -157,6 +186,9 @@ void srcfile_push(const char *fname)
srcfile->colno = 1; srcfile->colno = 1;
current_srcfile = srcfile; current_srcfile = srcfile;
if (srcfile_depth == 1)
set_initial_path(srcfile->name);
} }
bool srcfile_pop(void) bool srcfile_pop(void)
@ -197,18 +229,6 @@ void srcfile_add_search_path(const char *dirname)
search_path_tail = &node->next; 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) void srcpos_update(struct srcpos *pos, const char *text, int len)
{ {
int i; int i;
@ -234,13 +254,35 @@ struct srcpos *
srcpos_copy(struct srcpos *pos) srcpos_copy(struct srcpos *pos)
{ {
struct srcpos *pos_new; struct srcpos *pos_new;
struct srcfile_state *srcfile_state;
if (!pos)
return NULL;
pos_new = xmalloc(sizeof(struct srcpos)); pos_new = xmalloc(sizeof(struct srcpos));
assert(pos->next == NULL);
memcpy(pos_new, pos, sizeof(struct srcpos)); 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; 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 * char *
srcpos_string(struct srcpos *pos) srcpos_string(struct srcpos *pos)
{ {
@ -266,6 +308,68 @@ srcpos_string(struct srcpos *pos)
return pos_str; 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, void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va) const char *fmt, va_list va)
{ {
@ -294,4 +398,9 @@ void srcpos_set_line(char *f, int l)
{ {
current_srcfile->name = f; current_srcfile->name = f;
current_srcfile->lineno = l; current_srcfile->lineno = l;
if (initial_cpp) {
initial_cpp = false;
set_initial_path(f);
}
} }

View File

@ -1,20 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* /*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc. * 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 #ifndef SRCPOS_H
@ -74,6 +60,7 @@ struct srcpos {
int last_line; int last_line;
int last_column; int last_column;
struct srcfile_state *file; struct srcfile_state *file;
struct srcpos *next;
}; };
#define YYLTYPE struct srcpos #define YYLTYPE struct srcpos
@ -93,19 +80,18 @@ struct srcpos {
YYRHSLOC(Rhs, 0).last_column; \ YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \ (Current).file = YYRHSLOC (Rhs, 0).file; \
} \ } \
(Current).next = NULL; \
} while (0) } 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 void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos); 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(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, extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va); const char *fmt, va_list va);

View File

@ -1,21 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. * (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 "dtc.h"
@ -61,24 +46,18 @@ static bool isstring(char c)
|| strchr("\a\b\t\n\v\f\r", 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; const char *end = s + len - 1;
int i;
struct marker *m = val.markers;
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, "\""); fprintf(f, "\"");
while (s < end) {
for (i = 0; i < (val.len-1); i++) { char c = *s++;
char c = str[i];
switch (c) { switch (c) {
case '\a': case '\a':
fprintf(f, "\\a"); fprintf(f, "\\a");
@ -108,91 +87,80 @@ static void write_propval_string(FILE *f, struct data val)
fprintf(f, "\\\""); fprintf(f, "\\\"");
break; break;
case '\0': case '\0':
fprintf(f, "\", "); fprintf(f, "\\0");
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, "\"");
break; break;
default: default:
if (isprint((unsigned char)c)) if (isprint((unsigned char)c))
fprintf(f, "%c", c); fprintf(f, "%c", c);
else else
fprintf(f, "\\x%02hhx", c); fprintf(f, "\\x%02"PRIx8, c);
} }
} }
fprintf(f, "\""); 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; const char *end = p + len;
fdt32_t *cp = (fdt32_t *)val.val; assert(len % width == 0);
struct marker *m = val.markers;
fprintf(f, "<"); for (; p < end; p += width) {
for (;;) { switch (width) {
while (m && (m->offset <= ((char *)cp - val.val))) { case 1:
if (m->type == LABEL) { fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
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)
break; 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; return m->type >= TYPE_UINT8;
const char *bp = val.val;
struct marker *m = val.markers;
fprintf(f, "[");
for (;;) {
while (m && (m->offset == (bp-val.val))) {
if (m->type == LABEL)
fprintf(f, "%s: ", m->ref);
m = m->next;
}
fprintf(f, "%02hhx", (unsigned char)(*bp++));
if ((const void *)bp >= propend)
break;
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);
}
fprintf(f, "]");
} }
static void write_propval(FILE *f, struct property *prop) static struct marker *next_type_marker(struct marker *m)
{
while (m && !has_data_type_information(m))
m = m->next;
return m;
}
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;
}
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 enum markertype guess_value_type(struct property *prop)
{ {
int len = prop->val.len; int len = prop->val.len;
const char *p = prop->val.val; 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 nnotstringlbl = 0, nnotcelllbl = 0;
int i; int i;
if (len == 0) {
fprintf(f, ";\n");
return;
}
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (! isstring(p[i])) if (! isstring(p[i]))
nnotstring++; nnotstring++;
@ -220,17 +183,99 @@ static void write_propval(FILE *f, struct property *prop)
nnotcelllbl++; 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)) { && (nnotstringlbl == 0)) {
write_propval_string(f, prop->val); return TYPE_STRING;
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
write_propval_cells(f, prop->val); return TYPE_UINT32;
} else {
write_propval_bytes(f, prop->val);
} }
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) 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 property *prop;
struct node *child; struct node *child;
struct label *l; struct label *l;
char *srcstr;
write_prefix(f, level); write_prefix(f, level);
for_each_label(tree->labels, l) for_each_label(tree->labels, l)
fprintf(f, "%s: ", l->label); fprintf(f, "%s: ", l->label);
if (tree->name && (*tree->name)) if (tree->name && (*tree->name))
fprintf(f, "%s {\n", tree->name); fprintf(f, "%s {", tree->name);
else 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) { for_each_property(tree, prop) {
write_prefix(f, level+1); write_prefix(f, level+1);
@ -259,10 +314,17 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
write_tree_source_node(f, child, level+1); write_tree_source_node(f, child, level+1);
} }
write_prefix(f, level); 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) void dt_to_source(FILE *f, struct dt_info *dti)
{ {
struct reserve_info *re; struct reserve_info *re;
@ -281,4 +343,3 @@ void dt_to_source(FILE *f, struct dt_info *dti)
write_tree_source_node(f, dti->dt, 0); write_tree_source_node(f, dti->dt, 0);
} }

View File

@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc
DTC_LINUX_PATH=`pwd`/scripts/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 \ 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" dtc-lexer.l dtc-parser.y"
LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ 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 \ fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \

View File

@ -1,24 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
* *
* util_is_printable_string contributed by * util_is_printable_string contributed by
* Pantelis Antoniou <pantelis.antoniou AT gmail.com> * 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> #include <ctype.h>
@ -27,6 +13,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <inttypes.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@ -46,36 +33,54 @@ char *xstrdup(const char *s)
return d; return d;
} }
/* based in part from (3) vsnprintf */ int xavsprintf_append(char **strp, const char *fmt, va_list ap)
int xasprintf(char **strp, const char *fmt, ...)
{ {
int n, size = 128; /* start with 128 bytes */ int n, size = 0; /* start with 128 bytes */
char *p; char *p;
va_list ap; va_list ap_copy;
/* initial pointer is NULL making the fist realloc to be malloc */ p = *strp;
p = NULL; if (p)
while (1) { size = strlen(p);
p = xrealloc(p, size);
/* Try to print in the allocated space. */ va_copy(ap_copy, ap);
va_start(ap, fmt); n = vsnprintf(NULL, 0, fmt, ap_copy) + 1;
n = vsnprintf(p, size, fmt, ap); va_end(ap_copy);
va_end(ap);
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; *strp = p;
return strlen(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) char *join_path(const char *path, const char *name)
{ {
int lenp = strlen(path); int lenp = strlen(path);
@ -227,11 +232,11 @@ char get_escape_char(const char *s, int *i)
return val; 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 */ int fd = 0; /* assume stdin */
char *buf = NULL; char *buf = NULL;
off_t bufsize = 1024, offset = 0; size_t bufsize = 1024, offset = 0;
int ret = 0; int ret = 0;
*buffp = NULL; *buffp = NULL;
@ -264,20 +269,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
free(buf); free(buf);
else else
*buffp = buf; *buffp = buf;
*len = bufsize; if (len)
*len = bufsize;
return ret; return ret;
} }
int utilfdt_read_err(const char *filename, char **buffp) char *utilfdt_read(const char *filename, size_t *len)
{
off_t len;
return utilfdt_read_err_len(filename, buffp, &len);
}
char *utilfdt_read_len(const char *filename, off_t *len)
{ {
char *buff; char *buff;
int ret = utilfdt_read_err_len(filename, &buff, len); int ret = utilfdt_read_err(filename, &buff, len);
if (ret) { if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, 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; 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 utilfdt_write_err(const char *filename, const void *blob)
{ {
int fd = 1; /* assume stdout */ int fd = 1; /* assume stdout */
@ -400,7 +394,7 @@ void utilfdt_print_data(const char *data, int len)
printf(" = <"); printf(" = <");
for (i = 0, len /= 4; i < len; i++) 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) ? " " : ""); i < (len - 1) ? " " : "");
printf(">"); printf(">");
} else { } else {

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
@ -8,25 +9,14 @@
/* /*
* Copyright 2011 The Chromium Authors, All Rights Reserved. * Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc. * 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 __GNUC__
#ifdef __clang__
#define PRINTF(i, j) __attribute__((format (printf, i, j))) #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)) #define NORETURN __attribute__((noreturn))
#else #else
#define PRINTF(i, j) #define PRINTF(i, j)
@ -72,6 +62,8 @@ static inline void *xrealloc(void *p, size_t len)
extern char *xstrdup(const char *s); extern char *xstrdup(const char *s);
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...); 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); extern char *join_path(const char *path, const char *name);
/** /**
@ -98,16 +90,10 @@ char get_escape_char(const char *s, int *i);
* stderr. * stderr.
* *
* @param filename The filename to read, or - for stdin * @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 * @return Pointer to allocated buffer containing fdt, or NULL on error
*/ */
char *utilfdt_read(const char *filename); char *utilfdt_read(const char *filename, size_t *len);
/**
* 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);
/** /**
* Read a device tree file into a buffer. Does not report errors, but only * 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 filename The filename to read, or - for stdin
* @param buffp Returns pointer to buffer containing fdt * @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 * @return 0 if ok, else an errno value representing the error
*/ */
int utilfdt_read_err(const char *filename, char **buffp); int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
/**
* 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);
/** /**
* Write a device tree buffer to a file. This will report any errors on * Write a device tree buffer to a file. This will report any errors on
* stderr. * stderr.
* *
* @param filename The filename to write, or - for stdout * @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 * @return 0 if ok, -1 on error
*/ */
int utilfdt_write(const char *filename, const void *blob); 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. * an error message for the user.
* *
* @param filename The filename to write, or - for stdout * @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 * @return 0 if ok, else an errno value representing the error
*/ */
int utilfdt_write_err(const char *filename, const void *blob); int utilfdt_write_err(const char *filename, const void *blob);

View File

@ -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
View 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);
}

View File

@ -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)

View File

@ -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,
}