diff options
Diffstat (limited to 'scripts')
45 files changed, 1580 insertions, 429 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index ce53639a864a..bb015551c2d9 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include | |||
| @@ -115,7 +115,9 @@ __cc-option = $(call try-run,\ | |||
| 115 | 115 | ||
| 116 | # Do not attempt to build with gcc plugins during cc-option tests. | 116 | # Do not attempt to build with gcc plugins during cc-option tests. |
| 117 | # (And this uses delayed resolution so the flags will be up to date.) | 117 | # (And this uses delayed resolution so the flags will be up to date.) |
| 118 | CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) | 118 | # In addition, do not include the asm macros which are built later. |
| 119 | CC_OPTION_FILTERED = $(GCC_PLUGINS_CFLAGS) $(ASM_MACRO_FLAGS) | ||
| 120 | CC_OPTION_CFLAGS = $(filter-out $(CC_OPTION_FILTERED),$(KBUILD_CFLAGS)) | ||
| 119 | 121 | ||
| 120 | # cc-option | 122 | # cc-option |
| 121 | # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) | 123 | # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) |
| @@ -138,17 +140,9 @@ cc-option-yn = $(call try-run,\ | |||
| 138 | cc-disable-warning = $(call try-run,\ | 140 | cc-disable-warning = $(call try-run,\ |
| 139 | $(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))) |
| 140 | 142 | ||
| 141 | # cc-name | ||
| 142 | # Expands to either gcc or clang | ||
| 143 | cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) | ||
| 144 | |||
| 145 | # cc-version | 143 | # cc-version |
| 146 | cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) | 144 | cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) |
| 147 | 145 | ||
| 148 | # cc-fullversion | ||
| 149 | cc-fullversion = $(shell $(CONFIG_SHELL) \ | ||
| 150 | $(srctree)/scripts/gcc-version.sh -p $(CC)) | ||
| 151 | |||
| 152 | # cc-ifversion | 146 | # cc-ifversion |
| 153 | # Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) | 147 | # Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) |
| 154 | cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) | 148 | cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) |
| @@ -193,7 +187,7 @@ modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj | |||
| 193 | # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= | 187 | # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= |
| 194 | # Usage: | 188 | # Usage: |
| 195 | # $(Q)$(MAKE) $(dtbinst)=dir | 189 | # $(Q)$(MAKE) $(dtbinst)=dir |
| 196 | dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj | 190 | dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj |
| 197 | 191 | ||
| 198 | ### | 192 | ### |
| 199 | # 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 | |||
| 39 | subdir-$(CONFIG_MODVERSIONS) += genksyms | 39 | subdir-$(CONFIG_MODVERSIONS) += genksyms |
| 40 | subdir-y += mod | 40 | subdir-y += mod |
| 41 | subdir-$(CONFIG_SECURITY_SELINUX) += selinux | 41 | subdir-$(CONFIG_SECURITY_SELINUX) += selinux |
| 42 | subdir-$(CONFIG_DTC) += dtc | ||
| 43 | subdir-$(CONFIG_GDB_SCRIPTS) += gdb | 42 | subdir-$(CONFIG_GDB_SCRIPTS) += gdb |
| 44 | 43 | ||
| 45 | # Let clean descend into subdirs | 44 | # Let clean descend into subdirs |
| 46 | subdir- += basic kconfig package gcc-plugins | 45 | subdir- += 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 | ||
| 37 | include scripts/Kbuild.include | 37 | include scripts/Kbuild.include |
| 38 | 38 | ||
| 39 | # For backward compatibility check that these variables do not change | ||
| 40 | save-cflags := $(CFLAGS) | ||
| 41 | |||
| 42 | # The filename Kbuild has precedence over Makefile | 39 | # The filename Kbuild has precedence over Makefile |
| 43 | kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) | 40 | kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) |
| 44 | kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) | 41 | kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) |
| 45 | include $(kbuild-file) | 42 | include $(kbuild-file) |
| 46 | 43 | ||
| 47 | # If the save-* variables changed error out | ||
| 48 | ifeq ($(KBUILD_NOPEDANTIC),) | ||
| 49 | ifneq ("$(save-cflags)","$(CFLAGS)") | ||
| 50 | $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y) | ||
| 51 | endif | ||
| 52 | endif | ||
| 53 | |||
| 54 | include scripts/Makefile.lib | 44 | include 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 |
| 86 | ifneq ($(KBUILD_CHECKSRC),0) | 76 | ifeq ($(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) $< ; | 79 | else 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 | ||
| 94 | endif | 82 | endif |
| 95 | 83 | ||
| 96 | ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) | 84 | ifneq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) |
| @@ -495,28 +483,12 @@ targets += $(obj)/lib-ksyms.o | |||
| 495 | 483 | ||
| 496 | endif | 484 | endif |
| 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 | ||
| 508 | link_multi_deps = \ | ||
| 509 | $(filter $(addprefix $(obj)/, \ | ||
| 510 | $($(subst $(obj)/,,$(@:.o=-objs))) \ | ||
| 511 | $($(subst $(obj)/,,$(@:.o=-y))) \ | ||
| 512 | $($(subst $(obj)/,,$(@:.o=-m)))), $^) | ||
| 513 | |||
| 514 | quiet_cmd_link_multi-m = LD [M] $@ | 486 | quiet_cmd_link_multi-m = LD [M] $@ |
| 515 | cmd_link_multi-m = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) | 487 | cmd_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) | |||
| 29 | warning-1 += $(call cc-option, -Wunused-but-set-variable) | 29 | warning-1 += $(call cc-option, -Wunused-but-set-variable) |
| 30 | warning-1 += $(call cc-option, -Wunused-const-variable) | 30 | warning-1 += $(call cc-option, -Wunused-const-variable) |
| 31 | warning-1 += $(call cc-option, -Wpacked-not-aligned) | 31 | warning-1 += $(call cc-option, -Wpacked-not-aligned) |
| 32 | warning-1 += $(call cc-option, -Wstringop-truncation) | ||
| 32 | warning-1 += $(call cc-disable-warning, missing-field-initializers) | 33 | warning-1 += $(call cc-disable-warning, missing-field-initializers) |
| 33 | warning-1 += $(call cc-disable-warning, sign-compare) | 34 | warning-1 += $(call cc-disable-warning, sign-compare) |
| 34 | 35 | ||
| @@ -52,7 +53,6 @@ warning-3 += -Wpointer-arith | |||
| 52 | warning-3 += -Wredundant-decls | 53 | warning-3 += -Wredundant-decls |
| 53 | warning-3 += -Wswitch-default | 54 | warning-3 += -Wswitch-default |
| 54 | warning-3 += $(call cc-option, -Wpacked-bitfield-compat) | 55 | warning-3 += $(call cc-option, -Wpacked-bitfield-compat) |
| 55 | warning-3 += $(call cc-option, -Wvla) | ||
| 56 | 56 | ||
| 57 | warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) | 57 | warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) |
| 58 | warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) | 58 | warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) |
| @@ -65,7 +65,7 @@ endif | |||
| 65 | KBUILD_CFLAGS += $(warning) | 65 | KBUILD_CFLAGS += $(warning) |
| 66 | else | 66 | else |
| 67 | 67 | ||
| 68 | ifeq ($(cc-name),clang) | 68 | ifdef CONFIG_CC_IS_CLANG |
| 69 | KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides) | 69 | KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides) |
| 70 | KBUILD_CFLAGS += $(call cc-disable-warning, unused-value) | 70 | KBUILD_CFLAGS += $(call cc-disable-warning, unused-value) |
| 71 | KBUILD_CFLAGS += $(call cc-disable-warning, format) | 71 | KBUILD_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) \ | |||
| 26 | gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE) \ | 26 | gcc-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 | ||
| 29 | gcc-plugin-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak_plugin.so | ||
| 30 | gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ | ||
| 31 | += -DSTACKLEAK_PLUGIN | ||
| 32 | gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \ | ||
| 33 | += -fplugin-arg-stackleak_plugin-track-min-size=$(CONFIG_STACKLEAK_TRACK_MIN_SIZE) | ||
| 34 | ifdef CONFIG_GCC_PLUGIN_STACKLEAK | ||
| 35 | DISABLE_STACKLEAK_PLUGIN += -fplugin-arg-stackleak_plugin-disable | ||
| 36 | endif | ||
| 37 | export 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. |
| 31 | GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) | 41 | GCC_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 | ||
| 284 | quiet_cmd_dtc = DTC $@ | 284 | quiet_cmd_dtc = DTC $@ |
| 285 | cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ | 285 | cmd_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/check_00index.sh b/scripts/check_00index.sh deleted file mode 100755 index aa47f5926c80..000000000000 --- a/scripts/check_00index.sh +++ /dev/null | |||
| @@ -1,67 +0,0 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | |||
| 4 | cd Documentation/ | ||
| 5 | |||
| 6 | # Check entries that should be removed | ||
| 7 | |||
| 8 | obsolete="" | ||
| 9 | for i in $(tail -n +12 00-INDEX |grep -E '^[a-zA-Z0-9]+'); do | ||
| 10 | if [ ! -e $i ]; then | ||
| 11 | obsolete="$obsolete $i" | ||
| 12 | fi | ||
| 13 | done | ||
| 14 | |||
| 15 | # Check directory entries that should be added | ||
| 16 | search="" | ||
| 17 | dir="" | ||
| 18 | for i in $(find . -maxdepth 1 -type d); do | ||
| 19 | if [ "$i" != "." ]; then | ||
| 20 | new=$(echo $i|perl -ne 's,./(.*),$1/,; print $_') | ||
| 21 | search="$search $new" | ||
| 22 | fi | ||
| 23 | done | ||
| 24 | |||
| 25 | for i in $search; do | ||
| 26 | if [ "$(grep -P "^$i" 00-INDEX)" == "" ]; then | ||
| 27 | dir="$dir $i" | ||
| 28 | fi | ||
| 29 | done | ||
| 30 | |||
| 31 | # Check file entries that should be added | ||
| 32 | search="" | ||
| 33 | file="" | ||
| 34 | for i in $(find . -maxdepth 1 -type f); do | ||
| 35 | if [ "$i" != "./.gitignore" ]; then | ||
| 36 | new=$(echo $i|perl -ne 's,./(.*),$1,; print $_') | ||
| 37 | search="$search $new" | ||
| 38 | fi | ||
| 39 | done | ||
| 40 | |||
| 41 | for i in $search; do | ||
| 42 | if [ "$(grep -P "^$i\$" 00-INDEX)" == "" ]; then | ||
| 43 | file="$file $i" | ||
| 44 | fi | ||
| 45 | done | ||
| 46 | |||
| 47 | # Output its findings | ||
| 48 | |||
| 49 | echo -e "Documentation/00-INDEX check results:\n" | ||
| 50 | |||
| 51 | if [ "$obsolete" != "" ]; then | ||
| 52 | echo -e "- Should remove those entries:\n\t$obsolete\n" | ||
| 53 | else | ||
| 54 | echo -e "- No obsolete entries\n" | ||
| 55 | fi | ||
| 56 | |||
| 57 | if [ "$dir" != "" ]; then | ||
| 58 | echo -e "- Should document those directories:\n\t$dir\n" | ||
| 59 | else | ||
| 60 | echo -e "- No new directories to add\n" | ||
| 61 | fi | ||
| 62 | |||
| 63 | if [ "$file" != "" ]; then | ||
| 64 | echo -e "- Should document those files:\n\t$file" | ||
| 65 | else | ||
| 66 | echo "- No new files to add" | ||
| 67 | fi | ||
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 | ||
| 4 | hostprogs-y := dtc | 4 | hostprogs-$(CONFIG_DTC) := dtc |
| 5 | always := $(hostprogs-y) | 5 | always := $(hostprogs-y) |
| 6 | 6 | ||
| 7 | dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ | 7 | dtc-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 |
| 12 | HOST_EXTRACFLAGS := -I$(src)/libfdt | 12 | HOST_EXTRACFLAGS := -I$(src)/libfdt |
| 13 | 13 | ||
| 14 | ifeq ($(wildcard /usr/include/yaml.h),) | ||
| 15 | HOST_EXTRACFLAGS += -DNO_YAML | ||
| 16 | else | ||
| 17 | dtc-objs += yamltree.o | ||
| 18 | HOSTLDLIBS_dtc := -lyaml | ||
| 19 | endif | ||
| 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 |
| 15 | HOSTCFLAGS_dtc-lexer.lex.o := -I$(src) | 22 | HOSTCFLAGS_dtc-lexer.lex.o := -I$(src) |
| 16 | HOSTCFLAGS_dtc-parser.tab.o := -I$(src) | 23 | HOSTCFLAGS_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 | ||
| 17 | ifneq ($(NO_YAML),1) | ||
| 18 | DTC_SRCS += yamltree.c | ||
| 19 | endif | ||
| 20 | |||
| 17 | DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c | 21 | DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c |
| 18 | DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o) | 22 | DTC_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 | } |
| 963 | WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); | 963 | WARNING(simple_bus_reg, check_simple_bus_reg, NULL, ®_format, &simple_bus_bridge); |
| 964 | 964 | ||
| 965 | static const struct bus_type i2c_bus = { | ||
| 966 | .name = "i2c-bus", | ||
| 967 | }; | ||
| 968 | |||
| 969 | static 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 | } | ||
| 993 | WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells); | ||
| 994 | |||
| 995 | static 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 | } | ||
| 1030 | WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge); | ||
| 1031 | |||
| 1032 | static const struct bus_type spi_bus = { | ||
| 1033 | .name = "spi-bus", | ||
| 1034 | }; | ||
| 1035 | |||
| 1036 | static 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 | } | ||
| 1072 | WARNING(spi_bus_bridge, check_spi_bus_bridge, NULL, &addr_size_cells); | ||
| 1073 | |||
| 1074 | static 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 | } | ||
| 1100 | WARNING(spi_bus_reg, check_spi_bus_reg, NULL, ®_format, &spi_bus_bridge); | ||
| 1101 | |||
| 965 | static void check_unit_address_format(struct check *c, struct dt_info *dti, | 1102 | static 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: | |||
| 499 | bytestring: | 505 | bytestring: |
| 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 */ |
| 76 | enum markertype { | 76 | enum 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 | }; |
| 87 | extern const char *markername(enum markertype markertype); | ||
| 81 | 88 | ||
| 82 | struct marker { | 89 | struct 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 | ||
| 111 | size_t type_marker_length(struct marker *m); | ||
| 112 | |||
| 104 | void data_free(struct data d); | 113 | void data_free(struct data d); |
| 105 | 114 | ||
| 106 | struct data data_grow_for(struct data d, int xlen); | 115 | struct data data_grow_for(struct data d, int xlen); |
| @@ -290,6 +299,10 @@ struct dt_info *dt_from_blob(const char *fname); | |||
| 290 | void dt_to_source(FILE *f, struct dt_info *dti); | 299 | void dt_to_source(FILE *f, struct dt_info *dti); |
| 291 | struct dt_info *dt_from_source(const char *f); | 300 | struct dt_info *dt_from_source(const char *f); |
| 292 | 301 | ||
| 302 | /* YAML source */ | ||
| 303 | |||
| 304 | void dt_to_yaml(FILE *f, struct dt_info *dti); | ||
| 305 | |||
| 293 | /* FS trees */ | 306 | /* FS trees */ |
| 294 | 307 | ||
| 295 | struct dt_info *dt_from_fs(const char *dirname); | 308 | struct 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 | ||
| 58 | int 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 | */ | ||
| 63 | int 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 | ||
| 82 | static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) | ||
| 83 | { | ||
| 84 | return (off >= hdrsize) && (off <= totalsize); | ||
| 85 | } | ||
| 86 | |||
| 87 | static 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 | |||
| 99 | size_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 | |||
| 113 | int 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 | |||
| 77 | const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) | 154 | const 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 | ||
| 245 | int fdt_move(const void *fdt, void *buf, int bufsize) | 322 | int 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 | ||
| 58 | int fdt_address_cells(const void *fdt, int nodeoffset) | 59 | static 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 | ||
| 78 | int fdt_size_cells(const void *fdt, int nodeoffset) | 79 | int 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; | 84 | int 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 | ||
| 79 | const 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 | |||
| 127 | fail: | ||
| 128 | if (lenp) | ||
| 129 | *lenp = err; | ||
| 130 | return NULL; | ||
| 131 | } | ||
| 132 | |||
| 79 | const char *fdt_string(const void *fdt, int stroffset) | 133 | const 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 | ||
| 84 | static int fdt_string_eq_(const void *fdt, int stroffset, | 138 | static 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 | ||
| 92 | uint32_t fdt_get_max_phandle(const void *fdt) | 147 | uint32_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 | ||
| 173 | static 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 | |||
| 118 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | 185 | int 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 | ||
| 126 | int fdt_num_mem_rsv(const void *fdt) | 199 | int 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 | ||
| 135 | static int nextprop_(const void *fdt, int offset) | 211 | static 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 | ||
| 442 | const char *fdt_get_alias_namelen(const void *fdt, | 528 | const 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 | |||
| 861 | int 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 | ||
| 70 | static int fdt_rw_check_header_(void *fdt) | 70 | static 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 | ||
| 58 | static int fdt_sw_check_header_(void *fdt) | 58 | static 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 | */ | ||
| 80 | static 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 | */ | ||
| 106 | static 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 | |||
| 73 | static void *fdt_grab_space_(void *fdt, size_t len) | 129 | static 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 | ||
| 88 | int fdt_create(void *buf, int bufsize) | 144 | int 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 | ||
| 165 | int fdt_finish_reservemap(void *fdt) | 223 | int 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 | ||
| 170 | int fdt_begin_node(void *fdt, const char *name) | 234 | int 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 | ||
| 154 | uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); | 155 | uint32_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 | |||
| 164 | static 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 | |||
| 172 | static 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 | */ | ||
| 274 | size_t fdt_header_size_(uint32_t version); | ||
| 275 | static 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 | */ |
| 260 | int fdt_check_header(const void *fdt); | 297 | int 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 | ||
| 324 | int 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 | */ | ||
| 340 | const 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 | */ |
| 299 | const char *fdt_string(const void *fdt, int stroffset); | 354 | const 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 */ | ||
| 1316 | static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) | 1373 | static 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) \ | 58 | int 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) | |||
| 594 | cell_t get_node_phandle(struct node *root, struct node *node) | 594 | cell_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 | ||
| 64 | static void write_propval_string(FILE *f, struct data val) | 64 | static 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 | ||
| 137 | static void write_propval_cells(FILE *f, struct data val) | 113 | static 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 */ | 136 | static 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 | ||
| 167 | static void write_propval_bytes(FILE *f, struct data val) | 141 | static 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++)); | 148 | size_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 | ||
| 195 | static void write_propval(FILE *f, struct property *prop) | 157 | static const char *delim_start[] = { |
| 158 | [TYPE_UINT8] = "[", | ||
| 159 | [TYPE_UINT16] = "/bits/ 16 <", | ||
| 160 | [TYPE_UINT32] = "<", | ||
| 161 | [TYPE_UINT64] = "/bits/ 64 <", | ||
| 162 | [TYPE_STRING] = "", | ||
| 163 | }; | ||
| 164 | static const char *delim_end[] = { | ||
| 165 | [TYPE_UINT8] = " ]", | ||
| 166 | [TYPE_UINT16] = " >", | ||
| 167 | [TYPE_UINT32] = " >", | ||
| 168 | [TYPE_UINT64] = " >", | ||
| 169 | [TYPE_STRING] = "", | ||
| 170 | }; | ||
| 171 | |||
| 172 | static 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 | |||
| 205 | static 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 | ||
| 236 | static void write_tree_source_node(FILE *f, struct node *tree, int level) | 282 | static 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 | |||
| 32 | DTC_LINUX_PATH=`pwd`/scripts/dtc | 32 | DTC_LINUX_PATH=`pwd`/scripts/dtc |
| 33 | 33 | ||
| 34 | DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c \ | 34 | DTC_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" |
| 37 | LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c \ | 37 | LIBFDT_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 | ||
| 230 | int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len) | 230 | int 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 | ||
| 271 | int utilfdt_read_err(const char *filename, char **buffp) | 272 | char *utilfdt_read(const char *filename, size_t *len) |
| 272 | { | ||
| 273 | off_t len; | ||
| 274 | return utilfdt_read_err_len(filename, buffp, &len); | ||
| 275 | } | ||
| 276 | |||
| 277 | char *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 | ||
| 291 | char *utilfdt_read(const char *filename) | ||
| 292 | { | ||
| 293 | off_t len; | ||
| 294 | return utilfdt_read_len(filename, &len); | ||
| 295 | } | ||
| 296 | |||
| 297 | int utilfdt_write_err(const char *filename, const void *blob) | 286 | int 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 | */ | ||
| 103 | char *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 | */ |
| 110 | char *utilfdt_read_len(const char *filename, off_t *len); | 104 | char *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 | */ | ||
| 121 | int 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 | */ |
| 128 | int utilfdt_read_err_len(const char *filename, char **buffp, off_t *len); | 116 | int 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 | |||
| 27 | char *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 | |||
| 46 | static 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 | |||
| 109 | static 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 | |||
| 126 | static 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 | |||
| 190 | static 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 | |||
| 219 | void 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/extract-vmlinux b/scripts/extract-vmlinux index e6239f39abad..85e1f32fb4a0 100755 --- a/scripts/extract-vmlinux +++ b/scripts/extract-vmlinux | |||
| @@ -48,9 +48,6 @@ fi | |||
| 48 | tmp=$(mktemp /tmp/vmlinux-XXX) | 48 | tmp=$(mktemp /tmp/vmlinux-XXX) |
| 49 | trap "rm -f $tmp" 0 | 49 | trap "rm -f $tmp" 0 |
| 50 | 50 | ||
| 51 | # Initial attempt for uncompressed images or objects: | ||
| 52 | check_vmlinux $img | ||
| 53 | |||
| 54 | # That didn't work, so retry after decompression. | 51 | # That didn't work, so retry after decompression. |
| 55 | try_decompress '\037\213\010' xy gunzip | 52 | try_decompress '\037\213\010' xy gunzip |
| 56 | try_decompress '\3757zXZ\000' abcde unxz | 53 | try_decompress '\3757zXZ\000' abcde unxz |
| @@ -60,5 +57,8 @@ try_decompress '\211\114\132' xy 'lzop -d' | |||
| 60 | try_decompress '\002!L\030' xxx 'lz4 -d' | 57 | try_decompress '\002!L\030' xxx 'lz4 -d' |
| 61 | try_decompress '(\265/\375' xxx unzstd | 58 | try_decompress '(\265/\375' xxx unzstd |
| 62 | 59 | ||
| 60 | # Finally check for uncompressed images or objects: | ||
| 61 | check_vmlinux $img | ||
| 62 | |||
| 63 | # Bail out: | 63 | # Bail out: |
| 64 | echo "$me: Cannot find vmlinux." >&2 | 64 | echo "$me: Cannot find vmlinux." >&2 |
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 | ||
| 142 | config 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 | |||
| 161 | config 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 | |||
| 173 | config 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 | |||
| 185 | config 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 | |||
| 142 | endif | 193 | endif |
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 | |||
| 34 | static int track_frame_size = -1; | ||
| 35 | static 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 | */ | ||
| 41 | static GTY(()) tree track_function_decl; | ||
| 42 | |||
| 43 | static 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 | |||
| 49 | static 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 | |||
| 76 | static 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 | */ | ||
| 94 | static 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 | |||
| 177 | static 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 | */ | ||
| 191 | static 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 | |||
| 265 | static 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() */ | ||
| 288 | static 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 | */ | ||
| 309 | static 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 | |||
| 321 | static 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 = >_ggc_mx_tree_node, | ||
| 350 | .pchw = >_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 *)>_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; | |||
| 48 | static struct addr_range text_ranges[] = { | 48 | static 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 | ||
| 71 | PHONY += oldnoconfig silentoldconfig savedefconfig defconfig | 71 | PHONY += 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. | ||
| 76 | oldnoconfig: 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"). | ||
| 81 | silentoldconfig: 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 | ||
| 87 | savedefconfig: $(obj)/conf | 73 | savedefconfig: $(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 | ||
| 38 | RUNMAKE=true | 40 | RUNMAKE=true |
| 39 | ALLTARGET=alldefconfig | 41 | ALLTARGET=alldefconfig |
| 40 | WARNREDUN=false | 42 | WARNREDUN=false |
| 41 | OUTPUT=. | 43 | OUTPUT=. |
| 44 | CONFIG_PREFIX=${CONFIG_-CONFIG_} | ||
| 42 | 45 | ||
| 43 | while true; do | 46 | while true; do |
| 44 | case $1 in | 47 | case $1 in |
| @@ -99,7 +102,8 @@ if [ ! -r "$INITFILE" ]; then | |||
| 99 | fi | 102 | fi |
| 100 | 103 | ||
| 101 | MERGE_LIST=$* | 104 | MERGE_LIST=$* |
| 102 | SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p" | 105 | SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)[= ].*/\2/p" |
| 106 | |||
| 103 | TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) | 107 | TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) |
| 104 | 108 | ||
| 105 | echo "Using $INITFILE as base" | 109 | echo "Using $INITFILE as base" |
diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 8f0f508a78e9..ffbe901a37b5 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc | |||
| @@ -1904,13 +1904,13 @@ sub process_name($$) { | |||
| 1904 | ++$warnings; | 1904 | ++$warnings; |
| 1905 | } | 1905 | } |
| 1906 | 1906 | ||
| 1907 | if ($identifier =~ m/^struct/) { | 1907 | if ($identifier =~ m/^struct\b/) { |
| 1908 | $decl_type = 'struct'; | 1908 | $decl_type = 'struct'; |
| 1909 | } elsif ($identifier =~ m/^union/) { | 1909 | } elsif ($identifier =~ m/^union\b/) { |
| 1910 | $decl_type = 'union'; | 1910 | $decl_type = 'union'; |
| 1911 | } elsif ($identifier =~ m/^enum/) { | 1911 | } elsif ($identifier =~ m/^enum\b/) { |
| 1912 | $decl_type = 'enum'; | 1912 | $decl_type = 'enum'; |
| 1913 | } elsif ($identifier =~ m/^typedef/) { | 1913 | } elsif ($identifier =~ m/^typedef\b/) { |
| 1914 | $decl_type = 'typedef'; | 1914 | $decl_type = 'typedef'; |
| 1915 | } else { | 1915 | } else { |
| 1916 | $decl_type = 'function'; | 1916 | $decl_type = 'function'; |
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 | |||
| 14 | test ! -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) |
| 17 | if test -e $2/Makefile && ! grep -q Automatically $2/Makefile | 12 | if test -e Makefile && ! grep -q Automatically Makefile |
| 18 | then | 13 | then |
| 19 | exit 0 | 14 | exit 0 |
| 20 | fi | 15 | fi |
| 21 | if [ "${quiet}" != "silent_" ]; then | 16 | if [ "${quiet}" != "silent_" ]; then |
| 22 | echo " GEN $2/Makefile" | 17 | echo " GEN Makefile" |
| 23 | fi | 18 | fi |
| 24 | 19 | ||
| 25 | cat << EOF > $2/Makefile | 20 | cat << EOF > Makefile |
| 26 | # Automatically generated by $0: don't edit | 21 | # Automatically generated by $0: don't edit |
| 27 | 22 | ||
| 28 | VERSION = $3 | ||
| 29 | PATCHLEVEL = $4 | ||
| 30 | |||
| 31 | lastword = \$(word \$(words \$(1)),\$(1)) | ||
| 32 | makedir := \$(dir \$(call lastword,\$(MAKEFILE_LIST))) | ||
| 33 | |||
| 34 | ifeq ("\$(origin V)", "command line") | 23 | ifeq ("\$(origin V)", "command line") |
| 35 | VERBOSE := \$(V) | 24 | VERBOSE := \$(V) |
| 36 | endif | 25 | endif |
| @@ -38,15 +27,12 @@ ifneq (\$(VERBOSE),1) | |||
| 38 | Q := @ | 27 | Q := @ |
| 39 | endif | 28 | endif |
| 40 | 29 | ||
| 41 | MAKEARGS := -C $1 | ||
| 42 | MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$(makedir)) | ||
| 43 | |||
| 44 | MAKEFLAGS += --no-print-directory | 30 | MAKEFLAGS += --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/Makefile b/scripts/mod/Makefile index 42c5d50f2bcc..a5b4af47987a 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile | |||
| @@ -4,6 +4,8 @@ OBJECT_FILES_NON_STANDARD := y | |||
| 4 | hostprogs-y := modpost mk_elfconfig | 4 | hostprogs-y := modpost mk_elfconfig |
| 5 | always := $(hostprogs-y) empty.o | 5 | always := $(hostprogs-y) empty.o |
| 6 | 6 | ||
| 7 | CFLAGS_REMOVE_empty.o := $(ASM_MACRO_FLAGS) | ||
| 8 | |||
| 7 | modpost-objs := modpost.o file2alias.o sumversion.o | 9 | modpost-objs := modpost.o file2alias.o sumversion.o |
| 8 | 10 | ||
| 9 | devicetable-offsets-file := devicetable-offsets.h | 11 | devicetable-offsets-file := devicetable-offsets.h |
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 | ) |
| 208 | regex_kconfig=( | 208 | regex_kconfig=( |
| 209 | '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/' | 209 | '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/' |
