Linux_SDK_V0.9.5

This commit is contained in:
thead_admin
2022-09-13 11:04:33 +08:00
commit 43db9e00d5
16487 changed files with 4068554 additions and 0 deletions

4
scripts/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
#
# Generated files
#
bin2c

334
scripts/Kbuild.include Normal file
View File

@@ -0,0 +1,334 @@
####
# kbuild: Generic definitions
# Convenient variables
comma := ,
quote := "
squote := '
empty :=
space := $(empty) $(empty)
pound := \#
###
# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
dot-target = $(dir $@).$(notdir $@)
###
# The temporary file to save gcc -MD generated dependencies must not
# contain a comma
depfile = $(subst $(comma),_,$(dot-target).d)
###
# filename of target with directory and extension stripped
basetarget = $(basename $(notdir $@))
###
# filename of first prerequisite with directory and extension stripped
baseprereq = $(basename $(notdir $<))
###
# Escape single quote for use in echo statements
escsq = $(subst $(squote),'\$(squote)',$1)
###
# Easy method for doing a status message
kecho := :
quiet_kecho := echo
silent_kecho := :
kecho := $($(quiet)kecho)
###
# filechk is used to check if the content of a generated file is updated.
# Sample usage:
# define filechk_sample
# echo $KERNELRELEASE
# endef
# version.h : Makefile
# $(call filechk,sample)
# The rule defined shall write to stdout the content of the new file.
# The existing file will be compared with the new one.
# - If no file exist it is created
# - If the content differ the new file is used
# - If they are equal no change, and no timestamp update
# - stdin is piped in from the first prerequisite ($<) so one has
# to specify a valid file as first prerequisite (often the kbuild file)
define filechk
$(Q)set -e; \
$(kecho) ' CHK $@'; \
mkdir -p $(dir $@); \
$(filechk_$(1)) < $< > $@.tmp; \
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
rm -f $@.tmp; \
else \
$(kecho) ' UPD $@'; \
mv -f $@.tmp $@; \
fi
endef
######
# gcc support functions
# See documentation in Documentation/kbuild/makefiles.txt
# cc-cross-prefix
# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
# Return first prefix where a prefix$(CC) is found in PATH.
# If no $(CC) found in PATH with listed prefixes return nothing
cc-cross-prefix = \
$(word 1, $(foreach c,$(1), \
$(shell set -e; \
if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \
echo $(c); \
fi)))
# output directory for tests below
TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
# Exit code chooses option. "$$TMP" is can be used as temporary file and
# is automatically cleaned up.
# modifed for U-Boot: prevent cc-option from leaving .*.su files
try-run = $(shell set -e; \
TMP="$(TMPOUT).$$$$.tmp"; \
TMPO="$(TMPOUT).$$$$.o"; \
TMPSU="$(TMPOUT).$$$$.su"; \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
fi; \
rm -f "$$TMP" "$$TMPO" "$$TMPSU")
# as-option
# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
as-option = $(call try-run,\
$(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2))
# as-instr
# Usage: cflags-y += $(call as-instr,instr,option1,option2)
as-instr = $(call try-run,\
printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
cc-option = $(call try-run,\
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
$(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
# cc-option-align
# Prefix align with either -falign or -malign
cc-option-align = $(subst -functions=0,,\
$(call cc-option,-falign-functions=0,-malign-functions=0))
# cc-disable-warning
# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
cc-disable-warning = $(call try-run,\
$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
# cc-name
# Expands to either gcc or clang
cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc)
# cc-version
cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
# cc-fullversion
cc-fullversion = $(shell $(CONFIG_SHELL) \
$(srctree)/scripts/gcc-version.sh -p $(CC))
# cc-ifversion
# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4))
# added for U-Boot
binutils-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/binutils-version.sh $(AS))
dtc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/dtc-version.sh $(DTC))
# cc-ldoption
# Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both)
cc-ldoption = $(call try-run,\
$(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
# ld-option
# Usage: LDFLAGS += $(call ld-option, -X)
ld-option = $(call try-run,\
$(CC) -x c /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
# ar-option
# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
# Important: no spaces around options
ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
# ld-version
# Note this is mainly for HJ Lu's 3 number binutil versions
ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh)
# ld-ifversion
# Usage: $(call ld-ifversion, -ge, 22252, y)
ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4))
######
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
# Usage:
# $(Q)$(MAKE) $(build)=dir
build := -f $(srctree)/scripts/Makefile.build obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj=
# Usage:
# $(Q)$(MAKE) $(modbuiltin)=dir
modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
# Usage:
# $(Q)$(MAKE) $(dtbinst)=dir
dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=
# Usage:
# $(Q)$(MAKE) $(clean)=dir
clean := -f $(srctree)/scripts/Makefile.clean obj
###
# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.headersinst obj=
# Usage:
# $(Q)$(MAKE) $(hdr-inst)=dir
hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
# Prefix -I with $(srctree) if it is not an absolute path.
# skip if -I has no parameter
addtree = $(if $(patsubst -I%,%,$(1)), \
$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1))
# Find all -I options and call addtree
flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
# echo command.
# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
echo-cmd = $(if $($(quiet)cmd_$(1)),\
echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
# printing commands
cmd = @$(echo-cmd) $(cmd_$(1))
# Add $(obj)/ for paths that are not absolute
objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
###
# if_changed - execute command if any prerequisite is newer than
# target, or command line has changed
# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies
# including used config symbols
# if_changed_rule - as if_changed but execute rule instead
# See Documentation/kbuild/makefiles.txt for more info
ifneq ($(KBUILD_NOCMDDEP),1)
# Check if both arguments has same arguments. Result is empty string if equal.
# User may override this check using make KBUILD_NOCMDDEP=1
arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
$(filter-out $(cmd_$@), $(cmd_$(1))) )
else
arg-check = $(if $(strip $(cmd_$@)),,1)
endif
# Replace >$< with >$$< to preserve $ when reloading the .cmd file
# (needed for make)
# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file
# (needed for make)
# Replace >'< with >'\''< to be able to enclose the whole string in '...'
# (needed for the shell)
make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1)))))
# Find any prerequisites that is newer than target or that does not exist.
# PHONY targets skipped in both cases.
any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
# Execute command if command has changed or prerequisite(s) are updated.
#
if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
# Execute the command and also postprocess generated .d dependencies file.
if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(echo-cmd) $(cmd_$(1)); \
scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd)
# Usage: $(call if_changed_rule,foo)
# Will check if $(cmd_foo) or any of the prerequisites changed,
# and if so will execute $(rule_foo).
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(rule_$(1)))
###
# why - tell why a a target got build
# enabled by make V=2
# Output (listed in the order they are checked):
# (1) - due to target is PHONY
# (2) - due to target missing
# (3) - due to: file1.h file2.h
# (4) - due to command line change
# (5) - due to missing .cmd file
# (6) - due to target not in $(targets)
# (1) PHONY targets are always build
# (2) No target, so we better build it
# (3) Prerequisite is newer than target
# (4) The command line stored in the file named dir/.target.cmd
# differed from actual command line. This happens when compiler
# options changes
# (5) No dir/.target.cmd file (used to store command line)
# (6) No dir/.target.cmd file and target not listed in $(targets)
# This is a good hint that there is a bug in the kbuild file
ifeq ($(KBUILD_VERBOSE),2)
why = \
$(if $(filter $@, $(PHONY)),- due to target is PHONY, \
$(if $(wildcard $@), \
$(if $(strip $(any-prereq)),- due to: $(any-prereq), \
$(if $(arg-check), \
$(if $(cmd_$@),- due to command line change, \
$(if $(filter $@, $(targets)), \
- due to missing .cmd file, \
- due to $(notdir $@) not in $$(targets) \
) \
) \
) \
), \
- due to target missing \
) \
)
echo-why = $(call escsq, $(strip $(why)))
endif
# delete partially updated (i.e. corrupted) files on error
.DELETE_ON_ERROR:
# do not delete intermediate files automatically
.SECONDARY:
ifdef CONFIG_SPL_BUILD
SPL_ := SPL_
ifeq ($(CONFIG_TPL_BUILD),y)
SPL_TPL_ := TPL_
else
SPL_TPL_ := SPL_
endif
else
SPL_ :=
SPL_TPL_ :=
endif

18
scripts/Lindent Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
RES=`indent --version`
V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1`
V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2`
V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3`
if [ $V1 -gt 2 ]; then
PARAM="$PARAM -il0"
elif [ $V1 -eq 2 ]; then
if [ $V2 -gt 2 ]; then
PARAM="$PARAM -il0";
elif [ $V2 -eq 2 ]; then
if [ $V3 -ge 10 ]; then
PARAM="$PARAM -il0"
fi
fi
fi
indent $PARAM "$@"

13
scripts/Makefile Normal file
View File

@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
###
# scripts contains sources for various helper programs used throughout
# the kernel for the build process.
# ---------------------------------------------------------------------------
hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c
always := $(hostprogs-y)
# Let clean descend into subdirs
subdir- += basic kconfig
subdir-$(CONFIG_DTC) += dtc

158
scripts/Makefile.autoconf Normal file
View File

@@ -0,0 +1,158 @@
# SPDX-License-Identifier: GPL-2.0
# This helper makefile is used for creating
# - symbolic links (arch/$ARCH/include/asm/arch
# - include/autoconf.mk, {spl,tpl}/include/autoconf.mk
# - include/config.h
#
# When our migration to Kconfig is done
# (= When we move all CONFIGs from header files to Kconfig)
# this makefile can be deleted.
__all: include/autoconf.mk include/autoconf.mk.dep
ifeq ($(shell grep -q '^CONFIG_SPL=y' include/config/auto.conf 2>/dev/null && echo y),y)
__all: spl/include/autoconf.mk
endif
ifeq ($(shell grep -q '^CONFIG_TPL=y' include/config/auto.conf 2>/dev/null && echo y),y)
__all: tpl/include/autoconf.mk
endif
ifeq ($(shell grep -q '^CONFIG_PPL=y' include/config/auto.conf 2>/dev/null && echo y),y)
__all: ppl/include/autoconf.mk
endif
include include/config/auto.conf
include scripts/Kbuild.include
# Need to define CC and CPP again here in case the top Makefile did not
# include config.mk. Some architectures expect CROSS_COMPILE to be defined
# in arch/$(ARCH)/config.mk
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
include config.mk
UBOOTINCLUDE := \
-Iinclude \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
-I$(srctree)/arch/$(ARCH)/include \
-include $(srctree)/include/linux/kconfig.h
c_flags := $(KBUILD_CFLAGS) $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) \
$(UBOOTINCLUDE) $(NOSTDINC_FLAGS)
quiet_cmd_autoconf_dep = GEN $@
cmd_autoconf_dep = $(CC) -x c -DDO_DEPS_ONLY -M -MP $(c_flags) \
-MQ include/config/auto.conf $(srctree)/include/common.h > $@ || { \
rm $@; false; \
}
include/autoconf.mk.dep: include/config.h FORCE
$(call cmd,autoconf_dep)
# We are migrating from board headers to Kconfig little by little.
# In the interim, we use both of
# - include/config/auto.conf (generated by Kconfig)
# - include/autoconf.mk (used in the U-Boot conventional configuration)
# The following rule creates autoconf.mk
# include/config/auto.conf is grepped in order to avoid duplication of the
# same CONFIG macros
quiet_cmd_autoconf = GEN $@
cmd_autoconf = \
sed -n -f $(srctree)/tools/scripts/define2mk.sed $< | \
while read line; do \
if [ -n "${KCONFIG_IGNORE_DUPLICATES}" ] || \
! grep -q "$${line%=*}=" include/config/auto.conf; then \
echo "$$line"; \
fi \
done > $@
quiet_cmd_u_boot_cfg = CFG $@
cmd_u_boot_cfg = \
$(CPP) $(c_flags) $2 -DDO_DEPS_ONLY -dM $(srctree)/include/common.h > $@.tmp && { \
grep 'define CONFIG_' $@.tmp > $@; \
rm $@.tmp; \
} || { \
rm $@.tmp; false; \
}
u-boot.cfg: include/config.h FORCE
$(call cmd,u_boot_cfg)
spl/u-boot.cfg: include/config.h FORCE
$(Q)mkdir -p $(dir $@)
$(call cmd,u_boot_cfg,-DCONFIG_SPL_BUILD)
tpl/u-boot.cfg: include/config.h FORCE
$(Q)mkdir -p $(dir $@)
$(call cmd,u_boot_cfg,-DCONFIG_SPL_BUILD -DCONFIG_TPL_BUILD)
ppl/u-boot.cfg: include/config.h FORCE
$(Q)mkdir -p $(dir $@)
$(call cmd,u_boot_cfg,-DCONFIG_PPL_BUILD)
include/autoconf.mk: u-boot.cfg
$(call cmd,autoconf)
spl/include/autoconf.mk: spl/u-boot.cfg
$(Q)mkdir -p $(dir $@)
$(call cmd,autoconf)
tpl/include/autoconf.mk: tpl/u-boot.cfg
$(Q)mkdir -p $(dir $@)
$(call cmd,autoconf)
ppl/include/autoconf.mk: ppl/u-boot.cfg
$(Q)mkdir -p $(dir $@)
$(call cmd,autoconf)
# include/config.h
# Prior to Kconfig, it was generated by mkconfig. Now it is created here.
define filechk_config_h
(echo "/* Automatically generated - do not edit */"; \
for i in $$(echo $(CONFIG_SYS_EXTRA_OPTIONS) | sed 's/,/ /g'); do \
echo \#define CONFIG_$$i \
| sed '/=/ {s/=/ /;q; } ; { s/$$/ 1/; }'; \
done; \
echo \#define CONFIG_BOARDDIR board/$(if $(VENDOR),$(VENDOR)/)$(BOARD);\
echo \#include \<config_defaults.h\>; \
echo \#include \<config_uncmd_spl.h\>; \
echo \#include \<configs/$(CONFIG_SYS_CONFIG_NAME).h\>; \
echo \#include \<asm/config.h\>; \
echo \#include \<linux/kconfig.h\>; \
echo \#include \<config_fallbacks.h\>;)
endef
include/config.h: scripts/Makefile.autoconf create_symlink FORCE
$(call filechk,config_h)
# symbolic links
# If arch/$(ARCH)/mach-$(SOC)/include/mach exists,
# make a symbolic link to that directory.
# Otherwise, create a symbolic link to arch/$(ARCH)/include/asm/arch-$(SOC).
PHONY += create_symlink
create_symlink:
ifdef CONFIG_CREATE_ARCH_SYMLINK
ifneq ($(KBUILD_SRC),)
$(Q)mkdir -p include/asm
$(Q)if [ -d $(KBUILD_SRC)/arch/$(ARCH)/mach-$(SOC)/include/mach ]; then \
dest=arch/$(ARCH)/mach-$(SOC)/include/mach; \
else \
dest=arch/$(ARCH)/include/asm/arch-$(if $(SOC),$(SOC),$(CPU)); \
fi; \
ln -fsn $(KBUILD_SRC)/$$dest include/asm/arch
else
$(Q)if [ -d arch/$(ARCH)/mach-$(SOC)/include/mach ]; then \
dest=../../mach-$(SOC)/include/mach; \
else \
dest=arch-$(if $(SOC),$(SOC),$(CPU)); \
fi; \
ln -fsn $$dest arch/$(ARCH)/include/asm/arch
endif
endif
PHONY += FORCE
FORCE:
.PHONY: $(PHONY)

460
scripts/Makefile.build Normal file
View File

@@ -0,0 +1,460 @@
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Building
# ==========================================================================
# Modified for U-Boot
prefix := tpl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := spl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := ppl
src := $(patsubst $(prefix)/%,%,$(obj))
ifeq ($(obj),$(src))
prefix := .
endif
endif
endif
PHONY := __build
__build:
# Init all relevant variables used in kbuild files so
# 1) they have correct type
# 2) they do not inherit any value from the environment
obj-y :=
obj-m :=
lib-y :=
lib-m :=
always :=
targets :=
subdir-y :=
subdir-m :=
EXTRA_AFLAGS :=
EXTRA_CFLAGS :=
EXTRA_CPPFLAGS :=
EXTRA_LDFLAGS :=
asflags-y :=
ccflags-y :=
cppflags-y :=
ldflags-y :=
subdir-asflags-y :=
subdir-ccflags-y :=
# Read auto.conf if it exists, otherwise ignore
# Modified for U-Boot
-include include/config/auto.conf
-include $(prefix)/include/autoconf.mk
include scripts/Makefile.uncmd_spl
include scripts/Kbuild.include
# For backward compatibility check that these variables do not change
save-cflags := $(CFLAGS)
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
# Added for U-Boot
asflags-y += $(PLATFORM_CPPFLAGS)
ccflags-y += $(PLATFORM_CPPFLAGS)
cppflags-y += $(PLATFORM_CPPFLAGS)
# If the save-* variables changed error out
ifeq ($(KBUILD_NOPEDANTIC),)
ifneq ("$(save-cflags)","$(CFLAGS)")
$(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y)
endif
endif
include scripts/Makefile.lib
ifdef host-progs
ifneq ($(hostprogs-y),$(host-progs))
$(warning kbuild: $(obj)/Makefile - Usage of host-progs is deprecated. Please replace with hostprogs-y!)
hostprogs-y += $(host-progs)
endif
endif
# Do not include host rules unless needed
ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host
endif
# Uncommented for U-Boot
# We need to create output dicrectory for SPL and TPL even for in-tree build
#ifneq ($(KBUILD_SRC),)
# Create output directory if not already present
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
# Create directories for object files if directory does not exist
# Needed when obj-y := dir/file.o syntax is used
_dummy := $(foreach d,$(obj-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))
#endif
ifndef obj
$(warning kbuild: Makefile.build is included improperly)
endif
# ===========================================================================
ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),)
lib-target := $(obj)/lib.a
endif
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
modorder-target := $(obj)/modules.order
# We keep a list of all modules in $(MODVERDIR)
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
$(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
$(subdir-ym) $(always)
@:
# Linus' kernel sanity checking tool
ifneq ($(KBUILD_CHECKSRC),0)
ifeq ($(KBUILD_CHECKSRC),2)
quiet_cmd_force_checksrc = CHECK $<
cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
else
quiet_cmd_checksrc = CHECK $<
cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
endif
endif
# Do section mismatch analysis for each module/built-in.o
ifdef CONFIG_DEBUG_SECTION_MISMATCH
cmd_secanalysis = ; scripts/mod/modpost $@
endif
# Compile C sources (.c)
# ---------------------------------------------------------------------------
# Default is built-in, unless we know otherwise
modkern_cflags = \
$(if $(part-of-module), \
$(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \
$(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL))
quiet_modtag := $(empty) $(empty)
$(real-objs-m) : part-of-module := y
$(real-objs-m:.o=.i) : part-of-module := y
$(real-objs-m:.o=.s) : part-of-module := y
$(real-objs-m:.o=.lst): part-of-module := y
$(real-objs-m) : quiet_modtag := [M]
$(real-objs-m:.o=.i) : quiet_modtag := [M]
$(real-objs-m:.o=.s) : quiet_modtag := [M]
$(real-objs-m:.o=.lst): quiet_modtag := [M]
$(obj-m) : quiet_modtag := [M]
# Default for not multi-part modules
modname = $(basetarget)
$(multi-objs-m) : modname = $(modname-multi)
$(multi-objs-m:.o=.i) : modname = $(modname-multi)
$(multi-objs-m:.o=.s) : modname = $(modname-multi)
$(multi-objs-m:.o=.lst) : modname = $(modname-multi)
$(multi-objs-y) : modname = $(modname-multi)
$(multi-objs-y:.o=.i) : modname = $(modname-multi)
$(multi-objs-y:.o=.s) : modname = $(modname-multi)
$(multi-objs-y:.o=.lst) : modname = $(modname-multi)
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
cmd_cc_s_c = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $<
$(obj)/%.s: $(src)/%.c FORCE
$(call if_changed_dep,cc_s_c)
quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@
cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $<
$(obj)/%.i: $(src)/%.c FORCE
$(call if_changed_dep,cc_i_c)
cmd_gensymtypes = \
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
$(GENKSYMS) $(if $(1), -T $(2)) \
$(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \
$(if $(KBUILD_PRESERVE),-p) \
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
cmd_cc_symtypes_c = \
set -e; \
$(call cmd_gensymtypes,true,$@) >/dev/null; \
test -s $@ || rm -f $@
$(obj)/%.symtypes : $(src)/%.c FORCE
$(call cmd,cc_symtypes_c)
# C (.c) files
# The C file is compiled and updated dependency information is generated.
# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
ifndef CONFIG_MODVERSIONS
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
else
# When module versioning is enabled the following steps are executed:
# o compile a .tmp_<file>.o from <file>.c
# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
# not export symbols, we just rename .tmp_<file>.o to <file>.o and
# are done.
# o otherwise, we calculate symbol versions using the good old
# genksyms on the preprocessed source and postprocess them in a way
# that they are usable as a linker script
# o generate <file>.o from .tmp_<file>.o using the linker to
# replace the unresolved symbols __crc_exported_symbol with
# the actual value of the checksum generated by genksyms
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
cmd_modversions = \
if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
$(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
> $(@D)/.tmp_$(@F:.o=.ver); \
\
$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
-T $(@D)/.tmp_$(@F:.o=.ver); \
rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
else \
mv -f $(@D)/.tmp_$(@F) $@; \
fi;
endif
ifdef CONFIG_FTRACE_MCOUNT_RECORD
ifdef BUILD_C_RECORDMCOUNT
ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
RECORDMCOUNT_FLAGS = -w
endif
# Due to recursion, we must skip empty.o.
# The empty.o file is created in the make process in order to determine
# the target endianness and word size. It is made before all other C
# files, including recordmcount.
sub_cmd_record_mcount = \
if [ $(@) != "scripts/mod/empty.o" ]; then \
$(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
fi;
recordmcount_source := $(srctree)/scripts/recordmcount.c \
$(srctree)/scripts/recordmcount.h
else
sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
"$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
"$(if $(CONFIG_64BIT),64,32)" \
"$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
"$(LD)" "$(NM)" "$(RM)" "$(MV)" \
"$(if $(part-of-module),1,0)" "$(@)";
recordmcount_source := $(srctree)/scripts/recordmcount.pl
endif
cmd_record_mcount = \
if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" = \
"$(CC_FLAGS_FTRACE)" ]; then \
$(sub_cmd_record_mcount) \
fi;
endif
define rule_cc_o_c
$(call echo-cmd,checksrc) $(cmd_checksrc) \
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
$(cmd_modversions) \
$(call echo-cmd,record_mcount) \
$(cmd_record_mcount) \
scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
$(dot-target).tmp; \
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd
endef
# Built-in and composite module parts
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
# Single-part modules are special since we need to mark them in $(MODVERDIR)
$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
quiet_cmd_cc_lst_c = MKLST $@
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
$(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
System.map $(OBJDUMP) > $@
$(obj)/%.lst: $(src)/%.c FORCE
$(call if_changed_dep,cc_lst_c)
# Compile assembler sources (.S)
# ---------------------------------------------------------------------------
modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)
$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
$(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE)
quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
cmd_as_s_S = $(CPP) $(a_flags) -o $@ $<
$(obj)/%.s: $(src)/%.S FORCE
$(call if_changed_dep,as_s_S)
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
$(obj)/%.o: $(src)/%.S FORCE
$(call if_changed_dep,as_o_S)
targets += $(real-objs-y) $(real-objs-m) $(lib-y)
targets += $(extra-y) $(MAKECMDGOALS) $(always)
# Linker scripts preprocessor (.lds.S -> .lds)
# ---------------------------------------------------------------------------
quiet_cmd_cpp_lds_S = LDS $@
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
$(obj)/%.lds: $(src)/%.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
# ASN.1 grammar
# ---------------------------------------------------------------------------
quiet_cmd_asn1_compiler = ASN.1 $@
cmd_asn1_compiler = $(objtree)/tools/asn1_compiler $< \
$(subst .h,.c,$@) $(subst .c,.h,$@)
$(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/tools/asn1_compiler
$(call cmd,asn1_compiler)
# Build the compiled-in targets
# ---------------------------------------------------------------------------
# To build objects in subdirs, we need to descend into the directories
$(sort $(subdir-obj-y)): $(subdir-ym) ;
#
# Rule to compile a set of .o files into one .o file
#
ifdef builtin-target
quiet_cmd_link_o_target = LD $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cmd_secanalysis),\
rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)
targets += $(builtin-target)
endif # builtin-target
#
# Rule to create modules.order file
#
# Create commands to either record .ko file or cat modules.order from
# a subdirectory
modorder-cmds = \
$(foreach m, $(modorder), \
$(if $(filter %/modules.order, $m), \
cat $m;, echo kernel/$m;))
$(modorder-target): $(subdir-ym) FORCE
$(Q)(cat /dev/null; $(modorder-cmds)) > $@
#
# Rule to compile a set of .o files into one .a file
#
ifdef lib-target
quiet_cmd_link_l_target = AR $@
cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
$(lib-target): $(lib-y) FORCE
$(call if_changed,link_l_target)
targets += $(lib-target)
endif
#
# Rule to link composite objects
#
# Composite objects are specified in kbuild makefile as follows:
# <composite-object>-objs := <list of .o files>
# or
# <composite-object>-y := <list of .o files>
link_multi_deps = \
$(filter $(addprefix $(obj)/, \
$($(subst $(obj)/,,$(@:.o=-objs))) \
$($(subst $(obj)/,,$(@:.o=-y)))), $^)
quiet_cmd_link_multi-y = LD $@
cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
quiet_cmd_link_multi-m = LD [M] $@
cmd_link_multi-m = $(cmd_link_multi-y)
$(multi-used-y): FORCE
$(call if_changed,link_multi-y)
$(call multi_depend, $(multi-used-y), .o, -objs -y)
$(multi-used-m): FORCE
$(call if_changed,link_multi-m)
@{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
$(call multi_depend, $(multi-used-m), .o, -objs -y)
targets += $(multi-used-y) $(multi-used-m)
# Add intermediate targets:
# When building objects with specific suffix patterns, add intermediate
# targets that the final targets are derived from.
intermediate_targets = $(foreach sfx, $(2), \
$(patsubst %$(strip $(1)),%$(sfx), \
$(filter %$(strip $(1)), $(targets))))
# %.lex.o <- %.lex.c <- %.l
# %.tab.o <- %.tab.[ch] <- %.y
targets += $(call intermediate_targets, .lex.o, .lex.c) \
$(call intermediate_targets, .tab.o, .tab.c .tab.h)
# Descending
# ---------------------------------------------------------------------------
PHONY += $(subdir-ym)
$(subdir-ym):
$(Q)$(MAKE) $(build)=$@
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
PHONY += FORCE
FORCE:
# Read all saved command lines and dependencies for the $(targets) we
# may be building above, using $(if_changed{,_dep}). As an
# optimization, we don't need to read them if the target does not
# exist, we will rebuild anyway in that case.
targets := $(wildcard $(sort $(targets)))
cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
ifneq ($(cmd_files),)
include $(cmd_files)
endif
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable se we can use it in if_changed and friends.
.PHONY: $(PHONY)

97
scripts/Makefile.clean Normal file
View File

@@ -0,0 +1,97 @@
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Cleaning up
# ==========================================================================
src := $(obj)
PHONY := __clean
__clean:
include scripts/Kbuild.include
# The filename Kbuild has precedence over Makefile
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
# Figure out what we need to build from the various variables
# ==========================================================================
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
subdir-m += $(__subdir-m)
__subdir- := $(patsubst %/,%,$(filter %/, $(obj-)))
subdir- += $(__subdir-)
# Subdirectories we need to descend into
subdir-ym := $(sort $(subdir-y) $(subdir-m))
subdir-ymn := $(sort $(subdir-ym) $(subdir-))
# Add subdir path
subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn))
# Temporal work-around for U-Boot
subdir-ymn := $(foreach f, $(subdir-ymn), \
$(if $(wildcard $(srctree)/$f/Makefile),$f))
# build a list of files to remove, usually relative to the current
# directory
__clean-files := $(extra-y) $(extra-m) $(extra-) \
$(always) $(targets) $(clean-files) \
$(host-progs) \
$(hostprogs-y) $(hostprogs-m) $(hostprogs-)
__clean-files := $(filter-out $(no-clean-files), $(__clean-files))
# clean-files is given relative to the current directory, unless it
# starts with $(objtree)/ (which means "./", so do not add "./" unless
# you want to delete a file from the toplevel object directory).
__clean-files := $(wildcard \
$(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \
$(filter $(objtree)/%, $(__clean-files)))
# same as clean-files
__clean-dirs := $(wildcard \
$(addprefix $(obj)/, $(filter-out $(objtree)/%, $(clean-dirs))) \
$(filter $(objtree)/%, $(clean-dirs)))
# ==========================================================================
quiet_cmd_clean = CLEAN $(obj)
cmd_clean = rm -f $(__clean-files)
quiet_cmd_cleandir = CLEAN $(__clean-dirs)
cmd_cleandir = rm -rf $(__clean-dirs)
__clean: $(subdir-ymn)
ifneq ($(strip $(__clean-files)),)
+$(call cmd,clean)
endif
ifneq ($(strip $(__clean-dirs)),)
+$(call cmd,cleandir)
endif
@:
# ===========================================================================
# Generic stuff
# ===========================================================================
# Descending
# ---------------------------------------------------------------------------
PHONY += $(subdir-ymn)
$(subdir-ymn):
$(Q)$(MAKE) $(clean)=$@
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable se we can use it in if_changed and friends.
.PHONY: $(PHONY)

View File

@@ -0,0 +1,80 @@
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
#
# make W=... settings
#
# W=1 - warnings that may be relevant and does not occur too often
# W=2 - warnings that occur quite often but may still be relevant
# W=3 - the more obscure warnings, can most likely be ignored
#
# $(call cc-option, -W...) handles gcc -W.. options which
# are not supported by all versions of the compiler
# ==========================================================================
ifeq ("$(origin W)", "command line")
export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
endif
ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
warning- := $(empty)
warning-1 := -Wextra -Wunused -Wno-unused-parameter
warning-1 += -Wmissing-declarations
warning-1 += -Wmissing-format-attribute
warning-1 += $(call cc-option, -Wmissing-prototypes)
warning-1 += -Wold-style-definition
warning-1 += $(call cc-option, -Wmissing-include-dirs)
warning-1 += $(call cc-option, -Wunused-but-set-variable)
warning-1 += $(call cc-disable-warning, missing-field-initializers)
warning-2 := -Waggregate-return
warning-2 += -Wcast-align
warning-2 += -Wdisabled-optimization
warning-2 += -Wnested-externs
warning-2 += -Wshadow
warning-2 += $(call cc-option, -Wlogical-op)
warning-2 += $(call cc-option, -Wmissing-field-initializers)
warning-3 := -Wbad-function-cast
warning-3 += -Wcast-qual
warning-3 += -Wconversion
warning-3 += -Wpacked
warning-3 += -Wpadded
warning-3 += -Wpointer-arith
warning-3 += -Wredundant-decls
warning-3 += -Wswitch-default
warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
warning-3 += $(call cc-option, -Wvla)
warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
ifeq ("$(strip $(warning))","")
$(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
endif
KBUILD_CFLAGS += $(warning)
dtc-warning-2 += -Wnode_name_chars_strict
dtc-warning-2 += -Wproperty_name_chars_strict
dtc-warning := $(dtc-warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
dtc-warning += $(dtc-warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
dtc-warning += $(dtc-warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
DTC_FLAGS += $(dtc-warning)
else
# Disable noisy checks by default
DTC_FLAGS += -Wno-unit_address_vs_reg
DTC_FLAGS += -Wno-simple_bus_reg
DTC_FLAGS += -Wno-unit_address_format
DTC_FLAGS += -Wno-pci_bridge
DTC_FLAGS += -Wno-pci_device_bus_num
DTC_FLAGS += -Wno-pci_device_reg
DTC_FLAGS += -Wno-avoid_unnecessary_addr_size
DTC_FLAGS += -Wno-alias_paths
endif

134
scripts/Makefile.host Normal file
View File

@@ -0,0 +1,134 @@
# SPDX-License-Identifier: GPL-2.0
# ==========================================================================
# Building binaries on the host system
# Binaries are used during the compilation of the kernel, for example
# to preprocess a data file.
#
# Both C and C++ are supported, but preferred language is C for such utilities.
#
# Sample syntax (see Documentation/kbuild/makefiles.txt for reference)
# hostprogs-y := bin2hex
# Will compile bin2hex.c and create an executable named bin2hex
#
# hostprogs-y := lxdialog
# lxdialog-objs := checklist.o lxdialog.o
# Will compile lxdialog.c and checklist.c, and then link the executable
# lxdialog, based on checklist.o and lxdialog.o
#
# hostprogs-y := qconf
# qconf-cxxobjs := qconf.o
# qconf-objs := menu.o
# Will compile qconf as a C++ program, and menu as a C program.
# They are linked as C++ code to the executable qconf
__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
# C code
# Executables compiled from a single .c file
host-csingle := $(foreach m,$(__hostprogs), \
$(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-sharedobjs),,$(m)))
# C executables linked based on several .o files
host-cmulti := $(foreach m,$(__hostprogs),\
$(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
# Shared object libraries
host-shared := $(foreach m,$(__hostprogs),\
$(if $($(m)-sharedobjs),$(m))))
# Object (.o) files compiled from .c files
host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
# C++ code
# C++ executables compiled from at least one .cc file
# and zero or more .c files
host-cxxmulti := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
# C++ Object (.o) files compiled from .cc files
host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
# output directory for programs/.o files
# hostprogs-y := tools/build may have been specified.
# Retrieve also directory of .o files from prog-objs or prog-cxxobjs notation
host-objdirs := $(dir $(__hostprogs) $(host-cobjs) $(host-cxxobjs))
host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
__hostprogs := $(addprefix $(obj)/,$(__hostprogs))
host-csingle := $(addprefix $(obj)/,$(host-csingle))
host-cmulti := $(addprefix $(obj)/,$(host-cmulti))
host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti))
host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs))
host-shared := $(addprefix $(obj)/,$(host-shared))
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
obj-dirs += $(host-objdirs)
#####
# Handle options to gcc. Support building with separate output directory
_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
$(HOSTCFLAGS_$(basetarget).o)
_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
$(HOSTCXXFLAGS_$(basetarget).o)
ifeq ($(KBUILD_SRC),)
__hostc_flags = $(_hostc_flags)
__hostcxx_flags = $(_hostcxx_flags)
else
__hostc_flags = -I$(obj) $(call flags,_hostc_flags)
__hostcxx_flags = -I$(obj) $(call flags,_hostcxx_flags)
endif
hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags)
hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags)
#####
# Compile programs on the host
# Create executable from a single .c file
# host-csingle -> Executable
quiet_cmd_host-csingle = HOSTCC $@
cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
$(host-csingle): $(obj)/%: $(src)/%.c FORCE
$(call if_changed_dep,host-csingle)
# Link an executable based on list of .o files, all plain c
# host-cmulti -> executable
quiet_cmd_host-cmulti = HOSTLD $@
cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
$(addprefix $(obj)/,$($(@F)-objs)) \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
$(host-cmulti): FORCE
$(call if_changed,host-cmulti)
$(call multi_depend, $(host-cmulti), , -objs)
# Create .o file from a single .c file
# host-cobjs -> .o
quiet_cmd_host-cobjs = HOSTCC $@
cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $<
$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
$(call if_changed_dep,host-cobjs)
# Link an executable based on list of .o files, a mixture of .c and .cc
# host-cxxmulti -> executable
quiet_cmd_host-cxxmulti = HOSTLD $@
cmd_host-cxxmulti = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
$(foreach o,objs cxxobjs,\
$(addprefix $(obj)/,$($(@F)-$(o)))) \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
$(host-cxxmulti): FORCE
$(call if_changed,host-cxxmulti)
$(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs)
# Create .o file from a single .cc (C++) file
quiet_cmd_host-cxxobjs = HOSTCXX $@
cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
$(call if_changed_dep,host-cxxobjs)
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
$(host-cxxmulti) $(host-cxxobjs) $(host-shared)

540
scripts/Makefile.lib Normal file
View File

@@ -0,0 +1,540 @@
# SPDX-License-Identifier: GPL-2.0
# Backward compatibility
asflags-y += $(EXTRA_AFLAGS)
ccflags-y += $(EXTRA_CFLAGS)
cppflags-y += $(EXTRA_CPPFLAGS)
ldflags-y += $(EXTRA_LDFLAGS)
#
# flags that take effect in sub directories
export KBUILD_SUBDIR_ASFLAGS := $(KBUILD_SUBDIR_ASFLAGS) $(subdir-asflags-y)
export KBUILD_SUBDIR_CCFLAGS := $(KBUILD_SUBDIR_CCFLAGS) $(subdir-ccflags-y)
# Figure out what we need to build from the various variables
# ===========================================================================
# When an object is listed to be built compiled-in and modular,
# only build the compiled-in version
obj-m := $(filter-out $(obj-y),$(obj-m))
# Libraries are always collected in one lib file.
# Filter out objects already built-in
lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
# Handle objects in subdirs
# ---------------------------------------------------------------------------
# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o
# and add the directory to the list of dirs to descend into: $(subdir-y)
# o if we encounter foo/ in $(obj-m), remove it from $(obj-m)
# and add the directory to the list of dirs to descend into: $(subdir-m)
# Determine modorder.
# Unfortunately, we don't have information about ordering between -y
# and -m subdirs. Just put -y's first.
modorder := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko))
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m)))
subdir-m += $(__subdir-m)
obj-y := $(patsubst %/, %/built-in.o, $(obj-y))
obj-m := $(filter-out %/, $(obj-m))
# Subdirectories we need to descend into
subdir-ym := $(sort $(subdir-y) $(subdir-m))
# if $(foo-objs) exists, foo.o is a composite object
multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
multi-used := $(multi-used-y) $(multi-used-m)
single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
# Build list of the parts of our composite objects, our composite
# objects depend on those (obviously)
multi-objs-y := $(foreach m, $(multi-used-y), $($(m:.o=-objs)) $($(m:.o=-y)))
multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
multi-objs := $(multi-objs-y) $(multi-objs-m)
# $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to
# tell kbuild to descend
subdir-obj-y := $(filter %/built-in.o, $(obj-y))
# $(obj-dirs) is a list of directories that contain object files
obj-dirs := $(dir $(multi-objs) $(obj-y))
# Replace multi-part objects by their individual parts, look at local dir only
real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y)
real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
# Add subdir path
extra-y := $(addprefix $(obj)/,$(extra-y))
always := $(addprefix $(obj)/,$(always))
targets := $(addprefix $(obj)/,$(targets))
modorder := $(addprefix $(obj)/,$(modorder))
obj-y := $(addprefix $(obj)/,$(obj-y))
obj-m := $(addprefix $(obj)/,$(obj-m))
lib-y := $(addprefix $(obj)/,$(lib-y))
subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y))
real-objs-y := $(addprefix $(obj)/,$(real-objs-y))
real-objs-m := $(addprefix $(obj)/,$(real-objs-m))
single-used-m := $(addprefix $(obj)/,$(single-used-m))
multi-used-y := $(addprefix $(obj)/,$(multi-used-y))
multi-used-m := $(addprefix $(obj)/,$(multi-used-m))
multi-objs-y := $(addprefix $(obj)/,$(multi-objs-y))
multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m))
subdir-ym := $(addprefix $(obj)/,$(subdir-ym))
obj-dirs := $(addprefix $(obj)/,$(obj-dirs))
# These flags are needed for modversions and compiling, so we define them here
# already
# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will
# end up in (or would, if it gets compiled in)
# Note: Files that end up in two or more modules are compiled without the
# KBUILD_MODNAME definition. The reason is that any made-up name would
# differ in different configs.
name-fix = $(subst $(comma),_,$(subst -,_,$1))
basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
modname_flags = $(if $(filter 1,$(words $(modname))),\
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
$(ccflags-y) $(CFLAGS_$(basetarget).o)
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
orig_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
$(asflags-y) $(AFLAGS_$(basetarget).o)
_a_flags = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags))
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
#
# Enable gcov profiling flags for a file, directory or for all files depending
# on variables GCOV_PROFILE_obj.o, GCOV_PROFILE and CONFIG_GCOV_PROFILE_ALL
# (in this order)
#
ifeq ($(CONFIG_GCOV_KERNEL),y)
_c_flags += $(if $(patsubst n%,, \
$(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
$(CFLAGS_GCOV))
endif
#
# Enable address sanitizer flags for kernel except some files or directories
# we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE)
#
ifeq ($(CONFIG_KASAN),y)
_c_flags += $(if $(patsubst n%,, \
$(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
$(CFLAGS_KASAN))
endif
# If building the kernel in a separate objtree expand all occurrences
# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/').
ifeq ($(KBUILD_SRC),)
__c_flags = $(_c_flags)
__a_flags = $(_a_flags)
__cpp_flags = $(_cpp_flags)
else
# -I$(obj) locates generated .h files
# $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files
# and locates generated .h files
# FIXME: Replace both with specific CFLAGS* statements in the makefiles
__c_flags = $(call addtree,-I$(obj)) $(call flags,_c_flags)
__a_flags = $(call flags,_a_flags)
__cpp_flags = $(call flags,_cpp_flags)
endif
# Modified for U-Boot: LINUXINCLUDE -> UBOOTINCLUDE
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(UBOOTINCLUDE) \
$(__c_flags) $(modkern_cflags) \
-D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(UBOOTINCLUDE) \
$(__a_flags) $(modkern_aflags)
cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(UBOOTINCLUDE) \
$(__cpp_flags)
ld_flags = $(LDFLAGS) $(ldflags-y)
# Try these files in order to find the U-Boot-specific .dtsi include file
u_boot_dtsi_options = $(strip $(wildcard $(dir $<)$(basename $(notdir $<))-u-boot.dtsi) \
$(wildcard $(dir $<)$(subst $\",,$(CONFIG_SYS_SOC))-u-boot.dtsi) \
$(wildcard $(dir $<)$(subst $\",,$(CONFIG_SYS_CPU))-u-boot.dtsi) \
$(wildcard $(dir $<)$(subst $\",,$(CONFIG_SYS_VENDOR))-u-boot.dtsi) \
$(wildcard $(dir $<)u-boot.dtsi))
u_boot_dtsi_options_raw = $(warning Automatic .dtsi inclusion: options: \
$(dir $<)$(basename $(notdir $<))-u-boot.dtsi \
$(dir $<)$(subst $\",,$(CONFIG_SYS_SOC))-u-boot.dtsi \
$(dir $<)$(subst $\",,$(CONFIG_SYS_CPU))-u-boot.dtsi \
$(dir $<)$(subst $\",,$(CONFIG_SYS_VENDOR))-u-boot.dtsi \
$(dir $<)u-boot.dtsi ... \
found: $(if $(u_boot_dtsi_options),"$(u_boot_dtsi_options)",nothing!))
# Uncomment for debugging
# This shows all the files that were considered and the one that we chose.
# u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
# We use the first match
u_boot_dtsi = $(strip $(u_boot_dtsi_options_debug) \
$(notdir $(firstword $(u_boot_dtsi_options))))
# Modified for U-Boot
dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \
-I$(srctree)/arch/$(ARCH)/dts \
-I$(srctree)/arch/$(ARCH)/dts/include \
-Iinclude \
-I$(srctree)/include \
-I$(srctree)/arch/$(ARCH)/include \
-include $(srctree)/include/linux/kconfig.h \
-D__ASSEMBLY__ \
-undef -D__DTS__
# Finds the multi-part object the current object will be linked into
modname-multi = $(sort $(foreach m,$(multi-used),\
$(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))
# Useful for describing the dependency of composite objects
# Usage:
# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add)
define multi_depend
$(foreach m, $(notdir $1), \
$(eval $(obj)/$m: \
$(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s)))))))
endef
# LEX
# ---------------------------------------------------------------------------
quiet_cmd_flex = LEX $@
cmd_flex = $(LEX) -o$@ -L $<
$(obj)/%.lex.c: $(src)/%.l FORCE
$(call if_changed,flex)
# YACC
# ---------------------------------------------------------------------------
quiet_cmd_bison = YACC $@
cmd_bison = $(YACC) -o$@ -t -l $<
$(obj)/%.tab.c: $(src)/%.y FORCE
$(call if_changed,bison)
quiet_cmd_bison_h = YACC $@
cmd_bison_h = $(YACC) -o/dev/null --defines=$@ -t -l $<
$(obj)/%.tab.h: $(src)/%.y FORCE
$(call if_changed,bison_h)
# Shipped files
# ===========================================================================
quiet_cmd_shipped = SHIPPED $@
cmd_shipped = cat $< > $@
$(obj)/%: $(src)/%_shipped
$(call cmd,shipped)
# Commands useful for building a boot image
# ===========================================================================
#
# Use as following:
#
# target: source(s) FORCE
# $(if_changed,ld/objcopy/gzip)
#
# and add target to extra-y so that we know we have to
# read in the saved command line
# Linking
# ---------------------------------------------------------------------------
quiet_cmd_ld = LD $@
cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \
$(filter-out FORCE,$^) -o $@
# Objcopy
# ---------------------------------------------------------------------------
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
# Gzip
# ---------------------------------------------------------------------------
quiet_cmd_gzip = GZIP $@
cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
(rm -f $@ ; false)
# DTC
# ---------------------------------------------------------------------------
# Generate an assembly file to wrap the output of the device tree compiler
quiet_cmd_dt_S_dtb= DTB $@
# Modified for U-Boot
cmd_dt_S_dtb= \
( \
echo '.section .dtb.init.rodata,"a"'; \
echo '.balign 16'; \
echo '.global __dtb_$(subst -,_,$(*F))_begin'; \
echo '__dtb_$(subst -,_,$(*F))_begin:'; \
echo '.incbin "$<" '; \
echo '__dtb_$(subst -,_,$(*F))_end:'; \
echo '.global __dtb_$(subst -,_,$(*F))_end'; \
echo '.balign 16'; \
) > $@
$(obj)/%.dtb.S: $(obj)/%.dtb
$(call cmd,dt_S_dtb)
quiet_cmd_dtc = DTC $@
# Modified for U-Boot
# Bring in any U-Boot-specific include at the end of the file
cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
(cat $<; $(if $(u_boot_dtsi),echo '$(pound)include "$(u_boot_dtsi)"')) > $(pre-tmp); \
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $(pre-tmp) ; \
$(DTC) -O dtb -o $@ -b 0 \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) ; \
sed -i "s:$(pre-tmp):$(<):" $(depfile)
$(obj)/%.dtb: $(src)/%.dts FORCE
$(call if_changed_dep,dtc)
pre-tmp = $(subst $(comma),_,$(dot-target).pre.tmp)
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
# DTCO
# ---------------------------------------------------------------------------
quiet_cmd_dtco = DTCO $@
# Rule for objects only; does not put specific u-boot include at the end
# No generation of assembly file either
# Modified for U-Boot
cmd_dtco = mkdir -p $(dir ${dtc-tmp}) ; \
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
$(DTC) -@ -O dtb -o $@ -b 0 \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
$(obj)/%.dtbo: $(src)/%.dts FORCE
$(call if_changed_dep,dtco)
# Fonts
# ---------------------------------------------------------------------------
# Generate an assembly file to wrap the font data
quiet_cmd_S_ttf= TTF $@
# Modified for U-Boot
cmd_S_ttf= \
( \
echo '.section .rodata.ttf.init,"a"'; \
echo '.balign 16'; \
echo '.global __ttf_$(*F)_begin'; \
echo '__ttf_$(*F)_begin:'; \
echo '.incbin "$<" '; \
echo '__ttf_$(*F)_end:'; \
echo '.global __ttf_$(*F)_end'; \
echo '.balign 16'; \
) > $@
$(obj)/%.S: $(src)/%.ttf
$(call cmd,S_ttf)
# EFI applications
# A Makefile target *.efi is built as EFI application.
# A Makefile target *_efi.S wraps *.efi as built-in EFI application.
# ---------------------------------------------------------------------------
# Generate an assembly file to wrap the EFI app
cmd_S_efi= \
( \
echo '.section .rodata.$*.init,"a"'; \
echo '.balign 16'; \
echo '.global __efi_$*_begin'; \
echo '__efi_$*_begin:'; \
echo '.incbin "$<" '; \
echo '__efi_$*_end:'; \
echo '.global __efi_$*_end'; \
echo '.balign 16'; \
) > $@
$(obj)/%_efi.S: $(obj)/%.efi
$(call cmd,S_efi)
quiet_cmd_efi_objcopy = OBJCOPY $@
cmd_efi_objcopy = $(OBJCOPY) -j .header -j .text -j .sdata -j .data -j \
.dynamic -j .dynsym -j .rel* -j .rela* -j .reloc \
$(if $(EFI_TARGET),$(EFI_TARGET),-O binary) $^ $@
$(obj)/%.efi: $(obj)/%_efi.so
$(call cmd,efi_objcopy)
quiet_cmd_efi_ld = LD $@
cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \
-Bsymbolic -s $^ -o $@
EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS)
$(obj)/efi_crt0.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_CRT0:.o=.S) FORCE
$(call if_changed_dep,as_o_S)
$(obj)/efi_reloc.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_RELOC:.o=.c) $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
$(obj)/%_efi.so: $(obj)/%.o $(obj)/efi_crt0.o $(obj)/efi_reloc.o $(obj)/efi_freestanding.o
$(call cmd,efi_ld)
# ACPI
# ---------------------------------------------------------------------------
#
# This first sends the file (typically dsdt.asl) through the preprocessor
# resolve includes and any CONFIG options used. This produces dsdt.asl.tmp
# which is pure ASL code. The Intel ASL (ACPI (Advanced Configuration and Power
# Interface) Source Language compiler (iasl) then converts this ASL code into a
# C file containing the hex data to build into U-Boot. This file is called
# dsdt.hex (despite us setting the prefix to .../dsdt.asl.tmp) so must be
# renamed to dsdt.c for consumption by the build system.
ASL_TMP = $(patsubst %.c,%.asl.tmp,$@)
quiet_cmd_acpi_c_asl= ASL $<
cmd_acpi_c_asl= \
$(CPP) -x assembler-with-cpp -D__ASSEMBLY__ -P $(UBOOTINCLUDE) \
-o $(ASL_TMP) $< && \
iasl -p $@ -tc $(ASL_TMP) $(if $(KBUILD_VERBOSE:1=), >/dev/null) && \
mv $(patsubst %.c,%.hex,$@) $@
$(obj)/dsdt.c: $(src)/dsdt.asl
$(call cmd,acpi_c_asl)
$(Q)sed -i -e "s,dsdt_aml_code,AmlCode," $@
# Bzip2
# ---------------------------------------------------------------------------
# Bzip2 and LZMA do not include size in file... so we have to fake that;
# append the size as a 32-bit littleendian number as gzip does.
size_append = printf $(shell \
dec_size=0; \
for F in $1; do \
fsize=$$(stat -c "%s" $$F); \
dec_size=$$(expr $$dec_size + $$fsize); \
done; \
printf "%08x\n" $$dec_size | \
sed 's/\(..\)/\1 /g' | { \
read ch0 ch1 ch2 ch3; \
for ch in $$ch3 $$ch2 $$ch1 $$ch0; do \
printf '%s%03o' '\\' $$((0x$$ch)); \
done; \
} \
)
quiet_cmd_bzip2 = BZIP2 $@
cmd_bzip2 = (cat $(filter-out FORCE,$^) | \
bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
# Lzma
# ---------------------------------------------------------------------------
quiet_cmd_lzma = LZMA $@
cmd_lzma = (cat $(filter-out FORCE,$^) | \
lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
quiet_cmd_lzo = LZO $@
cmd_lzo = (cat $(filter-out FORCE,$^) | \
lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
quiet_cmd_lz4 = LZ4 $@
cmd_lz4 = (cat $(filter-out FORCE,$^) | \
lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
# U-Boot mkimage
# ---------------------------------------------------------------------------
MKIMAGE := $(srctree)/scripts/mkuboot.sh
# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
# the number of overrides in arch makefiles
UIMAGE_ARCH ?= $(SRCARCH)
UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
UIMAGE_OPTS-y ?=
UIMAGE_TYPE ?= kernel
UIMAGE_LOADADDR ?= arch_must_set_this
UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)'
UIMAGE_IN ?= $<
UIMAGE_OUT ?= $@
quiet_cmd_uimage = UIMAGE $(UIMAGE_OUT)
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \
-C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \
-T $(UIMAGE_TYPE) \
-a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \
-n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT)
# XZ
# ---------------------------------------------------------------------------
# Use xzkern to compress the kernel image and xzmisc to compress other things.
#
# xzkern uses a big LZMA2 dictionary since it doesn't increase memory usage
# of the kernel decompressor. A BCJ filter is used if it is available for
# the target architecture. xzkern also appends uncompressed size of the data
# using size_append. The .xz format has the size information available at
# the end of the file too, but it's in more complex format and it's good to
# avoid changing the part of the boot code that reads the uncompressed size.
# Note that the bytes added by size_append will make the xz tool think that
# the file is corrupt. This is expected.
#
# xzmisc doesn't use size_append, so it can be used to create normal .xz
# files. xzmisc uses smaller LZMA2 dictionary than xzkern, because a very
# big dictionary would increase the memory usage too much in the multi-call
# decompression mode. A BCJ filter isn't used either.
quiet_cmd_xzkern = XZKERN $@
cmd_xzkern = (cat $(filter-out FORCE,$^) | \
sh $(srctree)/scripts/xz_wrap.sh && \
$(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
quiet_cmd_xzmisc = XZMISC $@
cmd_xzmisc = (cat $(filter-out FORCE,$^) | \
xz --check=crc32 --lzma2=dict=1MiB) > $@ || \
(rm -f $@ ; false)
# Additional commands for U-Boot
#
# mkimage
# ---------------------------------------------------------------------------
MKIMAGEOUTPUT ?= /dev/null
quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
>$(MKIMAGEOUTPUT) $(if $(KBUILD_VERBOSE:0=), && cat $(MKIMAGEOUTPUT))
# fdtgrep
# ---------------------------------------------------------------------------
# Pass the original device tree file through fdtgrep twice. The first pass
# removes any unwanted nodes (i.e. those which don't have the
# 'u-boot,dm-pre-reloc' property and thus are not needed by SPL. The second
# pass removes various unused properties from the remaining nodes.
# The output is typically a much smaller device tree file.
ifeq ($(CONFIG_TPL_BUILD),y)
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-tpl
else
fdtgrep_props := -b u-boot,dm-pre-reloc -b u-boot,dm-spl
endif
quiet_cmd_fdtgrep = FDTGREP $@
cmd_fdtgrep = $(objtree)/tools/fdtgrep $(fdtgrep_props) -RT $< \
-n /chosen -n /config -O dtb | \
$(objtree)/tools/fdtgrep -r -O dtb - -o $@ \
-P u-boot,dm-pre-reloc -P u-boot,dm-spl -P u-boot,dm-tpl \
$(addprefix -P ,$(subst $\",,$(CONFIG_OF_SPL_REMOVE_PROPS)))

168
scripts/Makefile.ppl Normal file
View File

@@ -0,0 +1,168 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2020 Alibaba Group Holding Limited
#
src := $(obj)
# Create output directory if not already present
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
include $(srctree)/scripts/Kbuild.include
-include include/config/auto.conf
-include $(obj)/include/autoconf.mk
KBUILD_CPPFLAGS += -DCONFIG_PPL_BUILD
ifeq ($(obj)$(CONFIG_SUPPORT_PPL),ppl)
$(error You cannot build PPL without enabling CONFIG_SUPPORT_PPL)
endif
include $(srctree)/config.mk
include $(srctree)/arch/$(ARCH)/Makefile
include $(srctree)/scripts/Makefile.lib
# Enable garbage collection of un-used sections for SPL
KBUILD_CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS_FINAL += --gc-sections
# FIX ME
cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
$(NOSTDINC_FLAGS)
c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makefile),y,n)
libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
head-y := $(addprefix $(obj)/,$(head-y))
libs-y := $(addprefix $(obj)/,$(libs-y))
u-boot-ppl-dirs := $(patsubst %/,%,$(filter %/, $(libs-y)))
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
u-boot-ppl-init := $(head-y)
u-boot-ppl-main := $(libs-y)
# Linker Script
# First test whether there's a linker-script for the specific stage defined...
ifneq ($(CONFIG_PPL_LDSCRIPT),)
# need to strip off double quotes
LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_PPL_LDSCRIPT:"%"=%))
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot-ppl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot-ppl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot-ppl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
$(error could not find linker script)
endif
# Special flags for CPP when processing the linker script.
# Pass the version down so we can handle backwards compatibility
# on the fly.
LDPPFLAGS += \
-include $(srctree)/include/u-boot/u-boot.lds.h \
-include $(objtree)/include/config.h \
-DCPUDIR=$(CPUDIR) \
$(shell $(LD) --version | \
sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')
# Turn various CONFIG symbols into IMAGE symbols for easy reuse of
# the scripts between SPL and TPL.
ifneq ($(CONFIG_PPL_MAX_SIZE),)
LDPPFLAGS += -DIMAGE_MAX_SIZE=$(CONFIG_PPL_MAX_SIZE)
endif
ifneq ($(CONFIG_PPL_TEXT_BASE),)
LDPPFLAGS += -DIMAGE_TEXT_BASE=$(CONFIG_PPL_TEXT_BASE)
endif
MKIMAGEOUTPUT ?= /dev/null
quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
>$(MKIMAGEOUTPUT) $(if $(KBUILD_VERBOSE:0=), && cat $(MKIMAGEOUTPUT))
ALL-y += $(obj)/u-boot-ppl.bin
all: $(ALL-y)
quiet_cmd_cat = CAT $@
cmd_cat = cat $(filter-out $(PHONY), $^) > $@
quiet_cmd_copy = COPY $@
cmd_copy = cp $< $@
$(obj)/u-boot-ppl.bin: $(obj)/u-boot-ppl-nodtb.bin FORCE
$(call if_changed,copy)
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
OBJCOPYFLAGS_u-boot-ppl-nodtb.bin = $(PPL_OBJCFLAGS) -O binary
$(obj)/u-boot-ppl-nodtb.bin: $(obj)/u-boot-ppl FORCE
$(call if_changed,objcopy)
LDFLAGS_u-boot-ppl += -T u-boot-ppl.lds $(LDFLAGS_FINAL)
# Avoid 'Not enough room for program headers' error on binutils 2.28 onwards.
LDFLAGS_u-boot-ppl += $(call ld-option, --no-dynamic-linker)
# Pick the best-match (i.e. SPL_TEXT_BASE for SPL, TPL_TEXT_BASE for TPL)
ifneq ($(CONFIG_PPL_TEXT_BASE),)
LDFLAGS_u-boot-ppl += -Ttext $(CONFIG_PPL_TEXT_BASE)
endif
# Rule to link u-boot-ppl
# May be overridden by arch/$(ARCH)/config.mk
quiet_cmd_u-boot-ppl ?= LD $@
cmd_u-boot-ppl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
$(patsubst $(obj)/%,%,$(u-boot-ppl-init)) --start-group \
$(patsubst $(obj)/%,%,$(u-boot-ppl-main)) \
--end-group \
$(PLATFORM_LIBS) -Map u-boot-ppl.map -o u-boot-ppl)
$(obj)/u-boot-ppl: $(u-boot-ppl-init) \
$(u-boot-ppl-main) $(obj)/u-boot-ppl.lds FORCE
$(call if_changed,u-boot-ppl)
$(sort $(u-boot-ppl-init) $(u-boot-ppl-main)): $(u-boot-ppl-dirs) ;
PHONY += $(u-boot-ppl-dirs)
$(u-boot-ppl-dirs):
$(Q)$(MAKE) $(build)=$@
quiet_cmd_cpp_lds = LDS $@
cmd_cpp_lds = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
-D__ASSEMBLY__ -x assembler-with-cpp -std=c99 -P -o $@ $<
$(obj)/u-boot-ppl.lds: $(LDSCRIPT) FORCE
$(call if_changed_dep,cpp_lds)
# read all saved command lines
targets := $(wildcard $(sort $(targets)))
cmd_files := $(wildcard $(obj)/.*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
ifneq ($(cmd_files),)
$(cmd_files): ; # Do not try to update included dependency files
include $(cmd_files)
endif
PHONY += FORCE
FORCE:
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable so we can use it in if_changed and friends.
.PHONY: $(PHONY)

480
scripts/Makefile.spl Normal file
View File

@@ -0,0 +1,480 @@
# SPDX-License-Identifier: GPL-2.0+
#
# (C) Copyright 2000-2011
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# (C) Copyright 2011
# Daniel Schwierzeck, daniel.schwierzeck@googlemail.com.
#
# (C) Copyright 2011
# Texas Instruments Incorporated - http://www.ti.com/
# Aneesh V <aneesh@ti.com>
# Based on top-level Makefile.
#
src := $(obj)
# Create output directory if not already present
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
include $(srctree)/scripts/Kbuild.include
-include include/config/auto.conf
-include $(obj)/include/autoconf.mk
KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD
ifeq ($(CONFIG_TPL_BUILD),y)
KBUILD_CPPFLAGS += -DCONFIG_TPL_BUILD
endif
ifeq ($(CONFIG_TPL_BUILD),y)
SPL_BIN := u-boot-tpl
else
SPL_BIN := u-boot-spl
endif
ifdef CONFIG_SPL_BUILD
SPL_ := SPL_
ifeq ($(CONFIG_TPL_BUILD),y)
SPL_TPL_ := TPL_
else
SPL_TPL_ := SPL_
endif
else
SPL_ :=
SPL_TPL_ :=
endif
ifeq ($(obj)$(CONFIG_SUPPORT_SPL),spl)
$(error You cannot build SPL without enabling CONFIG_SUPPORT_SPL)
endif
ifeq ($(obj)$(CONFIG_SUPPORT_TPL),tpl)
$(error You cannot build TPL without enabling CONFIG_SUPPORT_TPL)
endif
include $(srctree)/config.mk
include $(srctree)/arch/$(ARCH)/Makefile
include $(srctree)/scripts/Makefile.lib
# Enable garbage collection of un-used sections for SPL
KBUILD_CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS_FINAL += --gc-sections
# FIX ME
cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
$(NOSTDINC_FLAGS)
c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makefile),y,n)
libs-y += $(if $(BOARDDIR),board/$(BOARDDIR)/)
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
ifeq ($(CONFIG_TPL_BUILD),y)
libs-$(CONFIG_TPL_FRAMEWORK) += common/spl/
else
libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
endif
libs-y += common/init/
# Special handling for a few options which support SPL/TPL
ifeq ($(CONFIG_TPL_BUILD),y)
libs-$(CONFIG_TPL_LIBCOMMON_SUPPORT) += common/ cmd/ env/
libs-$(CONFIG_TPL_LIBGENERIC_SUPPORT) += lib/
else
libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/ cmd/ env/
libs-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/
ifdef CONFIG_SPL_FRAMEWORK
libs-$(CONFIG_PARTITIONS) += disk/
endif
endif
libs-y += drivers/
libs-$(CONFIG_SPL_USB_GADGET) += drivers/usb/dwc3/
libs-$(CONFIG_SPL_USB_GADGET) += drivers/usb/cdns3/
libs-y += dts/
libs-y += fs/
libs-$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/
libs-$(CONFIG_SPL_NET_SUPPORT) += net/
head-y := $(addprefix $(obj)/,$(head-y))
libs-y := $(addprefix $(obj)/,$(libs-y))
u-boot-spl-dirs := $(patsubst %/,%,$(filter %/, $(libs-y)))
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
# Add GCC lib
ifeq ($(CONFIG_USE_PRIVATE_LIBGCC),y)
PLATFORM_LIBGCC = arch/$(ARCH)/lib/lib.a
PLATFORM_LIBS := $(filter-out %/lib.a, $(filter-out -lgcc, $(PLATFORM_LIBS))) $(PLATFORM_LIBGCC)
endif
u-boot-spl-init := $(head-y)
u-boot-spl-main := $(libs-y)
ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA
u-boot-spl-platdata := $(obj)/dts/dt-platdata.o
endif
# Linker Script
# First test whether there's a linker-script for the specific stage defined...
ifneq ($(CONFIG_$(SPL_TPL_)LDSCRIPT),)
# need to strip off double quotes
LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_$(SPL_TPL_)LDSCRIPT:"%"=%))
else
# ...then fall back to the generic SPL linker-script
ifneq ($(CONFIG_SPL_LDSCRIPT),)
# need to strip off double quotes
LDSCRIPT := $(addprefix $(srctree)/,$(CONFIG_SPL_LDSCRIPT:"%"=%))
endif
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/board/$(BOARDDIR)/u-boot-spl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/$(CPUDIR)/u-boot-spl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
LDSCRIPT := $(srctree)/arch/$(ARCH)/cpu/u-boot-spl.lds
endif
ifeq ($(wildcard $(LDSCRIPT)),)
$(error could not find linker script)
endif
# Special flags for CPP when processing the linker script.
# Pass the version down so we can handle backwards compatibility
# on the fly.
LDPPFLAGS += \
-include $(srctree)/include/u-boot/u-boot.lds.h \
-include $(objtree)/include/config.h \
-DCPUDIR=$(CPUDIR) \
$(shell $(LD) --version | \
sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')
# Turn various CONFIG symbols into IMAGE symbols for easy reuse of
# the scripts between SPL and TPL.
ifneq ($(CONFIG_$(SPL_TPL_)MAX_SIZE),)
LDPPFLAGS += -DIMAGE_MAX_SIZE=$(CONFIG_$(SPL_TPL_)MAX_SIZE)
endif
ifneq ($(CONFIG_$(SPL_TPL_)TEXT_BASE),)
LDPPFLAGS += -DIMAGE_TEXT_BASE=$(CONFIG_$(SPL_TPL_)TEXT_BASE)
endif
MKIMAGEOUTPUT ?= /dev/null
quiet_cmd_mkimage = MKIMAGE $@
cmd_mkimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -d $< $@ \
>$(MKIMAGEOUTPUT) $(if $(KBUILD_VERBOSE:0=), && cat $(MKIMAGEOUTPUT))
quiet_cmd_mkfitimage = MKIMAGE $@
cmd_mkfitimage = $(objtree)/tools/mkimage $(MKIMAGEFLAGS_$(@F)) -f $(SPL_ITS) -E $@ \
$(if $(KBUILD_VERBOSE:1=), MKIMAGEOUTPUT)
MKIMAGEFLAGS_MLO = -T omapimage -a $(CONFIG_SPL_TEXT_BASE)
MKIMAGEFLAGS_MLO.byteswap = -T omapimage -n byteswap -a $(CONFIG_SPL_TEXT_BASE)
MLO MLO.byteswap: $(obj)/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
ifeq ($(CONFIG_SYS_SOC),"at91")
MKIMAGEFLAGS_boot.bin = -T atmelimage
ifeq ($(CONFIG_SPL_GENERATE_ATMEL_PMECC_HEADER),y)
MKIMAGEFLAGS_boot.bin += -n $(shell $(obj)/../tools/atmel_pmecc_params)
$(obj)/boot.bin: $(obj)/../tools/atmel_pmecc_params
endif
$(obj)/boot.bin: $(obj)/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
else
ifdef CONFIG_ARCH_ZYNQ
MKIMAGEFLAGS_boot.bin = -T zynqimage -R $(srctree)/$(CONFIG_BOOT_INIT_FILE)
endif
ifdef CONFIG_ARCH_ZYNQMP
ifneq ($(CONFIG_PMUFW_INIT_FILE),"")
spl/boot.bin: zynqmp-check-pmufw
zynqmp-check-pmufw: FORCE
( cd $(srctree) && test -r $(CONFIG_PMUFW_INIT_FILE) ) \
|| ( echo "Cannot read $(CONFIG_PMUFW_INIT_FILE)" && false )
endif
MKIMAGEFLAGS_boot.bin = -T zynqmpimage -R $(srctree)/$(CONFIG_BOOT_INIT_FILE) \
-n "$(shell cd $(srctree); readlink -f $(CONFIG_PMUFW_INIT_FILE))"
endif
$(obj)/$(SPL_BIN)-align.bin: $(obj)/$(SPL_BIN).bin
@dd if=$< of=$@ conv=block,sync bs=4 2>/dev/null;
spl/boot.bin: $(obj)/$(SPL_BIN)-align.bin FORCE
$(call if_changed,mkimage)
endif
ALL-y += $(obj)/$(SPL_BIN).bin
ifdef CONFIG_SAMSUNG
ALL-y += $(obj)/$(BOARD)-spl.bin
endif
ifneq ($(CONFIG_TARGET_SOCFPGA_GEN5)$(CONFIG_TARGET_SOCFPGA_ARRIA10),)
ALL-y += $(obj)/$(SPL_BIN).sfp
endif
ifdef CONFIG_ARCH_SUNXI
ALL-y += $(obj)/sunxi-spl.bin
ifdef CONFIG_NAND_SUNXI
ALL-y += $(obj)/sunxi-spl-with-ecc.bin
endif
endif
ifeq ($(CONFIG_SYS_SOC),"at91")
ALL-y += $(obj)/boot.bin
endif
ifdef CONFIG_TPL_BUILD
ALL-$(CONFIG_TPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-start16-tpl.bin \
$(obj)/u-boot-x86-reset16-tpl.bin
else
ALL-$(CONFIG_SPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-start16-spl.bin \
$(obj)/u-boot-x86-reset16-spl.bin
endif
ALL-$(CONFIG_ARCH_ZYNQ) += $(obj)/boot.bin
ALL-$(CONFIG_ARCH_ZYNQMP) += $(obj)/boot.bin
ALL-$(CONFIG_ARCH_MEDIATEK) += $(obj)/u-boot-spl-mtk.bin
all: $(ALL-y)
quiet_cmd_cat = CAT $@
cmd_cat = cat $(filter-out $(PHONY), $^) > $@
quiet_cmd_copy = COPY $@
cmd_copy = cp $< $@
ifneq ($(CONFIG_SPL_MULTI_DTB_FIT),y)
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).dtb
else ifeq ($(CONFIG_SPL_MULTI_DTB_FIT_LZO),y)
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.lzo
else ifeq ($(CONFIG_SPL_MULTI_DTB_FIT_GZIP),y)
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit.gz
else
FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit
endif
# Build the .dtb file if:
# - we are not using OF_PLATDATA
# - we are using OF_CONTROL
# - we have either OF_SEPARATE or OF_HOSTFILE
build_dtb :=
ifeq ($(CONFIG_$(SPL_TPL_)OF_PLATDATA),)
ifneq ($(CONFIG_$(SPL_TPL_)OF_CONTROL),)
ifeq ($(CONFIG_OF_SEPARATE)$(CONFIG_OF_HOSTFILE),y)
build_dtb := y
endif
endif
endif
ifneq ($(build_dtb),)
$(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \
$(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \
$(FINAL_DTB_CONTAINER) FORCE
$(call if_changed,cat)
$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-dtb.bin FORCE
$(call if_changed,copy)
else
$(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN)-nodtb.bin FORCE
$(call if_changed,copy)
endif
# Create a file that pads from the end of u-boot-spl-nodtb.bin to bss_end
$(obj)/$(SPL_BIN)-pad.bin: $(obj)/$(SPL_BIN)
@bss_size_str=$(shell $(NM) $< | awk 'BEGIN {size = 0} /__bss_size/ {size = $$1} END {print "ibase=16; " toupper(size)}' | bc); \
dd if=/dev/zero of=$@ bs=1 count=$${bss_size_str} 2>/dev/null;
$(obj)/$(SPL_BIN).dtb: dts/dt-spl.dtb FORCE
$(call if_changed,copy)
pythonpath = PYTHONPATH=scripts/dtc/pylibfdt
quiet_cmd_dtocc = DTOC C $@
cmd_dtocc = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ platdata
quiet_cmd_dtoch = DTOC H $@
cmd_dtoch = $(pythonpath) $(srctree)/tools/dtoc/dtoc -d $(obj)/$(SPL_BIN).dtb -o $@ struct
quiet_cmd_plat = PLAT $@
cmd_plat = $(CC) $(c_flags) -c $< -o $@
$(obj)/dts/dt-platdata.o: $(obj)/dts/dt-platdata.c \
include/generated/dt-structs-gen.h
$(call if_changed,plat)
PHONY += dts_dir
dts_dir:
$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
include/generated/dt-structs-gen.h: $(obj)/$(SPL_BIN).dtb dts_dir FORCE
$(call if_changed,dtoch)
$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir FORCE
$(call if_changed,dtocc)
ifdef CONFIG_SAMSUNG
ifdef CONFIG_VAR_SIZE_SPL
VAR_SIZE_PARAM = --vs
else
VAR_SIZE_PARAM =
endif
$(obj)/$(BOARD)-spl.bin: $(obj)/u-boot-spl.bin
$(if $(wildcard $(objtree)/spl/board/samsung/$(BOARD)/tools/mk$(BOARD)spl),\
$(objtree)/spl/board/samsung/$(BOARD)/tools/mk$(BOARD)spl,\
$(objtree)/tools/mkexynosspl) $(VAR_SIZE_PARAM) $< $@
endif
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
OBJCOPYFLAGS_$(SPL_BIN)-nodtb.bin = $(SPL_OBJCFLAGS) -O binary \
$(if $(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),-R .start16 -R .resetvec)
$(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE
$(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot-x86-start16-spl.bin := -O binary -j .start16
$(obj)/u-boot-x86-start16-spl.bin: $(obj)/u-boot-spl FORCE
$(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot-x86-start16-tpl.bin := -O binary -j .start16
$(obj)/u-boot-x86-start16-tpl.bin: $(obj)/u-boot-tpl FORCE
$(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot-x86-reset16-spl.bin := -O binary -j .resetvec
$(obj)/u-boot-x86-reset16-spl.bin: $(obj)/u-boot-spl FORCE
$(call if_changed,objcopy)
OBJCOPYFLAGS_u-boot-x86-reset16-tpl.bin := -O binary -j .resetvec
$(obj)/u-boot-x86-reset16-tpl.bin: $(obj)/u-boot-tpl FORCE
$(call if_changed,objcopy)
LDFLAGS_$(SPL_BIN) += -T u-boot-spl.lds $(LDFLAGS_FINAL)
# Avoid 'Not enough room for program headers' error on binutils 2.28 onwards.
LDFLAGS_$(SPL_BIN) += $(call ld-option, --no-dynamic-linker)
# Pick the best-match (i.e. SPL_TEXT_BASE for SPL, TPL_TEXT_BASE for TPL)
ifneq ($(CONFIG_$(SPL_TPL_)TEXT_BASE),)
LDFLAGS_$(SPL_BIN) += -Ttext $(CONFIG_$(SPL_TPL_)TEXT_BASE)
endif
ifdef CONFIG_TARGET_SOCFPGA_ARRIA10
MKIMAGEFLAGS_$(SPL_BIN).sfp = -T socfpgaimage_v1
else
MKIMAGEFLAGS_$(SPL_BIN).sfp = -T socfpgaimage
endif
$(obj)/$(SPL_BIN).sfp: $(obj)/$(SPL_BIN).bin FORCE
$(call if_changed,mkimage)
quiet_cmd_mksunxiboot = MKSUNXI $@
cmd_mksunxiboot = $(objtree)/tools/mksunxiboot \
--default-dt $(CONFIG_DEFAULT_DEVICE_TREE) $< $@
$(obj)/sunxi-spl.bin: $(obj)/$(SPL_BIN).bin FORCE
$(call if_changed,mksunxiboot)
quiet_cmd_sunxi_spl_image_builder = SUNXI_SPL_IMAGE_BUILDER $@
cmd_sunxi_spl_image_builder = $(objtree)/tools/sunxi-spl-image-builder \
-c $(CONFIG_NAND_SUNXI_SPL_ECC_STRENGTH)/$(CONFIG_NAND_SUNXI_SPL_ECC_SIZE) \
-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
-o $(CONFIG_SYS_NAND_OOBSIZE) \
-u $(CONFIG_NAND_SUNXI_SPL_USABLE_PAGE_SIZE) \
-e $(CONFIG_SYS_NAND_BLOCK_SIZE) \
-s -b $< $@
$(obj)/sunxi-spl-with-ecc.bin: $(obj)/sunxi-spl.bin
$(call if_changed,sunxi_spl_image_builder)
# MediaTek's specific SPL build
MKIMAGEFLAGS_u-boot-spl-mtk.bin = -T mtk_image \
-a $(CONFIG_SPL_TEXT_BASE) -e $(CONFIG_SPL_TEXT_BASE) \
-n "$(patsubst "%",%,$(CONFIG_MTK_BROM_HEADER_INFO))"
$(obj)/u-boot-spl-mtk.bin: $(obj)/u-boot-spl.bin FORCE
$(call if_changed,mkimage)
# Rule to link u-boot-spl
# May be overridden by arch/$(ARCH)/config.mk
quiet_cmd_u-boot-spl ?= LD $@
cmd_u-boot-spl ?= (cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
$(patsubst $(obj)/%,%,$(u-boot-spl-init)) --start-group \
$(patsubst $(obj)/%,%,$(u-boot-spl-main)) \
$(patsubst $(obj)/%,%,$(u-boot-spl-platdata)) \
--end-group \
$(PLATFORM_LIBS) -Map $(SPL_BIN).map -o $(SPL_BIN))
$(obj)/$(SPL_BIN): $(u-boot-spl-platdata) $(u-boot-spl-init) \
$(u-boot-spl-main) $(obj)/u-boot-spl.lds FORCE
$(call if_changed,u-boot-spl)
$(sort $(u-boot-spl-init) $(u-boot-spl-main)): $(u-boot-spl-dirs) ;
PHONY += $(u-boot-spl-dirs)
$(u-boot-spl-dirs): $(u-boot-spl-platdata)
$(Q)$(MAKE) $(build)=$@
quiet_cmd_cpp_lds = LDS $@
cmd_cpp_lds = $(CPP) -Wp,-MD,$(depfile) $(cpp_flags) $(LDPPFLAGS) -ansi \
-D__ASSEMBLY__ -x assembler-with-cpp -std=c99 -P -o $@ $<
$(obj)/u-boot-spl.lds: $(LDSCRIPT) FORCE
$(call if_changed_dep,cpp_lds)
# read all saved command lines
targets := $(wildcard $(sort $(targets)))
cmd_files := $(wildcard $(obj)/.*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
ifneq ($(cmd_files),)
$(cmd_files): ; # Do not try to update included dependency files
include $(cmd_files)
endif
PHONY += FORCE
FORCE:
PHONY += dtbs
dtbs:
$(Q)$(MAKE) $(build)=dts dtbs
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable so we can use it in if_changed and friends.
.PHONY: $(PHONY)
SHRUNK_ARCH_DTB = $(patsubst %,$(obj)/dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST)))
.SECONDEXPANSION:
$(SHRUNK_ARCH_DTB): $$(patsubst $(obj)/dts/%, arch/$(ARCH)/dts/%, $$@)
$(call if_changed,fdtgrep)
MKIMAGEFLAGS_$(SPL_BIN).multidtb.fit = -f auto -A $(ARCH) -T firmware -C none -O u-boot \
-n "Multi DTB fit image for $(SPL_BIN)" -E \
$(patsubst %,-b %,$(SHRUNK_ARCH_DTB))
$(obj)/$(SPL_BIN).multidtb.fit: /dev/null $(SHRUNK_ARCH_DTB) FORCE
$(call if_changed,mkimage)
ifneq ($(SOURCE_DATE_EPOCH),)
touch -d @$(SOURCE_DATE_EPOCH) $(obj)/$(SPL_BIN).multidtb.fit
chmod 0600 $(obj)/$(SPL_BIN).multidtb.fit
endif
$(obj)/$(SPL_BIN).multidtb.fit.gz: $(obj)/$(SPL_BIN).multidtb.fit
@gzip -kf9 $< > $@
$(obj)/$(SPL_BIN).multidtb.fit.lzo: $(obj)/$(SPL_BIN).multidtb.fit
@lzop -f9 $< > $@
ifdef CONFIG_ARCH_K3
tispl.bin: $(obj)/u-boot-spl-nodtb.bin $(SHRUNK_ARCH_DTB) $(SPL_ITS) FORCE
$(call if_changed,mkfitimage)
endif

View File

@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0+
# Makefile version of include/config_uncmd_spl.h
# TODO: Invent a better way
ifdef CONFIG_SPL_BUILD
ifndef CONFIG_SPL_DM
CONFIG_DM_SERIAL=
CONFIG_DM_GPIO=
CONFIG_DM_I2C=
CONFIG_DM_SPI=
CONFIG_DM_SPI_FLASH=
endif
endif

1
scripts/basic/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
fixdep

16
scripts/basic/Makefile Normal file
View File

@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
###
# Makefile.basic lists the most basic programs used during the build process.
# The programs listed herein are what are needed to do the basic stuff,
# such as fix file dependencies.
# This initial step is needed to avoid files to be recompiled
# when kernel configuration changes (which is what happens when
# .config is included by main Makefile.
# ---------------------------------------------------------------------------
# fixdep: Used to generate dependency information during build process
hostprogs-y := fixdep
always := $(hostprogs-y)
# fixdep is needed to compile other host programs
$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep

481
scripts/basic/fixdep.c Normal file
View File

@@ -0,0 +1,481 @@
/*
* "Optimize" a list of dependencies as spit out by gcc -MD
* for the kernel build
* ===========================================================================
*
* Author Kai Germaschewski
* Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*
* Introduction:
*
* gcc produces a very nice and correct list of dependencies which
* tells make when to remake a file.
*
* To use this list as-is however has the drawback that virtually
* every file in the kernel includes autoconf.h.
*
* If the user re-runs make *config, autoconf.h will be
* regenerated. make notices that and will rebuild every file which
* includes autoconf.h, i.e. basically all files. This is extremely
* annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
*
* So we play the same trick that "mkdep" played before. We replace
* the dependency on autoconf.h by a dependency on every config
* option which is mentioned in any of the listed prequisites.
*
* kconfig populates a tree in include/config/ with an empty file
* for each config symbol and when the configuration is updated
* the files representing changed config options are touched
* which then let make pick up the changes and the files that use
* the config symbols are rebuilt.
*
* So if the user changes his CONFIG_HIS_DRIVER option, only the objects
* which depend on "include/linux/config/his/driver.h" will be rebuilt,
* so most likely only his driver ;-)
*
* The idea above dates, by the way, back to Michael E Chastain, AFAIK.
*
* So to get dependencies right, there are two issues:
* o if any of the files the compiler read changed, we need to rebuild
* o if the command line given to the compile the file changed, we
* better rebuild as well.
*
* The former is handled by using the -MD output, the later by saving
* the command line used to compile the old object and comparing it
* to the one we would now use.
*
* Again, also this idea is pretty old and has been discussed on
* kbuild-devel a long time ago. I don't have a sensibly working
* internet connection right now, so I rather don't mention names
* without double checking.
*
* This code here has been based partially based on mkdep.c, which
* says the following about its history:
*
* Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
* This is a C version of syncdep.pl by Werner Almesberger.
*
*
* It is invoked as
*
* fixdep <depfile> <target> <cmdline>
*
* and will read the dependency file <depfile>
*
* The transformed dependency snipped is written to stdout.
*
* It first generates a line
*
* cmd_<target> = <cmdline>
*
* and then basically copies the .<target>.d file to stdout, in the
* process filtering out the dependency on autoconf.h and adding
* dependencies on include/config/my/option.h for every
* CONFIG_MY_OPTION encountered in any of the prequisites.
*
* It will also filter out all the dependencies on *.ver. We need
* to make sure that the generated version checksum are globally up
* to date before even starting the recursive build, so it's too late
* at this point anyway.
*
* The algorithm to grep for "CONFIG_..." is bit unusual, but should
* be fast ;-) We don't even try to really parse the header files, but
* merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
* be picked up as well. It's not a problem with respect to
* correctness, since that can only give too many dependencies, thus
* we cannot miss a rebuild. Since people tend to not mention totally
* unrelated CONFIG_ options all over the place, it's not an
* efficiency problem either.
*
* (Note: it'd be easy to port over the complete mkdep state machine,
* but I don't think the added complexity is worth it)
*/
/*
* Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
* CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
* fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
* UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
* through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
* those files will have correct dependencies.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <arpa/inet.h>
#define INT_CONF ntohl(0x434f4e46)
#define INT_ONFI ntohl(0x4f4e4649)
#define INT_NFIG ntohl(0x4e464947)
#define INT_FIG_ ntohl(0x4649475f)
char *target;
char *depfile;
char *cmdline;
int is_spl_build = 0; /* hack for U-Boot */
static void usage(void)
{
fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
exit(1);
}
/*
* Print out the commandline prefixed with cmd_<target filename> :=
*/
static void print_cmdline(void)
{
printf("cmd_%s := %s\n\n", target, cmdline);
}
struct item {
struct item *next;
unsigned int len;
unsigned int hash;
char name[0];
};
#define HASHSZ 256
static struct item *hashtab[HASHSZ];
static unsigned int strhash(const char *str, unsigned int sz)
{
/* fnv32 hash */
unsigned int i, hash = 2166136261U;
for (i = 0; i < sz; i++)
hash = (hash ^ str[i]) * 0x01000193;
return hash;
}
/*
* Lookup a value in the configuration string.
*/
static int is_defined_config(const char *name, int len, unsigned int hash)
{
struct item *aux;
for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
if (aux->hash == hash && aux->len == len &&
memcmp(aux->name, name, len) == 0)
return 1;
}
return 0;
}
/*
* Add a new value to the configuration string.
*/
static void define_config(const char *name, int len, unsigned int hash)
{
struct item *aux = malloc(sizeof(*aux) + len);
if (!aux) {
perror("fixdep:malloc");
exit(1);
}
memcpy(aux->name, name, len);
aux->len = len;
aux->hash = hash;
aux->next = hashtab[hash % HASHSZ];
hashtab[hash % HASHSZ] = aux;
}
/*
* Record the use of a CONFIG_* word.
*/
static void use_config(const char *m, int slen)
{
unsigned int hash = strhash(m, slen);
int c, i;
if (is_defined_config(m, slen, hash))
return;
define_config(m, slen, hash);
printf(" $(wildcard include/config/");
for (i = 0; i < slen; i++) {
c = m[i];
if (c == '_')
c = '/';
else
c = tolower(c);
putchar(c);
}
printf(".h) \\\n");
}
static void parse_config_file(const char *map, size_t len)
{
const int *end = (const int *) (map + len);
/* start at +1, so that p can never be < map */
const int *m = (const int *) map + 1;
const char *p, *q;
char tmp_buf[256] = "SPL_"; /* hack for U-Boot */
for (; m < end; m++) {
if (*m == INT_CONF) { p = (char *) m ; goto conf; }
if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
continue;
conf:
if (p > map + len - 7)
continue;
if (memcmp(p, "CONFIG_", 7))
continue;
p += 7;
for (q = p; q < map + len; q++) {
if (!(isalnum(*q) || *q == '_'))
goto found;
}
continue;
found:
if (!memcmp(q - 7, "_MODULE", 7))
q -= 7;
if (q - p < 0)
continue;
/*
* U-Boot also handles
* CONFIG_IS_ENABLED(...)
* CONFIG_IS_BUILTIN(...)
* CONFIG_IS_MODULE(...)
* CONFIG_VAL(...)
*/
if ((q - p == 10 && !memcmp(p, "IS_ENABLED(", 11)) ||
(q - p == 10 && !memcmp(p, "IS_BUILTIN(", 11)) ||
(q - p == 9 && !memcmp(p, "IS_MODULE(", 10)) ||
(q - p == 3 && !memcmp(p, "VAL(", 4))) {
p = q + 1;
for (q = p; q < map + len; q++)
if (*q == ')')
goto found2;
continue;
found2:
if (is_spl_build) {
memcpy(tmp_buf + 4, p, q - p);
q = tmp_buf + 4 + (q - p);
p = tmp_buf;
}
}
/* end U-Boot hack */
use_config(p, q - p);
}
}
/* test is s ends in sub */
static int strrcmp(char *s, char *sub)
{
int slen = strlen(s);
int sublen = strlen(sub);
if (sublen > slen)
return 1;
return memcmp(s + slen - sublen, sub, sublen);
}
static void do_config_file(const char *filename)
{
struct stat st;
int fd;
void *map;
fd = open(filename, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "fixdep: error opening config file: ");
perror(filename);
exit(2);
}
if (fstat(fd, &st) < 0) {
fprintf(stderr, "fixdep: error fstat'ing config file: ");
perror(filename);
exit(2);
}
if (st.st_size == 0) {
close(fd);
return;
}
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if ((long) map == -1) {
perror("fixdep: mmap");
close(fd);
return;
}
parse_config_file(map, st.st_size);
munmap(map, st.st_size);
close(fd);
}
/*
* Important: The below generated source_foo.o and deps_foo.o variable
* assignments are parsed not only by make, but also by the rather simple
* parser in scripts/mod/sumversion.c.
*/
static void parse_dep_file(void *map, size_t len)
{
char *m = map;
char *end = m + len;
char *p;
char s[PATH_MAX];
int is_target;
int saw_any_target = 0;
int is_first_dep = 0;
while (m < end) {
/* Skip any "white space" */
while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
m++;
/* Find next "white space" */
p = m;
while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
p++;
/* Is the token we found a target name? */
is_target = (*(p-1) == ':');
/* Don't write any target names into the dependency file */
if (is_target) {
/* The /next/ file is the first dependency */
is_first_dep = 1;
} else {
/* Save this token/filename */
memcpy(s, m, p-m);
s[p - m] = 0;
/* Ignore certain dependencies */
if (strrcmp(s, "include/generated/autoconf.h") &&
strrcmp(s, "arch/um/include/uml-config.h") &&
strrcmp(s, "include/linux/kconfig.h") &&
strrcmp(s, ".ver")) {
/*
* Do not list the source file as dependency,
* so that kbuild is not confused if a .c file
* is rewritten into .S or vice versa. Storing
* it in source_* is needed for modpost to
* compute srcversions.
*/
if (is_first_dep) {
/*
* If processing the concatenation of
* multiple dependency files, only
* process the first target name, which
* will be the original source name,
* and ignore any other target names,
* which will be intermediate temporary
* files.
*/
if (!saw_any_target) {
saw_any_target = 1;
printf("source_%s := %s\n\n",
target, s);
printf("deps_%s := \\\n",
target);
}
is_first_dep = 0;
} else
printf(" %s \\\n", s);
do_config_file(s);
}
}
/*
* Start searching for next token immediately after the first
* "whitespace" character that follows this token.
*/
m = p + 1;
}
if (!saw_any_target) {
fprintf(stderr, "fixdep: parse error; no targets found\n");
exit(1);
}
printf("\n%s: $(deps_%s)\n\n", target, target);
printf("$(deps_%s):\n", target);
}
static void print_deps(void)
{
struct stat st;
int fd;
void *map;
fd = open(depfile, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "fixdep: error opening depfile: ");
perror(depfile);
exit(2);
}
if (fstat(fd, &st) < 0) {
fprintf(stderr, "fixdep: error fstat'ing depfile: ");
perror(depfile);
exit(2);
}
if (st.st_size == 0) {
fprintf(stderr,"fixdep: %s is empty\n",depfile);
close(fd);
return;
}
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if ((long) map == -1) {
perror("fixdep: mmap");
close(fd);
return;
}
parse_dep_file(map, st.st_size);
munmap(map, st.st_size);
close(fd);
}
static void traps(void)
{
static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
int *p = (int *)test;
if (*p != INT_CONF) {
fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianness? %#x\n",
*p);
exit(2);
}
}
int main(int argc, char *argv[])
{
traps();
if (argc != 4)
usage();
depfile = argv[1];
target = argv[2];
cmdline = argv[3];
/* hack for U-Boot */
if (!strncmp(target, "spl/", 4) || !strncmp(target, "tpl/", 4))
is_spl_build = 1;
print_cmdline();
print_deps();
return 0;
}

36
scripts/bin2c.c Normal file
View File

@@ -0,0 +1,36 @@
/*
* Unloved program to convert a binary on stdin to a C include on stdout
*
* Jan 1999 Matt Mackall <mpm@selenic.com>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include <stdio.h>
int main(int argc, char *argv[])
{
int ch, total = 0;
if (argc > 1)
printf("const char %s[] %s=\n",
argv[1], argc > 2 ? argv[2] : "");
do {
printf("\t\"");
while ((ch = getchar()) != EOF) {
total++;
printf("\\x%02x", ch);
if (total % 16 == 0)
break;
}
printf("\"\n");
} while (ch != EOF);
if (argc > 1)
printf("\t;\n\n#include <linux/types.h>\n\nconst size_t %s_size = %d;\n",
argv[1], total);
return 0;
}

23
scripts/binutils-version.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
#
# binutils-version [-p] gas-command
#
# Prints the binutils version of `gas-command' in a canonical 4-digit form
# such as `0222' for binutils 2.22
#
gas="$*"
if [ ${#gas} -eq 0 ]; then
echo "Error: No assembler specified."
printf "Usage:\n\t$0 <gas-command>\n"
exit 1
fi
version_string=$($gas --version | head -1 | \
sed -e 's/(.*)//; s/[^0-9.]*\([0-9.]*\).*/\1/')
MAJOR=$(echo $version_string | cut -d . -f 1)
MINOR=$(echo $version_string | cut -d . -f 2)
printf "%02d%02d\\n" $MAJOR $MINOR

62
scripts/build-whitelist.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/sh
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# This script creates the configuration whitelist file. This file contains
# all the config options which are allowed to be used outside Kconfig.
# Please do not add things to the whitelist. Instead, add your new option
# to Kconfig.
#
export LC_ALL=C LC_COLLATE=C
# There are two independent greps. The first pulls out the component parts
# of CONFIG_SYS_EXTRA_OPTIONS. An example is:
#
# SUN7I_GMAC,AHCI,SATAPWR=SUNXI_GPB(8)
#
# We want this to produce:
# CONFIG_SUN7I_GMAC
# CONFIG_AHCI
# CONFIG_SATAPWR
#
# The second looks for the rest of the CONFIG options, but excludes those in
# Kconfig and defconfig files.
#
(
git grep CONFIG_SYS_EXTRA_OPTIONS |sed -n \
's/.*CONFIG_SYS_EXTRA_OPTIONS="\(.*\)"/\1/ p' \
| tr , '\n' \
| sed 's/ *\([A-Za-z0-9_]*\).*/CONFIG_\1/'
git grep CONFIG_ | \
egrep -vi "(Kconfig:|defconfig:|README|\.py|\.pl:)" \
| tr ' \t' '\n\n' \
| sed -n 's/^\(CONFIG_[A-Za-z0-9_]*\).*/\1/p'
) \
|sort |uniq >scripts/config_whitelist.txt.tmp1;
# Finally, we need a list of the valid Kconfig options to exclude these from
# the whitelist.
cat `find . -name "Kconfig*"` |sed -n \
-e 's/^\s*config *\([A-Za-z0-9_]*\).*$/CONFIG_\1/p' \
-e 's/^\s*menuconfig *\([A-Za-z0-9_]*\).*$/CONFIG_\1/p' \
|sort |uniq >scripts/config_whitelist.txt.tmp2
# Use only the options that are present in the first file but not the second.
comm -23 scripts/config_whitelist.txt.tmp1 scripts/config_whitelist.txt.tmp2 \
|sort |uniq >scripts/config_whitelist.txt.tmp3
# If scripts/config_whitelist.txt already exists, take the intersection of the
# current list and the new one. We do not want to increase whitelist options.
if [ -r scripts/config_whitelist.txt ]; then
comm -12 scripts/config_whitelist.txt.tmp3 scripts/config_whitelist.txt \
> scripts/config_whitelist.txt.tmp4
mv scripts/config_whitelist.txt.tmp4 scripts/config_whitelist.txt
else
mv scripts/config_whitelist.txt.tmp3 scripts/config_whitelist.txt
fi
rm scripts/config_whitelist.txt.tmp*
unset LC_ALL LC_COLLATE

203
scripts/build_OID_registry Executable file
View File

@@ -0,0 +1,203 @@
#!/usr/bin/perl -w
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Build a static ASN.1 Object Identified (OID) registry
#
# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
# Written by David Howells (dhowells@redhat.com)
#
use strict;
my @names = ();
my @oids = ();
if ($#ARGV != 1) {
print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
exit(2);
}
#
# Open the file to read from
#
open IN_FILE, "<$ARGV[0]" || die;
while (<IN_FILE>) {
chomp;
if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {
push @names, $1;
push @oids, $2;
}
}
close IN_FILE || die;
#
# Open the files to write into
#
open C_FILE, ">$ARGV[1]" or die;
print C_FILE "/*\n";
print C_FILE " * Automatically generated by ", $0, ". Do not edit\n";
print C_FILE " */\n";
#
# Split the data up into separate lists and also determine the lengths of the
# encoded data arrays.
#
my @indices = ();
my @lengths = ();
my $total_length = 0;
for (my $i = 0; $i <= $#names; $i++) {
my $name = $names[$i];
my $oid = $oids[$i];
my @components = split(/[.]/, $oid);
# Determine the encoded length of this OID
my $size = $#components;
for (my $loop = 2; $loop <= $#components; $loop++) {
my $c = $components[$loop];
# We will base128 encode the number
my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
$tmp = int($tmp / 7);
$size += $tmp;
}
push @lengths, $size;
push @indices, $total_length;
$total_length += $size;
}
#
# Emit the look-up-by-OID index table
#
print C_FILE "\n";
if ($total_length <= 255) {
print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";
} else {
print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";
}
for (my $i = 0; $i <= $#names; $i++) {
print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"
}
print C_FILE "\t[OID__NR] = ", $total_length, "\n";
print C_FILE "};\n";
#
# Encode the OIDs
#
my @encoded_oids = ();
for (my $i = 0; $i <= $#names; $i++) {
my @octets = ();
my @components = split(/[.]/, $oids[$i]);
push @octets, $components[0] * 40 + $components[1];
for (my $loop = 2; $loop <= $#components; $loop++) {
my $c = $components[$loop];
# Base128 encode the number
my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
$tmp = int($tmp / 7);
for (; $tmp > 0; $tmp--) {
push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
}
push @octets, $c & 0x7f;
}
push @encoded_oids, \@octets;
}
#
# Create a hash value for each OID
#
my @hash_values = ();
for (my $i = 0; $i <= $#names; $i++) {
my @octets = @{$encoded_oids[$i]};
my $hash = $#octets;
foreach (@octets) {
$hash += $_ * 33;
}
$hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);
push @hash_values, $hash & 0xff;
}
#
# Emit the OID data
#
print C_FILE "\n";
print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";
for (my $i = 0; $i <= $#names; $i++) {
my @octets = @{$encoded_oids[$i]};
print C_FILE "\t";
print C_FILE $_, ", " foreach (@octets);
print C_FILE "\t// ", $names[$i];
print C_FILE "\n";
}
print C_FILE "};\n";
#
# Build the search index table (ordered by length then hash then content)
#
my @index_table = ( 0 .. $#names );
@index_table = sort {
my @octets_a = @{$encoded_oids[$a]};
my @octets_b = @{$encoded_oids[$b]};
return $hash_values[$a] <=> $hash_values[$b]
if ($hash_values[$a] != $hash_values[$b]);
return $#octets_a <=> $#octets_b
if ($#octets_a != $#octets_b);
for (my $i = $#octets_a; $i >= 0; $i--) {
return $octets_a[$i] <=> $octets_b[$i]
if ($octets_a[$i] != $octets_b[$i]);
}
return 0;
} @index_table;
#
# Emit the search index and hash value table
#
print C_FILE "\n";
print C_FILE "static const struct {\n";
print C_FILE "\tunsigned char hash;\n";
if ($#names <= 255) {
print C_FILE "\tenum OID oid : 8;\n";
} else {
print C_FILE "\tenum OID oid : 16;\n";
}
print C_FILE "} oid_search_table[OID__NR] = {\n";
for (my $i = 0; $i <= $#names; $i++) {
my @octets = @{$encoded_oids[$index_table[$i]]};
printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",
$i,
$hash_values[$index_table[$i]],
$names[$index_table[$i]]);
printf C_FILE "%02x", $_ foreach (@octets);
print C_FILE "\n";
}
print C_FILE "};\n";
#
# Emit the OID debugging name table
#
#print C_FILE "\n";
#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";
#
#for (my $i = 0; $i <= $#names; $i++) {
# print C_FILE "\t\"", $names[$i], "\",\n"
#}
#print C_FILE "\t\"Unknown-OID\"\n";
#print C_FILE "};\n";
#
# Polish off
#
close C_FILE or die;

63
scripts/check-config.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/sh
# Copyright (c) 2016 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# Check that the u-boot.cfg file provided does not introduce any new
# ad-hoc CONFIG options
#
# Use scripts/build-whitelist.sh to generate the list of current ad-hoc
# CONFIG options (those which are not in Kconfig).
# Usage
# check-config.sh <path to u-boot.cfg> <path to whitelist file> <source dir>
#
# For example:
# scripts/check-config.sh b/chromebook_link/u-boot.cfg kconfig_whitelist.txt .
set -e
set -u
PROG_NAME="${0##*/}"
usage() {
echo "$PROG_NAME <path to u-boot.cfg> <path to whitelist file> <source dir>"
exit 1
}
[ $# -ge 3 ] || usage
path="$1"
whitelist="$2"
srctree="$3"
# Temporary files
configs="${path}.configs"
suspects="${path}.suspects"
ok="${path}.ok"
new_adhoc="${path}.adhoc"
export LC_ALL=C
export LC_COLLATE=C
cat ${path} |sed -n 's/^#define \(CONFIG_[A-Za-z0-9_]*\).*/\1/p' |sort |uniq \
>${configs}
comm -23 ${configs} ${whitelist} > ${suspects}
cat `find ${srctree} -name "Kconfig*"` |sed -n \
-e 's/^\s*config *\([A-Za-z0-9_]*\).*$/CONFIG_\1/p' \
-e 's/^\s*menuconfig \([A-Za-z0-9_]*\).*$/CONFIG_\1/p' \
|sort |uniq > ${ok}
comm -23 ${suspects} ${ok} >${new_adhoc}
if [ -s ${new_adhoc} ]; then
echo >&2 "Error: You must add new CONFIG options using Kconfig"
echo >&2 "The following new ad-hoc CONFIG options were detected:"
cat >&2 ${new_adhoc}
echo >&2
echo >&2 "Please add these via Kconfig instead. Find a suitable Kconfig"
echo >&2 "file and add a 'config' or 'menuconfig' option."
# Don't delete the temporary files in case they are useful
exit 1
else
rm ${suspects} ${ok} ${new_adhoc}
fi

6794
scripts/checkpatch.pl Executable file

File diff suppressed because it is too large Load Diff

171
scripts/checkstack.pl Executable file
View File

@@ -0,0 +1,171 @@
#!/usr/bin/perl
# Check the stack usage of functions
#
# Copyright Joern Engel <joern@lazybastard.org>
# Inspired by Linus Torvalds
# Original idea maybe from Keith Owens
# s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
# Mips port by Juan Quintela <quintela@mandrakesoft.com>
# IA64 port via Andreas Dilger
# Arm port by Holger Schurig
# sh64 port by Paul Mundt
# Random bits by Matt Mackall <mpm@selenic.com>
# M68k port by Geert Uytterhoeven and Andreas Schwab
# AArch64, PARISC ports by Kyle McMartin
# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
#
# Usage:
# objdump -d vmlinux | scripts/checkstack.pl [arch]
#
# TODO : Port to all architectures (one regex per arch)
use strict;
# check for arch
#
# $re is used for two matches:
# $& (whole re) matches the complete objdump line with the stack growth
# $1 (first bracket) matches the size of the stack growth
#
# $dre is similar, but for dynamic stack redutions:
# $& (whole re) matches the complete objdump line with the stack growth
# $1 (first bracket) matches the dynamic amount of the stack growth
#
# use anything else and feel the pain ;)
my (@stack, $re, $dre, $x, $xs, $funcre);
{
my $arch = shift;
if ($arch eq "") {
$arch = `uname -m`;
chomp($arch);
}
$x = "[0-9a-f]"; # hex character
$xs = "[0-9a-f ]"; # hex character or space
$funcre = qr/^$x* <(.*)>:$/;
if ($arch eq 'aarch64') {
#ffffffc0006325cc: a9bb7bfd stp x29, x30, [sp,#-80]!
$re = qr/^.*stp.*sp,\#-([0-9]{1,8})\]\!/o;
} elsif ($arch eq 'arm') {
#c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64
$re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
} elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) {
#c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp
# or
# 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
$re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o;
$dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o;
} elsif ($arch eq 'ia64') {
#e0000000044011fc: 01 0f fc 8c adds r12=-384,r12
$re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
} elsif ($arch eq 'm68k') {
# 2b6c: 4e56 fb70 linkw %fp,#-1168
# 1df770: defc ffe4 addaw #-28,%sp
$re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o;
} elsif ($arch eq 'metag') {
#400026fc: 40 00 00 82 ADD A0StP,A0StP,#0x8
$re = qr/.*ADD.*A0StP,A0StP,\#(0x$x{1,8})/o;
$funcre = qr/^$x* <[^\$](.*)>:$/;
} elsif ($arch eq 'mips64') {
#8800402c: 67bdfff0 daddiu sp,sp,-16
$re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
} elsif ($arch eq 'mips') {
#88003254: 27bdffe0 addiu sp,sp,-32
$re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
} elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
$re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
} elsif ($arch eq 'ppc') {
#c00029f4: 94 21 ff 30 stwu r1,-208(r1)
$re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
} elsif ($arch eq 'ppc64') {
#XXX
$re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
} elsif ($arch eq 'powerpc') {
$re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
} elsif ($arch =~ /^s390x?$/) {
# 11160: a7 fb ff 60 aghi %r15,-160
# or
# 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15)
$re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
(?:\(\%r15\))?$/ox;
} elsif ($arch =~ /^sh64$/) {
#XXX: we only check for the immediate case presently,
# though we will want to check for the movi/sub
# pair for larger users. -- PFM.
#a00048e0: d4fc40f0 addi.l r15,-240,r15
$re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
} elsif ($arch =~ /^blackfin$/) {
# 0: 00 e8 38 01 LINK 0x4e0;
$re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o;
} elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
# f0019d10: 9d e3 bf 90 save %sp, -112, %sp
$re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
} else {
print("wrong or unknown architecture \"$arch\"\n");
exit
}
}
#
# main()
#
my ($func, $file, $lastslash);
while (my $line = <STDIN>) {
if ($line =~ m/$funcre/) {
$func = $1;
}
elsif ($line =~ m/(.*):\s*file format/) {
$file = $1;
$file =~ s/\.ko//;
$lastslash = rindex($file, "/");
if ($lastslash != -1) {
$file = substr($file, $lastslash + 1);
}
}
elsif ($line =~ m/$re/) {
my $size = $1;
$size = hex($size) if ($size =~ /^0x/);
if ($size > 0xf0000000) {
$size = - $size;
$size += 0x80000000;
$size += 0x80000000;
}
next if ($size > 0x10000000);
next if $line !~ m/^($xs*)/;
my $addr = $1;
$addr =~ s/ /0/g;
$addr = "0x$addr";
my $intro = "$addr $func [$file]:";
my $padlen = 56 - length($intro);
while ($padlen > 0) {
$intro .= ' ';
$padlen -= 8;
}
next if ($size < 100);
push @stack, "$intro$size\n";
}
elsif (defined $dre && $line =~ m/$dre/) {
my $size = "Dynamic ($1)";
next if $line !~ m/^($xs*)/;
my $addr = $1;
$addr =~ s/ /0/g;
$addr = "0x$addr";
my $intro = "$addr $func [$file]:";
my $padlen = 56 - length($intro);
while ($padlen > 0) {
$intro .= ' ';
$padlen -= 8;
}
push @stack, "$intro$size\n";
}
}
# Sort output by size (last field)
print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;

258
scripts/cleanpatch Executable file
View File

@@ -0,0 +1,258 @@
#!/usr/bin/perl -w
#
# Clean a patch file -- or directory of patch files -- of stealth whitespace.
# WARNING: this can be a highly destructive operation. Use with caution.
#
use bytes;
use File::Basename;
# Default options
$max_width = 79;
# Clean up space-tab sequences, either by removing spaces or
# replacing them with tabs.
sub clean_space_tabs($)
{
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($lo) = '';
my $pos = 0;
my $nsp = 0;
my($i, $c);
for ($i = 0; $i < length($li); $i++) {
$c = substr($li, $i, 1);
if ($c eq "\t") {
my $npos = ($pos+$nsp+8) & ~7;
my $ntab = ($npos >> 3) - ($pos >> 3);
$lo .= "\t" x $ntab;
$pos = $npos;
$nsp = 0;
} elsif ($c eq "\n" || $c eq "\r") {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos = 0;
} elsif ($c eq " ") {
$nsp++;
} else {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos++;
}
}
$lo .= " " x $nsp;
return $lo;
}
# Compute the visual width of a string
sub strwidth($) {
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($c, $i);
my $pos = 0;
my $mlen = 0;
for ($i = 0; $i < length($li); $i++) {
$c = substr($li,$i,1);
if ($c eq "\t") {
$pos = ($pos+8) & ~7;
} elsif ($c eq "\n") {
$mlen = $pos if ($pos > $mlen);
$pos = 0;
} else {
$pos++;
}
}
$mlen = $pos if ($pos > $mlen);
return $mlen;
}
$name = basename($0);
@files = ();
while (defined($a = shift(@ARGV))) {
if ($a =~ /^-/) {
if ($a eq '-width' || $a eq '-w') {
$max_width = shift(@ARGV)+0;
} else {
print STDERR "Usage: $name [-width #] files...\n";
exit 1;
}
} else {
push(@files, $a);
}
}
foreach $f ( @files ) {
print STDERR "$name: $f\n";
if (! -f $f) {
print STDERR "$f: not a file\n";
next;
}
if (!open(FILE, '+<', $f)) {
print STDERR "$name: Cannot open file: $f: $!\n";
next;
}
binmode FILE;
# First, verify that it is not a binary file; consider any file
# with a zero byte to be a binary file. Is there any better, or
# additional, heuristic that should be applied?
$is_binary = 0;
while (read(FILE, $data, 65536) > 0) {
if ($data =~ /\0/) {
$is_binary = 1;
last;
}
}
if ($is_binary) {
print STDERR "$name: $f: binary file\n";
next;
}
seek(FILE, 0, 0);
$in_bytes = 0;
$out_bytes = 0;
$lineno = 0;
@lines = ();
$in_hunk = 0;
$err = 0;
while ( defined($line = <FILE>) ) {
$lineno++;
$in_bytes += length($line);
if (!$in_hunk) {
if ($line =~
/^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
$minus_lines = $2;
$plus_lines = $4;
if ($minus_lines || $plus_lines) {
$in_hunk = 1;
@hunk_lines = ($line);
}
} else {
push(@lines, $line);
$out_bytes += length($line);
}
} else {
# We're in a hunk
if ($line =~ /^\+/) {
$plus_lines--;
$text = substr($line, 1);
$text =~ s/[ \t\r]*$//; # Remove trailing spaces
$text = clean_space_tabs($text);
$l_width = strwidth($text);
if ($max_width && $l_width > $max_width) {
print STDERR
"$f:$lineno: adds line exceeds $max_width ",
"characters ($l_width)\n";
}
push(@hunk_lines, '+'.$text);
} elsif ($line =~ /^\-/) {
$minus_lines--;
push(@hunk_lines, $line);
} elsif ($line =~ /^ /) {
$plus_lines--;
$minus_lines--;
push(@hunk_lines, $line);
} else {
print STDERR "$name: $f: malformed patch\n";
$err = 1;
last;
}
if ($plus_lines < 0 || $minus_lines < 0) {
print STDERR "$name: $f: malformed patch\n";
$err = 1;
last;
} elsif ($plus_lines == 0 && $minus_lines == 0) {
# End of a hunk. Process this hunk.
my $i;
my $l;
my @h = ();
my $adj = 0;
my $done = 0;
for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
$l = $hunk_lines[$i];
if (!$done && $l eq "+\n") {
$adj++; # Skip this line
} elsif ($l =~ /^[ +]/) {
$done = 1;
unshift(@h, $l);
} else {
unshift(@h, $l);
}
}
$l = $hunk_lines[0]; # Hunk header
undef @hunk_lines; # Free memory
if ($adj) {
die unless
($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
my $mstart = $1;
my $mlin = $2;
my $pstart = $3;
my $plin = $4;
my $tail = $5; # doesn't include the final newline
$l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
$mstart, $mlin, $pstart, $plin-$adj,
$tail);
}
unshift(@h, $l);
# Transfer to the output array
foreach $l (@h) {
$out_bytes += length($l);
push(@lines, $l);
}
$in_hunk = 0;
}
}
}
if ($in_hunk) {
print STDERR "$name: $f: malformed patch\n";
$err = 1;
}
if (!$err) {
if ($in_bytes != $out_bytes) {
# Only write to the file if changed
seek(FILE, 0, 0);
print FILE @lines;
if ( !defined($where = tell(FILE)) ||
!truncate(FILE, $where) ) {
die "$name: Failed to truncate modified file: $f: $!\n";
}
}
}
close(FILE);
}

256
scripts/coccicheck Executable file
View File

@@ -0,0 +1,256 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Linux kernel coccicheck
#
# Read doc/README.coccinelle
#
# This script requires at least spatch
# version 1.0.0-rc11.
DIR="$(dirname $(readlink -f $0))/.."
SPATCH="`which ${SPATCH:=spatch}`"
if [ ! -x "$SPATCH" ]; then
echo 'spatch is part of the Coccinelle project and is available at http://coccinelle.lip6.fr/'
exit 1
fi
SPATCH_VERSION=$($SPATCH --version | head -1 | awk '{print $3}')
SPATCH_VERSION_NUM=$(echo $SPATCH_VERSION | ${DIR}/scripts/ld-version.sh)
USE_JOBS="no"
$SPATCH --help | grep "\-\-jobs" > /dev/null && USE_JOBS="yes"
# The verbosity may be set by the environmental parameter V=
# as for example with 'make V=1 coccicheck'
if [ -n "$V" -a "$V" != "0" ]; then
VERBOSE="$V"
else
VERBOSE=0
fi
if [ -z "$J" ]; then
NPROC=$(getconf _NPROCESSORS_ONLN)
else
NPROC="$J"
fi
FLAGS="--very-quiet"
# You can use SPFLAGS to append extra arguments to coccicheck or override any
# heuristics done in this file as Coccinelle accepts the last options when
# options conflict.
#
# A good example for use of SPFLAGS is if you want to debug your cocci script,
# you can for instance use the following:
#
# $ export COCCI=scripts/coccinelle/misc/irqf_oneshot.cocci
# $ make coccicheck MODE=report DEBUG_FILE="all.err" SPFLAGS="--profile --show-trying" M=./drivers/mfd/arizona-irq.c
#
# "--show-trying" should show you what rule is being processed as it goes to
# stdout, you do not need a debug file for that. The profile output will be
# be sent to stdout, if you provide a DEBUG_FILE the profiling data can be
# inspected there.
#
# --profile will not output if --very-quiet is used, so avoid it.
echo $SPFLAGS | egrep -e "--profile|--show-trying" 2>&1 > /dev/null
if [ $? -eq 0 ]; then
FLAGS="--quiet"
fi
# spatch only allows include directories with the syntax "-I include"
# while gcc also allows "-Iinclude" and "-include include"
COCCIINCLUDE=${LINUXINCLUDE//-I/-I }
COCCIINCLUDE=${COCCIINCLUDE// -include/ --include}
if [ "$C" = "1" -o "$C" = "2" ]; then
ONLINE=1
# Take only the last argument, which is the C file to test
shift $(( $# - 1 ))
OPTIONS="$COCCIINCLUDE $1"
else
ONLINE=0
if [ "$KBUILD_EXTMOD" = "" ] ; then
OPTIONS="--dir $srctree $COCCIINCLUDE"
else
OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
fi
fi
if [ "$KBUILD_EXTMOD" != "" ] ; then
OPTIONS="--patch $srctree $OPTIONS"
fi
# You can override by using SPFLAGS
if [ "$USE_JOBS" = "no" ]; then
trap kill_running SIGTERM SIGINT
declare -a SPATCH_PID
elif [ "$NPROC" != "1" ]; then
# Using 0 should work as well, refer to _SC_NPROCESSORS_ONLN use on
# https://github.com/rdicosmo/parmap/blob/master/setcore_stubs.c
OPTIONS="$OPTIONS --jobs $NPROC --chunksize 1"
fi
if [ "$MODE" = "" ] ; then
if [ "$ONLINE" = "0" ] ; then
echo 'You have not explicitly specified the mode to use. Using default "report" mode.'
echo 'Available modes are the following: patch, report, context, org'
echo 'You can specify the mode with "make coccicheck MODE=<mode>"'
echo 'Note however that some modes are not implemented by some semantic patches.'
fi
MODE="report"
fi
if [ "$MODE" = "chain" ] ; then
if [ "$ONLINE" = "0" ] ; then
echo 'You have selected the "chain" mode.'
echo 'All available modes will be tried (in that order): patch, report, context, org'
fi
elif [ "$MODE" = "report" -o "$MODE" = "org" ] ; then
FLAGS="--no-show-diff $FLAGS"
fi
if [ "$ONLINE" = "0" ] ; then
echo ''
echo 'Please check for false positives in the output before submitting a patch.'
echo 'When using "patch" mode, carefully review the patch before submitting it.'
echo ''
fi
run_cmd_parmap() {
if [ $VERBOSE -ne 0 ] ; then
echo "Running ($NPROC in parallel): $@"
fi
if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
if [ -f $DEBUG_FILE ]; then
echo "Debug file $DEBUG_FILE exists, bailing"
exit
fi
else
DEBUG_FILE="/dev/null"
fi
$@ 2>$DEBUG_FILE
if [[ $? -ne 0 ]]; then
echo "coccicheck failed"
exit $?
fi
}
run_cmd_old() {
local i
if [ $VERBOSE -ne 0 ] ; then
echo "Running ($NPROC in parallel): $@"
fi
for i in $(seq 0 $(( NPROC - 1)) ); do
eval "$@ --max $NPROC --index $i &"
SPATCH_PID[$i]=$!
if [ $VERBOSE -eq 2 ] ; then
echo "${SPATCH_PID[$i]} running"
fi
done
wait
}
run_cmd() {
if [ "$USE_JOBS" = "yes" ]; then
run_cmd_parmap $@
else
run_cmd_old $@
fi
}
kill_running() {
for i in $(seq 0 $(( NPROC - 1 )) ); do
if [ $VERBOSE -eq 2 ] ; then
echo "Killing ${SPATCH_PID[$i]}"
fi
kill ${SPATCH_PID[$i]} 2>/dev/null
done
}
# You can override heuristics with SPFLAGS, these must always go last
OPTIONS="$OPTIONS $SPFLAGS"
coccinelle () {
COCCI="$1"
OPT=`grep "Option" $COCCI | cut -d':' -f2`
REQ=`grep "Requires" $COCCI | cut -d':' -f2 | sed "s| ||"`
REQ_NUM=$(echo $REQ | ${DIR}/scripts/ld-version.sh)
if [ "$REQ_NUM" != "0" ] ; then
if [ "$SPATCH_VERSION_NUM" -lt "$REQ_NUM" ] ; then
echo "Skipping coccinele SmPL patch: $COCCI"
echo "You have coccinelle: $SPATCH_VERSION"
echo "This SmPL patch requires: $REQ"
return
fi
fi
# The option '--parse-cocci' can be used to syntactically check the SmPL files.
#
# $SPATCH -D $MODE $FLAGS -parse_cocci $COCCI $OPT > /dev/null
if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then
FILE=`echo $COCCI | sed "s|$srctree/||"`
echo "Processing `basename $COCCI`"
echo "with option(s) \"$OPT\""
echo ''
echo 'Message example to submit a patch:'
sed -ne 's|^///||p' $COCCI
if [ "$MODE" = "patch" ] ; then
echo ' The semantic patch that makes this change is available'
elif [ "$MODE" = "report" ] ; then
echo ' The semantic patch that makes this report is available'
elif [ "$MODE" = "context" ] ; then
echo ' The semantic patch that spots this code is available'
elif [ "$MODE" = "org" ] ; then
echo ' The semantic patch that makes this Org report is available'
else
echo ' The semantic patch that makes this output is available'
fi
echo " in $FILE."
echo ''
echo ' More information about semantic patching is available at'
echo ' http://coccinelle.lip6.fr/'
echo ''
if [ "`sed -ne 's|^//#||p' $COCCI`" ] ; then
echo 'Semantic patch information:'
sed -ne 's|^//#||p' $COCCI
echo ''
fi
fi
if [ "$MODE" = "chain" ] ; then
run_cmd $SPATCH -D patch \
$FLAGS --cocci-file $COCCI $OPT $OPTIONS || \
run_cmd $SPATCH -D report \
$FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || \
run_cmd $SPATCH -D context \
$FLAGS --cocci-file $COCCI $OPT $OPTIONS || \
run_cmd $SPATCH -D org \
$FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff || exit 1
elif [ "$MODE" = "rep+ctxt" ] ; then
run_cmd $SPATCH -D report \
$FLAGS --cocci-file $COCCI $OPT $OPTIONS --no-show-diff && \
run_cmd $SPATCH -D context \
$FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
else
run_cmd $SPATCH -D $MODE $FLAGS --cocci-file $COCCI $OPT $OPTIONS || exit 1
fi
}
if [ "$COCCI" = "" ] ; then
for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
coccinelle $f
done
else
coccinelle $COCCI
fi

View File

@@ -0,0 +1,59 @@
/// NULL check before some freeing functions is not needed.
///
/// Based on checkpatch warning
/// "kfree(NULL) is safe this check is probably not required"
/// and kfreeaddr.cocci by Julia Lawall.
///
// Copyright: (C) 2014 Fabian Frederick. GPLv2.
// Comments: -
// Options: --no-includes --include-headers
virtual patch
virtual org
virtual report
virtual context
@r2 depends on patch@
expression E;
@@
- if (E != NULL)
(
kfree(E);
|
kzfree(E);
|
debugfs_remove(E);
|
debugfs_remove_recursive(E);
|
usb_free_urb(E);
|
kmem_cache_destroy(E);
|
mempool_destroy(E);
|
dma_pool_destroy(E);
)
@r depends on context || report || org @
expression E;
position p;
@@
* if (E != NULL)
* \(kfree@p\|kzfree@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|
* usb_free_urb@p\|kmem_cache_destroy@p\|mempool_destroy@p\|
* dma_pool_destroy@p\)(E);
@script:python depends on org@
p << r.p;
@@
cocci.print_main("NULL check before that freeing function is not needed", p)
@script:python depends on report@
p << r.p;
@@
msg = "WARNING: NULL check before freeing functions like kfree, debugfs_remove, debugfs_remove_recursive or usb_free_urb is not needed. Maybe consider reorganizing relevant code to avoid passing NULL values."
coccilib.report.print_report(p[0], msg)

View File

@@ -0,0 +1,94 @@
/// Many iterators have the property that the first argument is always bound
/// to a real list element, never NULL.
//# False positives arise for some iterators that do not have this property,
//# or in cases when the loop cursor is reassigned. The latter should only
//# happen when the matched code is on the way to a loop exit (break, goto,
//# or return).
///
// Confidence: Moderate
// Copyright: (C) 2010-2012 Nicolas Palix. GPLv2.
// Copyright: (C) 2010-2012 Julia Lawall, INRIA/LIP6. GPLv2.
// Copyright: (C) 2010-2012 Gilles Muller, INRIA/LiP6. GPLv2.
// URL: http://coccinelle.lip6.fr/
// Comments:
// Options: --no-includes --include-headers
virtual patch
virtual context
virtual org
virtual report
@depends on patch@
iterator I;
expression x,E,E1,E2;
statement S,S1,S2;
@@
I(x,...) { <...
(
- if (x == NULL && ...) S
|
- if (x != NULL || ...)
S
|
- (x == NULL) ||
E
|
- (x != NULL) &&
E
|
- (x == NULL && ...) ? E1 :
E2
|
- (x != NULL || ...) ?
E1
- : E2
|
- if (x == NULL && ...) S1 else
S2
|
- if (x != NULL || ...)
S1
- else S2
|
+ BAD(
x == NULL
+ )
|
+ BAD(
x != NULL
+ )
)
...> }
@r depends on !patch exists@
iterator I;
expression x,E;
position p1,p2;
@@
*I@p1(x,...)
{ ... when != x = E
(
* x@p2 == NULL
|
* x@p2 != NULL
)
... when any
}
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("iterator-bound variable",p1)
cocci.print_secs("useless NULL test",p2)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "ERROR: iterator variable bound on line %s cannot be NULL" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)

View File

@@ -0,0 +1,62 @@
/// list_for_each_entry uses its first argument to get from one element of
/// the list to the next, so it is usually not a good idea to reassign it.
/// The first rule finds such a reassignment and the second rule checks
/// that there is a path from the reassignment back to the top of the loop.
///
// Confidence: High
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
// URL: http://coccinelle.lip6.fr/
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r@
iterator name list_for_each_entry;
expression x,E;
position p1,p2;
@@
list_for_each_entry@p1(x,...) { <... x =@p2 E ...> }
@depends on context && !org && !report@
expression x,E;
position r.p1,r.p2;
statement S;
@@
*x =@p2 E
...
list_for_each_entry@p1(x,...) S
// ------------------------------------------------------------------------
@back depends on (org || report) && !context exists@
expression x,E;
position r.p1,r.p2;
statement S;
@@
x =@p2 E
...
list_for_each_entry@p1(x,...) S
@script:python depends on back && org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("iterator",p1)
cocci.print_secs("update",p2)
@script:python depends on back && report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "iterator with update on line %s" % (p2[0].line)
coccilib.report.print_report(p1[0],msg)

View File

@@ -0,0 +1,147 @@
/// If list_for_each_entry, etc complete a traversal of the list, the iterator
/// variable ends up pointing to an address at an offset from the list head,
/// and not a meaningful structure. Thus this value should not be used after
/// the end of the iterator.
//#False positives arise when there is a goto in the iterator and the
//#reported reference is at the label of this goto. Some flag tests
//#may also cause a report to be a false positive.
///
// Confidence: Moderate
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
// Copyright: (C) 2012 Gilles Muller, INRIA/LIP6. GPLv2.
// URL: http://coccinelle.lip6.fr/
// Comments:
// Options: --no-includes --include-headers
virtual context
virtual org
virtual report
@r exists@
identifier c,member;
expression E,x;
iterator name list_for_each_entry;
iterator name list_for_each_entry_reverse;
iterator name list_for_each_entry_continue;
iterator name list_for_each_entry_continue_reverse;
iterator name list_for_each_entry_from;
iterator name list_for_each_entry_safe;
iterator name list_for_each_entry_safe_continue;
iterator name list_for_each_entry_safe_from;
iterator name list_for_each_entry_safe_reverse;
iterator name hlist_for_each_entry;
iterator name hlist_for_each_entry_continue;
iterator name hlist_for_each_entry_from;
iterator name hlist_for_each_entry_safe;
statement S;
position p1,p2;
@@
(
list_for_each_entry@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_reverse@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_continue@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_continue_reverse@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_from@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe_continue@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe_from@p1(c,...,member) { ... when != break;
when forall
when strict
}
|
list_for_each_entry_safe_reverse@p1(c,...,member) { ... when != break;
when forall
when strict
}
)
...
(
list_for_each_entry(c,...) S
|
list_for_each_entry_reverse(c,...) S
|
list_for_each_entry_continue(c,...) S
|
list_for_each_entry_continue_reverse(c,...) S
|
list_for_each_entry_from(c,...) S
|
list_for_each_entry_safe(c,...) S
|
list_for_each_entry_safe(x,c,...) S
|
list_for_each_entry_safe_continue(c,...) S
|
list_for_each_entry_safe_continue(x,c,...) S
|
list_for_each_entry_safe_from(c,...) S
|
list_for_each_entry_safe_from(x,c,...) S
|
list_for_each_entry_safe_reverse(c,...) S
|
list_for_each_entry_safe_reverse(x,c,...) S
|
hlist_for_each_entry(c,...) S
|
hlist_for_each_entry_continue(c,...) S
|
hlist_for_each_entry_from(c,...) S
|
hlist_for_each_entry_safe(c,...) S
|
list_remove_head(x,c,...)
|
sizeof(<+...c...+>)
|
&c->member
|
c = E
|
*c@p2
)
@script:python depends on org@
p1 << r.p1;
p2 << r.p2;
@@
cocci.print_main("invalid iterator index reference",p2)
cocci.print_secs("iterator",p1)
@script:python depends on report@
p1 << r.p1;
p2 << r.p2;
@@
msg = "ERROR: invalid reference to the index variable of the iterator on line %s" % (p1[0].line)
coccilib.report.print_report(p2[0], msg)

View File

@@ -0,0 +1,76 @@
/// Use ARRAY_SIZE instead of dividing sizeof array with sizeof an element
///
//# This makes an effort to find cases where the argument to sizeof is wrong
//# in memory allocation functions by checking the type of the allocated memory
//# when it is a double pointer and ensuring the sizeof argument takes a pointer
//# to the the memory being allocated. There are false positives in cases the
//# sizeof argument is not used in constructing the return value. The result
//# may need some reformatting.
//
// Confidence: Moderate
// Copyright: (C) 2014 Himangi Saraogi. GPLv2.
// Comments:
// Options:
virtual patch
virtual context
virtual org
virtual report
//----------------------------------------------------------
// For context mode
//----------------------------------------------------------
@depends on context disable sizeof_type_expr@
type T;
T **x;
@@
x =
<+...sizeof(
* T
)...+>
//----------------------------------------------------------
// For patch mode
//----------------------------------------------------------
@depends on patch disable sizeof_type_expr@
type T;
T **x;
@@
x =
<+...sizeof(
- T
+ *x
)...+>
//----------------------------------------------------------
// For org and report mode
//----------------------------------------------------------
@r depends on (org || report) disable sizeof_type_expr@
type T;
T **x;
position p;
@@
x =
<+...sizeof(
T@p
)...+>
@script:python depends on org@
p << r.p;
@@
coccilib.org.print_todo(p[0], "WARNING sizeof argument should be pointer type, not structure type")
@script:python depends on report@
p << r.p;
@@
msg="WARNING: Use correct pointer type argument for sizeof"
coccilib.report.print_report(p[0], msg)

View File

@@ -0,0 +1,142 @@
/// Use mdio_alloc and mdio_register instead of miiphy_register
///
//# Stop using the oldest mii interface in drivers
//
// Confidence: High
// Copyright: (C) 2016 Joe Hershberger. GPLv2.
// Comments:
// Options: --include-headers --recursive-includes --local-includes -I include
@ mii_reg @
expression devname;
identifier readfunc, writefunc;
@@
+ int retval;
- miiphy_register(devname, readfunc, writefunc);
+ struct mii_dev *mdiodev = mdio_alloc();
+ if (!mdiodev) return -ENOMEM;
+ strncpy(mdiodev->name, devname, MDIO_NAME_LEN);
+ mdiodev->read = readfunc;
+ mdiodev->write = writefunc;
+
+ retval = mdio_register(mdiodev);
+ if (retval < 0) return retval;
@ update_read_sig @
identifier mii_reg.readfunc;
identifier name0, addr0, reg0, output;
type addrT, outputT;
@@
- readfunc (
- const char *name0,
- addrT addr0,
- addrT reg0,
- outputT *output
- )
+ readfunc (
+ struct mii_dev *bus,
+ int addr0,
+ int devad,
+ int reg0
+ )
{
...
}
@ update_read_impl @
identifier mii_reg.readfunc;
identifier update_read_sig.output;
type update_read_sig.outputT;
constant c;
identifier retvar;
expression E;
@@
readfunc (...)
{
+ outputT output = 0;
...
(
- return 0;
+ return *output;
|
return c;
|
- return retvar;
+ if (retvar < 0)
+ return retvar;
+ return *output;
|
- return E;
+ int retval = E;
+ if (retval < 0)
+ return retval;
+ return *output;
)
}
@ update_read_impl2 @
identifier mii_reg.readfunc;
identifier update_read_sig.output;
@@
readfunc (...)
{
<...
(
- *output
+ output
|
- output
+ &output
)
...>
}
@ update_read_name @
identifier mii_reg.readfunc;
identifier update_read_sig.name0;
@@
readfunc (...) {
<...
- name0
+ bus->name
...>
}
@ update_write_sig @
identifier mii_reg.writefunc;
identifier name0, addr0, reg0, value0;
type addrT, valueT;
typedef u16;
@@
- writefunc (
- const char *name0,
- addrT addr0,
- addrT reg0,
- valueT value0
- )
+ writefunc (
+ struct mii_dev *bus,
+ int addr0,
+ int devad,
+ int reg0,
+ u16 value0
+ )
{
...
}
@ update_write_name @
identifier mii_reg.writefunc;
identifier update_write_sig.name0;
@@
writefunc (...) {
<...
- name0
+ bus->name
...>
}

View File

@@ -0,0 +1,241 @@
/// Compare pointer-typed values to NULL rather than 0
///
//# This makes an effort to choose between !x and x == NULL. !x is used
//# if it has previously been used with the function used to initialize x.
//# This relies on type information. More type information can be obtained
//# using the option -all_includes and the option -I to specify an
//# include path.
//
// Confidence: High
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2.
// URL: http://coccinelle.lip6.fr/
// Requires: 1.0.0
// Options:
//
// SPDX-License-Identifier: GPL-2.0
//
virtual patch
virtual context
virtual org
virtual report
@initialize:ocaml@
@@
let negtable = Hashtbl.create 101
@depends on patch@
expression *E;
identifier f;
@@
(
(E = f(...)) ==
- 0
+ NULL
|
(E = f(...)) !=
- 0
+ NULL
|
- 0
+ NULL
== (E = f(...))
|
- 0
+ NULL
!= (E = f(...))
)
@t1 depends on !patch@
expression *E;
identifier f;
position p;
@@
(
(E = f(...)) ==
* 0@p
|
(E = f(...)) !=
* 0@p
|
* 0@p
== (E = f(...))
|
* 0@p
!= (E = f(...))
)
@script:python depends on org@
p << t1.p;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
@script:python depends on report@
p << t1.p;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
// Tests of returned values
@s@
identifier f;
expression E,E1;
@@
E = f(...)
... when != E = E1
!E
@script:ocaml depends on s@
f << s.f;
@@
try let _ = Hashtbl.find negtable f in ()
with Not_found -> Hashtbl.add negtable f ()
@ r disable is_zero,isnt_zero exists @
expression *E;
identifier f;
@@
E = f(...)
...
(E == 0
|E != 0
|0 == E
|0 != E
)
@script:ocaml@
f << r.f;
@@
try let _ = Hashtbl.find negtable f in ()
with Not_found -> include_match false
// This rule may lead to inconsistent path problems, if E is defined in two
// places
@ depends on patch disable is_zero,isnt_zero @
expression *E;
expression E1;
identifier r.f;
@@
E = f(...)
<...
(
- E == 0
+ !E
|
- E != 0
+ E
|
- 0 == E
+ !E
|
- 0 != E
+ E
)
...>
?E = E1
@t2 depends on !patch disable is_zero,isnt_zero @
expression *E;
expression E1;
identifier r.f;
position p1;
position p2;
@@
E = f(...)
<...
(
* E == 0@p1
|
* E != 0@p2
|
* 0@p1 == E
|
* 0@p1 != E
)
...>
?E = E1
@script:python depends on org@
p << t2.p1;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0, suggest !E")
@script:python depends on org@
p << t2.p2;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
@script:python depends on report@
p << t2.p1;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0, suggest !E")
@script:python depends on report@
p << t2.p2;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")
@ depends on patch disable is_zero,isnt_zero @
expression *E;
@@
(
E ==
- 0
+ NULL
|
E !=
- 0
+ NULL
|
- 0
+ NULL
== E
|
- 0
+ NULL
!= E
)
@ t3 depends on !patch disable is_zero,isnt_zero @
expression *E;
position p;
@@
(
* E == 0@p
|
* E != 0@p
|
* 0@p == E
|
* 0@p != E
)
@script:python depends on org@
p << t3.p;
@@
coccilib.org.print_todo(p[0], "WARNING comparing pointer to 0")
@script:python depends on report@
p << t3.p;
@@
coccilib.report.print_report(p[0], "WARNING comparing pointer to 0")

View File

@@ -0,0 +1,75 @@
/// This semantic patch looks for malloc etc that are not followed by a
/// NULL check. It only gives a report in the case where there is some
/// error handling code later in the function, which may be helpful
/// in determining what the error handling code for the call to malloc etc
/// should be.
///
// Confidence: High
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
// Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2.
// URL: http://coccinelle.lip6.fr/
// Comments:
// Options: --no-includes --include-headers
//
// SPDX-License-Identifier: GPL-2.0
//
virtual context
virtual org
virtual report
@withtest@
expression x;
position p;
identifier f,fld;
@@
x@p = f(...);
... when != x->fld
\(x == NULL \| x != NULL\)
@fixed depends on context && !org && !report@
expression x,x1;
position p1 != withtest.p;
statement S;
position any withtest.p;
identifier f;
@@
*x@p1 = \(malloc\|calloc\)(...);
...
*x1@p = f(...);
if (!x1) S
// ------------------------------------------------------------------------
@rfixed depends on (org || report) && !context exists@
expression x,x1;
position p1 != withtest.p;
position p2;
statement S;
position any withtest.p;
identifier f;
@@
x@p1 = \(malloc\|calloc\)(...);
...
x1@p = f@p2(...);
if (!x1) S
@script:python depends on org@
p1 << rfixed.p1;
p2 << rfixed.p2;
@@
cocci.print_main("alloc call",p1)
cocci.print_secs("possible model",p2)
@script:python depends on report@
p1 << rfixed.p1;
p2 << rfixed.p2;
@@
msg = "alloc with no test, possible model on line %s" % (p2[0].line)
coccilib.report.print_report(p1[0],msg)

4342
scripts/config_whitelist.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
# Put structs here that should be constant
__dummy__

15
scripts/coreboot.sed Normal file
View File

@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2016 Google, Inc
# Script to convert coreboot code to something similar to what U-Boot uses
# sed -f coreboot.sed <coreboot_file.c>
# Remember to add attribution to coreboot for new files added to U-Boot.
s/REG_RES_WRITE32(\(.*\), \(.*\), \(.*\)),/writel(\3, base + \2);/
s/REG_RES_POLL32(\(.*\), \(.*\), \(.*\), \(.*\), \(.*\)),/ret = poll32(base + \2, \3, \4, \5);/
s/REG_RES_OR32(\(.*\), \(.*\), \(.*\)),/setbits_le32(base + \2, \3);/
s/REG_RES_RMW32(\(.*\), \(.*\), \(.*\), \(.*\)),/clrsetbits_le32(base + \2, ~\3, \4);/
/REG_SCRIPT_END/d
s/read32/readl/
s/write32(\(.*\), \(.*\))/writel(\2, \1)/
s/conf->/plat->/
s/static const struct reg_script \(.*\)_script\[\] = {/static int \1(struct udevice *dev)/

125
scripts/decodecode Executable file
View File

@@ -0,0 +1,125 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Disassemble the Code: line in Linux oopses
# usage: decodecode < oops.file
#
# options: set env. variable AFLAGS=options to pass options to "as";
# e.g., to decode an i386 oops on an x86_64 system, use:
# AFLAGS=--32 decodecode < 386.oops
cleanup() {
rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
exit 1
}
die() {
echo "$@"
exit 1
}
trap cleanup EXIT
T=`mktemp` || die "cannot create temp file"
code=
cont=
while read i ; do
case "$i" in
*Code:*)
code=$i
cont=yes
;;
*)
[ -n "$cont" ] && {
xdump="$(echo $i | grep '^[[:xdigit:]<>[:space:]]\+$')"
if [ -n "$xdump" ]; then
code="$code $xdump"
else
cont=
fi
}
;;
esac
done
if [ -z "$code" ]; then
rm $T
exit
fi
echo $code
code=`echo $code | sed -e 's/.*Code: //'`
width=`expr index "$code" ' '`
width=$((($width-1)/2))
case $width in
1) type=byte ;;
2) type=2byte ;;
4) type=4byte ;;
esac
disas() {
${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s > /dev/null 2>&1
if [ "$ARCH" = "arm" ]; then
if [ $width -eq 2 ]; then
OBJDUMPFLAGS="-M force-thumb"
fi
${CROSS_COMPILE}strip $1.o
fi
if [ "$ARCH" = "arm64" ]; then
if [ $width -eq 4 ]; then
type=inst
fi
${CROSS_COMPILE}strip $1.o
fi
${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \
grep -v "/tmp\|Disassembly\|\.text\|^$" > $1.dis 2>&1
}
marker=`expr index "$code" "\<"`
if [ $marker -eq 0 ]; then
marker=`expr index "$code" "\("`
fi
touch $T.oo
if [ $marker -ne 0 ]; then
echo All code >> $T.oo
echo ======== >> $T.oo
beforemark=`echo "$code"`
echo -n " .$type 0x" > $T.s
echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
disas $T
cat $T.dis >> $T.oo
rm -f $T.o $T.s $T.dis
# and fix code at-and-after marker
code=`echo "$code" | cut -c$((${marker} + 1))-`
fi
echo Code starting with the faulting instruction > $T.aa
echo =========================================== >> $T.aa
code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
echo -n " .$type 0x" > $T.s
echo $code >> $T.s
disas $T
cat $T.dis >> $T.aa
# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is
# special)
faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \
$(wc -l $T.aa | cut -d" " -f1) + 3))
faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
cat $T.oo | sed -e "${faultlinenum}s/^\(.*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
echo
cat $T.aa
cleanup

21
scripts/dtc-version.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/sh
#
# dtc-version dtc-command
#
# Prints the dtc version of `dtc-command' in a canonical 6-digit form
# such as `010404' for dtc 1.4.4
#
dtc="$*"
if [ ${#dtc} -eq 0 ]; then
echo "Error: No dtc command specified."
printf "Usage:\n\t$0 <dtc-command>\n"
exit 1
fi
MAJOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 1)
MINOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 2)
PATCH=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 3 | cut -d - -f 1)
printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCH

1
scripts/dtc/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/dtc

32
scripts/dtc/Makefile Normal file
View File

@@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0
# scripts/dtc makefile
hostprogs-y := dtc
always := $(hostprogs-y)
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
srcpos.o checks.o util.o
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
HOSTCFLAGS_DTC := -I$(src) -I$(src)/libfdt
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-lexer.lex.o: $(obj)/dtc-parser.tab.h
# Added for U-Boot
subdir-$(CONFIG_PYLIBFDT) += pylibfdt

18
scripts/dtc/Makefile.dtc Normal file
View File

@@ -0,0 +1,18 @@
# Makefile.dtc
#
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
#
DTC_SRCS = \
checks.c \
data.c \
dtc.c \
flattree.c \
fstree.c \
livetree.c \
srcpos.c \
treesource.c \
util.c
DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)

1506
scripts/dtc/checks.c Normal file

File diff suppressed because it is too large Load Diff

269
scripts/dtc/data.c Normal file
View File

@@ -0,0 +1,269 @@
/*
* (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"
void data_free(struct data d)
{
struct marker *m, *nm;
m = d.markers;
while (m) {
nm = m->next;
free(m->ref);
free(m);
m = nm;
}
if (d.val)
free(d.val);
}
struct data data_grow_for(struct data d, int xlen)
{
struct data nd;
int newsize;
if (xlen == 0)
return d;
nd = d;
newsize = xlen;
while ((d.len + xlen) > newsize)
newsize *= 2;
nd.val = xrealloc(d.val, newsize);
return nd;
}
struct data data_copy_mem(const char *mem, int len)
{
struct data d;
d = data_grow_for(empty_data, len);
d.len = len;
memcpy(d.val, mem, len);
return d;
}
struct data data_copy_escape_string(const char *s, int len)
{
int i = 0;
struct data d;
char *q;
d = data_grow_for(empty_data, len + 1);
q = d.val;
while (i < len) {
char c = s[i++];
if (c == '\\')
c = get_escape_char(s, &i);
q[d.len++] = c;
}
q[d.len++] = '\0';
return d;
}
struct data data_copy_file(FILE *f, size_t maxlen)
{
struct data d = empty_data;
while (!feof(f) && (d.len < maxlen)) {
size_t chunksize, ret;
if (maxlen == -1)
chunksize = 4096;
else
chunksize = maxlen - d.len;
d = data_grow_for(d, chunksize);
ret = fread(d.val + d.len, 1, chunksize, f);
if (ferror(f))
die("Error reading file into data: %s", strerror(errno));
if (d.len + ret < d.len)
die("Overflow reading file into data\n");
d.len += ret;
}
return d;
}
struct data data_append_data(struct data d, const void *p, int len)
{
d = data_grow_for(d, len);
memcpy(d.val + d.len, p, len);
d.len += len;
return d;
}
struct data data_insert_at_marker(struct data d, struct marker *m,
const void *p, int len)
{
d = data_grow_for(d, len);
memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
memcpy(d.val + m->offset, p, len);
d.len += len;
/* Adjust all markers after the one we're inserting at */
m = m->next;
for_each_marker(m)
m->offset += len;
return d;
}
static struct data data_append_markers(struct data d, struct marker *m)
{
struct marker **mp = &d.markers;
/* Find the end of the markerlist */
while (*mp)
mp = &((*mp)->next);
*mp = m;
return d;
}
struct data data_merge(struct data d1, struct data d2)
{
struct data d;
struct marker *m2 = d2.markers;
d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
/* Adjust for the length of d1 */
for_each_marker(m2)
m2->offset += d1.len;
d2.markers = NULL; /* So data_free() doesn't clobber them */
data_free(d2);
return d;
}
struct data data_append_integer(struct data d, uint64_t value, int bits)
{
uint8_t value_8;
fdt16_t value_16;
fdt32_t value_32;
fdt64_t value_64;
switch (bits) {
case 8:
value_8 = value;
return data_append_data(d, &value_8, 1);
case 16:
value_16 = cpu_to_fdt16(value);
return data_append_data(d, &value_16, 2);
case 32:
value_32 = cpu_to_fdt32(value);
return data_append_data(d, &value_32, 4);
case 64:
value_64 = cpu_to_fdt64(value);
return data_append_data(d, &value_64, 8);
default:
die("Invalid literal size (%d)\n", bits);
}
}
struct data data_append_re(struct data d, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry re;
re.address = cpu_to_fdt64(address);
re.size = cpu_to_fdt64(size);
return data_append_data(d, &re, sizeof(re));
}
struct data data_append_cell(struct data d, cell_t word)
{
return data_append_integer(d, word, sizeof(word) * 8);
}
struct data data_append_addr(struct data d, uint64_t addr)
{
return data_append_integer(d, addr, sizeof(addr) * 8);
}
struct data data_append_byte(struct data d, uint8_t byte)
{
return data_append_data(d, &byte, 1);
}
struct data data_append_zeroes(struct data d, int len)
{
d = data_grow_for(d, len);
memset(d.val + d.len, 0, len);
d.len += len;
return d;
}
struct data data_append_align(struct data d, int align)
{
int newlen = ALIGN(d.len, align);
return data_append_zeroes(d, newlen - d.len);
}
struct data data_add_marker(struct data d, enum markertype type, char *ref)
{
struct marker *m;
m = xmalloc(sizeof(*m));
m->offset = d.len;
m->type = type;
m->ref = ref;
m->next = NULL;
return data_append_markers(d, m);
}
bool data_is_one_string(struct data d)
{
int i;
int len = d.len;
if (len == 0)
return false;
for (i = 0; i < len-1; i++)
if (d.val[i] == '\0')
return false;
if (d.val[len-1] != '\0')
return false;
return true;
}

306
scripts/dtc/dtc-lexer.l Normal file
View File

@@ -0,0 +1,306 @@
/*
* (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
%x BYTESTRING
%x PROPNODENAME
%s V1
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
PATHCHAR ({PROPNODECHAR}|[/])
LABEL [a-zA-Z_][a-zA-Z0-9_]*
STRING \"([^\\"]|\\.)*\"
CHAR_LITERAL '([^']|\\')*'
WS [[:space:]]
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
LINECOMMENT "//".*\n
%{
#include "dtc.h"
#include "srcpos.h"
#include "dtc-parser.tab.h"
YYLTYPE yylloc;
extern bool treesource_error;
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
#define YY_USER_ACTION \
{ \
srcpos_update(&yylloc, yytext, yyleng); \
}
/*#define LEXDEBUG 1*/
#ifdef LEXDEBUG
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
#define DPRINT(fmt, ...) do { } while (0)
#endif
static int dts_version = 1;
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
BEGIN(V1); \
static void push_input_file(const char *filename);
static bool pop_input_file(void);
static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
%}
%%
<*>"/include/"{WS}*{STRING} {
char *name = strchr(yytext, '\"') + 1;
yytext[yyleng-1] = '\0';
push_input_file(name);
}
<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
char *line, *fnstart, *fnend;
struct data fn;
/* skip text before line # */
line = yytext;
while (!isdigit((unsigned char)*line))
line++;
/* regexp ensures that first and list "
* in the whole yytext are those at
* beginning and end of the filename string */
fnstart = memchr(yytext, '"', yyleng);
for (fnend = yytext + yyleng - 1;
*fnend != '"'; fnend--)
;
assert(fnstart && fnend && (fnend > fnstart));
fn = data_copy_escape_string(fnstart + 1,
fnend - fnstart - 1);
/* Don't allow nuls in filenames */
if (memchr(fn.val, '\0', fn.len - 1))
lexical_error("nul in line number directive");
/* -1 since #line is the number of the next line */
srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
data_free(fn);
}
<*><<EOF>> {
if (!pop_input_file()) {
yyterminate();
}
}
<*>{STRING} {
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
yyleng-2);
return DT_STRING;
}
<*>"/dts-v1/" {
DPRINT("Keyword: /dts-v1/\n");
dts_version = 1;
BEGIN_DEFAULT();
return DT_V1;
}
<*>"/plugin/" {
DPRINT("Keyword: /plugin/\n");
return DT_PLUGIN;
}
<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
return DT_MEMRESERVE;
}
<*>"/bits/" {
DPRINT("Keyword: /bits/\n");
BEGIN_DEFAULT();
return DT_BITS;
}
<*>"/delete-property/" {
DPRINT("Keyword: /delete-property/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_DEL_PROP;
}
<*>"/delete-node/" {
DPRINT("Keyword: /delete-node/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_DEL_NODE;
}
<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
yylval.labelref[yyleng-1] = '\0';
return DT_LABEL;
}
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
char *e;
DPRINT("Integer Literal: '%s'\n", yytext);
errno = 0;
yylval.integer = strtoull(yytext, &e, 0);
if (*e && e[strspn(e, "UL")]) {
lexical_error("Bad integer literal '%s'",
yytext);
}
if (errno == ERANGE)
lexical_error("Integer literal '%s' out of range",
yytext);
else
/* ERANGE is the only strtoull error triggerable
* by strings matching the pattern */
assert(errno == 0);
return DT_LITERAL;
}
<*>{CHAR_LITERAL} {
struct data d;
DPRINT("Character literal: %s\n", yytext);
d = data_copy_escape_string(yytext+1, yyleng-2);
if (d.len == 1) {
lexical_error("Empty character literal");
yylval.integer = 0;
} else {
yylval.integer = (unsigned char)d.val[0];
if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
}
data_free(d);
return DT_CHAR_LITERAL;
}
<*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_REF;
}
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
return DT_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
<BYTESTRING>"]" {
DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT();
return ']';
}
<PROPNODENAME>\\?{PROPNODECHAR}+ {
DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = xstrdup((yytext[0] == '\\') ?
yytext + 1 : yytext);
BEGIN_DEFAULT();
return DT_PROPNODENAME;
}
"/incbin/" {
DPRINT("Binary Include\n");
return DT_INCBIN;
}
<*>{WS}+ /* eat whitespace */
<*>{COMMENT}+ /* eat C-style comments */
<*>{LINECOMMENT}+ /* eat C++-style comments */
<*>"<<" { return DT_LSHIFT; };
<*>">>" { return DT_RSHIFT; };
<*>"<=" { return DT_LE; };
<*>">=" { return DT_GE; };
<*>"==" { return DT_EQ; };
<*>"!=" { return DT_NE; };
<*>"&&" { return DT_AND; };
<*>"||" { return DT_OR; };
<*>. {
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
if (yytext[0] == '[') {
DPRINT("<BYTESTRING>\n");
BEGIN(BYTESTRING);
}
if ((yytext[0] == '{')
|| (yytext[0] == ';')) {
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
}
return yytext[0];
}
%%
static void push_input_file(const char *filename)
{
assert(filename);
srcfile_push(filename);
yyin = current_srcfile->f;
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
}
static bool pop_input_file(void)
{
if (srcfile_pop() == 0)
return false;
yypop_buffer_state();
yyin = current_srcfile->f;
return true;
}
static void lexical_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
srcpos_verror(&yylloc, "Lexical error", fmt, ap);
va_end(ap);
treesource_error = true;
}

538
scripts/dtc/dtc-parser.y Normal file
View File

@@ -0,0 +1,538 @@
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%{
#include <stdio.h>
#include <inttypes.h>
#include "dtc.h"
#include "srcpos.h"
extern int yylex(void);
extern void yyerror(char const *s);
#define ERROR(loc, ...) \
do { \
srcpos_error((loc), "Error", __VA_ARGS__); \
treesource_error = true; \
} while (0)
extern struct dt_info *parser_output;
extern bool treesource_error;
%}
%union {
char *propnodename;
char *labelref;
uint8_t byte;
struct data data;
struct {
struct data data;
int bits;
} array;
struct property *prop;
struct property *proplist;
struct node *node;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
}
%token DT_V1
%token DT_PLUGIN
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
%token DT_DEL_PROP
%token DT_DEL_NODE
%token <propnodename> DT_PROPNODENAME
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
%token DT_INCBIN
%type <data> propdata
%type <data> propdataprefix
%type <flags> header
%type <flags> headers
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <node> devicetree
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
%type <integer> integer_prim
%type <integer> integer_unary
%type <integer> integer_mul
%type <integer> integer_add
%type <integer> integer_shift
%type <integer> integer_rela
%type <integer> integer_eq
%type <integer> integer_bitand
%type <integer> integer_bitxor
%type <integer> integer_bitor
%type <integer> integer_and
%type <integer> integer_or
%type <integer> integer_trinary
%type <integer> integer_expr
%%
sourcefile:
headers memreserves devicetree
{
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3));
}
;
header:
DT_V1 ';'
{
$$ = DTSF_V1;
}
| DT_V1 ';' DT_PLUGIN ';'
{
$$ = DTSF_V1 | DTSF_PLUGIN;
}
;
headers:
header
| header headers
{
if ($2 != $1)
ERROR(&@2, "Header flags don't match earlier ones");
$$ = $1;
}
;
memreserves:
/* empty */
{
$$ = NULL;
}
| memreserve memreserves
{
$$ = chain_reserve_entry($1, $2);
}
;
memreserve:
DT_MEMRESERVE integer_prim integer_prim ';'
{
$$ = build_reserve_entry($2, $3);
}
| DT_LABEL memreserve
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
devicetree:
'/' nodedef
{
$$ = name_node($2, "");
}
| devicetree '/' nodedef
{
$$ = merge_nodes($1, $3);
}
| DT_REF nodedef
{
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
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);
}
| devicetree DT_LABEL DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $3);
if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
} else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
| devicetree DT_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);
if (target)
delete_node(target);
else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
;
nodedef:
'{' proplist subnodes '}' ';'
{
$$ = build_node($2, $3);
}
;
proplist:
/* empty */
{
$$ = NULL;
}
| proplist propdef
{
$$ = chain_property($2, $1);
}
;
propdef:
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
}
| DT_PROPNODENAME ';'
{
$$ = build_property($1, empty_data);
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
}
| DT_LABEL propdef
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
propdata:
propdataprefix DT_STRING
{
$$ = data_merge($1, $2);
}
| propdataprefix arrayprefix '>'
{
$$ = data_merge($1, $2.data);
}
| propdataprefix '[' bytestring ']'
{
$$ = data_merge($1, $3);
}
| propdataprefix DT_REF
{
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d;
if ($6 != 0)
if (fseek(f, $6, SEEK_SET) != 0)
die("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6, $4.val,
strerror(errno));
d = data_copy_file(f, $8);
$$ = data_merge($1, d);
fclose(f);
}
| propdataprefix DT_INCBIN '(' DT_STRING ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d = empty_data;
d = data_copy_file(f, -1);
$$ = data_merge($1, d);
fclose(f);
}
| propdata DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
propdataprefix:
/* empty */
{
$$ = empty_data;
}
| propdata ','
{
$$ = $1;
}
| propdataprefix DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
bits = $2;
if ((bits != 8) && (bits != 16) &&
(bits != 32) && (bits != 64)) {
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}
$$.data = empty_data;
$$.bits = bits;
}
| '<'
{
$$.data = empty_data;
$$.bits = 32;
}
| arrayprefix integer_prim
{
if ($1.bits < 64) {
uint64_t mask = (1ULL << $1.bits) - 1;
/*
* Bits above mask must either be all zero
* (positive within range of mask) or all one
* (negative and sign-extended). The second
* condition is true if when we set all bits
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
if (($2 > mask) && (($2 | mask) != -1ULL))
ERROR(&@2, "Value out of range for"
" %d-bit array element", $1.bits);
}
$$.data = data_append_integer($1.data, $2, $1.bits);
}
| arrayprefix DT_REF
{
uint64_t val = ~0ULL >> (64 - $1.bits);
if ($1.bits == 32)
$1.data = data_add_marker($1.data,
REF_PHANDLE,
$2);
else
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
$$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_LABEL
{
$$.data = data_add_marker($1.data, LABEL, $2);
}
;
integer_prim:
DT_LITERAL
| DT_CHAR_LITERAL
| '(' integer_expr ')'
{
$$ = $2;
}
;
integer_expr:
integer_trinary
;
integer_trinary:
integer_or
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
;
integer_or:
integer_and
| integer_or DT_OR integer_and { $$ = $1 || $3; }
;
integer_and:
integer_bitor
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
;
integer_bitor:
integer_bitxor
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
;
integer_bitxor:
integer_bitand
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
;
integer_bitand:
integer_eq
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
;
integer_eq:
integer_rela
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
;
integer_rela:
integer_shift
| integer_rela '<' integer_shift { $$ = $1 < $3; }
| integer_rela '>' integer_shift { $$ = $1 > $3; }
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
;
integer_shift:
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
| integer_add
;
integer_add:
integer_add '+' integer_mul { $$ = $1 + $3; }
| integer_add '-' integer_mul { $$ = $1 - $3; }
| integer_mul
;
integer_mul:
integer_mul '*' integer_unary { $$ = $1 * $3; }
| integer_mul '/' integer_unary
{
if ($3 != 0) {
$$ = $1 / $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_mul '%' integer_unary
{
if ($3 != 0) {
$$ = $1 % $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_unary
;
integer_unary:
integer_prim
| '-' integer_unary { $$ = -$2; }
| '~' integer_unary { $$ = ~$2; }
| '!' integer_unary { $$ = !$2; }
;
bytestring:
/* empty */
{
$$ = empty_data;
}
| bytestring DT_BYTE
{
$$ = data_append_byte($1, $2);
}
| bytestring DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
subnodes:
/* empty */
{
$$ = NULL;
}
| subnode subnodes
{
$$ = chain_node($1, $2);
}
| subnode propdef
{
ERROR(&@2, "Properties must precede subnodes");
YYERROR;
}
;
subnode:
DT_PROPNODENAME nodedef
{
$$ = name_node($2, $1);
}
| DT_DEL_NODE DT_PROPNODENAME ';'
{
$$ = name_node(build_node_delete(), $2);
}
| DT_LABEL subnode
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
%%
void yyerror(char const *s)
{
ERROR(&yylloc, "%s", s);
}

364
scripts/dtc/dtc.c Normal file
View File

@@ -0,0 +1,364 @@
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <sys/stat.h>
#include "dtc.h"
#include "srcpos.h"
/*
* Command line options
*/
int quiet; /* Level of quietness */
int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
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 */
static int is_power_of_2(int x)
{
return (x > 0) && ((x & (x - 1)) == 0);
}
static void fill_fullpaths(struct node *tree, const char *prefix)
{
struct node *child;
const char *unit;
tree->fullpath = join_path(prefix, tree->name);
unit = strchr(tree->name, '@');
if (unit)
tree->basenamelen = unit - tree->name;
else
tree->basenamelen = strlen(tree->name);
for_each_child(tree, child)
fill_fullpaths(child, tree->fullpath);
}
/* 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 struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
{"out", a_argument, NULL, 'o'},
{"out-format", a_argument, NULL, 'O'},
{"out-version", a_argument, NULL, 'V'},
{"out-dependency", a_argument, NULL, 'd'},
{"reserve", a_argument, NULL, 'R'},
{"space", a_argument, NULL, 'S'},
{"pad", a_argument, NULL, 'p'},
{"align", a_argument, NULL, 'a'},
{"boot-cpu", a_argument, NULL, 'b'},
{"force", no_argument, NULL, 'f'},
{"include", a_argument, NULL, 'i'},
{"sort", no_argument, NULL, 's'},
{"phandle", a_argument, NULL, 'H'},
{"warning", a_argument, NULL, 'W'},
{"error", a_argument, NULL, 'E'},
{"symbols", no_argument, NULL, '@'},
{"auto-alias", no_argument, NULL, 'A'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
};
static const char * const usage_opts_help[] = {
"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
"\n\tInput formats are:\n"
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
"\t\tfs - /proc/device-tree style directory",
"\n\tOutput file",
"\n\tOutput formats are:\n"
"\t\tdts - device tree source text\n"
"\t\tdtb - device tree blob\n"
"\t\tasm - assembler source",
"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
"\n\tOutput dependency file",
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
"\n\tMake the blob at least <bytes> long (extra space)",
"\n\tAdd padding to the blob of <bytes> long (extra space)",
"\n\tMake the blob align to the <bytes> (extra space)",
"\n\tSet the physical boot cpu",
"\n\tTry to produce output even if the input tree has errors",
"\n\tAdd a path to search for include files",
"\n\tSort nodes and properties before outputting (useful for comparing trees)",
"\n\tValid phandle formats are:\n"
"\t\tlegacy - \"linux,phandle\" properties only\n"
"\t\tepapr - \"phandle\" properties only\n"
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
"\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tEnable generation of symbols",
"\n\tEnable auto-alias of labels",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
};
static const char *guess_type_by_name(const char *fname, const char *fallback)
{
const char *s;
s = strrchr(fname, '.');
if (s == NULL)
return fallback;
if (!strcasecmp(s, ".dts"))
return "dts";
if (!strcasecmp(s, ".dtb"))
return "dtb";
return fallback;
}
static const char *guess_input_format(const char *fname, const char *fallback)
{
struct stat statbuf;
fdt32_t magic;
FILE *f;
if (stat(fname, &statbuf) != 0)
return fallback;
if (S_ISDIR(statbuf.st_mode))
return "fs";
if (!S_ISREG(statbuf.st_mode))
return fallback;
f = fopen(fname, "r");
if (f == NULL)
return fallback;
if (fread(&magic, 4, 1, f) != 1) {
fclose(f);
return fallback;
}
fclose(f);
if (fdt32_to_cpu(magic) == FDT_MAGIC)
return "dtb";
return guess_type_by_name(fname, fallback);
}
int main(int argc, char *argv[])
{
struct dt_info *dti;
const char *inform = NULL;
const char *outform = NULL;
const char *outname = "-";
const char *depname = NULL;
bool force = false, sort = false;
const char *arg;
int opt;
FILE *outf = NULL;
int outversion = DEFAULT_FDT_VERSION;
long long cmdline_boot_cpuid = -1;
quiet = 0;
reservenum = 0;
minsize = 0;
padsize = 0;
alignsize = 0;
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
case 'I':
inform = optarg;
break;
case 'O':
outform = optarg;
break;
case 'o':
outname = optarg;
break;
case 'V':
outversion = strtol(optarg, NULL, 0);
break;
case 'd':
depname = optarg;
break;
case 'R':
reservenum = strtol(optarg, NULL, 0);
break;
case 'S':
minsize = strtol(optarg, NULL, 0);
break;
case 'p':
padsize = strtol(optarg, NULL, 0);
break;
case 'a':
alignsize = strtol(optarg, NULL, 0);
if (!is_power_of_2(alignsize))
die("Invalid argument \"%d\" to -a option\n",
alignsize);
break;
case 'f':
force = true;
break;
case 'q':
quiet++;
break;
case 'b':
cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
break;
case 'i':
srcfile_add_search_path(optarg);
break;
case 'v':
util_version();
case 'H':
if (streq(optarg, "legacy"))
phandle_format = PHANDLE_LEGACY;
else if (streq(optarg, "epapr"))
phandle_format = PHANDLE_EPAPR;
else if (streq(optarg, "both"))
phandle_format = PHANDLE_BOTH;
else
die("Invalid argument \"%s\" to -H option\n",
optarg);
break;
case 's':
sort = true;
break;
case 'W':
parse_checks_option(true, false, optarg);
break;
case 'E':
parse_checks_option(false, true, optarg);
break;
case '@':
generate_symbols = 1;
break;
case 'A':
auto_label_aliases = 1;
break;
case 'h':
usage(NULL);
default:
usage("unknown option");
}
}
if (argc > (optind+1))
usage("missing files");
else if (argc < (optind+1))
arg = "-";
else
arg = argv[optind];
/* minsize and padsize are mutually exclusive */
if (minsize && padsize)
die("Can't set both -p and -S\n");
if (depname) {
depfile = fopen(depname, "w");
if (!depfile)
die("Couldn't open dependency file %s: %s\n", depname,
strerror(errno));
fprintf(depfile, "%s:", outname);
}
if (inform == NULL)
inform = guess_input_format(arg, "dts");
if (outform == NULL) {
outform = guess_type_by_name(outname, NULL);
if (outform == NULL) {
if (streq(inform, "dts"))
outform = "dtb";
else
outform = "dts";
}
}
if (streq(inform, "dts"))
dti = dt_from_source(arg);
else if (streq(inform, "fs"))
dti = dt_from_fs(arg);
else if(streq(inform, "dtb"))
dti = dt_from_blob(arg);
else
die("Unknown input format \"%s\"\n", inform);
dti->outname = outname;
if (depfile) {
fputc('\n', depfile);
fclose(depfile);
}
if (cmdline_boot_cpuid != -1)
dti->boot_cpuid_phys = cmdline_boot_cpuid;
fill_fullpaths(dti->dt, "");
/* on a plugin, generate by default */
if (dti->dtsflags & DTSF_PLUGIN) {
generate_fixups = 1;
}
process_checks(force, dti);
if (auto_label_aliases)
generate_label_tree(dti, "aliases", false);
if (generate_symbols)
generate_label_tree(dti, "__symbols__", true);
if (generate_fixups) {
generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__");
}
if (sort)
sort_tree(dti);
if (streq(outname, "-")) {
outf = stdout;
} else {
outf = fopen(outname, "wb");
if (! outf)
die("Couldn't open output file %s: %s\n",
outname, strerror(errno));
}
if (streq(outform, "dts")) {
dt_to_source(outf, dti);
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) {
dt_to_asm(outf, dti, outversion);
} else if (streq(outform, "null")) {
/* do nothing */
} else {
die("Unknown output format \"%s\"\n", outform);
}
exit(0);
}

293
scripts/dtc/dtc.h Normal file
View File

@@ -0,0 +1,293 @@
#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>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <libfdt_env.h>
#include <fdt.h>
#include "util.h"
#ifdef DEBUG
#define debug(...) printf(__VA_ARGS__)
#else
#define debug(...)
#endif
#define DEFAULT_FDT_VERSION 17
/*
* Command line options
*/
extern int quiet; /* Level of quietness */
extern int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
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 */
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
#define PHANDLE_BOTH 0x3
typedef uint32_t cell_t;
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
/* Data blobs */
enum markertype {
REF_PHANDLE,
REF_PATH,
LABEL,
};
struct marker {
enum markertype type;
int offset;
char *ref;
struct marker *next;
};
struct data {
int len;
char *val;
struct marker *markers;
};
#define empty_data ((struct data){ 0 /* all .members = 0 or NULL */ })
#define for_each_marker(m) \
for (; (m); (m) = (m)->next)
#define for_each_marker_of_type(m, t) \
for_each_marker(m) \
if ((m)->type == (t))
void data_free(struct data d);
struct data data_grow_for(struct data d, int xlen);
struct data data_copy_mem(const char *mem, int len);
struct data data_copy_escape_string(const char *s, int len);
struct data data_copy_file(FILE *f, size_t len);
struct data data_append_data(struct data d, const void *p, int len);
struct data data_insert_at_marker(struct data d, struct marker *m,
const void *p, int len);
struct data data_merge(struct data d1, struct data d2);
struct data data_append_cell(struct data d, cell_t word);
struct data data_append_integer(struct data d, uint64_t word, int bits);
struct data data_append_re(struct data d, uint64_t address, uint64_t size);
struct data data_append_addr(struct data d, uint64_t addr);
struct data data_append_byte(struct data d, uint8_t byte);
struct data data_append_zeroes(struct data d, int len);
struct data data_append_align(struct data d, int align);
struct data data_add_marker(struct data d, enum markertype type, char *ref);
bool data_is_one_string(struct data d);
/* DT constraints */
#define MAX_PROPNAME_LEN 31
#define MAX_NODENAME_LEN 31
/* Live trees */
struct label {
bool deleted;
char *label;
struct label *next;
};
struct bus_type {
const char *name;
};
struct property {
bool deleted;
char *name;
struct data val;
struct property *next;
struct label *labels;
};
struct node {
bool deleted;
char *name;
struct property *proplist;
struct node *children;
struct node *parent;
struct node *next_sibling;
char *fullpath;
int basenamelen;
cell_t phandle;
int addr_cells, size_cells;
struct label *labels;
const struct bus_type *bus;
};
#define for_each_label_withdel(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next)
#define for_each_label(l0, l) \
for_each_label_withdel(l0, l) \
if (!(l)->deleted)
#define for_each_property_withdel(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next)
#define for_each_property(n, p) \
for_each_property_withdel(n, p) \
if (!(p)->deleted)
#define for_each_child_withdel(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
#define for_each_child(n, c) \
for_each_child_withdel(n, c) \
if (!(c)->deleted)
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_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 *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
struct node *add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
void delete_property(struct property *prop);
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);
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop);
cell_t propval_cell_n(struct property *prop, int n);
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename);
struct node *get_node_by_path(struct node *tree, const char *path);
struct node *get_node_by_label(struct node *tree, const char *label);
struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
struct node *get_node_by_ref(struct node *tree, const char *ref);
cell_t get_node_phandle(struct node *root, struct node *node);
uint32_t guess_boot_cpuid(struct node *tree);
/* Boot info (tree plus memreserve information */
struct reserve_info {
uint64_t address, size;
struct reserve_info *next;
struct label *labels;
};
struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
struct reserve_info *chain_reserve_entry(struct reserve_info *first,
struct reserve_info *list);
struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct reserve_info *new);
struct dt_info {
unsigned int dtsflags;
struct reserve_info *reservelist;
uint32_t boot_cpuid_phys;
struct node *dt; /* the device tree */
const char *outname; /* filename being written to, "-" for stdout */
};
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
#define DTSF_PLUGIN 0x0002 /* /plugin/ */
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti);
void generate_label_tree(struct dt_info *dti, char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, char *name);
void generate_local_fixups_tree(struct dt_info *dti, char *name);
/* Checks */
void parse_checks_option(bool warn, bool error, const char *arg);
void process_checks(bool force, struct dt_info *dti);
/* Flattened trees */
void dt_to_blob(FILE *f, struct dt_info *dti, int version);
void dt_to_asm(FILE *f, struct dt_info *dti, int version);
struct dt_info *dt_from_blob(const char *fname);
/* Tree source */
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);
/* FS trees */
struct dt_info *dt_from_fs(const char *dirname);
#endif /* DTC_H */

940
scripts/dtc/flattree.c Normal file
View File

@@ -0,0 +1,940 @@
/*
* (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"
#define FTF_FULLPATH 0x1
#define FTF_VARALIGN 0x2
#define FTF_NAMEPROPS 0x4
#define FTF_BOOTCPUID 0x8
#define FTF_STRTABSIZE 0x10
#define FTF_STRUCTSIZE 0x20
#define FTF_NOPS 0x40
static struct version_info {
int version;
int last_comp_version;
int hdr_size;
int flags;
} version_table[] = {
{1, 1, FDT_V1_SIZE,
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
{2, 1, FDT_V2_SIZE,
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
{3, 1, FDT_V3_SIZE,
FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
{16, 16, FDT_V3_SIZE,
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
{17, 16, FDT_V17_SIZE,
FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
};
struct emitter {
void (*cell)(void *, cell_t);
void (*string)(void *, const char *, int);
void (*align)(void *, int);
void (*data)(void *, struct data);
void (*beginnode)(void *, struct label *labels);
void (*endnode)(void *, struct label *labels);
void (*property)(void *, struct label *labels);
};
static void bin_emit_cell(void *e, cell_t val)
{
struct data *dtbuf = e;
*dtbuf = data_append_cell(*dtbuf, val);
}
static void bin_emit_string(void *e, const char *str, int len)
{
struct data *dtbuf = e;
if (len == 0)
len = strlen(str);
*dtbuf = data_append_data(*dtbuf, str, len);
*dtbuf = data_append_byte(*dtbuf, '\0');
}
static void bin_emit_align(void *e, int a)
{
struct data *dtbuf = e;
*dtbuf = data_append_align(*dtbuf, a);
}
static void bin_emit_data(void *e, struct data d)
{
struct data *dtbuf = e;
*dtbuf = data_append_data(*dtbuf, d.val, d.len);
}
static void bin_emit_beginnode(void *e, struct label *labels)
{
bin_emit_cell(e, FDT_BEGIN_NODE);
}
static void bin_emit_endnode(void *e, struct label *labels)
{
bin_emit_cell(e, FDT_END_NODE);
}
static void bin_emit_property(void *e, struct label *labels)
{
bin_emit_cell(e, FDT_PROP);
}
static struct emitter bin_emitter = {
.cell = bin_emit_cell,
.string = bin_emit_string,
.align = bin_emit_align,
.data = bin_emit_data,
.beginnode = bin_emit_beginnode,
.endnode = bin_emit_endnode,
.property = bin_emit_property,
};
static void emit_label(FILE *f, const char *prefix, const char *label)
{
fprintf(f, "\t.globl\t%s_%s\n", prefix, label);
fprintf(f, "%s_%s:\n", prefix, label);
fprintf(f, "_%s_%s:\n", prefix, label);
}
static void emit_offset_label(FILE *f, const char *label, int offset)
{
fprintf(f, "\t.globl\t%s\n", label);
fprintf(f, "%s\t= . + %d\n", label, offset);
}
#define ASM_EMIT_BELONG(f, fmt, ...) \
{ \
fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
}
static void asm_emit_cell(void *e, cell_t val)
{
FILE *f = e;
fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n",
(val >> 24) & 0xff, (val >> 16) & 0xff,
(val >> 8) & 0xff, val & 0xff);
}
static void asm_emit_string(void *e, const char *str, int len)
{
FILE *f = e;
if (len != 0)
fprintf(f, "\t.string\t\"%.*s\"\n", len, str);
else
fprintf(f, "\t.string\t\"%s\"\n", str);
}
static void asm_emit_align(void *e, int a)
{
FILE *f = e;
fprintf(f, "\t.balign\t%d, 0\n", a);
}
static void asm_emit_data(void *e, struct data d)
{
FILE *f = e;
int off = 0;
struct marker *m = d.markers;
for_each_marker_of_type(m, LABEL)
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))));
off += sizeof(uint32_t);
}
while ((d.len - off) >= 1) {
fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
off += 1;
}
assert(off == d.len);
}
static void asm_emit_beginnode(void *e, struct label *labels)
{
FILE *f = e;
struct label *l;
for_each_label(labels, l) {
fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", l->label);
}
fprintf(f, "\t/* FDT_BEGIN_NODE */\n");
asm_emit_cell(e, FDT_BEGIN_NODE);
}
static void asm_emit_endnode(void *e, struct label *labels)
{
FILE *f = e;
struct label *l;
fprintf(f, "\t/* FDT_END_NODE */\n");
asm_emit_cell(e, FDT_END_NODE);
for_each_label(labels, l) {
fprintf(f, "\t.globl\t%s_end\n", l->label);
fprintf(f, "%s_end:\n", l->label);
}
}
static void asm_emit_property(void *e, struct label *labels)
{
FILE *f = e;
struct label *l;
for_each_label(labels, l) {
fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", l->label);
}
fprintf(f, "\t/* FDT_PROP */\n");
asm_emit_cell(e, FDT_PROP);
}
static struct emitter asm_emitter = {
.cell = asm_emit_cell,
.string = asm_emit_string,
.align = asm_emit_align,
.data = asm_emit_data,
.beginnode = asm_emit_beginnode,
.endnode = asm_emit_endnode,
.property = asm_emit_property,
};
static int stringtable_insert(struct data *d, const char *str)
{
int i;
/* FIXME: do this more efficiently? */
for (i = 0; i < d->len; i++) {
if (streq(str, d->val + i))
return i;
}
*d = data_append_data(*d, str, strlen(str)+1);
return i;
}
static void flatten_tree(struct node *tree, struct emitter *emit,
void *etarget, struct data *strbuf,
struct version_info *vi)
{
struct property *prop;
struct node *child;
bool seen_name_prop = false;
if (tree->deleted)
return;
emit->beginnode(etarget, tree->labels);
if (vi->flags & FTF_FULLPATH)
emit->string(etarget, tree->fullpath, 0);
else
emit->string(etarget, tree->name, 0);
emit->align(etarget, sizeof(cell_t));
for_each_property(tree, prop) {
int nameoff;
if (streq(prop->name, "name"))
seen_name_prop = true;
nameoff = stringtable_insert(strbuf, prop->name);
emit->property(etarget, prop->labels);
emit->cell(etarget, prop->val.len);
emit->cell(etarget, nameoff);
if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8))
emit->align(etarget, 8);
emit->data(etarget, prop->val);
emit->align(etarget, sizeof(cell_t));
}
if ((vi->flags & FTF_NAMEPROPS) && !seen_name_prop) {
emit->property(etarget, NULL);
emit->cell(etarget, tree->basenamelen+1);
emit->cell(etarget, stringtable_insert(strbuf, "name"));
if ((vi->flags & FTF_VARALIGN) && ((tree->basenamelen+1) >= 8))
emit->align(etarget, 8);
emit->string(etarget, tree->name, tree->basenamelen);
emit->align(etarget, sizeof(cell_t));
}
for_each_child(tree, child) {
flatten_tree(child, emit, etarget, strbuf, vi);
}
emit->endnode(etarget, tree->labels);
}
static struct data flatten_reserve_list(struct reserve_info *reservelist,
struct version_info *vi)
{
struct reserve_info *re;
struct data d = empty_data;
int j;
for (re = reservelist; re; re = re->next) {
d = data_append_re(d, re->address, re->size);
}
/*
* Add additional reserved slots if the user asked for them.
*/
for (j = 0; j < reservenum; j++) {
d = data_append_re(d, 0, 0);
}
return d;
}
static void make_fdt_header(struct fdt_header *fdt,
struct version_info *vi,
int reservesize, int dtsize, int strsize,
int boot_cpuid_phys)
{
int reserve_off;
reservesize += sizeof(struct fdt_reserve_entry);
memset(fdt, 0xff, sizeof(*fdt));
fdt->magic = cpu_to_fdt32(FDT_MAGIC);
fdt->version = cpu_to_fdt32(vi->version);
fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
/* Reserve map should be doubleword aligned */
reserve_off = ALIGN(vi->hdr_size, 8);
fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
+ dtsize);
fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
if (vi->flags & FTF_BOOTCPUID)
fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
if (vi->flags & FTF_STRTABSIZE)
fdt->size_dt_strings = cpu_to_fdt32(strsize);
if (vi->flags & FTF_STRUCTSIZE)
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
}
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
int i;
struct data blob = empty_data;
struct data reservebuf = empty_data;
struct data dtbuf = empty_data;
struct data strbuf = empty_data;
struct fdt_header fdt;
int padlen = 0;
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
if (version_table[i].version == version)
vi = &version_table[i];
}
if (!vi)
die("Unknown device tree blob version %d\n", version);
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
bin_emit_cell(&dtbuf, FDT_END);
reservebuf = flatten_reserve_list(dti->reservelist, vi);
/* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
dti->boot_cpuid_phys);
/*
* If the user asked for more space than is used, adjust the totalsize.
*/
if (minsize > 0) {
padlen = minsize - fdt32_to_cpu(fdt.totalsize);
if (padlen < 0) {
padlen = 0;
if (quiet < 1)
fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
}
}
if (padsize > 0)
padlen = padsize;
if (alignsize > 0)
padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
- fdt32_to_cpu(fdt.totalsize);
if (padlen > 0) {
int tsize = fdt32_to_cpu(fdt.totalsize);
tsize += padlen;
fdt.totalsize = cpu_to_fdt32(tsize);
}
/*
* Assemble the blob: start with the header, add with alignment
* the reserve buffer, add the reserve map terminating zeroes,
* the device tree itself, and finally the strings.
*/
blob = data_append_data(blob, &fdt, vi->hdr_size);
blob = data_append_align(blob, 8);
blob = data_merge(blob, reservebuf);
blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
blob = data_merge(blob, dtbuf);
blob = data_merge(blob, strbuf);
/*
* If the user asked for more space than is used, pad out the blob.
*/
if (padlen > 0)
blob = data_append_zeroes(blob, padlen);
if (fwrite(blob.val, blob.len, 1, f) != 1) {
if (ferror(f))
die("Error writing device tree blob: %s\n",
strerror(errno));
else
die("Short write on device tree blob\n");
}
/*
* data_merge() frees the right-hand element so only the blob
* remains to be freed.
*/
data_free(blob);
}
static void dump_stringtable_asm(FILE *f, struct data strbuf)
{
const char *p;
int len;
p = strbuf.val;
while (p < (strbuf.val + strbuf.len)) {
len = strlen(p);
fprintf(f, "\t.string \"%s\"\n", p);
p += len+1;
}
}
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
int i;
struct data strbuf = empty_data;
struct reserve_info *re;
const char *symprefix = "dt";
for (i = 0; i < ARRAY_SIZE(version_table); i++) {
if (version_table[i].version == version)
vi = &version_table[i];
}
if (!vi)
die("Unknown device tree blob version %d\n", version);
fprintf(f, "/* autogenerated by dtc, do not edit */\n\n");
emit_label(f, symprefix, "blob_start");
emit_label(f, symprefix, "header");
fprintf(f, "\t/* magic */\n");
asm_emit_cell(f, FDT_MAGIC);
fprintf(f, "\t/* totalsize */\n");
ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* off_dt_struct */\n");
ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* off_dt_strings */\n");
ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* off_mem_rsvmap */\n");
ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start",
symprefix, symprefix);
fprintf(f, "\t/* version */\n");
asm_emit_cell(f, vi->version);
fprintf(f, "\t/* last_comp_version */\n");
asm_emit_cell(f, vi->last_comp_version);
if (vi->flags & FTF_BOOTCPUID) {
fprintf(f, "\t/* boot_cpuid_phys */\n");
asm_emit_cell(f, dti->boot_cpuid_phys);
}
if (vi->flags & FTF_STRTABSIZE) {
fprintf(f, "\t/* size_dt_strings */\n");
ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start",
symprefix, symprefix);
}
if (vi->flags & FTF_STRUCTSIZE) {
fprintf(f, "\t/* size_dt_struct */\n");
ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start",
symprefix, symprefix);
}
/*
* Reserve map entries.
* Align the reserve map to a doubleword boundary.
* Each entry is an (address, size) pair of u64 values.
* Always supply a zero-sized temination entry.
*/
asm_emit_align(f, 8);
emit_label(f, symprefix, "reserve_map");
fprintf(f, "/* Memory reserve map from source file */\n");
/*
* Use .long on high and low halfs of u64s to avoid .quad
* as it appears .quad isn't available in some assemblers.
*/
for (re = dti->reservelist; re; re = re->next) {
struct label *l;
for_each_label(re->labels, l) {
fprintf(f, "\t.globl\t%s\n", l->label);
fprintf(f, "%s:\n", l->label);
}
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->address >> 32));
ASM_EMIT_BELONG(f, "0x%08x",
(unsigned int)(re->address & 0xffffffff));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size >> 32));
ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->size & 0xffffffff));
}
for (i = 0; i < reservenum; i++) {
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
}
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
emit_label(f, symprefix, "struct_start");
flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
fprintf(f, "\t/* FDT_END */\n");
asm_emit_cell(f, FDT_END);
emit_label(f, symprefix, "struct_end");
emit_label(f, symprefix, "strings_start");
dump_stringtable_asm(f, strbuf);
emit_label(f, symprefix, "strings_end");
emit_label(f, symprefix, "blob_end");
/*
* If the user asked for more space than is used, pad it out.
*/
if (minsize > 0) {
fprintf(f, "\t.space\t%d - (_%s_blob_end - _%s_blob_start), 0\n",
minsize, symprefix, symprefix);
}
if (padsize > 0) {
fprintf(f, "\t.space\t%d, 0\n", padsize);
}
if (alignsize > 0)
asm_emit_align(f, alignsize);
emit_label(f, symprefix, "blob_abs_end");
data_free(strbuf);
}
struct inbuf {
char *base, *limit, *ptr;
};
static void inbuf_init(struct inbuf *inb, void *base, void *limit)
{
inb->base = base;
inb->limit = limit;
inb->ptr = inb->base;
}
static void flat_read_chunk(struct inbuf *inb, void *p, int len)
{
if ((inb->ptr + len) > inb->limit)
die("Premature end of data parsing flat device tree\n");
memcpy(p, inb->ptr, len);
inb->ptr += len;
}
static uint32_t flat_read_word(struct inbuf *inb)
{
fdt32_t val;
assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
flat_read_chunk(inb, &val, sizeof(val));
return fdt32_to_cpu(val);
}
static void flat_realign(struct inbuf *inb, int align)
{
int off = inb->ptr - inb->base;
inb->ptr = inb->base + ALIGN(off, align);
if (inb->ptr > inb->limit)
die("Premature end of data parsing flat device tree\n");
}
static char *flat_read_string(struct inbuf *inb)
{
int len = 0;
const char *p = inb->ptr;
char *str;
do {
if (p >= inb->limit)
die("Premature end of data parsing flat device tree\n");
len++;
} while ((*p++) != '\0');
str = xstrdup(inb->ptr);
inb->ptr += len;
flat_realign(inb, sizeof(uint32_t));
return str;
}
static struct data flat_read_data(struct inbuf *inb, int len)
{
struct data d = empty_data;
if (len == 0)
return empty_data;
d = data_grow_for(d, len);
d.len = len;
flat_read_chunk(inb, d.val, len);
flat_realign(inb, sizeof(uint32_t));
return d;
}
static char *flat_read_stringtable(struct inbuf *inb, int offset)
{
const char *p;
p = inb->base + offset;
while (1) {
if (p >= inb->limit || p < inb->base)
die("String offset %d overruns string table\n",
offset);
if (*p == '\0')
break;
p++;
}
return xstrdup(inb->base + offset);
}
static struct property *flat_read_property(struct inbuf *dtbuf,
struct inbuf *strbuf, int flags)
{
uint32_t proplen, stroff;
char *name;
struct data val;
proplen = flat_read_word(dtbuf);
stroff = flat_read_word(dtbuf);
name = flat_read_stringtable(strbuf, stroff);
if ((flags & FTF_VARALIGN) && (proplen >= 8))
flat_realign(dtbuf, 8);
val = flat_read_data(dtbuf, proplen);
return build_property(name, val);
}
static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
{
struct reserve_info *reservelist = NULL;
struct reserve_info *new;
struct fdt_reserve_entry re;
/*
* Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
* List terminates at an entry with size equal to zero.
*
* First pass, count entries.
*/
while (1) {
uint64_t address, size;
flat_read_chunk(inb, &re, sizeof(re));
address = fdt64_to_cpu(re.address);
size = fdt64_to_cpu(re.size);
if (size == 0)
break;
new = build_reserve_entry(address, size);
reservelist = add_reserve_entry(reservelist, new);
}
return reservelist;
}
static char *nodename_from_path(const char *ppath, const char *cpath)
{
int plen;
plen = strlen(ppath);
if (!strstarts(cpath, ppath))
die("Path \"%s\" is not valid as a child of \"%s\"\n",
cpath, ppath);
/* root node is a special case */
if (!streq(ppath, "/"))
plen++;
return xstrdup(cpath + plen);
}
static struct node *unflatten_tree(struct inbuf *dtbuf,
struct inbuf *strbuf,
const char *parent_flatname, int flags)
{
struct node *node;
char *flatname;
uint32_t val;
node = build_node(NULL, NULL);
flatname = flat_read_string(dtbuf);
if (flags & FTF_FULLPATH)
node->name = nodename_from_path(parent_flatname, flatname);
else
node->name = flatname;
do {
struct property *prop;
struct node *child;
val = flat_read_word(dtbuf);
switch (val) {
case FDT_PROP:
if (node->children)
fprintf(stderr, "Warning: Flat tree input has "
"subnodes preceding a property.\n");
prop = flat_read_property(dtbuf, strbuf, flags);
add_property(node, prop);
break;
case FDT_BEGIN_NODE:
child = unflatten_tree(dtbuf,strbuf, flatname, flags);
add_child(node, child);
break;
case FDT_END_NODE:
break;
case FDT_END:
die("Premature FDT_END in device tree blob\n");
break;
case FDT_NOP:
if (!(flags & FTF_NOPS))
fprintf(stderr, "Warning: NOP tag found in flat tree"
" version <16\n");
/* Ignore */
break;
default:
die("Invalid opcode word %08x in device tree blob\n",
val);
}
} while (val != FDT_END_NODE);
if (node->name != flatname) {
free(flatname);
}
return node;
}
struct dt_info *dt_from_blob(const char *fname)
{
FILE *f;
fdt32_t magic_buf, totalsize_buf;
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
uint32_t off_dt, off_str, off_mem_rsvmap;
int rc;
char *blob;
struct fdt_header *fdt;
char *p;
struct inbuf dtbuf, strbuf;
struct inbuf memresvbuf;
int sizeleft;
struct reserve_info *reservelist;
struct node *tree;
uint32_t val;
int flags = 0;
f = srcfile_relative_open(fname, NULL);
rc = fread(&magic_buf, sizeof(magic_buf), 1, f);
if (ferror(f))
die("Error reading DT blob magic number: %s\n",
strerror(errno));
if (rc < 1) {
if (feof(f))
die("EOF reading DT blob magic number\n");
else
die("Mysterious short read reading magic number\n");
}
magic = fdt32_to_cpu(magic_buf);
if (magic != FDT_MAGIC)
die("Blob has incorrect magic number\n");
rc = fread(&totalsize_buf, sizeof(totalsize_buf), 1, f);
if (ferror(f))
die("Error reading DT blob size: %s\n", strerror(errno));
if (rc < 1) {
if (feof(f))
die("EOF reading DT blob size\n");
else
die("Mysterious short read reading blob size\n");
}
totalsize = fdt32_to_cpu(totalsize_buf);
if (totalsize < FDT_V1_SIZE)
die("DT blob size (%d) is too small\n", totalsize);
blob = xmalloc(totalsize);
fdt = (struct fdt_header *)blob;
fdt->magic = cpu_to_fdt32(magic);
fdt->totalsize = cpu_to_fdt32(totalsize);
sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
p = blob + sizeof(magic) + sizeof(totalsize);
while (sizeleft) {
if (feof(f))
die("EOF before reading %d bytes of DT blob\n",
totalsize);
rc = fread(p, 1, sizeleft, f);
if (ferror(f))
die("Error reading DT blob: %s\n",
strerror(errno));
sizeleft -= rc;
p += rc;
}
off_dt = fdt32_to_cpu(fdt->off_dt_struct);
off_str = fdt32_to_cpu(fdt->off_dt_strings);
off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
version = fdt32_to_cpu(fdt->version);
boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
if (off_mem_rsvmap >= totalsize)
die("Mem Reserve structure offset exceeds total size\n");
if (off_dt >= totalsize)
die("DT structure offset exceeds total size\n");
if (off_str > totalsize)
die("String table offset exceeds total size\n");
if (version >= 3) {
uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
if ((off_str+size_str < off_str) || (off_str+size_str > totalsize))
die("String table extends past total size\n");
inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
} else {
inbuf_init(&strbuf, blob + off_str, blob + totalsize);
}
if (version >= 17) {
size_dt = fdt32_to_cpu(fdt->size_dt_struct);
if ((off_dt+size_dt < off_dt) || (off_dt+size_dt > totalsize))
die("Structure block extends past total size\n");
}
if (version < 16) {
flags |= FTF_FULLPATH | FTF_NAMEPROPS | FTF_VARALIGN;
} else {
flags |= FTF_NOPS;
}
inbuf_init(&memresvbuf,
blob + off_mem_rsvmap, blob + totalsize);
inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
reservelist = flat_read_mem_reserve(&memresvbuf);
val = flat_read_word(&dtbuf);
if (val != FDT_BEGIN_NODE)
die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
val = flat_read_word(&dtbuf);
if (val != FDT_END)
die("Device tree blob doesn't end with FDT_END\n");
free(blob);
fclose(f);
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
}

90
scripts/dtc/fstree.c Normal file
View File

@@ -0,0 +1,90 @@
/*
* (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 <dirent.h>
#include <sys/stat.h>
static struct node *read_fstree(const char *dirname)
{
DIR *d;
struct dirent *de;
struct stat st;
struct node *tree;
d = opendir(dirname);
if (!d)
die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
tree = build_node(NULL, NULL);
while ((de = readdir(d)) != NULL) {
char *tmpname;
if (streq(de->d_name, ".")
|| streq(de->d_name, ".."))
continue;
tmpname = join_path(dirname, de->d_name);
if (lstat(tmpname, &st) < 0)
die("stat(%s): %s\n", tmpname, strerror(errno));
if (S_ISREG(st.st_mode)) {
struct property *prop;
FILE *pfile;
pfile = fopen(tmpname, "rb");
if (! pfile) {
fprintf(stderr,
"WARNING: Cannot open %s: %s\n",
tmpname, strerror(errno));
} else {
prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile,
st.st_size));
add_property(tree, prop);
fclose(pfile);
}
} else if (S_ISDIR(st.st_mode)) {
struct node *newchild;
newchild = read_fstree(tmpname);
newchild = name_node(newchild, xstrdup(de->d_name));
add_child(tree, newchild);
}
free(tmpname);
}
closedir(d);
return tree;
}
struct dt_info *dt_from_fs(const char *dirname)
{
struct node *tree;
tree = read_fstree(dirname);
tree = name_node(tree, "");
return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
}

View File

@@ -0,0 +1,18 @@
# 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
# be easily embeddable into other systems of Makefiles.
#
LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
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)

312
scripts/dtc/libfdt/fdt.c Normal file
View File

@@ -0,0 +1,312 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
/*
* 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 (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_chk_version()) {
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) >
FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}
if (totalsize < INT32_MAX)
return totalsize;
else
return -FDT_ERR_TRUNCATED;
}
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
{
return (off >= hdrsize) && (off <= totalsize);
}
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;
}
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 fdt_chk_version() ? fdt_header_size_(fdt_version(fdt)) :
FDT_V17_SIZE;
}
int fdt_check_header(const void *fdt)
{
size_t hdrsize;
if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
if (fdt_chk_version()) {
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 (fdt_chk_basic()) {
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 (fdt_chk_extra()) {
/* Bounds check structure block */
if (fdt_chk_version() && 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;
}
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{
unsigned absoffset = offset + fdt_off_dt_struct(fdt);
if (fdt_chk_basic())
if ((absoffset < offset)
|| ((absoffset + len) < absoffset)
|| (absoffset + len) > fdt_totalsize(fdt))
return NULL;
if (!fdt_chk_version() || fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
return fdt_offset_ptr_(fdt, offset);
}
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
{
const fdt32_t *tagp, *lenp;
uint32_t tag;
int offset = startoffset;
const char *p;
*nextoffset = -FDT_ERR_TRUNCATED;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (fdt_chk_basic() && !tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
*nextoffset = -FDT_ERR_BADSTRUCTURE;
switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (fdt_chk_basic() && !p)
return FDT_END; /* premature end */
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (fdt_chk_basic() && !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_chk_version() &&
fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4;
break;
case FDT_END:
case FDT_END_NODE:
case FDT_NOP:
break;
default:
return FDT_END;
}
if (fdt_chk_basic() &&
!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
return FDT_END; /* premature end */
*nextoffset = FDT_TAGALIGN(offset);
return tag;
}
int fdt_check_node_offset_(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
return -FDT_ERR_BADOFFSET;
return offset;
}
int fdt_check_prop_offset_(const void *fdt, int offset)
{
if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
return -FDT_ERR_BADOFFSET;
return offset;
}
int fdt_next_node(const void *fdt, int offset, int *depth)
{
int nextoffset = 0;
uint32_t tag;
if (offset >= 0)
if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
return nextoffset;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_PROP:
case FDT_NOP:
break;
case FDT_BEGIN_NODE:
if (depth)
(*depth)++;
break;
case FDT_END_NODE:
if (depth && ((--(*depth)) < 0))
return nextoffset;
break;
case FDT_END:
if ((nextoffset >= 0)
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
return -FDT_ERR_NOTFOUND;
else
return nextoffset;
}
} while (tag != FDT_BEGIN_NODE);
return offset;
}
int fdt_first_subnode(const void *fdt, int offset)
{
int depth = 0;
offset = fdt_next_node(fdt, offset, &depth);
if (offset < 0 || depth != 1)
return -FDT_ERR_NOTFOUND;
return offset;
}
int fdt_next_subnode(const void *fdt, int offset)
{
int depth = 1;
/*
* With respect to the parent, the depth of the next subnode will be
* the same as the last.
*/
do {
offset = fdt_next_node(fdt, offset, &depth);
if (offset < 0 || depth < 1)
return -FDT_ERR_NOTFOUND;
} while (depth > 1);
return offset;
}
const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;
const char *p;
for (p = strtab; p <= last; p++)
if (memcmp(p, s, len) == 0)
return p;
return NULL;
}
int fdt_move(const void *fdt, void *buf, int bufsize)
{
FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
memmove(buf, fdt, fdt_totalsize(fdt));
return 0;
}

66
scripts/dtc/libfdt/fdt.h Normal file
View File

@@ -0,0 +1,66 @@
/* 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.
*/
#ifndef __ASSEMBLY__
struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */
fdt32_t totalsize; /* total size of DT block */
fdt32_t off_dt_struct; /* offset to structure */
fdt32_t off_dt_strings; /* offset to strings */
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
fdt32_t version; /* format version */
fdt32_t last_comp_version; /* last compatible version */
/* version 2 fields below */
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
fdt32_t size_dt_strings; /* size of the strings block */
/* version 17 fields below */
fdt32_t size_dt_struct; /* size of the structure block */
};
struct fdt_reserve_entry {
fdt64_t address;
fdt64_t size;
};
struct fdt_node_header {
fdt32_t tag;
char name[0];
};
struct fdt_property {
fdt32_t tag;
fdt32_t len;
fdt32_t nameoff;
char data[0];
};
#endif /* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
#define FDT_END_NODE 0x2 /* End node */
#define FDT_PROP 0x3 /* Property: name off,
size, content */
#define FDT_NOP 0x4 /* nop */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
#endif /* FDT_H */

View File

@@ -0,0 +1,101 @@
// 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>
* Copyright (C) 2018 embedded brains GmbH
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{
const fdt32_t *c;
uint32_t val;
int len;
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;
return val;
}
int fdt_size_cells(const void *fdt, int nodeoffset)
{
int val;
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

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_create_empty_tree(void *buf, int bufsize)
{
int err;
err = fdt_create(buf, bufsize);
if (err)
return err;
err = fdt_finish_reservemap(buf);
if (err)
return err;
err = fdt_begin_node(buf, "");
if (err)
return err;
err = fdt_end_node(buf);
if (err)
return err;
err = fdt_finish(buf);
if (err)
return err;
return fdt_open_into(buf, buf, bufsize);
}

View File

@@ -0,0 +1,881 @@
// 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.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
/**
* overlay_get_target_phandle - retrieves the target phandle of a fragment
* @fdto: pointer to the device tree overlay blob
* @fragment: node offset of the fragment in the overlay
*
* overlay_get_target_phandle() retrieves the target phandle of an
* overlay fragment when that fragment uses a phandle (target
* property) instead of a path (target-path property).
*
* returns:
* the phandle pointed by the target property
* 0, if the phandle was not found
* -1, if the phandle was malformed
*/
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
{
const fdt32_t *val;
int len;
val = fdt_getprop(fdto, fragment, "target", &len);
if (!val)
return 0;
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
return (uint32_t)-1;
return fdt32_to_cpu(*val);
}
/**
* overlay_get_target - retrieves the offset of a fragment's target
* @fdt: Base device tree blob
* @fdto: Device tree overlay blob
* @fragment: node offset of the fragment in the overlay
* @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 targeting is
* done (through a phandle or a path)
*
* returns:
* 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,
int fragment, char const **pathp)
{
uint32_t phandle;
const char *path = NULL;
int path_len = 0, ret;
/* Try first to do a phandle based lookup */
phandle = overlay_get_target_phandle(fdto, fragment);
if (phandle == (uint32_t)-1)
return -FDT_ERR_BADPHANDLE;
/* no phandle, try path */
if (!phandle) {
/* And then a path based lookup */
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
if (path)
ret = fdt_path_offset(fdt, path);
else
ret = path_len;
} else
ret = fdt_node_offset_by_phandle(fdt, phandle);
/*
* If we haven't found either a target or a
* target-path property in a node that contains a
* __overlay__ subnode (we wouldn't be called
* otherwise), consider it a improperly written
* overlay
*/
if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
ret = -FDT_ERR_BADOVERLAY;
/* return on error */
if (ret < 0)
return ret;
/* return pointer to path (if available) */
if (pathp)
*pathp = path ? path : NULL;
return ret;
}
/**
* overlay_phandle_add_offset - Increases a phandle by an offset
* @fdt: Base device tree blob
* @node: Device tree overlay blob
* @name: Name of the property to modify (phandle or linux,phandle)
* @delta: offset to apply
*
* overlay_phandle_add_offset() increments a node phandle by a given
* offset.
*
* returns:
* 0 on success.
* Negative error code on error
*/
static int overlay_phandle_add_offset(void *fdt, int node,
const char *name, uint32_t delta)
{
const fdt32_t *val;
uint32_t adj_val;
int len;
val = fdt_getprop(fdt, node, name, &len);
if (!val)
return len;
if (len != sizeof(*val))
return -FDT_ERR_BADPHANDLE;
adj_val = fdt32_to_cpu(*val);
if ((adj_val + delta) < adj_val)
return -FDT_ERR_NOPHANDLES;
adj_val += delta;
if (adj_val == (uint32_t)-1)
return -FDT_ERR_NOPHANDLES;
return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
}
/**
* overlay_adjust_node_phandles - Offsets the phandles of a node
* @fdto: Device tree overlay blob
* @node: Offset of the node we want to adjust
* @delta: Offset to shift the phandles of
*
* overlay_adjust_node_phandles() adds a constant to all the phandles
* of a given node. This is mainly use as part of the overlay
* application process, when we want to update all the overlay
* phandles to not conflict with the overlays of the base device tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_adjust_node_phandles(void *fdto, int node,
uint32_t delta)
{
int child;
int ret;
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
if (ret && ret != -FDT_ERR_NOTFOUND)
return ret;
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
if (ret && ret != -FDT_ERR_NOTFOUND)
return ret;
fdt_for_each_subnode(child, fdto, node) {
ret = overlay_adjust_node_phandles(fdto, child, delta);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
* @fdto: Device tree overlay blob
* @delta: Offset to shift the phandles of
*
* overlay_adjust_local_phandles() adds a constant to all the
* phandles of an overlay. This is mainly use as part of the overlay
* application process, when we want to update all the overlay
* phandles to not conflict with the overlays of the base device tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
{
/*
* Start adjusting the phandles from the overlay root
*/
return overlay_adjust_node_phandles(fdto, 0, delta);
}
/**
* overlay_update_local_node_references - Adjust the overlay references
* @fdto: Device tree overlay blob
* @tree_node: Node offset of the node to operate on
* @fixup_node: Node offset of the matching local fixups node
* @delta: Offset to shift the phandles of
*
* overlay_update_local_nodes_references() update the phandles
* pointing to a node within the device tree overlay by adding a
* constant delta.
*
* This is mainly used as part of a device tree application process,
* where you want the device tree overlays phandles to not conflict
* with the ones from the base device tree before merging them.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_update_local_node_references(void *fdto,
int tree_node,
int fixup_node,
uint32_t delta)
{
int fixup_prop;
int fixup_child;
int ret;
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
const fdt32_t *fixup_val;
const char *tree_val;
const char *name;
int fixup_len;
int tree_len;
int i;
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
&name, &fixup_len);
if (!fixup_val)
return fixup_len;
if (fixup_len % sizeof(uint32_t))
return -FDT_ERR_BADOVERLAY;
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
if (!tree_val) {
if (tree_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
return tree_len;
}
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
fdt32_t adj_val;
uint32_t poffset;
poffset = fdt32_to_cpu(fixup_val[i]);
/*
* phandles to fixup can be unaligned.
*
* Use a memcpy for the architectures that do
* not support unaligned accesses.
*/
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
ret = fdt_setprop_inplace_namelen_partial(fdto,
tree_node,
name,
strlen(name),
poffset,
&adj_val,
sizeof(adj_val));
if (ret == -FDT_ERR_NOSPACE)
return -FDT_ERR_BADOVERLAY;
if (ret)
return ret;
}
}
fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
NULL);
int tree_child;
tree_child = fdt_subnode_offset(fdto, tree_node,
fixup_child_name);
if (tree_child == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
if (tree_child < 0)
return tree_child;
ret = overlay_update_local_node_references(fdto,
tree_child,
fixup_child,
delta);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_update_local_references - Adjust the overlay references
* @fdto: Device tree overlay blob
* @delta: Offset to shift the phandles of
*
* overlay_update_local_references() update all the phandles pointing
* to a node within the device tree overlay by adding a constant
* delta to not conflict with the base overlay.
*
* This is mainly used as part of a device tree application process,
* where you want the device tree overlays phandles to not conflict
* with the ones from the base device tree before merging them.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_update_local_references(void *fdto, uint32_t delta)
{
int fixups;
fixups = fdt_path_offset(fdto, "/__local_fixups__");
if (fixups < 0) {
/* There's no local phandles to adjust, bail out */
if (fixups == -FDT_ERR_NOTFOUND)
return 0;
return fixups;
}
/*
* Update our local references from the root of the tree
*/
return overlay_update_local_node_references(fdto, 0, fixups,
delta);
}
/**
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
* @symbols_off: Node offset of the symbols node in the base device tree
* @path: Path to a node holding a phandle in the overlay
* @path_len: number of path characters to consider
* @name: Name of the property holding the phandle reference in the overlay
* @name_len: number of name characters to consider
* @poffset: Offset within the overlay property where the phandle is stored
* @label: Label of the node referenced by the phandle
*
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
* a node in the base device tree.
*
* This is part of the device tree overlay application process, when
* you want all the phandles in the overlay to point to the actual
* base dt nodes.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_fixup_one_phandle(void *fdt, void *fdto,
int symbols_off,
const char *path, uint32_t path_len,
const char *name, uint32_t name_len,
int poffset, const char *label)
{
const char *symbol_path;
uint32_t phandle;
fdt32_t phandle_prop;
int symbol_off, fixup_off;
int prop_len;
if (symbols_off < 0)
return symbols_off;
symbol_path = fdt_getprop(fdt, symbols_off, label,
&prop_len);
if (!symbol_path)
return prop_len;
symbol_off = fdt_path_offset(fdt, symbol_path);
if (symbol_off < 0)
return symbol_off;
phandle = fdt_get_phandle(fdt, symbol_off);
if (!phandle)
return -FDT_ERR_NOTFOUND;
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
if (fixup_off == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
if (fixup_off < 0)
return fixup_off;
phandle_prop = cpu_to_fdt32(phandle);
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
name, name_len, poffset,
&phandle_prop,
sizeof(phandle_prop));
};
/**
* overlay_fixup_phandle - Set an overlay phandle to the base one
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
* @symbols_off: Node offset of the symbols node in the base device tree
* @property: Property offset in the overlay holding the list of fixups
*
* overlay_fixup_phandle() resolves all the overlay phandles pointed
* to in a __fixups__ property, and updates them to match the phandles
* in use in the base device tree.
*
* This is part of the device tree overlay application process, when
* you want all the phandles in the overlay to point to the actual
* base dt nodes.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
int property)
{
const char *value;
const char *label;
int len;
value = fdt_getprop_by_offset(fdto, property,
&label, &len);
if (!value) {
if (len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
return len;
}
do {
const char *path, *name, *fixup_end;
const char *fixup_str = value;
uint32_t path_len, name_len;
uint32_t fixup_len;
char *sep, *endptr;
int poffset, ret;
fixup_end = memchr(value, '\0', len);
if (!fixup_end)
return -FDT_ERR_BADOVERLAY;
fixup_len = fixup_end - fixup_str;
len -= fixup_len + 1;
value += fixup_len + 1;
path = fixup_str;
sep = memchr(fixup_str, ':', fixup_len);
if (!sep || *sep != ':')
return -FDT_ERR_BADOVERLAY;
path_len = sep - path;
if (path_len == (fixup_len - 1))
return -FDT_ERR_BADOVERLAY;
fixup_len -= path_len + 1;
name = sep + 1;
sep = memchr(name, ':', fixup_len);
if (!sep || *sep != ':')
return -FDT_ERR_BADOVERLAY;
name_len = sep - name;
if (!name_len)
return -FDT_ERR_BADOVERLAY;
poffset = strtoul(sep + 1, &endptr, 10);
if ((*endptr != '\0') || (endptr <= (sep + 1)))
return -FDT_ERR_BADOVERLAY;
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
path, path_len, name, name_len,
poffset, label);
if (ret)
return ret;
} while (len > 0);
return 0;
}
/**
* overlay_fixup_phandles - Resolve the overlay phandles to the base
* device tree
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_fixup_phandles() resolves all the overlay phandles pointing
* to nodes in the base device tree.
*
* This is one of the steps of the device tree overlay application
* process, when you want all the phandles in the overlay to point to
* the actual base dt nodes.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_fixup_phandles(void *fdt, void *fdto)
{
int fixups_off, symbols_off;
int property;
/* We can have overlays without any fixups */
fixups_off = fdt_path_offset(fdto, "/__fixups__");
if (fixups_off == -FDT_ERR_NOTFOUND)
return 0; /* nothing to do */
if (fixups_off < 0)
return fixups_off;
/* And base DTs without symbols */
symbols_off = fdt_path_offset(fdt, "/__symbols__");
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
return symbols_off;
fdt_for_each_property_offset(property, fdto, fixups_off) {
int ret;
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_apply_node - Merges a node into the base device tree
* @fdt: Base Device Tree blob
* @target: Node offset in the base device tree to apply the fragment to
* @fdto: Device tree overlay blob
* @node: Node offset in the overlay holding the changes to merge
*
* overlay_apply_node() merges a node into a target base device tree
* node pointed.
*
* This is part of the final step in the device tree overlay
* application process, when all the phandles have been adjusted and
* resolved and you just have to merge overlay into the base device
* tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_apply_node(void *fdt, int target,
void *fdto, int node)
{
int property;
int subnode;
fdt_for_each_property_offset(property, fdto, node) {
const char *name;
const void *prop;
int prop_len;
int ret;
prop = fdt_getprop_by_offset(fdto, property, &name,
&prop_len);
if (prop_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
if (prop_len < 0)
return prop_len;
ret = fdt_setprop(fdt, target, name, prop, prop_len);
if (ret)
return ret;
}
fdt_for_each_subnode(subnode, fdto, node) {
const char *name = fdt_get_name(fdto, subnode, NULL);
int nnode;
int ret;
nnode = fdt_add_subnode(fdt, target, name);
if (nnode == -FDT_ERR_EXISTS) {
nnode = fdt_subnode_offset(fdt, target, name);
if (nnode == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
}
if (nnode < 0)
return nnode;
ret = overlay_apply_node(fdt, nnode, fdto, subnode);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_merge - Merge an overlay into its base device tree
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_merge() merges an overlay into its base device tree.
*
* This is the next to last step in the device tree overlay application
* process, when all the phandles have been adjusted and resolved and
* you just have to merge overlay into the base device tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_merge(void *fdt, void *fdto)
{
int fragment;
fdt_for_each_subnode(fragment, fdto, 0) {
int overlay;
int target;
int ret;
/*
* Each fragments will have an __overlay__ node. If
* they don't, it's not supposed to be merged
*/
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
if (overlay == -FDT_ERR_NOTFOUND)
continue;
if (overlay < 0)
return overlay;
target = overlay_get_target(fdt, fdto, fragment, NULL);
if (target < 0)
return target;
ret = overlay_apply_node(fdt, target, fdto, overlay);
if (ret)
return ret;
}
return 0;
}
static int get_path_len(const void *fdt, int nodeoffset)
{
int len = 0, namelen;
const char *name;
FDT_RO_PROBE(fdt);
for (;;) {
name = fdt_get_name(fdt, nodeoffset, &namelen);
if (!name)
return namelen;
/* root? we're done */
if (namelen == 0)
break;
nodeoffset = fdt_parent_offset(fdt, nodeoffset);
if (nodeoffset < 0)
return nodeoffset;
len += namelen + 1;
}
/* in case of root pretend it's "/" */
if (len == 0)
len++;
return len;
}
/**
* overlay_symbol_update - Update the symbols of base tree after a merge
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_symbol_update() updates the symbols of the base tree with the
* symbols of the applied overlay
*
* This is the last step in the device tree overlay application
* process, allowing the reference of overlay symbols by subsequent
* overlay operations.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_symbol_update(void *fdt, void *fdto)
{
int root_sym, ov_sym, prop, path_len, fragment, target;
int len, frag_name_len, ret, rel_path_len;
const char *s, *e;
const char *path;
const char *name;
const char *frag_name;
const char *rel_path;
const char *target_path;
char *buf;
void *p;
ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
/* if no overlay symbols exist no problem */
if (ov_sym < 0)
return 0;
root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
/* it no root symbols exist we should create them */
if (root_sym == -FDT_ERR_NOTFOUND)
root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
/* any error is fatal now */
if (root_sym < 0)
return root_sym;
/* iterate over each overlay symbol */
fdt_for_each_property_offset(prop, fdto, ov_sym) {
path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
if (!path)
return path_len;
/* verify it's a string property (terminated by a single \0) */
if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
return -FDT_ERR_BADVALUE;
/* keep end marker to avoid strlen() */
e = path + path_len;
if (*path != '/')
return -FDT_ERR_BADVALUE;
/* get fragment name first */
s = strchr(path + 1, '/');
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) == 0)) {
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
rel_path = s + len;
rel_path_len = e - rel_path;
} else if ((e - s) == len
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
/* /<fragment-name>/__overlay__ */
rel_path = "";
rel_path_len = 0;
} else {
/* Symbol refers to something that won't end
* up in the target tree */
continue;
}
/* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
frag_name_len);
/* not found? */
if (ret < 0)
return -FDT_ERR_BADOVERLAY;
fragment = ret;
/* an __overlay__ subnode must exist */
ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
if (ret < 0)
return -FDT_ERR_BADOVERLAY;
/* get the target of the fragment */
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
/* if we have a target path use */
if (!target_path) {
ret = get_path_len(fdt, target);
if (ret < 0)
return ret;
len = ret;
} else {
len = strlen(target_path);
}
ret = fdt_setprop_placeholder(fdt, root_sym, name,
len + (len > 1) + rel_path_len + 1, &p);
if (ret < 0)
return ret;
if (!target_path) {
/* again in case setprop_placeholder changed it */
ret = overlay_get_target(fdt, fdto, fragment, &target_path);
if (ret < 0)
return ret;
target = ret;
}
buf = p;
if (len > 1) { /* target is not root */
if (!target_path) {
ret = fdt_get_path(fdt, target, buf, len + 1);
if (ret < 0)
return ret;
} else
memcpy(buf, target_path, len + 1);
} else
len--;
buf[len] = '/';
memcpy(buf + len + 1, rel_path, rel_path_len);
buf[len + 1 + rel_path_len] = '\0';
}
return 0;
}
int fdt_overlay_apply(void *fdt, void *fdto)
{
uint32_t delta;
int ret;
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)
goto err;
ret = overlay_update_local_references(fdto, delta);
if (ret)
goto err;
ret = overlay_fixup_phandles(fdt, fdto);
if (ret)
goto err;
ret = overlay_merge(fdt, fdto);
if (ret)
goto err;
ret = overlay_symbol_update(fdt, fdto);
if (ret)
goto err;
/*
* The overlay has been damaged, erase its magic.
*/
fdt_set_magic(fdto, ~0);
return 0;
err:
/*
* The overlay might have been damaged, erase its magic.
*/
fdt_set_magic(fdto, ~0);
/*
* The base device tree might have been damaged, erase its
* magic.
*/
fdt_set_magic(fdt, ~0);
return ret;
}

921
scripts/dtc/libfdt/fdt_ro.c Normal file
View File

@@ -0,0 +1,921 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int fdt_nodename_eq_(const void *fdt, int offset,
const char *s, int len)
{
int olen;
const char *p = fdt_get_name(fdt, offset, &olen);
if (!p || (fdt_chk_extra() && olen < len))
/* short match */
return 0;
if (memcmp(p, s, len) != 0)
return 0;
if (p[len] == '\0')
return 1;
else if (!memchr(s, '@', len) && (p[len] == '@'))
return 1;
else
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 (!fdt_chk_extra()) {
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 (!fdt_chk_version() || 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 fdt_get_string(fdt, stroffset, NULL);
}
static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len)
{
int slen;
const char *p = fdt_get_string(fdt, stroffset, &slen);
return p && (slen == len) && (memcmp(p, s, len) == 0);
}
int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
{
uint32_t max = 0;
int offset = -1;
while (true) {
uint32_t value;
offset = fdt_next_node(fdt, offset, NULL);
if (offset < 0) {
if (offset == -FDT_ERR_NOTFOUND)
break;
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 (fdt_chk_extra()) {
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)
{
const struct fdt_reserve_entry *re;
FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n);
if (fdt_chk_extra() && !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;
const struct fdt_reserve_entry *re;
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)
{
uint32_t tag;
int nextoffset;
do {
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
if (nextoffset >= 0)
return -FDT_ERR_BADSTRUCTURE;
else
return nextoffset;
case FDT_PROP:
return offset;
}
offset = nextoffset;
} while (tag == FDT_NOP);
return -FDT_ERR_NOTFOUND;
}
int fdt_subnode_offset_namelen(const void *fdt, int offset,
const char *name, int namelen)
{
int depth;
FDT_RO_PROBE(fdt);
for (depth = 0;
(offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth))
if ((depth == 1)
&& fdt_nodename_eq_(fdt, offset, name, namelen))
return offset;
if (depth < 0)
return -FDT_ERR_NOTFOUND;
return offset; /* error */
}
int fdt_subnode_offset(const void *fdt, int parentoffset,
const char *name)
{
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
{
const char *end = path + namelen;
const char *p = path;
int offset = 0;
FDT_RO_PROBE(fdt);
/* see if we have an alias */
if (*path != '/') {
const char *q = memchr(path, '/', end - p);
if (!q)
q = end;
p = fdt_get_alias_namelen(fdt, p, q - p);
if (!p)
return -FDT_ERR_BADPATH;
offset = fdt_path_offset(fdt, p);
p = q;
}
while (p < end) {
const char *q;
while (*p == '/') {
p++;
if (p == end)
return offset;
}
q = memchr(p, '/', end - p);
if (! q)
q = end;
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
if (offset < 0)
return offset;
p = q;
}
return offset;
}
int fdt_path_offset(const void *fdt, const char *path)
{
return fdt_path_offset_namelen(fdt, path, strlen(path));
}
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
const char *nameptr;
int err;
if (fdt_chk_extra() &&
(((err = fdt_ro_probe_(fdt)) < 0)
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
goto fail;
nameptr = nh->name;
if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
* contents are loosely checked.
*/
const char *leaf;
leaf = strrchr(nameptr, '/');
if (leaf == NULL) {
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
}
nameptr = leaf+1;
}
if (len)
*len = strlen(nameptr);
return nameptr;
fail:
if (len)
*len = err;
return NULL;
}
int fdt_first_property_offset(const void *fdt, int nodeoffset)
{
int offset;
if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return offset;
return nextprop_(fdt, offset);
}
int fdt_next_property_offset(const void *fdt, int offset)
{
if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
return offset;
return nextprop_(fdt, offset);
}
static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int offset,
int *lenp)
{
int err;
const struct fdt_property *prop;
if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp)
*lenp = err;
return NULL;
}
prop = fdt_offset_ptr_(fdt, offset);
if (lenp)
*lenp = fdt32_ld(&prop->len);
return prop;
}
const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
}
return fdt_get_property_by_offset_(fdt, offset, lenp);
}
static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
int offset,
const char *name,
int namelen,
int *lenp,
int *poffset)
{
for (offset = fdt_first_property_offset(fdt, offset);
(offset >= 0);
(offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop;
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (fdt_chk_extra() && !prop) {
offset = -FDT_ERR_INTERNAL;
break;
}
if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) {
if (poffset)
*poffset = offset;
return prop;
}
}
if (lenp)
*lenp = offset;
return NULL;
}
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int offset,
const char *name,
int namelen, int *lenp)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_chk_version() && fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
}
return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
NULL);
}
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
{
return fdt_get_property_namelen(fdt, nodeoffset, name,
strlen(name), lenp);
}
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp)
{
int poffset;
const struct fdt_property *prop;
prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
&poffset);
if (!prop)
return NULL;
/* Handle realignment */
if (fdt_chk_version() && fdt_version(fdt) < 0x10 &&
(poffset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop)
return NULL;
if (namep) {
const char *name;
int namelen;
if (fdt_chk_extra()) {
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_chk_version() && fdt_version(fdt) < 0x10 &&
(offset + sizeof(*prop)) % 8 && fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
}
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const fdt32_t *php;
int len;
/* FIXME: This is a bit sub-optimal, since we potentially scan
* over all the properties twice. */
php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
if (!php || (len != sizeof(*php))) {
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php)))
return 0;
}
return fdt32_ld(php);
}
const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen)
{
int aliasoffset;
aliasoffset = fdt_path_offset(fdt, "/aliases");
if (aliasoffset < 0)
return NULL;
return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
}
const char *fdt_get_alias(const void *fdt, const char *name)
{
return fdt_get_alias_namelen(fdt, name, strlen(name));
}
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
int offset, depth, namelen;
const char *name;
FDT_RO_PROBE(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
while (pdepth > depth) {
do {
p--;
} while (buf[p-1] != '/');
pdepth--;
}
if (pdepth >= depth) {
name = fdt_get_name(fdt, offset, &namelen);
if (!name)
return namelen;
if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
pdepth++;
}
}
if (offset == nodeoffset) {
if (pdepth < (depth + 1))
return -FDT_ERR_NOSPACE;
if (p > 1) /* special case so that root path is "/", not "" */
p--;
buf[p] = '\0';
return 0;
}
}
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() */
}
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int supernodedepth, int *nodedepth)
{
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_RO_PROBE(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth == supernodedepth)
supernodeoffset = offset;
if (offset == nodeoffset) {
if (nodedepth)
*nodedepth = depth;
if (supernodedepth > depth)
return -FDT_ERR_NOTFOUND;
else
return supernodeoffset;
}
}
if (fdt_chk_extra()) {
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() */
}
int fdt_node_depth(const void *fdt, int nodeoffset)
{
int nodedepth;
int err;
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth;
}
int fdt_parent_offset(const void *fdt, int nodeoffset)
{
int nodedepth = fdt_node_depth(fdt, nodeoffset);
if (nodedepth < 0)
return nodedepth;
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
nodedepth - 1, NULL);
}
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const char *propname,
const void *propval, int proplen)
{
int offset;
const void *val;
int len;
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
* find what we want, we scan over them again making our way
* to the next node. Still it's the easiest to implement
* approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
val = fdt_getprop(fdt, offset, propname, &len);
if (val && (len == proplen)
&& (memcmp(val, propval, len) == 0))
return offset;
}
return offset; /* error from fdt_next_node() */
}
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
int offset;
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
* fdt_get_phandle(), then if that didn't find what
* we want, we scan over them again making our way to the next
* node. Still it's the easiest to implement approach;
* performance can come later. */
for (offset = fdt_next_node(fdt, -1, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
if (fdt_get_phandle(fdt, offset) == phandle)
return offset;
}
return offset; /* error from fdt_next_node() */
}
int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
{
int len = strlen(str);
const char *p;
while (listlen >= len) {
if (memcmp(str, strlist, len+1) == 0)
return 1;
p = memchr(strlist, '\0', listlen);
if (!p)
return 0; /* malformed strlist.. */
listlen -= (p-strlist) + 1;
strlist = p + 1;
}
return 0;
}
int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
{
const char *list, *end;
int length, count = 0;
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return length;
end = list + length;
while (list < end) {
length = strnlen(list, end - list) + 1;
/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end)
return -FDT_ERR_BADVALUE;
list += length;
count++;
}
return count;
}
int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
const char *string)
{
int length, len, idx = 0;
const char *list, *end;
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return length;
len = strlen(string) + 1;
end = list + length;
while (list < end) {
length = strnlen(list, end - list) + 1;
/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end)
return -FDT_ERR_BADVALUE;
if (length == len && memcmp(list, string, length) == 0)
return idx;
list += length;
idx++;
}
return -FDT_ERR_NOTFOUND;
}
const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
const char *property, int idx,
int *lenp)
{
const char *list, *end;
int length;
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list) {
if (lenp)
*lenp = length;
return NULL;
}
end = list + length;
while (list < end) {
length = strnlen(list, end - list) + 1;
/* Abort if the last string isn't properly NUL-terminated. */
if (list + length > end) {
if (lenp)
*lenp = -FDT_ERR_BADVALUE;
return NULL;
}
if (idx == 0) {
if (lenp)
*lenp = length - 1;
return list;
}
list += length;
idx--;
}
if (lenp)
*lenp = -FDT_ERR_NOTFOUND;
return NULL;
}
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
const void *prop;
int len;
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
return !fdt_stringlist_contains(prop, len, compatible);
}
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible)
{
int offset, err;
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
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
err = fdt_node_check_compatible(fdt, offset, compatible);
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
return err;
else if (err == 0)
return offset;
}
return offset; /* error from fdt_next_node() */
}
#if !defined(FDT_ASSUME_MASK) || FDT_ASSUME_MASK != 0xff
int fdt_check_full(const void *fdt, size_t bufsize)
{
int err;
int num_memrsv;
int offset, nextoffset = 0;
uint32_t tag;
unsigned depth = 0;
const void *prop;
const char *propname;
if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
err = fdt_check_header(fdt);
if (err != 0)
return err;
if (bufsize < fdt_totalsize(fdt))
return -FDT_ERR_TRUNCATED;
num_memrsv = fdt_num_mem_rsv(fdt);
if (num_memrsv < 0)
return num_memrsv;
while (1) {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (nextoffset < 0)
return nextoffset;
switch (tag) {
case FDT_NOP:
break;
case FDT_END:
if (depth != 0)
return -FDT_ERR_BADSTRUCTURE;
return 0;
case FDT_BEGIN_NODE:
depth++;
if (depth > INT_MAX)
return -FDT_ERR_BADSTRUCTURE;
break;
case FDT_END_NODE:
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
break;
case FDT_PROP:
prop = fdt_getprop_by_offset(fdt, offset, &propname,
&err);
if (!prop)
return err;
break;
default:
return -FDT_ERR_INTERNAL;
}
}
}
#endif

492
scripts/dtc/libfdt/fdt_rw.c Normal file
View File

@@ -0,0 +1,492 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int fdt_blocks_misordered_(const void *fdt,
int mem_rsv_size, int struct_size)
{
if (!fdt_chk_basic())
return false;
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|| (fdt_off_dt_strings(fdt) <
(fdt_off_dt_struct(fdt) + struct_size))
|| (fdt_totalsize(fdt) <
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
static int fdt_rw_probe_(void *fdt)
{
if (!fdt_chk_basic())
return 0;
FDT_RO_PROBE(fdt);
if (fdt_chk_version() && 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_chk_version() && fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
}
#define FDT_RW_PROBE(fdt) \
{ \
int err_; \
if (fdt_chk_extra() && (err_ = fdt_rw_probe_(fdt)) != 0) \
return err_; \
}
static inline int fdt_data_size_(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
char *p = splicepoint;
char *end = (char *)fdt + fdt_data_size_(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen);
return 0;
}
static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int fdt_splice_struct_(void *fdt, void *p,
int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;
if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
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
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;
if ((err = fdt_splice_(fdt, p, 0, newlen)))
return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
/**
* 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 !fdt_chk_basic()
* @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;
char *new;
int len = strlen(s) + 1;
int err;
if (fdt_chk_basic())
*allocated = 0;
p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
err = fdt_splice_string_(fdt, len);
if (err)
return err;
if (fdt_chk_basic())
*allocated = 1;
memcpy(new, s, len);
return (new - strtab);
}
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry *re;
int err;
FDT_RW_PROBE(fdt);
re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
if (err)
return err;
re->address = cpu_to_fdt64(address);
re->size = cpu_to_fdt64(size);
return 0;
}
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
FDT_RW_PROBE(fdt);
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
return fdt_splice_mem_rsv_(fdt, re, 1, 0);
}
static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int oldlen;
int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (!*prop)
return oldlen;
if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(len))))
return err;
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop)
{
int proplen;
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, &allocated);
if (namestroff < 0)
return namestroff;
*prop = fdt_offset_ptr_w_(fdt, nextoffset);
proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) {
/* Delete the string if we failed to add it */
if (fdt_chk_basic() && allocated)
fdt_del_last_string_(fdt, name);
return err;
}
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff);
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
{
char *namep;
int oldlen, newlen;
int err;
FDT_RW_PROBE(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
return oldlen;
newlen = strlen(name);
err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
FDT_TAGALIGN(newlen+1));
if (err)
return err;
memcpy(namep, name, newlen+1);
return 0;
}
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
int len, void **prop_data)
{
struct fdt_property *prop;
int err;
FDT_RW_PROBE(fdt);
err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
*prop_data = prop->data;
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *prop_data;
int err;
err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
if (err)
return err;
if (len)
memcpy(prop_data, val, len);
return 0;
}
int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err, oldlen, newlen;
FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) {
newlen = len + oldlen;
err = fdt_splice_struct_(fdt, prop->data,
FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen));
if (err)
return err;
prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len);
} else {
err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
}
return 0;
}
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len, proplen;
FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop)
return len;
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
return fdt_splice_struct_(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen)
{
struct fdt_node_header *nh;
int offset, nextoffset;
int nodelen;
int err;
uint32_t tag;
fdt32_t *endtag;
FDT_RW_PROBE(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
return -FDT_ERR_EXISTS;
else if (offset != -FDT_ERR_NOTFOUND)
return offset;
/* Try to place the new node after the parent's properties */
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = fdt_offset_ptr_w_(fdt, offset);
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
err = fdt_splice_struct_(fdt, nh, 0, nodelen);
if (err)
return err;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
memcpy(nh->name, name, namelen);
endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
*endtag = cpu_to_fdt32(FDT_END_NODE);
return offset;
}
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
{
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
FDT_RW_PROBE(fdt);
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}
static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size, int struct_size)
{
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;
strings_off = struct_off + struct_size;
memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
fdt_set_off_mem_rsvmap(new, mem_rsv_off);
memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
fdt_set_off_dt_struct(new, struct_off);
fdt_set_size_dt_struct(new, struct_size);
memmove(new + strings_off, old + fdt_off_dt_strings(old),
fdt_size_dt_strings(old));
fdt_set_off_dt_strings(new, strings_off);
fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
}
int fdt_open_into(const void *fdt, void *buf, int bufsize)
{
int err;
int mem_rsv_size, struct_size;
int newsize;
const char *fdtstart = fdt;
const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp;
FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
if (!fdt_chk_version() || fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else {
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
if (struct_size < 0)
return struct_size;
}
if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
return err;
fdt_set_version(buf, 17);
fdt_set_size_dt_struct(buf, struct_size);
fdt_set_totalsize(buf, bufsize);
return 0;
}
/* Need to reorder */
newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ struct_size + fdt_size_dt_strings(fdt);
if (bufsize < newsize)
return -FDT_ERR_NOSPACE;
/* First attempt to build converted tree at beginning of buffer */
tmp = buf;
/* But if that overlaps with the old tree... */
if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
/* Try right after the old tree instead */
tmp = (char *)(uintptr_t)fdtend;
if ((tmp + newsize) > ((char *)buf + bufsize))
return -FDT_ERR_NOSPACE;
}
fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
fdt_set_totalsize(buf, bufsize);
fdt_set_version(buf, 17);
fdt_set_last_comp_version(buf, 16);
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
return 0;
}
int fdt_pack(void *fdt)
{
int mem_rsv_size;
FDT_RW_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, fdt_data_size_(fdt));
return 0;
}

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
struct fdt_errtabent {
const char *str;
};
#define FDT_ERRTABENT(val) \
[(val)] = { .str = #val, }
static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_NOTFOUND),
FDT_ERRTABENT(FDT_ERR_EXISTS),
FDT_ERRTABENT(FDT_ERR_NOSPACE),
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
FDT_ERRTABENT(FDT_ERR_BADPATH),
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
FDT_ERRTABENT(FDT_ERR_BADSTATE),
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
FDT_ERRTABENT(FDT_ERR_BADMAGIC),
FDT_ERRTABENT(FDT_ERR_BADVERSION),
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
FDT_ERRTABENT(FDT_ERR_INTERNAL),
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
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]))
const char *fdt_strerror(int errval)
{
if (errval > 0)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
else if (errval > -FDT_ERRTABSIZE) {
const char *s = fdt_errtable[-errval].str;
if (s)
return s;
}
return "<unknown error>";
}

383
scripts/dtc/libfdt/fdt_sw.c Normal file
View File

@@ -0,0 +1,383 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int fdt_sw_probe_(void *fdt)
{
if (fdt_chk_basic()) {
if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
}
return 0;
}
#define FDT_SW_PROBE(fdt) \
{ \
int err; \
if (fdt_chk_basic() && (err = fdt_sw_probe_(fdt)) != 0) \
return err; \
}
/* 'memrsv' state: Initial state after fdt_create()
*
* Allowed functions:
* fdt_add_reservmap_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 (fdt_chk_extra() && fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}
#define FDT_SW_PROBE_MEMRSV(fdt) \
{ \
int err; \
if (fdt_chk_extra() && (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;
if (!fdt_chk_extra())
return 0;
err = fdt_sw_probe_(fdt);
if (err)
return err;
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE;
return 0;
}
#define FDT_SW_PROBE_STRUCT(fdt) \
{ \
int err; \
if (fdt_chk_extra() && (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);
int spaceleft;
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
if ((offset + len < offset) || (offset + len > spaceleft))
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w_(fdt, offset);
}
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 < 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, flags);
fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, hdrsize);
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
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_PROBE(fdt);
headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt);
if (fdt_chk_extra() && (headsize + tailsize) > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE;
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
newtail = (char *)buf + bufsize - tailsize;
/* Two cases to avoid clobbering data if the old and new
* buffers partially overlap */
if (buf <= fdt) {
memmove(buf, fdt, headsize);
memmove(newtail, oldtail, tailsize);
} else {
memmove(newtail, oldtail, tailsize);
memmove(buf, fdt, headsize);
}
fdt_set_totalsize(buf, bufsize);
if (fdt_off_dt_strings(buf))
fdt_set_off_dt_strings(buf, bufsize);
return 0;
}
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{
struct fdt_reserve_entry *re;
int offset;
FDT_SW_PROBE_MEMRSV(fdt);
offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
re = (struct fdt_reserve_entry *)((char *)fdt + offset);
re->address = cpu_to_fdt64(addr);
re->size = cpu_to_fdt64(size);
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
return 0;
}
int fdt_finish_reservemap(void *fdt)
{
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;
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;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memcpy(nh->name, name, namelen);
return 0;
}
int fdt_end_node(void *fdt)
{
fdt32_t *en;
FDT_SW_PROBE_STRUCT(fdt);
en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
*en = cpu_to_fdt32(FDT_END_NODE);
return 0;
}
static int fdt_add_string_(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;
offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top)
return 0; /* no more room :( */
memcpy(strtab + offset, s, len);
fdt_set_size_dt_strings(fdt, strtabsize + len);
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_PROBE_STRUCT(fdt);
/* 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 (allocated)
fdt_del_last_string_(fdt, name);
return -FDT_ERR_NOSPACE;
}
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
*valp = prop->data;
return 0;
}
int fdt_property(void *fdt, const char *name, const void *val, int len)
{
void *ptr;
int ret;
ret = fdt_property_placeholder(fdt, name, len, &ptr);
if (ret)
return ret;
memcpy(ptr, val, len);
return 0;
}
int fdt_finish(void *fdt)
{
char *p = (char *)fdt;
fdt32_t *end;
int oldstroffset, newstroffset;
uint32_t tag;
int offset, nextoffset;
FDT_SW_PROBE_STRUCT(fdt);
/* Add terminator */
end = fdt_grab_space_(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
/* Relocate the string table */
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
fdt_set_off_dt_strings(fdt, newstroffset);
/* Walk the structure, correcting string offsets */
offset = 0;
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
fdt_offset_ptr_w_(fdt, offset);
int nameoff;
nameoff = fdt32_to_cpu(prop->nameoff);
nameoff += fdt_size_dt_strings(fdt);
prop->nameoff = cpu_to_fdt32(nameoff);
}
offset = nextoffset;
}
if (nextoffset < 0)
return nextoffset;
/* 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

@@ -0,0 +1,94 @@
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len)
{
void *propval;
int proplen;
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
&proplen);
if (!propval)
return proplen;
if (proplen < (len + idx))
return -FDT_ERR_NOSPACE;
memcpy((char *)propval + idx, val, len);
return 0;
}
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
const void *propval;
int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (!propval)
return proplen;
if (proplen != len)
return -FDT_ERR_NOSPACE;
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
strlen(name), 0,
val, len);
}
static void fdt_nop_region_(void *start, int len)
{
fdt32_t *p;
for (p = start; (char *)p < ((char *)start + len); p++)
*p = cpu_to_fdt32(FDT_NOP);
}
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (!prop)
return len;
fdt_nop_region_(prop, len + sizeof(*prop));
return 0;
}
int fdt_node_end_offset_(void *fdt, int offset)
{
int depth = 0;
while ((offset >= 0) && (depth >= 0))
offset = fdt_next_node(fdt, offset, &depth);
return offset;
}
int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;
endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
endoffset - nodeoffset);
return 0;
}

2072
scripts/dtc/libfdt/libfdt.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
/* 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.
*/
#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))
#define FDT_BITWISE __attribute__((bitwise))
#else
#define FDT_FORCE
#define FDT_BITWISE
#endif
typedef uint16_t FDT_BITWISE fdt16_t;
typedef uint32_t FDT_BITWISE fdt32_t;
typedef uint64_t FDT_BITWISE fdt64_t;
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
(EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
(EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
(EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
(EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
static inline uint16_t fdt16_to_cpu(fdt16_t x)
{
return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
}
static inline fdt16_t cpu_to_fdt16(uint16_t x)
{
return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
}
static inline uint32_t fdt32_to_cpu(fdt32_t x)
{
return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
}
static inline fdt32_t cpu_to_fdt32(uint32_t x)
{
return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
}
static inline uint64_t fdt64_to_cpu(fdt64_t x)
{
return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
}
static inline fdt64_t cpu_to_fdt64(uint64_t x)
{
return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
}
#undef CPU_TO_FDT64
#undef CPU_TO_FDT32
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE
#ifdef __APPLE__
#include <AvailabilityMacros.h>
/* strnlen() is not available on Mac OS < 10.7 */
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
MAC_OS_X_VERSION_10_7)
#define strnlen fdt_strnlen
/*
* fdt_strnlen: returns the length of a string or max_count - which ever is
* smallest.
* Input 1 string: the string whose size is to be determined
* Input 2 max_count: the maximum value returned by this function
* Output: length of the string or max_count (the smallest of the two)
*/
static inline size_t fdt_strnlen(const char *string, size_t max_count)
{
const char *p = memchr(string, 0, max_count);
return p ? p - string : max_count;
}
#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7) */
#endif /* __APPLE__ */
#endif /* LIBFDT_ENV_H */

View File

@@ -0,0 +1,137 @@
/* 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.
*/
#include <fdt.h>
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
int fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
{ \
int totalsize_; \
if (fdt_chk_basic()) { \
totalsize_ = fdt_ro_probe_(fdt); \
if (totalsize_ < 0) \
return totalsize_; \
} \
}
int fdt_check_node_offset_(const void *fdt, int offset);
int fdt_check_prop_offset_(const void *fdt, int offset);
const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
int fdt_node_end_offset_(void *fdt, int nodeoffset);
static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
{
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
}
static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
{
return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
}
static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
(const struct fdt_reserve_entry *)
((const char *)fdt + fdt_off_mem_rsvmap(fdt));
return rsv_table + n;
}
static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
{
return (void *)(uintptr_t)fdt_mem_rsv_(fdt, 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 saftey, don't enable any assumptions!
*
* For minimal code size and no safety, use FDT_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
* FDT_ASSUME_FRIENDLY.
*/
enum {
/*
* This does essentially no checks. Only the latest device-tree
* version is correctly handled. Incosistencies or errors in the device
* tree may cause undefined behaviour or crashes.
*
* 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.
*/
FDT_ASSUME_PERFECT = 0xff,
/*
* This assumes that the device tree is sane. i.e. header metadata
* and basic hierarchy are correct.
*
* These checks will be sufficient if you have a valid device tree with
* no internal inconsistencies. With this assumption, libfdt will
* generally not return -FDT_ERR_INTERNAL, -FDT_ERR_BADLAYOUT, etc.
*/
FDT_ASSUME_SANE = 1 << 0,
/*
* 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.
*/
FDT_ASSUME_LATEST = 1 << 1,
/*
* This disables any extensive checking of parameters and the device
* tree, making various assumptions about correctness. 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.
*/
FDT_ASSUME_FRIENDLY = 1 << 2,
};
/** fdt_chk_basic() - see if basic checking of params and DT data is enabled */
static inline bool fdt_chk_basic(void)
{
return !(FDT_ASSUME_MASK & FDT_ASSUME_SANE);
}
/** fdt_chk_version() - see if we need to handle old versions of the DT */
static inline bool fdt_chk_version(void)
{
return !(FDT_ASSUME_MASK & FDT_ASSUME_LATEST);
}
/** fdt_chk_extra() - see if extra checking is enabled */
static inline bool fdt_chk_extra(void)
{
return !(FDT_ASSUME_MASK & FDT_ASSUME_FRIENDLY);
}
#endif /* LIBFDT_INTERNAL_H */

1013
scripts/dtc/livetree.c Normal file

File diff suppressed because it is too large Load Diff

5
scripts/dtc/pylibfdt/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/_libfdt.*
/libfdt.py
/libfdt.pyc
/libfdt_wrap.c
/__pycache__

View File

@@ -0,0 +1,31 @@
# Unfortunately setup.py below cannot handle srctree being ".." which it often
# is. It fails with an error like:
# Fatal error: can't create build/temp.linux-x86_64-2.7/../lib/libfdt/fdt.o:
# No such file or directory
# To fix this, use an absolute path.
LIBFDT_srcdir = $(abspath $(srctree)/$(src)/../libfdt)
include $(LIBFDT_srcdir)/Makefile.libfdt
# Unfortunately setup.py (or actually the Python distutil implementation) puts
# files into the same directory as the .i file. We cannot touch the source
# directory, so we "ship" .i file into the objtree.
PYLIBFDT_srcs = $(addprefix $(LIBFDT_srcdir)/,$(LIBFDT_SRCS)) \
$(obj)/libfdt.i
quiet_cmd_pymod = PYMOD $@
cmd_pymod = unset CROSS_COMPILE; unset CFLAGS; \
CC="$(HOSTCC)" LDSHARED="$(HOSTCC) -shared " \
LDFLAGS="$(HOSTLDFLAGS)" \
VERSION="u-boot-$(UBOOTVERSION)" \
CPPFLAGS="$(HOSTCFLAGS) -I$(LIBFDT_srcdir)" OBJDIR=$(obj) \
SOURCES="$(PYLIBFDT_srcs)" \
SWIG_OPTS="-I$(LIBFDT_srcdir) -I$(LIBFDT_srcdir)/.." \
$(PYTHON3) $< --quiet build_ext --inplace
$(obj)/_libfdt.so: $(src)/setup.py $(PYLIBFDT_srcs) FORCE
$(call if_changed,pymod)
always += _libfdt.so
clean-files += libfdt.i _libfdt.so libfdt.py libfdt_wrap.c

File diff suppressed because it is too large Load Diff

123
scripts/dtc/pylibfdt/setup.py Executable file
View File

@@ -0,0 +1,123 @@
#!/usr/bin/env python3
"""
setup.py file for SWIG libfdt
Copyright (C) 2017 Google, Inc.
Written by Simon Glass <sjg@chromium.org>
SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
Files to be built into the extension are provided in SOURCES
C flags to use are provided in CPPFLAGS
Object file directory is provided in OBJDIR
Version is provided in VERSION
If these variables are not given they are parsed from the Makefiles. This
allows this script to be run stand-alone, e.g.:
./pylibfdt/setup.py install [--prefix=...]
"""
from distutils.core import setup, Extension
import os
import re
import sys
# Decodes a Makefile assignment line into key and value (and plus for +=)
RE_KEY_VALUE = re.compile('(?P<key>\w+) *(?P<plus>[+])?= *(?P<value>.*)$')
def ParseMakefile(fname):
"""Parse a Makefile to obtain its variables.
This collects variable assigments of the form:
VAR = value
VAR += more
It does not pick out := assignments, as these are not needed here. It does
handle line continuation.
Returns a dict:
key: Variable name (e.g. 'VAR')
value: Variable value (e.g. 'value more')
"""
makevars = {}
with open(fname) as fd:
prev_text = '' # Continuation text from previous line(s)
for line in fd.read().splitlines():
if line and line[-1] == '\\': # Deal with line continuation
prev_text += line[:-1]
continue
elif prev_text:
line = prev_text + line
prev_text = '' # Continuation is now used up
m = RE_KEY_VALUE.match(line)
if m:
value = m.group('value') or ''
key = m.group('key')
# Appending to a variable inserts a space beforehand
if 'plus' in m.groupdict() and key in makevars:
makevars[key] += ' ' + value
else:
makevars[key] = value
return makevars
def GetEnvFromMakefiles():
"""Scan the Makefiles to obtain the settings we need.
This assumes that this script is being run from the top-level directory,
not the pylibfdt directory.
Returns:
Tuple with:
List of swig options
Version string
List of files to build
List of extra C preprocessor flags needed
Object directory to use (always '')
"""
basedir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
swig_opts = ['-I%s' % basedir]
makevars = ParseMakefile(os.path.join(basedir, 'Makefile'))
version = '%s.%s.%s' % (makevars['VERSION'], makevars['PATCHLEVEL'],
makevars['SUBLEVEL'])
makevars = ParseMakefile(os.path.join(basedir, 'libfdt', 'Makefile.libfdt'))
files = makevars['LIBFDT_SRCS'].split()
files = [os.path.join(basedir, 'libfdt', fname) for fname in files]
files.append('pylibfdt/libfdt.i')
cflags = ['-I%s' % basedir, '-I%s/libfdt' % basedir]
objdir = ''
return swig_opts, version, files, cflags, objdir
progname = sys.argv[0]
files = os.environ.get('SOURCES', '').split()
cflags = os.environ.get('CPPFLAGS', '').split()
objdir = os.environ.get('OBJDIR')
version = os.environ.get('VERSION')
swig_opts = os.environ.get('SWIG_OPTS', '').split()
# If we were called directly rather than through our Makefile (which is often
# the case with Python module installation), read the settings from the
# Makefile.
if not all((swig_opts, version, files, cflags, objdir)):
swig_opts, version, files, cflags, objdir = GetEnvFromMakefiles()
libfdt_module = Extension(
'_libfdt',
sources = files,
extra_compile_args = cflags,
swig_opts = swig_opts,
)
setup(
name='libfdt',
version= version,
author='Simon Glass <sjg@chromium.org>',
description='Python binding for libfdt',
ext_modules=[libfdt_module],
package_dir={'': objdir},
py_modules=['pylibfdt/libfdt'],
)

297
scripts/dtc/srcpos.c Normal file
View File

@@ -0,0 +1,297 @@
/*
* 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
#include <stdio.h>
#include "dtc.h"
#include "srcpos.h"
/* A node in our list of directories to search for source/include files */
struct search_path {
struct search_path *next; /* next node in list, NULL for end */
const char *dirname; /* name of directory to search */
};
/* This is the list of directories that we search for source files */
static struct search_path *search_path_head, **search_path_tail;
static char *get_dirname(const char *path)
{
const char *slash = strrchr(path, '/');
if (slash) {
int len = slash - path;
char *dir = xmalloc(len + 1);
memcpy(dir, path, len);
dir[len] = '\0';
return dir;
}
return NULL;
}
FILE *depfile; /* = NULL */
struct srcfile_state *current_srcfile; /* = NULL */
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (100)
static int srcfile_depth; /* = 0 */
/**
* Try to open a file in a given directory.
*
* If the filename is an absolute path, then dirname is ignored. If it is a
* relative path, then we look in that directory for the file.
*
* @param dirname Directory to look in, or NULL for none
* @param fname Filename to look for
* @param fp Set to NULL if file did not open
* @return allocated filename on success (caller must free), NULL on failure
*/
static char *try_open(const char *dirname, const char *fname, FILE **fp)
{
char *fullname;
if (!dirname || fname[0] == '/')
fullname = xstrdup(fname);
else
fullname = join_path(dirname, fname);
*fp = fopen(fullname, "rb");
if (!*fp) {
free(fullname);
fullname = NULL;
}
return fullname;
}
/**
* Open a file for read access
*
* If it is a relative filename, we search the full search path for it.
*
* @param fname Filename to open
* @param fp Returns pointer to opened FILE, or NULL on failure
* @return pointer to allocated filename, which caller must free
*/
static char *fopen_any_on_path(const char *fname, FILE **fp)
{
const char *cur_dir = NULL;
struct search_path *node;
char *fullname;
/* Try current directory first */
assert(fp);
if (current_srcfile)
cur_dir = current_srcfile->dir;
fullname = try_open(cur_dir, fname, fp);
/* Failing that, try each search path in turn */
for (node = search_path_head; !*fp && node; node = node->next)
fullname = try_open(node->dirname, fname, fp);
return fullname;
}
FILE *srcfile_relative_open(const char *fname, char **fullnamep)
{
FILE *f;
char *fullname;
if (streq(fname, "-")) {
f = stdin;
fullname = xstrdup("<stdin>");
} else {
fullname = fopen_any_on_path(fname, &f);
if (!f)
die("Couldn't open \"%s\": %s\n", fname,
strerror(errno));
}
if (depfile)
fprintf(depfile, " %s", fullname);
if (fullnamep)
*fullnamep = fullname;
else
free(fullname);
return f;
}
void srcfile_push(const char *fname)
{
struct srcfile_state *srcfile;
if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
die("Includes nested too deeply");
srcfile = xmalloc(sizeof(*srcfile));
srcfile->f = srcfile_relative_open(fname, &srcfile->name);
srcfile->dir = get_dirname(srcfile->name);
srcfile->prev = current_srcfile;
srcfile->lineno = 1;
srcfile->colno = 1;
current_srcfile = srcfile;
}
bool srcfile_pop(void)
{
struct srcfile_state *srcfile = current_srcfile;
assert(srcfile);
current_srcfile = srcfile->prev;
if (fclose(srcfile->f))
die("Error closing \"%s\": %s\n", srcfile->name,
strerror(errno));
/* FIXME: We allow the srcfile_state structure to leak,
* because it could still be referenced from a location
* variable being carried through the parser somewhere. To
* fix this we could either allocate all the files from a
* table, or use a pool allocator. */
return current_srcfile ? true : false;
}
void srcfile_add_search_path(const char *dirname)
{
struct search_path *node;
/* Create the node */
node = xmalloc(sizeof(*node));
node->next = NULL;
node->dirname = xstrdup(dirname);
/* Add to the end of our list */
if (search_path_tail)
*search_path_tail = node;
else
search_path_head = node;
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;
pos->file = current_srcfile;
pos->first_line = current_srcfile->lineno;
pos->first_column = current_srcfile->colno;
for (i = 0; i < len; i++)
if (text[i] == '\n') {
current_srcfile->lineno++;
current_srcfile->colno = 1;
} else {
current_srcfile->colno++;
}
pos->last_line = current_srcfile->lineno;
pos->last_column = current_srcfile->colno;
}
struct srcpos *
srcpos_copy(struct srcpos *pos)
{
struct srcpos *pos_new;
pos_new = xmalloc(sizeof(struct srcpos));
memcpy(pos_new, pos, sizeof(struct srcpos));
return pos_new;
}
char *
srcpos_string(struct srcpos *pos)
{
const char *fname = "<no-file>";
char *pos_str;
if (pos->file && pos->file->name)
fname = pos->file->name;
if (pos->first_line != pos->last_line)
xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
else if (pos->first_column != pos->last_column)
xasprintf(&pos_str, "%s:%d.%d-%d", fname,
pos->first_line, pos->first_column,
pos->last_column);
else
xasprintf(&pos_str, "%s:%d.%d", fname,
pos->first_line, pos->first_column);
return pos_str;
}
void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)
{
char *srcstr;
srcstr = srcpos_string(pos);
fprintf(stderr, "%s: %s ", prefix, srcstr);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
free(srcstr);
}
void srcpos_error(struct srcpos *pos, const char *prefix,
const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
srcpos_verror(pos, prefix, fmt, va);
va_end(va);
}
void srcpos_set_line(char *f, int l)
{
current_srcfile->name = f;
current_srcfile->lineno = l;
}

117
scripts/dtc/srcpos.h Normal file
View File

@@ -0,0 +1,117 @@
/*
* 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
#define SRCPOS_H
#include <stdio.h>
#include <stdbool.h>
#include "util.h"
struct srcfile_state {
FILE *f;
char *name;
char *dir;
int lineno, colno;
struct srcfile_state *prev;
};
extern FILE *depfile; /* = NULL */
extern struct srcfile_state *current_srcfile; /* = NULL */
/**
* Open a source file.
*
* If the source file is a relative pathname, then it is searched for in the
* current directory (the directory of the last source file read) and after
* that in the search path.
*
* We work through the search path in order from the first path specified to
* the last.
*
* If the file is not found, then this function does not return, but calls
* die().
*
* @param fname Filename to search
* @param fullnamep If non-NULL, it is set to the allocated filename of the
* file that was opened. The caller is then responsible
* for freeing the pointer.
* @return pointer to opened FILE
*/
FILE *srcfile_relative_open(const char *fname, char **fullnamep);
void srcfile_push(const char *fname);
bool srcfile_pop(void);
/**
* Add a new directory to the search path for input files
*
* The new path is added at the end of the list.
*
* @param dirname Directory to add
*/
void srcfile_add_search_path(const char *dirname);
struct srcpos {
int first_line;
int first_column;
int last_line;
int last_column;
struct srcfile_state *file;
};
#define YYLTYPE struct srcpos
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (N) { \
(Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC(Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
(Current).file = YYRHSLOC(Rhs, N).file; \
} else { \
(Current).first_line = (Current).last_line = \
YYRHSLOC(Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
} 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 char *srcpos_string(struct srcpos *pos);
extern void PRINTF(3, 0) srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va);
extern void PRINTF(3, 4) srcpos_error(struct srcpos *pos, const char *prefix,
const char *fmt, ...);
extern void srcpos_set_line(char *f, int l);
#endif /* SRCPOS_H */

284
scripts/dtc/treesource.c Normal file
View File

@@ -0,0 +1,284 @@
/*
* (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"
extern FILE *yyin;
extern int yyparse(void);
extern YYLTYPE yylloc;
struct dt_info *parser_output;
bool treesource_error;
struct dt_info *dt_from_source(const char *fname)
{
parser_output = NULL;
treesource_error = false;
srcfile_push(fname);
yyin = current_srcfile->f;
yylloc.file = current_srcfile;
if (yyparse() != 0)
die("Unable to parse input tree\n");
if (treesource_error)
die("Syntax error parsing input tree\n");
return parser_output;
}
static void write_prefix(FILE *f, int level)
{
int i;
for (i = 0; i < level; i++)
fputc('\t', f);
}
static bool isstring(char c)
{
return (isprint((unsigned char)c)
|| (c == '\0')
|| strchr("\a\b\t\n\v\f\r", c));
}
static void write_propval_string(FILE *f, struct data val)
{
const char *str = val.val;
int i;
struct marker *m = val.markers;
assert(str[val.len-1] == '\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];
switch (c) {
case '\a':
fprintf(f, "\\a");
break;
case '\b':
fprintf(f, "\\b");
break;
case '\t':
fprintf(f, "\\t");
break;
case '\n':
fprintf(f, "\\n");
break;
case '\v':
fprintf(f, "\\v");
break;
case '\f':
fprintf(f, "\\f");
break;
case '\r':
fprintf(f, "\\r");
break;
case '\\':
fprintf(f, "\\\\");
break;
case '\"':
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, "\"");
break;
default:
if (isprint((unsigned char)c))
fprintf(f, "%c", c);
else
fprintf(f, "\\x%02hhx", 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)
{
void *propend = val.val + val.len;
fdt32_t *cp = (fdt32_t *)val.val;
struct marker *m = val.markers;
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)
break;
fprintf(f, " ");
}
/* Wrap up any labels at the end of the value */
for_each_marker_of_type(m, LABEL) {
assert (m->offset == val.len);
fprintf(f, " %s:", m->ref);
}
fprintf(f, ">");
}
static void write_propval_bytes(FILE *f, struct data val)
{
void *propend = val.val + val.len;
const char *bp = val.val;
struct marker *m = val.markers;
fprintf(f, "[");
for (;;) {
while (m && (m->offset == (bp-val.val))) {
if (m->type == LABEL)
fprintf(f, "%s: ", m->ref);
m = m->next;
}
fprintf(f, "%02hhx", (unsigned char)(*bp++));
if ((const void *)bp >= propend)
break;
fprintf(f, " ");
}
/* Wrap up any labels at the end of the value */
for_each_marker_of_type(m, LABEL) {
assert (m->offset == val.len);
fprintf(f, " %s:", m->ref);
}
fprintf(f, "]");
}
static void write_propval(FILE *f, struct property *prop)
{
int len = prop->val.len;
const char *p = prop->val.val;
struct marker *m = prop->val.markers;
int nnotstring = 0, nnul = 0;
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++;
if (p[i] == '\0')
nnul++;
}
for_each_marker_of_type(m, LABEL) {
if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
nnotstringlbl++;
if ((m->offset % sizeof(cell_t)) != 0)
nnotcelllbl++;
}
fprintf(f, " = ");
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
&& (nnotstringlbl == 0)) {
write_propval_string(f, prop->val);
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
write_propval_cells(f, prop->val);
} else {
write_propval_bytes(f, prop->val);
}
fprintf(f, ";\n");
}
static void write_tree_source_node(FILE *f, struct node *tree, int level)
{
struct property *prop;
struct node *child;
struct label *l;
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);
else
fprintf(f, "/ {\n");
for_each_property(tree, prop) {
write_prefix(f, level+1);
for_each_label(prop->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "%s", prop->name);
write_propval(f, prop);
}
for_each_child(tree, child) {
fprintf(f, "\n");
write_tree_source_node(f, child, level+1);
}
write_prefix(f, level);
fprintf(f, "};\n");
}
void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
fprintf(f, "/dts-v1/;\n\n");
for (re = dti->reservelist; re; re = re->next) {
struct label *l;
for_each_label(re->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
(unsigned long long)re->address,
(unsigned long long)re->size);
}
write_tree_source_node(f, dti->dt, 0);
}

View File

@@ -0,0 +1,79 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Simple script to update the version of DTC carried by the Linux kernel
#
# This script assumes that the dtc and the linux git trees are in the
# same directory. After building dtc in the dtc directory, it copies the
# source files and generated source file(s) into the scripts/dtc directory
# in the kernel and creates a git commit updating them to the new
# version.
#
# Usage: from the top level Linux source tree, run:
# $ ./scripts/dtc/update-dtc-source.sh
#
# The script will change into the dtc tree, build and test dtc, copy the
# relevant files into the kernel tree and create a git commit. The commit
# message will need to be modified to reflect the version of DTC being
# imported
#
# TODO:
# This script is pretty basic, but it is seldom used so a few manual tasks
# aren't a big deal. If anyone is interested in making it more robust, the
# the following would be nice:
# * Actually fail to complete if any testcase fails.
# - The dtc "make check" target needs to return a failure
# * Extract the version number from the dtc repo for the commit message
# * Build dtc in the kernel tree
# * run 'make check" on dtc built from the kernel tree
set -ev
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 \
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 \
fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h"
get_last_dtc_version() {
git log --oneline scripts/dtc/ | grep 'upstream' | head -1 | sed -e 's/^.* \(.*\)/\1/'
}
last_dtc_ver=$(get_last_dtc_version)
# Build DTC
cd $DTC_UPSTREAM_PATH
make clean
make check
dtc_version=$(git describe HEAD)
dtc_log=$(git log --oneline ${last_dtc_ver}..)
# Copy the files into the Linux tree
cd $DTC_LINUX_PATH
for f in $DTC_SOURCE; do
cp ${DTC_UPSTREAM_PATH}/${f} ${f}
git add ${f}
done
for f in $LIBFDT_SOURCE; do
cp ${DTC_UPSTREAM_PATH}/libfdt/${f} libfdt/${f}
git add libfdt/${f}
done
sed -i -- 's/#include <libfdt_env.h>/#include "libfdt_env.h"/g' ./libfdt/libfdt.h
sed -i -- 's/#include <fdt.h>/#include "fdt.h"/g' ./libfdt/libfdt.h
git add ./libfdt/libfdt.h
commit_msg=$(cat << EOF
scripts/dtc: Update to upstream version ${dtc_version}
This adds the following commits from upstream:
${dtc_log}
EOF
)
git commit -e -v -s -m "${commit_msg}"

474
scripts/dtc/util.c Normal file
View File

@@ -0,0 +1,474 @@
/*
* 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>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "libfdt.h"
#include "util.h"
#include "version_gen.h"
char *xstrdup(const char *s)
{
int len = strlen(s) + 1;
char *d = xmalloc(len);
memcpy(d, s, len);
return d;
}
/* based in part from (3) vsnprintf */
int xasprintf(char **strp, const char *fmt, ...)
{
int n, size = 128; /* start with 128 bytes */
char *p;
va_list ap;
/* initial pointer is NULL making the fist realloc to be malloc */
p = NULL;
while (1) {
p = xrealloc(p, size);
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(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);
}
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
bool util_is_printable_string(const void *data, int len)
{
const char *s = data;
const char *ss, *se;
/* zero length is not */
if (len == 0)
return 0;
/* must terminate with zero */
if (s[len - 1] != '\0')
return 0;
se = s + len;
while (s < se) {
ss = s;
while (s < se && *s && isprint((unsigned char)*s))
s++;
/* not zero, or not done yet */
if (*s != '\0' || s == ss)
return 0;
s++;
}
return 1;
}
/*
* Parse a octal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static char get_oct_char(const char *s, int *i)
{
char x[4];
char *endx;
long val;
x[3] = '\0';
strncpy(x, s + *i, 3);
val = strtol(x, &endx, 8);
assert(endx > x);
(*i) += endx - x;
return val;
}
/*
* Parse a hexadecimal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static char get_hex_char(const char *s, int *i)
{
char x[3];
char *endx;
long val;
x[2] = '\0';
strncpy(x, s + *i, 2);
val = strtol(x, &endx, 16);
if (!(endx > x))
die("\\x used with no following hex digits\n");
(*i) += endx - x;
return val;
}
char get_escape_char(const char *s, int *i)
{
char c = s[*i];
int j = *i + 1;
char val;
switch (c) {
case 'a':
val = '\a';
break;
case 'b':
val = '\b';
break;
case 't':
val = '\t';
break;
case 'n':
val = '\n';
break;
case 'v':
val = '\v';
break;
case 'f':
val = '\f';
break;
case 'r':
val = '\r';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
j--; /* need to re-read the first digit as
* part of the octal value */
val = get_oct_char(s, &j);
break;
case 'x':
val = get_hex_char(s, &j);
break;
default:
val = c;
}
(*i) = j;
return val;
}
int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
{
int fd = 0; /* assume stdin */
char *buf = NULL;
off_t bufsize = 1024, offset = 0;
int ret = 0;
*buffp = NULL;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_RDONLY);
if (fd < 0)
return errno;
}
/* Loop until we have read everything */
buf = xmalloc(bufsize);
do {
/* Expand the buffer to hold the next chunk */
if (offset == bufsize) {
bufsize *= 2;
buf = xrealloc(buf, bufsize);
}
ret = read(fd, &buf[offset], bufsize - offset);
if (ret < 0) {
ret = errno;
break;
}
offset += ret;
} while (ret != 0);
/* Clean up, including closing stdin; return errno on error */
close(fd);
if (ret)
free(buf);
else
*buffp = buf;
*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 *buff;
int ret = utilfdt_read_err_len(filename, &buff, len);
if (ret) {
fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
strerror(ret));
return NULL;
}
/* Successful read */
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 */
int totalsize;
int offset;
int ret = 0;
const char *ptr = blob;
if (strcmp(filename, "-") != 0) {
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
return errno;
}
totalsize = fdt_totalsize(blob);
offset = 0;
while (offset < totalsize) {
ret = write(fd, ptr + offset, totalsize - offset);
if (ret < 0) {
ret = -errno;
break;
}
offset += ret;
}
/* Close the file/stdin; return errno on error */
if (fd != 1)
close(fd);
return ret < 0 ? -ret : 0;
}
int utilfdt_write(const char *filename, const void *blob)
{
int ret = utilfdt_write_err(filename, blob);
if (ret) {
fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
strerror(ret));
}
return ret ? -1 : 0;
}
int utilfdt_decode_type(const char *fmt, int *type, int *size)
{
int qualifier = 0;
if (!*fmt)
return -1;
/* get the conversion qualifier */
*size = -1;
if (strchr("hlLb", *fmt)) {
qualifier = *fmt++;
if (qualifier == *fmt) {
switch (*fmt++) {
/* TODO: case 'l': qualifier = 'L'; break;*/
case 'h':
qualifier = 'b';
break;
}
}
}
/* we should now have a type */
if ((*fmt == '\0') || !strchr("iuxs", *fmt))
return -1;
/* convert qualifier (bhL) to byte size */
if (*fmt != 's')
*size = qualifier == 'b' ? 1 :
qualifier == 'h' ? 2 :
qualifier == 'l' ? 4 : -1;
*type = *fmt++;
/* that should be it! */
if (*fmt)
return -1;
return 0;
}
void utilfdt_print_data(const char *data, int len)
{
int i;
const char *s;
/* no data, don't print */
if (len == 0)
return;
if (util_is_printable_string(data, len)) {
printf(" = ");
s = data;
do {
printf("\"%s\"", s);
s += strlen(s) + 1;
if (s < data + len)
printf(", ");
} while (s < data + len);
} else if ((len % 4) == 0) {
const fdt32_t *cell = (const fdt32_t *)data;
printf(" = <");
for (i = 0, len /= 4; i < len; i++)
printf("0x%08x%s", fdt32_to_cpu(cell[i]),
i < (len - 1) ? " " : "");
printf(">");
} else {
const unsigned char *p = (const unsigned char *)data;
printf(" = [");
for (i = 0; i < len; i++)
printf("%02x%s", *p++, i < len - 1 ? " " : "");
printf("]");
}
}
void NORETURN util_version(void)
{
printf("Version: %s\n", DTC_VERSION);
exit(0);
}
void NORETURN util_usage(const char *errmsg, const char *synopsis,
const char *short_opts,
struct option const long_opts[],
const char * const opts_help[])
{
FILE *fp = errmsg ? stderr : stdout;
const char a_arg[] = "<arg>";
size_t a_arg_len = strlen(a_arg) + 1;
size_t i;
int optlen;
fprintf(fp,
"Usage: %s\n"
"\n"
"Options: -[%s]\n", synopsis, short_opts);
/* prescan the --long opt length to auto-align */
optlen = 0;
for (i = 0; long_opts[i].name; ++i) {
/* +1 is for space between --opt and help text */
int l = strlen(long_opts[i].name) + 1;
if (long_opts[i].has_arg == a_argument)
l += a_arg_len;
if (optlen < l)
optlen = l;
}
for (i = 0; long_opts[i].name; ++i) {
/* helps when adding new applets or options */
assert(opts_help[i] != NULL);
/* first output the short flag if it has one */
if (long_opts[i].val > '~')
fprintf(fp, " ");
else
fprintf(fp, " -%c, ", long_opts[i].val);
/* then the long flag */
if (long_opts[i].has_arg == no_argument)
fprintf(fp, "--%-*s", optlen, long_opts[i].name);
else
fprintf(fp, "--%s %s%*s", long_opts[i].name, a_arg,
(int)(optlen - strlen(long_opts[i].name) - a_arg_len), "");
/* finally the help text */
fprintf(fp, "%s\n", opts_help[i]);
}
if (errmsg) {
fprintf(fp, "\nError: %s\n", errmsg);
exit(EXIT_FAILURE);
} else
exit(EXIT_SUCCESS);
}

266
scripts/dtc/util.h Normal file
View File

@@ -0,0 +1,266 @@
#ifndef UTIL_H
#define UTIL_H
#include <stdarg.h>
#include <stdbool.h>
#include <getopt.h>
/*
* 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__
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
#define NORETURN __attribute__((noreturn))
#else
#define PRINTF(i, j)
#define NORETURN
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define stringify(s) stringify_(s)
#define stringify_(s) #s
static inline void NORETURN PRINTF(1, 2) die(const char *str, ...)
{
va_list ap;
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, ap);
va_end(ap);
exit(1);
}
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
if (!new)
die("malloc() failed\n");
return new;
}
static inline void *xrealloc(void *p, size_t len)
{
void *new = realloc(p, len);
if (!new)
die("realloc() failed (len=%zd)\n", len);
return new;
}
extern char *xstrdup(const char *s);
extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...);
extern char *join_path(const char *path, const char *name);
/**
* Check a property of a given length to see if it is all printable and
* has a valid terminator. The property can contain either a single string,
* or multiple strings each of non-zero length.
*
* @param data The string to check
* @param len The string length including terminator
* @return 1 if a valid printable string, 0 if not
*/
bool util_is_printable_string(const void *data, int len);
/*
* Parse an escaped character starting at index i in string s. The resulting
* character will be returned and the index i will be updated to point at the
* character directly after the end of the encoding, this may be the '\0'
* terminator of the string.
*/
char get_escape_char(const char *s, int *i);
/**
* Read a device tree file into a buffer. This will report any errors on
* stderr.
*
* @param filename The filename to read, or - for stdin
* @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);
/**
* Read a device tree file into a buffer. Does not report errors, but only
* returns them. The value returned can be passed to strerror() to obtain
* an error message for the user.
*
* @param filename The filename to read, or - for stdin
* @param buffp Returns pointer to buffer containing fdt
* @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);
/**
* 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
* @return 0 if ok, -1 on error
*/
int utilfdt_write(const char *filename, const void *blob);
/**
* Write a device tree buffer to a file. Does not report errors, but only
* returns them. The value returned can be passed to strerror() to obtain
* an error message for the user.
*
* @param filename The filename to write, or - for stdout
* @param blob Poiner 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);
/**
* Decode a data type string. The purpose of this string
*
* The string consists of an optional character followed by the type:
* Modifier characters:
* hh or b 1 byte
* h 2 byte
* l 4 byte, default
*
* Type character:
* s string
* i signed integer
* u unsigned integer
* x hex
*
* TODO: Implement ll modifier (8 bytes)
* TODO: Implement o type (octal)
*
* @param fmt Format string to process
* @param type Returns type found(s/d/u/x), or 0 if none
* @param size Returns size found(1,2,4,8) or 4 if none
* @return 0 if ok, -1 on error (no type given, or other invalid format)
*/
int utilfdt_decode_type(const char *fmt, int *type, int *size);
/*
* This is a usage message fragment for the -t option. It is the format
* supported by utilfdt_decode_type.
*/
#define USAGE_TYPE_MSG \
"<type>\ts=string, i=int, u=unsigned, x=hex\n" \
"\tOptional modifier prefix:\n" \
"\t\thh or b=byte, h=2 byte, l=4 byte (default)";
/**
* Print property data in a readable format to stdout
*
* Properties that look like strings will be printed as strings. Otherwise
* the data will be displayed either as cells (if len is a multiple of 4
* bytes) or bytes.
*
* If len is 0 then this function does nothing.
*
* @param data Pointers to property data
* @param len Length of property data
*/
void utilfdt_print_data(const char *data, int len);
/**
* Show source version and exit
*/
void NORETURN util_version(void);
/**
* Show usage and exit
*
* This helps standardize the output of various utils. You most likely want
* to use the usage() helper below rather than call this.
*
* @param errmsg If non-NULL, an error message to display
* @param synopsis The initial example usage text (and possible examples)
* @param short_opts The string of short options
* @param long_opts The structure of long options
* @param opts_help An array of help strings (should align with long_opts)
*/
void NORETURN util_usage(const char *errmsg, const char *synopsis,
const char *short_opts,
struct option const long_opts[],
const char * const opts_help[]);
/**
* Show usage and exit
*
* If you name all your usage variables with usage_xxx, then you can call this
* help macro rather than expanding all arguments yourself.
*
* @param errmsg If non-NULL, an error message to display
*/
#define usage(errmsg) \
util_usage(errmsg, usage_synopsis, usage_short_opts, \
usage_long_opts, usage_opts_help)
/**
* Call getopt_long() with standard options
*
* Since all util code runs getopt in the same way, provide a helper.
*/
#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
usage_long_opts, NULL)
/* Helper for aligning long_opts array */
#define a_argument required_argument
/* Helper for usage_short_opts string constant */
#define USAGE_COMMON_SHORT_OPTS "hV"
/* Helper for usage_long_opts option array */
#define USAGE_COMMON_LONG_OPTS \
{"help", no_argument, NULL, 'h'}, \
{"version", no_argument, NULL, 'V'}, \
{NULL, no_argument, NULL, 0x0}
/* Helper for usage_opts_help array */
#define USAGE_COMMON_OPTS_HELP \
"Print this help and exit", \
"Print version and exit", \
NULL
/* Helper for getopt case statements */
#define case_USAGE_COMMON_FLAGS \
case 'h': usage(NULL); \
case 'V': util_version(); \
case '?': usage("unknown option");
#endif /* UTIL_H */

View File

@@ -0,0 +1 @@
#define DTC_VERSION "DTC 1.4.6-gaadd0b65"

17
scripts/gcc-stack-usage.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0+
# Test for gcc '-fstack-usage' support
# Copyright (C) 2013, Masahiro Yamada <yamada.m@jp.panasonic.com>
#
TMP="$$"
cat <<END | $@ -Werror -fstack-usage -x c - -c -o $TMP >/dev/null 2>&1 \
&& echo "y"
int main(void)
{
return 0;
}
END
rm -f $TMP $TMP.su

32
scripts/gcc-version.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/bin/sh
#
# gcc-version [-p] gcc-command
#
# Prints the gcc version of `gcc-command' in a canonical 4-digit form
# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc.
#
# With the -p option, prints the patchlevel as well, for example `029503' for
# gcc-2.95.3, `030301' for gcc-3.3.1, etc.
#
if [ "$1" = "-p" ] ; then
with_patchlevel=1;
shift;
fi
compiler="$*"
if [ ${#compiler} -eq 0 ]; then
echo "Error: No compiler specified."
printf "Usage:\n\t$0 <gcc-command>\n"
exit 1
fi
MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1)
MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1)
if [ "x$with_patchlevel" != "x" ] ; then
PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1)
printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
else
printf "%02d%02d\\n" $MAJOR $MINOR
fi

42
scripts/get_default_envs.sh Executable file
View File

@@ -0,0 +1,42 @@
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2016, Lukasz Majewski <l.majewski@majess.pl>
#
# This file extracts default envs from built u-boot
# usage: get_default_envs.sh [build dir] > u-boot-env-default.txt
set -ue
: "${OBJCOPY:=${CROSS_COMPILE:-}objcopy}"
ENV_OBJ_FILE="built-in.o"
ENV_OBJ_FILE_COPY="copy_${ENV_OBJ_FILE}"
echoerr() { echo "$@" 1>&2; }
if [ "$#" -eq 1 ]; then
path=${1}
else
path=$(readlink -f $0)
path=${path%/scripts*}
fi
env_obj_file_path=$(find ${path} -path "*/env/*" -not -path "*/spl/*" \
-not -path "*/tools/*" -name "${ENV_OBJ_FILE}")
[ -z "${env_obj_file_path}" ] && \
{ echoerr "File '${ENV_OBJ_FILE}' not found!"; exit 1; }
cp ${env_obj_file_path} ${ENV_OBJ_FILE_COPY}
# NOTE: objcopy saves its output to file passed in
# (copy_${ENV_OBJ_FILE} in this case)
${OBJCOPY} -O binary -j ".rodata.default_environment" ${ENV_OBJ_FILE_COPY}
# Replace default '\0' with '\n' and sort entries
tr '\0' '\n' < ${ENV_OBJ_FILE_COPY} | sort -u
rm ${ENV_OBJ_FILE_COPY}
exit 0

2554
scripts/get_maintainer.pl Executable file

File diff suppressed because it is too large Load Diff

17
scripts/kconfig/.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
#
# Generated files
#
*.moc
gconf.glade.h
*.pot
*.mo
#
# configuration programs
#
conf
mconf
nconf
qconf
gconf
kxgettext

322
scripts/kconfig/Makefile Normal file
View File

@@ -0,0 +1,322 @@
# SPDX-License-Identifier: GPL-2.0
# ===========================================================================
# Kernel configuration targets
# These targets are used from top-level makefile
PHONY += xconfig gconfig menuconfig config syncconfig update-po-config \
localmodconfig localyesconfig
# Added for U-Boot
# Linux has defconfig files in arch/$(SRCARCH)/configs/,
# on the other hand, U-Boot does in configs/.
# Set SRCARCH to .. fake this Makefile.
SRCARCH := ..
ifdef KBUILD_KCONFIG
Kconfig := $(KBUILD_KCONFIG)
else
Kconfig := Kconfig
endif
ifeq ($(quiet),silent_)
silent := -s
endif
# We need this, in case the user has it in its environment
unexport CONFIG_
xconfig: $(obj)/qconf
$< $(silent) $(Kconfig)
gconfig: $(obj)/gconf
$< $(silent) $(Kconfig)
menuconfig: $(obj)/mconf
$< $(silent) $(Kconfig)
config: $(obj)/conf
$< $(silent) --oldaskconfig $(Kconfig)
nconfig: $(obj)/nconf
$< $(silent) $(Kconfig)
# This has become an internal implementation detail and is now deprecated
# for external use.
syncconfig: $(obj)/conf
$(Q)mkdir -p include/config include/generated
$< $(silent) --$@ $(Kconfig)
localyesconfig localmodconfig: $(obj)/conf
$(Q)mkdir -p include/config include/generated
$(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
$(Q)if [ -f .config ]; then \
cmp -s .tmp.config .config || \
(mv -f .config .config.old.1; \
mv -f .tmp.config .config; \
$< $(silent) --oldconfig $(Kconfig); \
mv -f .config.old.1 .config.old) \
else \
mv -f .tmp.config .config; \
$< $(silent) --oldconfig $(Kconfig); \
fi
$(Q)rm -f .tmp.config
# Create new linux.pot file
# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
$(Q)$(kecho) " GEN config.pot"
$(Q)xgettext --default-domain=linux \
--add-comments --keyword=_ --keyword=N_ \
--from-code=UTF-8 \
--files-from=$(srctree)/scripts/kconfig/POTFILES.in \
--directory=$(srctree) --directory=$(objtree) \
--output $(obj)/config.pot
$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
$(Q)(for i in `ls $(srctree)/arch/*/Kconfig \
$(srctree)/arch/*/um/Kconfig`; \
do \
$(kecho) " GEN $$i"; \
$(obj)/kxgettext $$i \
>> $(obj)/config.pot; \
done )
$(Q)$(kecho) " GEN linux.pot"
$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
--output $(obj)/linux.pot
$(Q)rm -f $(obj)/config.pot
# These targets map 1:1 to the commandline options of 'conf'
simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
alldefconfig randconfig listnewconfig olddefconfig
PHONY += $(simple-targets)
$(simple-targets): $(obj)/conf
$< $(silent) --$@ $(Kconfig)
PHONY += oldnoconfig silentoldconfig savedefconfig defconfig
# oldnoconfig is an alias of olddefconfig, because people already are dependent
# on its behavior (sets new symbols to their default value but not 'n') with the
# counter-intuitive name.
oldnoconfig: olddefconfig
@echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
@echo " Please use \"olddefconfig\" instead, which is an alias."
# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig").
silentoldconfig: syncconfig
@echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\""
@echo " and is now an internal implementation detail."
@echo " What you want is probably \"oldconfig\"."
@echo " \"silentoldconfig\" will be removed after Linux 4.19"
savedefconfig: $(obj)/conf
$< $(silent) --$@=defconfig $(Kconfig)
defconfig: $(obj)/conf
ifeq ($(KBUILD_DEFCONFIG),)
$< $(silent) --defconfig $(Kconfig)
else
ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
@$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
else
@$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'"
$(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG)
endif
endif
%_defconfig: $(obj)/conf
$(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
# Added for U-Boot (backward compatibility)
%_config: %_defconfig
@:
configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/configs/$@)
%.config: $(obj)/conf
$(if $(call configfiles),, $(error No configuration exists for this target on this architecture))
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles)
+$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig
PHONY += kvmconfig
kvmconfig: kvm_guest.config
@:
PHONY += xenconfig
xenconfig: xen.config
@:
PHONY += tinyconfig
tinyconfig:
$(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
# CHECK: -o cache_dir=<path> working?
PHONY += testconfig
testconfig: $(obj)/conf
$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
-o cache_dir=$(abspath $(obj)/tests/.cache) \
$(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
clean-dirs += tests/.cache
# Help text used by make help
help:
@echo ' config - Update current config utilising a line-oriented program'
@echo ' nconfig - Update current config utilising a ncurses menu based'
@echo ' program'
@echo ' menuconfig - Update current config utilising a menu based program'
@echo ' xconfig - Update current config utilising a Qt based front-end'
@echo ' gconfig - Update current config utilising a GTK+ based front-end'
@echo ' oldconfig - Update current config utilising a provided .config as base'
@echo ' localmodconfig - Update current config disabling modules not loaded'
@echo ' localyesconfig - Update current config converting local mods to core'
@echo ' defconfig - New config with default from ARCH supplied defconfig'
@echo ' savedefconfig - Save current config as ./defconfig (minimal config)'
@echo ' allnoconfig - New config where all options are answered with no'
@echo ' allyesconfig - New config where all options are accepted with yes'
@echo ' allmodconfig - New config selecting modules when possible'
@echo ' alldefconfig - New config with all symbols set to default'
@echo ' randconfig - New config with random answer to all options'
@echo ' listnewconfig - List new options'
@echo ' olddefconfig - Same as oldconfig but sets new symbols to their'
@echo ' default value without prompting'
# @echo ' kvmconfig - Enable additional options for kvm guest kernel support'
# @echo ' xenconfig - Enable additional options for xen dom0 and guest kernel support'
# @echo ' tinyconfig - Configure the tiniest possible kernel'
# lxdialog stuff
check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
# Use recursively expanded variables so we do not call gcc unless
# we really need to do so. (Do not call gcc as part of make mrproper)
HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
-DLOCALE
# ===========================================================================
# Shared Makefile for the various kconfig executables:
# conf: Used for defconfig, oldconfig and related targets
# nconf: Used for the nconfig target.
# Utilizes ncurses
# mconf: Used for the menuconfig target
# Utilizes the lxdialog package
# qconf: Used for the xconfig target
# Based on Qt which needs to be installed to compile it
# gconf: Used for the gconfig target
# Based on GTK+ which needs to be installed to compile it
# object files used by all kconfig flavours
lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
conf-objs := conf.o zconf.tab.o
mconf-objs := mconf.o zconf.tab.o $(lxdialog)
nconf-objs := nconf.o zconf.tab.o nconf.gui.o
kxgettext-objs := kxgettext.o zconf.tab.o
qconf-cxxobjs := qconf.o
qconf-objs := zconf.tab.o
gconf-objs := gconf.o zconf.tab.o
hostprogs-y := conf nconf mconf kxgettext qconf gconf
targets += zconf.lex.c
clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck
clean-files += gconf.glade.h
clean-files += config.pot linux.pot
# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
PHONY += $(obj)/dochecklxdialog
$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/dochecklxdialog
$(obj)/dochecklxdialog:
$(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
always := dochecklxdialog
# Add environment specific flags
HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
HOST_EXTRACXXFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCXX) $(HOSTCXXFLAGS))
# generated files seem to need this to find local include files
HOSTCFLAGS_zconf.lex.o := -I$(src)
HOSTCFLAGS_zconf.tab.o := -I$(src)
HOSTLOADLIBES_qconf = $(KC_QT_LIBS)
HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS)
HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
-Wno-missing-prototypes
HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
HOSTLOADLIBES_nconf = $(shell \
pkg-config --libs menuw panelw ncursesw 2>/dev/null \
|| pkg-config --libs menu panel ncurses 2>/dev/null \
|| echo "-lmenu -lpanel -lncurses" )
$(obj)/qconf.o: $(obj)/.tmp_qtcheck
ifeq ($(MAKECMDGOALS),xconfig)
$(obj)/.tmp_qtcheck: $(src)/Makefile
-include $(obj)/.tmp_qtcheck
# Qt needs some extra effort...
$(obj)/.tmp_qtcheck:
@set -e; $(kecho) " CHECK qt"; \
if pkg-config --exists Qt5Core; then \
cflags="-std=c++11 -fPIC `pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets`"; \
libs=`pkg-config --libs Qt5Core Qt5Gui Qt5Widgets`; \
moc=`pkg-config --variable=host_bins Qt5Core`/moc; \
elif pkg-config --exists QtCore; then \
cflags=`pkg-config --cflags QtCore QtGui`; \
libs=`pkg-config --libs QtCore QtGui`; \
moc=`pkg-config --variable=moc_location QtCore`; \
else \
echo >&2 "*"; \
echo >&2 "* Could not find Qt via pkg-config."; \
echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH"; \
echo >&2 "*"; \
exit 1; \
fi; \
echo "KC_QT_CFLAGS=$$cflags" > $@; \
echo "KC_QT_LIBS=$$libs" >> $@; \
echo "KC_QT_MOC=$$moc" >> $@
endif
$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
ifeq ($(MAKECMDGOALS),gconfig)
-include $(obj)/.tmp_gtkcheck
# GTK+ needs some extra effort, too...
$(obj)/.tmp_gtkcheck:
@if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \
if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \
touch $@; \
else \
echo >&2 "*"; \
echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \
echo >&2 "*"; \
false; \
fi \
else \
echo >&2 "*"; \
echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \
echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \
echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \
echo >&2 "*"; \
false; \
fi
endif
$(obj)/zconf.tab.o: $(obj)/zconf.lex.c
$(obj)/qconf.o: $(obj)/qconf.moc
quiet_cmd_moc = MOC $@
cmd_moc = $(KC_QT_MOC) -i $< -o $@
$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
$(call cmd,moc)
# Extract gconf menu items for i18n support
$(obj)/gconf.glade.h: $(obj)/gconf.glade
$(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
$(obj)/gconf.glade

View File

@@ -0,0 +1,12 @@
scripts/kconfig/lxdialog/checklist.c
scripts/kconfig/lxdialog/inputbox.c
scripts/kconfig/lxdialog/menubox.c
scripts/kconfig/lxdialog/textbox.c
scripts/kconfig/lxdialog/util.c
scripts/kconfig/lxdialog/yesno.c
scripts/kconfig/mconf.c
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/gconf.c
scripts/kconfig/gconf.glade.h
scripts/kconfig/qconf.cc

14
scripts/kconfig/check.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Needed for systems without gettext
$* -x c -o /dev/null - > /dev/null 2>&1 << EOF
#include <libintl.h>
int main()
{
gettext("");
return 0;
}
EOF
if [ ! "$?" -eq "0" ]; then
echo -DKBUILD_NO_NLS;
fi

717
scripts/kconfig/conf.c Normal file
View File

@@ -0,0 +1,717 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <locale.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include "lkc.h"
static void conf(struct menu *menu);
static void check_conf(struct menu *menu);
enum input_mode {
oldaskconfig,
syncconfig,
oldconfig,
allnoconfig,
allyesconfig,
allmodconfig,
alldefconfig,
randconfig,
defconfig,
savedefconfig,
listnewconfig,
olddefconfig,
};
static enum input_mode input_mode = oldaskconfig;
static int indent = 1;
static int tty_stdio;
static int sync_kconfig;
static int conf_cnt;
static char line[PATH_MAX];
static struct menu *rootEntry;
static void print_help(struct menu *menu)
{
struct gstr help = str_new();
menu_get_ext_help(menu, &help);
printf("\n%s\n", str_get(&help));
str_free(&help);
}
static void strip(char *str)
{
char *p = str;
int l;
while ((isspace(*p)))
p++;
l = strlen(p);
if (p != str)
memmove(str, p, l + 1);
if (!l)
return;
p = str + l - 1;
while ((isspace(*p)))
*p-- = 0;
}
/* Helper function to facilitate fgets() by Jean Sacren. */
static void xfgets(char *str, int size, FILE *in)
{
if (!fgets(str, size, in))
fprintf(stderr, "\nError in reading or end of file.\n");
if (!tty_stdio)
printf("%s", str);
}
static int conf_askvalue(struct symbol *sym, const char *def)
{
enum symbol_type type = sym_get_type(sym);
if (!sym_has_value(sym))
printf(_("(NEW) "));
line[0] = '\n';
line[1] = 0;
if (!sym_is_changable(sym)) {
printf("%s\n", def);
line[0] = '\n';
line[1] = 0;
return 0;
}
switch (input_mode) {
case oldconfig:
case syncconfig:
if (sym_has_value(sym)) {
printf("%s\n", def);
return 0;
}
/* fall through */
case oldaskconfig:
fflush(stdout);
xfgets(line, sizeof(line), stdin);
return 1;
default:
break;
}
switch (type) {
case S_INT:
case S_HEX:
case S_STRING:
printf("%s\n", def);
return 1;
default:
;
}
printf("%s", line);
return 1;
}
static int conf_string(struct menu *menu)
{
struct symbol *sym = menu->sym;
const char *def;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
printf("(%s) ", sym->name);
def = sym_get_string_value(sym);
if (sym_get_string_value(sym))
printf("[%s] ", def);
if (!conf_askvalue(sym, def))
return 0;
switch (line[0]) {
case '\n':
break;
case '?':
/* print help */
if (line[1] == '\n') {
print_help(menu);
def = NULL;
break;
}
/* fall through */
default:
line[strlen(line)-1] = 0;
def = line;
}
if (def && sym_set_string_value(sym, def))
return 0;
}
}
static int conf_sym(struct menu *menu)
{
struct symbol *sym = menu->sym;
tristate oldval, newval;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
if (sym->name)
printf("(%s) ", sym->name);
putchar('[');
oldval = sym_get_tristate_value(sym);
switch (oldval) {
case no:
putchar('N');
break;
case mod:
putchar('M');
break;
case yes:
putchar('Y');
break;
}
if (oldval != no && sym_tristate_within_range(sym, no))
printf("/n");
if (oldval != mod && sym_tristate_within_range(sym, mod))
printf("/m");
if (oldval != yes && sym_tristate_within_range(sym, yes))
printf("/y");
printf("/?] ");
if (!conf_askvalue(sym, sym_get_string_value(sym)))
return 0;
strip(line);
switch (line[0]) {
case 'n':
case 'N':
newval = no;
if (!line[1] || !strcmp(&line[1], "o"))
break;
continue;
case 'm':
case 'M':
newval = mod;
if (!line[1])
break;
continue;
case 'y':
case 'Y':
newval = yes;
if (!line[1] || !strcmp(&line[1], "es"))
break;
continue;
case 0:
newval = oldval;
break;
case '?':
goto help;
default:
continue;
}
if (sym_set_tristate_value(sym, newval))
return 0;
help:
print_help(menu);
}
}
static int conf_choice(struct menu *menu)
{
struct symbol *sym, *def_sym;
struct menu *child;
bool is_new;
sym = menu->sym;
is_new = !sym_has_value(sym);
if (sym_is_changable(sym)) {
conf_sym(menu);
sym_calc_value(sym);
switch (sym_get_tristate_value(sym)) {
case no:
return 1;
case mod:
return 0;
case yes:
break;
}
} else {
switch (sym_get_tristate_value(sym)) {
case no:
return 1;
case mod:
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
return 0;
case yes:
break;
}
}
while (1) {
int cnt, def;
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
def_sym = sym_get_choice_value(sym);
cnt = def = 0;
line[0] = 0;
for (child = menu->list; child; child = child->next) {
if (!menu_is_visible(child))
continue;
if (!child->sym) {
printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
continue;
}
cnt++;
if (child->sym == def_sym) {
def = cnt;
printf("%*c", indent, '>');
} else
printf("%*c", indent, ' ');
printf(" %d. %s", cnt, _(menu_get_prompt(child)));
if (child->sym->name)
printf(" (%s)", child->sym->name);
if (!sym_has_value(child->sym))
printf(_(" (NEW)"));
printf("\n");
}
printf(_("%*schoice"), indent - 1, "");
if (cnt == 1) {
printf("[1]: 1\n");
goto conf_childs;
}
printf("[1-%d?]: ", cnt);
switch (input_mode) {
case oldconfig:
case syncconfig:
if (!is_new) {
cnt = def;
printf("%d\n", cnt);
break;
}
/* fall through */
case oldaskconfig:
fflush(stdout);
xfgets(line, sizeof(line), stdin);
strip(line);
if (line[0] == '?') {
print_help(menu);
continue;
}
if (!line[0])
cnt = def;
else if (isdigit(line[0]))
cnt = atoi(line);
else
continue;
break;
default:
break;
}
conf_childs:
for (child = menu->list; child; child = child->next) {
if (!child->sym || !menu_is_visible(child))
continue;
if (!--cnt)
break;
}
if (!child)
continue;
if (line[0] && line[strlen(line) - 1] == '?') {
print_help(child);
continue;
}
sym_set_choice_value(sym, child->sym);
for (child = child->list; child; child = child->next) {
indent += 2;
conf(child);
indent -= 2;
}
return 1;
}
}
static void conf(struct menu *menu)
{
struct symbol *sym;
struct property *prop;
struct menu *child;
if (!menu_is_visible(menu))
return;
sym = menu->sym;
prop = menu->prompt;
if (prop) {
const char *prompt;
switch (prop->type) {
case P_MENU:
/*
* Except in oldaskconfig mode, we show only menus that
* contain new symbols.
*/
if (input_mode != oldaskconfig && rootEntry != menu) {
check_conf(menu);
return;
}
/* fall through */
case P_COMMENT:
prompt = menu_get_prompt(menu);
if (prompt)
printf("%*c\n%*c %s\n%*c\n",
indent, '*',
indent, '*', _(prompt),
indent, '*');
default:
;
}
}
if (!sym)
goto conf_childs;
if (sym_is_choice(sym)) {
conf_choice(menu);
if (sym->curr.tri != mod)
return;
goto conf_childs;
}
switch (sym->type) {
case S_INT:
case S_HEX:
case S_STRING:
conf_string(menu);
break;
default:
conf_sym(menu);
break;
}
conf_childs:
if (sym)
indent += 2;
for (child = menu->list; child; child = child->next)
conf(child);
if (sym)
indent -= 2;
}
static void check_conf(struct menu *menu)
{
struct symbol *sym;
struct menu *child;
if (!menu_is_visible(menu))
return;
sym = menu->sym;
if (sym && !sym_has_value(sym)) {
if (sym_is_changable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
if (input_mode == listnewconfig) {
if (sym->name) {
const char *str;
if (sym->type == S_STRING) {
str = sym_get_string_value(sym);
str = sym_escape_string_value(str);
printf("%s%s=%s\n", CONFIG_, sym->name, str);
free((void *)str);
} else {
str = sym_get_string_value(sym);
printf("%s%s=%s\n", CONFIG_, sym->name, str);
}
}
} else {
if (!conf_cnt++)
printf(_("*\n* Restart config...\n*\n"));
rootEntry = menu_get_parent_menu(menu);
conf(rootEntry);
}
}
}
for (child = menu->list; child; child = child->next)
check_conf(child);
}
static struct option long_opts[] = {
{"oldaskconfig", no_argument, NULL, oldaskconfig},
{"oldconfig", no_argument, NULL, oldconfig},
{"syncconfig", no_argument, NULL, syncconfig},
{"defconfig", optional_argument, NULL, defconfig},
{"savedefconfig", required_argument, NULL, savedefconfig},
{"allnoconfig", no_argument, NULL, allnoconfig},
{"allyesconfig", no_argument, NULL, allyesconfig},
{"allmodconfig", no_argument, NULL, allmodconfig},
{"alldefconfig", no_argument, NULL, alldefconfig},
{"randconfig", no_argument, NULL, randconfig},
{"listnewconfig", no_argument, NULL, listnewconfig},
{"olddefconfig", no_argument, NULL, olddefconfig},
/*
* oldnoconfig is an alias of olddefconfig, because people already
* are dependent on its behavior(sets new symbols to their default
* value but not 'n') with the counter-intuitive name.
*/
{"oldnoconfig", no_argument, NULL, olddefconfig},
{NULL, 0, NULL, 0}
};
static void conf_usage(const char *progname)
{
printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
printf("[option] is _one_ of the following:\n");
printf(" --listnewconfig List new options\n");
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
printf(" --oldconfig Update a configuration using a provided .config as base\n");
printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
" include/{generated/,config/}\n");
printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
printf(" --oldnoconfig An alias of olddefconfig\n");
printf(" --defconfig <file> New config with default defined in <file>\n");
printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
printf(" --allnoconfig New config where all options are answered with no\n");
printf(" --allyesconfig New config where all options are answered with yes\n");
printf(" --allmodconfig New config where all options are answered with mod\n");
printf(" --alldefconfig New config with all symbols set to default\n");
printf(" --randconfig New config with random answer to all options\n");
}
int main(int ac, char **av)
{
const char *progname = av[0];
int opt;
const char *name, *defconfig_file = NULL /* gcc uninit */;
struct stat tmpstat;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
tty_stdio = isatty(0) && isatty(1);
while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
if (opt == 's') {
conf_set_message_callback(NULL);
continue;
}
input_mode = (enum input_mode)opt;
switch (opt) {
case syncconfig:
sync_kconfig = 1;
break;
case defconfig:
case savedefconfig:
defconfig_file = optarg;
break;
case randconfig:
{
struct timeval now;
unsigned int seed;
char *seed_env;
/*
* Use microseconds derived seed,
* compensate for systems where it may be zero
*/
gettimeofday(&now, NULL);
seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
seed_env = getenv("KCONFIG_SEED");
if( seed_env && *seed_env ) {
char *endp;
int tmp = (int)strtol(seed_env, &endp, 0);
if (*endp == '\0') {
seed = tmp;
}
}
fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
srand(seed);
break;
}
case oldaskconfig:
case oldconfig:
case allnoconfig:
case allyesconfig:
case allmodconfig:
case alldefconfig:
case listnewconfig:
case olddefconfig:
break;
case '?':
conf_usage(progname);
exit(1);
break;
}
}
if (ac == optind) {
fprintf(stderr, _("%s: Kconfig file missing\n"), av[0]);
conf_usage(progname);
exit(1);
}
name = av[optind];
conf_parse(name);
//zconfdump(stdout);
if (sync_kconfig) {
name = conf_get_configname();
if (stat(name, &tmpstat)) {
fprintf(stderr, _("***\n"
"*** Configuration file \"%s\" not found!\n"
"***\n"
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
"*** \"make menuconfig\" or \"make xconfig\").\n"
"***\n"), name);
exit(1);
}
}
switch (input_mode) {
case defconfig:
if (!defconfig_file)
defconfig_file = conf_get_default_confname();
if (conf_read(defconfig_file)) {
fprintf(stderr,
_("***\n"
"*** Can't find default configuration \"%s\"!\n"
"***\n"),
defconfig_file);
exit(1);
}
break;
case savedefconfig:
case syncconfig:
case oldaskconfig:
case oldconfig:
case listnewconfig:
case olddefconfig:
conf_read(NULL);
break;
case allnoconfig:
case allyesconfig:
case allmodconfig:
case alldefconfig:
case randconfig:
name = getenv("KCONFIG_ALLCONFIG");
if (!name)
break;
if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
if (conf_read_simple(name, S_DEF_USER)) {
fprintf(stderr,
_("*** Can't read seed configuration \"%s\"!\n"),
name);
exit(1);
}
break;
}
switch (input_mode) {
case allnoconfig: name = "allno.config"; break;
case allyesconfig: name = "allyes.config"; break;
case allmodconfig: name = "allmod.config"; break;
case alldefconfig: name = "alldef.config"; break;
case randconfig: name = "allrandom.config"; break;
default: break;
}
if (conf_read_simple(name, S_DEF_USER) &&
conf_read_simple("all.config", S_DEF_USER)) {
fprintf(stderr,
_("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
name);
exit(1);
}
break;
default:
break;
}
if (sync_kconfig) {
if (conf_get_changed()) {
name = getenv("KCONFIG_NOSILENTUPDATE");
if (name && *name) {
fprintf(stderr,
_("\n*** The configuration requires explicit update.\n\n"));
return 1;
}
}
}
switch (input_mode) {
case allnoconfig:
conf_set_all_new_symbols(def_no);
break;
case allyesconfig:
conf_set_all_new_symbols(def_yes);
break;
case allmodconfig:
conf_set_all_new_symbols(def_mod);
break;
case alldefconfig:
conf_set_all_new_symbols(def_default);
break;
case randconfig:
/* Really nothing to do in this loop */
while (conf_set_all_new_symbols(def_random)) ;
break;
case defconfig:
conf_set_all_new_symbols(def_default);
break;
case savedefconfig:
break;
case oldaskconfig:
rootEntry = &rootmenu;
conf(&rootmenu);
input_mode = oldconfig;
/* fall through */
case oldconfig:
case listnewconfig:
case syncconfig:
/* Update until a loop caused no more changes */
do {
conf_cnt = 0;
check_conf(&rootmenu);
} while (conf_cnt);
break;
case olddefconfig:
default:
break;
}
if (sync_kconfig) {
/* syncconfig is used during the build so we shall update autoconf.
* All other commands are only used to generate a config.
*/
if (conf_get_changed() && conf_write(NULL)) {
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
exit(1);
}
if (conf_write_autoconf()) {
fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
return 1;
}
} else if (input_mode == savedefconfig) {
if (conf_write_defconfig(defconfig_file)) {
fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
defconfig_file);
return 1;
}
} else if (input_mode != listnewconfig) {
if (conf_write(NULL)) {
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
exit(1);
}
}
return 0;
}

1247
scripts/kconfig/confdata.c Normal file

File diff suppressed because it is too large Load Diff

1305
scripts/kconfig/expr.c Normal file

File diff suppressed because it is too large Load Diff

329
scripts/kconfig/expr.h Normal file
View File

@@ -0,0 +1,329 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#ifndef EXPR_H
#define EXPR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <assert.h>
#include <stdio.h>
#include "list.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
struct file {
struct file *next;
struct file *parent;
const char *name;
int lineno;
};
typedef enum tristate {
no, mod, yes
} tristate;
enum expr_type {
E_NONE, E_OR, E_AND, E_NOT,
E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
E_LIST, E_SYMBOL, E_RANGE
};
union expr_data {
struct expr *expr;
struct symbol *sym;
};
struct expr {
enum expr_type type;
union expr_data left, right;
};
#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#define EXPR_NOT(dep) (2-(dep))
#define expr_list_for_each_sym(l, e, s) \
for (e = (l); e && (s = e->right.sym); e = e->left.expr)
struct expr_value {
struct expr *expr;
tristate tri;
};
struct symbol_value {
void *val;
tristate tri;
};
enum symbol_type {
S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
};
/* enum values are used as index to symbol.def[] */
enum {
S_DEF_USER, /* main user value */
S_DEF_AUTO, /* values read from auto.conf */
S_DEF_DEF3, /* Reserved for UI usage */
S_DEF_DEF4, /* Reserved for UI usage */
S_DEF_COUNT
};
/*
* Represents a configuration symbol.
*
* Choices are represented as a special kind of symbol and have the
* SYMBOL_CHOICE bit set in 'flags'.
*/
struct symbol {
/* The next symbol in the same bucket in the symbol hash table */
struct symbol *next;
/* The name of the symbol, e.g. "FOO" for 'config FOO' */
char *name;
/* S_BOOLEAN, S_TRISTATE, ... */
enum symbol_type type;
/*
* The calculated value of the symbol. The SYMBOL_VALID bit is set in
* 'flags' when this is up to date. Note that this value might differ
* from the user value set in e.g. a .config file, due to visibility.
*/
struct symbol_value curr;
/*
* Values for the symbol provided from outside. def[S_DEF_USER] holds
* the .config value.
*/
struct symbol_value def[S_DEF_COUNT];
/*
* An upper bound on the tristate value the user can set for the symbol
* if it is a boolean or tristate. Calculated from prompt dependencies,
* which also inherit dependencies from enclosing menus, choices, and
* ifs. If 'n', the user value will be ignored.
*
* Symbols lacking prompts always have visibility 'n'.
*/
tristate visible;
/* SYMBOL_* flags */
int flags;
/* List of properties. See prop_type. */
struct property *prop;
/* Dependencies from enclosing menus, choices, and ifs */
struct expr_value dir_dep;
/* Reverse dependencies through being selected by other symbols */
struct expr_value rev_dep;
/*
* "Weak" reverse dependencies through being implied by other symbols
*/
struct expr_value implied;
};
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
#define SYMBOL_CONST 0x0001 /* symbol is const */
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
#define SYMBOL_CHANGED 0x0400 /* ? */
#define SYMBOL_AUTO 0x1000 /* value from environment variable */
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
/* Set when symbol.def[] is used */
#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */
#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */
#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */
#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
/* choice values need to be set before calculating this symbol value */
#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
/* Set symbol to y if allnoconfig; used for symbols that hide others */
#define SYMBOL_ALLNOCONFIG_Y 0x200000
#define SYMBOL_MAXLENGTH 256
#define SYMBOL_HASHSIZE 9973
/* A property represent the config options that can be associated
* with a config "symbol".
* Sample:
* config FOO
* default y
* prompt "foo prompt"
* select BAR
* config BAZ
* int "BAZ Value"
* range 1..255
*/
enum prop_type {
P_UNKNOWN,
P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
P_COMMENT, /* text associated with a comment */
P_MENU, /* prompt associated with a menu or menuconfig symbol */
P_DEFAULT, /* default y */
P_CHOICE, /* choice value */
P_SELECT, /* select BAR */
P_IMPLY, /* imply BAR */
P_RANGE, /* range 7..100 (for a symbol) */
P_ENV, /* value from environment variable */
P_SYMBOL, /* where a symbol is defined */
};
struct property {
struct property *next; /* next property - null if last */
struct symbol *sym; /* the symbol for which the property is associated */
enum prop_type type; /* type of property */
const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
struct expr_value visible;
struct expr *expr; /* the optional conditional part of the property */
struct menu *menu; /* the menu the property are associated with
* valid for: P_SELECT, P_RANGE, P_CHOICE,
* P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
struct file *file; /* what file was this property defined */
int lineno; /* what lineno was this property defined */
};
#define for_all_properties(sym, st, tok) \
for (st = sym->prop; st; st = st->next) \
if (st->type == (tok))
#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
#define for_all_prompts(sym, st) \
for (st = sym->prop; st; st = st->next) \
if (st->text)
/*
* Represents a node in the menu tree, as seen in e.g. menuconfig (though used
* for all front ends). Each symbol, menu, etc. defined in the Kconfig files
* gets a node. A symbol defined in multiple locations gets one node at each
* location.
*/
struct menu {
/* The next menu node at the same level */
struct menu *next;
/* The parent menu node, corresponding to e.g. a menu or choice */
struct menu *parent;
/* The first child menu node, for e.g. menus and choices */
struct menu *list;
/*
* The symbol associated with the menu node. Choices are implemented as
* a special kind of symbol. NULL for menus, comments, and ifs.
*/
struct symbol *sym;
/*
* The prompt associated with the node. This holds the prompt for a
* symbol as well as the text for a menu or comment, along with the
* type (P_PROMPT, P_MENU, etc.)
*/
struct property *prompt;
/*
* 'visible if' dependencies. If more than one is given, they will be
* ANDed together.
*/
struct expr *visibility;
/*
* Ordinary dependencies from e.g. 'depends on' and 'if', ANDed
* together
*/
struct expr *dep;
/* MENU_* flags */
unsigned int flags;
/* Any help text associated with the node */
char *help;
/* The location where the menu node appears in the Kconfig files */
struct file *file;
int lineno;
/* For use by front ends that need to store auxiliary data */
void *data;
};
/*
* Set on a menu node when the corresponding symbol changes state in some way.
* Can be checked by front ends.
*/
#define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002
struct jump_key {
struct list_head entries;
size_t offset;
struct menu *target;
int index;
};
#define JUMP_NB 9
extern struct file *file_list;
extern struct file *current_file;
struct file *lookup_file(const char *name);
extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym;
extern struct symbol *sym_defconfig_list;
extern int cdebug;
struct expr *expr_alloc_symbol(struct symbol *sym);
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
struct expr *expr_copy(const struct expr *org);
void expr_free(struct expr *e);
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
tristate expr_calc_value(struct expr *e);
struct expr *expr_trans_bool(struct expr *e);
struct expr *expr_eliminate_dups(struct expr *e);
struct expr *expr_transform(struct expr *e);
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
void expr_fprint(struct expr *e, FILE *out);
struct gstr; /* forward */
void expr_gstr_print(struct expr *e, struct gstr *gs);
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
tristate pr_type, const char *title);
static inline int expr_is_yes(struct expr *e)
{
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
}
static inline int expr_is_no(struct expr *e)
{
return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
}
#ifdef __cplusplus
}
#endif
#endif /* EXPR_H */

1521
scripts/kconfig/gconf.c Normal file

File diff suppressed because it is too large Load Diff

661
scripts/kconfig/gconf.glade Normal file
View File

@@ -0,0 +1,661 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<glade-interface>
<widget class="GtkWindow" id="window1">
<property name="visible">True</property>
<property name="title" translatable="yes">Gtk Kernel Configurator</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="default_width">640</property>
<property name="default_height">480</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<signal name="destroy" handler="on_window1_destroy" object="window1"/>
<signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
<signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkMenuBar" id="menubar1">
<property name="visible">True</property>
<child>
<widget class="GtkMenuItem" id="file1">
<property name="visible">True</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="file1_menu">
<child>
<widget class="GtkImageMenuItem" id="load1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Load a config file</property>
<property name="label" translatable="yes">_Load</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_load1_activate"/>
<accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image39">
<property name="visible">True</property>
<property name="stock">gtk-open</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="save1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Save the config in .config</property>
<property name="label" translatable="yes">_Save</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_save_activate"/>
<accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image40">
<property name="visible">True</property>
<property name="stock">gtk-save</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="save_as1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Save the config in a file</property>
<property name="label" translatable="yes">Save _as</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_save_as1_activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image41">
<property name="visible">True</property>
<property name="stock">gtk-save-as</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separator1">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="quit1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Quit</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_quit1_activate"/>
<accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image42">
<property name="visible">True</property>
<property name="stock">gtk-quit</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="options1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Options</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="options1_menu">
<child>
<widget class="GtkCheckMenuItem" id="show_name1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show name</property>
<property name="label" translatable="yes">Show _name</property>
<property name="use_underline">True</property>
<property name="active">False</property>
<signal name="activate" handler="on_show_name1_activate"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="show_range1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
<property name="label" translatable="yes">Show _range</property>
<property name="use_underline">True</property>
<property name="active">False</property>
<signal name="activate" handler="on_show_range1_activate"/>
</widget>
</child>
<child>
<widget class="GtkCheckMenuItem" id="show_data1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show value of the option</property>
<property name="label" translatable="yes">Show _data</property>
<property name="use_underline">True</property>
<property name="active">False</property>
<signal name="activate" handler="on_show_data1_activate"/>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separator2">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkRadioMenuItem" id="set_option_mode1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show normal options</property>
<property name="label" translatable="yes">Show normal options</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="activate" handler="on_set_option_mode1_activate"/>
</widget>
</child>
<child>
<widget class="GtkRadioMenuItem" id="set_option_mode2">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show all options</property>
<property name="label" translatable="yes">Show all _options</property>
<property name="use_underline">True</property>
<property name="active">False</property>
<property name="group">set_option_mode1</property>
<signal name="activate" handler="on_set_option_mode2_activate"/>
</widget>
</child>
<child>
<widget class="GtkRadioMenuItem" id="set_option_mode3">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show all options with prompts</property>
<property name="label" translatable="yes">Show all prompt options</property>
<property name="use_underline">True</property>
<property name="active">False</property>
<property name="group">set_option_mode1</property>
<signal name="activate" handler="on_set_option_mode3_activate"/>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="help1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Help</property>
<property name="use_underline">True</property>
<child>
<widget class="GtkMenu" id="help1_menu">
<child>
<widget class="GtkImageMenuItem" id="introduction1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Introduction</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
<accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image43">
<property name="visible">True</property>
<property name="stock">gtk-dialog-question</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="about1">
<property name="visible">True</property>
<property name="label" translatable="yes">_About</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
<accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
<widget class="GtkImage" id="image44">
<property name="visible">True</property>
<property name="stock">gtk-properties</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="license1">
<property name="visible">True</property>
<property name="label" translatable="yes">_License</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
<child internal-child="image">
<widget class="GtkImage" id="image45">
<property name="visible">True</property>
<property name="stock">gtk-justify-fill</property>
<property name="icon_size">1</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHandleBox" id="handlebox1">
<property name="visible">True</property>
<property name="shadow_type">GTK_SHADOW_OUT</property>
<property name="handle_position">GTK_POS_LEFT</property>
<property name="snap_edge">GTK_POS_TOP</property>
<child>
<widget class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
<property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
<property name="tooltips">True</property>
<property name="show_arrow">True</property>
<child>
<widget class="GtkToolButton" id="button1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
<property name="label" translatable="yes">Back</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-undo</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_back_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolItem" id="toolitem1">
<property name="visible">True</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<child>
<widget class="GtkVSeparator" id="vseparator1">
<property name="visible">True</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button2">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Load a config file</property>
<property name="label" translatable="yes">Load</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-open</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_load_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button3">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Save a config file</property>
<property name="label" translatable="yes">Save</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-save</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_save_activate"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolItem" id="toolitem2">
<property name="visible">True</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<child>
<widget class="GtkVSeparator" id="vseparator2">
<property name="visible">True</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button4">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Single view</property>
<property name="label" translatable="yes">Single</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-missing-image</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button5">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Split view</property>
<property name="label" translatable="yes">Split</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-missing-image</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button6">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Full view</property>
<property name="label" translatable="yes">Full</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-missing-image</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolItem" id="toolitem3">
<property name="visible">True</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<child>
<widget class="GtkVSeparator" id="vseparator3">
<property name="visible">True</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button7">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
<property name="label" translatable="yes">Collapse</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-remove</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_collapse_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<widget class="GtkToolButton" id="button8">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
<property name="label" translatable="yes">Expand</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-add</property>
<property name="visible_horizontal">True</property>
<property name="visible_vertical">True</property>
<property name="is_important">False</property>
<signal name="clicked" handler="on_expand_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHPaned" id="hpaned1">
<property name="width_request">1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">0</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTreeView" id="treeview1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">True</property>
<property name="rules_hint">False</property>
<property name="reorderable">False</property>
<property name="enable_search">False</property>
<signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
<signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
<signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="shrink">True</property>
<property name="resize">False</property>
</packing>
</child>
<child>
<widget class="GtkVPaned" id="vpaned1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">0</property>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTreeView" id="treeview2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="headers_visible">True</property>
<property name="rules_hint">False</property>
<property name="reorderable">False</property>
<property name="enable_search">False</property>
<signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
<signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
<signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="shrink">True</property>
<property name="resize">False</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow3">
<property name="visible">True</property>
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTextView" id="textview3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="overwrite">False</property>
<property name="accepts_tab">True</property>
<property name="justification">GTK_JUSTIFY_LEFT</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
<property name="cursor_visible">True</property>
<property name="pixels_above_lines">0</property>
<property name="pixels_below_lines">0</property>
<property name="pixels_inside_wrap">0</property>
<property name="left_margin">0</property>
<property name="right_margin">0</property>
<property name="indent">0</property>
<property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
</widget>
</child>
</widget>
<packing>
<property name="shrink">True</property>
<property name="resize">True</property>
</packing>
</child>
</widget>
<packing>
<property name="shrink">True</property>
<property name="resize">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

326
scripts/kconfig/images.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
static const char *xpm_load[] = {
"22 22 5 1",
". c None",
"# c #000000",
"c c #838100",
"a c #ffff00",
"b c #ffffff",
"......................",
"......................",
"......................",
"............####....#.",
"...........#....##.##.",
"..................###.",
".................####.",
".####...........#####.",
"#abab##########.......",
"#babababababab#.......",
"#ababababababa#.......",
"#babababababab#.......",
"#ababab###############",
"#babab##cccccccccccc##",
"#abab##cccccccccccc##.",
"#bab##cccccccccccc##..",
"#ab##cccccccccccc##...",
"#b##cccccccccccc##....",
"###cccccccccccc##.....",
"##cccccccccccc##......",
"###############.......",
"......................"};
static const char *xpm_save[] = {
"22 22 5 1",
". c None",
"# c #000000",
"a c #838100",
"b c #c5c2c5",
"c c #cdb6d5",
"......................",
".####################.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbcbb####.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aaa############aaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaa#############aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
"..##################..",
"......................"};
static const char *xpm_back[] = {
"22 22 3 1",
". c None",
"# c #000083",
"a c #838183",
"......................",
"......................",
"......................",
"......................",
"......................",
"...........######a....",
"..#......##########...",
"..##...####......##a..",
"..###.###.........##..",
"..######..........##..",
"..#####...........##..",
"..######..........##..",
"..#######.........##..",
"..########.......##a..",
"...............a###...",
"...............###....",
"......................",
"......................",
"......................",
"......................",
"......................",
"......................"};
static const char *xpm_tree_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......................",
"......................"};
static const char *xpm_single_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"......................",
"......................"};
static const char *xpm_split_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......................",
"......................"};
static const char *xpm_symbol_no[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .......... ",
" "};
static const char *xpm_symbol_mod[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" . . ",
" .......... ",
" "};
static const char *xpm_symbol_yes[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . . ",
" . .. . ",
" . . .. . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
static const char *xpm_choice_no[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .. .. ",
" .... ",
" "};
static const char *xpm_choice_yes[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" .. .. ",
" .... ",
" "};
static const char *xpm_menu[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
static const char *xpm_menu_inv[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" .......... ",
" .. ...... ",
" .. .... ",
" .. .. ",
" .. .. ",
" .. .... ",
" .. ...... ",
" .......... ",
" .......... ",
" "};
static const char *xpm_menuback[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
static const char *xpm_void[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "};

View File

@@ -0,0 +1,53 @@
static struct kconf_id kconf_id_array[] = {
{ "mainmenu", T_MAINMENU, TF_COMMAND },
{ "menu", T_MENU, TF_COMMAND },
{ "endmenu", T_ENDMENU, TF_COMMAND },
{ "source", T_SOURCE, TF_COMMAND },
{ "choice", T_CHOICE, TF_COMMAND },
{ "endchoice", T_ENDCHOICE, TF_COMMAND },
{ "comment", T_COMMENT, TF_COMMAND },
{ "config", T_CONFIG, TF_COMMAND },
{ "menuconfig", T_MENUCONFIG, TF_COMMAND },
{ "help", T_HELP, TF_COMMAND },
{ "---help---", T_HELP, TF_COMMAND },
{ "if", T_IF, TF_COMMAND|TF_PARAM },
{ "endif", T_ENDIF, TF_COMMAND },
{ "depends", T_DEPENDS, TF_COMMAND },
{ "optional", T_OPTIONAL, TF_COMMAND },
{ "default", T_DEFAULT, TF_COMMAND, S_UNKNOWN },
{ "prompt", T_PROMPT, TF_COMMAND },
{ "tristate", T_TYPE, TF_COMMAND, S_TRISTATE },
{ "def_tristate", T_DEFAULT, TF_COMMAND, S_TRISTATE },
{ "bool", T_TYPE, TF_COMMAND, S_BOOLEAN },
{ "def_bool", T_DEFAULT, TF_COMMAND, S_BOOLEAN },
{ "int", T_TYPE, TF_COMMAND, S_INT },
{ "hex", T_TYPE, TF_COMMAND, S_HEX },
{ "string", T_TYPE, TF_COMMAND, S_STRING },
{ "select", T_SELECT, TF_COMMAND },
{ "imply", T_IMPLY, TF_COMMAND },
{ "range", T_RANGE, TF_COMMAND },
{ "visible", T_VISIBLE, TF_COMMAND },
{ "option", T_OPTION, TF_COMMAND },
{ "on", T_ON, TF_PARAM },
{ "modules", T_OPT_MODULES, TF_OPTION },
{ "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION },
{ "env", T_OPT_ENV, TF_OPTION },
{ "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION },
};
#define KCONF_ID_ARRAY_SIZE (sizeof(kconf_id_array)/sizeof(struct kconf_id))
static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len)
{
int i;
for (i = 0; i < KCONF_ID_ARRAY_SIZE; i++) {
struct kconf_id *id = kconf_id_array+i;
int l = strlen(id->name);
if (len == l && !memcmp(str, id->name, len))
return id;
}
return NULL;
}

235
scripts/kconfig/kxgettext.c Normal file
View File

@@ -0,0 +1,235 @@
/*
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
*
* Released under the terms of the GNU GPL v2.0
*/
#include <stdlib.h>
#include <string.h>
#include "lkc.h"
static char *escape(const char* text, char *bf, int len)
{
char *bfp = bf;
int multiline = strchr(text, '\n') != NULL;
int eol = 0;
int textlen = strlen(text);
if ((textlen > 0) && (text[textlen-1] == '\n'))
eol = 1;
*bfp++ = '"';
--len;
if (multiline) {
*bfp++ = '"';
*bfp++ = '\n';
*bfp++ = '"';
len -= 3;
}
while (*text != '\0' && len > 1) {
if (*text == '"')
*bfp++ = '\\';
else if (*text == '\n') {
*bfp++ = '\\';
*bfp++ = 'n';
*bfp++ = '"';
*bfp++ = '\n';
*bfp++ = '"';
len -= 5;
++text;
goto next;
}
else if (*text == '\\') {
*bfp++ = '\\';
len--;
}
*bfp++ = *text++;
next:
--len;
}
if (multiline && eol)
bfp -= 3;
*bfp++ = '"';
*bfp = '\0';
return bf;
}
struct file_line {
struct file_line *next;
const char *file;
int lineno;
};
static struct file_line *file_line__new(const char *file, int lineno)
{
struct file_line *self = malloc(sizeof(*self));
if (self == NULL)
goto out;
self->file = file;
self->lineno = lineno;
self->next = NULL;
out:
return self;
}
struct message {
const char *msg;
const char *option;
struct message *next;
struct file_line *files;
};
static struct message *message__list;
static struct message *message__new(const char *msg, char *option,
const char *file, int lineno)
{
struct message *self = malloc(sizeof(*self));
if (self == NULL)
goto out;
self->files = file_line__new(file, lineno);
if (self->files == NULL)
goto out_fail;
self->msg = xstrdup(msg);
if (self->msg == NULL)
goto out_fail_msg;
self->option = option;
self->next = NULL;
out:
return self;
out_fail_msg:
free(self->files);
out_fail:
free(self);
self = NULL;
goto out;
}
static struct message *mesage__find(const char *msg)
{
struct message *m = message__list;
while (m != NULL) {
if (strcmp(m->msg, msg) == 0)
break;
m = m->next;
}
return m;
}
static int message__add_file_line(struct message *self, const char *file,
int lineno)
{
int rc = -1;
struct file_line *fl = file_line__new(file, lineno);
if (fl == NULL)
goto out;
fl->next = self->files;
self->files = fl;
rc = 0;
out:
return rc;
}
static int message__add(const char *msg, char *option, const char *file,
int lineno)
{
int rc = 0;
char bf[16384];
char *escaped = escape(msg, bf, sizeof(bf));
struct message *m = mesage__find(escaped);
if (m != NULL)
rc = message__add_file_line(m, file, lineno);
else {
m = message__new(escaped, option, file, lineno);
if (m != NULL) {
m->next = message__list;
message__list = m;
} else
rc = -1;
}
return rc;
}
static void menu_build_message_list(struct menu *menu)
{
struct menu *child;
message__add(menu_get_prompt(menu), NULL,
menu->file == NULL ? "Root Menu" : menu->file->name,
menu->lineno);
if (menu->sym != NULL && menu_has_help(menu))
message__add(menu_get_help(menu), menu->sym->name,
menu->file == NULL ? "Root Menu" : menu->file->name,
menu->lineno);
for (child = menu->list; child != NULL; child = child->next)
if (child->prompt != NULL)
menu_build_message_list(child);
}
static void message__print_file_lineno(struct message *self)
{
struct file_line *fl = self->files;
putchar('\n');
if (self->option != NULL)
printf("# %s:00000\n", self->option);
printf("#: %s:%d", fl->file, fl->lineno);
fl = fl->next;
while (fl != NULL) {
printf(", %s:%d", fl->file, fl->lineno);
fl = fl->next;
}
putchar('\n');
}
static void message__print_gettext_msgid_msgstr(struct message *self)
{
message__print_file_lineno(self);
printf("msgid %s\n"
"msgstr \"\"\n", self->msg);
}
static void menu__xgettext(void)
{
struct message *m = message__list;
while (m != NULL) {
/* skip empty lines ("") */
if (strlen(m->msg) > sizeof("\"\""))
message__print_gettext_msgid_msgstr(m);
m = m->next;
}
}
int main(int ac, char **av)
{
conf_parse(av[1]);
menu_build_message_list(menu_get_root_menu(NULL));
menu__xgettext();
return 0;
}

132
scripts/kconfig/list.h Normal file
View File

@@ -0,0 +1,132 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LIST_H
#define LIST_H
/*
* Copied from include/linux/...
*/
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *_new,
struct list_head *prev,
struct list_head *next)
{
next->prev = _new;
_new->next = next;
_new->prev = prev;
prev->next = _new;
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *_new, struct list_head *head)
{
__list_add(_new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (struct list_head*)LIST_POISON1;
entry->prev = (struct list_head*)LIST_POISON2;
}
#endif

188
scripts/kconfig/lkc.h Normal file
View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#ifndef LKC_H
#define LKC_H
#include "expr.h"
#ifndef KBUILD_NO_NLS
# include <libintl.h>
#else
static inline const char *gettext(const char *txt) { return txt; }
static inline void textdomain(const char *domainname) {}
static inline void bindtextdomain(const char *name, const char *dir) {}
static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "lkc_proto.h"
#define SRCTREE "srctree"
#ifndef PACKAGE
#define PACKAGE "linux"
#endif
#define LOCALEDIR "/usr/share/locale"
#define _(text) gettext(text)
#define N_(text) (text)
#ifndef CONFIG_
#define CONFIG_ "CONFIG_"
#endif
static inline const char *CONFIG_prefix(void)
{
return getenv( "CONFIG_" ) ?: CONFIG_;
}
#undef CONFIG_
#define CONFIG_ CONFIG_prefix()
#define TF_COMMAND 0x0001
#define TF_PARAM 0x0002
#define TF_OPTION 0x0004
enum conf_def_mode {
def_default,
def_yes,
def_mod,
def_no,
def_random
};
#define T_OPT_MODULES 1
#define T_OPT_DEFCONFIG_LIST 2
#define T_OPT_ENV 3
#define T_OPT_ALLNOCONFIG_Y 4
struct kconf_id {
const char *name;
int token;
unsigned int flags;
enum symbol_type stype;
};
extern int yylineno;
void zconfdump(FILE *out);
void zconf_starthelp(void);
FILE *zconf_fopen(const char *name);
void zconf_initscan(const char *name);
void zconf_nextfile(const char *name);
int zconf_lineno(void);
const char *zconf_curname(void);
/* confdata.c */
const char *conf_get_configname(void);
const char *conf_get_autoconfig_name(void);
char *conf_get_default_confname(void);
void sym_set_change_count(int count);
void sym_add_change_count(int count);
bool conf_set_all_new_symbols(enum conf_def_mode mode);
void set_all_choice_values(struct symbol *csym);
/* confdata.c and expr.c */
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
{
assert(len != 0);
if (fwrite(str, len, count, out) != count)
fprintf(stderr, "Error in writing or end of file.\n");
}
/* menu.c */
void _menu_init(void);
void menu_warn(struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym);
void menu_add_dep(struct expr *dep);
void menu_add_visibility(struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_add_option(int token, char *arg);
void menu_finalize(struct menu *parent);
void menu_set_type(int type);
/* util.c */
struct file *file_lookup(const char *name);
int file_write_dep(const char *name);
void *xmalloc(size_t size);
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *p, size_t size);
char *xstrdup(const char *s);
struct gstr {
size_t len;
char *s;
/*
* when max_width is not zero long lines in string s (if any) get
* wrapped not to exceed the max_width value
*/
int max_width;
};
struct gstr str_new(void);
void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...);
const char *str_get(struct gstr *gs);
/* symbol.c */
extern struct expr *sym_env_list;
void sym_init(void);
void sym_clear_all_valid(void);
struct symbol *sym_choice_default(struct symbol *sym);
const char *sym_get_string_default(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym);
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
struct symbol *prop_get_symbol(struct property *prop);
struct property *sym_get_env_prop(struct symbol *sym);
static inline tristate sym_get_tristate_value(struct symbol *sym)
{
return sym->curr.tri;
}
static inline struct symbol *sym_get_choice_value(struct symbol *sym)
{
return (struct symbol *)sym->curr.val;
}
static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
{
return sym_set_tristate_value(chval, yes);
}
static inline bool sym_is_choice(struct symbol *sym)
{
return sym->flags & SYMBOL_CHOICE ? true : false;
}
static inline bool sym_is_choice_value(struct symbol *sym)
{
return sym->flags & SYMBOL_CHOICEVAL ? true : false;
}
static inline bool sym_is_optional(struct symbol *sym)
{
return sym->flags & SYMBOL_OPTIONAL ? true : false;
}
static inline bool sym_has_value(struct symbol *sym)
{
return sym->flags & SYMBOL_DEF_USER ? true : false;
}
#ifdef __cplusplus
}
#endif
#endif /* LKC_H */

View File

@@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <stdarg.h>
/* confdata.c */
void conf_parse(const char *name);
int conf_read(const char *name);
int conf_read_simple(const char *name, int);
int conf_write_defconfig(const char *name);
int conf_write(const char *name);
int conf_write_autoconf(void);
bool conf_get_changed(void);
void conf_set_changed_callback(void (*fn)(void));
void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap));
/* menu.c */
extern struct menu rootmenu;
bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu);
bool menu_has_prompt(struct menu *menu);
const char * menu_get_prompt(struct menu *menu);
struct menu * menu_get_root_menu(struct menu *menu);
struct menu * menu_get_parent_menu(struct menu *menu);
bool menu_has_help(struct menu *menu);
const char * menu_get_help(struct menu *menu);
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
void menu_get_ext_help(struct menu *menu, struct gstr *help);
/* symbol.c */
extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name);
char *sym_expand_string_value(const char *in);
const char * sym_escape_string_value(const char *in);
struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym);
enum symbol_type sym_get_type(struct symbol *sym);
bool sym_tristate_within_range(struct symbol *sym,tristate tri);
bool sym_set_tristate_value(struct symbol *sym,tristate tri);
tristate sym_toggle_tristate_value(struct symbol *sym);
bool sym_string_valid(struct symbol *sym, const char *newval);
bool sym_string_within_range(struct symbol *sym, const char *str);
bool sym_set_string_value(struct symbol *sym, const char *newval);
bool sym_is_changable(struct symbol *sym);
struct property * sym_get_choice_prop(struct symbol *sym);
const char * sym_get_string_value(struct symbol *sym);
const char * prop_get_type_name(enum prop_type type);
/* expr.c */
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);

4
scripts/kconfig/lxdialog/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
#
# Generated files
#
lxdialog

View File

@@ -0,0 +1,4 @@
This is NOT the official version of dialog. This version has been
significantly modified from the original. It is for use by the Linux
kernel configuration script. Please do not bother Savio Lam with
questions about this program.

View File

@@ -0,0 +1,93 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Check ncurses compatibility
# What library to link
ldflags()
{
pkg-config --libs ncursesw 2>/dev/null && exit
pkg-config --libs ncurses 2>/dev/null && exit
for ext in so a dll.a dylib ; do
for lib in ncursesw ncurses curses ; do
$cc -print-file-name=lib${lib}.${ext} | grep -q /
if [ $? -eq 0 ]; then
echo "-l${lib}"
exit
fi
done
done
exit 1
}
# Where is ncurses.h?
ccflags()
{
if pkg-config --cflags ncursesw 2>/dev/null; then
echo '-DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1'
elif pkg-config --cflags ncurses 2>/dev/null; then
echo '-DCURSES_LOC="<ncurses.h>"'
elif [ -f /usr/include/ncursesw/curses.h ]; then
echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
echo ' -DNCURSES_WIDECHAR=1'
elif [ -f /usr/include/ncurses/ncurses.h ]; then
echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
elif [ -f /usr/include/ncurses/curses.h ]; then
echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
elif [ -f /usr/include/ncurses.h ]; then
echo '-DCURSES_LOC="<ncurses.h>"'
else
echo '-DCURSES_LOC="<curses.h>"'
fi
}
# Temp file, try to clean up after us
tmp=.lxdialog.tmp
trap "rm -f $tmp" 0 1 2 3 15
# Check if we can link to ncurses
check() {
$cc -x c - -o $tmp 2>/dev/null <<'EOF'
#include CURSES_LOC
main() {}
EOF
if [ $? != 0 ]; then
echo " *** Unable to find the ncurses libraries or the" 1>&2
echo " *** required header files." 1>&2
echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
echo " *** " 1>&2
echo " *** Install ncurses (ncurses-devel or libncurses-dev " 1>&2
echo " *** depending on your distribution) and try again." 1>&2
echo " *** " 1>&2
exit 1
fi
}
usage() {
printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
}
if [ $# -eq 0 ]; then
usage
exit 1
fi
cc=""
case "$1" in
"-check")
shift
cc="$@"
check
;;
"-ccflags")
ccflags
;;
"-ldflags")
shift
cc="$@"
ldflags
;;
"*")
usage
exit 1
;;
esac

View File

@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* checklist.c -- implements the checklist box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
* Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*/
#include "dialog.h"
static int list_width, check_x, item_x;
/*
* Print list item
*/
static void print_item(WINDOW * win, int choice, int selected)
{
int i;
char *list_item = malloc(list_width + 1);
strncpy(list_item, item_str(), list_width - item_x);
list_item[list_width - item_x] = '\0';
/* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr);
wmove(win, choice, 0);
for (i = 0; i < list_width; i++)
waddch(win, ' ');
wmove(win, choice, check_x);
wattrset(win, selected ? dlg.check_selected.atr
: dlg.check.atr);
if (!item_is_tag(':'))
wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
mvwaddch(win, choice, item_x, list_item[0]);
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
waddstr(win, list_item + 1);
if (selected) {
wmove(win, choice, check_x + 1);
wrefresh(win);
}
free(list_item);
}
/*
* Print the scroll indicators.
*/
static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
int y, int x, int height)
{
wmove(win, y, x);
if (scroll > 0) {
wattrset(win, dlg.uarrow.atr);
waddch(win, ACS_UARROW);
waddstr(win, "(-)");
} else {
wattrset(win, dlg.menubox.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
}
y = y + height + 1;
wmove(win, y, x);
if ((height < item_no) && (scroll + choice < item_no - 1)) {
wattrset(win, dlg.darrow.atr);
waddch(win, ACS_DARROW);
waddstr(win, "(+)");
} else {
wattrset(win, dlg.menubox_border.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
}
}
/*
* Display the termination buttons
*/
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{
int x = width / 2 - 11;
int y = height - 2;
print_button(dialog, gettext("Select"), y, x, selected == 0);
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
wmove(dialog, y, x + 1 + 14 * selected);
wrefresh(dialog);
}
/*
* Display a dialog box with a list of options that can be turned on or off
* in the style of radiolist (only one option turned on at a time).
*/
int dialog_checklist(const char *title, const char *prompt, int height,
int width, int list_height)
{
int i, x, y, box_x, box_y;
int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
WINDOW *dialog, *list;
/* which item to highlight */
item_foreach() {
if (item_is_tag('X'))
choice = item_n();
if (item_is_selected()) {
choice = item_n();
break;
}
}
do_resize:
if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
max_choice = MIN(list_height, item_count());
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
list_width = width - 6;
box_y = height - list_height - 5;
box_x = (width - list_width) / 2 - 1;
/* create new window for the list */
list = subwin(dialog, list_height, list_width, y + box_y + 1,
x + box_x + 1);
keypad(list, TRUE);
/* draw a box around the list items */
draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
dlg.menubox_border.atr, dlg.menubox.atr);
/* Find length of longest item in order to center checklist */
check_x = 0;
item_foreach()
check_x = MAX(check_x, strlen(item_str()) + 4);
check_x = MIN(check_x, list_width);
check_x = (list_width - check_x) / 2;
item_x = check_x + 4;
if (choice >= list_height) {
scroll = choice - list_height + 1;
choice -= scroll;
}
/* Print the list */
for (i = 0; i < max_choice; i++) {
item_set(scroll + i);
print_item(list, i, i == choice);
}
print_arrows(dialog, choice, item_count(), scroll,
box_y, box_x + check_x + 5, list_height);
print_buttons(dialog, height, width, 0);
wnoutrefresh(dialog);
wnoutrefresh(list);
doupdate();
while (key != KEY_ESC) {
key = wgetch(dialog);
for (i = 0; i < max_choice; i++) {
item_set(i + scroll);
if (toupper(key) == toupper(item_str()[0]))
break;
}
if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
key == '+' || key == '-') {
if (key == KEY_UP || key == '-') {
if (!choice) {
if (!scroll)
continue;
/* Scroll list down */
if (list_height > 1) {
/* De-highlight current first item */
item_set(scroll);
print_item(list, 0, FALSE);
scrollok(list, TRUE);
wscrl(list, -1);
scrollok(list, FALSE);
}
scroll--;
item_set(scroll);
print_item(list, 0, TRUE);
print_arrows(dialog, choice, item_count(),
scroll, box_y, box_x + check_x + 5, list_height);
wnoutrefresh(dialog);
wrefresh(list);
continue; /* wait for another key press */
} else
i = choice - 1;
} else if (key == KEY_DOWN || key == '+') {
if (choice == max_choice - 1) {
if (scroll + choice >= item_count() - 1)
continue;
/* Scroll list up */
if (list_height > 1) {
/* De-highlight current last item before scrolling up */
item_set(scroll + max_choice - 1);
print_item(list,
max_choice - 1,
FALSE);
scrollok(list, TRUE);
wscrl(list, 1);
scrollok(list, FALSE);
}
scroll++;
item_set(scroll + max_choice - 1);
print_item(list, max_choice - 1, TRUE);
print_arrows(dialog, choice, item_count(),
scroll, box_y, box_x + check_x + 5, list_height);
wnoutrefresh(dialog);
wrefresh(list);
continue; /* wait for another key press */
} else
i = choice + 1;
}
if (i != choice) {
/* De-highlight current item */
item_set(scroll + choice);
print_item(list, choice, FALSE);
/* Highlight new item */
choice = i;
item_set(scroll + choice);
print_item(list, choice, TRUE);
wnoutrefresh(dialog);
wrefresh(list);
}
continue; /* wait for another key press */
}
switch (key) {
case 'H':
case 'h':
case '?':
button = 1;
/* fall-through */
case 'S':
case 's':
case ' ':
case '\n':
item_foreach()
item_set_selected(0);
item_set(scroll + choice);
item_set_selected(1);
delwin(list);
delwin(dialog);
return button;
case TAB:
case KEY_LEFT:
case KEY_RIGHT:
button = ((key == KEY_LEFT ? --button : ++button) < 0)
? 1 : (button > 1 ? 0 : button);
print_buttons(dialog, height, width, button);
wrefresh(dialog);
break;
case 'X':
case 'x':
key = KEY_ESC;
break;
case KEY_ESC:
key = on_key_esc(dialog);
break;
case KEY_RESIZE:
delwin(list);
delwin(dialog);
on_key_resize();
goto do_resize;
}
/* Now, update everything... */
doupdate();
}
delwin(list);
delwin(dialog);
return key; /* ESC pressed */
}

View File

@@ -0,0 +1,244 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* dialog.h -- common declarations for all dialog modules
*
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
*/
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifndef KBUILD_NO_NLS
# include <libintl.h>
#else
# define gettext(Msgid) ((const char *) (Msgid))
#endif
#ifdef __sun__
#define CURS_MACROS
#endif
#include CURSES_LOC
/*
* Colors in ncurses 1.9.9e do not work properly since foreground and
* background colors are OR'd rather than separately masked. This version
* of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
* with standard curses. The simplest fix (to make this work with standard
* curses) uses the wbkgdset() function, not used in the original hack.
* Turn it off if we're building with 1.9.9e, since it just confuses things.
*/
#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
#define OLD_NCURSES 1
#undef wbkgdset
#define wbkgdset(w,p) /*nothing */
#else
#define OLD_NCURSES 0
#endif
#define TR(params) _tracef params
#define KEY_ESC 27
#define TAB 9
#define MAX_LEN 2048
#define BUF_SIZE (10*1024)
#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x : y)
#ifndef ACS_ULCORNER
#define ACS_ULCORNER '+'
#endif
#ifndef ACS_LLCORNER
#define ACS_LLCORNER '+'
#endif
#ifndef ACS_URCORNER
#define ACS_URCORNER '+'
#endif
#ifndef ACS_LRCORNER
#define ACS_LRCORNER '+'
#endif
#ifndef ACS_HLINE
#define ACS_HLINE '-'
#endif
#ifndef ACS_VLINE
#define ACS_VLINE '|'
#endif
#ifndef ACS_LTEE
#define ACS_LTEE '+'
#endif
#ifndef ACS_RTEE
#define ACS_RTEE '+'
#endif
#ifndef ACS_UARROW
#define ACS_UARROW '^'
#endif
#ifndef ACS_DARROW
#define ACS_DARROW 'v'
#endif
/* error return codes */
#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
/*
* Color definitions
*/
struct dialog_color {
chtype atr; /* Color attribute */
int fg; /* foreground */
int bg; /* background */
int hl; /* highlight this item */
};
struct subtitle_list {
struct subtitle_list *next;
const char *text;
};
struct dialog_info {
const char *backtitle;
struct subtitle_list *subtitles;
struct dialog_color screen;
struct dialog_color shadow;
struct dialog_color dialog;
struct dialog_color title;
struct dialog_color border;
struct dialog_color button_active;
struct dialog_color button_inactive;
struct dialog_color button_key_active;
struct dialog_color button_key_inactive;
struct dialog_color button_label_active;
struct dialog_color button_label_inactive;
struct dialog_color inputbox;
struct dialog_color inputbox_border;
struct dialog_color searchbox;
struct dialog_color searchbox_title;
struct dialog_color searchbox_border;
struct dialog_color position_indicator;
struct dialog_color menubox;
struct dialog_color menubox_border;
struct dialog_color item;
struct dialog_color item_selected;
struct dialog_color tag;
struct dialog_color tag_selected;
struct dialog_color tag_key;
struct dialog_color tag_key_selected;
struct dialog_color check;
struct dialog_color check_selected;
struct dialog_color uarrow;
struct dialog_color darrow;
};
/*
* Global variables
*/
extern struct dialog_info dlg;
extern char dialog_input_result[];
extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */
/*
* Function prototypes
*/
/* item list as used by checklist and menubox */
void item_reset(void);
void item_make(const char *fmt, ...);
void item_add_str(const char *fmt, ...);
void item_set_tag(char tag);
void item_set_data(void *p);
void item_set_selected(int val);
int item_activate_selected(void);
void *item_data(void);
char item_tag(void);
/* item list manipulation for lxdialog use */
#define MAXITEMSTR 200
struct dialog_item {
char str[MAXITEMSTR]; /* prompt displayed */
char tag;
void *data; /* pointer to menu item - used by menubox+checklist */
int selected; /* Set to 1 by dialog_*() function if selected. */
};
/* list of lialog_items */
struct dialog_list {
struct dialog_item node;
struct dialog_list *next;
};
extern struct dialog_list *item_cur;
extern struct dialog_list item_nil;
extern struct dialog_list *item_head;
int item_count(void);
void item_set(int n);
int item_n(void);
const char *item_str(void);
int item_is_selected(void);
int item_is_tag(char tag);
#define item_foreach() \
for (item_cur = item_head ? item_head: item_cur; \
item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
/* generic key handlers */
int on_key_esc(WINDOW *win);
int on_key_resize(void);
/* minimum (re)size values */
#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */
#define CHECKLIST_WIDTH_MIN 6
#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */
#define INPUTBOX_WIDTH_MIN 2
#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */
#define MENUBOX_WIDTH_MIN 65
#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */
#define TEXTBOX_WIDTH_MIN 8
#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */
#define YESNO_WIDTH_MIN 4
#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */
#define WINDOW_WIDTH_MIN 80
int init_dialog(const char *backtitle);
void set_dialog_backtitle(const char *backtitle);
void set_dialog_subtitles(struct subtitle_list *subtitles);
void end_dialog(int x, int y);
void attr_clear(WINDOW * win, int height, int width, chtype attr);
void dialog_clear(void);
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
void print_button(WINDOW * win, const char *label, int y, int x, int selected);
void print_title(WINDOW *dialog, const char *title, int width);
void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
chtype border);
void draw_shadow(WINDOW * win, int y, int x, int height, int width);
int first_alpha(const char *string, const char *exempt);
int dialog_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause);
typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
*_data);
int dialog_textbox(const char *title, char *tbuf, int initial_height,
int initial_width, int *keys, int *_vscroll, int *_hscroll,
update_text_fn update_text, void *data);
int dialog_menu(const char *title, const char *prompt,
const void *selected, int *s_scroll);
int dialog_checklist(const char *title, const char *prompt, int height,
int width, int list_height);
int dialog_inputbox(const char *title, const char *prompt, int height,
int width, const char *init);
/*
* This is the base for fictitious keys, which activate
* the buttons.
*
* Mouse-generated keys are the following:
* -- the first 32 are used as numbers, in addition to '0'-'9'
* -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
* -- uppercase chars are used to invoke the button (M_EVENT + 'O')
*/
#define M_EVENT (KEY_MAX+1)

Some files were not shown because too many files have changed in this diff Show More