summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-11-30 13:41:50 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2024-11-30 13:41:50 -0800
commit6a34dfa15d6edf7e78b8118d862d2db0889cf669 (patch)
treef5bc36ccaa5251fa660cf2efdb00d6ffa3ace36b
parent0e287d31b62bb53ad81d5e59778384a40f8b6f56 (diff)
parente6064da6461f989a357f2e280d7f8d4155267c4c (diff)
Merge tag 'kbuild-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild
Pull Kbuild updates from Masahiro Yamada: - Add generic support for built-in boot DTB files - Enable TAB cycling for dialog buttons in nconfig - Fix issues in streamline_config.pl - Refactor Kconfig - Add support for Clang's AutoFDO (Automatic Feedback-Directed Optimization) - Add support for Clang's Propeller, a profile-guided optimization. - Change the working directory to the external module directory for M= builds - Support building external modules in a separate output directory - Enable objtool for *.mod.o and additional kernel objects - Use lz4 instead of deprecated lz4c - Work around a performance issue with "git describe" - Refactor modpost * tag 'kbuild-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild: (85 commits) kbuild: rename .tmp_vmlinux.kallsyms0.syms to .tmp_vmlinux0.syms gitignore: Don't ignore 'tags' directory kbuild: add dependency from vmlinux to resolve_btfids modpost: replace tdb_hash() with hash_str() kbuild: deb-pkg: add python3:native to build dependency genksyms: reduce indentation in export_symbol() modpost: improve error messages in device_id_check() modpost: rename alias symbol for MODULE_DEVICE_TABLE() modpost: rename variables in handle_moddevtable() modpost: move strstarts() to modpost.h modpost: convert do_usb_table() to a generic handler modpost: convert do_of_table() to a generic handler modpost: convert do_pnp_device_entry() to a generic handler modpost: convert do_pnp_card_entries() to a generic handler modpost: call module_alias_printf() from all do_*_entry() functions modpost: pass (struct module *) to do_*_entry() functions modpost: remove DEF_FIELD_ADDR_VAR() macro modpost: deduplicate MODULE_ALIAS() for all drivers modpost: introduce module_alias_printf() helper modpost: remove unnecessary check in do_acpi_entry() ...
-rw-r--r--.gitignore1
-rw-r--r--Documentation/dev-tools/autofdo.rst168
-rw-r--r--Documentation/dev-tools/coccinelle.rst22
-rw-r--r--Documentation/dev-tools/index.rst2
-rw-r--r--Documentation/dev-tools/propeller.rst162
-rw-r--r--Documentation/kbuild/kbuild.rst8
-rw-r--r--Documentation/kbuild/kconfig-language.rst4
-rw-r--r--Documentation/kbuild/makefiles.rst14
-rw-r--r--Documentation/kbuild/modules.rst29
-rw-r--r--MAINTAINERS14
-rw-r--r--Makefile223
-rw-r--r--arch/Kconfig39
-rw-r--r--arch/arm/Makefile4
-rw-r--r--arch/arm64/Makefile2
-rw-r--r--arch/mips/kernel/head.S1
-rw-r--r--arch/mips/kernel/vmlinux.lds.S1
-rw-r--r--arch/powerpc/Makefile6
-rw-r--r--arch/riscv/Makefile2
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S5
-rw-r--r--arch/x86/Kconfig2
-rw-r--r--arch/x86/kernel/vmlinux.lds.S4
-rw-r--r--drivers/accessibility/speakup/Makefile4
-rw-r--r--drivers/of/Kconfig6
-rw-r--r--drivers/usb/dwc2/Kconfig2
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/isp1760/Kconfig2
-rw-r--r--drivers/usb/mtu3/Kconfig2
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--include/asm-generic/vmlinux.lds.h53
-rw-r--r--include/linux/mmdebug.h6
-rw-r--r--include/linux/module.h2
-rw-r--r--include/linux/once.h4
-rw-r--r--include/linux/once_lite.h2
-rw-r--r--include/linux/rcupdate.h2
-rw-r--r--include/net/net_debug.h2
-rw-r--r--mm/internal.h2
-rw-r--r--rust/Makefile4
-rw-r--r--scripts/Kbuild.include2
-rw-r--r--scripts/Makefile.autofdo24
-rw-r--r--scripts/Makefile.build59
-rw-r--r--scripts/Makefile.clean2
-rw-r--r--scripts/Makefile.compiler2
-rw-r--r--scripts/Makefile.host8
-rw-r--r--scripts/Makefile.lib62
-rw-r--r--scripts/Makefile.modfinal31
-rw-r--r--scripts/Makefile.modinst8
-rw-r--r--scripts/Makefile.modpost24
-rw-r--r--scripts/Makefile.propeller39
-rw-r--r--scripts/Makefile.vmlinux51
-rwxr-xr-xscripts/coccicheck6
-rwxr-xr-xscripts/depmod.sh4
-rw-r--r--scripts/genksyms/genksyms.c73
-rw-r--r--scripts/head-object-list.txt1
-rw-r--r--scripts/kconfig/conf.c5
-rw-r--r--scripts/kconfig/lkc_proto.h1
-rw-r--r--scripts/kconfig/nconf.c2
-rw-r--r--scripts/kconfig/nconf.gui.c9
-rw-r--r--scripts/kconfig/parser.y28
-rw-r--r--scripts/kconfig/qconf.cc204
-rw-r--r--scripts/kconfig/qconf.h19
-rwxr-xr-xscripts/kconfig/streamline_config.pl18
-rw-r--r--scripts/kconfig/symbol.c26
-rwxr-xr-xscripts/link-vmlinux.sh16
-rw-r--r--scripts/mod/file2alias.c779
-rw-r--r--scripts/mod/modpost.c31
-rw-r--r--scripts/mod/modpost.h21
-rw-r--r--scripts/nsdeps10
-rwxr-xr-xscripts/package/builddeb22
-rwxr-xr-xscripts/package/install-extmod-build7
-rwxr-xr-xscripts/package/mkdebian2
-rwxr-xr-xscripts/setlocalversion58
-rw-r--r--tools/objtool/check.c2
-rw-r--r--tools/objtool/elf.c15
73 files changed, 1471 insertions, 1010 deletions
diff --git a/.gitignore b/.gitignore
index a61e4778d011..6839cf84acda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,6 +129,7 @@ series
# ctags files
tags
+!tags/
TAGS
# cscope files
diff --git a/Documentation/dev-tools/autofdo.rst b/Documentation/dev-tools/autofdo.rst
new file mode 100644
index 000000000000..1f0a451e9ccd
--- /dev/null
+++ b/Documentation/dev-tools/autofdo.rst
@@ -0,0 +1,168 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================================
+Using AutoFDO with the Linux kernel
+===================================
+
+This enables AutoFDO build support for the kernel when using
+the Clang compiler. AutoFDO (Auto-Feedback-Directed Optimization)
+is a type of profile-guided optimization (PGO) used to enhance the
+performance of binary executables. It gathers information about the
+frequency of execution of various code paths within a binary using
+hardware sampling. This data is then used to guide the compiler's
+optimization decisions, resulting in a more efficient binary. AutoFDO
+is a powerful optimization technique, and data indicates that it can
+significantly improve kernel performance. It's especially beneficial
+for workloads affected by front-end stalls.
+
+For AutoFDO builds, unlike non-FDO builds, the user must supply a
+profile. Acquiring an AutoFDO profile can be done in several ways.
+AutoFDO profiles are created by converting hardware sampling using
+the "perf" tool. It is crucial that the workload used to create these
+perf files is representative; they must exhibit runtime
+characteristics similar to the workloads that are intended to be
+optimized. Failure to do so will result in the compiler optimizing
+for the wrong objective.
+
+The AutoFDO profile often encapsulates the program's behavior. If the
+performance-critical codes are architecture-independent, the profile
+can be applied across platforms to achieve performance gains. For
+instance, using the profile generated on Intel architecture to build
+a kernel for AMD architecture can also yield performance improvements.
+
+There are two methods for acquiring a representative profile:
+(1) Sample real workloads using a production environment.
+(2) Generate the profile using a representative load test.
+When enabling the AutoFDO build configuration without providing an
+AutoFDO profile, the compiler only modifies the dwarf information in
+the kernel without impacting runtime performance. It's advisable to
+use a kernel binary built with the same AutoFDO configuration to
+collect the perf profile. While it's possible to use a kernel built
+with different options, it may result in inferior performance.
+
+One can collect profiles using AutoFDO build for the previous kernel.
+AutoFDO employs relative line numbers to match the profiles, offering
+some tolerance for source changes. This mode is commonly used in a
+production environment for profile collection.
+
+In a profile collection based on a load test, the AutoFDO collection
+process consists of the following steps:
+
+#. Initial build: The kernel is built with AutoFDO options
+ without a profile.
+
+#. Profiling: The above kernel is then run with a representative
+ workload to gather execution frequency data. This data is
+ collected using hardware sampling, via perf. AutoFDO is most
+ effective on platforms supporting advanced PMU features like
+ LBR on Intel machines.
+
+#. AutoFDO profile generation: Perf output file is converted to
+ the AutoFDO profile via offline tools.
+
+The support requires a Clang compiler LLVM 17 or later.
+
+Preparation
+===========
+
+Configure the kernel with::
+
+ CONFIG_AUTOFDO_CLANG=y
+
+Customization
+=============
+
+The default CONFIG_AUTOFDO_CLANG setting covers kernel space objects for
+AutoFDO builds. One can, however, enable or disable AutoFDO build for
+individual files and directories by adding a line similar to the following
+to the respective kernel Makefile:
+
+- For enabling a single file (e.g. foo.o) ::
+
+ AUTOFDO_PROFILE_foo.o := y
+
+- For enabling all files in one directory ::
+
+ AUTOFDO_PROFILE := y
+
+- For disabling one file ::
+
+ AUTOFDO_PROFILE_foo.o := n
+
+- For disabling all files in one directory ::
+
+ AUTOFDO_PROFILE := n
+
+Workflow
+========
+
+Here is an example workflow for AutoFDO kernel:
+
+1) Build the kernel on the host machine with LLVM enabled,
+ for example, ::
+
+ $ make menuconfig LLVM=1
+
+ Turn on AutoFDO build config::
+
+ CONFIG_AUTOFDO_CLANG=y
+
+ With a configuration that with LLVM enabled, use the following command::
+
+ $ scripts/config -e AUTOFDO_CLANG
+
+ After getting the config, build with ::
+
+ $ make LLVM=1
+
+2) Install the kernel on the test machine.
+
+3) Run the load tests. The '-c' option in perf specifies the sample
+ event period. We suggest using a suitable prime number, like 500009,
+ for this purpose.
+
+ - For Intel platforms::
+
+ $ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
+
+ - For AMD platforms:
+
+ The supported systems are: Zen3 with BRS, or Zen4 with amd_lbr_v2. To check,
+
+ For Zen3::
+
+ $ cat proc/cpuinfo | grep " brs"
+
+ For Zen4::
+
+ $ cat proc/cpuinfo | grep amd_lbr_v2
+
+ The following command generated the perf data file::
+
+ $ perf record --pfm-events RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
+
+4) (Optional) Download the raw perf file to the host machine.
+
+5) To generate an AutoFDO profile, two offline tools are available:
+ create_llvm_prof and llvm_profgen. The create_llvm_prof tool is part
+ of the AutoFDO project and can be found on GitHub
+ (https://github.com/google/autofdo), version v0.30.1 or later.
+ The llvm_profgen tool is included in the LLVM compiler itself. It's
+ important to note that the version of llvm_profgen doesn't need to match
+ the version of Clang. It needs to be the LLVM 19 release of Clang
+ or later, or just from the LLVM trunk. ::
+
+ $ llvm-profgen --kernel --binary=<vmlinux> --perfdata=<perf_file> -o <profile_file>
+
+ or ::
+
+ $ create_llvm_prof --binary=<vmlinux> --profile=<perf_file> --format=extbinary --out=<profile_file>
+
+ Note that multiple AutoFDO profile files can be merged into one via::
+
+ $ llvm-profdata merge -o <profile_file> <profile_1> <profile_2> ... <profile_n>
+
+6) Rebuild the kernel using the AutoFDO profile file with the same config as step 1,
+ (Note CONFIG_AUTOFDO_CLANG needs to be enabled)::
+
+ $ make LLVM=1 CLANG_AUTOFDO_PROFILE=<profile_file>
diff --git a/Documentation/dev-tools/coccinelle.rst b/Documentation/dev-tools/coccinelle.rst
index 535ce126fb4f..6e70a1e9a3c0 100644
--- a/Documentation/dev-tools/coccinelle.rst
+++ b/Documentation/dev-tools/coccinelle.rst
@@ -250,25 +250,17 @@ variables for .cocciconfig is as follows:
- Your directory from which spatch is called is processed next
- The directory provided with the ``--dir`` option is processed last, if used
-Since coccicheck runs through make, it naturally runs from the kernel
-proper dir; as such the second rule above would be implied for picking up a
-.cocciconfig when using ``make coccicheck``.
-
``make coccicheck`` also supports using M= targets. If you do not supply
any M= target, it is assumed you want to target the entire kernel.
The kernel coccicheck script has::
- if [ "$KBUILD_EXTMOD" = "" ] ; then
- OPTIONS="--dir $srctree $COCCIINCLUDE"
- else
- OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
- fi
-
-KBUILD_EXTMOD is set when an explicit target with M= is used. For both cases
-the spatch ``--dir`` argument is used, as such third rule applies when whether
-M= is used or not, and when M= is used the target directory can have its own
-.cocciconfig file. When M= is not passed as an argument to coccicheck the
-target directory is the same as the directory from where spatch was called.
+ OPTIONS="--dir $srcroot $COCCIINCLUDE"
+
+Here, $srcroot refers to the source directory of the target: it points to the
+external module's source directory when M= used, and otherwise, to the kernel
+source directory. The third rule ensures the spatch reads the .cocciconfig from
+the target directory, allowing external modules to have their own .cocciconfig
+file.
If not using the kernel's coccicheck target, keep the above precedence
order logic of .cocciconfig reading. If using the kernel's coccicheck target,
diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst
index 53d4d124f9c5..3c0ac08b2709 100644
--- a/Documentation/dev-tools/index.rst
+++ b/Documentation/dev-tools/index.rst
@@ -34,6 +34,8 @@ Documentation/dev-tools/testing-overview.rst
ktap
checkuapi
gpio-sloppy-logic-analyzer
+ autofdo
+ propeller
.. only:: subproject and html
diff --git a/Documentation/dev-tools/propeller.rst b/Documentation/dev-tools/propeller.rst
new file mode 100644
index 000000000000..92195958e3db
--- /dev/null
+++ b/Documentation/dev-tools/propeller.rst
@@ -0,0 +1,162 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+Using Propeller with the Linux kernel
+=====================================
+
+This enables Propeller build support for the kernel when using Clang
+compiler. Propeller is a profile-guided optimization (PGO) method used
+to optimize binary executables. Like AutoFDO, it utilizes hardware
+sampling to gather information about the frequency of execution of
+different code paths within a binary. Unlike AutoFDO, this information
+is then used right before linking phase to optimize (among others)
+block layout within and across functions.
+
+A few important notes about adopting Propeller optimization:
+
+#. Although it can be used as a standalone optimization step, it is
+ strongly recommended to apply Propeller on top of AutoFDO,
+ AutoFDO+ThinLTO or Instrument FDO. The rest of this document
+ assumes this paradigm.
+
+#. Propeller uses another round of profiling on top of
+ AutoFDO/AutoFDO+ThinLTO/iFDO. The whole build process involves
+ "build-afdo - train-afdo - build-propeller - train-propeller -
+ build-optimized".
+
+#. Propeller requires LLVM 19 release or later for Clang/Clang++
+ and the linker(ld.lld).
+
+#. In addition to LLVM toolchain, Propeller requires a profiling
+ conversion tool: https://github.com/google/autofdo with a release
+ after v0.30.1: https://github.com/google/autofdo/releases/tag/v0.30.1.
+
+The Propeller optimization process involves the following steps:
+
+#. Initial building: Build the AutoFDO or AutoFDO+ThinLTO binary as
+ you would normally do, but with a set of compile-time / link-time
+ flags, so that a special metadata section is created within the
+ kernel binary. The special section is only intend to be used by the
+ profiling tool, it is not part of the runtime image, nor does it
+ change kernel run time text sections.
+
+#. Profiling: The above kernel is then run with a representative
+ workload to gather execution frequency data. This data is collected
+ using hardware sampling, via perf. Propeller is most effective on
+ platforms supporting advanced PMU features like LBR on Intel
+ machines. This step is the same as profiling the kernel for AutoFDO
+ (the exact perf parameters can be different).
+
+#. Propeller profile generation: Perf output file is converted to a
+ pair of Propeller profiles via an offline tool.
+
+#. Optimized build: Build the AutoFDO or AutoFDO+ThinLTO optimized
+ binary as you would normally do, but with a compile-time /
+ link-time flag to pick up the Propeller compile time and link time
+ profiles. This build step uses 3 profiles - the AutoFDO profile,
+ the Propeller compile-time profile and the Propeller link-time
+ profile.
+
+#. Deployment: The optimized kernel binary is deployed and used
+ in production environments, providing improved performance
+ and reduced latency.
+
+Preparation
+===========
+
+Configure the kernel with::
+
+ CONFIG_AUTOFDO_CLANG=y
+ CONFIG_PROPELLER_CLANG=y
+
+Customization
+=============
+
+The default CONFIG_PROPELLER_CLANG setting covers kernel space objects
+for Propeller builds. One can, however, enable or disable Propeller build
+for individual files and directories by adding a line similar to the
+following to the respective kernel Makefile:
+
+- For enabling a single file (e.g. foo.o)::
+
+ PROPELLER_PROFILE_foo.o := y
+
+- For enabling all files in one directory::
+
+ PROPELLER_PROFILE := y
+
+- For disabling one file::
+
+ PROPELLER_PROFILE_foo.o := n
+
+- For disabling all files in one directory::
+
+ PROPELLER__PROFILE := n
+
+
+Workflow
+========
+
+Here is an example workflow for building an AutoFDO+Propeller kernel:
+
+1) Assuming an AutoFDO profile is already collected following
+ instructions in the AutoFDO document, build the kernel on the host
+ machine, with AutoFDO and Propeller build configs ::
+
+ CONFIG_AUTOFDO_CLANG=y
+ CONFIG_PROPELLER_CLANG=y
+
+ and ::
+
+ $ make LLVM=1 CLANG_AUTOFDO_PROFILE=<autofdo-profile-name>
+
+2) Install the kernel on the test machine.
+
+3) Run the load tests. The '-c' option in perf specifies the sample
+ event period. We suggest using a suitable prime number, like 500009,
+ for this purpose.
+
+ - For Intel platforms::
+
+ $ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
+
+ - For AMD platforms::
+
+ $ perf record --pfm-event RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
+
+ Note you can repeat the above steps to collect multiple <perf_file>s.
+
+4) (Optional) Download the raw perf file(s) to the host machine.
+
+5) Use the create_llvm_prof tool (https://github.com/google/autofdo) to
+ generate Propeller profile. ::
+
+ $ create_llvm_prof --binary=<vmlinux> --profile=<perf_file>
+ --format=propeller --propeller_output_module_name
+ --out=<propeller_profile_prefix>_cc_profile.txt
+ --propeller_symorder=<propeller_profile_prefix>_ld_profile.txt
+
+ "<propeller_profile_prefix>" can be something like "/home/user/dir/any_string".
+
+ This command generates a pair of Propeller profiles:
+ "<propeller_profile_prefix>_cc_profile.txt" and
+ "<propeller_profile_prefix>_ld_profile.txt".
+
+ If there are more than 1 perf_file collected in the previous step,
+ you can create a temp list file "<perf_file_list>" with each line
+ containing one perf file name and run::
+
+ $ create_llvm_prof --binary=<vmlinux> --profile=@<perf_file_list>
+ --format=propeller --propeller_output_module_name
+ --out=<propeller_profile_prefix>_cc_profile.txt
+ --propeller_symorder=<propeller_profile_prefix>_ld_profile.txt
+
+6) Rebuild the kernel using the AutoFDO and Propeller
+ profiles. ::
+
+ CONFIG_AUTOFDO_CLANG=y
+ CONFIG_PROPELLER_CLANG=y
+
+ and ::
+
+ $ make LLVM=1 CLANG_AUTOFDO_PROFILE=<profile_file> CLANG_PROPELLER_PROFILE_PREFIX=<propeller_profile_prefix>
diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst
index 1796b3eba37b..17c9f920f03d 100644
--- a/Documentation/kbuild/kbuild.rst
+++ b/Documentation/kbuild/kbuild.rst
@@ -137,12 +137,18 @@ Specify the output directory when building the kernel.
This variable can also be used to point to the kernel output directory when
building external modules against a pre-built kernel in a separate build
directory. Please note that this does NOT specify the output directory for the
-external modules themselves.
+external modules themselves. (Use KBUILD_EXTMOD_OUTPUT for that purpose.)
The output directory can also be specified using "O=...".
Setting "O=..." takes precedence over KBUILD_OUTPUT.
+KBUILD_EXTMOD_OUTPUT
+--------------------
+Specify the output directory for external modules.
+
+Setting "MO=..." takes precedence over KBUILD_EXTMOD_OUTPUT.
+
KBUILD_EXTRA_WARN
-----------------
Specify the extra build checks. The same value can be assigned by passing
diff --git a/Documentation/kbuild/kconfig-language.rst b/Documentation/kbuild/kconfig-language.rst
index 43037be96a16..2619fdf56e68 100644
--- a/Documentation/kbuild/kconfig-language.rst
+++ b/Documentation/kbuild/kconfig-language.rst
@@ -412,8 +412,8 @@ choices::
<choice block>
"endchoice"
-This defines a choice group and accepts any of the above attributes as
-options.
+This defines a choice group and accepts "prompt", "default", "depends on", and
+"help" attributes as options.
A choice only allows a single config entry to be selected.
diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst
index 7964e0c245ae..d36519f194dc 100644
--- a/Documentation/kbuild/makefiles.rst
+++ b/Documentation/kbuild/makefiles.rst
@@ -449,6 +449,20 @@ $(obj)
to prerequisites are referenced with $(src) (because they are not
generated files).
+$(srcroot)
+ $(srcroot) refers to the root of the source you are building, which can be
+ either the kernel source or the external modules source, depending on whether
+ KBUILD_EXTMOD is set. This can be either a relative or an absolute path, but
+ if KBUILD_ABS_SRCTREE=1 is set, it is always an absolute path.
+
+$(srctree)
+ $(srctree) refers to the root of the kernel source tree. When building the
+ kernel, this is the same as $(srcroot).
+
+$(objtree)
+ $(objtree) refers to the root of the kernel object tree. It is ``.`` when
+ building the kernel, but it is different when building external modules.
+
$(kecho)
echoing information to user in a rule is often a good practice
but when execution ``make -s`` one does not expect to see any output
diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst
index cd5a54d91e6d..101de236cd0c 100644
--- a/Documentation/kbuild/modules.rst
+++ b/Documentation/kbuild/modules.rst
@@ -59,6 +59,12 @@ Command Syntax
$ make -C /lib/modules/`uname -r`/build M=$PWD modules_install
+ Starting from Linux 6.13, you can use the -f option instead of -C. This
+ will avoid unnecessary change of the working directory. The external
+ module will be output to the directory where you invoke make.
+
+ $ make -f /lib/modules/`uname -r`/build/Makefile M=$PWD
+
Options
-------
@@ -66,7 +72,10 @@ Options
of the kernel output directory if the kernel was built in a separate
build directory.)
- make -C $KDIR M=$PWD
+ You can optionally pass MO= option if you want to build the modules in
+ a separate directory.
+
+ make -C $KDIR M=$PWD [MO=$BUILD_DIR]
-C $KDIR
The directory that contains the kernel and relevant build
@@ -80,6 +89,9 @@ Options
directory where the external module (kbuild file) is
located.
+ MO=$BUILD_DIR
+ Specifies a separate output directory for the external module.
+
Targets
-------
@@ -215,6 +227,21 @@ Separate Kbuild File and Makefile
consisting of several hundred lines, and here it really pays
off to separate the kbuild part from the rest.
+ Linux 6.13 and later support another way. The external module Makefile
+ can include the kernel Makefile directly, rather than invoking sub Make.
+
+ Example 3::
+
+ --> filename: Kbuild
+ obj-m := 8123.o
+ 8123-y := 8123_if.o 8123_pci.o
+
+ --> filename: Makefile
+ KDIR ?= /lib/modules/$(shell uname -r)/build
+ export KBUILD_EXTMOD := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
+ include $(KDIR)/Makefile
+
+
Building Multiple Modules
-------------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index 3cf2858145bf..7292e4a1ddb8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3715,6 +3715,13 @@ F: kernel/audit*
F: lib/*audit.c
K: \baudit_[a-z_0-9]\+\b
+AUTOFDO BUILD
+M: Rong Xu <xur@google.com>
+M: Han Shen <shenhan@google.com>
+S: Supported
+F: Documentation/dev-tools/autofdo.rst
+F: scripts/Makefile.autofdo
+
AUXILIARY BUS DRIVER
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
R: Dave Ertman <david.m.ertman@intel.com>
@@ -18708,6 +18715,13 @@ S: Maintained
F: include/linux/psi*
F: kernel/sched/psi.c
+PROPELLER BUILD
+M: Rong Xu <xur@google.com>
+M: Han Shen <shenhan@google.com>
+S: Supported
+F: Documentation/dev-tools/propeller.rst
+F: scripts/Makefile.propeller
+
PRINTK
M: Petr Mladek <pmladek@suse.com>
R: Steven Rostedt <rostedt@goodmis.org>
diff --git a/Makefile b/Makefile
index 8129de0b214f..e34a97473fb6 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,7 @@ __all:
this-makefile := $(lastword $(MAKEFILE_LIST))
abs_srctree := $(realpath $(dir $(this-makefile)))
-abs_objtree := $(CURDIR)
+abs_output := $(CURDIR)
ifneq ($(sub_make_done),1)
@@ -134,6 +134,10 @@ ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
+ifeq ("$(origin MO)", "command line")
+ KBUILD_EXTMOD_OUTPUT := $(MO)
+endif
+
$(if $(word 2, $(KBUILD_EXTMOD)), \
$(error building multiple external modules is not supported))
@@ -176,18 +180,41 @@ export KBUILD_EXTRA_WARN
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.
-# Do we want to change the working directory?
ifeq ("$(origin O)", "command line")
KBUILD_OUTPUT := $(O)
endif
-ifneq ($(KBUILD_OUTPUT),)
+ifdef KBUILD_EXTMOD
+ ifdef KBUILD_OUTPUT
+ objtree := $(realpath $(KBUILD_OUTPUT))
+ $(if $(objtree),,$(error specified kernel directory "$(KBUILD_OUTPUT)" does not exist))
+ else
+ objtree := $(abs_srctree)
+ endif
+ # If Make is invoked from the kernel directory (either kernel
+ # source directory or kernel build directory), external modules
+ # are built in $(KBUILD_EXTMOD) for backward compatibility,
+ # otherwise, built in the current directory.
+ output := $(or $(KBUILD_EXTMOD_OUTPUT),$(if $(filter $(CURDIR),$(objtree) $(abs_srctree)),$(KBUILD_EXTMOD)))
+ # KBUILD_EXTMOD might be a relative path. Remember its absolute path before
+ # Make changes the working directory.
+ srcroot := $(realpath $(KBUILD_EXTMOD))
+ $(if $(srcroot),,$(error specified external module directory "$(KBUILD_EXTMOD)" does not exist))
+else
+ objtree := .
+ output := $(KBUILD_OUTPUT)
+endif
+
+export objtree srcroot
+
+# Do we want to change the working directory?
+ifneq ($(output),)
# $(realpath ...) gets empty if the path does not exist. Run 'mkdir -p' first.
-$(shell mkdir -p "$(KBUILD_OUTPUT)")
+$(shell mkdir -p "$(output)")
# $(realpath ...) resolves symlinks
-abs_objtree := $(realpath $(KBUILD_OUTPUT))
-$(if $(abs_objtree),,$(error failed to create output directory "$(KBUILD_OUTPUT)"))
-endif # ifneq ($(KBUILD_OUTPUT),)
+abs_output := $(realpath $(output))
+$(if $(abs_output),,$(error failed to create output directory "$(output)"))
+endif
ifneq ($(words $(subst :, ,$(abs_srctree))), 1)
$(error source directory cannot contain spaces or colons)
@@ -197,7 +224,7 @@ export sub_make_done := 1
endif # sub_make_done
-ifeq ($(abs_objtree),$(CURDIR))
+ifeq ($(abs_output),$(CURDIR))
# Suppress "Entering directory ..." if we are at the final work directory.
no-print-directory := --no-print-directory
else
@@ -221,43 +248,41 @@ $(filter-out $(this-makefile), $(MAKECMDGOALS)) __all: __sub-make
# Invoke a second make in the output directory, passing relevant variables
__sub-make:
- $(Q)$(MAKE) $(no-print-directory) -C $(abs_objtree) \
+ $(Q)$(MAKE) $(no-print-directory) -C $(abs_output) \
-f $(abs_srctree)/Makefile $(MAKECMDGOALS)
else # need-sub-make
# We process the rest of the Makefile if this is the final invocation of make
-ifeq ($(abs_srctree),$(abs_objtree))
- # building in the source tree
- srctree := .
- building_out_of_srctree :=
-else
- ifeq ($(abs_srctree)/,$(dir $(abs_objtree)))
- # building in a subdirectory of the source tree
- srctree := ..
- else
- srctree := $(abs_srctree)
- endif
- building_out_of_srctree := 1
+ifndef KBUILD_EXTMOD
+srcroot := $(abs_srctree)
endif
-ifneq ($(KBUILD_ABS_SRCTREE),)
-srctree := $(abs_srctree)
+ifeq ($(srcroot),$(CURDIR))
+building_out_of_srctree :=
+else
+export building_out_of_srctree := 1
endif
-objtree := .
+ifdef KBUILD_ABS_SRCTREE
+ # Do nothing. Use the absolute path.
+else ifeq ($(srcroot),$(CURDIR))
+ # Building in the source.
+ srcroot := .
+else ifeq ($(srcroot)/,$(dir $(CURDIR)))
+ # Building in a subdirectory of the source.
+ srcroot := ..
+endif
-VPATH :=
+export srctree := $(if $(KBUILD_EXTMOD),$(abs_srctree),$(srcroot))
-ifeq ($(KBUILD_EXTMOD),)
ifdef building_out_of_srctree
-VPATH := $(srctree)
-endif
+export VPATH := $(srcroot)
+else
+VPATH :=
endif
-export building_out_of_srctree srctree objtree VPATH
-
# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
@@ -276,7 +301,7 @@ no-dot-config-targets := $(clean-targets) \
outputmakefile rustavailable rustfmt rustfmtcheck
no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \
image_name
-single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %/
+single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %/
config-build :=
mixed-build :=
@@ -354,7 +379,7 @@ else # !mixed-build
include $(srctree)/scripts/Kbuild.include
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
-KERNELRELEASE = $(call read-file, include/config/kernel.release)
+KERNELRELEASE = $(call read-file, $(objtree)/include/config/kernel.release)
KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
@@ -513,7 +538,7 @@ KGZIP = gzip
KBZIP2 = bzip2
KLZOP = lzop
LZMA = lzma
-LZ4 = lz4c
+LZ4 = lz4
XZ = xz
ZSTD = zstd
@@ -543,7 +568,7 @@ USERINCLUDE := \
LINUXINCLUDE := \
-I$(srctree)/arch/$(SRCARCH)/include \
-I$(objtree)/arch/$(SRCARCH)/include/generated \
- $(if $(building_out_of_srctree),-I$(srctree)/include) \
+ -I$(srctree)/include \
-I$(objtree)/include \
$(USERINCLUDE)
@@ -629,13 +654,25 @@ ifdef building_out_of_srctree
# At the same time when output Makefile generated, generate .gitignore to
# ignore whole output directory
+ifdef KBUILD_EXTMOD
+print_env_for_makefile = \
+ echo "export KBUILD_OUTPUT = $(objtree)"; \
+ echo "export KBUILD_EXTMOD = $(realpath $(srcroot))" ; \
+ echo "export KBUILD_EXTMOD_OUTPUT = $(CURDIR)"
+else
+print_env_for_makefile = \
+ echo "export KBUILD_OUTPUT = $(CURDIR)"
+endif
+
quiet_cmd_makefile = GEN Makefile
cmd_makefile = { \
- echo "\# Automatically generated by $(srctree)/Makefile: don't edit"; \
- echo "include $(srctree)/Makefile"; \
+ echo "\# Automatically generated by $(abs_srctree)/Makefile: don't edit"; \
+ $(print_env_for_makefile); \
+ echo "include $(abs_srctree)/Makefile"; \
} > Makefile
outputmakefile:
+ifeq ($(KBUILD_EXTMOD),)
@if [ -f $(srctree)/.config -o \
-d $(srctree)/include/config -o \
-d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \
@@ -645,7 +682,16 @@ outputmakefile:
echo >&2 "***"; \
false; \
fi
- $(Q)ln -fsn $(srctree) source
+else
+ @if [ -f $(srcroot)/modules.order ]; then \
+ echo >&2 "***"; \
+ echo >&2 "*** The external module source tree is not clean."; \
+ echo >&2 "*** Please run 'make -C $(abs_srctree) M=$(realpath $(srcroot)) clean'"; \
+ echo >&2 "***"; \
+ false; \
+ fi
+endif
+ $(Q)ln -fsn $(srcroot) source
$(call cmd,makefile)
$(Q)test -e .gitignore || \
{ echo "# this is build directory, ignore it"; echo "*"; } > .gitignore
@@ -717,7 +763,7 @@ endif
# in addition to whatever we do anyway.
# Just "make" or "make all" shall build modules as well
-ifneq ($(filter all modules nsdeps %compile_commands.json clang-%,$(MAKECMDGOALS)),)
+ifneq ($(filter all modules nsdeps compile_commands.json clang-%,$(MAKECMDGOALS)),)
KBUILD_MODULES := 1
endif
@@ -728,7 +774,7 @@ endif
export KBUILD_MODULES KBUILD_BUILTIN
ifdef need-config
-include include/config/auto.conf
+include $(objtree)/include/config/auto.conf
endif
ifeq ($(KBUILD_EXTMOD),)
@@ -789,17 +835,22 @@ $(KCONFIG_CONFIG):
else # !may-sync-config
# External modules and some install targets need include/generated/autoconf.h
# and include/config/auto.conf but do not care if they are up-to-date.
-# Use auto.conf to trigger the test
-PHONY += include/config/auto.conf
-
-include/config/auto.conf:
- @test -e include/generated/autoconf.h -a -e $@ || ( \
- echo >&2; \
- echo >&2 " ERROR: Kernel configuration is invalid."; \
- echo >&2 " include/generated/autoconf.h or $@ are missing.";\
- echo >&2 " Run 'make oldconfig && make prepare' on kernel src to fix it."; \
- echo >&2 ; \
- /bin/false)
+# Use auto.conf to show the error message
+
+checked-configs := $(addprefix $(objtree)/, include/generated/autoconf.h include/generated/rustc_cfg include/config/auto.conf)
+missing-configs := $(filter-out $(wildcard $(checked-configs)), $(checked-configs))
+
+ifdef missing-configs
+PHONY += $(objtree)/include/config/auto.conf
+
+$(objtree)/include/config/auto.conf:
+ @echo >&2 '***'
+ @echo >&2 '*** ERROR: Kernel configuration is invalid. The following files are missing:'
+ @printf >&2 '*** - %s\n' $(missing-configs)
+ @echo >&2 '*** Run "make oldconfig && make prepare" on kernel source to fix it.'
+ @echo >&2 '***'
+ @/bin/false
+endif
endif # may-sync-config
endif # need-config
@@ -1013,8 +1064,10 @@ ifdef CONFIG_CC_IS_GCC
KBUILD_CFLAGS += -fconserve-stack
endif
-# change __FILE__ to the relative path from the srctree
-KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
+# change __FILE__ to the relative path to the source directory
+ifdef building_out_of_srctree
+KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srcroot)/=)
+endif
# include additional Makefiles when needed
include-y := scripts/Makefile.extrawarn
@@ -1026,6 +1079,8 @@ include-$(CONFIG_KMSAN) += scripts/Makefile.kmsan
include-$(CONFIG_UBSAN) += scripts/Makefile.ubsan
include-$(CONFIG_KCOV) += scripts/Makefile.kcov
include-$(CONFIG_RANDSTRUCT) += scripts/Makefile.randstruct
+include-$(CONFIG_AUTOFDO_CLANG) += scripts/Makefile.autofdo
+include-$(CONFIG_PROPELLER_CLANG) += scripts/Makefile.propeller
include-$(CONFIG_GCC_PLUGINS) += scripts/Makefile.gcc-plugins
include $(addprefix $(srctree)/, $(include-y))
@@ -1106,10 +1161,6 @@ export MODLIB
PHONY += prepare0
-export extmod_prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/)
-export MODORDER := $(extmod_prefix)modules.order
-export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps
-
ifeq ($(KBUILD_EXTMOD),)
build-dir := .
@@ -1204,7 +1255,8 @@ PHONY += prepare archprepare
archprepare: outputmakefile archheaders archscripts scripts include/config/kernel.release \
asm-generic $(version_h) include/generated/utsrelease.h \
- include/generated/compile.h include/generated/autoconf.h remove-stale-files
+ include/generated/compile.h include/generated/autoconf.h \
+ include/generated/rustc_cfg remove-stale-files
prepare0: archprepare
$(Q)$(MAKE) $(build)=scripts/mod
@@ -1435,6 +1487,10 @@ ifdef CONFIG_OF_EARLY_FLATTREE
all: dtbs
endif
+ifdef CONFIG_GENERIC_BUILTIN_DTB
+vmlinux: dtbs
+endif
+
endif
PHONY += scripts_dtc
@@ -1502,7 +1558,8 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \
modules.builtin modules.builtin.modinfo modules.nsdeps \
modules.builtin.ranges vmlinux.o.map \
compile_commands.json rust/test \
- rust-project.json .vmlinux.objs .vmlinux.export.c
+ rust-project.json .vmlinux.objs .vmlinux.export.c \
+ .builtin-dtbs-list .builtin-dtb.S
# Directories & files removed with 'make mrproper'
MRPROPER_FILES += include/config include/generated \
@@ -1750,18 +1807,9 @@ rusttest: prepare
# Formatting targets
PHONY += rustfmt rustfmtcheck
-# We skip `rust/alloc` since we want to minimize the diff w.r.t. upstream.
-#
-# We match using absolute paths since `find` does not resolve them
-# when matching, which is a problem when e.g. `srctree` is `..`.
-# We `grep` afterwards in order to remove the directory entry itself.
rustfmt:
- $(Q)find $(abs_srctree) -type f -name '*.rs' \
- -o -path $(abs_srctree)/rust/alloc -prune \
- -o -path $(abs_objtree)/rust/test -prune \
- | grep -Fv $(abs_srctree)/rust/alloc \
- | grep -Fv $(abs_objtree)/rust/test \
- | grep -Fv generated \
+ $(Q)find $(srctree) $(RCS_FIND_IGNORE) \
+ -type f -a -name '*.rs' -a ! -name '*generated*' -print \
| xargs $(RUSTFMT) $(rustfmt_flags)
rustfmtcheck: rustfmt_flags = --check
@@ -1800,14 +1848,10 @@ filechk_kernel.release = echo $(KERNELRELEASE)
KBUILD_BUILTIN :=
KBUILD_MODULES := 1
-build-dir := $(KBUILD_EXTMOD)
+build-dir := .
-compile_commands.json: $(extmod_prefix)compile_commands.json
-PHONY += compile_commands.json
-
-clean-dirs := $(KBUILD_EXTMOD)
-clean: private rm-files := $(KBUILD_EXTMOD)/Module.symvers $(KBUILD_EXTMOD)/modules.nsdeps \
- $(KBUILD_EXTMOD)/compile_commands.json
+clean-dirs := .
+clean: private rm-files := Module.symvers modules.nsdeps compile_commands.json
PHONY += prepare
# now expand this into a simple variable to reduce the cost of shell evaluations
@@ -1866,7 +1910,7 @@ endif
ifdef CONFIG_MODULES
-$(MODORDER): $(build-dir)
+modules.order: $(build-dir)
@:
# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
@@ -1877,7 +1921,7 @@ ifneq ($(KBUILD_MODPOST_NOFINAL),1)
endif
PHONY += modules_check
-modules_check: $(MODORDER)
+modules_check: modules.order
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/modules-check.sh $<
else # CONFIG_MODULES
@@ -1918,15 +1962,15 @@ $(single-ko): single_modules
$(single-no-ko): $(build-dir)
@:
-# Remove MODORDER when done because it is not the real one.
+# Remove modules.order when done because it is not the real one.
PHONY += single_modules
single_modules: $(single-no-ko) modules_prepare
- $(Q){ $(foreach m, $(single-ko), echo $(extmod_prefix)$(m:%.ko=%.o);) } > $(MODORDER)
+ $(Q){ $(foreach m, $(single-ko), echo $(m:%.ko=%.o);) } > modules.order
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
ifneq ($(KBUILD_MODPOST_NOFINAL),1)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal
endif
- $(Q)rm -f $(MODORDER)
+ $(Q)rm -f modules.order
single-goals := $(addprefix $(build-dir)/, $(single-no-ko))
@@ -1934,6 +1978,8 @@ KBUILD_MODULES := 1
endif
+prepare: outputmakefile
+
# Preset locale variables to speed up the build process. Limit locale
# tweaks to this spot to avoid wrong language settings when running
# make menuconfig etc.
@@ -1949,7 +1995,7 @@ $(clean-dirs):
clean: $(clean-dirs)
$(call cmd,rmfiles)
- @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+ @find . $(RCS_FIND_IGNORE) \
\( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '*.ko.*' \
-o -name '*.dtb' -o -name '*.dtbo' \
@@ -1982,7 +2028,12 @@ tags TAGS cscope gtags: FORCE
PHONY += rust-analyzer
rust-analyzer:
+$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
+ifdef KBUILD_EXTMOD
+# FIXME: external modules must not descend into a sub-directory of the kernel
+ $(Q)$(MAKE) $(build)=$(objtree)/rust src=$(srctree)/rust $@
+else
$(Q)$(MAKE) $(build)=rust $@
+endif
# Script to generate missing namespace dependencies
# ---------------------------------------------------------------------------
@@ -1998,12 +2049,12 @@ nsdeps: modules
quiet_cmd_gen_compile_commands = GEN $@
cmd_gen_compile_commands = $(PYTHON3) $< -a $(AR) -o $@ $(filter-out $<, $(real-prereqs))
-$(extmod_prefix)compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \
+compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \
$(if $(KBUILD_EXTMOD),, vmlinux.a $(KBUILD_VMLINUX_LIBS)) \
- $(if $(CONFIG_MODULES), $(MODORDER)) FORCE
+ $(if $(CONFIG_MODULES), modules.order) FORCE
$(call if_changed,gen_compile_commands)
-targets += $(extmod_prefix)compile_commands.json
+targets += compile_commands.json
PHONY += clang-tidy clang-analyzer
@@ -2011,7 +2062,7 @@ ifdef CONFIG_CC_IS_CLANG
quiet_cmd_clang_tools = CHECK $<
cmd_clang_tools = $(PYTHON3) $(srctree)/scripts/clang-tools/run-clang-tools.py $@ $<
-clang-tidy clang-analyzer: $(extmod_prefix)compile_commands.json
+clang-tidy clang-analyzer: compile_commands.json
$(call cmd,clang_tools)
else
clang-tidy clang-analyzer:
diff --git a/arch/Kconfig b/arch/Kconfig
index 832f68af7c77..6682b2a53e34 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -812,6 +812,45 @@ config LTO_CLANG_THIN
If unsure, say Y.
endchoice
+config ARCH_SUPPORTS_AUTOFDO_CLANG
+ bool
+
+config AUTOFDO_CLANG
+ bool "Enable Clang's AutoFDO build (EXPERIMENTAL)"
+ depends on ARCH_SUPPORTS_AUTOFDO_CLANG
+ depends on CC_IS_CLANG && CLANG_VERSION >= 170000
+ help
+ This option enables Clang’s AutoFDO build. When
+ an AutoFDO profile is specified in variable
+ CLANG_AUTOFDO_PROFILE during the build process,
+ Clang uses the profile to optimize the kernel.
+
+ If no profile is specified, AutoFDO options are
+ still passed to Clang to facilitate the collection
+ of perf data for creating an AutoFDO profile in
+ subsequent builds.
+
+ If unsure, say N.
+
+config ARCH_SUPPORTS_PROPELLER_CLANG
+ bool
+
+config PROPELLER_CLANG
+ bool "Enable Clang's Propeller build"
+ depends on ARCH_SUPPORTS_PROPELLER_CLANG
+ depends on CC_IS_CLANG && CLANG_VERSION >= 190000
+ help
+ This option enables Clang’s Propeller build. When the Propeller
+ profiles is specified in variable CLANG_PROPELLER_PROFILE_PREFIX
+ during the build process, Clang uses the profiles to optimize
+ the kernel.
+
+ If no profile is specified, Propeller options are still passed
+ to Clang to facilitate the collection of perf data for creating
+ the Propeller profiles in subsequent builds.
+
+ If unsure, say N.
+
config ARCH_SUPPORTS_CFI_CLANG
bool
help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index aafebf145738..00ca7886b18e 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -264,13 +264,13 @@ stack_protector_prepare: prepare0
-mstack-protector-guard=tls \
-mstack-protector-guard-offset=$(shell \
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\
- include/generated/asm-offsets.h))
+ $(objtree)/include/generated/asm-offsets.h))
else
stack_protector_prepare: prepare0
$(eval SSP_PLUGIN_CFLAGS := \
-fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell \
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\
- include/generated/asm-offsets.h))
+ $(objtree)/include/generated/asm-offsets.h))
$(eval KBUILD_CFLAGS += $(SSP_PLUGIN_CFLAGS))
$(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
endif
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 9efd3f37c2fd..358c68565bfd 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -71,7 +71,7 @@ stack_protector_prepare: prepare0
-mstack-protector-guard-reg=sp_el0 \
-mstack-protector-guard-offset=$(shell \
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
- include/generated/asm-offsets.h))
+ $(objtree)/include/generated/asm-offsets.h))
endif
ifeq ($(CONFIG_ARM64_BTI_KERNEL),y)
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index b825ed4476c7..e3ff6179c99f 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -59,6 +59,7 @@
#endif
.endm
+ __HEAD
#ifndef CONFIG_NO_EXCEPT_FILL
/*
* Reserved space for exception handlers.
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 9ff55cb80a64..2b708fac8d2c 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -61,6 +61,7 @@ SECTIONS
/* read-only */
_text = .; /* Text and read-only data */
.text : {
+ HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 41489483a602..f3804103c56c 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -403,10 +403,12 @@ PHONY += stack_protector_prepare
stack_protector_prepare: prepare0
ifdef CONFIG_PPC64
$(eval KBUILD_CFLAGS += -mstack-protector-guard=tls -mstack-protector-guard-reg=r13 \
- -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' include/generated/asm-offsets.h))
+ -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' \
+ $(objtree)/include/generated/asm-offsets.h))
else
$(eval KBUILD_CFLAGS += -mstack-protector-guard=tls -mstack-protector-guard-reg=r2 \
- -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h))
+ -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' \
+ $(objtree)/include/generated/asm-offsets.h))
endif
endif
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 9fe1ee740dda..13fbc0f94238 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -135,7 +135,7 @@ stack_protector_prepare: prepare0
-mstack-protector-guard-reg=tp \
-mstack-protector-guard-offset=$(shell \
awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
- include/generated/asm-offsets.h))
+ $(objtree)/include/generated/asm-offsets.h))
endif
# arch specific predefines for sparse
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index d317a843f7ea..f1b86eb30340 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -48,6 +48,11 @@ SECTIONS
{
_text = .;
HEAD_TEXT
+ ALIGN_FUNCTION();
+#ifdef CONFIG_SPARC64
+ /* Match text section symbols in head_64.S first */
+ *head_64.o(.text)
+#endif
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6c633d93c639..9d7bd0ae48c4 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -128,6 +128,8 @@ config X86
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_LTO_CLANG_THIN
select ARCH_SUPPORTS_RT
+ select ARCH_SUPPORTS_AUTOFDO_CLANG
+ select ARCH_SUPPORTS_PROPELLER_CLANG if X86_64
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF if X86_CMPXCHG64
select ARCH_USE_MEMTEST
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 68efd8cd8bf1..fab3ac9a4574 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -420,6 +420,10 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+#ifdef CONFIG_PROPELLER_CLANG
+ .llvm_bb_addr_map : { *(.llvm_bb_addr_map) }
+#endif
+
ELF_DETAILS
DISCARDS
diff --git a/drivers/accessibility/speakup/Makefile b/drivers/accessibility/speakup/Makefile
index 6f6a83565c0d..14ba1cca87f4 100644
--- a/drivers/accessibility/speakup/Makefile
+++ b/drivers/accessibility/speakup/Makefile
@@ -40,9 +40,7 @@ hostprogs += makemapdata
makemapdata-objs := makemapdata.o
quiet_cmd_mkmap = MKMAP $@
- cmd_mkmap = TOPDIR=$(srctree) \
- SPKDIR=$(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD),$(srctree)/drivers/accessibility/speakup) \
- $(obj)/makemapdata > $@
+ cmd_mkmap = TOPDIR=$(srctree) SPKDIR=$(src) $(obj)/makemapdata > $@
$(obj)/mapdata.h: $(obj)/makemapdata
$(call cmd,mkmap)
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index f0b8cc23c46d..50697cc3b07e 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -2,6 +2,12 @@
config DTC
bool
+config GENERIC_BUILTIN_DTB
+ bool
+
+config BUILTIN_DTB_ALL
+ bool
+
menuconfig OF
bool "Device Tree and Open Firmware support"
help
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
index c131719367ec..d7af55a8eced 100644
--- a/drivers/usb/dwc2/Kconfig
+++ b/drivers/usb/dwc2/Kconfig
@@ -21,7 +21,7 @@ config USB_DWC2
if USB_DWC2
choice
- bool "DWC2 Mode Selection"
+ prompt "DWC2 Mode Selection"
default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET)
default USB_DWC2_HOST if (USB && !USB_GADGET)
default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET)
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 31078f3d41b8..310d182e10b5 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -23,7 +23,7 @@ config USB_DWC3_ULPI
controller.
choice
- bool "DWC3 Mode Selection"
+ prompt "DWC3 Mode Selection"
default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
default USB_DWC3_HOST if (USB && !USB_GADGET)
default USB_DWC3_GADGET if (!USB && USB_GADGET)
diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig
index 2ed2b73291d1..e19178f3cdd3 100644
--- a/drivers/usb/isp1760/Kconfig
+++ b/drivers/usb/isp1760/Kconfig
@@ -26,7 +26,7 @@ config USB_ISP1761_UDC
if USB_ISP1760
choice
- bool "ISP1760 Mode Selection"
+ prompt "ISP1760 Mode Selection"
default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
index bf98fd36341d..d281da1cdbcc 100644
--- a/drivers/usb/mtu3/Kconfig
+++ b/drivers/usb/mtu3/Kconfig
@@ -21,7 +21,7 @@ config USB_MTU3
if USB_MTU3
choice
- bool "MTU3 Mode Selection"
+ prompt "MTU3 Mode Selection"
default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET)
default USB_MTU3_HOST if (USB && !USB_GADGET)
default USB_MTU3_GADGET if (!USB && USB_GADGET)
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 9a8cf3de0617..9e45d12b81d3 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -29,7 +29,7 @@ config USB_MUSB_HDRC
if USB_MUSB_HDRC
choice
- bool "MUSB Mode Selection"
+ prompt "MUSB Mode Selection"
default USB_MUSB_DUAL_ROLE if (USB && USB_GADGET)
default USB_MUSB_HOST if (USB && !USB_GADGET)
default USB_MUSB_GADGET if (!USB && USB_GADGET)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index eeadbaeccf88..54504013c749 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -95,18 +95,25 @@
* With LTO_CLANG, the linker also splits sections by default, so we need
* these macros to combine the sections during the final link.
*
+ * With AUTOFDO_CLANG and PROPELLER_CLANG, by default, the linker splits
+ * text sections and regroups functions into subsections.
+ *
* RODATA_MAIN is not used because existing code already defines .rodata.x
* sections to be brought in with rodata.
*/
-#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
+#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG) || \
+defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
#define TEXT_MAIN .text .text.[0-9a-zA-Z_]*
+#else
+#define TEXT_MAIN .text
+#endif
+#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CLANG)
#define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..L* .data..compoundliteral* .data.$__unnamed_* .data.$L*
#define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]*
#define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L*
#define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..L* .bss..compoundliteral*
#define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]*
#else
-#define TEXT_MAIN .text
#define DATA_MAIN .data
#define SDATA_MAIN .sdata
#define RODATA_MAIN .rodata
@@ -350,9 +357,9 @@
*(.data..decrypted) \
*(.ref.data) \
*(.data..shared_aligned) /* percpu related */ \
- *(.data.unlikely) \
+ *(.data..unlikely) \
__start_once = .; \
- *(.data.once) \
+ *(.data..once) \
__end_once = .; \
STRUCT_ALIGN(); \
*(__tracepoints) \
@@ -549,24 +556,44 @@
__cpuidle_text_end = .; \
__noinstr_text_end = .;
+#define TEXT_SPLIT \
+ __split_text_start = .; \
+ *(.text.split .text.split.[0-9a-zA-Z_]*) \
+ __split_text_end = .;
+
+#define TEXT_UNLIKELY \
+ __unlikely_text_start = .; \
+ *(.text.unlikely .text.unlikely.*) \
+ __unlikely_text_end = .;
+
+#define TEXT_HOT \
+ __hot_text_start = .; \
+ *(.text.hot .text.hot.*) \
+ __hot_text_end = .;
+
/*
* .text section. Map to function alignment to avoid address changes
* during second ld run in second ld pass when generating System.map
*
- * TEXT_MAIN here will match .text.fixup and .text.unlikely if dead
- * code elimination is enabled, so these sections should be converted
- * to use ".." first.
+ * TEXT_MAIN here will match symbols with a fixed pattern (for example,
+ * .text.hot or .text.unlikely) if dead code elimination or
+ * function-section is enabled. Match these symbols first before
+ * TEXT_MAIN to ensure they are grouped together.
+ *
+ * Also placing .text.hot section at the beginning of a page, this
+ * would help the TLB performance.
*/
#define TEXT_TEXT \
ALIGN_FUNCTION(); \
- *(.text.hot .text.hot.*) \
- *(TEXT_MAIN .text.fixup) \
- *(.text.unlikely .text.unlikely.*) \
+ *(.text.asan.* .text.tsan.*) \
*(.text.unknown .text.unknown.*) \
+ TEXT_SPLIT \
+ TEXT_UNLIKELY \
+ . = ALIGN(PAGE_SIZE); \
+ TEXT_HOT \
+ *(TEXT_MAIN .text.fixup) \
NOINSTR_TEXT \
- *(.ref.text) \
- *(.text.asan.* .text.tsan.*)
-
+ *(.ref.text)
/* sched.text is aling to function alignment to secure we have same
* address even at second ld pass when generating System.map */
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 39a7714605a7..d7cb1e5ecbda 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -46,7 +46,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
} \
} while (0)
#define VM_WARN_ON_ONCE_PAGE(cond, page) ({ \
- static bool __section(".data.once") __warned; \
+ static bool __section(".data..once") __warned; \
int __ret_warn_once = !!(cond); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
@@ -66,7 +66,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
unlikely(__ret_warn); \
})
#define VM_WARN_ON_ONCE_FOLIO(cond, folio) ({ \
- static bool __section(".data.once") __warned; \
+ static bool __section(".data..once") __warned; \
int __ret_warn_once = !!(cond); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
@@ -77,7 +77,7 @@ void vma_iter_dump_tree(const struct vma_iterator *vmi);
unlikely(__ret_warn_once); \
})
#define VM_WARN_ON_ONCE_MM(cond, mm) ({ \
- static bool __section(".data.once") __warned; \
+ static bool __section(".data..once") __warned; \
int __ret_warn_once = !!(cond); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
diff --git a/include/linux/module.h b/include/linux/module.h
index 2a9386cbdf85..c60ee39cb9b1 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -247,7 +247,7 @@ extern void cleanup_module(void);
#ifdef MODULE
/* Creates an alias so file2alias.c can find device table. */
#define MODULE_DEVICE_TABLE(type, name) \
-extern typeof(name) __mod_##type##__##name##_device_table \
+extern typeof(name) __mod_device_table__##type##__##name \
__attribute__ ((unused, alias(__stringify(name))))
#else /* !MODULE */
#define MODULE_DEVICE_TABLE(type, name)
diff --git a/include/linux/once.h b/include/linux/once.h
index bc714d414448..30346fcdc799 100644
--- a/include/linux/once.h
+++ b/include/linux/once.h
@@ -46,7 +46,7 @@ void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,
#define DO_ONCE(func, ...) \
({ \
bool ___ret = false; \
- static bool __section(".data.once") ___done = false; \
+ static bool __section(".data..once") ___done = false; \
static DEFINE_STATIC_KEY_TRUE(___once_key); \
if (static_branch_unlikely(&___once_key)) { \
unsigned long ___flags; \
@@ -64,7 +64,7 @@ void __do_once_sleepable_done(bool *done, struct static_key_true *once_key,
#define DO_ONCE_SLEEPABLE(func, ...) \
({ \
bool ___ret = false; \
- static bool __section(".data.once") ___done = false; \
+ static bool __section(".data..once") ___done = false; \
static DEFINE_STATIC_KEY_TRUE(___once_key); \
if (static_branch_unlikely(&___once_key)) { \
___ret = __do_once_sleepable_start(&___done); \
diff --git a/include/linux/once_lite.h b/include/linux/once_lite.h
index b7bce4983638..27de7bc32a06 100644
--- a/include/linux/once_lite.h
+++ b/include/linux/once_lite.h
@@ -12,7 +12,7 @@
#define __ONCE_LITE_IF(condition) \
({ \
- static bool __section(".data.once") __already_done; \
+ static bool __section(".data..once") __already_done; \
bool __ret_cond = !!(condition); \
bool __ret_once = false; \
\
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 58d84c59f3dd..48e5c03df1dd 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -401,7 +401,7 @@ static inline int debug_lockdep_rcu_enabled(void)
*/
#define RCU_LOCKDEP_WARN(c, s) \
do { \
- static bool __section(".data.unlikely") __warned; \
+ static bool __section(".data..unlikely") __warned; \
if (debug_lockdep_rcu_enabled() && (c) && \
debug_lockdep_rcu_enabled() && !__warned) { \
__warned = true; \
diff --git a/include/net/net_debug.h b/include/net/net_debug.h
index 9fecb1496be3..47f7a4a878b9 100644
--- a/include/net/net_debug.h
+++ b/include/net/net_debug.h
@@ -27,7 +27,7 @@ void netdev_info(const struct net_device *dev, const char *format, ...);
#define netdev_level_once(level, dev, fmt, ...) \
do { \
- static bool __section(".data.once") __print_once; \
+ static bool __section(".data..once") __print_once; \
\
if (!__print_once) { \
__print_once = true; \
diff --git a/mm/internal.h b/mm/internal.h
index 5a7302baeed7..cb8d8e8e3ffa 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -49,7 +49,7 @@ struct folio_batch;
* when we specify __GFP_NOWARN.
*/
#define WARN_ON_ONCE_GFP(cond, gfp) ({ \
- static bool __section(".data.once") __warned; \
+ static bool __section(".data..once") __warned; \
int __ret_warn_once = !!(cond); \
\
if (unlikely(!(gfp & __GFP_NOWARN) && __ret_warn_once && !__warned)) { \
diff --git a/rust/Makefile b/rust/Makefile
index 01cf8e6ba3b3..9da9042fd627 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -372,8 +372,8 @@ rust-analyzer:
$(Q)$(srctree)/scripts/generate_rust_analyzer.py \
--cfgs='core=$(core-cfgs)' \
$(realpath $(srctree)) $(realpath $(objtree)) \
- $(rustc_sysroot) $(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
- $(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
+ $(rustc_sysroot) $(RUST_LIB_SRC) $(if $(KBUILD_EXTMOD),$(srcroot)) \
+ > rust-project.json
redirect-intrinsics = \
__addsf3 __eqsf2 __extendsfdf2 __gesf2 __lesf2 __ltsf2 __mulsf3 __nesf2 __truncdfsf2 __unordsf2 \
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index ed8a7493524b..8c311b997e24 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -205,7 +205,7 @@ if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:)
cmd_and_fixdep = \
$(cmd); \
- scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
+ $(objtree)/scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
rm -f $(depfile)
# Usage: $(call if_changed_rule,foo)
diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo
new file mode 100644
index 000000000000..1caf2457e585
--- /dev/null
+++ b/scripts/Makefile.autofdo
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Enable available and selected Clang AutoFDO features.
+
+CFLAGS_AUTOFDO_CLANG := -fdebug-info-for-profiling -mllvm -enable-fs-discriminator=true -mllvm -improved-fs-discriminator=true
+
+ifndef CONFIG_DEBUG_INFO
+ CFLAGS_AUTOFDO_CLANG += -gmlt
+endif
+
+ifdef CLANG_AUTOFDO_PROFILE
+ CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -ffunction-sections
+ CFLAGS_AUTOFDO_CLANG += -fsplit-machine-functions
+endif
+
+ifdef CONFIG_LTO_CLANG_THIN
+ ifdef CLANG_AUTOFDO_PROFILE
+ KBUILD_LDFLAGS += --lto-sample-profile=$(CLANG_AUTOFDO_PROFILE)
+ endif
+ KBUILD_LDFLAGS += --mllvm=-enable-fs-discriminator=true --mllvm=-improved-fs-discriminator=true -plugin-opt=thinlto
+ KBUILD_LDFLAGS += -plugin-opt=-split-machine-functions
+endif
+
+export CFLAGS_AUTOFDO_CLANG
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index f483a54380e7..c16e4cf54d77 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -3,7 +3,7 @@
# Building
# ==========================================================================
-src := $(if $(VPATH),$(VPATH)/)$(obj)
+src := $(srcroot)/$(obj)
PHONY := $(obj)/
$(obj)/:
@@ -34,7 +34,7 @@ subdir-asflags-y :=
subdir-ccflags-y :=
# Read auto.conf if it exists, otherwise ignore
--include include/config/auto.conf
+-include $(objtree)/include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
include $(srctree)/scripts/Makefile.compiler
@@ -107,20 +107,14 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $<
$(obj)/%.i: $(obj)/%.c FORCE
$(call if_changed_dep,cpp_i_c)
-genksyms = scripts/genksyms/genksyms \
- $(if $(1), -T $(2)) \
- $(if $(KBUILD_PRESERVE), -p) \
- -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null)
+genksyms = $(objtree)/scripts/genksyms/genksyms \
+ $(if $(KBUILD_SYMTYPES), -T $(@:.o=.symtypes)) \
+ $(if $(KBUILD_PRESERVE), -p) \
+ $(addprefix -r , $(wildcard $(@:.o=.symref)))
# These mirror gensymtypes_S and co below, keep them in synch.
cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms)
-quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
- cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null
-
-$(obj)/%.symtypes : $(obj)/%.c FORCE
- $(call cmd,cc_symtypes_c)
-
# LLVM assembly
# Generate .ll files from .c
quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@
@@ -135,17 +129,6 @@ $(obj)/%.ll: $(obj)/%.c FORCE
is-single-obj-m = $(and $(part-of-module),$(filter $@, $(obj-m)),y)
-# When a module consists of a single object, there is no reason to keep LLVM IR.
-# Make $(LD) covert LLVM IR to ELF here.
-ifdef CONFIG_LTO_CLANG
-cmd_ld_single_m = $(if $(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@)
-endif
-
-quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
- cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \
- $(cmd_ld_single_m) \
- $(cmd_objtool)
-
ifdef CONFIG_MODVERSIONS
# When module versioning is enabled the following steps are executed:
# o compile a <file>.o from <file>.c
@@ -158,8 +141,7 @@ ifdef CONFIG_MODVERSIONS
gen_symversions = \
if $(NM) $@ 2>/dev/null | grep -q ' __export_symbol_'; then \
- $(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
- >> $(dot-target).cmd; \
+ $(cmd_gensymtypes_$1) >> $(dot-target).cmd; \
fi
cmd_gen_symversions_c = $(call gen_symversions,c)
@@ -207,23 +189,6 @@ ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
cmd_warn_shared_object = $(if $(word 2, $(modname-multi)),$(warning $(kbuild-file): $*.o is added to multiple modules: $(modname-multi)))
endif
-define rule_cc_o_c
- $(call cmd_and_fixdep,cc_o_c)
- $(call cmd,checksrc)
- $(call cmd,checkdoc)
- $(call cmd,gen_objtooldep)
- $(call cmd,gen_symversions_c)
- $(call cmd,record_mcount)
- $(call cmd,warn_shared_object)
-endef
-
-define rule_as_o_S
- $(call cmd_and_fixdep,as_o_S)
- $(call cmd,gen_objtooldep)
- $(call cmd,gen_symversions_S)
- $(call cmd,warn_shared_object)
-endef
-
# Built-in and composite module parts
$(obj)/%.o: $(obj)/%.c $(recordmcount_source) FORCE
$(call if_changed_rule,cc_o_c)
@@ -330,22 +295,12 @@ cmd_gensymtypes_S = \
$(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' ; } | \
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms)
-quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
- cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null
-
-$(obj)/%.symtypes : $(obj)/%.S FORCE
- $(call cmd,cc_symtypes_S)
-
-
quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@
cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $<
$(obj)/%.s: $(obj)/%.S FORCE
$(call if_changed_dep,cpp_s_S)
-quiet_cmd_as_o_S = AS $(quiet_modtag) $@
- cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool)
-
ifdef CONFIG_ASM_MODVERSIONS
# versioning matches the C process described above, with difference that
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
index 4fcfab40ed61..6ead00ec7313 100644
--- a/scripts/Makefile.clean
+++ b/scripts/Makefile.clean
@@ -3,7 +3,7 @@
# Cleaning up
# ==========================================================================
-src := $(if $(VPATH),$(VPATH)/)$(obj)
+src := $(srcroot)/$(obj)
PHONY := __clean
__clean:
diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler
index e0842496d26e..8c1029687e2e 100644
--- a/scripts/Makefile.compiler
+++ b/scripts/Makefile.compiler
@@ -13,7 +13,7 @@ cc-cross-prefix = $(firstword $(foreach c, $(1), \
$(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c))))
# output directory for tests below
-TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$
+TMPOUT = .tmp_$$$$
# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index e01c13a588dd..c1dedf646a39 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -96,12 +96,10 @@ hostrust_flags = --out-dir $(dir $@) --emit=dep-info=$(depfile) \
$(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \
$(HOSTRUSTFLAGS_$(target-stem))
-# $(objtree)/$(obj) for including generated headers from checkin source files
-ifeq ($(KBUILD_EXTMOD),)
+# $(obj) for including generated headers from checkin source files
ifdef building_out_of_srctree
-hostc_flags += -I $(objtree)/$(obj)
-hostcxx_flags += -I $(objtree)/$(obj)
-endif
+hostc_flags += -I $(obj)
+hostcxx_flags += -I $(obj)
endif
#####
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 01a9f567d5af..7395200538da 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -191,15 +191,33 @@ _c_flags += $(if $(patsubst n%,, \
-D__KCSAN_INSTRUMENT_BARRIERS__)
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).
+#
+ifeq ($(CONFIG_AUTOFDO_CLANG),y)
+_c_flags += $(if $(patsubst n%,, \
+ $(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(is-kernel-object)), \
+ $(CFLAGS_AUTOFDO_CLANG))
+endif
+
+#
+# Enable Propeller build flags except some files or directories we don't want to
+# enable (depends on variables AUTOFDO_PROPELLER_obj.o and PROPELLER_PROFILE).
+#
+ifdef CONFIG_PROPELLER_CLANG
+_c_flags += $(if $(patsubst n%,, \
+ $(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(PROPELLER_PROFILE))$(is-kernel-object), \
+ $(CFLAGS_PROPELLER_CLANG))
+endif
+
# $(src) for including checkin headers from generated source files
# $(obj) for including generated headers from checkin source files
-ifeq ($(KBUILD_EXTMOD),)
ifdef building_out_of_srctree
_c_flags += $(addprefix -I, $(src) $(obj))
_a_flags += $(addprefix -I, $(src) $(obj))
_cpp_flags += $(addprefix -I, $(src) $(obj))
endif
-endif
# If $(is-kernel-object) is 'y', this object will be linked to vmlinux or modules
is-kernel-object = $(or $(part-of-builtin),$(part-of-module))
@@ -280,6 +298,42 @@ $(foreach m, $1, \
$(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3))))
endef
+# Build commands
+# ===========================================================================
+# These are shared by some Makefile.* files.
+
+objtool-enabled := y
+
+ifdef CONFIG_LTO_CLANG
+# objtool cannot process LLVM IR. Make $(LD) covert LLVM IR to ELF here.
+cmd_ld_single = $(if $(objtool-enabled), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@)
+endif
+
+quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
+ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \
+ $(cmd_ld_single) \
+ $(cmd_objtool)
+
+define rule_cc_o_c
+ $(call cmd_and_fixdep,cc_o_c)
+ $(call cmd,checksrc)
+ $(call cmd,checkdoc)
+ $(call cmd,gen_objtooldep)
+ $(call cmd,gen_symversions_c)
+ $(call cmd,record_mcount)
+ $(call cmd,warn_shared_object)
+endef
+
+quiet_cmd_as_o_S = AS $(quiet_modtag) $@
+ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool)
+
+define rule_as_o_S
+ $(call cmd_and_fixdep,as_o_S)
+ $(call cmd,gen_objtooldep)
+ $(call cmd,gen_symversions_S)
+ $(call cmd,warn_shared_object)
+endef
+
# Copy a file
# ===========================================================================
# 'cp' preserves permissions. If you use it to copy a file in read-only srctree,
@@ -371,10 +425,10 @@ quiet_cmd_lzo_with_size = LZO $@
cmd_lzo_with_size = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@
quiet_cmd_lz4 = LZ4 $@
- cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout > $@
+ cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -9 - - > $@
quiet_cmd_lz4_with_size = LZ4 $@
- cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \
+ cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -9 - -; \
$(size_append); } > $@
# U-Boot mkimage
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 1482884ec3ca..542ba462ed3e 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -6,14 +6,12 @@
PHONY := __modfinal
__modfinal:
-include include/config/auto.conf
+include $(objtree)/include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-
-# for c_flags
include $(srctree)/scripts/Makefile.lib
# find all modules listed in modules.order
-modules := $(call read-file, $(MODORDER))
+modules := $(call read-file, modules.order)
__modfinal: $(modules:%.o=%.ko)
@:
@@ -22,30 +20,27 @@ __modfinal: $(modules:%.o=%.ko)
modname = $(notdir $(@:.mod.o=))
part-of-module = y
GCOV_PROFILE := n
-KCSAN_SANITIZE := n
-
-quiet_cmd_cc_o_c = CC [M] $@
- cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI), $(c_flags)) -c -o $@ $<
+ccflags-remove-y := $(CC_FLAGS_CFI)
%.mod.o: %.mod.c FORCE
- $(call if_changed_dep,cc_o_c)
+ $(call if_changed_rule,cc_o_c)
-$(extmod_prefix).module-common.o: $(srctree)/scripts/module-common.c FORCE
- $(call if_changed_dep,cc_o_c)
+.module-common.o: $(srctree)/scripts/module-common.c FORCE
+ $(call if_changed_rule,cc_o_c)
quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = \
$(LD) -r $(KBUILD_LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
- -T scripts/module.lds -o $@ $(filter %.o, $^)
+ -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^)
quiet_cmd_btf_ko = BTF [M] $@
cmd_btf_ko = \
- if [ ! -f vmlinux ]; then \
+ 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 vmlinux $@; \
- $(RESOLVE_BTFIDS) -b vmlinux $@; \
+ LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base $(objtree)/vmlinux $@; \
+ $(RESOLVE_BTFIDS) -b $(objtree)/vmlinux $@; \
fi;
# Same as newer-prereqs, but allows to exclude specified extra dependencies
@@ -57,13 +52,13 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \
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 $(extmod_prefix).module-common.o scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),vmlinux) FORCE
- +$(call if_changed_except,ld_ko_o,vmlinux)
+%.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)
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+$(if $(newer-prereqs),$(call cmd,btf_ko))
endif
-targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) $(extmod_prefix).module-common.o
+targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) .module-common.o
# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index d97720943189..f97c9926ed31 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -6,7 +6,7 @@
PHONY := __modinst
__modinst:
-include include/config/auto.conf
+include $(objtree)/include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
install-y :=
@@ -40,7 +40,7 @@ $(addprefix $(MODLIB)/, modules.builtin modules.builtin.modinfo modules.builtin.
endif
-modules := $(call read-file, $(MODORDER))
+modules := $(call read-file, modules.order)
ifeq ($(KBUILD_EXTMOD),)
dst := $(MODLIB)/kernel
@@ -59,7 +59,7 @@ suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz
suffix-$(CONFIG_MODULE_COMPRESS_ZSTD) := .zst
endif
-modules := $(patsubst $(extmod_prefix)%.o, $(dst)/%.ko$(suffix-y), $(modules))
+modules := $(patsubst %.o, $(dst)/%.ko$(suffix-y), $(modules))
install-$(CONFIG_MODULES) += $(modules)
__modinst: $(install-y)
@@ -119,7 +119,7 @@ endif
# Create necessary directories
$(foreach dir, $(sort $(dir $(install-y))), $(shell mkdir -p $(dir)))
-$(dst)/%.ko: $(extmod_prefix)%.ko FORCE
+$(dst)/%.ko: %.ko FORCE
$(call cmd,install)
$(call cmd,strip)
$(call cmd,sign)
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 44936ebad161..ab0e94ea6249 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -35,10 +35,10 @@
PHONY := __modpost
__modpost:
-include include/config/auto.conf
+include $(objtree)/include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-MODPOST = scripts/mod/modpost
+MODPOST = $(objtree)/scripts/mod/modpost
modpost-args = \
$(if $(CONFIG_MODULES),-M) \
@@ -46,7 +46,7 @@ modpost-args = \
$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \
$(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \
$(if $(KBUILD_MODPOST_WARN),-w) \
- $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \
+ $(if $(KBUILD_NSDEPS),-d modules.nsdeps) \
$(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) \
$(if $(findstring 1, $(KBUILD_EXTRA_WARN)),-W) \
-o $@
@@ -61,8 +61,8 @@ endif
# Read out modules.order to pass in modpost.
# Otherwise, allmodconfig would fail with "Argument list too long".
ifdef KBUILD_MODULES
-modpost-args += -T $(MODORDER)
-modpost-deps += $(MODORDER)
+modpost-args += -T modules.order
+modpost-deps += modules.order
endif
ifeq ($(KBUILD_EXTMOD),)
@@ -111,19 +111,19 @@ endif
else
# set src + obj - they may be used in the modules's Makefile
-obj := $(KBUILD_EXTMOD)
-src := $(if $(VPATH),$(VPATH)/)$(obj)
+obj := .
+src := $(srcroot)
# Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS
include $(kbuild-file)
-output-symdump := $(KBUILD_EXTMOD)/Module.symvers
+output-symdump := Module.symvers
-ifeq ($(wildcard Module.symvers),)
-missing-input := Module.symvers
+ifeq ($(wildcard $(objtree)/Module.symvers),)
+missing-input := $(objtree)/Module.symvers
else
-modpost-args += -i Module.symvers
-modpost-deps += Module.symvers
+modpost-args += -i $(objtree)/Module.symvers
+modpost-deps += $(objtree)/Module.symvers
endif
modpost-args += -e $(addprefix -i , $(KBUILD_EXTRA_SYMBOLS))
diff --git a/scripts/Makefile.propeller b/scripts/Makefile.propeller
new file mode 100644
index 000000000000..48a660128e25
--- /dev/null
+++ b/scripts/Makefile.propeller
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# Enable available and selected Clang Propeller features.
+ifdef CLANG_PROPELLER_PROFILE_PREFIX
+ CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=list=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt -ffunction-sections
+ KBUILD_LDFLAGS += --symbol-ordering-file=$(CLANG_PROPELLER_PROFILE_PREFIX)_ld_profile.txt --no-warn-symbol-ordering
+else
+ # Starting with Clang v20, the '-fbasic-block-sections=labels' option is
+ # deprecated. Use the recommended '-fbasic-block-address-map' option.
+ # Link: https://github.com/llvm/llvm-project/pull/110039
+ ifeq ($(call clang-min-version, 200000),y)
+ CFLAGS_PROPELLER_CLANG := -fbasic-block-address-map
+ else
+ CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=labels
+ endif
+endif
+
+# Propeller requires debug information to embed module names in the profiles.
+# If CONFIG_DEBUG_INFO is not enabled, set -gmlt option. Skip this for AutoFDO,
+# as the option should already be set.
+ifndef CONFIG_DEBUG_INFO
+ ifndef CONFIG_AUTOFDO_CLANG
+ CFLAGS_PROPELLER_CLANG += -gmlt
+ endif
+endif
+
+ifdef CONFIG_LTO_CLANG_THIN
+ ifdef CLANG_PROPELLER_PROFILE_PREFIX
+ KBUILD_LDFLAGS += --lto-basic-block-sections=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt
+ else
+ ifeq ($(call test-ge, $(CONFIG_LLD_VERSION), 200000),y)
+ KBUILD_LDFLAGS += --lto-basic-block-address-map
+ else
+ KBUILD_LDFLAGS += --lto-basic-block-sections=labels
+ endif
+ endif
+endif
+
+export CFLAGS_PROPELLER_CLANG
diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index dddad554e912..873caaa55313 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -5,17 +5,53 @@ __default: vmlinux
include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-
-# for c_flags
include $(srctree)/scripts/Makefile.lib
targets :=
-quiet_cmd_cc_o_c = CC $@
- cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
-
%.o: %.c FORCE
- $(call if_changed_dep,cc_o_c)
+ $(call if_changed_rule,cc_o_c)
+
+%.o: %.S FORCE
+ $(call if_changed_rule,as_o_S)
+
+# Built-in dtb
+# ---------------------------------------------------------------------------
+
+quiet_cmd_wrap_dtbs = WRAP $@
+ cmd_wrap_dtbs = { \
+ echo '\#include <asm-generic/vmlinux.lds.h>'; \
+ echo '.section .dtb.init.rodata,"a"'; \
+ while read dtb; do \
+ symbase=__dtb_$$(basename -s .dtb "$${dtb}" | tr - _); \
+ echo '.balign STRUCT_ALIGNMENT'; \
+ echo ".global $${symbase}_begin"; \
+ echo "$${symbase}_begin:"; \
+ echo '.incbin "'$$dtb'" '; \
+ echo ".global $${symbase}_end"; \
+ echo "$${symbase}_end:"; \
+ done < $<; \
+ } > $@
+
+.builtin-dtbs.S: .builtin-dtbs-list FORCE
+ $(call if_changed,wrap_dtbs)
+
+quiet_cmd_gen_dtbs_list = GEN $@
+ cmd_gen_dtbs_list = \
+ $(if $(CONFIG_BUILTIN_DTB_NAME), echo "arch/$(SRCARCH)/boot/dts/$(CONFIG_BUILTIN_DTB_NAME).dtb",:) > $@
+
+.builtin-dtbs-list: arch/$(SRCARCH)/boot/dts/dtbs-list FORCE
+ $(call if_changed,$(if $(CONFIG_BUILTIN_DTB_ALL),copy,gen_dtbs_list))
+
+targets += .builtin-dtbs-list
+
+ifdef CONFIG_GENERIC_BUILTIN_DTB
+targets += .builtin-dtbs.S .builtin-dtbs.o
+vmlinux: .builtin-dtbs.o
+endif
+
+# vmlinux
+# ---------------------------------------------------------------------------
ifdef CONFIG_MODULES
targets += .vmlinux.export.o
@@ -39,6 +75,9 @@ cmd_link_vmlinux = \
targets += vmlinux
vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE
+$(call if_changed_dep,link_vmlinux)
+ifdef CONFIG_DEBUG_INFO_BTF
+vmlinux: $(RESOLVE_BTFIDS)
+endif
# module.builtin.ranges
# ---------------------------------------------------------------------------
diff --git a/scripts/coccicheck b/scripts/coccicheck
index e52cb43fede6..0e6bc5a10320 100755
--- a/scripts/coccicheck
+++ b/scripts/coccicheck
@@ -80,11 +80,7 @@ command results in a shift count error.'
NPROC=1
else
ONLINE=0
- if [ "$KBUILD_EXTMOD" = "" ] ; then
- OPTIONS="--dir $srctree $COCCIINCLUDE"
- else
- OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE"
- fi
+ OPTIONS="--dir $srcroot $COCCIINCLUDE"
# Use only one thread per core by default if hyperthreading is enabled
THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]")
diff --git a/scripts/depmod.sh b/scripts/depmod.sh
index e22da27fe13e..3c34fecacbc8 100755
--- a/scripts/depmod.sh
+++ b/scripts/depmod.sh
@@ -12,7 +12,7 @@ KERNELRELEASE=$1
: ${DEPMOD:=depmod}
-if ! test -r System.map ; then
+if ! test -r "${objtree}/System.map" ; then
echo "Warning: modules_install: missing 'System.map' file. Skipping depmod." >&2
exit 0
fi
@@ -25,7 +25,7 @@ if [ -z $(command -v $DEPMOD) ]; then
exit 0
fi
-set -- -ae -F System.map
+set -- -ae -F "${objtree}/System.map"
if test -n "$INSTALL_MOD_PATH"; then
set -- "$@" -b "$INSTALL_MOD_PATH"
fi
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index f3901c55df23..07f9b8cfb233 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -632,54 +632,55 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
void export_symbol(const char *name)
{
struct symbol *sym;
+ unsigned long crc;
+ int has_changed = 0;
sym = find_symbol(name, SYM_NORMAL, 0);
- if (!sym)
+ if (!sym) {
error_with_pos("export undefined symbol %s", name);
- else {
- unsigned long crc;
- int has_changed = 0;
+ return;
+ }
- if (flag_dump_defs)
- fprintf(debugfile, "Export %s == <", name);
+ if (flag_dump_defs)
+ fprintf(debugfile, "Export %s == <", name);
- expansion_trail = (struct symbol *)-1L;
+ expansion_trail = (struct symbol *)-1L;
- sym->expansion_trail = expansion_trail;
- expansion_trail = sym;
- crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
+ sym->expansion_trail = expansion_trail;
+ expansion_trail = sym;
+ crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
- sym = expansion_trail;
- while (sym != (struct symbol *)-1L) {
- struct symbol *n = sym->expansion_trail;
+ sym = expansion_trail;
+ while (sym != (struct symbol *)-1L) {
+ struct symbol *n = sym->expansion_trail;
- if (sym->status != STATUS_UNCHANGED) {
- if (!has_changed) {
- print_location();
- fprintf(stderr, "%s: %s: modversion "
- "changed because of changes "
- "in ", flag_preserve ? "error" :
- "warning", name);
- } else
- fprintf(stderr, ", ");
- print_type_name(sym->type, sym->name);
- if (sym->status == STATUS_DEFINED)
- fprintf(stderr, " (became defined)");
- has_changed = 1;
- if (flag_preserve)
- errors++;
+ if (sym->status != STATUS_UNCHANGED) {
+ if (!has_changed) {
+ print_location();
+ fprintf(stderr,
+ "%s: %s: modversion changed because of changes in ",
+ flag_preserve ? "error" : "warning",
+ name);
+ } else {
+ fprintf(stderr, ", ");
}
- sym->expansion_trail = 0;
- sym = n;
+ print_type_name(sym->type, sym->name);
+ if (sym->status == STATUS_DEFINED)
+ fprintf(stderr, " (became defined)");
+ has_changed = 1;
+ if (flag_preserve)
+ errors++;
}
- if (has_changed)
- fprintf(stderr, "\n");
+ sym->expansion_trail = 0;
+ sym = n;
+ }
+ if (has_changed)
+ fprintf(stderr, "\n");
- if (flag_dump_defs)
- fputs(">\n", debugfile);
+ if (flag_dump_defs)
+ fputs(">\n", debugfile);
- printf("#SYMVER %s 0x%08lx\n", name, crc);
- }
+ printf("#SYMVER %s 0x%08lx\n", name, crc);
}
/*----------------------------------------------------------------------*/
diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt
index fd5d00bac447..f12b4a7b8406 100644
--- a/scripts/head-object-list.txt
+++ b/scripts/head-object-list.txt
@@ -23,7 +23,6 @@ arch/m68k/coldfire/head.o
arch/m68k/kernel/head.o
arch/m68k/kernel/sun3-head.o
arch/microblaze/kernel/head.o
-arch/mips/kernel/head.o
arch/nios2/kernel/head.o
arch/openrisc/kernel/head.o
arch/parisc/kernel/head.o
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 3d7d454c54da..8abe57041955 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -628,7 +628,7 @@ static const struct option long_opts[] = {
static void conf_usage(const char *progname)
{
- printf("Usage: %s [options] <kconfig-file>\n", progname);
+ printf("Usage: %s [options] kconfig_file\n", progname);
printf("\n");
printf("Generic options:\n");
printf(" -h, --help Print this message and exit.\n");
@@ -653,6 +653,9 @@ static void conf_usage(const char *progname)
printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
printf(" --mod2noconfig Change answers from mod to no if possible\n");
printf(" (If none of the above is given, --oldaskconfig is the default)\n");
+ printf("\n");
+ printf("Arguments:\n");
+ printf(" kconfig_file Top-level Kconfig file.\n");
}
int main(int ac, char **av)
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 63519cd24bc7..8914b4e8f2a8 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -34,6 +34,7 @@ bool sym_string_valid(struct symbol *sym, const char *newval);
bool sym_string_within_range(struct symbol *sym, const char *str);
bool sym_set_string_value(struct symbol *sym, const char *newval);
bool sym_is_changeable(const struct symbol *sym);
+struct menu *sym_get_prompt_menu(const struct symbol *sym);
struct menu *sym_get_choice_menu(const struct symbol *sym);
const char * sym_get_string_value(struct symbol *sym);
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index 063b4f7ccbdb..c0b2dabf6c89 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -467,7 +467,7 @@ static void handle_f9(int *key, struct menu *current_item)
return;
}
-/* return != 0 to indicate the key was handles */
+/* return != 0 to indicate the key was handled */
static int process_special_keys(int *key, struct menu *menu)
{
int i;
diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c
index 72b605efe549..4bfdf8ac2a9a 100644
--- a/scripts/kconfig/nconf.gui.c
+++ b/scripts/kconfig/nconf.gui.c
@@ -277,6 +277,15 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
case KEY_RIGHT:
menu_driver(menu, REQ_RIGHT_ITEM);
break;
+ case 9: /* TAB */
+ if (btn_num > 1) {
+ /* cycle through buttons */
+ if (item_index(current_item(menu)) == btn_num - 1)
+ menu_driver(menu, REQ_FIRST_ITEM);
+ else
+ menu_driver(menu, REQ_NEXT_ITEM);
+ }
+ break;
case 10: /* ENTER */
case 27: /* ESCAPE */
case ' ':
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
index bc43fb67c7c4..68372d3ff325 100644
--- a/scripts/kconfig/parser.y
+++ b/scripts/kconfig/parser.y
@@ -24,7 +24,6 @@
int cdebug = PRINTD;
static void yyerror(const char *err);
-static void zconfprint(const char *err, ...);
static void zconf_error(const char *err, ...);
static bool zconf_endtoken(const char *tokenname,
const char *expected_tokenname);
@@ -183,7 +182,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
if (current_entry->prompt)
current_entry->prompt->type = P_MENU;
else
- zconfprint("warning: menuconfig statement without prompt");
+ zconf_error("menuconfig statement without prompt");
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
};
@@ -293,12 +292,6 @@ choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
};
-choice_option: T_BOOL T_WORD_QUOTE if_expr T_EOL
-{
- menu_add_prompt(P_PROMPT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:bool\n", cur_filename, cur_lineno);
-};
-
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_DEFAULT, $2, $3);
@@ -408,14 +401,14 @@ help: help_start T_HELPTEXT
{
if (current_entry->help) {
free(current_entry->help);
- zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used",
- current_entry->sym->name ?: "<choice>");
+ zconf_error("'%s' defined with more than one help text",
+ current_entry->sym->name ?: "<choice>");
}
/* Is the help text empty or all whitespace? */
if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
- zconfprint("warning: '%s' defined with blank help text",
- current_entry->sym->name ?: "<choice>");
+ zconf_error("'%s' defined with blank help text",
+ current_entry->sym->name ?: "<choice>");
current_entry->help = $2;
};
@@ -598,17 +591,6 @@ static bool zconf_endtoken(const char *tokenname,
return true;
}
-static void zconfprint(const char *err, ...)
-{
- va_list ap;
-
- fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
- va_start(ap, err);
- vfprintf(stderr, err, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-}
-
static void zconf_error(const char *err, ...)
{
va_list ap;
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index e260cab1c2af..6c92ef1e16ef 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -110,7 +110,7 @@ void ConfigItem::updateMenu(void)
if (prop) switch (prop->type) {
case P_MENU:
- if (list->mode == singleMode || list->mode == symbolMode) {
+ if (list->mode == singleMode) {
/* a menuconfig entry is displayed differently
* depending whether it's at the view root or a child.
*/
@@ -159,7 +159,7 @@ void ConfigItem::updateMenu(void)
ch = 'M';
break;
default:
- if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ if (sym_is_choice_value(sym))
setIcon(promptColIdx, choiceNoIcon);
else
setIcon(promptColIdx, symbolNoIcon);
@@ -175,17 +175,16 @@ void ConfigItem::updateMenu(void)
setText(dataColIdx, sym_get_string_value(sym));
break;
}
- if (!sym_has_value(sym) && visible)
+ if (!sym_has_value(sym))
prompt += " (NEW)";
set_prompt:
setText(promptColIdx, prompt);
}
-void ConfigItem::testUpdateMenu(bool v)
+void ConfigItem::testUpdateMenu(void)
{
ConfigItem* i;
- visible = v;
if (!menu)
return;
@@ -307,7 +306,6 @@ ConfigList::ConfigList(QWidget *parent, const char *name)
{
setObjectName(name);
setSortingEnabled(false);
- setRootIsDecorated(true);
setVerticalScrollMode(ScrollPerPixel);
setHorizontalScrollMode(ScrollPerPixel);
@@ -430,27 +428,26 @@ void ConfigList::updateList()
item = (ConfigItem*)(*it);
if (!item->menu)
continue;
- item->testUpdateMenu(menu_is_visible(item->menu));
+ item->testUpdateMenu();
++it;
}
return;
}
- if (rootEntry != &rootmenu && (mode == singleMode ||
- (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+ if (rootEntry != &rootmenu && mode == singleMode) {
item = (ConfigItem *)topLevelItem(0);
if (!item)
- item = new ConfigItem(this, 0, true);
+ item = new ConfigItem(this, 0);
last = item;
}
if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
rootEntry->sym && rootEntry->prompt) {
item = last ? last->nextSibling() : nullptr;
if (!item)
- item = new ConfigItem(this, last, rootEntry, true);
+ item = new ConfigItem(this, last, rootEntry);
else
- item->testUpdateMenu(true);
+ item->testUpdateMenu();
updateMenuList(item, rootEntry);
update();
@@ -599,7 +596,6 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
struct menu* child;
ConfigItem* item;
ConfigItem* last;
- bool visible;
enum prop_type type;
if (!menu) {
@@ -631,14 +627,13 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
break;
}
- visible = menu_is_visible(child);
if (!menuSkip(child)) {
if (!child->sym && !child->list && !child->prompt)
continue;
if (!item || item->menu != child)
- item = new ConfigItem(parent, last, child, visible);
+ item = new ConfigItem(parent, last, child);
else
- item->testUpdateMenu(visible);
+ item->testUpdateMenu();
if (mode == fullMode || mode == menuMode || type != P_MENU)
updateMenuList(item, child);
@@ -664,7 +659,6 @@ void ConfigList::updateMenuList(struct menu *menu)
struct menu* child;
ConfigItem* item;
ConfigItem* last;
- bool visible;
enum prop_type type;
if (!menu) {
@@ -696,14 +690,13 @@ void ConfigList::updateMenuList(struct menu *menu)
break;
}
- visible = menu_is_visible(child);
if (!menuSkip(child)) {
if (!child->sym && !child->list && !child->prompt)
continue;
if (!item || item->menu != child)
- item = new ConfigItem(this, last, child, visible);
+ item = new ConfigItem(this, last, child);
else
- item->testUpdateMenu(visible);
+ item->testUpdateMenu();
if (mode == fullMode || mode == menuMode || type != P_MENU)
updateMenuList(item, child);
@@ -731,7 +724,7 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
struct menu *menu;
enum prop_type type;
- if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
+ if (ev->key() == Qt::Key_Escape && mode == singleMode) {
emit parentSelected();
ev->accept();
return;
@@ -781,13 +774,6 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
ev->accept();
}
-void ConfigList::mousePressEvent(QMouseEvent* e)
-{
- //QPoint p(contentsToViewport(e->pos()));
- //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
- Parent::mousePressEvent(e);
-}
-
void ConfigList::mouseReleaseEvent(QMouseEvent* e)
{
QPoint p = e->pos();
@@ -834,13 +820,6 @@ skip:
Parent::mouseReleaseEvent(e);
}
-void ConfigList::mouseMoveEvent(QMouseEvent* e)
-{
- //QPoint p(contentsToViewport(e->pos()));
- //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
- Parent::mouseMoveEvent(e);
-}
-
void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
{
QPoint p = e->pos();
@@ -1022,7 +1001,7 @@ void ConfigInfoView::menuInfo(void)
if (sym->name) {
stream << " (";
if (showDebug())
- stream << "<a href=\"s" << sym->name << "\">";
+ stream << "<a href=\"" << sym->name << "\">";
stream << print_filter(sym->name);
if (showDebug())
stream << "</a>";
@@ -1031,7 +1010,7 @@ void ConfigInfoView::menuInfo(void)
} else if (sym->name) {
stream << "<big><b>";
if (showDebug())
- stream << "<a href=\"s" << sym->name << "\">";
+ stream << "<a href=\"" << sym->name << "\">";
stream << print_filter(sym->name);
if (showDebug())
stream << "</a>";
@@ -1086,9 +1065,9 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
switch (prop->type) {
case P_PROMPT:
case P_MENU:
- stream << "prompt: <a href=\"m" << sym->name << "\">";
+ stream << "prompt: ";
stream << print_filter(prop->text);
- stream << "</a><br>";
+ stream << "<br>";
break;
case P_DEFAULT:
case P_SELECT:
@@ -1122,28 +1101,19 @@ QString ConfigInfoView::print_filter(const QString &str)
{
QRegularExpression re("[<>&\"\\n]");
QString res = str;
+
+ QHash<QChar, QString> patterns;
+ patterns['<'] = "&lt;";
+ patterns['>'] = "&gt;";
+ patterns['&'] = "&amp;";
+ patterns['"'] = "&quot;";
+ patterns['\n'] = "<br>";
+
for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
- switch (res[i].toLatin1()) {
- case '<':
- res.replace(i, 1, "&lt;");
- i += 4;
- break;
- case '>':
- res.replace(i, 1, "&gt;");
- i += 4;
- break;
- case '&':
- res.replace(i, 1, "&amp;");
- i += 5;
- break;
- case '"':
- res.replace(i, 1, "&quot;");
- i += 6;
- break;
- case '\n':
- res.replace(i, 1, "<br>");
- i += 4;
- break;
+ const QString n = patterns.value(res[i], QString());
+ if (!n.isEmpty()) {
+ res.replace(i, 1, n);
+ i += n.length();
}
}
return res;
@@ -1154,7 +1124,7 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
QTextStream *stream = reinterpret_cast<QTextStream *>(data);
if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
- *stream << "<a href=\"s" << sym->name << "\">";
+ *stream << "<a href=\"" << sym->name << "\">";
*stream << print_filter(str);
*stream << "</a>";
} else {
@@ -1164,39 +1134,11 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
void ConfigInfoView::clicked(const QUrl &url)
{
- QByteArray str = url.toEncoded();
- const std::size_t count = str.size();
- char *data = new char[count + 2]; // '$' + '\0'
- struct symbol **result;
- struct menu *m = NULL;
-
- if (count < 1) {
- delete[] data;
- return;
- }
-
- memcpy(data, str.constData(), count);
- data[count] = '\0';
-
- /* Seek for exact match */
- data[0] = '^';
- strcat(data, "$");
- result = sym_re_search(data);
- if (!result) {
- delete[] data;
- return;
- }
+ struct menu *m;
- sym = *result;
-
- /* Seek for the menu which holds the symbol */
- for (struct property *prop = sym->prop; prop; prop = prop->next) {
- if (prop->type != P_PROMPT && prop->type != P_MENU)
- continue;
- m = prop->menu;
- break;
- }
+ sym = sym_find(url.toEncoded().constData());
+ m = sym_get_prompt_menu(sym);
if (!m) {
/* Symbol is not visible as a menu */
symbolInfo();
@@ -1204,9 +1146,6 @@ void ConfigInfoView::clicked(const QUrl &url)
} else {
emit menuSelected(m);
}
-
- free(result);
- delete[] data;
}
void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
@@ -1240,8 +1179,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
layout2->addWidget(searchButton);
layout1->addLayout(layout2);
- split = new QSplitter(this);
- split->setOrientation(Qt::Vertical);
+ split = new QSplitter(Qt::Vertical, this);
list = new ConfigList(split, "search");
list->mode = listMode;
info = new ConfigInfoView(split, "search");
@@ -1300,8 +1238,7 @@ void ConfigSearchWindow::search(void)
return;
for (p = result; *p; p++) {
for_all_prompts((*p), prop)
- lastItem = new ConfigItem(list, lastItem, prop->menu,
- menu_is_visible(prop->menu));
+ lastItem = new ConfigItem(list, lastItem, prop->menu);
}
}
@@ -1341,61 +1278,56 @@ ConfigMainWindow::ConfigMainWindow(void)
ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
QWidget *widget = new QWidget(this);
- QVBoxLayout *layout = new QVBoxLayout(widget);
setCentralWidget(widget);
- split1 = new QSplitter(widget);
- split1->setOrientation(Qt::Horizontal);
- split1->setChildrenCollapsible(false);
-
- menuList = new ConfigList(widget, "menu");
+ QVBoxLayout *layout = new QVBoxLayout(widget);
- split2 = new QSplitter(widget);
+ split2 = new QSplitter(Qt::Vertical, widget);
+ layout->addWidget(split2);
split2->setChildrenCollapsible(false);
- split2->setOrientation(Qt::Vertical);
- // create config tree
- configList = new ConfigList(widget, "config");
+ split1 = new QSplitter(Qt::Horizontal, split2);
+ split1->setChildrenCollapsible(false);
- helpText = new ConfigInfoView(widget, "help");
+ configList = new ConfigList(split1, "config");
- layout->addWidget(split2);
- split2->addWidget(split1);
- split1->addWidget(configList);
- split1->addWidget(menuList);
- split2->addWidget(helpText);
+ menuList = new ConfigList(split1, "menu");
+ helpText = new ConfigInfoView(split2, "help");
setTabOrder(configList, helpText);
+
configList->setFocus();
backAction = new QAction(QPixmap(xpm_back), "Back", this);
+ backAction->setShortcut(QKeySequence::Back);
connect(backAction, &QAction::triggered,
this, &ConfigMainWindow::goBack);
QAction *quitAction = new QAction("&Quit", this);
- quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
+ quitAction->setShortcut(QKeySequence::Quit);
connect(quitAction, &QAction::triggered,
this, &ConfigMainWindow::close);
- QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
- loadAction->setShortcut(Qt::CTRL | Qt::Key_L);
+ QAction *loadAction = new QAction(QPixmap(xpm_load), "&Open", this);
+ loadAction->setShortcut(QKeySequence::Open);
connect(loadAction, &QAction::triggered,
this, &ConfigMainWindow::loadConfig);
saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
- saveAction->setShortcut(Qt::CTRL | Qt::Key_S);
+ saveAction->setShortcut(QKeySequence::Save);
connect(saveAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfig);
conf_set_changed_callback(conf_changed);
- configname = xstrdup(conf_get_configname());
+ configname = conf_get_configname();
QAction *saveAsAction = new QAction("Save &As...", this);
+ saveAsAction->setShortcut(QKeySequence::SaveAs);
connect(saveAsAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfigAs);
QAction *searchAction = new QAction("&Find", this);
- searchAction->setShortcut(Qt::CTRL | Qt::Key_F);
+ searchAction->setShortcut(QKeySequence::Find);
connect(searchAction, &QAction::triggered,
this, &ConfigMainWindow::searchConfig);
singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
@@ -1505,6 +1437,9 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(helpText, &ConfigInfoView::menuSelected,
this, &ConfigMainWindow::setMenuLink);
+ connect(configApp, &QApplication::aboutToQuit,
+ this, &ConfigMainWindow::saveSettings);
+
conf_read(NULL);
QString listMode = configSettings->value("/listMode", "symbol").toString();
@@ -1528,28 +1463,22 @@ ConfigMainWindow::ConfigMainWindow(void)
void ConfigMainWindow::loadConfig(void)
{
QString str;
- QByteArray ba;
- const char *name;
str = QFileDialog::getOpenFileName(this, "", configname);
if (str.isNull())
return;
- ba = str.toLocal8Bit();
- name = ba.data();
-
- if (conf_read(name))
+ if (conf_read(str.toLocal8Bit().constData()))
QMessageBox::information(this, "qconf", "Unable to load configuration!");
- free(configname);
- configname = xstrdup(name);
+ configname = str;
ConfigList::updateListAllForAll();
}
bool ConfigMainWindow::saveConfig(void)
{
- if (conf_write(configname)) {
+ if (conf_write(configname.toLocal8Bit().constData())) {
QMessageBox::information(this, "qconf", "Unable to save configuration!");
return false;
}
@@ -1561,23 +1490,17 @@ bool ConfigMainWindow::saveConfig(void)
void ConfigMainWindow::saveConfigAs(void)
{
QString str;
- QByteArray ba;
- const char *name;
str = QFileDialog::getSaveFileName(this, "", configname);
if (str.isNull())
return;
- ba = str.toLocal8Bit();
- name = ba.data();
-
- if (conf_write(name)) {
+ if (conf_write(str.toLocal8Bit().constData())) {
QMessageBox::information(this, "qconf", "Unable to save configuration!");
}
conf_write_autoconf(0);
- free(configname);
- configname = xstrdup(name);
+ configname = str;
}
void ConfigMainWindow::searchConfig(void)
@@ -1662,9 +1585,6 @@ void ConfigMainWindow::listFocusChanged(void)
void ConfigMainWindow::goBack(void)
{
- if (configList->rootEntry == &rootmenu)
- return;
-
configList->setParentMenu();
}
@@ -1905,8 +1825,6 @@ int main(int ac, char** av)
v = new ConfigMainWindow();
//zconfdump(stdout);
- configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
- configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
v->show();
configApp->exec();
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index 53373064d90a..62ab3286d04f 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -55,9 +55,7 @@ public:
protected:
void keyPressEvent(QKeyEvent *e);
- void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
- void mouseMoveEvent(QMouseEvent *e);
void mouseDoubleClickEvent(QMouseEvent *e);
void focusInEvent(QFocusEvent *e);
void contextMenuEvent(QContextMenuEvent *e);
@@ -116,25 +114,25 @@ public:
class ConfigItem : public QTreeWidgetItem {
typedef class QTreeWidgetItem Parent;
public:
- ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v)
- : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
+ ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m)
+ : Parent(parent, after), nextItem(0), menu(m), goParent(false)
{
init();
}
- ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
- : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
+ ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m)
+ : Parent(parent, after), nextItem(0), menu(m), goParent(false)
{
init();
}
- ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
- : Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true)
+ ConfigItem(ConfigList *parent, ConfigItem *after)
+ : Parent(parent, after), nextItem(0), menu(0), goParent(true)
{
init();
}
~ConfigItem(void);
void init(void);
void updateMenu(void);
- void testUpdateMenu(bool v);
+ void testUpdateMenu(void);
ConfigList* listView() const
{
return (ConfigList*)Parent::treeWidget();
@@ -161,7 +159,6 @@ public:
ConfigItem* nextItem;
struct menu *menu;
- bool visible;
bool goParent;
static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon;
@@ -237,7 +234,7 @@ protected:
class ConfigMainWindow : public QMainWindow {
Q_OBJECT
- char *configname;
+ QString configname;
static QAction *saveAction;
static void conf_changed(bool);
public:
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index d51cd7ac15d2..8e23faab5d22 100755
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -144,6 +144,7 @@ my %selects;
my %prompts;
my %objects;
my %config2kfile;
+my %defaults;
my $var;
my $iflevel = 0;
my @ifdeps;
@@ -220,8 +221,9 @@ sub read_kconfig {
$depends{$config} = $1;
} elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
$depends{$config} .= " " . $1;
- } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
+ } elsif ($state ne "NONE" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
my $dep = $3;
+ $defaults{$config} = 1;
if ($dep !~ /^\s*(y|m|n)\s*$/) {
$dep =~ s/.*\sif\s+//;
$depends{$config} .= " " . $dep;
@@ -503,7 +505,7 @@ sub parse_config_selects
# Check if something other than a module selects this config
if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
- dprint "$conf (non module) selects config, we are good\n";
+ dprint "$conf (non module) selects $config, we are good\n";
# we are good with this
return;
}
@@ -523,8 +525,16 @@ sub parse_config_selects
# If no possible config selected this, then something happened.
if (!defined($next_config)) {
- print STDERR "WARNING: $config is required, but nothing in the\n";
- print STDERR " current config selects it.\n";
+
+ # Some config options have no prompt, and nothing selects them, but
+ # they stay turned on once the final checks for the configs
+ # are done. These configs have a default option, so turn off the
+ # warnings for configs with default options.
+ if (!defined($defaults{$config})) {
+ print STDERR "WARNING: $config is required, but nothing in the\n";
+ print STDERR " current config selects it.\n";
+ }
+
return;
}
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index a3af93aaaf32..89b84bf8e21f 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -71,6 +71,24 @@ const char *sym_type_name(enum symbol_type type)
}
/**
+ * sym_get_prompt_menu - get the menu entry with a prompt
+ *
+ * @sym: a symbol pointer
+ *
+ * Return: the menu entry with a prompt.
+ */
+struct menu *sym_get_prompt_menu(const struct symbol *sym)
+{
+ struct menu *m;
+
+ list_for_each_entry(m, &sym->menus, link)
+ if (m->prompt)
+ return m;
+
+ return NULL;
+}
+
+/**
* sym_get_choice_menu - get the parent choice menu if present
*
* @sym: a symbol pointer
@@ -80,18 +98,12 @@ const char *sym_type_name(enum symbol_type type)
struct menu *sym_get_choice_menu(const struct symbol *sym)
{
struct menu *menu = NULL;
- struct menu *m;
/*
* Choice members must have a prompt. Find a menu entry with a prompt,
* and assume it resides inside a choice block.
*/
- list_for_each_entry(m, &sym->menus, link)
- if (m->prompt) {
- menu = m;
- break;
- }
-
+ menu = sym_get_prompt_menu(sym);
if (!menu)
return NULL;
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index a3c634b2f348..d853ddb3b28c 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -68,6 +68,10 @@ vmlinux_link()
libs="${KBUILD_VMLINUX_LIBS}"
fi
+ if is_enabled CONFIG_GENERIC_BUILTIN_DTB; then
+ objs="${objs} .builtin-dtbs.o"
+ fi
+
if is_enabled CONFIG_MODULES; then
objs="${objs} .vmlinux.export.o"
fi
@@ -208,8 +212,8 @@ kallsymso=
strip_debug=
if is_enabled CONFIG_KALLSYMS; then
- true > .tmp_vmlinux.kallsyms0.syms
- kallsyms .tmp_vmlinux.kallsyms0.syms .tmp_vmlinux0.kallsyms
+ true > .tmp_vmlinux0.syms
+ kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms
fi
if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then
@@ -236,14 +240,14 @@ if is_enabled CONFIG_KALLSYMS; then
# Generate section listing all symbols and add it into vmlinux
# It's a four step process:
# 0) Generate a dummy __kallsyms with empty symbol list.
- # 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections,
+ # 1) Link .tmp_vmlinux1.kallsyms so it has all symbols and sections,
# with a dummy __kallsyms.
- # Running kallsyms on that gives us .tmp_kallsyms1.o with
+ # Running kallsyms on that gives us .tmp_vmlinux1.kallsyms.o with
# the right size
- # 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of
+ # 2) Link .tmp_vmlinux2.kallsyms so it now has a __kallsyms section of
# the right size, but due to the added section, some
# addresses have shifted.
- # From here, we generate a correct .tmp_vmlinux.kallsyms2.o
+ # From here, we generate a correct .tmp_vmlinux2.kallsyms.o
# 3) That link may have expanded the kernel image enough that
# more linker branch stubs / trampolines had to be added, which
# introduces new names, which further expands kallsyms. Do another
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index c4cc11aa558f..5b5745f00eb3 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -10,6 +10,12 @@
* of the GNU General Public License, incorporated herein by reference.
*/
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "list.h"
+#include "xalloc.h"
+
#include "modpost.h"
#include "devicetable-offsets.h"
@@ -31,6 +37,66 @@ typedef Elf64_Addr kernel_ulong_t;
#include <ctype.h>
#include <stdbool.h>
+/**
+ * module_alias_printf - add auto-generated MODULE_ALIAS()
+ *
+ * @mod: module
+ * @append_wildcard: append '*' for future extension if not exist yet
+ * @fmt: printf(3)-like format
+ */
+static void __attribute__((format (printf, 3, 4)))
+module_alias_printf(struct module *mod, bool append_wildcard,
+ const char *fmt, ...)
+{
+ struct module_alias *new, *als;
+ size_t len;
+ int n;
+ va_list ap;
+
+ /* Determine required size. */
+ va_start(ap, fmt);
+ n = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+
+ if (n < 0) {
+ error("vsnprintf failed\n");
+ return;
+ }
+
+ len = n + 1; /* extra byte for '\0' */
+
+ if (append_wildcard)
+ len++; /* extra byte for '*' */
+
+ new = xmalloc(sizeof(*new) + len);
+
+ /* Now, really print it to the allocated buffer */
+ va_start(ap, fmt);
+ n = vsnprintf(new->str, len, fmt, ap);
+ va_end(ap);
+
+ if (n < 0) {
+ error("vsnprintf failed\n");
+ free(new);
+ return;
+ }
+
+ if (append_wildcard && (n == 0 || new->str[n - 1] != '*')) {
+ new->str[n] = '*';
+ new->str[n + 1] = '\0';
+ }
+
+ /* avoid duplication */
+ list_for_each_entry(als, &mod->aliases, node) {
+ if (!strcmp(als->str, new->str)) {
+ free(new);
+ return;
+ }
+ }
+
+ list_add_tail(&new->node, &mod->aliases);
+}
+
typedef uint32_t __u32;
typedef uint16_t __u16;
typedef unsigned char __u8;
@@ -56,35 +122,24 @@ typedef struct {
* we handle those differences explicitly below */
#include "../../include/linux/mod_devicetable.h"
-/* This array collects all instances that use the generic do_table */
struct devtable {
- const char *device_id; /* name of table, __mod_<name>__*_device_table. */
+ const char *device_id;
unsigned long id_size;
- int (*do_entry)(const char *filename, void *symval, char *alias);
+ void (*do_entry)(struct module *mod, void *symval);
};
-/* Size of alias provided to do_entry functions */
-#define ALIAS_SIZE 500
-
/* Define a variable f that holds the value of field f of struct devid
* based at address m.
*/
#define DEF_FIELD(m, devid, f) \
typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f))
-/* Define a variable v that holds the address of field f of struct devid
- * based at address m. Due to the way typeof works, for a field of type
- * T[N] the variable has type T(*)[N], _not_ T*.
- */
-#define DEF_FIELD_ADDR_VAR(m, devid, f, v) \
- typeof(((struct devid *)0)->f) *v = ((m) + OFF_##devid##_##f)
-
/* Define a variable f that holds the address of field f of struct devid
* based at address m. Due to the way typeof works, for a field of type
* T[N] the variable has type T(*)[N], _not_ T*.
*/
#define DEF_FIELD_ADDR(m, devid, f) \
- DEF_FIELD_ADDR_VAR(m, devid, f, f)
+ typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f)
#define ADD(str, sep, cond, field) \
do { \
@@ -99,15 +154,6 @@ do { \
sprintf(str + strlen(str), "*"); \
} while(0)
-/* End in a wildcard, for future extension */
-static inline void add_wildcard(char *str)
-{
- int len = strlen(str);
-
- if (str[len - 1] != '*')
- strcat(str + len, "*");
-}
-
static inline void add_uuid(char *str, uuid_le uuid)
{
int len = strlen(str);
@@ -130,40 +176,6 @@ static inline void add_guid(char *str, guid_t guid)
guid.b[12], guid.b[13], guid.b[14], guid.b[15]);
}
-/**
- * Check that sizeof(device_id type) are consistent with size of section
- * in .o file. If in-consistent then userspace and kernel does not agree
- * on actual size which is a bug.
- * Also verify that the final entry in the table is all zeros.
- * Ignore both checks if build host differ from target host and size differs.
- **/
-static void device_id_check(const char *modname, const char *device_id,
- unsigned long size, unsigned long id_size,
- void *symval)
-{
- int i;
-
- if (size % id_size || size < id_size) {
- fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo of the size of section __mod_%s__<identifier>_device_table=%lu.\n"
- "Fix definition of struct %s_device_id in mod_devicetable.h\n",
- modname, device_id, id_size, device_id, size, device_id);
- }
- /* Verify last one is a terminator */
- for (i = 0; i < id_size; i++ ) {
- if (*(uint8_t*)(symval+size-id_size+i)) {
- fprintf(stderr,
- "%s: struct %s_device_id is %lu bytes. The last of %lu is:\n",
- modname, device_id, id_size, size / id_size);
- for (i = 0; i < id_size; i++ )
- fprintf(stderr,"0x%02x ",
- *(uint8_t*)(symval+size-id_size+i) );
- fprintf(stderr,"\n");
- fatal("%s: struct %s_device_id is not terminated with a NULL entry!\n",
- modname, device_id);
- }
- }
-}
-
/* USB is special because the bcdDevice can be matched against a numeric range */
/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */
static void do_usb_entry(void *symval,
@@ -229,9 +241,7 @@ static void do_usb_entry(void *symval,
ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER,
bInterfaceNumber);
- add_wildcard(alias);
- buf_printf(&mod->dev_table_buf,
- "MODULE_ALIAS(\"%s\");\n", alias);
+ module_alias_printf(mod, true, "%s", alias);
}
/* Handles increment/decrement of BCD formatted integers */
@@ -273,7 +283,7 @@ static unsigned int incbcd(unsigned int *bcd,
return init;
}
-static void do_usb_entry_multi(void *symval, struct module *mod)
+static void do_usb_entry_multi(struct module *mod, void *symval)
{
unsigned int devlo, devhi;
unsigned char chi, clo, max;
@@ -338,22 +348,7 @@ static void do_usb_entry_multi(void *symval, struct module *mod)
}
}
-static void do_usb_table(void *symval, unsigned long size,
- struct module *mod)
-{
- unsigned int i;
- const unsigned long id_size = SIZE_usb_device_id;
-
- device_id_check(mod->name, "usb", size, id_size, symval);
-
- /* Leave last one: it's the terminator. */
- size -= id_size;
-
- for (i = 0; i < size; i += id_size)
- do_usb_entry_multi(symval + i, mod);
-}
-
-static void do_of_entry_multi(void *symval, struct module *mod)
+static void do_of_entry(struct module *mod, void *symval)
{
char alias[500];
int len;
@@ -375,56 +370,39 @@ static void do_of_entry_multi(void *symval, struct module *mod)
if (isspace(*tmp))
*tmp = '_';
- buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias);
- strcat(alias, "C");
- add_wildcard(alias);
- buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias);
-}
-
-static void do_of_table(void *symval, unsigned long size,
- struct module *mod)
-{
- unsigned int i;
- const unsigned long id_size = SIZE_of_device_id;
-
- device_id_check(mod->name, "of", size, id_size, symval);
-
- /* Leave last one: it's the terminator. */
- size -= id_size;
-
- for (i = 0; i < size; i += id_size)
- do_of_entry_multi(symval + i, mod);
+ module_alias_printf(mod, false, "%s", alias);
+ module_alias_printf(mod, false, "%sC*", alias);
}
/* Looks like: hid:bNvNpN */
-static int do_hid_entry(const char *filename,
- void *symval, char *alias)
+static void do_hid_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, hid_device_id, bus);
DEF_FIELD(symval, hid_device_id, group);
DEF_FIELD(symval, hid_device_id, vendor);
DEF_FIELD(symval, hid_device_id, product);
- sprintf(alias, "hid:");
ADD(alias, "b", bus != HID_BUS_ANY, bus);
ADD(alias, "g", group != HID_GROUP_ANY, group);
ADD(alias, "v", vendor != HID_ANY_ID, vendor);
ADD(alias, "p", product != HID_ANY_ID, product);
- return 1;
+ module_alias_printf(mod, false, "hid:%s", alias);
}
/* Looks like: ieee1394:venNmoNspNverN */
-static int do_ieee1394_entry(const char *filename,
- void *symval, char *alias)
+static void do_ieee1394_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, ieee1394_device_id, match_flags);
DEF_FIELD(symval, ieee1394_device_id, vendor_id);
DEF_FIELD(symval, ieee1394_device_id, model_id);
DEF_FIELD(symval, ieee1394_device_id, specifier_id);
DEF_FIELD(symval, ieee1394_device_id, version);
- strcpy(alias, "ieee1394:");
ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID,
vendor_id);
ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID,
@@ -434,14 +412,13 @@ static int do_ieee1394_entry(const char *filename,
ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION,
version);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "ieee1394:%s", alias);
}
/* Looks like: pci:vNdNsvNsdNbcNscNiN or <prefix>_pci:vNdNsvNsdNbcNscNiN. */
-static int do_pci_entry(const char *filename,
- void *symval, char *alias)
+static void do_pci_entry(struct module *mod, void *symval)
{
+ char alias[256];
/* Class field can be divided into these three. */
unsigned char baseclass, subclass, interface,
baseclass_mask, subclass_mask, interface_mask;
@@ -464,7 +441,6 @@ static int do_pci_entry(const char *filename,
default:
warn("Unknown PCI driver_override alias %08X\n",
override_only);
- return 0;
}
ADD(alias, "v", vendor != PCI_ANY_ID, vendor);
@@ -483,28 +459,28 @@ static int do_pci_entry(const char *filename,
|| (subclass_mask != 0 && subclass_mask != 0xFF)
|| (interface_mask != 0 && interface_mask != 0xFF)) {
warn("Can't handle masks in %s:%04X\n",
- filename, class_mask);
- return 0;
+ mod->name, class_mask);
+ return;
}
ADD(alias, "bc", baseclass_mask == 0xFF, baseclass);
ADD(alias, "sc", subclass_mask == 0xFF, subclass);
ADD(alias, "i", interface_mask == 0xFF, interface);
- add_wildcard(alias);
- return 1;
+
+ module_alias_printf(mod, true, "%s", alias);
}
/* looks like: "ccw:tNmNdtNdmN" */
-static int do_ccw_entry(const char *filename,
- void *symval, char *alias)
+static void do_ccw_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, ccw_device_id, match_flags);
DEF_FIELD(symval, ccw_device_id, cu_type);
DEF_FIELD(symval, ccw_device_id, cu_model);
DEF_FIELD(symval, ccw_device_id, dev_type);
DEF_FIELD(symval, ccw_device_id, dev_model);
- strcpy(alias, "ccw:");
ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE,
cu_type);
ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL,
@@ -513,47 +489,42 @@ static int do_ccw_entry(const char *filename,
dev_type);
ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL,
dev_model);
- add_wildcard(alias);
- return 1;
+
+ module_alias_printf(mod, true, "ccw:%s", alias);
}
/* looks like: "ap:tN" */
-static int do_ap_entry(const char *filename,
- void *symval, char *alias)
+static void do_ap_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, ap_device_id, dev_type);
- sprintf(alias, "ap:t%02X*", dev_type);
- return 1;
+ module_alias_printf(mod, false, "ap:t%02X*", dev_type);
}
/* looks like: "css:tN" */
-static int do_css_entry(const char *filename,
- void *symval, char *alias)
+static void do_css_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, css_device_id, type);
- sprintf(alias, "css:t%01X", type);
- return 1;
+ module_alias_printf(mod, false, "css:t%01X", type);
}
/* Looks like: "serio:tyNprNidNexN" */
-static int do_serio_entry(const char *filename,
- void *symval, char *alias)
+static void do_serio_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, serio_device_id, type);
DEF_FIELD(symval, serio_device_id, proto);
DEF_FIELD(symval, serio_device_id, id);
DEF_FIELD(symval, serio_device_id, extra);
- strcpy(alias, "serio:");
ADD(alias, "ty", type != SERIO_ANY, type);
ADD(alias, "pr", proto != SERIO_ANY, proto);
ADD(alias, "id", id != SERIO_ANY, id);
ADD(alias, "ex", extra != SERIO_ANY, extra);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "serio:%s", alias);
}
/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or
@@ -563,21 +534,19 @@ static int do_serio_entry(const char *filename,
* or _CLS. Also, bb, ss, and pp can be substituted with ??
* as don't care byte.
*/
-static int do_acpi_entry(const char *filename,
- void *symval, char *alias)
+static void do_acpi_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, acpi_device_id, id);
DEF_FIELD(symval, acpi_device_id, cls);
DEF_FIELD(symval, acpi_device_id, cls_msk);
- if (id && strlen((const char *)*id))
- sprintf(alias, "acpi*:%s:*", *id);
+ if ((*id)[0])
+ module_alias_printf(mod, false, "acpi*:%s:*", *id);
else {
+ char alias[256];
int i, byte_shift, cnt = 0;
unsigned int msk;
- sprintf(&alias[cnt], "acpi*:");
- cnt = 6;
for (i = 1; i <= 3; i++) {
byte_shift = 8 * (3-i);
msk = (cls_msk >> byte_shift) & 0xFF;
@@ -588,101 +557,49 @@ static int do_acpi_entry(const char *filename,
sprintf(&alias[cnt], "??");
cnt += 2;
}
- sprintf(&alias[cnt], ":*");
+ module_alias_printf(mod, false, "acpi*:%s:*", alias);
}
- return 1;
}
/* looks like: "pnp:dD" */
-static void do_pnp_device_entry(void *symval, unsigned long size,
- struct module *mod)
+static void do_pnp_device_entry(struct module *mod, void *symval)
{
- const unsigned long id_size = SIZE_pnp_device_id;
- const unsigned int count = (size / id_size)-1;
- unsigned int i;
-
- device_id_check(mod->name, "pnp", size, id_size, symval);
+ DEF_FIELD_ADDR(symval, pnp_device_id, id);
+ char acpi_id[sizeof(*id)];
- for (i = 0; i < count; i++) {
- DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id);
- char acpi_id[sizeof(*id)];
- int j;
-
- buf_printf(&mod->dev_table_buf,
- "MODULE_ALIAS(\"pnp:d%s*\");\n", *id);
-
- /* fix broken pnp bus lowercasing */
- for (j = 0; j < sizeof(acpi_id); j++)
- acpi_id[j] = toupper((*id)[j]);
- buf_printf(&mod->dev_table_buf,
- "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
- }
+ /* fix broken pnp bus lowercasing */
+ for (unsigned int i = 0; i < sizeof(acpi_id); i++)
+ acpi_id[i] = toupper((*id)[i]);
+ module_alias_printf(mod, false, "pnp:d%s*", *id);
+ module_alias_printf(mod, false, "acpi*:%s:*", acpi_id);
}
/* looks like: "pnp:dD" for every device of the card */
-static void do_pnp_card_entries(void *symval, unsigned long size,
- struct module *mod)
+static void do_pnp_card_entry(struct module *mod, void *symval)
{
- const unsigned long id_size = SIZE_pnp_card_device_id;
- const unsigned int count = (size / id_size)-1;
- unsigned int i;
-
- device_id_check(mod->name, "pnp", size, id_size, symval);
-
- for (i = 0; i < count; i++) {
- unsigned int j;
- DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs);
-
- for (j = 0; j < PNP_MAX_DEVICES; j++) {
- const char *id = (char *)(*devs)[j].id;
- int i2, j2;
- int dup = 0;
-
- if (!id[0])
- break;
+ DEF_FIELD_ADDR(symval, pnp_card_device_id, devs);
- /* find duplicate, already added value */
- for (i2 = 0; i2 < i && !dup; i2++) {
- DEF_FIELD_ADDR_VAR(symval + i2 * id_size,
- pnp_card_device_id,
- devs, devs_dup);
+ for (unsigned int i = 0; i < PNP_MAX_DEVICES; i++) {
+ const char *id = (char *)(*devs)[i].id;
+ char acpi_id[PNP_ID_LEN];
- for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) {
- const char *id2 =
- (char *)(*devs_dup)[j2].id;
-
- if (!id2[0])
- break;
-
- if (!strcmp(id, id2)) {
- dup = 1;
- break;
- }
- }
- }
-
- /* add an individual alias for every device entry */
- if (!dup) {
- char acpi_id[PNP_ID_LEN];
- int k;
+ if (!id[0])
+ break;
- buf_printf(&mod->dev_table_buf,
- "MODULE_ALIAS(\"pnp:d%s*\");\n", id);
+ /* fix broken pnp bus lowercasing */
+ for (unsigned int j = 0; j < sizeof(acpi_id); j++)
+ acpi_id[j] = toupper(id[j]);
- /* fix broken pnp bus lowercasing */
- for (k = 0; k < sizeof(acpi_id); k++)
- acpi_id[k] = toupper(id[k]);
- buf_printf(&mod->dev_table_buf,
- "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);
- }
- }
+ /* add an individual alias for every device entry */
+ module_alias_printf(mod, false, "pnp:d%s*", id);
+ module_alias_printf(mod, false, "acpi*:%s:*", acpi_id);
}
}
/* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */
-static int do_pcmcia_entry(const char *filename,
- void *symval, char *alias)
+static void do_pcmcia_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
unsigned int i;
DEF_FIELD(symval, pcmcia_device_id, match_flags);
DEF_FIELD(symval, pcmcia_device_id, manf_id);
@@ -696,7 +613,6 @@ static int do_pcmcia_entry(const char *filename,
(*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]);
}
- strcpy(alias, "pcmcia:");
ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
manf_id);
ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
@@ -712,13 +628,12 @@ static int do_pcmcia_entry(const char *filename,
ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]);
ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "pcmcia:%s", alias);
}
-static int do_vio_entry(const char *filename, void *symval,
- char *alias)
+static void do_vio_entry(struct module *mod, void *symval)
{
+ char alias[256];
char *tmp;
DEF_FIELD_ADDR(symval, vio_device_id, type);
DEF_FIELD_ADDR(symval, vio_device_id, compat);
@@ -731,8 +646,7 @@ static int do_vio_entry(const char *filename, void *symval,
if (isspace (*tmp))
*tmp = '_';
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "%s", alias);
}
static void do_input(char *alias,
@@ -748,9 +662,10 @@ static void do_input(char *alias,
}
/* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */
-static int do_input_entry(const char *filename, void *symval,
- char *alias)
+static void do_input_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, input_device_id, flags);
DEF_FIELD(symval, input_device_id, bustype);
DEF_FIELD(symval, input_device_id, vendor);
@@ -766,8 +681,6 @@ static int do_input_entry(const char *filename, void *symval,
DEF_FIELD_ADDR(symval, input_device_id, ffbit);
DEF_FIELD_ADDR(symval, input_device_id, swbit);
- sprintf(alias, "input:");
-
ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype);
ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor);
ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product);
@@ -802,102 +715,96 @@ static int do_input_entry(const char *filename, void *symval,
sprintf(alias + strlen(alias), "w*");
if (flags & INPUT_DEVICE_ID_MATCH_SWBIT)
do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX);
- return 1;
+
+ module_alias_printf(mod, false, "input:%s", alias);
}
-static int do_eisa_entry(const char *filename, void *symval,
- char *alias)
+static void do_eisa_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, eisa_device_id, sig);
- if (sig[0])
- sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig);
- else
- strcat(alias, "*");
- return 1;
+ module_alias_printf(mod, false, EISA_DEVICE_MODALIAS_FMT "*", *sig);
}
/* Looks like: parisc:tNhvNrevNsvN */
-static int do_parisc_entry(const char *filename, void *symval,
- char *alias)
+static void do_parisc_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, parisc_device_id, hw_type);
DEF_FIELD(symval, parisc_device_id, hversion);
DEF_FIELD(symval, parisc_device_id, hversion_rev);
DEF_FIELD(symval, parisc_device_id, sversion);
- strcpy(alias, "parisc:");
ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type);
ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion);
ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev);
ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "parisc:%s", alias);
}
/* Looks like: sdio:cNvNdN. */
-static int do_sdio_entry(const char *filename,
- void *symval, char *alias)
+static void do_sdio_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, sdio_device_id, class);
DEF_FIELD(symval, sdio_device_id, vendor);
DEF_FIELD(symval, sdio_device_id, device);
- strcpy(alias, "sdio:");
ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class);
ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor);
ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device);
- add_wildcard(alias);
- return 1;
+
+ module_alias_printf(mod, true, "sdio:%s", alias);
}
/* Looks like: ssb:vNidNrevN. */
-static int do_ssb_entry(const char *filename,
- void *symval, char *alias)
+static void do_ssb_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, ssb_device_id, vendor);
DEF_FIELD(symval, ssb_device_id, coreid);
DEF_FIELD(symval, ssb_device_id, revision);
- strcpy(alias, "ssb:");
ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor);
ADD(alias, "id", coreid != SSB_ANY_ID, coreid);
ADD(alias, "rev", revision != SSB_ANY_REV, revision);
- add_wildcard(alias);
- return 1;
+
+ module_alias_printf(mod, true, "ssb:%s", alias);
}
/* Looks like: bcma:mNidNrevNclN. */
-static int do_bcma_entry(const char *filename,
- void *symval, char *alias)
+static void do_bcma_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, bcma_device_id, manuf);
DEF_FIELD(symval, bcma_device_id, id);
DEF_FIELD(symval, bcma_device_id, rev);
DEF_FIELD(symval, bcma_device_id, class);
- strcpy(alias, "bcma:");
ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf);
ADD(alias, "id", id != BCMA_ANY_ID, id);
ADD(alias, "rev", rev != BCMA_ANY_REV, rev);
ADD(alias, "cl", class != BCMA_ANY_CLASS, class);
- add_wildcard(alias);
- return 1;
+
+ module_alias_printf(mod, true, "bcma:%s", alias);
}
/* Looks like: virtio:dNvN */
-static int do_virtio_entry(const char *filename, void *symval,
- char *alias)
+static void do_virtio_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, virtio_device_id, device);
DEF_FIELD(symval, virtio_device_id, vendor);
- strcpy(alias, "virtio:");
ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device);
ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "virtio:%s", alias);
}
/*
@@ -906,8 +813,7 @@ static int do_virtio_entry(const char *filename, void *symval,
* in the name.
*/
-static int do_vmbus_entry(const char *filename, void *symval,
- char *alias)
+static void do_vmbus_entry(struct module *mod, void *symval)
{
int i;
DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid);
@@ -916,68 +822,57 @@ static int do_vmbus_entry(const char *filename, void *symval,
for (i = 0; i < (sizeof(*guid) * 2); i += 2)
sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2]));
- strcpy(alias, "vmbus:");
- strcat(alias, guid_name);
-
- return 1;
+ module_alias_printf(mod, false, "vmbus:%s", guid_name);
}
/* Looks like: rpmsg:S */
-static int do_rpmsg_entry(const char *filename, void *symval,
- char *alias)
+static void do_rpmsg_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, rpmsg_device_id, name);
- sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name);
- return 1;
+ module_alias_printf(mod, false, RPMSG_DEVICE_MODALIAS_FMT, *name);
}
/* Looks like: i2c:S */
-static int do_i2c_entry(const char *filename, void *symval,
- char *alias)
+static void do_i2c_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, i2c_device_id, name);
- sprintf(alias, I2C_MODULE_PREFIX "%s", *name);
- return 1;
+ module_alias_printf(mod, false, I2C_MODULE_PREFIX "%s", *name);
}
-static int do_i3c_entry(const char *filename, void *symval,
- char *alias)
+static void do_i3c_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, i3c_device_id, match_flags);
DEF_FIELD(symval, i3c_device_id, dcr);
DEF_FIELD(symval, i3c_device_id, manuf_id);
DEF_FIELD(symval, i3c_device_id, part_id);
DEF_FIELD(symval, i3c_device_id, extra_info);
- strcpy(alias, "i3c:");
ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr);
ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id);
ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id);
ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info);
- return 1;
+ module_alias_printf(mod, false, "i3c:%s", alias);
}
-static int do_slim_entry(const char *filename, void *symval, char *alias)
+static void do_slim_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, slim_device_id, manf_id);
DEF_FIELD(symval, slim_device_id, prod_code);
- sprintf(alias, "slim:%x:%x:*", manf_id, prod_code);
-
- return 1;
+ module_alias_printf(mod, false, "slim:%x:%x:*", manf_id, prod_code);
}
/* Looks like: spi:S */
-static int do_spi_entry(const char *filename, void *symval,
- char *alias)
+static void do_spi_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, spi_device_id, name);
- sprintf(alias, SPI_MODULE_PREFIX "%s", *name);
- return 1;
+ module_alias_printf(mod, false, SPI_MODULE_PREFIX "%s", *name);
}
static const struct dmifield {
@@ -1012,12 +907,11 @@ static void dmi_ascii_filter(char *d, const char *s)
}
-static int do_dmi_entry(const char *filename, void *symval,
- char *alias)
+static void do_dmi_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
int i, j;
DEF_FIELD_ADDR(symval, dmi_system_id, matches);
- sprintf(alias, "dmi*");
for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {
for (j = 0; j < 4; j++) {
@@ -1032,80 +926,75 @@ static int do_dmi_entry(const char *filename, void *symval,
}
}
- strcat(alias, ":");
- return 1;
+ module_alias_printf(mod, false, "dmi*%s:", alias);
}
-static int do_platform_entry(const char *filename,
- void *symval, char *alias)
+static void do_platform_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, platform_device_id, name);
- sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name);
- return 1;
+
+ module_alias_printf(mod, false, PLATFORM_MODULE_PREFIX "%s", *name);
}
-static int do_mdio_entry(const char *filename,
- void *symval, char *alias)
+static void do_mdio_entry(struct module *mod, void *symval)
{
+ char id[33];
int i;
DEF_FIELD(symval, mdio_device_id, phy_id);
DEF_FIELD(symval, mdio_device_id, phy_id_mask);
- alias += sprintf(alias, MDIO_MODULE_PREFIX);
-
for (i = 0; i < 32; i++) {
if (!((phy_id_mask >> (31-i)) & 1))
- *(alias++) = '?';
+ id[i] = '?';
else if ((phy_id >> (31-i)) & 1)
- *(alias++) = '1';
+ id[i] = '1';
else
- *(alias++) = '0';
+ id[i] = '0';
}
/* Terminate the string */
- *alias = 0;
+ id[32] = '\0';
- return 1;
+ module_alias_printf(mod, false, MDIO_MODULE_PREFIX "%s", id);
}
/* Looks like: zorro:iN. */
-static int do_zorro_entry(const char *filename, void *symval,
- char *alias)
+static void do_zorro_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
DEF_FIELD(symval, zorro_device_id, id);
- strcpy(alias, "zorro:");
+
ADD(alias, "i", id != ZORRO_WILDCARD, id);
- return 1;
+
+ module_alias_printf(mod, false, "zorro:%s", alias);
}
/* looks like: "pnp:dD" */
-static int do_isapnp_entry(const char *filename,
- void *symval, char *alias)
+static void do_isapnp_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, isapnp_device_id, vendor);
DEF_FIELD(symval, isapnp_device_id, function);
- sprintf(alias, "pnp:d%c%c%c%x%x%x%x*",
+ module_alias_printf(mod, false, "pnp:d%c%c%c%x%x%x%x*",
'A' + ((vendor >> 2) & 0x3f) - 1,
'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
'A' + ((vendor >> 8) & 0x1f) - 1,
(function >> 4) & 0x0f, function & 0x0f,
(function >> 12) & 0x0f, (function >> 8) & 0x0f);
- return 1;
}
/* Looks like: "ipack:fNvNdN". */
-static int do_ipack_entry(const char *filename,
- void *symval, char *alias)
+static void do_ipack_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
DEF_FIELD(symval, ipack_device_id, format);
DEF_FIELD(symval, ipack_device_id, vendor);
DEF_FIELD(symval, ipack_device_id, device);
- strcpy(alias, "ipack:");
+
ADD(alias, "f", format != IPACK_ANY_FORMAT, format);
ADD(alias, "v", vendor != IPACK_ANY_ID, vendor);
ADD(alias, "d", device != IPACK_ANY_ID, device);
- add_wildcard(alias);
- return 1;
+
+ module_alias_printf(mod, true, "ipack:%s", alias);
}
/*
@@ -1156,9 +1045,9 @@ static void append_nibble_mask(char **outp,
* N is exactly 8 digits, where each is an upper-case hex digit, or
* a ? or [] pattern matching exactly one digit.
*/
-static int do_amba_entry(const char *filename,
- void *symval, char *alias)
+static void do_amba_entry(struct module *mod, void *symval)
{
+ char alias[256];
unsigned int digit;
char *p = alias;
DEF_FIELD(symval, amba_id, id);
@@ -1166,15 +1055,14 @@ static int do_amba_entry(const char *filename,
if ((id & mask) != id)
fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: id=0x%08X, mask=0x%08X. Please fix this driver.\n",
- filename, id, mask);
+ mod->name, id, mask);
- p += sprintf(alias, "amba:d");
for (digit = 0; digit < 8; digit++)
append_nibble_mask(&p,
(id >> (4 * (7 - digit))) & 0xf,
(mask >> (4 * (7 - digit))) & 0xf);
- return 1;
+ module_alias_printf(mod, false, "amba:d%s", alias);
}
/*
@@ -1183,13 +1071,11 @@ static int do_amba_entry(const char *filename,
* N is exactly 2 digits, where each is an upper-case hex digit, or
* a ? or [] pattern matching exactly one digit.
*/
-static int do_mips_cdmm_entry(const char *filename,
- void *symval, char *alias)
+static void do_mips_cdmm_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, mips_cdmm_device_id, type);
- sprintf(alias, "mipscdmm:t%02X*", type);
- return 1;
+ module_alias_printf(mod, false, "mipscdmm:t%02X*", type);
}
/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,*
@@ -1198,137 +1084,130 @@ static int do_mips_cdmm_entry(const char *filename,
* complicated.
*/
-static int do_x86cpu_entry(const char *filename, void *symval,
- char *alias)
+static void do_x86cpu_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, x86_cpu_id, feature);
DEF_FIELD(symval, x86_cpu_id, family);
DEF_FIELD(symval, x86_cpu_id, model);
DEF_FIELD(symval, x86_cpu_id, vendor);
- strcpy(alias, "cpu:type:x86,");
ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor);
ADD(alias, "fam", family != X86_FAMILY_ANY, family);
ADD(alias, "mod", model != X86_MODEL_ANY, model);
strcat(alias, ":feature:*");
if (feature != X86_FEATURE_ANY)
sprintf(alias + strlen(alias), "%04X*", feature);
- return 1;
+
+ module_alias_printf(mod, false, "cpu:type:x86,%s", alias);
}
/* LOOKS like cpu:type:*:feature:*FEAT* */
-static int do_cpu_entry(const char *filename, void *symval, char *alias)
+static void do_cpu_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, cpu_feature, feature);
- sprintf(alias, "cpu:type:*:feature:*%04X*", feature);
- return 1;
+ module_alias_printf(mod, false, "cpu:type:*:feature:*%04X*", feature);
}
/* Looks like: mei:S:uuid:N:* */
-static int do_mei_entry(const char *filename, void *symval,
- char *alias)
+static void do_mei_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid);
DEF_FIELD(symval, mei_cl_device_id, version);
- sprintf(alias, MEI_CL_MODULE_PREFIX);
- sprintf(alias + strlen(alias), "%s:", (*name)[0] ? *name : "*");
add_uuid(alias, *uuid);
ADD(alias, ":", version != MEI_CL_VERSION_ANY, version);
- strcat(alias, ":*");
-
- return 1;
+ module_alias_printf(mod, false, MEI_CL_MODULE_PREFIX "%s:%s:*",
+ (*name)[0] ? *name : "*", alias);
}
/* Looks like: rapidio:vNdNavNadN */
-static int do_rio_entry(const char *filename,
- void *symval, char *alias)
+static void do_rio_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, rio_device_id, did);
DEF_FIELD(symval, rio_device_id, vid);
DEF_FIELD(symval, rio_device_id, asm_did);
DEF_FIELD(symval, rio_device_id, asm_vid);
- strcpy(alias, "rapidio:");
ADD(alias, "v", vid != RIO_ANY_ID, vid);
ADD(alias, "d", did != RIO_ANY_ID, did);
ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid);
ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "rapidio:%s", alias);
}
/* Looks like: ulpi:vNpN */
-static int do_ulpi_entry(const char *filename, void *symval,
- char *alias)
+static void do_ulpi_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, ulpi_device_id, vendor);
DEF_FIELD(symval, ulpi_device_id, product);
- sprintf(alias, "ulpi:v%04xp%04x", vendor, product);
-
- return 1;
+ module_alias_printf(mod, false, "ulpi:v%04xp%04x", vendor, product);
}
/* Looks like: hdaudio:vNrNaN */
-static int do_hda_entry(const char *filename, void *symval, char *alias)
+static void do_hda_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, hda_device_id, vendor_id);
DEF_FIELD(symval, hda_device_id, rev_id);
DEF_FIELD(symval, hda_device_id, api_version);
- strcpy(alias, "hdaudio:");
ADD(alias, "v", vendor_id != 0, vendor_id);
ADD(alias, "r", rev_id != 0, rev_id);
ADD(alias, "a", api_version != 0, api_version);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "hdaudio:%s", alias);
}
/* Looks like: sdw:mNpNvNcN */
-static int do_sdw_entry(const char *filename, void *symval, char *alias)
+static void do_sdw_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, sdw_device_id, mfg_id);
DEF_FIELD(symval, sdw_device_id, part_id);
DEF_FIELD(symval, sdw_device_id, sdw_version);
DEF_FIELD(symval, sdw_device_id, class_id);
- strcpy(alias, "sdw:");
ADD(alias, "m", mfg_id != 0, mfg_id);
ADD(alias, "p", part_id != 0, part_id);
ADD(alias, "v", sdw_version != 0, sdw_version);
ADD(alias, "c", class_id != 0, class_id);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "sdw:%s", alias);
}
/* Looks like: fsl-mc:vNdN */
-static int do_fsl_mc_entry(const char *filename, void *symval,
- char *alias)
+static void do_fsl_mc_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, fsl_mc_device_id, vendor);
DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type);
- sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type);
- return 1;
+ module_alias_printf(mod, false, "fsl-mc:v%08Xd%s", vendor, *obj_type);
}
/* Looks like: tbsvc:kSpNvNrN */
-static int do_tbsvc_entry(const char *filename, void *symval, char *alias)
+static void do_tbsvc_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, tb_service_id, match_flags);
DEF_FIELD_ADDR(symval, tb_service_id, protocol_key);
DEF_FIELD(symval, tb_service_id, protocol_id);
DEF_FIELD(symval, tb_service_id, protocol_version);
DEF_FIELD(symval, tb_service_id, protocol_revision);
- strcpy(alias, "tbsvc:");
if (match_flags & TBSVC_MATCH_PROTOCOL_KEY)
sprintf(alias + strlen(alias), "k%s", *protocol_key);
else
@@ -1339,93 +1218,80 @@ static int do_tbsvc_entry(const char *filename, void *symval, char *alias)
ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION,
protocol_revision);
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "tbsvc:%s", alias);
}
/* Looks like: typec:idNmN */
-static int do_typec_entry(const char *filename, void *symval, char *alias)
+static void do_typec_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, typec_device_id, svid);
DEF_FIELD(symval, typec_device_id, mode);
- sprintf(alias, "typec:id%04X", svid);
ADD(alias, "m", mode != TYPEC_ANY_MODE, mode);
- return 1;
+ module_alias_printf(mod, false, "typec:id%04X%s", svid, alias);
}
/* Looks like: tee:uuid */
-static int do_tee_entry(const char *filename, void *symval, char *alias)
+static void do_tee_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, tee_client_device_id, uuid);
- sprintf(alias, "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ module_alias_printf(mod, true,
+ "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid->b[0], uuid->b[1], uuid->b[2], uuid->b[3], uuid->b[4],
uuid->b[5], uuid->b[6], uuid->b[7], uuid->b[8], uuid->b[9],
uuid->b[10], uuid->b[11], uuid->b[12], uuid->b[13], uuid->b[14],
uuid->b[15]);
-
- add_wildcard(alias);
- return 1;
}
/* Looks like: wmi:guid */
-static int do_wmi_entry(const char *filename, void *symval, char *alias)
+static void do_wmi_entry(struct module *mod, void *symval)
{
- int len;
DEF_FIELD_ADDR(symval, wmi_device_id, guid_string);
if (strlen(*guid_string) != UUID_STRING_LEN) {
warn("Invalid WMI device id 'wmi:%s' in '%s'\n",
- *guid_string, filename);
- return 0;
+ *guid_string, mod->name);
+ return;
}
- len = snprintf(alias, ALIAS_SIZE, WMI_MODULE_PREFIX "%s", *guid_string);
- if (len < 0 || len >= ALIAS_SIZE) {
- warn("Could not generate all MODULE_ALIAS's in '%s'\n",
- filename);
- return 0;
- }
- return 1;
+ module_alias_printf(mod, false, WMI_MODULE_PREFIX "%s", *guid_string);
}
/* Looks like: mhi:S */
-static int do_mhi_entry(const char *filename, void *symval, char *alias)
+static void do_mhi_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, mhi_device_id, chan);
- sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan);
- return 1;
+ module_alias_printf(mod, false, MHI_DEVICE_MODALIAS_FMT, *chan);
}
/* Looks like: mhi_ep:S */
-static int do_mhi_ep_entry(const char *filename, void *symval, char *alias)
+static void do_mhi_ep_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, mhi_device_id, chan);
- sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan);
- return 1;
+ module_alias_printf(mod, false, MHI_EP_DEVICE_MODALIAS_FMT, *chan);
}
/* Looks like: ishtp:{guid} */
-static int do_ishtp_entry(const char *filename, void *symval, char *alias)
+static void do_ishtp_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
DEF_FIELD_ADDR(symval, ishtp_device_id, guid);
- strcpy(alias, ISHTP_MODULE_PREFIX "{");
add_guid(alias, *guid);
- strcat(alias, "}");
- return 1;
+ module_alias_printf(mod, false, ISHTP_MODULE_PREFIX "{%s}", alias);
}
-static int do_auxiliary_entry(const char *filename, void *symval, char *alias)
+static void do_auxiliary_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, auxiliary_device_id, name);
- sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name);
- return 1;
+ module_alias_printf(mod, false, AUXILIARY_MODULE_PREFIX "%s", *name);
}
/*
@@ -1433,8 +1299,10 @@ static int do_auxiliary_entry(const char *filename, void *symval, char *alias)
*
* N is exactly 2 digits, where each is an upper-case hex digit.
*/
-static int do_ssam_entry(const char *filename, void *symval, char *alias)
+static void do_ssam_entry(struct module *mod, void *symval)
{
+ char alias[256] = {};
+
DEF_FIELD(symval, ssam_device_id, match_flags);
DEF_FIELD(symval, ssam_device_id, domain);
DEF_FIELD(symval, ssam_device_id, category);
@@ -1442,30 +1310,28 @@ static int do_ssam_entry(const char *filename, void *symval, char *alias)
DEF_FIELD(symval, ssam_device_id, instance);
DEF_FIELD(symval, ssam_device_id, function);
- sprintf(alias, "ssam:d%02Xc%02X", domain, category);
ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target);
ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance);
ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function);
- return 1;
+ module_alias_printf(mod, false, "ssam:d%02Xc%02X%s",
+ domain, category, alias);
}
/* Looks like: dfl:tNfN */
-static int do_dfl_entry(const char *filename, void *symval, char *alias)
+static void do_dfl_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, dfl_device_id, type);
DEF_FIELD(symval, dfl_device_id, feature_id);
- sprintf(alias, "dfl:t%04Xf%04X", type, feature_id);
-
- add_wildcard(alias);
- return 1;
+ module_alias_printf(mod, true, "dfl:t%04Xf%04X", type, feature_id);
}
/* Looks like: cdx:vNdN */
-static int do_cdx_entry(const char *filename, void *symval,
- char *alias)
+static void do_cdx_entry(struct module *mod, void *symval)
{
+ char alias[256];
+
DEF_FIELD(symval, cdx_device_id, vendor);
DEF_FIELD(symval, cdx_device_id, device);
DEF_FIELD(symval, cdx_device_id, subvendor);
@@ -1484,7 +1350,7 @@ static int do_cdx_entry(const char *filename, void *symval,
default:
warn("Unknown CDX driver_override alias %08X\n",
override_only);
- return 0;
+ return;
}
ADD(alias, "v", vendor != CDX_ANY_ID, vendor);
@@ -1493,24 +1359,22 @@ static int do_cdx_entry(const char *filename, void *symval,
ADD(alias, "sd", subdevice != CDX_ANY_ID, subdevice);
ADD(alias, "c", class_mask == 0xFFFFFF, class);
- return 1;
+ module_alias_printf(mod, false, "%s", alias);
}
-static int do_vchiq_entry(const char *filename, void *symval, char *alias)
+static void do_vchiq_entry(struct module *mod, void *symval)
{
DEF_FIELD_ADDR(symval, vchiq_device_id, name);
- sprintf(alias, "vchiq:%s", *name);
- return 1;
+ module_alias_printf(mod, false, "vchiq:%s", *name);
}
/* Looks like: coreboot:tN */
-static int do_coreboot_entry(const char *filename, void *symval, char *alias)
+static void do_coreboot_entry(struct module *mod, void *symval)
{
DEF_FIELD(symval, coreboot_device_id, tag);
- sprintf(alias, "coreboot:t%08X", tag);
- return 1;
+ module_alias_printf(mod, false, "coreboot:t%08X", tag);
}
/* Does namelen bytes of name exactly match the symbol? */
@@ -1522,25 +1386,34 @@ static bool sym_is(const char *name, unsigned namelen, const char *symbol)
return memcmp(name, symbol, namelen) == 0;
}
-static void do_table(void *symval, unsigned long size,
+static void do_table(const char *name, void *symval, unsigned long size,
unsigned long id_size,
const char *device_id,
- int (*do_entry)(const char *filename, void *symval, char *alias),
+ void (*do_entry)(struct module *mod, void *symval),
struct module *mod)
{
unsigned int i;
- char alias[ALIAS_SIZE];
- device_id_check(mod->name, device_id, size, id_size, symval);
- /* Leave last one: it's the terminator. */
- size -= id_size;
+ if (size % id_size || size < id_size) {
+ error("%s: type mismatch between %s[] and MODULE_DEVICE_TABLE(%s, ...)\n",
+ mod->name, name, device_id);
+ return;
+ }
- for (i = 0; i < size; i += id_size) {
- if (do_entry(mod->name, symval+i, alias)) {
- buf_printf(&mod->dev_table_buf,
- "MODULE_ALIAS(\"%s\");\n", alias);
+ /* Verify the last entry is a terminator */
+ for (i = size - id_size; i < size; i++) {
+ if (*(uint8_t *)(symval + i)) {
+ error("%s: %s[] is not terminated with a NULL entry\n",
+ mod->name, name);
+ return;
}
}
+
+ /* Leave last one: it's the terminator. */
+ size -= id_size;
+
+ for (i = 0; i < size; i += id_size)
+ do_entry(mod, symval + i);
}
static const struct devtable devtable[] = {
@@ -1596,6 +1469,10 @@ static const struct devtable devtable[] = {
{"cdx", SIZE_cdx_device_id, do_cdx_entry},
{"vchiq", SIZE_vchiq_device_id, do_vchiq_entry},
{"coreboot", SIZE_coreboot_device_id, do_coreboot_entry},
+ {"of", SIZE_of_device_id, do_of_entry},
+ {"usb", SIZE_usb_device_id, do_usb_entry_multi},
+ {"pnp", SIZE_pnp_device_id, do_pnp_device_entry},
+ {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry},
};
/* Create MODULE_ALIAS() statements.
@@ -1606,8 +1483,9 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
{
void *symval;
char *zeros = NULL;
- const char *name, *identifier;
- unsigned int namelen;
+ const char *type, *name;
+ size_t typelen;
+ static const char *prefix = "__mod_device_table__";
/* We're looking for a section relative symbol */
if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)
@@ -1617,19 +1495,16 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
return;
- /* All our symbols are of form __mod_<name>__<identifier>_device_table. */
- if (strncmp(symname, "__mod_", strlen("__mod_")))
- return;
- name = symname + strlen("__mod_");
- namelen = strlen(name);
- if (namelen < strlen("_device_table"))
- return;
- if (strcmp(name + namelen - strlen("_device_table"), "_device_table"))
+ /* All our symbols are of form __mod_device_table__<type>__<name>. */
+ if (!strstarts(symname, prefix))
return;
- identifier = strstr(name, "__");
- if (!identifier)
+ type = symname + strlen(prefix);
+
+ name = strstr(type, "__");
+ if (!name)
return;
- namelen = identifier - name;
+ typelen = name - type;
+ name += strlen("__");
/* Handle all-NULL symbols allocated into .bss */
if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
@@ -1639,35 +1514,15 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
symval = sym_get_data(info, sym);
}
- /* First handle the "special" cases */
- if (sym_is(name, namelen, "usb"))
- do_usb_table(symval, sym->st_size, mod);
- else if (sym_is(name, namelen, "of"))
- do_of_table(symval, sym->st_size, mod);
- else if (sym_is(name, namelen, "pnp"))
- do_pnp_device_entry(symval, sym->st_size, mod);
- else if (sym_is(name, namelen, "pnp_card"))
- do_pnp_card_entries(symval, sym->st_size, mod);
- else {
- int i;
-
- for (i = 0; i < ARRAY_SIZE(devtable); i++) {
- const struct devtable *p = &devtable[i];
+ for (int i = 0; i < ARRAY_SIZE(devtable); i++) {
+ const struct devtable *p = &devtable[i];
- if (sym_is(name, namelen, p->device_id)) {
- do_table(symval, sym->st_size, p->id_size,
- p->device_id, p->do_entry, mod);
- break;
- }
+ if (sym_is(type, typelen, p->device_id)) {
+ do_table(name, symval, sym->st_size, p->id_size,
+ p->device_id, p->do_entry, mod);
+ break;
}
}
- free(zeros);
-}
-/* Now add out buffered information to the generated C source */
-void add_moddevtable(struct buffer *buf, struct module *mod)
-{
- buf_printf(buf, "\n");
- buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
- free(mod->dev_table_buf.p);
+ free(zeros);
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 107393a8c48a..0584cbcdbd2d 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include <errno.h>
+#include <hash.h>
#include <hashtable.h>
#include <list.h>
#include <xalloc.h>
@@ -176,6 +177,7 @@ static struct module *new_module(const char *name, size_t namelen)
INIT_LIST_HEAD(&mod->unresolved_symbols);
INIT_LIST_HEAD(&mod->missing_namespaces);
INIT_LIST_HEAD(&mod->imported_namespaces);
+ INIT_LIST_HEAD(&mod->aliases);
memcpy(mod->name, name, namelen);
mod->name[namelen] = '\0';
@@ -209,19 +211,6 @@ struct symbol {
static HASHTABLE_DEFINE(symbol_hashtable, 1U << 10);
-/* This is based on the hash algorithm from gdbm, via tdb */
-static inline unsigned int tdb_hash(const char *name)
-{
- unsigned value; /* Used to compute the hash value. */
- unsigned i; /* Used to cycle through random values. */
-
- /* Set the initial value from the key size. */
- for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++)
- value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
-
- return (1103515243 * value + 12345);
-}
-
/**
* Allocate a new symbols for use in the hash of exported symbols or
* the list of unresolved symbols per module
@@ -239,7 +228,7 @@ static struct symbol *alloc_symbol(const char *name)
/* For the hash of exported symbols */
static void hash_add_symbol(struct symbol *sym)
{
- hash_add(symbol_hashtable, &sym->hnode, tdb_hash(sym->name));
+ hash_add(symbol_hashtable, &sym->hnode, hash_str(sym->name));
}
static void sym_add_unresolved(const char *name, struct module *mod, bool weak)
@@ -260,7 +249,7 @@ static struct symbol *sym_find_with_module(const char *name, struct module *mod)
if (name[0] == '.')
name++;
- hash_for_each_possible(symbol_hashtable, s, hnode, tdb_hash(name)) {
+ hash_for_each_possible(symbol_hashtable, s, hnode, hash_str(name)) {
if (strcmp(s->name, name) == 0 && (!mod || s->module == mod))
return s;
}
@@ -340,8 +329,6 @@ static const char *sec_name(const struct elf_info *info, unsigned int secindex)
return sech_name(info, &info->sechdrs[secindex]);
}
-#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
-
static struct symbol *sym_add_exported(const char *name, struct module *mod,
bool gpl_only, const char *namespace)
{
@@ -1966,6 +1953,7 @@ static void write_vmlinux_export_c_file(struct module *mod)
static void write_mod_c_file(struct module *mod)
{
struct buffer buf = { };
+ struct module_alias *alias, *next;
char fname[PATH_MAX];
int ret;
@@ -1973,7 +1961,14 @@ static void write_mod_c_file(struct module *mod)
add_exported_symbols(&buf, mod);
add_versions(&buf, mod);
add_depends(&buf, mod);
- add_moddevtable(&buf, mod);
+
+ buf_printf(&buf, "\n");
+ list_for_each_entry_safe(alias, next, &mod->aliases, node) {
+ buf_printf(&buf, "MODULE_ALIAS(\"%s\");\n", alias->str);
+ list_del(&alias->node);
+ free(alias);
+ }
+
add_srcversion(&buf, mod);
ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index ada3a36cc4bc..49848fcbe2a1 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -67,6 +67,8 @@
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
+
struct buffer {
char *p;
int pos;
@@ -79,6 +81,22 @@ buf_printf(struct buffer *buf, const char *fmt, ...);
void
buf_write(struct buffer *buf, const char *s, int len);
+/**
+ * struct module_alias - auto-generated MODULE_ALIAS()
+ *
+ * @node: linked to module::aliases
+ * @str: a string for MODULE_ALIAS()
+ */
+struct module_alias {
+ struct list_head node;
+ char str[];
+};
+
+/**
+ * struct module - represent a module (vmlinux or *.ko)
+ *
+ * @aliases: list head for module_aliases
+ */
struct module {
struct list_head list;
struct list_head exported_symbols;
@@ -89,12 +107,12 @@ struct module {
bool seen;
bool has_init;
bool has_cleanup;
- struct buffer dev_table_buf;
char srcversion[25];
// Missing namespace dependencies
struct list_head missing_namespaces;
// Actual imported namespaces
struct list_head imported_namespaces;
+ struct list_head aliases;
char name[];
};
@@ -170,7 +188,6 @@ Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr,
/* file2alias.c */
void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname);
-void add_moddevtable(struct buffer *buf, struct module *mod);
/* sumversion.c */
void get_src_version(const char *modname, char sum[], unsigned sumlen);
diff --git a/scripts/nsdeps b/scripts/nsdeps
index f1718cc0d700..bab4ec870e50 100644
--- a/scripts/nsdeps
+++ b/scripts/nsdeps
@@ -19,12 +19,6 @@ if ! { echo "$SPATCH_REQ_VERSION"; echo "$SPATCH_VERSION"; } | sort -CV ; then
exit 1
fi
-if [ "$KBUILD_EXTMOD" ]; then
- src_prefix=
-else
- src_prefix=$srctree/
-fi
-
generate_deps_for_ns() {
$SPATCH --very-quiet --in-place --sp-file \
$srctree/scripts/coccinelle/misc/add_namespace.cocci -D nsdeps -D ns=$1 $2
@@ -34,7 +28,7 @@ generate_deps() {
local mod=${1%.ko:}
shift
local namespaces="$*"
- local mod_source_files=$(sed "s|^\(.*\)\.o$|${src_prefix}\1.c|" $mod.mod)
+ local mod_source_files=$(sed "s|^\(.*\)\.o$|${srcroot}/\1.c|" $mod.mod)
for ns in $namespaces; do
echo "Adding namespace $ns to module $mod.ko."
@@ -57,4 +51,4 @@ generate_deps() {
while read line
do
generate_deps $line
-done < $MODULES_NSDEPS
+done < modules.nsdeps
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 441b0bb66e0d..fb686fd3266f 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -96,16 +96,18 @@ install_linux_image_dbg () {
# Parse modules.order directly because 'make modules_install' may sign,
# compress modules, and then run unneeded depmod.
- while read -r mod; do
- mod="${mod%.o}.ko"
- dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}"
- buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p')
- link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug"
-
- mkdir -p "${dbg%/*}" "${link%/*}"
- "${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}"
- ln -sf --relative "${dbg}" "${link}"
- done < modules.order
+ if is_enabled CONFIG_MODULES; then
+ while read -r mod; do
+ mod="${mod%.o}.ko"
+ dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}"
+ buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p')
+ link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug"
+
+ mkdir -p "${dbg%/*}" "${link%/*}"
+ "${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}"
+ ln -sf --relative "${dbg}" "${link}"
+ done < modules.order
+ fi
# Build debug package
# Different tools want the image in different locations
diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build
index 7ec1f061a519..64d958ee45f3 100755
--- a/scripts/package/install-extmod-build
+++ b/scripts/package/install-extmod-build
@@ -51,6 +51,13 @@ mkdir -p "${destdir}"
if [ "${CC}" != "${HOSTCC}" ]; then
echo "Rebuilding host programs with ${CC}..."
+ # This leverages external module building.
+ # - Clear sub_make_done to allow the top-level Makefile to redo sub-make.
+ # - Filter out --no-print-directory to print "Entering directory" logs
+ # when Make changes the working directory.
+ unset sub_make_done
+ MAKEFLAGS=$(echo "${MAKEFLAGS}" | sed s/--no-print-directory//)
+
cat <<-'EOF' > "${destdir}/Kbuild"
subdir-y := scripts
EOF
diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian
index fc3b7fa709fc..4ffcc70f8e31 100755
--- a/scripts/package/mkdebian
+++ b/scripts/package/mkdebian
@@ -202,7 +202,7 @@ Build-Depends-Arch: bc, bison, cpio, flex,
gcc-${host_gnu} <!pkg.${sourcename}.nokernelheaders>,
kmod, libelf-dev:native,
libssl-dev:native, libssl-dev <!pkg.${sourcename}.nokernelheaders>,
- rsync
+ python3:native, rsync
Homepage: https://www.kernel.org/
Package: $packagename-$version
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 38b96c6797f4..28169d7e143b 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -10,6 +10,8 @@
#
#
+set -e
+
usage() {
echo "Usage: $0 [--no-local] [srctree]" >&2
exit 1
@@ -30,6 +32,29 @@ if test $# -gt 0 -o ! -d "$srctree"; then
usage
fi
+try_tag() {
+ tag="$1"
+
+ # Is $tag an annotated tag?
+ if [ "$(git cat-file -t "$tag" 2> /dev/null)" != tag ]; then
+ return
+ fi
+
+ # Is it an ancestor of HEAD, and if so, how many commits are in $tag..HEAD?
+ # shellcheck disable=SC2046 # word splitting is the point here
+ set -- $(git rev-list --count --left-right "$tag"...HEAD 2> /dev/null)
+
+ # $1 is 0 if and only if $tag is an ancestor of HEAD. Use
+ # string comparison, because $1 is empty if the 'git rev-list'
+ # command somehow failed.
+ if [ "$1" != 0 ]; then
+ return
+ fi
+
+ # $2 is the number of commits in the range $tag..HEAD, possibly 0.
+ count="$2"
+}
+
scm_version()
{
local short=false
@@ -61,33 +86,33 @@ scm_version()
# stable kernel: 6.1.7 -> v6.1.7
version_tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/')
+ # try_tag initializes count if the tag is usable.
+ count=
+
# If a localversion* file exists, and the corresponding
# annotated tag exists and is an ancestor of HEAD, use
# it. This is the case in linux-next.
- tag=${file_localversion#-}
- desc=
- if [ -n "${tag}" ]; then
- desc=$(git describe --match=$tag 2>/dev/null)
+ if [ -n "${file_localversion#-}" ] ; then
+ try_tag "${file_localversion#-}"
fi
# Otherwise, if a localversion* file exists, and the tag
# obtained by appending it to the tag derived from
# KERNELVERSION exists and is an ancestor of HEAD, use
# it. This is e.g. the case in linux-rt.
- if [ -z "${desc}" ] && [ -n "${file_localversion}" ]; then
- tag="${version_tag}${file_localversion}"
- desc=$(git describe --match=$tag 2>/dev/null)
+ if [ -z "${count}" ] && [ -n "${file_localversion}" ]; then
+ try_tag "${version_tag}${file_localversion}"
fi
# Otherwise, default to the annotated tag derived from KERNELVERSION.
- if [ -z "${desc}" ]; then
- tag="${version_tag}"
- desc=$(git describe --match=$tag 2>/dev/null)
+ if [ -z "${count}" ]; then
+ try_tag "${version_tag}"
fi
- # If we are at the tagged commit, we ignore it because the version is
- # well-defined.
- if [ "${tag}" != "${desc}" ]; then
+ # If we are at the tagged commit, we ignore it because the
+ # version is well-defined. If none of the attempted tags exist
+ # or were usable, $count is still empty.
+ if [ -z "${count}" ] || [ "${count}" -gt 0 ]; then
# If only the short version is requested, don't bother
# running further git commands
@@ -95,14 +120,15 @@ scm_version()
echo "+"
return
fi
+
# If we are past the tagged commit, we pretty print it.
# (like 6.1.0-14595-g292a089d78d3)
- if [ -n "${desc}" ]; then
- echo "${desc}" | awk -F- '{printf("-%05d", $(NF-1))}'
+ if [ -n "${count}" ]; then
+ printf "%s%05d" "-" "${count}"
fi
# Add -g and exactly 12 hex chars.
- printf '%s%s' -g "$(echo $head | cut -c1-12)"
+ printf '%s%.12s' -g "$head"
fi
if ${no_dirty}; then
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f7586f82b967..4ce176ad411f 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4573,6 +4573,8 @@ static int validate_ibt(struct objtool_file *file)
!strcmp(sec->name, "__jump_table") ||
!strcmp(sec->name, "__mcount_loc") ||
!strcmp(sec->name, ".kcfi_traps") ||
+ !strcmp(sec->name, ".llvm.call-graph-profile") ||
+ !strcmp(sec->name, ".llvm_bb_addr_map") ||
!strcmp(sec->name, "__tracepoints") ||
strstr(sec->name, "__patchable_function_entries"))
continue;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 3d27983dc908..6f64d611faea 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -224,12 +224,17 @@ int find_symbol_hole_containing(const struct section *sec, unsigned long offset)
if (n)
return 0; /* not a hole */
- /* didn't find a symbol for which @offset is after it */
- if (!hole.sym)
- return 0; /* not a hole */
+ /*
+ * @offset >= sym->offset + sym->len, find symbol after it.
+ * When hole.sym is empty, use the first node to compute the hole.
+ * If there is no symbol in the section, the first node will be NULL,
+ * in which case, -1 is returned to skip the whole section.
+ */
+ if (hole.sym)
+ n = rb_next(&hole.sym->node);
+ else
+ n = rb_first_cached(&sec->symbol_tree);
- /* @offset >= sym->offset + sym->len, find symbol after it */
- n = rb_next(&hole.sym->node);
if (!n)
return -1; /* until end of address space */