Merge tag 'v4.15' into x86/pti, to be able to merge dependent changes
Time has come to switch PTI development over to a v4.15 base - we'll still try to make sure that all PTI fixes backport cleanly to v4.14 and earlier. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
+90
-16
@@ -8,6 +8,8 @@ squote := '
|
||||
empty :=
|
||||
space := $(empty) $(empty)
|
||||
space_escape := _-_SPACE_-_
|
||||
right_paren := )
|
||||
left_paren := (
|
||||
|
||||
###
|
||||
# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
|
||||
@@ -80,6 +82,71 @@ cc-cross-prefix = \
|
||||
echo $(c); \
|
||||
fi)))
|
||||
|
||||
# Tools for caching Makefile variables that are "expensive" to compute.
|
||||
#
|
||||
# Here we want to help deal with variables that take a long time to compute
|
||||
# by making it easy to store these variables in a cache.
|
||||
#
|
||||
# The canonical example here is testing for compiler flags. On a simple system
|
||||
# each call to the compiler takes 10 ms, but on a system with a compiler that's
|
||||
# called through various wrappers it can take upwards of 100 ms. If we have
|
||||
# 100 calls to the compiler this can take 1 second (on a simple system) or 10
|
||||
# seconds (on a complicated system).
|
||||
#
|
||||
# The "cache" will be in Makefile syntax and can be directly included.
|
||||
# Any time we try to reference a variable that's not in the cache we'll
|
||||
# calculate it and store it in the cache for next time.
|
||||
|
||||
# Include values from last time
|
||||
make-cache := $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/,$(if $(obj),$(obj)/)).cache.mk
|
||||
$(make-cache): ;
|
||||
-include $(make-cache)
|
||||
|
||||
cached-data := $(filter __cached_%, $(.VARIABLES))
|
||||
|
||||
# If cache exceeds 1000 lines, shrink it down to 500.
|
||||
ifneq ($(word 1000,$(cached-data)),)
|
||||
$(shell tail -n 500 $(make-cache) > $(make-cache).tmp; \
|
||||
mv $(make-cache).tmp $(make-cache))
|
||||
endif
|
||||
|
||||
create-cache-dir := $(if $(KBUILD_SRC),$(if $(cache-data),,1))
|
||||
|
||||
# Usage: $(call __sanitize-opt,Hello=Hola$(comma)Goodbye Adios)
|
||||
#
|
||||
# Convert all '$', ')', '(', '\', '=', ' ', ',', ':' to '_'
|
||||
__sanitize-opt = $(subst $$,_,$(subst $(right_paren),_,$(subst $(left_paren),_,$(subst \,_,$(subst =,_,$(subst $(space),_,$(subst $(comma),_,$(subst :,_,$(1)))))))))
|
||||
|
||||
# Usage: $(call shell-cached,shell_command)
|
||||
# Example: $(call shell-cached,md5sum /usr/bin/gcc)
|
||||
#
|
||||
# If we've already seen a call to this exact shell command (even in a
|
||||
# previous invocation of make!) we'll return the value. If not, we'll
|
||||
# compute it and store the result for future runs.
|
||||
#
|
||||
# This is a bit of voodoo, but basic explanation is that if the variable
|
||||
# was undefined then we'll evaluate the shell command and store the result
|
||||
# into the variable. We'll then store that value in the cache and finally
|
||||
# output the value.
|
||||
#
|
||||
# NOTE: The $$(2) here isn't actually a parameter to __run-and-store. We
|
||||
# happen to know that the caller will have their shell command in $(2) so the
|
||||
# result of "call"ing this will produce a reference to that $(2). The reason
|
||||
# for this strangeness is to avoid an extra level of eval (and escaping) of
|
||||
# $(2).
|
||||
define __run-and-store
|
||||
ifeq ($(origin $(1)),undefined)
|
||||
$$(eval $(1) := $$(shell $$(2)))
|
||||
ifeq ($(create-cache-dir),1)
|
||||
$$(shell mkdir -p $(dir $(make-cache)))
|
||||
$$(eval create-cache-dir :=)
|
||||
endif
|
||||
$$(shell echo '$(1) := $$($(1))' >> $(make-cache))
|
||||
endif
|
||||
endef
|
||||
__shell-cached = $(eval $(call __run-and-store,$(1)))$($(1))
|
||||
shell-cached = $(call __shell-cached,__cached_$(call __sanitize-opt,$(1)),$(1))
|
||||
|
||||
# output directory for tests below
|
||||
TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
|
||||
|
||||
@@ -87,30 +154,36 @@ TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
|
||||
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
|
||||
# Exit code chooses option. "$$TMP" serves as a temporary file and is
|
||||
# automatically cleaned up.
|
||||
try-run = $(shell set -e; \
|
||||
__try-run = set -e; \
|
||||
TMP="$(TMPOUT).$$$$.tmp"; \
|
||||
TMPO="$(TMPOUT).$$$$.o"; \
|
||||
if ($(1)) >/dev/null 2>&1; \
|
||||
then echo "$(2)"; \
|
||||
else echo "$(3)"; \
|
||||
fi; \
|
||||
rm -f "$$TMP" "$$TMPO")
|
||||
rm -f "$$TMP" "$$TMPO"
|
||||
|
||||
try-run = $(shell $(__try-run))
|
||||
|
||||
# try-run-cached
|
||||
# This works like try-run, but the result is cached.
|
||||
try-run-cached = $(call shell-cached,$(__try-run))
|
||||
|
||||
# as-option
|
||||
# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
|
||||
|
||||
as-option = $(call try-run,\
|
||||
as-option = $(call try-run-cached,\
|
||||
$(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,\
|
||||
as-instr = $(call try-run-cached,\
|
||||
printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3))
|
||||
|
||||
# __cc-option
|
||||
# Usage: MY_CFLAGS += $(call __cc-option,$(CC),$(MY_CFLAGS),-march=winchip-c6,-march=i586)
|
||||
__cc-option = $(call try-run,\
|
||||
__cc-option = $(call try-run-cached,\
|
||||
$(1) -Werror $(2) $(3) -c -x c /dev/null -o "$$TMP",$(3),$(4))
|
||||
|
||||
# Do not attempt to build with gcc plugins during cc-option tests.
|
||||
@@ -130,23 +203,23 @@ hostcc-option = $(call __cc-option, $(HOSTCC),\
|
||||
|
||||
# cc-option-yn
|
||||
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
|
||||
cc-option-yn = $(call try-run,\
|
||||
cc-option-yn = $(call try-run-cached,\
|
||||
$(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n)
|
||||
|
||||
# cc-disable-warning
|
||||
# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
|
||||
cc-disable-warning = $(call try-run,\
|
||||
cc-disable-warning = $(call try-run-cached,\
|
||||
$(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_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-name = $(call shell-cached,$(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-version = $(call shell-cached,$(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
|
||||
|
||||
# cc-fullversion
|
||||
cc-fullversion = $(shell $(CONFIG_SHELL) \
|
||||
cc-fullversion = $(call shell-cached,$(CONFIG_SHELL) \
|
||||
$(srctree)/scripts/gcc-version.sh -p $(CC))
|
||||
|
||||
# cc-ifversion
|
||||
@@ -159,22 +232,23 @@ cc-if-fullversion = $(shell [ $(cc-fullversion) $(1) $(2) ] && echo $(3) || echo
|
||||
|
||||
# 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))
|
||||
cc-ldoption = $(call try-run-cached,\
|
||||
$(CC) $(1) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -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))
|
||||
ld-option = $(call try-run-cached,\
|
||||
$(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -x c /dev/null -c -o "$$TMPO"; \
|
||||
$(LD) $(LDFLAGS) $(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))
|
||||
ar-option = $(call try-run-cached, $(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-version = $(call shell-cached,$(LD) --version | $(srctree)/scripts/ld-version.sh)
|
||||
|
||||
# ld-ifversion
|
||||
# Usage: $(call ld-ifversion, -ge, 22252, y)
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
# and for each file listed in this file with generic-y creates
|
||||
# a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/$(src))
|
||||
|
||||
PHONY := all
|
||||
all:
|
||||
|
||||
kbuild-file := $(srctree)/arch/$(SRCARCH)/include/$(src)/Kbuild
|
||||
-include $(kbuild-file)
|
||||
|
||||
|
||||
+20
-14
@@ -65,15 +65,6 @@ ifneq ($(hostprogs-y)$(hostprogs-m)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(h
|
||||
include scripts/Makefile.host
|
||||
endif
|
||||
|
||||
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
|
||||
@@ -85,7 +76,7 @@ lib-target := $(obj)/lib.a
|
||||
obj-y += $(obj)/lib-ksyms.o
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),)
|
||||
ifneq ($(strip $(obj-y) $(need-builtin)),)
|
||||
builtin-target := $(obj)/built-in.o
|
||||
endif
|
||||
|
||||
@@ -109,6 +100,10 @@ ifneq ($(KBUILD_CHECKSRC),0)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),)
|
||||
cmd_checkdoc = $(srctree)/scripts/kernel-doc -none $< ;
|
||||
endif
|
||||
|
||||
# Do section mismatch analysis for each module/built-in.o
|
||||
ifdef CONFIG_DEBUG_SECTION_MISMATCH
|
||||
cmd_secanalysis = ; scripts/mod/modpost $@
|
||||
@@ -297,6 +292,7 @@ objtool_dep = $(objtool_obj) \
|
||||
define rule_cc_o_c
|
||||
$(call echo-cmd,checksrc) $(cmd_checksrc) \
|
||||
$(call cmd_and_fixdep,cc_o_c) \
|
||||
$(cmd_checkdoc) \
|
||||
$(call echo-cmd,objtool) $(cmd_objtool) \
|
||||
$(cmd_modversions_c) \
|
||||
$(call echo-cmd,record_mcount) $(cmd_record_mcount)
|
||||
@@ -569,14 +565,14 @@ $(multi-used-m): FORCE
|
||||
$(call multi_depend, $(multi-used-m), .o, -objs -y -m)
|
||||
|
||||
targets += $(multi-used-y) $(multi-used-m)
|
||||
|
||||
targets := $(filter-out $(PHONY), $(targets))
|
||||
|
||||
# Descending
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
PHONY += $(subdir-ym)
|
||||
$(subdir-ym):
|
||||
$(Q)$(MAKE) $(build)=$@
|
||||
$(Q)$(MAKE) $(build)=$@ need-builtin=$(if $(findstring $@,$(subdir-obj-y)),1)
|
||||
|
||||
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -590,13 +586,23 @@ FORCE:
|
||||
# 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))
|
||||
cmd_files := $(wildcard $(foreach f,$(sort $(targets)),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_SRC),)
|
||||
# Create directories for object files if they do not exist
|
||||
obj-dirs := $(sort $(obj) $(patsubst %/,%, $(dir $(targets))))
|
||||
# If cmd_files exist, their directories apparently exist. Skip mkdir.
|
||||
exist-dirs := $(sort $(patsubst %/,%, $(dir $(cmd_files))))
|
||||
obj-dirs := $(strip $(filter-out $(exist-dirs), $(obj-dirs)))
|
||||
ifneq ($(obj-dirs),)
|
||||
$(shell mkdir -p $(obj-dirs))
|
||||
endif
|
||||
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.
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
# INSTALL_DTBS_PATH directory or the default location:
|
||||
#
|
||||
# $INSTALL_PATH/dtbs/$KERNELRELEASE
|
||||
#
|
||||
# Traverse through subdirectories listed in $(dts-dirs).
|
||||
# ==========================================================================
|
||||
|
||||
src := $(obj)
|
||||
@@ -21,8 +19,8 @@ include include/config/auto.conf
|
||||
include scripts/Kbuild.include
|
||||
include $(src)/Makefile
|
||||
|
||||
dtbinst-files := $(dtb-y)
|
||||
dtbinst-dirs := $(dts-dirs)
|
||||
dtbinst-files := $(sort $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS), $(dtb-)))
|
||||
dtbinst-dirs := $(subdir-y) $(subdir-m)
|
||||
|
||||
# Helper targets for Installing DTBs into the boot directory
|
||||
quiet_cmd_dtb_install = INSTALL $<
|
||||
|
||||
@@ -27,11 +27,11 @@ subdirs := $(patsubst $(srcdir)/%/,%,\
|
||||
# Recursion
|
||||
__headers: $(subdirs)
|
||||
|
||||
.PHONY: $(subdirs)
|
||||
PHONY += $(subdirs)
|
||||
$(subdirs):
|
||||
$(Q)$(MAKE) $(hdr-inst)=$(obj)/$@ dst=$(dst)/$@
|
||||
|
||||
# Skip header install/check for include/uapi and arch/$(hdr-arch)/include/uapi.
|
||||
# Skip header install/check for include/uapi and arch/$(SRCARCH)/include/uapi.
|
||||
# We have only sub-directories there.
|
||||
skip-inst := $(if $(filter %/uapi,$(obj)),1)
|
||||
|
||||
@@ -115,9 +115,8 @@ $(check-file): scripts/headers_check.pl $(output-files) FORCE
|
||||
|
||||
endif
|
||||
|
||||
targets := $(wildcard $(sort $(targets)))
|
||||
cmd_files := $(wildcard \
|
||||
$(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
$(foreach f,$(sort $(targets)),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
@@ -125,6 +124,7 @@ endif
|
||||
|
||||
endif # skip-inst
|
||||
|
||||
.PHONY: $(PHONY)
|
||||
PHONY += FORCE
|
||||
FORCE: ;
|
||||
|
||||
.PHONY: $(PHONY)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
checker-help:
|
||||
@echo ' coccicheck - Check with Coccinelle.'
|
||||
@@ -49,15 +49,6 @@ host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
|
||||
host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
|
||||
host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs))))
|
||||
|
||||
# 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))
|
||||
@@ -67,9 +58,6 @@ host-cshlib := $(addprefix $(obj)/,$(host-cshlib))
|
||||
host-cxxshlib := $(addprefix $(obj)/,$(host-cxxshlib))
|
||||
host-cshobjs := $(addprefix $(obj)/,$(host-cshobjs))
|
||||
host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs))
|
||||
host-objdirs := $(addprefix $(obj)/,$(host-objdirs))
|
||||
|
||||
obj-dirs += $(host-objdirs)
|
||||
|
||||
#####
|
||||
# Handle options to gcc. Support building with separate output directory
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ifdef CONFIG_KCOV
|
||||
CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,)
|
||||
ifeq ($(CONFIG_KCOV_ENABLE_COMPARISONS),y)
|
||||
CFLAGS_KCOV += $(call cc-option,-fsanitize-coverage=trace-cmp,)
|
||||
endif
|
||||
|
||||
endif
|
||||
+17
-24
@@ -5,24 +5,25 @@ 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)
|
||||
# flags that take effect in current and sub directories
|
||||
KBUILD_AFLAGS += $(subdir-asflags-y)
|
||||
KBUILD_CFLAGS += $(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)))
|
||||
|
||||
# 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))
|
||||
|
||||
# Handle objects in subdirs
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -30,12 +31,6 @@ lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
|
||||
# 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)))
|
||||
@@ -44,10 +39,9 @@ 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
|
||||
# if $(foo-objs), $(foo-y), or $(foo-m) 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:.o=-m))), $(m))))
|
||||
multi-used := $(multi-used-y) $(multi-used-m)
|
||||
@@ -57,19 +51,20 @@ single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
|
||||
# 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-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)))
|
||||
real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m)))
|
||||
|
||||
# DTB
|
||||
# If CONFIG_OF_ALL_DTBS is enabled, all DT blobs are built
|
||||
extra-y += $(dtb-y)
|
||||
extra-$(CONFIG_OF_ALL_DTBS) += $(dtb-)
|
||||
|
||||
# Add subdir path
|
||||
|
||||
extra-y := $(addprefix $(obj)/,$(extra-y))
|
||||
@@ -88,11 +83,9 @@ 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
|
||||
# $(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
|
||||
@@ -102,10 +95,10 @@ basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget))
|
||||
modname_flags = $(if $(filter 1,$(words $(modname))),\
|
||||
-DKBUILD_MODNAME=$(call name-fix,$(modname)))
|
||||
|
||||
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
|
||||
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
|
||||
$(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) \
|
||||
orig_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) \
|
||||
$(asflags-y) $(AFLAGS_$(basetarget).o)
|
||||
_a_flags = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags))
|
||||
_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
|
||||
|
||||
@@ -143,8 +143,7 @@ FORCE:
|
||||
# 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))
|
||||
cmd_files := $(wildcard $(foreach f,$(sort $(targets)),$(dir $(f)).$(notdir $(f)).cmd))
|
||||
|
||||
ifneq ($(cmd_files),)
|
||||
include $(cmd_files)
|
||||
|
||||
+58
-34
@@ -12,18 +12,22 @@ from signal import signal, SIGPIPE, SIG_DFL
|
||||
|
||||
signal(SIGPIPE, SIG_DFL)
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
sys.stderr.write("usage: %s file1 file2\n" % sys.argv[0])
|
||||
if len(sys.argv) < 3:
|
||||
sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0])
|
||||
sys.stderr.write("The options are:\n")
|
||||
sys.stderr.write("-c cateogrize output based on symbole type\n")
|
||||
sys.stderr.write("-d Show delta of Data Section\n")
|
||||
sys.stderr.write("-t Show delta of text Section\n")
|
||||
sys.exit(-1)
|
||||
|
||||
re_NUMBER = re.compile(r'\.[0-9]+')
|
||||
|
||||
def getsizes(file):
|
||||
def getsizes(file, format):
|
||||
sym = {}
|
||||
with os.popen("nm --size-sort " + file) as f:
|
||||
for line in f:
|
||||
size, type, name = line.split()
|
||||
if type in "tTdDbBrR":
|
||||
if type in format:
|
||||
# strip generated symbols
|
||||
if name.startswith("__mod_"): continue
|
||||
if name.startswith("SyS_"): continue
|
||||
@@ -34,44 +38,64 @@ def getsizes(file):
|
||||
sym[name] = sym.get(name, 0) + int(size, 16)
|
||||
return sym
|
||||
|
||||
old = getsizes(sys.argv[1])
|
||||
new = getsizes(sys.argv[2])
|
||||
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
|
||||
delta, common = [], {}
|
||||
otot, ntot = 0, 0
|
||||
def calc(oldfile, newfile, format):
|
||||
old = getsizes(oldfile, format)
|
||||
new = getsizes(newfile, format)
|
||||
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
|
||||
delta, common = [], {}
|
||||
otot, ntot = 0, 0
|
||||
|
||||
for a in old:
|
||||
if a in new:
|
||||
common[a] = 1
|
||||
for a in old:
|
||||
if a in new:
|
||||
common[a] = 1
|
||||
|
||||
for name in old:
|
||||
otot += old[name]
|
||||
if name not in common:
|
||||
remove += 1
|
||||
down += old[name]
|
||||
delta.append((-old[name], name))
|
||||
for name in old:
|
||||
otot += old[name]
|
||||
if name not in common:
|
||||
remove += 1
|
||||
down += old[name]
|
||||
delta.append((-old[name], name))
|
||||
|
||||
for name in new:
|
||||
ntot += new[name]
|
||||
if name not in common:
|
||||
add += 1
|
||||
up += new[name]
|
||||
delta.append((new[name], name))
|
||||
for name in new:
|
||||
ntot += new[name]
|
||||
if name not in common:
|
||||
add += 1
|
||||
up += new[name]
|
||||
delta.append((new[name], name))
|
||||
|
||||
for name in common:
|
||||
for name in common:
|
||||
d = new.get(name, 0) - old.get(name, 0)
|
||||
if d>0: grow, up = grow+1, up+d
|
||||
if d<0: shrink, down = shrink+1, down-d
|
||||
delta.append((d, name))
|
||||
|
||||
delta.sort()
|
||||
delta.reverse()
|
||||
delta.sort()
|
||||
delta.reverse()
|
||||
return grow, shrink, add, remove, up, down, delta, old, new, otot, ntot
|
||||
|
||||
print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
|
||||
(add, remove, grow, shrink, up, -down, up-down))
|
||||
print("%-40s %7s %7s %+7s" % ("function", "old", "new", "delta"))
|
||||
for d, n in delta:
|
||||
if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d))
|
||||
def print_result(symboltype, symbolformat, argc):
|
||||
grow, shrink, add, remove, up, down, delta, old, new, otot, ntot = \
|
||||
calc(sys.argv[argc - 1], sys.argv[argc], symbolformat)
|
||||
|
||||
print("Total: Before=%d, After=%d, chg %+.2f%%" % \
|
||||
(otot, ntot, (ntot - otot)*100.0/otot))
|
||||
print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
|
||||
(add, remove, grow, shrink, up, -down, up-down))
|
||||
print("%-40s %7s %7s %+7s" % (symboltype, "old", "new", "delta"))
|
||||
for d, n in delta:
|
||||
if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d))
|
||||
|
||||
if otot:
|
||||
percent = (ntot - otot) * 100.0 / otot
|
||||
else:
|
||||
percent = 0
|
||||
print("Total: Before=%d, After=%d, chg %+.2f%%" % (otot, ntot, percent))
|
||||
|
||||
if sys.argv[1] == "-c":
|
||||
print_result("Function", "tT", 3)
|
||||
print_result("Data", "dDbB", 3)
|
||||
print_result("RO Data", "rR", 3)
|
||||
elif sys.argv[1] == "-d":
|
||||
print_result("Data", "dDbBrR", 3)
|
||||
elif sys.argv[1] == "-t":
|
||||
print_result("Function", "tT", 3)
|
||||
else:
|
||||
print_result("Function", "tTdDbBrR", 2)
|
||||
|
||||
+18
-49
@@ -454,6 +454,7 @@ our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
|
||||
our $logFunctions = qr{(?x:
|
||||
printk(?:_ratelimited|_once|_deferred_once|_deferred|)|
|
||||
(?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
|
||||
TP_printk|
|
||||
WARN(?:_RATELIMIT|_ONCE|)|
|
||||
panic|
|
||||
MODULE_[A-Z_]+|
|
||||
@@ -2900,8 +2901,9 @@ sub process {
|
||||
$line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) {
|
||||
$msg_type = "";
|
||||
|
||||
# EFI_GUID is another special case
|
||||
} elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) {
|
||||
# More special cases
|
||||
} elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/ ||
|
||||
$line =~ /^\+\s*(?:\w+)?\s*DEFINE_PER_CPU/) {
|
||||
$msg_type = "";
|
||||
|
||||
# Otherwise set the alternate message types
|
||||
@@ -3103,6 +3105,7 @@ sub process {
|
||||
$line =~ /^\+[a-z_]*init/ ||
|
||||
$line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ ||
|
||||
$line =~ /^\+\s*DECLARE/ ||
|
||||
$line =~ /^\+\s*builtin_[\w_]*driver/ ||
|
||||
$line =~ /^\+\s*__setup/)) {
|
||||
if (CHK("LINE_SPACING",
|
||||
"Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) &&
|
||||
@@ -3182,6 +3185,12 @@ sub process {
|
||||
# check we are in a valid C source file if not then ignore this hunk
|
||||
next if ($realfile !~ /\.(h|c)$/);
|
||||
|
||||
# check for unusual line ending [ or (
|
||||
if ($line =~ /^\+.*([\[\(])\s*$/) {
|
||||
CHK("OPEN_ENDED_LINE",
|
||||
"Lines should not end with a '$1'\n" . $herecurr);
|
||||
}
|
||||
|
||||
# check if this appears to be the start function declaration, save the name
|
||||
if ($sline =~ /^\+\{\s*$/ &&
|
||||
$prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) {
|
||||
@@ -3829,28 +3838,10 @@ sub process {
|
||||
"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
|
||||
}
|
||||
|
||||
# printk should use KERN_* levels. Note that follow on printk's on the
|
||||
# same line do not need a level, so we use the current block context
|
||||
# to try and find and validate the current printk. In summary the current
|
||||
# printk includes all preceding printk's which have no newline on the end.
|
||||
# we assume the first bad printk is the one to report.
|
||||
if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
|
||||
my $ok = 0;
|
||||
for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
|
||||
#print "CHECK<$lines[$ln - 1]\n";
|
||||
# we have a preceding printk if it ends
|
||||
# with "\n" ignore it, else it is to blame
|
||||
if ($lines[$ln - 1] =~ m{\bprintk\(}) {
|
||||
if ($rawlines[$ln - 1] !~ m{\\n"}) {
|
||||
$ok = 1;
|
||||
}
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($ok == 0) {
|
||||
WARN("PRINTK_WITHOUT_KERN_LEVEL",
|
||||
"printk() should include KERN_ facility level\n" . $herecurr);
|
||||
}
|
||||
# printk should use KERN_* levels
|
||||
if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) {
|
||||
WARN("PRINTK_WITHOUT_KERN_LEVEL",
|
||||
"printk() should include KERN_<LEVEL> facility level\n" . $herecurr);
|
||||
}
|
||||
|
||||
if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) {
|
||||
@@ -5762,7 +5753,7 @@ sub process {
|
||||
for (my $count = $linenr; $count <= $lc; $count++) {
|
||||
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
|
||||
$fmt =~ s/%%//g;
|
||||
if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
|
||||
if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNOx]).)/) {
|
||||
$bad_extension = $1;
|
||||
last;
|
||||
}
|
||||
@@ -5957,7 +5948,7 @@ sub process {
|
||||
|
||||
# check for function declarations that have arguments without identifier names
|
||||
if (defined $stat &&
|
||||
$stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s &&
|
||||
$stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s &&
|
||||
$1 ne "void") {
|
||||
my $args = trim($1);
|
||||
while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) {
|
||||
@@ -6109,7 +6100,7 @@ sub process {
|
||||
next if ($fline =~ /^.[\s$;]*$/);
|
||||
$has_statement = 1;
|
||||
$count++;
|
||||
$has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/);
|
||||
$has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|exit\s*\(\b|return\b|goto\b|continue\b)/);
|
||||
}
|
||||
if (!$has_break && $has_statement) {
|
||||
WARN("MISSING_BREAK",
|
||||
@@ -6242,28 +6233,6 @@ sub process {
|
||||
}
|
||||
}
|
||||
|
||||
# whine about ACCESS_ONCE
|
||||
if ($^V && $^V ge 5.10.0 &&
|
||||
$line =~ /\bACCESS_ONCE\s*$balanced_parens\s*(=(?!=))?\s*($FuncArg)?/) {
|
||||
my $par = $1;
|
||||
my $eq = $2;
|
||||
my $fun = $3;
|
||||
$par =~ s/^\(\s*(.*)\s*\)$/$1/;
|
||||
if (defined($eq)) {
|
||||
if (WARN("PREFER_WRITE_ONCE",
|
||||
"Prefer WRITE_ONCE(<FOO>, <BAR>) over ACCESS_ONCE(<FOO>) = <BAR>\n" . $herecurr) &&
|
||||
$fix) {
|
||||
$fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)\s*$eq\s*\Q$fun\E/WRITE_ONCE($par, $fun)/;
|
||||
}
|
||||
} else {
|
||||
if (WARN("PREFER_READ_ONCE",
|
||||
"Prefer READ_ONCE(<FOO>) over ACCESS_ONCE(<FOO>)\n" . $herecurr) &&
|
||||
$fix) {
|
||||
$fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)/READ_ONCE($par)/;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# check for mutex_trylock_recursive usage
|
||||
if ($line =~ /mutex_trylock_recursive/) {
|
||||
ERROR("LOCKING",
|
||||
|
||||
+23
-18
@@ -30,12 +30,6 @@ 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
|
||||
@@ -70,6 +64,9 @@ if [ "$C" = "1" -o "$C" = "2" ]; then
|
||||
# Take only the last argument, which is the C file to test
|
||||
shift $(( $# - 1 ))
|
||||
OPTIONS="$COCCIINCLUDE $1"
|
||||
|
||||
# No need to parallelize Coccinelle since this mode takes one input file.
|
||||
NPROC=1
|
||||
else
|
||||
ONLINE=0
|
||||
if [ "$KBUILD_EXTMOD" = "" ] ; then
|
||||
@@ -77,6 +74,12 @@ else
|
||||
else
|
||||
OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
|
||||
fi
|
||||
|
||||
if [ -z "$J" ]; then
|
||||
NPROC=$(getconf _NPROCESSORS_ONLN)
|
||||
else
|
||||
NPROC="$J"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$KBUILD_EXTMOD" != "" ] ; then
|
||||
@@ -123,15 +126,8 @@ 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
|
||||
echo $@ >>$DEBUG_FILE
|
||||
$@ 2>>$DEBUG_FILE
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "coccicheck failed"
|
||||
exit $?
|
||||
@@ -176,8 +172,8 @@ OPTIONS="$OPTIONS $SPFLAGS"
|
||||
coccinelle () {
|
||||
COCCI="$1"
|
||||
|
||||
OPT=`grep "Option" $COCCI | cut -d':' -f2`
|
||||
REQ=`grep "Requires" $COCCI | cut -d':' -f2 | sed "s| ||"`
|
||||
OPT=`grep "Options:" $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
|
||||
@@ -194,7 +190,7 @@ coccinelle () {
|
||||
|
||||
if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then
|
||||
|
||||
FILE=`echo $COCCI | sed "s|$srctree/||"`
|
||||
FILE=${COCCI#$srctree/}
|
||||
|
||||
echo "Processing `basename $COCCI`"
|
||||
echo "with option(s) \"$OPT\""
|
||||
@@ -247,6 +243,15 @@ coccinelle () {
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if [ "$COCCI" = "" ] ; then
|
||||
for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
|
||||
coccinelle $f
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/// Detect BQ27XXX_DATA structures with identical registers, dm registers or
|
||||
/// properties.
|
||||
//# Doesn't unfold macros used in register or property fields.
|
||||
//# Requires OCaml scripting
|
||||
///
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2017 Julia Lawall, Inria/LIP6, GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Requires: 1.0.7
|
||||
// Keywords: BQ27XXX_DATA
|
||||
|
||||
virtual report
|
||||
|
||||
@initialize:ocaml@
|
||||
@@
|
||||
|
||||
let print_report p msg =
|
||||
let p = List.hd p in
|
||||
Printf.printf "%s:%d:%d-%d: %s" p.file p.line p.col p.col_end msg
|
||||
|
||||
@str depends on report@
|
||||
type t;
|
||||
identifier i,i1,i2;
|
||||
expression e1,e2;
|
||||
@@
|
||||
|
||||
t i[] = {
|
||||
...,
|
||||
[e1] = BQ27XXX_DATA(i1,...),
|
||||
...,
|
||||
[e2] = BQ27XXX_DATA(i2,...),
|
||||
...,
|
||||
};
|
||||
|
||||
@script:ocaml tocheck@
|
||||
i1 << str.i1;
|
||||
i2 << str.i2;
|
||||
i1regs; i2regs;
|
||||
i1dmregs; i2dmregs;
|
||||
i1props; i2props;
|
||||
@@
|
||||
|
||||
if not(i1 = i2)
|
||||
then
|
||||
begin
|
||||
i1regs := make_ident (i1 ^ "_regs");
|
||||
i2regs := make_ident (i2 ^ "_regs");
|
||||
i1dmregs := make_ident (i1 ^ "_dm_regs");
|
||||
i2dmregs := make_ident (i2 ^ "_dm_regs");
|
||||
i1props := make_ident (i1 ^ "_props");
|
||||
i2props := make_ident (i2 ^ "_props")
|
||||
end
|
||||
|
||||
(* ---------------------------------------------------------------- *)
|
||||
|
||||
@getregs1@
|
||||
typedef u8;
|
||||
identifier tocheck.i1regs;
|
||||
initializer list i1regs_vals;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
u8 i1regs@p1[...] = { i1regs_vals, };
|
||||
|
||||
@getregs2@
|
||||
identifier tocheck.i2regs;
|
||||
initializer list i2regs_vals;
|
||||
position p2;
|
||||
@@
|
||||
|
||||
u8 i2regs@p2[...] = { i2regs_vals, };
|
||||
|
||||
@script:ocaml@
|
||||
(_,i1regs_vals) << getregs1.i1regs_vals;
|
||||
(_,i2regs_vals) << getregs2.i2regs_vals;
|
||||
i1regs << tocheck.i1regs;
|
||||
i2regs << tocheck.i2regs;
|
||||
p1 << getregs1.p1;
|
||||
p2 << getregs2.p2;
|
||||
@@
|
||||
|
||||
if i1regs < i2regs &&
|
||||
List.sort compare i1regs_vals = List.sort compare i2regs_vals
|
||||
then
|
||||
let msg =
|
||||
Printf.sprintf
|
||||
"WARNING %s and %s (line %d) are identical\n"
|
||||
i1regs i2regs (List.hd p2).line in
|
||||
print_report p1 msg
|
||||
|
||||
(* ---------------------------------------------------------------- *)
|
||||
|
||||
@getdmregs1@
|
||||
identifier tocheck.i1dmregs;
|
||||
initializer list i1dmregs_vals;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
struct bq27xxx_dm_reg i1dmregs@p1[] = { i1dmregs_vals, };
|
||||
|
||||
@getdmregs2@
|
||||
identifier tocheck.i2dmregs;
|
||||
initializer list i2dmregs_vals;
|
||||
position p2;
|
||||
@@
|
||||
|
||||
struct bq27xxx_dm_reg i2dmregs@p2[] = { i2dmregs_vals, };
|
||||
|
||||
@script:ocaml@
|
||||
(_,i1dmregs_vals) << getdmregs1.i1dmregs_vals;
|
||||
(_,i2dmregs_vals) << getdmregs2.i2dmregs_vals;
|
||||
i1dmregs << tocheck.i1dmregs;
|
||||
i2dmregs << tocheck.i2dmregs;
|
||||
p1 << getdmregs1.p1;
|
||||
p2 << getdmregs2.p2;
|
||||
@@
|
||||
|
||||
if i1dmregs < i2dmregs &&
|
||||
List.sort compare i1dmregs_vals = List.sort compare i2dmregs_vals
|
||||
then
|
||||
let msg =
|
||||
Printf.sprintf
|
||||
"WARNING %s and %s (line %d) are identical\n"
|
||||
i1dmregs i2dmregs (List.hd p2).line in
|
||||
print_report p1 msg
|
||||
|
||||
(* ---------------------------------------------------------------- *)
|
||||
|
||||
@getprops1@
|
||||
identifier tocheck.i1props;
|
||||
initializer list[n1] i1props_vals;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
enum power_supply_property i1props@p1[] = { i1props_vals, };
|
||||
|
||||
@getprops2@
|
||||
identifier tocheck.i2props;
|
||||
initializer list[n2] i2props_vals;
|
||||
position p2;
|
||||
@@
|
||||
|
||||
enum power_supply_property i2props@p2[] = { i2props_vals, };
|
||||
|
||||
@script:ocaml@
|
||||
(_,i1props_vals) << getprops1.i1props_vals;
|
||||
(_,i2props_vals) << getprops2.i2props_vals;
|
||||
i1props << tocheck.i1props;
|
||||
i2props << tocheck.i2props;
|
||||
p1 << getprops1.p1;
|
||||
p2 << getprops2.p2;
|
||||
@@
|
||||
|
||||
if i1props < i2props &&
|
||||
List.sort compare i1props_vals = List.sort compare i2props_vals
|
||||
then
|
||||
let msg =
|
||||
Printf.sprintf
|
||||
"WARNING %s and %s (line %d) are identical\n"
|
||||
i1props i2props (List.hd p2).line in
|
||||
print_report p1 msg
|
||||
@@ -51,6 +51,9 @@ expression object;
|
||||
|
|
||||
- drm_property_unreference_blob(object)
|
||||
+ drm_property_blob_put(object)
|
||||
|
|
||||
- drm_dev_unref(object)
|
||||
+ drm_dev_put(object)
|
||||
)
|
||||
|
||||
@r depends on report@
|
||||
@@ -82,6 +85,8 @@ drm_gem_object_unreference_unlocked(object)
|
||||
drm_property_unreference_blob@p(object)
|
||||
|
|
||||
drm_property_reference_blob@p(object)
|
||||
|
|
||||
drm_dev_unref@p(object)
|
||||
)
|
||||
|
||||
@script:python depends on report@
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/// Use setup_timer function instead of initializing timer with the function
|
||||
/// and data fields
|
||||
// Confidence: High
|
||||
// Copyright: (C) 2016 Vaishali Thakkar, Oracle. GPLv2
|
||||
// Options: --no-includes --include-headers
|
||||
// Keywords: init_timer, setup_timer
|
||||
|
||||
virtual patch
|
||||
virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@match_immediate_function_data_after_init_timer
|
||||
depends on patch && !context && !org && !report@
|
||||
expression e, func, da;
|
||||
@@
|
||||
|
||||
-init_timer (&e);
|
||||
+setup_timer (&e, func, da);
|
||||
|
||||
(
|
||||
-e.function = func;
|
||||
-e.data = da;
|
||||
|
|
||||
-e.data = da;
|
||||
-e.function = func;
|
||||
)
|
||||
|
||||
@match_function_and_data_after_init_timer
|
||||
depends on patch && !context && !org && !report@
|
||||
expression e1, e2, e3, e4, e5, a, b;
|
||||
@@
|
||||
|
||||
-init_timer (&e1);
|
||||
+setup_timer (&e1, a, b);
|
||||
|
||||
... when != a = e2
|
||||
when != b = e3
|
||||
(
|
||||
-e1.function = a;
|
||||
... when != b = e4
|
||||
-e1.data = b;
|
||||
|
|
||||
-e1.data = b;
|
||||
... when != a = e5
|
||||
-e1.function = a;
|
||||
)
|
||||
|
||||
@r1 exists@
|
||||
identifier f;
|
||||
position p;
|
||||
@@
|
||||
|
||||
f(...) { ... when any
|
||||
init_timer@p(...)
|
||||
... when any
|
||||
}
|
||||
|
||||
@r2 exists@
|
||||
identifier g != r1.f;
|
||||
struct timer_list t;
|
||||
expression e8;
|
||||
@@
|
||||
|
||||
g(...) { ... when any
|
||||
t.data = e8
|
||||
... when any
|
||||
}
|
||||
|
||||
// It is dangerous to use setup_timer if data field is initialized
|
||||
// in another function.
|
||||
|
||||
@script:python depends on r2@
|
||||
p << r1.p;
|
||||
@@
|
||||
|
||||
cocci.include_match(False)
|
||||
|
||||
@r3 depends on patch && !context && !org && !report@
|
||||
expression e6, e7, c;
|
||||
position r1.p;
|
||||
@@
|
||||
|
||||
-init_timer@p (&e6);
|
||||
+setup_timer (&e6, c, 0UL);
|
||||
... when != c = e7
|
||||
-e6.function = c;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@match_immediate_function_data_after_init_timer_context
|
||||
depends on !patch && (context || org || report)@
|
||||
expression da, e, func;
|
||||
position j0, j1, j2;
|
||||
@@
|
||||
|
||||
* init_timer@j0 (&e);
|
||||
(
|
||||
* e@j1.function = func;
|
||||
* e@j2.data = da;
|
||||
|
|
||||
* e@j1.data = da;
|
||||
* e@j2.function = func;
|
||||
)
|
||||
|
||||
@match_function_and_data_after_init_timer_context
|
||||
depends on !patch &&
|
||||
!match_immediate_function_data_after_init_timer_context &&
|
||||
(context || org || report)@
|
||||
expression a, b, e1, e2, e3, e4, e5;
|
||||
position j0, j1, j2;
|
||||
@@
|
||||
|
||||
* init_timer@j0 (&e1);
|
||||
... when != a = e2
|
||||
when != b = e3
|
||||
(
|
||||
* e1@j1.function = a;
|
||||
... when != b = e4
|
||||
* e1@j2.data = b;
|
||||
|
|
||||
* e1@j1.data = b;
|
||||
... when != a = e5
|
||||
* e1@j2.function = a;
|
||||
)
|
||||
|
||||
@r3_context depends on !patch &&
|
||||
!match_immediate_function_data_after_init_timer_context &&
|
||||
!match_function_and_data_after_init_timer_context &&
|
||||
(context || org || report)@
|
||||
expression c, e6, e7;
|
||||
position r1.p;
|
||||
position j0, j1;
|
||||
@@
|
||||
|
||||
* init_timer@j0@p (&e6);
|
||||
... when != c = e7
|
||||
* e6@j1.function = c;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@script:python match_immediate_function_data_after_init_timer_org
|
||||
depends on org@
|
||||
j0 << match_immediate_function_data_after_init_timer_context.j0;
|
||||
j1 << match_immediate_function_data_after_init_timer_context.j1;
|
||||
j2 << match_immediate_function_data_after_init_timer_context.j2;
|
||||
@@
|
||||
|
||||
msg = "Use setup_timer function."
|
||||
coccilib.org.print_todo(j0[0], msg)
|
||||
coccilib.org.print_link(j1[0], "")
|
||||
coccilib.org.print_link(j2[0], "")
|
||||
|
||||
@script:python match_function_and_data_after_init_timer_org depends on org@
|
||||
j0 << match_function_and_data_after_init_timer_context.j0;
|
||||
j1 << match_function_and_data_after_init_timer_context.j1;
|
||||
j2 << match_function_and_data_after_init_timer_context.j2;
|
||||
@@
|
||||
|
||||
msg = "Use setup_timer function."
|
||||
coccilib.org.print_todo(j0[0], msg)
|
||||
coccilib.org.print_link(j1[0], "")
|
||||
coccilib.org.print_link(j2[0], "")
|
||||
|
||||
@script:python r3_org depends on org@
|
||||
j0 << r3_context.j0;
|
||||
j1 << r3_context.j1;
|
||||
@@
|
||||
|
||||
msg = "Use setup_timer function."
|
||||
coccilib.org.print_todo(j0[0], msg)
|
||||
coccilib.org.print_link(j1[0], "")
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@script:python match_immediate_function_data_after_init_timer_report
|
||||
depends on report@
|
||||
j0 << match_immediate_function_data_after_init_timer_context.j0;
|
||||
j1 << match_immediate_function_data_after_init_timer_context.j1;
|
||||
@@
|
||||
|
||||
msg = "Use setup_timer function for function on line %s." % (j1[0].line)
|
||||
coccilib.report.print_report(j0[0], msg)
|
||||
|
||||
@script:python match_function_and_data_after_init_timer_report depends on report@
|
||||
j0 << match_function_and_data_after_init_timer_context.j0;
|
||||
j1 << match_function_and_data_after_init_timer_context.j1;
|
||||
@@
|
||||
|
||||
msg = "Use setup_timer function for function on line %s." % (j1[0].line)
|
||||
coccilib.report.print_report(j0[0], msg)
|
||||
|
||||
@script:python r3_report depends on report@
|
||||
j0 << r3_context.j0;
|
||||
j1 << r3_context.j1;
|
||||
@@
|
||||
|
||||
msg = "Use setup_timer function for function on line %s." % (j1[0].line)
|
||||
coccilib.report.print_report(j0[0], msg)
|
||||
@@ -15,7 +15,7 @@ virtual context
|
||||
virtual org
|
||||
virtual report
|
||||
|
||||
@r@
|
||||
@r exists@
|
||||
iterator name list_for_each_entry;
|
||||
expression x,E;
|
||||
position p1,p2;
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
/// Sometimes, code after an if that is indented is actually intended to be
|
||||
/// part of the if branch.
|
||||
///
|
||||
/// This has a high rate of false positives, because Coccinelle's column
|
||||
/// calculation does not distinguish between spaces and tabs, so code that
|
||||
/// is not visually aligned may be considered to be in the same column.
|
||||
///
|
||||
//# This has a high rate of false positives, because Coccinelle's column
|
||||
//# calculation does not distinguish between spaces and tabs, so code that
|
||||
//# is not visually aligned may be considered to be in the same column.
|
||||
//
|
||||
// Confidence: Low
|
||||
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
|
||||
// Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2.
|
||||
|
||||
@@ -14,7 +14,19 @@ virtual report
|
||||
virtual context
|
||||
|
||||
@r@
|
||||
constant c;
|
||||
constant c,c1;
|
||||
identifier i,i1;
|
||||
position p;
|
||||
@@
|
||||
|
||||
(
|
||||
c1 + c - 1
|
||||
|
|
||||
c1@i1 +@p c@i
|
||||
)
|
||||
|
||||
@s@
|
||||
constant r.c, r.c1;
|
||||
identifier i;
|
||||
expression e;
|
||||
@@
|
||||
@@ -27,28 +39,31 @@ e & c@i
|
||||
e |= c@i
|
||||
|
|
||||
e &= c@i
|
||||
|
|
||||
e | c1@i
|
||||
|
|
||||
e & c1@i
|
||||
|
|
||||
e |= c1@i
|
||||
|
|
||||
e &= c1@i
|
||||
)
|
||||
|
||||
@s@
|
||||
constant r.c,c1;
|
||||
identifier i1;
|
||||
position p;
|
||||
@depends on s@
|
||||
position r.p;
|
||||
constant c1,c2;
|
||||
@@
|
||||
|
||||
(
|
||||
c1 + c - 1
|
||||
|
|
||||
*c1@i1 +@p c
|
||||
)
|
||||
* c1 +@p c2
|
||||
|
||||
@script:python depends on org@
|
||||
p << s.p;
|
||||
@script:python depends on s && org@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
cocci.print_main("sum of probable bitmasks, consider |",p)
|
||||
|
||||
@script:python depends on report@
|
||||
p << s.p;
|
||||
@script:python depends on s && report@
|
||||
p << r.p;
|
||||
@@
|
||||
|
||||
msg = "WARNING: sum of probable bitmasks, consider |"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2.
|
||||
// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6. GPLv2.
|
||||
// URL: http://coccinelle.lip6.fr/
|
||||
// Comments: Requires Coccinelle version 1.0.0-rc20 or later
|
||||
// Requires: 1.0.0
|
||||
// Options:
|
||||
|
||||
virtual patch
|
||||
|
||||
@@ -59,6 +59,14 @@ disas() {
|
||||
${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
|
||||
}
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Treewide grep for references to files under Documentation, and report
|
||||
# non-existing files in stderr.
|
||||
|
||||
for f in $(git ls-files); do
|
||||
for ref in $(grep -ho "Documentation/[A-Za-z0-9_.,~/*+-]*" "$f"); do
|
||||
# presume trailing . and , are not part of the name
|
||||
ref=${ref%%[.,]}
|
||||
|
||||
# use ls to handle wildcards
|
||||
if ! ls $ref >/dev/null 2>&1; then
|
||||
echo "$f: $ref" >&2
|
||||
fi
|
||||
done
|
||||
done
|
||||
+290
-1
@@ -873,7 +873,7 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
|
||||
while (size--)
|
||||
reg = (reg << 32) | fdt32_to_cpu(*(cells++));
|
||||
|
||||
snprintf(unit_addr, sizeof(unit_addr), "%llx", (unsigned long long)reg);
|
||||
snprintf(unit_addr, sizeof(unit_addr), "%"PRIx64, reg);
|
||||
if (!streq(unitname, unit_addr))
|
||||
FAIL(c, dti, "Node %s simple-bus unit address format error, expected \"%s\"",
|
||||
node->fullpath, unit_addr);
|
||||
@@ -956,6 +956,274 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
|
||||
WARNING(obsolete_chosen_interrupt_controller,
|
||||
check_obsolete_chosen_interrupt_controller, NULL);
|
||||
|
||||
struct provider {
|
||||
const char *prop_name;
|
||||
const char *cell_name;
|
||||
bool optional;
|
||||
};
|
||||
|
||||
static void check_property_phandle_args(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node,
|
||||
struct property *prop,
|
||||
const struct provider *provider)
|
||||
{
|
||||
struct node *root = dti->dt;
|
||||
int cell, cellsize = 0;
|
||||
|
||||
if (prop->val.len % sizeof(cell_t)) {
|
||||
FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s",
|
||||
prop->name, prop->val.len, sizeof(cell_t), node->fullpath);
|
||||
return;
|
||||
}
|
||||
|
||||
for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) {
|
||||
struct node *provider_node;
|
||||
struct property *cellprop;
|
||||
int phandle;
|
||||
|
||||
phandle = propval_cell_n(prop, cell);
|
||||
/*
|
||||
* Some bindings use a cell value 0 or -1 to skip over optional
|
||||
* entries when each index position has a specific definition.
|
||||
*/
|
||||
if (phandle == 0 || phandle == -1) {
|
||||
/* Give up if this is an overlay with external references */
|
||||
if (dti->dtsflags & DTSF_PLUGIN)
|
||||
break;
|
||||
|
||||
cellsize = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we have markers, verify the current cell is a phandle */
|
||||
if (prop->val.markers) {
|
||||
struct marker *m = prop->val.markers;
|
||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||
if (m->offset == (cell * sizeof(cell_t)))
|
||||
break;
|
||||
}
|
||||
if (!m)
|
||||
FAIL(c, dti, "Property '%s', cell %d is not a phandle reference in %s",
|
||||
prop->name, cell, node->fullpath);
|
||||
}
|
||||
|
||||
provider_node = get_node_by_phandle(root, phandle);
|
||||
if (!provider_node) {
|
||||
FAIL(c, dti, "Could not get phandle node for %s:%s(cell %d)",
|
||||
node->fullpath, prop->name, cell);
|
||||
break;
|
||||
}
|
||||
|
||||
cellprop = get_property(provider_node, provider->cell_name);
|
||||
if (cellprop) {
|
||||
cellsize = propval_cell(cellprop);
|
||||
} else if (provider->optional) {
|
||||
cellsize = 0;
|
||||
} else {
|
||||
FAIL(c, dti, "Missing property '%s' in node %s or bad phandle (referred from %s:%s[%d])",
|
||||
provider->cell_name,
|
||||
provider_node->fullpath,
|
||||
node->fullpath, prop->name, cell);
|
||||
break;
|
||||
}
|
||||
|
||||
if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) {
|
||||
FAIL(c, dti, "%s property size (%d) too small for cell size %d in %s",
|
||||
prop->name, prop->val.len, cellsize, node->fullpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_provider_cells_property(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
struct provider *provider = c->data;
|
||||
struct property *prop;
|
||||
|
||||
prop = get_property(node, provider->prop_name);
|
||||
if (!prop)
|
||||
return;
|
||||
|
||||
check_property_phandle_args(c, dti, node, prop, provider);
|
||||
}
|
||||
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
|
||||
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
|
||||
WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
|
||||
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(dmas, "dmas", "#dma-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(hwlocks, "hwlocks", "#hwlock-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(interrupts_extended, "interrupts-extended", "#interrupt-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(io_channels, "io-channels", "#io-channel-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(iommus, "iommus", "#iommu-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(mboxes, "mboxes", "#mbox-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(msi_parent, "msi-parent", "#msi-cells", true);
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(mux_controls, "mux-controls", "#mux-control-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(phys, "phys", "#phy-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(power_domains, "power-domains", "#power-domain-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(pwms, "pwms", "#pwm-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(resets, "resets", "#reset-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(sound_dais, "sound-dais", "#sound-dai-cells");
|
||||
WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sensor-cells");
|
||||
|
||||
static bool prop_is_gpio(struct property *prop)
|
||||
{
|
||||
char *str;
|
||||
|
||||
/*
|
||||
* *-gpios and *-gpio can appear in property names,
|
||||
* so skip over any false matches (only one known ATM)
|
||||
*/
|
||||
if (strstr(prop->name, "nr-gpio"))
|
||||
return false;
|
||||
|
||||
str = strrchr(prop->name, '-');
|
||||
if (str)
|
||||
str++;
|
||||
else
|
||||
str = prop->name;
|
||||
if (!(streq(str, "gpios") || streq(str, "gpio")))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void check_gpios_property(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
/* Skip GPIO hog nodes which have 'gpios' property */
|
||||
if (get_property(node, "gpio-hog"))
|
||||
return;
|
||||
|
||||
for_each_property(node, prop) {
|
||||
struct provider provider;
|
||||
|
||||
if (!prop_is_gpio(prop))
|
||||
continue;
|
||||
|
||||
provider.prop_name = prop->name;
|
||||
provider.cell_name = "#gpio-cells";
|
||||
provider.optional = false;
|
||||
check_property_phandle_args(c, dti, node, prop, &provider);
|
||||
}
|
||||
|
||||
}
|
||||
WARNING(gpios_property, check_gpios_property, NULL, &phandle_references);
|
||||
|
||||
static void check_deprecated_gpio_property(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
for_each_property(node, prop) {
|
||||
char *str;
|
||||
|
||||
if (!prop_is_gpio(prop))
|
||||
continue;
|
||||
|
||||
str = strstr(prop->name, "gpio");
|
||||
if (!streq(str, "gpio"))
|
||||
continue;
|
||||
|
||||
FAIL(c, dti, "'[*-]gpio' is deprecated, use '[*-]gpios' instead for %s:%s",
|
||||
node->fullpath, prop->name);
|
||||
}
|
||||
|
||||
}
|
||||
CHECK(deprecated_gpio_property, check_deprecated_gpio_property, NULL);
|
||||
|
||||
static bool node_is_interrupt_provider(struct node *node)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
prop = get_property(node, "interrupt-controller");
|
||||
if (prop)
|
||||
return true;
|
||||
|
||||
prop = get_property(node, "interrupt-map");
|
||||
if (prop)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
static void check_interrupts_property(struct check *c,
|
||||
struct dt_info *dti,
|
||||
struct node *node)
|
||||
{
|
||||
struct node *root = dti->dt;
|
||||
struct node *irq_node = NULL, *parent = node;
|
||||
struct property *irq_prop, *prop = NULL;
|
||||
int irq_cells, phandle;
|
||||
|
||||
irq_prop = get_property(node, "interrupts");
|
||||
if (!irq_prop)
|
||||
return;
|
||||
|
||||
if (irq_prop->val.len % sizeof(cell_t))
|
||||
FAIL(c, dti, "property '%s' size (%d) is invalid, expected multiple of %zu in node %s",
|
||||
irq_prop->name, irq_prop->val.len, sizeof(cell_t),
|
||||
node->fullpath);
|
||||
|
||||
while (parent && !prop) {
|
||||
if (parent != node && node_is_interrupt_provider(parent)) {
|
||||
irq_node = parent;
|
||||
break;
|
||||
}
|
||||
|
||||
prop = get_property(parent, "interrupt-parent");
|
||||
if (prop) {
|
||||
phandle = propval_cell(prop);
|
||||
/* Give up if this is an overlay with external references */
|
||||
if ((phandle == 0 || phandle == -1) &&
|
||||
(dti->dtsflags & DTSF_PLUGIN))
|
||||
return;
|
||||
|
||||
irq_node = get_node_by_phandle(root, phandle);
|
||||
if (!irq_node) {
|
||||
FAIL(c, dti, "Bad interrupt-parent phandle for %s",
|
||||
node->fullpath);
|
||||
return;
|
||||
}
|
||||
if (!node_is_interrupt_provider(irq_node))
|
||||
FAIL(c, dti,
|
||||
"Missing interrupt-controller or interrupt-map property in %s",
|
||||
irq_node->fullpath);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
if (!irq_node) {
|
||||
FAIL(c, dti, "Missing interrupt-parent for %s", node->fullpath);
|
||||
return;
|
||||
}
|
||||
|
||||
prop = get_property(irq_node, "#interrupt-cells");
|
||||
if (!prop) {
|
||||
FAIL(c, dti, "Missing #interrupt-cells in interrupt-parent %s",
|
||||
irq_node->fullpath);
|
||||
return;
|
||||
}
|
||||
|
||||
irq_cells = propval_cell(prop);
|
||||
if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) {
|
||||
FAIL(c, dti,
|
||||
"interrupts size is (%d), expected multiple of %d in %s",
|
||||
irq_prop->val.len, (int)(irq_cells * sizeof(cell_t)),
|
||||
node->fullpath);
|
||||
}
|
||||
}
|
||||
WARNING(interrupts_property, check_interrupts_property, &phandle_references);
|
||||
|
||||
static struct check *check_table[] = {
|
||||
&duplicate_node_names, &duplicate_property_names,
|
||||
&node_name_chars, &node_name_format, &property_name_chars,
|
||||
@@ -987,6 +1255,27 @@ static struct check *check_table[] = {
|
||||
&avoid_default_addr_size,
|
||||
&obsolete_chosen_interrupt_controller,
|
||||
|
||||
&clocks_property,
|
||||
&cooling_device_property,
|
||||
&dmas_property,
|
||||
&hwlocks_property,
|
||||
&interrupts_extended_property,
|
||||
&io_channels_property,
|
||||
&iommus_property,
|
||||
&mboxes_property,
|
||||
&msi_parent_property,
|
||||
&mux_controls_property,
|
||||
&phys_property,
|
||||
&power_domains_property,
|
||||
&pwms_property,
|
||||
&resets_property,
|
||||
&sound_dais_property,
|
||||
&thermal_sensors_property,
|
||||
|
||||
&deprecated_gpio_property,
|
||||
&gpios_property,
|
||||
&interrupts_property,
|
||||
|
||||
&always_fail,
|
||||
};
|
||||
|
||||
|
||||
@@ -1397,7 +1397,7 @@ static int yy_get_next_buffer (void)
|
||||
{
|
||||
char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
|
||||
char *source = (yytext_ptr);
|
||||
yy_size_t number_to_move, i;
|
||||
int number_to_move, i;
|
||||
int ret_val;
|
||||
|
||||
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
|
||||
@@ -1426,7 +1426,7 @@ static int yy_get_next_buffer (void)
|
||||
/* Try to read more data. */
|
||||
|
||||
/* First move last chars to start of buffer. */
|
||||
number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1;
|
||||
number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
|
||||
|
||||
for ( i = 0; i < number_to_move; ++i )
|
||||
*(dest++) = *(source++);
|
||||
@@ -1508,7 +1508,7 @@ static int yy_get_next_buffer (void)
|
||||
else
|
||||
ret_val = EOB_ACT_CONTINUE_SCAN;
|
||||
|
||||
if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
|
||||
if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
|
||||
/* Extend the array by 50%, plus the number we really need. */
|
||||
int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
|
||||
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
|
||||
@@ -1987,10 +1987,10 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
|
||||
YY_BUFFER_STATE b;
|
||||
char *buf;
|
||||
yy_size_t n;
|
||||
yy_size_t i;
|
||||
int i;
|
||||
|
||||
/* Get memory for full buffer, including space for trailing EOB's. */
|
||||
n = (yy_size_t) _yybytes_len + 2;
|
||||
n = (yy_size_t) (_yybytes_len + 2);
|
||||
buf = (char *) yyalloc(n );
|
||||
if ( ! buf )
|
||||
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
|
||||
|
||||
@@ -448,7 +448,7 @@ union yyalloc
|
||||
/* YYNNTS -- Number of nonterminals. */
|
||||
#define YYNNTS 30
|
||||
/* YYNRULES -- Number of rules. */
|
||||
#define YYNRULES 84
|
||||
#define YYNRULES 85
|
||||
/* YYNSTATES -- Number of states. */
|
||||
#define YYNSTATES 149
|
||||
|
||||
@@ -499,14 +499,14 @@ static const yytype_uint8 yytranslate[] =
|
||||
static const yytype_uint16 yyrline[] =
|
||||
{
|
||||
0, 109, 109, 117, 121, 128, 129, 139, 142, 149,
|
||||
153, 161, 165, 170, 181, 191, 206, 214, 217, 224,
|
||||
228, 232, 236, 244, 248, 252, 256, 260, 276, 286,
|
||||
294, 297, 301, 308, 324, 329, 348, 362, 369, 370,
|
||||
371, 378, 382, 383, 387, 388, 392, 393, 397, 398,
|
||||
402, 403, 407, 408, 412, 413, 414, 418, 419, 420,
|
||||
421, 422, 426, 427, 428, 432, 433, 434, 438, 439,
|
||||
448, 457, 461, 462, 463, 464, 469, 472, 476, 484,
|
||||
487, 491, 499, 503, 507
|
||||
153, 161, 165, 170, 181, 200, 213, 220, 228, 231,
|
||||
238, 242, 246, 250, 258, 262, 266, 270, 274, 290,
|
||||
300, 308, 311, 315, 322, 338, 343, 362, 376, 383,
|
||||
384, 385, 392, 396, 397, 401, 402, 406, 407, 411,
|
||||
412, 416, 417, 421, 422, 426, 427, 428, 432, 433,
|
||||
434, 435, 436, 440, 441, 442, 446, 447, 448, 452,
|
||||
453, 462, 471, 475, 476, 477, 478, 483, 486, 490,
|
||||
498, 501, 505, 513, 517, 521
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -582,20 +582,20 @@ static const yytype_int8 yypact[] =
|
||||
static const yytype_uint8 yydefact[] =
|
||||
{
|
||||
0, 0, 0, 5, 7, 3, 1, 6, 0, 0,
|
||||
0, 7, 0, 38, 39, 0, 0, 10, 0, 2,
|
||||
8, 4, 0, 0, 0, 72, 0, 41, 42, 44,
|
||||
46, 48, 50, 52, 54, 57, 64, 67, 71, 0,
|
||||
17, 11, 0, 0, 0, 0, 73, 74, 75, 40,
|
||||
16, 7, 0, 39, 40, 0, 0, 10, 0, 2,
|
||||
8, 4, 0, 0, 0, 73, 0, 42, 43, 45,
|
||||
47, 49, 51, 53, 55, 58, 65, 68, 72, 0,
|
||||
18, 11, 0, 0, 0, 0, 74, 75, 76, 41,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
|
||||
79, 0, 0, 14, 12, 45, 0, 47, 49, 51,
|
||||
53, 55, 56, 60, 61, 59, 58, 62, 63, 65,
|
||||
66, 69, 68, 70, 0, 0, 0, 0, 18, 0,
|
||||
79, 15, 13, 0, 0, 0, 20, 30, 82, 22,
|
||||
84, 0, 81, 80, 43, 21, 83, 0, 0, 16,
|
||||
29, 19, 31, 0, 23, 32, 26, 0, 76, 34,
|
||||
0, 0, 0, 0, 37, 36, 24, 35, 33, 0,
|
||||
77, 78, 25, 0, 28, 0, 0, 0, 27
|
||||
80, 0, 0, 14, 12, 46, 0, 48, 50, 52,
|
||||
54, 56, 57, 61, 62, 60, 59, 63, 64, 66,
|
||||
67, 70, 69, 71, 0, 0, 0, 0, 19, 0,
|
||||
80, 15, 13, 0, 0, 0, 21, 31, 83, 23,
|
||||
85, 0, 82, 81, 44, 22, 84, 0, 0, 17,
|
||||
30, 20, 32, 0, 24, 33, 27, 0, 77, 35,
|
||||
0, 0, 0, 0, 38, 37, 25, 36, 34, 0,
|
||||
78, 79, 26, 0, 29, 0, 0, 0, 28
|
||||
};
|
||||
|
||||
/* YYPGOTO[NTERM-NUM]. */
|
||||
@@ -678,28 +678,28 @@ static const yytype_uint8 yystos[] =
|
||||
static const yytype_uint8 yyr1[] =
|
||||
{
|
||||
0, 48, 49, 50, 50, 51, 51, 52, 52, 53,
|
||||
53, 54, 54, 54, 54, 54, 55, 56, 56, 57,
|
||||
57, 57, 57, 58, 58, 58, 58, 58, 58, 58,
|
||||
59, 59, 59, 60, 60, 60, 60, 60, 61, 61,
|
||||
61, 62, 63, 63, 64, 64, 65, 65, 66, 66,
|
||||
67, 67, 68, 68, 69, 69, 69, 70, 70, 70,
|
||||
70, 70, 71, 71, 71, 72, 72, 72, 73, 73,
|
||||
73, 73, 74, 74, 74, 74, 75, 75, 75, 76,
|
||||
76, 76, 77, 77, 77
|
||||
53, 54, 54, 54, 54, 54, 54, 55, 56, 56,
|
||||
57, 57, 57, 57, 58, 58, 58, 58, 58, 58,
|
||||
58, 59, 59, 59, 60, 60, 60, 60, 60, 61,
|
||||
61, 61, 62, 63, 63, 64, 64, 65, 65, 66,
|
||||
66, 67, 67, 68, 68, 69, 69, 69, 70, 70,
|
||||
70, 70, 70, 71, 71, 71, 72, 72, 72, 73,
|
||||
73, 73, 73, 74, 74, 74, 74, 75, 75, 75,
|
||||
76, 76, 76, 77, 77, 77
|
||||
};
|
||||
|
||||
/* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
|
||||
static const yytype_uint8 yyr2[] =
|
||||
{
|
||||
0, 2, 3, 2, 4, 1, 2, 0, 2, 4,
|
||||
2, 2, 3, 4, 3, 4, 5, 0, 2, 4,
|
||||
2, 3, 2, 2, 3, 4, 2, 9, 5, 2,
|
||||
0, 2, 2, 3, 1, 2, 2, 2, 1, 1,
|
||||
3, 1, 1, 5, 1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3, 3, 1, 3, 3,
|
||||
3, 3, 3, 3, 1, 3, 3, 1, 3, 3,
|
||||
3, 1, 1, 2, 2, 2, 0, 2, 2, 0,
|
||||
2, 2, 2, 3, 2
|
||||
2, 2, 3, 4, 3, 4, 0, 5, 0, 2,
|
||||
4, 2, 3, 2, 2, 3, 4, 2, 9, 5,
|
||||
2, 0, 2, 2, 3, 1, 2, 2, 2, 1,
|
||||
1, 3, 1, 1, 5, 1, 3, 1, 3, 1,
|
||||
3, 1, 3, 1, 3, 1, 3, 3, 1, 3,
|
||||
3, 3, 3, 3, 3, 1, 3, 3, 1, 3,
|
||||
3, 3, 1, 1, 2, 2, 2, 0, 2, 2,
|
||||
0, 2, 2, 2, 3, 2
|
||||
};
|
||||
|
||||
|
||||
@@ -1572,17 +1572,26 @@ yyreduce:
|
||||
{
|
||||
struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref));
|
||||
|
||||
if (target)
|
||||
if (target) {
|
||||
merge_nodes(target, (yyvsp[0].node));
|
||||
else
|
||||
ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
|
||||
} else {
|
||||
/*
|
||||
* We rely on the rule being always:
|
||||
* versioninfo plugindecl memreserves devicetree
|
||||
* so $-1 is what we want (plugindecl)
|
||||
*/
|
||||
if ((yyvsp[(-1) - (3)].flags) & DTSF_PLUGIN)
|
||||
add_orphan_node((yyvsp[-2].node), (yyvsp[0].node), (yyvsp[-1].labelref));
|
||||
else
|
||||
ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref));
|
||||
}
|
||||
(yyval.node) = (yyvsp[-2].node);
|
||||
}
|
||||
#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1591 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 15:
|
||||
#line 192 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 201 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref));
|
||||
|
||||
@@ -1594,100 +1603,109 @@ yyreduce:
|
||||
|
||||
(yyval.node) = (yyvsp[-3].node);
|
||||
}
|
||||
#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1607 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 16:
|
||||
#line 207 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 213 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
|
||||
/* build empty node */
|
||||
(yyval.node) = name_node(build_node(NULL, NULL), "");
|
||||
}
|
||||
#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1616 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 17:
|
||||
#line 214 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 221 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.proplist) = NULL;
|
||||
(yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist));
|
||||
}
|
||||
#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1624 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 18:
|
||||
#line 218 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 228 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
|
||||
(yyval.proplist) = NULL;
|
||||
}
|
||||
#line 1622 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1632 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 19:
|
||||
#line 225 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 232 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
|
||||
(yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist));
|
||||
}
|
||||
#line 1630 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1640 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 20:
|
||||
#line 229 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 239 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
|
||||
(yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data));
|
||||
}
|
||||
#line 1638 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1648 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 21:
|
||||
#line 233 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 243 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
|
||||
(yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data);
|
||||
}
|
||||
#line 1646 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1656 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 22:
|
||||
#line 237 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 247 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.prop) = build_property_delete((yyvsp[-1].propnodename));
|
||||
}
|
||||
#line 1664 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 23:
|
||||
#line 251 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref));
|
||||
(yyval.prop) = (yyvsp[0].prop);
|
||||
}
|
||||
#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 23:
|
||||
#line 245 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
|
||||
}
|
||||
#line 1663 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1673 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 24:
|
||||
#line 249 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 259 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
|
||||
(yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data));
|
||||
}
|
||||
#line 1671 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1681 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 25:
|
||||
#line 253 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 263 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
|
||||
(yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data);
|
||||
}
|
||||
#line 1679 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 26:
|
||||
#line 257 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 267 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
|
||||
(yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data));
|
||||
}
|
||||
#line 1687 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 27:
|
||||
#line 261 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 271 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref));
|
||||
}
|
||||
#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 28:
|
||||
#line 275 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL);
|
||||
struct data d;
|
||||
@@ -1703,11 +1721,11 @@ yyreduce:
|
||||
(yyval.data) = data_merge((yyvsp[-8].data), d);
|
||||
fclose(f);
|
||||
}
|
||||
#line 1707 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1725 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 28:
|
||||
#line 277 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 29:
|
||||
#line 291 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL);
|
||||
struct data d = empty_data;
|
||||
@@ -1717,43 +1735,43 @@ yyreduce:
|
||||
(yyval.data) = data_merge((yyvsp[-4].data), d);
|
||||
fclose(f);
|
||||
}
|
||||
#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 29:
|
||||
#line 287 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
|
||||
}
|
||||
#line 1729 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1739 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 30:
|
||||
#line 294 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = empty_data;
|
||||
}
|
||||
#line 1737 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 31:
|
||||
#line 298 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = (yyvsp[-1].data);
|
||||
}
|
||||
#line 1745 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 32:
|
||||
#line 302 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 301 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
|
||||
}
|
||||
#line 1753 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1747 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 31:
|
||||
#line 308 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = empty_data;
|
||||
}
|
||||
#line 1755 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 32:
|
||||
#line 312 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = (yyvsp[-1].data);
|
||||
}
|
||||
#line 1763 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 33:
|
||||
#line 309 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 316 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
|
||||
}
|
||||
#line 1771 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 34:
|
||||
#line 323 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
unsigned long long bits;
|
||||
|
||||
@@ -1769,20 +1787,20 @@ yyreduce:
|
||||
(yyval.array).data = empty_data;
|
||||
(yyval.array).bits = bits;
|
||||
}
|
||||
#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 34:
|
||||
#line 325 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 35:
|
||||
#line 339 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.array).data = empty_data;
|
||||
(yyval.array).bits = 32;
|
||||
}
|
||||
#line 1782 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1800 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 35:
|
||||
#line 330 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 36:
|
||||
#line 344 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
if ((yyvsp[-1].array).bits < 64) {
|
||||
uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1;
|
||||
@@ -1801,11 +1819,11 @@ yyreduce:
|
||||
|
||||
(yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits);
|
||||
}
|
||||
#line 1805 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1823 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 36:
|
||||
#line 349 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 37:
|
||||
#line 363 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits);
|
||||
|
||||
@@ -1819,129 +1837,129 @@ yyreduce:
|
||||
|
||||
(yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits);
|
||||
}
|
||||
#line 1823 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1841 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 37:
|
||||
#line 363 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 38:
|
||||
#line 377 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref));
|
||||
}
|
||||
#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 40:
|
||||
#line 372 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 41:
|
||||
#line 386 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.integer) = (yyvsp[-1].integer);
|
||||
}
|
||||
#line 1839 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 43:
|
||||
#line 383 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
|
||||
#line 1845 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 45:
|
||||
#line 388 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
|
||||
#line 1851 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 47:
|
||||
#line 393 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
|
||||
#line 1857 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 49:
|
||||
#line 398 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
|
||||
case 44:
|
||||
#line 397 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); }
|
||||
#line 1863 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 51:
|
||||
#line 403 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
|
||||
case 46:
|
||||
#line 402 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); }
|
||||
#line 1869 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 53:
|
||||
#line 408 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
|
||||
case 48:
|
||||
#line 407 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); }
|
||||
#line 1875 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 55:
|
||||
#line 413 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
|
||||
case 50:
|
||||
#line 412 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); }
|
||||
#line 1881 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 56:
|
||||
#line 414 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
|
||||
case 52:
|
||||
#line 417 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); }
|
||||
#line 1887 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 58:
|
||||
#line 419 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
|
||||
case 54:
|
||||
#line 422 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); }
|
||||
#line 1893 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 59:
|
||||
#line 420 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
|
||||
case 56:
|
||||
#line 427 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); }
|
||||
#line 1899 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 60:
|
||||
#line 421 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
|
||||
case 57:
|
||||
#line 428 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); }
|
||||
#line 1905 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 61:
|
||||
#line 422 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
|
||||
case 59:
|
||||
#line 433 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); }
|
||||
#line 1911 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 62:
|
||||
#line 426 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
|
||||
case 60:
|
||||
#line 434 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); }
|
||||
#line 1917 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 63:
|
||||
#line 427 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
|
||||
case 61:
|
||||
#line 435 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); }
|
||||
#line 1923 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 65:
|
||||
#line 432 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
|
||||
case 62:
|
||||
#line 436 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); }
|
||||
#line 1929 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 66:
|
||||
#line 433 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
|
||||
case 63:
|
||||
#line 440 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); }
|
||||
#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 68:
|
||||
#line 438 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
|
||||
case 64:
|
||||
#line 441 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); }
|
||||
#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 66:
|
||||
#line 446 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); }
|
||||
#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 67:
|
||||
#line 447 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); }
|
||||
#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 69:
|
||||
#line 440 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 452 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); }
|
||||
#line 1959 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 70:
|
||||
#line 454 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
if ((yyvsp[0].integer) != 0) {
|
||||
(yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer);
|
||||
@@ -1950,11 +1968,11 @@ yyreduce:
|
||||
(yyval.integer) = 0;
|
||||
}
|
||||
}
|
||||
#line 1954 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 1972 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 70:
|
||||
#line 449 "dtc-parser.y" /* yacc.c:1646 */
|
||||
case 71:
|
||||
#line 463 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
if ((yyvsp[0].integer) != 0) {
|
||||
(yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer);
|
||||
@@ -1963,103 +1981,103 @@ yyreduce:
|
||||
(yyval.integer) = 0;
|
||||
}
|
||||
}
|
||||
#line 1967 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 73:
|
||||
#line 462 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = -(yyvsp[0].integer); }
|
||||
#line 1973 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 74:
|
||||
#line 463 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = ~(yyvsp[0].integer); }
|
||||
#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 75:
|
||||
#line 464 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = !(yyvsp[0].integer); }
|
||||
#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 74:
|
||||
#line 476 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = -(yyvsp[0].integer); }
|
||||
#line 1991 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 75:
|
||||
#line 477 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = ~(yyvsp[0].integer); }
|
||||
#line 1997 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 76:
|
||||
#line 469 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = empty_data;
|
||||
}
|
||||
#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 478 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{ (yyval.integer) = !(yyvsp[0].integer); }
|
||||
#line 2003 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 77:
|
||||
#line 473 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 483 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
|
||||
(yyval.data) = empty_data;
|
||||
}
|
||||
#line 2001 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2011 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 78:
|
||||
#line 477 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 487 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
|
||||
(yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte));
|
||||
}
|
||||
#line 2009 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2019 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 79:
|
||||
#line 484 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 491 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.nodelist) = NULL;
|
||||
(yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref));
|
||||
}
|
||||
#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2027 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 80:
|
||||
#line 488 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 498 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
|
||||
(yyval.nodelist) = NULL;
|
||||
}
|
||||
#line 2025 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2035 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 81:
|
||||
#line 492 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 502 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist));
|
||||
}
|
||||
#line 2043 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 82:
|
||||
#line 506 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
ERROR(&(yylsp[0]), "Properties must precede subnodes");
|
||||
YYERROR;
|
||||
}
|
||||
#line 2034 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 82:
|
||||
#line 500 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
|
||||
}
|
||||
#line 2042 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2052 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 83:
|
||||
#line 504 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 514 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
|
||||
(yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename));
|
||||
}
|
||||
#line 2050 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2060 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 84:
|
||||
#line 508 "dtc-parser.y" /* yacc.c:1646 */
|
||||
#line 518 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
(yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename));
|
||||
}
|
||||
#line 2068 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 85:
|
||||
#line 522 "dtc-parser.y" /* yacc.c:1646 */
|
||||
{
|
||||
add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref));
|
||||
(yyval.node) = (yyvsp[0].node);
|
||||
}
|
||||
#line 2059 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2077 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
|
||||
#line 2063 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
#line 2081 "dtc-parser.tab.c" /* yacc.c:1646 */
|
||||
default: break;
|
||||
}
|
||||
/* User semantic actions sometimes alter yychar, and that requires
|
||||
@@ -2294,7 +2312,7 @@ yyreturn:
|
||||
#endif
|
||||
return yyresult;
|
||||
}
|
||||
#line 514 "dtc-parser.y" /* yacc.c:1906 */
|
||||
#line 528 "dtc-parser.y" /* yacc.c:1906 */
|
||||
|
||||
|
||||
void yyerror(char const *s)
|
||||
|
||||
@@ -182,10 +182,19 @@ devicetree:
|
||||
{
|
||||
struct node *target = get_node_by_ref($1, $2);
|
||||
|
||||
if (target)
|
||||
if (target) {
|
||||
merge_nodes(target, $3);
|
||||
else
|
||||
ERROR(&@2, "Label or path %s not found", $2);
|
||||
} 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 ';'
|
||||
@@ -200,6 +209,11 @@ devicetree:
|
||||
|
||||
$$ = $1;
|
||||
}
|
||||
| /* empty */
|
||||
{
|
||||
/* build empty node */
|
||||
$$ = name_node(build_node(NULL, NULL), "");
|
||||
}
|
||||
;
|
||||
|
||||
nodedef:
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ 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_BOTH; /* Use linux,phandle or phandle properties */
|
||||
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 */
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <libfdt_env.h>
|
||||
#include <fdt.h>
|
||||
@@ -202,6 +203,7 @@ 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);
|
||||
void 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);
|
||||
@@ -215,6 +217,7 @@ void append_to_property(struct node *node,
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation
|
||||
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
|
||||
*
|
||||
* libfdt is dual licensed: you can use it either under the terms of
|
||||
* the GPL, or the BSD license, at your option.
|
||||
*
|
||||
* a) This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* Alternatively,
|
||||
*
|
||||
* b) Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "libfdt_env.h"
|
||||
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include "libfdt_internal.h"
|
||||
|
||||
int fdt_address_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *ac;
|
||||
int val;
|
||||
int len;
|
||||
|
||||
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
|
||||
if (!ac)
|
||||
return 2;
|
||||
|
||||
if (len != sizeof(*ac))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*ac);
|
||||
if ((val <= 0) || (val > FDT_MAX_NCELLS))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int fdt_size_cells(const void *fdt, int nodeoffset)
|
||||
{
|
||||
const fdt32_t *sc;
|
||||
int val;
|
||||
int len;
|
||||
|
||||
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
|
||||
if (!sc)
|
||||
return 2;
|
||||
|
||||
if (len != sizeof(*sc))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
val = fdt32_to_cpu(*sc);
|
||||
if ((val < 0) || (val > FDT_MAX_NCELLS))
|
||||
return -FDT_ERR_BADNCELLS;
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)
|
||||
|
||||
return fdt_open_into(buf, buf, bufsize);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,861 @@
|
||||
#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 targetting is
|
||||
* done (through a phandle or a path)
|
||||
*
|
||||
* returns:
|
||||
* the targetted 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_CHECK_HEADER(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;
|
||||
|
||||
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
|
||||
|
||||
if (*path != '/')
|
||||
return -FDT_ERR_BADVALUE;
|
||||
|
||||
/* get fragment name first */
|
||||
s = strchr(path + 1, '/');
|
||||
if (!s)
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
frag_name = path + 1;
|
||||
frag_name_len = s - path - 1;
|
||||
|
||||
/* verify format; safe since "s" lies in \0 terminated prop */
|
||||
len = sizeof("/__overlay__/") - 1;
|
||||
if ((e - s) < len || memcmp(s, "/__overlay__/", len))
|
||||
return -FDT_ERR_BADOVERLAY;
|
||||
|
||||
rel_path = s + len;
|
||||
rel_path_len = e - rel_path;
|
||||
|
||||
/* 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 = fdt_get_max_phandle(fdt);
|
||||
int ret;
|
||||
|
||||
FDT_CHECK_HEADER(fdt);
|
||||
FDT_CHECK_HEADER(fdto);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
|
||||
{
|
||||
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
|
||||
|
||||
if (! p)
|
||||
if (!p)
|
||||
/* short match */
|
||||
return 0;
|
||||
|
||||
@@ -327,7 +327,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
|
||||
const struct fdt_property *prop;
|
||||
|
||||
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
|
||||
if (! prop)
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
return prop->data;
|
||||
|
||||
@@ -207,7 +207,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
|
||||
int err;
|
||||
|
||||
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
|
||||
if (! (*prop))
|
||||
if (!*prop)
|
||||
return oldlen;
|
||||
|
||||
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
|
||||
@@ -269,8 +269,8 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len)
|
||||
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||
int len, void **prop_data)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int err;
|
||||
@@ -283,8 +283,22 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
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);
|
||||
memcpy(prop_data, val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -323,7 +337,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
|
||||
FDT_RW_CHECK_HEADER(fdt);
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (! prop)
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
proplen = sizeof(*prop) + FDT_TAGALIGN(len);
|
||||
|
||||
@@ -220,7 +220,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
|
||||
{
|
||||
struct fdt_property *prop;
|
||||
int nameoff;
|
||||
@@ -238,7 +238,19 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
|
||||
prop->tag = cpu_to_fdt32(FDT_PROP);
|
||||
prop->nameoff = cpu_to_fdt32(nameoff);
|
||||
prop->len = cpu_to_fdt32(len);
|
||||
memcpy(prop->data, val, 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
|
||||
int proplen;
|
||||
|
||||
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
|
||||
if (! propval)
|
||||
if (!propval)
|
||||
return proplen;
|
||||
|
||||
if (proplen != len)
|
||||
@@ -107,7 +107,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
|
||||
int len;
|
||||
|
||||
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
|
||||
if (! prop)
|
||||
if (!prop)
|
||||
return len;
|
||||
|
||||
_fdt_nop_region(prop, len + sizeof(*prop));
|
||||
|
||||
@@ -1314,6 +1314,22 @@ static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
|
||||
{
|
||||
return fdt_property_u32(fdt, name, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* fdt_property_placeholder - add a new property and return a ptr to its value
|
||||
*
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @name: name of property to add
|
||||
* @len: length of property value in bytes
|
||||
* @valp: returns a pointer to where where the value should be placed
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_NOSPACE, standard meanings
|
||||
*/
|
||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
|
||||
|
||||
#define fdt_property_string(fdt, name, str) \
|
||||
fdt_property(fdt, name, str, strlen(str)+1)
|
||||
int fdt_end_node(void *fdt);
|
||||
@@ -1432,6 +1448,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
|
||||
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
|
||||
const void *val, int len);
|
||||
|
||||
/**
|
||||
* fdt_setprop _placeholder - allocate space for a property
|
||||
* @fdt: pointer to the device tree blob
|
||||
* @nodeoffset: offset of the node whose property to change
|
||||
* @name: name of the property to change
|
||||
* @len: length of the property value
|
||||
* @prop_data: return pointer to property data
|
||||
*
|
||||
* fdt_setprop_placeholer() allocates the named property in the given node.
|
||||
* If the property exists it is resized. In either case a pointer to the
|
||||
* property data is returned.
|
||||
*
|
||||
* This function may insert or delete data from the blob, and will
|
||||
* therefore change the offsets of some existing nodes.
|
||||
*
|
||||
* returns:
|
||||
* 0, on success
|
||||
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
|
||||
* contain the new property value
|
||||
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_BADMAGIC,
|
||||
* -FDT_ERR_BADVERSION,
|
||||
* -FDT_ERR_BADSTATE,
|
||||
* -FDT_ERR_BADSTRUCTURE,
|
||||
* -FDT_ERR_BADLAYOUT,
|
||||
* -FDT_ERR_TRUNCATED, standard meanings
|
||||
*/
|
||||
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
|
||||
int len, void **prop_data);
|
||||
|
||||
/**
|
||||
* fdt_setprop_u32 - set a property to a 32-bit integer
|
||||
* @fdt: pointer to the device tree blob
|
||||
|
||||
+30
-1
@@ -216,6 +216,28 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
|
||||
return old_node;
|
||||
}
|
||||
|
||||
void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
|
||||
{
|
||||
static unsigned int next_orphan_fragment = 0;
|
||||
struct node *node;
|
||||
struct property *p;
|
||||
struct data d = empty_data;
|
||||
char *name;
|
||||
|
||||
d = data_add_marker(d, REF_PHANDLE, ref);
|
||||
d = data_append_integer(d, 0xffffffff, 32);
|
||||
|
||||
p = build_property("target", d);
|
||||
|
||||
xasprintf(&name, "fragment@%u",
|
||||
next_orphan_fragment++);
|
||||
name_node(new_node, "__overlay__");
|
||||
node = build_node(p, new_node);
|
||||
name_node(node, name);
|
||||
|
||||
add_child(dt, node);
|
||||
}
|
||||
|
||||
struct node *chain_node(struct node *first, struct node *list)
|
||||
{
|
||||
assert(first->next_sibling == NULL);
|
||||
@@ -396,6 +418,12 @@ cell_t propval_cell(struct property *prop)
|
||||
return fdt32_to_cpu(*((fdt32_t *)prop->val.val));
|
||||
}
|
||||
|
||||
cell_t propval_cell_n(struct property *prop, int n)
|
||||
{
|
||||
assert(prop->val.len / sizeof(cell_t) >= n);
|
||||
return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n));
|
||||
}
|
||||
|
||||
struct property *get_property_by_label(struct node *tree, const char *label,
|
||||
struct node **node)
|
||||
{
|
||||
@@ -478,7 +506,8 @@ struct node *get_node_by_path(struct node *tree, const char *path)
|
||||
p = strchr(path, '/');
|
||||
|
||||
for_each_child(tree, child) {
|
||||
if (p && strneq(path, child->name, p-path))
|
||||
if (p && (strlen(child->name) == p-path) &&
|
||||
strneq(path, child->name, p-path))
|
||||
return get_node_by_path(child, p+1);
|
||||
else if (!p && streq(path, child->name))
|
||||
return child;
|
||||
|
||||
@@ -35,7 +35,9 @@ 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"
|
||||
DTC_GENERATED="dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h"
|
||||
LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_empty_tree.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h"
|
||||
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/'
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define DTC_VERSION "DTC 1.4.4-g756ffc4f"
|
||||
#define DTC_VERSION "DTC 1.4.5-gc1e55a55"
|
||||
|
||||
+14
-7
@@ -44,9 +44,16 @@
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
|
||||
READELF="${CROSS_COMPILE:-}readelf"
|
||||
ADDR2LINE="${CROSS_COMPILE:-}addr2line"
|
||||
SIZE="${CROSS_COMPILE:-}size"
|
||||
NM="${CROSS_COMPILE:-}nm"
|
||||
|
||||
command -v awk >/dev/null 2>&1 || die "awk isn't installed"
|
||||
command -v readelf >/dev/null 2>&1 || die "readelf isn't installed"
|
||||
command -v addr2line >/dev/null 2>&1 || die "addr2line isn't installed"
|
||||
command -v ${READELF} >/dev/null 2>&1 || die "readelf isn't installed"
|
||||
command -v ${ADDR2LINE} >/dev/null 2>&1 || die "addr2line isn't installed"
|
||||
command -v ${SIZE} >/dev/null 2>&1 || die "size isn't installed"
|
||||
command -v ${NM} >/dev/null 2>&1 || die "nm isn't installed"
|
||||
|
||||
usage() {
|
||||
echo "usage: faddr2line <object file> <func+offset> <func+offset>..." >&2
|
||||
@@ -69,10 +76,10 @@ die() {
|
||||
find_dir_prefix() {
|
||||
local objfile=$1
|
||||
|
||||
local start_kernel_addr=$(readelf -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}')
|
||||
local start_kernel_addr=$(${READELF} -sW $objfile | awk '$8 == "start_kernel" {printf "0x%s", $2}')
|
||||
[[ -z $start_kernel_addr ]] && return
|
||||
|
||||
local file_line=$(addr2line -e $objfile $start_kernel_addr)
|
||||
local file_line=$(${ADDR2LINE} -e $objfile $start_kernel_addr)
|
||||
[[ -z $file_line ]] && return
|
||||
|
||||
local prefix=${file_line%init/main.c:*}
|
||||
@@ -104,7 +111,7 @@ __faddr2line() {
|
||||
|
||||
# Go through each of the object's symbols which match the func name.
|
||||
# In rare cases there might be duplicates.
|
||||
file_end=$(size -Ax $objfile | awk '$1 == ".text" {print $2}')
|
||||
file_end=$(${SIZE} -Ax $objfile | awk '$1 == ".text" {print $2}')
|
||||
while read symbol; do
|
||||
local fields=($symbol)
|
||||
local sym_base=0x${fields[0]}
|
||||
@@ -156,10 +163,10 @@ __faddr2line() {
|
||||
|
||||
# pass real address to addr2line
|
||||
echo "$func+$offset/$sym_size:"
|
||||
addr2line -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;"
|
||||
${ADDR2LINE} -fpie $objfile $addr | sed "s; $dir_prefix\(\./\)*; ;"
|
||||
DONE=1
|
||||
|
||||
done < <(nm -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }')
|
||||
done < <(${NM} -n $objfile | awk -v fn=$func -v end=$file_end '$3 == fn { found=1; line=$0; start=$1; next } found == 1 { found=0; print line, "0x"$1 } END {if (found == 1) print line, end; }')
|
||||
}
|
||||
|
||||
[[ $# -lt 2 ]] && usage
|
||||
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
# (c) 2017, Jonathan Corbet <corbet@lwn.net>
|
||||
# sayli karnik <karniksayli1995@gmail.com>
|
||||
#
|
||||
# This script detects files with kernel-doc comments for exported functions
|
||||
# that are not included in documentation.
|
||||
#
|
||||
# usage: Run 'scripts/find-unused-docs.sh directory' from top level of kernel
|
||||
# tree.
|
||||
#
|
||||
# example: $scripts/find-unused-docs.sh drivers/scsi
|
||||
#
|
||||
# Licensed under the terms of the GNU GPL License
|
||||
|
||||
if ! [ -d "Documentation" ]; then
|
||||
echo "Run from top level of kernel tree"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: scripts/find-unused-docs.sh directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -d "$1" ]; then
|
||||
echo "Directory $1 doesn't exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
||||
cd ..
|
||||
|
||||
cd Documentation/
|
||||
|
||||
echo "The following files contain kerneldoc comments for exported functions \
|
||||
that are not used in the formatted documentation"
|
||||
|
||||
# FILES INCLUDED
|
||||
|
||||
files_included=($(grep -rHR ".. kernel-doc" --include \*.rst | cut -d " " -f 3))
|
||||
|
||||
declare -A FILES_INCLUDED
|
||||
|
||||
for each in "${files_included[@]}"; do
|
||||
FILES_INCLUDED[$each]="$each"
|
||||
done
|
||||
|
||||
cd ..
|
||||
|
||||
# FILES NOT INCLUDED
|
||||
|
||||
for file in `find $1 -name '*.c'`; do
|
||||
|
||||
if [[ ${FILES_INCLUDED[$file]+_} ]]; then
|
||||
continue;
|
||||
fi
|
||||
str=$(scripts/kernel-doc -text -export "$file" 2>/dev/null)
|
||||
if [[ -n "$str" ]]; then
|
||||
echo "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -96,6 +96,8 @@ def get_thread_info(task):
|
||||
thread_info_addr = task.address + ia64_task_size
|
||||
thread_info = thread_info_addr.cast(thread_info_ptr_type)
|
||||
else:
|
||||
if task.type.fields()[0].type == thread_info_type.get_type():
|
||||
return task['thread_info']
|
||||
thread_info = task['stack'].cast(thread_info_ptr_type)
|
||||
return thread_info.dereference()
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
*.hash.c
|
||||
*.lex.c
|
||||
*.tab.c
|
||||
*.tab.h
|
||||
|
||||
+193
-18
@@ -57,6 +57,7 @@ my $sections = 0;
|
||||
my $file_emails = 0;
|
||||
my $from_filename = 0;
|
||||
my $pattern_depth = 0;
|
||||
my $self_test = undef;
|
||||
my $version = 0;
|
||||
my $help = 0;
|
||||
my $find_maintainer_files = 0;
|
||||
@@ -138,6 +139,7 @@ my %VCS_cmds_git = (
|
||||
"subject_pattern" => "^GitSubject: (.*)",
|
||||
"stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$",
|
||||
"file_exists_cmd" => "git ls-files \$file",
|
||||
"list_files_cmd" => "git ls-files \$file",
|
||||
);
|
||||
|
||||
my %VCS_cmds_hg = (
|
||||
@@ -167,6 +169,7 @@ my %VCS_cmds_hg = (
|
||||
"subject_pattern" => "^HgSubject: (.*)",
|
||||
"stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$",
|
||||
"file_exists_cmd" => "hg files \$file",
|
||||
"list_files_cmd" => "hg manifest -R \$file",
|
||||
);
|
||||
|
||||
my $conf = which_conf(".get_maintainer.conf");
|
||||
@@ -216,6 +219,14 @@ if (-f $ignore_file) {
|
||||
close($ignore);
|
||||
}
|
||||
|
||||
if ($#ARGV > 0) {
|
||||
foreach (@ARGV) {
|
||||
if ($_ =~ /^-{1,2}self-test(?:=|$)/) {
|
||||
die "$P: using --self-test does not allow any other option or argument\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetOptions(
|
||||
'email!' => \$email,
|
||||
'git!' => \$email_git,
|
||||
@@ -252,6 +263,7 @@ if (!GetOptions(
|
||||
'fe|file-emails!' => \$file_emails,
|
||||
'f|file' => \$from_filename,
|
||||
'find-maintainer-files' => \$find_maintainer_files,
|
||||
'self-test:s' => \$self_test,
|
||||
'v|version' => \$version,
|
||||
'h|help|usage' => \$help,
|
||||
)) {
|
||||
@@ -268,6 +280,12 @@ if ($version != 0) {
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if (defined $self_test) {
|
||||
read_all_maintainer_files();
|
||||
self_test();
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if (-t STDIN && !@ARGV) {
|
||||
# We're talking to a terminal, but have no command line arguments.
|
||||
die "$P: missing patchfile or -f file - use --help if necessary\n";
|
||||
@@ -311,14 +329,17 @@ if (!top_of_kernel_tree($lk_path)) {
|
||||
my @typevalue = ();
|
||||
my %keyword_hash;
|
||||
my @mfiles = ();
|
||||
my @self_test_info = ();
|
||||
|
||||
sub read_maintainer_file {
|
||||
my ($file) = @_;
|
||||
|
||||
open (my $maint, '<', "$file")
|
||||
or die "$P: Can't open MAINTAINERS file '$file': $!\n";
|
||||
my $i = 1;
|
||||
while (<$maint>) {
|
||||
my $line = $_;
|
||||
chomp $line;
|
||||
|
||||
if ($line =~ m/^([A-Z]):\s*(.*)/) {
|
||||
my $type = $1;
|
||||
@@ -338,9 +359,12 @@ sub read_maintainer_file {
|
||||
}
|
||||
push(@typevalue, "$type:$value");
|
||||
} elsif (!(/^\s*$/ || /^\s*\#/)) {
|
||||
$line =~ s/\n$//g;
|
||||
push(@typevalue, $line);
|
||||
}
|
||||
if (defined $self_test) {
|
||||
push(@self_test_info, {file=>$file, linenr=>$i, line=>$line});
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
close($maint);
|
||||
}
|
||||
@@ -357,26 +381,30 @@ sub find_ignore_git {
|
||||
return grep { $_ !~ /^\.git$/; } @_;
|
||||
}
|
||||
|
||||
if (-d "${lk_path}MAINTAINERS") {
|
||||
opendir(DIR, "${lk_path}MAINTAINERS") or die $!;
|
||||
my @files = readdir(DIR);
|
||||
closedir(DIR);
|
||||
foreach my $file (@files) {
|
||||
push(@mfiles, "${lk_path}MAINTAINERS/$file") if ($file !~ /^\./);
|
||||
read_all_maintainer_files();
|
||||
|
||||
sub read_all_maintainer_files {
|
||||
if (-d "${lk_path}MAINTAINERS") {
|
||||
opendir(DIR, "${lk_path}MAINTAINERS") or die $!;
|
||||
my @files = readdir(DIR);
|
||||
closedir(DIR);
|
||||
foreach my $file (@files) {
|
||||
push(@mfiles, "${lk_path}MAINTAINERS/$file") if ($file !~ /^\./);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($find_maintainer_files) {
|
||||
find( { wanted => \&find_is_maintainer_file,
|
||||
preprocess => \&find_ignore_git,
|
||||
no_chdir => 1,
|
||||
}, "${lk_path}");
|
||||
} else {
|
||||
push(@mfiles, "${lk_path}MAINTAINERS") if -f "${lk_path}MAINTAINERS";
|
||||
}
|
||||
if ($find_maintainer_files) {
|
||||
find( { wanted => \&find_is_maintainer_file,
|
||||
preprocess => \&find_ignore_git,
|
||||
no_chdir => 1,
|
||||
}, "${lk_path}");
|
||||
} else {
|
||||
push(@mfiles, "${lk_path}MAINTAINERS") if -f "${lk_path}MAINTAINERS";
|
||||
}
|
||||
|
||||
foreach my $file (@mfiles) {
|
||||
read_maintainer_file("$file");
|
||||
foreach my $file (@mfiles) {
|
||||
read_maintainer_file("$file");
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
@@ -586,6 +614,135 @@ if ($web) {
|
||||
|
||||
exit($exit);
|
||||
|
||||
sub self_test {
|
||||
my @lsfiles = ();
|
||||
my @good_links = ();
|
||||
my @bad_links = ();
|
||||
my @section_headers = ();
|
||||
my $index = 0;
|
||||
|
||||
@lsfiles = vcs_list_files($lk_path);
|
||||
|
||||
for my $x (@self_test_info) {
|
||||
$index++;
|
||||
|
||||
## Section header duplication and missing section content
|
||||
if (($self_test eq "" || $self_test =~ /\bsections\b/) &&
|
||||
$x->{line} =~ /^\S[^:]/ &&
|
||||
defined $self_test_info[$index] &&
|
||||
$self_test_info[$index]->{line} =~ /^([A-Z]):\s*\S/) {
|
||||
my $has_S = 0;
|
||||
my $has_F = 0;
|
||||
my $has_ML = 0;
|
||||
my $status = "";
|
||||
if (grep(m@^\Q$x->{line}\E@, @section_headers)) {
|
||||
print("$x->{file}:$x->{linenr}: warning: duplicate section header\t$x->{line}\n");
|
||||
} else {
|
||||
push(@section_headers, $x->{line});
|
||||
}
|
||||
my $nextline = $index;
|
||||
while (defined $self_test_info[$nextline] &&
|
||||
$self_test_info[$nextline]->{line} =~ /^([A-Z]):\s*(\S.*)/) {
|
||||
my $type = $1;
|
||||
my $value = $2;
|
||||
if ($type eq "S") {
|
||||
$has_S = 1;
|
||||
$status = $value;
|
||||
} elsif ($type eq "F" || $type eq "N") {
|
||||
$has_F = 1;
|
||||
} elsif ($type eq "M" || $type eq "R" || $type eq "L") {
|
||||
$has_ML = 1;
|
||||
}
|
||||
$nextline++;
|
||||
}
|
||||
if (!$has_ML && $status !~ /orphan|obsolete/i) {
|
||||
print("$x->{file}:$x->{linenr}: warning: section without email address\t$x->{line}\n");
|
||||
}
|
||||
if (!$has_S) {
|
||||
print("$x->{file}:$x->{linenr}: warning: section without status \t$x->{line}\n");
|
||||
}
|
||||
if (!$has_F) {
|
||||
print("$x->{file}:$x->{linenr}: warning: section without file pattern\t$x->{line}\n");
|
||||
}
|
||||
}
|
||||
|
||||
next if ($x->{line} !~ /^([A-Z]):\s*(.*)/);
|
||||
|
||||
my $type = $1;
|
||||
my $value = $2;
|
||||
|
||||
## Filename pattern matching
|
||||
if (($type eq "F" || $type eq "X") &&
|
||||
($self_test eq "" || $self_test =~ /\bpatterns\b/)) {
|
||||
$value =~ s@\.@\\\.@g; ##Convert . to \.
|
||||
$value =~ s/\*/\.\*/g; ##Convert * to .*
|
||||
$value =~ s/\?/\./g; ##Convert ? to .
|
||||
##if pattern is a directory and it lacks a trailing slash, add one
|
||||
if ((-d $value)) {
|
||||
$value =~ s@([^/])$@$1/@;
|
||||
}
|
||||
if (!grep(m@^$value@, @lsfiles)) {
|
||||
print("$x->{file}:$x->{linenr}: warning: no file matches\t$x->{line}\n");
|
||||
}
|
||||
|
||||
## Link reachability
|
||||
} elsif (($type eq "W" || $type eq "Q" || $type eq "B") &&
|
||||
$value =~ /^https?:/ &&
|
||||
($self_test eq "" || $self_test =~ /\blinks\b/)) {
|
||||
next if (grep(m@^\Q$value\E$@, @good_links));
|
||||
my $isbad = 0;
|
||||
if (grep(m@^\Q$value\E$@, @bad_links)) {
|
||||
$isbad = 1;
|
||||
} else {
|
||||
my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $value`;
|
||||
if ($? == 0) {
|
||||
push(@good_links, $value);
|
||||
} else {
|
||||
push(@bad_links, $value);
|
||||
$isbad = 1;
|
||||
}
|
||||
}
|
||||
if ($isbad) {
|
||||
print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
|
||||
}
|
||||
|
||||
## SCM reachability
|
||||
} elsif ($type eq "T" &&
|
||||
($self_test eq "" || $self_test =~ /\bscm\b/)) {
|
||||
next if (grep(m@^\Q$value\E$@, @good_links));
|
||||
my $isbad = 0;
|
||||
if (grep(m@^\Q$value\E$@, @bad_links)) {
|
||||
$isbad = 1;
|
||||
} elsif ($value !~ /^(?:git|quilt|hg)\s+\S/) {
|
||||
print("$x->{file}:$x->{linenr}: warning: malformed entry\t$x->{line}\n");
|
||||
} elsif ($value =~ /^git\s+(\S+)(\s+([^\(]+\S+))?/) {
|
||||
my $url = $1;
|
||||
my $branch = "";
|
||||
$branch = $3 if $3;
|
||||
my $output = `git ls-remote --exit-code -h "$url" $branch > /dev/null 2>&1`;
|
||||
if ($? == 0) {
|
||||
push(@good_links, $value);
|
||||
} else {
|
||||
push(@bad_links, $value);
|
||||
$isbad = 1;
|
||||
}
|
||||
} elsif ($value =~ /^(?:quilt|hg)\s+(https?:\S+)/) {
|
||||
my $url = $1;
|
||||
my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $url`;
|
||||
if ($? == 0) {
|
||||
push(@good_links, $value);
|
||||
} else {
|
||||
push(@bad_links, $value);
|
||||
$isbad = 1;
|
||||
}
|
||||
}
|
||||
if ($isbad) {
|
||||
print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub ignore_email_address {
|
||||
my ($address) = @_;
|
||||
|
||||
@@ -863,6 +1020,7 @@ Other options:
|
||||
--sections => print all of the subsystem sections with pattern matches
|
||||
--letters => print all matching 'letter' types from all matching sections
|
||||
--mailmap => use .mailmap file (default: $email_use_mailmap)
|
||||
--self-test => show potential issues with MAINTAINERS file content
|
||||
--version => show version
|
||||
--help => show this help information
|
||||
|
||||
@@ -2192,6 +2350,23 @@ sub vcs_file_exists {
|
||||
return $exists;
|
||||
}
|
||||
|
||||
sub vcs_list_files {
|
||||
my ($file) = @_;
|
||||
|
||||
my @lsfiles = ();
|
||||
|
||||
my $vcs_used = vcs_exists();
|
||||
return 0 if (!$vcs_used);
|
||||
|
||||
my $cmd = $VCS_cmds{"list_files_cmd"};
|
||||
$cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd
|
||||
@lsfiles = &{$VCS_cmds{"execute_cmd"}}($cmd);
|
||||
|
||||
return () if ($? != 0);
|
||||
|
||||
return @lsfiles;
|
||||
}
|
||||
|
||||
sub uniq {
|
||||
my (@parms) = @_;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ do
|
||||
sed -r \
|
||||
-e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \
|
||||
-e 's/__attribute_const__([ \t]|$)/\1/g' \
|
||||
-e 's@^#include <linux/compiler.h>@@' \
|
||||
-e 's@^#include <linux/compiler(|_types).h>@@' \
|
||||
-e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \
|
||||
-e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \
|
||||
-e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \
|
||||
|
||||
@@ -893,7 +893,10 @@ static enum string_value_kind expr_parse_string(const char *str,
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
return k_string;
|
||||
val->s = !strcmp(str, "n") ? 0 :
|
||||
!strcmp(str, "m") ? 1 :
|
||||
!strcmp(str, "y") ? 2 : -1;
|
||||
return k_signed;
|
||||
case S_INT:
|
||||
val->s = strtoll(str, &tail, 10);
|
||||
kind = k_signed;
|
||||
|
||||
@@ -1061,7 +1061,7 @@ struct symbol **sym_re_search(const char *pattern)
|
||||
}
|
||||
if (sym_match_arr) {
|
||||
qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
|
||||
sym_arr = malloc((cnt+1) * sizeof(struct symbol));
|
||||
sym_arr = malloc((cnt+1) * sizeof(struct symbol *));
|
||||
if (!sym_arr)
|
||||
goto sym_re_search_free;
|
||||
for (i = 0; i < cnt; i++)
|
||||
|
||||
+38
-8
@@ -58,6 +58,7 @@ Output format selection (mutually exclusive):
|
||||
-man Output troff manual page format. This is the default.
|
||||
-rst Output reStructuredText format.
|
||||
-text Output plain text format.
|
||||
-none Do not output documentation, only warnings.
|
||||
|
||||
Output selection (mutually exclusive):
|
||||
-export Only output documentation for symbols that have been
|
||||
@@ -532,6 +533,8 @@ while ($ARGV[0] =~ m/^-(.*)/) {
|
||||
$output_mode = "gnome";
|
||||
@highlights = @highlights_gnome;
|
||||
$blankline = $blankline_gnome;
|
||||
} elsif ($cmd eq "-none") {
|
||||
$output_mode = "none";
|
||||
} elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
|
||||
$modulename = shift @ARGV;
|
||||
} elsif ($cmd eq "-function") { # to only output specific functions
|
||||
@@ -2117,6 +2120,24 @@ sub output_blockhead_list(%) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## none mode output functions
|
||||
|
||||
sub output_function_none(%) {
|
||||
}
|
||||
|
||||
sub output_enum_none(%) {
|
||||
}
|
||||
|
||||
sub output_typedef_none(%) {
|
||||
}
|
||||
|
||||
sub output_struct_none(%) {
|
||||
}
|
||||
|
||||
sub output_blockhead_none(%) {
|
||||
}
|
||||
|
||||
##
|
||||
# generic output function for all types (function, struct/union, typedef, enum);
|
||||
# calls the generated, variable output_ function name based on
|
||||
@@ -2168,7 +2189,7 @@ sub dump_struct($$) {
|
||||
my $nested;
|
||||
|
||||
if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
|
||||
#my $decl_type = $1;
|
||||
my $decl_type = $1;
|
||||
$declaration_name = $2;
|
||||
my $members = $3;
|
||||
|
||||
@@ -2182,8 +2203,6 @@ sub dump_struct($$) {
|
||||
# strip comments:
|
||||
$members =~ s/\/\*.*?\*\///gos;
|
||||
$nested =~ s/\/\*.*?\*\///gos;
|
||||
# strip kmemcheck_bitfield_{begin,end}.*;
|
||||
$members =~ s/kmemcheck_bitfield_.*?;//gos;
|
||||
# strip attributes
|
||||
$members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
|
||||
$members =~ s/__aligned\s*\([^;]*\)//gos;
|
||||
@@ -2194,7 +2213,7 @@ sub dump_struct($$) {
|
||||
$members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
|
||||
|
||||
create_parameterlist($members, ';', $file);
|
||||
check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
|
||||
check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual, $nested);
|
||||
|
||||
output_declaration($declaration_name,
|
||||
'struct',
|
||||
@@ -2226,6 +2245,8 @@ sub dump_enum($$) {
|
||||
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
|
||||
$declaration_name = $1;
|
||||
my $members = $2;
|
||||
my %_members;
|
||||
|
||||
$members =~ s/\s+$//;
|
||||
|
||||
foreach my $arg (split ',', $members) {
|
||||
@@ -2236,9 +2257,16 @@ sub dump_enum($$) {
|
||||
print STDERR "${file}:$.: warning: Enum value '$arg' ".
|
||||
"not described in enum '$declaration_name'\n";
|
||||
}
|
||||
|
||||
$_members{$arg} = 1;
|
||||
}
|
||||
|
||||
while (my ($k, $v) = each %parameterdescs) {
|
||||
if (!exists($_members{$k})) {
|
||||
print STDERR "${file}:$.: warning: Excess enum value " .
|
||||
"'$k' description in '$declaration_name'\n";
|
||||
}
|
||||
}
|
||||
|
||||
output_declaration($declaration_name,
|
||||
'enum',
|
||||
{'enum' => $declaration_name,
|
||||
@@ -2506,7 +2534,7 @@ sub check_sections($$$$$$) {
|
||||
} else {
|
||||
if ($nested !~ m/\Q$sects[$sx]\E/) {
|
||||
print STDERR "${file}:$.: warning: " .
|
||||
"Excess struct/union/enum/typedef member " .
|
||||
"Excess $decl_type member " .
|
||||
"'$sects[$sx]' " .
|
||||
"description in '$decl_name'\n";
|
||||
++$warnings;
|
||||
@@ -3136,7 +3164,9 @@ sub process_file($) {
|
||||
}
|
||||
}
|
||||
if ($initial_section_counter == $section_counter) {
|
||||
print STDERR "${file}:1: warning: no structured comments found\n";
|
||||
if ($output_mode ne "none") {
|
||||
print STDERR "${file}:1: warning: no structured comments found\n";
|
||||
}
|
||||
if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) {
|
||||
print STDERR " Was looking for '$_'.\n" for keys %function_table;
|
||||
}
|
||||
@@ -3218,4 +3248,4 @@ if ($verbose && $warnings) {
|
||||
print STDERR "$warnings warnings\n";
|
||||
}
|
||||
|
||||
exit($errors);
|
||||
exit($output_mode eq "none" ? 0 : $errors);
|
||||
|
||||
+286
-90
@@ -7,25 +7,6 @@
|
||||
# - Scans dmesg output.
|
||||
# - Walks directory tree and parses each file (for each directory in @DIRS).
|
||||
#
|
||||
# You can configure the behaviour of the script;
|
||||
#
|
||||
# - By adding paths, for directories you do not want to walk;
|
||||
# absolute paths: @skip_walk_dirs_abs
|
||||
# directory names: @skip_walk_dirs_any
|
||||
#
|
||||
# - By adding paths, for files you do not want to parse;
|
||||
# absolute paths: @skip_parse_files_abs
|
||||
# file names: @skip_parse_files_any
|
||||
#
|
||||
# The use of @skip_xxx_xxx_any causes files to be skipped where ever they occur.
|
||||
# For example adding 'fd' to @skip_walk_dirs_any causes the fd/ directory to be
|
||||
# skipped for all PID sub-directories of /proc
|
||||
#
|
||||
# The same thing can be achieved by passing command line options to --dont-walk
|
||||
# and --dont-parse. If absolute paths are supplied to these options they are
|
||||
# appended to the @skip_xxx_xxx_abs arrays. If file names are supplied to these
|
||||
# options, they are appended to the @skip_xxx_xxx_any arrays.
|
||||
#
|
||||
# Use --debug to output path before parsing, this is useful to find files that
|
||||
# cause the script to choke.
|
||||
#
|
||||
@@ -40,6 +21,7 @@ use File::Spec;
|
||||
use Cwd 'abs_path';
|
||||
use Term::ANSIColor qw(:constants);
|
||||
use Getopt::Long qw(:config no_auto_abbrev);
|
||||
use Config;
|
||||
|
||||
my $P = $0;
|
||||
my $V = '0.01';
|
||||
@@ -47,21 +29,36 @@ my $V = '0.01';
|
||||
# Directories to scan.
|
||||
my @DIRS = ('/proc', '/sys');
|
||||
|
||||
# Timer for parsing each file, in seconds.
|
||||
my $TIMEOUT = 10;
|
||||
|
||||
# Script can only grep for kernel addresses on the following architectures. If
|
||||
# your architecture is not listed here and has a grep'able kernel address please
|
||||
# consider submitting a patch.
|
||||
my @SUPPORTED_ARCHITECTURES = ('x86_64', 'ppc64');
|
||||
|
||||
# Command line options.
|
||||
my $help = 0;
|
||||
my $debug = 0;
|
||||
my @dont_walk = ();
|
||||
my @dont_parse = ();
|
||||
my $raw = 0;
|
||||
my $output_raw = ""; # Write raw results to file.
|
||||
my $input_raw = ""; # Read raw results from file instead of scanning.
|
||||
|
||||
my $suppress_dmesg = 0; # Don't show dmesg in output.
|
||||
my $squash_by_path = 0; # Summary report grouped by absolute path.
|
||||
my $squash_by_filename = 0; # Summary report grouped by filename.
|
||||
|
||||
# Do not parse these files (absolute path).
|
||||
my @skip_parse_files_abs = ('/proc/kmsg',
|
||||
'/proc/kcore',
|
||||
'/proc/fs/ext4/sdb1/mb_groups',
|
||||
'/proc/1/fd/3',
|
||||
'/sys/firmware/devicetree',
|
||||
'/proc/device-tree',
|
||||
'/sys/kernel/debug/tracing/trace_pipe',
|
||||
'/sys/kernel/security/apparmor/revision');
|
||||
|
||||
# Do not parse thes files under any subdirectory.
|
||||
# Do not parse these files under any subdirectory.
|
||||
my @skip_parse_files_any = ('0',
|
||||
'1',
|
||||
'2',
|
||||
@@ -82,6 +79,7 @@ my @skip_walk_dirs_any = ('self',
|
||||
'thread-self',
|
||||
'cwd',
|
||||
'fd',
|
||||
'usbmon',
|
||||
'stderr',
|
||||
'stdin',
|
||||
'stdout');
|
||||
@@ -91,24 +89,31 @@ sub help
|
||||
my ($exitcode) = @_;
|
||||
|
||||
print << "EOM";
|
||||
|
||||
Usage: $P [OPTIONS]
|
||||
Version: $V
|
||||
|
||||
Options:
|
||||
|
||||
--dont-walk=<dir> Don't walk tree starting at <dir>.
|
||||
--dont-parse=<file> Don't parse <file>.
|
||||
-d, --debug Display debugging output.
|
||||
-h, --help, --version Display this help and exit.
|
||||
-o, --output-raw=<file> Save results for future processing.
|
||||
-i, --input-raw=<file> Read results from file instead of scanning.
|
||||
--raw Show raw results (default).
|
||||
--suppress-dmesg Do not show dmesg results.
|
||||
--squash-by-path Show one result per unique path.
|
||||
--squash-by-filename Show one result per unique filename.
|
||||
-d, --debug Display debugging output.
|
||||
-h, --help, --version Display this help and exit.
|
||||
|
||||
If an absolute path is passed to --dont_XXX then this path is skipped. If a
|
||||
single filename is passed then this file/directory will be skipped when
|
||||
appearing under any subdirectory.
|
||||
Examples:
|
||||
|
||||
Example:
|
||||
# Scan kernel and dump raw results.
|
||||
$0
|
||||
|
||||
# Just scan dmesg output.
|
||||
scripts/leaking_addresses.pl --dont_walk_abs /proc --dont_walk_abs /sys
|
||||
# Scan kernel and save results to file.
|
||||
$0 --output-raw scan.out
|
||||
|
||||
# View summary report.
|
||||
$0 --input-raw scan.out --squash-by-filename
|
||||
|
||||
Scans the running (64 bit) kernel for potential leaking addresses.
|
||||
|
||||
@@ -117,99 +122,136 @@ EOM
|
||||
}
|
||||
|
||||
GetOptions(
|
||||
'dont-walk=s' => \@dont_walk,
|
||||
'dont-parse=s' => \@dont_parse,
|
||||
'd|debug' => \$debug,
|
||||
'h|help' => \$help,
|
||||
'version' => \$help
|
||||
'version' => \$help,
|
||||
'o|output-raw=s' => \$output_raw,
|
||||
'i|input-raw=s' => \$input_raw,
|
||||
'suppress-dmesg' => \$suppress_dmesg,
|
||||
'squash-by-path' => \$squash_by_path,
|
||||
'squash-by-filename' => \$squash_by_filename,
|
||||
'raw' => \$raw,
|
||||
) or help(1);
|
||||
|
||||
help(0) if ($help);
|
||||
|
||||
push_to_global();
|
||||
if ($input_raw) {
|
||||
format_output($input_raw);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!$input_raw and ($squash_by_path or $squash_by_filename)) {
|
||||
printf "\nSummary reporting only available with --input-raw=<file>\n";
|
||||
printf "(First run scan with --output-raw=<file>.)\n";
|
||||
exit(128);
|
||||
}
|
||||
|
||||
if (!is_supported_architecture()) {
|
||||
printf "\nScript does not support your architecture, sorry.\n";
|
||||
printf "\nCurrently we support: \n\n";
|
||||
foreach(@SUPPORTED_ARCHITECTURES) {
|
||||
printf "\t%s\n", $_;
|
||||
}
|
||||
|
||||
my $archname = $Config{archname};
|
||||
printf "\n\$ perl -MConfig -e \'print \"\$Config{archname}\\n\"\'\n";
|
||||
printf "%s\n", $archname;
|
||||
|
||||
exit(129);
|
||||
}
|
||||
|
||||
if ($output_raw) {
|
||||
open my $fh, '>', $output_raw or die "$0: $output_raw: $!\n";
|
||||
select $fh;
|
||||
}
|
||||
|
||||
parse_dmesg();
|
||||
walk(@DIRS);
|
||||
|
||||
exit 0;
|
||||
|
||||
sub debug_arrays
|
||||
{
|
||||
print 'dirs_any: ' . join(", ", @skip_walk_dirs_any) . "\n";
|
||||
print 'dirs_abs: ' . join(", ", @skip_walk_dirs_abs) . "\n";
|
||||
print 'parse_any: ' . join(", ", @skip_parse_files_any) . "\n";
|
||||
print 'parse_abs: ' . join(", ", @skip_parse_files_abs) . "\n";
|
||||
}
|
||||
|
||||
sub dprint
|
||||
{
|
||||
printf(STDERR @_) if $debug;
|
||||
}
|
||||
|
||||
sub push_in_abs_any
|
||||
sub is_supported_architecture
|
||||
{
|
||||
my ($in, $abs, $any) = @_;
|
||||
|
||||
foreach my $path (@$in) {
|
||||
if (File::Spec->file_name_is_absolute($path)) {
|
||||
push @$abs, $path;
|
||||
} elsif (index($path,'/') == -1) {
|
||||
push @$any, $path;
|
||||
} else {
|
||||
print 'path error: ' . $path;
|
||||
}
|
||||
}
|
||||
return (is_x86_64() or is_ppc64());
|
||||
}
|
||||
|
||||
# Push command line options to global arrays.
|
||||
sub push_to_global
|
||||
sub is_x86_64
|
||||
{
|
||||
push_in_abs_any(\@dont_walk, \@skip_walk_dirs_abs, \@skip_walk_dirs_any);
|
||||
push_in_abs_any(\@dont_parse, \@skip_parse_files_abs, \@skip_parse_files_any);
|
||||
my $archname = $Config{archname};
|
||||
|
||||
if ($archname =~ m/x86_64/) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub is_ppc64
|
||||
{
|
||||
my $archname = $Config{archname};
|
||||
|
||||
if ($archname =~ m/powerpc/ and $archname =~ m/64/) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub is_false_positive
|
||||
{
|
||||
my ($match) = @_;
|
||||
my ($match) = @_;
|
||||
|
||||
if ($match =~ '\b(0x)?(f|F){16}\b' or
|
||||
$match =~ '\b(0x)?0{16}\b') {
|
||||
return 1;
|
||||
}
|
||||
if ($match =~ '\b(0x)?(f|F){16}\b' or
|
||||
$match =~ '\b(0x)?0{16}\b') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
# vsyscall memory region, we should probably check against a range here.
|
||||
if ($match =~ '\bf{10}600000\b' or
|
||||
$match =~ '\bf{10}601000\b') {
|
||||
return 1;
|
||||
}
|
||||
if (is_x86_64) {
|
||||
# vsyscall memory region, we should probably check against a range here.
|
||||
if ($match =~ '\bf{10}600000\b' or
|
||||
$match =~ '\bf{10}601000\b') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# True if argument potentially contains a kernel address.
|
||||
sub may_leak_address
|
||||
{
|
||||
my ($line) = @_;
|
||||
my $address = '\b(0x)?ffff[[:xdigit:]]{12}\b';
|
||||
my ($line) = @_;
|
||||
my $address_re;
|
||||
|
||||
# Signal masks.
|
||||
if ($line =~ '^SigBlk:' or
|
||||
$line =~ '^SigCgt:') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or
|
||||
$line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') {
|
||||
# Signal masks.
|
||||
if ($line =~ '^SigBlk:' or
|
||||
$line =~ '^SigIgn:' or
|
||||
$line =~ '^SigCgt:') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (/($address)/g) {
|
||||
if (!is_false_positive($1)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or
|
||||
$line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
# One of these is guaranteed to be true.
|
||||
if (is_x86_64()) {
|
||||
$address_re = '\b(0x)?ffff[[:xdigit:]]{12}\b';
|
||||
} elsif (is_ppc64()) {
|
||||
$address_re = '\b(0x)?[89abcdef]00[[:xdigit:]]{13}\b';
|
||||
}
|
||||
|
||||
while (/($address_re)/g) {
|
||||
if (!is_false_positive($1)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub parse_dmesg
|
||||
@@ -246,6 +288,23 @@ sub skip_parse
|
||||
return skip($path, \@skip_parse_files_abs, \@skip_parse_files_any);
|
||||
}
|
||||
|
||||
sub timed_parse_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
|
||||
eval {
|
||||
local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required.
|
||||
alarm $TIMEOUT;
|
||||
parse_file($file);
|
||||
alarm 0;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
die unless $@ eq "alarm\n"; # Propagate unexpected errors.
|
||||
printf STDERR "timed out parsing: %s\n", $file;
|
||||
}
|
||||
}
|
||||
|
||||
sub parse_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
@@ -281,7 +340,6 @@ sub skip_walk
|
||||
sub walk
|
||||
{
|
||||
my @dirs = @_;
|
||||
my %seen;
|
||||
|
||||
while (my $pwd = shift @dirs) {
|
||||
next if (skip_walk($pwd));
|
||||
@@ -298,8 +356,146 @@ sub walk
|
||||
if (-d $path) {
|
||||
push @dirs, $path;
|
||||
} else {
|
||||
parse_file($path);
|
||||
timed_parse_file($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub format_output
|
||||
{
|
||||
my ($file) = @_;
|
||||
|
||||
# Default is to show raw results.
|
||||
if ($raw or (!$squash_by_path and !$squash_by_filename)) {
|
||||
dump_raw_output($file);
|
||||
return;
|
||||
}
|
||||
|
||||
my ($total, $dmesg, $paths, $files) = parse_raw_file($file);
|
||||
|
||||
printf "\nTotal number of results from scan (incl dmesg): %d\n", $total;
|
||||
|
||||
if (!$suppress_dmesg) {
|
||||
print_dmesg($dmesg);
|
||||
}
|
||||
|
||||
if ($squash_by_filename) {
|
||||
squash_by($files, 'filename');
|
||||
}
|
||||
|
||||
if ($squash_by_path) {
|
||||
squash_by($paths, 'path');
|
||||
}
|
||||
}
|
||||
|
||||
sub dump_raw_output
|
||||
{
|
||||
my ($file) = @_;
|
||||
|
||||
open (my $fh, '<', $file) or die "$0: $file: $!\n";
|
||||
while (<$fh>) {
|
||||
if ($suppress_dmesg) {
|
||||
if ("dmesg:" eq substr($_, 0, 6)) {
|
||||
next;
|
||||
}
|
||||
}
|
||||
print $_;
|
||||
}
|
||||
close $fh;
|
||||
}
|
||||
|
||||
sub parse_raw_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
|
||||
my $total = 0; # Total number of lines parsed.
|
||||
my @dmesg; # dmesg output.
|
||||
my %files; # Unique filenames containing leaks.
|
||||
my %paths; # Unique paths containing leaks.
|
||||
|
||||
open (my $fh, '<', $file) or die "$0: $file: $!\n";
|
||||
while (my $line = <$fh>) {
|
||||
$total++;
|
||||
|
||||
if ("dmesg:" eq substr($line, 0, 6)) {
|
||||
push @dmesg, $line;
|
||||
next;
|
||||
}
|
||||
|
||||
cache_path(\%paths, $line);
|
||||
cache_filename(\%files, $line);
|
||||
}
|
||||
|
||||
return $total, \@dmesg, \%paths, \%files;
|
||||
}
|
||||
|
||||
sub print_dmesg
|
||||
{
|
||||
my ($dmesg) = @_;
|
||||
|
||||
print "\ndmesg output:\n";
|
||||
|
||||
if (@$dmesg == 0) {
|
||||
print "<no results>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(@$dmesg) {
|
||||
my $index = index($_, ': ');
|
||||
$index += 2; # skid ': '
|
||||
print substr($_, $index);
|
||||
}
|
||||
}
|
||||
|
||||
sub squash_by
|
||||
{
|
||||
my ($ref, $desc) = @_;
|
||||
|
||||
print "\nResults squashed by $desc (excl dmesg). ";
|
||||
print "Displaying [<number of results> <$desc>], <example result>\n";
|
||||
|
||||
if (keys %$ref == 0) {
|
||||
print "<no results>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(keys %$ref) {
|
||||
my $lines = $ref->{$_};
|
||||
my $length = @$lines;
|
||||
printf "[%d %s] %s", $length, $_, @$lines[0];
|
||||
}
|
||||
}
|
||||
|
||||
sub cache_path
|
||||
{
|
||||
my ($paths, $line) = @_;
|
||||
|
||||
my $index = index($line, ': ');
|
||||
my $path = substr($line, 0, $index);
|
||||
|
||||
$index += 2; # skip ': '
|
||||
add_to_cache($paths, $path, substr($line, $index));
|
||||
}
|
||||
|
||||
sub cache_filename
|
||||
{
|
||||
my ($files, $line) = @_;
|
||||
|
||||
my $index = index($line, ': ');
|
||||
my $path = substr($line, 0, $index);
|
||||
my $filename = basename($path);
|
||||
|
||||
$index += 2; # skip ': '
|
||||
add_to_cache($files, $filename, substr($line, $index));
|
||||
}
|
||||
|
||||
sub add_to_cache
|
||||
{
|
||||
my ($cache, $key, $value) = @_;
|
||||
|
||||
if (!$cache->{$key}) {
|
||||
$cache->{$key} = ();
|
||||
}
|
||||
push @{$cache->{$key}}, $value;
|
||||
}
|
||||
|
||||
+5
-10
@@ -188,10 +188,8 @@ sortextable()
|
||||
# Delete output files in case of error
|
||||
cleanup()
|
||||
{
|
||||
rm -f .old_version
|
||||
rm -f .tmp_System.map
|
||||
rm -f .tmp_kallsyms*
|
||||
rm -f .tmp_version
|
||||
rm -f .tmp_vmlinux*
|
||||
rm -f built-in.o
|
||||
rm -f System.map
|
||||
@@ -239,12 +237,12 @@ esac
|
||||
|
||||
# Update version
|
||||
info GEN .version
|
||||
if [ ! -r .version ]; then
|
||||
rm -f .version;
|
||||
echo 1 >.version;
|
||||
if [ -r .version ]; then
|
||||
VERSION=$(expr 0$(cat .version) + 1)
|
||||
echo $VERSION > .version
|
||||
else
|
||||
mv .version .old_version;
|
||||
expr 0$(cat .old_version) + 1 >.version;
|
||||
rm -f .version
|
||||
echo 1 > .version
|
||||
fi;
|
||||
|
||||
# final build of init/
|
||||
@@ -332,6 +330,3 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# We made a new kernel - delete old version file
|
||||
rm -f .old_version
|
||||
|
||||
+1
-6
@@ -28,12 +28,7 @@ LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
if [ -z "$KBUILD_BUILD_VERSION" ]; then
|
||||
if [ -r .version ]; then
|
||||
VERSION=`cat .version`
|
||||
else
|
||||
VERSION=0
|
||||
echo 0 > .version
|
||||
fi
|
||||
VERSION=$(cat .version 2>/dev/null || echo 1)
|
||||
else
|
||||
VERSION=$KBUILD_BUILD_VERSION
|
||||
fi
|
||||
|
||||
@@ -207,5 +207,12 @@ int main(void)
|
||||
DEVID_FIELD(fsl_mc_device_id, vendor);
|
||||
DEVID_FIELD(fsl_mc_device_id, obj_type);
|
||||
|
||||
DEVID(tb_service_id);
|
||||
DEVID_FIELD(tb_service_id, match_flags);
|
||||
DEVID_FIELD(tb_service_id, protocol_key);
|
||||
DEVID_FIELD(tb_service_id, protocol_id);
|
||||
DEVID_FIELD(tb_service_id, protocol_version);
|
||||
DEVID_FIELD(tb_service_id, protocol_revision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1301,6 +1301,31 @@ static int do_fsl_mc_entry(const char *filename, void *symval,
|
||||
}
|
||||
ADD_TO_DEVTABLE("fslmc", fsl_mc_device_id, do_fsl_mc_entry);
|
||||
|
||||
/* Looks like: tbsvc:kSpNvNrN */
|
||||
static int do_tbsvc_entry(const char *filename, void *symval, char *alias)
|
||||
{
|
||||
DEF_FIELD(symval, tb_service_id, match_flags);
|
||||
DEF_FIELD_ADDR(symval, tb_service_id, protocol_key);
|
||||
DEF_FIELD(symval, tb_service_id, protocol_id);
|
||||
DEF_FIELD(symval, tb_service_id, protocol_version);
|
||||
DEF_FIELD(symval, tb_service_id, protocol_revision);
|
||||
|
||||
strcpy(alias, "tbsvc:");
|
||||
if (match_flags & TBSVC_MATCH_PROTOCOL_KEY)
|
||||
sprintf(alias + strlen(alias), "k%s", *protocol_key);
|
||||
else
|
||||
strcat(alias + strlen(alias), "k*");
|
||||
ADD(alias, "p", match_flags & TBSVC_MATCH_PROTOCOL_ID, protocol_id);
|
||||
ADD(alias, "v", match_flags & TBSVC_MATCH_PROTOCOL_VERSION,
|
||||
protocol_version);
|
||||
ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION,
|
||||
protocol_revision);
|
||||
|
||||
add_wildcard(alias);
|
||||
return 1;
|
||||
}
|
||||
ADD_TO_DEVTABLE("tbsvc", tb_service_id, do_tbsvc_entry);
|
||||
|
||||
/* Does namelen bytes of name exactly match the symbol? */
|
||||
static bool sym_is(const char *name, unsigned namelen, const char *symbol)
|
||||
{
|
||||
|
||||
@@ -1963,7 +1963,7 @@ static void read_symbols(char *modname)
|
||||
}
|
||||
|
||||
license = get_modinfo(info.modinfo, info.modinfo_len, "license");
|
||||
if (info.modinfo && !license && !is_vmlinux(modname))
|
||||
if (!license && !is_vmlinux(modname))
|
||||
warn("modpost: missing MODULE_LICENSE() in %s\n"
|
||||
"see include/linux/module.h for "
|
||||
"more information\n", modname);
|
||||
|
||||
@@ -39,28 +39,28 @@ if test "$(objtree)" != "$(srctree)"; then \
|
||||
false; \
|
||||
fi ; \
|
||||
$(srctree)/scripts/setlocalversion --save-scmversion; \
|
||||
ln -sf $(srctree) $(2); \
|
||||
tar -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \
|
||||
$(addprefix $(2)/,$(TAR_CONTENT) $(3)); \
|
||||
rm -f $(2) $(objtree)/.scmversion
|
||||
--transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3); \
|
||||
rm -f $(objtree)/.scmversion
|
||||
|
||||
# rpm-pkg
|
||||
# ---------------------------------------------------------------------------
|
||||
rpm-pkg rpm: FORCE
|
||||
rpm-pkg: FORCE
|
||||
$(MAKE) clean
|
||||
$(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
|
||||
$(call cmd,src_tar,$(KERNELPATH),kernel.spec)
|
||||
rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz
|
||||
rm $(KERNELPATH).tar.gz kernel.spec
|
||||
+rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \
|
||||
--define='_smp_mflags %{nil}'
|
||||
|
||||
# binrpm-pkg
|
||||
# ---------------------------------------------------------------------------
|
||||
binrpm-pkg: FORCE
|
||||
$(MAKE) KBUILD_SRC=
|
||||
$(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec
|
||||
rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
|
||||
+rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
|
||||
$(UTS_MACHINE) -bb $(objtree)/binkernel.spec
|
||||
rm binkernel.spec
|
||||
|
||||
clean-files += $(objtree)/*.spec
|
||||
|
||||
# Deb target
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -408,9 +408,9 @@ EOF
|
||||
dpkg-source -cdebian/control -ldebian/changelog --format="3.0 (custom)" --target-format="3.0 (quilt)" \
|
||||
-b / ../${sourcename}_${version}.orig.tar.gz ../${sourcename}_${packageversion}.debian.tar.gz
|
||||
mv ${sourcename}_${packageversion}*dsc ..
|
||||
dpkg-genchanges > ../${sourcename}_${packageversion}_${debarch}.changes
|
||||
dpkg-genchanges -Vkernel:debarch="${debarch}" > ../${sourcename}_${packageversion}_${debarch}.changes
|
||||
else
|
||||
dpkg-genchanges -b > ../${sourcename}_${packageversion}_${debarch}.changes
|
||||
dpkg-genchanges -b -Vkernel:debarch="${debarch}" > ../${sourcename}_${packageversion}_${debarch}.changes
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
+115
-136
@@ -10,156 +10,135 @@
|
||||
#
|
||||
|
||||
# how we were called determines which rpms we build and how we build them
|
||||
if [ "$1" = "prebuilt" ]; then
|
||||
PREBUILT=true
|
||||
if [ "$1" = prebuilt ]; then
|
||||
S=DEL
|
||||
else
|
||||
PREBUILT=false
|
||||
S=
|
||||
fi
|
||||
|
||||
# starting to output the spec
|
||||
if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
|
||||
if grep -q CONFIG_MODULES=y .config; then
|
||||
M=
|
||||
else
|
||||
M=DEL
|
||||
fi
|
||||
|
||||
if grep -q CONFIG_DRM=y .config; then
|
||||
PROVIDES=kernel-drm
|
||||
fi
|
||||
|
||||
PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
|
||||
__KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-/_/g"`
|
||||
__KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g")
|
||||
EXCLUDES="$RCS_TAR_IGNORE --exclude=.tmp_versions --exclude=*vmlinux* \
|
||||
--exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation \
|
||||
--exclude=.config.old --exclude=.missing-syscalls.d"
|
||||
|
||||
echo "Name: kernel"
|
||||
echo "Summary: The Linux Kernel"
|
||||
echo "Version: $__KERNELRELEASE"
|
||||
echo "Release: $(cat .version 2>/dev/null || echo 1)"
|
||||
echo "License: GPL"
|
||||
echo "Group: System Environment/Kernel"
|
||||
echo "Vendor: The Linux Community"
|
||||
echo "URL: http://www.kernel.org"
|
||||
# We can label the here-doc lines for conditional output to the spec file
|
||||
#
|
||||
# Labels:
|
||||
# $S: this line is enabled only when building source package
|
||||
# $M: this line is enabled only when CONFIG_MODULES is enabled
|
||||
sed -e '/^DEL/d' -e 's/^\t*//' <<EOF
|
||||
Name: kernel
|
||||
Summary: The Linux Kernel
|
||||
Version: $__KERNELRELEASE
|
||||
Release: $(cat .version 2>/dev/null || echo 1)
|
||||
License: GPL
|
||||
Group: System Environment/Kernel
|
||||
Vendor: The Linux Community
|
||||
URL: http://www.kernel.org
|
||||
$S Source: kernel-$__KERNELRELEASE.tar.gz
|
||||
Provides: $PROVIDES
|
||||
%define __spec_install_post /usr/lib/rpm/brp-compress || :
|
||||
%define debug_package %{nil}
|
||||
|
||||
if ! $PREBUILT; then
|
||||
echo "Source: kernel-$__KERNELRELEASE.tar.gz"
|
||||
fi
|
||||
%description
|
||||
The Linux Kernel, the operating system core itself
|
||||
|
||||
echo "BuildRoot: %{_tmppath}/%{name}-%{PACKAGE_VERSION}-root"
|
||||
echo "Provides: $PROVIDES"
|
||||
echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
|
||||
echo "%define debug_package %{nil}"
|
||||
echo ""
|
||||
echo "%description"
|
||||
echo "The Linux Kernel, the operating system core itself"
|
||||
echo ""
|
||||
echo "%package headers"
|
||||
echo "Summary: Header files for the Linux kernel for use by glibc"
|
||||
echo "Group: Development/System"
|
||||
echo "Obsoletes: kernel-headers"
|
||||
echo "Provides: kernel-headers = %{version}"
|
||||
echo "%description headers"
|
||||
echo "Kernel-headers includes the C header files that specify the interface"
|
||||
echo "between the Linux kernel and userspace libraries and programs. The"
|
||||
echo "header files define structures and constants that are needed for"
|
||||
echo "building most standard programs and are also needed for rebuilding the"
|
||||
echo "glibc package."
|
||||
echo ""
|
||||
echo "%package devel"
|
||||
echo "Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel"
|
||||
echo "Group: System Environment/Kernel"
|
||||
echo "AutoReqProv: no"
|
||||
echo "%description -n kernel-devel"
|
||||
echo "This package provides kernel headers and makefiles sufficient to build modules"
|
||||
echo "against the $__KERNELRELEASE kernel package."
|
||||
echo ""
|
||||
%package headers
|
||||
Summary: Header files for the Linux kernel for use by glibc
|
||||
Group: Development/System
|
||||
Obsoletes: kernel-headers
|
||||
Provides: kernel-headers = %{version}
|
||||
%description headers
|
||||
Kernel-headers includes the C header files that specify the interface
|
||||
between the Linux kernel and userspace libraries and programs. The
|
||||
header files define structures and constants that are needed for
|
||||
building most standard programs and are also needed for rebuilding the
|
||||
glibc package.
|
||||
|
||||
if ! $PREBUILT; then
|
||||
echo "%prep"
|
||||
echo "%setup -q"
|
||||
echo ""
|
||||
fi
|
||||
$S$M %package devel
|
||||
$S$M Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel
|
||||
$S$M Group: System Environment/Kernel
|
||||
$S$M AutoReqProv: no
|
||||
$S$M %description -n kernel-devel
|
||||
$S$M This package provides kernel headers and makefiles sufficient to build modules
|
||||
$S$M against the $__KERNELRELEASE kernel package.
|
||||
$S$M
|
||||
$S %prep
|
||||
$S %setup -q
|
||||
$S
|
||||
$S %build
|
||||
$S make %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release}
|
||||
$S
|
||||
%install
|
||||
mkdir -p %{buildroot}/boot
|
||||
%ifarch ia64
|
||||
mkdir -p %{buildroot}/boot/efi
|
||||
cp \$(make image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE
|
||||
ln -s efi/vmlinuz-$KERNELRELEASE %{buildroot}/boot/
|
||||
%else
|
||||
cp \$(make image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE
|
||||
%endif
|
||||
$M make %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} KBUILD_SRC= modules_install
|
||||
make %{?_smp_mflags} INSTALL_HDR_PATH=%{buildroot}/usr KBUILD_SRC= headers_install
|
||||
cp System.map %{buildroot}/boot/System.map-$KERNELRELEASE
|
||||
cp .config %{buildroot}/boot/config-$KERNELRELEASE
|
||||
bzip2 -9 --keep vmlinux
|
||||
mv vmlinux.bz2 %{buildroot}/boot/vmlinux-$KERNELRELEASE.bz2
|
||||
$S$M rm -f %{buildroot}/lib/modules/$KERNELRELEASE/build
|
||||
$S$M rm -f %{buildroot}/lib/modules/$KERNELRELEASE/source
|
||||
$S$M mkdir -p %{buildroot}/usr/src/kernels/$KERNELRELEASE
|
||||
$S$M tar cf - . $EXCLUDES | tar xf - -C %{buildroot}/usr/src/kernels/$KERNELRELEASE
|
||||
$S$M cd %{buildroot}/lib/modules/$KERNELRELEASE
|
||||
$S$M ln -sf /usr/src/kernels/$KERNELRELEASE build
|
||||
$S$M ln -sf /usr/src/kernels/$KERNELRELEASE source
|
||||
|
||||
echo "%build"
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
if ! $PREBUILT; then
|
||||
echo "make clean && make %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release}"
|
||||
echo ""
|
||||
fi
|
||||
%post
|
||||
if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then
|
||||
cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm
|
||||
cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm
|
||||
rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE
|
||||
/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm
|
||||
rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm
|
||||
fi
|
||||
|
||||
echo "%install"
|
||||
echo 'KBUILD_IMAGE=$(make image_name)'
|
||||
echo "%ifarch ia64"
|
||||
echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
|
||||
echo "%else"
|
||||
echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
|
||||
echo "%endif"
|
||||
%preun
|
||||
if [ -x /sbin/new-kernel-pkg ]; then
|
||||
new-kernel-pkg --remove $KERNELRELEASE --rminitrd --initrdfile=/boot/initramfs-$KERNELRELEASE.img
|
||||
fi
|
||||
|
||||
echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= modules_install'
|
||||
echo "%ifarch ia64"
|
||||
echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
|
||||
echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
|
||||
echo "%else"
|
||||
echo "%ifarch ppc64"
|
||||
echo "cp vmlinux arch/powerpc/boot"
|
||||
echo "cp arch/powerpc/boot/"'$KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
|
||||
echo "%else"
|
||||
echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
|
||||
echo "%endif"
|
||||
echo "%endif"
|
||||
%postun
|
||||
if [ -x /sbin/update-bootloader ]; then
|
||||
/sbin/update-bootloader --remove $KERNELRELEASE
|
||||
fi
|
||||
|
||||
echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr KBUILD_SRC= headers_install'
|
||||
echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
|
||||
%files
|
||||
%defattr (-, root, root)
|
||||
$M /lib/modules/$KERNELRELEASE
|
||||
$M %exclude /lib/modules/$KERNELRELEASE/build
|
||||
$M %exclude /lib/modules/$KERNELRELEASE/source
|
||||
/boot/*
|
||||
|
||||
echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE"
|
||||
|
||||
echo "%ifnarch ppc64"
|
||||
echo 'bzip2 -9 --keep vmlinux'
|
||||
echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2"
|
||||
echo "%endif"
|
||||
|
||||
if ! $PREBUILT; then
|
||||
echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/build"
|
||||
echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/source"
|
||||
echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE"
|
||||
echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude .config.old --exclude .missing-syscalls.d\""
|
||||
echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)"
|
||||
echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE"
|
||||
echo "ln -sf /usr/src/kernels/$KERNELRELEASE build"
|
||||
echo "ln -sf /usr/src/kernels/$KERNELRELEASE source"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "%clean"
|
||||
echo 'rm -rf $RPM_BUILD_ROOT'
|
||||
echo ""
|
||||
echo "%post"
|
||||
echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then"
|
||||
echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm"
|
||||
echo "cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm"
|
||||
echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE"
|
||||
echo "/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
|
||||
echo "rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
|
||||
echo "fi"
|
||||
echo ""
|
||||
echo "%preun"
|
||||
echo "if [ -x /sbin/new-kernel-pkg ]; then"
|
||||
echo "new-kernel-pkg --remove $KERNELRELEASE --rminitrd --initrdfile=/boot/initramfs-$KERNELRELEASE.img"
|
||||
echo "fi"
|
||||
echo ""
|
||||
echo "%postun"
|
||||
echo "if [ -x /sbin/update-bootloader ]; then"
|
||||
echo "/sbin/update-bootloader --remove $KERNELRELEASE"
|
||||
echo "fi"
|
||||
echo ""
|
||||
echo "%files"
|
||||
echo '%defattr (-, root, root)'
|
||||
echo "/lib/modules/$KERNELRELEASE"
|
||||
echo "%exclude /lib/modules/$KERNELRELEASE/build"
|
||||
echo "%exclude /lib/modules/$KERNELRELEASE/source"
|
||||
echo "/boot/*"
|
||||
echo ""
|
||||
echo "%files headers"
|
||||
echo '%defattr (-, root, root)'
|
||||
echo "/usr/include"
|
||||
echo ""
|
||||
if ! $PREBUILT; then
|
||||
echo "%files devel"
|
||||
echo '%defattr (-, root, root)'
|
||||
echo "/usr/src/kernels/$KERNELRELEASE"
|
||||
echo "/lib/modules/$KERNELRELEASE/build"
|
||||
echo "/lib/modules/$KERNELRELEASE/source"
|
||||
echo ""
|
||||
fi
|
||||
%files headers
|
||||
%defattr (-, root, root)
|
||||
/usr/include
|
||||
$S$M
|
||||
$S$M %files devel
|
||||
$S$M %defattr (-, root, root)
|
||||
$S$M /usr/src/kernels/$KERNELRELEASE
|
||||
$S$M /lib/modules/$KERNELRELEASE/build
|
||||
$S$M /lib/modules/$KERNELRELEASE/source
|
||||
EOF
|
||||
|
||||
@@ -2,9 +2,44 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
use strict;
|
||||
use Getopt::Long qw(:config no_auto_abbrev);
|
||||
|
||||
my $input_file = "MAINTAINERS";
|
||||
my $output_file = "MAINTAINERS.new";
|
||||
my $output_section = "SECTION.new";
|
||||
my $help = 0;
|
||||
|
||||
my $P = $0;
|
||||
|
||||
if (!GetOptions(
|
||||
'input=s' => \$input_file,
|
||||
'output=s' => \$output_file,
|
||||
'section=s' => \$output_section,
|
||||
'h|help|usage' => \$help,
|
||||
)) {
|
||||
die "$P: invalid argument - use --help if necessary\n";
|
||||
}
|
||||
|
||||
if ($help != 0) {
|
||||
usage();
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub usage {
|
||||
print <<EOT;
|
||||
usage: $P [options] <pattern matching regexes>
|
||||
|
||||
--input => MAINTAINERS file to read (default: MAINTAINERS)
|
||||
--output => sorted MAINTAINERS file to write (default: MAINTAINERS.new)
|
||||
--section => new sorted MAINTAINERS file to write to (default: SECTION.new)
|
||||
|
||||
If <pattern match regexes> exist, then the sections that match the
|
||||
regexes are not written to the output file but are written to the
|
||||
section file.
|
||||
|
||||
EOT
|
||||
}
|
||||
|
||||
# sort comparison functions
|
||||
sub by_category($$) {
|
||||
my ($a, $b) = @_;
|
||||
@@ -56,13 +91,20 @@ sub trim {
|
||||
sub alpha_output {
|
||||
my ($hashref, $filename) = (@_);
|
||||
|
||||
return if ! scalar(keys %$hashref);
|
||||
|
||||
open(my $file, '>', "$filename") or die "$P: $filename: open failed - $!\n";
|
||||
my $separator;
|
||||
foreach my $key (sort by_category keys %$hashref) {
|
||||
if ($key eq " ") {
|
||||
chomp $$hashref{$key};
|
||||
print $file $$hashref{$key};
|
||||
} else {
|
||||
print $file "\n" . $key . "\n";
|
||||
if (! defined $separator) {
|
||||
$separator = "\n";
|
||||
} else {
|
||||
print $file $separator;
|
||||
}
|
||||
print $file $key . "\n";
|
||||
foreach my $pattern (sort by_pattern split('\n', %$hashref{$key})) {
|
||||
print $file ($pattern . "\n");
|
||||
}
|
||||
@@ -112,7 +154,7 @@ sub file_input {
|
||||
my %hash;
|
||||
my %new_hash;
|
||||
|
||||
file_input(\%hash, "MAINTAINERS");
|
||||
file_input(\%hash, $input_file);
|
||||
|
||||
foreach my $type (@ARGV) {
|
||||
foreach my $key (keys %hash) {
|
||||
@@ -123,7 +165,7 @@ foreach my $type (@ARGV) {
|
||||
}
|
||||
}
|
||||
|
||||
alpha_output(\%hash, "MAINTAINERS.new");
|
||||
alpha_output(\%new_hash, "SECTION.new");
|
||||
alpha_output(\%hash, $output_file);
|
||||
alpha_output(\%new_hash, $output_section);
|
||||
|
||||
exit(0);
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
subdir-y := mdp genheaders
|
||||
subdir- += mdp genheaders
|
||||
|
||||
@@ -1187,6 +1187,10 @@ unknonw||unknown
|
||||
unknow||unknown
|
||||
unkown||unknown
|
||||
unneded||unneeded
|
||||
unneccecary||unnecessary
|
||||
unneccesary||unnecessary
|
||||
unneccessary||unnecessary
|
||||
unnecesary||unnecessary
|
||||
unneedingly||unnecessarily
|
||||
unnsupported||unsupported
|
||||
unmached||unmatched
|
||||
|
||||
Reference in New Issue
Block a user