summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Kconfig.include2
-rw-r--r--scripts/Makefile1
-rw-r--r--scripts/Makefile.autofdo6
-rw-r--r--scripts/Makefile.btf21
-rw-r--r--scripts/Makefile.build19
-rw-r--r--scripts/Makefile.compiler2
-rw-r--r--scripts/Makefile.context-analysis11
-rw-r--r--scripts/Makefile.dtbs1
-rw-r--r--scripts/Makefile.kasan2
-rw-r--r--scripts/Makefile.lib30
-rw-r--r--scripts/Makefile.modfinal15
-rw-r--r--scripts/Makefile.package4
-rw-r--r--scripts/Makefile.thinlto40
-rw-r--r--scripts/Makefile.vdsoinst7
-rw-r--r--scripts/Makefile.vmlinux5
-rw-r--r--scripts/Makefile.vmlinux_a82
-rw-r--r--scripts/Makefile.warn42
-rwxr-xr-xscripts/atomic/gen-rust-atomic-helpers.sh5
-rw-r--r--scripts/atomic/kerneldoc/try_cmpxchg2
-rwxr-xr-xscripts/bloat-o-meter7
-rwxr-xr-xscripts/cc-can-link.sh2
-rwxr-xr-xscripts/check-uapi.sh19
-rwxr-xr-xscripts/checker-valid.sh19
-rwxr-xr-xscripts/checkpatch.pl89
-rwxr-xr-xscripts/checksyscalls.sh11
-rwxr-xr-xscripts/clang-tools/run-clang-tools.py15
-rwxr-xr-xscripts/coccicheck21
-rw-r--r--scripts/coccinelle/api/kmalloc_objs.cocci135
-rwxr-xr-xscripts/container199
-rw-r--r--scripts/context-analysis-suppression.txt34
-rwxr-xr-xscripts/crypto/gen-fips-testvecs.py10
-rwxr-xr-xscripts/crypto/gen-hash-testvecs.py137
-rwxr-xr-xscripts/decode_stacktrace.sh26
-rwxr-xr-xscripts/decodecode3
-rw-r--r--scripts/dtc/checks.c44
-rwxr-xr-xscripts/dtc/dt-extract-compatibles1
-rw-r--r--scripts/dtc/dtc-lexer.l3
-rw-r--r--scripts/dtc/dtc.c5
-rw-r--r--scripts/dtc/dtc.h8
-rw-r--r--scripts/dtc/flattree.c6
-rw-r--r--scripts/dtc/libfdt/fdt.c8
-rw-r--r--scripts/dtc/libfdt/fdt_overlay.c3
-rw-r--r--scripts/dtc/libfdt/fdt_ro.c4
-rw-r--r--scripts/dtc/libfdt/fdt_rw.c9
-rw-r--r--scripts/dtc/libfdt/libfdt.h214
-rw-r--r--scripts/dtc/libfdt/libfdt_env.h27
-rw-r--r--scripts/dtc/libfdt/libfdt_internal.h14
-rw-r--r--scripts/dtc/livetree.c309
-rw-r--r--scripts/dtc/srcpos.c22
-rw-r--r--scripts/dtc/treesource.c114
-rw-r--r--scripts/dtc/version_gen.h2
-rwxr-xr-xscripts/dummy-tools/python34
-rw-r--r--scripts/gcc-plugins/gcc-common.h4
-rw-r--r--scripts/gdb/linux/constants.py.in2
-rw-r--r--scripts/gdb/linux/interrupts.py106
-rw-r--r--scripts/gdb/linux/mm.py173
-rw-r--r--scripts/gdb/linux/slab.py4
-rw-r--r--scripts/gdb/linux/symbols.py2
-rw-r--r--scripts/gdb/linux/timerlist.py6
-rwxr-xr-xscripts/gen-btf.sh147
-rw-r--r--scripts/gendwarfksyms/dwarf.c4
-rw-r--r--scripts/gendwarfksyms/symbols.c5
-rwxr-xr-xscripts/generate_rust_analyzer.py363
-rw-r--r--scripts/generate_rust_target.rs8
-rw-r--r--scripts/genksyms/parse.y4
-rwxr-xr-xscripts/get_maintainer.pl9
-rwxr-xr-xscripts/headers_install.sh30
-rw-r--r--scripts/kallsyms.c64
-rw-r--r--scripts/kconfig/Makefile4
-rw-r--r--scripts/kconfig/conf.c6
-rw-r--r--scripts/kconfig/gconf.c35
-rw-r--r--scripts/kconfig/icons/back.xpm29
-rw-r--r--scripts/kconfig/icons/choice_no.xpm18
-rw-r--r--scripts/kconfig/icons/choice_yes.xpm18
-rw-r--r--scripts/kconfig/icons/load.xpm31
-rw-r--r--scripts/kconfig/icons/menu.xpm18
-rw-r--r--scripts/kconfig/icons/menuback.xpm18
-rw-r--r--scripts/kconfig/icons/save.xpm31
-rw-r--r--scripts/kconfig/icons/single_view.xpm28
-rw-r--r--scripts/kconfig/icons/split_view.xpm28
-rw-r--r--scripts/kconfig/icons/symbol_mod.xpm18
-rw-r--r--scripts/kconfig/icons/symbol_no.xpm18
-rw-r--r--scripts/kconfig/icons/symbol_yes.xpm18
-rw-r--r--scripts/kconfig/icons/tree_view.xpm28
-rw-r--r--scripts/kconfig/images.c328
-rw-r--r--scripts/kconfig/images.h33
-rwxr-xr-xscripts/kconfig/kconfig-sym-check.pl132
-rw-r--r--scripts/kconfig/lexer.l4
-rw-r--r--scripts/kconfig/lkc.h5
-rw-r--r--scripts/kconfig/menu.c12
-rwxr-xr-xscripts/kconfig/merge_config.sh272
-rw-r--r--scripts/kconfig/parser.y21
-rw-r--r--scripts/kconfig/qconf.cc29
-rwxr-xr-xscripts/kconfig/streamline_config.pl2
-rw-r--r--scripts/kconfig/tests/conditional_dep/Kconfig32
-rw-r--r--scripts/kconfig/tests/conditional_dep/__init__.py14
-rw-r--r--scripts/kconfig/tests/conditional_dep/expected_config111
-rw-r--r--scripts/kconfig/tests/conditional_dep/expected_config29
-rw-r--r--scripts/kconfig/tests/conditional_dep/expected_config311
-rw-r--r--scripts/kconfig/tests/conditional_dep/test_config16
-rw-r--r--scripts/kconfig/tests/conditional_dep/test_config27
-rw-r--r--scripts/kconfig/tests/conditional_dep/test_config36
-rw-r--r--scripts/kconfig/tests/err_repeated_inc/Kconfig3
-rw-r--r--scripts/kconfig/tests/err_repeated_inc/Kconfig.inc14
-rw-r--r--scripts/kconfig/tests/err_repeated_inc/Kconfig.inc23
-rw-r--r--scripts/kconfig/tests/err_repeated_inc/Kconfig.inc31
-rw-r--r--scripts/kconfig/tests/err_repeated_inc/__init__.py10
-rw-r--r--scripts/kconfig/tests/err_repeated_inc/expected_stderr2
-rw-r--r--scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py2
-rw-r--r--scripts/kconfig/util.c31
l---------scripts/kernel-doc2
-rwxr-xr-xscripts/kernel-doc.py339
-rwxr-xr-xscripts/link-vmlinux.sh47
-rw-r--r--scripts/livepatch/Makefile20
-rw-r--r--scripts/livepatch/init.c22
-rwxr-xr-xscripts/livepatch/klp-build386
-rwxr-xr-xscripts/make_fit.py177
-rwxr-xr-xscripts/min-tool-version.sh6
-rw-r--r--scripts/mod/file2alias.c79
-rw-r--r--scripts/mod/modpost.c52
-rw-r--r--scripts/module.lds.S26
-rw-r--r--scripts/package/PKGBUILD5
-rwxr-xr-xscripts/package/builddeb8
-rwxr-xr-xscripts/package/install-extmod-build4
-rw-r--r--scripts/package/kernel.spec67
-rwxr-xr-xscripts/package/mkspec38
-rwxr-xr-xscripts/rust_is_available.sh36
-rw-r--r--scripts/rust_is_available_bindgen_0_66.h2
-rw-r--r--scripts/rust_is_available_bindgen_libclang_concat.h3
-rwxr-xr-xscripts/rust_is_available_test.py58
-rw-r--r--scripts/rustdoc_test_gen.rs6
-rw-r--r--scripts/sign-file.c118
-rw-r--r--scripts/spelling.txt332
-rw-r--r--scripts/syscall.tbl1
-rwxr-xr-xscripts/tags.sh1
-rwxr-xr-xscripts/timer_migration_tree.py122
-rwxr-xr-xscripts/ver_linux63
137 files changed, 4109 insertions, 1999 deletions
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
index d42042b6c9e2..fc10671c297c 100644
--- a/scripts/Kconfig.include
+++ b/scripts/Kconfig.include
@@ -73,8 +73,6 @@ rustc-llvm-version := $(shell,$(srctree)/scripts/rustc-llvm-version.sh $(RUSTC))
# $(rustc-option,<flag>)
# Return y if the Rust compiler supports <flag>, n otherwise
-# Calls to this should be guarded so that they are not evaluated if
-# CONFIG_RUST_IS_AVAILABLE is not set.
# If you are testing for unstable features, consider testing RUSTC_VERSION
# instead, as features may have different completeness while available.
rustc-option = $(success,trap "rm -rf .tmp_$$" EXIT; mkdir .tmp_$$; $(RUSTC) $(1) --crate-type=rlib /dev/null --out-dir=.tmp_$$ -o .tmp_$$/tmp.rlib)
diff --git a/scripts/Makefile b/scripts/Makefile
index 0941e5ce7b57..3434a82a119f 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -35,6 +35,7 @@ HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
HOSTLDLIBS_sorttable = -lpthread
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null)
+HOSTCFLAGS_sign-file.o += -I$(srctree)/tools/include/uapi/
HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null || echo -lcrypto)
ifdef CONFIG_UNWINDER_ORC
diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo
index 1caf2457e585..1442043da139 100644
--- a/scripts/Makefile.autofdo
+++ b/scripts/Makefile.autofdo
@@ -3,14 +3,18 @@
# Enable available and selected Clang AutoFDO features.
CFLAGS_AUTOFDO_CLANG := -fdebug-info-for-profiling -mllvm -enable-fs-discriminator=true -mllvm -improved-fs-discriminator=true
+RUSTFLAGS_AUTOFDO_CLANG := $(if $(call rustc-min-version,109800),-Zdebuginfo-for-profiling,-Zdebug-info-for-profiling) -Cllvm-args=-enable-fs-discriminator=true -Cllvm-args=-improved-fs-discriminator=true
ifndef CONFIG_DEBUG_INFO
CFLAGS_AUTOFDO_CLANG += -gmlt
+ RUSTFLAGS_AUTOFDO_CLANG += -Cdebuginfo=line-tables-only
endif
ifdef CLANG_AUTOFDO_PROFILE
CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -ffunction-sections
CFLAGS_AUTOFDO_CLANG += -fsplit-machine-functions
+ RUSTFLAGS_AUTOFDO_CLANG += -Zprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -Zfunction-sections=y
+ RUSTFLAGS_AUTOFDO_CLANG += -Cllvm-args=-split-machine-functions
endif
ifdef CONFIG_LTO_CLANG_THIN
@@ -21,4 +25,4 @@ ifdef CONFIG_LTO_CLANG_THIN
KBUILD_LDFLAGS += -plugin-opt=-split-machine-functions
endif
-export CFLAGS_AUTOFDO_CLANG
+export CFLAGS_AUTOFDO_CLANG RUSTFLAGS_AUTOFDO_CLANG
diff --git a/scripts/Makefile.btf b/scripts/Makefile.btf
index db76335dd917..e66e13e79653 100644
--- a/scripts/Makefile.btf
+++ b/scripts/Makefile.btf
@@ -7,14 +7,7 @@ JOBS := $(patsubst -j%,%,$(filter -j%,$(MAKEFLAGS)))
ifeq ($(call test-le, $(pahole-ver), 125),y)
-# pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars
-ifeq ($(call test-le, $(pahole-ver), 121),y)
-pahole-flags-$(call test-ge, $(pahole-ver), 118) += --skip_encoding_btf_vars
-endif
-
-pahole-flags-$(call test-ge, $(pahole-ver), 121) += --btf_gen_floats
-
-pahole-flags-$(call test-ge, $(pahole-ver), 122) += -j$(JOBS)
+pahole-flags-y += --btf_gen_floats -j$(JOBS)
pahole-flags-$(call test-ge, $(pahole-ver), 125) += --skip_encoding_btf_inconsistent_proto --btf_gen_optimized
@@ -25,13 +18,17 @@ pahole-flags-$(call test-ge, $(pahole-ver), 126) = -j$(JOBS) --btf_features=enc
pahole-flags-$(call test-ge, $(pahole-ver), 130) += --btf_features=attributes
-ifneq ($(KBUILD_EXTMOD),)
-module-pahole-flags-$(call test-ge, $(pahole-ver), 128) += --btf_features=distilled_base
-endif
+pahole-flags-$(call test-ge, $(pahole-ver), 131) += --btf_features=layout
endif
pahole-flags-$(CONFIG_PAHOLE_HAS_LANG_EXCLUDE) += --lang_exclude=rust
export PAHOLE_FLAGS := $(pahole-flags-y)
-export MODULE_PAHOLE_FLAGS := $(module-pahole-flags-y)
+
+resolve-btfids-flags-y :=
+resolve-btfids-flags-$(CONFIG_WERROR) += --fatal_warnings
+resolve-btfids-flags-$(if $(KBUILD_EXTMOD),y) += --distill_base
+resolve-btfids-flags-$(if $(KBUILD_VERBOSE),y) += --verbose
+
+export RESOLVE_BTFIDS_FLAGS := $(resolve-btfids-flags-y)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 5037f4715d74..911745743246 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -166,11 +166,13 @@ else ifeq ($(KBUILD_CHECKSRC),2)
cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $<
endif
+ifeq ($(KBUILD_EXTMOD),)
ifneq ($(KBUILD_EXTRA_WARN),)
cmd_checkdoc = PYTHONDONTWRITEBYTECODE=1 $(PYTHON3) $(KERNELDOC) -none $(KDOCFLAGS) \
$(if $(findstring 2, $(KBUILD_EXTRA_WARN)), -Wall) \
$<
endif
+endif
# Compile C sources (.c)
# ---------------------------------------------------------------------------
@@ -308,16 +310,14 @@ $(obj)/%.lst: $(obj)/%.c FORCE
# The features in this list are the ones allowed for non-`rust/` code.
#
-# - Stable since Rust 1.81.0: `feature(lint_reasons)`.
-# - Stable since Rust 1.82.0: `feature(asm_const)`,
-# `feature(offset_of_nested)`, `feature(raw_ref_op)`.
# - Stable since Rust 1.87.0: `feature(asm_goto)`.
+# - Stable since Rust 1.89.0: `feature(generic_arg_infer)`.
# - Expected to become stable: `feature(arbitrary_self_types)`.
# - To be determined: `feature(used_with_arg)`.
#
# Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
# the unstable features in use.
-rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg
+rust_allowed_features := arbitrary_self_types,asm_goto,generic_arg_infer,used_with_arg
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
# current working directory, which may be not accessible in the out-of-tree
@@ -329,8 +329,8 @@ rust_common_cmd = \
-Zcrate-attr=no_std \
-Zcrate-attr='feature($(rust_allowed_features))' \
-Zunstable-options --extern pin_init --extern kernel \
+ --extern zerocopy --extern zerocopy_derive \
--crate-type rlib -L $(objtree)/rust/ \
- --crate-name $(basename $(notdir $@)) \
--sysroot=/dev/null \
--out-dir $(dir $@) --emit=dep-info=$(depfile)
@@ -343,7 +343,12 @@ rust_common_cmd = \
# would not match each other.
quiet_cmd_rustc_o_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
- cmd_rustc_o_rs = $(rust_common_cmd) --emit=obj=$@ $< $(cmd_objtool)
+ cmd_rustc_o_rs = $(rust_common_cmd) --emit=$(if $(CONFIG_RUST_INLINE_HELPERS),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) $< \
+ $(if $(CONFIG_RUST_INLINE_HELPERS),;$(LLVM_LINK) --internalize --suppress-warnings $(patsubst %.o,%.bc,$@) \
+ $(objtree)/rust/helpers/helpers$(if $(part-of-module),_module).bc -o $(patsubst %.o,%.m.bc,$@); \
+ $(CC) $(CLANG_FLAGS) $(KBUILD_CFLAGS) -Wno-override-module -c $(patsubst %.o,%.m.bc,$@) -o $@ \
+ $(cmd_ld_single)) \
+ $(cmd_objtool)
define rule_rustc_o_rs
$(call cmd_and_fixdep,rustc_o_rs)
@@ -356,7 +361,7 @@ $(obj)/%.o: $(obj)/%.rs FORCE
quiet_cmd_rustc_rsi_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@
cmd_rustc_rsi_rs = \
$(rust_common_cmd) -Zunpretty=expanded $< >$@; \
- command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@
+ command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) --config-path $(srctree)/.rustfmt.toml $@
$(obj)/%.rsi: $(obj)/%.rs FORCE
+$(call if_changed_dep,rustc_rsi_rs)
diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler
index ef91910de265..06bbe29c846c 100644
--- a/scripts/Makefile.compiler
+++ b/scripts/Makefile.compiler
@@ -80,7 +80,7 @@ ld-option = $(call try-run, $(LD) $(KBUILD_LDFLAGS) $(1) -v,$(1),$(2),$(3))
# TODO: remove RUSTC_BOOTSTRAP=1 when we raise the minimum GNU Make version to 4.4
__rustc-option = $(call try-run,\
echo '$(pound)![allow(missing_docs)]$(pound)![feature(no_core)]$(pound)![no_core]' | RUSTC_BOOTSTRAP=1\
- $(1) --sysroot=/dev/null $(filter-out --sysroot=/dev/null --target=%,$(2)) $(3)\
+ $(1) --sysroot=/dev/null $(KBUILD_RUSTFLAGS_OPTION_CHKS) $(filter-out --sysroot=/dev/null --target=%target.json,$(2)) $(3)\
--crate-type=rlib --out-dir=$(TMPOUT) --emit=obj=- - >/dev/null,$(3),$(4))
# rustc-option
diff --git a/scripts/Makefile.context-analysis b/scripts/Makefile.context-analysis
new file mode 100644
index 000000000000..cd3bb49d3f09
--- /dev/null
+++ b/scripts/Makefile.context-analysis
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+context-analysis-cflags := -DWARN_CONTEXT_ANALYSIS \
+ -fexperimental-late-parse-attributes -Wthread-safety \
+ -Wthread-safety-pointer -Wthread-safety-beta
+
+ifndef CONFIG_WARN_CONTEXT_ANALYSIS_ALL
+context-analysis-cflags += --warning-suppression-mappings=$(srctree)/scripts/context-analysis-suppression.txt
+endif
+
+export CFLAGS_CONTEXT_ANALYSIS := $(context-analysis-cflags)
diff --git a/scripts/Makefile.dtbs b/scripts/Makefile.dtbs
index e092b460d5a1..c4e466390284 100644
--- a/scripts/Makefile.dtbs
+++ b/scripts/Makefile.dtbs
@@ -105,7 +105,6 @@ ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),)
DTC_FLAGS += -Wno-unit_address_vs_reg \
-Wno-avoid_unnecessary_addr_size \
-Wno-alias_paths \
- -Wno-graph_child_address \
-Wno-interrupt_map \
-Wno-simple_bus_reg
else
diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan
index 0ba2aac3b8dc..91504e81247a 100644
--- a/scripts/Makefile.kasan
+++ b/scripts/Makefile.kasan
@@ -71,8 +71,6 @@ ifdef CONFIG_KASAN_SW_TAGS
CFLAGS_KASAN := -fsanitize=kernel-hwaddress
-# This sets flags that will enable SW_TAGS KASAN once enabled in Rust. These
-# will not work today, and is guarded against in dependencies for CONFIG_RUST.
RUSTFLAGS_KASAN := -Zsanitizer=kernel-hwaddress \
-Zsanitizer-recover=kernel-hwaddress
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 28a1c08e3b22..0a4fdd8bd975 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -106,6 +106,16 @@ _c_flags += $(if $(patsubst n%,, \
endif
#
+# Enable context analysis flags only where explicitly opted in.
+# (depends on variables CONTEXT_ANALYSIS_obj.o, CONTEXT_ANALYSIS)
+#
+ifeq ($(CONFIG_WARN_CONTEXT_ANALYSIS),y)
+_c_flags += $(if $(patsubst n%,, \
+ $(CONTEXT_ANALYSIS_$(target-stem).o)$(CONTEXT_ANALYSIS)$(if $(is-kernel-object),$(CONFIG_WARN_CONTEXT_ANALYSIS_ALL))), \
+ $(CFLAGS_CONTEXT_ANALYSIS))
+endif
+
+#
# Enable AutoFDO build flags except some files or directories we don't want to
# enable (depends on variables AUTOFDO_PROFILE_obj.o and AUTOFDO_PROFILE).
#
@@ -113,6 +123,9 @@ ifeq ($(CONFIG_AUTOFDO_CLANG),y)
_c_flags += $(if $(patsubst n%,, \
$(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(is-kernel-object)), \
$(CFLAGS_AUTOFDO_CLANG))
+_rust_flags += $(if $(patsubst n%,, \
+ $(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(is-kernel-object)), \
+ $(RUSTFLAGS_AUTOFDO_CLANG))
endif
#
@@ -177,7 +190,11 @@ objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label
objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr
objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) += --hacks=skylake
objtool-args-$(CONFIG_X86_KERNEL_IBT) += --ibt
-objtool-args-$(CONFIG_FINEIBT) += --cfi
+objtool-args-$(CONFIG_CALL_PADDING) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
+ifdef CONFIG_CALL_PADDING
+objtool-args-$(CONFIG_CFI) += --cfi
+objtool-args-$(CONFIG_FINEIBT) += --fineibt
+endif
objtool-args-$(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL) += --mcount
ifdef CONFIG_FTRACE_MCOUNT_USE_OBJTOOL
objtool-args-$(CONFIG_HAVE_OBJTOOL_NOP_MCOUNT) += --mnop
@@ -190,7 +207,6 @@ objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval
objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call
objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess
objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV)) += --no-unreachable
-objtool-args-$(CONFIG_PREFIX_SYMBOLS) += --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
objtool-args-$(CONFIG_OBJTOOL_WERROR) += --werror
objtool-args = $(objtool-args-y) \
@@ -239,6 +255,13 @@ ifdef CONFIG_LTO_CLANG
cmd_ld_single = $(if $(objtool-enabled)$(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@)
endif
+ifdef CONFIG_LTO_CLANG_THIN_DIST
+# Save the _c_flags, sliently.
+quiet_cmd_save_c_flags =
+ saved_c_flags = $(_c_flags) $(modkern_cflags)
+ cmd_save_c_flags = printf '\n%s\n' 'saved_c_flags_$@ := $(call escsq,$(saved_c_flags))' >> $(dot-target).cmd
+endif
+
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \
$(cmd_ld_single) \
@@ -246,6 +269,7 @@ quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
define rule_cc_o_c
$(call cmd_and_fixdep,cc_o_c)
+ $(call cmd,save_c_flags)
$(call cmd,checksrc)
$(call cmd,checkdoc)
$(call cmd,gen_objtooldep)
@@ -400,7 +424,7 @@ FIT_COMPRESSION ?= gzip
quiet_cmd_fit = FIT $@
cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
- --name '$(UIMAGE_NAME)' \
+ --name '$(UIMAGE_NAME)' $(FIT_EXTRA_ARGS) \
$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
$(if $(FIT_DECOMPOSE_DTBS),--decompose-dtbs) \
--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 149e12ff5700..01a37ec872b9 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -42,22 +42,13 @@ quiet_cmd_btf_ko = BTF [M] $@
cmd_btf_ko = \
if [ ! -f $(objtree)/vmlinux ]; then \
printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \
- else \
- LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base $(objtree)/vmlinux $@; \
- $(RESOLVE_BTFIDS) -b $(objtree)/vmlinux $@; \
+ else \
+ $(CONFIG_SHELL) $(srctree)/scripts/gen-btf.sh --btf_base $(objtree)/vmlinux $@; \
fi;
-# Same as newer-prereqs, but allows to exclude specified extra dependencies
-newer_prereqs_except = $(filter-out $(PHONY) $(1),$?)
-
-# Same as if_changed, but allows to exclude specified extra dependencies
-if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \
- $(cmd); \
- printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
-
# Re-generate module BTFs if either module's .ko or vmlinux changed
%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
- +$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux)
+ +$(call if_changed,ld_ko_o)
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+$(if $(newer-prereqs),$(call cmd,btf_ko))
endif
diff --git a/scripts/Makefile.package b/scripts/Makefile.package
index 83bfcf7cb09f..6d36786ba31c 100644
--- a/scripts/Makefile.package
+++ b/scripts/Makefile.package
@@ -195,13 +195,12 @@ tar%-pkg: linux-$(KERNELRELEASE)-$(ARCH).tar.% FORCE
.tmp_modules_cpio: FORCE
$(Q)$(MAKE) -f $(srctree)/Makefile
$(Q)rm -rf $@
- $(Q)$(MAKE) -f $(srctree)/Makefile INSTALL_MOD_PATH=$@ modules_install
+ $(Q)$(MAKE) -f $(srctree)/Makefile INSTALL_MOD_PATH=$@/$(INSTALL_MOD_PATH) modules_install
quiet_cmd_cpio = CPIO $@
cmd_cpio = $(CONFIG_SHELL) $(srctree)/usr/gen_initramfs.sh -o $@ $<
modules-$(KERNELRELEASE)-$(ARCH).cpio: .tmp_modules_cpio
- $(Q)$(MAKE) $(build)=usr usr/gen_init_cpio
$(call cmd,cpio)
PHONY += modules-cpio-pkg
@@ -265,6 +264,7 @@ help:
@echo ' tarxz-pkg - Build the kernel as a xz compressed tarball'
@echo ' tarzst-pkg - Build the kernel as a zstd compressed tarball'
@echo ' modules-cpio-pkg - Build the kernel modules as cpio archive'
+ @echo ' (uses INSTALL_MOD_PATH inside the archive)'
@echo ' perf-tar-src-pkg - Build the perf source tarball with no compression'
@echo ' perf-targz-src-pkg - Build the perf source tarball with gzip compression'
@echo ' perf-tarbz2-src-pkg - Build the perf source tarball with bz2 compression'
diff --git a/scripts/Makefile.thinlto b/scripts/Makefile.thinlto
new file mode 100644
index 000000000000..bb83f13f3cd6
--- /dev/null
+++ b/scripts/Makefile.thinlto
@@ -0,0 +1,40 @@
+PHONY := __default
+__default:
+
+include include/config/auto.conf
+include $(srctree)/scripts/Kbuild.include
+include $(srctree)/scripts/Makefile.lib
+
+native-objs := $(patsubst %.o,%.thinlto-native.o,$(call read-file, vmlinux.thinlto-index))
+
+__default: $(native-objs)
+
+# Generate .thinlto-native.o (obj) from .o (bitcode) and .thinlto.bc (summary) files
+# ---------------------------------------------------------------------------
+quiet_cmd_cc_o_bc = CC $(quiet_modtag) $@
+ be_flags = $(shell sed -n '/saved_c_flags_/s/.*:= //p' \
+ $(dir $(<)).$(notdir $(<)).cmd)
+ cmd_cc_o_bc = \
+ $(CC) $(be_flags) -x ir -fno-lto -Wno-unused-command-line-argument \
+ -fthinlto-index=$(word 2, $^) -c -o $@ $<
+
+targets += $(native-objs)
+$(native-objs): %.thinlto-native.o: %.o %.o.thinlto.bc FORCE
+ $(call if_changed,cc_o_bc)
+
+# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+existing-targets := $(wildcard $(sort $(targets)))
+
+-include $(foreach f, $(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.vdsoinst b/scripts/Makefile.vdsoinst
index ac85f9a4a569..d9f7243217bc 100644
--- a/scripts/Makefile.vdsoinst
+++ b/scripts/Makefile.vdsoinst
@@ -19,9 +19,10 @@ __default: $$(dest)
$$(dest): $(1) FORCE
$$(call cmd,install)
-# Some architectures create .build-id symlinks
-ifneq ($(filter arm s390 sparc x86, $(SRCARCH)),)
-link := $(install-dir)/.build-id/$$(shell $(READELF) -n $(1) | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p').debug
+build-id-file := $$(shell $(READELF) -n $(1) 2>/dev/null | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p')
+
+ifneq ($$(build-id-file),)
+link := $(install-dir)/.build-id/$$(build-id-file).debug
__default: $$(link)
$$(link): $$(dest) FORCE
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index cd788cac9d91..fcae1e432d9a 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -71,7 +71,7 @@ targets += vmlinux.unstripped .vmlinux.export.o
vmlinux.unstripped: scripts/link-vmlinux.sh vmlinux.o .vmlinux.export.o $(KBUILD_LDS) FORCE
+$(call if_changed_dep,link_vmlinux)
ifdef CONFIG_DEBUG_INFO_BTF
-vmlinux.unstripped: $(RESOLVE_BTFIDS)
+vmlinux.unstripped: $(RESOLVE_BTFIDS) $(srctree)/scripts/gen-btf.sh
endif
ifdef CONFIG_BUILDTIME_TABLE_SORT
@@ -113,7 +113,8 @@ vmlinux: vmlinux.unstripped FORCE
# what kmod expects to parse.
quiet_cmd_modules_builtin_modinfo = GEN $@
cmd_modules_builtin_modinfo = $(cmd_objcopy); \
- sed -i 's/\x00\+$$/\x00/g' $@
+ sed -i 's/\x00\+$$/\x00/g' $@; \
+ chmod -x $@
OBJCOPYFLAGS_modules.builtin.modinfo := -j .modinfo -O binary
diff --git a/scripts/Makefile.vmlinux_a b/scripts/Makefile.vmlinux_a
new file mode 100644
index 000000000000..395e29998d7d
--- /dev/null
+++ b/scripts/Makefile.vmlinux_a
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+PHONY := __default
+__default: vmlinux.a
+
+include include/config/auto.conf
+include $(srctree)/scripts/Kbuild.include
+include $(srctree)/scripts/Makefile.lib
+
+# Link of built-in-fixup.a
+# ---------------------------------------------------------------------------
+
+quiet_cmd_ar_builtin_fixup = AR $@
+ cmd_ar_builtin_fixup = \
+ rm -f $@; \
+ $(AR) cDPrST $@ $(KBUILD_VMLINUX_OBJS); \
+ $(AR) mPi $$($(AR) t $@ | sed -n 1p) $@ $$($(AR) t $@ | grep -F -f $(srctree)/scripts/head-object-list.txt)
+
+targets += built-in-fixup.a
+built-in-fixup.a: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt FORCE
+ $(call if_changed,ar_builtin_fixup)
+
+ifdef CONFIG_LTO_CLANG_THIN_DIST
+
+quiet_cmd_builtin.order = GEN $@
+ cmd_builtin.order = $(AR) t $< > $@
+
+targets += builtin.order
+builtin.order: built-in-fixup.a FORCE
+ $(call if_changed,builtin.order)
+
+quiet_cmd_ld_thinlto_index = LD $@
+ cmd_ld_thinlto_index = \
+ $(LD) $(KBUILD_LDFLAGS) -r --thinlto-index-only=$@ @$<
+
+targets += vmlinux.thinlto-index
+vmlinux.thinlto-index: builtin.order FORCE
+ $(call if_changed,ld_thinlto_index)
+
+quiet_cmd_ar_vmlinux.a = GEN $@
+ cmd_ar_vmlinux.a = \
+ rm -f $@; \
+ while read -r obj; do \
+ if grep -Fqx $${obj} $(word 2, $^); then \
+ echo $${obj%.o}.thinlto-native.o; \
+ else \
+ echo $${obj}; \
+ fi; \
+ done < $< | xargs $(AR) cDPrS --thin $@
+
+targets += vmlinux.a
+vmlinux.a: builtin.order vmlinux.thinlto-index FORCE
+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.thinlto
+ $(call if_changed,ar_vmlinux.a)
+
+else
+
+# vmlinux.a
+# ---------------------------------------------------------------------------
+
+targets += vmlinux.a
+vmlinux.a: built-in-fixup.a FORCE
+ $(call if_changed,copy)
+
+endif
+
+# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+existing-targets := $(wildcard $(sort $(targets)))
+
+-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.warn b/scripts/Makefile.warn
index 68e6fafcb80c..35af7d6c6d18 100644
--- a/scripts/Makefile.warn
+++ b/scripts/Makefile.warn
@@ -16,7 +16,7 @@ KBUILD_CFLAGS += -Werror=return-type
KBUILD_CFLAGS += -Werror=strict-prototypes
KBUILD_CFLAGS += -Wno-format-security
KBUILD_CFLAGS += -Wno-trigraphs
-KBUILD_CFLAGS += $(call cc-option, -Wno-frame-address)
+KBUILD_CFLAGS += -Wno-frame-address
KBUILD_CFLAGS += $(call cc-option, -Wno-address-of-packed-member)
KBUILD_CFLAGS += -Wmissing-declarations
KBUILD_CFLAGS += -Wmissing-prototypes
@@ -28,11 +28,6 @@ endif
KBUILD_CFLAGS-$(CONFIG_CC_NO_ARRAY_BOUNDS) += -Wno-array-bounds
ifdef CONFIG_CC_IS_CLANG
-# The kernel builds with '-std=gnu11' and '-fms-extensions' so use of GNU and
-# Microsoft extensions is acceptable.
-KBUILD_CFLAGS += -Wno-gnu
-KBUILD_CFLAGS += -Wno-microsoft-anon-tag
-
# Clang checks for overflow/truncation with '%p', while GCC does not:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111219
KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow-non-kprintf)
@@ -55,6 +50,9 @@ else
KBUILD_CFLAGS += -Wno-main
endif
+# Too noisy on range checks and in macros handling both signed and unsigned.
+KBUILD_CFLAGS += -Wno-type-limits
+
# These result in bogus false positives
KBUILD_CFLAGS += $(call cc-option, -Wno-dangling-pointer)
@@ -72,7 +70,7 @@ KBUILD_CFLAGS += -Wno-pointer-sign
# In order to make sure new function cast mismatches are not introduced
# in the kernel (to avoid tripping CFI checking), the kernel should be
# globally built with -Wcast-function-type.
-KBUILD_CFLAGS += $(call cc-option, -Wcast-function-type)
+KBUILD_CFLAGS += -Wcast-function-type
# Currently, disable -Wstringop-overflow for GCC 11, globally.
KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(call cc-option, -Wno-stringop-overflow)
@@ -99,7 +97,7 @@ KBUILD_CFLAGS += $(KBUILD_CFLAGS-y) $(CONFIG_CC_IMPLICIT_FALLTHROUGH)
KBUILD_CFLAGS += -Werror=date-time
# enforce correct pointer usage
-KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types)
+KBUILD_CFLAGS += -Werror=incompatible-pointer-types
# Require designated initializers for all marked structures
KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
@@ -116,7 +114,7 @@ ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
KBUILD_CFLAGS += -Wmissing-format-attribute
KBUILD_CFLAGS += -Wmissing-include-dirs
-KBUILD_CFLAGS += $(call cc-option, -Wunused-const-variable)
+KBUILD_CFLAGS += -Wunused-const-variable
KBUILD_CPPFLAGS += -Wundef
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1
@@ -125,34 +123,21 @@ else
# Some diagnostics enabled by default are noisy.
# Suppress them by using -Wno... except for W=1.
-KBUILD_CFLAGS += $(call cc-option, -Wno-unused-but-set-variable)
-KBUILD_CFLAGS += $(call cc-option, -Wno-unused-const-variable)
+KBUILD_CFLAGS += -Wno-unused-but-set-variable
+KBUILD_CFLAGS += -Wno-unused-const-variable
KBUILD_CFLAGS += $(call cc-option, -Wno-packed-not-aligned)
KBUILD_CFLAGS += $(call cc-option, -Wno-format-overflow)
ifdef CONFIG_CC_IS_GCC
-KBUILD_CFLAGS += $(call cc-option, -Wno-format-truncation)
+KBUILD_CFLAGS += -Wno-format-truncation
endif
KBUILD_CFLAGS += $(call cc-option, -Wno-stringop-truncation)
KBUILD_CFLAGS += -Wno-override-init # alias for -Wno-initializer-overrides in clang
ifdef CONFIG_CC_IS_CLANG
-# Clang before clang-16 would warn on default argument promotions.
-ifneq ($(call clang-min-version, 160000),y)
-# Disable -Wformat
-KBUILD_CFLAGS += -Wno-format
-# Then re-enable flags that were part of the -Wformat group that aren't
-# problematic.
-KBUILD_CFLAGS += -Wformat-extra-args -Wformat-invalid-specifier
-KBUILD_CFLAGS += -Wformat-zero-length -Wnonnull
-# Requires clang-12+.
-ifeq ($(call clang-min-version, 120000),y)
-KBUILD_CFLAGS += -Wformat-insufficient-args
-endif
-endif
-KBUILD_CFLAGS += $(call cc-option, -Wno-pointer-to-enum-cast)
+KBUILD_CFLAGS += -Wno-pointer-to-enum-cast
KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare
-KBUILD_CFLAGS += $(call cc-option, -Wno-unaligned-access)
+KBUILD_CFLAGS += -Wno-unaligned-access
KBUILD_CFLAGS += -Wno-enum-compare-conditional
endif
@@ -166,7 +151,7 @@ ifneq ($(findstring 2, $(KBUILD_EXTRA_WARN)),)
KBUILD_CFLAGS += -Wdisabled-optimization
KBUILD_CFLAGS += -Wshadow
KBUILD_CFLAGS += $(call cc-option, -Wlogical-op)
-KBUILD_CFLAGS += $(call cc-option, -Wunused-macros)
+KBUILD_CFLAGS += -Wunused-macros
KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN2
@@ -174,7 +159,6 @@ else
# The following turn off the warnings enabled by -Wextra
KBUILD_CFLAGS += -Wno-missing-field-initializers
-KBUILD_CFLAGS += -Wno-type-limits
KBUILD_CFLAGS += -Wno-shift-negative-value
ifdef CONFIG_CC_IS_CLANG
diff --git a/scripts/atomic/gen-rust-atomic-helpers.sh b/scripts/atomic/gen-rust-atomic-helpers.sh
index 45b1e100ed7c..a3732153af29 100755
--- a/scripts/atomic/gen-rust-atomic-helpers.sh
+++ b/scripts/atomic/gen-rust-atomic-helpers.sh
@@ -47,11 +47,6 @@ cat << EOF
#include <linux/atomic.h>
-// TODO: Remove this after INLINE_HELPERS support is added.
-#ifndef __rust_helper
-#define __rust_helper
-#endif
-
EOF
grep '^[a-z]' "$1" | while read name meta args; do
diff --git a/scripts/atomic/kerneldoc/try_cmpxchg b/scripts/atomic/kerneldoc/try_cmpxchg
index 3ccff29538f5..4dfc7a167ea1 100644
--- a/scripts/atomic/kerneldoc/try_cmpxchg
+++ b/scripts/atomic/kerneldoc/try_cmpxchg
@@ -11,6 +11,6 @@ cat <<EOF
*
* ${desc_noinstr}
*
- * Return: @true if the exchange occured, @false otherwise.
+ * Return: @true if the exchange occurred, @false otherwise.
*/
EOF
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter
index 888ce286a351..9b4fb996d95b 100755
--- a/scripts/bloat-o-meter
+++ b/scripts/bloat-o-meter
@@ -18,8 +18,8 @@ group.add_argument('-c', help='categorize output based on symbol type', action='
group.add_argument('-d', help='Show delta of Data Section', action='store_true')
group.add_argument('-t', help='Show delta of text Section', action='store_true')
parser.add_argument('-p', dest='prefix', help='Arch prefix for the tool being used. Useful in cross build scenarios')
-parser.add_argument('file1', help='First file to compare')
-parser.add_argument('file2', help='Second file to compare')
+parser.add_argument('file_old', help='First file to compare')
+parser.add_argument('file_new', help='Second file to compare')
args = parser.parse_args()
@@ -42,6 +42,7 @@ def getsizes(file, format):
if name.startswith("__se_sys"): continue
if name.startswith("__se_compat_sys"): continue
if name.startswith("__addressable_"): continue
+ if name.startswith("__noinstr_text_start"): continue
if name == "linux_banner": continue
if name == "vermagic": continue
# statics and some other optimizations adds random .NUMBER
@@ -85,7 +86,7 @@ def calc(oldfile, newfile, format):
def print_result(symboltype, symbolformat):
grow, shrink, add, remove, up, down, delta, old, new, otot, ntot = \
- calc(args.file1, args.file2, symbolformat)
+ calc(args.file_old, args.file_new, symbolformat)
print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
(add, remove, grow, shrink, up, -down, up-down))
diff --git a/scripts/cc-can-link.sh b/scripts/cc-can-link.sh
index e67fd8d7b684..58dc7dd6d556 100755
--- a/scripts/cc-can-link.sh
+++ b/scripts/cc-can-link.sh
@@ -5,7 +5,7 @@ cat << "END" | $@ -Werror -Wl,--fatal-warnings -x c - -o /dev/null >/dev/null 2>
#include <stdio.h>
int main(void)
{
- printf("");
+ printf("\n");
return 0;
}
END
diff --git a/scripts/check-uapi.sh b/scripts/check-uapi.sh
index 955581735cb3..c8beec58871c 100755
--- a/scripts/check-uapi.sh
+++ b/scripts/check-uapi.sh
@@ -33,9 +33,10 @@ Options:
-v Verbose operation (print more information about each header being checked).
Environmental args:
- ABIDIFF Custom path to abidiff binary
- CC C compiler (default is "gcc")
- ARCH Target architecture for the UAPI check (default is host arch)
+ ABIDIFF Custom path to abidiff binary
+ CROSS_COMPILE Toolchain prefix for compiler
+ CC C compiler (default is "\${CROSS_COMPILE}gcc")
+ ARCH Target architecture for the UAPI check (default is host arch)
Exit codes:
$SUCCESS) Success
@@ -178,8 +179,11 @@ do_compile() {
local -r inc_dir="$1"
local -r header="$2"
local -r out="$3"
- printf "int main(void) { return 0; }\n" | \
- "$CC" -c \
+ printf "int f(void) { return 0; }\n" | \
+ "$CC" \
+ -shared \
+ -nostdlib \
+ -fPIC \
-o "$out" \
-x c \
-O0 \
@@ -187,6 +191,7 @@ do_compile() {
-fno-eliminate-unused-debug-types \
-g \
"-I${inc_dir}" \
+ "-Iusr/dummy-include" \
-include "$header" \
-
}
@@ -195,7 +200,7 @@ do_compile() {
run_make_headers_install() {
local -r ref="$1"
local -r install_dir="$(get_header_tree "$ref")"
- make -j "$MAX_THREADS" ARCH="$ARCH" INSTALL_HDR_PATH="$install_dir" \
+ make -j "$MAX_THREADS" CROSS_COMPILE="${CROSS_COMPILE}" ARCH="$ARCH" INSTALL_HDR_PATH="$install_dir" \
headers_install > /dev/null
}
@@ -404,7 +409,7 @@ min_version_is_satisfied() {
# Make sure we have the tools we need and the arguments make sense
check_deps() {
ABIDIFF="${ABIDIFF:-abidiff}"
- CC="${CC:-gcc}"
+ CC="${CC:-${CROSS_COMPILE}gcc}"
ARCH="${ARCH:-$(uname -m)}"
if [ "$ARCH" = "x86_64" ]; then
ARCH="x86"
diff --git a/scripts/checker-valid.sh b/scripts/checker-valid.sh
new file mode 100755
index 000000000000..625a789ed1c8
--- /dev/null
+++ b/scripts/checker-valid.sh
@@ -0,0 +1,19 @@
+#!/bin/sh -eu
+# SPDX-License-Identifier: GPL-2.0
+
+[ ! -x "$(command -v "$1")" ] && exit 1
+
+tmp_file=$(mktemp)
+trap "rm -f $tmp_file" EXIT
+
+cat << EOF >$tmp_file
+static inline int u(const int *q)
+{
+ __typeof_unqual__(*q) v = *q;
+ return v;
+}
+EOF
+
+# sparse happily exits with 0 on error so validate
+# there is none on stderr. Use awk as grep is a pain with sh -e
+$@ $tmp_file 2>&1 | awk -v c=1 '/error/{c=0}END{print c}'
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index c0250244cf7a..cc5bbd70cb84 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -641,6 +641,7 @@ our $signature_tags = qr{(?xi:
Reviewed-by:|
Reported-by:|
Suggested-by:|
+ Assisted-by:|
To:|
Cc:
)};
@@ -863,7 +864,7 @@ our %deprecated_apis = (
#These should be enough to drive away new IDR users
"DEFINE_IDR" => "DEFINE_XARRAY",
"idr_init" => "xa_init",
- "idr_init_base" => "xa_init_flags"
+ "idr_init_base" => "xa_init_flags",
);
#Create a search pattern for all these strings to speed up a loop below
@@ -1100,7 +1101,9 @@ our $declaration_macros = qr{(?x:
(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
(?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
(?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(|
- (?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\(
+ (?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\(|
+ __cacheline_group_(?:begin|end)(?:_aligned)?\s*\(|
+ __dma_from_device_group_(?:begin|end)\s*\(
)};
our %allow_repeated_words = (
@@ -2924,7 +2927,7 @@ sub process {
}
$checklicenseline = 1;
- if ($realfile !~ /^MAINTAINERS/) {
+ if ($realfile !~ /^(MAINTAINERS|dev\/null)/) {
my $last_binding_patch = $is_binding_patch;
$is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@;
@@ -3031,6 +3034,16 @@ sub process {
}
}
+# Check for invalid patch separator
+ if ($in_commit_log &&
+ $line =~ /^---.+/) {
+ if (ERROR("BAD_COMMIT_SEPARATOR",
+ "Invalid commit separator - some tools may have problems applying this\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/-/=/g;
+ }
+ }
+
# Check for patch separator
if ($line =~ /^---$/) {
$has_patch_separator = 1;
@@ -3091,6 +3104,15 @@ sub process {
}
}
+ # Assisted-by uses AGENT_NAME:MODEL_VERSION format, not email
+ if ($sign_off =~ /^Assisted-by:/i) {
+ if ($email !~ /^\S+:\S+/) {
+ WARN("BAD_SIGN_OFF",
+ "Assisted-by expects 'AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]' format\n" . $herecurr);
+ }
+ next;
+ }
+
my ($email_name, $name_comment, $email_address, $comment) = parse_email($email);
my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment));
if ($suggested_email eq "") {
@@ -3842,6 +3864,14 @@ sub process {
"Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $herecurr);
}
+# check for disallowed SPDX file tags
+ if ($rawline =~ /\bSPDX-.*:/ &&
+ $rawline !~ /\bSPDX-License-Identifier:/ &&
+ $rawline !~ /\bSPDX-FileCopyrightText:/) {
+ WARN("SPDX_LICENSE_TAG",
+ "Disallowed SPDX tag\n" . $herecurr);
+ }
+
# line length limit (with some exclusions)
#
# There are a few types of lines that may extend beyond $max_line_length:
@@ -6733,6 +6763,13 @@ sub process {
}
}
+# check for context_unsafe without a comment.
+ if ($line =~ /\bcontext_unsafe\b/ &&
+ !ctx_has_comment($first_line, $linenr)) {
+ WARN("CONTEXT_UNSAFE",
+ "context_unsafe without comment\n" . $herecurr);
+ }
+
# check of hardware specific defines
if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
CHK("ARCH_DEFINES",
@@ -7258,17 +7295,42 @@ sub process {
"Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr);
}
-# check for (kv|k)[mz]alloc with multiplies that could be kmalloc_array/kvmalloc_array/kvcalloc/kcalloc
+# check for (kv|k)[mz]alloc that could be kmalloc_obj/kvmalloc_obj/kzalloc_obj/kvzalloc_obj
+ if ($perl_version_ok &&
+ defined $stat &&
+ $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*,/) {
+ my $oldfunc = $3;
+ my $a1 = $4;
+ my $newfunc = "kmalloc_obj";
+ $newfunc = "kvmalloc_obj" if ($oldfunc eq "kvmalloc");
+ $newfunc = "kvzalloc_obj" if ($oldfunc eq "kvzalloc");
+ $newfunc = "kzalloc_obj" if ($oldfunc eq "kzalloc");
+
+ if ($a1 =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/) {
+ my $cnt = statement_rawlines($stat);
+ my $herectx = get_stat_here($linenr, $cnt, $here);
+
+ if (WARN("ALLOC_WITH_SIZEOF",
+ "Prefer $newfunc over $oldfunc with sizeof\n" . $herectx) &&
+ $cnt == 1 &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*,/$1 = $newfunc($a1,/;
+ }
+ }
+ }
+
+
+# check for (kv|k)[mz]alloc with multiplies that could be kmalloc_objs/kvmalloc_objs/kzalloc_objs/kvzalloc_objs
if ($perl_version_ok &&
defined $stat &&
$stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
my $oldfunc = $3;
my $a1 = $4;
my $a2 = $10;
- my $newfunc = "kmalloc_array";
- $newfunc = "kvmalloc_array" if ($oldfunc eq "kvmalloc");
- $newfunc = "kvcalloc" if ($oldfunc eq "kvzalloc");
- $newfunc = "kcalloc" if ($oldfunc eq "kzalloc");
+ my $newfunc = "kmalloc_objs";
+ $newfunc = "kvmalloc_objs" if ($oldfunc eq "kvmalloc");
+ $newfunc = "kvzalloc_objs" if ($oldfunc eq "kvzalloc");
+ $newfunc = "kzalloc_objs" if ($oldfunc eq "kzalloc");
my $r1 = $a1;
my $r2 = $a2;
if ($a1 =~ /^sizeof\s*\S/) {
@@ -7284,7 +7346,9 @@ sub process {
"Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
$cnt == 1 &&
$fix) {
- $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
+ my $sized = trim($r2);
+ $sized =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/;
+ $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . $sized . ', ' . trim($r1)/e;
}
}
}
@@ -7454,10 +7518,10 @@ sub process {
}
# check for various structs that are normally const (ops, kgdb, device_tree)
-# and avoid what seem like struct definitions 'struct foo {'
+# and avoid what seem like struct definitions 'struct foo {' or forward declarations 'struct foo;'
if (defined($const_structs) &&
$line !~ /\bconst\b/ &&
- $line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) {
+ $line =~ /\bstruct\s+($const_structs)\b(?!\s*[\{;])/) {
WARN("CONST_STRUCT",
"struct $1 should normally be const\n" . $herecurr);
}
@@ -7530,12 +7594,15 @@ sub process {
# Complain about RCU Tasks Trace used outside of BPF (and of course, RCU).
our $rcu_trace_funcs = qr{(?x:
+ rcu_read_lock_tasks_trace |
rcu_read_lock_trace |
rcu_read_lock_trace_held |
rcu_read_unlock_trace |
+ rcu_read_unlock_tasks_trace |
call_rcu_tasks_trace |
synchronize_rcu_tasks_trace |
rcu_barrier_tasks_trace |
+ rcu_tasks_trace_expedite_current |
rcu_request_urgent_qs_task
)};
our $rcu_trace_paths = qr{(?x:
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
index 1e5d2eeb726d..e2970421c1ff 100755
--- a/scripts/checksyscalls.sh
+++ b/scripts/checksyscalls.sh
@@ -10,6 +10,10 @@
# checksyscalls.sh gcc gcc-options
#
+set -e
+
+reference_table="$(dirname $0)/../arch/x86/entry/syscalls/syscall_32.tbl"
+
ignore_list() {
cat << EOF
#include <asm/types.h>
@@ -269,5 +273,10 @@ syscall_list() {
done
}
-(ignore_list && syscall_list $(dirname $0)/../arch/x86/entry/syscalls/syscall_32.tbl) | \
+(ignore_list && syscall_list ${reference_table}) | \
$* -Wno-error -Wno-unused-macros -E -x c - > /dev/null
+
+# For fixdep
+if [ -n "${DEPFILE}" ]; then
+ echo "${0}: ${0} ${reference_table}" >> "${DEPFILE}"
+fi
diff --git a/scripts/clang-tools/run-clang-tools.py b/scripts/clang-tools/run-clang-tools.py
index f31ffd09e1ea..e78be82aa693 100755
--- a/scripts/clang-tools/run-clang-tools.py
+++ b/scripts/clang-tools/run-clang-tools.py
@@ -79,14 +79,15 @@ def run_analysis(entry):
def main():
- try:
- args = parse_arguments()
+ args = parse_arguments()
+
+ # Read JSON data into the datastore variable
+ with open(args.path) as f:
+ datastore = json.load(f)
- lock = multiprocessing.Lock()
- pool = multiprocessing.Pool(initializer=init, initargs=(lock, args))
- # Read JSON data into the datastore variable
- with open(args.path, "r") as f:
- datastore = json.load(f)
+ lock = multiprocessing.Lock()
+ try:
+ with multiprocessing.Pool(initializer=init, initargs=(lock, args)) as pool:
pool.map(run_analysis, datastore)
except BrokenPipeError:
# Python flushes standard streams on exit; redirect remaining output
diff --git a/scripts/coccicheck b/scripts/coccicheck
index 89d591af5f3e..8dd766009de1 100755
--- a/scripts/coccicheck
+++ b/scripts/coccicheck
@@ -138,7 +138,7 @@ run_cmd_parmap() {
if [ $VERBOSE -ne 0 ] ; then
echo "Running ($NPROC in parallel): $@"
fi
- if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
+ if [ "$DEBUG_FILE" != "/dev/null" ]; then
echo $@>>$DEBUG_FILE
$@ 2>>$DEBUG_FILE
else
@@ -259,13 +259,18 @@ coccinelle () {
}
-if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
- if [ -f $DEBUG_FILE ]; then
- echo "Debug file $DEBUG_FILE exists, bailing"
- exit
- fi
-else
- DEBUG_FILE="/dev/null"
+if [ "$DEBUG_FILE" = "" ]; then
+ echo 'You have not explicitly specified the debug file to use.'
+ echo 'Using default "/dev/null" as debug file.'
+ echo 'Debug logs will be printed to stdout.'
+ echo 'You can specify the debug file with "make coccicheck DEBUG_FILE=<debug_file>"'
+ echo ''
+ DEBUG_FILE="/dev/null"
+fi
+
+if [ -f $DEBUG_FILE ]; then
+ echo "Debug file $DEBUG_FILE exists, bailing"
+ exit
fi
if [ "$COCCI" = "" ] ; then
diff --git a/scripts/coccinelle/api/kmalloc_objs.cocci b/scripts/coccinelle/api/kmalloc_objs.cocci
new file mode 100644
index 000000000000..e9a415b7b6f4
--- /dev/null
+++ b/scripts/coccinelle/api/kmalloc_objs.cocci
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/// Use kmalloc_obj family of macros for allocations
+///
+// Confidence: High
+// Options: --include-headers-for-types --all-includes --include-headers --keep-comments
+
+virtual patch
+
+@initialize:python@
+@@
+import sys
+
+def alloc_array(name):
+ func = "FAILED_RENAME"
+ if name == "kmalloc_array":
+ func = "kmalloc_objs"
+ elif name == "kvmalloc_array":
+ func = "kvmalloc_objs"
+ elif name == "kcalloc":
+ func = "kzalloc_objs"
+ elif name == "kvcalloc":
+ func = "kvzalloc_objs"
+ else:
+ print(f"Unknown transform for {name}", file=sys.stderr)
+ return func
+
+// This excludes anything that is assigning to or from integral types or
+// string literals. Everything else gets the sizeof() extracted for the
+// kmalloc_obj() type/var argument. sizeof(void *) is also excluded because
+// it will need case-by-case double-checking to make sure the right type is
+// being assigned.
+@direct depends on patch && !(file in "tools") && !(file in "samples")@
+typedef u8, u16, u32, u64;
+typedef __u8, __u16, __u32, __u64;
+typedef uint8_t, uint16_t, uint32_t, uint64_t;
+typedef uchar, ushort, uint, ulong;
+typedef __le16, __le32, __le64;
+typedef __be16, __be32, __be64;
+typedef wchar_t;
+type INTEGRAL = {u8,__u8,uint8_t,char,unsigned char,uchar,wchar_t,
+ u16,__u16,uint16_t,unsigned short,ushort,
+ u32,__u32,uint32_t,unsigned int,uint,
+ u64,__u64,uint64_t,unsigned long,ulong,
+ __le16,__le32,__le64,__be16,__be32,__be64};
+char [] STRING;
+INTEGRAL *BYTES;
+INTEGRAL **BYTES_PTRS;
+type TYPE;
+expression VAR;
+expression GFP;
+expression COUNT;
+expression FLEX;
+expression E;
+identifier ALLOC =~ "^kv?[mz]alloc$";
+fresh identifier ALLOC_OBJ = ALLOC ## "_obj";
+fresh identifier ALLOC_FLEX = ALLOC ## "_flex";
+identifier ALLOC_ARRAY = {kmalloc_array,kvmalloc_array,kcalloc,kvcalloc};
+fresh identifier ALLOC_OBJS = script:python(ALLOC_ARRAY) { alloc_array(ALLOC_ARRAY) };
+@@
+
+(
+- VAR = ALLOC((sizeof(*VAR)), GFP)
++ VAR = ALLOC_OBJ(*VAR, GFP)
+|
+ ALLOC((\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP)
+|
+ BYTES = ALLOC((sizeof(E)), GFP)
+|
+ BYTES = ALLOC((sizeof(TYPE)), GFP)
+|
+ BYTES_PTRS = ALLOC((sizeof(E)), GFP)
+|
+ BYTES_PTRS = ALLOC((sizeof(TYPE)), GFP)
+|
+ ALLOC((sizeof(void *)), GFP)
+|
+- ALLOC((sizeof(E)), GFP)
++ ALLOC_OBJ(E, GFP)
+|
+- ALLOC((sizeof(TYPE)), GFP)
++ ALLOC_OBJ(TYPE, GFP)
+|
+ ALLOC_ARRAY(COUNT, (\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), GFP)
+|
+ BYTES = ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
+|
+ BYTES = ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
+|
+ ALLOC_ARRAY((\(sizeof(STRING)\|sizeof(INTEGRAL)\|sizeof(INTEGRAL *)\)), COUNT, GFP)
+|
+ BYTES = ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
+|
+ BYTES = ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
+|
+ BYTES_PTRS = ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
+|
+ ALLOC_ARRAY(COUNT, (sizeof(void *)), GFP)
+|
+ ALLOC_ARRAY((sizeof(void *)), COUNT, GFP)
+|
+- ALLOC_ARRAY(COUNT, (sizeof(E)), GFP)
++ ALLOC_OBJS(E, COUNT, GFP)
+|
+- ALLOC_ARRAY(COUNT, (sizeof(TYPE)), GFP)
++ ALLOC_OBJS(TYPE, COUNT, GFP)
+|
+- ALLOC_ARRAY((sizeof(E)), COUNT, GFP)
++ ALLOC_OBJS(E, COUNT, GFP)
+|
+- ALLOC_ARRAY((sizeof(TYPE)), COUNT, GFP)
++ ALLOC_OBJS(TYPE, COUNT, GFP)
+|
+- ALLOC(struct_size(VAR, FLEX, COUNT), GFP)
++ ALLOC_FLEX(*VAR, FLEX, COUNT, GFP)
+|
+- ALLOC(struct_size_t(TYPE, FLEX, COUNT), GFP)
++ ALLOC_FLEX(TYPE, FLEX, COUNT, GFP)
+)
+
+@drop_gfp_kernel depends on patch && !(file in "tools") && !(file in "samples")@
+identifier ALLOC = {kmalloc_obj,kmalloc_objs,kmalloc_flex,
+ kzalloc_obj,kzalloc_objs,kzalloc_flex,
+ kvmalloc_obj,kvmalloc_objs,kvmalloc_flex,
+ kvzalloc_obj,kvzalloc_objs,kvzalloc_flex};
+@@
+
+ ALLOC(...
+- , GFP_KERNEL
+ )
diff --git a/scripts/container b/scripts/container
new file mode 100755
index 000000000000..b05333d8530b
--- /dev/null
+++ b/scripts/container
@@ -0,0 +1,199 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2025 Guillaume Tucker
+
+"""Containerized builds"""
+
+import abc
+import argparse
+import logging
+import os
+import pathlib
+import shutil
+import subprocess
+import sys
+import uuid
+
+
+class ContainerRuntime(abc.ABC):
+ """Base class for a container runtime implementation"""
+
+ name = None # Property defined in each implementation class
+
+ def __init__(self, args, logger):
+ self._uid = args.uid or os.getuid()
+ self._gid = args.gid or args.uid or os.getgid()
+ self._env_file = args.env_file
+ self._shell = args.shell
+ self._logger = logger
+
+ @classmethod
+ def is_present(cls):
+ """Determine whether the runtime is present on the system"""
+ return shutil.which(cls.name) is not None
+
+ @abc.abstractmethod
+ def _do_run(self, image, cmd, container_name):
+ """Runtime-specific handler to run a command in a container"""
+
+ @abc.abstractmethod
+ def _do_abort(self, container_name):
+ """Runtime-specific handler to abort a running container"""
+
+ def run(self, image, cmd):
+ """Run a command in a runtime container"""
+ container_name = str(uuid.uuid4())
+ self._logger.debug("container: %s", container_name)
+ try:
+ return self._do_run(image, cmd, container_name)
+ except KeyboardInterrupt:
+ self._logger.error("user aborted")
+ self._do_abort(container_name)
+ return 1
+
+
+class CommonRuntime(ContainerRuntime):
+ """Common logic for Docker and Podman"""
+
+ def _do_run(self, image, cmd, container_name):
+ cmdline = [self.name, 'run']
+ cmdline += self._get_opts(container_name)
+ cmdline.append(image)
+ cmdline += cmd
+ self._logger.debug('command: %s', ' '.join(cmdline))
+ return subprocess.call(cmdline)
+
+ def _get_opts(self, container_name):
+ opts = [
+ '--name', container_name,
+ '--rm',
+ '--volume', f'{pathlib.Path.cwd()}:/src',
+ '--workdir', '/src',
+ ]
+ if self._env_file:
+ opts += ['--env-file', self._env_file]
+ if self._shell:
+ opts += ['--interactive', '--tty']
+ return opts
+
+ def _do_abort(self, container_name):
+ subprocess.call([self.name, 'kill', container_name])
+
+
+class DockerRuntime(CommonRuntime):
+ """Run a command in a Docker container"""
+
+ name = 'docker'
+
+ def _get_opts(self, container_name):
+ return super()._get_opts(container_name) + [
+ '--user', f'{self._uid}:{self._gid}'
+ ]
+
+
+class PodmanRuntime(CommonRuntime):
+ """Run a command in a Podman container"""
+
+ name = 'podman'
+
+ def _get_opts(self, container_name):
+ return super()._get_opts(container_name) + [
+ '--userns', f'keep-id:uid={self._uid},gid={self._gid}',
+ ]
+
+
+class Runtimes:
+ """List of all supported runtimes"""
+
+ runtimes = [PodmanRuntime, DockerRuntime]
+
+ @classmethod
+ def get_names(cls):
+ """Get a list of all the runtime names"""
+ return list(runtime.name for runtime in cls.runtimes)
+
+ @classmethod
+ def get(cls, name):
+ """Get a single runtime class matching the given name"""
+ for runtime in cls.runtimes:
+ if runtime.name == name:
+ if not runtime.is_present():
+ raise ValueError(f"runtime not found: {name}")
+ return runtime
+ raise ValueError(f"unknown runtime: {name}")
+
+ @classmethod
+ def find(cls):
+ """Find the first runtime present on the system"""
+ for runtime in cls.runtimes:
+ if runtime.is_present():
+ return runtime
+ raise ValueError("no runtime found")
+
+
+def _get_logger(verbose):
+ """Set up a logger with the appropriate level"""
+ logger = logging.getLogger('container')
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter(
+ fmt='[container {levelname}] {message}', style='{'
+ ))
+ logger.addHandler(handler)
+ logger.setLevel(logging.DEBUG if verbose is True else logging.INFO)
+ return logger
+
+
+def main(args):
+ """Main entry point for the container tool"""
+ logger = _get_logger(args.verbose)
+ try:
+ cls = Runtimes.get(args.runtime) if args.runtime else Runtimes.find()
+ except ValueError as ex:
+ logger.error(ex)
+ return 1
+ logger.debug("runtime: %s", cls.name)
+ logger.debug("image: %s", args.image)
+ return cls(args, logger).run(args.image, args.cmd)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ 'container',
+ description="See the documentation for more details: "
+ "https://docs.kernel.org/dev-tools/container.html"
+ )
+ parser.add_argument(
+ '-e', '--env-file',
+ help="Path to an environment file to load in the container."
+ )
+ parser.add_argument(
+ '-g', '--gid',
+ help="Group ID to use inside the container."
+ )
+ parser.add_argument(
+ '-i', '--image', required=True,
+ help="Container image name."
+ )
+ parser.add_argument(
+ '-r', '--runtime', choices=Runtimes.get_names(),
+ help="Container runtime name. If not specified, the first one found "
+ "on the system will be used i.e. Podman if present, otherwise Docker."
+ )
+ parser.add_argument(
+ '-s', '--shell', action='store_true',
+ help="Run the container in an interactive shell."
+ )
+ parser.add_argument(
+ '-u', '--uid',
+ help="User ID to use inside the container. If the -g option is not "
+ "specified, the user ID will also be set as the group ID."
+ )
+ parser.add_argument(
+ '-v', '--verbose', action='store_true',
+ help="Enable verbose output."
+ )
+ parser.add_argument(
+ 'cmd', nargs='+',
+ help="Command to run in the container"
+ )
+ sys.exit(main(parser.parse_args(sys.argv[1:])))
diff --git a/scripts/context-analysis-suppression.txt b/scripts/context-analysis-suppression.txt
new file mode 100644
index 000000000000..1c51b6153f08
--- /dev/null
+++ b/scripts/context-analysis-suppression.txt
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# The suppressions file should only match common paths such as header files.
+# For individual subsytems use Makefile directive CONTEXT_ANALYSIS := [yn].
+#
+# The suppressions are ignored when CONFIG_WARN_CONTEXT_ANALYSIS_ALL is
+# selected.
+
+[thread-safety]
+src:*arch/*/include/*
+src:*include/acpi/*
+src:*include/asm-generic/*
+src:*include/linux/*
+src:*include/net/*
+
+# Opt-in headers:
+src:*include/linux/bit_spinlock.h=emit
+src:*include/linux/cleanup.h=emit
+src:*include/linux/kref.h=emit
+src:*include/linux/list*.h=emit
+src:*include/linux/local_lock*.h=emit
+src:*include/linux/lockdep.h=emit
+src:*include/linux/mutex*.h=emit
+src:*include/linux/rcupdate.h=emit
+src:*include/linux/refcount.h=emit
+src:*include/linux/rhashtable.h=emit
+src:*include/linux/rtmutex*.h=emit
+src:*include/linux/rwlock*.h=emit
+src:*include/linux/rwsem.h=emit
+src:*include/linux/sched*=emit
+src:*include/linux/seqlock*.h=emit
+src:*include/linux/spinlock*.h=emit
+src:*include/linux/srcu*.h=emit
+src:*include/linux/ww_mutex.h=emit
diff --git a/scripts/crypto/gen-fips-testvecs.py b/scripts/crypto/gen-fips-testvecs.py
index db873f88619a..9f18bcb97412 100755
--- a/scripts/crypto/gen-fips-testvecs.py
+++ b/scripts/crypto/gen-fips-testvecs.py
@@ -3,8 +3,12 @@
#
# Script that generates lib/crypto/fips.h
#
+# Requires that python-cryptography be installed.
+#
# Copyright 2025 Google LLC
+import cryptography.hazmat.primitives.ciphers
+import cryptography.hazmat.primitives.cmac
import hashlib
import hmac
@@ -34,3 +38,9 @@ for alg in 'sha1', 'sha256', 'sha512':
print_static_u8_array_definition(f'fips_test_sha3_256_value',
hashlib.sha3_256(fips_test_data).digest())
+
+aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(fips_test_key)
+aes_cmac = cryptography.hazmat.primitives.cmac.CMAC(aes)
+aes_cmac.update(fips_test_data)
+print_static_u8_array_definition('fips_test_aes_cmac_value',
+ aes_cmac.finalize())
diff --git a/scripts/crypto/gen-hash-testvecs.py b/scripts/crypto/gen-hash-testvecs.py
index c773294fba64..f356f87e1c77 100755
--- a/scripts/crypto/gen-hash-testvecs.py
+++ b/scripts/crypto/gen-hash-testvecs.py
@@ -3,8 +3,12 @@
#
# Script that generates test vectors for the given hash function.
#
+# Requires that python-cryptography be installed.
+#
# Copyright 2025 Google LLC
+import cryptography.hazmat.primitives.ciphers
+import cryptography.hazmat.primitives.cmac
import hashlib
import hmac
import sys
@@ -24,6 +28,20 @@ def rand_bytes(length):
out.append((seed >> 16) % 256)
return bytes(out)
+AES_256_KEY_SIZE = 32
+
+# AES-CMAC. Just wraps the implementation from python-cryptography.
+class AesCmac:
+ def __init__(self, key):
+ aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(key)
+ self.cmac = cryptography.hazmat.primitives.cmac.CMAC(aes)
+
+ def update(self, data):
+ self.cmac.update(data)
+
+ def digest(self):
+ return self.cmac.finalize()
+
POLY1305_KEY_SIZE = 32
# A straightforward, unoptimized implementation of Poly1305.
@@ -50,6 +68,52 @@ class Poly1305:
m = (self.h + self.s) % 2**128
return m.to_bytes(16, byteorder='little')
+GHASH_POLY = sum((1 << i) for i in [128, 7, 2, 1, 0])
+GHASH_BLOCK_SIZE = 16
+
+# A straightforward, unoptimized implementation of GHASH.
+class Ghash:
+
+ @staticmethod
+ def reflect_bits_in_bytes(v):
+ res = 0
+ for offs in range(0, 128, 8):
+ for bit in range(8):
+ if (v & (1 << (offs + bit))) != 0:
+ res ^= 1 << (offs + 7 - bit)
+ return res
+
+ @staticmethod
+ def bytes_to_poly(data):
+ return Ghash.reflect_bits_in_bytes(int.from_bytes(data, byteorder='little'))
+
+ @staticmethod
+ def poly_to_bytes(poly):
+ return Ghash.reflect_bits_in_bytes(poly).to_bytes(16, byteorder='little')
+
+ def __init__(self, key):
+ assert len(key) == 16
+ self.h = Ghash.bytes_to_poly(key)
+ self.acc = 0
+
+ # Note: this supports partial blocks only at the end.
+ def update(self, data):
+ for i in range(0, len(data), 16):
+ # acc += block
+ self.acc ^= Ghash.bytes_to_poly(data[i:i+16])
+ # acc = (acc * h) mod GHASH_POLY
+ product = 0
+ for j in range(127, -1, -1):
+ if (self.h & (1 << j)) != 0:
+ product ^= self.acc << j
+ if (product & (1 << (128 + j))) != 0:
+ product ^= GHASH_POLY << j
+ self.acc = product
+ return self
+
+ def digest(self):
+ return Ghash.poly_to_bytes(self.acc)
+
POLYVAL_POLY = sum((1 << i) for i in [128, 127, 126, 121, 0])
POLYVAL_BLOCK_SIZE = 16
@@ -80,9 +144,14 @@ class Polyval:
return self.acc.to_bytes(16, byteorder='little')
def hash_init(alg):
+ # The keyed hash functions are assigned a fixed random key here, to present
+ # them as unkeyed hash functions. This allows all the test cases for
+ # unkeyed hash functions to work on them.
+ if alg == 'aes-cmac':
+ return AesCmac(rand_bytes(AES_256_KEY_SIZE))
+ if alg == 'ghash':
+ return Ghash(rand_bytes(GHASH_BLOCK_SIZE))
if alg == 'poly1305':
- # Use a fixed random key here, to present Poly1305 as an unkeyed hash.
- # This allows all the test cases for unkeyed hashes to work on Poly1305.
return Poly1305(rand_bytes(POLY1305_KEY_SIZE))
if alg == 'polyval':
return Polyval(rand_bytes(POLYVAL_BLOCK_SIZE))
@@ -116,6 +185,8 @@ def print_c_struct_u8_array_field(name, value):
print('\t\t},')
def alg_digest_size_const(alg):
+ if alg == 'aes-cmac':
+ return 'AES_BLOCK_SIZE'
if alg.startswith('blake2'):
return f'{alg.upper()}_HASH_SIZE'
return f"{alg.upper().replace('-', '_')}_DIGEST_SIZE"
@@ -184,6 +255,44 @@ def gen_additional_blake2_testvecs(alg):
f'{alg}_keyed_testvec_consolidated[{alg_digest_size_const(alg)}]',
compute_hash(alg, hashes))
+def nh_extract_int(bytestr, pos, length):
+ assert pos % 8 == 0 and length % 8 == 0
+ return int.from_bytes(bytestr[pos//8 : pos//8 + length//8], byteorder='little')
+
+# The NH "almost-universal hash function" used in Adiantum. This is a
+# straightforward translation of the pseudocode from Section 6.3 of the Adiantum
+# paper (https://eprint.iacr.org/2018/720.pdf), except the outer loop is omitted
+# because we assume len(msg) <= 1024. (The kernel's nh() function is only
+# expected to handle up to 1024 bytes; it's just called repeatedly as needed.)
+def nh(key, msg):
+ (w, s, r, u) = (32, 2, 4, 8192)
+ l = 8 * len(msg)
+ assert l <= u
+ assert l % (2*s*w) == 0
+ h = bytes()
+ for i in range(0, 2*s*w*r, 2*s*w):
+ p = 0
+ for j in range(0, l, 2*s*w):
+ for k in range(0, w*s, w):
+ a0 = nh_extract_int(key, i + j + k, w)
+ a1 = nh_extract_int(key, i + j + k + s*w, w)
+ b0 = nh_extract_int(msg, j + k, w)
+ b1 = nh_extract_int(msg, j + k + s*w, w)
+ p += ((a0 + b0) % 2**w) * ((a1 + b1) % 2**w)
+ h += (p % 2**64).to_bytes(8, byteorder='little')
+ return h
+
+def gen_nh_testvecs():
+ NH_KEY_BYTES = 1072
+ NH_MESSAGE_BYTES = 1024
+ key = rand_bytes(NH_KEY_BYTES)
+ msg = rand_bytes(NH_MESSAGE_BYTES)
+ print_static_u8_array_definition('nh_test_key[NH_KEY_BYTES]', key)
+ print_static_u8_array_definition('nh_test_msg[NH_MESSAGE_BYTES]', msg)
+ for length in [16, 96, 256, 1024]:
+ print_static_u8_array_definition(f'nh_test_val{length}[NH_HASH_BYTES]',
+ nh(key, msg[:length]))
+
def gen_additional_poly1305_testvecs():
key = b'\xff' * POLY1305_KEY_SIZE
data = b''
@@ -196,6 +305,15 @@ def gen_additional_poly1305_testvecs():
'poly1305_allones_macofmacs[POLY1305_DIGEST_SIZE]',
Poly1305(key).update(data).digest())
+def gen_additional_ghash_testvecs():
+ key = b'\xff' * GHASH_BLOCK_SIZE
+ hashes = b''
+ for data_len in range(0, 4097, 16):
+ hashes += Ghash(key).update(b'\xff' * data_len).digest()
+ print_static_u8_array_definition(
+ 'ghash_allones_hashofhashes[GHASH_DIGEST_SIZE]',
+ Ghash(key).update(hashes).digest())
+
def gen_additional_polyval_testvecs():
key = b'\xff' * POLYVAL_BLOCK_SIZE
hashes = b''
@@ -207,16 +325,24 @@ def gen_additional_polyval_testvecs():
if len(sys.argv) != 2:
sys.stderr.write('Usage: gen-hash-testvecs.py ALGORITHM\n')
- sys.stderr.write('ALGORITHM may be any supported by Python hashlib; or poly1305, polyval, or sha3.\n')
+ sys.stderr.write('ALGORITHM may be any supported by Python hashlib;\n')
+ sys.stderr.write(' or aes-cmac, ghash, nh, poly1305, polyval, or sha3.\n')
sys.stderr.write('Example: gen-hash-testvecs.py sha512\n')
sys.exit(1)
alg = sys.argv[1]
print('/* SPDX-License-Identifier: GPL-2.0-or-later */')
print(f'/* This file was generated by: {sys.argv[0]} {" ".join(sys.argv[1:])} */')
-if alg.startswith('blake2'):
+if alg == 'aes-cmac':
+ gen_unkeyed_testvecs(alg)
+elif alg.startswith('blake2'):
gen_unkeyed_testvecs(alg)
gen_additional_blake2_testvecs(alg)
+elif alg == 'ghash':
+ gen_unkeyed_testvecs(alg)
+ gen_additional_ghash_testvecs()
+elif alg == 'nh':
+ gen_nh_testvecs()
elif alg == 'poly1305':
gen_unkeyed_testvecs(alg)
gen_additional_poly1305_testvecs()
@@ -230,6 +356,9 @@ elif alg == 'sha3':
print()
print('/* SHAKE test vectors */')
gen_additional_sha3_testvecs()
+elif alg == 'sm3':
+ gen_unkeyed_testvecs(alg)
+ # Kernel doesn't implement HMAC-SM3 library functions yet.
else:
gen_unkeyed_testvecs(alg)
gen_hmac_testvecs(alg)
diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index 8d01b741de62..39d60d477bf3 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -5,9 +5,11 @@
usage() {
echo "Usage:"
- echo " $0 -r <release>"
- echo " $0 [<vmlinux> [<base_path>|auto [<modules_path>]]]"
+ echo " $0 [-R] -r <release>"
+ echo " $0 [-R] [<vmlinux> [<base_path>|auto [<modules_path>]]]"
echo " $0 -h"
+ echo "Options:"
+ echo " -R: decode return address instead of caller address."
}
# Try to find a Rust demangler
@@ -33,11 +35,17 @@ fi
READELF=${UTIL_PREFIX}readelf${UTIL_SUFFIX}
ADDR2LINE=${UTIL_PREFIX}addr2line${UTIL_SUFFIX}
NM=${UTIL_PREFIX}nm${UTIL_SUFFIX}
+decode_retaddr=false
if [[ $1 == "-h" ]] ; then
usage
exit 0
-elif [[ $1 == "-r" ]] ; then
+elif [[ $1 == "-R" ]] ; then
+ decode_retaddr=true
+ shift 1
+fi
+
+if [[ $1 == "-r" ]] ; then
vmlinux=""
basepath="auto"
modpath=""
@@ -176,13 +184,23 @@ parse_symbol() {
# Let's start doing the math to get the exact address into the
# symbol. First, strip out the symbol total length.
local expr=${symbol%/*}
+ # Also parse the offset from symbol.
+ local offset=${expr#*+}
+ offset=$((offset))
# Now, replace the symbol name with the base address we found
# before.
expr=${expr/$name/0x$base_addr}
# Evaluate it to find the actual address
- expr=$((expr))
+ # The stack trace shows the return address, which is the next
+ # instruction after the actual call, so as long as it's in the same
+ # symbol, subtract one from that to point the call instruction.
+ if [[ $decode_retaddr == false && $offset != 0 ]]; then
+ expr=$((expr-1))
+ else
+ expr=$((expr))
+ fi
local address=$(printf "%x\n" "$expr")
# Pass it to addr2line to get filename and line number
diff --git a/scripts/decodecode b/scripts/decodecode
index 6364218b2178..01d25dc110de 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -12,7 +12,6 @@ faultlinenum=1
cleanup() {
rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
- exit 1
}
die() {
@@ -49,7 +48,7 @@ done
if [ -z "$code" ]; then
rm $T
- exit
+ die "Code line not found"
fi
echo $code
diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c
index 7e3fed5005b3..946c1429e0f1 100644
--- a/scripts/dtc/checks.c
+++ b/scripts/dtc/checks.c
@@ -324,7 +324,7 @@ ERROR(node_name_chars, check_node_name_chars, NODECHARS);
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
struct node *node)
{
- int n = strspn(node->name, c->data);
+ size_t n = strspn(node->name, c->data);
if (n < node->basenamelen)
FAIL(c, dti, node, "Character '%c' not recommended in node name",
@@ -340,6 +340,14 @@ static void check_node_name_format(struct check *c, struct dt_info *dti,
}
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
+static void check_node_name_not_empty(struct check *c, struct dt_info *dti,
+ struct node *node)
+{
+ if (node->basenamelen == 0 && node->parent != NULL)
+ FAIL(c, dti, node, "Empty node name");
+}
+ERROR(node_name_not_empty, check_node_name_not_empty, NULL, &node_name_chars);
+
static void check_node_name_vs_property_name(struct check *c,
struct dt_info *dti,
struct node *node)
@@ -718,11 +726,14 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
continue;
}
- if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
+ /* This check does not work for overlays with external paths */
+ if (!(dti->dtsflags & DTSF_PLUGIN) &&
+ (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val))) {
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
prop->val.val);
continue;
}
+
if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name))
FAIL(c, dti, node, "aliases property name must include only lowercase and '-'");
}
@@ -1894,34 +1905,9 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
}
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
-static void check_graph_child_address(struct check *c, struct dt_info *dti,
- struct node *node)
-{
- int cnt = 0;
- struct node *child;
-
- if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
- return;
-
- for_each_child(node, child) {
- struct property *prop = get_property(child, "reg");
-
- /* No error if we have any non-zero unit address */
- if (prop && propval_cell(prop) != 0 )
- return;
-
- cnt++;
- }
-
- if (cnt == 1 && node->addr_cells != -1)
- FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
- node->children->name);
-}
-WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes, &graph_port, &graph_endpoint);
-
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
- &node_name_chars, &node_name_format, &property_name_chars,
+ &node_name_chars, &node_name_format, &node_name_not_empty, &property_name_chars,
&name_is_string, &name_properties, &node_name_vs_property_name,
&duplicate_label,
@@ -2005,7 +1991,7 @@ static struct check *check_table[] = {
&alias_paths,
- &graph_nodes, &graph_child_address, &graph_port, &graph_endpoint,
+ &graph_nodes, &graph_port, &graph_endpoint,
&always_fail,
};
diff --git a/scripts/dtc/dt-extract-compatibles b/scripts/dtc/dt-extract-compatibles
index 6570efabaa64..87999d707390 100755
--- a/scripts/dtc/dt-extract-compatibles
+++ b/scripts/dtc/dt-extract-compatibles
@@ -72,6 +72,7 @@ def parse_compatibles(file, compat_ignore_list):
compat_list += parse_of_functions(data, "_is_compatible")
compat_list += parse_of_functions(data, "of_find_compatible_node")
compat_list += parse_of_functions(data, "for_each_compatible_node")
+ compat_list += parse_of_functions(data, "for_each_compatible_node_scoped")
compat_list += parse_of_functions(data, "of_get_compatible_child")
return compat_list
diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
index 15d585c80798..1b129b118b0f 100644
--- a/scripts/dtc/dtc-lexer.l
+++ b/scripts/dtc/dtc-lexer.l
@@ -39,8 +39,6 @@ extern bool treesource_error;
#define DPRINT(fmt, ...) do { } while (0)
#endif
-static int dts_version = 1;
-
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
BEGIN(V1); \
@@ -101,7 +99,6 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
<*>"/dts-v1/" {
DPRINT("Keyword: /dts-v1/\n");
- dts_version = 1;
BEGIN_DEFAULT();
return DT_V1;
}
diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c
index b3445b7d6473..6dae60de0ea5 100644
--- a/scripts/dtc/dtc.c
+++ b/scripts/dtc/dtc.c
@@ -338,9 +338,14 @@ int main(int argc, char *argv[])
if (auto_label_aliases)
generate_label_tree(dti, "aliases", false);
+ generate_labels_from_tree(dti, "__symbols__");
+
if (generate_symbols)
generate_label_tree(dti, "__symbols__", true);
+ fixup_phandles(dti, "__fixups__");
+ local_fixup_phandles(dti, "__local_fixups__");
+
if (generate_fixups) {
generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__");
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index 3a220b9afc99..473552ebf017 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -227,7 +227,7 @@ struct node {
struct node *next_sibling;
char *fullpath;
- int basenamelen;
+ size_t basenamelen;
cell_t phandle;
int addr_cells, size_cells;
@@ -339,9 +339,12 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti);
+void generate_labels_from_tree(struct dt_info *dti, const char *name);
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, const char *name);
+void fixup_phandles(struct dt_info *dti, const char *name);
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
+void local_fixup_phandles(struct dt_info *dti, const char *name);
/* Checks */
@@ -357,6 +360,9 @@ struct dt_info *dt_from_blob(const char *fname);
/* Tree source */
+void property_add_marker(struct property *prop,
+ enum markertype type, unsigned int offset, char *ref);
+void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset);
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);
diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c
index 30e6de2044b2..f3b698c17e89 100644
--- a/scripts/dtc/flattree.c
+++ b/scripts/dtc/flattree.c
@@ -807,6 +807,7 @@ struct dt_info *dt_from_blob(const char *fname)
struct node *tree;
uint32_t val;
int flags = 0;
+ unsigned int dtsflags = DTSF_V1;
f = srcfile_relative_open(fname, NULL);
@@ -919,5 +920,8 @@ struct dt_info *dt_from_blob(const char *fname)
fclose(f);
- return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
+ if (get_subnode(tree, "__fixups__") || get_subnode(tree, "__local_fixups__"))
+ dtsflags |= DTSF_PLUGIN;
+
+ return build_dt_info(dtsflags, reservelist, tree, boot_cpuid_phys);
}
diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c
index 95f644c31f94..56d4dcb2dc92 100644
--- a/scripts/dtc/libfdt/fdt.c
+++ b/scripts/dtc/libfdt/fdt.c
@@ -110,6 +110,14 @@ int fdt_check_header(const void *fdt)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
+ /* memrsv block must be 8 byte aligned */
+ if (fdt_off_mem_rsvmap(fdt) % sizeof(uint64_t))
+ return -FDT_ERR_ALIGNMENT;
+
+ /* Structure block must be 4 byte aligned */
+ if (fdt_off_dt_struct(fdt) % FDT_TAGSIZE)
+ return -FDT_ERR_ALIGNMENT;
+
/* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_mem_rsvmap(fdt)))
diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c
index e6b9eb643958..51a3859620a4 100644
--- a/scripts/dtc/libfdt/fdt_overlay.c
+++ b/scripts/dtc/libfdt/fdt_overlay.c
@@ -407,7 +407,8 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
const char *fixup_str = value;
uint32_t path_len, name_len;
uint32_t fixup_len;
- char *sep, *endptr;
+ const char *sep;
+ char *endptr;
int poffset, ret;
fixup_end = memchr(value, '\0', len);
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c
index b78c4e48f1cb..63494fb7ad90 100644
--- a/scripts/dtc/libfdt/fdt_ro.c
+++ b/scripts/dtc/libfdt/fdt_ro.c
@@ -306,8 +306,8 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
const char *nameptr;
int err;
- if (((err = fdt_ro_probe_(fdt)) < 0)
- || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
+ if (!can_assume(VALID_DTB) && (((err = fdt_ro_probe_(fdt)) < 0)
+ || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
goto fail;
nameptr = nh->name;
diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c
index 7475cafce071..90ea14e944cc 100644
--- a/scripts/dtc/libfdt/fdt_rw.c
+++ b/scripts/dtc/libfdt/fdt_rw.c
@@ -22,6 +22,12 @@ static int fdt_blocks_misordered_(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
+static void fdt_downgrade_version(void *fdt)
+{
+ if (!can_assume(LATEST) && fdt_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+}
+
static int fdt_rw_probe_(void *fdt)
{
if (can_assume(VALID_DTB))
@@ -33,9 +39,8 @@ static int fdt_rw_probe_(void *fdt)
if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
- if (!can_assume(LATEST) && fdt_version(fdt) > 17)
- fdt_set_version(fdt, 17);
+ fdt_downgrade_version(fdt);
return 0;
}
diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h
index 914bf90785ab..81aaf7cbae13 100644
--- a/scripts/dtc/libfdt/libfdt.h
+++ b/scripts/dtc/libfdt/libfdt.h
@@ -116,6 +116,20 @@ extern "C" {
/* Low-level functions (you probably don't need these) */
/**********************************************************************/
+/**
+ * fdt_offset_ptr - safely get a byte range within the device tree blob
+ * @fdt: Pointer to the device tree blob
+ * @offset: Offset within the blob to the desired byte range
+ * @checklen: Required length of the byte range
+ *
+ * fdt_offset_ptr() returns a pointer to the byte range of length @checklen at
+ * the given @offset within the device tree blob, after verifying that the byte
+ * range fits entirely within the blob and does not overflow.
+ *
+ * returns:
+ * pointer to the byte range, on success
+ * NULL, if the requested range does not fit within the blob
+ */
#ifndef SWIG /* This function is not useful in Python */
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
#endif
@@ -124,6 +138,20 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
}
+/**
+ * fdt_next_tag - get next tag in the device tree
+ * @fdt: Pointer to the device tree blob
+ * @offset: Offset within the blob to start searching
+ * @nextoffset: Pointer to variable to store the offset of the next tag
+ *
+ * fdt_next_tag() returns the tag type of the next tag in the device tree
+ * blob starting from the given @offset. If @nextoffset is non-NULL, it will
+ * be set to the offset immediately following the tag.
+ *
+ * returns:
+ * the tag type (FDT_BEGIN_NODE, FDT_END_NODE, FDT_PROP, FDT_NOP, FDT_END),
+ * FDT_END, if offset is out of bounds
+ */
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
/*
@@ -334,6 +362,23 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/* Read-only functions */
/**********************************************************************/
+/**
+ * fdt_check_full - check device tree validity
+ * @fdt: pointer to the device tree blob
+ * @bufsize: size of the buffer containing the device tree
+ *
+ * fdt_check_full() checks that the given buffer contains a valid
+ * flattened device tree and that the tree structure is internally
+ * consistent. This is a more thorough check than fdt_check_header().
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_check_full(const void *fdt, size_t bufsize);
/**
@@ -1540,10 +1585,90 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
*/
int fdt_create(void *buf, int bufsize);
+/**
+ * fdt_resize - move and resize a device tree in sequential write state
+ * @fdt: Pointer to the device tree to resize
+ * @buf: Buffer where resized tree should be placed
+ * @bufsize: Size of the buffer at @buf
+ *
+ * fdt_resize() moves the device tree blob from @fdt to @buf and
+ * resizes it to fit in the new buffer size.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if @bufsize is too small
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
int fdt_resize(void *fdt, void *buf, int bufsize);
+
+/**
+ * fdt_add_reservemap_entry - add an entry to the memory reserve map
+ * @fdt: Pointer to the device tree blob
+ * @addr: Start address of the reserve map entry
+ * @size: Size of the reserved region
+ *
+ * fdt_add_reservemap_entry() adds a memory reserve map entry to the
+ * device tree blob during the sequential write process. This function
+ * can only be called after fdt_create() and before fdt_finish_reservemap().
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if there is insufficient space in the blob
+ * -FDT_ERR_BADSTATE, if not in the correct sequential write state
+ */
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+
+/**
+ * fdt_finish_reservemap - complete the memory reserve map
+ * @fdt: Pointer to the device tree blob
+ *
+ * fdt_finish_reservemap() completes the memory reserve map section
+ * of the device tree blob during sequential write. After calling this
+ * function, no more reserve map entries can be added and the blob
+ * moves to the structure creation phase.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADSTATE, if not in the correct sequential write state
+ */
int fdt_finish_reservemap(void *fdt);
+
+/**
+ * fdt_begin_node - start creation of a new node
+ * @fdt: Pointer to the device tree blob
+ * @name: Name of the node to create
+ *
+ * fdt_begin_node() starts the creation of a new node with the given
+ * @name during sequential write. After calling this function, properties
+ * can be added with fdt_property() and subnodes can be created with
+ * additional fdt_begin_node() calls. The node must be completed with
+ * fdt_end_node().
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if there is insufficient space in the blob
+ * -FDT_ERR_BADSTATE, if not in the correct sequential write state
+ */
int fdt_begin_node(void *fdt, const char *name);
+
+/**
+ * fdt_property - add a property to the current node
+ * @fdt: Pointer to the device tree blob
+ * @name: Name of the property to add
+ * @val: Pointer to the property value
+ * @len: Length of the property value in bytes
+ *
+ * fdt_property() adds a property with the given @name and value to
+ * the current node during sequential write. This function can only
+ * be called between fdt_begin_node() and fdt_end_node().
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if there is insufficient space in the blob
+ * -FDT_ERR_BADSTATE, if not currently within a node
+ */
int fdt_property(void *fdt, const char *name, const void *val, int len);
static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
{
@@ -1580,15 +1705,94 @@ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
#define fdt_property_string(fdt, name, str) \
fdt_property(fdt, name, str, strlen(str)+1)
+
+/**
+ * fdt_end_node - complete the current node
+ * @fdt: Pointer to the device tree blob
+ *
+ * fdt_end_node() completes the current node during sequential write. This
+ * function must be called to close each node started with
+ * fdt_begin_node(). After calling this function, no more properties or subnodes
+ * can be added to the node.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADSTATE, if not currently within a node
+ */
int fdt_end_node(void *fdt);
+
+/**
+ * fdt_finish - complete device tree creation
+ * @fdt: Pointer to the device tree blob
+ *
+ * fdt_finish() completes the device tree creation process started with
+ * fdt_create(). This function finalizes the device tree blob and makes it ready
+ * for use. After calling this function, the blob is complete and can be used
+ * with libfdt read-only and read-write functions, but not with sequential write
+ * functions.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADSTATE, if the sequential write process is incomplete
+ */
int fdt_finish(void *fdt);
/**********************************************************************/
/* Read-write functions */
/**********************************************************************/
+/**
+ * fdt_create_empty_tree - create an empty device tree
+ * @buf: Buffer where the empty tree should be created
+ * @bufsize: Size of the buffer at @buf
+ *
+ * fdt_create_empty_tree() creates a minimal empty device tree blob
+ * in the given buffer. The tree contains only a root node with no
+ * properties or subnodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if @bufsize is too small for even an empty tree
+ */
int fdt_create_empty_tree(void *buf, int bufsize);
+
+/**
+ * fdt_open_into - move a device tree into a new buffer and make editable
+ * @fdt: Pointer to the device tree to move
+ * @buf: Buffer where the editable tree should be placed
+ * @bufsize: Size of the buffer at @buf
+ *
+ * fdt_open_into() moves and reorganizes the device tree blob from @fdt
+ * into @buf, converting it to a format suitable for read-write operations.
+ * The new buffer should allow space for modifications.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if @bufsize is too small
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_open_into(const void *fdt, void *buf, int bufsize);
+
+/**
+ * fdt_pack - pack a device tree blob
+ * @fdt: Pointer to the device tree blob
+ *
+ * fdt_pack() reorganizes the device tree blob to eliminate any free space
+ * and pack it into the minimum possible size. This is useful after making
+ * modifications that might have left gaps in the blob.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT, standard meanings
+ */
int fdt_pack(void *fdt);
/**
@@ -2317,6 +2521,16 @@ int fdt_overlay_target_offset(const void *fdt, const void *fdto,
/* Debugging / informational functions */
/**********************************************************************/
+/**
+ * fdt_strerror - return string description of error code
+ * @errval: Error code returned by a libfdt function
+ *
+ * fdt_strerror() returns a string description of the error code passed
+ * in @errval.
+ *
+ * returns:
+ * pointer to a string describing the error code
+ */
const char *fdt_strerror(int errval);
#ifdef __cplusplus
diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h
index 73b6d40450ac..5580b483e6a9 100644
--- a/scripts/dtc/libfdt/libfdt_env.h
+++ b/scripts/dtc/libfdt/libfdt_env.h
@@ -66,31 +66,4 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE
-#ifdef __APPLE__
-#include <AvailabilityMacros.h>
-
-/* strnlen() is not available on Mac OS < 10.7 */
-# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
- MAC_OS_X_VERSION_10_7)
-
-#define strnlen fdt_strnlen
-
-/*
- * fdt_strnlen: returns the length of a string or max_count - which ever is
- * smallest.
- * Input 1 string: the string whose size is to be determined
- * Input 2 max_count: the maximum value returned by this function
- * Output: length of the string or max_count (the smallest of the two)
- */
-static inline size_t fdt_strnlen(const char *string, size_t max_count)
-{
- const char *p = memchr(string, 0, max_count);
- return p ? p - string : max_count;
-}
-
-#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
- MAC_OS_X_VERSION_10_7) */
-
-#endif /* __APPLE__ */
-
#endif /* LIBFDT_ENV_H */
diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h
index b60b5456f596..0e103cafa714 100644
--- a/scripts/dtc/libfdt/libfdt_internal.h
+++ b/scripts/dtc/libfdt/libfdt_internal.h
@@ -11,11 +11,13 @@
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
int32_t fdt_ro_probe_(const void *fdt);
-#define FDT_RO_PROBE(fdt) \
- { \
- int32_t totalsize_; \
- if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
- return totalsize_; \
+#define FDT_RO_PROBE(fdt) \
+ { \
+ if (!can_assume(VALID_DTB)) { \
+ int32_t totalsize_; \
+ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
+ return totalsize_; \
+ } \
}
int fdt_check_node_offset_(const void *fdt, int offset);
@@ -92,7 +94,7 @@ static inline uint64_t fdt64_ld_(const fdt64_t *p)
* signature or hash check before using libfdt.
*
* For situations where security is not a concern it may be safe to enable
- * ASSUME_SANE.
+ * ASSUME_PERFECT.
*/
enum {
/*
diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c
index d51d05830b18..5d72abceb526 100644
--- a/scripts/dtc/livetree.c
+++ b/scripts/dtc/livetree.c
@@ -340,20 +340,73 @@ void append_to_property(struct node *node,
char *name, const void *data, int len,
enum markertype type)
{
- struct data d;
+ struct property *p;
+
+ p = get_property(node, name);
+ if (!p) {
+ p = build_property(name, empty_data, NULL);
+ add_property(node, p);
+ }
+
+ p->val = data_add_marker(p->val, type, name);
+ p->val = data_append_data(p->val, data, len);
+}
+
+static int append_unique_str_to_property(struct node *node,
+ char *name, const char *data, int len)
+{
struct property *p;
p = get_property(node, name);
if (p) {
- d = data_add_marker(p->val, type, name);
- d = data_append_data(d, data, len);
- p->val = d;
+ const char *s;
+
+ if (p->val.len && p->val.val[p->val.len - 1] != '\0')
+ /* The current content doesn't look like a string */
+ return -1;
+
+ for (s = p->val.val; s < p->val.val + p->val.len; s = strchr(s, '\0') + 1) {
+ if (strcmp(data, s) == 0)
+ /* data already contained in node.name */
+ return 0;
+ }
} else {
- d = data_add_marker(empty_data, type, name);
- d = data_append_data(d, data, len);
- p = build_property(name, d, NULL);
+ p = build_property(name, empty_data, NULL);
add_property(node, p);
}
+
+ p->val = data_add_marker(p->val, TYPE_STRING, name);
+ p->val = data_append_data(p->val, data, len);
+
+ return 0;
+}
+
+static int append_unique_u32_to_property(struct node *node, char *name, fdt32_t value)
+{
+ struct property *p;
+
+ p = get_property(node, name);
+ if (p) {
+ const fdt32_t *v, *val_end = (const fdt32_t *)p->val.val + p->val.len / 4;
+
+ if (p->val.len % 4 != 0)
+ /* The current content doesn't look like a u32 array */
+ return -1;
+
+ for (v = (const void *)p->val.val; v < val_end; v++) {
+ if (*v == value)
+ /* value already contained */
+ return 0;
+ }
+ } else {
+ p = build_property(name, empty_data, NULL);
+ add_property(node, p);
+ }
+
+ p->val = data_add_marker(p->val, TYPE_UINT32, name);
+ p->val = data_append_data(p->val, &value, 4);
+
+ return 0;
}
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
@@ -918,11 +971,12 @@ static bool any_fixup_tree(struct dt_info *dti, struct node *node)
return false;
}
-static void add_fixup_entry(struct dt_info *dti, struct node *fn,
- struct node *node, struct property *prop,
- struct marker *m)
+static int add_fixup_entry(struct dt_info *dti, struct node *fn,
+ struct node *node, struct property *prop,
+ struct marker *m)
{
char *entry;
+ int ret;
/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);
@@ -939,32 +993,39 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
- append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
+ ret = append_unique_str_to_property(fn, m->ref, entry, strlen(entry) + 1);
free(entry);
+
+ return ret;
}
-static void generate_fixups_tree_internal(struct dt_info *dti,
- struct node *fn,
- struct node *node)
+static int generate_fixups_tree_internal(struct dt_info *dti,
+ struct node *fn,
+ struct node *node)
{
struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;
+ int ret = 0;
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (!refnode)
- add_fixup_entry(dti, fn, node, prop, m);
+ if (add_fixup_entry(dti, fn, node, prop, m))
+ ret = -1;
}
}
for_each_child(node, c)
- generate_fixups_tree_internal(dti, fn, c);
+ if (generate_fixups_tree_internal(dti, fn, c))
+ ret = -1;
+
+ return ret;
}
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
@@ -989,7 +1050,7 @@ static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
return false;
}
-static void add_local_fixup_entry(struct dt_info *dti,
+static int add_local_fixup_entry(struct dt_info *dti,
struct node *lfn, struct node *node,
struct property *prop, struct marker *m,
struct node *refnode)
@@ -1020,30 +1081,56 @@ static void add_local_fixup_entry(struct dt_info *dti,
free(compp);
value_32 = cpu_to_fdt32(m->offset);
- append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
+ return append_unique_u32_to_property(wn, prop->name, value_32);
}
-static void generate_local_fixups_tree_internal(struct dt_info *dti,
- struct node *lfn,
- struct node *node)
+static int generate_local_fixups_tree_internal(struct dt_info *dti,
+ struct node *lfn,
+ struct node *node)
{
struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;
+ int ret = 0;
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (refnode)
- add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
+ if (add_local_fixup_entry(dti, lfn, node, prop, m, refnode))
+ ret = -1;
}
}
for_each_child(node, c)
- generate_local_fixups_tree_internal(dti, lfn, c);
+ if (generate_local_fixups_tree_internal(dti, lfn, c))
+ ret = -1;
+
+ return ret;
+}
+
+void generate_labels_from_tree(struct dt_info *dti, const char *name)
+{
+ struct node *an;
+ struct property *p;
+
+ an = get_subnode(dti->dt, name);
+ if (!an)
+ return;
+
+ for_each_property(an, p) {
+ struct node *labeled_node;
+
+ labeled_node = get_node_by_path(dti->dt, p->val.val);
+ if (labeled_node)
+ add_label(&labeled_node->labels, p->name);
+ else if (quiet < 1)
+ fprintf(stderr, "Warning: Path %s referenced in property %s/%s missing",
+ p->val.val, name, p->name);
+ }
}
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
@@ -1056,29 +1143,173 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
void generate_fixups_tree(struct dt_info *dti, const char *name)
{
- struct node *n = get_subnode(dti->dt, name);
+ if (!any_fixup_tree(dti, dti->dt))
+ return;
+ if (generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
+ fprintf(stderr,
+ "Warning: Preexisting data in %s malformed, some content could not be added.\n",
+ name);
+}
- /* Start with an empty __fixups__ node to not get duplicates */
- if (n)
- n->deleted = true;
+void fixup_phandles(struct dt_info *dti, const char *name)
+{
+ struct node *an;
+ struct property *fp;
- if (!any_fixup_tree(dti, dti->dt))
+ an = get_subnode(dti->dt, name);
+ if (!an)
return;
- generate_fixups_tree_internal(dti,
- build_and_name_child_node(dti->dt, name),
- dti->dt);
+
+ for_each_property(an, fp) {
+ char *fnext = fp->val.val;
+ char *fv;
+ unsigned int fl;
+
+ while ((fl = fp->val.len - (fnext - fp->val.val))) {
+ char *propname, *soffset;
+ struct node *n;
+ struct property *p;
+ long offset;
+
+ fv = fnext;
+ fnext = memchr(fv, 0, fl);
+
+ if (!fnext) {
+ if (quiet < 1)
+ fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
+ fp->name);
+ break;
+ }
+ fnext += 1;
+
+ propname = memchr(fv, ':', fnext - 1 - fv);
+ if (!propname) {
+ if (quiet < 1)
+ fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
+ fp->name);
+ continue;
+ }
+ propname++;
+
+ soffset = memchr(propname, ':', fnext - 1 - propname);
+ if (!soffset) {
+ if (quiet < 1)
+ fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
+ fp->name);
+ continue;
+ }
+ soffset++;
+
+ /*
+ * temporarily modify the property to not have to create
+ * a copy for the node path.
+ */
+ *(propname - 1) = '\0';
+
+ n = get_node_by_path(dti->dt, fv);
+ if (!n && quiet < 1)
+ fprintf(stderr, "Warning: Label %s references non-existing node %s\n",
+ fp->name, fv);
+
+ *(propname - 1) = ':';
+
+ if (!n)
+ continue;
+
+ /*
+ * temporarily modify the property to not have to create
+ * a copy for the property name.
+ */
+ *(soffset - 1) = '\0';
+
+ p = get_property(n, propname);
+
+ if (!p && quiet < 1)
+ fprintf(stderr, "Warning: Label %s references non-existing property %s in node %s\n",
+ fp->name, n->fullpath, propname);
+
+ *(soffset - 1) = ':';
+
+ if (!p)
+ continue;
+
+ offset = strtol(soffset, NULL, 0);
+ if (offset < 0 || offset + 4 > p->val.len) {
+ if (quiet < 1)
+ fprintf(stderr,
+ "Warning: Label %s contains invalid offset for property %s in node %s\n",
+ fp->name, p->name, n->fullpath);
+ continue;
+ }
+
+ property_add_marker(p, REF_PHANDLE, offset, fp->name);
+ }
+ }
}
void generate_local_fixups_tree(struct dt_info *dti, const char *name)
{
- struct node *n = get_subnode(dti->dt, name);
-
- /* Start with an empty __local_fixups__ node to not get duplicates */
- if (n)
- n->deleted = true;
if (!any_local_fixup_tree(dti, dti->dt))
return;
- generate_local_fixups_tree_internal(dti,
- build_and_name_child_node(dti->dt, name),
- dti->dt);
+ if (generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
+ fprintf(stderr,
+ "Warning: Preexisting data in %s malformed, some content could not be added.\n",
+ name);
+}
+
+static void local_fixup_phandles_node(struct dt_info *dti, struct node *lf, struct node *n)
+{
+ struct property *lfp;
+ struct node *lfsubnode;
+
+ for_each_property(lf, lfp) {
+ struct property *p = get_property(n, lfp->name);
+ fdt32_t *offsets = (fdt32_t *)lfp->val.val;
+ size_t i;
+
+ if (!p) {
+ if (quiet < 1)
+ fprintf(stderr, "Warning: Property %s in %s referenced in __local_fixups__ missing\n",
+ lfp->name, n->fullpath);
+ continue;
+ }
+
+ /*
+ * Each property in the __local_fixups__ tree is a concatenation
+ * of offsets, so it must be a multiple of sizeof(fdt32_t).
+ */
+ if (lfp->val.len % sizeof(fdt32_t)) {
+ if (quiet < 1)
+ fprintf(stderr, "Warning: property %s in /__local_fixups__%s malformed\n",
+ lfp->name, n->fullpath);
+ continue;
+ }
+
+ for (i = 0; i < lfp->val.len / sizeof(fdt32_t); i++)
+ add_phandle_marker(dti, p, dtb_ld32(offsets + i));
+ }
+
+ for_each_child(lf, lfsubnode) {
+ struct node *subnode = get_subnode(n, lfsubnode->name);
+
+ if (!subnode) {
+ if (quiet < 1)
+ fprintf(stderr, "Warning: node %s/%s referenced in __local_fixups__ missing\n",
+ lfsubnode->name, n->fullpath);
+ continue;
+ }
+
+ local_fixup_phandles_node(dti, lfsubnode, subnode);
+ }
+}
+
+void local_fixup_phandles(struct dt_info *dti, const char *name)
+{
+ struct node *an;
+
+ an = get_subnode(dti->dt, name);
+ if (!an)
+ return;
+
+ local_fixup_phandles_node(dti, an, dti->dt);
}
diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c
index 5bb57bf6856c..fef892fb6fdd 100644
--- a/scripts/dtc/srcpos.c
+++ b/scripts/dtc/srcpos.c
@@ -89,6 +89,26 @@ static char *shorten_to_initial_path(char *fname)
}
/**
+ * Returns true if the given path is an absolute one.
+ *
+ * On Windows, it either needs to begin with a forward slash or with a drive
+ * letter (e.g. "C:").
+ * On all other operating systems, it must begin with a forward slash to be
+ * considered an absolute path.
+ */
+static bool is_absolute_path(const char *path)
+{
+#ifdef WIN32
+ return (
+ path[0] == '/' ||
+ (((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) && path[1] == ':')
+ );
+#else
+ return (path[0] == '/');
+#endif
+}
+
+/**
* Try to open a file in a given directory.
*
* If the filename is an absolute path, then dirname is ignored. If it is a
@@ -103,7 +123,7 @@ static char *try_open(const char *dirname, const char *fname, FILE **fp)
{
char *fullname;
- if (!dirname || fname[0] == '/')
+ if (!dirname || is_absolute_path(fname))
fullname = xstrdup(fname);
else
fullname = join_path(dirname, fname);
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
index d25f01fc6937..bf648bf6c21a 100644
--- a/scripts/dtc/treesource.c
+++ b/scripts/dtc/treesource.c
@@ -173,23 +173,59 @@ static struct marker **add_marker(struct marker **mi,
return &nm->next;
}
-static void add_string_markers(struct property *prop)
+void property_add_marker(struct property *prop,
+ enum markertype type, unsigned int offset, char *ref)
{
- int l, len = prop->val.len;
- const char *p = prop->val.val;
+ add_marker(&prop->val.markers, type, offset, ref);
+}
+
+static void add_string_markers(struct property *prop, unsigned int offset, int len)
+{
+ int l;
+ const char *p = prop->val.val + offset;
struct marker **mi = &prop->val.markers;
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
- mi = add_marker(mi, TYPE_STRING, l, NULL);
+ mi = add_marker(mi, TYPE_STRING, offset + l, NULL);
+}
+
+void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset)
+{
+ cell_t phandle;
+ struct node *refn;
+ char *ref;
+
+ if (prop->val.len < offset + 4) {
+ if (quiet < 1)
+ fprintf(stderr,
+ "Warning: property %s too short to contain a phandle at offset %u\n",
+ prop->name, offset);
+ return;
+ }
+
+ phandle = dtb_ld32(prop->val.val + offset);
+ refn = get_node_by_phandle(dti->dt, phandle);
+
+ if (!refn) {
+ if (quiet < 1)
+ fprintf(stderr,
+ "Warning: node referenced by phandle 0x%x in property %s not found\n",
+ phandle, prop->name);
+ return;
+ }
+
+ if (refn->labels)
+ ref = refn->labels->label;
+ else
+ ref = refn->fullpath;
+
+ add_marker(&prop->val.markers, REF_PHANDLE, offset, ref);
}
-static enum markertype guess_value_type(struct property *prop)
+static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len)
{
- int len = prop->val.len;
- const char *p = prop->val.val;
- struct marker *m = prop->val.markers;
+ const char *p = prop->val.val + offset;
int nnotstring = 0, nnul = 0;
- int nnotstringlbl = 0, nnotcelllbl = 0;
int i;
for (i = 0; i < len; i++) {
@@ -199,30 +235,49 @@ static enum markertype guess_value_type(struct property *prop)
nnul++;
}
- for_each_marker_of_type(m, LABEL) {
- if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
- nnotstringlbl++;
- if ((m->offset % sizeof(cell_t)) != 0)
- nnotcelllbl++;
- }
-
- if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
- && (nnotstringlbl == 0)) {
+ if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) {
if (nnul > 1)
- add_string_markers(prop);
+ add_string_markers(prop, offset, len);
return TYPE_STRING;
- } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
+ } else if ((len % sizeof(cell_t)) == 0) {
return TYPE_UINT32;
}
return TYPE_UINT8;
}
+static void guess_type_markers(struct property *prop)
+{
+ struct marker **m = &prop->val.markers;
+ unsigned int offset = 0;
+
+ for (m = &prop->val.markers; *m; m = &((*m)->next)) {
+ if (is_type_marker((*m)->type))
+ /* assume the whole property is already marked */
+ return;
+
+ if ((*m)->offset > offset) {
+ m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset),
+ offset, NULL);
+
+ offset = (*m)->offset;
+ }
+
+ if ((*m)->type == REF_PHANDLE) {
+ m = add_marker(m, TYPE_UINT32, offset, NULL);
+ offset += 4;
+ }
+ }
+
+ if (offset < prop->val.len)
+ add_marker(m, guess_value_type(prop, offset, prop->val.len - offset),
+ offset, NULL);
+}
+
static void write_propval(FILE *f, struct property *prop)
{
size_t len = prop->val.len;
- struct marker *m = prop->val.markers;
- struct marker dummy_marker;
+ struct marker *m;
enum markertype emit_type = TYPE_NONE;
char *srcstr;
@@ -241,14 +296,8 @@ static void write_propval(FILE *f, struct property *prop)
fprintf(f, " =");
- if (!next_type_marker(m)) {
- /* data type information missing, need to guess */
- dummy_marker.type = guess_value_type(prop);
- dummy_marker.next = prop->val.markers;
- dummy_marker.offset = 0;
- dummy_marker.ref = NULL;
- m = &dummy_marker;
- }
+ guess_type_markers(prop);
+ m = prop->val.markers;
for_each_marker(m) {
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
@@ -369,7 +418,10 @@ void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
- fprintf(f, "/dts-v1/;\n\n");
+ fprintf(f, "/dts-v1/;\n");
+ if (dti->dtsflags & DTSF_PLUGIN)
+ fprintf(f, "/plugin/;\n");
+ fprintf(f, "\n");
for (re = dti->reservelist; re; re = re->next) {
struct label *l;
diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h
index 226c48bf75dc..122e684e76a1 100644
--- a/scripts/dtc/version_gen.h
+++ b/scripts/dtc/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.7.2-g52f07dcc"
+#define DTC_VERSION "DTC 1.7.2-g53373d13"
diff --git a/scripts/dummy-tools/python3 b/scripts/dummy-tools/python3
new file mode 100755
index 000000000000..24c5584861b6
--- /dev/null
+++ b/scripts/dummy-tools/python3
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+
+true
diff --git a/scripts/gcc-plugins/gcc-common.h b/scripts/gcc-plugins/gcc-common.h
index 8f1b3500f8e2..abb1964c44d4 100644
--- a/scripts/gcc-plugins/gcc-common.h
+++ b/scripts/gcc-plugins/gcc-common.h
@@ -309,7 +309,9 @@ typedef const gimple *const_gimple_ptr;
#define gimple gimple_ptr
#define const_gimple const_gimple_ptr
#undef CONST_CAST_GIMPLE
-#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X))
+#define CONST_CAST_GIMPLE(X) const_cast<gimple>((X))
+#undef CONST_CAST_TREE
+#define CONST_CAST_TREE(X) const_cast<tree>((X))
/* gimple related */
static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL)
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 6d475540c6ba..dab8b80bed69 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -150,8 +150,8 @@ LX_CONFIG(CONFIG_ARM64_64K_PAGES)
if IS_BUILTIN(CONFIG_ARM64):
LX_VALUE(CONFIG_ARM64_PA_BITS)
LX_VALUE(CONFIG_ARM64_VA_BITS)
- LX_VALUE(CONFIG_PAGE_SHIFT)
LX_VALUE(CONFIG_ARCH_FORCE_MAX_ORDER)
+LX_VALUE(CONFIG_PAGE_SHIFT)
LX_CONFIG(CONFIG_SPARSEMEM)
LX_CONFIG(CONFIG_SPARSEMEM_EXTREME)
LX_CONFIG(CONFIG_SPARSEMEM_VMEMMAP)
diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py
index f4f715a8f0e3..a68ae91b4531 100644
--- a/scripts/gdb/linux/interrupts.py
+++ b/scripts/gdb/linux/interrupts.py
@@ -20,7 +20,7 @@ def irq_desc_is_chained(desc):
def irqd_is_level(desc):
return desc['irq_data']['common']['state_use_accessors'] & constants.LX_IRQD_LEVEL
-def show_irq_desc(prec, irq):
+def show_irq_desc(prec, chip_width, irq):
text = ""
desc = mapletree.mtree_load(gdb.parse_and_eval("&sparse_irqs"), irq)
@@ -48,7 +48,7 @@ def show_irq_desc(prec, irq):
count = cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt']
else:
count = 0
- text += "%10u" % (count)
+ text += "%10u " % (count)
name = "None"
if desc['irq_data']['chip']:
@@ -58,7 +58,7 @@ def show_irq_desc(prec, irq):
else:
name = "-"
- text += " %8s" % (name)
+ text += " %-*s" % (chip_width, name)
if desc['irq_data']['domain']:
text += " %*lu" % (prec, desc['irq_data']['hwirq'])
@@ -97,64 +97,29 @@ def show_irq_err_count(prec):
text += "%*s: %10u\n" % (prec, "ERR", cnt['counter'])
return text
-def x86_show_irqstat(prec, pfx, field, desc):
- irq_stat = gdb.parse_and_eval("&irq_stat")
+def x86_show_irqstat(prec, pfx, idx, desc):
+ irq_stat = gdb.parse_and_eval("&irq_stat.counts[%d]" %idx)
text = "%*s: " % (prec, pfx)
for cpu in cpus.each_online_cpu():
stat = cpus.per_cpu(irq_stat, cpu)
- text += "%10u " % (stat[field])
- text += " %s\n" % (desc)
- return text
-
-def x86_show_mce(prec, var, pfx, desc):
- pvar = gdb.parse_and_eval(var)
- text = "%*s: " % (prec, pfx)
- for cpu in cpus.each_online_cpu():
- text += "%10u " % (cpus.per_cpu(pvar, cpu).dereference())
- text += " %s\n" % (desc)
+ text += "%10u " % (stat.dereference())
+ text += desc
return text
def x86_show_interupts(prec):
- text = x86_show_irqstat(prec, "NMI", '__nmi_count', 'Non-maskable interrupts')
-
- if constants.LX_CONFIG_X86_LOCAL_APIC:
- text += x86_show_irqstat(prec, "LOC", 'apic_timer_irqs', "Local timer interrupts")
- text += x86_show_irqstat(prec, "SPU", 'irq_spurious_count', "Spurious interrupts")
- text += x86_show_irqstat(prec, "PMI", 'apic_perf_irqs', "Performance monitoring interrupts")
- text += x86_show_irqstat(prec, "IWI", 'apic_irq_work_irqs', "IRQ work interrupts")
- text += x86_show_irqstat(prec, "RTR", 'icr_read_retry_count', "APIC ICR read retries")
- if utils.gdb_eval_or_none("x86_platform_ipi_callback") is not None:
- text += x86_show_irqstat(prec, "PLT", 'x86_platform_ipis', "Platform interrupts")
-
- if constants.LX_CONFIG_SMP:
- text += x86_show_irqstat(prec, "RES", 'irq_resched_count', "Rescheduling interrupts")
- text += x86_show_irqstat(prec, "CAL", 'irq_call_count', "Function call interrupts")
- text += x86_show_irqstat(prec, "TLB", 'irq_tlb_count', "TLB shootdowns")
-
- if constants.LX_CONFIG_X86_THERMAL_VECTOR:
- text += x86_show_irqstat(prec, "TRM", 'irq_thermal_count', "Thermal events interrupts")
-
- if constants.LX_CONFIG_X86_MCE_THRESHOLD:
- text += x86_show_irqstat(prec, "THR", 'irq_threshold_count', "Threshold APIC interrupts")
-
- if constants.LX_CONFIG_X86_MCE_AMD:
- text += x86_show_irqstat(prec, "DFR", 'irq_deferred_error_count', "Deferred Error APIC interrupts")
+ info_type = gdb.lookup_type('struct irq_stat_info')
+ info = gdb.parse_and_eval('irq_stat_info')
+ bitmap = gdb.parse_and_eval('irq_stat_count_show')
+ bitsperlong = 8 * int(bitmap.type.target().sizeof)
- if constants.LX_CONFIG_X86_MCE:
- text += x86_show_mce(prec, "&mce_exception_count", "MCE", "Machine check exceptions")
- text += x86_show_mce(prec, "&mce_poll_count", "MCP", "Machine check polls")
-
- text += show_irq_err_count(prec)
-
- if constants.LX_CONFIG_X86_IO_APIC:
- cnt = utils.gdb_eval_or_none("irq_mis_count")
- if cnt is not None:
- text += "%*s: %10u\n" % (prec, "MIS", cnt['counter'])
-
- if constants.LX_CONFIG_KVM:
- text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event')
- text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event')
- text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event')
+ text = ""
+ for idx in range(int(info.type.sizeof / info_type.sizeof)):
+ show = bitmap[int(idx / bitsperlong)]
+ if not show & 1 << int(idx % bitsperlong):
+ continue
+ pfx = info[idx]['symbol'].string()
+ desc = info[idx]['text'].string()
+ text += x86_show_irqstat(prec, pfx, idx, desc)
return text
@@ -166,23 +131,19 @@ def arm_common_show_interrupts(prec):
if nr_ipi is None or ipi_desc is None or ipi_types is None:
return text
- if prec >= 4:
- sep = " "
- else:
- sep = ""
-
for ipi in range(nr_ipi):
- text += "%*s%u:%s" % (prec - 1, "IPI", ipi, sep)
+ text += "%*s%u: " % (prec - 1, "IPI", ipi)
desc = ipi_desc[ipi].cast(irq_desc_type.get_type().pointer())
if desc == 0:
continue
for cpu in cpus.each_online_cpu():
- text += "%10u" % (cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt'])
- text += " %s" % (ipi_types[ipi].string())
+ text += "%10u " % (cpus.per_cpu(desc['kstat_irqs'], cpu)['cnt'])
+ text += "%s" % (ipi_types[ipi].string())
text += "\n"
return text
def aarch64_show_interrupts(prec):
+ # Does not work for ARM64 as "ipi_desc" is not available there
text = arm_common_show_interrupts(prec)
text += "%*s: %10lu\n" % (prec, "ERR", gdb.parse_and_eval("irq_err_count"))
return text
@@ -209,12 +170,19 @@ class LxInterruptList(gdb.Command):
super(LxInterruptList, self).__init__("lx-interruptlist", gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
- nr_irqs = gdb.parse_and_eval("nr_irqs")
- prec = 3
- j = 1000
- while prec < 10 and j <= nr_irqs:
- prec += 1
- j *= 10
+ nr_irqs = gdb.parse_and_eval("total_nr_irqs")
+ constr = utils.gdb_eval_or_none('irq_proc_constraints')
+
+ if constr:
+ prec = int(constr['num_prec'])
+ chip_width = int(constr['chip_width'])
+ else:
+ prec = 4
+ j = 10000
+ while prec < 10 and j <= nr_irqs:
+ prec += 1
+ j *= 10
+ chip_width = 8
gdb.write("%*s" % (prec + 8, ""))
for cpu in cpus.each_online_cpu():
@@ -225,7 +193,7 @@ class LxInterruptList(gdb.Command):
raise gdb.GdbError("Unable to find the sparse IRQ tree, is CONFIG_SPARSE_IRQ enabled?")
for irq in range(nr_irqs):
- gdb.write(show_irq_desc(prec, irq))
+ gdb.write(show_irq_desc(prec, chip_width, irq))
gdb.write(arch_show_interrupts(prec))
diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py
index 7571aebbe650..dffadccbb01d 100644
--- a/scripts/gdb/linux/mm.py
+++ b/scripts/gdb/linux/mm.py
@@ -26,8 +26,179 @@ class page_ops():
raise gdb.GdbError('Only support CONFIG_SPARSEMEM_VMEMMAP now')
if constants.LX_CONFIG_ARM64 and utils.is_target_arch('aarch64'):
self.ops = aarch64_page_ops()
+ elif utils.is_target_arch('x86_64') or utils.is_target_arch('x86-64'):
+ self.ops = x86_page_ops()
else:
- raise gdb.GdbError('Only support aarch64 now')
+ raise gdb.GdbError('Only support aarch64 and x86_64 now')
+
+class x86_page_ops():
+ def __init__(self):
+ self.struct_page_size = utils.get_page_type().sizeof
+ self.PAGE_SHIFT = constants.LX_CONFIG_PAGE_SHIFT
+ self.PAGE_SIZE = 1 << self.PAGE_SHIFT
+ self.PAGE_MASK = (~(self.PAGE_SIZE - 1)) & ((1 << 64) - 1)
+
+ self.PAGE_OFFSET = int(gdb.parse_and_eval("page_offset_base"))
+ self.VMEMMAP_START = int(gdb.parse_and_eval("vmemmap_base"))
+ self.PHYS_BASE = int(gdb.parse_and_eval("(unsigned long) phys_base"))
+ self.START_KERNEL_map = 0xffffffff80000000
+
+ self.KERNEL_START = gdb.parse_and_eval("(unsigned long) &_text")
+ self.KERNEL_END = gdb.parse_and_eval("(unsigned long) &_end")
+
+ self.VMALLOC_START = int(gdb.parse_and_eval("vmalloc_base"))
+ if self.VMALLOC_START == 0xffffc90000000000:
+ self.VMALLOC_END = self.VMALLOC_START + (32 * 1024 * 1024 * 1024 * 1024) - 1
+ elif self.VMALLOC_START == 0xffa0000000000000:
+ self.VMALLOC_END = self.VMALLOC_START + (12800 * 1024 * 1024 * 1024 * 1024) - 1
+ else:
+ self.VMALLOC_END = self.VMALLOC_START + (12800 * 1024 * 1024 * 1024 * 1024) - 1
+
+ self.MAX_PHYSMEM_BITS = 46
+ self.SECTION_SIZE_BITS = 27
+ self.MAX_ORDER = 10
+
+ self.SECTIONS_SHIFT = self.MAX_PHYSMEM_BITS - self.SECTION_SIZE_BITS
+ self.NR_MEM_SECTIONS = 1 << self.SECTIONS_SHIFT
+ self.PFN_SECTION_SHIFT = self.SECTION_SIZE_BITS - self.PAGE_SHIFT
+ self.PAGES_PER_SECTION = 1 << self.PFN_SECTION_SHIFT
+ self.PAGE_SECTION_MASK = (~(self.PAGES_PER_SECTION - 1)) & ((1 << 64) - 1)
+
+ if constants.LX_CONFIG_SPARSEMEM_EXTREME:
+ self.SECTIONS_PER_ROOT = self.PAGE_SIZE // gdb.lookup_type("struct mem_section").sizeof
+ else:
+ self.SECTIONS_PER_ROOT = 1
+
+ self.NR_SECTION_ROOTS = DIV_ROUND_UP(self.NR_MEM_SECTIONS, self.SECTIONS_PER_ROOT)
+ self.SECTION_ROOT_MASK = self.SECTIONS_PER_ROOT - 1
+
+ try:
+ self.SECTION_HAS_MEM_MAP = 1 << int(gdb.parse_and_eval('SECTION_HAS_MEM_MAP_BIT'))
+ self.SECTION_IS_EARLY = 1 << int(gdb.parse_and_eval('SECTION_IS_EARLY_BIT'))
+ except:
+ self.SECTION_HAS_MEM_MAP = 1 << 0
+ self.SECTION_IS_EARLY = 1 << 3
+
+ self.SUBSECTION_SHIFT = 21
+ self.PAGES_PER_SUBSECTION = 1 << (self.SUBSECTION_SHIFT - self.PAGE_SHIFT)
+
+ if constants.LX_CONFIG_NUMA and constants.LX_CONFIG_NODES_SHIFT:
+ self.NODE_SHIFT = constants.LX_CONFIG_NODES_SHIFT
+ else:
+ self.NODE_SHIFT = 0
+
+ self.MAX_NUMNODES = 1 << self.NODE_SHIFT
+
+ self.vmemmap = gdb.Value(self.VMEMMAP_START).cast(utils.get_page_type().pointer())
+
+ def kasan_reset_tag(self, addr):
+ return addr
+
+ def SECTION_NR_TO_ROOT(self, sec):
+ return sec // self.SECTIONS_PER_ROOT
+
+ def __nr_to_section(self, nr):
+ root = self.SECTION_NR_TO_ROOT(nr)
+ mem_section = gdb.parse_and_eval("mem_section")
+ return mem_section[root][nr & self.SECTION_ROOT_MASK]
+
+ def pfn_to_section_nr(self, pfn):
+ return pfn >> self.PFN_SECTION_SHIFT
+
+ def section_nr_to_pfn(self, sec):
+ return sec << self.PFN_SECTION_SHIFT
+
+ def __pfn_to_section(self, pfn):
+ return self.__nr_to_section(self.pfn_to_section_nr(pfn))
+
+ def pfn_to_section(self, pfn):
+ return self.__pfn_to_section(pfn)
+
+ def subsection_map_index(self, pfn):
+ return (pfn & ~(self.PAGE_SECTION_MASK)) // self.PAGES_PER_SUBSECTION
+
+ def pfn_section_valid(self, ms, pfn):
+ if constants.LX_CONFIG_SPARSEMEM_VMEMMAP:
+ idx = self.subsection_map_index(pfn)
+ return test_bit(idx, ms['usage']['subsection_map'])
+ else:
+ return True
+
+ def valid_section(self, mem_section):
+ if mem_section != None and (mem_section['section_mem_map'] & self.SECTION_HAS_MEM_MAP):
+ return True
+ return False
+
+ def early_section(self, mem_section):
+ if mem_section != None and (mem_section['section_mem_map'] & self.SECTION_IS_EARLY):
+ return True
+ return False
+
+ def pfn_valid(self, pfn):
+ ms = None
+ if self.PHYS_PFN(self.PFN_PHYS(pfn)) != pfn:
+ return False
+ if self.pfn_to_section_nr(pfn) >= self.NR_MEM_SECTIONS:
+ return False
+ ms = self.__pfn_to_section(pfn)
+
+ if not self.valid_section(ms):
+ return False
+ return self.early_section(ms) or self.pfn_section_valid(ms, pfn)
+
+ def PFN_PHYS(self, pfn):
+ return pfn << self.PAGE_SHIFT
+
+ def PHYS_PFN(self, phys):
+ return phys >> self.PAGE_SHIFT
+
+ def __phys_to_virt(self, pa):
+ return pa + self.PAGE_OFFSET
+
+ def __virt_to_phys(self, va):
+ if va >= self.START_KERNEL_map:
+ return va - self.START_KERNEL_map + self.PHYS_BASE
+ else:
+ return va - self.PAGE_OFFSET
+
+ def virt_to_phys(self, va):
+ return self.__virt_to_phys(va)
+
+ def virt_to_page(self, va):
+ return self.pfn_to_page(self.virt_to_pfn(va))
+
+ def __pa(self, va):
+ return self.__virt_to_phys(va)
+
+ def __va(self, pa):
+ return self.__phys_to_virt(pa)
+
+ def pfn_to_kaddr(self, pfn):
+ return self.__va(pfn << self.PAGE_SHIFT)
+
+ def virt_to_pfn(self, va):
+ return self.PHYS_PFN(self.__virt_to_phys(va))
+
+ def sym_to_pfn(self, x):
+ return self.PHYS_PFN(self.__virt_to_phys(x))
+
+ def page_to_pfn(self, page):
+ return int(page.cast(utils.get_page_type().pointer()) - self.vmemmap)
+
+ def pfn_to_page(self, pfn):
+ return self.vmemmap + pfn
+
+ def page_to_phys(self, page):
+ return self.PFN_PHYS(self.page_to_pfn(page))
+
+ def page_to_virt(self, page):
+ return self.__va(self.page_to_phys(page))
+
+ def page_address(self, page):
+ return self.page_to_virt(page)
+
+ def folio_address(self, folio):
+ return self.page_address(folio['page'].address)
class aarch64_page_ops():
def __init__(self):
diff --git a/scripts/gdb/linux/slab.py b/scripts/gdb/linux/slab.py
index 0e2d93867fe2..ddde25aeca8d 100644
--- a/scripts/gdb/linux/slab.py
+++ b/scripts/gdb/linux/slab.py
@@ -196,7 +196,7 @@ def slabtrace(alloc, cache_name):
if target_cache['flags'] & SLAB_STORE_USER:
for i in range(0, nr_node_ids):
- cache_node = target_cache['node'][i]
+ cache_node = target_cache['per_node']['node'][i]
if cache_node['nr_slabs']['counter'] == 0:
continue
process_slab(loc_track, cache_node['partial'], alloc, target_cache)
@@ -300,7 +300,7 @@ def slabinfo():
nr_free = 0
nr_slabs = 0
for i in range(0, nr_node_ids):
- cache_node = cache['node'][i]
+ cache_node = cache['per_node']['node'][i]
try:
nr_slabs += cache_node['nr_slabs']['counter']
nr_objs = int(cache_node['total_objects']['counter'])
diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py
index d4308b726183..943ff1228b48 100644
--- a/scripts/gdb/linux/symbols.py
+++ b/scripts/gdb/linux/symbols.py
@@ -298,7 +298,7 @@ are loaded as well."""
if p == "-bpf":
monitor_bpf = True
else:
- p.append(os.path.abspath(os.path.expanduser(p)))
+ self.module_paths.append(os.path.abspath(os.path.expanduser(p)))
self.module_paths.append(os.getcwd())
if self.breakpoint is not None:
diff --git a/scripts/gdb/linux/timerlist.py b/scripts/gdb/linux/timerlist.py
index ccc24d30de80..744b032e4d38 100644
--- a/scripts/gdb/linux/timerlist.py
+++ b/scripts/gdb/linux/timerlist.py
@@ -20,7 +20,7 @@ def ktime_get():
We can't read the hardware timer itself to add any nanoseconds
that need to be added since we last stored the time in the
timekeeper. But this is probably good enough for debug purposes."""
- tk_core = gdb.parse_and_eval("&tk_core")
+ tk_core = gdb.parse_and_eval("&timekeeper_data[TIMEKEEPER_CORE]")
return tk_core['timekeeper']['tkr_mono']['base']
@@ -90,14 +90,10 @@ def print_cpu(hrtimer_bases, cpu, max_clock_bases):
text += f" .{'nohz':15s}: {int(bool(ts['flags'] & TS_FLAG_NOHZ))}\n"
text += f" .{'last_tick':15s}: {ts['last_tick']}\n"
text += f" .{'tick_stopped':15s}: {int(bool(ts['flags'] & TS_FLAG_STOPPED))}\n"
- text += f" .{'idle_jiffies':15s}: {ts['idle_jiffies']}\n"
text += f" .{'idle_calls':15s}: {ts['idle_calls']}\n"
text += f" .{'idle_sleeps':15s}: {ts['idle_sleeps']}\n"
text += f" .{'idle_entrytime':15s}: {ts['idle_entrytime']} nsecs\n"
text += f" .{'idle_waketime':15s}: {ts['idle_waketime']} nsecs\n"
- text += f" .{'idle_exittime':15s}: {ts['idle_exittime']} nsecs\n"
- text += f" .{'idle_sleeptime':15s}: {ts['idle_sleeptime']} nsecs\n"
- text += f" .{'iowait_sleeptime':15s}: {ts['iowait_sleeptime']} nsecs\n"
text += f" .{'last_jiffies':15s}: {ts['last_jiffies']}\n"
text += f" .{'next_timer':15s}: {ts['next_timer']}\n"
text += f" .{'idle_expires':15s}: {ts['idle_expires']} nsecs\n"
diff --git a/scripts/gen-btf.sh b/scripts/gen-btf.sh
new file mode 100755
index 000000000000..8ca96eb10a69
--- /dev/null
+++ b/scripts/gen-btf.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
+#
+# This script generates BTF data for the provided ELF file.
+#
+# Kernel BTF generation involves these conceptual steps:
+# 1. pahole generates BTF from DWARF data
+# 2. resolve_btfids applies kernel-specific btf2btf
+# transformations and computes data for .BTF_ids section
+# 3. the result gets linked/objcopied into the target binary
+#
+# How step (3) should be done differs between vmlinux, and
+# kernel modules, which is the primary reason for the existence
+# of this script.
+#
+# For modules the script expects vmlinux passed in as --btf_base.
+# Generated .BTF, .BTF.base and .BTF_ids sections become embedded
+# into the input ELF file with objcopy.
+#
+# For vmlinux the input file remains unchanged and two files are produced:
+# - ${1}.btf.o ready for linking into vmlinux
+# - ${1}.BTF_ids with .BTF_ids data blob
+# This output is consumed by scripts/link-vmlinux.sh
+
+set -e
+
+usage()
+{
+ echo "Usage: $0 [--btf_base <file>] <target ELF file>"
+ exit 1
+}
+
+BTF_BASE=""
+
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --btf_base)
+ BTF_BASE="$2"
+ shift 2
+ ;;
+ -*)
+ echo "Unknown option: $1" >&2
+ usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+if [ $# -ne 1 ]; then
+ usage
+fi
+
+ELF_FILE="$1"
+shift
+
+is_enabled() {
+ grep -q "^$1=y" ${objtree}/include/config/auto.conf
+}
+
+case "${KBUILD_VERBOSE}" in
+*1*)
+ set -x
+ ;;
+esac
+
+gen_btf_data()
+{
+ btf1="${ELF_FILE}.BTF.1"
+ ${PAHOLE} -J ${PAHOLE_FLAGS} \
+ ${BTF_BASE:+--btf_base ${BTF_BASE}} \
+ --btf_encode_detached=${btf1} \
+ "${ELF_FILE}"
+
+ ${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_FLAGS} \
+ ${BTF_BASE:+--btf_base ${BTF_BASE}} \
+ --btf ${btf1} "${ELF_FILE}"
+}
+
+gen_btf_o()
+{
+ btf_data=${ELF_FILE}.btf.o
+
+ # Create ${btf_data} which contains just .BTF section but no symbols. Add
+ # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
+ # deletes all symbols including __start_BTF and __stop_BTF, which will
+ # be redefined in the linker script.
+ echo "" | ${CC} ${CLANG_FLAGS} ${KBUILD_CPPFLAGS} ${KBUILD_CFLAGS} -fno-lto -c -x c -o ${btf_data} -
+ ${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF \
+ --set-section-flags .BTF=alloc,readonly ${btf_data}
+ ${OBJCOPY} --only-section=.BTF --strip-all ${btf_data}
+
+ # Change e_type to ET_REL so that it can be used to link final vmlinux.
+ # GNU ld 2.35+ and lld do not allow an ET_EXEC input.
+ if is_enabled CONFIG_CPU_BIG_ENDIAN; then
+ et_rel='\0\1'
+ else
+ et_rel='\1\0'
+ fi
+ printf "${et_rel}" | dd of="${btf_data}" conv=notrunc bs=1 seek=16 status=none
+}
+
+embed_btf_data()
+{
+ ${OBJCOPY} --add-section .BTF=${ELF_FILE}.BTF ${ELF_FILE}
+
+ # a module might not have a .BTF_ids or .BTF.base section
+ btf_base="${ELF_FILE}.BTF.base"
+ if [ -f "${btf_base}" ]; then
+ ${OBJCOPY} --add-section .BTF.base=${btf_base} ${ELF_FILE}
+ fi
+ btf_ids="${ELF_FILE}.BTF_ids"
+ if [ -f "${btf_ids}" ]; then
+ ${RESOLVE_BTFIDS} --patch_btfids ${btf_ids} ${ELF_FILE}
+ fi
+}
+
+cleanup()
+{
+ rm -f "${ELF_FILE}.BTF.1"
+ rm -f "${ELF_FILE}.BTF"
+ if [ "${BTFGEN_MODE}" = "module" ]; then
+ rm -f "${ELF_FILE}.BTF.base"
+ rm -f "${ELF_FILE}.BTF_ids"
+ fi
+}
+trap cleanup EXIT
+
+BTFGEN_MODE="vmlinux"
+if [ -n "${BTF_BASE}" ]; then
+ BTFGEN_MODE="module"
+fi
+
+gen_btf_data
+
+case "${BTFGEN_MODE}" in
+vmlinux)
+ gen_btf_o
+ ;;
+module)
+ embed_btf_data
+ ;;
+esac
+
+exit 0
diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c
index 3538a7d9cb07..e76d732f5f60 100644
--- a/scripts/gendwarfksyms/dwarf.c
+++ b/scripts/gendwarfksyms/dwarf.c
@@ -750,6 +750,7 @@ static void process_enumerator_type(struct state *state, struct die *cache,
Dwarf_Die *die)
{
bool overridden = false;
+ unsigned long override;
Dwarf_Word value;
if (stable) {
@@ -761,7 +762,8 @@ static void process_enumerator_type(struct state *state, struct die *cache,
return;
overridden = kabi_get_enumerator_value(
- state->expand.current_fqn, cache->fqn, &value);
+ state->expand.current_fqn, cache->fqn, &override);
+ value = override;
}
process_list_comma(state, cache);
diff --git a/scripts/gendwarfksyms/symbols.c b/scripts/gendwarfksyms/symbols.c
index ecddcb5ffcdf..42cd27c9cec4 100644
--- a/scripts/gendwarfksyms/symbols.c
+++ b/scripts/gendwarfksyms/symbols.c
@@ -3,6 +3,7 @@
* Copyright (C) 2024 Google LLC
*/
+#include <inttypes.h>
#include "gendwarfksyms.h"
#define SYMBOL_HASH_BITS 12
@@ -242,7 +243,7 @@ static void elf_for_each_global(int fd, elf_symbol_callback_t func, void *arg)
error("elf_getdata failed: %s", elf_errmsg(-1));
if (shdr->sh_entsize != sym_size)
- error("expected sh_entsize (%lu) to be %zu",
+ error("expected sh_entsize (%" PRIu64 ") to be %zu",
shdr->sh_entsize, sym_size);
nsyms = shdr->sh_size / shdr->sh_entsize;
@@ -292,7 +293,7 @@ static void set_symbol_addr(struct symbol *sym, void *arg)
hash_add(symbol_addrs, &sym->addr_hash,
symbol_addr_hash(&sym->addr));
- debug("%s -> { %u, %lx }", sym->name, sym->addr.section,
+ debug("%s -> { %u, %" PRIx64 " }", sym->name, sym->addr.section,
sym->addr.address);
} else if (sym->addr.section != addr->section ||
sym->addr.address != addr->address) {
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index 147d0cc94068..dc1219736f77 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -10,8 +10,15 @@ import os
import pathlib
import subprocess
import sys
+from typing import Dict, Iterable, List, Literal, Optional, TypedDict
-def args_crates_cfgs(cfgs):
+def invoke_rustc(args: List[str]) -> str:
+ return subprocess.check_output(
+ [os.environ["RUSTC"]] + args,
+ stdin=subprocess.DEVNULL,
+ ).decode('utf-8').strip()
+
+def args_crates_cfgs(cfgs: List[str]) -> Dict[str, List[str]]:
crates_cfgs = {}
for cfg in cfgs:
crate, vals = cfg.split("=", 1)
@@ -19,205 +26,379 @@ def args_crates_cfgs(cfgs):
return crates_cfgs
-def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edition):
+def args_crates_envs(envs: List[str]) -> Dict[str, Dict[str, str]]:
+ crates_envs = {}
+ for env in envs:
+ crate, vals = env.split("=", 1)
+ crates_envs[crate] = dict(v.split("=", 1) for v in vals.split())
+
+ return crates_envs
+
+class Dependency(TypedDict):
+ crate: int
+ name: str
+
+
+class Source(TypedDict):
+ include_dirs: List[str]
+ exclude_dirs: List[str]
+
+
+class Crate(TypedDict):
+ display_name: str
+ root_module: str
+ is_workspace_member: bool
+ deps: List[Dependency]
+ cfg: List[str]
+ edition: str
+ env: Dict[str, str]
+
+
+class ProcMacroCrate(Crate):
+ is_proc_macro: Literal[True]
+ proc_macro_dylib_path: str # `pathlib.Path` is not JSON serializable.
+
+
+class CrateWithGenerated(Crate):
+ source: Source
+
+
+def generate_crates(
+ srctree: pathlib.Path,
+ objtree: pathlib.Path,
+ sysroot_src: pathlib.Path,
+ external_src: Optional[pathlib.Path],
+ cfgs: List[str],
+ envs: List[str],
+ core_edition: str,
+) -> List[Crate]:
# Generate the configuration list.
- cfg = []
+ generated_cfg = []
with open(objtree / "include" / "generated" / "rustc_cfg") as fd:
for line in fd:
line = line.replace("--cfg=", "")
line = line.replace("\n", "")
- cfg.append(line)
+ generated_cfg.append(line)
- # Now fill the crates list -- dependencies need to come first.
- #
- # Avoid O(n^2) iterations by keeping a map of indexes.
- crates = []
- crates_indexes = {}
+ # Now fill the crates list.
+ crates: List[Crate] = []
crates_cfgs = args_crates_cfgs(cfgs)
+ crates_envs = args_crates_envs(envs)
+
+ def get_crate_name(path: pathlib.Path) -> str:
+ return invoke_rustc(["--print", "crate-name", str(path)])
- def append_crate(display_name, root_module, deps, cfg=[], is_workspace_member=True, is_proc_macro=False, edition="2021"):
- crate = {
+ def build_crate(
+ display_name: str,
+ root_module: pathlib.Path,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]],
+ is_workspace_member: Optional[bool],
+ edition: Optional[str],
+ ) -> Crate:
+ cfg = cfg if cfg is not None else crates_cfgs.get(display_name, [])
+ is_workspace_member = (
+ is_workspace_member if is_workspace_member is not None else True
+ )
+ edition = edition if edition is not None else "2021"
+ crate_env = {
+ "RUST_MODFILE": "This is only for rust-analyzer",
+ **crates_envs.get(display_name, {}),
+ }
+ return {
"display_name": display_name,
"root_module": str(root_module),
"is_workspace_member": is_workspace_member,
- "is_proc_macro": is_proc_macro,
- "deps": [{"crate": crates_indexes[dep], "name": dep} for dep in deps],
+ "deps": deps,
"cfg": cfg,
"edition": edition,
- "env": {
- "RUST_MODFILE": "This is only for rust-analyzer"
- }
+ "env": crate_env,
+ }
+
+ def append_proc_macro_crate(
+ display_name: str,
+ root_module: pathlib.Path,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]] = None,
+ is_workspace_member: Optional[bool] = None,
+ edition: Optional[str] = None,
+ ) -> Dependency:
+ crate = build_crate(
+ display_name,
+ root_module,
+ deps,
+ cfg=cfg,
+ is_workspace_member=is_workspace_member,
+ edition=edition,
+ )
+ proc_macro_dylib_name = invoke_rustc([
+ "--print",
+ "file-names",
+ "--crate-name",
+ display_name,
+ "--crate-type",
+ "proc-macro",
+ "-",
+ ])
+ proc_macro_crate: ProcMacroCrate = {
+ **crate,
+ "is_proc_macro": True,
+ "proc_macro_dylib_path": str(objtree / "rust" / proc_macro_dylib_name),
}
- if is_proc_macro:
- proc_macro_dylib_name = subprocess.check_output(
- [os.environ["RUSTC"], "--print", "file-names", "--crate-name", display_name, "--crate-type", "proc-macro", "-"],
- stdin=subprocess.DEVNULL,
- ).decode('utf-8').strip()
- crate["proc_macro_dylib_path"] = f"{objtree}/rust/{proc_macro_dylib_name}"
- crates_indexes[display_name] = len(crates)
+ return register_crate(proc_macro_crate)
+
+ def register_crate(crate: Crate) -> Dependency:
+ index = len(crates)
crates.append(crate)
+ return {"crate": index, "name": crate["display_name"]}
+
+ def append_crate(
+ display_name: str,
+ root_module: pathlib.Path,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]] = None,
+ is_workspace_member: Optional[bool] = None,
+ edition: Optional[str] = None,
+ ) -> Dependency:
+ return register_crate(
+ build_crate(
+ display_name,
+ root_module,
+ deps,
+ cfg=cfg,
+ is_workspace_member=is_workspace_member,
+ edition=edition,
+ )
+ )
def append_sysroot_crate(
- display_name,
- deps,
- cfg=[],
- edition="2021",
- ):
- append_crate(
+ display_name: str,
+ deps: List[Dependency],
+ *,
+ cfg: Optional[List[str]] = None,
+ ) -> Dependency:
+ return append_crate(
display_name,
sysroot_src / display_name / "src" / "lib.rs",
deps,
- cfg,
+ cfg=cfg,
is_workspace_member=False,
- edition=edition,
+ # Miguel Ojeda writes:
+ #
+ # > ... in principle even the sysroot crates may have different
+ # > editions.
+ # >
+ # > For instance, in the move to 2024, it seems all happened at once
+ # > in 1.87.0 in these upstream commits:
+ # >
+ # > 0e071c2c6a58 ("Migrate core to Rust 2024")
+ # > f505d4e8e380 ("Migrate alloc to Rust 2024")
+ # > 0b2489c226c3 ("Migrate proc_macro to Rust 2024")
+ # > 993359e70112 ("Migrate std to Rust 2024")
+ # >
+ # > But in the previous move to 2021, `std` moved in 1.59.0, while
+ # > the others in 1.60.0:
+ # >
+ # > b656384d8398 ("Update stdlib to the 2021 edition")
+ # > 06a1c14d52a8 ("Switch all libraries to the 2021 edition")
+ #
+ # Link: https://lore.kernel.org/all/CANiq72kd9bHdKaAm=8xCUhSHMy2csyVed69bOc4dXyFAW4sfuw@mail.gmail.com/
+ #
+ # At the time of writing all rust versions we support build the
+ # sysroot crates with the same edition. We may need to relax this
+ # assumption if future edition moves span multiple rust versions.
+ edition=core_edition,
)
# NB: sysroot crates reexport items from one another so setting up our transitive dependencies
# here is important for ensuring that rust-analyzer can resolve symbols. The sources of truth
# for this dependency graph are `(sysroot_src / crate / "Cargo.toml" for crate in crates)`.
- append_sysroot_crate("core", [], cfg=crates_cfgs.get("core", []), edition=core_edition)
- append_sysroot_crate("alloc", ["core"])
- append_sysroot_crate("std", ["alloc", "core"])
- append_sysroot_crate("proc_macro", ["core", "std"])
+ core = append_sysroot_crate("core", [])
+ alloc = append_sysroot_crate("alloc", [core])
+ std = append_sysroot_crate("std", [alloc, core])
+ proc_macro = append_sysroot_crate("proc_macro", [core, std])
- append_crate(
+ compiler_builtins = append_crate(
"compiler_builtins",
srctree / "rust" / "compiler_builtins.rs",
- [],
+ [core],
)
- append_crate(
+ proc_macro2 = append_crate(
"proc_macro2",
srctree / "rust" / "proc-macro2" / "lib.rs",
- ["core", "alloc", "std", "proc_macro"],
- cfg=crates_cfgs["proc_macro2"],
+ [core, alloc, std, proc_macro],
)
- append_crate(
+ quote = append_crate(
"quote",
srctree / "rust" / "quote" / "lib.rs",
- ["alloc", "proc_macro", "proc_macro2"],
- cfg=crates_cfgs["quote"],
+ [core, alloc, std, proc_macro, proc_macro2],
+ edition="2018",
)
- append_crate(
+ syn = append_crate(
"syn",
srctree / "rust" / "syn" / "lib.rs",
- ["proc_macro", "proc_macro2", "quote"],
- cfg=crates_cfgs["syn"],
+ [std, proc_macro, proc_macro2, quote],
)
- append_crate(
+ macros = append_proc_macro_crate(
"macros",
srctree / "rust" / "macros" / "lib.rs",
- ["std", "proc_macro", "proc_macro2", "quote", "syn"],
- is_proc_macro=True,
+ [std, proc_macro, proc_macro2, quote, syn],
)
- append_crate(
+ zerocopy_derive = append_proc_macro_crate(
+ "zerocopy_derive",
+ srctree / "rust" / "zerocopy-derive" / "lib.rs",
+ [std, proc_macro, proc_macro2, quote, syn],
+ )
+
+ build_error = append_crate(
"build_error",
srctree / "rust" / "build_error.rs",
- ["core", "compiler_builtins"],
+ [core, compiler_builtins],
)
- append_crate(
+ pin_init_internal = append_proc_macro_crate(
"pin_init_internal",
srctree / "rust" / "pin-init" / "internal" / "src" / "lib.rs",
- [],
- cfg=["kernel"],
- is_proc_macro=True,
+ [std, proc_macro, proc_macro2, quote, syn],
)
- append_crate(
+ pin_init = append_crate(
"pin_init",
srctree / "rust" / "pin-init" / "src" / "lib.rs",
- ["core", "pin_init_internal", "macros"],
- cfg=["kernel"],
+ [core, compiler_builtins, pin_init_internal, macros],
)
- append_crate(
+ ffi = append_crate(
"ffi",
srctree / "rust" / "ffi.rs",
- ["core", "compiler_builtins"],
+ [core, compiler_builtins],
+ )
+
+ zerocopy = append_crate(
+ "zerocopy",
+ srctree / "rust" / "zerocopy" / "src" / "lib.rs",
+ [core, compiler_builtins],
)
def append_crate_with_generated(
- display_name,
- deps,
- ):
- append_crate(
+ display_name: str,
+ deps: List[Dependency],
+ ) -> Dependency:
+ crate = build_crate(
display_name,
srctree / "rust"/ display_name / "lib.rs",
deps,
- cfg=cfg,
+ cfg=generated_cfg,
+ is_workspace_member=True,
+ edition=None,
)
- crates[-1]["env"]["OBJTREE"] = str(objtree.resolve(True))
- crates[-1]["source"] = {
- "include_dirs": [
- str(srctree / "rust" / display_name),
- str(objtree / "rust")
- ],
- "exclude_dirs": [],
+ crate["env"]["OBJTREE"] = str(objtree.resolve(True))
+ crate_with_generated: CrateWithGenerated = {
+ **crate,
+ "source": {
+ "include_dirs": [
+ str(srctree / "rust" / display_name),
+ str(objtree / "rust"),
+ ],
+ "exclude_dirs": [],
+ },
}
+ return register_crate(crate_with_generated)
- append_crate_with_generated("bindings", ["core", "ffi", "pin_init"])
- append_crate_with_generated("uapi", ["core", "ffi", "pin_init"])
- append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"])
+ bindings = append_crate_with_generated("bindings", [core, ffi, pin_init])
+ uapi = append_crate_with_generated("uapi", [core, ffi, pin_init])
+ kernel = append_crate_with_generated(
+ "kernel", [core, macros, build_error, pin_init, ffi, bindings, uapi, zerocopy, zerocopy_derive]
+ )
+
+ scripts = srctree / "scripts"
+ makefile = (scripts / "Makefile").read_text()
+ for path in scripts.glob("*.rs"):
+ name = path.stem
+ if f"{name}-rust" not in makefile:
+ continue
+ append_crate(
+ name,
+ path,
+ [std],
+ )
- def is_root_crate(build_file, target):
+ def is_root_crate(build_file: pathlib.Path, target: str) -> bool:
try:
- return f"{target}.o" in open(build_file).read()
+ contents = build_file.read_text()
except FileNotFoundError:
return False
+ return f"{target}.o" in contents
# Then, the rest outside of `rust/`.
#
# We explicitly mention the top-level folders we want to cover.
- extra_dirs = map(lambda dir: srctree / dir, ("samples", "drivers"))
+ extra_dirs: Iterable[pathlib.Path] = (
+ srctree / dir for dir in ("samples", "drivers")
+ )
if external_src is not None:
extra_dirs = [external_src]
for folder in extra_dirs:
for path in folder.rglob("*.rs"):
logging.info("Checking %s", path)
- name = path.name.replace(".rs", "")
+ file_name = path.stem
# Skip those that are not crate roots.
- if not is_root_crate(path.parent / "Makefile", name) and \
- not is_root_crate(path.parent / "Kbuild", name):
+ if not is_root_crate(path.parent / "Makefile", file_name) and \
+ not is_root_crate(path.parent / "Kbuild", file_name):
continue
- logging.info("Adding %s", name)
+ crate_name = get_crate_name(path)
+ logging.info("Adding %s", crate_name)
append_crate(
- name,
+ crate_name,
path,
- ["core", "kernel"],
- cfg=cfg,
+ [core, kernel, pin_init, zerocopy, zerocopy_derive],
+ cfg=generated_cfg,
)
return crates
-def main():
+def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument('--verbose', '-v', action='store_true')
parser.add_argument('--cfgs', action='append', default=[])
+ parser.add_argument('--envs', action='append', default=[])
parser.add_argument("core_edition")
parser.add_argument("srctree", type=pathlib.Path)
parser.add_argument("objtree", type=pathlib.Path)
parser.add_argument("sysroot", type=pathlib.Path)
parser.add_argument("sysroot_src", type=pathlib.Path)
parser.add_argument("exttree", type=pathlib.Path, nargs="?")
- args = parser.parse_args()
+
+ class Args(argparse.Namespace):
+ verbose: bool
+ cfgs: List[str]
+ envs: List[str]
+ srctree: pathlib.Path
+ objtree: pathlib.Path
+ sysroot: pathlib.Path
+ sysroot_src: pathlib.Path
+ exttree: Optional[pathlib.Path]
+ core_edition: str
+
+ args = parser.parse_args(namespace=Args())
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s",
level=logging.INFO if args.verbose else logging.WARNING
)
- # Making sure that the `sysroot` and `sysroot_src` belong to the same toolchain.
- assert args.sysroot in args.sysroot_src.parents
-
rust_project = {
- "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, args.core_edition),
+ "crates": generate_crates(args.srctree, args.objtree, args.sysroot_src, args.exttree, args.cfgs, args.envs, args.core_edition),
"sysroot": str(args.sysroot),
}
diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs
index 38b3416bb979..16f7e855e012 100644
--- a/scripts/generate_rust_target.rs
+++ b/scripts/generate_rust_target.rs
@@ -196,7 +196,9 @@ fn main() {
}
} else if cfg.has("X86_64") {
ts.push("arch", "x86_64");
- if cfg.rustc_version_atleast(1, 86, 0) {
+ if cfg.rustc_version_atleast(1, 98, 0) {
+ ts.push("rustc-abi", "softfloat");
+ } else if cfg.rustc_version_atleast(1, 86, 0) {
ts.push("rustc-abi", "x86-softfloat");
}
ts.push(
@@ -236,7 +238,9 @@ fn main() {
panic!("32-bit x86 only works under UML");
}
ts.push("arch", "x86");
- if cfg.rustc_version_atleast(1, 86, 0) {
+ if cfg.rustc_version_atleast(1, 98, 0) {
+ ts.push("rustc-abi", "softfloat");
+ } else if cfg.rustc_version_atleast(1, 86, 0) {
ts.push("rustc-abi", "x86-softfloat");
}
ts.push(
diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y
index efdcf07c4eb6..cabcd146f3aa 100644
--- a/scripts/genksyms/parse.y
+++ b/scripts/genksyms/parse.y
@@ -325,8 +325,8 @@ direct_declarator:
{ $$ = $4; }
| direct_declarator BRACKET_PHRASE
{ $$ = $2; }
- | '(' declarator ')'
- { $$ = $3; }
+ | '(' attribute_opt declarator ')'
+ { $$ = $4; }
;
/* Nested declarators differ from regular declarators in that they do
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index 4414194bedcf..f0ca0db6ddc2 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -375,8 +375,10 @@ sub read_maintainer_file {
##Filename pattern matching
if ($type eq "F" || $type eq "X") {
$value =~ s@\.@\\\.@g; ##Convert . to \.
+ $value =~ s/\*\*/\x00/g; ##Convert ** to placeholder
$value =~ s/\*/\.\*/g; ##Convert * to .*
$value =~ s/\?/\./g; ##Convert ? to .
+ $value =~ s/\x00/(?:.*)/g; ##Convert placeholder to (?:.*)
##if pattern is a directory and it lacks a trailing slash, add one
if ((-d $value)) {
$value =~ s@([^/])$@$1/@;
@@ -746,8 +748,10 @@ sub self_test {
if (($type eq "F" || $type eq "X") &&
($self_test eq "" || $self_test =~ /\bpatterns\b/)) {
$value =~ s@\.@\\\.@g; ##Convert . to \.
+ $value =~ s/\*\*/\x00/g; ##Convert ** to placeholder
$value =~ s/\*/\.\*/g; ##Convert * to .*
$value =~ s/\?/\./g; ##Convert ? to .
+ $value =~ s/\x00/(?:.*)/g; ##Convert placeholder to (?:.*)
##if pattern is a directory and it lacks a trailing slash, add one
if ((-d $value)) {
$value =~ s@([^/])$@$1/@;
@@ -921,7 +925,7 @@ sub get_maintainers {
my $value_pd = ($value =~ tr@/@@);
my $file_pd = ($file =~ tr@/@@);
$value_pd++ if (substr($value,-1,1) ne "/");
- $value_pd = -1 if ($value =~ /^\.\*/);
+ $value_pd = -1 if ($value =~ /^(\.\*|\(\?:\.\*\))/);
if ($value_pd >= $file_pd &&
range_is_maintained($start, $end) &&
range_has_maintainer($start, $end)) {
@@ -955,6 +959,7 @@ sub get_maintainers {
$line =~ s/([^\\])\.([^\*])/$1\?$2/g;
$line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ?
$line =~ s/\\\./\./g; ##Convert \. to .
+ $line =~ s/\(\?:\.\*\)/\*\*/g; ##Convert (?:.*) to **
$line =~ s/\.\*/\*/g; ##Convert .* to *
}
my $count = $line =~ s/^([A-Z]):/$1:\t/g;
@@ -1048,7 +1053,7 @@ sub file_match_pattern {
if ($file =~ m@^$pattern@) {
my $s1 = ($file =~ tr@/@@);
my $s2 = ($pattern =~ tr@/@@);
- if ($s1 == $s2) {
+ if ($s1 == $s2 || $pattern =~ /\(\?:/) {
return 1;
}
}
diff --git a/scripts/headers_install.sh b/scripts/headers_install.sh
index 0e4e939efc94..9c15e748761c 100755
--- a/scripts/headers_install.sh
+++ b/scripts/headers_install.sh
@@ -64,36 +64,10 @@ configs=$(sed -e '
d
' $OUTFILE)
-# The entries in the following list do not result in an error.
-# Please do not add a new entry. This list is only for existing ones.
-# The list will be reduced gradually, and deleted eventually. (hopefully)
-#
-# The format is <file-name>:<CONFIG-option> in each line.
-config_leak_ignores="
-arch/arc/include/uapi/asm/swab.h:CONFIG_ARC_HAS_SWAPE
-arch/arm/include/uapi/asm/ptrace.h:CONFIG_CPU_ENDIAN_BE8
-arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_NO
-arch/nios2/include/uapi/asm/swab.h:CONFIG_NIOS2_CI_SWAB_SUPPORT
-arch/x86/include/uapi/asm/auxvec.h:CONFIG_IA32_EMULATION
-arch/x86/include/uapi/asm/auxvec.h:CONFIG_X86_64
-"
-
for c in $configs
do
- leak_error=1
-
- for ignore in $config_leak_ignores
- do
- if echo "$INFILE:$c" | grep -q "$ignore$"; then
- leak_error=
- break
- fi
- done
-
- if [ "$leak_error" = 1 ]; then
- echo "error: $INFILE: leak $c to user-space" >&2
- exit 1
- fi
+ echo "error: $INFILE: leak $c to user-space" >&2
+ exit 1
done
rm -f $TMPFILE
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 4b0234e4b12f..37d5c095ad22 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -46,7 +46,6 @@ struct addr_range {
};
static unsigned long long _text;
-static unsigned long long relative_base;
static struct addr_range text_ranges[] = {
{ "_stext", "_etext" },
{ "_sinittext", "_einittext" },
@@ -57,6 +56,7 @@ static struct addr_range text_ranges[] = {
static struct sym_entry **table;
static unsigned int table_size, table_cnt;
static int all_symbols;
+static int pc_relative;
static int token_profit[0x10000];
@@ -280,7 +280,7 @@ static void read_map(const char *in)
static void output_label(const char *label)
{
printf(".globl %s\n", label);
- printf("\tALGN\n");
+ printf("\t.balign 4\n");
printf("%s:\n", label);
}
@@ -343,15 +343,6 @@ static void write_src(void)
unsigned int *markers, markers_cnt;
char buf[KSYM_NAME_LEN];
- printf("#include <asm/bitsperlong.h>\n");
- printf("#if BITS_PER_LONG == 64\n");
- printf("#define PTR .quad\n");
- printf("#define ALGN .balign 8\n");
- printf("#else\n");
- printf("#define PTR .long\n");
- printf("#define ALGN .balign 4\n");
- printf("#endif\n");
-
printf("\t.section .rodata, \"a\"\n");
output_label("kallsyms_num_syms");
@@ -434,34 +425,24 @@ static void write_src(void)
output_label("kallsyms_offsets");
for (i = 0; i < table_cnt; i++) {
- /*
- * Use the offset relative to the lowest value
- * encountered of all relative symbols, and emit
- * non-relocatable fixed offsets that will be fixed
- * up at runtime.
- */
-
- long long offset;
-
- offset = table[i]->addr - relative_base;
- if (offset < 0 || offset > UINT_MAX) {
- fprintf(stderr, "kallsyms failure: "
- "relative symbol value %#llx out of range\n",
- table[i]->addr);
- exit(EXIT_FAILURE);
+ if (pc_relative) {
+ long long offset = table[i]->addr - _text;
+
+ if (offset < INT_MIN || offset > INT_MAX) {
+ fprintf(stderr, "kallsyms failure: "
+ "relative symbol value %#llx out of range\n",
+ table[i]->addr);
+ exit(EXIT_FAILURE);
+ }
+ printf("\t.long\t_text - . + (%d)\t/* %s */\n",
+ (int)offset, table[i]->sym);
+ } else {
+ printf("\t.long\t%#x\t/* %s */\n",
+ (unsigned int)table[i]->addr, table[i]->sym);
}
- printf("\t.long\t%#x\t/* %s */\n", (int)offset, table[i]->sym);
}
printf("\n");
- output_label("kallsyms_relative_base");
- /* Provide proper symbols relocatability by their '_text' relativeness. */
- if (_text <= relative_base)
- printf("\tPTR\t_text + %#llx\n", relative_base - _text);
- else
- printf("\tPTR\t_text - %#llx\n", _text - relative_base);
- printf("\n");
-
sort_symbols_by_name();
output_label("kallsyms_seqs_of_names");
for (i = 0; i < table_cnt; i++)
@@ -701,22 +682,12 @@ static void sort_symbols(void)
qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
}
-/* find the minimum non-absolute symbol address */
-static void record_relative_base(void)
-{
- /*
- * The table is sorted by address.
- * Take the first symbol value.
- */
- if (table_cnt)
- relative_base = table[0]->addr;
-}
-
int main(int argc, char **argv)
{
while (1) {
static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
+ {"pc-relative", no_argument, &pc_relative, 1},
{},
};
@@ -734,7 +705,6 @@ int main(int argc, char **argv)
read_map(argv[optind]);
shrink_table();
sort_symbols();
- record_relative_base();
optimize_token_table();
write_src();
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index fb50bd4f4103..5baf1c44ffa2 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -201,7 +201,7 @@ $(addprefix $(obj)/, mconf.o $(lxdialog)): | $(obj)/mconf-cflags
# qconf: Used for the xconfig target based on Qt
hostprogs += qconf
qconf-cxxobjs := qconf.o qconf-moc.o
-qconf-objs := images.o $(common-objs)
+qconf-objs := $(common-objs)
HOSTLDLIBS_qconf = $(call read-file, $(obj)/qconf-libs)
HOSTCXXFLAGS_qconf.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags)
@@ -219,7 +219,7 @@ targets += qconf-moc.cc
# gconf: Used for the gconfig target based on GTK+
hostprogs += gconf
-gconf-objs := gconf.o images.o $(common-objs)
+gconf-objs := gconf.o $(common-objs)
HOSTLDLIBS_gconf = $(call read-file, $(obj)/gconf-libs)
HOSTCFLAGS_gconf.o = $(call read-file, $(obj)/gconf-cflags)
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index a7b44cd8ae14..c368bec5ab60 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -297,9 +297,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
line[1] = 0;
if (!sym_is_changeable(sym)) {
- printf("%s\n", def);
- line[0] = '\n';
- line[1] = 0;
+ printf("%s\n", def ?: "");
return 0;
}
@@ -307,7 +305,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
case oldconfig:
case syncconfig:
if (sym_has_value(sym)) {
- printf("%s\n", def);
+ printf("%s\n", def ?: "");
return 0;
}
/* fall through */
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 8b164ccfa008..9f8586cb8a3e 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -5,7 +5,6 @@
#include <stdlib.h>
#include "lkc.h"
-#include "images.h"
#include <gtk/gtk.h>
@@ -951,12 +950,24 @@ static void fixup_rootmenu(struct menu *menu)
}
/* Main Window Initialization */
-static void replace_button_icon(GtkWidget *widget, const char * const xpm[])
+static void replace_button_icon(GtkWidget *widget, const char *filename)
{
GdkPixbuf *pixbuf;
GtkWidget *image;
+ GError *err = NULL;
+
+ char *env = getenv(SRCTREE);
+ gchar *path = g_strconcat(env ? env : g_get_current_dir(), "/scripts/kconfig/icons/", filename, NULL);
+
+ pixbuf = gdk_pixbuf_new_from_file(path, &err);
+ g_free(path);
+
+ if (err) {
+ g_warning("Failed to load icon %s: %s", filename, err->message);
+ g_error_free(err);
+ return;
+ }
- pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)xpm);
image = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
@@ -1078,17 +1089,17 @@ static void init_main_window(const gchar *glade_file)
single_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button4"));
g_signal_connect(single_btn, "clicked",
G_CALLBACK(on_single_clicked), NULL);
- replace_button_icon(single_btn, xpm_single_view);
+ replace_button_icon(single_btn, "single_view.xpm");
split_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button5"));
g_signal_connect(split_btn, "clicked",
G_CALLBACK(on_split_clicked), NULL);
- replace_button_icon(split_btn, xpm_split_view);
+ replace_button_icon(split_btn, "split_view.xpm");
full_btn = GTK_WIDGET(gtk_builder_get_object(builder, "button6"));
g_signal_connect(full_btn, "clicked",
G_CALLBACK(on_full_clicked), NULL);
- replace_button_icon(full_btn, xpm_tree_view);
+ replace_button_icon(full_btn, "tree_view.xpm");
widget = GTK_WIDGET(gtk_builder_get_object(builder, "button7"));
g_signal_connect(widget, "clicked",
@@ -1269,7 +1280,17 @@ static void init_right_tree(void)
g_signal_connect(G_OBJECT(renderer), "edited",
G_CALLBACK(renderer_edited), tree2_w);
- pix_menu = gdk_pixbuf_new_from_xpm_data((const char **)xpm_menu);
+ char *env = getenv(SRCTREE);
+ gchar *path = g_strconcat(env ? env : g_get_current_dir(), "/scripts/kconfig/icons/menu.xpm", NULL);
+ GError *err = NULL;
+
+ pix_menu = gdk_pixbuf_new_from_file(path, &err);
+ g_free(path);
+
+ if (err) {
+ g_warning("Failed to load menu icon: %s", err->message);
+ g_error_free(err);
+ }
for (i = 0; i < COL_VALUE; i++) {
column = gtk_tree_view_get_column(view, i);
diff --git a/scripts/kconfig/icons/back.xpm b/scripts/kconfig/icons/back.xpm
new file mode 100644
index 000000000000..2a4c30127608
--- /dev/null
+++ b/scripts/kconfig/icons/back.xpm
@@ -0,0 +1,29 @@
+/* XPM */
+static char * back_xpm[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"
+};
diff --git a/scripts/kconfig/icons/choice_no.xpm b/scripts/kconfig/icons/choice_no.xpm
new file mode 100644
index 000000000000..306e314ed9c6
--- /dev/null
+++ b/scripts/kconfig/icons/choice_no.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * choice_no_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "
+};
diff --git a/scripts/kconfig/icons/choice_yes.xpm b/scripts/kconfig/icons/choice_yes.xpm
new file mode 100644
index 000000000000..edeb91067379
--- /dev/null
+++ b/scripts/kconfig/icons/choice_yes.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * choice_yes_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "
+};
diff --git a/scripts/kconfig/icons/load.xpm b/scripts/kconfig/icons/load.xpm
new file mode 100644
index 000000000000..8c2d8725d1ef
--- /dev/null
+++ b/scripts/kconfig/icons/load.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static char * load_xpm[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"
+};
diff --git a/scripts/kconfig/icons/menu.xpm b/scripts/kconfig/icons/menu.xpm
new file mode 100644
index 000000000000..8ae1b74b3c0c
--- /dev/null
+++ b/scripts/kconfig/icons/menu.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * menu_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "
+};
diff --git a/scripts/kconfig/icons/menuback.xpm b/scripts/kconfig/icons/menuback.xpm
new file mode 100644
index 000000000000..f988c2c323c3
--- /dev/null
+++ b/scripts/kconfig/icons/menuback.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * menuback_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "
+};
diff --git a/scripts/kconfig/icons/save.xpm b/scripts/kconfig/icons/save.xpm
new file mode 100644
index 000000000000..f8be53d83b40
--- /dev/null
+++ b/scripts/kconfig/icons/save.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static char * save_xpm[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"
+};
diff --git a/scripts/kconfig/icons/single_view.xpm b/scripts/kconfig/icons/single_view.xpm
new file mode 100644
index 000000000000..33c3b239dc8e
--- /dev/null
+++ b/scripts/kconfig/icons/single_view.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char * single_view_xpm[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"
+};
diff --git a/scripts/kconfig/icons/split_view.xpm b/scripts/kconfig/icons/split_view.xpm
new file mode 100644
index 000000000000..09e22246d936
--- /dev/null
+++ b/scripts/kconfig/icons/split_view.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char * split_view_xpm[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"
+};
diff --git a/scripts/kconfig/icons/symbol_mod.xpm b/scripts/kconfig/icons/symbol_mod.xpm
new file mode 100644
index 000000000000..769465fcb0ce
--- /dev/null
+++ b/scripts/kconfig/icons/symbol_mod.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * symbol_mod_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" . . ",
+" .......... ",
+" "
+};
diff --git a/scripts/kconfig/icons/symbol_no.xpm b/scripts/kconfig/icons/symbol_no.xpm
new file mode 100644
index 000000000000..e4e9d46c9aca
--- /dev/null
+++ b/scripts/kconfig/icons/symbol_no.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * symbol_no_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .......... ",
+" "
+};
diff --git a/scripts/kconfig/icons/symbol_yes.xpm b/scripts/kconfig/icons/symbol_yes.xpm
new file mode 100644
index 000000000000..dab7e10ae7a9
--- /dev/null
+++ b/scripts/kconfig/icons/symbol_yes.xpm
@@ -0,0 +1,18 @@
+/* XPM */
+static char * symbol_yes_xpm[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . . ",
+" . .. . ",
+" . . .. . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "
+};
diff --git a/scripts/kconfig/icons/tree_view.xpm b/scripts/kconfig/icons/tree_view.xpm
new file mode 100644
index 000000000000..290835b802eb
--- /dev/null
+++ b/scripts/kconfig/icons/tree_view.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char * tree_view_xpm[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"
+};
diff --git a/scripts/kconfig/images.c b/scripts/kconfig/images.c
deleted file mode 100644
index 2f9afffa5d79..000000000000
--- a/scripts/kconfig/images.c
+++ /dev/null
@@ -1,328 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-
-#include "images.h"
-
-const char * const xpm_load[] = {
-"22 22 5 1",
-". c None",
-"# c #000000",
-"c c #838100",
-"a c #ffff00",
-"b c #ffffff",
-"......................",
-"......................",
-"......................",
-"............####....#.",
-"...........#....##.##.",
-"..................###.",
-".................####.",
-".####...........#####.",
-"#abab##########.......",
-"#babababababab#.......",
-"#ababababababa#.......",
-"#babababababab#.......",
-"#ababab###############",
-"#babab##cccccccccccc##",
-"#abab##cccccccccccc##.",
-"#bab##cccccccccccc##..",
-"#ab##cccccccccccc##...",
-"#b##cccccccccccc##....",
-"###cccccccccccc##.....",
-"##cccccccccccc##......",
-"###############.......",
-"......................"};
-
-const char * const xpm_save[] = {
-"22 22 5 1",
-". c None",
-"# c #000000",
-"a c #838100",
-"b c #c5c2c5",
-"c c #cdb6d5",
-"......................",
-".####################.",
-".#aa#bbbbbbbbbbbb#bb#.",
-".#aa#bbbbbbbbbbbb#bb#.",
-".#aa#bbbbbbbbbcbb####.",
-".#aa#bbbccbbbbbbb#aa#.",
-".#aa#bbbccbbbbbbb#aa#.",
-".#aa#bbbbbbbbbbbb#aa#.",
-".#aa#bbbbbbbbbbbb#aa#.",
-".#aa#bbbbbbbbbbbb#aa#.",
-".#aa#bbbbbbbbbbbb#aa#.",
-".#aaa############aaa#.",
-".#aaaaaaaaaaaaaaaaaa#.",
-".#aaaaaaaaaaaaaaaaaa#.",
-".#aaa#############aa#.",
-".#aaa#########bbb#aa#.",
-".#aaa#########bbb#aa#.",
-".#aaa#########bbb#aa#.",
-".#aaa#########bbb#aa#.",
-".#aaa#########bbb#aa#.",
-"..##################..",
-"......................"};
-
-const char * const xpm_back[] = {
-"22 22 3 1",
-". c None",
-"# c #000083",
-"a c #838183",
-"......................",
-"......................",
-"......................",
-"......................",
-"......................",
-"...........######a....",
-"..#......##########...",
-"..##...####......##a..",
-"..###.###.........##..",
-"..######..........##..",
-"..#####...........##..",
-"..######..........##..",
-"..#######.........##..",
-"..########.......##a..",
-"...............a###...",
-"...............###....",
-"......................",
-"......................",
-"......................",
-"......................",
-"......................",
-"......................"};
-
-const char * const xpm_tree_view[] = {
-"22 22 2 1",
-". c None",
-"# c #000000",
-"......................",
-"......................",
-"......#...............",
-"......#...............",
-"......#...............",
-"......#...............",
-"......#...............",
-"......########........",
-"......#...............",
-"......#...............",
-"......#...............",
-"......#...............",
-"......#...............",
-"......########........",
-"......#...............",
-"......#...............",
-"......#...............",
-"......#...............",
-"......#...............",
-"......########........",
-"......................",
-"......................"};
-
-const char * const xpm_single_view[] = {
-"22 22 2 1",
-". c None",
-"# c #000000",
-"......................",
-"......................",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"..........#...........",
-"......................",
-"......................"};
-
-const char * const xpm_split_view[] = {
-"22 22 2 1",
-". c None",
-"# c #000000",
-"......................",
-"......................",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......#......#........",
-"......................",
-"......................"};
-
-const char * const xpm_symbol_no[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .......... ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" .......... ",
-" "};
-
-const char * const xpm_symbol_mod[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .......... ",
-" . . ",
-" . . ",
-" . .. . ",
-" . .... . ",
-" . .... . ",
-" . .. . ",
-" . . ",
-" . . ",
-" .......... ",
-" "};
-
-const char * const xpm_symbol_yes[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .......... ",
-" . . ",
-" . . ",
-" . . . ",
-" . .. . ",
-" . . .. . ",
-" . .... . ",
-" . .. . ",
-" . . ",
-" .......... ",
-" "};
-
-const char * const xpm_choice_no[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .... ",
-" .. .. ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" . . ",
-" .. .. ",
-" .... ",
-" "};
-
-const char * const xpm_choice_yes[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .... ",
-" .. .. ",
-" . . ",
-" . .. . ",
-" . .... . ",
-" . .... . ",
-" . .. . ",
-" . . ",
-" .. .. ",
-" .... ",
-" "};
-
-const char * const xpm_menu[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .......... ",
-" . . ",
-" . .. . ",
-" . .... . ",
-" . ...... . ",
-" . ...... . ",
-" . .... . ",
-" . .. . ",
-" . . ",
-" .......... ",
-" "};
-
-const char * const xpm_menu_inv[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .......... ",
-" .......... ",
-" .. ...... ",
-" .. .... ",
-" .. .. ",
-" .. .. ",
-" .. .... ",
-" .. ...... ",
-" .......... ",
-" .......... ",
-" "};
-
-const char * const xpm_menuback[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" .......... ",
-" . . ",
-" . .. . ",
-" . .... . ",
-" . ...... . ",
-" . ...... . ",
-" . .... . ",
-" . .. . ",
-" . . ",
-" .......... ",
-" "};
-
-const char * const xpm_void[] = {
-"12 12 2 1",
-" c white",
-". c black",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" ",
-" "};
diff --git a/scripts/kconfig/images.h b/scripts/kconfig/images.h
deleted file mode 100644
index 7212dec2006c..000000000000
--- a/scripts/kconfig/images.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- */
-
-#ifndef IMAGES_H
-#define IMAGES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern const char * const xpm_load[];
-extern const char * const xpm_save[];
-extern const char * const xpm_back[];
-extern const char * const xpm_tree_view[];
-extern const char * const xpm_single_view[];
-extern const char * const xpm_split_view[];
-extern const char * const xpm_symbol_no[];
-extern const char * const xpm_symbol_mod[];
-extern const char * const xpm_symbol_yes[];
-extern const char * const xpm_choice_no[];
-extern const char * const xpm_choice_yes[];
-extern const char * const xpm_menu[];
-extern const char * const xpm_menu_inv[];
-extern const char * const xpm_menuback[];
-extern const char * const xpm_void[];
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* IMAGES_H */
diff --git a/scripts/kconfig/kconfig-sym-check.pl b/scripts/kconfig/kconfig-sym-check.pl
new file mode 100755
index 000000000000..daa5285fdefc
--- /dev/null
+++ b/scripts/kconfig/kconfig-sym-check.pl
@@ -0,0 +1,132 @@
+#!/usr/bin/env perl
+# SPDX-License-Identifier: GPL-2.0
+
+use warnings;
+use strict;
+
+my $srctree = shift @ARGV;
+unless (defined $srctree) {
+ $srctree = `git rev-parse --show-toplevel 2>/dev/null`;
+ chomp $srctree;
+ my $msg = "Usage: $0 <srctree> [excludes file]\n";
+ $msg .= "Please provide <srctree>.";
+ $msg .= " Is it '$srctree'?" if $srctree;
+ $msg .= "\n";
+ die $msg;
+}
+my $kconfig_sym_check_excludes = defined $ARGV[0] ? $ARGV[0] : undef;
+
+sub indent_depth {
+ my ($ws) = @_;
+ my $col = 0;
+ for my $c (split //, $ws) {
+ $col = $c eq "\t" ? int($col / 8) * 8 + 8 : $col + 1;
+ }
+ return $col;
+}
+
+my @files = `git -C \Q$srctree\E ls-files '*Kconfig*' 2>/dev/null`;
+if (@files) {
+ chomp @files;
+ @files = map { "$srctree/$_" } @files;
+} else {
+ @files = `find \Q$srctree\E -name '*Kconfig*'`;
+ chomp @files;
+}
+
+@files = grep { !m{/scripts/kconfig/tests/} } @files;
+
+my %configs = ();
+my %refs = ();
+
+foreach my $file (@files) {
+ open F, $file or die "Cannot open $file: $!";
+
+ my $help = 0;
+ my $help_level;
+ my $level;
+
+ while (<F>) {
+ chomp;
+
+ while (/\\\s*$/) {
+ s/\\\s*$/ /;
+ my $cont = <F> // last;
+ chomp $cont;
+ $_ .= $cont;
+ }
+
+ next if /^\s*$/;
+ next if /^\s*#/;
+
+ /^(\s*)/;
+ $level = indent_depth($1);
+
+ if ($help && $level < $help_level) {
+ $help = 0;
+ }
+
+ next if ($help);
+
+ if (/^\s*(help|\-\-\-help\-\-\-)$/) {
+ $help = 1;
+ my $next;
+ while (defined($next = <F>)) {
+ last unless $next =~ /^\s*(?:#.*)?$/;
+ }
+ last unless defined $next;
+ $next =~ /^(\s*)/;
+ if (indent_depth($1) >= $level) {
+ $help_level = indent_depth($1);
+ } else {
+ $help = 0;
+ }
+ $_ = $next;
+ redo;
+ }
+
+ if (/^\s*(config|menuconfig)\s+([a-zA-Z0-9_]+)\s*(#.*)?$/) {
+ $configs{$2}++;
+ next;
+ }
+
+ if (/^\s*(default|def_bool|def_tristate|select|depends\s+on|imply|visible\s+if|range|if|bool|tristate|int|hex|string|prompt)\s+(.+)\s*$/) {
+ my $s = $2;
+ $s =~ s/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'//g;
+ $s =~ s/#.*//;
+ $s =~ s/\$\((?:[^()]*|\((?:[^()]*|\([^()]*\))*\))*\)//g;
+ $s =~ s/%%[^%]*%%//g;
+ my @syms = split /[^a-zA-Z0-9_]+/, $s;
+ map {
+ $refs{$_}++ if (/[a-zA-Z]/ && $_ ne "if" && $_ ne "y" && $_ ne "n" && $_ ne "m" && !/^0[xX][0-9a-fA-F]+$/);
+ } @syms
+ }
+ }
+
+ close F;
+}
+
+my %known_syms = ();
+if (defined $kconfig_sym_check_excludes) {
+ my $file = $kconfig_sym_check_excludes;
+ open(F, "<", $file) or die "Cannot open $file: $!";
+ while (<F>) {
+ chomp;
+ next if /^\s*$/;
+ next if /^\s*#/;
+ $known_syms{$1}++ if (/^\s*([a-zA-Z0-9_]+)\s*(#.*)?$/);
+ }
+}
+
+my $ret = 0;
+foreach my $k (sort keys %refs) {
+ next if (exists $configs{$k} || exists $known_syms{$k});
+
+ print "$k";
+ print " - warning: '$k' is probably not what you want; Kconfig tristate literals are always lowercase ('n', 'y', 'm')" if ($k eq "N" || $k eq "Y" || $k eq "M");
+ print "\n";
+
+ $ret = 1;
+}
+
+exit $ret;
diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l
index 6d2c92c6095d..a6155422b4a6 100644
--- a/scripts/kconfig/lexer.l
+++ b/scripts/kconfig/lexer.l
@@ -402,7 +402,7 @@ void zconf_initscan(const char *name)
exit(1);
}
- cur_filename = file_lookup(name);
+ cur_filename = file_lookup(name, NULL, 0);
yylineno = 1;
}
@@ -443,7 +443,7 @@ void zconf_nextfile(const char *name)
}
yylineno = 1;
- cur_filename = file_lookup(name);
+ cur_filename = file_lookup(name, cur_filename, cur_lineno);
}
static void zconf_endfile(void)
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 56548efc14d7..7e6f6ca299cf 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -51,7 +51,8 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
}
/* util.c */
-const char *file_lookup(const char *name);
+const char *file_lookup(const char *name,
+ const char *parent_name, int parent_lineno);
/* lexer.l */
int yylex(void);
@@ -82,7 +83,7 @@ void menu_warn(const struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym, enum menu_type type);
-void menu_add_dep(struct expr *dep);
+void menu_add_dep(struct expr *dep, struct expr *cond);
void menu_add_visibility(struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, const char *prompt,
struct expr *dep);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 0f1a6513987c..b2d8d4e11e07 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -127,8 +127,18 @@ static struct expr *rewrite_m(struct expr *e)
return e;
}
-void menu_add_dep(struct expr *dep)
+void menu_add_dep(struct expr *dep, struct expr *cond)
{
+ if (cond) {
+ /*
+ * We have "depends on X if Y" and we want:
+ * Y != n --> X
+ * Y == n --> y
+ * That simplifies to: (X || (Y == n))
+ */
+ dep = expr_alloc_or(dep,
+ expr_trans_compare(cond, E_EQUAL, &symbol_no));
+ }
current_entry->dep = expr_alloc_and(current_entry->dep, dep);
}
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 79c09b378be8..f08e0863b712 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -16,8 +16,8 @@
set -e
clean_up() {
- rm -f $TMP_FILE
- rm -f $MERGE_FILE
+ rm -f "$TMP_FILE"
+ rm -f "$TMP_FILE.new"
}
usage() {
@@ -43,6 +43,10 @@ STRICT=false
CONFIG_PREFIX=${CONFIG_-CONFIG_}
WARNOVERRIDE=echo
+if [ -z "$AWK" ]; then
+ AWK=awk
+fi
+
while true; do
case $1 in
"-n")
@@ -117,11 +121,8 @@ if [ ! -r "$INITFILE" ]; then
fi
MERGE_LIST=$*
-SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p"
-SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p"
TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
-MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
echo "Using $INITFILE as base"
@@ -129,6 +130,8 @@ trap clean_up EXIT
cat $INITFILE > $TMP_FILE
+PROCESSED_FILES=""
+
# Merge files, printing warnings on overridden values
for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "Merging $ORIG_MERGE_FILE"
@@ -136,42 +139,134 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
echo "The merge file '$ORIG_MERGE_FILE' does not exist. Exit." >&2
exit 1
fi
- cat $ORIG_MERGE_FILE > $MERGE_FILE
- CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $MERGE_FILE)
-
- for CFG in $CFG_LIST ; do
- grep -q -w $CFG $TMP_FILE || continue
- PREV_VAL=$(grep -w $CFG $TMP_FILE)
- NEW_VAL=$(grep -w $CFG $MERGE_FILE)
- BUILTIN_FLAG=false
- if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] && [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
- ${WARNOVERRIDE} Previous value: $PREV_VAL
- ${WARNOVERRIDE} New value: $NEW_VAL
- ${WARNOVERRIDE} -y passed, will not demote y to m
- ${WARNOVERRIDE}
- BUILTIN_FLAG=true
- elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
- ${WARNOVERRIDE} Value of $CFG is redefined by fragment $ORIG_MERGE_FILE:
- ${WARNOVERRIDE} Previous value: $PREV_VAL
- ${WARNOVERRIDE} New value: $NEW_VAL
- ${WARNOVERRIDE}
- if [ "$STRICT" = "true" ]; then
- STRICT_MODE_VIOLATED=true
- fi
- elif [ "$WARNREDUN" = "true" ]; then
- ${WARNOVERRIDE} Value of $CFG is redundant by fragment $ORIG_MERGE_FILE:
- fi
- if [ "$BUILTIN_FLAG" = "false" ]; then
- sed -i "/$CFG[ =]/d" $TMP_FILE
- else
- sed -i "/$CFG[ =]/d" $MERGE_FILE
- fi
- done
- # In case the previous file lacks a new line at the end
- echo >> $TMP_FILE
- cat $MERGE_FILE >> $TMP_FILE
-done
+ # Check for duplicate input files
+ case " $PROCESSED_FILES " in
+ *" $ORIG_MERGE_FILE "*)
+ ${WARNOVERRIDE} "WARNING: Input file provided multiple times: $ORIG_MERGE_FILE"
+ ;;
+ esac
+
+ # Use awk for single-pass processing instead of per-symbol grep/sed
+ if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
+ -v warnoverride="$WARNOVERRIDE" \
+ -v strict="$STRICT" \
+ -v outfile="$TMP_FILE.new" \
+ -v builtin="$BUILTIN" \
+ -v warnredun="$WARNREDUN" '
+ BEGIN {
+ strict_violated = 0
+ cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
+ notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
+ }
+
+ # Extract config name from a line, returns "" if not a config line
+ function get_cfg(line) {
+ if (match(line, cfg_regex)) {
+ return substr(line, RSTART, RLENGTH)
+ } else if (match(line, notset_regex)) {
+ # Extract CONFIG_FOO from "# CONFIG_FOO is not set"
+ sub(/^# /, "", line)
+ sub(/ is not set$/, "", line)
+ return line
+ }
+ return ""
+ }
+
+ function warn_builtin(cfg, prev, new) {
+ if (warnoverride == "true") return
+ print cfg ": -y passed, will not demote y to m"
+ print "Previous value: " prev
+ print "New value: " new
+ print ""
+ }
+
+ function warn_redefined(cfg, prev, new) {
+ if (warnoverride == "true") return
+ print "Value of " cfg " is redefined by fragment " mergefile ":"
+ print "Previous value: " prev
+ print "New value: " new
+ print ""
+ }
+
+ function warn_redundant(cfg) {
+ if (warnredun != "true" || warnoverride == "true") return
+ print "Value of " cfg " is redundant by fragment " mergefile ":"
+ }
+
+ # First pass: read merge file, store all lines and index
+ FILENAME == ARGV[1] {
+ mergefile = FILENAME
+ merge_lines[FNR] = $0
+ merge_total = FNR
+ cfg = get_cfg($0)
+ if (cfg != "") {
+ merge_cfg[cfg] = $0
+ merge_cfg_line[cfg] = FNR
+ }
+ next
+ }
+
+ # Second pass: process base file (TMP_FILE)
+ FILENAME == ARGV[2] {
+ cfg = get_cfg($0)
+
+ # Not a config or not in merge file - keep it
+ if (cfg == "" || !(cfg in merge_cfg)) {
+ print $0 >> outfile
+ next
+ }
+
+ prev_val = $0
+ new_val = merge_cfg[cfg]
+
+ # BUILTIN: do not demote y to m
+ if (builtin == "true" && new_val ~ /=m$/ && prev_val ~ /=y$/) {
+ warn_builtin(cfg, prev_val, new_val)
+ print $0 >> outfile
+ skip_merge[merge_cfg_line[cfg]] = 1
+ next
+ }
+
+ # Values equal - redundant
+ if (prev_val == new_val) {
+ warn_redundant(cfg)
+ next
+ }
+
+ # "=n" is the same as "is not set"
+ if (prev_val ~ /=n$/ && new_val ~ / is not set$/) {
+ print $0 >> outfile
+ next
+ }
+
+ # Values differ - redefined
+ warn_redefined(cfg, prev_val, new_val)
+ if (strict == "true") {
+ strict_violated = 1
+ }
+ }
+
+ END {
+ # Newline in case base file lacks trailing newline
+ print "" >> outfile
+ # Append merge file, skipping lines marked for builtin preservation
+ for (i = 1; i <= merge_total; i++) {
+ if (!(i in skip_merge)) {
+ print merge_lines[i] >> outfile
+ }
+ }
+ if (strict_violated) {
+ exit 1
+ }
+ }' \
+ "$ORIG_MERGE_FILE" "$TMP_FILE"; then
+ # awk exited non-zero, strict mode was violated
+ STRICT_MODE_VIOLATED=true
+ fi
+ mv "$TMP_FILE.new" "$TMP_FILE"
+ PROCESSED_FILES="$PROCESSED_FILES $ORIG_MERGE_FILE"
+done
if [ "$STRICT_MODE_VIOLATED" = "true" ]; then
echo "The fragment redefined a value and strict mode had been passed."
exit 1
@@ -198,16 +293,91 @@ fi
# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
+# Check all specified config values took effect (might have missed-dependency issues)
+if ! "$AWK" -v prefix="$CONFIG_PREFIX" \
+ -v warnoverride="$WARNOVERRIDE" \
+ -v strict="$STRICT" \
+ -v warnredun="$WARNREDUN" '
+BEGIN {
+ strict_violated = 0
+ cfg_regex = "^" prefix "[a-zA-Z0-9_]+"
+ notset_regex = "^# " prefix "[a-zA-Z0-9_]+ is not set$"
+}
-# Check all specified config values took (might have missed-dependency issues)
-for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do
+# Extract config name from a line, returns "" if not a config line
+function get_cfg(line) {
+ if (match(line, cfg_regex)) {
+ return substr(line, RSTART, RLENGTH)
+ } else if (match(line, notset_regex)) {
+ # Extract CONFIG_FOO from "# CONFIG_FOO is not set"
+ sub(/^# /, "", line)
+ sub(/ is not set$/, "", line)
+ return line
+ }
+ return ""
+}
- REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
- ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true)
- if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
- echo "Value requested for $CFG not in final .config"
- echo "Requested value: $REQUESTED_VAL"
- echo "Actual value: $ACTUAL_VAL"
- echo ""
- fi
-done
+function warn_mismatch(cfg, merged, final) {
+ if (warnredun == "true") return
+ if (final == "" && !(merged ~ / is not set$/ || merged ~ /=n$/)) {
+ print "WARNING: Value requested for " cfg " not in final .config"
+ print "Requested value: " merged
+ print "Actual value: " final
+ } else if (final == "" && merged ~ / is not set$/) {
+ # not set, pass
+ } else if (merged == "" && final != "") {
+ print "WARNING: " cfg " not in merged config but added in final .config:"
+ print "Requested value: " merged
+ print "Actual value: " final
+ } else {
+ print "WARNING: " cfg " differs:"
+ print "Requested value: " merged
+ print "Actual value: " final
+ }
+}
+
+# First pass: read effective config file, store all lines
+FILENAME == ARGV[1] {
+ cfg = get_cfg($0)
+ if (cfg != "") {
+ config_cfg[cfg] = $0
+ }
+ next
+}
+
+# Second pass: process merged config and compare against effective config
+{
+ cfg = get_cfg($0)
+ if (cfg == "") next
+
+ # strip trailing comment
+ sub(/[[:space:]]+#.*/, "", $0)
+ merged_val = $0
+ final_val = config_cfg[cfg]
+
+ if (merged_val == final_val) next
+
+ if (merged_val ~ /=n$/ && final_val ~ / is not set$/) next
+ if (merged_val ~ /=n$/ && final_val == "") next
+
+ warn_mismatch(cfg, merged_val, final_val)
+
+ if (strict == "true") {
+ strict_violated = 1
+ }
+}
+
+END {
+ if (strict_violated) {
+ exit 1
+ }
+}' \
+"$KCONFIG_CONFIG" "$TMP_FILE"; then
+ # awk exited non-zero, strict mode was violated
+ STRICT_MODE_VIOLATED=true
+fi
+
+if [ "$STRICT" = "true" ] && [ "$STRICT_MODE_VIOLATED" = "true" ]; then
+ echo "Requested and effective config differ"
+ exit 1
+fi
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
index 49b79dde1725..5fb6f07b6ad2 100644
--- a/scripts/kconfig/parser.y
+++ b/scripts/kconfig/parser.y
@@ -159,14 +159,8 @@ config_stmt: config_entry_start config_option_list
yynerrs++;
}
- /*
- * If the same symbol appears twice in a choice block, the list
- * node would be added twice, leading to a broken linked list.
- * list_empty() ensures that this symbol has not yet added.
- */
- if (list_empty(&current_entry->sym->choice_link))
- list_add_tail(&current_entry->sym->choice_link,
- &current_choice->choice_members);
+ list_add_tail(&current_entry->sym->choice_link,
+ &current_choice->choice_members);
}
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
@@ -323,7 +317,7 @@ if_entry: T_IF expr T_EOL
{
printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
menu_add_entry(NULL, M_IF);
- menu_add_dep($2);
+ menu_add_dep($2, NULL);
$$ = menu_add_menu();
};
@@ -422,9 +416,9 @@ help: help_start T_HELPTEXT
/* depends option */
-depends: T_DEPENDS T_ON expr T_EOL
+depends: T_DEPENDS T_ON expr if_expr T_EOL
{
- menu_add_dep($3);
+ menu_add_dep($3, $4);
printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
};
@@ -546,11 +540,10 @@ static int choice_check_sanity(const struct menu *menu)
ret = -1;
}
- if (prop->menu != menu && prop->type == P_PROMPT &&
- prop->menu->parent != menu->parent) {
+ if (prop->menu != menu && prop->type == P_PROMPT) {
fprintf(stderr, "%s:%d: error: %s",
prop->filename, prop->lineno,
- "choice value has a prompt outside its choice group\n");
+ "choice value must not have a prompt in another entry\n");
ret = -1;
}
}
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index b84c9f2485d1..b02ead7a3f98 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -26,8 +26,6 @@
#include "lkc.h"
#include "qconf.h"
-#include "images.h"
-
static QApplication *configApp;
static ConfigSettings *configSettings;
@@ -1283,13 +1281,14 @@ ConfigMainWindow::ConfigMainWindow(void)
move(x.toInt(), y.toInt());
// set up icons
- ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
- ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
- ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
- ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
- ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
- ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
- ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
+ QString iconsDir = QString(getenv(SRCTREE) ? getenv(SRCTREE) : QDir::currentPath()) + "/scripts/kconfig/icons/";
+ ConfigItem::symbolYesIcon = QIcon(QPixmap(iconsDir + "symbol_yes.xpm"));
+ ConfigItem::symbolModIcon = QIcon(QPixmap(iconsDir + "symbol_mod.xpm"));
+ ConfigItem::symbolNoIcon = QIcon(QPixmap(iconsDir + "symbol_no.xpm"));
+ ConfigItem::choiceYesIcon = QIcon(QPixmap(iconsDir + "choice_yes.xpm"));
+ ConfigItem::choiceNoIcon = QIcon(QPixmap(iconsDir + "choice_no.xpm"));
+ ConfigItem::menuIcon = QIcon(QPixmap(iconsDir + "menu.xpm"));
+ ConfigItem::menubackIcon = QIcon(QPixmap(iconsDir + "menuback.xpm"));
QWidget *widget = new QWidget(this);
setCentralWidget(widget);
@@ -1312,7 +1311,7 @@ ConfigMainWindow::ConfigMainWindow(void)
configList->setFocus();
- backAction = new QAction(QPixmap(xpm_back), "Back", this);
+ backAction = new QAction(QPixmap(iconsDir + "back.xpm"), "Back", this);
backAction->setShortcut(QKeySequence::Back);
connect(backAction, &QAction::triggered,
this, &ConfigMainWindow::goBack);
@@ -1322,12 +1321,12 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(quitAction, &QAction::triggered,
this, &ConfigMainWindow::close);
- QAction *loadAction = new QAction(QPixmap(xpm_load), "&Open", this);
+ QAction *loadAction = new QAction(QPixmap(iconsDir + "load.xpm"), "&Open", this);
loadAction->setShortcut(QKeySequence::Open);
connect(loadAction, &QAction::triggered,
this, &ConfigMainWindow::loadConfig);
- saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
+ saveAction = new QAction(QPixmap(iconsDir + "save.xpm"), "&Save", this);
saveAction->setShortcut(QKeySequence::Save);
connect(saveAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfig);
@@ -1344,15 +1343,15 @@ ConfigMainWindow::ConfigMainWindow(void)
searchAction->setShortcut(QKeySequence::Find);
connect(searchAction, &QAction::triggered,
this, &ConfigMainWindow::searchConfig);
- singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
+ singleViewAction = new QAction(QPixmap(iconsDir + "single_view.xpm"), "Single View", this);
singleViewAction->setCheckable(true);
connect(singleViewAction, &QAction::triggered,
this, &ConfigMainWindow::showSingleView);
- splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
+ splitViewAction = new QAction(QPixmap(iconsDir + "split_view.xpm"), "Split View", this);
splitViewAction->setCheckable(true);
connect(splitViewAction, &QAction::triggered,
this, &ConfigMainWindow::showSplitView);
- fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
+ fullViewAction = new QAction(QPixmap(iconsDir + "tree_view.xpm"), "Full View", this);
fullViewAction->setCheckable(true);
connect(fullViewAction, &QAction::triggered,
this, &ConfigMainWindow::showFullView);
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index 8e23faab5d22..8677d1ca06a7 100755
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -415,7 +415,7 @@ foreach my $module (keys(%modules)) {
}
} else {
# Most likely, someone has a custom (binary?) module loaded.
- print STDERR "$module config not found!!\n";
+ print STDERR "$module config not found!\n";
}
}
diff --git a/scripts/kconfig/tests/conditional_dep/Kconfig b/scripts/kconfig/tests/conditional_dep/Kconfig
new file mode 100644
index 000000000000..2015dfbce2b1
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/Kconfig
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0
+# Test Kconfig file for conditional dependencies.
+
+# Enable module support for tristate testing
+config MODULES
+ bool "Enable loadable module support"
+ modules
+ default y
+
+config FOO
+ bool "FOO symbol"
+
+config BAR
+ bool "BAR symbol"
+
+config TEST_BASIC
+ bool "Test basic conditional dependency"
+ depends on FOO if BAR
+ default y
+
+config TEST_COMPLEX
+ bool "Test complex conditional dependency"
+ depends on (FOO && BAR) if (FOO || BAR)
+ default y
+
+config BAZ
+ tristate "BAZ symbol"
+
+config TEST_OPTIONAL
+ tristate "Test simple optional dependency"
+ depends on BAZ if BAZ
+ default y
diff --git a/scripts/kconfig/tests/conditional_dep/__init__.py b/scripts/kconfig/tests/conditional_dep/__init__.py
new file mode 100644
index 000000000000..ab16df6487ec
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/__init__.py
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Correctly handle conditional dependencies.
+"""
+
+def test(conf):
+ assert conf.oldconfig('test_config1') == 0
+ assert conf.config_matches('expected_config1')
+
+ assert conf.oldconfig('test_config2') == 0
+ assert conf.config_matches('expected_config2')
+
+ assert conf.oldconfig('test_config3') == 0
+ assert conf.config_matches('expected_config3')
diff --git a/scripts/kconfig/tests/conditional_dep/expected_config1 b/scripts/kconfig/tests/conditional_dep/expected_config1
new file mode 100644
index 000000000000..826ed7f541b8
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/expected_config1
@@ -0,0 +1,11 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_MODULES=y
+CONFIG_FOO=y
+CONFIG_BAR=y
+CONFIG_TEST_BASIC=y
+CONFIG_TEST_COMPLEX=y
+CONFIG_BAZ=m
+CONFIG_TEST_OPTIONAL=m
diff --git a/scripts/kconfig/tests/conditional_dep/expected_config2 b/scripts/kconfig/tests/conditional_dep/expected_config2
new file mode 100644
index 000000000000..10d2354f687f
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/expected_config2
@@ -0,0 +1,9 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_MODULES=y
+# CONFIG_FOO is not set
+CONFIG_BAR=y
+CONFIG_BAZ=y
+CONFIG_TEST_OPTIONAL=y
diff --git a/scripts/kconfig/tests/conditional_dep/expected_config3 b/scripts/kconfig/tests/conditional_dep/expected_config3
new file mode 100644
index 000000000000..b04fa6fdfeb4
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/expected_config3
@@ -0,0 +1,11 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_MODULES=y
+# CONFIG_FOO is not set
+# CONFIG_BAR is not set
+CONFIG_TEST_BASIC=y
+CONFIG_TEST_COMPLEX=y
+# CONFIG_BAZ is not set
+CONFIG_TEST_OPTIONAL=y
diff --git a/scripts/kconfig/tests/conditional_dep/test_config1 b/scripts/kconfig/tests/conditional_dep/test_config1
new file mode 100644
index 000000000000..9b05f3ce8a99
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/test_config1
@@ -0,0 +1,6 @@
+# Basic check that everything can be configured if selected.
+CONFIG_FOO=y
+CONFIG_BAR=y
+CONFIG_BAZ=m
+# Ensure that TEST_OPTIONAL=y with BAZ=m is converted to TEST_OPTIONAL=m
+CONFIG_TEST_OPTIONAL=y
diff --git a/scripts/kconfig/tests/conditional_dep/test_config2 b/scripts/kconfig/tests/conditional_dep/test_config2
new file mode 100644
index 000000000000..5e66d230a836
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/test_config2
@@ -0,0 +1,7 @@
+# If FOO is not selected, then TEST_BASIC should fail the conditional
+# dependency since BAR is set.
+# TEST_COMPLEX will fail dependency as it depends on both FOO and BAR
+# if either of those is selected.
+CONFIG_FOO=n
+CONFIG_BAR=y
+CONFIG_BAZ=y
diff --git a/scripts/kconfig/tests/conditional_dep/test_config3 b/scripts/kconfig/tests/conditional_dep/test_config3
new file mode 100644
index 000000000000..86304f3aa557
--- /dev/null
+++ b/scripts/kconfig/tests/conditional_dep/test_config3
@@ -0,0 +1,6 @@
+# If FOO is not selected, but BAR is also not selected, then TEST_BASIC
+# should pass since the dependency on FOO is conditional on BAR.
+# TEST_COMPLEX should be also set since neither FOO nor BAR are selected
+# so it has no dependencies.
+CONFIG_FOO=n
+CONFIG_BAR=n
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig b/scripts/kconfig/tests/err_repeated_inc/Kconfig
new file mode 100644
index 000000000000..09a88fd29cb5
--- /dev/null
+++ b/scripts/kconfig/tests/err_repeated_inc/Kconfig
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "Kconfig.inc1"
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc1 b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc1
new file mode 100644
index 000000000000..495dc38314a1
--- /dev/null
+++ b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc1
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "Kconfig.inc2"
+source "Kconfig.inc3"
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc2 b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc2
new file mode 100644
index 000000000000..2b630eec2e99
--- /dev/null
+++ b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc2
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+source "Kconfig.inc3"
diff --git a/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc3 b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc3
new file mode 100644
index 000000000000..a4e40e534e6a
--- /dev/null
+++ b/scripts/kconfig/tests/err_repeated_inc/Kconfig.inc3
@@ -0,0 +1 @@
+# SPDX-License-Identifier: GPL-2.0-only
diff --git a/scripts/kconfig/tests/err_repeated_inc/__init__.py b/scripts/kconfig/tests/err_repeated_inc/__init__.py
new file mode 100644
index 000000000000..129d740a874b
--- /dev/null
+++ b/scripts/kconfig/tests/err_repeated_inc/__init__.py
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+"""
+Detect repeated inclusion error.
+
+If repeated inclusion is detected, it should fail with error message.
+"""
+
+def test(conf):
+ assert conf.oldaskconfig() != 0
+ assert conf.stderr_contains('expected_stderr')
diff --git a/scripts/kconfig/tests/err_repeated_inc/expected_stderr b/scripts/kconfig/tests/err_repeated_inc/expected_stderr
new file mode 100644
index 000000000000..53071430ea7d
--- /dev/null
+++ b/scripts/kconfig/tests/err_repeated_inc/expected_stderr
@@ -0,0 +1,2 @@
+Kconfig.inc1:4: error: repeated inclusion of Kconfig.inc3
+Kconfig.inc2:3: note: location of first inclusion of Kconfig.inc3
diff --git a/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py b/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
index ffd469d1f226..791ed659c76b 100644
--- a/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
+++ b/scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py
@@ -8,7 +8,7 @@ for symbols with unmet dependency.
This was not working correctly for choice values because choice needs
a bit different symbol computation.
-This checks that no unneeded "# COFIG_... is not set" is contained in
+This checks that no unneeded "# CONFIG_... is not set" is contained in
the .config file.
Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
index 5cdcee144b58..0809aa061b6a 100644
--- a/scripts/kconfig/util.c
+++ b/scripts/kconfig/util.c
@@ -18,25 +18,50 @@ static HASHTABLE_DEFINE(file_hashtable, 1U << 11);
struct file {
struct hlist_node node;
+ struct {
+ const char *name;
+ int lineno;
+ } parent;
char name[];
};
+static void die_duplicated_include(struct file *file,
+ const char *parent, int lineno)
+{
+ fprintf(stderr,
+ "%s:%d: error: repeated inclusion of %s\n"
+ "%s:%d: note: location of first inclusion of %s\n",
+ parent, lineno, file->name,
+ file->parent.name, file->parent.lineno, file->name);
+ exit(1);
+}
+
/* file already present in list? If not add it */
-const char *file_lookup(const char *name)
+const char *file_lookup(const char *name,
+ const char *parent_name, int parent_lineno)
{
+ const char *parent = NULL;
struct file *file;
size_t len;
int hash = hash_str(name);
+ if (parent_name)
+ parent = file_lookup(parent_name, NULL, 0);
+
hash_for_each_possible(file_hashtable, file, node, hash)
- if (!strcmp(name, file->name))
- return file->name;
+ if (!strcmp(name, file->name)) {
+ if (!parent_name)
+ return file->name;
+ die_duplicated_include(file, parent, parent_lineno);
+ }
len = strlen(name);
file = xmalloc(sizeof(*file) + len + 1);
memset(file, 0, sizeof(*file));
memcpy(file->name, name, len);
file->name[len] = '\0';
+ file->parent.name = parent;
+ file->parent.lineno = parent_lineno;
hash_add(file_hashtable, &file->node, hash);
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 3b6ef807791a..9cc1459ffcdb 120000
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1 +1 @@
-kernel-doc.py \ No newline at end of file
+../tools/docs/kernel-doc \ No newline at end of file
diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py
deleted file mode 100755
index 7a1eaf986bcd..000000000000
--- a/scripts/kernel-doc.py
+++ /dev/null
@@ -1,339 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-License-Identifier: GPL-2.0
-# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>.
-#
-# pylint: disable=C0103,R0912,R0914,R0915
-
-# NOTE: While kernel-doc requires at least version 3.6 to run, the
-# command line should work with Python 3.2+ (tested with 3.4).
-# The rationale is that it shall fail gracefully during Kernel
-# compilation with older Kernel versions. Due to that:
-# - encoding line is needed here;
-# - no f-strings can be used on this file.
-# - the libraries that require newer versions can only be included
-# after Python version is checked.
-
-# Converted from the kernel-doc script originally written in Perl
-# under GPLv2, copyrighted since 1998 by the following authors:
-#
-# Aditya Srivastava <yashsri421@gmail.com>
-# Akira Yokosawa <akiyks@gmail.com>
-# Alexander A. Klimov <grandmaster@al2klimov.de>
-# Alexander Lobakin <aleksander.lobakin@intel.com>
-# André Almeida <andrealmeid@igalia.com>
-# Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-# Anna-Maria Behnsen <anna-maria@linutronix.de>
-# Armin Kuster <akuster@mvista.com>
-# Bart Van Assche <bart.vanassche@sandisk.com>
-# Ben Hutchings <ben@decadent.org.uk>
-# Borislav Petkov <bbpetkov@yahoo.de>
-# Chen-Yu Tsai <wenst@chromium.org>
-# Coco Li <lixiaoyan@google.com>
-# Conchúr Navid <conchur@web.de>
-# Daniel Santos <daniel.santos@pobox.com>
-# Danilo Cesar Lemes de Paula <danilo.cesar@collabora.co.uk>
-# Dan Luedtke <mail@danrl.de>
-# Donald Hunter <donald.hunter@gmail.com>
-# Gabriel Krisman Bertazi <krisman@collabora.co.uk>
-# Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-# Harvey Harrison <harvey.harrison@gmail.com>
-# Horia Geanta <horia.geanta@freescale.com>
-# Ilya Dryomov <idryomov@gmail.com>
-# Jakub Kicinski <kuba@kernel.org>
-# Jani Nikula <jani.nikula@intel.com>
-# Jason Baron <jbaron@redhat.com>
-# Jason Gunthorpe <jgg@nvidia.com>
-# Jérémy Bobbio <lunar@debian.org>
-# Johannes Berg <johannes.berg@intel.com>
-# Johannes Weiner <hannes@cmpxchg.org>
-# Jonathan Cameron <Jonathan.Cameron@huawei.com>
-# Jonathan Corbet <corbet@lwn.net>
-# Jonathan Neuschäfer <j.neuschaefer@gmx.net>
-# Kamil Rytarowski <n54@gmx.com>
-# Kees Cook <kees@kernel.org>
-# Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-# Levin, Alexander (Sasha Levin) <alexander.levin@verizon.com>
-# Linus Torvalds <torvalds@linux-foundation.org>
-# Lucas De Marchi <lucas.demarchi@profusion.mobi>
-# Mark Rutland <mark.rutland@arm.com>
-# Markus Heiser <markus.heiser@darmarit.de>
-# Martin Waitz <tali@admingilde.org>
-# Masahiro Yamada <masahiroy@kernel.org>
-# Matthew Wilcox <willy@infradead.org>
-# Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
-# Michal Wajdeczko <michal.wajdeczko@intel.com>
-# Michael Zucchi
-# Mike Rapoport <rppt@linux.ibm.com>
-# Niklas Söderlund <niklas.soderlund@corigine.com>
-# Nishanth Menon <nm@ti.com>
-# Paolo Bonzini <pbonzini@redhat.com>
-# Pavan Kumar Linga <pavan.kumar.linga@intel.com>
-# Pavel Pisa <pisa@cmp.felk.cvut.cz>
-# Peter Maydell <peter.maydell@linaro.org>
-# Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
-# Randy Dunlap <rdunlap@infradead.org>
-# Richard Kennedy <richard@rsk.demon.co.uk>
-# Rich Walker <rw@shadow.org.uk>
-# Rolf Eike Beer <eike-kernel@sf-tec.de>
-# Sakari Ailus <sakari.ailus@linux.intel.com>
-# Silvio Fricke <silvio.fricke@gmail.com>
-# Simon Huggins
-# Tim Waugh <twaugh@redhat.com>
-# Tomasz Warniełło <tomasz.warniello@gmail.com>
-# Utkarsh Tripathi <utripathi2002@gmail.com>
-# valdis.kletnieks@vt.edu <valdis.kletnieks@vt.edu>
-# Vegard Nossum <vegard.nossum@oracle.com>
-# Will Deacon <will.deacon@arm.com>
-# Yacine Belkadi <yacine.belkadi.1@gmail.com>
-# Yujie Liu <yujie.liu@intel.com>
-
-"""
-kernel_doc
-==========
-
-Print formatted kernel documentation to stdout
-
-Read C language source or header FILEs, extract embedded
-documentation comments, and print formatted documentation
-to standard output.
-
-The documentation comments are identified by the "/**"
-opening comment mark.
-
-See Documentation/doc-guide/kernel-doc.rst for the
-documentation comment syntax.
-"""
-
-import argparse
-import logging
-import os
-import sys
-
-# Import Python modules
-
-LIB_DIR = "../tools/lib/python"
-SRC_DIR = os.path.dirname(os.path.realpath(__file__))
-
-sys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR))
-
-DESC = """
-Read C language source or header FILEs, extract embedded documentation comments,
-and print formatted documentation to standard output.
-
-The documentation comments are identified by the "/**" opening comment mark.
-
-See Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax.
-"""
-
-EXPORT_FILE_DESC = """
-Specify an additional FILE in which to look for EXPORT_SYMBOL information.
-
-May be used multiple times.
-"""
-
-EXPORT_DESC = """
-Only output documentation for the symbols that have been
-exported using EXPORT_SYMBOL() and related macros in any input
-FILE or -export-file FILE.
-"""
-
-INTERNAL_DESC = """
-Only output documentation for the symbols that have NOT been
-exported using EXPORT_SYMBOL() and related macros in any input
-FILE or -export-file FILE.
-"""
-
-FUNCTION_DESC = """
-Only output documentation for the given function or DOC: section
-title. All other functions and DOC: sections are ignored.
-
-May be used multiple times.
-"""
-
-NOSYMBOL_DESC = """
-Exclude the specified symbol from the output documentation.
-
-May be used multiple times.
-"""
-
-FILES_DESC = """
-Header and C source files to be parsed.
-"""
-
-WARN_CONTENTS_BEFORE_SECTIONS_DESC = """
-Warns if there are contents before sections (deprecated).
-
-This option is kept just for backward-compatibility, but it does nothing,
-neither here nor at the original Perl script.
-"""
-
-
-class MsgFormatter(logging.Formatter):
- """Helper class to format warnings on a similar way to kernel-doc.pl"""
-
- def format(self, record):
- record.levelname = record.levelname.capitalize()
- return logging.Formatter.format(self, record)
-
-def main():
- """Main program"""
-
- parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
- description=DESC)
-
- # Normal arguments
-
- parser.add_argument("-v", "-verbose", "--verbose", action="store_true",
- help="Verbose output, more warnings and other information.")
-
- parser.add_argument("-d", "-debug", "--debug", action="store_true",
- help="Enable debug messages")
-
- parser.add_argument("-M", "-modulename", "--modulename",
- default="Kernel API",
- help="Allow setting a module name at the output.")
-
- parser.add_argument("-l", "-enable-lineno", "--enable_lineno",
- action="store_true",
- help="Enable line number output (only in ReST mode)")
-
- # Arguments to control the warning behavior
-
- parser.add_argument("-Wreturn", "--wreturn", action="store_true",
- help="Warns about the lack of a return markup on functions.")
-
- parser.add_argument("-Wshort-desc", "-Wshort-description", "--wshort-desc",
- action="store_true",
- help="Warns if initial short description is missing")
-
- parser.add_argument("-Wcontents-before-sections",
- "--wcontents-before-sections", action="store_true",
- help=WARN_CONTENTS_BEFORE_SECTIONS_DESC)
-
- parser.add_argument("-Wall", "--wall", action="store_true",
- help="Enable all types of warnings")
-
- parser.add_argument("-Werror", "--werror", action="store_true",
- help="Treat warnings as errors.")
-
- parser.add_argument("-export-file", "--export-file", action='append',
- help=EXPORT_FILE_DESC)
-
- # Output format mutually-exclusive group
-
- out_group = parser.add_argument_group("Output format selection (mutually exclusive)")
-
- out_fmt = out_group.add_mutually_exclusive_group()
-
- out_fmt.add_argument("-m", "-man", "--man", action="store_true",
- help="Output troff manual page format.")
- out_fmt.add_argument("-r", "-rst", "--rst", action="store_true",
- help="Output reStructuredText format (default).")
- out_fmt.add_argument("-N", "-none", "--none", action="store_true",
- help="Do not output documentation, only warnings.")
-
- # Output selection mutually-exclusive group
-
- sel_group = parser.add_argument_group("Output selection (mutually exclusive)")
- sel_mut = sel_group.add_mutually_exclusive_group()
-
- sel_mut.add_argument("-e", "-export", "--export", action='store_true',
- help=EXPORT_DESC)
-
- sel_mut.add_argument("-i", "-internal", "--internal", action='store_true',
- help=INTERNAL_DESC)
-
- sel_mut.add_argument("-s", "-function", "--symbol", action='append',
- help=FUNCTION_DESC)
-
- # Those are valid for all 3 types of filter
- parser.add_argument("-n", "-nosymbol", "--nosymbol", action='append',
- help=NOSYMBOL_DESC)
-
- parser.add_argument("-D", "-no-doc-sections", "--no-doc-sections",
- action='store_true', help="Don't outputt DOC sections")
-
- parser.add_argument("files", metavar="FILE",
- nargs="+", help=FILES_DESC)
-
- args = parser.parse_args()
-
- if args.wall:
- args.wreturn = True
- args.wshort_desc = True
- args.wcontents_before_sections = True
-
- logger = logging.getLogger()
-
- if not args.debug:
- logger.setLevel(logging.INFO)
- else:
- logger.setLevel(logging.DEBUG)
-
- formatter = MsgFormatter('%(levelname)s: %(message)s')
-
- handler = logging.StreamHandler()
- handler.setFormatter(formatter)
-
- logger.addHandler(handler)
-
- python_ver = sys.version_info[:2]
- if python_ver < (3,6):
- # Depending on Kernel configuration, kernel-doc --none is called at
- # build time. As we don't want to break compilation due to the
- # usage of an old Python version, return 0 here.
- if args.none:
- logger.error("Python 3.6 or later is required by kernel-doc. skipping checks")
- sys.exit(0)
-
- sys.exit("Python 3.6 or later is required by kernel-doc. Aborting.")
-
- if python_ver < (3,7):
- logger.warning("Python 3.7 or later is required for correct results")
-
- # Import kernel-doc libraries only after checking Python version
- from kdoc.kdoc_files import KernelFiles # pylint: disable=C0415
- from kdoc.kdoc_output import RestFormat, ManFormat # pylint: disable=C0415
-
- if args.man:
- out_style = ManFormat(modulename=args.modulename)
- elif args.none:
- out_style = None
- else:
- out_style = RestFormat()
-
- kfiles = KernelFiles(verbose=args.verbose,
- out_style=out_style, werror=args.werror,
- wreturn=args.wreturn, wshort_desc=args.wshort_desc,
- wcontents_before_sections=args.wcontents_before_sections)
-
- kfiles.parse(args.files, export_file=args.export_file)
-
- for t in kfiles.msg(enable_lineno=args.enable_lineno, export=args.export,
- internal=args.internal, symbol=args.symbol,
- nosymbol=args.nosymbol, export_file=args.export_file,
- no_doc_sections=args.no_doc_sections):
- msg = t[1]
- if msg:
- print(msg)
-
- error_count = kfiles.errors
- if not error_count:
- sys.exit(0)
-
- if args.werror:
- print("%s warnings as errors" % error_count) # pylint: disable=C0209
- sys.exit(error_count)
-
- if args.verbose:
- print("%s errors" % error_count) # pylint: disable=C0209
-
- if args.none:
- sys.exit(0)
-
- sys.exit(error_count)
-
-
-# Call main method
-if __name__ == "__main__":
- main()
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 4ab44c73da4d..f99e196abeea 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -106,34 +106,6 @@ vmlinux_link()
${kallsymso} ${btf_vmlinux_bin_o} ${arch_vmlinux_o} ${ldlibs}
}
-# generate .BTF typeinfo from DWARF debuginfo
-# ${1} - vmlinux image
-gen_btf()
-{
- local btf_data=${1}.btf.o
-
- info BTF "${btf_data}"
- LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
-
- # Create ${btf_data} which contains just .BTF section but no symbols. Add
- # SHF_ALLOC because .BTF will be part of the vmlinux image. --strip-all
- # deletes all symbols including __start_BTF and __stop_BTF, which will
- # be redefined in the linker script. Add 2>/dev/null to suppress GNU
- # objcopy warnings: "empty loadable segment detected at ..."
- ${OBJCOPY} --only-section=.BTF --set-section-flags .BTF=alloc,readonly \
- --strip-all ${1} "${btf_data}" 2>/dev/null
- # Change e_type to ET_REL so that it can be used to link final vmlinux.
- # GNU ld 2.35+ and lld do not allow an ET_EXEC input.
- if is_enabled CONFIG_CPU_BIG_ENDIAN; then
- et_rel='\0\1'
- else
- et_rel='\1\0'
- fi
- printf "${et_rel}" | dd of="${btf_data}" conv=notrunc bs=1 seek=16 status=none
-
- btf_vmlinux_bin_o=${btf_data}
-}
-
# Create ${2}.o file with all symbols from the ${1} object file
kallsyms()
{
@@ -143,6 +115,10 @@ kallsyms()
kallsymopt="${kallsymopt} --all-symbols"
fi
+ if is_enabled CONFIG_64BIT || is_enabled CONFIG_RELOCATABLE; then
+ kallsymopt="${kallsymopt} --pc-relative"
+ fi
+
info KSYMS "${2}.S"
scripts/kallsyms ${kallsymopt} "${1}" > "${2}.S"
@@ -205,6 +181,7 @@ if is_enabled CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX; then
fi
btf_vmlinux_bin_o=
+btfids_vmlinux=
kallsymso=
strip_debug=
generate_map=
@@ -232,11 +209,14 @@ if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then
fi
if is_enabled CONFIG_DEBUG_INFO_BTF; then
- if ! gen_btf .tmp_vmlinux1; then
+ info BTF .tmp_vmlinux1
+ if ! ${CONFIG_SHELL} ${srctree}/scripts/gen-btf.sh .tmp_vmlinux1; then
echo >&2 "Failed to generate BTF for vmlinux"
echo >&2 "Try to disable CONFIG_DEBUG_INFO_BTF"
exit 1
fi
+ btf_vmlinux_bin_o=.tmp_vmlinux1.btf.o
+ btfids_vmlinux=.tmp_vmlinux1.BTF_ids
fi
if is_enabled CONFIG_KALLSYMS; then
@@ -289,14 +269,9 @@ fi
vmlinux_link "${VMLINUX}"
-# fill in BTF IDs
if is_enabled CONFIG_DEBUG_INFO_BTF; then
- info BTFIDS "${VMLINUX}"
- RESOLVE_BTFIDS_ARGS=""
- if is_enabled CONFIG_WERROR; then
- RESOLVE_BTFIDS_ARGS=" --fatal_warnings "
- fi
- ${RESOLVE_BTFIDS} ${RESOLVE_BTFIDS_ARGS} "${VMLINUX}"
+ info BTFIDS ${VMLINUX}
+ ${RESOLVE_BTFIDS} --patch_btfids ${btfids_vmlinux} ${VMLINUX}
fi
mksysmap "${VMLINUX}" System.map
diff --git a/scripts/livepatch/Makefile b/scripts/livepatch/Makefile
new file mode 100644
index 000000000000..17b590213740
--- /dev/null
+++ b/scripts/livepatch/Makefile
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0
+# Standalone Makefile for developer tooling (not part of kbuild).
+
+SHELLCHECK := $(shell which shellcheck 2> /dev/null)
+
+SRCS := \
+ klp-build
+
+.DEFAULT_GOAL := help
+.PHONY: help
+help:
+ @echo " check - Run shellcheck on $(SRCS)"
+ @echo " help - Show this help message"
+
+.PHONY: check
+check:
+ifndef SHELLCHECK
+ $(error shellcheck is not installed. Please install it to run checks)
+endif
+ @$(SHELLCHECK) $(SHELLCHECK_OPTIONS) $(SRCS)
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 2274d8f5a482..f14d8c8fb35f 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -9,26 +9,26 @@
#include <linux/slab.h>
#include <linux/livepatch.h>
-extern struct klp_object_ext __start_klp_objects[];
-extern struct klp_object_ext __stop_klp_objects[];
-
static struct klp_patch *patch;
static int __init livepatch_mod_init(void)
{
+ struct klp_object_ext *obj_exts;
+ size_t obj_exts_sec_size;
struct klp_object *objs;
unsigned int nr_objs;
int ret;
- nr_objs = __stop_klp_objects - __start_klp_objects;
-
+ obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects",
+ &obj_exts_sec_size);
+ nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
if (!nr_objs) {
pr_err("nothing to patch!\n");
ret = -EINVAL;
goto err;
}
- patch = kzalloc(sizeof(*patch), GFP_KERNEL);
+ patch = kzalloc_obj(*patch);
if (!patch) {
ret = -ENOMEM;
goto err;
@@ -41,7 +41,7 @@ static int __init livepatch_mod_init(void)
}
for (int i = 0; i < nr_objs; i++) {
- struct klp_object_ext *obj_ext = __start_klp_objects + i;
+ struct klp_object_ext *obj_ext = obj_exts + i;
struct klp_func_ext *funcs_ext = obj_ext->funcs;
unsigned int nr_funcs = obj_ext->nr_funcs;
struct klp_func *funcs = objs[i].funcs;
@@ -90,12 +90,10 @@ err:
static void __exit livepatch_mod_exit(void)
{
- unsigned int nr_objs;
-
- nr_objs = __stop_klp_objects - __start_klp_objects;
+ struct klp_object *obj;
- for (int i = 0; i < nr_objs; i++)
- kfree(patch->objs[i].funcs);
+ klp_for_each_object_static(patch, obj)
+ kfree(obj->funcs);
kfree(patch->objs);
kfree(patch);
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index 882272120c9e..c4a7acf8edc3 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -3,7 +3,7 @@
#
# Build a livepatch module
-# shellcheck disable=SC1090,SC2155
+# shellcheck disable=SC1090,SC2155,SC2164
if (( BASH_VERSINFO[0] < 4 || \
(BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] < 4) )); then
@@ -11,21 +11,19 @@ if (( BASH_VERSINFO[0] < 4 || \
exit 1
fi
-set -o errexit
set -o errtrace
set -o pipefail
set -o nounset
# Allow doing 'cmd | mapfile -t array' instead of 'mapfile -t array < <(cmd)'.
-# This helps keep execution in pipes so pipefail+errexit can catch errors.
+# This helps keep execution in pipes so pipefail+ERR trap can catch errors.
shopt -s lastpipe
-unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP XTRACE
+unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP VERBOSE XTRACE
REPLACE=1
SHORT_CIRCUIT=0
JOBS="$(getconf _NPROCESSORS_ONLN)"
-VERBOSE="-s"
shopt -o xtrace | grep -q 'on' && XTRACE=1
# Avoid removing the previous $TMP_DIR until args have been fully processed.
@@ -35,16 +33,16 @@ SCRIPT="$(basename "$0")"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FIX_PATCH_LINES="$SCRIPT_DIR/fix-patch-lines"
-SRC="$(pwd)"
-OBJ="$(pwd)"
+OBJTOOL="$PWD/tools/objtool/objtool"
+CONFIG="$PWD/.config"
+TMP_DIR="$PWD/klp-tmp"
-CONFIG="$OBJ/.config"
-TMP_DIR="$OBJ/klp-tmp"
-
-ORIG_DIR="$TMP_DIR/orig"
-PATCHED_DIR="$TMP_DIR/patched"
-DIFF_DIR="$TMP_DIR/diff"
-KMOD_DIR="$TMP_DIR/kmod"
+ORIG_DIR="$TMP_DIR/1-orig"
+PATCHED_DIR="$TMP_DIR/2-patched"
+ORIG_CSUM_DIR="$TMP_DIR/3-checksum-orig"
+PATCHED_CSUM_DIR="$TMP_DIR/3-checksum-patched"
+DIFF_DIR="$TMP_DIR/4-diff"
+KMOD_DIR="$TMP_DIR/5-kmod"
STASH_DIR="$TMP_DIR/stash"
TIMESTAMP="$TMP_DIR/timestamp"
@@ -52,20 +50,37 @@ PATCH_TMP_DIR="$TMP_DIR/tmp"
KLP_DIFF_LOG="$DIFF_DIR/diff.log"
+# Terminal output colors
+read -r COLOR_RESET COLOR_BOLD COLOR_ERROR COLOR_WARN <<< ""
+if [[ -t 1 && -t 2 ]]; then
+ COLOR_RESET="\033[0m"
+ COLOR_BOLD="\033[1m"
+ COLOR_ERROR="\033[0;31m"
+ COLOR_WARN="\033[0;33m"
+fi
+
grep0() {
+ # shellcheck disable=SC2317
command grep "$@" || true
}
+# Because pipefail is enabled, the grep0 helper should be used instead of
+# grep, otherwise a failed match can propagate to an error.
+grep() {
+ echo "error: $SCRIPT: use grep0 or 'command grep' instead of bare grep" >&2
+ exit 1
+}
+
status() {
- echo "$*"
+ echo -e "${COLOR_BOLD}$*${COLOR_RESET}"
}
warn() {
- echo "error: $SCRIPT: $*" >&2
+ echo -e "${COLOR_WARN}warning${COLOR_RESET}: $SCRIPT: $*" >&2
}
die() {
- warn "$@"
+ echo -e "${COLOR_ERROR}error${COLOR_RESET}: $SCRIPT: $*" >&2
exit 1
}
@@ -73,7 +88,7 @@ declare -a STASHED_FILES
stash_file() {
local file="$1"
- local rel_file="${file#"$SRC"/}"
+ local rel_file="${file#"$PWD"/}"
[[ ! -e "$file" ]] && die "no file to stash: $file"
@@ -87,7 +102,7 @@ restore_files() {
local file
for file in "${STASHED_FILES[@]}"; do
- mv -f "$STASH_DIR/$file" "$SRC/$file" || warn "can't restore file: $file"
+ mv -f "$STASH_DIR/$file" "$PWD/$file" || warn "can't restore file: $file"
done
STASHED_FILES=()
@@ -95,14 +110,14 @@ restore_files() {
cleanup() {
set +o nounset
- revert_patches "--recount"
+ revert_patches
restore_files
[[ "$KEEP_TMP" -eq 0 ]] && rm -rf "$TMP_DIR"
return 0
}
trap_err() {
- warn "line ${BASH_LINENO[0]}: '$BASH_COMMAND'"
+ die "line ${BASH_LINENO[0]}: '$BASH_COMMAND'"
}
trap cleanup EXIT INT TERM HUP
@@ -123,10 +138,11 @@ Options:
Advanced Options:
-d, --debug Show symbol/reloc cloning decisions
-S, --short-circuit=STEP Start at build step (requires prior --keep-tmp)
- 1|orig Build original kernel (default)
- 2|patched Build patched kernel
- 3|diff Diff objects
- 4|kmod Build patch module
+ 1|orig Build original kernel (default)
+ 2|patched Build patched kernel
+ 3|checksum Generate checksums
+ 4|diff Diff objects
+ 5|kmod Build patch module
-T, --keep-tmp Preserve tmp dir on exit
EOF
@@ -141,6 +157,7 @@ process_args() {
local short
local long
local args
+ local patch
short="hfj:o:vdS:T"
long="help,show-first-changed,jobs:,output:,no-replace,verbose,debug,short-circuit:,keep-tmp"
@@ -177,7 +194,7 @@ process_args() {
shift
;;
-v | --verbose)
- VERBOSE="V=1"
+ VERBOSE=1
shift
;;
-d | --debug)
@@ -189,10 +206,11 @@ process_args() {
[[ ! -d "$TMP_DIR" ]] && die "--short-circuit requires preserved klp-tmp dir"
keep_tmp=1
case "$2" in
- 1 | orig) SHORT_CIRCUIT=1; ;;
- 2 | patched) SHORT_CIRCUIT=2; ;;
- 3 | diff) SHORT_CIRCUIT=3; ;;
- 4 | mod) SHORT_CIRCUIT=4; ;;
+ 1 | orig) SHORT_CIRCUIT=1; ;;
+ 2 | patched) SHORT_CIRCUIT=2; ;;
+ 3 | checksum) SHORT_CIRCUIT=3; ;;
+ 4 | diff) SHORT_CIRCUIT=4; ;;
+ 5 | kmod) SHORT_CIRCUIT=5; ;;
*) die "invalid short-circuit step '$2'" ;;
esac
shift 2
@@ -212,13 +230,17 @@ process_args() {
esac
done
- if [[ $# -eq 0 ]]; then
+ if [[ $# -eq 0 ]] && (( SHORT_CIRCUIT <= 2 )); then
usage
exit 1
fi
KEEP_TMP="$keep_tmp"
PATCHES=("$@")
+
+ for patch in "${PATCHES[@]}"; do
+ [[ -f "$patch" ]] || die "$patch doesn't exist"
+ done
}
# temporarily disable xtrace for especially verbose code
@@ -249,6 +271,13 @@ validate_config() {
[[ -v CONFIG_GCC_PLUGIN_RANDSTRUCT ]] && \
die "kernel option 'CONFIG_GCC_PLUGIN_RANDSTRUCT' not supported"
+ [[ -v CONFIG_AS_IS_LLVM ]] && \
+ [[ "$CONFIG_AS_VERSION" -lt 200000 ]] && \
+ die "Clang assembler version < 20 not supported"
+
+ [[ -x "$OBJTOOL" ]] && "$OBJTOOL" klp 2>&1 | command grep -q "not implemented" && \
+ die "objtool not built with KLP support; install xxhash-devel/libxxhash-dev (version >= 0.8) and recompile"
+
return 0
}
@@ -278,42 +307,49 @@ set_module_name() {
}
# Hardcode the value printed by the localversion script to prevent patch
-# application from appending it with '+' due to a dirty git working tree.
+# application from appending it with '+' due to a dirty working tree.
set_kernelversion() {
- local file="$SRC/scripts/setlocalversion"
- local localversion
+ local file="$PWD/scripts/setlocalversion"
+ local kernelrelease
stash_file "$file"
- localversion="$(cd "$SRC" && make --no-print-directory kernelversion)"
- localversion="$(cd "$SRC" && KERNELVERSION="$localversion" ./scripts/setlocalversion)"
- [[ -z "$localversion" ]] && die "setlocalversion failed"
+ if [[ -n "$(make -s listnewconfig 2>/dev/null)" ]]; then
+ die ".config mismatch, check your .config or run 'make olddefconfig'"
+ fi
+ make syncconfig &>/dev/null || die "make syncconfig failed"
- sed -i "2i echo $localversion; exit 0" scripts/setlocalversion
+ kernelrelease="$(make -s kernelrelease)"
+ [[ -z "$kernelrelease" ]] && die "failed to get kernel version"
+
+ sed -i "2i echo $kernelrelease; exit 0" scripts/setlocalversion
}
-get_patch_files() {
+get_patch_input_files() {
local patch="$1"
- grep0 -E '^(--- |\+\+\+ )' "$patch" \
+ grep0 -E '^--- ' "$patch" \
+ | grep0 -v -e '/dev/null' -e '1969-12-31' -e '1970-01-01' \
| gawk '{print $2}' \
| sed 's|^[^/]*/||' \
| sort -u
}
-# Make sure git re-stats the changed files
-git_refresh() {
+get_patch_output_files() {
local patch="$1"
- local files=()
- [[ ! -e "$SRC/.git" ]] && return
+ grep0 -E '^\+\+\+ ' "$patch" \
+ | grep0 -v -e '/dev/null' -e '1969-12-31' -e '1970-01-01' \
+ | gawk '{print $2}' \
+ | sed 's|^[^/]*/||' \
+ | sort -u
+}
- get_patch_files "$patch" | mapfile -t files
+get_patch_files() {
+ local patch="$1"
- (
- cd "$SRC"
- git update-index -q --refresh -- "${files[@]}"
- )
+ { get_patch_input_files "$patch"; get_patch_output_files "$patch"; } \
+ | sort -u
}
check_unsupported_patches() {
@@ -326,8 +362,8 @@ check_unsupported_patches() {
for file in "${files[@]}"; do
case "$file" in
- lib/*|*.S)
- die "unsupported patch to $file"
+ lib/*|*/vdso/*|*/realmode/rm/*|*.S)
+ die "${patch}: unsupported patch to $file"
;;
esac
done
@@ -338,34 +374,30 @@ apply_patch() {
local patch="$1"
shift
local extra_args=("$@")
+ local drift_regex="with fuzz|offset [0-9]+ line"
+ local output
+ local status
[[ ! -f "$patch" ]] && die "$patch doesn't exist"
-
- (
- cd "$SRC"
-
- # The sed strips the version signature from 'git format-patch',
- # otherwise 'git apply --recount' warns.
- sed -n '/^-- /q;p' "$patch" |
- git apply "${extra_args[@]}"
- )
+ status=0
+ output=$(patch -p1 --dry-run --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" < "$patch" 2>&1) || status=$?
+ if [[ "$status" -ne 0 ]]; then
+ echo "$output" >&2
+ die "$patch did not apply"
+ elif [[ "$output" =~ $drift_regex ]]; then
+ [[ -v VERBOSE ]] && echo "$output" >&2
+ warn "${patch} applied with fuzz"
+ fi
APPLIED_PATCHES+=("$patch")
+ patch -p1 --no-backup-if-mismatch -r /dev/null "${extra_args[@]}" --silent < "$patch"
}
revert_patch() {
local patch="$1"
- shift
- local extra_args=("$@")
local tmp=()
- (
- cd "$SRC"
-
- sed -n '/^-- /q;p' "$patch" |
- git apply --reverse "${extra_args[@]}"
- )
- git_refresh "$patch"
+ patch -p1 -R --force --no-backup-if-mismatch -r /dev/null &> /dev/null < "$patch" || true
for p in "${APPLIED_PATCHES[@]}"; do
[[ "$p" == "$patch" ]] && continue
@@ -376,19 +408,19 @@ revert_patch() {
}
apply_patches() {
+ local extra_args=("$@")
local patch
for patch in "${PATCHES[@]}"; do
- apply_patch "$patch"
+ apply_patch "$patch" "${extra_args[@]}"
done
}
revert_patches() {
- local extra_args=("$@")
local patches=("${APPLIED_PATCHES[@]}")
for (( i=${#patches[@]}-1 ; i>=0 ; i-- )) ; do
- revert_patch "${patches[$i]}" "${extra_args[@]}"
+ revert_patch "${patches[$i]}"
done
APPLIED_PATCHES=()
@@ -403,8 +435,21 @@ validate_patches() {
do_init() {
# We're not yet smart enough to handle anything other than in-tree
# builds in pwd.
- [[ ! "$SRC" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
- [[ ! "$OBJ" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
+ [[ ! "$PWD" -ef "$SCRIPT_DIR/../.." ]] && die "please run from the kernel root directory"
+
+ if (( SHORT_CIRCUIT >= 2 )); then
+ [[ -f "$ORIG_DIR/.complete" ]] || die "-S $SHORT_CIRCUIT requires completed $ORIG_DIR"
+ fi
+ if (( SHORT_CIRCUIT >= 3 )); then
+ [[ -f "$PATCHED_DIR/.complete" ]] || die "-S $SHORT_CIRCUIT requires completed $PATCHED_DIR"
+ fi
+ if (( SHORT_CIRCUIT >= 4 )); then
+ [[ -f "$ORIG_CSUM_DIR/.complete" ]] || die "-S $SHORT_CIRCUIT requires completed $ORIG_CSUM_DIR"
+ [[ -f "$PATCHED_CSUM_DIR/.complete" ]] || die "-S $SHORT_CIRCUIT requires completed $PATCHED_CSUM_DIR"
+ fi
+ if (( SHORT_CIRCUIT >= 5 )); then
+ [[ -f "$DIFF_DIR/.complete" ]] || die "-S $SHORT_CIRCUIT requires completed $DIFF_DIR"
+ fi
(( SHORT_CIRCUIT <= 1 )) && rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
@@ -412,6 +457,7 @@ do_init() {
APPLIED_PATCHES=()
[[ -x "$FIX_PATCH_LINES" ]] || die "can't find fix-patch-lines"
+ command -v recountdiff &>/dev/null || die "recountdiff not found (install patchutils)"
validate_config
set_module_name
@@ -422,25 +468,27 @@ do_init() {
refresh_patch() {
local patch="$1"
local tmpdir="$PATCH_TMP_DIR"
- local files=()
+ local input_files=()
+ local output_files=()
rm -rf "$tmpdir"
mkdir -p "$tmpdir/a"
mkdir -p "$tmpdir/b"
# Get all source files affected by the patch
- get_patch_files "$patch" | mapfile -t files
+ get_patch_input_files "$patch" | mapfile -t input_files
+ get_patch_output_files "$patch" | mapfile -t output_files
# Copy orig source files to 'a'
- ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/a" )
+ echo "${input_files[@]}" | xargs cp --parents --target-directory="$tmpdir/a"
# Copy patched source files to 'b'
- apply_patch "$patch" --recount
- ( cd "$SRC" && echo "${files[@]}" | xargs cp --parents --target-directory="$tmpdir/b" )
- revert_patch "$patch" --recount
+ apply_patch "$patch" "--silent"
+ echo "${output_files[@]}" | xargs cp --parents --target-directory="$tmpdir/b"
+ revert_patch "$patch"
# Diff 'a' and 'b' to make a clean patch
- ( cd "$tmpdir" && git diff --no-index --no-prefix a b > "$patch" ) || true
+ ( cd "$tmpdir" && diff -Nupr a b > "$patch" ) || true
}
# Copy the patches to a temporary directory, fix their lines so as not to
@@ -463,8 +511,7 @@ fix_patches() {
cp -f "$old_patch" "$tmp_patch"
refresh_patch "$tmp_patch"
- "$FIX_PATCH_LINES" "$tmp_patch" > "$new_patch"
- refresh_patch "$new_patch"
+ "$FIX_PATCH_LINES" "$tmp_patch" | recountdiff > "$new_patch"
PATCHES[i]="$new_patch"
@@ -481,19 +528,14 @@ clean_kernel() {
cmd+=("-j$JOBS")
cmd+=("clean")
- (
- cd "$SRC"
- "${cmd[@]}"
- )
+ "${cmd[@]}"
}
build_kernel() {
+ local build="$1"
local log="$TMP_DIR/build.log"
- local objtool_args=()
local cmd=()
- objtool_args=("--checksum")
-
cmd=("make")
# When a patch to a kernel module references a newly created unexported
@@ -513,19 +555,20 @@ build_kernel() {
#
cmd+=("KBUILD_MODPOST_WARN=1")
- cmd+=("$VERBOSE")
+ if [[ -v VERBOSE ]]; then
+ cmd+=("V=1")
+ else
+ cmd+=("-s")
+ fi
cmd+=("-j$JOBS")
cmd+=("KCFLAGS=-ffunction-sections -fdata-sections")
- cmd+=("OBJTOOL_ARGS=${objtool_args[*]}")
cmd+=("vmlinux")
cmd+=("modules")
- (
- cd "$SRC"
- "${cmd[@]}" \
- 1> >(tee -a "$log") \
- 2> >(tee -a "$log" | grep0 -v "modpost.*undefined!" >&2)
- )
+ "${cmd[@]}" \
+ 1> >(tee -a "$log") \
+ 2> >(tee -a "$log" | grep0 -v "modpost.*undefined!" >&2) \
+ || die "$build kernel build failed"
}
find_objects() {
@@ -533,9 +576,9 @@ find_objects() {
# Find root-level vmlinux.o and non-root-level .ko files,
# excluding klp-tmp/ and .git/
- find "$OBJ" \( -path "$TMP_DIR" -o -path "$OBJ/.git" -o -regex "$OBJ/[^/][^/]*\.ko" \) -prune -o \
+ find "$PWD" \( -path "$TMP_DIR" -o -path "$PWD/.git" -o -regex "$PWD/[^/][^/]*\.ko" \) -prune -o \
-type f "${opts[@]}" \
- \( -name "*.ko" -o -path "$OBJ/vmlinux.o" \) \
+ \( -name "*.ko" -o -path "$PWD/vmlinux.o" \) \
-printf '%P\n'
}
@@ -548,25 +591,23 @@ copy_orig_objects() {
find_objects | mapfile -t files
- xtrace_save "copying orig objects"
+ xtrace_save "copying original objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
- local file="$OBJ/$rel_file"
- local file_dir="$(dirname "$file")"
+ local file="$PWD/$rel_file"
local orig_file="$ORIG_DIR/$rel_file"
local orig_dir="$(dirname "$orig_file")"
- local cmd_file="$file_dir/.$(basename "$file").cmd"
[[ ! -f "$file" ]] && die "missing $(basename "$file") for $_file"
mkdir -p "$orig_dir"
cp -f "$file" "$orig_dir"
- [[ -e "$cmd_file" ]] && cp -f "$cmd_file" "$orig_dir"
done
xtrace_restore
mv -f "$TMP_DIR/build.log" "$ORIG_DIR"
touch "$TIMESTAMP"
+ touch "$ORIG_DIR/.complete"
}
# Copy all changed objects to $PATCHED_DIR
@@ -587,7 +628,7 @@ copy_patched_objects() {
xtrace_save "copying changed objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
- local file="$OBJ/$rel_file"
+ local file="$PWD/$rel_file"
local orig_file="$ORIG_DIR/$rel_file"
local patched_file="$PATCHED_DIR/$rel_file"
local patched_dir="$(dirname "$patched_file")"
@@ -605,6 +646,36 @@ copy_patched_objects() {
(( found == 0 )) && die "no changes detected"
mv -f "$TMP_DIR/build.log" "$PATCHED_DIR"
+ touch "$PATCHED_DIR/.complete"
+}
+
+# Copy .o files to a separate directory and run "objtool klp checksum" on each
+# copy. The checksums are written to a .discard.sym_checksum section.
+#
+# If match_dir is given, only process files which also exist there.
+generate_checksums() {
+ local src_dir="$1"
+ local dest_dir="$2"
+ local match_dir="${3:-}"
+ local files=()
+ local file
+
+ rm -rf "$dest_dir"
+ mkdir -p "$dest_dir"
+
+ find "$src_dir" -type f -name "*.o" | mapfile -t files
+ for file in "${files[@]}"; do
+ local rel="${file#"$src_dir"/}"
+ local dest="$dest_dir/$rel"
+
+ [[ -n "$match_dir" && ! -f "$match_dir/$rel" ]] && continue
+
+ mkdir -p "$(dirname "$dest")"
+ cp -f "$file" "$dest"
+ "$OBJTOOL" klp checksum "$dest"
+ done
+
+ touch "$dest_dir/.complete"
}
# Diff changed objects, writing output object to $DIFF_DIR
@@ -616,23 +687,23 @@ diff_objects() {
rm -rf "$DIFF_DIR"
mkdir -p "$DIFF_DIR"
- find "$PATCHED_DIR" -type f -name "*.o" | mapfile -t files
+ find "$PATCHED_CSUM_DIR" -type f -name "*.o" | mapfile -t files
[[ ${#files[@]} -eq 0 ]] && die "no changes detected"
[[ -v DEBUG_CLONE ]] && opts=("--debug")
# Diff all changed objects
for file in "${files[@]}"; do
- local rel_file="${file#"$PATCHED_DIR"/}"
+ local rel_file="${file#"$PATCHED_CSUM_DIR"/}"
local orig_file="$rel_file"
- local patched_file="$PATCHED_DIR/$rel_file"
+ local patched_file="$PATCHED_CSUM_DIR/$rel_file"
local out_file="$DIFF_DIR/$rel_file"
local filter=()
local cmd=()
mkdir -p "$(dirname "$out_file")"
- cmd=("$SRC/tools/objtool/objtool")
+ cmd=("$OBJTOOL")
cmd+=("klp")
cmd+=("diff")
(( ${#opts[@]} > 0 )) && cmd+=("${opts[@]}")
@@ -649,18 +720,21 @@ diff_objects() {
fi
(
- cd "$ORIG_DIR"
+ cd "$ORIG_CSUM_DIR"
+ [[ -v VERBOSE ]] && echo "cd $ORIG_CSUM_DIR && ${cmd[*]}"
"${cmd[@]}" \
1> >(tee -a "$log") \
2> >(tee -a "$log" | "${filter[@]}" >&2) || \
die "objtool klp diff failed"
)
done
+
+ touch "$DIFF_DIR/.complete"
}
-# For each changed object, run objtool with --debug-checksum to get the
-# per-instruction checksums, and then diff those to find the first changed
-# instruction for each function.
+# For each changed object, run "objtool klp checksum" with --debug-checksum to
+# get the per-instruction checksums, and then diff those to find the first
+# changed instruction for each function.
diff_checksums() {
local orig_log="$ORIG_DIR/checksum.log"
local patched_log="$PATCHED_DIR/checksum.log"
@@ -684,9 +758,8 @@ diff_checksums() {
fi
done
- cmd=("$SRC/tools/objtool/objtool")
- cmd+=("--checksum")
- cmd+=("--link")
+ cmd=("$OBJTOOL")
+ cmd+=("klp" "checksum")
cmd+=("--dry-run")
for file in "${!funcs[@]}"; do
@@ -695,21 +768,37 @@ diff_checksums() {
(
cd "$ORIG_DIR"
"${cmd[@]}" "$opt" "$file" &> "$orig_log" || \
- ( cat "$orig_log" >&2; die "objtool --debug-checksum failed" )
+ ( cat "$orig_log" >&2; die "objtool klp checksum failed" )
cd "$PATCHED_DIR"
"${cmd[@]}" "$opt" "$file" &> "$patched_log" || \
- ( cat "$patched_log" >&2; die "objtool --debug-checksum failed" )
+ ( cat "$patched_log" >&2; die "objtool klp checksum failed" )
)
for func in ${funcs[$file]}; do
- diff <( grep0 -E "^DEBUG: .*checksum: $func " "$orig_log" | sed "s|$ORIG_DIR/||") \
- <( grep0 -E "^DEBUG: .*checksum: $func " "$patched_log" | sed "s|$PATCHED_DIR/||") \
- | gawk '/^< DEBUG: / {
- gsub(/:/, "")
- printf "%s: %s: %s\n", $3, $5, $6
- exit
- }' || true
+ local -a orig patched
+ paste <(grep0 -E "^DEBUG: .*checksum: $func " "$orig_log") \
+ <(grep0 -E "^DEBUG: .*checksum: $func " "$patched_log") |
+ while IFS= read -r line; do
+ read -ra orig <<< "${line%%$'\t'*}"
+ read -ra patched <<< "${line#*$'\t'}"
+
+ if [[ ${#patched[@]} -eq 0 ]]; then
+ printf "%s: %s: %s (removed)\n" "${orig[1]%:}" "${orig[3]}" "${orig[-2]}"
+ break
+ elif [[ ${#orig[@]} -eq 0 ]]; then
+ printf "%s: %s: %s (added)\n" "${patched[1]%:}" "${patched[3]}" "${patched[-2]}"
+ break
+ fi
+
+ [[ "${orig[-1]}" == "${patched[-1]}" ]] && continue
+
+ printf "%s: %s: %s" "${orig[1]%:}" "${orig[3]}" "${orig[-2]}"
+ [[ "${orig[-2]}" != "${patched[-2]}" ]] && \
+ printf " (patched: %s)" "${patched[-2]}"
+ printf "\n"
+ break
+ done || true
done
done
}
@@ -726,7 +815,7 @@ build_patch_module() {
rm -rf "$KMOD_DIR"
mkdir -p "$KMOD_DIR"
- cp -f "$SRC/scripts/livepatch/init.c" "$KMOD_DIR"
+ cp -f "$SCRIPT_DIR/init.c" "$KMOD_DIR"
echo "obj-m := $NAME.o" > "$makefile"
echo -n "$NAME-y := init.o" >> "$makefile"
@@ -740,15 +829,17 @@ build_patch_module() {
local orig_dir="$(dirname "$orig_file")"
local kmod_file="$KMOD_DIR/$rel_file"
local kmod_dir="$(dirname "$kmod_file")"
- local cmd_file="$orig_dir/.$(basename "$file").cmd"
+ local cmd_file="$kmod_dir/.$(basename "$file").cmd"
mkdir -p "$kmod_dir"
cp -f "$file" "$kmod_dir"
- [[ -e "$cmd_file" ]] && cp -f "$cmd_file" "$kmod_dir"
# Tell kbuild this is a prebuilt object
cp -f "$file" "${kmod_file}_shipped"
+ # Make modpost happy
+ touch "$cmd_file"
+
echo -n " $rel_file" >> "$makefile"
done
@@ -759,19 +850,20 @@ build_patch_module() {
[[ $REPLACE -eq 0 ]] && cflags+=("-DKLP_NO_REPLACE")
cmd=("make")
- cmd+=("$VERBOSE")
+ if [[ -v VERBOSE ]]; then
+ cmd+=("V=1")
+ else
+ cmd+=("-s")
+ fi
cmd+=("-j$JOBS")
cmd+=("--directory=.")
cmd+=("M=$KMOD_DIR")
cmd+=("KCFLAGS=${cflags[*]}")
# Build a "normal" kernel module with init.c and the diffed objects
- (
- cd "$SRC"
- "${cmd[@]}" \
- 1> >(tee -a "$log") \
- 2> >(tee -a "$log" >&2)
- )
+ "${cmd[@]}" \
+ 1> >(tee -a "$log") \
+ 2> >(tee -a "$log" >&2)
kmod_file="$KMOD_DIR/$NAME.ko"
@@ -782,7 +874,7 @@ build_patch_module() {
objcopy --remove-section=.BTF "$kmod_file"
# Fix (and work around) linker wreckage for klp syms / relocs
- "$SRC/tools/objtool/objtool" klp post-link "$kmod_file" || die "objtool klp post-link failed"
+ "$OBJTOOL" klp post-link "$kmod_file" || die "objtool klp post-link failed"
cp -f "$kmod_file" "$OUTFILE"
}
@@ -793,12 +885,15 @@ build_patch_module() {
process_args "$@"
do_init
-if (( SHORT_CIRCUIT <= 1 )); then
+if (( SHORT_CIRCUIT <= 2 )); then
status "Validating patch(es)"
validate_patches
+fi
+
+if (( SHORT_CIRCUIT <= 1 )); then
status "Building original kernel"
clean_kernel
- build_kernel
+ build_kernel "original"
status "Copying original object files"
copy_orig_objects
fi
@@ -806,15 +901,22 @@ fi
if (( SHORT_CIRCUIT <= 2 )); then
status "Fixing patch(es)"
fix_patches
- apply_patches
+ apply_patches "--silent"
status "Building patched kernel"
- build_kernel
+ build_kernel "patched"
revert_patches
status "Copying patched object files"
copy_patched_objects
fi
if (( SHORT_CIRCUIT <= 3 )); then
+ status "Generating original checksums"
+ generate_checksums "$ORIG_DIR" "$ORIG_CSUM_DIR" "$PATCHED_DIR"
+ status "Generating patched checksums"
+ generate_checksums "$PATCHED_DIR" "$PATCHED_CSUM_DIR"
+fi
+
+if (( SHORT_CIRCUIT <= 4 )); then
status "Diffing objects"
diff_objects
if [[ -v DIFF_CHECKSUM ]]; then
@@ -823,7 +925,7 @@ if (( SHORT_CIRCUIT <= 3 )); then
fi
fi
-if (( SHORT_CIRCUIT <= 4 )); then
+if (( SHORT_CIRCUIT <= 5 )); then
status "Building patch module: $OUTFILE"
build_patch_module
fi
diff --git a/scripts/make_fit.py b/scripts/make_fit.py
index 1683e5ec6e67..15ba26974fd7 100755
--- a/scripts/make_fit.py
+++ b/scripts/make_fit.py
@@ -10,10 +10,14 @@
Usage:
make_fit.py -A arm64 -n 'Linux-6.6' -O linux
-o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk
- @arch/arm64/boot/dts/dtbs-list -E -c gzip
+ -r /boot/initrd.img-6.14.0-27-generic @arch/arm64/boot/dts/dtbs-list
+ -E -c gzip
-Creates a FIT containing the supplied kernel and a set of devicetree files,
-either specified individually or listed in a file (with an '@' prefix).
+Creates a FIT containing the supplied kernel, an optional ramdisk, and a set of
+devicetree files, either specified individually or listed in a file (with an
+'@' prefix).
+
+Use -r to specify an existing ramdisk/initrd file.
Use -E to generate an external FIT (where the data is placed after the
FIT data structure). This allows parsing of the data without loading
@@ -29,12 +33,11 @@ looks at the .cmd files produced by the kernel build.
The resulting FIT can be booted by bootloaders which support FIT, such
as U-Boot, Linuxboot, Tianocore, etc.
-
-Note that this tool does not yet support adding a ramdisk / initrd.
"""
import argparse
import collections
+import multiprocessing
import os
import subprocess
import sys
@@ -48,11 +51,12 @@ import libfdt
CompTool = collections.namedtuple('CompTool', 'ext,tools')
COMP_TOOLS = {
- 'bzip2': CompTool('.bz2', 'bzip2'),
+ 'bzip2': CompTool('.bz2', 'pbzip2,bzip2'),
'gzip': CompTool('.gz', 'pigz,gzip'),
'lz4': CompTool('.lz4', 'lz4'),
'lzma': CompTool('.lzma', 'lzma'),
'lzo': CompTool('.lzo', 'lzop'),
+ 'xz': CompTool('.xz', 'xz'),
'zstd': CompTool('.zstd', 'zstd'),
}
@@ -81,6 +85,8 @@ def parse_args():
help='Specifies the operating system')
parser.add_argument('-k', '--kernel', type=str, required=True,
help='Specifies the (uncompressed) kernel input file (.itk)')
+ parser.add_argument('-r', '--ramdisk', type=str,
+ help='Specifies the ramdisk/initrd input file')
parser.add_argument('-v', '--verbose', action='store_true',
help='Enable verbose output')
parser.add_argument('dtbs', type=str, nargs='*',
@@ -98,7 +104,7 @@ def setup_fit(fsw, name):
fsw (libfdt.FdtSw): Object to use for writing
name (str): Name of kernel image
"""
- fsw.INC_SIZE = 65536
+ fsw.INC_SIZE = 16 << 20
fsw.finish_reservemap()
fsw.begin_node('')
fsw.property_string('description', f'{name} with devicetree set')
@@ -133,7 +139,28 @@ def write_kernel(fsw, data, args):
fsw.property_u32('entry', 0)
-def finish_fit(fsw, entries):
+def write_ramdisk(fsw, data, args):
+ """Write out the ramdisk image
+
+ Writes a ramdisk node along with the required properties
+
+ Args:
+ fsw (libfdt.FdtSw): Object to use for writing
+ data (bytes): Data to write (possibly compressed)
+ args (Namespace): Contains necessary strings:
+ arch: FIT architecture, e.g. 'arm64'
+ fit_os: Operating Systems, e.g. 'linux'
+ """
+ with fsw.add_node('ramdisk'):
+ fsw.property_string('description', 'Ramdisk')
+ fsw.property_string('type', 'ramdisk')
+ fsw.property_string('arch', args.arch)
+ fsw.property_string('compression', 'none')
+ fsw.property_string('os', args.os)
+ fsw.property('data', data)
+
+
+def finish_fit(fsw, entries, has_ramdisk=False):
"""Finish the FIT ready for use
Writes the /configurations node and subnodes
@@ -143,6 +170,7 @@ def finish_fit(fsw, entries):
entries (list of tuple): List of configurations:
str: Description of model
str: Compatible stringlist
+ has_ramdisk (bool): True if a ramdisk is included in the FIT
"""
fsw.end_node()
seq = 0
@@ -154,6 +182,8 @@ def finish_fit(fsw, entries):
fsw.property_string('description', model)
fsw.property('fdt', bytes(''.join(f'fdt-{x}\x00' for x in files), "ascii"))
fsw.property_string('kernel', 'kernel')
+ if has_ramdisk:
+ fsw.property_string('ramdisk', 'ramdisk')
fsw.end_node()
@@ -179,7 +209,12 @@ def compress_data(inf, compress):
done = False
for tool in comp.tools.split(','):
try:
- subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
+ # Add parallel flags for tools that support them
+ cmd = [tool]
+ if tool in ('zstd', 'xz'):
+ cmd.extend(['-T0']) # Use all available cores
+ cmd.append('-c')
+ subprocess.call(cmd, stdin=inf, stdout=outf)
done = True
break
except FileNotFoundError:
@@ -191,15 +226,31 @@ def compress_data(inf, compress):
return comp_data
-def output_dtb(fsw, seq, fname, arch, compress):
+def compress_dtb(fname, compress):
+ """Compress a single DTB file
+
+ Args:
+ fname (str): Filename containing the DTB
+ compress (str): Compression algorithm, e.g. 'gzip'
+
+ Returns:
+ tuple: (str: fname, bytes: compressed_data)
+ """
+ with open(fname, 'rb') as inf:
+ compressed = compress_data(inf, compress)
+ return fname, compressed
+
+
+def output_dtb(fsw, seq, fname, arch, compress, data=None):
"""Write out a single devicetree to the FIT
Args:
fsw (libfdt.FdtSw): Object to use for writing
seq (int): Sequence number (1 for first)
fname (str): Filename containing the DTB
- arch: FIT architecture, e.g. 'arm64'
+ arch (str): FIT architecture, e.g. 'arm64'
compress (str): Compressed algorithm, e.g. 'gzip'
+ data (bytes): Pre-compressed data (optional)
"""
with fsw.add_node(f'fdt-{seq}'):
fsw.property_string('description', os.path.basename(fname))
@@ -207,9 +258,10 @@ def output_dtb(fsw, seq, fname, arch, compress):
fsw.property_string('arch', arch)
fsw.property_string('compression', compress)
- with open(fname, 'rb') as inf:
- compressed = compress_data(inf, compress)
- fsw.property('data', compressed)
+ if data is None:
+ with open(fname, 'rb') as inf:
+ data = compress_data(inf, compress)
+ fsw.property('data', data)
def process_dtb(fname, args):
@@ -249,30 +301,27 @@ def process_dtb(fname, args):
return (model, compat, files)
-def build_fit(args):
- """Build the FIT from the provided files and arguments
+
+def _process_dtbs(args, fsw, entries, fdts):
+ """Process all DTB files and add them to the FIT
Args:
- args (Namespace): Program arguments
+ args: Program arguments
+ fsw: FIT writer object
+ entries: List to append entries to
+ fdts: Dictionary of processed DTBs
Returns:
tuple:
- bytes: FIT data
- int: Number of configurations generated
- size: Total uncompressed size of data
+ Number of files processed
+ Total size of files processed
"""
seq = 0
size = 0
- fsw = libfdt.FdtSw()
- setup_fit(fsw, args.name)
- entries = []
- fdts = {}
- # Handle the kernel
- with open(args.kernel, 'rb') as inf:
- comp_data = compress_data(inf, args.compress)
- size += os.path.getsize(args.kernel)
- write_kernel(fsw, comp_data, args)
+ # First figure out the unique DTB files that need compression
+ todo = []
+ file_info = [] # List of (fname, model, compat, files) tuples
for fname in args.dtbs:
# Ignore non-DTB (*.dtb) files
@@ -282,24 +331,84 @@ def build_fit(args):
try:
(model, compat, files) = process_dtb(fname, args)
except Exception as e:
- sys.stderr.write(f"Error processing {fname}:\n")
+ sys.stderr.write(f'Error processing {fname}:\n')
raise e
+ file_info.append((fname, model, compat, files))
+ for fn in files:
+ if fn not in fdts and fn not in todo:
+ todo.append(fn)
+
+ # Compress all DTBs in parallel
+ cache = {}
+ if todo and args.compress != 'none':
+ if args.verbose:
+ print(f'Compressing {len(todo)} DTBs...')
+
+ with multiprocessing.Pool() as pool:
+ compress_args = [(fn, args.compress) for fn in todo]
+ # unpacks each tuple, calls compress_dtb(fn, compress) in parallel
+ results = pool.starmap(compress_dtb, compress_args)
+
+ cache = dict(results)
+
+ # Now write all DTBs to the FIT using pre-compressed data
+ for fname, model, compat, files in file_info:
for fn in files:
if fn not in fdts:
seq += 1
size += os.path.getsize(fn)
- output_dtb(fsw, seq, fn, args.arch, args.compress)
+ output_dtb(fsw, seq, fn, args.arch, args.compress,
+ cache.get(fn))
fdts[fn] = seq
files_seq = [fdts[fn] for fn in files]
-
entries.append([model, compat, files_seq])
- finish_fit(fsw, entries)
+ return seq, size
+
+
+def build_fit(args):
+ """Build the FIT from the provided files and arguments
+
+ Args:
+ args (Namespace): Program arguments
+
+ Returns:
+ tuple:
+ bytes: FIT data
+ int: Number of configurations generated
+ size: Total uncompressed size of data
+ """
+ size = 0
+ fsw = libfdt.FdtSw()
+ setup_fit(fsw, args.name)
+ entries = []
+ fdts = {}
+
+ # Handle the kernel
+ with open(args.kernel, 'rb') as inf:
+ comp_data = compress_data(inf, args.compress)
+ size += os.path.getsize(args.kernel)
+ write_kernel(fsw, comp_data, args)
+
+ # Handle the ramdisk if provided. Compression is not supported as it is
+ # already compressed.
+ if args.ramdisk:
+ with open(args.ramdisk, 'rb') as inf:
+ data = inf.read()
+ size += len(data)
+ write_ramdisk(fsw, data, args)
+
+ count, fdt_size = _process_dtbs(args, fsw, entries, fdts)
+ size += fdt_size
+
+ finish_fit(fsw, entries, bool(args.ramdisk))
# Include the kernel itself in the returned file count
- return fsw.as_fdt().as_bytearray(), seq + 1, size
+ fdt = fsw.as_fdt()
+ fdt.pack()
+ return fdt.as_bytearray(), count + 1 + bool(args.ramdisk), size
def run_make_fit():
diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh
index 99b5575c1ef7..ea2689bc9641 100755
--- a/scripts/min-tool-version.sh
+++ b/scripts/min-tool-version.sh
@@ -27,14 +27,14 @@ llvm)
if [ "$SRCARCH" = loongarch ]; then
echo 18.0.0
else
- echo 15.0.0
+ echo 17.0.1
fi
;;
rustc)
- echo 1.78.0
+ echo 1.85.0
;;
bindgen)
- echo 0.65.1
+ echo 0.71.1
;;
*)
echo "$1: unknown tool" >&2
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 4e99393a35f1..2ad87a74bb03 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -651,7 +651,26 @@ static void do_vio_entry(struct module *mod, void *symval)
module_alias_printf(mod, true, "%s", alias);
}
-static void do_input(char *alias,
+static void __attribute__((format(printf, 3, 4)))
+alias_append(char *alias, size_t size, const char *fmt, ...)
+{
+ size_t len = strlen(alias);
+ va_list args;
+ int n;
+
+ if (len >= size)
+ fatal("alias buffer (%zu) overflow before append\n", size);
+
+ va_start(args, fmt);
+ n = vsnprintf(alias + len, size - len, fmt, args);
+ va_end(args);
+
+ if (n < 0 || (size_t)n >= size - len)
+ fatal("alias buffer (%zu) overflow on append (need %d, have %zu)\n",
+ size, n, size - len);
+}
+
+static void do_input(char *alias, size_t size,
kernel_ulong_t *arr, unsigned int min, unsigned int max)
{
unsigned int i;
@@ -659,13 +678,14 @@ static void do_input(char *alias,
for (i = min; i <= max; i++)
if (get_unaligned_native(arr + i / BITS_PER_LONG) &
(1ULL << (i % BITS_PER_LONG)))
- sprintf(alias + strlen(alias), "%X,*", i);
+ alias_append(alias, size, "%X,*", i);
}
/* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */
static void do_input_entry(struct module *mod, void *symval)
{
char alias[256] = {};
+ const size_t sizeof_alias = sizeof(alias);
DEF_FIELD(symval, input_device_id, flags);
DEF_FIELD(symval, input_device_id, bustype);
@@ -687,35 +707,35 @@ static void do_input_entry(struct module *mod, void *symval)
ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product);
ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version);
- sprintf(alias + strlen(alias), "-e*");
+ alias_append(alias, sizeof_alias, "-e*");
if (flags & INPUT_DEVICE_ID_MATCH_EVBIT)
- do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX);
- sprintf(alias + strlen(alias), "k*");
+ do_input(alias, sizeof_alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX);
+ alias_append(alias, sizeof_alias, "k*");
if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT)
- do_input(alias, *keybit,
+ do_input(alias, sizeof_alias, *keybit,
INPUT_DEVICE_ID_KEY_MIN_INTERESTING,
INPUT_DEVICE_ID_KEY_MAX);
- sprintf(alias + strlen(alias), "r*");
+ alias_append(alias, sizeof_alias, "r*");
if (flags & INPUT_DEVICE_ID_MATCH_RELBIT)
- do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX);
- sprintf(alias + strlen(alias), "a*");
+ do_input(alias, sizeof_alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX);
+ alias_append(alias, sizeof_alias, "a*");
if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT)
- do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX);
- sprintf(alias + strlen(alias), "m*");
+ do_input(alias, sizeof_alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX);
+ alias_append(alias, sizeof_alias, "m*");
if (flags & INPUT_DEVICE_ID_MATCH_MSCIT)
- do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);
- sprintf(alias + strlen(alias), "l*");
+ do_input(alias, sizeof_alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);
+ alias_append(alias, sizeof_alias, "l*");
if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT)
- do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX);
- sprintf(alias + strlen(alias), "s*");
+ do_input(alias, sizeof_alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX);
+ alias_append(alias, sizeof_alias, "s*");
if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT)
- do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX);
- sprintf(alias + strlen(alias), "f*");
+ do_input(alias, sizeof_alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX);
+ alias_append(alias, sizeof_alias, "f*");
if (flags & INPUT_DEVICE_ID_MATCH_FFBIT)
- do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX);
- sprintf(alias + strlen(alias), "w*");
+ do_input(alias, sizeof_alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX);
+ alias_append(alias, sizeof_alias, "w*");
if (flags & INPUT_DEVICE_ID_MATCH_SWBIT)
- do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX);
+ do_input(alias, sizeof_alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX);
module_alias_printf(mod, false, "input:%s", alias);
}
@@ -895,12 +915,16 @@ static const struct dmifield {
{ NULL, DMI_NONE }
};
-static void dmi_ascii_filter(char *d, const char *s)
+static void dmi_ascii_filter(char *d, size_t avail, const char *s)
{
/* Filter out characters we don't want to see in the modalias string */
for (; *s; s++)
- if (*s > ' ' && *s < 127 && *s != ':')
+ if (*s > ' ' && *s < 127 && *s != ':') {
+ if (avail <= 1)
+ fatal("%s: alias buffer overflow\n", __func__);
*(d++) = *s;
+ avail--;
+ }
*d = 0;
}
@@ -909,6 +933,8 @@ static void dmi_ascii_filter(char *d, const char *s)
static void do_dmi_entry(struct module *mod, void *symval)
{
char alias[256] = {};
+ const size_t sizeof_alias = sizeof(alias);
+ size_t len;
int i, j;
DEF_FIELD_ADDR(symval, dmi_system_id, matches);
@@ -916,11 +942,12 @@ static void do_dmi_entry(struct module *mod, void *symval)
for (j = 0; j < 4; j++) {
if ((*matches)[j].slot &&
(*matches)[j].slot == dmi_fields[i].field) {
- sprintf(alias + strlen(alias), ":%s*",
- dmi_fields[i].prefix);
- dmi_ascii_filter(alias + strlen(alias),
+ alias_append(alias, sizeof_alias, ":%s*",
+ dmi_fields[i].prefix);
+ len = strlen(alias);
+ dmi_ascii_filter(alias + len, sizeof_alias - len,
(*matches)[j].substr);
- strcat(alias, "*");
+ alias_append(alias, sizeof_alias, "*");
}
}
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 755b842f1f9b..d592548cbd60 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -56,7 +56,7 @@ static bool allow_missing_ns_imports;
static bool error_occurred;
-static bool extra_warn;
+static bool extra_warn __attribute__((unused));
bool target_is_big_endian;
bool host_is_big_endian;
@@ -244,6 +244,11 @@ static struct symbol *alloc_symbol(const char *name)
return s;
}
+static uint8_t get_symbol_flags(const struct symbol *sym)
+{
+ return sym->is_gpl_only ? KSYM_FLAG_GPL_ONLY : 0;
+}
+
/* For the hash of exported symbols */
static void hash_add_symbol(struct symbol *sym)
{
@@ -602,6 +607,10 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
/* Special register function linked on all modules during final link of .ko */
if (strstarts(symname, "_restgpr0_") ||
strstarts(symname, "_savegpr0_") ||
+ strstarts(symname, "_restgpr1_") ||
+ strstarts(symname, "_savegpr1_") ||
+ strstarts(symname, "_restfpr_") ||
+ strstarts(symname, "_savefpr_") ||
strstarts(symname, "_restvr_") ||
strstarts(symname, "_savevr_") ||
strcmp(symname, ".TOC.") == 0)
@@ -756,6 +765,8 @@ static const char *const section_white_list[] =
".gnu.lto*",
".discard.*",
".llvm.call-graph-profile", /* call graph */
+ "__llvm_covfun",
+ "__llvm_covmap",
NULL
};
@@ -958,7 +969,7 @@ static int secref_whitelist(const char *fromsec, const char *fromsym,
/* symbols in data sections that may refer to any init/exit sections */
if (match(fromsec, PATTERNS(DATA_SECTIONS)) &&
match(tosec, PATTERNS(ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS)) &&
- match(fromsym, PATTERNS("*_ops", "*_probe", "*_console")))
+ match(fromsym, PATTERNS("*_ops", "*_console")))
return 0;
/* Check for pattern 3 */
@@ -1478,13 +1489,22 @@ static void extract_crcs_for_object(const char *object, struct module *mod)
char cmd_file[PATH_MAX];
char *buf, *p;
const char *base;
- int dirlen, ret;
+ int dirlen, baselen_without_suffix, ret;
base = get_basename(object);
dirlen = base - object;
- ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%s.cmd",
- dirlen, object, base);
+ baselen_without_suffix = strlen(object) - dirlen - strlen(".o");
+
+ /*
+ * When CONFIG_LTO_CLANG_THIN_DIST=y, the ELF is *.thinlto-native.o
+ * but the symbol CRCs are recorded in *.o.cmd file.
+ */
+ if (strends(object, ".thinlto-native.o"))
+ baselen_without_suffix -= strlen(".thinlto-native");
+
+ ret = snprintf(cmd_file, sizeof(cmd_file), "%.*s.%.*s.o.cmd",
+ dirlen, object, baselen_without_suffix, base);
if (ret >= sizeof(cmd_file)) {
error("%s: too long path was truncated\n", cmd_file);
return;
@@ -1680,8 +1700,17 @@ void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf,
va_start(ap, fmt);
len = vsnprintf(tmp, SZ, fmt, ap);
- buf_write(buf, tmp, len);
va_end(ap);
+
+ if (len < 0) {
+ perror("vsnprintf failed");
+ exit(1);
+ }
+ if (len >= SZ)
+ fatal("buf_printf output truncated for string %s: %d bytes needed, %d available\n",
+ tmp, len + 1, SZ);
+
+ buf_write(buf, tmp, len);
}
void buf_write(struct buffer *buf, const char *s, int len)
@@ -1867,9 +1896,12 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
if (trim_unused_exports && !sym->used)
continue;
- buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n",
+ buf_printf(buf, "KSYMTAB_%s(%s, \"%s\");\n",
sym->is_func ? "FUNC" : "DATA", sym->name,
- sym->is_gpl_only ? "_gpl" : "", sym->namespace);
+ sym->namespace);
+
+ buf_printf(buf, "SYMBOL_FLAGS(%s, 0x%02x);\n",
+ sym->name, get_symbol_flags(sym));
}
if (!modversions)
@@ -1887,8 +1919,8 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
sym->name, mod->name, mod->is_vmlinux ? "" : ".ko",
sym->name);
- buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n",
- sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : "");
+ buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x);\n",
+ sym->name, sym->crc);
}
}
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 3037d5e5527c..b62683061d79 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -20,9 +20,8 @@ SECTIONS {
}
__ksymtab 0 : ALIGN(8) { *(SORT(___ksymtab+*)) }
- __ksymtab_gpl 0 : ALIGN(8) { *(SORT(___ksymtab_gpl+*)) }
__kcrctab 0 : ALIGN(4) { *(SORT(___kcrctab+*)) }
- __kcrctab_gpl 0 : ALIGN(4) { *(SORT(___kcrctab_gpl+*)) }
+ __kflagstab 0 : ALIGN(1) { *(SORT(___kflagstab+*)) }
.ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) }
.init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) }
@@ -32,35 +31,32 @@ SECTIONS {
__jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) }
__ex_table 0 : ALIGN(4) { KEEP(*(__ex_table)) }
- __patchable_function_entries : { *(__patchable_function_entries) }
+ __patchable_function_entries 0 : { *(__patchable_function_entries) }
- __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
-
- __klp_objects 0: ALIGN(8) {
- __start_klp_objects = .;
- KEEP(*(__klp_objects))
- __stop_klp_objects = .;
- }
+ .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+ .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
- __kcfi_traps : { KEEP(*(.kcfi_traps)) }
+ __kcfi_traps 0 : { KEEP(*(.kcfi_traps)) }
#endif
- .text : {
+#ifndef CONFIG_ARCH_WANTS_MODULES_TEXT_SECTIONS
+ .text 0 : {
*(.text .text.[0-9a-zA-Z_]*)
}
+#endif
- .bss : {
+ .bss 0 : {
*(.bss .bss.[0-9a-zA-Z_]*)
*(.bss..L*)
}
- .data : {
+ .data 0 : {
*(.data .data.[0-9a-zA-Z_]*)
*(.data..L*)
}
- .rodata : {
+ .rodata 0 : {
*(.rodata .rodata.[0-9a-zA-Z_]*)
*(.rodata..L*)
}
diff --git a/scripts/package/PKGBUILD b/scripts/package/PKGBUILD
index 452374d63c24..66e4b6a37783 100644
--- a/scripts/package/PKGBUILD
+++ b/scripts/package/PKGBUILD
@@ -10,7 +10,7 @@ for pkg in $_extrapackages; do
pkgname+=("${pkgbase}-${pkg}")
done
-pkgver="${KERNELRELEASE//-/_}"
+pkgver="$(echo "${KERNELRELEASE}" | sed 's/-\(rc[0-9]\+\)/\1/;s/-/_/g')"
# The PKGBUILD is evaluated multiple times.
# Running scripts/build-version from here would introduce inconsistencies.
pkgrel="${KBUILD_REVISION}"
@@ -121,6 +121,9 @@ _package-debug(){
install -Dt "${debugdir}" -m644 vmlinux
mkdir -p "${builddir}"
ln -sr "${debugdir}/vmlinux" "${builddir}/vmlinux"
+
+ echo "Installing unstripped vDSO(s)..."
+ ${MAKE} INSTALL_MOD_PATH="${pkgdir}/usr" vdso_install
}
for _p in "${pkgname[@]}"; do
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 3627ca227e5a..ba1defc61652 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -139,7 +139,13 @@ install_kernel_headers () {
pdir=debian/$1
version=${1#linux-headers-}
- CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ # Override $CC only for cross-compiles, to not unnecessarily rebuild
+ # scripts/ including plugins, which may lead to a full kernel rebuild.
+ if [ -n "${CROSS_COMPILE}" ]; then
+ CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ else
+ "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}"
+ fi
mkdir -p $pdir/lib/modules/$version/
ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build
index 2576cf7902db..f12e1ffe409e 100755
--- a/scripts/package/install-extmod-build
+++ b/scripts/package/install-extmod-build
@@ -32,6 +32,10 @@ mkdir -p "${destdir}"
echo tools/objtool/objtool
fi
+ if is_enabled CONFIG_DEBUG_INFO_BTF_MODULES; then
+ echo tools/bpf/resolve_btfids/resolve_btfids
+ fi
+
echo Module.symvers
echo "arch/${SRCARCH}/include/generated"
echo include/config/auto.conf
diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec
index 98f206cb7c60..c732415662ef 100644
--- a/scripts/package/kernel.spec
+++ b/scripts/package/kernel.spec
@@ -6,7 +6,7 @@
Name: kernel
Summary: The Linux Kernel
Version: %(echo %{KERNELRELEASE} | sed -e 's/-/_/g')
-Release: %{pkg_release}
+Release: %{pkg_release}%{?dist}
License: GPL
Group: System Environment/Kernel
Vendor: The Linux Community
@@ -45,7 +45,19 @@ This package provides kernel headers and makefiles sufficient to build modules
against the %{version} kernel package.
%endif
-%if %{with_debuginfo}
+%if %{with_debuginfo_manual}
+%package debuginfo
+Summary: Debug information package for the Linux kernel
+Group: Development/Debug
+AutoReq: 0
+AutoProv: 1
+%description debuginfo
+This package provides debug information for the kernel image and modules from the
+%{version} package.
+%define install_mod_strip 1
+%endif
+
+%if %{with_debuginfo_rpm}
# list of debuginfo-related options taken from distribution kernel.spec
# files
%undefine _include_minidebuginfo
@@ -59,11 +71,6 @@ against the %{version} kernel package.
%global _missing_build_ids_terminate_build 1
%global _no_recompute_build_ids 1
%{debug_package}
-%endif
-# some (but not all) versions of rpmbuild emit %%debug_package with
-# %%install. since we've already emitted it manually, that would cause
-# a package redefinition error. ensure that doesn't happen
-%define debug_package %{nil}
# later, we make all modules executable so that find-debuginfo.sh strips
# them up. but they don't actually need to be executable, so remove the
@@ -74,6 +81,13 @@ against the %{version} kernel package.
%{__os_install_post} \
find %{buildroot}/lib/modules/%{KERNELRELEASE} -name "*.ko" -type f \\\
| xargs --no-run-if-empty chmod u-x
+%else
+%define __spec_install_post /usr/lib/rpm/brp-compress || :
+%endif
+# some (but not all) versions of rpmbuild emit %%debug_package with
+# %%install. since we've already emitted it manually, that would cause
+# a package redefinition error. ensure that doesn't happen
+%define debug_package %{nil}
%prep
%setup -q -n linux
@@ -87,7 +101,7 @@ patch -p1 < %{SOURCE2}
mkdir -p %{buildroot}/lib/modules/%{KERNELRELEASE}
cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEASE}/vmlinuz
# DEPMOD=true makes depmod no-op. We do not package depmod-generated files.
-%{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} DEPMOD=true modules_install
+%{make} %{makeflags} INSTALL_MOD_PATH=%{buildroot} %{?install_mod_strip:INSTALL_MOD_STRIP=1} DEPMOD=true modules_install
%{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install
cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE}
cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config
@@ -118,22 +132,43 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA
echo "%exclude /lib/modules/%{KERNELRELEASE}/build"
} > %{buildroot}/kernel.list
+%if 0%{with_debuginfo_manual}%{with_debuginfo_rpm} > 0
+# copying vmlinux directly to the debug directory means it will not get
+# stripped (but its source paths will still be collected + fixed up)
+mkdir -p %{buildroot}/usr/lib/debug/lib/modules/%{KERNELRELEASE}
+cp vmlinux %{buildroot}/usr/lib/debug/lib/modules/%{KERNELRELEASE}
+%endif
+
+%if %{with_debuginfo_rpm}
# make modules executable so that find-debuginfo.sh strips them. this
# will be undone later in %%__spec_install_post
find %{buildroot}/lib/modules/%{KERNELRELEASE} -name "*.ko" -type f \
| xargs --no-run-if-empty chmod u+x
+%endif
-%if %{with_debuginfo}
-# copying vmlinux directly to the debug directory means it will not get
-# stripped (but its source paths will still be collected + fixed up)
-mkdir -p %{buildroot}/usr/lib/debug/lib/modules/%{KERNELRELEASE}
-cp vmlinux %{buildroot}/usr/lib/debug/lib/modules/%{KERNELRELEASE}
+%if %{with_debuginfo_manual}
+echo /usr/lib/debug/lib/modules/%{KERNELRELEASE}/vmlinux > %{buildroot}/debuginfo.list
+while read -r mod; do
+ mod="${mod%.o}.ko"
+ dbg="%{buildroot}/usr/lib/debug/lib/modules/%{KERNELRELEASE}/kernel/${mod}"
+ buildid=$("${READELF:-readelf}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p')
+ link="%{buildroot}/usr/lib/debug/.build-id/${buildid}.debug"
+
+ mkdir -p "${dbg%/*}" "${link%/*}"
+ "${OBJCOPY:-objcopy}" --only-keep-debug "${mod}" "${dbg}"
+ ln -sf --relative "${dbg}" "${link}"
+
+ echo "${dbg#%{buildroot}}" >> %{buildroot}/debuginfo.list
+ echo "${link#%{buildroot}}" >> %{buildroot}/debuginfo.list
+done < modules.order
%endif
%clean
rm -rf %{buildroot}
+%if %{with_debuginfo_rpm}
rm -f debugfiles.list debuglinks.list debugsourcefiles.list debugsources.list \
elfbins.list
+%endif
%post
if [ -x /usr/bin/kernel-install ]; then
@@ -172,3 +207,9 @@ fi
/usr/src/kernels/%{KERNELRELEASE}
/lib/modules/%{KERNELRELEASE}/build
%endif
+
+%if %{with_debuginfo_manual}
+%files -f %{buildroot}/debuginfo.list debuginfo
+%defattr (-, root, root)
+%exclude /debuginfo.list
+%endif
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index c7375bfc25a9..c604f8c174e2 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -23,15 +23,47 @@ else
echo '%define with_devel 0'
fi
+# use %{debug_package} machinery to generate -debuginfo
+with_debuginfo_rpm=0
+# manually generate -debuginfo package
+with_debuginfo_manual=0
# debuginfo package generation uses find-debuginfo.sh under the hood,
# which only works on uncompressed modules that contain debuginfo
if grep -q CONFIG_DEBUG_INFO=y include/config/auto.conf &&
(! grep -q CONFIG_MODULE_COMPRESS=y include/config/auto.conf) &&
(! grep -q CONFIG_DEBUG_INFO_SPLIT=y include/config/auto.conf); then
-echo '%define with_debuginfo %{?_without_debuginfo: 0} %{?!_without_debuginfo: 1}'
-else
-echo '%define with_debuginfo 0'
+ # If module signing is enabled (which may be required to boot with
+ # lockdown enabled), the find-debuginfo.sh machinery cannot be used
+ # because the signatures will be stripped off the modules. However, due
+ # to an rpm bug in versions prior to 4.20.0
+ #
+ # https://github.com/rpm-software-management/rpm/issues/3057
+ # https://github.com/rpm-software-management/rpm/commit/49f906998f3cf1f4152162ca61ac0869251c380f
+ #
+ # We cannot provide our own debuginfo package because it does not listen
+ # to our custom files list, failing the build due to unpackaged files.
+ # Manually generate the debug info package if using rpm 4.20.0. If not
+ # using rpm 4.20.0, avoid generating a -debuginfo package altogether,
+ # as it is not safe.
+ if grep -q CONFIG_MODULE_SIG=y include/config/auto.conf; then
+ rpm_ver_str=$(rpm --version 2>/dev/null)
+ # Split the version on spaces
+ IFS=' '
+ set -- $rpm_ver_str
+ if [ "${1:-}" = RPM -a "${2:-}" = version ]; then
+ IFS=.
+ set -- $3
+ rpm_ver=$(( 1000000 * $1 + 10000 * $2 + 100 * $3 + ${4:-0} ))
+ if [ "$rpm_ver" -ge 4200000 ]; then
+ with_debuginfo_manual='%{?_without_debuginfo:0}%{?!_without_debuginfo:1}'
+ fi
+ fi
+ else
+ with_debuginfo_rpm='%{?_without_debuginfo:0}%{?!_without_debuginfo:1}'
+ fi
fi
+echo "%define with_debuginfo_manual $with_debuginfo_manual"
+echo "%define with_debuginfo_rpm $with_debuginfo_rpm"
cat<<EOF
%define ARCH ${ARCH}
diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh
index d2323de0692c..551f1ebd0dcb 100755
--- a/scripts/rust_is_available.sh
+++ b/scripts/rust_is_available.sh
@@ -121,14 +121,8 @@ fi
# Check that the Rust bindings generator is suitable.
#
# Non-stable and distributions' versions may have a version suffix, e.g. `-dev`.
-#
-# The dummy parameter `workaround-for-0.69.0` is required to support 0.69.0
-# (https://github.com/rust-lang/rust-bindgen/pull/2678) and 0.71.0
-# (https://github.com/rust-lang/rust-bindgen/pull/3040). It can be removed when
-# the minimum version is upgraded past the latter (0.69.1 and 0.71.1 both fixed
-# the issue).
rust_bindings_generator_output=$( \
- LC_ALL=C "$BINDGEN" --version workaround-for-0.69.0 2>/dev/null
+ LC_ALL=C "$BINDGEN" --version 2>/dev/null
) || rust_bindings_generator_code=$?
if [ -n "$rust_bindings_generator_code" ]; then
echo >&2 "***"
@@ -163,19 +157,6 @@ if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cvers
echo >&2 "***"
exit 1
fi
-if [ "$rust_bindings_generator_cversion" -eq 6600 ] ||
- [ "$rust_bindings_generator_cversion" -eq 6601 ]; then
- # Distributions may have patched the issue (e.g. Debian did).
- if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_0_66.h >/dev/null; then
- echo >&2 "***"
- echo >&2 "*** Rust bindings generator '$BINDGEN' versions 0.66.0 and 0.66.1 may not"
- echo >&2 "*** work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567),"
- echo >&2 "*** unless patched (like Debian's)."
- echo >&2 "*** Your version: $rust_bindings_generator_version"
- echo >&2 "***"
- warning=1
- fi
-fi
# Check that the `libclang` used by the Rust bindings generator is suitable.
#
@@ -227,21 +208,6 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then
exit 1
fi
-if [ "$bindgen_libclang_cversion" -ge 1900100 ] &&
- [ "$rust_bindings_generator_cversion" -lt 6905 ]; then
- # Distributions may have patched the issue (e.g. Debian did).
- if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_concat.h | grep -q foofoo; then
- echo >&2 "***"
- echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.69.5 together with libclang >= 19.1"
- echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2824),"
- echo >&2 "*** unless patched (like Debian's)."
- echo >&2 "*** Your bindgen version: $rust_bindings_generator_version"
- echo >&2 "*** Your libclang version: $bindgen_libclang_version"
- echo >&2 "***"
- warning=1
- fi
-fi
-
# If the C compiler is Clang, then we can also check whether its version
# matches the `libclang` version used by the Rust bindings generator.
#
diff --git a/scripts/rust_is_available_bindgen_0_66.h b/scripts/rust_is_available_bindgen_0_66.h
deleted file mode 100644
index c0431293421c..000000000000
--- a/scripts/rust_is_available_bindgen_0_66.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define A "\0"
diff --git a/scripts/rust_is_available_bindgen_libclang_concat.h b/scripts/rust_is_available_bindgen_libclang_concat.h
deleted file mode 100644
index efc6e98d0f1d..000000000000
--- a/scripts/rust_is_available_bindgen_libclang_concat.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#define F(x) int x##x
-F(foo);
diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py
index 4fcc319dea84..d6d54b7ea42a 100755
--- a/scripts/rust_is_available_test.py
+++ b/scripts/rust_is_available_test.py
@@ -54,37 +54,23 @@ else:
""")
@classmethod
- def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False, libclang_concat_patched=False):
+ def generate_bindgen(cls, version_stdout, libclang_stderr):
if libclang_stderr is None:
libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})"
else:
libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)"
- if version_0_66_patched:
- version_0_66_case = "pass"
- else:
- version_0_66_case = "raise SystemExit(1)"
-
- if libclang_concat_patched:
- libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')"
- else:
- libclang_concat_case = "pass"
-
return cls.generate_executable(f"""#!/usr/bin/env python3
import sys
if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv):
{libclang_case}
-elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv):
- {version_0_66_case}
-elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv):
- {libclang_concat_case}
else:
print({repr(version_stdout)})
""")
@classmethod
- def generate_bindgen_version(cls, stdout, version_0_66_patched=False):
- return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr, version_0_66_patched)
+ def generate_bindgen_version(cls, stdout):
+ return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr)
@classmethod
def generate_bindgen_libclang_failure(cls):
@@ -245,19 +231,6 @@ else:
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr)
- def test_bindgen_bad_version_0_66_0_and_0_66_1(self):
- for version in ("0.66.0", "0.66.1"):
- with self.subTest(version=version):
- bindgen = self.generate_bindgen_version(f"bindgen {version}")
- result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })
- self.assertIn(f"Rust bindings generator '{bindgen}' versions 0.66.0 and 0.66.1 may not", result.stderr)
-
- def test_bindgen_bad_version_0_66_0_and_0_66_1_patched(self):
- for version in ("0.66.0", "0.66.1"):
- with self.subTest(version=version):
- bindgen = self.generate_bindgen_version(f"bindgen {version}", True)
- result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen })
-
def test_bindgen_libclang_failure(self):
bindgen = self.generate_bindgen_libclang_failure()
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
@@ -275,31 +248,6 @@ else:
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr)
- def test_bindgen_bad_libclang_concat(self):
- for (bindgen_version, libclang_version, expected_not_patched) in (
- ("0.69.4", "18.0.0", self.Expected.SUCCESS),
- ("0.69.4", "19.1.0", self.Expected.SUCCESS_WITH_WARNINGS),
- ("0.69.4", "19.2.0", self.Expected.SUCCESS_WITH_WARNINGS),
-
- ("0.69.5", "18.0.0", self.Expected.SUCCESS),
- ("0.69.5", "19.1.0", self.Expected.SUCCESS),
- ("0.69.5", "19.2.0", self.Expected.SUCCESS),
-
- ("0.70.0", "18.0.0", self.Expected.SUCCESS),
- ("0.70.0", "19.1.0", self.Expected.SUCCESS),
- ("0.70.0", "19.2.0", self.Expected.SUCCESS),
- ):
- with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version):
- cc = self.generate_clang(f"clang version {libclang_version}")
- libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false"
- bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr)
- result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc })
- if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS:
- self.assertIn(f"Rust bindings generator '{bindgen}' < 0.69.5 together with libclang >= 19.1", result.stderr)
-
- bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_concat_patched=True)
- result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc })
-
def test_clang_matches_bindgen_libclang_different_bindgen(self):
bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false")
result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })
diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
index be0561049660..d61a77219a8c 100644
--- a/scripts/rustdoc_test_gen.rs
+++ b/scripts/rustdoc_test_gen.rs
@@ -174,7 +174,7 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{
macro_rules! assert {{
($cond:expr $(,)?) => {{{{
::kernel::kunit_assert!(
- "{kunit_name}", "{real_path}", __DOCTEST_ANCHOR - {line}, $cond
+ "{kunit_name}", c"{real_path}", __DOCTEST_ANCHOR - {line}, $cond
);
}}}}
}}
@@ -184,7 +184,7 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{
macro_rules! assert_eq {{
($left:expr, $right:expr $(,)?) => {{{{
::kernel::kunit_assert_eq!(
- "{kunit_name}", "{real_path}", __DOCTEST_ANCHOR - {line}, $left, $right
+ "{kunit_name}", c"{real_path}", __DOCTEST_ANCHOR - {line}, $left, $right
);
}}}}
}}
@@ -206,7 +206,7 @@ pub extern "C" fn {kunit_name}(__kunit_test: *mut ::kernel::bindings::kunit) {{
/// The anchor where the test code body starts.
#[allow(unused)]
- static __DOCTEST_ANCHOR: i32 = ::core::line!() as i32 + {body_offset} + 1;
+ static __DOCTEST_ANCHOR: i32 = ::core::line!() as i32 + {body_offset} + 2;
{{
#![allow(unreachable_pub, clippy::disallowed_names)]
{body}
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 7070245edfc1..86b010ac1514 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -24,10 +24,11 @@
#include <arpa/inet.h>
#include <openssl/opensslv.h>
#include <openssl/bio.h>
+#include <openssl/cms.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
-#if OPENSSL_VERSION_MAJOR >= 3
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
# define USE_PKCS11_PROVIDER
# include <openssl/provider.h>
# include <openssl/store.h>
@@ -39,42 +40,7 @@
#endif
#include "ssl-common.h"
-/*
- * Use CMS if we have openssl-1.0.0 or newer available - otherwise we have to
- * assume that it's not available and its header file is missing and that we
- * should use PKCS#7 instead. Switching to the older PKCS#7 format restricts
- * the options we have on specifying the X.509 certificate we want.
- *
- * Further, older versions of OpenSSL don't support manually adding signers to
- * the PKCS#7 message so have to accept that we get a certificate included in
- * the signature message. Nor do such older versions of OpenSSL support
- * signing with anything other than SHA1 - so we're stuck with that if such is
- * the case.
- */
-#if defined(LIBRESSL_VERSION_NUMBER) || \
- OPENSSL_VERSION_NUMBER < 0x10000000L || \
- defined(OPENSSL_NO_CMS)
-#define USE_PKCS7
-#endif
-#ifndef USE_PKCS7
-#include <openssl/cms.h>
-#else
-#include <openssl/pkcs7.h>
-#endif
-
-struct module_signature {
- uint8_t algo; /* Public-key crypto algorithm [0] */
- uint8_t hash; /* Digest algorithm [0] */
- uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */
- uint8_t signer_len; /* Length of signer's name [0] */
- uint8_t key_id_len; /* Length of key identifier [0] */
- uint8_t __pad[3];
- uint32_t sig_len; /* Length of signature data */
-};
-
-#define PKEY_ID_PKCS7 2
-
-static char magic_number[] = "~Module signature appended~\n";
+#include <linux/module_signature.h>
static __attribute__((noreturn))
void format(void)
@@ -219,7 +185,7 @@ static X509 *read_x509(const char *x509_name)
int main(int argc, char **argv)
{
- struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
+ struct module_signature sig_info = { .id_type = MODULE_SIGNATURE_TYPE_PKCS7 };
char *hash_algo = NULL;
char *private_key_name = NULL, *raw_sig_name = NULL;
char *x509_name, *module_name, *dest_name;
@@ -228,15 +194,10 @@ int main(int argc, char **argv)
bool raw_sig = false;
unsigned char buf[4096];
unsigned long module_size, sig_size;
- unsigned int use_signed_attrs;
const EVP_MD *digest_algo;
EVP_PKEY *private_key;
-#ifndef USE_PKCS7
CMS_ContentInfo *cms = NULL;
unsigned int use_keyid = 0;
-#else
- PKCS7 *pkcs7 = NULL;
-#endif
X509 *x509;
BIO *bd, *bm;
int opt, n;
@@ -246,21 +207,13 @@ int main(int argc, char **argv)
key_pass = getenv("KBUILD_SIGN_PIN");
-#ifndef USE_PKCS7
- use_signed_attrs = CMS_NOATTR;
-#else
- use_signed_attrs = PKCS7_NOATTR;
-#endif
-
do {
opt = getopt(argc, argv, "sdpk");
switch (opt) {
case 's': raw_sig = true; break;
case 'p': save_sig = true; break;
case 'd': sign_only = true; save_sig = true; break;
-#ifndef USE_PKCS7
case 'k': use_keyid = CMS_USE_KEYID; break;
-#endif
case -1: break;
default: format();
}
@@ -289,14 +242,6 @@ int main(int argc, char **argv)
replace_orig = true;
}
-#ifdef USE_PKCS7
- if (strcmp(hash_algo, "sha1") != 0) {
- fprintf(stderr, "sign-file: %s only supports SHA1 signing\n",
- OPENSSL_VERSION_TEXT);
- exit(3);
- }
-#endif
-
/* Open the module file */
bm = BIO_new_file(module_name, "rb");
ERR(!bm, "%s", module_name);
@@ -314,28 +259,39 @@ int main(int argc, char **argv)
digest_algo = EVP_get_digestbyname(hash_algo);
ERR(!digest_algo, "EVP_get_digestbyname");
-#ifndef USE_PKCS7
+ unsigned int flags =
+ CMS_NOCERTS |
+ CMS_NOATTR |
+ CMS_PARTIAL |
+ CMS_BINARY |
+ CMS_DETACHED |
+ CMS_STREAM |
+ CMS_NOSMIMECAP |
+#ifdef CMS_NO_SIGNING_TIME
+ CMS_NO_SIGNING_TIME |
+#endif
+ use_keyid;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L
+ if (EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-87")) {
+ /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
+ * and before.
+ */
+ flags &= ~CMS_NOATTR;
+ }
+#endif
+
/* Load the signature message from the digest buffer. */
- cms = CMS_sign(NULL, NULL, NULL, NULL,
- CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
- CMS_DETACHED | CMS_STREAM);
+ cms = CMS_sign(NULL, NULL, NULL, NULL, flags);
ERR(!cms, "CMS_sign");
- ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
- CMS_NOCERTS | CMS_BINARY |
- CMS_NOSMIMECAP | use_keyid |
- use_signed_attrs),
+ ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags),
"CMS_add1_signer");
- ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) != 1,
+ ERR(CMS_final(cms, bm, NULL, flags) != 1,
"CMS_final");
-#else
- pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
- PKCS7_NOCERTS | PKCS7_BINARY |
- PKCS7_DETACHED | use_signed_attrs);
- ERR(!pkcs7, "PKCS7_sign");
-#endif
-
if (save_sig) {
char *sig_file_name;
BIO *b;
@@ -344,13 +300,8 @@ int main(int argc, char **argv)
"asprintf");
b = BIO_new_file(sig_file_name, "wb");
ERR(!b, "%s", sig_file_name);
-#ifndef USE_PKCS7
ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) != 1,
"%s", sig_file_name);
-#else
- ERR(i2d_PKCS7_bio(b, pkcs7) != 1,
- "%s", sig_file_name);
-#endif
BIO_free(b);
}
@@ -377,11 +328,7 @@ int main(int argc, char **argv)
module_size = BIO_number_written(bd);
if (!raw_sig) {
-#ifndef USE_PKCS7
ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) != 1, "%s", dest_name);
-#else
- ERR(i2d_PKCS7_bio(bd, pkcs7) != 1, "%s", dest_name);
-#endif
} else {
BIO *b;
@@ -398,7 +345,8 @@ int main(int argc, char **argv)
sig_size = BIO_number_written(bd) - module_size;
sig_info.sig_len = htonl(sig_size);
ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);
- ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name);
+ ERR(BIO_write(bd, MODULE_SIGNATURE_MARKER, sizeof(MODULE_SIGNATURE_MARKER) - 1) < 0,
+ "%s", dest_name);
ERR(BIO_free(bd) != 1, "%s", dest_name);
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
index 1e89b92c2f9a..2f2e81dbda03 100644
--- a/scripts/spelling.txt
+++ b/scripts/spelling.txt
@@ -57,8 +57,8 @@ acknowledgement||acknowledgment
ackowledge||acknowledge
ackowledged||acknowledged
acording||according
-activete||activate
actived||activated
+activete||activate
actualy||actually
actvie||active
acumulating||accumulating
@@ -66,12 +66,12 @@ acumulative||accumulative
acumulator||accumulator
acutally||actually
adapater||adapter
+adddress||address
adderted||asserted
addional||additional
additionaly||additionally
additonal||additional
addres||address
-adddress||address
addreses||addresses
addresss||address
addrress||address
@@ -95,9 +95,9 @@ alegorical||allegorical
algined||aligned
algorith||algorithm
algorithmical||algorithmically
+algorithmn||algorithm
algoritm||algorithm
algoritms||algorithms
-algorithmn||algorithm
algorrithm||algorithm
algorritm||algorithm
aligment||alignment
@@ -128,20 +128,20 @@ amount of times||number of times
amout||amount
amplifer||amplifier
amplifyer||amplifier
-an union||a union
-an user||a user
-an userspace||a userspace
-an one||a one
analysator||analyzer
ang||and
anniversery||anniversary
annoucement||announcement
anomolies||anomalies
anomoly||anomaly
+an one||a one
anonynous||anonymous
+an union||a union
+an user||a user
+an userspace||a userspace
anway||anyway
-aplication||application
apeared||appeared
+aplication||application
appearence||appearance
applicaion||application
appliction||application
@@ -155,8 +155,8 @@ approriately||appropriately
apropriate||appropriate
aquainted||acquainted
aquired||acquired
-aquisition||acquisition
aquires||acquires
+aquisition||acquisition
arbitary||arbitrary
architechture||architecture
archtecture||architecture
@@ -189,30 +189,30 @@ assum||assume
assumtpion||assumption
asume||assume
asuming||assuming
-asycronous||asynchronous
asychronous||asynchronous
+asycronous||asynchronous
+asymetric||asymmetric
+asymmeric||asymmetric
asynchnous||asynchronous
asynchrnous||asynchronous
-asynchronus||asynchronous
asynchromous||asynchronous
-asymetric||asymmetric
-asymmeric||asymmetric
+asynchronus||asynchronous
+atempt||attempt
atleast||at least
atomatically||automatically
atomicly||atomically
-atempt||attempt
atrributes||attributes
attachement||attachment
attatch||attach
attched||attached
attemp||attempt
-attemps||attempts
attemping||attempting
+attemps||attempts
attepmpt||attempt
attnetion||attention
attruibutes||attributes
-authentification||authentication
authenicated||authenticated
+authentification||authentication
automaticaly||automatically
automaticly||automatically
automatize||automate
@@ -257,6 +257,7 @@ begining||beginning
beter||better
betweeen||between
bianries||binaries
+binded||bound
bitmast||bitmask
bitwiedh||bitwidth
boardcast||broadcast
@@ -287,19 +288,19 @@ calucate||calculate
calulate||calculate
cancelation||cancellation
cancle||cancel
-cant||can't
-cant'||can't
-canot||cannot
-cann't||can't
cannnot||cannot
+cann't||can't
+canot||cannot
+cant'||can't
+cant||can't
capabiity||capability
capabilites||capabilities
capabilties||capabilities
capabilty||capability
capabitilies||capabilities
capablity||capability
-capatibilities||capabilities
capapbilities||capabilities
+capatibilities||capabilities
captuer||capture
caputure||capture
carefuly||carefully
@@ -307,9 +308,9 @@ cariage||carriage
casued||caused
catagory||category
cehck||check
+chache||cache
challange||challenge
challanges||challenges
-chache||cache
chanell||channel
changable||changeable
chanined||chained
@@ -347,6 +348,7 @@ colescing||coalescing
collapsable||collapsible
colorfull||colorful
comand||command
+comaptible||compatible
comit||commit
commerical||commercial
comming||coming
@@ -357,10 +359,6 @@ committ||commit
commmand||command
commnunication||communication
commoditiy||commodity
-comsume||consume
-comsumer||consumer
-comsuming||consuming
-comaptible||compatible
compability||compatibility
compaibility||compatibility
comparsion||comparison
@@ -376,22 +374,25 @@ compleatly||completely
completition||completion
completly||completely
complient||compliant
-componnents||components
compoment||component
+componnents||components
comppatible||compatible
compres||compress
compresion||compression
compresser||compressor
comression||compression
+comsume||consume
comsumed||consumed
+comsumer||consumer
+comsuming||consuming
comunicate||communicate
comunication||communication
conbination||combination
concurent||concurrent
conditionaly||conditionally
conditon||condition
-condtion||condition
condtional||conditional
+condtion||condition
conected||connected
conector||connector
configed||configured
@@ -428,13 +429,13 @@ continous||continuous
continously||continuously
continueing||continuing
contiuous||continuous
-contraints||constraints
-contruct||construct
contol||control
contoller||controller
+contraints||constraints
controled||controlled
controler||controller
controll||control
+contruct||construct
contruction||construction
contry||country
conuntry||country
@@ -465,10 +466,9 @@ debouce||debounce
decendant||descendant
decendants||descendants
decompres||decompress
-decsribed||described
decrese||decrease
decription||description
-detault||default
+decsribed||described
dectected||detected
defailt||default
deferal||deferral
@@ -482,9 +482,9 @@ defintion||definition
defintions||definitions
defualt||default
defult||default
-deintializing||deinitializing
-deintialize||deinitialize
deintialized||deinitialized
+deintialize||deinitialize
+deintializing||deinitializing
deivce||device
delared||declared
delare||declare
@@ -494,8 +494,8 @@ delemiter||delimiter
deley||delay
delibrately||deliberately
delievered||delivered
-demodualtor||demodulator
demension||dimension
+demodualtor||demodulator
dependancies||dependencies
dependancy||dependency
dependant||dependent
@@ -505,15 +505,15 @@ depreacte||deprecate
desactivate||deactivate
desciptor||descriptor
desciptors||descriptors
-descritpor||descriptor
descripto||descriptor
descripton||description
descrition||description
+descritpor||descriptor
descritptor||descriptor
desctiptor||descriptor
+desination||destination
desriptor||descriptor
desriptors||descriptors
-desination||destination
destionation||destination
destoried||destroyed
destory||destroy
@@ -521,6 +521,7 @@ destoryed||destroyed
destorys||destroys
destroied||destroyed
detabase||database
+detault||default
deteced||detected
detecion||detection
detectt||detect
@@ -535,55 +536,54 @@ deveolpment||development
devided||divided
deviece||device
devision||division
-diable||disable
diabled||disabled
+diable||disable
dicline||decline
+diconnected||disconnected
dictionnary||dictionary
didnt||didn't
diferent||different
-differrence||difference
-diffrent||different
differenciate||differentiate
+differrence||difference
diffreential||differential
+diffrent||different
diffrentiate||differentiate
difinition||definition
digial||digital
dimention||dimension
dimesions||dimensions
-diconnected||disconnected
-disabed||disabled
-disasembler||disassembler
-disble||disable
-disgest||digest
-disired||desired
-dispalying||displaying
-dissable||disable
-dissapeared||disappeared
diplay||display
-directon||direction
direcly||directly
+directon||direction
direectly||directly
diregard||disregard
-disassocation||disassociation
-disassocative||disassociative
+disabed||disabled
disapear||disappear
disapeared||disappeared
disappared||disappeared
-disbale||disable
+disasembler||disassembler
+disassocation||disassociation
+disassocative||disassociative
disbaled||disabled
-disble||disable
+disbale||disable
disbled||disabled
+disble||disable
+disble||disable
disconnet||disconnect
discontinous||discontinuous
+disgest||digest
disharge||discharge
+disired||desired
disnabled||disabled
+dispalying||displaying
dispertion||dispersion
+dissable||disable
+dissapeared||disappeared
dissapears||disappears
dissconect||disconnect
distiction||distinction
divisable||divisible
divsiors||divisors
-dsiabled||disabled
docuentation||documentation
documantation||documentation
documentaion||documentation
@@ -598,6 +598,7 @@ downlads||downloads
droped||dropped
droput||dropout
druing||during
+dsiabled||disabled
dyanmic||dynamic
dynmaic||dynamic
eanable||enable
@@ -621,20 +622,20 @@ enble||enable
enchanced||enhanced
encorporating||incorporating
encrupted||encrypted
-encrypiton||encryption
encryped||encrypted
+encrypiton||encryption
encryptio||encryption
endianess||endianness
-enpoint||endpoint
enhaced||enhanced
enlightnment||enlightenment
+enocded||encoded
+enought||enough
+enpoint||endpoint
enqueing||enqueuing
+enterily||entirely
entires||entries
entites||entities
entrys||entries
-enocded||encoded
-enought||enough
-enterily||entirely
enviroiment||environment
enviroment||environment
environement||environment
@@ -653,8 +654,9 @@ evalute||evaluate
evalutes||evaluates
evalution||evaluation
evaulated||evaluated
-excecutable||executable
+exaclty||exactly
excceed||exceed
+excecutable||executable
exceded||exceeded
exceds||exceeds
exceeed||exceed
@@ -668,41 +670,41 @@ exeuction||execution
existance||existence
existant||existent
exixt||exist
-exsits||exists
exlcude||exclude
exlcuding||excluding
exlcusive||exclusive
-exlusive||exclusive
exlicitly||explicitly
+exlusive||exclusive
exmaple||example
expecially||especially
experies||expires
explicite||explicit
-explicity||explicitly
explicitely||explicitly
-explict||explicit
+explicity||explicitly
explictely||explicitly
+explict||explicit
explictly||explicitly
expresion||expression
exprienced||experienced
exprimental||experimental
-extened||extended
+exsits||exists
exteneded||extended
+extened||extended
extensability||extensibility
-extention||extension
extenstion||extension
+extention||extension
extracter||extractor
faied||failed
faield||failed
-faild||failed
failded||failed
+faild||failed
failer||failure
-faill||fail
failied||failed
+faill||fail
faillure||failure
+failng||failing
failue||failure
failuer||failure
-failng||failing
faireness||fairness
falied||failed
faliure||failure
@@ -717,15 +719,15 @@ fetcing||fetching
fileystem||filesystem
fimrware||firmware
fimware||firmware
+finanize||finalize
+findn||find
+finilizes||finalizes
+finsih||finish
firmare||firmware
firmaware||firmware
firtly||firstly
firware||firmware
firwmare||firmware
-finanize||finalize
-findn||find
-finilizes||finalizes
-finsih||finish
fliter||filter
flusing||flushing
folloing||following
@@ -742,9 +744,9 @@ forwared||forwarded
frambuffer||framebuffer
framming||framing
framwork||framework
+frequancy||frequency
frequence||frequency
frequncy||frequency
-frequancy||frequency
frome||from
fronend||frontend
fucntion||function
@@ -766,9 +768,9 @@ gatable||gateable
gateing||gating
gauage||gauge
gaurenteed||guaranteed
-generiously||generously
genereate||generate
genereted||generated
+generiously||generously
genric||generic
gerenal||general
geting||getting
@@ -790,18 +792,17 @@ hanlde||handle
hanled||handled
happend||happened
hardare||hardware
-harware||hardware
hardward||hardware
+harware||hardware
havind||having
+hearbeat||heartbeat
heigth||height
+heirachy||hierarchy
heirarchically||hierarchically
heirarchy||hierarchy
-heirachy||hierarchy
helpfull||helpful
-hearbeat||heartbeat
heterogenous||heterogeneous
hexdecimal||hexadecimal
-hybernate||hibernate
hiearchy||hierarchy
hierachy||hierarchy
hierarchie||hierarchy
@@ -809,14 +810,14 @@ homogenous||homogeneous
horizental||horizontal
howver||however
hsould||should
+hybernate||hibernate
hypervior||hypervisor
hypter||hyper
idel||idle
identidier||identifier
iligal||illegal
-illigal||illegal
illgal||illegal
-iomaped||iomapped
+illigal||illegal
imblance||imbalance
immeadiately||immediately
immedaite||immediate
@@ -831,13 +832,14 @@ implemantation||implementation
implemenation||implementation
implementaiton||implementation
implementated||implemented
-implemention||implementation
implementd||implemented
+implemention||implementation
implemetation||implementation
implemntation||implementation
implentation||implementation
implmentation||implementation
implmenting||implementing
+inavlid||invalid
incative||inactive
incomming||incoming
incompaitiblity||incompatibility
@@ -869,9 +871,9 @@ infromation||information
ingore||ignore
inheritence||inheritance
inital||initial
-initalized||initialized
initalised||initialized
initalise||initialize
+initalized||initialized
initalize||initialize
initation||initiation
initators||initiators
@@ -879,20 +881,20 @@ initialiazation||initialization
initializationg||initialization
initializiation||initialization
initializtion||initialization
-initialze||initialize
initialzed||initialized
+initialze||initialize
initialzing||initializing
initilization||initialization
+initilized||initialized
initilize||initialize
initliaze||initialize
-initilized||initialized
inofficial||unofficial
inrerface||interface
insititute||institute
instace||instance
instal||install
-instanciate||instantiate
instanciated||instantiated
+instanciate||instantiate
instuments||instruments
insufficent||insufficient
intead||instead
@@ -911,16 +913,16 @@ intergrated||integrated
intermittant||intermittent
internel||internal
interoprability||interoperability
-interuupt||interrupt
-interupt||interrupt
-interupts||interrupts
-interurpt||interrupt
interrface||interface
interrrupt||interrupt
interrup||interrupt
interrups||interrupts
interruptted||interrupted
interupted||interrupted
+interupt||interrupt
+interupts||interrupts
+interurpt||interrupt
+interuupt||interrupt
intiailized||initialized
intial||initial
intialisation||initialisation
@@ -934,18 +936,18 @@ intrerrupt||interrupt
intrrupt||interrupt
intterrupt||interrupt
intuative||intuitive
-inavlid||invalid
invaid||invalid
invaild||invalid
invailid||invalid
-invald||invalid
invalde||invalid
+invald||invalid
invalide||invalid
invalidiate||invalidate
invalud||invalid
invididual||individual
invokation||invocation
invokations||invocations
+iomaped||iomapped
ireelevant||irrelevant
irrelevent||irrelevant
isnt||isn't
@@ -991,11 +993,11 @@ losted||lost
maangement||management
machinary||machinery
maibox||mailbox
+mailformed||malformed
maintainance||maintenance
maintainence||maintenance
maintan||maintain
makeing||making
-mailformed||malformed
malplaced||misplaced
malplace||misplace
managable||manageable
@@ -1005,21 +1007,22 @@ mangement||management
manger||manager
manoeuvering||maneuvering
manufaucturing||manufacturing
-mappping||mapping
maping||mapping
+mappping||mapping
matchs||matches
mathimatical||mathematical
mathimatic||mathematic
mathimatics||mathematics
-maxmium||maximum
maximium||maximum
maxium||maximum
+maxmium||maximum
mechamism||mechanism
mechanim||mechanism
meetign||meeting
memeory||memory
memmber||member
memoery||memory
+memomry||memory
memroy||memory
ment||meant
mergable||mergeable
@@ -1036,19 +1039,19 @@ migrateable||migratable
miliseconds||milliseconds
millenium||millennium
milliseonds||milliseconds
-minimim||minimum
-minium||minimum
minimam||minimum
+minimim||minimum
minimun||minimum
+minium||minimum
miniumum||minimum
minumum||minimum
misalinged||misaligned
miscelleneous||miscellaneous
misformed||malformed
-mispelled||misspelled
-mispelt||misspelt
mising||missing
mismactch||mismatch
+mispelled||misspelled
+mispelt||misspelt
missign||missing
missmanaged||mismanaged
missmatch||mismatch
@@ -1061,18 +1064,17 @@ modifer||modifier
modul||module
modulues||modules
momery||memory
-memomry||memory
monitring||monitoring
monochorome||monochrome
monochromo||monochrome
monocrome||monochrome
mopdule||module
mroe||more
-mulitplied||multiplied
muliple||multiple
-multipler||multiplier
+mulitplied||multiplied
multidimensionnal||multidimensional
multipe||multiple
+multipler||multiplier
multple||multiple
mumber||number
muticast||multicast
@@ -1094,6 +1096,7 @@ nerver||never
nescessary||necessary
nessessary||necessary
none existent||non-existent
+notfify||notify
noticable||noticeable
notication||notification
notications||notifications
@@ -1101,7 +1104,6 @@ notifcations||notifications
notifed||notified
notifer||notifier
notity||notify
-notfify||notify
nubmer||number
numebr||number
numer||number
@@ -1119,10 +1121,10 @@ occurence||occurrence
occure||occurred
occuring||occurring
ocurrence||occurrence
-offser||offset
offet||offset
offlaod||offload
offloded||offloaded
+offser||offset
offseting||offsetting
oflload||offload
omited||omitted
@@ -1141,25 +1143,25 @@ optionnal||optional
optmizations||optimizations
orientatied||orientated
orientied||oriented
-orignal||original
originial||original
+orignal||original
orphanded||orphaned
otherise||otherwise
ouput||output
oustanding||outstanding
+oveflow||overflow
overaall||overall
+overflw||overflow
overhread||overhead
+overide||override
overlaping||overlapping
-oveflow||overflow
-overflw||overflow
overlfow||overflow
-overide||override
overrided||overridden
overriden||overridden
overrrun||overrun
overun||overrun
-overwritting||overwriting
overwriten||overwritten
+overwritting||overwriting
pacakge||package
pachage||package
packacge||package
@@ -1169,11 +1171,11 @@ packtes||packets
pakage||package
paket||packet
pallette||palette
-paln||plan
palne||plane
+paln||plan
paramameters||parameters
-paramaters||parameters
paramater||parameter
+paramaters||parameters
paramenters||parameters
parametes||parameters
parametised||parametrised
@@ -1241,8 +1243,6 @@ prefered||preferred
prefferably||preferably
prefitler||prefilter
preform||perform
-previleged||privileged
-previlege||privilege
premption||preemption
prepaired||prepared
prepate||prepare
@@ -1250,6 +1250,8 @@ preperation||preparation
preprare||prepare
pressre||pressure
presuambly||presumably
+previleged||privileged
+previlege||privilege
previosuly||previously
previsously||previously
primative||primitive
@@ -1258,17 +1260,17 @@ priorty||priority
priting||printing
privilaged||privileged
privilage||privilege
-priviledge||privilege
priviledged||privileged
+priviledge||privilege
priviledges||privileges
privleges||privileges
-probaly||probably
probabalistic||probabilistic
+probaly||probably
procceed||proceed
proccesors||processors
procesed||processed
-proces||process
procesing||processing
+proces||process
processessing||processing
processess||processes
processpr||processor
@@ -1288,6 +1290,7 @@ progresss||progress
prohibitted||prohibited
prohibitting||prohibiting
promiscous||promiscuous
+promixity||proximity
promps||prompts
pronnounced||pronounced
prononciation||pronunciation
@@ -1296,15 +1299,14 @@ pronunce||pronounce
propery||property
propigate||propagate
propigation||propagation
-propogation||propagation
propogate||propagate
+propogation||propagation
prosess||process
protable||portable
protcol||protocol
protecion||protection
protedcted||protected
protocoll||protocol
-promixity||proximity
psudo||pseudo
psuedo||pseudo
psychadelic||psychedelic
@@ -1333,8 +1335,8 @@ recieves||receives
recieving||receiving
recogniced||recognised
recognizeable||recognizable
-recompte||recompute
recommanded||recommended
+recompte||recompute
recyle||recycle
redect||reject
redircet||redirect
@@ -1344,8 +1346,8 @@ reename||rename
refcounf||refcount
refence||reference
refered||referred
-referencce||reference
referenace||reference
+referencce||reference
refererence||reference
refering||referring
refernces||references
@@ -1353,8 +1355,8 @@ refernnce||reference
refrence||reference
regiser||register
registed||registered
-registerd||registered
registeration||registration
+registerd||registered
registeresd||registered
registerred||registered
registes||registers
@@ -1371,8 +1373,8 @@ reloade||reload
remoote||remote
remore||remote
removeable||removable
-repective||respective
repectively||respectively
+repective||respective
replacable||replaceable
replacments||replacements
replys||replies
@@ -1389,8 +1391,8 @@ requieres||requires
requirment||requirement
requred||required
requried||required
-requst||request
requsted||requested
+requst||request
reregisteration||reregistration
reseting||resetting
reseved||reserved
@@ -1412,11 +1414,11 @@ retransmited||retransmitted
retreived||retrieved
retreive||retrieve
retreiving||retrieving
-retrive||retrieve
retrived||retrieved
+retrive||retrieve
retrun||return
-retun||return
retuned||returned
+retun||return
reudce||reduce
reuest||request
reuqest||request
@@ -1464,9 +1466,9 @@ seperate||separate
seperatly||separately
seperator||separator
sepperate||separate
-seqeunce||sequence
-seqeuncer||sequencer
seqeuencer||sequencer
+seqeuncer||sequencer
+seqeunce||sequence
sequece||sequence
sequemce||sequence
sequencial||sequential
@@ -1505,8 +1507,8 @@ soley||solely
soluation||solution
souce||source
speach||speech
-specfic||specific
specfication||specification
+specfic||specific
specfield||specified
speciefied||specified
specifc||specific
@@ -1515,8 +1517,8 @@ specificatin||specification
specificaton||specification
specificed||specified
specifing||specifying
-specifiy||specify
specifiying||specifying
+specifiy||specify
speficied||specified
speicify||specify
speling||spelling
@@ -1543,23 +1545,23 @@ stoppped||stopped
straming||streaming
struc||struct
structres||structures
-stuct||struct
strucuture||structure
+stuct||struct
stucture||structure
sturcture||structure
subdirectoires||subdirectories
suble||subtle
-substract||subtract
submited||submitted
submition||submission
+substract||subtract
succeded||succeeded
-suceed||succeed
-succesfuly||successfully
succesfully||successfully
succesful||successful
+succesfuly||successfully
successed||succeeded
successfull||successful
successfuly||successfully
+suceed||succeed
sucessfully||successfully
sucessful||successful
sucess||success
@@ -1568,9 +1570,9 @@ superseeded||superseded
suplied||supplied
suported||supported
suport||support
-supportet||supported
suppored||supported
supporing||supporting
+supportet||supported
supportin||supporting
suppoted||supported
suppported||supported
@@ -1581,27 +1583,27 @@ surpressed||suppressed
surpresses||suppresses
susbsystem||subsystem
suspeneded||suspended
-suspsend||suspend
suspicously||suspiciously
+suspsend||suspend
swaping||swapping
switchs||switches
-swith||switch
swithable||switchable
-swithc||switch
swithced||switched
swithcing||switching
+swithc||switch
swithed||switched
swithing||switching
+swith||switch
swtich||switch
+sychronization||synchronization
+sychronously||synchronously
syfs||sysfs
symetric||symmetric
synax||syntax
synchonized||synchronized
-sychronization||synchronization
-sychronously||synchronously
synchronuously||synchronously
-syncronize||synchronize
syncronized||synchronized
+syncronize||synchronize
syncronizing||synchronizing
syncronus||synchronous
syste||system
@@ -1610,16 +1612,17 @@ sythesis||synthesis
tagert||target
taht||that
tained||tainted
-tarffic||traffic
+tansition||transition
tansmit||transmit
+tarffic||traffic
targetted||targeted
targetting||targeting
taskelt||tasklet
teh||the
temeprature||temperature
temorary||temporary
-temproarily||temporarily
temperture||temperature
+temproarily||temporarily
theads||threads
therfore||therefore
thier||their
@@ -1629,23 +1632,20 @@ threshhold||threshold
thresold||threshold
throtting||throttling
throught||through
-tansition||transition
-trackling||tracking
-troughput||throughput
-trys||tries
thses||these
-tiggers||triggers
tiggered||triggered
tiggerring||triggering
-tipically||typically
+tiggers||triggers
timeing||timing
timming||timing
timout||timeout
+tipically||typically
tmis||this
tolarance||tolerance
toogle||toggle
torerable||tolerable
torlence||tolerance
+trackling||tracking
traget||target
traking||tracking
tramsmitted||transmitted
@@ -1669,20 +1669,20 @@ trasfer||transfer
trasmission||transmission
trasmitter||transmitter
treshold||threshold
-trigged||triggered
-triggerd||triggered
trigerred||triggered
trigerring||triggering
+trigged||triggered
+triggerd||triggered
+troughput||throughput
trun||turn
+trys||tries
tunning||tuning
ture||true
tyep||type
udpate||update
-updtes||updates
uesd||used
-unknwon||unknown
uknown||unknown
-usccess||success
+unamed||unnamed
uncommited||uncommitted
uncompatible||incompatible
uncomressed||uncompressed
@@ -1691,6 +1691,7 @@ undeflow||underflow
undelying||underlying
underun||underrun
unecessary||unnecessary
+uneeded||unneeded
unexecpted||unexpected
unexepected||unexpected
unexpcted||unexpected
@@ -1699,26 +1700,24 @@ unexpeted||unexpected
unexpexted||unexpected
unfortunatelly||unfortunately
unifiy||unify
-uniterrupted||uninterrupted
uninterruptable||uninterruptible
unintialized||uninitialized
+uniterrupted||uninterrupted
unitialized||uninitialized
unkmown||unknown
unknonw||unknown
unknouwn||unknown
unknow||unknown
+unknwon||unknown
unkown||unknown
-unamed||unnamed
-uneeded||unneeded
-unneded||unneeded
+unmached||unmatched
unneccecary||unnecessary
unneccesary||unnecessary
unneccessary||unnecessary
unnecesary||unnecessary
+unneded||unneeded
unneedingly||unnecessarily
unnsupported||unsupported
-unuspported||unsupported
-unmached||unmatched
unprecise||imprecise
unpriviledged||unprivileged
unpriviliged||unprivileged
@@ -1726,18 +1725,21 @@ unregester||unregister
unresgister||unregister
unrgesiter||unregister
unsinged||unsigned
-unstabel||unstable
-unsolicted||unsolicited
unsolicitied||unsolicited
+unsolicted||unsolicited
+unstabel||unstable
unsuccessfull||unsuccessful
unsuported||unsupported
untill||until
ununsed||unused
unuseful||useless
+unuspported||unsupported
unvalid||invalid
upate||update
+updtes||updates
upsupported||unsupported
upto||up to
+usccess||success
useable||usable
usefule||useful
usefull||useful
@@ -1759,14 +1761,14 @@ variantions||variations
varible||variable
varient||variant
vaule||value
-verbse||verbose
veify||verify
+verbse||verbose
verfication||verification
veriosn||version
-versoin||version
verisons||versions
verison||version
veritical||vertical
+versoin||version
verson||version
vicefersa||vice-versa
virtal||virtual
@@ -1779,13 +1781,13 @@ wakeus||wakeups
was't||wasn't
wathdog||watchdog
wating||waiting
-wiat||wait
wether||whether
whataver||whatever
whcih||which
whenver||whenever
wheter||whether
whe||when
+wiat||wait
wierd||weird
wihout||without
wiil||will
diff --git a/scripts/syscall.tbl b/scripts/syscall.tbl
index e74868be513c..7a42b32b6577 100644
--- a/scripts/syscall.tbl
+++ b/scripts/syscall.tbl
@@ -411,3 +411,4 @@
468 common file_getattr sys_file_getattr
469 common file_setattr sys_file_setattr
470 common listns sys_listns
+471 common rseq_slice_yield sys_rseq_slice_yield
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 99ce427d9a69..243373683f98 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -221,6 +221,7 @@ regex_c=(
'/^\<DEFINE_GUARD_COND(\([[:alnum:]_]\+\),[[:space:]]*\([[:alnum:]_]\+\)/class_\1\2/'
'/^\<DEFINE_LOCK_GUARD_[[:digit:]](\([[:alnum:]_]\+\)/class_\1/'
'/^\<DEFINE_LOCK_GUARD_[[:digit:]]_COND(\([[:alnum:]_]\+\),[[:space:]]*\([[:alnum:]_]\+\)/class_\1\2/'
+ '/^context_lock_struct(\([^,)]*\)[^)]*)/struct \1/'
)
regex_kconfig=(
'/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/'
diff --git a/scripts/timer_migration_tree.py b/scripts/timer_migration_tree.py
new file mode 100755
index 000000000000..faac9de854bd
--- /dev/null
+++ b/scripts/timer_migration_tree.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+Draw the timer migration tree.
+
+1) Boot with trace_event==tmigr_connect_cpu_parent,tmigr_connect_child_parent
+2) ./timer_migration_tree.py < /sys/kernel/tracing/trace
+"""
+
+import re, sys
+from ete3 import Tree
+
+class Node:
+ def __init__(self, group):
+ self.group = group
+ self.children = []
+ self.parent = None
+ self.num_children = 0
+ self.groupmask = 0
+ self.lvl = -1
+
+ def set_groupmask(self, groupmask):
+ self.groupmask = groupmask
+
+ def set_parent(self, parent):
+ self.parent = parent
+
+ def add_child(self, child):
+ self.children.append(child)
+
+ def set_lvl(self, lvl):
+ self.lvl = lvl
+
+ def set_numa(self, numa):
+ self.numa = numa
+
+ def set_num_children(self, num_children):
+ self.num_children = num_children
+
+ def __repr__(self):
+ if self.parent:
+ parent_grp = self.parent.group
+ else:
+ parent_grp = "-"
+ return "Group: %s mask: %s parent: %s lvl: %d numa: %d num_children: %d" % (self.group, self.groupmask, parent_grp, self.lvl, self.numa, self.num_children)
+
+hierarchies = { }
+
+def get_hierarchy(capacity):
+ if capacity not in hierarchies:
+ hierarchies[capacity] = {}
+ return hierarchies[capacity]
+
+def get_node(capacity, group):
+ hier = get_hierarchy(capacity)
+ if group in hier:
+ return hier[group]
+ else:
+ n = Node(group)
+ hier[group] = n
+ return n
+
+def tmigr_connect_cpu_parent(ts, line):
+ s = re.search("tmigr_connect_cpu_parent: cpu=([0-9]+) groupmask=([0-9a-zA-Z]+) parent=([0-9a-zA-Z]+) lvl=([0-9]+) numa=([-]?[0-9]+) capacity=([-]?[0-9]+) num_children=([0-9]+)", line)
+ if s is None:
+ return False
+ (cpu, groupmask, parent, lvl, numa, capacity, num_children) = (int(s.group(1)), s.group(2), s.group(3), int(s.group(4)), int(s.group(5)), int(s.group(6)), int(s.group(7)))
+ n = get_node(capacity, cpu)
+ p = get_node(capacity, parent)
+ n.set_parent(p)
+ n.set_groupmask(groupmask)
+ n.set_lvl(-1)
+ p.set_lvl(lvl)
+ p.set_numa(numa)
+ n.set_numa(numa)
+ p.set_num_children(num_children)
+ p.add_child(n)
+
+def tmigr_connect_child_parent(ts, line):
+ s = re.search("tmigr_connect_child_parent: group=([0-9a-zA-Z]+) groupmask=([0-9a-zA-Z]+) parent=([0-9a-zA-Z]+) lvl=([0-9]+) numa=([-]?[0-9]+) capacity=([-]?[0-9]+) num_children=([0-9]+)", line)
+ if s is None:
+ return False
+ (group, groupmask, parent, lvl, numa, capacity, num_children) = (s.group(1), s.group(2), s.group(3), int(s.group(4)), int(s.group(5)), int(s.group(6)), int(s.group(7)))
+ n = get_node(capacity, group)
+ p = get_node(capacity, parent)
+ n.set_parent(p)
+ n.set_groupmask(groupmask)
+ p.set_lvl(lvl)
+ p.set_numa(numa)
+ p.set_num_children(num_children)
+ p.add_child(n)
+
+def populate(enode, node):
+ enode = enode.add_child(name = node.group)
+ enode.add_feature("groupmask", "m:%s" % node.groupmask)
+ enode.add_feature("lvl", "lvl:%d" % node.lvl)
+ enode.add_feature("numa", "node %d" % node.numa)
+ enode.add_feature("num_children", "c=%d" % node.num_children)
+ for child in node.children:
+ populate(enode, child)
+
+if __name__ == "__main__":
+ for line in sys.stdin:
+ s = re.search("([0-9]+[.][0-9]{6}): (.+?)$", line, re.S)
+ if s is not None:
+ if tmigr_connect_cpu_parent(float(s.group(1)), s.group(2)):
+ continue
+ if tmigr_connect_child_parent(float(s.group(1)), s.group(2)):
+ continue
+
+ for cap in hierarchies:
+ h = hierarchies[cap]
+ print("Tree for capacity %d" % cap)
+ for k in h:
+ n = h[k]
+ while n.parent != None:
+ n = n.parent
+ root = Tree()
+ populate(root, n)
+ print(root.get_ascii(show_internal=True, attributes=["name", "numa", "lvl"]))
+ break
diff --git a/scripts/ver_linux b/scripts/ver_linux
index d6f2362d3792..00bdaf30d590 100755
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -7,7 +7,7 @@
BEGIN {
usage = "If some fields are empty or look unusual you may have an old version.\n"
- usage = usage "Compare to the current minimal requirements in Documentation/Changes.\n"
+ usage = usage "Compare to the current minimal requirements in Documentation/process/changes.rst\n"
print usage
system("uname -a")
@@ -17,37 +17,58 @@ BEGIN {
libc = "libc[.]so[.][0-9]+$"
libcpp = "(libg|stdc)[+]+[.]so([.][0-9]+)+$"
+ printversion("bash", version("bash --version"))
+ printversion("bc", version("bc --version"))
+ printversion("bindgen", version("bindgen --version"))
+ printversion("binutils", version("ld -v"))
+ printversion("bison", version("bison --version"))
+ printversion("btrfs-progs", version("btrfs --version"))
+ printversion("Clang", version("clang --version"))
+ printversion("Console-tools", version("loadkeys -V"))
+ printversion("Dynamic linker (ldd)", version("ldd --version"))
+ printversion("e2fsprogs", version("e2fsck -V"))
+ printversion("flex", version("flex --version"))
+ printversion("gdb", version("gdb -version"))
+ printversion("GNU awk", version("gawk --version"))
printversion("GNU C", version("gcc -dumpversion"))
- printversion("GNU Make", version("make --version"))
- printversion("Binutils", version("ld -v"))
- printversion("Util-linux", version("mount --version"))
- printversion("Mount", version("mount --version"))
- printversion("Module-init-tools", version("depmod -V"))
- printversion("E2fsprogs", version("tune2fs"))
- printversion("Jfsutils", version("fsck.jfs -V"))
- printversion("Xfsprogs", version("xfs_db -V"))
- printversion("Pcmciautils", version("pccardctl -V"))
- printversion("Pcmcia-cs", version("cardmgr -V"))
- printversion("Quota-tools", version("quota -V"))
- printversion("PPP", version("pppd --version"))
+ printversion("GNU make", version("make --version"))
+ printversion("GNU tar", version("tar --version"))
+ printversion("GRUB2", version("grub2-install --version"))
+ printversion("GRUB", version("grub-install --version"))
+ printversion("gtags", version("gtags --version"))
+ printversion("iptables", version("iptables -V"))
printversion("Isdn4k-utils", version("isdnctrl"))
- printversion("Nfs-utils", version("showmount --version"))
- printversion("Bison", version("bison --version"))
- printversion("Flex", version("flex --version"))
+ printversion("jfsutils", version("fsck.jfs -V"))
+ printversion("Kbd", version("loadkeys -V"))
+ printversion("kmod", version("kmod -V"))
while ("ldconfig -p 2>/dev/null" | getline > 0)
if ($NF ~ libc || $NF ~ libcpp)
if (!seen[ver = version("readlink " $NF)]++)
printversion("Linux C" ($NF ~ libcpp? "++" : "") " Library", ver)
- printversion("Dynamic linker (ldd)", version("ldd --version"))
- printversion("Procps", version("ps --version"))
+ printversion("mcelog", version("mcelog --version"))
+ printversion("mkimage", version("mkimage --version"))
+ printversion("Module-init-tools", version("depmod -V"))
+ printversion("Mount", version("mount --version"))
printversion("Net-tools", version("ifconfig --version"))
- printversion("Kbd", version("loadkeys -V"))
- printversion("Console-tools", version("loadkeys -V"))
+ printversion("nfs-utils", version("showmount --version"))
+ printversion("openssl", version("openssl version"))
+ printversion("pahole", version("pahole --version"))
+ printversion("Pcmcia-cs", version("cardmgr -V"))
+ printversion("pcmciautils", version("pccardctl -V"))
+ printversion("PPP", version("pppd --version"))
+ printversion("procps", version("ps --version"))
+ printversion("Python", version("python3 -V"))
+ printversion("quota-tools", version("quota -V"))
+ printversion("Rust", version("rustc --version"))
printversion("Sh-utils", version("expr --v"))
- printversion("Udev", version("udevadm --version"))
+ printversion("Sphinx", version("sphinx-build --version"))
+ printversion("squashfs-tools", version("mksquashfs -version"))
+ printversion("udev", version("udevadm --version"))
+ printversion("util-linux", version("mount --version"))
printversion("Wireless-tools", version("iwconfig --version"))
+ printversion("xfsprogs", version("xfs_db -V"))
while ("sort /proc/modules" | getline > 0) {
mods = mods sep $1