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
building a concatenated Image.gz-dtb.
config BUILD_ARM64_EMBEDDED_DTB
bool "Embed DTB into kernel image"
depends on OF
help
Embed DTB directly into kernel image and ignore DTB from bootloader.
choice
prompt "Kernel compression method"
default BUILD_ARM64_KERNEL_COMPRESSION_GZIP

View File

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

View File

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

View File

@ -28,8 +28,6 @@ DTB_LIST := $(dtb-y)
endif
DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
DTBO_OBJS := $(shell find -L $(obj)/dts/ -name \*.dtbo)
# Add RTIC DTB to the DTB list if RTIC MPGen is enabled
# Note, we keep this for compatibility with
# BUILD_ARM64_APPENDED_DTB_IMAGE targets.
@ -55,11 +53,6 @@ $(obj)/Image-dtb-hdr: $(obj)/Image FORCE
$(obj)/Image-dtb: $(obj)/Image-dtb-hdr $(obj)/Image $(DTB_OBJS) FORCE
$(call if_changed,cat)
quiet_cmd_overlay = OVERLAY $@
cmd_overlay = PATH=$(srctree)/scripts/ufdt/libufdt/utils/src:$(objtree)/scripts/dtc-aosp:$(objtree)/scripts/ufdt:$(PATH) $(srctree)/$(src)/overlay.sh $@ $^ > /dev/null
$(obj)/../kernel/embedded-dtb.c: $(obj)/dtbo.img $(DTB_OBJS) FORCE
$(call if_changed,overlay)
$(obj)/Image.gz: $(obj)/Image FORCE
$(call if_changed,gzip)
@ -75,10 +68,6 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE
$(call if_changed,cat)
$(obj)/dtbo.img: $(obj)/dts/dtboimg.cfg $(DTBO_OBJS) FORCE
$(call if_changed,mkdtimg,4096) # align dtbo.img to 4kB
install:
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
$(obj)/Image System.map "$(INSTALL_PATH)"

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_EFI is not set
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
CONFIG_BUILD_ARM64_EMBEDDED_DTB=y
CONFIG_BUILD_ARM64_DT_OVERLAY=y
CONFIG_COMPAT=y
CONFIG_COMPAT_VDSO=y

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,
unsigned long virt, phys_addr_t size,
pgprot_t prot, bool page_mappings_only);
extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
extern void mark_linear_text_alias_ro(void);
#ifdef CONFIG_MEMORY_HOTPLUG
extern void hotplug_paging(phys_addr_t start, phys_addr_t size);
@ -108,9 +108,5 @@ extern void remove_pagetable(unsigned long start,
#endif
#endif
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
extern void select_embedded_dt(void *dt_virt) __init;
#endif
#endif /* !__ASSEMBLY__ */
#endif

View File

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

View File

@ -65,9 +65,6 @@ out:
return default_cmdline;
}
extern void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size,
pgprot_t prot);
/*
* This routine will be executed with the kernel mapped at its default virtual
* address, and if it returns successfully, the kernel will be remapped, and
@ -96,7 +93,7 @@ u64 __init kaslr_early_init(u64 dt_phys)
* attempt at mapping the FDT in setup_machine()
*/
early_fixmap_init();
fdt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
fdt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
if (!fdt)
return 0;

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)
{
void *dt_virt = fixmap_remap_fdt(dt_phys);
int size;
void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
const char *name;
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
select_embedded_dt(dt_virt);
#endif
if (dt_virt)
memblock_reserve(dt_phys, size);
if (!dt_virt || !early_init_dt_scan(dt_virt)) {
pr_crit("\n"
@ -209,6 +209,9 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
cpu_relax();
}
/* Early fixups are done, map the FDT as read-only now */
fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
name = of_flat_dt_get_machine_name();
if (!name)
return;

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);
int offset;
@ -1376,13 +1376,9 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
if (fdt_magic(dt_virt) != FDT_MAGIC)
return NULL;
#ifdef CONFIG_BUILD_ARM64_EMBEDDED_DTB
*size = MAX_FDT_SIZE;
#else
*size = fdt_totalsize(dt_virt);
if (*size > MAX_FDT_SIZE)
return NULL;
#endif
if (offset + *size > SWAPPER_BLOCK_SIZE)
create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
@ -1391,18 +1387,9 @@ void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
return dt_virt;
}
void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
int __init arch_ioremap_p4d_supported(void)
{
void *dt_virt;
int size;
dt_virt = __fixmap_remap_fdt(dt_phys, &size,
IS_ENABLED(CONFIG_BUILD_ARM64_EMBEDDED_DTB) ? PAGE_KERNEL : PAGE_KERNEL_RO);
if (!dt_virt)
return NULL;
memblock_reserve(dt_phys, size);
return dt_virt;
return 0;
}
int __init arch_ioremap_pud_supported(void)

View File

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

View File

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

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
HOST_EXTRACFLAGS := -I$(src)/libfdt
ifeq ($(wildcard /usr/include/yaml.h),)
HOST_EXTRACFLAGS += -DNO_YAML
else
dtc-objs += yamltree.o
HOSTLDLIBS_dtc := -lyaml
endif
# Generated files need one more search path to include headers in source tree
HOSTCFLAGS_dtc-lexer.lex.o := -I$(src)
HOSTCFLAGS_dtc-parser.tab.o := -I$(src)

