From 5390d99fdb45fe8754120495d8b107a08e4d05f8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 17 Sep 2024 23:16:37 +0900 Subject: [PATCH 01/85] speakup: use SPKDIR=$(src) to specify the source directory Commit e68a558fb2af ("speakup: Fix building as extmod") was intended to support building this as an external module. Since commit b1992c3772e6 ("kbuild: use $(src) instead of $(srctree)/$(src) for source directory"), $(src) consistently points to the source directory, regardless of whether it is compiled as an external module or not. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- drivers/accessibility/speakup/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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) From ec873a4c551e2851adbafa27c89872255a891bf7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 17 Sep 2024 23:16:38 +0900 Subject: [PATCH 02/85] kbuild: refactor the check for missing config files This commit refactors the check for missing configuration files, making it easier to add more files to the list. The format of the error message has been slightly changed, as follows: [Before] ERROR: Kernel configuration is invalid. include/generated/autoconf.h or include/config/auto.conf are missing. Run 'make oldconfig && make prepare' on kernel src to fix it. [After] *** *** ERROR: Kernel configuration is invalid. The following files are missing: *** - include/generated/autoconf.h *** - include/config/auto.conf *** Run "make oldconfig && make prepare" on kernel source to fix it. *** Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier Tested-by: Miguel Ojeda --- Makefile | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index b8efbfe9da94..096b1e6cd965 100644 --- a/Makefile +++ b/Makefile @@ -781,17 +781,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 +# Use auto.conf to show the error message + +checked-configs := include/generated/autoconf.h include/config/auto.conf +missing-configs := $(filter-out $(wildcard $(checked-configs)), $(checked-configs)) + +ifdef missing-configs 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) + @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 From 985d6cccb67c1943c687294095df04a031183fdb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 17 Sep 2024 23:16:39 +0900 Subject: [PATCH 03/85] kbuild: check the presence of include/generated/rustc_cfg Since commit 2f7ab1267dc9 ("Kbuild: add Rust support"), Kconfig generates include/generated/rustc_cfg, but its presence is not checked in the top-level Makefile. It should be checked similarly to the C header counterpart, include/generated/autoconf.h. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier Acked-by: Miguel Ojeda Tested-by: Miguel Ojeda --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 096b1e6cd965..9b30c42ce3b3 100644 --- a/Makefile +++ b/Makefile @@ -783,7 +783,7 @@ else # !may-sync-config # and include/config/auto.conf but do not care if they are up-to-date. # Use auto.conf to show the error message -checked-configs := include/generated/autoconf.h include/config/auto.conf +checked-configs := include/generated/autoconf.h include/generated/rustc_cfg include/config/auto.conf missing-configs := $(filter-out $(wildcard $(checked-configs)), $(checked-configs)) ifdef missing-configs @@ -1201,7 +1201,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 From 654102df2ac2a0d02a416100c3d44ff1dae932ca Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 23 Sep 2024 16:56:03 +0900 Subject: [PATCH 04/85] kbuild: add generic support for built-in boot DTBs Some architectures embed boot DTBs in vmlinux. A potential issue for these architectures is a race condition during parallel builds because Kbuild descends into arch/*/boot/dts/ twice. One build thread is initiated by the 'dtbs' target, which is a prerequisite of the 'all' target in the top-level Makefile: ifdef CONFIG_OF_EARLY_FLATTREE all: dtbs endif For architectures that support the built-in boot dtb, arch/*/boot/dts/ is visited also during the ordinary directory traversal in order to build obj-y objects that wrap DTBs. Since these build threads are unaware of each other, they can run simultaneously during parallel builds. This commit introduces a generic build rule to scripts/Makefile.vmlinux to support embedded boot DTBs in a race-free way. Architectures that want to use this rule need to select CONFIG_GENERIC_BUILTIN_DTB. After the migration, Makefiles under arch/*/boot/dts/ will be visited only once to build only *.dtb files. This change also aims to unify the CONFIG options used for built-in DTBs support. Currently, different architectures use different CONFIG options for the same purposes. With this commit, the CONFIG options will be unified as follows: - CONFIG_GENERIC_BUILTIN_DTB This enables the generic rule for built-in boot DTBs. This will be renamed to CONFIG_BUILTIN_DTB after all architectures migrate to the generic rule. - CONFIG_BUILTIN_DTB_NAME This specifies the path to the embedded DTB. (relative to arch/*/boot/dts/) - CONFIG_BUILTIN_DTB_ALL If this is enabled, all DTB files compiled under arch/*/boot/dts/ are embedded into vmlinux. Only used by MIPS. Signed-off-by: Masahiro Yamada --- Makefile | 7 ++++++- drivers/of/Kconfig | 6 ++++++ scripts/Makefile.vmlinux | 44 ++++++++++++++++++++++++++++++++++++++++ scripts/link-vmlinux.sh | 4 ++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9b30c42ce3b3..855913b71e7a 100644 --- a/Makefile +++ b/Makefile @@ -1433,6 +1433,10 @@ ifdef CONFIG_OF_EARLY_FLATTREE all: dtbs endif +ifdef CONFIG_GENERIC_BUILTIN_DTB +vmlinux: dtbs +endif + endif PHONY += scripts_dtc @@ -1500,7 +1504,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 \ diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 0e2d608c3e20..6a53cbaa134c 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/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index 1284f05555b9..9ef0480ed755 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -17,6 +17,50 @@ quiet_cmd_cc_o_c = CC $@ %.o: %.c FORCE $(call if_changed_dep,cc_o_c) +quiet_cmd_as_o_S = AS $@ + cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< + +%.o: %.S FORCE + $(call if_changed_dep,as_o_S) + +# Built-in dtb +# --------------------------------------------------------------------------- + +quiet_cmd_wrap_dtbs = WRAP $@ + cmd_wrap_dtbs = { \ + echo '\#include '; \ + 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 vmlinux: .vmlinux.export.o diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a9b3f34a78d2..53bd4b727e21 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 From b95d0899c8bfa1346dd195e868c48008d888bac9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 30 Sep 2024 02:32:36 +0900 Subject: [PATCH 05/85] usb: use "prompt" instead of "bool" for choice prompts Since commit fde192511bdb ("kconfig: remove tristate choice support"), all choice blocks are now boolean. There is no longer a need to specify the choice type explicitly. Most choice blocks already use "prompt". Before the next commit removes support for the "bool" syntax in choice entries, this commit converts the remaining "bool" occurences under drivers/usb/. Signed-off-by: Masahiro Yamada --- drivers/usb/dwc2/Kconfig | 2 +- drivers/usb/dwc3/Kconfig | 2 +- drivers/usb/isp1760/Kconfig | 2 +- drivers/usb/mtu3/Kconfig | 2 +- drivers/usb/musb/Kconfig | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) 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) From bea2c5ef789a37bace99f2f45eeef3be4559b228 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 30 Sep 2024 02:32:37 +0900 Subject: [PATCH 06/85] kconfig: remove support for "bool" prompt for choice entries Since commit fde192511bdb ("kconfig: remove tristate choice support"), all choice blocks are now boolean. There is no longer a need to specify the choice type explicitly. All "bool" prompts in choice entries have been converted to "prompt". This commit removes support for the "bool" syntax in choice entries. Signed-off-by: Masahiro Yamada --- Documentation/kbuild/kconfig-language.rst | 4 ++-- scripts/kconfig/parser.y | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) 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:: "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/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index bc43fb67c7c4..f0f17b21d1b5 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -293,12 +293,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); From 6971f7192c12043667173cc78fe88d52ff7ee488 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 30 Sep 2024 02:32:38 +0900 Subject: [PATCH 07/85] kconfig: remove zconfprint() Turn all warnings during parsing into hard errors. Signed-off-by: Masahiro Yamada --- scripts/kconfig/parser.y | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index f0f17b21d1b5..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); }; @@ -402,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 ?: ""); + zconf_error("'%s' defined with more than one help text", + current_entry->sym->name ?: ""); } /* 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 ?: ""); + zconf_error("'%s' defined with blank help text", + current_entry->sym->name ?: ""); current_entry->help = $2; }; @@ -592,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; From ccb3ee82fa50dccdcd186ed0f6c0d8d14c86a24f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Oct 2024 03:00:06 +0900 Subject: [PATCH 08/85] kconfig: qconf: set QSplitter orientation in the constructor The orientation of the QSplitter can be specified directly in its constructor. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index e260cab1c2af..202823aad393 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1240,8 +1240,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"); @@ -1344,15 +1343,13 @@ ConfigMainWindow::ConfigMainWindow(void) QVBoxLayout *layout = new QVBoxLayout(widget); setCentralWidget(widget); - split1 = new QSplitter(widget); - split1->setOrientation(Qt::Horizontal); + split1 = new QSplitter(Qt::Horizontal, widget); split1->setChildrenCollapsible(false); menuList = new ConfigList(widget, "menu"); - split2 = new QSplitter(widget); + split2 = new QSplitter(Qt::Vertical, widget); split2->setChildrenCollapsible(false); - split2->setOrientation(Qt::Vertical); // create config tree configList = new ConfigList(widget, "config"); From 7d48998b58e83a11500d2234e528003ef5d7e982 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Oct 2024 03:00:07 +0900 Subject: [PATCH 09/85] kconfig: qconf: reorder code in ConfigMainWindow() constructor Rearrange the code to make the upcoming refactoring easier to understand. No functional changes intended. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 202823aad393..2c80e3e1a91a 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1340,29 +1340,28 @@ ConfigMainWindow::ConfigMainWindow(void) ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback)); QWidget *widget = new QWidget(this); - QVBoxLayout *layout = new QVBoxLayout(widget); setCentralWidget(widget); - split1 = new QSplitter(Qt::Horizontal, widget); - split1->setChildrenCollapsible(false); - - menuList = new ConfigList(widget, "menu"); + QVBoxLayout *layout = new QVBoxLayout(widget); split2 = new QSplitter(Qt::Vertical, widget); + layout->addWidget(split2); split2->setChildrenCollapsible(false); - // create config tree + split1 = new QSplitter(Qt::Horizontal, widget); + split2->addWidget(split1); + split1->setChildrenCollapsible(false); + configList = new ConfigList(widget, "config"); + split1->addWidget(configList); + + menuList = new ConfigList(widget, "menu"); + split1->addWidget(menuList); helpText = new ConfigInfoView(widget, "help"); - - layout->addWidget(split2); - split2->addWidget(split1); - split1->addWidget(configList); - split1->addWidget(menuList); split2->addWidget(helpText); - setTabOrder(configList, helpText); + configList->setFocus(); backAction = new QAction(QPixmap(xpm_back), "Back", this); From 93096d7d2a86b45d1590b041fa9b31546f2f8095 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Oct 2024 03:00:08 +0900 Subject: [PATCH 10/85] kconfig: qconf: set parent in the widget constructor The ->addWidget() method re-parents the widget. The parent QWidget can be specified directly in the constructor. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 2c80e3e1a91a..7bac48ac5d21 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1348,18 +1348,14 @@ ConfigMainWindow::ConfigMainWindow(void) layout->addWidget(split2); split2->setChildrenCollapsible(false); - split1 = new QSplitter(Qt::Horizontal, widget); - split2->addWidget(split1); + split1 = new QSplitter(Qt::Horizontal, split2); split1->setChildrenCollapsible(false); - configList = new ConfigList(widget, "config"); - split1->addWidget(configList); + configList = new ConfigList(split1, "config"); - menuList = new ConfigList(widget, "menu"); - split1->addWidget(menuList); + menuList = new ConfigList(split1, "menu"); - helpText = new ConfigInfoView(widget, "help"); - split2->addWidget(helpText); + helpText = new ConfigInfoView(split2, "help"); setTabOrder(configList, helpText); configList->setFocus(); From 4da0f0d0cc16606376b3fdb8a257f539b37ab057 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 14 Oct 2024 11:18:28 +0200 Subject: [PATCH 11/85] kconfig: nconf: Use TAB to cycle thru dialog buttons Add the ability to cycle through dialog buttons with the TAB key. Signed-off-by: Thorsten Blum Signed-off-by: Masahiro Yamada --- scripts/kconfig/nconf.gui.c | 9 +++++++++ 1 file changed, 9 insertions(+) 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 ' ': From f16c8c08185420092d04edce6066eaf4a454bb20 Mon Sep 17 00:00:00 2001 From: David Hunter Date: Mon, 14 Oct 2024 10:13:31 -0400 Subject: [PATCH 12/85] streamline_config.pl: fix missing variable operator in debug print Put in the dollar sign for the variable '$config'. That way, the debug message has more meaning. Signed-off-by: David Hunter Signed-off-by: Masahiro Yamada --- scripts/kconfig/streamline_config.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index d51cd7ac15d2..a85d6a3108a1 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -503,7 +503,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; } From 90edd30b8696833a995ab6196a6bee70fb9fcf2c Mon Sep 17 00:00:00 2001 From: David Hunter Date: Mon, 14 Oct 2024 10:13:32 -0400 Subject: [PATCH 13/85] streamline_config.pl: ensure all defaults are tracked Track default options on the second line. On the second line of some config entries, default and dependency options sometimes appear. In those instances, the state will be "NEW" and not "DEP". Signed-off-by: David Hunter Signed-off-by: Masahiro Yamada --- scripts/kconfig/streamline_config.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index a85d6a3108a1..85f4712e2bf3 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -220,7 +220,7 @@ 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; if ($dep !~ /^\s*(y|m|n)\s*$/) { $dep =~ s/.*\sif\s+//; From bf98f6d1082463392f7fadd6292f3289207e07c7 Mon Sep 17 00:00:00 2001 From: David Hunter Date: Mon, 14 Oct 2024 10:13:33 -0400 Subject: [PATCH 14/85] streamline_config.pl: remove prompt warnings for configs with defaults Ignore process select warnings for config entries that have a default option. Some config entries have no prompt, and nothing selects them, but these config options are okay because they have a default option. Signed-off-by: David Hunter Signed-off-by: Masahiro Yamada --- scripts/kconfig/streamline_config.pl | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 85f4712e2bf3..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; @@ -222,6 +223,7 @@ sub read_kconfig { $depends{$config} .= " " . $1; } 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; @@ -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; } From cdb1e767c8db704965e0ca13f6e91a94a5d6cfb1 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sat, 19 Oct 2024 23:17:47 +0200 Subject: [PATCH 15/85] kconfig: nconf: Fix typo in function comment s/handles/handled/ Signed-off-by: Thorsten Blum Signed-off-by: Masahiro Yamada --- scripts/kconfig/nconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From cdb37fe66fb260acce16c999a61a963fca93468a Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Wed, 23 Oct 2024 08:31:46 +0200 Subject: [PATCH 16/85] kconfig: qconf: use QString to store path to configuration file This is the native type used by the file dialogs and avoids any hassle with filename encoding when converting this back and forth to a character array. Signed-off-by: Rolf Eike Beer Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 24 ++++++------------------ scripts/kconfig/qconf.h | 2 +- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 7bac48ac5d21..b620efac7da0 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1381,7 +1381,7 @@ ConfigMainWindow::ConfigMainWindow(void) conf_set_changed_callback(conf_changed); - configname = xstrdup(conf_get_configname()); + configname = conf_get_configname(); QAction *saveAsAction = new QAction("Save &As...", this); connect(saveAsAction, &QAction::triggered, @@ -1520,28 +1520,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; } @@ -1553,23 +1547,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) diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index 53373064d90a..aab25ece95c6 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -237,7 +237,7 @@ public slots: class ConfigMainWindow : public QMainWindow { Q_OBJECT - char *configname; + QString configname; static QAction *saveAction; static void conf_changed(bool); public: From 5a4bed0fad83cdecc91dfd541b326801d3979564 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Wed, 23 Oct 2024 08:36:10 +0200 Subject: [PATCH 17/85] kconfig: qconf: use default platform shortcuts This renames "Load" to "Open" and switches Ctrl-L to Ctrl-O for the default platforms. This may break the workflow for those used to it, but will make it actually work for everyone else like me who would just expect the default behavior. Add some more standard shortcuts where available. If they replace the existing shortcuts they would have the same value in my case. Signed-off-by: Rolf Eike Beer Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index b620efac7da0..f01fa1481d6e 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1361,21 +1361,22 @@ ConfigMainWindow::ConfigMainWindow(void) 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); @@ -1384,10 +1385,11 @@ ConfigMainWindow::ConfigMainWindow(void) 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); From 8b36d3f2e612866e705b16e9c792e10b62c6c10e Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Wed, 23 Oct 2024 08:39:15 +0200 Subject: [PATCH 18/85] kconfig: qconf: simplify character replacement Replace the hand crafted lookup table with a QHash. This has the nice benefit that the added offsets can not get out of sync with the length of the replacement strings. Signed-off-by: Rolf Eike Beer Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index f01fa1481d6e..90f139480eda 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1122,28 +1122,19 @@ QString ConfigInfoView::print_filter(const QString &str) { QRegularExpression re("[<>&\"\\n]"); QString res = str; + + QHash patterns; + patterns['<'] = "<"; + patterns['>'] = ">"; + patterns['&'] = "&"; + patterns['"'] = """; + patterns['\n'] = "
"; + for (int i = 0; (i = res.indexOf(re, i)) >= 0;) { - switch (res[i].toLatin1()) { - case '<': - res.replace(i, 1, "<"); - i += 4; - break; - case '>': - res.replace(i, 1, ">"); - i += 4; - break; - case '&': - res.replace(i, 1, "&"); - i += 5; - break; - case '"': - res.replace(i, 1, """); - i += 6; - break; - case '\n': - res.replace(i, 1, "
"); - i += 4; - break; + const QString n = patterns.value(res[i], QString()); + if (!n.isEmpty()) { + res.replace(i, 1, n); + i += n.length(); } } return res; From 4a798a1e1017ef72240e23882aa2ab93efb553e7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:51 +0900 Subject: [PATCH 19/85] kconfig: qconf: remove mouse{Press,Move}Event() functions These functions simply passes the event to the parent. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 14 -------------- scripts/kconfig/qconf.h | 2 -- 2 files changed, 16 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 90f139480eda..18cc5c184f56 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -781,13 +781,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 +827,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(); diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index aab25ece95c6..0b62fb26821a 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -55,9 +55,7 @@ class ConfigList : public QTreeWidget { 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); From 0bab492cfe04e8b61188d4162b302b1f7ae9f4df Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:52 +0900 Subject: [PATCH 20/85] kconfig: qconf: remove redundant type check for choice members Since commit fde192511bdb ("kconfig: remove tristate choice support"), choice members are always boolean. The type check is redundant. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 18cc5c184f56..58c57c908149 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -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); From ac845932cbaa30020d5943fc4448bba7b7327158 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:53 +0900 Subject: [PATCH 21/85] kconfig: qconf: remove unnecessary setRootIsDecorated() call The default value of the rootIsDecorated property is true. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 58c57c908149..120090fa4ac9 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -307,7 +307,6 @@ ConfigList::ConfigList(QWidget *parent, const char *name) { setObjectName(name); setSortingEnabled(false); - setRootIsDecorated(true); setVerticalScrollMode(ScrollPerPixel); setHorizontalScrollMode(ScrollPerPixel); From 375a4f4ea719ad68e305373cfe0f77ecd1378531 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:54 +0900 Subject: [PATCH 22/85] kconfig: qconf: remove unnecessary lastWindowClosed() signal connection The default value of the quitOnLastWindowClosed property is true. Hence, the application implicitly quits when the last window is closed. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 120090fa4ac9..49a3d0365c39 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1863,7 +1863,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(); From b6962d8694963620401c24f051999678943a7123 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:55 +0900 Subject: [PATCH 23/85] kconfig: qconf: convert the last old connection syntax to Qt5 style Commit a2574c12df0d ("kconfig: qconf: convert to Qt5 new signal/slot connection syntax") converted most of the old string-based connections, but one more instance still remains. Convert it to the new style. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 49a3d0365c39..c922c34621a4 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1475,6 +1475,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(); @@ -1863,7 +1866,6 @@ int main(int ac, char** av) v = new ConfigMainWindow(); //zconfdump(stdout); - configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); v->show(); configApp->exec(); From 76567f93b3454cae3a3eaa23a3b28c94b70ee013 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:56 +0900 Subject: [PATCH 24/85] kconfig: qconf: do not show goParent button in split view When a menu is selected in the split view, the right pane displays the goParent button, but it is never functional. This is unnecessary, as you can select a menu from the menu tree in the left pane. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index c922c34621a4..7c844c4a119e 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -436,8 +436,7 @@ void ConfigList::updateList() 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); From 511ff539c31d89e3f7132a61dae2ebcb0c4b2912 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:57 +0900 Subject: [PATCH 25/85] kconfig: qconf: remove ConfigItem::visible member The " (NEW)" string should be displayed regardless of the visibility of the associated menu. The ConfigItem::visible member is not used for any other purpose. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 28 +++++++++++----------------- scripts/kconfig/qconf.h | 15 +++++++-------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 7c844c4a119e..5b1237bf085a 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -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; @@ -429,7 +428,7 @@ void ConfigList::updateList() item = (ConfigItem*)(*it); if (!item->menu) continue; - item->testUpdateMenu(menu_is_visible(item->menu)); + item->testUpdateMenu(); ++it; } @@ -439,16 +438,16 @@ void ConfigList::updateList() 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(); @@ -597,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) { @@ -629,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); @@ -662,7 +659,6 @@ void ConfigList::updateMenuList(struct menu *menu) struct menu* child; ConfigItem* item; ConfigItem* last; - bool visible; enum prop_type type; if (!menu) { @@ -694,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); @@ -1274,8 +1269,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); } } diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index 0b62fb26821a..62ab3286d04f 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -114,25 +114,25 @@ public slots: 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(); @@ -159,7 +159,6 @@ class ConfigItem : public QTreeWidgetItem { ConfigItem* nextItem; struct menu *menu; - bool visible; bool goParent; static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon; From 572cd1d2a9a68b66af98a60f4aad4f01d6589447 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:58 +0900 Subject: [PATCH 26/85] kconfig: qconf: avoid unnecessary parentSelected() when ESC is pressed When the ESC key is pressed, the parentSelected() signal is currently emitted for singleMode, menuMode, and symbolMode. However, parentSelected() signal is functional only for singleMode. In menuMode, the signal is connected to the goBack() slot, but nothing occurs because configList->rootEntry is always &rootmenu. In symbolMode (in the right pane), the parentSelected() signal is not connected to any slot. This commit prevents the unnecessary emission of the parentSelected() signal. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 5b1237bf085a..1948cda048d2 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -724,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; From 8e8ce9531e09376d987ff0e09491bea82a0f6411 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:17:59 +0900 Subject: [PATCH 27/85] kconfig: qconf: remove redundant check in goBack() The same check is performed in the configList->setParentMenu() call. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 1948cda048d2..acbc4331ebc5 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1616,9 +1616,6 @@ void ConfigMainWindow::listFocusChanged(void) void ConfigMainWindow::goBack(void) { - if (configList->rootEntry == &rootmenu) - return; - configList->setParentMenu(); } From 929ce506d60ede917f241fb40e0bed6ab3e52999 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:18:00 +0900 Subject: [PATCH 28/85] kconfig: qconf: remove non-functional href="m..." tag The only functional tag is href="s". Commit c4f7398bee9c ("kconfig: qconf: make debug links work again") changed prop->name to sym->name for this reference, but it missed to change the tag "m" to "s". This tag is not functional at all. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index acbc4331ebc5..a208ef33128f 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1065,9 +1065,9 @@ QString ConfigInfoView::debug_info(struct symbol *sym) switch (prop->type) { case P_PROMPT: case P_MENU: - stream << "prompt: name << "\">"; + stream << "prompt: "; stream << print_filter(prop->text); - stream << "
"; + stream << "
"; break; case P_DEFAULT: case P_SELECT: From bce590f1020742d81e9fbfe3b045538973111c11 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:18:01 +0900 Subject: [PATCH 29/85] kconfig: add sym_get_prompt_menu() helper function Split out the code that retrieves the menu entry with a prompt, so it can be reused in other functions. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lkc_proto.h | 1 + scripts/kconfig/symbol.c | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) 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/symbol.c b/scripts/kconfig/symbol.c index a3af93aaaf32..89b84bf8e21f 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -70,6 +70,24 @@ const char *sym_type_name(enum symbol_type type) return "???"; } +/** + * 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 * @@ -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; From a914032b71f0a74e9c9114ff9be8babb55bbca67 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:18:02 +0900 Subject: [PATCH 30/85] kconfig: qconf: refactor ConfigInfoView::clicked() Most of the code in ConfigInfoView::clicked() is unnecessary. There is no need to use the regular expression to search for a symbol. Calling sym_find() is simpler and faster. The hyperlink always begins with the "s" tag, and there is no other tag used. Remove it. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 43 ++++++---------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index a208ef33128f..f59a9597f09b 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1001,7 +1001,7 @@ void ConfigInfoView::menuInfo(void) if (sym->name) { stream << " ("; if (showDebug()) - stream << "name << "\">"; + stream << "name << "\">"; stream << print_filter(sym->name); if (showDebug()) stream << ""; @@ -1010,7 +1010,7 @@ void ConfigInfoView::menuInfo(void) } else if (sym->name) { stream << ""; if (showDebug()) - stream << "name << "\">"; + stream << "name << "\">"; stream << print_filter(sym->name); if (showDebug()) stream << ""; @@ -1124,7 +1124,7 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char QTextStream *stream = reinterpret_cast(data); if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { - *stream << "name << "\">"; + *stream << "name << "\">"; *stream << print_filter(str); *stream << ""; } else { @@ -1134,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; + struct menu *m; - 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; - } - - 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(); @@ -1174,9 +1146,6 @@ void ConfigInfoView::clicked(const QUrl &url) } else { emit menuSelected(m); } - - free(result); - delete[] data; } void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event) From d6a91e28d11902e6cd5715633ed6f9b6df75de32 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 03:18:03 +0900 Subject: [PATCH 31/85] kconfig: qconf: remove unnecessary mode check in ConfigItem::updateMenu() The P_MENU entries ("menu" and "menuconfig") are never displayed in symbolMode. The condition, list->mode == symbolMode, is never met here. Signed-off-by: Masahiro Yamada --- scripts/kconfig/qconf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index f59a9597f09b..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. */ From a49401be4c780f3397ca19a070d7c38e6f032efa Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 24 Oct 2024 20:25:45 +0900 Subject: [PATCH 32/85] kconfig: document the positional argument in the help message The positional argument specifies the top-level Kconfig. Include this information in the help message. Signed-off-by: Masahiro Yamada --- scripts/kconfig/conf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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] \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) From 397a479b511df4e6e7c665d7d8991943645b4cab Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 25 Oct 2024 02:09:22 +0900 Subject: [PATCH 33/85] kbuild: simplify rustfmt target There is no need to prune the rust/alloc directory because it was removed by commit 9d0441bab775 ("rust: alloc: remove our fork of the `alloc` crate"). There is no need to prune the rust/test directory because no '*.rs' files are generated within it. To avoid forking the 'grep -Fv generated' process, filter out generated files using the option, ! -name '*generated*'. Now that the '-path ... -prune' option is no longer used, there is no need to use the absolute path. Searching in $(srctree), which can be a relative path, is sufficient. The comment mentions the use case where $(srctree) is '..', that is, $(objtree) is a sub-directory of $(srctree). In this scenario, all '*.rs' files under $(objtree) are generated files and filters out by the '*generated*' pattern. Add $(RCS_FIND_IGNORE) as a shortcut. Although I do not believe '*.rs' files would exist under the .git directory, there is no need for the 'find' command to traverse it. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier Acked-by: Miguel Ojeda --- Makefile | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 855913b71e7a..266376f7f164 100644 --- a/Makefile +++ b/Makefile @@ -1754,18 +1754,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 From 315ad8780a129e82e2c5c65ee6e970d91a577acb Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:08 -0700 Subject: [PATCH 34/85] kbuild: Add AutoFDO support for Clang build Add the build support for using Clang's AutoFDO. Building the kernel with AutoFDO does not reduce the optimization level from the compiler. AutoFDO uses hardware sampling to gather information about the frequency of execution of different code paths within a binary. This information is then used to guide the compiler's optimization decisions, resulting in a more efficient binary. Experiments showed that the kernel can improve up to 10% in latency. The support requires a Clang compiler after LLVM 17. This submission is limited to x86 platforms that support PMU features like LBR on Intel machines and AMD Zen3 BRS. Support for SPE on ARM 1, and BRBE on ARM 1 is part of planned future work. 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 has 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 \ -o -- For AMD platforms: The supported system are: Zen3 with BRS, or Zen4 with amd_lbr_v2 For Zen3: $ cat proc/cpuinfo | grep " brs" For Zen4: $ cat proc/cpuinfo | grep amd_lbr_v2 $ perf record --pfm-events RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a \ -N -b -c -o -- 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 or later, or from the LLVM trunk. $ llvm-profgen --kernel --binary= --perfdata= \ -o or $ create_llvm_prof --binary= --profile= \ --format=extbinary --out= Note that multiple AutoFDO profile files can be merged into one via: $ llvm-profdata merge -o ... 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= Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Suggested-by: Krzysztof Pszeniczny Suggested-by: Nick Desaulniers Suggested-by: Stephane Eranian Tested-by: Yonghong Song Tested-by: Yabin Cui Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Tested-by: Peter Jung Signed-off-by: Masahiro Yamada --- Documentation/dev-tools/autofdo.rst | 168 ++++++++++++++++++++++++++++ Documentation/dev-tools/index.rst | 1 + MAINTAINERS | 7 ++ Makefile | 1 + arch/Kconfig | 20 ++++ arch/x86/Kconfig | 1 + scripts/Makefile.autofdo | 22 ++++ scripts/Makefile.lib | 10 ++ tools/objtool/check.c | 1 + 9 files changed, 231 insertions(+) create mode 100644 Documentation/dev-tools/autofdo.rst create mode 100644 scripts/Makefile.autofdo 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 -o -- + + - 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 -o -- + +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= --perfdata= -o + + or :: + + $ create_llvm_prof --binary= --profile= --format=extbinary --out= + + Note that multiple AutoFDO profile files can be merged into one via:: + + $ llvm-profdata merge -o ... + +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= diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index 53d4d124f9c5..6945644f7008 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -34,6 +34,7 @@ Documentation/dev-tools/testing-overview.rst ktap checkuapi gpio-sloppy-logic-analyzer + autofdo .. only:: subproject and html diff --git a/MAINTAINERS b/MAINTAINERS index bdae0faf000c..1eba172ed532 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3665,6 +3665,13 @@ F: kernel/audit* F: lib/*audit.c K: \baudit_[a-z_0-9]\+\b +AUTOFDO BUILD +M: Rong Xu +M: Han Shen +S: Supported +F: Documentation/dev-tools/autofdo.rst +F: scripts/Makefile.autofdo + AUXILIARY BUS DRIVER M: Greg Kroah-Hartman R: Dave Ertman diff --git a/Makefile b/Makefile index 266376f7f164..1f31c633a41d 100644 --- a/Makefile +++ b/Makefile @@ -1023,6 +1023,7 @@ 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_GCC_PLUGINS) += scripts/Makefile.gcc-plugins include $(addprefix $(srctree)/, $(include-y)) diff --git a/arch/Kconfig b/arch/Kconfig index bd9f095d69fa..8dca3b5e6ef5 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -811,6 +811,26 @@ 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_CFI_CLANG bool help diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 16354dfa6d96..9dc87661fb37 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -126,6 +126,7 @@ config X86 select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN select ARCH_SUPPORTS_RT + select ARCH_SUPPORTS_AUTOFDO_CLANG select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if X86_CMPXCHG64 select ARCH_USE_MEMTEST diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo new file mode 100644 index 000000000000..ff96a63fea7c --- /dev/null +++ b/scripts/Makefile.autofdo @@ -0,0 +1,22 @@ +# 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) +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 +endif + +export CFLAGS_AUTOFDO_CLANG diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 01a9f567d5af..2d0942c1a027 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -191,6 +191,16 @@ _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 + # $(src) for including checkin headers from generated source files # $(obj) for including generated headers from checkin source files ifeq ($(KBUILD_EXTMOD),) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 6604f5d038aa..4c5229991e1e 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4557,6 +4557,7 @@ 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") || strstr(sec->name, "__patchable_function_entries")) continue; From 18e885099f1c52755f054202525cb60d3edcda44 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:09 -0700 Subject: [PATCH 35/85] objtool: Fix unreachable instruction warnings for weak functions In the presence of both weak and strong function definitions, the linker drops the weak symbol in favor of a strong symbol, but leaves the code in place. Code in ignore_unreachable_insn() has some heuristics to suppress the warning, but it does not work when -ffunction-sections is enabled. Suppose function foo has both strong and weak definitions. Case 1: The strong definition has an annotated section name, like .init.text. Only the weak definition will be placed into .text.foo. But since the section has no symbols, there will be no "hole" in the section. Case 2: Both sections are without an annotated section name. Both will be placed into .text.foo section, but there will be only one symbol (the strong one). If the weak code is before the strong code, there is no "hole" as it fails to find the right-most symbol before the offset. The fix is to use the first node to compute the hole if hole.sym is empty. 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. Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Suggested-by: Krzysztof Pszeniczny Tested-by: Yonghong Song Tested-by: Yabin Cui Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Acked-by: Josh Poimboeuf Signed-off-by: Masahiro Yamada --- tools/objtool/elf.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) 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 */ From 52892ed6b03a14b961c1df783ed05763758abc73 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Tue, 26 Nov 2024 09:34:09 -0800 Subject: [PATCH 36/85] MIPS: Place __kernel_entry at the beginning of text section Mark __kernel_entry as ".head.text" and place HEAD_TEXT before TEXT_TEXT in the linker script. This ensures that __kernel_entry will be placed at the beginning of text section. Drop mips from scripts/head-object-list.txt. Signed-off-by: Rong Xu Reported-by: Chris Packham Closes: https://lore.kernel.org/lkml/c6719149-8531-4174-824e-a3caf4bc6d0e@alliedtelesis.co.nz/T/ Tested-by: Chris Packham Signed-off-by: Masahiro Yamada --- arch/mips/kernel/head.S | 1 + arch/mips/kernel/vmlinux.lds.S | 1 + scripts/head-object-list.txt | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) 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/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 From 0043ecea2399ffc8bfd99ed9dbbe766e7c79293c Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:10 -0700 Subject: [PATCH 37/85] vmlinux.lds.h: Adjust symbol ordering in text output section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the -ffunction-sections compiler option is enabled, each function is placed in a separate section named .text.function_name rather than putting all functions in a single .text section. However, using -function-sections can cause problems with the linker script. The comments included in include/asm-generic/vmlinux.lds.h note these issues.: “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.” It is unclear whether there is a straightforward method for converting a suffix to "..". This patch modifies the order of subsections within the text output section. Specifically, it changes current order: .text.hot, .text, .text_unlikely, .text.unknown, .text.asan to the new order: .text.asan, .text.unknown, .text_unlikely, .text.hot, .text Here is the rationale behind the new layout: The majority of the code resides in three sections: .text.hot, .text, and .text.unlikely, with .text.unknown containing a negligible amount. .text.asan is only generated in ASAN builds. The primary goal is to group code segments based on their execution frequency (hotness). First, we want to place .text.hot adjacent to .text. Since we cannot put .text.hot after .text (Due to constraints with -ffunction-sections, placing .text.hot after .text is problematic), we need to put .text.hot before .text. Then it comes to .text.unlikely, we cannot put it after .text (same -ffunction-sections issue) . Therefore, we position .text.unlikely before .text.hot. .text.unknown and .tex.asan follow the same logic. This revised ordering effectively reverses the original arrangement (for .text.unlikely, .text.unknown, and .tex.asan), maintaining a similar level of affinity between sections. It also places .text.hot section at the beginning of a page to better utilize the TLB entry. Note that the limitation arises because the linker script employs glob patterns instead of regular expressions for string matching. While there is a method to maintain the current order using complex patterns, this significantly complicates the pattern and increases the likelihood of errors. This patch also changes vmlinux.lds.S for the sparc64 architecture to accommodate specific symbol placement requirements. Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Suggested-by: Krzysztof Pszeniczny Tested-by: Yonghong Song Tested-by: Yabin Cui Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Signed-off-by: Masahiro Yamada --- arch/sparc/kernel/vmlinux.lds.S | 5 +++++ include/asm-generic/vmlinux.lds.h | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) 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/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index eeadbaeccf88..fd901951549c 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -553,19 +553,24 @@ * .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.asan.* .text.tsan.*) \ + *(.text.unknown .text.unknown.*) \ + *(.text.unlikely .text.unlikely.*) \ + . = ALIGN(PAGE_SIZE); \ *(.text.hot .text.hot.*) \ *(TEXT_MAIN .text.fixup) \ - *(.text.unlikely .text.unlikely.*) \ - *(.text.unknown .text.unknown.*) \ NOINSTR_TEXT \ - *(.ref.text) \ - *(.text.asan.* .text.tsan.*) + *(.ref.text) /* sched.text is aling to function alignment to secure we have same From db0b2991ae1aac5ca985ec6fd8ff9bd9b2126c9b Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:11 -0700 Subject: [PATCH 38/85] vmlinux.lds.h: Add markers for text_unlikely and text_hot sections Add markers like __hot_text_start, __hot_text_end, __unlikely_text_start, and __unlikely_text_end which will be included in System.map. These markers indicate how the compiler groups functions, providing valuable information to developers about the layout and optimization of the code. Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Tested-by: Yonghong Song Tested-by: Yabin Cui Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Signed-off-by: Masahiro Yamada --- include/asm-generic/vmlinux.lds.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index fd901951549c..e02973f3b418 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -549,6 +549,16 @@ __cpuidle_text_end = .; \ __noinstr_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 @@ -565,9 +575,9 @@ ALIGN_FUNCTION(); \ *(.text.asan.* .text.tsan.*) \ *(.text.unknown .text.unknown.*) \ - *(.text.unlikely .text.unlikely.*) \ + TEXT_UNLIKELY \ . = ALIGN(PAGE_SIZE); \ - *(.text.hot .text.hot.*) \ + TEXT_HOT \ *(TEXT_MAIN .text.fixup) \ NOINSTR_TEXT \ *(.ref.text) From 0847420f5e499a7ab518942fff71482179290163 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:12 -0700 Subject: [PATCH 39/85] AutoFDO: Enable -ffunction-sections for the AutoFDO build Enable -ffunction-sections by default for the AutoFDO build. With -ffunction-sections, the compiler places each function in its own section named .text.function_name instead of placing all functions in the .text section. In the AutoFDO build, this allows the linker to utilize profile information to reorganize functions for improved utilization of iCache and iTLB. Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Tested-by: Yonghong Song Tested-by: Yabin Cui Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Signed-off-by: Masahiro Yamada --- include/asm-generic/vmlinux.lds.h | 11 +++++++++-- scripts/Makefile.autofdo | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index e02973f3b418..bd64fdedabd2 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, 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) #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 diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo index ff96a63fea7c..6155d6fc4ca7 100644 --- a/scripts/Makefile.autofdo +++ b/scripts/Makefile.autofdo @@ -9,7 +9,7 @@ ifndef CONFIG_DEBUG_INFO endif ifdef CLANG_AUTOFDO_PROFILE - CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) + CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -ffunction-sections endif ifdef CONFIG_LTO_CLANG_THIN From 2fd65f7afd5a73b685a1651cb651ade120b53e15 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:13 -0700 Subject: [PATCH 40/85] AutoFDO: Enable machine function split optimization for AutoFDO Enable the machine function split optimization for AutoFDO in Clang. Machine function split (MFS) is a pass in the Clang compiler that splits a function into hot and cold parts. The linker groups all cold blocks across functions together. This decreases hot code fragmentation and improves iCache and iTLB utilization. MFS requires a profile so this is enabled only for the AutoFDO builds. Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Suggested-by: Krzysztof Pszeniczny Tested-by: Yonghong Song Tested-by: Yabin Cui Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Signed-off-by: Masahiro Yamada --- include/asm-generic/vmlinux.lds.h | 7 ++++++- scripts/Makefile.autofdo | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index bd64fdedabd2..8a0bb3946cf0 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -556,6 +556,11 @@ defined(CONFIG_AUTOFDO_CLANG) __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.*) \ @@ -582,6 +587,7 @@ defined(CONFIG_AUTOFDO_CLANG) ALIGN_FUNCTION(); \ *(.text.asan.* .text.tsan.*) \ *(.text.unknown .text.unknown.*) \ + TEXT_SPLIT \ TEXT_UNLIKELY \ . = ALIGN(PAGE_SIZE); \ TEXT_HOT \ @@ -589,7 +595,6 @@ defined(CONFIG_AUTOFDO_CLANG) NOINSTR_TEXT \ *(.ref.text) - /* sched.text is aling to function alignment to secure we have same * address even at second ld pass when generating System.map */ #define SCHED_TEXT \ diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo index 6155d6fc4ca7..1caf2457e585 100644 --- a/scripts/Makefile.autofdo +++ b/scripts/Makefile.autofdo @@ -10,6 +10,7 @@ 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 @@ -17,6 +18,7 @@ ifdef CONFIG_LTO_CLANG_THIN 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 From d5dc95836147f2e25b134c0ca3a0bc1a5867ea29 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Sat, 2 Nov 2024 10:51:14 -0700 Subject: [PATCH 41/85] kbuild: Add Propeller configuration for kernel build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the build support for using Clang's Propeller optimizer. Like AutoFDO, Propeller uses hardware sampling to gather information about the frequency of execution of different code paths within a binary. This information is then used to guide the compiler's optimization decisions, resulting in a more efficient binary. The support requires a Clang compiler LLVM 19 or later, and the create_llvm_prof tool (https://github.com/google/autofdo/releases/tag/v0.30.1). This commit is limited to x86 platforms that support PMU features like LBR on Intel machines and AMD Zen3 BRS. Here is an example workflow for building an AutoFDO+Propeller optimized kernel: 1) Build the kernel on the host machine, with AutoFDO and Propeller build config CONFIG_AUTOFDO_CLANG=y CONFIG_PROPELLER_CLANG=y then $ make LLVM=1 CLANG_AUTOFDO_PROFILE=” is the profile collected when doing a non-Propeller AutoFDO build. This step builds a kernel that has the same optimization level as AutoFDO, plus a metadata section that records basic block information. This kernel image runs as fast as an AutoFDO optimized kernel. 2) Install the kernel on test/production machines. 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 \ -o -- For AMD platforms: The supported system are: Zen3 with BRS, or Zen4 with amd_lbr_v2 # To see if Zen3 support LBR: $ cat proc/cpuinfo | grep " brs" # To see if Zen4 support LBR: $ cat proc/cpuinfo | grep amd_lbr_v2 # If the result is yes, then collect the profile using: $ perf record --pfm-events RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a \ -N -b -c -o -- 4) (Optional) Download the raw perf file to the host machine. 5) Generate Propeller profile: $ create_llvm_prof --binary= --profile= \ --format=propeller --propeller_output_module_name \ --out=_cc_profile.txt \ --propeller_symorder=_ld_profile.txt “create_llvm_prof” is the profile conversion tool, and a prebuilt binary for linux can be found on https://github.com/google/autofdo/releases/tag/v0.30.1 (can also build from source). "" can be something like "/home/user/dir/any_string". This command generates a pair of Propeller profiles: "_cc_profile.txt" and "_ld_profile.txt". 6) Rebuild the kernel using the AutoFDO and Propeller profile files. CONFIG_AUTOFDO_CLANG=y CONFIG_PROPELLER_CLANG=y and $ make LLVM=1 CLANG_AUTOFDO_PROFILE= \ CLANG_PROPELLER_PROFILE_PREFIX= Co-developed-by: Han Shen Signed-off-by: Han Shen Signed-off-by: Rong Xu Suggested-by: Sriraman Tallam Suggested-by: Krzysztof Pszeniczny Suggested-by: Nick Desaulniers Suggested-by: Stephane Eranian Tested-by: Yonghong Song Tested-by: Nathan Chancellor Reviewed-by: Kees Cook Signed-off-by: Masahiro Yamada --- Documentation/dev-tools/index.rst | 1 + Documentation/dev-tools/propeller.rst | 162 ++++++++++++++++++++++++++ MAINTAINERS | 7 ++ Makefile | 1 + arch/Kconfig | 19 +++ arch/x86/Kconfig | 1 + arch/x86/kernel/vmlinux.lds.S | 4 + include/asm-generic/vmlinux.lds.h | 6 +- scripts/Makefile.lib | 10 ++ scripts/Makefile.propeller | 28 +++++ tools/objtool/check.c | 1 + 11 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 Documentation/dev-tools/propeller.rst create mode 100644 scripts/Makefile.propeller diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index 6945644f7008..3c0ac08b2709 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -35,6 +35,7 @@ Documentation/dev-tools/testing-overview.rst 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= + +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 -o -- + + - For AMD platforms:: + + $ perf record --pfm-event RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c -o -- + + Note you can repeat the above steps to collect multiple 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= --profile= + --format=propeller --propeller_output_module_name + --out=_cc_profile.txt + --propeller_symorder=_ld_profile.txt + + "" can be something like "/home/user/dir/any_string". + + This command generates a pair of Propeller profiles: + "_cc_profile.txt" and + "_ld_profile.txt". + + If there are more than 1 perf_file collected in the previous step, + you can create a temp list file "" with each line + containing one perf file name and run:: + + $ create_llvm_prof --binary= --profile=@ + --format=propeller --propeller_output_module_name + --out=_cc_profile.txt + --propeller_symorder=_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= CLANG_PROPELLER_PROFILE_PREFIX= diff --git a/MAINTAINERS b/MAINTAINERS index 1eba172ed532..b422561537a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18503,6 +18503,13 @@ S: Maintained F: include/linux/psi* F: kernel/sched/psi.c +PROPELLER BUILD +M: Rong Xu +M: Han Shen +S: Supported +F: Documentation/dev-tools/propeller.rst +F: scripts/Makefile.propeller + PRINTK M: Petr Mladek R: Steven Rostedt diff --git a/Makefile b/Makefile index 1f31c633a41d..8dceb6830486 100644 --- a/Makefile +++ b/Makefile @@ -1024,6 +1024,7 @@ 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)) diff --git a/arch/Kconfig b/arch/Kconfig index 8dca3b5e6ef5..00551f340dbe 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -831,6 +831,25 @@ config AUTOFDO_CLANG 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/x86/Kconfig b/arch/x86/Kconfig index 9dc87661fb37..89b8fc452a7c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -127,6 +127,7 @@ config X86 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 b8c5741d2fb4..cf22081601ed 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -443,6 +443,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/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 8a0bb3946cf0..c995474e4c64 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -95,14 +95,14 @@ * 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, by default, the linker splits text sections and - * regroups functions into subsections. + * 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) || \ -defined(CONFIG_AUTOFDO_CLANG) +defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* #else #define TEXT_MAIN .text diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 2d0942c1a027..e7859ad90224 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -201,6 +201,16 @@ _c_flags += $(if $(patsubst n%,, \ $(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),) diff --git a/scripts/Makefile.propeller b/scripts/Makefile.propeller new file mode 100644 index 000000000000..344190717e47 --- /dev/null +++ b/scripts/Makefile.propeller @@ -0,0 +1,28 @@ +# 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 + CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=labels +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 + KBUILD_LDFLAGS += --lto-basic-block-sections=labels + endif +endif + +export CFLAGS_PROPELLER_CLANG diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 4c5229991e1e..05a0fb4a3d1a 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4558,6 +4558,7 @@ static int validate_ibt(struct objtool_file *file) !strcmp(sec->name, "__mcount_loc") || !strcmp(sec->name, ".kcfi_traps") || !strcmp(sec->name, ".llvm.call-graph-profile") || + !strcmp(sec->name, ".llvm_bb_addr_map") || strstr(sec->name, "__patchable_function_entries")) continue; From d63b852430be7fa2b6d7c550ea67e94b6681d0b5 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Fri, 8 Nov 2024 13:49:53 -0800 Subject: [PATCH 42/85] kbuild: Fix Propeller build option The '-fbasic-block-sections=labels' option has been deprecated in tip of tree clang (20.0.0) [1]. While the option still works, a warning is emitted: clang: warning: argument '-fbasic-block-sections=labels' is deprecated, use '-fbasic-block-address-map' instead [-Wdeprecated] Add a version check to set the proper option. Link: https://github.com/llvm/llvm-project/pull/110039 [1] Signed-off-by: Rong Xu Reported-by: Nathan Chancellor Suggested-by: Nathan Chancellor Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor Signed-off-by: Masahiro Yamada --- scripts/Makefile.propeller | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.propeller b/scripts/Makefile.propeller index 344190717e47..48a660128e25 100644 --- a/scripts/Makefile.propeller +++ b/scripts/Makefile.propeller @@ -5,7 +5,14 @@ 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 - CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=labels + # 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. @@ -21,7 +28,11 @@ ifdef CONFIG_LTO_CLANG_THIN ifdef CLANG_PROPELLER_PROFILE_PREFIX KBUILD_LDFLAGS += --lto-basic-block-sections=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt else - KBUILD_LDFLAGS += --lto-basic-block-sections=labels + 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 From bb43a59944f45e89aa158740b8a16ba8f0b0fa2b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 7 Nov 2024 01:14:40 +0900 Subject: [PATCH 43/85] Rename .data.unlikely to .data..unlikely Commit 7ccaba5314ca ("consolidate WARN_...ONCE() static variables") was intended to collect all .data.unlikely sections into one chunk. However, this has not worked when CONFIG_LD_DEAD_CODE_DATA_ELIMINATION or CONFIG_LTO_CLANG is enabled, because .data.unlikely matches the .data.[0-9a-zA-Z_]* pattern in the DATA_MAIN macro. Commit cb87481ee89d ("kbuild: linker script do not match C names unless LD_DEAD_CODE_DATA_ELIMINATION is configured") was introduced to suppress the issue for the default CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=n case, providing a minimal fix for stable backporting. We were aware this did not address the issue for CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y. The plan was to apply correct fixes and then revert cb87481ee89d. [1] Seven years have passed since then, yet the #ifdef workaround remains in place. Using a ".." separator in the section name fixes the issue for CONFIG_LD_DEAD_CODE_DATA_ELIMINATION and CONFIG_LTO_CLANG. [1]: https://lore.kernel.org/linux-kbuild/CAK7LNASck6BfdLnESxXUeECYL26yUDm0cwRZuM4gmaWUkxjL5g@mail.gmail.com/ Fixes: cb87481ee89d ("kbuild: linker script do not match C names unless LD_DEAD_CODE_DATA_ELIMINATION is configured") Signed-off-by: Masahiro Yamada --- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/rcupdate.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index c995474e4c64..3c9dc1fd094d 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -357,7 +357,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) *(.data..decrypted) \ *(.ref.data) \ *(.data..shared_aligned) /* percpu related */ \ - *(.data.unlikely) \ + *(.data..unlikely) \ __start_once = .; \ *(.data.once) \ __end_once = .; \ 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; \ From dbefa1f31a91670c9e7dac9b559625336206466f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 7 Nov 2024 01:14:41 +0900 Subject: [PATCH 44/85] Rename .data.once to .data..once to fix resetting WARN*_ONCE Commit b1fca27d384e ("kernel debug: support resetting WARN*_ONCE") added support for clearing the state of once warnings. However, it is not functional when CONFIG_LD_DEAD_CODE_DATA_ELIMINATION or CONFIG_LTO_CLANG is enabled, because .data.once matches the .data.[0-9a-zA-Z_]* pattern in the DATA_MAIN macro. Commit cb87481ee89d ("kbuild: linker script do not match C names unless LD_DEAD_CODE_DATA_ELIMINATION is configured") was introduced to suppress the issue for the default CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=n case, providing a minimal fix for stable backporting. We were aware this did not address the issue for CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y. The plan was to apply correct fixes and then revert cb87481ee89d. [1] Seven years have passed since then, yet the #ifdef workaround remains in place. Meanwhile, commit b1fca27d384e introduced the .data.once section, and commit dc5723b02e52 ("kbuild: add support for Clang LTO") extended the #ifdef. Using a ".." separator in the section name fixes the issue for CONFIG_LD_DEAD_CODE_DATA_ELIMINATION and CONFIG_LTO_CLANG. [1]: https://lore.kernel.org/linux-kbuild/CAK7LNASck6BfdLnESxXUeECYL26yUDm0cwRZuM4gmaWUkxjL5g@mail.gmail.com/ Fixes: b1fca27d384e ("kernel debug: support resetting WARN*_ONCE") Fixes: dc5723b02e52 ("kbuild: add support for Clang LTO") Signed-off-by: Masahiro Yamada --- include/asm-generic/vmlinux.lds.h | 2 +- include/linux/mmdebug.h | 6 +++--- include/linux/once.h | 4 ++-- include/linux/once_lite.h | 2 +- include/net/net_debug.h | 2 +- mm/internal.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 3c9dc1fd094d..54504013c749 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -359,7 +359,7 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) *(.data..shared_aligned) /* percpu related */ \ *(.data..unlikely) \ __start_once = .; \ - *(.data.once) \ + *(.data..once) \ __end_once = .; \ STRUCT_ALIGN(); \ *(__tracepoints) \ 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/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/net/net_debug.h b/include/net/net_debug.h index 1e74684cbbdb..4a79204c8d30 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 93083bbeeefa..a23f7b11b760 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -48,7 +48,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)) { \ From bcbbf493f2fa6fa1f0832f6b5b4c80a65de242d6 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Thu, 7 Nov 2024 15:05:08 +0000 Subject: [PATCH 45/85] kbuild: deb-pkg: Don't fail if modules.order is missing Kernels built without CONFIG_MODULES might still want to create -dbg deb packages but install_linux_image_dbg() assumes modules.order always exists. This obviously isn't true if no modules were built, so we should skip reading modules.order in that case. Fixes: 16c36f8864e3 ("kbuild: deb-pkg: use build ID instead of debug link for dbg package") Signed-off-by: Matt Fleming Signed-off-by: Masahiro Yamada --- scripts/package/builddeb | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) 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" + 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 + 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 From 0afd73c5f5c606b0f8f8ff036e4f5d6c4b788d02 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:29 +0900 Subject: [PATCH 46/85] kbuild: replace two $(abs_objtree) with $(CURDIR) in top Makefile Kbuild changes the working directory until it matches $(abs_objtree). When $(need-sub-make) is empty, $(abs_objtree) is the same as $(CURDIR). Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8dceb6830486..891d28e54791 100644 --- a/Makefile +++ b/Makefile @@ -228,12 +228,12 @@ else # need-sub-make # We process the rest of the Makefile if this is the final invocation of make -ifeq ($(abs_srctree),$(abs_objtree)) +ifeq ($(abs_srctree),$(CURDIR)) # building in the source tree srctree := . building_out_of_srctree := else - ifeq ($(abs_srctree)/,$(dir $(abs_objtree))) + ifeq ($(abs_srctree)/,$(dir $(CURDIR))) # building in a subdirectory of the source tree srctree := .. else From 214c0eea43b2ea66bcd6467ea57e47ce8874191b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:30 +0900 Subject: [PATCH 47/85] kbuild: add $(objtree)/ prefix to some in-kernel build artifacts $(objtree) refers to the top of the output directory of kernel builds. This commit adds the explicit $(objtree)/ prefix to build artifacts needed for building external modules. This change has no immediate impact, as the top-level Makefile currently defines: objtree := . This commit prepares for supporting the building of external modules in a different directory. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 10 +++++----- arch/arm/Makefile | 4 ++-- arch/arm64/Makefile | 2 +- arch/powerpc/Makefile | 4 ++-- arch/riscv/Makefile | 2 +- scripts/Kbuild.include | 2 +- scripts/Makefile.build | 4 ++-- scripts/Makefile.modfinal | 14 +++++++------- scripts/Makefile.modinst | 2 +- scripts/Makefile.modpost | 12 ++++++------ scripts/depmod.sh | 4 ++-- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 891d28e54791..9b8f4f4cb01b 100644 --- a/Makefile +++ b/Makefile @@ -354,7 +354,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 @@ -720,7 +720,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),) @@ -783,13 +783,13 @@ else # !may-sync-config # and include/config/auto.conf but do not care if they are up-to-date. # Use auto.conf to show the error message -checked-configs := include/generated/autoconf.h include/generated/rustc_cfg include/config/auto.conf +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 += include/config/auto.conf +PHONY += $(objtree)/include/config/auto.conf -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) 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/powerpc/Makefile b/arch/powerpc/Makefile index bbfe4a1f06ef..321b596d2550 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -402,9 +402,9 @@ prepare: stack_protector_prepare PHONY += stack_protector_prepare stack_protector_prepare: prepare0 ifdef CONFIG_PPC64 - $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' include/generated/asm-offsets.h)) + $(eval KBUILD_CFLAGS += -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-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h)) + $(eval KBUILD_CFLAGS += -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 d469db9f46f4..a08cfeb6cbf9 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -129,7 +129,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/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.build b/scripts/Makefile.build index 8f423a1faf50..dd7a80ebca62 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -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,7 +107,7 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(obj)/%.c FORCE $(call if_changed_dep,cpp_i_c) -genksyms = scripts/genksyms/genksyms \ +genksyms = $(objtree)/scripts/genksyms/genksyms \ $(if $(1), -T $(2)) \ $(if $(KBUILD_PRESERVE), -p) \ -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null) diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 1482884ec3ca..6d8aa3059ee2 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -6,7 +6,7 @@ PHONY := __modfinal __modfinal: -include include/config/auto.conf +include $(objtree)/include/config/auto.conf include $(srctree)/scripts/Kbuild.include # for c_flags @@ -37,15 +37,15 @@ 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,8 +57,8 @@ 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 $(extmod_prefix).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 diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index d97720943189..6fa9af4a25b4 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 := diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 44936ebad161..12e7c15d099c 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) \ @@ -119,11 +119,11 @@ include $(kbuild-file) output-symdump := $(KBUILD_EXTMOD)/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/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 From 5ea172165400e6efaa88989c837d2077c49161d8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:31 +0900 Subject: [PATCH 48/85] kbuild: rename abs_objtree to abs_output 'objtree' refers to the top of the output directory of kernel builds. Rename abs_objtree to a more generic name, to better reflect its use in the context of external module builds. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 9b8f4f4cb01b..deb3f01863f8 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) @@ -185,8 +185,8 @@ ifneq ($(KBUILD_OUTPUT),) # $(realpath ...) gets empty if the path does not exist. Run 'mkdir -p' first. $(shell mkdir -p "$(KBUILD_OUTPUT)") # $(realpath ...) resolves symlinks -abs_objtree := $(realpath $(KBUILD_OUTPUT)) -$(if $(abs_objtree),,$(error failed to create output directory "$(KBUILD_OUTPUT)")) +abs_output := $(realpath $(KBUILD_OUTPUT)) +$(if $(abs_output),,$(error failed to create output directory "$(KBUILD_OUTPUT)")) endif # ifneq ($(KBUILD_OUTPUT),) ifneq ($(words $(subst :, ,$(abs_srctree))), 1) @@ -197,7 +197,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,7 +221,7 @@ $(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 From d17113601909eb43c29cbb3449fd49db427ff6be Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:32 +0900 Subject: [PATCH 49/85] kbuild: use 'output' variable to create the output directory $(KBUILD_OUTPUT) specifies the output directory of kernel builds. Use a more generic name, 'output', to better reflect this code hunk in the context of external module builds. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index deb3f01863f8..cf1d55560ae2 100644 --- a/Makefile +++ b/Makefile @@ -176,18 +176,20 @@ 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),) +output := $(KBUILD_OUTPUT) + +# 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_output := $(realpath $(KBUILD_OUTPUT)) -$(if $(abs_output),,$(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) From 13b25489b6f8bd73ed65f07928f7c27a481f1820 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:33 +0900 Subject: [PATCH 50/85] kbuild: change working directory to external module directory with M= Currently, Kbuild always operates in the output directory of the kernel, even when building external modules. This increases the risk of external module Makefiles attempting to write to the kernel directory. This commit switches the working directory to the external module directory, allowing the removal of the $(KBUILD_EXTMOD)/ prefix from some build artifacts. The command for building external modules maintains backward compatibility, but Makefiles that rely on working in the kernel directory may break. In such cases, $(objtree) and $(srctree) should be used to refer to the output and source directories of the kernel. The appearance of the build log will change as follows: [Before] $ make -C /path/to/my/linux M=/path/to/my/externel/module make: Entering directory '/path/to/my/linux' CC [M] /path/to/my/externel/module/helloworld.o MODPOST /path/to/my/externel/module/Module.symvers CC [M] /path/to/my/externel/module/helloworld.mod.o CC [M] /path/to/my/externel/module/.module-common.o LD [M] /path/to/my/externel/module/helloworld.ko make: Leaving directory '/path/to/my/linux' [After] $ make -C /path/to/my/linux M=/path/to/my/externel/module make: Entering directory '/path/to/my/linux' make[1]: Entering directory '/path/to/my/externel/module' CC [M] helloworld.o MODPOST Module.symvers CC [M] helloworld.mod.o CC [M] .module-common.o LD [M] helloworld.ko make[1]: Leaving directory '/path/to/my/externel/module' make: Leaving directory '/path/to/my/linux' Printing "Entering directory" twice is cumbersome. This will be addressed later. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/dev-tools/coccinelle.rst | 20 ++----- Documentation/kbuild/makefiles.rst | 14 +++++ Makefile | 82 +++++++++++++++----------- rust/Makefile | 4 +- scripts/Makefile.build | 2 +- scripts/Makefile.clean | 2 +- scripts/Makefile.compiler | 2 +- scripts/Makefile.modpost | 6 +- scripts/coccicheck | 6 +- scripts/nsdeps | 8 +-- scripts/package/install-extmod-build | 7 +++ 11 files changed, 86 insertions(+), 67 deletions(-) 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 + OPTIONS="--dir $srcroot $COCCIINCLUDE" -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. +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/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/Makefile b/Makefile index cf1d55560ae2..2718d2037f5e 100644 --- a/Makefile +++ b/Makefile @@ -180,7 +180,24 @@ ifeq ("$(origin O)", "command line") KBUILD_OUTPUT := $(O) endif -output := $(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 := $(CURDIR) + endif + output := $(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),) @@ -230,35 +247,33 @@ else # need-sub-make # We process the rest of the Makefile if this is the final invocation of make -ifeq ($(abs_srctree),$(CURDIR)) - # building in the source tree - srctree := . - building_out_of_srctree := +ifndef KBUILD_EXTMOD +srcroot := $(abs_srctree) +endif + +ifeq ($(srcroot),$(CURDIR)) +building_out_of_srctree := else - ifeq ($(abs_srctree)/,$(dir $(CURDIR))) - # building in a subdirectory of the source tree - srctree := .. - else - srctree := $(abs_srctree) - endif - building_out_of_srctree := 1 +export building_out_of_srctree := 1 endif -ifneq ($(KBUILD_ABS_SRCTREE),) -srctree := $(abs_srctree) +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 -objtree := . +export srctree := $(if $(KBUILD_EXTMOD),$(abs_srctree),$(srcroot)) -VPATH := - -ifeq ($(KBUILD_EXTMOD),) ifdef building_out_of_srctree -VPATH := $(srctree) +export VPATH := $(srcroot) +else +VPATH := endif -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 @@ -540,7 +555,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) @@ -711,7 +726,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 @@ -1107,7 +1122,7 @@ export MODLIB PHONY += prepare0 -export extmod_prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/) +export extmod_prefix = export MODORDER := $(extmod_prefix)modules.order export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps @@ -1799,14 +1814,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 @@ -1948,7 +1959,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' \ @@ -1981,7 +1992,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 # --------------------------------------------------------------------------- diff --git a/rust/Makefile b/rust/Makefile index b5e0a73b78f3..742740816c4b 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -362,8 +362,8 @@ rust-analyzer: $(Q)$(srctree)/scripts/generate_rust_analyzer.py \ --cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-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/Makefile.build b/scripts/Makefile.build index dd7a80ebca62..e5e382a1d64d 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)/: 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.modpost b/scripts/Makefile.modpost index 12e7c15d099c..78d2ca4f25f5 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -111,13 +111,13 @@ 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 $(objtree)/Module.symvers),) missing-input := $(objtree)/Module.symvers 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/nsdeps b/scripts/nsdeps index f1718cc0d700..8ca12e2b5c03 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." 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 From bad6beb2c0bb982b830f592a7b3e3eee76cbb85a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:34 +0900 Subject: [PATCH 51/85] kbuild: remove extmod_prefix, MODORDER, MODULES_NSDEPS variables With the previous changes, $(extmod_prefix), $(MODORDER), and $(MODULES_NSDEPS) are constant. (empty, modules.order, and modules.nsdeps, respectively). Remove these variables and hard-code their values. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 22 +++++++++------------- scripts/Makefile.modfinal | 8 ++++---- scripts/Makefile.modinst | 6 +++--- scripts/Makefile.modpost | 6 +++--- scripts/nsdeps | 2 +- 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 2718d2037f5e..b82c84903c88 100644 --- a/Makefile +++ b/Makefile @@ -1122,10 +1122,6 @@ export MODLIB PHONY += prepare0 -export extmod_prefix = -export MODORDER := $(extmod_prefix)modules.order -export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps - ifeq ($(KBUILD_EXTMOD),) build-dir := . @@ -1876,7 +1872,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. @@ -1887,7 +1883,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 @@ -1928,15 +1924,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)) @@ -2013,12 +2009,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 @@ -2026,7 +2022,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/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 6d8aa3059ee2..bab53884f7e3 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -13,7 +13,7 @@ include $(srctree)/scripts/Kbuild.include 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) @: @@ -30,7 +30,7 @@ quiet_cmd_cc_o_c = CC [M] $@ %.mod.o: %.mod.c FORCE $(call if_changed_dep,cc_o_c) -$(extmod_prefix).module-common.o: $(srctree)/scripts/module-common.c FORCE +.module-common.o: $(srctree)/scripts/module-common.c FORCE $(call if_changed_dep,cc_o_c) quiet_cmd_ld_ko_o = LD [M] $@ @@ -57,13 +57,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 $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE +%.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 6fa9af4a25b4..f97c9926ed31 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -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 78d2ca4f25f5..ab0e94ea6249 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -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),) diff --git a/scripts/nsdeps b/scripts/nsdeps index 8ca12e2b5c03..bab4ec870e50 100644 --- a/scripts/nsdeps +++ b/scripts/nsdeps @@ -51,4 +51,4 @@ generate_deps() { while read line do generate_deps $line -done < $MODULES_NSDEPS +done < modules.nsdeps From 11b3d5175e6bc3779159228e6077be202d2b0069 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:35 +0900 Subject: [PATCH 52/85] kbuild: support building external modules in a separate build directory There has been a long-standing request to support building external modules in a separate build directory. This commit introduces a new environment variable, KBUILD_EXTMOD_OUTPUT, and its shorthand Make variable, MO. A simple usage: $ make -C M= MO= Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/kbuild.rst | 8 +++++++- Documentation/kbuild/modules.rst | 8 +++++++- Makefile | 20 ++++++++++++++++++-- scripts/Makefile.host | 8 +++----- scripts/Makefile.lib | 2 -- 5 files changed, 35 insertions(+), 11 deletions(-) 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/modules.rst b/Documentation/kbuild/modules.rst index cd5a54d91e6d..a01f3754c7fc 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -66,7 +66,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 +83,9 @@ Options directory where the external module (kbuild file) is located. + MO=$BUILD_DIR + Specifies a separate output directory for the external module. + Targets ------- diff --git a/Makefile b/Makefile index b82c84903c88..5aba1ac89375 100644 --- a/Makefile +++ b/Makefile @@ -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)) @@ -187,7 +191,7 @@ ifdef KBUILD_EXTMOD else objtree := $(CURDIR) endif - output := $(KBUILD_EXTMOD) + output := $(or $(KBUILD_EXTMOD_OUTPUT),$(KBUILD_EXTMOD)) # KBUILD_EXTMOD might be a relative path. Remember its absolute path before # Make changes the working directory. srcroot := $(realpath $(KBUILD_EXTMOD)) @@ -645,6 +649,7 @@ quiet_cmd_makefile = GEN Makefile } > Makefile outputmakefile: +ifeq ($(KBUILD_EXTMOD),) @if [ -f $(srctree)/.config -o \ -d $(srctree)/include/config -o \ -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \ @@ -654,7 +659,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 @@ -1940,6 +1954,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. 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 e7859ad90224..5660dfc9ed36 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -213,13 +213,11 @@ 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)) From 1d3730f0012fa04ec392b52cc21f945704ac2e16 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:36 +0900 Subject: [PATCH 53/85] kbuild: support -fmacro-prefix-map for external modules This commit makes -fmacro-prefix-map work for external modules built in a separate output directory. It improves the reproducibility of external modules and provides the benefits described in commit a73619a845d5 ("kbuild: use -fmacro-prefix-map to make __FILE__ a relative path"). When building_out_of_srctree is not defined (e.g., when the kernel or external module is built in the source directory), this option is unnecessary. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5aba1ac89375..a4ac0133f7cd 100644 --- a/Makefile +++ b/Makefile @@ -1041,8 +1041,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 From 822b11a74ba2bc79ddd4165d55e988514c053d71 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:37 +0900 Subject: [PATCH 54/85] kbuild: use absolute path in the generated wrapper Makefile Keep the consistent behavior when this Makefile is invoked from another directory. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a4ac0133f7cd..446acb6ba967 100644 --- a/Makefile +++ b/Makefile @@ -644,8 +644,9 @@ ifdef building_out_of_srctree 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"; \ + echo "export KBUILD_OUTPUT = $(CURDIR)"; \ + echo "include $(abs_srctree)/Makefile"; \ } > Makefile outputmakefile: From a2a45ebee0969b804b1d474a930001a83c954140 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:38 +0900 Subject: [PATCH 55/85] kbuild: make wrapper Makefile more convenient for external modules When Kbuild starts building in a separate output directory, it generates a wrapper Makefile, allowing you to invoke 'make' from the output directory. This commit makes it more convenient, so you can invoke 'make' without M= or MO=. First, you need to build external modules in a separate directory: $ make M=/path/to/module/source/dir MO=/path/to/module/build/dir Once the wrapper Makefile is generated in /path/to/module/build/dir, you can proceed as follows: $ cd /path/to/module/build/dir $ make Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 446acb6ba967..f0bce5081d53 100644 --- a/Makefile +++ b/Makefile @@ -642,10 +642,20 @@ 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 $(abs_srctree)/Makefile: don't edit"; \ - echo "export KBUILD_OUTPUT = $(CURDIR)"; \ + $(print_env_for_makefile); \ echo "include $(abs_srctree)/Makefile"; \ } > Makefile From 8cd07cc6c88cab5cbfe5dd83aacf860a209eb521 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Nov 2024 10:34:39 +0900 Subject: [PATCH 56/85] kbuild: allow to start building external modules in any directory Unless an explicit O= option is provided, external module builds must start from the kernel directory. This can be achieved by using the -C option: $ make -C /path/to/kernel M=/path/to/external/module This commit allows starting external module builds from any directory, so you can also do the following: $ make -f /path/to/kernel/Makefile M=/path/to/external/module The key difference is that the -C option changes the working directory and parses the Makefile located there, while the -f option only specifies the Makefile to use. As shown in the examples in Documentation/kbuild/modules.rst, external modules usually have a wrapper Makefile that allows you to build them without specifying any make arguments. The Makefile typically contains a rule as follows: KDIR ?= /path/to/kernel default: $(MAKE) -C $(KDIR) M=$(CURDIR) $(MAKECMDGOALS) The log will appear as follows: $ make make -C /path/to/kernel M=/path/to/external/module make[1]: Entering directory '/path/to/kernel' make[2]: Entering directory '/path/to/external/module' CC [M] helloworld.o MODPOST Module.symvers CC [M] helloworld.mod.o CC [M] .module-common.o LD [M] helloworld.ko make[2]: Leaving directory '/path/to/external/module' make[1]: Leaving directory '/path/to/kernel' This changes the working directory twice because the -C option first switches to the kernel directory, and then Kbuild internally recurses back to the external module directory. With this commit, the wrapper Makefile can directly include the kernel Makefile: KDIR ?= /path/to/kernel export KBUILD_EXTMOD := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) include $(KDIR)/Makefile This avoids unnecessary sub-make invocations: $ make CC [M] helloworld.o MODPOST Module.symvers CC [M] helloworld.mod.o CC [M] .module-common.o LD [M] helloworld.ko Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/modules.rst | 21 +++++++++++++++++++++ Makefile | 8 ++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index a01f3754c7fc..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 ------- @@ -221,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/Makefile b/Makefile index f0bce5081d53..b77dae5aa03c 100644 --- a/Makefile +++ b/Makefile @@ -189,9 +189,13 @@ ifdef KBUILD_EXTMOD objtree := $(realpath $(KBUILD_OUTPUT)) $(if $(objtree),,$(error specified kernel directory "$(KBUILD_OUTPUT)" does not exist)) else - objtree := $(CURDIR) + objtree := $(abs_srctree) endif - output := $(or $(KBUILD_EXTMOD_OUTPUT),$(KBUILD_EXTMOD)) + # 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)) From c2386abf55616b979b07a63b4eb2a14eedb4c9e5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 12 Nov 2024 02:17:40 +0900 Subject: [PATCH 57/85] kbuild: do not pass -r to genksyms when *.symref does not exist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to pass '-r /dev/null', which is no-op. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/Makefile.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index e5e382a1d64d..628e0ce28dc8 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -110,7 +110,7 @@ $(obj)/%.i: $(obj)/%.c FORCE genksyms = $(objtree)/scripts/genksyms/genksyms \ $(if $(1), -T $(2)) \ $(if $(KBUILD_PRESERVE), -p) \ - -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null) + $(addprefix -r , $(wildcard $(2:.symtypes=.symref))) # These mirror gensymtypes_S and co below, keep them in synch. cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms) From 91ca8be3c402c566de75685ce99c714b0e8638bf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 12 Nov 2024 02:17:41 +0900 Subject: [PATCH 58/85] kbuild: remove support for single %.symtypes build rule This rule is unnecessary because you can generate foo/bar.symtypes as a side effect using: $ make KBUILD_SYMTYPES=1 foo/bar.o While compiling *.o is slower than preprocessing, the impact is negligible. I prioritize keeping the code simpler. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 2 +- scripts/Makefile.build | 22 ++++------------------ 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index b77dae5aa03c..215d5fd95a28 100644 --- a/Makefile +++ b/Makefile @@ -301,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 := diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 628e0ce28dc8..15a88f4d6ef6 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -108,19 +108,13 @@ $(obj)/%.i: $(obj)/%.c FORCE $(call if_changed_dep,cpp_i_c) genksyms = $(objtree)/scripts/genksyms/genksyms \ - $(if $(1), -T $(2)) \ - $(if $(KBUILD_PRESERVE), -p) \ - $(addprefix -r , $(wildcard $(2:.symtypes=.symref))) + $(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) $@ @@ -158,8 +152,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) @@ -323,13 +316,6 @@ 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 $@ $< From 000e22a80de0727839bb753159ac05c8ba20c3e3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 14 Nov 2024 08:45:21 +0900 Subject: [PATCH 59/85] kbuild: move cmd_cc_o_c and cmd_as_o_S to scripts/Malefile.lib The cmd_cc_o_c and cmd_as_o_S macros are duplicated in scripts/Makefile.{build,modfinal,vmlinux}. This commit factors them out to scripts/Makefile.lib. No functional changes are intended. Signed-off-by: Masahiro Yamada --- scripts/Makefile.build | 8 -------- scripts/Makefile.lib | 12 ++++++++++++ scripts/Makefile.modfinal | 6 +----- scripts/Makefile.vmlinux | 8 -------- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 15a88f4d6ef6..c0b61ae71e3e 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -135,11 +135,6 @@ 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 .o from .c @@ -322,9 +317,6 @@ 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.lib b/scripts/Makefile.lib index 5660dfc9ed36..c0b485ab029a 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -298,6 +298,18 @@ $(foreach m, $1, \ $(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3)))) endef +# Build commands +# =========================================================================== +# These are shared by some Makefile.* files. + +quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \ + $(cmd_ld_single_m) \ + $(cmd_objtool) + +quiet_cmd_as_o_S = AS $(quiet_modtag) $@ + cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool) + # Copy a file # =========================================================================== # 'cp' preserves permissions. If you use it to copy a file in read-only srctree, diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index bab53884f7e3..f63410ba5c2c 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -8,8 +8,6 @@ __modfinal: 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 @@ -23,9 +21,7 @@ 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) diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index 9ef0480ed755..2ce61f6c79c6 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -5,21 +5,13 @@ __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) -quiet_cmd_as_o_S = AS $@ - cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< - %.o: %.S FORCE $(call if_changed_dep,as_o_S) From bede169618c68379e1be7ace14e8ac85b964a9ec Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 14 Nov 2024 08:45:22 +0900 Subject: [PATCH 60/85] kbuild: enable objtool for *.mod.o and additional kernel objects Currently, objtool is disabled in scripts/Makefile.{modfinal,vmlinux}. This commit moves rule_cc_o_c and rule_as_o_S to scripts/Makefile.lib and set objtool-enabled to y there. With this change, *.mod.o, .module-common.o, builtin-dtb.o, and vmlinux.export.o will now be covered by objtool. Signed-off-by: Masahiro Yamada --- scripts/Makefile.build | 23 ----------------------- scripts/Makefile.lib | 26 +++++++++++++++++++++++++- scripts/Makefile.modfinal | 4 ++-- scripts/Makefile.vmlinux | 4 ++-- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index c0b61ae71e3e..f41ce2131979 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -129,12 +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 - ifdef CONFIG_MODVERSIONS # When module versioning is enabled the following steps are executed: # o compile a .o from .c @@ -195,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) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index c0b485ab029a..01040a767c1d 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -302,14 +302,38 @@ endef # =========================================================================== # 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_m) \ + $(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, diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index f63410ba5c2c..85d5fadbcc93 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -24,10 +24,10 @@ KCSAN_SANITIZE := n 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) .module-common.o: $(srctree)/scripts/module-common.c FORCE - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index 2ce61f6c79c6..997be5dc7bf5 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -10,10 +10,10 @@ include $(srctree)/scripts/Makefile.lib targets := %.o: %.c FORCE - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) %.o: %.S FORCE - $(call if_changed_dep,as_o_S) + $(call if_changed_rule,as_o_S) # Built-in dtb # --------------------------------------------------------------------------- From 1b466b29a3bf02ed95f28682a975f41ae47bce7d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 14 Nov 2024 08:45:23 +0900 Subject: [PATCH 61/85] kbuild: re-enable KCSAN for autogenerated *.mod.c intermediaries This reverts commit 54babdc0343f ("kbuild: Disable KCSAN for autogenerated *.mod.c intermediaries"). Now that objtool is enabled for *.mod.c, there is no need to filter out CFLAGS_KCSAN. I no longer see "Unpatched return thunk in use. This should not happen!" error with KCSAN when loading a module. Signed-off-by: Masahiro Yamada --- scripts/Makefile.modfinal | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 85d5fadbcc93..542ba462ed3e 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -20,7 +20,6 @@ __modfinal: $(modules:%.o=%.ko) modname = $(notdir $(@:.mod.o=)) part-of-module = y GCOV_PROFILE := n -KCSAN_SANITIZE := n ccflags-remove-y := $(CC_FLAGS_CFI) %.mod.o: %.mod.c FORCE From e397a603e49cc7c7c113fad9f55a09637f290c34 Mon Sep 17 00:00:00 2001 From: Parth Pancholi Date: Thu, 14 Nov 2024 15:56:44 +0100 Subject: [PATCH 62/85] kbuild: switch from lz4c to lz4 for compression Replace lz4c with lz4 for kernel image compression. Although lz4 and lz4c are functionally similar, lz4c has been deprecated upstream since 2018. Since as early as Ubuntu 16.04 and Fedora 25, lz4 and lz4c have been packaged together, making it safe to update the requirement from lz4c to lz4. Consequently, some distributions and build systems, such as OpenEmbedded, have fully transitioned to using lz4. OpenEmbedded core adopted this change in commit fe167e082cbd ("bitbake.conf: require lz4 instead of lz4c"), causing compatibility issues when building the mainline kernel in the latest OpenEmbedded environment, as seen in the errors below. This change also updates the LZ4 compression commands to make it backward compatible by replacing stdin and stdout with the '-' option, due to some unclear reason, the stdout keyword does not work for lz4 and '-' works for both. In addition, this modifies the legacy '-c1' with '-9' which is also compatible with both. This fixes the mainline kernel build failures with the latest master OpenEmbedded builds associated with the mentioned compatibility issues. LZ4 arch/arm/boot/compressed/piggy_data /bin/sh: 1: lz4c: not found ... ... ERROR: oe_runmake failed Link: https://github.com/lz4/lz4/pull/553 Suggested-by: Francesco Dolcini Signed-off-by: Parth Pancholi Signed-off-by: Masahiro Yamada --- Makefile | 2 +- scripts/Makefile.lib | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 215d5fd95a28..f7f43c8997ae 100644 --- a/Makefile +++ b/Makefile @@ -533,7 +533,7 @@ KGZIP = gzip KBZIP2 = bzip2 KLZOP = lzop LZMA = lzma -LZ4 = lz4c +LZ4 = lz4 XZ = xz ZSTD = zstd diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 01040a767c1d..7395200538da 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -425,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 From 523f3dbc187a9618d4fd80c2b438e4d490705dcd Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 18 Nov 2024 12:01:54 +0100 Subject: [PATCH 63/85] setlocalversion: work around "git describe" performance Contrary to expectations, passing a single candidate tag to "git describe" is slower than not passing any --match options. $ time git describe --debug ... traversed 10619 commits ... v6.12-rc5-63-g0fc810ae3ae1 real 0m0.169s $ time git describe --match=v6.12-rc5 --debug ... traversed 1310024 commits v6.12-rc5-63-g0fc810ae3ae1 real 0m1.281s In fact, the --debug output shows that git traverses all or most of history. For some repositories and/or git versions, those 1.3s are actually 10-15 seconds. This has been acknowledged as a performance bug in git [1], and a fix is on its way [2]. However, no solution is yet in git.git, and even when one lands, it will take quite a while before it finds its way to a release and for $random_kernel_developer to pick that up. So rewrite the logic to use plumbing commands. For each of the candidate values of $tag, we ask: (1) is $tag even an annotated tag? (2) Is it eligible to describe HEAD, i.e. an ancestor of HEAD? (3) If so, how many commits are in $tag..HEAD? I have tested that this produces the same output as the current script for ~700 random commits between v6.9..v6.10. For those 700 commits, and in my git repo, the 'make -s kernelrelease' command is on average ~4 times faster with this patch applied (geometric mean of ratios). For the commit mentioned in Josh's original report [3], the time-consuming part of setlocalversion goes from $ time git describe --match=v6.12-rc5 c1e939a21eb1 v6.12-rc5-44-gc1e939a21eb1 real 0m1.210s to $ time git rev-list --count --left-right v6.12-rc5..c1e939a21eb1 0 44 real 0m0.037s [1] https://lore.kernel.org/git/20241101113910.GA2301440@coredump.intra.peff.net/ [2] https://lore.kernel.org/git/20241106192236.GC880133@coredump.intra.peff.net/ [3] https://lore.kernel.org/lkml/309549cafdcfe50c4fceac3263220cc3d8b109b2.1730337435.git.jpoimboe@kernel.org/ Reported-by: Sean Christopherson Closes: https://lore.kernel.org/lkml/ZPtlxmdIJXOe0sEy@google.com/ Reported-by: Josh Poimboeuf Closes: https://lore.kernel.org/lkml/309549cafdcfe50c4fceac3263220cc3d8b109b2.1730337435.git.jpoimboe@kernel.org/ Tested-by: Josh Poimboeuf Signed-off-by: Rasmus Villemoes Signed-off-by: Masahiro Yamada --- scripts/setlocalversion | 54 +++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 38b96c6797f4..5818465abba9 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -30,6 +30,27 @@ if test $# -gt 0 -o ! -d "$srctree"; then usage fi +try_tag() { + tag="$1" + + # Is $tag an annotated tag? + [ "$(git cat-file -t "$tag" 2> /dev/null)" = tag ] || return 1 + + # 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. + [ "$1" = 0 ] || return 1 + + # $2 is the number of commits in the range $tag..HEAD, possibly 0. + count="$2" + + return 0 +} + scm_version() { local short=false @@ -61,33 +82,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 +116,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 From e2ff1219a5541a22921016219c4d86a6d0190d15 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 19 Nov 2024 08:09:06 +0900 Subject: [PATCH 64/85] setlocalversion: add -e option Set the -e option to ensure this script fails on any unexpected errors. Without this change, the kernel build may continue running with an incorrect string in include/config/kernel.release. Currently, try_tag() returns 1 when the expected tag is not found as an ancestor, but this is a case where the script should continue. Signed-off-by: Masahiro Yamada --- scripts/setlocalversion | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 5818465abba9..28169d7e143b 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -10,6 +10,8 @@ # # +set -e + usage() { echo "Usage: $0 [--no-local] [srctree]" >&2 exit 1 @@ -34,7 +36,9 @@ try_tag() { tag="$1" # Is $tag an annotated tag? - [ "$(git cat-file -t "$tag" 2> /dev/null)" = tag ] || return 1 + 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 @@ -43,12 +47,12 @@ try_tag() { # $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. - [ "$1" = 0 ] || return 1 + if [ "$1" != 0 ]; then + return + fi # $2 is the number of commits in the range $tag..HEAD, possibly 0. count="$2" - - return 0 } scm_version() From 0c3e091319e4748cb36ac9a50848903dc6f54054 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:39 +0900 Subject: [PATCH 65/85] modpost: remove incorrect code in do_eisa_entry() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function contains multiple bugs after the following commits:  - ac551828993e ("modpost: i2c aliases need no trailing wildcard")  - 6543becf26ff ("mod/file2alias: make modalias generation safe for cross compiling") Commit ac551828993e inserted the following code to do_eisa_entry():     else             strcat(alias, "*"); This is incorrect because 'alias' is uninitialized. If it is not NULL-terminated, strcat() could cause a buffer overrun. Even if 'alias' happens to be zero-filled, it would output: MODULE_ALIAS("*"); This would match anything. As a result, the module could be loaded by any unrelated uevent from an unrelated subsystem. Commit ac551828993e introduced another bug.             Prior to that commit, the conditional check was:     if (eisa->sig[0]) This checked if the first character of eisa_device_id::sig was not '\0'. However, commit ac551828993e changed it as follows:     if (sig[0]) sig[0] is NOT the first character of the eisa_device_id::sig. The type of 'sig' is 'char (*)[8]', meaning that the type of 'sig[0]' is 'char [8]' instead of 'char'. 'sig[0]' and 'symval' refer to the same address, which never becomes NULL. The correct conversion would have been:     if ((*sig)[0]) However, this if-conditional was meaningless because the earlier change in commit ac551828993e was incorrect. This commit removes the entire incorrect code, which should never have been executed. Fixes: ac551828993e ("modpost: i2c aliases need no trailing wildcard") Fixes: 6543becf26ff ("mod/file2alias: make modalias generation safe for cross compiling") Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index c4cc11aa558f..634e40748287 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -809,10 +809,7 @@ static int do_eisa_entry(const char *filename, void *symval, char *alias) { DEF_FIELD_ADDR(symval, eisa_device_id, sig); - if (sig[0]) - sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); - else - strcat(alias, "*"); + sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); return 1; } From b7bca42d101d8d9678068cde645bd6d0afa8a20f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:40 +0900 Subject: [PATCH 66/85] modpost: remove unnecessary check in do_acpi_entry() The 'id' pointer is never NULL since it has the same address as 'symval'. Also, checking (*id)[0] is simpler than calling strlen(). Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 634e40748287..34678ed40fdb 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -570,7 +570,7 @@ static int do_acpi_entry(const char *filename, DEF_FIELD(symval, acpi_device_id, cls); DEF_FIELD(symval, acpi_device_id, cls_msk); - if (id && strlen((const char *)*id)) + if ((*id)[0]) sprintf(alias, "acpi*:%s:*", *id); else { int i, byte_shift, cnt = 0; From f4fdb17ca5a5285d4a0ed81b25d5a3d7b9b3ebf3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:41 +0900 Subject: [PATCH 67/85] modpost: introduce module_alias_printf() helper The generic ->do_entry() handler is currently limited to returning a single alias string. However, this is not flexible enough for several subsystems, which currently require their own implementations: - do_usb_table() - do_of_table() - do_pnp_device_entry() - do_pnp_card_entries() This commit introduces a helper function so that these special cases can add multiple MODULE_ALIAS() and then migrate to the generic framework. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 91 +++++++++++++++++++++++++++++----------- scripts/mod/modpost.c | 11 ++++- scripts/mod/modpost.h | 19 ++++++++- 3 files changed, 93 insertions(+), 28 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 34678ed40fdb..d6c8d5e08821 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 +#include + +#include "list.h" +#include "xalloc.h" + #include "modpost.h" #include "devicetable-offsets.h" @@ -31,6 +37,58 @@ typedef Elf64_Addr kernel_ulong_t; #include #include +/** + * 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; + 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'; + } + + list_add_tail(&new->node, &mod->aliases); +} + typedef uint32_t __u32; typedef uint16_t __u16; typedef unsigned char __u8; @@ -229,9 +287,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 */ @@ -375,10 +431,8 @@ 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); + module_alias_printf(mod, false, "%s", alias); + module_alias_printf(mod, false, "%sC*", alias); } static void do_of_table(void *symval, unsigned long size, @@ -608,14 +662,12 @@ static void do_pnp_device_entry(void *symval, unsigned long size, char acpi_id[sizeof(*id)]; int j; - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); + module_alias_printf(mod, false, "pnp:d%s*", *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); + module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); } } @@ -666,14 +718,12 @@ static void do_pnp_card_entries(void *symval, unsigned long size, char acpi_id[PNP_ID_LEN]; int k; - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", id); + module_alias_printf(mod, false, "pnp:d%s*", id); /* 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); + module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); } } } @@ -1534,8 +1584,7 @@ static void do_table(void *symval, unsigned long size, 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); + module_alias_printf(mod, false, "%s", alias); } } } @@ -1660,11 +1709,3 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, } 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); -} diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 107393a8c48a..1948d69ce2b9 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -176,6 +176,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'; @@ -1966,6 +1967,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 +1975,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..52efe0026b34 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -79,6 +79,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 +105,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 +186,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); From d92b7a3b528bb4b69fa8b6f99c63fe8ad7927cec Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:42 +0900 Subject: [PATCH 68/85] modpost: deduplicate MODULE_ALIAS() for all drivers MODULE_DEVICE_TABLE(pnp_card, ...) may have duplicated IDs. For instance, snd_ad1816a_pnpids[] in sound/isa/ad1816a/ad1816a.c includes multiple occurrences of the "ADS7180" string within its .devs fields. Currently, do_pnp_card_entries() handles deduplication on its own, but this logic should be moved to a common helper function, as drivers in other subsystems might also have similar duplication issues. For example, drivers/media/i2c/s5c73m3/s5c73m3.mod.c contains duplicated MODULE_ALIAS() entries because both s5c73m3-core.c and s5c73m3-spi.c define the same compatible string. This commit eliminates redundant MODULE_ALIAS() entries across all drivers. [Before] $ grep MODULE_ALIAS drivers/media/i2c/s5c73m3/s5c73m3.mod.c MODULE_ALIAS("i2c:S5C73M3"); MODULE_ALIAS("of:N*T*Csamsung,s5c73m3"); MODULE_ALIAS("of:N*T*Csamsung,s5c73m3C*"); MODULE_ALIAS("of:N*T*Csamsung,s5c73m3"); MODULE_ALIAS("of:N*T*Csamsung,s5c73m3C*"); [After] $ grep MODULE_ALIAS drivers/media/i2c/s5c73m3/s5c73m3.mod.c MODULE_ALIAS("i2c:S5C73M3"); MODULE_ALIAS("of:N*T*Csamsung,s5c73m3"); MODULE_ALIAS("of:N*T*Csamsung,s5c73m3C*"); Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 48 +++++++++++++--------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index d6c8d5e08821..71dd5272013b 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -48,7 +48,7 @@ static void __attribute__((format (printf, 3, 4))) module_alias_printf(struct module *mod, bool append_wildcard, const char *fmt, ...) { - struct module_alias *new; + struct module_alias *new, *als; size_t len; int n; va_list ap; @@ -86,6 +86,14 @@ module_alias_printf(struct module *mod, bool append_wildcard, 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); } @@ -687,44 +695,18 @@ static void do_pnp_card_entries(void *symval, unsigned long size, for (j = 0; j < PNP_MAX_DEVICES; j++) { const char *id = (char *)(*devs)[j].id; - int i2, j2; - int dup = 0; + char acpi_id[PNP_ID_LEN]; if (!id[0]) break; - /* 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 (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; + module_alias_printf(mod, false, "pnp:d%s*", id); - module_alias_printf(mod, false, "pnp:d%s*", id); - - /* fix broken pnp bus lowercasing */ - for (k = 0; k < sizeof(acpi_id); k++) - acpi_id[k] = toupper(id[k]); - module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); - } + /* fix broken pnp bus lowercasing */ + for (int k = 0; k < sizeof(acpi_id); k++) + acpi_id[k] = toupper(id[k]); + module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); } } } From c4d1a9f9d11b5d7c5cf4fab33f86f7d7a978801e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:43 +0900 Subject: [PATCH 69/85] modpost: remove DEF_FIELD_ADDR_VAR() macro With the former cleanups in do_pnp_card_entries(), this macro is no longer used by anyone. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 71dd5272013b..cd8be749260c 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -138,19 +138,12 @@ struct devtable { #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 { \ From c7c24d60151c022bd8e357f5395a327d354a676a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:44 +0900 Subject: [PATCH 70/85] modpost: pass (struct module *) to do_*_entry() functions Replace the first argument with a pointer to struct module. 'filename' can be replaced with mod->name. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 118 +++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index cd8be749260c..b23ef324b155 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -126,7 +126,7 @@ typedef struct { struct devtable { const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; - int (*do_entry)(const char *filename, void *symval, char *alias); + int (*do_entry)(struct module *mod, void *symval, char *alias); }; /* Size of alias provided to do_entry functions */ @@ -452,7 +452,7 @@ static void do_of_table(void *symval, unsigned long size, } /* Looks like: hid:bNvNpN */ -static int do_hid_entry(const char *filename, +static int do_hid_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, hid_device_id, bus); @@ -470,7 +470,7 @@ static int do_hid_entry(const char *filename, } /* Looks like: ieee1394:venNmoNspNverN */ -static int do_ieee1394_entry(const char *filename, +static int do_ieee1394_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ieee1394_device_id, match_flags); @@ -494,7 +494,7 @@ static int do_ieee1394_entry(const char *filename, } /* Looks like: pci:vNdNsvNsdNbcNscNiN or _pci:vNdNsvNsdNbcNscNiN. */ -static int do_pci_entry(const char *filename, +static int do_pci_entry(struct module *mod, void *symval, char *alias) { /* Class field can be divided into these three. */ @@ -538,7 +538,7 @@ 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); + mod->name, class_mask); return 0; } @@ -550,7 +550,7 @@ static int do_pci_entry(const char *filename, } /* looks like: "ccw:tNmNdtNdmN" */ -static int do_ccw_entry(const char *filename, +static int do_ccw_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ccw_device_id, match_flags); @@ -573,7 +573,7 @@ static int do_ccw_entry(const char *filename, } /* looks like: "ap:tN" */ -static int do_ap_entry(const char *filename, +static int do_ap_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ap_device_id, dev_type); @@ -583,7 +583,7 @@ static int do_ap_entry(const char *filename, } /* looks like: "css:tN" */ -static int do_css_entry(const char *filename, +static int do_css_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, css_device_id, type); @@ -593,7 +593,7 @@ static int do_css_entry(const char *filename, } /* Looks like: "serio:tyNprNidNexN" */ -static int do_serio_entry(const char *filename, +static int do_serio_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, serio_device_id, type); @@ -618,7 +618,7 @@ 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, +static int do_acpi_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, acpi_device_id, id); @@ -705,7 +705,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size, } /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ -static int do_pcmcia_entry(const char *filename, +static int do_pcmcia_entry(struct module *mod, void *symval, char *alias) { unsigned int i; @@ -741,7 +741,7 @@ static int do_pcmcia_entry(const char *filename, return 1; } -static int do_vio_entry(const char *filename, void *symval, +static int do_vio_entry(struct module *mod, void *symval, char *alias) { char *tmp; @@ -773,7 +773,7 @@ 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, +static int do_input_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, input_device_id, flags); @@ -830,7 +830,7 @@ static int do_input_entry(const char *filename, void *symval, return 1; } -static int do_eisa_entry(const char *filename, void *symval, +static int do_eisa_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, eisa_device_id, sig); @@ -839,7 +839,7 @@ static int do_eisa_entry(const char *filename, void *symval, } /* Looks like: parisc:tNhvNrevNsvN */ -static int do_parisc_entry(const char *filename, void *symval, +static int do_parisc_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, parisc_device_id, hw_type); @@ -858,7 +858,7 @@ static int do_parisc_entry(const char *filename, void *symval, } /* Looks like: sdio:cNvNdN. */ -static int do_sdio_entry(const char *filename, +static int do_sdio_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, sdio_device_id, class); @@ -874,7 +874,7 @@ static int do_sdio_entry(const char *filename, } /* Looks like: ssb:vNidNrevN. */ -static int do_ssb_entry(const char *filename, +static int do_ssb_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ssb_device_id, vendor); @@ -890,7 +890,7 @@ static int do_ssb_entry(const char *filename, } /* Looks like: bcma:mNidNrevNclN. */ -static int do_bcma_entry(const char *filename, +static int do_bcma_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, bcma_device_id, manuf); @@ -908,7 +908,7 @@ static int do_bcma_entry(const char *filename, } /* Looks like: virtio:dNvN */ -static int do_virtio_entry(const char *filename, void *symval, +static int do_virtio_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, virtio_device_id, device); @@ -928,7 +928,7 @@ static int do_virtio_entry(const char *filename, void *symval, * in the name. */ -static int do_vmbus_entry(const char *filename, void *symval, +static int do_vmbus_entry(struct module *mod, void *symval, char *alias) { int i; @@ -945,7 +945,7 @@ static int do_vmbus_entry(const char *filename, void *symval, } /* Looks like: rpmsg:S */ -static int do_rpmsg_entry(const char *filename, void *symval, +static int do_rpmsg_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, rpmsg_device_id, name); @@ -955,7 +955,7 @@ static int do_rpmsg_entry(const char *filename, void *symval, } /* Looks like: i2c:S */ -static int do_i2c_entry(const char *filename, void *symval, +static int do_i2c_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, i2c_device_id, name); @@ -964,7 +964,7 @@ static int do_i2c_entry(const char *filename, void *symval, return 1; } -static int do_i3c_entry(const char *filename, void *symval, +static int do_i3c_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, i3c_device_id, match_flags); @@ -982,7 +982,7 @@ static int do_i3c_entry(const char *filename, void *symval, return 1; } -static int do_slim_entry(const char *filename, void *symval, char *alias) +static int do_slim_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, slim_device_id, manf_id); DEF_FIELD(symval, slim_device_id, prod_code); @@ -993,7 +993,7 @@ static int do_slim_entry(const char *filename, void *symval, char *alias) } /* Looks like: spi:S */ -static int do_spi_entry(const char *filename, void *symval, +static int do_spi_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, spi_device_id, name); @@ -1034,7 +1034,7 @@ static void dmi_ascii_filter(char *d, const char *s) } -static int do_dmi_entry(const char *filename, void *symval, +static int do_dmi_entry(struct module *mod, void *symval, char *alias) { int i, j; @@ -1058,7 +1058,7 @@ static int do_dmi_entry(const char *filename, void *symval, return 1; } -static int do_platform_entry(const char *filename, +static int do_platform_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, platform_device_id, name); @@ -1066,7 +1066,7 @@ static int do_platform_entry(const char *filename, return 1; } -static int do_mdio_entry(const char *filename, +static int do_mdio_entry(struct module *mod, void *symval, char *alias) { int i; @@ -1091,7 +1091,7 @@ static int do_mdio_entry(const char *filename, } /* Looks like: zorro:iN. */ -static int do_zorro_entry(const char *filename, void *symval, +static int do_zorro_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, zorro_device_id, id); @@ -1101,7 +1101,7 @@ static int do_zorro_entry(const char *filename, void *symval, } /* looks like: "pnp:dD" */ -static int do_isapnp_entry(const char *filename, +static int do_isapnp_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, isapnp_device_id, vendor); @@ -1116,7 +1116,7 @@ static int do_isapnp_entry(const char *filename, } /* Looks like: "ipack:fNvNdN". */ -static int do_ipack_entry(const char *filename, +static int do_ipack_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ipack_device_id, format); @@ -1178,7 +1178,7 @@ 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, +static int do_amba_entry(struct module *mod, void *symval, char *alias) { unsigned int digit; @@ -1188,7 +1188,7 @@ 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++) @@ -1205,7 +1205,7 @@ 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, +static int do_mips_cdmm_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, mips_cdmm_device_id, type); @@ -1220,7 +1220,7 @@ static int do_mips_cdmm_entry(const char *filename, * complicated. */ -static int do_x86cpu_entry(const char *filename, void *symval, +static int do_x86cpu_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, x86_cpu_id, feature); @@ -1239,7 +1239,7 @@ static int do_x86cpu_entry(const char *filename, void *symval, } /* LOOKS like cpu:type:*:feature:*FEAT* */ -static int do_cpu_entry(const char *filename, void *symval, char *alias) +static int do_cpu_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, cpu_feature, feature); @@ -1248,7 +1248,7 @@ static int do_cpu_entry(const char *filename, void *symval, char *alias) } /* Looks like: mei:S:uuid:N:* */ -static int do_mei_entry(const char *filename, void *symval, +static int do_mei_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, mei_cl_device_id, name); @@ -1266,7 +1266,7 @@ static int do_mei_entry(const char *filename, void *symval, } /* Looks like: rapidio:vNdNavNadN */ -static int do_rio_entry(const char *filename, +static int do_rio_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, rio_device_id, did); @@ -1285,7 +1285,7 @@ static int do_rio_entry(const char *filename, } /* Looks like: ulpi:vNpN */ -static int do_ulpi_entry(const char *filename, void *symval, +static int do_ulpi_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ulpi_device_id, vendor); @@ -1297,7 +1297,7 @@ static int do_ulpi_entry(const char *filename, void *symval, } /* Looks like: hdaudio:vNrNaN */ -static int do_hda_entry(const char *filename, void *symval, char *alias) +static int do_hda_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, hda_device_id, vendor_id); DEF_FIELD(symval, hda_device_id, rev_id); @@ -1313,7 +1313,7 @@ static int do_hda_entry(const char *filename, void *symval, char *alias) } /* Looks like: sdw:mNpNvNcN */ -static int do_sdw_entry(const char *filename, void *symval, char *alias) +static int do_sdw_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, sdw_device_id, mfg_id); DEF_FIELD(symval, sdw_device_id, part_id); @@ -1331,7 +1331,7 @@ static int do_sdw_entry(const char *filename, void *symval, char *alias) } /* Looks like: fsl-mc:vNdN */ -static int do_fsl_mc_entry(const char *filename, void *symval, +static int do_fsl_mc_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, fsl_mc_device_id, vendor); @@ -1342,7 +1342,7 @@ static int do_fsl_mc_entry(const char *filename, void *symval, } /* Looks like: tbsvc:kSpNvNrN */ -static int do_tbsvc_entry(const char *filename, void *symval, char *alias) +static int do_tbsvc_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, tb_service_id, match_flags); DEF_FIELD_ADDR(symval, tb_service_id, protocol_key); @@ -1366,7 +1366,7 @@ static int do_tbsvc_entry(const char *filename, void *symval, char *alias) } /* Looks like: typec:idNmN */ -static int do_typec_entry(const char *filename, void *symval, char *alias) +static int do_typec_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, typec_device_id, svid); DEF_FIELD(symval, typec_device_id, mode); @@ -1378,7 +1378,7 @@ static int do_typec_entry(const char *filename, void *symval, char *alias) } /* Looks like: tee:uuid */ -static int do_tee_entry(const char *filename, void *symval, char *alias) +static int do_tee_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, tee_client_device_id, uuid); @@ -1393,28 +1393,28 @@ static int do_tee_entry(const char *filename, void *symval, char *alias) } /* Looks like: wmi:guid */ -static int do_wmi_entry(const char *filename, void *symval, char *alias) +static int do_wmi_entry(struct module *mod, void *symval, char *alias) { 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); + *guid_string, mod->name); return 0; } 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); + mod->name); return 0; } return 1; } /* Looks like: mhi:S */ -static int do_mhi_entry(const char *filename, void *symval, char *alias) +static int do_mhi_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, mhi_device_id, chan); sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan); @@ -1422,7 +1422,7 @@ static int do_mhi_entry(const char *filename, void *symval, char *alias) } /* Looks like: mhi_ep:S */ -static int do_mhi_ep_entry(const char *filename, void *symval, char *alias) +static int do_mhi_ep_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, mhi_device_id, chan); sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan); @@ -1431,7 +1431,7 @@ static int do_mhi_ep_entry(const char *filename, void *symval, char *alias) } /* Looks like: ishtp:{guid} */ -static int do_ishtp_entry(const char *filename, void *symval, char *alias) +static int do_ishtp_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, ishtp_device_id, guid); @@ -1442,7 +1442,7 @@ static int do_ishtp_entry(const char *filename, void *symval, char *alias) return 1; } -static int do_auxiliary_entry(const char *filename, void *symval, char *alias) +static int do_auxiliary_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, auxiliary_device_id, name); sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name); @@ -1455,7 +1455,7 @@ 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 int do_ssam_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, ssam_device_id, match_flags); DEF_FIELD(symval, ssam_device_id, domain); @@ -1473,7 +1473,7 @@ static int do_ssam_entry(const char *filename, void *symval, char *alias) } /* Looks like: dfl:tNfN */ -static int do_dfl_entry(const char *filename, void *symval, char *alias) +static int do_dfl_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, dfl_device_id, type); DEF_FIELD(symval, dfl_device_id, feature_id); @@ -1485,7 +1485,7 @@ static int do_dfl_entry(const char *filename, void *symval, char *alias) } /* Looks like: cdx:vNdN */ -static int do_cdx_entry(const char *filename, void *symval, +static int do_cdx_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, cdx_device_id, vendor); @@ -1518,7 +1518,7 @@ static int do_cdx_entry(const char *filename, void *symval, return 1; } -static int do_vchiq_entry(const char *filename, void *symval, char *alias) +static int do_vchiq_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD_ADDR(symval, vchiq_device_id, name); sprintf(alias, "vchiq:%s", *name); @@ -1527,7 +1527,7 @@ static int do_vchiq_entry(const char *filename, void *symval, char *alias) } /* Looks like: coreboot:tN */ -static int do_coreboot_entry(const char *filename, void *symval, char *alias) +static int do_coreboot_entry(struct module *mod, void *symval, char *alias) { DEF_FIELD(symval, coreboot_device_id, tag); sprintf(alias, "coreboot:t%08X", tag); @@ -1547,7 +1547,7 @@ static bool sym_is(const char *name, unsigned namelen, const char *symbol) static void do_table(void *symval, unsigned long size, unsigned long id_size, const char *device_id, - int (*do_entry)(const char *filename, void *symval, char *alias), + int (*do_entry)(struct module *mod, void *symval, char *alias), struct module *mod) { unsigned int i; @@ -1558,7 +1558,7 @@ static void do_table(void *symval, unsigned long size, size -= id_size; for (i = 0; i < size; i += id_size) { - if (do_entry(mod->name, symval+i, alias)) { + if (do_entry(mod, symval+i, alias)) { module_alias_printf(mod, false, "%s", alias); } } From 6d3b3dd26fd71dde0b41478755a59ca30aaeb664 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:45 +0900 Subject: [PATCH 71/85] modpost: call module_alias_printf() from all do_*_entry() functions The do_*_entry() functions cannot check the length of the given buffer. Use module_alias_printf() helper consistently for these functions. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 438 ++++++++++++++++----------------------- 1 file changed, 181 insertions(+), 257 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index b23ef324b155..5ef87a6d33f8 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -126,12 +126,9 @@ typedef struct { struct devtable { const char *device_id; /* name of table, __mod___*_device_table. */ unsigned long id_size; - int (*do_entry)(struct module *mod, 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. */ @@ -158,15 +155,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); @@ -452,34 +440,34 @@ static void do_of_table(void *symval, unsigned long size, } /* Looks like: hid:bNvNpN */ -static int do_hid_entry(struct module *mod, - 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(struct module *mod, - 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, @@ -489,14 +477,13 @@ static int do_ieee1394_entry(struct module *mod, 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 _pci:vNdNsvNsdNbcNscNiN. */ -static int do_pci_entry(struct module *mod, - 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; @@ -519,7 +506,6 @@ static int do_pci_entry(struct module *mod, default: warn("Unknown PCI driver_override alias %08X\n", override_only); - return 0; } ADD(alias, "v", vendor != PCI_ANY_ID, vendor); @@ -539,27 +525,27 @@ static int do_pci_entry(struct module *mod, || (interface_mask != 0 && interface_mask != 0xFF)) { warn("Can't handle masks in %s:%04X\n", mod->name, class_mask); - return 0; + 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(struct module *mod, - 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, @@ -568,47 +554,42 @@ static int do_ccw_entry(struct module *mod, 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(struct module *mod, - 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(struct module *mod, - 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(struct module *mod, - 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 @@ -618,21 +599,19 @@ static int do_serio_entry(struct module *mod, * or _CLS. Also, bb, ss, and pp can be substituted with ?? * as don't care byte. */ -static int do_acpi_entry(struct module *mod, - 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)[0]) - sprintf(alias, "acpi*:%s:*", *id); + 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; @@ -643,9 +622,8 @@ static int do_acpi_entry(struct module *mod, sprintf(&alias[cnt], "??"); cnt += 2; } - sprintf(&alias[cnt], ":*"); + module_alias_printf(mod, false, "acpi*:%s:*", alias); } - return 1; } /* looks like: "pnp:dD" */ @@ -705,9 +683,9 @@ static void do_pnp_card_entries(void *symval, unsigned long size, } /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ -static int do_pcmcia_entry(struct module *mod, - 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); @@ -721,7 +699,6 @@ static int do_pcmcia_entry(struct module *mod, (*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, @@ -737,13 +714,12 @@ static int do_pcmcia_entry(struct module *mod, 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(struct module *mod, 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); @@ -756,8 +732,7 @@ static int do_vio_entry(struct module *mod, void *symval, if (isspace (*tmp)) *tmp = '_'; - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "%s", alias); } static void do_input(char *alias, @@ -773,9 +748,10 @@ static void do_input(char *alias, } /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ -static int do_input_entry(struct module *mod, 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); @@ -791,8 +767,6 @@ static int do_input_entry(struct module *mod, 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); @@ -827,99 +801,96 @@ static int do_input_entry(struct module *mod, 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(struct module *mod, void *symval, - char *alias) +static void do_eisa_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, eisa_device_id, sig); - sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); - return 1; + module_alias_printf(mod, false, EISA_DEVICE_MODALIAS_FMT "*", *sig); } /* Looks like: parisc:tNhvNrevNsvN */ -static int do_parisc_entry(struct module *mod, 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(struct module *mod, - 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(struct module *mod, - 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(struct module *mod, - 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(struct module *mod, 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); } /* @@ -928,8 +899,7 @@ static int do_virtio_entry(struct module *mod, void *symval, * in the name. */ -static int do_vmbus_entry(struct module *mod, 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); @@ -938,68 +908,57 @@ static int do_vmbus_entry(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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 { @@ -1034,12 +993,11 @@ static void dmi_ascii_filter(char *d, const char *s) } -static int do_dmi_entry(struct module *mod, 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++) { @@ -1054,80 +1012,75 @@ static int do_dmi_entry(struct module *mod, void *symval, } } - strcat(alias, ":"); - return 1; + module_alias_printf(mod, false, "dmi*%s:", alias); } -static int do_platform_entry(struct module *mod, - 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(struct module *mod, - 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(struct module *mod, 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(struct module *mod, - 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(struct module *mod, - 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); } /* @@ -1178,9 +1131,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(struct module *mod, - 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); @@ -1190,13 +1143,12 @@ static int do_amba_entry(struct module *mod, fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: id=0x%08X, mask=0x%08X. Please fix this driver.\n", 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); } /* @@ -1205,13 +1157,11 @@ static int do_amba_entry(struct module *mod, * 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(struct module *mod, - 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,* @@ -1220,137 +1170,130 @@ static int do_mips_cdmm_entry(struct module *mod, * complicated. */ -static int do_x86cpu_entry(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, - 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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 @@ -1361,93 +1304,80 @@ static int do_tbsvc_entry(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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, mod->name); - return 0; + 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", - mod->name); - return 0; - } - return 1; + module_alias_printf(mod, false, WMI_MODULE_PREFIX "%s", *guid_string); } /* Looks like: mhi:S */ -static int do_mhi_entry(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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); } /* @@ -1455,8 +1385,10 @@ static int do_auxiliary_entry(struct module *mod, void *symval, char *alias) * * N is exactly 2 digits, where each is an upper-case hex digit. */ -static int do_ssam_entry(struct module *mod, 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); @@ -1464,30 +1396,28 @@ static int do_ssam_entry(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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); @@ -1506,7 +1436,7 @@ static int do_cdx_entry(struct module *mod, void *symval, default: warn("Unknown CDX driver_override alias %08X\n", override_only); - return 0; + return; } ADD(alias, "v", vendor != CDX_ANY_ID, vendor); @@ -1515,24 +1445,22 @@ static int do_cdx_entry(struct module *mod, 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(struct module *mod, 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(struct module *mod, 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? */ @@ -1547,21 +1475,17 @@ static bool sym_is(const char *name, unsigned namelen, const char *symbol) static void do_table(void *symval, unsigned long size, unsigned long id_size, const char *device_id, - int (*do_entry)(struct module *mod, 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; - for (i = 0; i < size; i += id_size) { - if (do_entry(mod, symval+i, alias)) { - module_alias_printf(mod, false, "%s", alias); - } - } + for (i = 0; i < size; i += id_size) + do_entry(mod, symval + i); } static const struct devtable devtable[] = { From a5d8d417e62ab3823a06e1bc08634d737d810e59 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:46 +0900 Subject: [PATCH 72/85] modpost: convert do_pnp_card_entries() to a generic handler do_pnp_card_entries() no longer needs to iterate over the pnp_card_device_id array. Convert it to a generic ->do_entry() handler. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 5ef87a6d33f8..00bb3f8f0647 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -651,34 +651,24 @@ static void do_pnp_device_entry(void *symval, unsigned long size, } /* 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; + DEF_FIELD_ADDR(symval, pnp_card_device_id, devs); - device_id_check(mod->name, "pnp", size, id_size, symval); + for (unsigned int i = 0; i < PNP_MAX_DEVICES; i++) { + const char *id = (char *)(*devs)[i].id; + char acpi_id[PNP_ID_LEN]; - for (i = 0; i < count; i++) { - unsigned int j; - DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs); + if (!id[0]) + break; - for (j = 0; j < PNP_MAX_DEVICES; j++) { - const char *id = (char *)(*devs)[j].id; - char acpi_id[PNP_ID_LEN]; + /* fix broken pnp bus lowercasing */ + for (unsigned int j = 0; j < sizeof(acpi_id); j++) + acpi_id[j] = toupper(id[j]); - if (!id[0]) - break; - - /* add an individual alias for every device entry */ - module_alias_printf(mod, false, "pnp:d%s*", id); - - /* fix broken pnp bus lowercasing */ - for (int k = 0; k < sizeof(acpi_id); k++) - acpi_id[k] = toupper(id[k]); - module_alias_printf(mod, false, "acpi*:%s:*", 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); } } @@ -1541,6 +1531,7 @@ 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}, + {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry}, }; /* Create MODULE_ALIAS() statements. @@ -1591,8 +1582,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, 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; From 600dbaf1e2f0c0b70b2d3e7513a161b884e7718f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:47 +0900 Subject: [PATCH 73/85] modpost: convert do_pnp_device_entry() to a generic handler do_pnp_device_entry() no longer needs to iterate over the pnp_device_id array. Convert it to a generic ->do_entry() handler. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 00bb3f8f0647..cacfa0de634b 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -627,27 +627,16 @@ static void do_acpi_entry(struct module *mod, void *symval) } /* 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; + DEF_FIELD_ADDR(symval, pnp_device_id, id); + char acpi_id[sizeof(*id)]; - device_id_check(mod->name, "pnp", size, id_size, symval); - - for (i = 0; i < count; i++) { - DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); - char acpi_id[sizeof(*id)]; - int j; - - module_alias_printf(mod, false, "pnp:d%s*", *id); - - /* fix broken pnp bus lowercasing */ - for (j = 0; j < sizeof(acpi_id); j++) - acpi_id[j] = toupper((*id)[j]); - module_alias_printf(mod, false, "acpi*:%s:*", 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 */ @@ -1531,6 +1520,7 @@ 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}, + {"pnp", SIZE_pnp_device_id, do_pnp_device_entry}, {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry}, }; @@ -1580,8 +1570,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, 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 { int i; From c58854c8e0b50c2f30c729b82b92b3fd8cc8f2c1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:48 +0900 Subject: [PATCH 74/85] modpost: convert do_of_table() to a generic handler do_of_table() no longer needs to iterate over the of_device_id array. Convert it to a generic ->do_entry() handler. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index cacfa0de634b..7f079a3857b2 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -398,7 +398,7 @@ static void do_usb_table(void *symval, unsigned long 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; @@ -424,21 +424,6 @@ static void do_of_entry_multi(void *symval, struct module *mod) module_alias_printf(mod, false, "%sC*", 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); -} - /* Looks like: hid:bNvNpN */ static void do_hid_entry(struct module *mod, void *symval) { @@ -1520,6 +1505,7 @@ 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}, {"pnp", SIZE_pnp_device_id, do_pnp_device_entry}, {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry}, }; @@ -1568,8 +1554,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, /* 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 { int i; From abd20428c3f2f8b97a2a0414343faf0ff246a018 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:49 +0900 Subject: [PATCH 75/85] modpost: convert do_usb_table() to a generic handler do_usb_table() no longer needs to iterate over the usb_device_id array. Convert it to a generic ->do_entry() handler. This is the last special case. Clean up handle_moddevtable(). Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 7f079a3857b2..7f1bbb46dc65 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -122,7 +122,6 @@ 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___*_device_table. */ unsigned long id_size; @@ -318,7 +317,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; @@ -383,21 +382,6 @@ 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(struct module *mod, void *symval) { char alias[500]; @@ -1506,6 +1490,7 @@ static const struct devtable devtable[] = { {"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}, }; @@ -1551,21 +1536,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 { - int i; + for (int i = 0; i < ARRAY_SIZE(devtable); i++) { + const struct devtable *p = &devtable[i]; - for (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(name, namelen, p->device_id)) { + do_table(symval, sym->st_size, p->id_size, + p->device_id, p->do_entry, mod); + break; } } + free(zeros); } From 9d98038d438d8515473a75a29bc524e9a4a5882a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:50 +0900 Subject: [PATCH 76/85] modpost: move strstarts() to modpost.h This macro is useful in file2alias.c as well. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 2 +- scripts/mod/modpost.c | 2 -- scripts/mod/modpost.h | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 7f1bbb46dc65..541e6a3f95bc 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1515,7 +1515,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, return; /* All our symbols are of form __mod____device_table. */ - if (strncmp(symname, "__mod_", strlen("__mod_"))) + if (!strstarts(symname, "__mod_")) return; name = symname + strlen("__mod_"); namelen = strlen(name); diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 1948d69ce2b9..3bbd5efcf3f3 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -341,8 +341,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) { diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 52efe0026b34..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; From 9a8ace8bb2efa0ca43a77866fa9c835294b1e045 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:51 +0900 Subject: [PATCH 77/85] modpost: rename variables in handle_moddevtable() This commit renames the variables in handle_moddevtable() as follows: name -> type namelen -> typelen identifier -> name These changes align with the definition in include/linux/module.h: extern typeof(name) __mod_##type##__##name##_device_table Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 541e6a3f95bc..038b2ab79e11 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1503,8 +1503,8 @@ 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; /* We're looking for a section relative symbol */ if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) @@ -1514,19 +1514,19 @@ 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____device_table. */ + /* All our symbols are of form __mod____device_table. */ if (!strstarts(symname, "__mod_")) return; - name = symname + strlen("__mod_"); - namelen = strlen(name); - if (namelen < strlen("_device_table")) + type = symname + strlen("__mod_"); + typelen = strlen(type); + if (typelen < strlen("_device_table")) return; - if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) + if (strcmp(type + typelen - strlen("_device_table"), "_device_table")) return; - identifier = strstr(name, "__"); - if (!identifier) + name = strstr(type, "__"); + if (!name) return; - namelen = identifier - name; + typelen = name - type; /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { @@ -1539,7 +1539,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, for (int i = 0; i < ARRAY_SIZE(devtable); i++) { const struct devtable *p = &devtable[i]; - if (sym_is(name, namelen, p->device_id)) { + if (sym_is(type, typelen, p->device_id)) { do_table(symval, sym->st_size, p->id_size, p->device_id, p->do_entry, mod); break; From 054a9cd395a79f4a5595f2cd24542e9bca8723c8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:52 +0900 Subject: [PATCH 78/85] modpost: rename alias symbol for MODULE_DEVICE_TABLE() This commit renames the alias symbol, __mod____device_table to __mod_device_table____. This change simplifies the code slightly, as there is no longer a need to check both the prefix and suffix. Signed-off-by: Masahiro Yamada --- include/linux/module.h | 2 +- scripts/mod/file2alias.c | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 88ecc5e9f523..3dd79a3d0cbf 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/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 038b2ab79e11..fc4bbeea1268 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -123,7 +123,7 @@ typedef struct { #include "../../include/linux/mod_devicetable.h" struct devtable { - const char *device_id; /* name of table, __mod___*_device_table. */ + const char *device_id; unsigned long id_size; void (*do_entry)(struct module *mod, void *symval); }; @@ -190,7 +190,7 @@ static void device_id_check(const char *modname, const char *device_id, 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___device_table=%lu.\n" + fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo of the size of section __mod_device_table__%s__=%lu.\n" "Fix definition of struct %s_device_id in mod_devicetable.h\n", modname, device_id, id_size, device_id, size, device_id); } @@ -1505,6 +1505,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, char *zeros = NULL; 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) @@ -1514,15 +1515,11 @@ 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____device_table. */ - if (!strstarts(symname, "__mod_")) - return; - type = symname + strlen("__mod_"); - typelen = strlen(type); - if (typelen < strlen("_device_table")) - return; - if (strcmp(type + typelen - strlen("_device_table"), "_device_table")) + /* All our symbols are of form __mod_device_table____. */ + if (!strstarts(symname, prefix)) return; + type = symname + strlen(prefix); + name = strstr(type, "__"); if (!name) return; From 2b1bd507542a6ec1506a847da8e81fc764a4e707 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Nov 2024 08:56:53 +0900 Subject: [PATCH 79/85] modpost: improve error messages in device_id_check() The first error message in device_id_check() is obscure and can be misleading because the cause of the error is unlikely to be found in the struct definition in mod_devicetable.h. This type of error occurs when an array is passed to an incorrect type of MODULE_DEVICE_TABLE(). [Example 1] static const struct acpi_device_id foo_ids[] = { { "FOO" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, foo_ids); Currently, modpost outputs a meaningless suggestion: ERROR: modpost: ...: sizeof(struct of_device_id)=200 is not a modulo of the size of section __mod_device_table__of__=64. Fix definition of struct of_device_id in mod_devicetable.h The root cause here is that MODULE_DEVICE_TABLE(of, ...) is used instead of the correct MODULE_DEVICE_TABLE(acpi, ...). This commit provides a more intuitive error message: ERROR: modpost: ...: type mismatch between foo_ids[] and MODULE_DEVICE_TABLE(of, ...) The second error message, related to a missing terminator, is too verbose. [Example 2] static const struct acpi_device_id foo_ids[] = { { "FOO" }, }; MODULE_DEVICE_TABLE(acpi, foo_ids); The current error message is overly long, and does not pinpoint the incorrect array: ...: struct acpi_device_id is 32 bytes. The last of 1 is: 0x46 0x4f 0x4f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ERROR: modpost: ...: struct acpi_device_id is not terminated with a NULL entry! This commit changes it to a more concise error message, sufficient to identify the incorrect array: ERROR: modpost: ...: foo_ids[] is not terminated with a NULL entry Lastly, this commit squashes device_id_check() into do_table() and changes fatal() into error(), allowing modpost to continue processing other modules. Signed-off-by: Masahiro Yamada --- scripts/mod/file2alias.c | 55 +++++++++++++--------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index fc4bbeea1268..5b5745f00eb3 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -176,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_device_table__%s__=%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, @@ -1420,7 +1386,7 @@ 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, void (*do_entry)(struct module *mod, void *symval), @@ -1428,7 +1394,21 @@ static void do_table(void *symval, unsigned long size, { unsigned int i; - device_id_check(mod->name, device_id, size, id_size, symval); + 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; + } + + /* 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; @@ -1524,6 +1504,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (!name) return; typelen = name - type; + name += strlen("__"); /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { @@ -1537,7 +1518,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, const struct devtable *p = &devtable[i]; if (sym_is(type, typelen, p->device_id)) { - do_table(symval, sym->st_size, p->id_size, + do_table(name, symval, sym->st_size, p->id_size, p->device_id, p->do_entry, mod); break; } From 091aa11a2983cdc608f3978d365f5479e78917d8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Nov 2024 08:22:55 +0900 Subject: [PATCH 80/85] genksyms: reduce indentation in export_symbol() Modify this function to return earlier when find_symbol() returns NULL, reducing the level of improve readability. No functional changes are intended. Signed-off-by: Masahiro Yamada --- scripts/genksyms/genksyms.c | 89 +++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 44 deletions(-) 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; - - if (flag_dump_defs) - fprintf(debugfile, "Export %s == <", name); - - expansion_trail = (struct symbol *)-1L; - - 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; - - 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++; - } - sym->expansion_trail = 0; - sym = n; - } - if (has_changed) - fprintf(stderr, "\n"); - - if (flag_dump_defs) - fputs(">\n", debugfile); - - printf("#SYMVER %s 0x%08lx\n", name, crc); + return; } + + if (flag_dump_defs) + fprintf(debugfile, "Export %s == <", name); + + expansion_trail = (struct symbol *)-1L; + + 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; + + 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++; + } + sym->expansion_trail = 0; + sym = n; + } + if (has_changed) + fprintf(stderr, "\n"); + + if (flag_dump_defs) + fputs(">\n", debugfile); + + printf("#SYMVER %s 0x%08lx\n", name, crc); } /*----------------------------------------------------------------------*/ From 6b1fabce7313dcd4d95e541dd400ba5748b09b94 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 23 Nov 2024 17:26:45 +0900 Subject: [PATCH 81/85] kbuild: deb-pkg: add python3:native to build dependency Python3 is necessary for running some scripts such as drivers/gpu/drm/msm/registers/gen_header.py Both scripts/package/kernel.spec and scripts/package/PKGBUILD already list Python as the build dependency. Do likewise for scripts/package/mkdebian. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/mkdebian | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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} , kmod, libelf-dev:native, libssl-dev:native, libssl-dev , - rsync + python3:native, rsync Homepage: https://www.kernel.org/ Package: $packagename-$version From 5eaea85187bf2132d1af916010fa9e26bb63f97f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 23 Nov 2024 17:36:08 +0900 Subject: [PATCH 82/85] modpost: replace tdb_hash() with hash_str() Use a helper available in scripts/include/hash.h. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3bbd5efcf3f3..0584cbcdbd2d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -210,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 @@ -240,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) @@ -261,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; } From 18e9944e56f68423e52505066f79939e7d12a62b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 23 Nov 2024 14:33:37 +0100 Subject: [PATCH 83/85] kbuild: add dependency from vmlinux to resolve_btfids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolve_btfids is used by link-vmlinux.sh. In contrast to other configuration options and targets no transitive dependency between resolve_btfids and vmlinux. Add an explicit one. Signed-off-by: Thomas Weißschuh Acked-by: Jiri Olsa Signed-off-by: Masahiro Yamada --- scripts/Makefile.vmlinux | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index 997be5dc7bf5..2ecd350e9c43 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -68,6 +68,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 # --------------------------------------------------------------------------- From 4198a4d25141c76021ae65368a5841843ee66098 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Mon, 25 Nov 2024 16:37:36 +0800 Subject: [PATCH 84/85] gitignore: Don't ignore 'tags' directory W=1 builds reported warnings regarding files being ignored: tools/testing/selftests/arm64/tags/.gitignore: warning: ignored by one of the .gitignore files tools/testing/selftests/arm64/tags/Makefile: warning: ignored by one of the .gitignore files tools/testing/selftests/arm64/tags/tags_test.c: warning: ignored by one of the .gitignore files Adjusting the .gitignore entries will prevent these warnings and ensure a smoother script execution. Reported-by: kernel test robot Signed-off-by: Li Zhijian Signed-off-by: Masahiro Yamada --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 56972adb5031..6c57bb0259c6 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ series # ctags files tags +!tags/ TAGS # cscope files From e6064da6461f989a357f2e280d7f8d4155267c4c Mon Sep 17 00:00:00 2001 From: Sedat Dilek Date: Tue, 26 Nov 2024 16:58:01 +0100 Subject: [PATCH 85/85] kbuild: rename .tmp_vmlinux.kallsyms0.syms to .tmp_vmlinux0.syms Change the naming for consistency. While at this, fix the comments in scripts/link-vmlinux.sh. Signed-off-by: Sedat Dilek Signed-off-by: Masahiro Yamada --- scripts/link-vmlinux.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 53bd4b727e21..139aa4d1215a 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -207,8 +207,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 @@ -235,14 +235,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