aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Kbuild.include10
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/Makefile.build44
-rw-r--r--scripts/Makefile.extrawarn4
-rw-r--r--scripts/Makefile.gcc-plugins10
-rw-r--r--scripts/Makefile.lib2
-rw-r--r--scripts/asn1_compiler.c2
-rwxr-xr-xscripts/checkpatch.pl11
-rw-r--r--scripts/dtc/Makefile9
-rw-r--r--scripts/dtc/Makefile.dtc4
-rw-r--r--scripts/dtc/checks.c143
-rw-r--r--scripts/dtc/data.c4
-rw-r--r--scripts/dtc/dtc-parser.y16
-rw-r--r--scripts/dtc/dtc.c11
-rw-r--r--scripts/dtc/dtc.h13
-rw-r--r--scripts/dtc/flattree.c2
-rw-r--r--scripts/dtc/libfdt/fdt.c81
-rw-r--r--scripts/dtc/libfdt/fdt_addresses.c35
-rw-r--r--scripts/dtc/libfdt/fdt_overlay.c6
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c199
-rw-r--r--scripts/dtc/libfdt/fdt_rw.c28
-rw-r--r--scripts/dtc/libfdt/fdt_sw.c109
-rw-r--r--scripts/dtc/libfdt/libfdt.h76
-rw-r--r--scripts/dtc/libfdt/libfdt_env.h1
-rw-r--r--scripts/dtc/libfdt/libfdt_internal.h5
-rw-r--r--scripts/dtc/livetree.c12
-rw-r--r--scripts/dtc/treesource.c225
-rwxr-xr-xscripts/dtc/update-dtc-source.sh2
-rw-r--r--scripts/dtc/util.c23
-rw-r--r--scripts/dtc/util.h20
-rw-r--r--scripts/dtc/version_gen.h2
-rw-r--r--scripts/dtc/yamltree.c247
-rw-r--r--scripts/gcc-plugins/Kconfig51
-rw-r--r--scripts/gcc-plugins/stackleak_plugin.c427
-rw-r--r--scripts/kallsyms.c6
-rw-r--r--scripts/kconfig/Makefile16
-rw-r--r--scripts/kconfig/conf.c7
-rwxr-xr-xscripts/kconfig/merge_config.sh6
-rwxr-xr-xscripts/mkmakefile22
-rw-r--r--scripts/mod/file2alias.c26
-rwxr-xr-xscripts/tags.sh2
41 files changed, 1568 insertions, 354 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 8aeb60eb6ee3..bb015551c2d9 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -140,17 +140,9 @@ cc-option-yn = $(call try-run,\
140cc-disable-warning = $(call try-run,\ 140cc-disable-warning = $(call try-run,\
141 $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) 141 $(CC) -Werror $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1)))
142 142
143# cc-name
144# Expands to either gcc or clang
145cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc)
146
147# cc-version 143# cc-version
148cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) 144cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
149 145
150# cc-fullversion
151cc-fullversion = $(shell $(CONFIG_SHELL) \
152 $(srctree)/scripts/gcc-version.sh -p $(CC))
153
154# cc-ifversion 146# cc-ifversion
155# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) 147# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
156cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) 148cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4))
@@ -195,7 +187,7 @@ modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj
195# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= 187# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
196# Usage: 188# Usage:
197# $(Q)$(MAKE) $(dtbinst)=dir 189# $(Q)$(MAKE) $(dtbinst)=dir
198dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj 190dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj
199 191
200### 192###
201# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= 193# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=
diff --git a/scripts/Makefile b/scripts/Makefile
index 61affa300d25..ece52ff20171 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -39,8 +39,7 @@ build_unifdef: $(obj)/unifdef
39subdir-$(CONFIG_MODVERSIONS) += genksyms 39subdir-$(CONFIG_MODVERSIONS) += genksyms
40subdir-y += mod 40subdir-y += mod
41subdir-$(CONFIG_SECURITY_SELINUX) += selinux 41subdir-$(CONFIG_SECURITY_SELINUX) += selinux
42subdir-$(CONFIG_DTC) += dtc
43subdir-$(CONFIG_GDB_SCRIPTS) += gdb 42subdir-$(CONFIG_GDB_SCRIPTS) += gdb
44 43
45# Let clean descend into subdirs 44# Let clean descend into subdirs
46subdir- += basic kconfig package gcc-plugins 45subdir- += basic dtc kconfig package gcc-plugins
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 54da4b070db3..a8e7ba9f73e8 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -36,21 +36,11 @@ subdir-ccflags-y :=
36 36
37include scripts/Kbuild.include 37include scripts/Kbuild.include
38 38
39# For backward compatibility check that these variables do not change
40save-cflags := $(CFLAGS)
41
42# The filename Kbuild has precedence over Makefile 39# The filename Kbuild has precedence over Makefile
43kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) 40kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
44kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) 41kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
45include $(kbuild-file) 42include $(kbuild-file)
46 43
47# If the save-* variables changed error out
48ifeq ($(KBUILD_NOPEDANTIC),)
49 ifneq ("$(save-cflags)","$(CFLAGS)")
50 $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y)
51 endif
52endif
53
54include scripts/Makefile.lib 44include scripts/Makefile.lib
55 45
56# Do not include host rules unless needed 46# Do not include host rules unless needed
@@ -83,14 +73,12 @@ __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
83 @: 73 @:
84 74
85# Linus' kernel sanity checking tool 75# Linus' kernel sanity checking tool
86ifneq ($(KBUILD_CHECKSRC),0) 76ifeq ($(KBUILD_CHECKSRC),1)
87 ifeq ($(KBUILD_CHECKSRC),2) 77 quiet_cmd_checksrc = CHECK $<
88 quiet_cmd_force_checksrc = CHECK $< 78 cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
89 cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; 79else ifeq ($(KBUILD_CHECKSRC),2)
90 else 80 quiet_cmd_force_checksrc = CHECK $<
91 quiet_cmd_checksrc = CHECK $< 81 cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
92 cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
93 endif
94endif 82endif
95 83
96ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) 84ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),)
@@ -495,28 +483,12 @@ targets += $(obj)/lib-ksyms.o
495 483
496endif 484endif
497 485
498#
499# Rule to link composite objects
500#
501# Composite objects are specified in kbuild makefile as follows:
502# <composite-object>-objs := <list of .o files>
503# or
504# <composite-object>-y := <list of .o files>
505# or
506# <composite-object>-m := <list of .o files>
507# The -m syntax only works if <composite object> is a module
508link_multi_deps = \
509$(filter $(addprefix $(obj)/, \
510$($(subst $(obj)/,,$(@:.o=-objs))) \
511$($(subst $(obj)/,,$(@:.o=-y))) \
512$($(subst $(obj)/,,$(@:.o=-m)))), $^)
513
514quiet_cmd_link_multi-m = LD [M] $@ 486quiet_cmd_link_multi-m = LD [M] $@
515cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) 487cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(filter %.o,$^) $(cmd_secanalysis)
516 488
517$(multi-used-m): FORCE 489$(multi-used-m): FORCE
518 $(call if_changed,link_multi-m) 490 $(call if_changed,link_multi-m)
519 @{ echo $(@:.o=.ko); echo $(link_multi_deps); \ 491 @{ echo $(@:.o=.ko); echo $(filter %.o,$^); \
520 $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) 492 $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod)
521$(call multi_depend, $(multi-used-m), .o, -objs -y -m) 493$(call multi_depend, $(multi-used-m), .o, -objs -y -m)
522 494
diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn
index 8d5357053f86..768306add591 100644
--- a/scripts/Makefile.extrawarn
+++ b/scripts/Makefile.extrawarn
@@ -29,6 +29,7 @@ warning-1 += $(call cc-option, -Wmissing-include-dirs)
29warning-1 += $(call cc-option, -Wunused-but-set-variable) 29warning-1 += $(call cc-option, -Wunused-but-set-variable)
30warning-1 += $(call cc-option, -Wunused-const-variable) 30warning-1 += $(call cc-option, -Wunused-const-variable)
31warning-1 += $(call cc-option, -Wpacked-not-aligned) 31warning-1 += $(call cc-option, -Wpacked-not-aligned)
32warning-1 += $(call cc-option, -Wstringop-truncation)
32warning-1 += $(call cc-disable-warning, missing-field-initializers) 33warning-1 += $(call cc-disable-warning, missing-field-initializers)
33warning-1 += $(call cc-disable-warning, sign-compare) 34warning-1 += $(call cc-disable-warning, sign-compare)
34 35
@@ -52,7 +53,6 @@ warning-3 += -Wpointer-arith
52warning-3 += -Wredundant-decls 53warning-3 += -Wredundant-decls
53warning-3 += -Wswitch-default 54warning-3 += -Wswitch-default
54warning-3 += $(call cc-option, -Wpacked-bitfield-compat) 55warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
55warning-3 += $(call cc-option, -Wvla)
56 56
57warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) 57warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
58warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) 58warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
@@ -65,7 +65,7 @@ endif
65KBUILD_CFLAGS += $(warning) 65KBUILD_CFLAGS += $(warning)
66else 66else
67 67
68ifeq ($(cc-name),clang) 68ifdef CONFIG_CC_IS_CLANG
69KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides) 69KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides)
70KBUILD_CFLAGS += $(call cc-disable-warning, unused-value) 70KBUILD_CFLAGS += $(call cc-disable-warning, unused-value)
71KBUILD_CFLAGS += $(call cc-disable-warning, format) 71KBUILD_CFLAGS += $(call cc-disable-warning, format)
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 0a482f341576..46c5c6809806 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -26,6 +26,16 @@ gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT) \
26gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \ 26gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \
27 += -fplugin-arg-randomize_layout_plugin-performance-mode 27 += -fplugin-arg-randomize_layout_plugin-performance-mode
28 28
29gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so
30gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
31 += -DSTACKLEAK_PLUGIN
32gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
33 += -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE)
34ifdef CONFIG_GCC_PLUGIN_STACKLEAK
35 DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable
36endif
37export DISABLE_STACKLEAK_PLUGIN
38
29# All the plugin CFLAGS are collected here in case a build target needs to 39# All the plugin CFLAGS are collected here in case a build target needs to
30# filter them out of the KBUILD_CFLAGS. 40# filter them out of the KBUILD_CFLAGS.
31GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) 41GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 61e596650ed3..8fe4468f9bda 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -283,7 +283,7 @@ $(obj)/%.dtb.S: $(obj)/%.dtb FORCE
283 283
284quiet_cmd_dtc = DTC $@ 284quiet_cmd_dtc = DTC $@
285cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ 285cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
286 $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ 286 $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
287 $(DTC) -O dtb -o $@ -b 0 \ 287 $(DTC) -O dtb -o $@ -b 0 \
288 $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \ 288 $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \
289 -d $(depfile).dtc.tmp $(dtc-tmp) ; \ 289 -d $(depfile).dtc.tmp $(dtc-tmp) ; \
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c
index c146020fc783..1b28787028d3 100644
--- a/scripts/asn1_compiler.c
+++ b/scripts/asn1_compiler.c
@@ -413,7 +413,7 @@ static void tokenise(char *buffer, char *end)
413 413
414 /* Handle string tokens */ 414 /* Handle string tokens */
415 if (isalpha(*p)) { 415 if (isalpha(*p)) {
416 const char **dir, *start = p; 416 const char **dir;
417 417
418 /* Can be a directive, type name or element 418 /* Can be a directive, type name or element
419 * name. Find the end of the name. 419 * name. Find the end of the name.
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 161b0224d6ae..c883ec55654f 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -4934,17 +4934,6 @@ sub process {
4934 while ($line =~ m{($Constant|$Lval)}g) { 4934 while ($line =~ m{($Constant|$Lval)}g) {
4935 my $var = $1; 4935 my $var = $1;
4936 4936
4937#gcc binary extension
4938 if ($var =~ /^$Binary$/) {
4939 if (WARN("GCC_BINARY_CONSTANT",
4940 "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) &&
4941 $fix) {
4942 my $hexval = sprintf("0x%x", oct($var));
4943 $fixed[$fixlinenr] =~
4944 s/\b$var\b/$hexval/;
4945 }
4946 }
4947
4948#CamelCase 4937#CamelCase
4949 if ($var !~ /^$Constant$/ && 4938 if ($var !~ /^$Constant$/ &&
4950 $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && 4939 $var =~ /[A-Z][a-z]|[a-z][A-Z]/ &&
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 1c943e03eaf2..056d5da6c477 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -1,7 +1,7 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2# scripts/dtc makefile 2# scripts/dtc makefile
3 3
4hostprogs-y := dtc 4hostprogs-$(CONFIG_DTC) := dtc
5always := $(hostprogs-y) 5always := $(hostprogs-y)
6 6
7dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ 7dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
@@ -11,6 +11,13 @@ dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
11# Source files need to get at the userspace version of libfdt_env.h to compile 11# Source files need to get at the userspace version of libfdt_env.h to compile
12HOST_EXTRACFLAGS := -I$(src)/libfdt 12HOST_EXTRACFLAGS := -I$(src)/libfdt
13 13
14ifeq ($(wildcard /usr/include/yaml.h),)
15HOST_EXTRACFLAGS += -DNO_YAML
16else
17dtc-objs += yamltree.o
18HOSTLDLIBS_dtc := -lyaml
19endif
20
14# Generated files need one more search path to include headers in source tree 21# Generated files need one more search path to include headers in source tree
15HOSTCFLAGS_dtc-lexer.lex.o := -I$(src) 22HOSTCFLAGS_dtc-lexer.lex.o := -I$(src)
16HOSTCFLAGS_dtc-parser.tab.o := -I$(src) 23HOSTCFLAGS_dtc-parser.tab.o := -I$(src)
diff --git a/scripts/dtc/Makefile.dtc b/scripts/dtc/Makefile.dtc
index bece49b35535..d4375630a7f7 100644
--- a/scripts/dtc/Makefile.dtc
+++ b/scripts/dtc/Makefile.dtc
@@ -14,5 +14,9 @@ DTC_SRCS = \
14 treesource.c \ 14 treesource.c \
15 util.c 15 util.c
16 16
17ifneq ($(NO_YAML),1)
18DTC_SRCS += yamltree.c
19endif
20
17DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c 21DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
18DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) 22DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index a2cc1036c915..9c9b0c328af6 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -962,6 +962,143 @@ static void check_simple_bus_reg(struct check *c, struct dt_info *dti, struct no
962} 962}
963WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge); 963WARNING(simple_bus_reg, check_simple_bus_reg, NULL, &reg_format, &simple_bus_bridge);
964 964
965static const struct bus_type i2c_bus = {
966 .name = "i2c-bus",
967};
968
969static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
970{
971 if (strprefixeq(node->name, node->basenamelen, "i2c-bus") ||
972 strprefixeq(node->name, node->basenamelen, "i2c-arb")) {
973 node->bus = &i2c_bus;
974 } else if (strprefixeq(node->name, node->basenamelen, "i2c")) {
975 struct node *child;
976 for_each_child(node, child) {
977 if (strprefixeq(child->name, node->basenamelen, "i2c-bus"))
978 return;
979 }
980 node->bus = &i2c_bus;
981 } else
982 return;
983
984 if (!node->children)
985 return;
986
987 if (node_addr_cells(node) != 1)
988 FAIL(c, dti, node, "incorrect #address-cells for I2C bus");
989 if (node_size_cells(node) != 0)
990 FAIL(c, dti, node, "incorrect #size-cells for I2C bus");
991
992}
993WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells);
994
995static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
996{
997 struct property *prop;
998 const char *unitname = get_unitname(node);
999 char unit_addr[17];
1000 uint32_t reg = 0;
1001 int len;
1002 cell_t *cells = NULL;
1003
1004 if (!node->parent || (node->parent->bus != &i2c_bus))
1005 return;
1006
1007 prop = get_property(node, "reg");
1008 if (prop)
1009 cells = (cell_t *)prop->val.val;
1010
1011 if (!cells) {
1012 FAIL(c, dti, node, "missing or empty reg property");
1013 return;
1014 }
1015
1016 reg = fdt32_to_cpu(*cells);
1017 snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
1018 if (!streq(unitname, unit_addr))
1019 FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"",
1020 unit_addr);
1021
1022 for (len = prop->val.len; len > 0; len -= 4) {
1023 reg = fdt32_to_cpu(*(cells++));
1024 if (reg > 0x3ff)
1025 FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"",
1026 reg);
1027
1028 }
1029}
1030WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, &reg_format, &i2c_bus_bridge);
1031
1032static const struct bus_type spi_bus = {
1033 .name = "spi-bus",
1034};
1035
1036static void check_spi_bus_bridge(struct check *c, struct dt_info *dti, struct node *node)
1037{
1038
1039 if (strprefixeq(node->name, node->basenamelen, "spi")) {
1040 node->bus = &spi_bus;
1041 } else {
1042 /* Try to detect SPI buses which don't have proper node name */
1043 struct node *child;
1044
1045 if (node_addr_cells(node) != 1 || node_size_cells(node) != 0)
1046 return;
1047
1048 for_each_child(node, child) {
1049 struct property *prop;
1050 for_each_property(child, prop) {
1051 if (strprefixeq(prop->name, 4, "spi-")) {
1052 node->bus = &spi_bus;
1053 break;
1054 }
1055 }
1056 if (node->bus == &spi_bus)
1057 break;
1058 }
1059
1060 if (node->bus == &spi_bus && get_property(node, "reg"))
1061 FAIL(c, dti, node, "node name for SPI buses should be 'spi'");
1062 }
1063 if (node->bus != &spi_bus || !node->children)
1064 return;
1065
1066 if (node_addr_cells(node) != 1)
1067 FAIL(c, dti, node, "incorrect #address-cells for SPI bus");
1068 if (node_size_cells(node) != 0)
1069 FAIL(c, dti, node, "incorrect #size-cells for SPI bus");
1070
1071}
1072WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells);
1073
1074static void check_spi_bus_reg(struct check *c, struct dt_info *dti, struct node *node)
1075{
1076 struct property *prop;
1077 const char *unitname = get_unitname(node);
1078 char unit_addr[9];
1079 uint32_t reg = 0;
1080 cell_t *cells = NULL;
1081
1082 if (!node->parent || (node->parent->bus != &spi_bus))
1083 return;
1084
1085 prop = get_property(node, "reg");
1086 if (prop)
1087 cells = (cell_t *)prop->val.val;
1088
1089 if (!cells) {
1090 FAIL(c, dti, node, "missing or empty reg property");
1091 return;
1092 }
1093
1094 reg = fdt32_to_cpu(*cells);
1095 snprintf(unit_addr, sizeof(unit_addr), "%x", reg);
1096 if (!streq(unitname, unit_addr))
1097 FAIL(c, dti, node, "SPI bus unit address format error, expected \"%s\"",
1098 unit_addr);
1099}
1100WARNING(spi_bus_reg, check_spi_bus_reg, NULL, &reg_format, &spi_bus_bridge);
1101
965static void check_unit_address_format(struct check *c, struct dt_info *dti, 1102static void check_unit_address_format(struct check *c, struct dt_info *dti,
966 struct node *node) 1103 struct node *node)
967{ 1104{
@@ -1582,6 +1719,12 @@ static struct check *check_table[] = {
1582 &simple_bus_bridge, 1719 &simple_bus_bridge,
1583 &simple_bus_reg, 1720 &simple_bus_reg,
1584 1721
1722 &i2c_bus_bridge,
1723 &i2c_bus_reg,
1724
1725 &spi_bus_bridge,
1726 &spi_bus_reg,
1727
1585 &avoid_default_addr_size, 1728 &avoid_default_addr_size,
1586 &avoid_unnecessary_addr_size, 1729 &avoid_unnecessary_addr_size,
1587 &unique_unit_address, 1730 &unique_unit_address,
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c
index aa37a16c8891..4a204145cc7b 100644
--- a/scripts/dtc/data.c
+++ b/scripts/dtc/data.c
@@ -74,7 +74,8 @@ struct data data_copy_escape_string(const char *s, int len)
74 struct data d; 74 struct data d;
75 char *q; 75 char *q;
76 76
77 d = data_grow_for(empty_data, len + 1); 77 d = data_add_marker(empty_data, TYPE_STRING, NULL);
78 d = data_grow_for(d, len + 1);
78 79
79 q = d.val; 80 q = d.val;
80 while (i < len) { 81 while (i < len) {
@@ -94,6 +95,7 @@ struct data data_copy_file(FILE *f, size_t maxlen)
94{ 95{
95 struct data d = empty_data; 96 struct data d = empty_data;
96 97
98 d = data_add_marker(d, TYPE_NONE, NULL);
97 while (!feof(f) && (d.len < maxlen)) { 99 while (!feof(f) && (d.len < maxlen)) {
98 size_t chunksize, ret; 100 size_t chunksize, ret;
99 101
diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y
index 011a5b25539a..dd70ebf386f4 100644
--- a/scripts/dtc/dtc-parser.y
+++ b/scripts/dtc/dtc-parser.y
@@ -287,6 +287,7 @@ propdata:
287 } 287 }
288 | propdataprefix DT_REF 288 | propdataprefix DT_REF
289 { 289 {
290 $1 = data_add_marker($1, TYPE_STRING, $2);
290 $$ = data_add_marker($1, REF_PATH, $2); 291 $$ = data_add_marker($1, REF_PATH, $2);
291 } 292 }
292 | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')' 293 | propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
@@ -340,22 +341,27 @@ arrayprefix:
340 DT_BITS DT_LITERAL '<' 341 DT_BITS DT_LITERAL '<'
341 { 342 {
342 unsigned long long bits; 343 unsigned long long bits;
344 enum markertype type = TYPE_UINT32;
343 345
344 bits = $2; 346 bits = $2;
345 347
346 if ((bits != 8) && (bits != 16) && 348 switch (bits) {
347 (bits != 32) && (bits != 64)) { 349 case 8: type = TYPE_UINT8; break;
350 case 16: type = TYPE_UINT16; break;
351 case 32: type = TYPE_UINT32; break;
352 case 64: type = TYPE_UINT64; break;
353 default:
348 ERROR(&@2, "Array elements must be" 354 ERROR(&@2, "Array elements must be"
349 " 8, 16, 32 or 64-bits"); 355 " 8, 16, 32 or 64-bits");
350 bits = 32; 356 bits = 32;
351 } 357 }
352 358
353 $$.data = empty_data; 359 $$.data = data_add_marker(empty_data, type, NULL);
354 $$.bits = bits; 360 $$.bits = bits;
355 } 361 }
356 | '<' 362 | '<'
357 { 363 {
358 $$.data = empty_data; 364 $$.data = data_add_marker(empty_data, TYPE_UINT32, NULL);
359 $$.bits = 32; 365 $$.bits = 32;
360 } 366 }
361 | arrayprefix integer_prim 367 | arrayprefix integer_prim
@@ -499,7 +505,7 @@ integer_unary:
499bytestring: 505bytestring:
500 /* empty */ 506 /* empty */
501 { 507 {
502 $$ = empty_data; 508 $$ = data_add_marker(empty_data, TYPE_UINT8, NULL);
503 } 509 }
504 | bytestring DT_BYTE 510 | bytestring DT_BYTE
505 { 511 {
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index c36994e6eac5..64134aadb997 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -95,6 +95,9 @@ static const char * const usage_opts_help[] = {
95 "\n\tOutput formats are:\n" 95 "\n\tOutput formats are:\n"
96 "\t\tdts - device tree source text\n" 96 "\t\tdts - device tree source text\n"
97 "\t\tdtb - device tree blob\n" 97 "\t\tdtb - device tree blob\n"
98#ifndef NO_YAML
99 "\t\tyaml - device tree encoded as YAML\n"
100#endif
98 "\t\tasm - assembler source", 101 "\t\tasm - assembler source",
99 "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)", 102 "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
100 "\n\tOutput dependency file", 103 "\n\tOutput dependency file",
@@ -128,6 +131,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback)
128 return fallback; 131 return fallback;
129 if (!strcasecmp(s, ".dts")) 132 if (!strcasecmp(s, ".dts"))
130 return "dts"; 133 return "dts";
134 if (!strcasecmp(s, ".yaml"))
135 return "yaml";
131 if (!strcasecmp(s, ".dtb")) 136 if (!strcasecmp(s, ".dtb"))
132 return "dtb"; 137 return "dtb";
133 return fallback; 138 return fallback;
@@ -350,6 +355,12 @@ int main(int argc, char *argv[])
350 355
351 if (streq(outform, "dts")) { 356 if (streq(outform, "dts")) {
352 dt_to_source(outf, dti); 357 dt_to_source(outf, dti);
358#ifndef NO_YAML
359 } else if (streq(outform, "yaml")) {
360 if (!streq(inform, "dts"))
361 die("YAML output format requires dts input format\n");
362 dt_to_yaml(outf, dti);
363#endif
353 } else if (streq(outform, "dtb")) { 364 } else if (streq(outform, "dtb")) {
354 dt_to_blob(outf, dti, outversion); 365 dt_to_blob(outf, dti, outversion);
355 } else if (streq(outform, "asm")) { 366 } else if (streq(outform, "asm")) {
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 6d667701ab6a..cbe541525c2c 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -74,10 +74,17 @@ typedef uint32_t cell_t;
74 74
75/* Data blobs */ 75/* Data blobs */
76enum markertype { 76enum markertype {
77 TYPE_NONE,
77 REF_PHANDLE, 78 REF_PHANDLE,
78 REF_PATH, 79 REF_PATH,
79 LABEL, 80 LABEL,
81 TYPE_UINT8,
82 TYPE_UINT16,
83 TYPE_UINT32,
84 TYPE_UINT64,
85 TYPE_STRING,
80}; 86};
87extern const char *markername(enum markertype markertype);
81 88
82struct marker { 89struct marker {
83 enum markertype type; 90 enum markertype type;
@@ -101,6 +108,8 @@ struct data {
101 for_each_marker(m) \ 108 for_each_marker(m) \
102 if ((m)->type == (t)) 109 if ((m)->type == (t))
103 110
111size_t type_marker_length(struct marker *m);
112
104void data_free(struct data d); 113void data_free(struct data d);
105 114
106struct data data_grow_for(struct data d, int xlen); 115struct data data_grow_for(struct data d, int xlen);
@@ -290,6 +299,10 @@ struct dt_info *dt_from_blob(const char *fname);
290void dt_to_source(FILE *f, struct dt_info *dti); 299void dt_to_source(FILE *f, struct dt_info *dti);
291struct dt_info *dt_from_source(const char *f); 300struct dt_info *dt_from_source(const char *f);
292 301
302/* YAML source */
303
304void dt_to_yaml(FILE *f, struct dt_info *dti);
305
293/* FS trees */ 306/* FS trees */
294 307
295struct dt_info *dt_from_fs(const char *dirname); 308struct dt_info *dt_from_fs(const char *dirname);
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index 8d268fb785db..851ea87dbc0f 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -393,7 +393,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
393 padlen = 0; 393 padlen = 0;
394 if (quiet < 1) 394 if (quiet < 1)
395 fprintf(stderr, 395 fprintf(stderr,
396 "Warning: blob size %d >= minimum size %d\n", 396 "Warning: blob size %"PRIu32" >= minimum size %d\n",
397 fdt32_to_cpu(fdt.totalsize), minsize); 397 fdt32_to_cpu(fdt.totalsize), minsize);
398 } 398 }
399 } 399 }
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 7855a1787763..ae03b1112961 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -55,7 +55,12 @@
55 55
56#include "libfdt_internal.h" 56#include "libfdt_internal.h"
57 57
58int fdt_check_header(const void *fdt) 58/*
59 * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
60 * that the given buffer contains what appears to be a flattened
61 * device tree with sane information in its header.
62 */
63int fdt_ro_probe_(const void *fdt)
59{ 64{
60 if (fdt_magic(fdt) == FDT_MAGIC) { 65 if (fdt_magic(fdt) == FDT_MAGIC) {
61 /* Complete tree */ 66 /* Complete tree */
@@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt)
74 return 0; 79 return 0;
75} 80}
76 81
82static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
83{
84 return (off >= hdrsize) && (off <= totalsize);
85}
86
87static int check_block_(uint32_t hdrsize, uint32_t totalsize,
88 uint32_t base, uint32_t size)
89{
90 if (!check_off_(hdrsize, totalsize, base))
91 return 0; /* block start out of bounds */
92 if ((base + size) < base)
93 return 0; /* overflow */
94 if (!check_off_(hdrsize, totalsize, base + size))
95 return 0; /* block end out of bounds */
96 return 1;
97}
98
99size_t fdt_header_size_(uint32_t version)
100{
101 if (version <= 1)
102 return FDT_V1_SIZE;
103 else if (version <= 2)
104 return FDT_V2_SIZE;
105 else if (version <= 3)
106 return FDT_V3_SIZE;
107 else if (version <= 16)
108 return FDT_V16_SIZE;
109 else
110 return FDT_V17_SIZE;
111}
112
113int fdt_check_header(const void *fdt)
114{
115 size_t hdrsize;
116
117 if (fdt_magic(fdt) != FDT_MAGIC)
118 return -FDT_ERR_BADMAGIC;
119 hdrsize = fdt_header_size(fdt);
120 if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
121 || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
122 return -FDT_ERR_BADVERSION;
123 if (fdt_version(fdt) < fdt_last_comp_version(fdt))
124 return -FDT_ERR_BADVERSION;
125
126 if ((fdt_totalsize(fdt) < hdrsize)
127 || (fdt_totalsize(fdt) > INT_MAX))
128 return -FDT_ERR_TRUNCATED;
129
130 /* Bounds check memrsv block */
131 if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
132 return -FDT_ERR_TRUNCATED;
133
134 /* Bounds check structure block */
135 if (fdt_version(fdt) < 17) {
136 if (!check_off_(hdrsize, fdt_totalsize(fdt),
137 fdt_off_dt_struct(fdt)))
138 return -FDT_ERR_TRUNCATED;
139 } else {
140 if (!check_block_(hdrsize, fdt_totalsize(fdt),
141 fdt_off_dt_struct(fdt),
142 fdt_size_dt_struct(fdt)))
143 return -FDT_ERR_TRUNCATED;
144 }
145
146 /* Bounds check strings block */
147 if (!check_block_(hdrsize, fdt_totalsize(fdt),
148 fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
149 return -FDT_ERR_TRUNCATED;
150
151 return 0;
152}
153
77const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) 154const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
78{ 155{
79 unsigned absoffset = offset + fdt_off_dt_struct(fdt); 156 unsigned absoffset = offset + fdt_off_dt_struct(fdt);
@@ -244,7 +321,7 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
244 321
245int fdt_move(const void *fdt, void *buf, int bufsize) 322int fdt_move(const void *fdt, void *buf, int bufsize)
246{ 323{
247 FDT_CHECK_HEADER(fdt); 324 FDT_RO_PROBE(fdt);
248 325
249 if (fdt_totalsize(fdt) > bufsize) 326 if (fdt_totalsize(fdt) > bufsize)
250 return -FDT_ERR_NOSPACE; 327 return -FDT_ERR_NOSPACE;
diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c
index eff4dbcc729d..49537b578d03 100644
--- a/scripts/dtc/libfdt/fdt_addresses.c
+++ b/scripts/dtc/libfdt/fdt_addresses.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * libfdt - Flat Device Tree manipulation 2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> 3 * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
4 * Copyright (C) 2018 embedded brains GmbH
4 * 5 *
5 * libfdt is dual licensed: you can use it either under the terms of 6 * libfdt is dual licensed: you can use it either under the terms of
6 * the GPL, or the BSD license, at your option. 7 * the GPL, or the BSD license, at your option.
@@ -55,42 +56,32 @@
55 56
56#include "libfdt_internal.h" 57#include "libfdt_internal.h"
57 58
58int fdt_address_cells(const void *fdt, int nodeoffset) 59static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
59{ 60{
60 const fdt32_t *ac; 61 const fdt32_t *c;
61 int val; 62 int val;
62 int len; 63 int len;
63 64
64 ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); 65 c = fdt_getprop(fdt, nodeoffset, name, &len);
65 if (!ac) 66 if (!c)
66 return 2; 67 return 2;
67 68
68 if (len != sizeof(*ac)) 69 if (len != sizeof(*c))
69 return -FDT_ERR_BADNCELLS; 70 return -FDT_ERR_BADNCELLS;
70 71
71 val = fdt32_to_cpu(*ac); 72 val = fdt32_to_cpu(*c);
72 if ((val <= 0) || (val > FDT_MAX_NCELLS)) 73 if ((val <= 0) || (val > FDT_MAX_NCELLS))
73 return -FDT_ERR_BADNCELLS; 74 return -FDT_ERR_BADNCELLS;
74 75
75 return val; 76 return val;
76} 77}
77 78
78int fdt_size_cells(const void *fdt, int nodeoffset) 79int fdt_address_cells(const void *fdt, int nodeoffset)
79{ 80{
80 const fdt32_t *sc; 81 return fdt_cells(fdt, nodeoffset, "#address-cells");
81 int val; 82}
82 int len;
83
84 sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
85 if (!sc)
86 return 2;
87
88 if (len != sizeof(*sc))
89 return -FDT_ERR_BADNCELLS;
90
91 val = fdt32_to_cpu(*sc);
92 if ((val < 0) || (val > FDT_MAX_NCELLS))
93 return -FDT_ERR_BADNCELLS;
94 83
95 return val; 84int fdt_size_cells(const void *fdt, int nodeoffset)
85{
86 return fdt_cells(fdt, nodeoffset, "#size-cells");
96} 87}
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index bf75388ec9a2..5fdab6c6371d 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -697,7 +697,7 @@ static int get_path_len(const void *fdt, int nodeoffset)
697 int len = 0, namelen; 697 int len = 0, namelen;
698 const char *name; 698 const char *name;
699 699
700 FDT_CHECK_HEADER(fdt); 700 FDT_RO_PROBE(fdt);
701 701
702 for (;;) { 702 for (;;) {
703 name = fdt_get_name(fdt, nodeoffset, &namelen); 703 name = fdt_get_name(fdt, nodeoffset, &namelen);
@@ -866,8 +866,8 @@ int fdt_overlay_apply(void *fdt, void *fdto)
866 uint32_t delta = fdt_get_max_phandle(fdt); 866 uint32_t delta = fdt_get_max_phandle(fdt);
867 int ret; 867 int ret;
868 868
869 FDT_CHECK_HEADER(fdt); 869 FDT_RO_PROBE(fdt);
870 FDT_CHECK_HEADER(fdto); 870 FDT_RO_PROBE(fdto);
871 871
872 ret = overlay_adjust_local_phandles(fdto, delta); 872 ret = overlay_adjust_local_phandles(fdto, delta);
873 if (ret) 873 if (ret)
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index dfb3236da388..eafc14282892 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -76,17 +76,72 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
76 return 0; 76 return 0;
77} 77}
78 78
79const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
80{
81 uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
82 size_t len;
83 int err;
84 const char *s, *n;
85
86 err = fdt_ro_probe_(fdt);
87 if (err != 0)
88 goto fail;
89
90 err = -FDT_ERR_BADOFFSET;
91 if (absoffset >= fdt_totalsize(fdt))
92 goto fail;
93 len = fdt_totalsize(fdt) - absoffset;
94
95 if (fdt_magic(fdt) == FDT_MAGIC) {
96 if (stroffset < 0)
97 goto fail;
98 if (fdt_version(fdt) >= 17) {
99 if (stroffset >= fdt_size_dt_strings(fdt))
100 goto fail;
101 if ((fdt_size_dt_strings(fdt) - stroffset) < len)
102 len = fdt_size_dt_strings(fdt) - stroffset;
103 }
104 } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
105 if ((stroffset >= 0)
106 || (stroffset < -fdt_size_dt_strings(fdt)))
107 goto fail;
108 if ((-stroffset) < len)
109 len = -stroffset;
110 } else {
111 err = -FDT_ERR_INTERNAL;
112 goto fail;
113 }
114
115 s = (const char *)fdt + absoffset;
116 n = memchr(s, '\0', len);
117 if (!n) {
118 /* missing terminating NULL */
119 err = -FDT_ERR_TRUNCATED;
120 goto fail;
121 }
122
123 if (lenp)
124 *lenp = n - s;
125 return s;
126
127fail:
128 if (lenp)
129 *lenp = err;
130 return NULL;
131}
132
79const char *fdt_string(const void *fdt, int stroffset) 133const char *fdt_string(const void *fdt, int stroffset)
80{ 134{
81 return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; 135 return fdt_get_string(fdt, stroffset, NULL);
82} 136}
83 137
84static int fdt_string_eq_(const void *fdt, int stroffset, 138static int fdt_string_eq_(const void *fdt, int stroffset,
85 const char *s, int len) 139 const char *s, int len)
86{ 140{
87 const char *p = fdt_string(fdt, stroffset); 141 int slen;
142 const char *p = fdt_get_string(fdt, stroffset, &slen);
88 143
89 return (strlen(p) == len) && (memcmp(p, s, len) == 0); 144 return p && (slen == len) && (memcmp(p, s, len) == 0);
90} 145}
91 146
92uint32_t fdt_get_max_phandle(const void *fdt) 147uint32_t fdt_get_max_phandle(const void *fdt)
@@ -115,21 +170,42 @@ uint32_t fdt_get_max_phandle(const void *fdt)
115 return 0; 170 return 0;
116} 171}
117 172
173static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
174{
175 int offset = n * sizeof(struct fdt_reserve_entry);
176 int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
177
178 if (absoffset < fdt_off_mem_rsvmap(fdt))
179 return NULL;
180 if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
181 return NULL;
182 return fdt_mem_rsv_(fdt, n);
183}
184
118int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) 185int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
119{ 186{
120 FDT_CHECK_HEADER(fdt); 187 const struct fdt_reserve_entry *re;
121 *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); 188
122 *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); 189 FDT_RO_PROBE(fdt);
190 re = fdt_mem_rsv(fdt, n);
191 if (!re)
192 return -FDT_ERR_BADOFFSET;
193
194 *address = fdt64_ld(&re->address);
195 *size = fdt64_ld(&re->size);
123 return 0; 196 return 0;
124} 197}
125 198
126int fdt_num_mem_rsv(const void *fdt) 199int fdt_num_mem_rsv(const void *fdt)
127{ 200{
128 int i = 0; 201 int i;
202 const struct fdt_reserve_entry *re;
129 203
130 while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) 204 for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
131 i++; 205 if (fdt64_ld(&re->size) == 0)
132 return i; 206 return i;
207 }
208 return -FDT_ERR_TRUNCATED;
133} 209}
134 210
135static int nextprop_(const void *fdt, int offset) 211static int nextprop_(const void *fdt, int offset)
@@ -161,7 +237,7 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
161{ 237{
162 int depth; 238 int depth;
163 239
164 FDT_CHECK_HEADER(fdt); 240 FDT_RO_PROBE(fdt);
165 241
166 for (depth = 0; 242 for (depth = 0;
167 (offset >= 0) && (depth >= 0); 243 (offset >= 0) && (depth >= 0);
@@ -187,7 +263,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
187 const char *p = path; 263 const char *p = path;
188 int offset = 0; 264 int offset = 0;
189 265
190 FDT_CHECK_HEADER(fdt); 266 FDT_RO_PROBE(fdt);
191 267
192 /* see if we have an alias */ 268 /* see if we have an alias */
193 if (*path != '/') { 269 if (*path != '/') {
@@ -237,7 +313,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
237 const char *nameptr; 313 const char *nameptr;
238 int err; 314 int err;
239 315
240 if (((err = fdt_check_header(fdt)) != 0) 316 if (((err = fdt_ro_probe_(fdt)) != 0)
241 || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) 317 || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
242 goto fail; 318 goto fail;
243 319
@@ -303,7 +379,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
303 prop = fdt_offset_ptr_(fdt, offset); 379 prop = fdt_offset_ptr_(fdt, offset);
304 380
305 if (lenp) 381 if (lenp)
306 *lenp = fdt32_to_cpu(prop->len); 382 *lenp = fdt32_ld(&prop->len);
307 383
308 return prop; 384 return prop;
309} 385}
@@ -340,7 +416,7 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
340 offset = -FDT_ERR_INTERNAL; 416 offset = -FDT_ERR_INTERNAL;
341 break; 417 break;
342 } 418 }
343 if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), 419 if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
344 name, namelen)) { 420 name, namelen)) {
345 if (poffset) 421 if (poffset)
346 *poffset = offset; 422 *poffset = offset;
@@ -393,7 +469,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
393 469
394 /* Handle realignment */ 470 /* Handle realignment */
395 if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && 471 if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
396 fdt32_to_cpu(prop->len) >= 8) 472 fdt32_ld(&prop->len) >= 8)
397 return prop->data + 4; 473 return prop->data + 4;
398 return prop->data; 474 return prop->data;
399} 475}
@@ -406,12 +482,22 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
406 prop = fdt_get_property_by_offset_(fdt, offset, lenp); 482 prop = fdt_get_property_by_offset_(fdt, offset, lenp);
407 if (!prop) 483 if (!prop)
408 return NULL; 484 return NULL;
409 if (namep) 485 if (namep) {
410 *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 486 const char *name;
487 int namelen;
488 name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
489 &namelen);
490 if (!name) {
491 if (lenp)
492 *lenp = namelen;
493 return NULL;
494 }
495 *namep = name;
496 }
411 497
412 /* Handle realignment */ 498 /* Handle realignment */
413 if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && 499 if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
414 fdt32_to_cpu(prop->len) >= 8) 500 fdt32_ld(&prop->len) >= 8)
415 return prop->data + 4; 501 return prop->data + 4;
416 return prop->data; 502 return prop->data;
417} 503}
@@ -436,7 +522,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
436 return 0; 522 return 0;
437 } 523 }
438 524
439 return fdt32_to_cpu(*php); 525 return fdt32_ld(php);
440} 526}
441 527
442const char *fdt_get_alias_namelen(const void *fdt, 528const char *fdt_get_alias_namelen(const void *fdt,
@@ -462,7 +548,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
462 int offset, depth, namelen; 548 int offset, depth, namelen;
463 const char *name; 549 const char *name;
464 550
465 FDT_CHECK_HEADER(fdt); 551 FDT_RO_PROBE(fdt);
466 552
467 if (buflen < 2) 553 if (buflen < 2)
468 return -FDT_ERR_NOSPACE; 554 return -FDT_ERR_NOSPACE;
@@ -514,7 +600,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
514 int offset, depth; 600 int offset, depth;
515 int supernodeoffset = -FDT_ERR_INTERNAL; 601 int supernodeoffset = -FDT_ERR_INTERNAL;
516 602
517 FDT_CHECK_HEADER(fdt); 603 FDT_RO_PROBE(fdt);
518 604
519 if (supernodedepth < 0) 605 if (supernodedepth < 0)
520 return -FDT_ERR_NOTFOUND; 606 return -FDT_ERR_NOTFOUND;
@@ -573,7 +659,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
573 const void *val; 659 const void *val;
574 int len; 660 int len;
575 661
576 FDT_CHECK_HEADER(fdt); 662 FDT_RO_PROBE(fdt);
577 663
578 /* FIXME: The algorithm here is pretty horrible: we scan each 664 /* FIXME: The algorithm here is pretty horrible: we scan each
579 * property of a node in fdt_getprop(), then if that didn't 665 * property of a node in fdt_getprop(), then if that didn't
@@ -599,7 +685,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
599 if ((phandle == 0) || (phandle == -1)) 685 if ((phandle == 0) || (phandle == -1))
600 return -FDT_ERR_BADPHANDLE; 686 return -FDT_ERR_BADPHANDLE;
601 687
602 FDT_CHECK_HEADER(fdt); 688 FDT_RO_PROBE(fdt);
603 689
604 /* FIXME: The algorithm here is pretty horrible: we 690 /* FIXME: The algorithm here is pretty horrible: we
605 * potentially scan each property of a node in 691 * potentially scan each property of a node in
@@ -752,7 +838,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
752{ 838{
753 int offset, err; 839 int offset, err;
754 840
755 FDT_CHECK_HEADER(fdt); 841 FDT_RO_PROBE(fdt);
756 842
757 /* FIXME: The algorithm here is pretty horrible: we scan each 843 /* FIXME: The algorithm here is pretty horrible: we scan each
758 * property of a node in fdt_node_check_compatible(), then if 844 * property of a node in fdt_node_check_compatible(), then if
@@ -771,3 +857,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
771 857
772 return offset; /* error from fdt_next_node() */ 858 return offset; /* error from fdt_next_node() */
773} 859}
860
861int fdt_check_full(const void *fdt, size_t bufsize)
862{
863 int err;
864 int num_memrsv;
865 int offset, nextoffset = 0;
866 uint32_t tag;
867 unsigned depth = 0;
868 const void *prop;
869 const char *propname;
870
871 if (bufsize < FDT_V1_SIZE)
872 return -FDT_ERR_TRUNCATED;
873 err = fdt_check_header(fdt);
874 if (err != 0)
875 return err;
876 if (bufsize < fdt_totalsize(fdt))
877 return -FDT_ERR_TRUNCATED;
878
879 num_memrsv = fdt_num_mem_rsv(fdt);
880 if (num_memrsv < 0)
881 return num_memrsv;
882
883 while (1) {
884 offset = nextoffset;
885 tag = fdt_next_tag(fdt, offset, &nextoffset);
886
887 if (nextoffset < 0)
888 return nextoffset;
889
890 switch (tag) {
891 case FDT_NOP:
892 break;
893
894 case FDT_END:
895 if (depth != 0)
896 return -FDT_ERR_BADSTRUCTURE;
897 return 0;
898
899 case FDT_BEGIN_NODE:
900 depth++;
901 if (depth > INT_MAX)
902 return -FDT_ERR_BADSTRUCTURE;
903 break;
904
905 case FDT_END_NODE:
906 if (depth == 0)
907 return -FDT_ERR_BADSTRUCTURE;
908 depth--;
909 break;
910
911 case FDT_PROP:
912 prop = fdt_getprop_by_offset(fdt, offset, &propname,
913 &err);
914 if (!prop)
915 return err;
916 break;
917
918 default:
919 return -FDT_ERR_INTERNAL;
920 }
921 }
922}
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 9b829051e444..2e49855d7cf8 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -67,9 +67,9 @@ static int fdt_blocks_misordered_(const void *fdt,
67 (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); 67 (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
68} 68}
69 69
70static int fdt_rw_check_header_(void *fdt) 70static int fdt_rw_probe_(void *fdt)
71{ 71{
72 FDT_CHECK_HEADER(fdt); 72 FDT_RO_PROBE(fdt);
73 73
74 if (fdt_version(fdt) < 17) 74 if (fdt_version(fdt) < 17)
75 return -FDT_ERR_BADVERSION; 75 return -FDT_ERR_BADVERSION;
@@ -82,10 +82,10 @@ static int fdt_rw_check_header_(void *fdt)
82 return 0; 82 return 0;
83} 83}
84 84
85#define FDT_RW_CHECK_HEADER(fdt) \ 85#define FDT_RW_PROBE(fdt) \
86 { \ 86 { \
87 int err_; \ 87 int err_; \
88 if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ 88 if ((err_ = fdt_rw_probe_(fdt)) != 0) \
89 return err_; \ 89 return err_; \
90 } 90 }
91 91
@@ -176,7 +176,7 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
176 struct fdt_reserve_entry *re; 176 struct fdt_reserve_entry *re;
177 int err; 177 int err;
178 178
179 FDT_RW_CHECK_HEADER(fdt); 179 FDT_RW_PROBE(fdt);
180 180
181 re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); 181 re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
182 err = fdt_splice_mem_rsv_(fdt, re, 0, 1); 182 err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
@@ -192,7 +192,7 @@ int fdt_del_mem_rsv(void *fdt, int n)
192{ 192{
193 struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); 193 struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
194 194
195 FDT_RW_CHECK_HEADER(fdt); 195 FDT_RW_PROBE(fdt);
196 196
197 if (n >= fdt_num_mem_rsv(fdt)) 197 if (n >= fdt_num_mem_rsv(fdt))
198 return -FDT_ERR_NOTFOUND; 198 return -FDT_ERR_NOTFOUND;
@@ -252,7 +252,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
252 int oldlen, newlen; 252 int oldlen, newlen;
253 int err; 253 int err;
254 254
255 FDT_RW_CHECK_HEADER(fdt); 255 FDT_RW_PROBE(fdt);
256 256
257 namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); 257 namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
258 if (!namep) 258 if (!namep)
@@ -275,7 +275,7 @@ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
275 struct fdt_property *prop; 275 struct fdt_property *prop;
276 int err; 276 int err;
277 277
278 FDT_RW_CHECK_HEADER(fdt); 278 FDT_RW_PROBE(fdt);
279 279
280 err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); 280 err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
281 if (err == -FDT_ERR_NOTFOUND) 281 if (err == -FDT_ERR_NOTFOUND)
@@ -308,7 +308,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
308 struct fdt_property *prop; 308 struct fdt_property *prop;
309 int err, oldlen, newlen; 309 int err, oldlen, newlen;
310 310
311 FDT_RW_CHECK_HEADER(fdt); 311 FDT_RW_PROBE(fdt);
312 312
313 prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); 313 prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
314 if (prop) { 314 if (prop) {
@@ -334,7 +334,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
334 struct fdt_property *prop; 334 struct fdt_property *prop;
335 int len, proplen; 335 int len, proplen;
336 336
337 FDT_RW_CHECK_HEADER(fdt); 337 FDT_RW_PROBE(fdt);
338 338
339 prop = fdt_get_property_w(fdt, nodeoffset, name, &len); 339 prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
340 if (!prop) 340 if (!prop)
@@ -354,7 +354,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
354 uint32_t tag; 354 uint32_t tag;
355 fdt32_t *endtag; 355 fdt32_t *endtag;
356 356
357 FDT_RW_CHECK_HEADER(fdt); 357 FDT_RW_PROBE(fdt);
358 358
359 offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); 359 offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
360 if (offset >= 0) 360 if (offset >= 0)
@@ -394,7 +394,7 @@ int fdt_del_node(void *fdt, int nodeoffset)
394{ 394{
395 int endoffset; 395 int endoffset;
396 396
397 FDT_RW_CHECK_HEADER(fdt); 397 FDT_RW_PROBE(fdt);
398 398
399 endoffset = fdt_node_end_offset_(fdt, nodeoffset); 399 endoffset = fdt_node_end_offset_(fdt, nodeoffset);
400 if (endoffset < 0) 400 if (endoffset < 0)
@@ -435,7 +435,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
435 const char *fdtend = fdtstart + fdt_totalsize(fdt); 435 const char *fdtend = fdtstart + fdt_totalsize(fdt);
436 char *tmp; 436 char *tmp;
437 437
438 FDT_CHECK_HEADER(fdt); 438 FDT_RO_PROBE(fdt);
439 439
440 mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 440 mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
441 * sizeof(struct fdt_reserve_entry); 441 * sizeof(struct fdt_reserve_entry);
@@ -494,7 +494,7 @@ int fdt_pack(void *fdt)
494{ 494{
495 int mem_rsv_size; 495 int mem_rsv_size;
496 496
497 FDT_RW_CHECK_HEADER(fdt); 497 FDT_RW_PROBE(fdt);
498 498
499 mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) 499 mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
500 * sizeof(struct fdt_reserve_entry); 500 * sizeof(struct fdt_reserve_entry);
diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c
index 6d33cc29d022..9fa4a94d83c3 100644
--- a/scripts/dtc/libfdt/fdt_sw.c
+++ b/scripts/dtc/libfdt/fdt_sw.c
@@ -55,21 +55,77 @@
55 55
56#include "libfdt_internal.h" 56#include "libfdt_internal.h"
57 57
58static int fdt_sw_check_header_(void *fdt) 58static int fdt_sw_probe_(void *fdt)
59{ 59{
60 if (fdt_magic(fdt) != FDT_SW_MAGIC) 60 if (fdt_magic(fdt) == FDT_MAGIC)
61 return -FDT_ERR_BADSTATE;
62 else if (fdt_magic(fdt) != FDT_SW_MAGIC)
61 return -FDT_ERR_BADMAGIC; 63 return -FDT_ERR_BADMAGIC;
62 /* FIXME: should check more details about the header state */
63 return 0; 64 return 0;
64} 65}
65 66
66#define FDT_SW_CHECK_HEADER(fdt) \ 67#define FDT_SW_PROBE(fdt) \
68 { \
69 int err; \
70 if ((err = fdt_sw_probe_(fdt)) != 0) \
71 return err; \
72 }
73
74/* 'memrsv' state: Initial state after fdt_create()
75 *
76 * Allowed functions:
77 * fdt_add_reservmap_entry()
78 * fdt_finish_reservemap() [moves to 'struct' state]
79 */
80static int fdt_sw_probe_memrsv_(void *fdt)
81{
82 int err = fdt_sw_probe_(fdt);
83 if (err)
84 return err;
85
86 if (fdt_off_dt_strings(fdt) != 0)
87 return -FDT_ERR_BADSTATE;
88 return 0;
89}
90
91#define FDT_SW_PROBE_MEMRSV(fdt) \
92 { \
93 int err; \
94 if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
95 return err; \
96 }
97
98/* 'struct' state: Enter this state after fdt_finish_reservemap()
99 *
100 * Allowed functions:
101 * fdt_begin_node()
102 * fdt_end_node()
103 * fdt_property*()
104 * fdt_finish() [moves to 'complete' state]
105 */
106static int fdt_sw_probe_struct_(void *fdt)
107{
108 int err = fdt_sw_probe_(fdt);
109 if (err)
110 return err;
111
112 if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
113 return -FDT_ERR_BADSTATE;
114 return 0;
115}
116
117#define FDT_SW_PROBE_STRUCT(fdt) \
67 { \ 118 { \
68 int err; \ 119 int err; \
69 if ((err = fdt_sw_check_header_(fdt)) != 0) \ 120 if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
70 return err; \ 121 return err; \
71 } 122 }
72 123
124/* 'complete' state: Enter this state after fdt_finish()
125 *
126 * Allowed functions: none
127 */
128
73static void *fdt_grab_space_(void *fdt, size_t len) 129static void *fdt_grab_space_(void *fdt, size_t len)
74{ 130{
75 int offset = fdt_size_dt_struct(fdt); 131 int offset = fdt_size_dt_struct(fdt);
@@ -87,9 +143,11 @@ static void *fdt_grab_space_(void *fdt, size_t len)
87 143
88int fdt_create(void *buf, int bufsize) 144int fdt_create(void *buf, int bufsize)
89{ 145{
146 const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
147 sizeof(struct fdt_reserve_entry));
90 void *fdt = buf; 148 void *fdt = buf;
91 149
92 if (bufsize < sizeof(struct fdt_header)) 150 if (bufsize < hdrsize)
93 return -FDT_ERR_NOSPACE; 151 return -FDT_ERR_NOSPACE;
94 152
95 memset(buf, 0, bufsize); 153 memset(buf, 0, bufsize);
@@ -99,10 +157,9 @@ int fdt_create(void *buf, int bufsize)
99 fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); 157 fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
100 fdt_set_totalsize(fdt, bufsize); 158 fdt_set_totalsize(fdt, bufsize);
101 159
102 fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), 160 fdt_set_off_mem_rsvmap(fdt, hdrsize);
103 sizeof(struct fdt_reserve_entry)));
104 fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); 161 fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
105 fdt_set_off_dt_strings(fdt, bufsize); 162 fdt_set_off_dt_strings(fdt, 0);
106 163
107 return 0; 164 return 0;
108} 165}
@@ -112,11 +169,14 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
112 size_t headsize, tailsize; 169 size_t headsize, tailsize;
113 char *oldtail, *newtail; 170 char *oldtail, *newtail;
114 171
115 FDT_SW_CHECK_HEADER(fdt); 172 FDT_SW_PROBE(fdt);
116 173
117 headsize = fdt_off_dt_struct(fdt); 174 headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
118 tailsize = fdt_size_dt_strings(fdt); 175 tailsize = fdt_size_dt_strings(fdt);
119 176
177 if ((headsize + tailsize) > fdt_totalsize(fdt))
178 return -FDT_ERR_INTERNAL;
179
120 if ((headsize + tailsize) > bufsize) 180 if ((headsize + tailsize) > bufsize)
121 return -FDT_ERR_NOSPACE; 181 return -FDT_ERR_NOSPACE;
122 182
@@ -133,8 +193,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
133 memmove(buf, fdt, headsize); 193 memmove(buf, fdt, headsize);
134 } 194 }
135 195
136 fdt_set_off_dt_strings(buf, bufsize);
137 fdt_set_totalsize(buf, bufsize); 196 fdt_set_totalsize(buf, bufsize);
197 if (fdt_off_dt_strings(buf))
198 fdt_set_off_dt_strings(buf, bufsize);
138 199
139 return 0; 200 return 0;
140} 201}
@@ -144,10 +205,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
144 struct fdt_reserve_entry *re; 205 struct fdt_reserve_entry *re;
145 int offset; 206 int offset;
146 207
147 FDT_SW_CHECK_HEADER(fdt); 208 FDT_SW_PROBE_MEMRSV(fdt);
148
149 if (fdt_size_dt_struct(fdt))
150 return -FDT_ERR_BADSTATE;
151 209
152 offset = fdt_off_dt_struct(fdt); 210 offset = fdt_off_dt_struct(fdt);
153 if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) 211 if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
@@ -164,16 +222,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
164 222
165int fdt_finish_reservemap(void *fdt) 223int fdt_finish_reservemap(void *fdt)
166{ 224{
167 return fdt_add_reservemap_entry(fdt, 0, 0); 225 int err = fdt_add_reservemap_entry(fdt, 0, 0);
226
227 if (err)
228 return err;
229
230 fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
231 return 0;
168} 232}
169 233
170int fdt_begin_node(void *fdt, const char *name) 234int fdt_begin_node(void *fdt, const char *name)
171{ 235{
172 struct fdt_node_header *nh; 236 struct fdt_node_header *nh;
173 int namelen = strlen(name) + 1; 237 int namelen;
174 238
175 FDT_SW_CHECK_HEADER(fdt); 239 FDT_SW_PROBE_STRUCT(fdt);
176 240
241 namelen = strlen(name) + 1;
177 nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); 242 nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
178 if (! nh) 243 if (! nh)
179 return -FDT_ERR_NOSPACE; 244 return -FDT_ERR_NOSPACE;
@@ -187,7 +252,7 @@ int fdt_end_node(void *fdt)
187{ 252{
188 fdt32_t *en; 253 fdt32_t *en;
189 254
190 FDT_SW_CHECK_HEADER(fdt); 255 FDT_SW_PROBE_STRUCT(fdt);
191 256
192 en = fdt_grab_space_(fdt, FDT_TAGSIZE); 257 en = fdt_grab_space_(fdt, FDT_TAGSIZE);
193 if (! en) 258 if (! en)
@@ -225,7 +290,7 @@ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
225 struct fdt_property *prop; 290 struct fdt_property *prop;
226 int nameoff; 291 int nameoff;
227 292
228 FDT_SW_CHECK_HEADER(fdt); 293 FDT_SW_PROBE_STRUCT(fdt);
229 294
230 nameoff = fdt_find_add_string_(fdt, name); 295 nameoff = fdt_find_add_string_(fdt, name);
231 if (nameoff == 0) 296 if (nameoff == 0)
@@ -262,7 +327,7 @@ int fdt_finish(void *fdt)
262 uint32_t tag; 327 uint32_t tag;
263 int offset, nextoffset; 328 int offset, nextoffset;
264 329
265 FDT_SW_CHECK_HEADER(fdt); 330 FDT_SW_PROBE_STRUCT(fdt);
266 331
267 /* Add terminator */ 332 /* Add terminator */
268 end = fdt_grab_space_(fdt, sizeof(*end)); 333 end = fdt_grab_space_(fdt, sizeof(*end));
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index 1e27780e1185..2bd151dd355f 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -90,8 +90,9 @@
90 90
91/* Error codes: codes for bad device tree blobs */ 91/* Error codes: codes for bad device tree blobs */
92#define FDT_ERR_TRUNCATED 8 92#define FDT_ERR_TRUNCATED 8
93 /* FDT_ERR_TRUNCATED: Structure block of the given device tree 93 /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
94 * ends without an FDT_END tag. */ 94 * terminated (overflows, goes outside allowed bounds, or
95 * isn't properly terminated). */
95#define FDT_ERR_BADMAGIC 9 96#define FDT_ERR_BADMAGIC 9
96 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a 97 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
97 * device tree at all - it is missing the flattened device 98 * device tree at all - it is missing the flattened device
@@ -153,6 +154,29 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
153 154
154uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); 155uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
155 156
157/*
158 * Alignment helpers:
159 * These helpers access words from a device tree blob. They're
160 * built to work even with unaligned pointers on platforms (ike
161 * ARM) that don't like unaligned loads and stores
162 */
163
164static inline uint32_t fdt32_ld(const fdt32_t *p)
165{
166 fdt32_t v;
167
168 memcpy(&v, p, sizeof(v));
169 return fdt32_to_cpu(v);
170}
171
172static inline uint64_t fdt64_ld(const fdt64_t *p)
173{
174 fdt64_t v;
175
176 memcpy(&v, p, sizeof(v));
177 return fdt64_to_cpu(v);
178}
179
156/**********************************************************************/ 180/**********************************************************************/
157/* Traversal functions */ 181/* Traversal functions */
158/**********************************************************************/ 182/**********************************************************************/
@@ -213,7 +237,7 @@ int fdt_next_subnode(const void *fdt, int offset);
213/* General functions */ 237/* General functions */
214/**********************************************************************/ 238/**********************************************************************/
215#define fdt_get_header(fdt, field) \ 239#define fdt_get_header(fdt, field) \
216 (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) 240 (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
217#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) 241#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
218#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) 242#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
219#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) 243#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
@@ -244,18 +268,31 @@ fdt_set_hdr_(size_dt_struct);
244#undef fdt_set_hdr_ 268#undef fdt_set_hdr_
245 269
246/** 270/**
247 * fdt_check_header - sanity check a device tree or possible device tree 271 * fdt_header_size - return the size of the tree's header
272 * @fdt: pointer to a flattened device tree
273 */
274size_t fdt_header_size_(uint32_t version);
275static inline size_t fdt_header_size(const void *fdt)
276{
277 return fdt_header_size_(fdt_version(fdt));
278}
279
280/**
281 * fdt_check_header - sanity check a device tree header
282
248 * @fdt: pointer to data which might be a flattened device tree 283 * @fdt: pointer to data which might be a flattened device tree
249 * 284 *
250 * fdt_check_header() checks that the given buffer contains what 285 * fdt_check_header() checks that the given buffer contains what
251 * appears to be a flattened device tree with sane information in its 286 * appears to be a flattened device tree, and that the header contains
252 * header. 287 * valid information (to the extent that can be determined from the
288 * header alone).
253 * 289 *
254 * returns: 290 * returns:
255 * 0, if the buffer appears to contain a valid device tree 291 * 0, if the buffer appears to contain a valid device tree
256 * -FDT_ERR_BADMAGIC, 292 * -FDT_ERR_BADMAGIC,
257 * -FDT_ERR_BADVERSION, 293 * -FDT_ERR_BADVERSION,
258 * -FDT_ERR_BADSTATE, standard meanings, as above 294 * -FDT_ERR_BADSTATE,
295 * -FDT_ERR_TRUNCATED, standard meanings, as above
259 */ 296 */
260int fdt_check_header(const void *fdt); 297int fdt_check_header(const void *fdt);
261 298
@@ -284,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
284/* Read-only functions */ 321/* Read-only functions */
285/**********************************************************************/ 322/**********************************************************************/
286 323
324int fdt_check_full(const void *fdt, size_t bufsize);
325
326/**
327 * fdt_get_string - retrieve a string from the strings block of a device tree
328 * @fdt: pointer to the device tree blob
329 * @stroffset: offset of the string within the strings block (native endian)
330 * @lenp: optional pointer to return the string's length
331 *
332 * fdt_get_string() retrieves a pointer to a single string from the
333 * strings block of the device tree blob at fdt, and optionally also
334 * returns the string's length in *lenp.
335 *
336 * returns:
337 * a pointer to the string, on success
338 * NULL, if stroffset is out of bounds, or doesn't point to a valid string
339 */
340const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
341
287/** 342/**
288 * fdt_string - retrieve a string from the strings block of a device tree 343 * fdt_string - retrieve a string from the strings block of a device tree
289 * @fdt: pointer to the device tree blob 344 * @fdt: pointer to the device tree blob
@@ -294,7 +349,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
294 * 349 *
295 * returns: 350 * returns:
296 * a pointer to the string, on success 351 * a pointer to the string, on success
297 * NULL, if stroffset is out of bounds 352 * NULL, if stroffset is out of bounds, or doesn't point to a valid string
298 */ 353 */
299const char *fdt_string(const void *fdt, int stroffset); 354const char *fdt_string(const void *fdt, int stroffset);
300 355
@@ -1090,7 +1145,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
1090 * 1145 *
1091 * returns: 1146 * returns:
1092 * 0 <= n < FDT_MAX_NCELLS, on success 1147 * 0 <= n < FDT_MAX_NCELLS, on success
1093 * 2, if the node has no #address-cells property 1148 * 2, if the node has no #size-cells property
1094 * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid 1149 * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
1095 * #size-cells property 1150 * #size-cells property
1096 * -FDT_ERR_BADMAGIC, 1151 * -FDT_ERR_BADMAGIC,
@@ -1313,10 +1368,13 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
1313 fdt64_t tmp = cpu_to_fdt64(val); 1368 fdt64_t tmp = cpu_to_fdt64(val);
1314 return fdt_property(fdt, name, &tmp, sizeof(tmp)); 1369 return fdt_property(fdt, name, &tmp, sizeof(tmp));
1315} 1370}
1371
1372#ifndef SWIG /* Not available in Python */
1316static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) 1373static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
1317{ 1374{
1318 return fdt_property_u32(fdt, name, val); 1375 return fdt_property_u32(fdt, name, val);
1319} 1376}
1377#endif
1320 1378
1321/** 1379/**
1322 * fdt_property_placeholder - add a new property and return a ptr to its value 1380 * fdt_property_placeholder - add a new property and return a ptr to its value
diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h
index bd2474628775..eb2053845c9c 100644
--- a/scripts/dtc/libfdt/libfdt_env.h
+++ b/scripts/dtc/libfdt/libfdt_env.h
@@ -56,6 +56,7 @@
56#include <stdint.h> 56#include <stdint.h>
57#include <stdlib.h> 57#include <stdlib.h>
58#include <string.h> 58#include <string.h>
59#include <limits.h>
59 60
60#ifdef __CHECKER__ 61#ifdef __CHECKER__
61#define FDT_FORCE __attribute__((force)) 62#define FDT_FORCE __attribute__((force))
diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h
index 7681e192295b..4109f890ae60 100644
--- a/scripts/dtc/libfdt/libfdt_internal.h
+++ b/scripts/dtc/libfdt/libfdt_internal.h
@@ -55,10 +55,11 @@
55#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) 55#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
56#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) 56#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
57 57
58#define FDT_CHECK_HEADER(fdt) \ 58int fdt_ro_probe_(const void *fdt);
59#define FDT_RO_PROBE(fdt) \
59 { \ 60 { \
60 int err_; \ 61 int err_; \
61 if ((err_ = fdt_check_header(fdt)) != 0) \ 62 if ((err_ = fdt_ro_probe_(fdt)) != 0) \
62 return err_; \ 63 return err_; \
63 } 64 }
64 65
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index 6e4c367f54b3..4ff0679e0062 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -594,6 +594,7 @@ struct node *get_node_by_ref(struct node *tree, const char *ref)
594cell_t get_node_phandle(struct node *root, struct node *node) 594cell_t get_node_phandle(struct node *root, struct node *node)
595{ 595{
596 static cell_t phandle = 1; /* FIXME: ick, static local */ 596 static cell_t phandle = 1; /* FIXME: ick, static local */
597 struct data d = empty_data;
597 598
598 if ((node->phandle != 0) && (node->phandle != -1)) 599 if ((node->phandle != 0) && (node->phandle != -1))
599 return node->phandle; 600 return node->phandle;
@@ -603,17 +604,16 @@ cell_t get_node_phandle(struct node *root, struct node *node)
603 604
604 node->phandle = phandle; 605 node->phandle = phandle;
605 606
607 d = data_add_marker(d, TYPE_UINT32, NULL);
608 d = data_append_cell(d, phandle);
609
606 if (!get_property(node, "linux,phandle") 610 if (!get_property(node, "linux,phandle")
607 && (phandle_format & PHANDLE_LEGACY)) 611 && (phandle_format & PHANDLE_LEGACY))
608 add_property(node, 612 add_property(node, build_property("linux,phandle", d));
609 build_property("linux,phandle",
610 data_append_cell(empty_data, phandle)));
611 613
612 if (!get_property(node, "phandle") 614 if (!get_property(node, "phandle")
613 && (phandle_format & PHANDLE_EPAPR)) 615 && (phandle_format & PHANDLE_EPAPR))
614 add_property(node, 616 add_property(node, build_property("phandle", d));
615 build_property("phandle",
616 data_append_cell(empty_data, phandle)));
617 617
618 /* If the node *does* have a phandle property, we must 618 /* If the node *does* have a phandle property, we must
619 * be dealing with a self-referencing phandle, which will be 619 * be dealing with a self-referencing phandle, which will be
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
index 2461a3d068a0..f2874f1d1465 100644
--- a/scripts/dtc/treesource.c
+++ b/scripts/dtc/treesource.c
@@ -61,24 +61,14 @@ static bool isstring(char c)
61 || strchr("\a\b\t\n\v\f\r", c)); 61 || strchr("\a\b\t\n\v\f\r", c));
62} 62}
63 63
64static void write_propval_string(FILE *f, struct data val) 64static void write_propval_string(FILE *f, const char *s, size_t len)
65{ 65{
66 const char *str = val.val; 66 const char *end = s + len - 1;
67 int i; 67 assert(*end == '\0');
68 struct marker *m = val.markers;
69
70 assert(str[val.len-1] == '\0');
71 68
72 while (m && (m->offset == 0)) {
73 if (m->type == LABEL)
74 fprintf(f, "%s: ", m->ref);
75 m = m->next;
76 }
77 fprintf(f, "\""); 69 fprintf(f, "\"");
78 70 while (s < end) {
79 for (i = 0; i < (val.len-1); i++) { 71 char c = *s++;
80 char c = str[i];
81
82 switch (c) { 72 switch (c) {
83 case '\a': 73 case '\a':
84 fprintf(f, "\\a"); 74 fprintf(f, "\\a");
@@ -108,91 +98,78 @@ static void write_propval_string(FILE *f, struct data val)
108 fprintf(f, "\\\""); 98 fprintf(f, "\\\"");
109 break; 99 break;
110 case '\0': 100 case '\0':
111 fprintf(f, "\", "); 101 fprintf(f, "\\0");
112 while (m && (m->offset <= (i + 1))) {
113 if (m->type == LABEL) {
114 assert(m->offset == (i+1));
115 fprintf(f, "%s: ", m->ref);
116 }
117 m = m->next;
118 }
119 fprintf(f, "\"");
120 break; 102 break;
121 default: 103 default:
122 if (isprint((unsigned char)c)) 104 if (isprint((unsigned char)c))
123 fprintf(f, "%c", c); 105 fprintf(f, "%c", c);
124 else 106 else
125 fprintf(f, "\\x%02hhx", c); 107 fprintf(f, "\\x%02"PRIx8, c);
126 } 108 }
127 } 109 }
128 fprintf(f, "\""); 110 fprintf(f, "\"");
129
130 /* Wrap up any labels at the end of the value */
131 for_each_marker_of_type(m, LABEL) {
132 assert (m->offset == val.len);
133 fprintf(f, " %s:", m->ref);
134 }
135} 111}
136 112
137static void write_propval_cells(FILE *f, struct data val) 113static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
138{ 114{
139 void *propend = val.val + val.len; 115 const char *end = p + len;
140 fdt32_t *cp = (fdt32_t *)val.val; 116 assert(len % width == 0);
141 struct marker *m = val.markers;
142
143 fprintf(f, "<");
144 for (;;) {
145 while (m && (m->offset <= ((char *)cp - val.val))) {
146 if (m->type == LABEL) {
147 assert(m->offset == ((char *)cp - val.val));
148 fprintf(f, "%s: ", m->ref);
149 }
150 m = m->next;
151 }
152 117
153 fprintf(f, "0x%x", fdt32_to_cpu(*cp++)); 118 for (; p < end; p += width) {
154 if ((void *)cp >= propend) 119 switch (width) {
120 case 1:
121 fprintf(f, " %02"PRIx8, *(const uint8_t*)p);
122 break;
123 case 2:
124 fprintf(f, " 0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p));
125 break;
126 case 4:
127 fprintf(f, " 0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p));
128 break;
129 case 8:
130 fprintf(f, " 0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p));
155 break; 131 break;
156 fprintf(f, " "); 132 }
157 } 133 }
134}
158 135
159 /* Wrap up any labels at the end of the value */ 136static bool has_data_type_information(struct marker *m)
160 for_each_marker_of_type(m, LABEL) { 137{
161 assert (m->offset == val.len); 138 return m->type >= TYPE_UINT8;
162 fprintf(f, " %s:", m->ref);
163 }
164 fprintf(f, ">");
165} 139}
166 140
167static void write_propval_bytes(FILE *f, struct data val) 141static struct marker *next_type_marker(struct marker *m)
168{ 142{
169 void *propend = val.val + val.len; 143 while (m && !has_data_type_information(m))
170 const char *bp = val.val; 144 m = m->next;
171 struct marker *m = val.markers; 145 return m;
172 146}
173 fprintf(f, "[");
174 for (;;) {
175 while (m && (m->offset == (bp-val.val))) {
176 if (m->type == LABEL)
177 fprintf(f, "%s: ", m->ref);
178 m = m->next;
179 }
180 147
181 fprintf(f, "%02hhx", (unsigned char)(*bp++)); 148size_t type_marker_length(struct marker *m)
182 if ((const void *)bp >= propend) 149{
183 break; 150 struct marker *next = next_type_marker(m->next);
184 fprintf(f, " ");
185 }
186 151
187 /* Wrap up any labels at the end of the value */ 152 if (next)
188 for_each_marker_of_type(m, LABEL) { 153 return next->offset - m->offset;
189 assert (m->offset == val.len); 154 return 0;
190 fprintf(f, " %s:", m->ref);
191 }
192 fprintf(f, "]");
193} 155}
194 156
195static void write_propval(FILE *f, struct property *prop) 157static const char *delim_start[] = {
158 [TYPE_UINT8] = "[",
159 [TYPE_UINT16] = "/bits/ 16 <",
160 [TYPE_UINT32] = "<",
161 [TYPE_UINT64] = "/bits/ 64 <",
162 [TYPE_STRING] = "",
163};
164static const char *delim_end[] = {
165 [TYPE_UINT8] = " ]",
166 [TYPE_UINT16] = " >",
167 [TYPE_UINT32] = " >",
168 [TYPE_UINT64] = " >",
169 [TYPE_STRING] = "",
170};
171
172static enum markertype guess_value_type(struct property *prop)
196{ 173{
197 int len = prop->val.len; 174 int len = prop->val.len;
198 const char *p = prop->val.val; 175 const char *p = prop->val.val;
@@ -201,11 +178,6 @@ static void write_propval(FILE *f, struct property *prop)
201 int nnotstringlbl = 0, nnotcelllbl = 0; 178 int nnotstringlbl = 0, nnotcelllbl = 0;
202 int i; 179 int i;
203 180
204 if (len == 0) {
205 fprintf(f, ";\n");
206 return;
207 }
208
209 for (i = 0; i < len; i++) { 181 for (i = 0; i < len; i++) {
210 if (! isstring(p[i])) 182 if (! isstring(p[i]))
211 nnotstring++; 183 nnotstring++;
@@ -220,17 +192,91 @@ static void write_propval(FILE *f, struct property *prop)
220 nnotcelllbl++; 192 nnotcelllbl++;
221 } 193 }
222 194
223 fprintf(f, " = ");
224 if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) 195 if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul))
225 && (nnotstringlbl == 0)) { 196 && (nnotstringlbl == 0)) {
226 write_propval_string(f, prop->val); 197 return TYPE_STRING;
227 } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { 198 } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
228 write_propval_cells(f, prop->val); 199 return TYPE_UINT32;
229 } else {
230 write_propval_bytes(f, prop->val);
231 } 200 }
232 201
233 fprintf(f, ";\n"); 202 return TYPE_UINT8;
203}
204
205static void write_propval(FILE *f, struct property *prop)
206{
207 size_t len = prop->val.len;
208 struct marker *m = prop->val.markers;
209 struct marker dummy_marker;
210 enum markertype emit_type = TYPE_NONE;
211
212 if (len == 0) {
213 fprintf(f, ";\n");
214 return;
215 }
216
217 fprintf(f, " = ");
218
219 if (!next_type_marker(m)) {
220 /* data type information missing, need to guess */
221 dummy_marker.type = guess_value_type(prop);
222 dummy_marker.next = prop->val.markers;
223 dummy_marker.offset = 0;
224 dummy_marker.ref = NULL;
225 m = &dummy_marker;
226 }
227
228 struct marker *m_label = prop->val.markers;
229 for_each_marker(m) {
230 size_t chunk_len;
231 const char *p = &prop->val.val[m->offset];
232
233 if (!has_data_type_information(m))
234 continue;
235
236 chunk_len = type_marker_length(m);
237 if (!chunk_len)
238 chunk_len = len - m->offset;
239
240 if (emit_type != TYPE_NONE)
241 fprintf(f, "%s, ", delim_end[emit_type]);
242 emit_type = m->type;
243
244 for_each_marker_of_type(m_label, LABEL) {
245 if (m_label->offset > m->offset)
246 break;
247 fprintf(f, "%s: ", m_label->ref);
248 }
249
250 fprintf(f, "%s", delim_start[emit_type]);
251
252 if (chunk_len <= 0)
253 continue;
254
255 switch(emit_type) {
256 case TYPE_UINT16:
257 write_propval_int(f, p, chunk_len, 2);
258 break;
259 case TYPE_UINT32:
260 write_propval_int(f, p, chunk_len, 4);
261 break;
262 case TYPE_UINT64:
263 write_propval_int(f, p, chunk_len, 8);
264 break;
265 case TYPE_STRING:
266 write_propval_string(f, p, chunk_len);
267 break;
268 default:
269 write_propval_int(f, p, chunk_len, 1);
270 }
271 }
272
273 /* Wrap up any labels at the end of the value */
274 for_each_marker_of_type(m_label, LABEL) {
275 assert (m_label->offset == len);
276 fprintf(f, " %s:", m_label->ref);
277 }
278
279 fprintf(f, "%s;\n", delim_end[emit_type] ? : "");
234} 280}
235 281
236static void write_tree_source_node(FILE *f, struct node *tree, int level) 282static void write_tree_source_node(FILE *f, struct node *tree, int level)
@@ -281,4 +327,3 @@ void dt_to_source(FILE *f, struct dt_info *dti)
281 327
282 write_tree_source_node(f, dti->dt, 0); 328 write_tree_source_node(f, dti->dt, 0);
283} 329}
284
diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh
index 1a009fd195d0..7dd29a0362b8 100755
--- a/scripts/dtc/update-dtc-source.sh
+++ b/scripts/dtc/update-dtc-source.sh
@@ -32,7 +32,7 @@ DTC_UPSTREAM_PATH=`pwd`/../dtc
32DTC_LINUX_PATH=`pwd`/scripts/dtc 32DTC_LINUX_PATH=`pwd`/scripts/dtc
33 33
34DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ 34DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \
35 srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \ 35 srcpos.h treesource.c util.c util.h version_gen.h yamltree.c Makefile.dtc \
36 dtc-lexer.l dtc-parser.y" 36 dtc-lexer.l dtc-parser.y"
37LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ 37LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \
38 fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \ 38 fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c \
diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
index 9953c32a0244..a69b7a13463d 100644
--- a/scripts/dtc/util.c
+++ b/scripts/dtc/util.c
@@ -227,11 +227,11 @@ char get_escape_char(const char *s, int *i)
227 return val; 227 return val;
228} 228}
229 229
230int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) 230int utilfdt_read_err(const char *filename, char **buffp, size_t *len)
231{ 231{
232 int fd = 0; /* assume stdin */ 232 int fd = 0; /* assume stdin */
233 char *buf = NULL; 233 char *buf = NULL;
234 off_t bufsize = 1024, offset = 0; 234 size_t bufsize = 1024, offset = 0;
235 int ret = 0; 235 int ret = 0;
236 236
237 *buffp = NULL; 237 *buffp = NULL;
@@ -264,20 +264,15 @@ int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len)
264 free(buf); 264 free(buf);
265 else 265 else
266 *buffp = buf; 266 *buffp = buf;
267 *len = bufsize; 267 if (len)
268 *len = bufsize;
268 return ret; 269 return ret;
269} 270}
270 271
271int utilfdt_read_err(const char *filename, char **buffp) 272char *utilfdt_read(const char *filename, size_t *len)
272{
273 off_t len;
274 return utilfdt_read_err_len(filename, buffp, &len);
275}
276
277char *utilfdt_read_len(const char *filename, off_t *len)
278{ 273{
279 char *buff; 274 char *buff;
280 int ret = utilfdt_read_err_len(filename, &buff, len); 275 int ret = utilfdt_read_err(filename, &buff, len);
281 276
282 if (ret) { 277 if (ret) {
283 fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename, 278 fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
@@ -288,12 +283,6 @@ char *utilfdt_read_len(const char *filename, off_t *len)
288 return buff; 283 return buff;
289} 284}
290 285
291char *utilfdt_read(const char *filename)
292{
293 off_t len;
294 return utilfdt_read_len(filename, &len);
295}
296
297int utilfdt_write_err(const char *filename, const void *blob) 286int utilfdt_write_err(const char *filename, const void *blob)
298{ 287{
299 int fd = 1; /* assume stdout */ 288 int fd = 1; /* assume stdout */
diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h
index 66fba8ea709b..f6cea8274174 100644
--- a/scripts/dtc/util.h
+++ b/scripts/dtc/util.h
@@ -98,16 +98,10 @@ char get_escape_char(const char *s, int *i);
98 * stderr. 98 * stderr.
99 * 99 *
100 * @param filename The filename to read, or - for stdin 100 * @param filename The filename to read, or - for stdin
101 * @return Pointer to allocated buffer containing fdt, or NULL on error
102 */
103char *utilfdt_read(const char *filename);
104
105/**
106 * Like utilfdt_read(), but also passes back the size of the file read.
107 *
108 * @param len If non-NULL, the amount of data we managed to read 101 * @param len If non-NULL, the amount of data we managed to read
102 * @return Pointer to allocated buffer containing fdt, or NULL on error
109 */ 103 */
110char *utilfdt_read_len(const char *filename, off_t *len); 104char *utilfdt_read(const char *filename, size_t *len);
111 105
112/** 106/**
113 * Read a device tree file into a buffer. Does not report errors, but only 107 * Read a device tree file into a buffer. Does not report errors, but only
@@ -116,16 +110,10 @@ char *utilfdt_read_len(const char *filename, off_t *len);
116 * 110 *
117 * @param filename The filename to read, or - for stdin 111 * @param filename The filename to read, or - for stdin
118 * @param buffp Returns pointer to buffer containing fdt 112 * @param buffp Returns pointer to buffer containing fdt
119 * @return 0 if ok, else an errno value representing the error
120 */
121int utilfdt_read_err(const char *filename, char **buffp);
122
123/**
124 * Like utilfdt_read_err(), but also passes back the size of the file read.
125 *
126 * @param len If non-NULL, the amount of data we managed to read 113 * @param len If non-NULL, the amount of data we managed to read
114 * @return 0 if ok, else an errno value representing the error
127 */ 115 */
128int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len); 116int utilfdt_read_err(const char *filename, char **buffp, size_t *len);
129 117
130/** 118/**
131 * Write a device tree buffer to a file. This will report any errors on 119 * Write a device tree buffer to a file. This will report any errors on
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index b00f14ff7a17..6d23fd095f16 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
#define DTC_VERSION "DTC 1.4.6-g84e414b0" #define DTC_VERSION "DTC 1.4.7-gc86da84d"
diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c
new file mode 100644
index 000000000000..a00285a5a9ec
--- /dev/null
+++ b/scripts/dtc/yamltree.c
@@ -0,0 +1,247 @@
1/*
2 * (C) Copyright Linaro, Ltd. 2018
3 * (C) Copyright Arm Holdings. 2017
4 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22#include <stdlib.h>
23#include <yaml.h>
24#include "dtc.h"
25#include "srcpos.h"
26
27char *yaml_error_name[] = {
28 [YAML_NO_ERROR] = "no error",
29 [YAML_MEMORY_ERROR] = "memory error",
30 [YAML_READER_ERROR] = "reader error",
31 [YAML_SCANNER_ERROR] = "scanner error",
32 [YAML_PARSER_ERROR] = "parser error",
33 [YAML_COMPOSER_ERROR] = "composer error",
34 [YAML_WRITER_ERROR] = "writer error",
35 [YAML_EMITTER_ERROR] = "emitter error",
36};
37
38#define yaml_emitter_emit_or_die(emitter, event) ( \
39{ \
40 if (!yaml_emitter_emit(emitter, event)) \
41 die("yaml '%s': %s in %s, line %i\n", \
42 yaml_error_name[(emitter)->error], \
43 (emitter)->problem, __func__, __LINE__); \
44})
45
46static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width)
47{
48 yaml_event_t event;
49 void *tag;
50 int off, start_offset = markers->offset;
51
52 switch(width) {
53 case 1: tag = "!u8"; break;
54 case 2: tag = "!u16"; break;
55 case 4: tag = "!u32"; break;
56 case 8: tag = "!u64"; break;
57 default:
58 die("Invalid width %i", width);
59 }
60 assert(len % width == 0);
61
62 yaml_sequence_start_event_initialize(&event, NULL,
63 (yaml_char_t *)tag, width == 4, YAML_FLOW_SEQUENCE_STYLE);
64 yaml_emitter_emit_or_die(emitter, &event);
65
66 for (off = 0; off < len; off += width) {
67 char buf[32];
68 struct marker *m;
69 bool is_phandle = false;
70
71 switch(width) {
72 case 1:
73 sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off));
74 break;
75 case 2:
76 sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off)));
77 break;
78 case 4:
79 sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off)));
80 m = markers;
81 is_phandle = false;
82 for_each_marker_of_type(m, REF_PHANDLE) {
83 if (m->offset == (start_offset + off)) {
84 is_phandle = true;
85 break;
86 }
87 }
88 break;
89 case 8:
90 sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off)));
91 break;
92 }
93
94 if (is_phandle)
95 yaml_scalar_event_initialize(&event, NULL,
96 (yaml_char_t*)"!phandle", (yaml_char_t *)buf,
97 strlen(buf), 0, 0, YAML_PLAIN_SCALAR_STYLE);
98 else
99 yaml_scalar_event_initialize(&event, NULL,
100 (yaml_char_t*)YAML_INT_TAG, (yaml_char_t *)buf,
101 strlen(buf), 1, 1, YAML_PLAIN_SCALAR_STYLE);
102 yaml_emitter_emit_or_die(emitter, &event);
103 }
104
105 yaml_sequence_end_event_initialize(&event);
106 yaml_emitter_emit_or_die(emitter, &event);
107}
108
109static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len)
110{
111 yaml_event_t event;
112 int i;
113
114 assert(str[len-1] == '\0');
115
116 /* Make sure the entire string is in the lower 7-bit ascii range */
117 for (i = 0; i < len; i++)
118 assert(isascii(str[i]));
119
120 yaml_scalar_event_initialize(&event, NULL,
121 (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)str,
122 len-1, 0, 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE);
123 yaml_emitter_emit_or_die(emitter, &event);
124}
125
126static void yaml_propval(yaml_emitter_t *emitter, struct property *prop)
127{
128 yaml_event_t event;
129 int len = prop->val.len;
130 struct marker *m = prop->val.markers;
131
132 /* Emit the property name */
133 yaml_scalar_event_initialize(&event, NULL,
134 (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)prop->name,
135 strlen(prop->name), 1, 1, YAML_PLAIN_SCALAR_STYLE);
136 yaml_emitter_emit_or_die(emitter, &event);
137
138 /* Boolean properties are easiest to deal with. Length is zero, so just emit 'true' */
139 if (len == 0) {
140 yaml_scalar_event_initialize(&event, NULL,
141 (yaml_char_t *)YAML_BOOL_TAG,
142 (yaml_char_t*)"true",
143 strlen("true"), 1, 0, YAML_PLAIN_SCALAR_STYLE);
144 yaml_emitter_emit_or_die(emitter, &event);
145 return;
146 }
147
148 if (!m)
149 die("No markers present in property '%s' value\n", prop->name);
150
151 yaml_sequence_start_event_initialize(&event, NULL,
152 (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_FLOW_SEQUENCE_STYLE);
153 yaml_emitter_emit_or_die(emitter, &event);
154
155 for_each_marker(m) {
156 int chunk_len;
157 char *data = &prop->val.val[m->offset];
158
159 if (m->type < TYPE_UINT8)
160 continue;
161
162 chunk_len = type_marker_length(m) ? : len;
163 assert(chunk_len > 0);
164 len -= chunk_len;
165
166 switch(m->type) {
167 case TYPE_UINT16:
168 yaml_propval_int(emitter, m, data, chunk_len, 2);
169 break;
170 case TYPE_UINT32:
171 yaml_propval_int(emitter, m, data, chunk_len, 4);
172 break;
173 case TYPE_UINT64:
174 yaml_propval_int(emitter, m, data, chunk_len, 8);
175 break;
176 case TYPE_STRING:
177 yaml_propval_string(emitter, data, chunk_len);
178 break;
179 default:
180 yaml_propval_int(emitter, m, data, chunk_len, 1);
181 break;
182 }
183 }
184
185 yaml_sequence_end_event_initialize(&event);
186 yaml_emitter_emit_or_die(emitter, &event);
187}
188
189
190static void yaml_tree(struct node *tree, yaml_emitter_t *emitter)
191{
192 struct property *prop;
193 struct node *child;
194 yaml_event_t event;
195
196 if (tree->deleted)
197 return;
198
199 yaml_mapping_start_event_initialize(&event, NULL,
200 (yaml_char_t *)YAML_MAP_TAG, 1, YAML_ANY_MAPPING_STYLE);
201 yaml_emitter_emit_or_die(emitter, &event);
202
203 for_each_property(tree, prop)
204 yaml_propval(emitter, prop);
205
206 /* Loop over all the children, emitting them into the map */
207 for_each_child(tree, child) {
208 yaml_scalar_event_initialize(&event, NULL,
209 (yaml_char_t *)YAML_STR_TAG, (yaml_char_t*)child->name,
210 strlen(child->name), 1, 0, YAML_PLAIN_SCALAR_STYLE);
211 yaml_emitter_emit_or_die(emitter, &event);
212 yaml_tree(child, emitter);
213 }
214
215 yaml_mapping_end_event_initialize(&event);
216 yaml_emitter_emit_or_die(emitter, &event);
217}
218
219void dt_to_yaml(FILE *f, struct dt_info *dti)
220{
221 yaml_emitter_t emitter;
222 yaml_event_t event;
223
224 yaml_emitter_initialize(&emitter);
225 yaml_emitter_set_output_file(&emitter, f);
226 yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING);
227 yaml_emitter_emit_or_die(&emitter, &event);
228
229 yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
230 yaml_emitter_emit_or_die(&emitter, &event);
231
232 yaml_sequence_start_event_initialize(&event, NULL, (yaml_char_t *)YAML_SEQ_TAG, 1, YAML_ANY_SEQUENCE_STYLE);
233 yaml_emitter_emit_or_die(&emitter, &event);
234
235 yaml_tree(dti->dt, &emitter);
236
237 yaml_sequence_end_event_initialize(&event);
238 yaml_emitter_emit_or_die(&emitter, &event);
239
240 yaml_document_end_event_initialize(&event, 0);
241 yaml_emitter_emit_or_die(&emitter, &event);
242
243 yaml_stream_end_event_initialize(&event);
244 yaml_emitter_emit_or_die(&emitter, &event);
245
246 yaml_emitter_delete(&emitter);
247}
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index cb0c889e13aa..0d5c799688f0 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -139,4 +139,55 @@ config GCC_PLUGIN_RANDSTRUCT_PERFORMANCE
139 in structures. This reduces the performance hit of RANDSTRUCT 139 in structures. This reduces the performance hit of RANDSTRUCT
140 at the cost of weakened randomization. 140 at the cost of weakened randomization.
141 141
142config GCC_PLUGIN_STACKLEAK
143 bool "Erase the kernel stack before returning from syscalls"
144 depends on GCC_PLUGINS
145 depends on HAVE_ARCH_STACKLEAK
146 help
147 This option makes the kernel erase the kernel stack before
148 returning from system calls. That reduces the information which
149 kernel stack leak bugs can reveal and blocks some uninitialized
150 stack variable attacks.
151
152 The tradeoff is the performance impact: on a single CPU system kernel
153 compilation sees a 1% slowdown, other systems and workloads may vary
154 and you are advised to test this feature on your expected workload
155 before deploying it.
156
157 This plugin was ported from grsecurity/PaX. More information at:
158 * https://grsecurity.net/
159 * https://pax.grsecurity.net/
160
161config STACKLEAK_TRACK_MIN_SIZE
162 int "Minimum stack frame size of functions tracked by STACKLEAK"
163 default 100
164 range 0 4096
165 depends on GCC_PLUGIN_STACKLEAK
166 help
167 The STACKLEAK gcc plugin instruments the kernel code for tracking
168 the lowest border of the kernel stack (and for some other purposes).
169 It inserts the stackleak_track_stack() call for the functions with
170 a stack frame size greater than or equal to this parameter.
171 If unsure, leave the default value 100.
172
173config STACKLEAK_METRICS
174 bool "Show STACKLEAK metrics in the /proc file system"
175 depends on GCC_PLUGIN_STACKLEAK
176 depends on PROC_FS
177 help
178 If this is set, STACKLEAK metrics for every task are available in
179 the /proc file system. In particular, /proc/<pid>/stack_depth
180 shows the maximum kernel stack consumption for the current and
181 previous syscalls. Although this information is not precise, it
182 can be useful for estimating the STACKLEAK performance impact for
183 your workloads.
184
185config STACKLEAK_RUNTIME_DISABLE
186 bool "Allow runtime disabling of kernel stack erasing"
187 depends on GCC_PLUGIN_STACKLEAK
188 help
189 This option provides 'stack_erasing' sysctl, which can be used in
190 runtime to control kernel stack erasing for kernels built with
191 CONFIG_GCC_PLUGIN_STACKLEAK.
192
142endif 193endif
diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c
new file mode 100644
index 000000000000..2f48da98b5d4
--- /dev/null
+++ b/scripts/gcc-plugins/stackleak_plugin.c
@@ -0,0 +1,427 @@
1/*
2 * Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu>
3 * Modified by Alexander Popov <alex.popov@linux.com>
4 * Licensed under the GPL v2
5 *
6 * Note: the choice of the license means that the compilation process is
7 * NOT 'eligible' as defined by gcc's library exception to the GPL v3,
8 * but for the kernel it doesn't matter since it doesn't link against
9 * any of the gcc libraries
10 *
11 * This gcc plugin is needed for tracking the lowest border of the kernel stack.
12 * It instruments the kernel code inserting stackleak_track_stack() calls:
13 * - after alloca();
14 * - for the functions with a stack frame size greater than or equal
15 * to the "track-min-size" plugin parameter.
16 *
17 * This plugin is ported from grsecurity/PaX. For more information see:
18 * https://grsecurity.net/
19 * https://pax.grsecurity.net/
20 *
21 * Debugging:
22 * - use fprintf() to stderr, debug_generic_expr(), debug_gimple_stmt(),
23 * print_rtl() and print_simple_rtl();
24 * - add "-fdump-tree-all -fdump-rtl-all" to the plugin CFLAGS in
25 * Makefile.gcc-plugins to see the verbose dumps of the gcc passes;
26 * - use gcc -E to understand the preprocessing shenanigans;
27 * - use gcc with enabled CFG/GIMPLE/SSA verification (--enable-checking).
28 */
29
30#include "gcc-common.h"
31
32__visible int plugin_is_GPL_compatible;
33
34static int track_frame_size = -1;
35static const char track_function[] = "stackleak_track_stack";
36
37/*
38 * Mark these global variables (roots) for gcc garbage collector since
39 * they point to the garbage-collected memory.
40 */
41static GTY(()) tree track_function_decl;
42
43static struct plugin_info stackleak_plugin_info = {
44 .version = "201707101337",
45 .help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n"
46 "disable\t\tdo not activate the plugin\n"
47};
48
49static void stackleak_add_track_stack(gimple_stmt_iterator *gsi, bool after)
50{
51 gimple stmt;
52 gcall *stackleak_track_stack;
53 cgraph_node_ptr node;
54 int frequency;
55 basic_block bb;
56
57 /* Insert call to void stackleak_track_stack(void) */
58 stmt = gimple_build_call(track_function_decl, 0);
59 stackleak_track_stack = as_a_gcall(stmt);
60 if (after) {
61 gsi_insert_after(gsi, stackleak_track_stack,
62 GSI_CONTINUE_LINKING);
63 } else {
64 gsi_insert_before(gsi, stackleak_track_stack, GSI_SAME_STMT);
65 }
66
67 /* Update the cgraph */
68 bb = gimple_bb(stackleak_track_stack);
69 node = cgraph_get_create_node(track_function_decl);
70 gcc_assert(node);
71 frequency = compute_call_stmt_bb_frequency(current_function_decl, bb);
72 cgraph_create_edge(cgraph_get_node(current_function_decl), node,
73 stackleak_track_stack, bb->count, frequency);
74}
75
76static bool is_alloca(gimple stmt)
77{
78 if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA))
79 return true;
80
81#if BUILDING_GCC_VERSION >= 4007
82 if (gimple_call_builtin_p(stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
83 return true;
84#endif
85
86 return false;
87}
88
89/*
90 * Work with the GIMPLE representation of the code. Insert the
91 * stackleak_track_stack() call after alloca() and into the beginning
92 * of the function if it is not instrumented.
93 */
94static unsigned int stackleak_instrument_execute(void)
95{
96 basic_block bb, entry_bb;
97 bool prologue_instrumented = false, is_leaf = true;
98 gimple_stmt_iterator gsi;
99
100 /*
101 * ENTRY_BLOCK_PTR is a basic block which represents possible entry
102 * point of a function. This block does not contain any code and
103 * has a CFG edge to its successor.
104 */
105 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
106 entry_bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
107
108 /*
109 * Loop through the GIMPLE statements in each of cfun basic blocks.
110 * cfun is a global variable which represents the function that is
111 * currently processed.
112 */
113 FOR_EACH_BB_FN(bb, cfun) {
114 for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
115 gimple stmt;
116
117 stmt = gsi_stmt(gsi);
118
119 /* Leaf function is a function which makes no calls */
120 if (is_gimple_call(stmt))
121 is_leaf = false;
122
123 if (!is_alloca(stmt))
124 continue;
125
126 /* Insert stackleak_track_stack() call after alloca() */
127 stackleak_add_track_stack(&gsi, true);
128 if (bb == entry_bb)
129 prologue_instrumented = true;
130 }
131 }
132
133 if (prologue_instrumented)
134 return 0;
135
136 /*
137 * Special cases to skip the instrumentation.
138 *
139 * Taking the address of static inline functions materializes them,
140 * but we mustn't instrument some of them as the resulting stack
141 * alignment required by the function call ABI will break other
142 * assumptions regarding the expected (but not otherwise enforced)
143 * register clobbering ABI.
144 *
145 * Case in point: native_save_fl on amd64 when optimized for size
146 * clobbers rdx if it were instrumented here.
147 *
148 * TODO: any more special cases?
149 */
150 if (is_leaf &&
151 !TREE_PUBLIC(current_function_decl) &&
152 DECL_DECLARED_INLINE_P(current_function_decl)) {
153 return 0;
154 }
155
156 if (is_leaf &&
157 !strncmp(IDENTIFIER_POINTER(DECL_NAME(current_function_decl)),
158 "_paravirt_", 10)) {
159 return 0;
160 }
161
162 /* Insert stackleak_track_stack() call at the function beginning */
163 bb = entry_bb;
164 if (!single_pred_p(bb)) {
165 /* gcc_assert(bb_loop_depth(bb) ||
166 (bb->flags & BB_IRREDUCIBLE_LOOP)); */
167 split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
168 gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun)));
169 bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));
170 }
171 gsi = gsi_after_labels(bb);
172 stackleak_add_track_stack(&gsi, false);
173
174 return 0;
175}
176
177static bool large_stack_frame(void)
178{
179#if BUILDING_GCC_VERSION >= 8000
180 return maybe_ge(get_frame_size(), track_frame_size);
181#else
182 return (get_frame_size() >= track_frame_size);
183#endif
184}
185
186/*
187 * Work with the RTL representation of the code.
188 * Remove the unneeded stackleak_track_stack() calls from the functions
189 * which don't call alloca() and don't have a large enough stack frame size.
190 */
191static unsigned int stackleak_cleanup_execute(void)
192{
193 rtx_insn *insn, *next;
194
195 if (cfun->calls_alloca)
196 return 0;
197
198 if (large_stack_frame())
199 return 0;
200
201 /*
202 * Find stackleak_track_stack() calls. Loop through the chain of insns,
203 * which is an RTL representation of the code for a function.
204 *
205 * The example of a matching insn:
206 * (call_insn 8 4 10 2 (call (mem (symbol_ref ("stackleak_track_stack")
207 * [flags 0x41] <function_decl 0x7f7cd3302a80 stackleak_track_stack>)
208 * [0 stackleak_track_stack S1 A8]) (0)) 675 {*call} (expr_list
209 * (symbol_ref ("stackleak_track_stack") [flags 0x41] <function_decl
210 * 0x7f7cd3302a80 stackleak_track_stack>) (expr_list (0) (nil))) (nil))
211 */
212 for (insn = get_insns(); insn; insn = next) {
213 rtx body;
214
215 next = NEXT_INSN(insn);
216
217 /* Check the expression code of the insn */
218 if (!CALL_P(insn))
219 continue;
220
221 /*
222 * Check the expression code of the insn body, which is an RTL
223 * Expression (RTX) describing the side effect performed by
224 * that insn.
225 */
226 body = PATTERN(insn);
227
228 if (GET_CODE(body) == PARALLEL)
229 body = XVECEXP(body, 0, 0);
230
231 if (GET_CODE(body) != CALL)
232 continue;
233
234 /*
235 * Check the first operand of the call expression. It should
236 * be a mem RTX describing the needed subroutine with a
237 * symbol_ref RTX.
238 */
239 body = XEXP(body, 0);
240 if (GET_CODE(body) != MEM)
241 continue;
242
243 body = XEXP(body, 0);
244 if (GET_CODE(body) != SYMBOL_REF)
245 continue;
246
247 if (SYMBOL_REF_DECL(body) != track_function_decl)
248 continue;
249
250 /* Delete the stackleak_track_stack() call */
251 delete_insn_and_edges(insn);
252#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION < 8000
253 if (GET_CODE(next) == NOTE &&
254 NOTE_KIND(next) == NOTE_INSN_CALL_ARG_LOCATION) {
255 insn = next;
256 next = NEXT_INSN(insn);
257 delete_insn_and_edges(insn);
258 }
259#endif
260 }
261
262 return 0;
263}
264
265static bool stackleak_gate(void)
266{
267 tree section;
268
269 section = lookup_attribute("section",
270 DECL_ATTRIBUTES(current_function_decl));
271 if (section && TREE_VALUE(section)) {
272 section = TREE_VALUE(TREE_VALUE(section));
273
274 if (!strncmp(TREE_STRING_POINTER(section), ".init.text", 10))
275 return false;
276 if (!strncmp(TREE_STRING_POINTER(section), ".devinit.text", 13))
277 return false;
278 if (!strncmp(TREE_STRING_POINTER(section), ".cpuinit.text", 13))
279 return false;
280 if (!strncmp(TREE_STRING_POINTER(section), ".meminit.text", 13))
281 return false;
282 }
283
284 return track_frame_size >= 0;
285}
286
287/* Build the function declaration for stackleak_track_stack() */
288static void stackleak_start_unit(void *gcc_data __unused,
289 void *user_data __unused)
290{
291 tree fntype;
292
293 /* void stackleak_track_stack(void) */
294 fntype = build_function_type_list(void_type_node, NULL_TREE);
295 track_function_decl = build_fn_decl(track_function, fntype);
296 DECL_ASSEMBLER_NAME(track_function_decl); /* for LTO */
297 TREE_PUBLIC(track_function_decl) = 1;
298 TREE_USED(track_function_decl) = 1;
299 DECL_EXTERNAL(track_function_decl) = 1;
300 DECL_ARTIFICIAL(track_function_decl) = 1;
301 DECL_PRESERVE_P(track_function_decl) = 1;
302}
303
304/*
305 * Pass gate function is a predicate function that gets executed before the
306 * corresponding pass. If the return value is 'true' the pass gets executed,
307 * otherwise, it is skipped.
308 */
309static bool stackleak_instrument_gate(void)
310{
311 return stackleak_gate();
312}
313
314#define PASS_NAME stackleak_instrument
315#define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg
316#define TODO_FLAGS_START TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts
317#define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \
318 | TODO_update_ssa | TODO_rebuild_cgraph_edges
319#include "gcc-generate-gimple-pass.h"
320
321static bool stackleak_cleanup_gate(void)
322{
323 return stackleak_gate();
324}
325
326#define PASS_NAME stackleak_cleanup
327#define TODO_FLAGS_FINISH TODO_dump_func
328#include "gcc-generate-rtl-pass.h"
329
330/*
331 * Every gcc plugin exports a plugin_init() function that is called right
332 * after the plugin is loaded. This function is responsible for registering
333 * the plugin callbacks and doing other required initialization.
334 */
335__visible int plugin_init(struct plugin_name_args *plugin_info,
336 struct plugin_gcc_version *version)
337{
338 const char * const plugin_name = plugin_info->base_name;
339 const int argc = plugin_info->argc;
340 const struct plugin_argument * const argv = plugin_info->argv;
341 int i = 0;
342
343 /* Extra GGC root tables describing our GTY-ed data */
344 static const struct ggc_root_tab gt_ggc_r_gt_stackleak[] = {
345 {
346 .base = &track_function_decl,
347 .nelt = 1,
348 .stride = sizeof(track_function_decl),
349 .cb = &gt_ggc_mx_tree_node,
350 .pchw = &gt_pch_nx_tree_node
351 },
352 LAST_GGC_ROOT_TAB
353 };
354
355 /*
356 * The stackleak_instrument pass should be executed before the
357 * "optimized" pass, which is the control flow graph cleanup that is
358 * performed just before expanding gcc trees to the RTL. In former
359 * versions of the plugin this new pass was inserted before the
360 * "tree_profile" pass, which is currently called "profile".
361 */
362 PASS_INFO(stackleak_instrument, "optimized", 1,
363 PASS_POS_INSERT_BEFORE);
364
365 /*
366 * The stackleak_cleanup pass should be executed after the
367 * "reload" pass, when the stack frame size is final.
368 */
369 PASS_INFO(stackleak_cleanup, "reload", 1, PASS_POS_INSERT_AFTER);
370
371 if (!plugin_default_version_check(version, &gcc_version)) {
372 error(G_("incompatible gcc/plugin versions"));
373 return 1;
374 }
375
376 /* Parse the plugin arguments */
377 for (i = 0; i < argc; i++) {
378 if (!strcmp(argv[i].key, "disable"))
379 return 0;
380
381 if (!strcmp(argv[i].key, "track-min-size")) {
382 if (!argv[i].value) {
383 error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
384 plugin_name, argv[i].key);
385 return 1;
386 }
387
388 track_frame_size = atoi(argv[i].value);
389 if (track_frame_size < 0) {
390 error(G_("invalid option argument '-fplugin-arg-%s-%s=%s'"),
391 plugin_name, argv[i].key, argv[i].value);
392 return 1;
393 }
394 } else {
395 error(G_("unknown option '-fplugin-arg-%s-%s'"),
396 plugin_name, argv[i].key);
397 return 1;
398 }
399 }
400
401 /* Give the information about the plugin */
402 register_callback(plugin_name, PLUGIN_INFO, NULL,
403 &stackleak_plugin_info);
404
405 /* Register to be called before processing a translation unit */
406 register_callback(plugin_name, PLUGIN_START_UNIT,
407 &stackleak_start_unit, NULL);
408
409 /* Register an extra GCC garbage collector (GGC) root table */
410 register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL,
411 (void *)&gt_ggc_r_gt_stackleak);
412
413 /*
414 * Hook into the Pass Manager to register new gcc passes.
415 *
416 * The stack frame size info is available only at the last RTL pass,
417 * when it's too late to insert complex code like a function call.
418 * So we register two gcc passes to instrument every function at first
419 * and remove the unneeded instrumentation later.
420 */
421 register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
422 &stackleak_instrument_pass_info);
423 register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
424 &stackleak_cleanup_pass_info);
425
426 return 0;
427}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index a9186a98a37d..109a1af7e444 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -48,8 +48,6 @@ static unsigned long long relative_base;
48static struct addr_range text_ranges[] = { 48static struct addr_range text_ranges[] = {
49 { "_stext", "_etext" }, 49 { "_stext", "_etext" },
50 { "_sinittext", "_einittext" }, 50 { "_sinittext", "_einittext" },
51 { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */
52 { "_stext_l2", "_etext_l2" }, /* Blackfin on-chip L2 SRAM */
53}; 51};
54#define text_range_text (&text_ranges[0]) 52#define text_range_text (&text_ranges[0])
55#define text_range_inittext (&text_ranges[1]) 53#define text_range_inittext (&text_ranges[1])
@@ -405,7 +403,7 @@ static void write_src(void)
405 } 403 }
406 404
407 output_label("kallsyms_num_syms"); 405 output_label("kallsyms_num_syms");
408 printf("\tPTR\t%u\n", table_cnt); 406 printf("\t.long\t%u\n", table_cnt);
409 printf("\n"); 407 printf("\n");
410 408
411 /* table of offset markers, that give the offset in the compressed stream 409 /* table of offset markers, that give the offset in the compressed stream
@@ -434,7 +432,7 @@ static void write_src(void)
434 432
435 output_label("kallsyms_markers"); 433 output_label("kallsyms_markers");
436 for (i = 0; i < ((table_cnt + 255) >> 8); i++) 434 for (i = 0; i < ((table_cnt + 255) >> 8); i++)
437 printf("\tPTR\t%d\n", markers[i]); 435 printf("\t.long\t%u\n", markers[i]);
438 printf("\n"); 436 printf("\n");
439 437
440 free(markers); 438 free(markers);
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 67ed9f6ccdf8..63b609243d03 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -68,21 +68,7 @@ PHONY += $(simple-targets)
68$(simple-targets): $(obj)/conf 68$(simple-targets): $(obj)/conf
69 $< $(silent) --$@ $(Kconfig) 69 $< $(silent) --$@ $(Kconfig)
70 70
71PHONY += oldnoconfig silentoldconfig savedefconfig defconfig 71PHONY += savedefconfig defconfig
72
73# oldnoconfig is an alias of olddefconfig, because people already are dependent
74# on its behavior (sets new symbols to their default value but not 'n') with the
75# counter-intuitive name.
76oldnoconfig: olddefconfig
77 @echo " WARNING: \"oldnoconfig\" target will be removed after Linux 4.19"
78 @echo " Please use \"olddefconfig\" instead, which is an alias."
79
80# We do not expect manual invokcation of "silentoldcofig" (or "syncconfig").
81silentoldconfig: syncconfig
82 @echo " WARNING: \"silentoldconfig\" has been renamed to \"syncconfig\""
83 @echo " and is now an internal implementation detail."
84 @echo " What you want is probably \"oldconfig\"."
85 @echo " \"silentoldconfig\" will be removed after Linux 4.19"
86 72
87savedefconfig: $(obj)/conf 73savedefconfig: $(obj)/conf
88 $< $(silent) --$@=defconfig $(Kconfig) 74 $< $(silent) --$@=defconfig $(Kconfig)
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 7b2b37260669..98e0c7a34699 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -460,12 +460,6 @@ static struct option long_opts[] = {
460 {"randconfig", no_argument, NULL, randconfig}, 460 {"randconfig", no_argument, NULL, randconfig},
461 {"listnewconfig", no_argument, NULL, listnewconfig}, 461 {"listnewconfig", no_argument, NULL, listnewconfig},
462 {"olddefconfig", no_argument, NULL, olddefconfig}, 462 {"olddefconfig", no_argument, NULL, olddefconfig},
463 /*
464 * oldnoconfig is an alias of olddefconfig, because people already
465 * are dependent on its behavior(sets new symbols to their default
466 * value but not 'n') with the counter-intuitive name.
467 */
468 {"oldnoconfig", no_argument, NULL, olddefconfig},
469 {NULL, 0, NULL, 0} 463 {NULL, 0, NULL, 0}
470}; 464};
471 465
@@ -480,7 +474,6 @@ static void conf_usage(const char *progname)
480 printf(" --syncconfig Similar to oldconfig but generates configuration in\n" 474 printf(" --syncconfig Similar to oldconfig but generates configuration in\n"
481 " include/{generated/,config/}\n"); 475 " include/{generated/,config/}\n");
482 printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n"); 476 printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n");
483 printf(" --oldnoconfig An alias of olddefconfig\n");
484 printf(" --defconfig <file> New config with default defined in <file>\n"); 477 printf(" --defconfig <file> New config with default defined in <file>\n");
485 printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); 478 printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
486 printf(" --allnoconfig New config where all options are answered with no\n"); 479 printf(" --allnoconfig New config where all options are answered with no\n");
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 67d131447631..da66e7742282 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -33,12 +33,15 @@ usage() {
33 echo " -n use allnoconfig instead of alldefconfig" 33 echo " -n use allnoconfig instead of alldefconfig"
34 echo " -r list redundant entries when merging fragments" 34 echo " -r list redundant entries when merging fragments"
35 echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead." 35 echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
36 echo
37 echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ environment variable."
36} 38}
37 39
38RUNMAKE=true 40RUNMAKE=true
39ALLTARGET=alldefconfig 41ALLTARGET=alldefconfig
40WARNREDUN=false 42WARNREDUN=false
41OUTPUT=. 43OUTPUT=.
44CONFIG_PREFIX=${CONFIG_-CONFIG_}
42 45
43while true; do 46while true; do
44 case $1 in 47 case $1 in
@@ -99,7 +102,8 @@ if [ ! -r "$INITFILE" ]; then
99fi 102fi
100 103
101MERGE_LIST=$* 104MERGE_LIST=$*
102SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" 105SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)[= ].*/\2/p"
106
103TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) 107TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
104 108
105echo "Using $INITFILE as base" 109echo "Using $INITFILE as base"
diff --git a/scripts/mkmakefile b/scripts/mkmakefile
index e19d6565f245..412f13fdff52 100755
--- a/scripts/mkmakefile
+++ b/scripts/mkmakefile
@@ -6,31 +6,20 @@
6 6
7# Usage 7# Usage
8# $1 - Kernel src directory 8# $1 - Kernel src directory
9# $2 - Output directory
10# $3 - version
11# $4 - patchlevel
12 9
13
14test ! -r $2/Makefile -o -O $2/Makefile || exit 0
15# Only overwrite automatically generated Makefiles 10# Only overwrite automatically generated Makefiles
16# (so we do not overwrite kernel Makefile) 11# (so we do not overwrite kernel Makefile)
17if test -e $2/Makefile && ! grep -q Automatically $2/Makefile 12if test -e Makefile && ! grep -q Automatically Makefile
18then 13then
19 exit 0 14 exit 0
20fi 15fi
21if [ "${quiet}" != "silent_" ]; then 16if [ "${quiet}" != "silent_" ]; then
22 echo " GEN $2/Makefile" 17 echo " GEN Makefile"
23fi 18fi
24 19
25cat << EOF > $2/Makefile 20cat << EOF > Makefile
26# Automatically generated by $0: don't edit 21# Automatically generated by $0: don't edit
27 22
28VERSION = $3
29PATCHLEVEL = $4
30
31lastword = \$(word \$(words \$(1)),\$(1))
32makedir := \$(dir \$(call lastword,\$(MAKEFILE_LIST)))
33
34ifeq ("\$(origin V)", "command line") 23ifeq ("\$(origin V)", "command line")
35VERBOSE := \$(V) 24VERBOSE := \$(V)
36endif 25endif
@@ -38,15 +27,12 @@ ifneq (\$(VERBOSE),1)
38Q := @ 27Q := @
39endif 28endif
40 29
41MAKEARGS := -C $1
42MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$(makedir))
43
44MAKEFLAGS += --no-print-directory 30MAKEFLAGS += --no-print-directory
45 31
46.PHONY: __sub-make \$(MAKECMDGOALS) 32.PHONY: __sub-make \$(MAKECMDGOALS)
47 33
48__sub-make: 34__sub-make:
49 \$(Q)\$(MAKE) \$(MAKEARGS) \$(MAKECMDGOALS) 35 \$(Q)\$(MAKE) -C $1 O=\$(CURDIR) \$(MAKECMDGOALS)
50 36
51\$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make 37\$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make
52 @: 38 @:
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 7be43697ff84..28a61665bb9c 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -95,12 +95,20 @@ extern struct devtable *__start___devtable[], *__stop___devtable[];
95 */ 95 */
96#define DEF_FIELD(m, devid, f) \ 96#define DEF_FIELD(m, devid, f) \
97 typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) 97 typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
98
99/* Define a variable v that holds the address of field f of struct devid
100 * based at address m. Due to the way typeof works, for a field of type
101 * T[N] the variable has type T(*)[N], _not_ T*.
102 */
103#define DEF_FIELD_ADDR_VAR(m, devid, f, v) \
104 typeof(((struct devid *)0)->f) *v = ((m) + OFF_##devid##_##f)
105
98/* Define a variable f that holds the address of field f of struct devid 106/* Define a variable f that holds the address of field f of struct devid
99 * based at address m. Due to the way typeof works, for a field of type 107 * based at address m. Due to the way typeof works, for a field of type
100 * T[N] the variable has type T(*)[N], _not_ T*. 108 * T[N] the variable has type T(*)[N], _not_ T*.
101 */ 109 */
102#define DEF_FIELD_ADDR(m, devid, f) \ 110#define DEF_FIELD_ADDR(m, devid, f) \
103 typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) 111 DEF_FIELD_ADDR_VAR(m, devid, f, f)
104 112
105/* Add a table entry. We test function type matches while we're here. */ 113/* Add a table entry. We test function type matches while we're here. */
106#define ADD_TO_DEVTABLE(device_id, type, function) \ 114#define ADD_TO_DEVTABLE(device_id, type, function) \
@@ -644,7 +652,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size,
644 652
645 for (i = 0; i < count; i++) { 653 for (i = 0; i < count; i++) {
646 unsigned int j; 654 unsigned int j;
647 DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs); 655 DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs);
648 656
649 for (j = 0; j < PNP_MAX_DEVICES; j++) { 657 for (j = 0; j < PNP_MAX_DEVICES; j++) {
650 const char *id = (char *)(*devs)[j].id; 658 const char *id = (char *)(*devs)[j].id;
@@ -656,10 +664,13 @@ static void do_pnp_card_entries(void *symval, unsigned long size,
656 664
657 /* find duplicate, already added value */ 665 /* find duplicate, already added value */
658 for (i2 = 0; i2 < i && !dup; i2++) { 666 for (i2 = 0; i2 < i && !dup; i2++) {
659 DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs); 667 DEF_FIELD_ADDR_VAR(symval + i2 * id_size,
668 pnp_card_device_id,
669 devs, devs_dup);
660 670
661 for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { 671 for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) {
662 const char *id2 = (char *)(*devs)[j2].id; 672 const char *id2 =
673 (char *)(*devs_dup)[j2].id;
663 674
664 if (!id2[0]) 675 if (!id2[0])
665 break; 676 break;
@@ -1415,11 +1426,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
1415 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 1426 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
1416 return; 1427 return;
1417 1428
1418 /* All our symbols are of form <prefix>__mod_<name>__<identifier>_device_table. */ 1429 /* All our symbols are of form __mod_<name>__<identifier>_device_table. */
1419 name = strstr(symname, "__mod_"); 1430 if (strncmp(symname, "__mod_", strlen("__mod_")))
1420 if (!name)
1421 return; 1431 return;
1422 name += strlen("__mod_"); 1432 name = symname + strlen("__mod_");
1423 namelen = strlen(name); 1433 namelen = strlen(name);
1424 if (namelen < strlen("_device_table")) 1434 if (namelen < strlen("_device_table"))
1425 return; 1435 return;
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 26de7d5aa5c8..4fa070f9231a 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -203,7 +203,7 @@ regex_c=(
203 '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/' 203 '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/'
204 '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/' 204 '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/'
205 '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/' 205 '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/'
206 '/\<DEFINE_HASHTABLE(\([[:alnum:]_]*\)/\1/v/' 206 '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/'
207) 207)
208regex_kconfig=( 208regex_kconfig=(
209 '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/' 209 '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'