View File

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

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#include "srcpos.h"
#ifdef TRACE_CHECKS
#define TRACE(c, ...) \
@ -78,23 +64,56 @@ static inline void PRINTF(5, 6) check_msg(struct check *c, struct dt_info *dti,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char *str = NULL;
struct srcpos *pos = NULL;
char *file_str;
if ((c->warn && (quiet < 1))
|| (c->error && (quiet < 2))) {
fprintf(stderr, "%s: %s (%s): ",
strcmp(dti->outname, "-") ? dti->outname : "<stdout>",
if (!(c->warn && (quiet < 1)) && !(c->error && (quiet < 2)))
return;
if (prop && prop->srcpos)
pos = prop->srcpos;
else if (node && node->srcpos)
pos = node->srcpos;
if (pos) {
file_str = srcpos_string(pos);
xasprintf(&str, "%s", file_str);
free(file_str);
} else if (streq(dti->outname, "-")) {
xasprintf(&str, "<stdout>");
} else {
xasprintf(&str, "%s", dti->outname);
}
xasprintf_append(&str, ": %s (%s): ",
(c->error) ? "ERROR" : "Warning", c->name);
if (node) {
fprintf(stderr, "%s", node->fullpath);
if (prop)
fprintf(stderr, ":%s", prop->name);
fputs(": ", stderr);
}
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
xasprintf_append(&str, "%s:%s: ", node->fullpath, prop->name);
else
xasprintf_append(&str, "%s: ", node->fullpath);
}
va_start(ap, fmt);
xavsprintf_append(&str, fmt, ap);
va_end(ap);
xasprintf_append(&str, "\n");
if (!prop && pos) {
pos = node->srcpos;
while (pos->next) {
pos = pos->next;
file_str = srcpos_string(pos);
xasprintf_append(&str, " also defined at %s\n", file_str);
free(file_str);
}
}
fputs(str, stderr);
}
#define FAIL(c, dti, node, ...) \
@ -333,7 +352,7 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
FAIL(c, dti, node, "node has a reg or ranges property, but no unit name");
} else {
if (unitname[0])
FAIL(c, dti, node, "node has a unit name, but no reg property");
FAIL(c, dti, node, "node has a unit name, but no reg or ranges property");
}
}
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
@ -626,6 +645,8 @@ ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
static void fixup_omit_unused_nodes(struct check *c, struct dt_info *dti,
struct node *node)
{
if (generate_symbols && node->labels)
return;
if (node->omit_if_unused && !node->is_referenced)
delete_node(node);
}
@ -670,6 +691,11 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
return;
for_each_property(node, prop) {
if (streq(prop->name, "phandle")
|| streq(prop->name, "linux,phandle")) {
continue;
}
if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val);
@ -739,13 +765,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
{
struct property *prop;
int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen;
const char *ranges = c->data;
prop = get_property(node, "ranges");
prop = get_property(node, ranges);
if (!prop)
return;
if (!node->parent) {
FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property");
FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property",
ranges);
return;
}
@ -757,23 +785,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti,
if (prop->val.len == 0) {
if (p_addr_cells != c_addr_cells)
FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its "
FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
"#address-cells (%d) differs from %s (%d)",
c_addr_cells, node->parent->fullpath,
ranges, c_addr_cells, node->parent->fullpath,
p_addr_cells);
if (p_size_cells != c_size_cells)
FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its "
FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its "
"#size-cells (%d) differs from %s (%d)",
c_size_cells, node->parent->fullpath,
ranges, c_size_cells, node->parent->fullpath,
p_size_cells);
} else if ((prop->val.len % entrylen) != 0) {
FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) "
FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) "
"(parent #address-cells == %d, child #address-cells == %d, "
"#size-cells == %d)", prop->val.len,
"#size-cells == %d)", ranges, prop->val.len,
p_addr_cells, c_addr_cells, c_size_cells);
}
}
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells);
WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells);
static const struct bus_type pci_bus = {
.name = "PCI",
@ -910,7 +939,7 @@ static bool node_is_compatible(struct node *node, const char *compat)
for (str = prop->val.val, end = str + prop->val.len; str < end;
str += strnlen(str, end - str) + 1) {
if (strprefixeq(str, end - str, compat))
if (streq(str, compat))
return true;
}
return false;
@ -921,7 +950,8 @@ static void check_simple_bus_bridge(struct check *c, struct dt_info *dti, struct
if (node_is_compatible(node, "simple-bus"))
node->bus = &simple_bus;
}
WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL, &addr_size_cells);
WARNING(simple_bus_bridge, check_simple_bus_bridge, NULL,
&addr_size_cells, &compatible_is_string_list);
static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
{
@ -962,6 +992,159 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
}
WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &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,
struct node *node)
{
@ -1034,8 +1217,24 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d
}
WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size);
static void check_unique_unit_address(struct check *c, struct dt_info *dti,
struct node *node)
static bool node_is_disabled(struct node *node)
{
struct property *prop;
prop = get_property(node, "status");
if (prop) {
char *str = prop->val.val;
if (streq("disabled", str))
return true;
}
return false;
}
static void check_unique_unit_address_common(struct check *c,
struct dt_info *dti,
struct node *node,
bool disable_check)
{
struct node *childa;
@ -1052,18 +1251,38 @@ static void check_unique_unit_address(struct check *c, struct dt_info *dti,
if (!strlen(addr_a))
continue;
if (disable_check && node_is_disabled(childa))
continue;
for_each_child(node, childb) {
const char *addr_b = get_unitname(childb);
if (childa == childb)
break;
if (disable_check && node_is_disabled(childb))
continue;
if (streq(addr_a, addr_b))
FAIL(c, dti, childb, "duplicate unit-address (also used in node %s)", childa->fullpath);
}
}
}
static void check_unique_unit_address(struct check *c, struct dt_info *dti,
struct node *node)
{
check_unique_unit_address_common(c, dti, node, false);
}
WARNING(unique_unit_address, check_unique_unit_address, NULL, &avoid_default_addr_size);
static void check_unique_unit_address_if_enabled(struct check *c, struct dt_info *dti,
struct node *node)
{
check_unique_unit_address_common(c, dti, node, true);
}
CHECK_ENTRY(unique_unit_address_if_enabled, check_unique_unit_address_if_enabled,
NULL, false, false, &avoid_default_addr_size);
static void check_obsolete_chosen_interrupt_controller(struct check *c,
struct dt_info *dti,
struct node *node)
@ -1338,6 +1557,28 @@ static bool node_is_interrupt_provider(struct node *node)
return false;
}
static void check_interrupt_provider(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct property *prop;
if (!node_is_interrupt_provider(node))
return;
prop = get_property(node, "#interrupt-cells");
if (!prop)
FAIL(c, dti, node,
"Missing #interrupt-cells in interrupt provider");
prop = get_property(node, "#address-cells");
if (!prop)
FAIL(c, dti, node,
"Missing #address-cells in interrupt provider");
}
WARNING(interrupt_provider, check_interrupt_provider, NULL);
static void check_interrupts_property(struct check *c,
struct dt_info *dti,
struct node *node)
@ -1364,10 +1605,14 @@ static void check_interrupts_property(struct check *c,
prop = get_property(parent, "interrupt-parent");
if (prop) {
phandle = propval_cell(prop);
/* Give up if this is an overlay with external references */
if ((phandle == 0 || phandle == -1) &&
(dti->dtsflags & DTSF_PLUGIN))
if ((phandle == 0) || (phandle == -1)) {
/* Give up if this is an overlay with
* external references */
if (dti->dtsflags & DTSF_PLUGIN)
return;
FAIL_PROP(c, dti, parent, prop, "Invalid phandle");
continue;
}
irq_node = get_node_by_phandle(root, phandle);
if (!irq_node) {
@ -1391,7 +1636,7 @@ static void check_interrupts_property(struct check *c,
prop = get_property(irq_node, "#interrupt-cells");
if (!prop) {
FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent");
/* We warn about that already in another test. */
return;
}
@ -1536,7 +1781,7 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
return;
if (!strprefixeq(node->name, node->basenamelen, "endpoint"))
FAIL(c, dti, node, "graph endpont node name should be 'endpoint'");
FAIL(c, dti, node, "graph endpoint node name should be 'endpoint'");
check_graph_reg(c, dti, node);
@ -1570,7 +1815,7 @@ static struct check *check_table[] = {
&property_name_chars_strict,
&node_name_chars_strict,
&addr_size_cells, &reg_format, &ranges_format,
&addr_size_cells, &reg_format, &ranges_format, &dma_ranges_format,
&unit_address_vs_reg,
&unit_address_format,
@ -1582,9 +1827,16 @@ static struct check *check_table[] = {
&simple_bus_bridge,
&simple_bus_reg,
&i2c_bus_bridge,
&i2c_bus_reg,
&spi_bus_bridge,
&spi_bus_reg,
&avoid_default_addr_size,
&avoid_unnecessary_addr_size,
&unique_unit_address,
&unique_unit_address_if_enabled,
&obsolete_chosen_interrupt_controller,
&chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path,
@ -1608,6 +1860,7 @@ static struct check *check_table[] = {
&deprecated_gpio_property,
&gpios_property,
&interrupts_property,
&interrupt_provider,
&alias_paths,

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
@ -74,7 +59,8 @@ struct data data_copy_escape_string(const char *s, int len)
struct data d;
char *q;
d = data_grow_for(empty_data, len + 1);
d = data_add_marker(empty_data, TYPE_STRING, NULL);
d = data_grow_for(d, len + 1);
q = d.val;
while (i < len) {
@ -94,6 +80,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;
d = data_add_marker(d, TYPE_NONE, NULL);
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%option noyywrap nounput noinput never-interactive
@ -212,14 +197,14 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
<*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_REF;
return DT_LABEL_REF;
}
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
return DT_REF;
return DT_PATH_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%locations
%{
#include <stdio.h>
#include <inttypes.h>
@ -32,6 +19,8 @@ extern void yyerror(char const *s);
treesource_error = true; \
} while (0)
#define YYERROR_CALL(msg) yyerror(msg)
extern struct dt_info *parser_output;
extern bool treesource_error;
%}
@ -70,7 +59,8 @@ extern bool treesource_error;
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
%token <labelref> DT_LABEL_REF
%token <labelref> DT_PATH_REF
%token DT_INCBIN
%type <data> propdata
@ -83,6 +73,7 @@ extern bool treesource_error;
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <labelref> dt_ref
%type <node> devicetree
%type <node> nodedef
@ -158,6 +149,8 @@ memreserve:
}
;
dt_ref: DT_LABEL_REF | DT_PATH_REF;
devicetree:
'/' nodedef
{
@ -167,7 +160,7 @@ devicetree:
{
$$ = merge_nodes($1, $3);
}
| DT_REF nodedef
| dt_ref nodedef
{
/*
* We rely on the rule being always:
@ -176,9 +169,12 @@ devicetree:
*/
if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
$$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
$$ = add_orphan_node(
name_node(build_node(NULL, NULL, NULL),
""),
$2, $1);
}
| devicetree DT_LABEL DT_REF nodedef
| devicetree DT_LABEL dt_ref nodedef
{
struct node *target = get_node_by_ref($1, $3);
@ -189,7 +185,7 @@ devicetree:
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
| devicetree DT_REF nodedef
| devicetree DT_PATH_REF nodedef
{
/*
* We rely on the rule being always:
@ -208,7 +204,26 @@ devicetree:
}
$$ = $1;
}
| devicetree DT_DEL_NODE DT_REF ';'
| devicetree DT_LABEL_REF nodedef
{
struct node *target = get_node_by_ref($1, $2);
if (target) {
merge_nodes(target, $3);
} else {
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_DEL_NODE dt_ref ';'
{
struct node *target = get_node_by_ref($1, $3);
@ -220,7 +235,7 @@ devicetree:
$$ = $1;
}
| devicetree DT_OMIT_NO_REF DT_REF ';'
| devicetree DT_OMIT_NO_REF dt_ref ';'
{
struct node *target = get_node_by_ref($1, $3);
@ -237,7 +252,7 @@ devicetree:
nodedef:
'{' proplist subnodes '}' ';'
{
$$ = build_node($2, $3);
$$ = build_node($2, $3, &@$);
}
;
@ -255,11 +270,11 @@ proplist:
propdef:
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
$$ = build_property($1, $3, &@$);
}
| DT_PROPNODENAME ';'
{
$$ = build_property($1, empty_data);
$$ = build_property($1, empty_data, &@$);
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
@ -285,8 +300,9 @@ propdata:
{
$$ = data_merge($1, $3);
}
| propdataprefix DT_REF
| propdataprefix dt_ref
{
$1 = data_add_marker($1, TYPE_STRING, $2);
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@ -340,22 +356,27 @@ arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
enum markertype type = TYPE_UINT32;
bits = $2;
if ((bits != 8) && (bits != 16) &&
(bits != 32) && (bits != 64)) {
switch (bits) {
case 8: type = TYPE_UINT8; break;
case 16: type = TYPE_UINT16; break;
case 32: type = TYPE_UINT32; break;
case 64: type = TYPE_UINT64; break;
default:
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}
$$.data = empty_data;
$$.data = data_add_marker(empty_data, type, NULL);
$$.bits = bits;
}
| '<'
{
$$.data = empty_data;
$$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
$$.bits = 32;
}
| arrayprefix integer_prim
@ -377,7 +398,7 @@ arrayprefix:
$$.data = data_append_integer($1.data, $2, $1.bits);
}
| arrayprefix DT_REF
| arrayprefix dt_ref
{
uint64_t val = ~0ULL >> (64 - $1.bits);
@ -499,7 +520,7 @@ integer_unary:
bytestring:
/* empty */
{
$$ = empty_data;
$$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
}
| bytestring DT_BYTE
{
@ -534,7 +555,7 @@ subnode:
}
| DT_DEL_NODE DT_PROPNODENAME ';'
{
$$ = name_node(build_node_delete(), $2);
$$ = name_node(build_node_delete(&@$), $2);
}
| DT_OMIT_NO_REF subnode
{

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <sys/stat.h>
@ -35,6 +20,8 @@ int phandle_format = PHANDLE_EPAPR; /* Use linux,phandle or phandle properties *
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */
int annotate; /* Level of annotation: 1 for input source location
>1 for full input source location. */
static int is_power_of_2(int x)
{
@ -60,7 +47,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
/* Usage related data. */
static const char usage_synopsis[] = "dtc [options] <input file>";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv";
static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
@ -81,6 +68,7 @@ static struct option const usage_long_opts[] = {
{"error", a_argument, NULL, 'E'},
{"symbols", no_argument, NULL, '@'},
{"auto-alias", no_argument, NULL, 'A'},
{"annotate", no_argument, NULL, 'T'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@ -95,6 +83,9 @@ static const char * const usage_opts_help[] = {
"\n\tOutput formats are:\n"
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
#ifndef NO_YAML
"\t\tyaml - device tree encoded as YAML\n"
#endif
"\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file",
@ -114,6 +105,7 @@ static const char * const usage_opts_help[] = {
"\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tEnable generation of symbols",
"\n\tEnable auto-alias of labels",
"\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
@ -128,6 +120,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
return fallback;
if (!strcasecmp(s, ".dts"))
return "dts";
if (!strcasecmp(s, ".yaml"))
return "yaml";
if (!strcasecmp(s, ".dtb"))
return "dtb";
return fallback;
@ -259,6 +253,9 @@ int main(int argc, char *argv[])
case 'A':
auto_label_aliases = 1;
break;
case 'T':
annotate++;
break;
case 'h':
usage(NULL);
@ -297,6 +294,8 @@ int main(int argc, char *argv[])
outform = "dts";
}
}
if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
die("--annotate requires -I dts -O dts\n");
if (streq(inform, "dts"))
dti = dt_from_source(arg);
else if (streq(inform, "fs"))
@ -350,6 +349,12 @@ int main(int argc, char *argv[])
if (streq(outform, "dts")) {
dt_to_source(outf, dti);
#ifndef NO_YAML
} else if (streq(outform, "yaml")) {
if (!streq(inform, "dts"))
die("YAML output format requires dts input format\n");
dt_to_yaml(outf, dti);
#endif
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) {

View File

@ -1,24 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef DTC_H
#define DTC_H
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <stdio.h>
@ -58,6 +43,7 @@ extern int phandle_format; /* Use linux,phandle or phandle properties */
extern int generate_symbols; /* generate symbols for nodes with labels */
extern int generate_fixups; /* generate fixups */
extern int auto_label_aliases; /* auto generate labels -> aliases */
extern int annotate; /* annotate .dts with input source location */
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
@ -65,6 +51,37 @@ extern int auto_label_aliases; /* auto generate labels -> aliases */
typedef uint32_t cell_t;
static inline uint16_t dtb_ld16(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;
return ((uint16_t)bp[0] << 8)
| bp[1];
}
static inline uint32_t dtb_ld32(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;
return ((uint32_t)bp[0] << 24)
| ((uint32_t)bp[1] << 16)
| ((uint32_t)bp[2] << 8)
| bp[3];
}
static inline uint64_t dtb_ld64(const void *p)
{
const uint8_t *bp = (const uint8_t *)p;
return ((uint64_t)bp[0] << 56)
| ((uint64_t)bp[1] << 48)
| ((uint64_t)bp[2] << 40)
| ((uint64_t)bp[3] << 32)
| ((uint64_t)bp[4] << 24)
| ((uint64_t)bp[5] << 16)
| ((uint64_t)bp[6] << 8)
| bp[7];
}
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
@ -74,10 +91,17 @@ typedef uint32_t cell_t;
/* Data blobs */
enum markertype {
TYPE_NONE,
REF_PHANDLE,
REF_PATH,
LABEL,
TYPE_UINT8,
TYPE_UINT16,
TYPE_UINT32,
TYPE_UINT64,
TYPE_STRING,
};
extern const char *markername(enum markertype markertype);
struct marker {
enum markertype type;
@ -101,6 +125,8 @@ struct data {
for_each_marker(m) \
if ((m)->type == (t))
size_t type_marker_length(struct marker *m);
void data_free(struct data d);
struct data data_grow_for(struct data d, int xlen);
@ -149,6 +175,7 @@ struct property {
struct property *next;
struct label *labels;
struct srcpos *srcpos;
};
struct node {
@ -168,6 +195,7 @@ struct node {
struct label *labels;
const struct bus_type *bus;
struct srcpos *srcpos;
bool omit_if_unused, is_referenced;
};
@ -196,13 +224,15 @@ struct node {
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);
struct property *build_property(char *name, struct data val);
struct property *build_property(char *name, struct data val,
struct srcpos *srcpos);
struct property *build_property_delete(char *name);
struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children);
struct node *build_node_delete(void);
struct node *build_node(struct property *proplist, struct node *children,
struct srcpos *srcpos);
struct node *build_node_delete(struct srcpos *srcpos);
struct node *name_node(struct node *node, char *name);
struct node *omit_node_if_unused(struct node *node);
struct node *reference_node(struct node *node);
@ -217,7 +247,8 @@ void add_child(struct node *parent, struct node *child);
void delete_node_by_name(struct node *parent, char *name);
void delete_node(struct node *node);
void append_to_property(struct node *node,
char *name, const void *data, int len);
char *name, const void *data, int len,
enum markertype type);
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
@ -290,6 +321,10 @@ struct dt_info *dt_from_blob(const char *fname);
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);
/* YAML source */
void dt_to_yaml(FILE *f, struct dt_info *dti);
/* FS trees */
struct dt_info *dt_from_fs(const char *dirname);

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
@ -171,7 +156,7 @@ static void asm_emit_data(void *e, struct data d)
emit_offset_label(f, m->ref, m->offset);
while ((d.len - off) >= sizeof(uint32_t)) {
asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off))));
asm_emit_cell(e, dtb_ld32(d.val + off));
off += sizeof(uint32_t);
}
@ -393,7 +378,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
padlen = 0;
if (quiet < 1)
fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n",
"Warning: blob size %"PRIu32" >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
}
}
@ -525,7 +510,7 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
fprintf(f, "/* Memory reserve map from source file */\n");
/*
* Use .long on high and low halfs of u64s to avoid .quad
* Use .long on high and low halves of u64s to avoid .quad
* as it appears .quad isn't available in some assemblers.
*/
for (re = dti->reservelist; re; re = re->next) {
@ -692,7 +677,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf,
val = flat_read_data(dtbuf, proplen);
return build_property(name, val);
return build_property(name, val, NULL);
}
@ -750,7 +735,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
char *flatname;
uint32_t val;
node = build_node(NULL, NULL);
node = build_node(NULL, NULL, NULL);
flatname = flat_read_string(dtbuf);

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
@ -34,7 +19,7 @@ static struct node *read_fstree(const char *dirname)
if (!d)
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
tree = build_node(NULL, NULL);
tree = build_node(NULL, NULL, NULL);
while ((de = readdir(d)) != NULL) {
char *tmpname;
@ -45,7 +30,7 @@ static struct node *read_fstree(const char *dirname)
tmpname = join_path(dirname, de->d_name);
if (lstat(tmpname, &st) < 0)
if (stat(tmpname, &st) < 0)
die("stat(%s): %s\n", tmpname, strerror(errno));
if (S_ISREG(st.st_mode)) {
@ -60,7 +45,8 @@ static struct node *read_fstree(const char *dirname)
} else {
prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile,
st.st_size));
st.st_size),
NULL);
add_property(tree, prop);
fclose(pfile);
}

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
# Makefile.libfdt
#
# This is not a complete Makefile of itself. Instead, it is designed to
@ -9,3 +10,9 @@ LIBFDT_VERSION = version.lds
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
fdt_addresses.c fdt_overlay.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT)
libfdt_clean:
@$(VECHO) CLEAN "(libfdt)"
rm -f $(STD_CLEANFILES:%=$(LIBFDT_dir)/%)
rm -f $(LIBFDT_dir)/$(LIBFDT_soname)

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -55,35 +10,124 @@
#include "libfdt_internal.h"
int fdt_check_header(const void *fdt)
/*
* Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
* that the given buffer contains what appears to be a flattened
* device tree with sane information in its header.
*/
int32_t fdt_ro_probe_(const void *fdt)
{
uint32_t totalsize = fdt_totalsize(fdt);
if (can_assume(VALID_DTB))
return totalsize;
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (!can_assume(LATEST)) {
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
if (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}
if (fdt_off_dt_struct(fdt) > (UINT_MAX - fdt_size_dt_struct(fdt)))
return FDT_ERR_BADOFFSET;
if (totalsize < INT32_MAX)
return totalsize;
else
return -FDT_ERR_TRUNCATED;
}
if (fdt_off_dt_strings(fdt) > (UINT_MAX - fdt_size_dt_strings(fdt)))
return FDT_ERR_BADOFFSET;
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
{
return (off >= hdrsize) && (off <= totalsize);
}
if ((fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))
> fdt_totalsize(fdt))
return FDT_ERR_BADOFFSET;
static int check_block_(uint32_t hdrsize, uint32_t totalsize,
uint32_t base, uint32_t size)
{
if (!check_off_(hdrsize, totalsize, base))
return 0; /* block start out of bounds */
if ((base + size) < base)
return 0; /* overflow */
if (!check_off_(hdrsize, totalsize, base + size))
return 0; /* block end out of bounds */
return 1;
}
if ((fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))
> fdt_totalsize(fdt))
return FDT_ERR_BADOFFSET;
size_t fdt_header_size_(uint32_t version)
{
if (version <= 1)
return FDT_V1_SIZE;
else if (version <= 2)
return FDT_V2_SIZE;
else if (version <= 3)
return FDT_V3_SIZE;
else if (version <= 16)
return FDT_V16_SIZE;
else
return FDT_V17_SIZE;
}
size_t fdt_header_size(const void *fdt)
{
return can_assume(LATEST) ? FDT_V17_SIZE :
fdt_header_size_(fdt_version(fdt));
}
int fdt_check_header(const void *fdt)
{
size_t hdrsize;
if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
if (!can_assume(LATEST)) {
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
}
hdrsize = fdt_header_size(fdt);
if (!can_assume(VALID_DTB)) {
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
/* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;
}
if (!can_assume(VALID_DTB)) {
/* Bounds check structure block */
if (!can_assume(LATEST) && fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
} else {
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
}
/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_strings(fdt),
fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
}
return 0;
}
@ -92,12 +136,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if (!can_assume(VALID_INPUT))
if ((absoffset < offset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (fdt_version(fdt) >= 0x11)
if (can_assume(LATEST) || fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
@ -114,7 +159,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (!tagp)
if (!can_assume(VALID_DTB) && !tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
@ -126,18 +171,19 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (!p)
if (!can_assume(VALID_DTB) && !p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (!lenp)
if (!can_assume(VALID_DTB) && !lenp)
return FDT_END; /* premature end */
/* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp);
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
if (!can_assume(LATEST) &&
fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4;
break;
@ -160,6 +206,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
int fdt_check_node_offset_(const void *fdt, int offset)
{
if (can_assume(VALID_INPUT))
return offset;
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
return -FDT_ERR_BADOFFSET;
@ -258,7 +306,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
int fdt_move(const void *fdt, void *buf, int bufsize)
{
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;

View File

@ -1,55 +1,10 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef FDT_H
#define FDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ASSEMBLY__

View File

@ -1,52 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Copyright (C) 2018 embedded brains GmbH
*/
#include "libfdt_env.h"
@ -55,42 +11,91 @@
#include "libfdt_internal.h"
int fdt_address_cells(const void *fdt, int nodeoffset)
static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
const fdt32_t *ac;
int val;
const fdt32_t *c;
uint32_t val;
int len;
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
if (!ac)
c = fdt_getprop(fdt, nodeoffset, name, &len);
if (!c)
return len;
if (len != sizeof(*c))
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*c);
if (val > FDT_MAX_NCELLS)
return -FDT_ERR_BADNCELLS;
return (int)val;
}
int fdt_address_cells(const void *fdt, int nodeoffset)
{
int val;
val = fdt_cells(fdt, nodeoffset, "#address-cells");
if (val == 0)
return -FDT_ERR_BADNCELLS;
if (val == -FDT_ERR_NOTFOUND)
return 2;
if (len != sizeof(*ac))
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*ac);
if ((val <= 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;
return val;
}
int fdt_size_cells(const void *fdt, int nodeoffset)
{
const fdt32_t *sc;
int val;
int len;
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
if (!sc)
return 2;
if (len != sizeof(*sc))
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*sc);
if ((val < 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;
val = fdt_cells(fdt, nodeoffset, "#size-cells");
if (val == -FDT_ERR_NOTFOUND)
return 1;
return val;
}
/* This function assumes that [address|size]_cells is 1 or 2 */
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
const char *name, uint64_t addr, uint64_t size)
{
int addr_cells, size_cells, ret;
uint8_t data[sizeof(fdt64_t) * 2], *prop;
ret = fdt_address_cells(fdt, parent);
if (ret < 0)
return ret;
addr_cells = ret;
ret = fdt_size_cells(fdt, parent);
if (ret < 0)
return ret;
size_cells = ret;
/* check validity of address */
prop = data;
if (addr_cells == 1) {
if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size))
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)addr);
} else if (addr_cells == 2) {
fdt64_st(prop, addr);
} else {
return -FDT_ERR_BADNCELLS;
}
/* check validity of size */
prop += addr_cells * sizeof(fdt32_t);
if (size_cells == 1) {
if (size > UINT32_MAX)
return -FDT_ERR_BADVALUE;
fdt32_st(prop, (uint32_t)size);
} else if (size_cells == 2) {
fdt64_st(prop, size);
} else {
return -FDT_ERR_BADNCELLS;
}
return fdt_appendprop(fdt, nodeoffset, name, data,
(addr_cells + size_cells) * sizeof(fdt32_t));
}

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

View File

@ -1,53 +1,8 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2016 Free Electrons
* Copyright (C) 2016 NextThing Co.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -93,11 +48,11 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
* @pathp: pointer which receives the path of the target (or NULL)
*
* overlay_get_target() retrieves the target offset in the base
* device tree of a fragment, no matter how the actual targetting is
* device tree of a fragment, no matter how the actual targeting is
* done (through a phandle or a path)
*
* returns:
* the targetted node offset in the base device tree
* the targeted node offset in the base device tree
* Negative error code on error
*/
static int overlay_get_target(const void *fdt, const void *fdto,
@ -697,7 +652,7 @@ static int get_path_len(const void *fdt, int nodeoffset)
int len = 0, namelen;
const char *name;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen);
@ -778,26 +733,36 @@ static int overlay_symbol_update(void *fdt, void *fdto)
/* keep end marker to avoid strlen() */
e = path + path_len;
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
if (*path != '/')
return -FDT_ERR_BADVALUE;
/* get fragment name first */
s = strchr(path + 1, '/');
if (!s)
return -FDT_ERR_BADOVERLAY;
if (!s) {
/* Symbol refers to something that won't end
* up in the target tree */
continue;
}
frag_name = path + 1;
frag_name_len = s - path - 1;
/* verify format; safe since "s" lies in \0 terminated prop */
len = sizeof("/__overlay__/") - 1;
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
return -FDT_ERR_BADOVERLAY;
if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
rel_path = s + len;
rel_path_len = e - rel_path;
rel_path_len = e - rel_path - 1;
} else if ((e - s) == len
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
/* /<fragment-name>/__overlay__ */
rel_path = "";
rel_path_len = 0;
} else {
/* Symbol refers to something that won't end
* up in the target tree */
continue;
}
/* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
@ -863,11 +828,15 @@ static int overlay_symbol_update(void *fdt, void *fdto)
int fdt_overlay_apply(void *fdt, void *fdto)
{
uint32_t delta = fdt_get_max_phandle(fdt);
uint32_t delta;
int ret;
FDT_CHECK_HEADER(fdt);
FDT_CHECK_HEADER(fdto);
FDT_RO_PROBE(fdt);
FDT_RO_PROBE(fdto);
ret = fdt_find_max_phandle(fdt, &delta);
if (ret)
goto err;
ret = overlay_adjust_local_phandles(fdto, delta);
if (ret)

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -76,61 +31,170 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
return 0;
}
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
int32_t totalsize;
uint32_t absoffset;
size_t len;
int err;
const char *s, *n;
if (can_assume(VALID_INPUT)) {
s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
if (lenp)
*lenp = strlen(s);
return s;
}
totalsize = fdt_ro_probe_(fdt);
err = totalsize;
if (totalsize < 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
absoffset = stroffset + fdt_off_dt_strings(fdt);
if (absoffset >= totalsize)
goto fail;
len = totalsize - absoffset;
if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
goto fail;
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
if (stroffset >= fdt_size_dt_strings(fdt))
goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
len = fdt_size_dt_strings(fdt) - stroffset;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
if ((stroffset >= 0)
|| (stroffset < -fdt_size_dt_strings(fdt)))
goto fail;
if ((-stroffset) < len)
len = -stroffset;
} else {
err = -FDT_ERR_INTERNAL;
goto fail;
}
s = (const char *)fdt + absoffset;
n = memchr(s, '\0', len);
if (!n) {
/* missing terminating NULL */
err = -FDT_ERR_TRUNCATED;
goto fail;
}
if (lenp)
*lenp = n - s;
return s;
fail:
if (lenp)
*lenp = err;
return NULL;
}
const char *fdt_string(const void *fdt, int stroffset)
{
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
return fdt_get_string(fdt, stroffset, NULL);
}
static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len)
{
const char *p = fdt_string(fdt, stroffset);
int slen;
const char *p = fdt_get_string(fdt, stroffset, &slen);
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
return p && (slen == len) && (memcmp(p, s, len) == 0);
}
uint32_t fdt_get_max_phandle(const void *fdt)
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max_phandle = 0;
int offset;
uint32_t max = 0;
int offset = -1;
for (offset = fdt_next_node(fdt, -1, NULL);;
offset = fdt_next_node(fdt, offset, NULL)) {
uint32_t phandle;
while (true) {
uint32_t value;
offset = fdt_next_node(fdt, offset, NULL);
if (offset < 0) {
if (offset == -FDT_ERR_NOTFOUND)
return max_phandle;
break;
if (offset < 0)
return (uint32_t)-1;
phandle = fdt_get_phandle(fdt, offset);
if (phandle == (uint32_t)-1)
continue;
if (phandle > max_phandle)
max_phandle = phandle;
return offset;
}
value = fdt_get_phandle(fdt, offset);
if (value > max)
max = value;
}
if (phandle)
*phandle = max;
return 0;
}
int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max;
int err;
err = fdt_find_max_phandle(fdt, &max);
if (err < 0)
return err;
if (max == FDT_MAX_PHANDLE)
return -FDT_ERR_NOPHANDLES;
if (phandle)
*phandle = max + 1;
return 0;
}
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
{
int offset = n * sizeof(struct fdt_reserve_entry);
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
if (!can_assume(VALID_INPUT)) {
if (absoffset < fdt_off_mem_rsvmap(fdt))
return NULL;
if (absoffset > fdt_totalsize(fdt) -
sizeof(struct fdt_reserve_entry))
return NULL;
}
return fdt_mem_rsv_(fdt, n);
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
FDT_CHECK_HEADER(fdt);
*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
const struct fdt_reserve_entry *re;
FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n);
if (!can_assume(VALID_INPUT) && !re)
return -FDT_ERR_BADOFFSET;
*address = fdt64_ld(&re->address);
*size = fdt64_ld(&re->size);
return 0;
}
int fdt_num_mem_rsv(const void *fdt)
{
int i = 0;
int i;
const struct fdt_reserve_entry *re;
while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
i++;
for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
if (fdt64_ld(&re->size) == 0)
return i;
}
return -FDT_ERR_TRUNCATED;
}
static int nextprop_(const void *fdt, int offset)
{
@ -161,7 +225,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{
int depth;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
for (depth = 0;
(offset >= 0) && (depth >= 0);
@ -187,7 +251,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
const char *p = path;
int offset = 0;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
/* see if we have an alias */
if (*path != '/') {
@ -237,13 +301,13 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr;
int err;
if (((err = fdt_check_header(fdt)) != 0)
if (((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;
nameptr = nh->name;
if (fdt_version(fdt) < 0x10) {
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
@ -294,7 +358,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int err;
const struct fdt_property *prop;
if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (!can_assume(VALID_INPUT) &&
(err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
@ -303,7 +368,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
*lenp = fdt32_to_cpu(prop->len);
*lenp = fdt32_ld(&prop->len);
return prop;
}
@ -315,7 +380,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) {
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@ -336,11 +401,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
(offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop;
if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
offset = -FDT_ERR_INTERNAL;
break;
}
if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
@ -361,7 +427,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) {
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
@ -392,8 +458,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
return NULL;
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
fdt32_to_cpu(prop->len) >= 8)
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
(poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@ -406,12 +472,27 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop)
return NULL;
if (namep)
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
if (namep) {
const char *name;
int namelen;
if (!can_assume(VALID_INPUT)) {
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
&namelen);
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
}
*namep = name;
} else {
*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
}
}
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
fdt32_to_cpu(prop->len) >= 8)
if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
(offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
@ -436,7 +517,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0;
}
return fdt32_to_cpu(*php);
return fdt32_ld(php);
}
const char *fdt_get_alias_namelen(const void *fdt,
@ -462,7 +543,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
int offset, depth, namelen;
const char *name;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
@ -514,7 +595,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
@ -536,10 +617,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
}
}
if (!can_assume(VALID_INPUT)) {
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
}
return offset; /* error from fdt_next_node() */
}
@ -551,7 +634,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL;
return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
-FDT_ERR_INTERNAL;
return nodedepth;
}
@ -573,7 +657,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val;
int len;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
@ -599,7 +683,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
@ -752,7 +836,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
{
int offset, err;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -67,29 +22,31 @@ static int fdt_blocks_misordered_(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
static int fdt_rw_check_header_(void *fdt)
static int fdt_rw_probe_(void *fdt)
{
FDT_CHECK_HEADER(fdt);
if (can_assume(VALID_DTB))
return 0;
FDT_RO_PROBE(fdt);
if (fdt_version(fdt) < 17)
if (!can_assume(LATEST) && fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
if (!can_assume(LATEST) && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
}
#define FDT_RW_CHECK_HEADER(fdt) \
#define FDT_RW_PROBE(fdt) \
{ \
int err_; \
if ((err_ = fdt_rw_check_header_(fdt)) != 0) \
if ((err_ = fdt_rw_probe_(fdt)) != 0) \
return err_; \
}
static inline int fdt_data_size_(void *fdt)
static inline unsigned int fdt_data_size_(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
@ -97,15 +54,16 @@ static inline int fdt_data_size_(void *fdt)
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
char *end = (char *)fdt + fdt_data_size_(fdt);
unsigned int dsize = fdt_data_size_(fdt);
size_t soff = p - (char *)fdt;
if (((p + oldlen) < p) || ((p + oldlen) > end))
if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
return -FDT_ERR_BADOFFSET;
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
if ((p < (char *)fdt) || (dsize + newlen < oldlen))
return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
if (dsize - oldlen + newlen > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen);
memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
return 0;
}
@ -136,6 +94,14 @@ static int fdt_splice_struct_(void *fdt, void *p,
return 0;
}
/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
int newlen = strlen(s) + 1;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) - newlen);
}
static int fdt_splice_string_(void *fdt, int newlen)
{
void *p = (char *)fdt
@ -149,7 +115,16 @@ static int fdt_splice_string_(void *fdt, int newlen)
return 0;
}
static int fdt_find_add_string_(void *fdt, const char *s)
/**
* fdt_find_add_string_() - Find or allocate a string
*
* @fdt: pointer to the device tree to check/adjust
* @s: string to find/add
* @allocated: Set to 0 if the string was found, 1 if not found and so
* allocated. Ignored if can_assume(NO_ROLLBACK)
* @return offset of string in the string table (whether found or added)
*/
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
@ -157,6 +132,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
int len = strlen(s) + 1;
int err;
if (!can_assume(NO_ROLLBACK))
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
@ -167,6 +145,9 @@ static int fdt_find_add_string_(void *fdt, const char *s)
if (err)
return err;
if (!can_assume(NO_ROLLBACK))
*allocated = 1;
memcpy(new, s, len);
return (new - strtab);
}
@ -176,7 +157,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
struct fdt_reserve_entry *re;
int err;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
@ -192,7 +173,7 @@ int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
@ -225,11 +206,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int nextoffset;
int namestroff;
int err;
int allocated;
if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset;
namestroff = fdt_find_add_string_(fdt, name);
namestroff = fdt_find_add_string_(fdt, name, &allocated);
if (namestroff < 0)
return namestroff;
@ -237,8 +219,12 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err)
if (err) {
/* Delete the string if we failed to add it */
if (!can_assume(NO_ROLLBACK) && allocated)
fdt_del_last_string_(fdt, name);
return err;
}
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff);
@ -252,7 +238,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
int oldlen, newlen;
int err;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
@ -275,7 +261,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop;
int err;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
@ -308,7 +294,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop;
int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
@ -334,7 +320,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop;
int len, proplen;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop)
@ -354,7 +340,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag;
fdt32_t *endtag;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
@ -394,7 +380,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
@ -407,7 +393,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
uint32_t mem_rsv_off, struct_off, strings_off;
int mem_rsv_off, struct_off, strings_off;
mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
@ -435,12 +421,12 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp;
FDT_CHECK_HEADER(fdt);
FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
if (fdt_version(fdt) >= 17) {
if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else {
struct_size = 0;
@ -450,7 +436,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size;
}
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
if (can_assume(LIBFDT_ORDER) ||
!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
@ -494,7 +481,7 @@ int fdt_pack(void *fdt)
{
int mem_rsv_size;
FDT_RW_CHECK_HEADER(fdt);
FDT_RW_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);

View File

@ -1,51 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -82,6 +38,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
FDT_ERRTABENT(FDT_ERR_BADFLAGS),
};
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
@ -55,21 +10,87 @@
#include "libfdt_internal.h"
static int fdt_sw_check_header_(void *fdt)
static int fdt_sw_probe_(void *fdt)
{
if (fdt_magic(fdt) != FDT_SW_MAGIC)
if (!can_assume(VALID_INPUT)) {
if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
/* FIXME: should check more details about the header state */
}
return 0;
}
#define FDT_SW_CHECK_HEADER(fdt) \
#define FDT_SW_PROBE(fdt) \
{ \
int err; \
if ((err = fdt_sw_check_header_(fdt)) != 0) \
if ((err = fdt_sw_probe_(fdt)) != 0) \
return err; \
}
/* 'memrsv' state: Initial state after fdt_create()
*
* Allowed functions:
* fdt_add_reservemap_entry()
* fdt_finish_reservemap() [moves to 'struct' state]
*/
static int fdt_sw_probe_memrsv_(void *fdt)
{
int err = fdt_sw_probe_(fdt);
if (err)
return err;
if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}
#define FDT_SW_PROBE_MEMRSV(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
return err; \
}
/* 'struct' state: Enter this state after fdt_finish_reservemap()
*
* Allowed functions:
* fdt_begin_node()
* fdt_end_node()
* fdt_property*()
* fdt_finish() [moves to 'complete' state]
*/
static int fdt_sw_probe_struct_(void *fdt)
{
int err = fdt_sw_probe_(fdt);
if (err)
return err;
if (!can_assume(VALID_INPUT) &&
fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE;
return 0;
}
#define FDT_SW_PROBE_STRUCT(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
return err; \
}
static inline uint32_t sw_flags(void *fdt)
{
/* assert: (fdt_magic(fdt) == FDT_SW_MAGIC) */
return fdt_last_comp_version(fdt);
}
/* 'complete' state: Enter this state after fdt_finish()
*
* Allowed functions: none
*/
static void *fdt_grab_space_(void *fdt, size_t len)
{
int offset = fdt_size_dt_struct(fdt);
@ -85,38 +106,59 @@ static void *fdt_grab_space_(void *fdt, size_t len)
return fdt_offset_ptr_w_(fdt, offset);
}
int fdt_create(void *buf, int bufsize)
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
{
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry));
void *fdt = buf;
if (bufsize < sizeof(struct fdt_header))
if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE;
if (flags & ~FDT_CREATE_FLAGS_ALL)
return -FDT_ERR_BADFLAGS;
memset(buf, 0, bufsize);
/*
* magic and last_comp_version keep intermediate state during the fdt
* creation process, which is replaced with the proper FDT format by
* fdt_finish().
*
* flags should be accessed with sw_flags().
*/
fdt_set_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, flags);
fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry)));
fdt_set_off_mem_rsvmap(fdt, hdrsize);
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, bufsize);
fdt_set_off_dt_strings(fdt, 0);
return 0;
}
int fdt_create(void *buf, int bufsize)
{
return fdt_create_with_flags(buf, bufsize, 0);
}
int fdt_resize(void *fdt, void *buf, int bufsize)
{
size_t headsize, tailsize;
char *oldtail, *newtail;
FDT_SW_CHECK_HEADER(fdt);
FDT_SW_PROBE(fdt);
headsize = fdt_off_dt_struct(fdt);
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
if (!can_assume(VALID_DTB) &&
headsize + tailsize > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE;
@ -133,8 +175,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
memmove(buf, fdt, headsize);
}
fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize);
if (fdt_off_dt_strings(buf))
fdt_set_off_dt_strings(buf, bufsize);
return 0;
}
@ -144,10 +187,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
struct fdt_reserve_entry *re;
int offset;
FDT_SW_CHECK_HEADER(fdt);
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
FDT_SW_PROBE_MEMRSV(fdt);
offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
@ -164,16 +204,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
int fdt_finish_reservemap(void *fdt)
{
return fdt_add_reservemap_entry(fdt, 0, 0);
int err = fdt_add_reservemap_entry(fdt, 0, 0);
if (err)
return err;
fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
return 0;
}
int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
int namelen = strlen(name) + 1;
int namelen;
FDT_SW_CHECK_HEADER(fdt);
FDT_SW_PROBE_STRUCT(fdt);
namelen = strlen(name) + 1;
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh)
return -FDT_ERR_NOSPACE;
@ -187,7 +234,7 @@ int fdt_end_node(void *fdt)
{
fdt32_t *en;
FDT_SW_CHECK_HEADER(fdt);
FDT_SW_PROBE_STRUCT(fdt);
en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en)
@ -197,19 +244,13 @@ int fdt_end_node(void *fdt)
return 0;
}
static int fdt_find_add_string_(void *fdt, const char *s)
static int fdt_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top)
@ -220,20 +261,56 @@ static int fdt_find_add_string_(void *fdt, const char *s)
return offset;
}
/* Must only be used to roll back in case of error */
static void fdt_del_last_string_(void *fdt, const char *s)
{
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
fdt_set_size_dt_strings(fdt, strtabsize - len);
}
static int fdt_find_add_string_(void *fdt, const char *s, int *allocated)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
int strtabsize = fdt_size_dt_strings(fdt);
const char *p;
*allocated = 0;
p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
*allocated = 1;
return fdt_add_string_(fdt, s);
}
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{
struct fdt_property *prop;
int nameoff;
int allocated;
FDT_SW_CHECK_HEADER(fdt);
FDT_SW_PROBE_STRUCT(fdt);
nameoff = fdt_find_add_string_(fdt, name);
/* String de-duplication can be slow, _NO_NAME_DEDUP skips it */
if (sw_flags(fdt) & FDT_CREATE_FLAG_NO_NAME_DEDUP) {
allocated = 1;
nameoff = fdt_add_string_(fdt, name);
} else {
nameoff = fdt_find_add_string_(fdt, name, &allocated);
}
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop)
if (! prop) {
if (allocated)
fdt_del_last_string_(fdt, name);
return -FDT_ERR_NOSPACE;
}
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
@ -262,7 +339,7 @@ int fdt_finish(void *fdt)
uint32_t tag;
int offset, nextoffset;
FDT_SW_CHECK_HEADER(fdt);
FDT_SW_PROBE_STRUCT(fdt);
/* Add terminator */
end = fdt_grab_space_(fdt, sizeof(*end));
@ -295,6 +372,10 @@ int fdt_finish(void *fdt)
/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
/* And fix up fields that were keeping intermediate state. */
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_magic(fdt, FDT_MAGIC);
return 0;
}

View File

@ -1,52 +1,7 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"

View File

@ -1,59 +1,18 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_H
#define LIBFDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include "fdt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FDT_FIRST_SUPPORTED_VERSION 0x02
#define FDT_LAST_SUPPORTED_VERSION 0x11
@ -90,8 +49,9 @@
/* Error codes: codes for bad device tree blobs */
#define FDT_ERR_TRUNCATED 8
/* FDT_ERR_TRUNCATED: Structure block of the given device tree
* ends without an FDT_END tag. */
/* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
* terminated (overflows, goes outside allowed bounds, or
* isn't properly terminated). */
#define FDT_ERR_BADMAGIC 9
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
* device tree at all - it is missing the flattened device
@ -137,7 +97,15 @@
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
* phandle available anymore without causing an overflow */
#define FDT_ERR_MAX 17
#define FDT_ERR_BADFLAGS 18
/* FDT_ERR_BADFLAGS: The function was passed a flags field that
* contains invalid flags or an invalid combination of flags. */
#define FDT_ERR_MAX 18
/* constants */
#define FDT_MAX_PHANDLE 0xfffffffe
/* Valid values for phandles range from 1 to 2^32-2. */
/**********************************************************************/
/* Low-level functions (you probably don't need these) */
@ -153,6 +121,61 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
/*
* Alignment helpers:
* These helpers access words from a device tree blob. They're
* built to work even with unaligned pointers on platforms (ike
* ARM) that don't like unaligned loads and stores
*/
static inline uint32_t fdt32_ld(const fdt32_t *p)
{
const uint8_t *bp = (const uint8_t *)p;
return ((uint32_t)bp[0] << 24)
| ((uint32_t)bp[1] << 16)
| ((uint32_t)bp[2] << 8)
| bp[3];
}
static inline void fdt32_st(void *property, uint32_t value)
{
uint8_t *bp = (uint8_t *)property;
bp[0] = value >> 24;
bp[1] = (value >> 16) & 0xff;
bp[2] = (value >> 8) & 0xff;
bp[3] = value & 0xff;
}
static inline uint64_t fdt64_ld(const fdt64_t *p)
{
const uint8_t *bp = (const uint8_t *)p;
return ((uint64_t)bp[0] << 56)
| ((uint64_t)bp[1] << 48)
| ((uint64_t)bp[2] << 40)
| ((uint64_t)bp[3] << 32)
| ((uint64_t)bp[4] << 24)
| ((uint64_t)bp[5] << 16)
| ((uint64_t)bp[6] << 8)
| bp[7];
}
static inline void fdt64_st(void *property, uint64_t value)
{
uint8_t *bp = (uint8_t *)property;
bp[0] = value >> 56;
bp[1] = (value >> 48) & 0xff;
bp[2] = (value >> 40) & 0xff;
bp[3] = (value >> 32) & 0xff;
bp[4] = (value >> 24) & 0xff;
bp[5] = (value >> 16) & 0xff;
bp[6] = (value >> 8) & 0xff;
bp[7] = value & 0xff;
}
/**********************************************************************/
/* Traversal functions */
/**********************************************************************/
@ -195,7 +218,7 @@ int fdt_next_subnode(const void *fdt, int offset);
* ...
* }
*
* if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
* if ((node < 0) && (node != -FDT_ERR_NOTFOUND)) {
* Error handling
* }
*
@ -213,7 +236,7 @@ int fdt_next_subnode(const void *fdt, int offset);
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
(fdt32_ld(&((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
@ -244,18 +267,32 @@ fdt_set_hdr_(size_dt_struct);
#undef fdt_set_hdr_
/**
* fdt_check_header - sanity check a device tree or possible device tree
* fdt_header_size - return the size of the tree's header
* @fdt: pointer to a flattened device tree
*/
size_t fdt_header_size(const void *fdt);
/**
* fdt_header_size_ - internal function which takes a version number
*/
size_t fdt_header_size_(uint32_t version);
/**
* fdt_check_header - sanity check a device tree header
* @fdt: pointer to data which might be a flattened device tree
*
* fdt_check_header() checks that the given buffer contains what
* appears to be a flattened device tree with sane information in its
* header.
* appears to be a flattened device tree, and that the header contains
* valid information (to the extent that can be determined from the
* header alone).
*
* returns:
* 0, if the buffer appears to contain a valid device tree
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings, as above
* -FDT_ERR_BADSTATE,
* -FDT_ERR_TRUNCATED, standard meanings, as above
*/
int fdt_check_header(const void *fdt);
@ -284,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/* Read-only functions */
/**********************************************************************/
int fdt_check_full(const void *fdt, size_t bufsize);
/**
* fdt_get_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob
* @stroffset: offset of the string within the strings block (native endian)
* @lenp: optional pointer to return the string's length
*
* fdt_get_string() retrieves a pointer to a single string from the
* strings block of the device tree blob at fdt, and optionally also
* returns the string's length in *lenp.
*
* returns:
* a pointer to the string, on success
* NULL, if stroffset is out of bounds, or doesn't point to a valid string
*/
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
/**
* fdt_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob
@ -294,10 +349,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
*
* returns:
* a pointer to the string, on success
* NULL, if stroffset is out of bounds
* NULL, if stroffset is out of bounds, or doesn't point to a valid string
*/
const char *fdt_string(const void *fdt, int stroffset);
/**
* fdt_find_max_phandle - find and return the highest phandle in a tree
* @fdt: pointer to the device tree blob
* @phandle: return location for the highest phandle value found in the tree
*
* fdt_find_max_phandle() finds the highest phandle value in the given device
* tree. The value returned in @phandle is only valid if the function returns
* success.
*
* returns:
* 0 on success or a negative error code on failure
*/
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle);
/**
* fdt_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob
@ -306,12 +375,39 @@ const char *fdt_string(const void *fdt, int stroffset);
* device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1.
*
* This function is deprecated in favour of fdt_find_max_phandle().
*
* returns:
* the highest phandle on success
* 0, if no phandle was found in the device tree
* -1, if an error occurred
*/
uint32_t fdt_get_max_phandle(const void *fdt);
static inline uint32_t fdt_get_max_phandle(const void *fdt)
{
uint32_t phandle;
int err;
err = fdt_find_max_phandle(fdt, &phandle);
if (err < 0)
return (uint32_t)-1;
return phandle;
}
/**
* fdt_generate_phandle - return a new, unused phandle for a device tree blob
* @fdt: pointer to the device tree blob
* @phandle: return location for the new phandle
*
* Walks the device tree blob and looks for the highest phandle value. On
* success, the new, unused phandle value (one higher than the previously
* highest phandle value in the device tree blob) will be returned in the
* @phandle parameter.
*
* Returns:
* 0 on success or a negative error-code on failure
*/
int fdt_generate_phandle(const void *fdt, uint32_t *phandle);
/**
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
@ -503,7 +599,7 @@ int fdt_next_property_offset(const void *fdt, int offset);
* ...
* }
*
* if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
* if ((property < 0) && (property != -FDT_ERR_NOTFOUND)) {
* Error handling
* }
*
@ -606,7 +702,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
/**
* fdt_getprop_by_offset - retrieve the value of a property at a given offset
* @fdt: pointer to the device tree blob
* @ffset: offset of the property to read
* @offset: offset of the property to read
* @namep: pointer to a string variable (will be overwritten) or NULL
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
@ -1090,7 +1186,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
*
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
* 2, if the node has no #address-cells property
* 1, if the node has no #size-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property
* -FDT_ERR_BADMAGIC,
@ -1297,7 +1393,45 @@ int fdt_nop_node(void *fdt, int nodeoffset);
/* Sequential write functions */
/**********************************************************************/
/* fdt_create_with_flags flags */
#define FDT_CREATE_FLAG_NO_NAME_DEDUP 0x1
/* FDT_CREATE_FLAG_NO_NAME_DEDUP: Do not try to de-duplicate property
* names in the fdt. This can result in faster creation times, but
* a larger fdt. */
#define FDT_CREATE_FLAGS_ALL (FDT_CREATE_FLAG_NO_NAME_DEDUP)
/**
* fdt_create_with_flags - begin creation of a new fdt
* @fdt: pointer to memory allocated where fdt will be created
* @bufsize: size of the memory space at fdt
* @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0.
*
* fdt_create_with_flags() begins the process of creating a new fdt with
* the sequential write interface.
*
* fdt creation process must end with fdt_finished() to produce a valid fdt.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
* -FDT_ERR_BADFLAGS, flags is not valid
*/
int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
/**
* fdt_create - begin creation of a new fdt
* @fdt: pointer to memory allocated where fdt will be created
* @bufsize: size of the memory space at fdt
*
* fdt_create() is equivalent to fdt_create_with_flags() with flags=0.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, bufsize is insufficient for a minimal fdt
*/
int fdt_create(void *buf, int bufsize);
int fdt_resize(void *fdt, void *buf, int bufsize);
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
int fdt_finish_reservemap(void *fdt);
@ -1313,10 +1447,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
fdt64_t tmp = cpu_to_fdt64(val);
return fdt_property(fdt, name, &tmp, sizeof(tmp));
}
#ifndef SWIG /* Not available in Python */
static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
{
return fdt_property_u32(fdt, name, val);
}
#endif
/**
* fdt_property_placeholder - add a new property and return a ptr to its value
@ -1765,6 +1902,43 @@ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/**
* fdt_appendprop_addrrange - append a address range property
* @fdt: pointer to the device tree blob
* @parent: offset of the parent node
* @nodeoffset: offset of the node to add a property at
* @name: name of property
* @addr: start address of a given range
* @size: size of a given range
*
* fdt_appendprop_addrrange() appends an address range value (start
* address and size) to the value of the named property in the given
* node, or creates a new property with that value if it does not
* already exist.
* If "name" is not specified, a default "reg" is used.
* Cell sizes are determined by parent's #address-cells and #size-cells.
*
* This function may insert data into the blob, and will therefore
* change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #address-cells property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADVALUE, addr or size doesn't fit to respective cells size
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain a new property
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset,
const char *name, uint64_t addr, uint64_t size);
/**
* fdt_delprop - delete a property
* @fdt: pointer to the device tree blob
@ -1899,4 +2073,8 @@ int fdt_overlay_apply(void *fdt, void *fdto);
const char *fdt_strerror(int errval);
#ifdef __cplusplus
}
#endif
#endif /* LIBFDT_H */

View File

@ -1,61 +1,18 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef __CHECKER__
#define FDT_FORCE __attribute__((force))

View File

@ -1,65 +1,21 @@
/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
#ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <fdt.h>
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
#define FDT_CHECK_HEADER(fdt) \
int32_t fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
{ \
int err_; \
if ((err_ = fdt_check_header(fdt)) != 0) \
return err_; \
int32_t totalsize_; \
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
return totalsize_; \
}
int fdt_check_node_offset_(const void *fdt, int offset);
@ -92,4 +48,126 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
#define FDT_SW_MAGIC (~FDT_MAGIC)
/**********************************************************************/
/* Checking controls */
/**********************************************************************/
#ifndef FDT_ASSUME_MASK
#define FDT_ASSUME_MASK 0
#endif
/*
* Defines assumptions which can be enabled. Each of these can be enabled
* individually. For maximum safety, don't enable any assumptions!
*
* For minimal code size and no safety, use ASSUME_PERFECT at your own risk.
* You should have another method of validating the device tree, such as a
* signature or hash check before using libfdt.
*
* For situations where security is not a concern it may be safe to enable
* ASSUME_SANE.
*/
enum {
/*
* This does essentially no checks. Only the latest device-tree
* version is correctly handled. Inconsistencies or errors in the device
* tree may cause undefined behaviour or crashes. Invalid parameters
* passed to libfdt may do the same.
*
* If an error occurs when modifying the tree it may leave the tree in
* an intermediate (but valid) state. As an example, adding a property
* where there is insufficient space may result in the property name
* being added to the string table even though the property itself is
* not added to the struct section.
*
* Only use this if you have a fully validated device tree with
* the latest supported version and wish to minimise code size.
*/
ASSUME_PERFECT = 0xff,
/*
* This assumes that the device tree is sane. i.e. header metadata
* and basic hierarchy are correct.
*
* With this assumption enabled, normal device trees produced by libfdt
* and the compiler should be handled safely. Malicious device trees and
* complete garbage may cause libfdt to behave badly or crash. Truncated
* device trees (e.g. those only partially loaded) can also cause
* problems.
*
* Note: Only checks that relate exclusively to the device tree itself
* (not the parameters passed to libfdt) are disabled by this
* assumption. This includes checking headers, tags and the like.
*/
ASSUME_VALID_DTB = 1 << 0,
/*
* This builds on ASSUME_VALID_DTB and further assumes that libfdt
* functions are called with valid parameters, i.e. not trigger
* FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any
* extensive checking of parameters and the device tree, making various
* assumptions about correctness.
*
* It doesn't make sense to enable this assumption unless
* ASSUME_VALID_DTB is also enabled.
*/
ASSUME_VALID_INPUT = 1 << 1,
/*
* This disables checks for device-tree version and removes all code
* which handles older versions.
*
* Only enable this if you know you have a device tree with the latest
* version.
*/
ASSUME_LATEST = 1 << 2,
/*
* This assumes that it is OK for a failed addition to the device tree,
* due to lack of space or some other problem, to skip any rollback
* steps (such as dropping the property name from the string table).
* This is safe to enable in most circumstances, even though it may
* leave the tree in a sub-optimal state.
*/
ASSUME_NO_ROLLBACK = 1 << 3,
/*
* This assumes that the device tree components appear in a 'convenient'
* order, i.e. the memory reservation block first, then the structure
* block and finally the string block.
*
* This order is not specified by the device-tree specification,
* but is expected by libfdt. The device-tree compiler always created
* device trees with this order.
*
* This assumption disables a check in fdt_open_into() and removes the
* ability to fix the problem there. This is safe if you know that the
* device tree is correctly ordered. See fdt_blocks_misordered_().
*/
ASSUME_LIBFDT_ORDER = 1 << 4,
/*
* This assumes that libfdt itself does not have any internal bugs. It
* drops certain checks that should never be needed unless libfdt has an
* undiscovered bug.
*
* This can generally be considered safe to enable.
*/
ASSUME_LIBFDT_FLAWLESS = 1 << 5,
};
/**
* can_assume_() - check if a particular assumption is enabled
*
* @mask: Mask to check (ASSUME_...)
* @return true if that assumption is enabled, else false
*/
static inline bool can_assume_(int mask)
{
return FDT_ASSUME_MASK & mask;
}
/** helper macros for checking assumptions */
#define can_assume(_assume) can_assume_(ASSUME_ ## _assume)
#endif /* LIBFDT_INTERNAL_H */

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#include "srcpos.h"
/*
* Tree building functions
@ -50,7 +36,8 @@ void delete_labels(struct label **labels)
label->deleted = 1;
}
struct property *build_property(char *name, struct data val)
struct property *build_property(char *name, struct data val,
struct srcpos *srcpos)
{
struct property *new = xmalloc(sizeof(*new));
@ -58,6 +45,7 @@ struct property *build_property(char *name, struct data val)
new->name = name;
new->val = val;
new->srcpos = srcpos_copy(srcpos);
return new;
}
@ -97,7 +85,8 @@ struct property *reverse_properties(struct property *first)
return head;
}
struct node *build_node(struct property *proplist, struct node *children)
struct node *build_node(struct property *proplist, struct node *children,
struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
struct node *child;
@ -106,6 +95,7 @@ struct node *build_node(struct property *proplist, struct node *children)
new->proplist = reverse_properties(proplist);
new->children = children;
new->srcpos = srcpos_copy(srcpos);
for_each_child(new, child) {
child->parent = new;
@ -114,13 +104,14 @@ struct node *build_node(struct property *proplist, struct node *children)
return new;
}
struct node *build_node_delete(void)
struct node *build_node_delete(struct srcpos *srcpos)
{
struct node *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->deleted = 1;
new->srcpos = srcpos_copy(srcpos);
return new;
}
@ -183,6 +174,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
old_prop->val = new_prop->val;
old_prop->deleted = 0;
free(old_prop->srcpos);
old_prop->srcpos = new_prop->srcpos;
free(new_prop);
new_prop = NULL;
break;
@ -223,6 +216,8 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
add_child(old_node, new_child);
}
old_node->srcpos = srcpos_extend(old_node->srcpos, new_node->srcpos);
/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);
@ -239,20 +234,21 @@ struct node * add_orphan_node(struct node *dt, struct node *new_node, char *ref)
char *name;
if (ref[0] == '/') {
d = data_add_marker(d, TYPE_STRING, ref);
d = data_append_data(d, ref, strlen(ref) + 1);
p = build_property("target-path", d);
p = build_property("target-path", d, NULL);
} else {
d = data_add_marker(d, REF_PHANDLE, ref);
d = data_append_integer(d, 0xffffffff, 32);
p = build_property("target", d);
p = build_property("target", d, NULL);
}
xasprintf(&name, "fragment@%u",
next_orphan_fragment++);
name_node(new_node, "__overlay__");
node = build_node(p, new_node);
node = build_node(p, new_node, NULL);
name_node(node, name);
add_child(dt, node);
@ -340,18 +336,21 @@ void delete_node(struct node *node)
}
void append_to_property(struct node *node,
char *name, const void *data, int len)
char *name, const void *data, int len,
enum markertype type)
{
struct data d;
struct property *p;
p = get_property(node, name);
if (p) {
d = data_append_data(p->val, data, len);
d = data_add_marker(p->val, type, name);
d = data_append_data(d, data, len);
p->val = d;
} else {
d = data_append_data(empty_data, data, len);
p = build_property(name, d);
d = data_add_marker(empty_data, type, name);
d = data_append_data(d, data, len);
p = build_property(name, d, NULL);
add_property(node, p);
}
}
@ -527,8 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path)
p = strchr(path, '/');
for_each_child(tree, child) {
if (p && (strlen(child->name) == p-path) &&
strprefixeq(path, p - path, child->name))
if (p && strprefixeq(path, p - path, child->name))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
@ -594,6 +592,7 @@ struct node *get_node_by_ref(struct node *tree, const char *ref)
cell_t get_node_phandle(struct node *root, struct node *node)
{
static cell_t phandle = 1; /* FIXME: ick, static local */
struct data d = empty_data;
if ((node->phandle != 0) && (node->phandle != -1))
return node->phandle;
@ -603,17 +602,16 @@ cell_t get_node_phandle(struct node *root, struct node *node)
node->phandle = phandle;
d = data_add_marker(d, TYPE_UINT32, NULL);
d = data_append_cell(d, phandle);
if (!get_property(node, "linux,phandle")
&& (phandle_format & PHANDLE_LEGACY))
add_property(node,
build_property("linux,phandle",
data_append_cell(empty_data, phandle)));
add_property(node, build_property("linux,phandle", d, NULL));
if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR))
add_property(node,
build_property("phandle",
data_append_cell(empty_data, phandle)));
add_property(node, build_property("phandle", d, NULL));
/* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be
@ -787,7 +785,7 @@ static struct node *build_and_name_child_node(struct node *parent, char *name)
{
struct node *node;
node = build_node(NULL, NULL);
node = build_node(NULL, NULL, NULL);
name_node(node, xstrdup(name));
add_child(parent, node);
@ -848,8 +846,9 @@ static void generate_label_tree_internal(struct dt_info *dti,
/* insert it */
p = build_property(l->label,
data_copy_mem(node->fullpath,
strlen(node->fullpath) + 1));
data_copy_escape_string(node->fullpath,
strlen(node->fullpath)),
NULL);
add_property(an, p);
}
@ -899,7 +898,7 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
free(entry);
}
@ -959,7 +958,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
char **compp;
int i, depth;
/* walk back retreiving depth */
/* walk back retrieving depth */
depth = 0;
for (wn = node; wn; wn = wn->parent)
depth++;
@ -982,7 +981,7 @@ static void add_local_fixup_entry(struct dt_info *dti,
free(compp);
value_32 = cpu_to_fdt32(m->offset);
append_to_property(wn, prop->name, &value_32, sizeof(value_32));
append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
}
static void generate_local_fixups_tree_internal(struct dt_info *dti,

View File

@ -1,20 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#define _GNU_SOURCE
@ -33,6 +19,9 @@ struct search_path {
/* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail;
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (100)
static int srcfile_depth; /* = 0 */
static char *get_dirname(const char *path)
{
@ -51,11 +40,51 @@ static char *get_dirname(const char *path)
FILE *depfile; /* = NULL */
struct srcfile_state *current_srcfile; /* = NULL */
static char *initial_path; /* = NULL */
static int initial_pathlen; /* = 0 */
static bool initial_cpp = true;
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (100)
static int srcfile_depth; /* = 0 */
static void set_initial_path(char *fname)
{
int i, len = strlen(fname);
xasprintf(&initial_path, "%s", fname);
initial_pathlen = 0;
for (i = 0; i != len; i++)
if (initial_path[i] == '/')
initial_pathlen++;
}
static char *shorten_to_initial_path(char *fname)
{
char *p1, *p2, *prevslash1 = NULL;
int slashes = 0;
for (p1 = fname, p2 = initial_path; *p1 && *p2; p1++, p2++) {
if (*p1 != *p2)
break;
if (*p1 == '/') {
prevslash1 = p1;
slashes++;
}
}
p1 = prevslash1 + 1;
if (prevslash1) {
int diff = initial_pathlen - slashes, i, j;
int restlen = strlen(fname) - (p1 - fname);
char *res;
res = xmalloc((3 * diff) + restlen + 1);
for (i = 0, j = 0; i != diff; i++) {
res[j++] = '.';
res[j++] = '.';
res[j++] = '/';
}
strcpy(res + j, p1);
return res;
}
return NULL;
}
/**
* Try to open a file in a given directory.
@ -157,6 +186,9 @@ void srcfile_push(const char *fname)
srcfile->colno = 1;
current_srcfile = srcfile;
if (srcfile_depth == 1)
set_initial_path(srcfile->name);
}
bool srcfile_pop(void)
@ -197,18 +229,6 @@ void srcfile_add_search_path(const char *dirname)
search_path_tail = &node->next;
}
/*
* The empty source position.
*/
struct srcpos srcpos_empty = {
.first_line = 0,
.first_column = 0,
.last_line = 0,
.last_column = 0,
.file = NULL,
};
void srcpos_update(struct srcpos *pos, const char *text, int len)
{
int i;
@ -234,13 +254,35 @@ struct srcpos *
srcpos_copy(struct srcpos *pos)
{
struct srcpos *pos_new;
struct srcfile_state *srcfile_state;
if (!pos)
return NULL;
pos_new = xmalloc(sizeof(struct srcpos));
assert(pos->next == NULL);
memcpy(pos_new, pos, sizeof(struct srcpos));
/* allocate without free */
srcfile_state = xmalloc(sizeof(struct srcfile_state));
memcpy(srcfile_state, pos->file, sizeof(struct srcfile_state));
pos_new->file = srcfile_state;
return pos_new;
}
struct srcpos *srcpos_extend(struct srcpos *pos, struct srcpos *newtail)
{
struct srcpos *p;
if (!pos)
return newtail;
for (p = pos; p->next != NULL; p = p->next);
p->next = newtail;
return pos;
}
char *
srcpos_string(struct srcpos *pos)
{
@ -266,6 +308,68 @@ srcpos_string(struct srcpos *pos)
return pos_str;
}
static char *
srcpos_string_comment(struct srcpos *pos, bool first_line, int level)
{
char *pos_str, *fname, *first, *rest;
bool fresh_fname = false;
if (!pos) {
if (level > 1) {
xasprintf(&pos_str, "<no-file>:<no-line>");
return pos_str;
} else {
return NULL;
}
}
if (!pos->file)
fname = "<no-file>";
else if (!pos->file->name)
fname = "<no-filename>";
else if (level > 1)
fname = pos->file->name;
else {
fname = shorten_to_initial_path(pos->file->name);
if (fname)
fresh_fname = true;
else
fname = pos->file->name;
}
if (level > 1)
xasprintf(&first, "%s:%d:%d-%d:%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
else
xasprintf(&first, "%s:%d", fname,
first_line ? pos->first_line : pos->last_line);
if (fresh_fname)
free(fname);
if (pos->next != NULL) {
rest = srcpos_string_comment(pos->next, first_line, level);
xasprintf(&pos_str, "%s, %s", first, rest);
free(first);
free(rest);
} else {
pos_str = first;
}
return pos_str;
}
char *srcpos_string_first(struct srcpos *pos, int level)
{
return srcpos_string_comment(pos, true, level);
}
char *srcpos_string_last(struct srcpos *pos, int level)
{
return srcpos_string_comment(pos, false, level);
}
void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)
{
@ -294,4 +398,9 @@ void srcpos_set_line(char *f, int l)
{
current_srcfile->name = f;
current_srcfile->lineno = l;
if (initial_cpp) {
initial_cpp = false;
set_initial_path(f);
}
}

View File

@ -1,20 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#ifndef SRCPOS_H
@ -74,6 +60,7 @@ struct srcpos {
int last_line;
int last_column;
struct srcfile_state *file;
struct srcpos *next;
};
#define YYLTYPE struct srcpos
@ -93,19 +80,18 @@ struct srcpos {
YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
(Current).next = NULL; \
} while (0)
/*
* Fictional source position used for IR nodes that are
* created without otherwise knowing a true source position.
* For example,constant definitions from the command line.
*/
extern struct srcpos srcpos_empty;
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos);
extern struct srcpos *srcpos_extend(struct srcpos *new_srcpos,
struct srcpos *old_srcpos);
extern char *srcpos_string(struct srcpos *pos);
extern char *srcpos_string_first(struct srcpos *pos, int level);
extern char *srcpos_string_last(struct srcpos *pos, int level);
extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va);

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.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
@ -61,24 +46,18 @@ static bool isstring(char c)
|| strchr("\a\b\t\n\v\f\r", c));
}
static void write_propval_string(FILE *f, struct data val)
static void write_propval_string(FILE *f, const char *s, size_t len)
{
const char *str = val.val;
int i;
struct marker *m = val.markers;
const char *end = s + len - 1;
assert(str[val.len-1] == '\0');
if (!len)
return;
assert(*end == '\0');
while (m && (m->offset == 0)) {
if (m->type == LABEL)
fprintf(f, "%s: ", m->ref);
m = m->next;
}
fprintf(f, "\"");
for (i = 0; i < (val.len-1); i++) {
char c = str[i];
while (s < end) {
char c = *s++;
switch (c) {
case '\a':
fprintf(f, "\\a");
@ -108,91 +87,80 @@ static void write_propval_string(FILE *f, struct data val)
fprintf(f, "\\\"");
break;
case '\0':
fprintf(f, "\", ");
while (m && (m->offset <= (i + 1))) {
if (m->type == LABEL) {
assert(m->offset == (i+1));
fprintf(f, "%s: ", m->ref);
}
m = m->next;
}
fprintf(f, "\"");
fprintf(f, "\\0");
break;
default:
if (isprint((unsigned char)c))
fprintf(f, "%c", c);
else
fprintf(f, "\\x%02hhx", c);
fprintf(f, "\\x%02"PRIx8, c);
}
}
fprintf(f, "\"");
/* Wrap up any labels at the end of the value */
for_each_marker_of_type(m, LABEL) {
assert (m->offset == val.len);
fprintf(f, " %s:", m->ref);
}
}
static void write_propval_cells(FILE *f, struct data val)
static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
{
void *propend = val.val + val.len;
fdt32_t *cp = (fdt32_t *)val.val;
struct marker *m = val.markers;
const char *end = p + len;
assert(len % width == 0);
fprintf(f, "<");
for (;;) {
while (m && (m->offset <= ((char *)cp - val.val))) {
if (m->type == LABEL) {
assert(m->offset == ((char *)cp - val.val));
fprintf(f, "%s: ", m->ref);
}
m = m->next;
}
fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
if ((void *)cp >= propend)
for (; p < end; p += width) {
switch (width) {
case 1:
fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
break;
fprintf(f, " ");
case 2:
fprintf(f, "0x%02"PRIx16, dtb_ld16(p));
break;
case 4:
fprintf(f, "0x%02"PRIx32, dtb_ld32(p));
break;
case 8:
fprintf(f, "0x%02"PRIx64, dtb_ld64(p));
break;
}
if (p + width < end)
fputc(' ', f);
}
}
/* Wrap up any labels at the end of the value */
for_each_marker_of_type(m, LABEL) {
assert (m->offset == val.len);
fprintf(f, " %s:", m->ref);
}
fprintf(f, ">");
}
static void write_propval_bytes(FILE *f, struct data val)
static bool has_data_type_information(struct marker *m)
{
void *propend = val.val + val.len;
const char *bp = val.val;
struct marker *m = val.markers;
return m->type >= TYPE_UINT8;
}
fprintf(f, "[");
for (;;) {
while (m && (m->offset == (bp-val.val))) {
if (m->type == LABEL)
fprintf(f, "%s: ", m->ref);
static struct marker *next_type_marker(struct marker *m)
{
while (m && !has_data_type_information(m))
m = m->next;
return m;
}
fprintf(f, "%02hhx", (unsigned char)(*bp++));
if ((const void *)bp >= propend)
break;
fprintf(f, " ");
size_t type_marker_length(struct marker *m)
{
struct marker *next = next_type_marker(m->next);
if (next)
return next->offset - m->offset;
return 0;
}
/* Wrap up any labels at the end of the value */
for_each_marker_of_type(m, LABEL) {
assert (m->offset == val.len);
fprintf(f, " %s:", m->ref);
}
fprintf(f, "]");
}
static const char *delim_start[] = {
[TYPE_UINT8] = "[",
[TYPE_UINT16] = "/bits/ 16 <",
[TYPE_UINT32] = "<",
[TYPE_UINT64] = "/bits/ 64 <",
[TYPE_STRING] = "",
};
static const char *delim_end[] = {
[TYPE_UINT8] = "]",
[TYPE_UINT16] = ">",
[TYPE_UINT32] = ">",
[TYPE_UINT64] = ">",
[TYPE_STRING] = "",
};
static void write_propval(FILE *f, struct property *prop)
static enum markertype guess_value_type(struct property *prop)
{
int len = prop->val.len;
const char *p = prop->val.val;
@ -201,11 +169,6 @@ static void write_propval(FILE *f, struct property *prop)
int nnotstringlbl = 0, nnotcelllbl = 0;
int i;
if (len == 0) {
fprintf(f, ";\n");
return;
}
for (i = 0; i < len; i++) {
if (! isstring(p[i]))
nnotstring++;
@ -220,17 +183,99 @@ static void write_propval(FILE *f, struct property *prop)
nnotcelllbl++;
}
fprintf(f, " = ");
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
&& (nnotstringlbl == 0)) {
write_propval_string(f, prop->val);
return TYPE_STRING;
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
write_propval_cells(f, prop->val);
} else {
write_propval_bytes(f, prop->val);
return TYPE_UINT32;
}
fprintf(f, ";\n");
return TYPE_UINT8;
}
static void write_propval(FILE *f, struct property *prop)
{
size_t len = prop->val.len;
struct marker *m = prop->val.markers;
struct marker dummy_marker;
enum markertype emit_type = TYPE_NONE;
char *srcstr;
if (len == 0) {
fprintf(f, ";");
if (annotate) {
srcstr = srcpos_string_first(prop->srcpos, annotate);
if (srcstr) {
fprintf(f, " /* %s */", srcstr);
free(srcstr);
}
}
fprintf(f, "\n");
return;
}
fprintf(f, " =");
if (!next_type_marker(m)) {
/* data type information missing, need to guess */
dummy_marker.type = guess_value_type(prop);
dummy_marker.next = prop->val.markers;
dummy_marker.offset = 0;
dummy_marker.ref = NULL;
m = &dummy_marker;
}
for_each_marker(m) {
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
size_t data_len = type_marker_length(m) ? : len - m->offset;
const char *p = &prop->val.val[m->offset];
if (has_data_type_information(m)) {
emit_type = m->type;
fprintf(f, " %s", delim_start[emit_type]);
} else if (m->type == LABEL)
fprintf(f, " %s:", m->ref);
else if (m->offset)
fputc(' ', f);
if (emit_type == TYPE_NONE) {
assert(chunk_len == 0);
continue;
}
switch(emit_type) {
case TYPE_UINT16:
write_propval_int(f, p, chunk_len, 2);
break;
case TYPE_UINT32:
write_propval_int(f, p, chunk_len, 4);
break;
case TYPE_UINT64:
write_propval_int(f, p, chunk_len, 8);
break;
case TYPE_STRING:
write_propval_string(f, p, chunk_len);
break;
default:
write_propval_int(f, p, chunk_len, 1);
}
if (chunk_len == data_len) {
size_t pos = m->offset + chunk_len;
fprintf(f, pos == len ? "%s" : "%s,",
delim_end[emit_type] ? : "");
emit_type = TYPE_NONE;
}
}
fprintf(f, ";");
if (annotate) {
srcstr = srcpos_string_first(prop->srcpos, annotate);
if (srcstr) {
fprintf(f, " /* %s */", srcstr);
free(srcstr);
}
}
fprintf(f, "\n");
}
static void write_tree_source_node(FILE *f, struct node *tree, int level)
@ -238,14 +283,24 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
struct property *prop;
struct node *child;
struct label *l;
char *srcstr;
write_prefix(f, level);
for_each_label(tree->labels, l)
fprintf(f, "%s: ", l->label);
if (tree->name && (*tree->name))
fprintf(f, "%s {\n", tree->name);
fprintf(f, "%s {", tree->name);
else
fprintf(f, "/ {\n");
fprintf(f, "/ {");
if (annotate) {
srcstr = srcpos_string_first(tree->srcpos, annotate);
if (srcstr) {
fprintf(f, " /* %s */", srcstr);
free(srcstr);
}
}
fprintf(f, "\n");
for_each_property(tree, prop) {
write_prefix(f, level+1);
@ -259,9 +314,16 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
write_tree_source_node(f, child, level+1);
}
write_prefix(f, level);
fprintf(f, "};\n");
fprintf(f, "};");
if (annotate) {
srcstr = srcpos_string_last(tree->srcpos, annotate);
if (srcstr) {
fprintf(f, " /* %s */", srcstr);
free(srcstr);
}
}
fprintf(f, "\n");
}
void dt_to_source(FILE *f, struct dt_info *dti)
{
@ -281,4 +343,3 @@ void dt_to_source(FILE *f, struct dt_info *dti)
write_tree_source_node(f, dti->dt, 0);
}

View File

@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc
DTC_LINUX_PATH=`pwd`/scripts/dtc
DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \
srcpos.h treesource.c util.c util.h version_gen.h yamltree.c Makefile.dtc \
dtc-lexer.l dtc-parser.y"
LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \
fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \

View File

@ -1,24 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* util_is_printable_string contributed by
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <ctype.h>
@ -27,6 +13,7 @@
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include <errno.h>
#include <fcntl.h>
@ -46,36 +33,54 @@ char *xstrdup(const char *s)
return d;
}
/* based in part from (3) vsnprintf */
int xasprintf(char **strp, const char *fmt, ...)
int xavsprintf_append(char **strp, const char *fmt, va_list ap)
{
int n, size = 128; /* start with 128 bytes */
int n, size = 0; /* start with 128 bytes */
char *p;
va_list ap;
va_list ap_copy;
/* initial pointer is NULL making the fist realloc to be malloc */
p = NULL;
while (1) {
p = xrealloc(p, size);
p = *strp;
if (p)
size = strlen(p);
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
va_copy(ap_copy, ap);
n = vsnprintf(NULL, 0, fmt, ap_copy) + 1;
va_end(ap_copy);
p = xrealloc(p, size + n);
n = vsnprintf(p + size, n, fmt, ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
break;
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n + 1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
}
*strp = p;
return strlen(p);
}
int xasprintf_append(char **strp, const char *fmt, ...)
{
int n;
va_list ap;
va_start(ap, fmt);
n = xavsprintf_append(strp, fmt, ap);
va_end(ap);
return n;
}
int xasprintf(char **strp, const char *fmt, ...)
{
int n;
va_list ap;
*strp = NULL;
va_start(ap, fmt);
n = xavsprintf_append(strp, fmt, ap);
va_end(ap);
return n;
}
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
@ -227,11 +232,11 @@ char get_escape_char(const char *s, int *i)
return val;
}
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
int utilfdt_read_err(const char *filename, char **buffp, size_t *len)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
off_t bufsize = 1024, offset = 0;
size_t bufsize = 1024, offset = 0;
int ret = 0;
*buffp = NULL;
@ -264,20 +269,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
free(buf);
else
*buffp = buf;
if (len)
*len = bufsize;
return ret;
}
int utilfdt_read_err(const char *filename, char **buffp)
{
off_t len;
return utilfdt_read_err_len(filename, buffp, &len);
}
char *utilfdt_read_len(const char *filename, off_t *len)
char *utilfdt_read(const char *filename, size_t *len)
{
char *buff;
int ret = utilfdt_read_err_len(filename, &buff, len);
int ret = utilfdt_read_err(filename, &buff, len);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
@ -288,12 +288,6 @@ char *utilfdt_read_len(const char *filename, off_t *len)
return buff;
}
char *utilfdt_read(const char *filename)
{
off_t len;
return utilfdt_read_len(filename, &len);
}
int utilfdt_write_err(const char *filename, const void *blob)
{
int fd = 1; /* assume stdout */
@ -400,7 +394,7 @@ void utilfdt_print_data(const char *data, int len)
printf(" = <");
for (i = 0, len /= 4; i < len; i++)
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
printf("0x%08" PRIx32 "%s", fdt32_to_cpu(cell[i]),
i < (len - 1) ? " " : "");
printf(">");
} else {

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef UTIL_H
#define UTIL_H
@ -8,25 +9,14 @@
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#ifdef __GNUC__
#ifdef __clang__
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
#else
#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j)))
#endif
#define NORETURN __attribute__((noreturn))
#else
#define PRINTF(i, j)
@ -72,6 +62,8 @@ static inline void *xrealloc(void *p, size_t len)
extern char *xstrdup(const char *s);
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...);
extern int xavsprintf_append(char **strp, const char *fmt, va_list ap);
extern char *join_path(const char *path, const char *name);
/**
@ -98,16 +90,10 @@ char get_escape_char(const char *s, int *i);
* stderr.
*
* @param filename The filename to read, or - for stdin
* @param len If non-NULL, the amount of data we managed to read
* @return Pointer to allocated buffer containing fdt, or NULL on error
*/
char *utilfdt_read(const char *filename);
/**
* Like utilfdt_read(), but also passes back the size of the file read.
*
* @param len If non-NULL, the amount of data we managed to read
*/
char *utilfdt_read_len(const char *filename, off_t *len);
char *utilfdt_read(const char *filename, size_t *len);
/**
* Read a device tree file into a buffer. Does not report errors, but only
@ -116,23 +102,17 @@ char *utilfdt_read_len(const char *filename, off_t *len);
*
* @param filename The filename to read, or - for stdin
* @param buffp Returns pointer to buffer containing fdt
* @param len If non-NULL, the amount of data we managed to read
* @return 0 if ok, else an errno value representing the error
*/
int utilfdt_read_err(const char *filename, char **buffp);
/**
* Like utilfdt_read_err(), but also passes back the size of the file read.
*
* @param len If non-NULL, the amount of data we managed to read
*/
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len);
int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
/**
* Write a device tree buffer to a file. This will report any errors on
* stderr.
*
* @param filename The filename to write, or - for stdout
* @param blob Poiner to buffer containing fdt
* @param blob Pointer to buffer containing fdt
* @return 0 if ok, -1 on error
*/
int utilfdt_write(const char *filename, const void *blob);
@ -143,7 +123,7 @@ int utilfdt_write(const char *filename, const void *blob);
* an error message for the user.
*
* @param filename The filename to write, or - for stdout
* @param blob Poiner to buffer containing fdt
* @param blob Pointer to buffer containing fdt
* @return 0 if ok, else an errno value representing the error
*/
int utilfdt_write_err(const char *filename, const void *blob);

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