From 4f32f799a950c7fffa17971177be42c79d74b69f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 27 Jul 2024 16:42:01 +0900 Subject: [PATCH 01/51] modpost: remove unused HOST_ELFCLASS HOST_ELFCLASS is output to elfconfig.h, but it is not used in modpost. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/mod/mk_elfconfig.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c index 680eade89be1..aca96b3aada0 100644 --- a/scripts/mod/mk_elfconfig.c +++ b/scripts/mod/mk_elfconfig.c @@ -39,12 +39,6 @@ main(int argc, char **argv) exit(1); } - if (sizeof(unsigned long) == 4) { - printf("#define HOST_ELFCLASS ELFCLASS32\n"); - } else if (sizeof(unsigned long) == 8) { - printf("#define HOST_ELFCLASS ELFCLASS64\n"); - } - endian_test.s = 0x0102; if (memcmp(endian_test.c, "\x01\x02", 2) == 0) printf("#define HOST_ELFDATA ELFDATA2MSB\n"); From a660deb0f1f62214439640292cd7726f6ed8023d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 27 Jul 2024 16:42:02 +0900 Subject: [PATCH 02/51] modpost: detect endianness on run-time Endianness is currently detected on compile-time, but we can defer this until run-time. This change avoids re-executing scripts/mod/mk_elfconfig even if modpost in the linux-headers package needs to be rebuilt for a foreign architecture. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/mod/mk_elfconfig.c | 19 ------------------- scripts/mod/modpost.c | 36 ++++++++++++++++++++++++++++++++++++ scripts/mod/modpost.h | 13 ++++--------- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c index aca96b3aada0..e8cee4e4bc73 100644 --- a/scripts/mod/mk_elfconfig.c +++ b/scripts/mod/mk_elfconfig.c @@ -8,7 +8,6 @@ int main(int argc, char **argv) { unsigned char ei[EI_NIDENT]; - union { short s; char c[2]; } endian_test; if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) { fprintf(stderr, "Error: input truncated\n"); @@ -28,24 +27,6 @@ main(int argc, char **argv) default: exit(1); } - switch (ei[EI_DATA]) { - case ELFDATA2LSB: - printf("#define KERNEL_ELFDATA ELFDATA2LSB\n"); - break; - case ELFDATA2MSB: - printf("#define KERNEL_ELFDATA ELFDATA2MSB\n"); - break; - default: - exit(1); - } - - endian_test.s = 0x0102; - if (memcmp(endian_test.c, "\x01\x02", 2) == 0) - printf("#define HOST_ELFDATA ELFDATA2MSB\n"); - else if (memcmp(endian_test.c, "\x02\x01", 2) == 0) - printf("#define HOST_ELFDATA ELFDATA2LSB\n"); - else - exit(1); return 0; } diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index d16d0ace2775..bfd758ad9e4f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -50,6 +50,9 @@ static bool error_occurred; static bool extra_warn; +bool target_is_big_endian; +bool host_is_big_endian; + /* * Cut off the warnings when there are too many. This typically occurs when * vmlinux is missing. ('make modules' without building vmlinux.) @@ -438,6 +441,18 @@ static int parse_elf(struct elf_info *info, const char *filename) /* Not an ELF file - silently ignore it */ return 0; } + + switch (hdr->e_ident[EI_DATA]) { + case ELFDATA2LSB: + target_is_big_endian = false; + break; + case ELFDATA2MSB: + target_is_big_endian = true; + break; + default: + fatal("target endian is unknown\n"); + } + /* Fix endianness in ELF header */ hdr->e_type = TO_NATIVE(hdr->e_type); hdr->e_machine = TO_NATIVE(hdr->e_machine); @@ -2117,6 +2132,25 @@ struct dump_list { const char *file; }; +static void check_host_endian(void) +{ + static const union { + short s; + char c[2]; + } endian_test = { .c = {0x01, 0x02} }; + + switch (endian_test.s) { + case 0x0102: + host_is_big_endian = true; + break; + case 0x0201: + host_is_big_endian = false; + break; + default: + fatal("Unknown host endian\n"); + } +} + int main(int argc, char **argv) { struct module *mod; @@ -2181,6 +2215,8 @@ int main(int argc, char **argv) } } + check_host_endian(); + list_for_each_entry_safe(dl, dl2, &dump_lists, list) { read_dump(dl->file); list_del(&dl->list); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 58197b34a3c8..54ba9431713f 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -62,15 +62,8 @@ x); \ }) -#if KERNEL_ELFDATA != HOST_ELFDATA - -#define TO_NATIVE(x) (bswap(x)) - -#else /* endianness matches */ - -#define TO_NATIVE(x) (x) - -#endif +#define TO_NATIVE(x) \ + (target_is_big_endian == host_is_big_endian ? x : bswap(x)) #define NOFAIL(ptr) do_nofail((ptr), #ptr) @@ -187,6 +180,8 @@ void add_moddevtable(struct buffer *buf, struct module *mod); void get_src_version(const char *modname, char sum[], unsigned sumlen); /* from modpost.c */ +extern bool target_is_big_endian; +extern bool host_is_big_endian; char *read_text_file(const char *filename); char *get_line(char **stringp); void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); From aaed5c7739be81ebdd6008aedc8befd98c88e67a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 27 Jul 2024 16:42:03 +0900 Subject: [PATCH 03/51] kbuild: slim down package for building external modules Exclude directories and files unnecessary for building external modules: - include/config/ (except include/config/{auto.conf,kernel.release}) - scripts/atomic/ - scripts/dtc/ - scripts/kconfig/ - scripts/mod/mk_elfconfig - scripts/package/ - scripts/unifdef - .config - *.o - .*.cmd Avoid copying files twice for the following directories: - include/generated/ - arch/*/include/generated/ Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/install-extmod-build | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build index 8cc9e13403ae..9fee4a3236cc 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -9,15 +9,22 @@ is_enabled() { grep -q "^$1=y" include/config/auto.conf } +find_in_scripts() { + find scripts \ + \( -name atomic -o -name dtc -o -name kconfig -o -name package \) -prune -o \ + ! -name unifdef -a ! -name mk_elfconfig -a \( -type f -o -type l \) -print +} + mkdir -p "${destdir}" ( cd "${srctree}" echo Makefile find "arch/${SRCARCH}" -maxdepth 1 -name 'Makefile*' - find include scripts -type f -o -type l + find "arch/${SRCARCH}" -name generated -prune -o -name include -type d -print find "arch/${SRCARCH}" -name Kbuild.platforms -o -name Platform - find "arch/${SRCARCH}" -name include -type d + find include \( -name config -o -name generated \) -prune -o \( -type f -o -type l \) -print + find_in_scripts ) | tar -c -f - -C "${srctree}" -T - | tar -xf - -C "${destdir}" { @@ -25,12 +32,16 @@ mkdir -p "${destdir}" echo tools/objtool/objtool fi - find "arch/${SRCARCH}/include" Module.symvers include scripts -type f + echo Module.symvers + echo "arch/${SRCARCH}/include/generated" + echo include/config/auto.conf + echo include/config/kernel.release + echo include/generated + find_in_scripts if is_enabled CONFIG_GCC_PLUGINS; then find scripts/gcc-plugins -name '*.so' fi } | tar -c -f - -T - | tar -xf - -C "${destdir}" -# copy .config manually to be where it's expected to be -cp "${KCONFIG_CONFIG}" "${destdir}/.config" +find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete From f1d87664b82aeeaa1be9ee22dc85a59fd5a60d63 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 27 Jul 2024 16:42:04 +0900 Subject: [PATCH 04/51] kbuild: cross-compile linux-headers package when possible A long standing issue in the upstream kernel packaging is that the linux-headers package is not cross-compiled. For example, you can cross-build Debian packages for arm64 by running the following command: $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bindeb-pkg However, the generated linux-headers-*_arm64.deb is useless because the host programs in it were built for your build machine architecture (likely x86), not arm64. The Debian kernel maintains its own Makefiles to cross-compile host tools without relying on Kbuild. [1] Instead of adding such full custom Makefiles, this commit adds a small piece of code to cross-compile host programs located under the scripts/ directory. A straightforward solution is to pass HOSTCC=${CROSS_COMPILE}gcc, but it would also cross-compile scripts/basic/fixdep, which needs to be native to process the if_changed_dep macro. (This approach may work under some circumstances; you can execute foreign architecture programs with the help of binfmt_misc because Debian systems enable CONFIG_BINFMT_MISC, but it would require installing QEMU and libc for that architecture.) A trick is to use the external module build (KBUILD_EXTMOD=), which does not rebuild scripts/basic/fixdep. ${CC} needs to be able to link userspace programs (CONFIG_CC_CAN_LINK=y). There are known limitations: - GCC plugins It would possible to rebuild GCC plugins for the target architecture by passing HOSTCXX=${CROSS_COMPILE}g++ with necessary packages installed, but gcc on the installed system emits "cc1: error: incompatible gcc/plugin versions". - objtool and resolve_btfids These are built by the tools build system. They are not covered by the current solution. The resulting linux-headers package is broken if CONFIG_OBJTOOL or CONFIG_DEBUG_INFO_BTF is enabled. I only tested this with Debian, but it should work for other package systems as well. [1]: https://salsa.debian.org/kernel-team/linux/-/blob/debian/6.9.9-1/debian/rules.real#L586 Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/install-extmod-build | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build index 9fee4a3236cc..d2c9cacecc0c 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -44,4 +44,38 @@ mkdir -p "${destdir}" fi } | tar -c -f - -T - | tar -xf - -C "${destdir}" +# When ${CC} and ${HOSTCC} differ, we are likely cross-compiling. Rebuild host +# programs using ${CC}. This assumes CC=${CROSS_COMPILE}gcc, which is usually +# the case for package building. It does not cross-compile when CC=clang. +# +# This caters to host programs that participate in Kbuild. objtool and +# resolve_btfids are out of scope. +if [ "${CC}" != "${HOSTCC}" ] && is_enabled CONFIG_CC_CAN_LINK; then + echo "Rebuilding host programs with ${CC}..." + + cat <<-'EOF' > "${destdir}/Kbuild" + subdir-y := scripts + EOF + + # HOSTCXX is not overridden. The C++ compiler is used to build: + # - scripts/kconfig/qconf, which is unneeded for external module builds + # - GCC plugins, which will not work on the installed system even after + # being rebuilt. + # + # Use the single-target build to avoid the modpost invocation, which + # would overwrite Module.symvers. + "${MAKE}" HOSTCC="${CC}" KBUILD_EXTMOD="${destdir}" scripts/ + + cat <<-'EOF' > "${destdir}/scripts/Kbuild" + subdir-y := basic + hostprogs-always-y := mod/modpost + mod/modpost-objs := $(addprefix mod/, modpost.o file2alias.o sumversion.o symsearch.o) + EOF + + # Run once again to rebuild scripts/basic/ and scripts/mod/modpost. + "${MAKE}" HOSTCC="${CC}" KBUILD_EXTMOD="${destdir}" scripts/ + + rm -f "${destdir}/Kbuild" "${destdir}/scripts/Kbuild" +fi + find "${destdir}" \( -name '.*.cmd' -o -name '*.o' \) -delete From 76be4f5a784533c71afbbb1b8f2963ef9e2ee258 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 29 Jul 2024 18:57:38 +0300 Subject: [PATCH 05/51] Remove *.orig pattern from .gitignore Commit 3f1b0e1f2875 (".gitignore update") added *.orig and *.rej patterns to .gitignore in v2.6.23. The commit message didn't give a rationale. Later on, commit 1f5d3a6b6532 ("Remove *.rej pattern from .gitignore") removed the *.rej pattern in v2.6.26, on the rationale that *.rej files indicated something went really wrong and should not be ignored. The *.rej files are now shown by `git status`, which helps located conflicts when applying patches and lowers the probability that they will go unnoticed. It is however still easy to overlook the *.orig files which slowly polute the source tree. That's not as big of a deal as not noticing a conflict, but it's still not nice. Drop the *.orig pattern from .gitignore to avoid this and help keep the source tree clean. Signed-off-by: Laurent Pinchart [masahiroy@kernel.org: I do not have a strong opinion about this. Perhaps some people may have a different opinion. If you are someone who wants to ignore *.orig, it is likely you would want to do so across all projects. Then, $XDG_CONFIG_HOME/git/ignore would be more suitable for your needs. gitignore(5) suggests, "Patterns which a user wants Git to ignore in all situations generally go into a file specified by core.excludesFile in the user's ~/.gitconfig". Please note that you cannot do the opposite; if *.orig is ignored by the project's .gitignore, you cannot override the decision because $XDG_CONFIG_HOME/git/ignore has a lower priority. If *.orig is sitting on the fence, I'd leave it to the users. ] Signed-off-by: Masahiro Yamada --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7902adf4f7f1..58fdbb35e2f1 100644 --- a/.gitignore +++ b/.gitignore @@ -142,7 +142,6 @@ GTAGS # id-utils files ID -*.orig *~ \#*# From 0c4beffbfe3fcd711b5d9268e7c7d63d4c1cc964 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 4 Aug 2024 12:33:07 +0900 Subject: [PATCH 06/51] kbuild: modinst: remove the multithread option from zstd compression Parallel execution is supported by GNU Make: $ make -j modules_install It is questionable to enable multithreading within each zstd process by default. If you still want to do it, you can use the environment variable: $ ZSTD_NBTHREADS= make modules_install Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier Tested-by: Sedat Dilek --- scripts/Makefile.modinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index 0afd75472679..04f5229efa6b 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -146,7 +146,7 @@ quiet_cmd_gzip = GZIP $@ quiet_cmd_xz = XZ $@ cmd_xz = $(XZ) --check=crc32 --lzma2=dict=1MiB -f $< quiet_cmd_zstd = ZSTD $@ - cmd_zstd = $(ZSTD) -T0 --rm -f -q $< + cmd_zstd = $(ZSTD) --rm -f -q $< $(dst)/%.ko.gz: $(dst)/%.ko FORCE $(call cmd,gzip) From 2893f00322922b2adce07fd6d0db37d6b8e30977 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 19:01:47 +0900 Subject: [PATCH 07/51] tinyconfig: remove unnecessary 'is not set' for choice blocks This reverts the following commits: - 236dec051078 ("kconfig: tinyconfig: provide whole choice blocks to avoid warnings") - b0f269728ccd ("x86/config: Fix warning for 'make ARCH=x86_64 tinyconfig'") Since commit f79dc03fe68c ("kconfig: refactor choice value calculation"), it is no longer necessary to disable the remaining options in choice blocks. Signed-off-by: Masahiro Yamada Acked-by: Thomas Gleixner --- arch/x86/configs/tiny.config | 4 ---- kernel/configs/tiny.config | 6 ------ 2 files changed, 10 deletions(-) diff --git a/arch/x86/configs/tiny.config b/arch/x86/configs/tiny.config index be3ee4294903..aabafa3faa6d 100644 --- a/arch/x86/configs/tiny.config +++ b/arch/x86/configs/tiny.config @@ -1,6 +1,2 @@ CONFIG_NOHIGHMEM=y -# CONFIG_HIGHMEM4G is not set -# CONFIG_HIGHMEM64G is not set -# CONFIG_UNWINDER_ORC is not set CONFIG_UNWINDER_GUESS=y -# CONFIG_UNWINDER_FRAME_POINTER is not set diff --git a/kernel/configs/tiny.config b/kernel/configs/tiny.config index 00009f7d0835..b753695c5a8f 100644 --- a/kernel/configs/tiny.config +++ b/kernel/configs/tiny.config @@ -1,10 +1,4 @@ -# CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE is not set CONFIG_CC_OPTIMIZE_FOR_SIZE=y -# CONFIG_KERNEL_GZIP is not set -# CONFIG_KERNEL_BZIP2 is not set -# CONFIG_KERNEL_LZMA is not set CONFIG_KERNEL_XZ=y -# CONFIG_KERNEL_LZO is not set -# CONFIG_KERNEL_LZ4 is not set CONFIG_SLUB=y CONFIG_SLUB_TINY=y From dc73a57aeaaabe148c69c16b388771f891a996a2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 20:49:45 +0900 Subject: [PATCH 08/51] kconfig: remove dummy assignments to cur_{filename,lineno} Since commit ca4c74ba306e ("kconfig: remove P_CHOICE property"), menu_finalize() no longer calls menu_add_symbol(). No function references cur_filename or cur_lineno after yyparse(). Signed-off-by: Masahiro Yamada --- scripts/kconfig/parser.y | 8 -------- 1 file changed, 8 deletions(-) diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 61900feb4254..e03731184840 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -530,14 +530,6 @@ void conf_parse(const char *name) yydebug = 1; yyparse(); - /* - * FIXME: - * cur_filename and cur_lineno are used even after yyparse(); - * menu_finalize() calls menu_add_symbol(). This should be fixed. - */ - cur_filename = ""; - cur_lineno = 0; - str_printf(&autoconf_cmd, "\n" "$(autoconfig): $(deps_config)\n" From 5e6cc7e3f2965fc3df901416336f6bf985a363da Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 20:49:46 +0900 Subject: [PATCH 09/51] kconfig: stop adding P_SYMBOL property to symbols I believe its last usage was in the following code: if (prop == NULL) prop = stack->sym->prop; This code was previously used to print the file name and line number of associated symbols in sym_check_print_recursive(), which was removed by commit 9d0d26604657 ("kconfig: recursive checks drop file/lineno"). Signed-off-by: Masahiro Yamada --- scripts/kconfig/menu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 323cc0b62be6..854edeb4d2db 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -78,10 +78,8 @@ void menu_add_entry(struct symbol *sym) *last_entry_ptr = menu; last_entry_ptr = &menu->next; current_entry = menu; - if (sym) { - menu_add_symbol(P_SYMBOL, sym, NULL); + if (sym) list_add_tail(&menu->link, &sym->menus); - } } struct menu *menu_add_menu(void) From 96490176f1e11947be2bdd2700075275e2c27310 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 20:49:47 +0900 Subject: [PATCH 10/51] kconfig: remove P_SYMBOL property P_SYMBOL is a pseudo property that was previously used for data linking purposes. It is no longer used except for debug prints. Remove it. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 1 - scripts/kconfig/parser.y | 4 ---- scripts/kconfig/qconf.cc | 1 - scripts/kconfig/symbol.c | 2 -- 4 files changed, 8 deletions(-) diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 2bc96cd28253..c82d08bbd704 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -168,7 +168,6 @@ enum prop_type { P_SELECT, /* select BAR */ P_IMPLY, /* imply BAR */ P_RANGE, /* range 7..100 (for a symbol) */ - P_SYMBOL, /* where a symbol is defined */ }; struct property { diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index e03731184840..2d5e5ed56aba 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -707,10 +707,6 @@ static void print_symbol(FILE *out, const struct menu *menu) print_quoted_string(out, prop->text); fputc('\n', out); break; - case P_SYMBOL: - fputs( " symbol ", out); - fprintf(out, "%s\n", prop->menu->sym->name); - break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 7d239c032b3d..88797d174261 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1094,7 +1094,6 @@ QString ConfigInfoView::debug_info(struct symbol *sym) case P_RANGE: case P_COMMENT: case P_IMPLY: - case P_SYMBOL: stream << prop_get_type_name(prop->type); stream << ": "; expr_print(prop->expr, expr_print_help, diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 71502abd3b12..d75665f3dfa2 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -1321,8 +1321,6 @@ const char *prop_get_type_name(enum prop_type type) return "imply"; case P_RANGE: return "range"; - case P_SYMBOL: - return "symbol"; case P_UNKNOWN: break; } From a9d83d74783b00f9189c14180f77bbed133b092c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 21:48:50 +0900 Subject: [PATCH 11/51] kbuild: split x*alloc() functions in kconfig to scripts/include/xalloc.h These functions will be useful for other host programs. Signed-off-by: Masahiro Yamada --- scripts/include/xalloc.h | 53 ++++++++++++++++++++++++++++++++++++ scripts/kconfig/confdata.c | 1 + scripts/kconfig/expr.c | 1 + scripts/kconfig/lexer.l | 1 + scripts/kconfig/lkc.h | 5 ---- scripts/kconfig/mconf.c | 1 + scripts/kconfig/menu.c | 1 + scripts/kconfig/nconf.c | 1 + scripts/kconfig/nconf.gui.c | 1 + scripts/kconfig/parser.y | 1 + scripts/kconfig/preprocess.c | 1 + scripts/kconfig/qconf.cc | 1 + scripts/kconfig/symbol.c | 1 + scripts/kconfig/util.c | 50 +--------------------------------- 14 files changed, 65 insertions(+), 54 deletions(-) create mode 100644 scripts/include/xalloc.h diff --git a/scripts/include/xalloc.h b/scripts/include/xalloc.h new file mode 100644 index 000000000000..cdadb07d0592 --- /dev/null +++ b/scripts/include/xalloc.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XALLOC_H +#define XALLOC_H + +#include +#include + +static inline void *xmalloc(size_t size) +{ + void *p = malloc(size); + + if (!p) + exit(1); + return p; +} + +static inline void *xcalloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + + if (!p) + exit(1); + return p; +} + +static inline void *xrealloc(void *p, size_t size) +{ + p = realloc(p, size); + if (!p) + exit(1); + return p; +} + +static inline char *xstrdup(const char *s) +{ + char *p = strdup(s); + + if (!p) + exit(1); + return p; +} + +static inline char *xstrndup(const char *s, size_t n) +{ + char *p = strndup(s, n); + + if (!p) + exit(1); + return p; +} + +#endif /* XALLOC_H */ diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 76193ce5a792..d8849dfb06db 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -18,6 +18,7 @@ #include #include +#include #include "internal.h" #include "lkc.h" diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index c349da7fe3f8..a16451347f63 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -9,6 +9,7 @@ #include #include +#include #include "lkc.h" #define DEBUG_EXPR 0 diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 8dd597c4710d..9c2cdfc33c6f 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -13,6 +13,7 @@ #include #include +#include #include "lkc.h" #include "preprocess.h" diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 401bdf36323a..ddfb2b1cb737 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -53,11 +53,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) /* util.c */ unsigned int strhash(const char *s); const char *file_lookup(const char *name); -void *xmalloc(size_t size); -void *xcalloc(size_t nmemb, size_t size); -void *xrealloc(void *p, size_t size); -char *xstrdup(const char *s); -char *xstrndup(const char *s, size_t n); /* lexer.l */ int yylex(void); diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 3887eac75289..84ea9215c0a7 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -20,6 +20,7 @@ #include #include +#include #include "lkc.h" #include "lxdialog/dialog.h" #include "mnconf-common.h" diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 854edeb4d2db..f61327fabead 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -9,6 +9,7 @@ #include #include +#include #include "lkc.h" #include "internal.h" diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index b91ca47e9e9a..063b4f7ccbdb 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -12,6 +12,7 @@ #include #include +#include #include "lkc.h" #include "mnconf-common.h" #include "nconf.h" diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 25a7263ef3c8..72b605efe549 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -4,6 +4,7 @@ * * Derived from menuconfig. */ +#include #include "nconf.h" #include "lkc.h" diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 2d5e5ed56aba..1ad60f9e164e 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -11,6 +11,7 @@ #include #include +#include #include "lkc.h" #include "internal.h" #include "preprocess.h" diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index 67d1fb95c491..783abcaa5cc5 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -11,6 +11,7 @@ #include #include +#include #include "internal.h" #include "lkc.h" #include "preprocess.h" diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 88797d174261..97fce13e551e 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -22,6 +22,7 @@ #include +#include #include "lkc.h" #include "qconf.h" diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index d75665f3dfa2..6793f016af5e 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -9,6 +9,7 @@ #include #include +#include #include "internal.h" #include "lkc.h" diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 696ff477671e..50698fff5b9d 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -9,6 +9,7 @@ #include #include +#include #include "lkc.h" unsigned int strhash(const char *s) @@ -102,52 +103,3 @@ char *str_get(const struct gstr *gs) { return gs->s; } - -void *xmalloc(size_t size) -{ - void *p = malloc(size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -void *xcalloc(size_t nmemb, size_t size) -{ - void *p = calloc(nmemb, size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -void *xrealloc(void *p, size_t size) -{ - p = realloc(p, size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -char *xstrdup(const char *s) -{ - char *p; - - p = strdup(s); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -char *xstrndup(const char *s, size_t n) -{ - char *p; - - p = strndup(s, n); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} From 4c2598e3b62102d5ea7f618e13d996b069cde27d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 21:48:51 +0900 Subject: [PATCH 12/51] modpost: replace the use of NOFAIL() with xmalloc() etc. I think x*alloc() functions are cleaner. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 28 ++++++++++------------------ scripts/mod/modpost.h | 4 ---- scripts/mod/sumversion.c | 6 ++++-- scripts/mod/symsearch.c | 6 +++--- 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index bfd758ad9e4f..66bd89b2a8b6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -23,6 +23,7 @@ #include #include +#include #include "modpost.h" #include "../../include/linux/license.h" @@ -97,14 +98,6 @@ static inline bool strends(const char *str, const char *postfix) return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; } -void *do_nofail(void *ptr, const char *expr) -{ - if (!ptr) - fatal("Memory allocation failure: %s.\n", expr); - - return ptr; -} - char *read_text_file(const char *filename) { struct stat st; @@ -123,7 +116,7 @@ char *read_text_file(const char *filename) exit(1); } - buf = NOFAIL(malloc(st.st_size + 1)); + buf = xmalloc(st.st_size + 1); nbytes = st.st_size; @@ -181,7 +174,7 @@ static struct module *new_module(const char *name, size_t namelen) { struct module *mod; - mod = NOFAIL(malloc(sizeof(*mod) + namelen + 1)); + mod = xmalloc(sizeof(*mod) + namelen + 1); memset(mod, 0, sizeof(*mod)); INIT_LIST_HEAD(&mod->exported_symbols); @@ -240,7 +233,7 @@ static inline unsigned int tdb_hash(const char *name) **/ static struct symbol *alloc_symbol(const char *name) { - struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); + struct symbol *s = xmalloc(sizeof(*s) + strlen(name) + 1); memset(s, 0, sizeof(*s)); strcpy(s->name, name); @@ -313,8 +306,7 @@ static void add_namespace(struct list_head *head, const char *namespace) struct namespace_list *ns_entry; if (!contains_namespace(head, namespace)) { - ns_entry = NOFAIL(malloc(sizeof(*ns_entry) + - strlen(namespace) + 1)); + ns_entry = xmalloc(sizeof(*ns_entry) + strlen(namespace) + 1); strcpy(ns_entry->namespace, namespace); list_add_tail(&ns_entry->list, head); } @@ -369,7 +361,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod, s = alloc_symbol(name); s->module = mod; s->is_gpl_only = gpl_only; - s->namespace = NOFAIL(strdup(namespace)); + s->namespace = xstrdup(namespace); list_add_tail(&s->list, &mod->exported_symbols); hash_add_symbol(s); @@ -637,7 +629,7 @@ static void handle_symbol(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) break; if (symname[0] == '.') { - char *munged = NOFAIL(strdup(symname)); + char *munged = xstrdup(symname); munged[0] = '_'; munged[1] = toupper(munged[1]); symname = munged; @@ -1677,7 +1669,7 @@ void buf_write(struct buffer *buf, const char *s, int len) { if (buf->size - buf->pos < len) { buf->size += len + SZ; - buf->p = NOFAIL(realloc(buf->p, buf->size)); + buf->p = xrealloc(buf->p, buf->size); } strncpy(buf->p + buf->pos, s, len); buf->pos += len; @@ -1962,7 +1954,7 @@ static void write_if_changed(struct buffer *b, const char *fname) if (st.st_size != b->pos) goto close_write; - tmp = NOFAIL(malloc(b->pos)); + tmp = xmalloc(b->pos); if (fread(tmp, 1, b->pos, file) != b->pos) goto free_write; @@ -2167,7 +2159,7 @@ int main(int argc, char **argv) external_module = true; break; case 'i': - dl = NOFAIL(malloc(sizeof(*dl))); + dl = xmalloc(sizeof(*dl)); dl->file = optarg; list_add_tail(&dl->list, &dump_lists); break; diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 54ba9431713f..7fa8bdd801a9 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -65,12 +65,8 @@ #define TO_NATIVE(x) \ (target_is_big_endian == host_is_big_endian ? x : bswap(x)) -#define NOFAIL(ptr) do_nofail((ptr), #ptr) - #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -void *do_nofail(void *ptr, const char *expr); - struct buffer { char *p; int pos; diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index dc4878502276..e7d2da45b0df 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -8,6 +8,8 @@ #include #include #include + +#include #include "modpost.h" /* @@ -305,7 +307,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) const char *base; int dirlen, ret = 0, check_files = 0; - cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd"))); + cmd = xmalloc(strlen(objfile) + sizeof("..cmd")); base = strrchr(objfile, '/'); if (base) { @@ -316,7 +318,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md) dirlen = 0; sprintf(cmd, ".%s.cmd", objfile); } - dir = NOFAIL(malloc(dirlen + 1)); + dir = xmalloc(dirlen + 1); strncpy(dir, objfile, dirlen); dir[dirlen] = '\0'; diff --git a/scripts/mod/symsearch.c b/scripts/mod/symsearch.c index aa4ed51f9960..b9737b92f7f8 100644 --- a/scripts/mod/symsearch.c +++ b/scripts/mod/symsearch.c @@ -4,7 +4,7 @@ * Helper functions for finding the symbol in an ELF which is "nearest" * to a given address. */ - +#include #include "modpost.h" struct syminfo { @@ -125,8 +125,8 @@ void symsearch_init(struct elf_info *elf) { unsigned int table_size = symbol_count(elf); - elf->symsearch = NOFAIL(malloc(sizeof(struct symsearch) + - sizeof(struct syminfo) * table_size)); + elf->symsearch = xmalloc(sizeof(struct symsearch) + + sizeof(struct syminfo) * table_size); elf->symsearch->table_size = table_size; symsearch_populate(elf, elf->symsearch->table, table_size); From aeaa4283a309520c22a783071f554645943955d8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 21:48:52 +0900 Subject: [PATCH 13/51] kallsyms: use xmalloc() and xrealloc() When malloc() or realloc() fails, there is not much userspace programs can do. xmalloc() and xrealloc() are useful to bail out on a memory allocation failure. Signed-off-by: Masahiro Yamada --- scripts/kallsyms.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 123dab0572f8..c70458e68ece 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -27,6 +27,8 @@ #include #include +#include + #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) #define KSYM_NAME_LEN 512 @@ -168,12 +170,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len) * compressed together */ len++; - sym = malloc(sizeof(*sym) + len + 1); - if (!sym) { - fprintf(stderr, "kallsyms failure: " - "unable to allocate required amount of memory\n"); - exit(EXIT_FAILURE); - } + sym = xmalloc(sizeof(*sym) + len + 1); sym->addr = addr; sym->len = len; sym->sym[0] = type; @@ -278,12 +275,7 @@ static void read_map(const char *in) if (table_cnt >= table_size) { table_size += 10000; - table = realloc(table, sizeof(*table) * table_size); - if (!table) { - fprintf(stderr, "out of memory\n"); - fclose(fp); - exit (1); - } + table = xrealloc(table, sizeof(*table) * table_size); } table[table_cnt++] = sym; @@ -391,12 +383,7 @@ static void write_src(void) /* table of offset markers, that give the offset in the compressed stream * every 256 symbols */ markers_cnt = (table_cnt + 255) / 256; - markers = malloc(sizeof(*markers) * markers_cnt); - if (!markers) { - fprintf(stderr, "kallsyms failure: " - "unable to allocate required memory\n"); - exit(EXIT_FAILURE); - } + markers = xmalloc(sizeof(*markers) * markers_cnt); output_label("kallsyms_names"); off = 0; From a46078d651819c988d36379e8df68cb866eae747 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 12 Aug 2024 21:48:53 +0900 Subject: [PATCH 14/51] fixdep: use xmalloc() When malloc() fails, there is not much userspace programs can do. xmalloc() is useful to bail out on a memory allocation failure. Signed-off-by: Masahiro Yamada --- scripts/basic/fixdep.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 84b6efa849f4..cdd5da7e009b 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -99,6 +99,8 @@ #include #include +#include + static void usage(void) { fprintf(stderr, "Usage: fixdep \n"); @@ -131,12 +133,9 @@ static unsigned int strhash(const char *str, unsigned int sz) static void add_to_hashtable(const char *name, int len, unsigned int hash, struct item *hashtab[]) { - struct item *aux = malloc(sizeof(*aux) + len); + struct item *aux; - if (!aux) { - perror("fixdep:malloc"); - exit(1); - } + aux = xmalloc(sizeof(*aux) + len); memcpy(aux->name, name, len); aux->len = len; aux->hash = hash; @@ -228,11 +227,7 @@ static void *read_file(const char *filename) perror(filename); exit(2); } - buf = malloc(st.st_size + 1); - if (!buf) { - perror("fixdep: malloc"); - exit(2); - } + buf = xmalloc(st.st_size + 1); if (read(fd, buf, st.st_size) != st.st_size) { perror("fixdep: read"); exit(2); From 7a7f974594cd5d6723242cb8c018b59db16fe27b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 13 Aug 2024 01:54:51 +0900 Subject: [PATCH 15/51] modpost: improve the section mismatch warning format This commit improves the section mismatch warning format when there is no suitable symbol name to print. The section mismatch warning prints the reference source in the form of + and the reference destination in the form of . However, there are some corner cases where becomes "(unknown)", as reported in commit 23dfd914d2bf ("modpost: fix null pointer dereference"). In such cases, it is better to print the symbol address. Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 66bd89b2a8b6..704963cba5fe 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -697,10 +697,7 @@ static char *get_modinfo(struct elf_info *info, const char *tag) static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) { - if (sym) - return elf->strtab + sym->st_name; - else - return "(unknown)"; + return sym ? elf->strtab + sym->st_name : ""; } /* @@ -1013,6 +1010,7 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, Elf_Sym *from; const char *tosym; const char *fromsym; + char taddr_str[16]; from = find_fromsym(elf, faddr, fsecndx); fromsym = sym_name(elf, from); @@ -1026,10 +1024,17 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, sec_mismatch_count++; - warn("%s: section mismatch in reference: %s+0x%x (section: %s) -> %s (section: %s)\n", - modname, fromsym, - (unsigned int)(faddr - (from ? from->st_value : 0)), - fromsec, tosym, tosec); + if (!tosym[0]) + snprintf(taddr_str, sizeof(taddr_str), "0x%x", (unsigned int)taddr); + + /* + * The format for the reference source: + or
+ * The format for the reference destination: or
+ */ + warn("%s: section mismatch in reference: %s%s0x%x (section: %s) -> %s (section: %s)\n", + modname, fromsym, fromsym[0] ? "+" : "", + (unsigned int)(faddr - (fromsym[0] ? from->st_value : 0)), + fromsec, tosym[0] ? tosym : taddr_str, tosec); if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) { if (match(tosec, mismatch->bad_tosec)) From e6b65ee10588a552d04d488ebeac24bba20747a8 Mon Sep 17 00:00:00 2001 From: Jose Fernandez Date: Mon, 12 Aug 2024 19:16:19 -0600 Subject: [PATCH 16/51] kbuild: control extra pacman packages with PACMAN_EXTRAPACKAGES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the PACMAN_EXTRAPACKAGES variable in PKGBUILD to allow users to specify which additional packages are built by the pacman-pkg target. Previously, the api-headers package was always included, and the headers package was included only if CONFIG_MODULES=y. With this change, both headers and api-headers packages are included by default. Users can now control this behavior by setting PACMAN_EXTRAPACKAGES to a space-separated list of desired extra packages or leaving it empty to exclude all. For example, to build only the base package without extras: make pacman-pkg PACMAN_EXTRAPACKAGES="" Signed-off-by: Jose Fernandez Reviewed-by: Peter Jung Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor Reviewed-by: Christian Heusel Tested-by: Christian Heusel Acked-by: Thomas Weißschuh Signed-off-by: Masahiro Yamada --- scripts/package/PKGBUILD | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/package/PKGBUILD b/scripts/package/PKGBUILD index 663ce300dd06..fbd7eb10a52c 100644 --- a/scripts/package/PKGBUILD +++ b/scripts/package/PKGBUILD @@ -3,10 +3,13 @@ # Contributor: Jan Alexander Steffens (heftig) pkgbase=${PACMAN_PKGBASE:-linux-upstream} -pkgname=("${pkgbase}" "${pkgbase}-api-headers") -if grep -q CONFIG_MODULES=y include/config/auto.conf; then - pkgname+=("${pkgbase}-headers") -fi +pkgname=("${pkgbase}") + +_extrapackages=${PACMAN_EXTRAPACKAGES-headers api-headers} +for pkg in $_extrapackages; do + pkgname+=("${pkgbase}-${pkg}") +done + pkgver="${KERNELRELEASE//-/_}" # The PKGBUILD is evaluated multiple times. # Running scripts/build-version from here would introduce inconsistencies. @@ -77,10 +80,13 @@ _package-headers() { cd "${objtree}" local builddir="${pkgdir}/usr/${MODLIB}/build" - echo "Installing build files..." - "${srctree}/scripts/package/install-extmod-build" "${builddir}" + if grep -q CONFIG_MODULES=y include/config/auto.conf; then + echo "Installing build files..." + "${srctree}/scripts/package/install-extmod-build" "${builddir}" + fi echo "Installing System.map and config..." + mkdir -p "${builddir}" cp System.map "${builddir}/System.map" cp .config "${builddir}/.config" From b6223c2de6b0cade1e1d37490b304cb5df8d45d9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 16 Aug 2024 23:18:14 +0900 Subject: [PATCH 17/51] kbuild: pacman-pkg: move common commands to a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All build and package functions share the following commands: export MAKEFLAGS="${KBUILD_MAKEFLAGS}" cd "${objtree}" Factor out the common code. Signed-off-by: Masahiro Yamada Acked-by:  Thomas Weißschuh Reviewed-by: Nathan Chancellor Reviewed-by: Christian Heusel --- scripts/package/PKGBUILD | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/package/PKGBUILD b/scripts/package/PKGBUILD index fbd7eb10a52c..e2d9c2601ca9 100644 --- a/scripts/package/PKGBUILD +++ b/scripts/package/PKGBUILD @@ -36,11 +36,15 @@ makedepends=( ) options=(!debug !strip !buildflags !makeflags) -build() { +_prologue() { # MAKEFLAGS from makepkg.conf override the ones inherited from kbuild. # Bypass this override with a custom variable. export MAKEFLAGS="${KBUILD_MAKEFLAGS}" cd "${objtree}" +} + +build() { + _prologue ${MAKE} KERNELRELEASE="${KERNELRELEASE}" KBUILD_BUILD_VERSION="${pkgrel}" } @@ -48,10 +52,10 @@ build() { _package() { pkgdesc="The ${pkgdesc} kernel and modules" - export MAKEFLAGS="${KBUILD_MAKEFLAGS}" - cd "${objtree}" local modulesdir="${pkgdir}/usr/${MODLIB}" + _prologue + echo "Installing boot image..." # systemd expects to find the kernel here to allow hibernation # https://github.com/systemd/systemd/commit/edda44605f06a41fb86b7ab8128dcf99161d2344 @@ -76,10 +80,10 @@ _package() { _package-headers() { pkgdesc="Headers and scripts for building modules for the ${pkgdesc} kernel" - export MAKEFLAGS="${KBUILD_MAKEFLAGS}" - cd "${objtree}" local builddir="${pkgdir}/usr/${MODLIB}/build" + _prologue + if grep -q CONFIG_MODULES=y include/config/auto.conf; then echo "Installing build files..." "${srctree}/scripts/package/install-extmod-build" "${builddir}" @@ -100,8 +104,7 @@ _package-api-headers() { provides=(linux-api-headers) conflicts=(linux-api-headers) - export MAKEFLAGS="${KBUILD_MAKEFLAGS}" - cd "${objtree}" + _prologue ${MAKE} headers_install INSTALL_HDR_PATH="${pkgdir}/usr" } From 5b000f3cbb38c23992ee95fcd3e983ca66164eff Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 16 Aug 2024 23:18:15 +0900 Subject: [PATCH 18/51] kbuild: pacman-pkg: do not override objtree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit objtree is defined and exported by the top-level Makefile. I prefer not to override it. There is no need to pass the absolute path of objtree. PKGBUILD can detect it by itself. Signed-off-by: Masahiro Yamada Acked-by:  Thomas Weißschuh Reviewed-by: Nathan Chancellor Reviewed-by: Christian Heusel --- scripts/Makefile.package | 3 +-- scripts/package/PKGBUILD | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/Makefile.package b/scripts/Makefile.package index 4a80584ec771..11d53f240a2b 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -147,8 +147,7 @@ snap-pkg: PHONY += pacman-pkg pacman-pkg: @ln -srf $(srctree)/scripts/package/PKGBUILD $(objtree)/PKGBUILD - +objtree="$(realpath $(objtree))" \ - BUILDDIR="$(realpath $(objtree))/pacman" \ + +BUILDDIR="$(realpath $(objtree))/pacman" \ CARCH="$(UTS_MACHINE)" \ KBUILD_MAKEFLAGS="$(MAKEFLAGS)" \ KBUILD_REVISION="$(shell $(srctree)/scripts/build-version)" \ diff --git a/scripts/package/PKGBUILD b/scripts/package/PKGBUILD index e2d9c2601ca9..839cd5e634d2 100644 --- a/scripts/package/PKGBUILD +++ b/scripts/package/PKGBUILD @@ -40,7 +40,9 @@ _prologue() { # MAKEFLAGS from makepkg.conf override the ones inherited from kbuild. # Bypass this override with a custom variable. export MAKEFLAGS="${KBUILD_MAKEFLAGS}" - cd "${objtree}" + + # Kbuild works in the output directory, where this PKGBUILD is located. + cd "$(dirname "${BASH_SOURCE[0]}")" } build() { From 4079fe8e7b2b42b278e77dae7cb9d95e62c415a2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 16 Aug 2024 22:44:29 +0900 Subject: [PATCH 19/51] modpost: simplify modpost_log() With commit cda5f94e88b4 ("modpost: avoid using the alias attribute"), only two log levels remain: LOG_WARN and LOG_ERROR. Simplify this by making it a boolean variable. Signed-off-by: Masahiro Yamada Reviewed-by: Nathan Chancellor --- scripts/mod/modpost.c | 17 ++++++----------- scripts/mod/modpost.h | 11 +++-------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 704963cba5fe..c8cd5d822bb6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -67,20 +67,15 @@ static unsigned int nr_unresolved; #define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) -void modpost_log(enum loglevel loglevel, const char *fmt, ...) +void modpost_log(bool is_error, const char *fmt, ...) { va_list arglist; - switch (loglevel) { - case LOG_WARN: - fprintf(stderr, "WARNING: "); - break; - case LOG_ERROR: + if (is_error) { fprintf(stderr, "ERROR: "); error_occurred = true; - break; - default: /* invalid loglevel, ignore */ - break; + } else { + fprintf(stderr, "WARNING: "); } fprintf(stderr, "modpost: "); @@ -1689,7 +1684,7 @@ static void check_exports(struct module *mod) exp = find_symbol(s->name); if (!exp) { if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS) - modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, + modpost_log(!warn_unresolved, "\"%s\" [%s.ko] undefined!\n", s->name, mod->name); continue; @@ -1712,7 +1707,7 @@ static void check_exports(struct module *mod) basename = mod->name; if (!contains_namespace(&mod->imported_namespaces, exp->namespace)) { - modpost_log(allow_missing_ns_imports ? LOG_WARN : LOG_ERROR, + modpost_log(!allow_missing_ns_imports, "module %s uses symbol %s from namespace %s, but does not import it.\n", basename, exp->name, exp->namespace); add_namespace(&mod->missing_namespaces, exp->namespace); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 7fa8bdd801a9..ada3a36cc4bc 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -182,13 +182,8 @@ char *read_text_file(const char *filename); char *get_line(char **stringp); void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym); -enum loglevel { - LOG_WARN, - LOG_ERROR, -}; - void __attribute__((format(printf, 2, 3))) -modpost_log(enum loglevel loglevel, const char *fmt, ...); +modpost_log(bool is_error, const char *fmt, ...); /* * warn - show the given message, then let modpost continue running, still @@ -203,6 +198,6 @@ modpost_log(enum loglevel loglevel, const char *fmt, ...); * fatal - show the given message, and bail out immediately. This should be * used when there is no point to continue running modpost. */ -#define warn(fmt, args...) modpost_log(LOG_WARN, fmt, ##args) -#define error(fmt, args...) modpost_log(LOG_ERROR, fmt, ##args) +#define warn(fmt, args...) modpost_log(false, fmt, ##args) +#define error(fmt, args...) modpost_log(true, fmt, ##args) #define fatal(fmt, args...) do { error(fmt, ##args); exit(1); } while (1) From 87af9388b4e0c2ce94275ab4bef7227550b30df3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 18 Aug 2024 17:37:29 +0900 Subject: [PATCH 20/51] kbuild: remove *.symversions left-over Commit 5ce2176b81f7 ("genksyms: adjust the output format to modpost") stopped generating *.symversions files. Remove the left-over from the .gitignore file and the 'clean' rule. Signed-off-by: Masahiro Yamada Reviewed-by: Nathan Chancellor --- .gitignore | 1 - Makefile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 58fdbb35e2f1..c06a3ef6d6c6 100644 --- a/.gitignore +++ b/.gitignore @@ -46,7 +46,6 @@ *.so.dbg *.su *.symtypes -*.symversions *.tab.[ch] *.tar *.xz diff --git a/Makefile b/Makefile index d57cfc6896b8..145112bf281a 100644 --- a/Makefile +++ b/Makefile @@ -1946,7 +1946,7 @@ clean: $(clean-dirs) -o -name '*.c.[012]*.*' \ -o -name '*.ll' \ -o -name '*.gcno' \ - -o -name '*.*.symversions' \) -type f -print \ + \) -type f -print \ -o -name '.tmp_*' -print \ | xargs rm -rf From d97eae80d57220477a02435e49b48ac6f01e289c Mon Sep 17 00:00:00 2001 From: Stephen Brennan Date: Fri, 23 Aug 2024 12:41:51 -0700 Subject: [PATCH 21/51] Documentation: kconfig: explicitly document missing prompt There are a few lines in the kbuild-language.rst document which obliquely reference the behavior of config options without prompts. But there is nothing in the obvious location that explicitly calls out that users cannot edit config options unless they have a prompt. Signed-off-by: Stephen Brennan Reviewed-by: Nathan Chancellor Signed-off-by: Masahiro Yamada --- Documentation/kbuild/kconfig-language.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/kbuild/kconfig-language.rst b/Documentation/kbuild/kconfig-language.rst index 71b38a7670f3..43037be96a16 100644 --- a/Documentation/kbuild/kconfig-language.rst +++ b/Documentation/kbuild/kconfig-language.rst @@ -70,7 +70,11 @@ applicable everywhere (see syntax). Every menu entry can have at most one prompt, which is used to display to the user. Optionally dependencies only for this prompt can be added - with "if". + with "if". If a prompt is not present, the config option is a non-visible + symbol, meaning its value cannot be directly changed by the user (such as + altering the value in ``.config``) and the option will not appear in any + config menus. Its value can only be set via "default" and "select" (see + below). - default value: "default" ["if" ] From 4929f5b95f6b20ae10f2c409fb2ca58253e73706 Mon Sep 17 00:00:00 2001 From: Jose Fernandez Date: Sat, 24 Aug 2024 16:07:56 -0600 Subject: [PATCH 22/51] kbuild: add debug package to pacman PKGBUILD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new debug package to the PKGBUILD for the pacman-pkg target. The debug package includes the non-stripped vmlinux file with debug symbols for kernel debugging and profiling. The file is installed at /usr/src/debug/${pkgbase}, with a symbolic link at /usr/lib/modules/$(uname -r)/build/vmlinux. The debug package is built by default. Signed-off-by: Jose Fernandez Reviewed-by: Peter Jung Acked-by: Thomas Weißschuh Signed-off-by: Masahiro Yamada --- scripts/package/PKGBUILD | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/package/PKGBUILD b/scripts/package/PKGBUILD index 839cd5e634d2..f83493838cf9 100644 --- a/scripts/package/PKGBUILD +++ b/scripts/package/PKGBUILD @@ -5,7 +5,7 @@ pkgbase=${PACMAN_PKGBASE:-linux-upstream} pkgname=("${pkgbase}") -_extrapackages=${PACMAN_EXTRAPACKAGES-headers api-headers} +_extrapackages=${PACMAN_EXTRAPACKAGES-headers api-headers debug} for pkg in $_extrapackages; do pkgname+=("${pkgbase}-${pkg}") done @@ -111,6 +111,19 @@ _package-api-headers() { ${MAKE} headers_install INSTALL_HDR_PATH="${pkgdir}/usr" } +_package-debug(){ + pkgdesc="Non-stripped vmlinux file for the ${pkgdesc} kernel" + + local debugdir="${pkgdir}/usr/src/debug/${pkgbase}" + local builddir="${pkgdir}/usr/${MODLIB}/build" + + _prologue + + install -Dt "${debugdir}" -m644 vmlinux + mkdir -p "${builddir}" + ln -sr "${debugdir}/vmlinux" "${builddir}/vmlinux" +} + for _p in "${pkgname[@]}"; do eval "package_$_p() { $(declare -f "_package${_p#$pkgbase}") From dde60e7d103bf6cf820b2c4c4bb5658bad1759a9 Mon Sep 17 00:00:00 2001 From: Tony Battersby Date: Thu, 29 Aug 2024 09:51:25 -0400 Subject: [PATCH 23/51] kbuild: remove recent dependency on "truncate" program Remove the recently-added dependency on the truncate program for building the kernel. truncate is not available when building the kernel under Yocto. It could be added, but it would be better just to avoid the unnecessary dependency. Fixes: 1472464c6248 ("kbuild: avoid scripts/kallsyms parsing /dev/null") Signed-off-by: Tony Battersby Reviewed-by: Nathan Chancellor Signed-off-by: Masahiro Yamada --- scripts/link-vmlinux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 070a319140e8..c27b4e969f20 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -215,7 +215,7 @@ kallsymso= strip_debug= if is_enabled CONFIG_KALLSYMS; then - truncate -s0 .tmp_vmlinux.kallsyms0.syms + true > .tmp_vmlinux.kallsyms0.syms kallsyms .tmp_vmlinux.kallsyms0.syms .tmp_vmlinux0.kallsyms fi From cd615d7fcc7958107d1506c6eb5be50f4e920312 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 31 Aug 2024 19:10:28 +0900 Subject: [PATCH 24/51] ARC: update the help message for CONFIG_ARC_BUILTIN_DTB_NAME Commit abe11ddea1d7 ("ARC: [plat-arcfpga]: Enabling DeviceTree for Angel4 board") changed the default built-in DTB from "skeleton" to "angel4". Commit fd1557923b2e ("ARC: [plat_arcfpga]->[plat_sim]") changed it from "angel4" to "nsim_700". Signed-off-by: Masahiro Yamada Acked-by: Vineet Gupta --- arch/arc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index fd0b0a0d4686..d01e69a29b69 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -553,7 +553,7 @@ config ARC_BUILTIN_DTB_NAME string "Built in DTB" help Set the name of the DTB to embed in the vmlinux binary - Leaving it blank selects the minimal "skeleton" dtb + Leaving it blank selects the "nsim_700" dtb. endmenu # "ARC Architecture Configuration" From fdf94e4403ece60b29ef9e2da95e2fcefe50817f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 1 Sep 2024 19:55:21 +0200 Subject: [PATCH 25/51] kbuild: compile constant module information only once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various information about modules is compiled into the info sections. For that a dedicated .mod.c file is generated by modpost for each module and then linked into the module. However most of the information in the .mod.c is the same for all modules, internal and external. Split the shared information into a dedicated source file that is compiled once and then linked into all modules. This avoids frequent rebuilds for all .mod.c files when using CONFIG_LOCALVERSION_AUTO because the local version ends up in .mod.c through UTS_RELEASE and VERMAGIC_STRING. The modules are still relinked in this case. The code is also easier to maintain as it's now in a proper source file instead of an inline string literal. Signed-off-by: Thomas Weißschuh Signed-off-by: Masahiro Yamada --- scripts/Makefile.modfinal | 7 +++++-- scripts/mod/modpost.c | 23 ----------------------- scripts/module-common.c | 25 +++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 scripts/module-common.c diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 306a6bb86e4d..6b1b72257b29 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -30,6 +30,9 @@ 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 + $(call if_changed_dep,cc_o_c) + quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o += \ $(LD) -r $(KBUILD_LDFLAGS) \ @@ -54,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 scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),vmlinux) FORCE +%.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) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) endif -targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) +targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) $(extmod_prefix).module-common.o # Add FORCE to the prerequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index c8cd5d822bb6..107393a8c48a 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1755,26 +1755,9 @@ static void check_modname_len(struct module *mod) static void add_header(struct buffer *b, struct module *mod) { buf_printf(b, "#include \n"); - /* - * Include build-salt.h after module.h in order to - * inherit the definitions. - */ - buf_printf(b, "#define INCLUDE_VERMAGIC\n"); - buf_printf(b, "#include \n"); - buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); - buf_printf(b, "#include \n"); buf_printf(b, "#include \n"); buf_printf(b, "\n"); - buf_printf(b, "#ifdef CONFIG_UNWINDER_ORC\n"); - buf_printf(b, "#include \n"); - buf_printf(b, "ORC_HEADER;\n"); - buf_printf(b, "#endif\n"); - buf_printf(b, "\n"); - buf_printf(b, "BUILD_SALT;\n"); - buf_printf(b, "BUILD_LTO_INFO;\n"); - buf_printf(b, "\n"); - buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); buf_printf(b, "\n"); buf_printf(b, "__visible struct module __this_module\n"); @@ -1792,12 +1775,6 @@ static void add_header(struct buffer *b, struct module *mod) if (!external_module) buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); - buf_printf(b, - "\n" - "#ifdef CONFIG_MITIGATION_RETPOLINE\n" - "MODULE_INFO(retpoline, \"Y\");\n" - "#endif\n"); - if (strstarts(mod->name, "drivers/staging")) buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); diff --git a/scripts/module-common.c b/scripts/module-common.c new file mode 100644 index 000000000000..12fbc6d3aae8 --- /dev/null +++ b/scripts/module-common.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +/* + * Include build-salt.h after module.h in order to + * inherit the definitions. + */ +#define INCLUDE_VERMAGIC +#include +#include +#include + +#ifdef CONFIG_UNWINDER_ORC +#include +ORC_HEADER; +#endif + +BUILD_SALT; +BUILD_LTO_INFO; + +MODULE_INFO(vermagic, VERMAGIC_STRING); + +#ifdef CONFIG_MITIGATION_RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif From fc41a0a7498636ac0af7c37be80ca8571c2f4173 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 5 Sep 2024 08:47:37 +0900 Subject: [PATCH 26/51] kbuild: add intermediate targets for Flex/Bison in scripts/Makefile.host Flex and Bison are used only for host programs. Move their intermediate target processing from scripts/Makefile.build to scripts/Makefile.host. Signed-off-by: Masahiro Yamada --- scripts/Makefile.build | 35 ++++++++++++++++------------------- scripts/Makefile.host | 5 +++++ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/scripts/Makefile.build b/scripts/Makefile.build index a5ac8ed1936f..4b6942653093 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -41,20 +41,6 @@ include $(srctree)/scripts/Makefile.compiler include $(kbuild-file) include $(srctree)/scripts/Makefile.lib -# Do not include hostprogs rules unless needed. -# $(sort ...) is used here to remove duplicated words and excessive spaces. -hostprogs := $(sort $(hostprogs)) -ifneq ($(hostprogs),) -include $(srctree)/scripts/Makefile.host -endif - -# Do not include userprogs rules unless needed. -# $(sort ...) is used here to remove duplicated words and excessive spaces. -userprogs := $(sort $(userprogs)) -ifneq ($(userprogs),) -include $(srctree)/scripts/Makefile.userprogs -endif - ifndef obj $(warning kbuild: Makefile.build is included improperly) endif @@ -452,13 +438,24 @@ intermediate_targets = $(foreach sfx, $(2), \ # %.asn1.o <- %.asn1.[ch] <- %.asn1 # %.dtb.o <- %.dtb.S <- %.dtb <- %.dts # %.dtbo.o <- %.dtbo.S <- %.dtbo <- %.dtso -# %.lex.o <- %.lex.c <- %.l -# %.tab.o <- %.tab.[ch] <- %.y targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \ $(call intermediate_targets, .dtb.o, .dtb.S .dtb) \ - $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo) \ - $(call intermediate_targets, .lex.o, .lex.c) \ - $(call intermediate_targets, .tab.o, .tab.c .tab.h) + $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo) + +# Include additional build rules when necessary +# --------------------------------------------------------------------------- + +# $(sort ...) is used here to remove duplicated words and excessive spaces. +hostprogs := $(sort $(hostprogs)) +ifneq ($(hostprogs),) +include $(srctree)/scripts/Makefile.host +endif + +# $(sort ...) is used here to remove duplicated words and excessive spaces. +userprogs := $(sort $(userprogs)) +ifneq ($(userprogs),) +include $(srctree)/scripts/Makefile.userprogs +endif # Build # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.host b/scripts/Makefile.host index e85be7721a48..e01c13a588dd 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -160,3 +160,8 @@ $(host-rust): $(obj)/%: $(src)/%.rs FORCE targets += $(host-csingle) $(host-cmulti) $(host-cobjs) \ $(host-cxxmulti) $(host-cxxobjs) $(host-rust) + +# %.lex.o <- %.lex.c <- %.l +# %.tab.o <- %.tab.[ch] <- %.y +targets += $(call intermediate_targets, .lex.o, .lex.c) \ + $(call intermediate_targets, .tab.o, .tab.c .tab.h) From e7e2941300d258d551dda6ca9a370e29e085fa73 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 5 Sep 2024 08:47:38 +0900 Subject: [PATCH 27/51] kbuild: split device tree build rules into scripts/Makefile.dtbs scripts/Makefile.lib is included not only from scripts/Makefile.build but also from scripts/Makefile.{modfinal,package,vmlinux,vmlinux_o}, where DT build rules are not required. Split the DT build rules out to scripts/Makefile.dtbs, and include it only when necessary. While I was here, I added $(DT_TMP_SCHEMA) as a prerequisite of $(multi-dtb-y). Signed-off-by: Masahiro Yamada Reviewed-by: Rob Herring (Arm) --- drivers/of/fdt.c | 2 +- drivers/of/unittest.c | 4 +- scripts/Makefile.build | 25 +++----- scripts/Makefile.dtbs | 142 +++++++++++++++++++++++++++++++++++++++++ scripts/Makefile.lib | 115 --------------------------------- 5 files changed, 153 insertions(+), 135 deletions(-) create mode 100644 scripts/Makefile.dtbs diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 68103ad230ee..4d528c10df3a 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -34,7 +34,7 @@ /* * __dtb_empty_root_begin[] and __dtb_empty_root_end[] magically created by - * cmd_dt_S_dtb in scripts/Makefile.lib + * cmd_wrap_S_dtb in scripts/Makefile.dtbs */ extern uint8_t __dtb_empty_root_begin[]; extern uint8_t __dtb_empty_root_end[]; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index c830f346df45..fd8cb931b1cc 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1861,7 +1861,7 @@ static int __init unittest_data_add(void) struct device_node *unittest_data_node = NULL, *np; /* * __dtbo_testcases_begin[] and __dtbo_testcases_end[] are magically - * created by cmd_dt_S_dtbo in scripts/Makefile.lib + * created by cmd_wrap_S_dtbo in scripts/Makefile.dtbs */ extern uint8_t __dtbo_testcases_begin[]; extern uint8_t __dtbo_testcases_end[]; @@ -3525,7 +3525,7 @@ static void __init of_unittest_lifecycle(void) /* * __dtbo_##overlay_name##_begin[] and __dtbo_##overlay_name##_end[] are - * created by cmd_dt_S_dtbo in scripts/Makefile.lib + * created by cmd_wrap_S_dtbo in scripts/Makefile.dtbs */ #define OVERLAY_INFO_EXTERN(overlay_name) \ diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 4b6942653093..8403eba15457 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -57,7 +57,6 @@ endif # subdir-builtin and subdir-modorder may contain duplications. Use $(sort ...) subdir-builtin := $(sort $(filter %/built-in.a, $(real-obj-y))) subdir-modorder := $(sort $(filter %/modules.order, $(obj-m))) -subdir-dtbslist := $(sort $(filter %/dtbs-list, $(dtb-y))) targets-for-builtin := $(extra-y) @@ -349,7 +348,7 @@ $(obj)/%.o: $(obj)/%.S FORCE targets += $(filter-out $(subdir-builtin), $(real-obj-y)) targets += $(filter-out $(subdir-modorder), $(real-obj-m)) -targets += $(real-dtb-y) $(lib-y) $(always-y) +targets += $(lib-y) $(always-y) # Linker scripts preprocessor (.lds.S -> .lds) # --------------------------------------------------------------------------- @@ -375,7 +374,6 @@ $(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler # To build objects in subdirs, we need to descend into the directories $(subdir-builtin): $(obj)/%/built-in.a: $(obj)/% ; $(subdir-modorder): $(obj)/%/modules.order: $(obj)/% ; -$(subdir-dtbslist): $(obj)/%/dtbs-list: $(obj)/% ; # # Rule to compile a set of .o files into one .a file (without symbol table) @@ -391,12 +389,8 @@ quiet_cmd_ar_builtin = AR $@ $(obj)/built-in.a: $(real-obj-y) FORCE $(call if_changed,ar_builtin) -# -# Rule to create modules.order and dtbs-list -# -# This is a list of build artifacts (module or dtb) from the current Makefile -# and its sub-directories. The timestamp should be updated when any of the -# member files. +# This is a list of build artifacts from the current Makefile and its +# sub-directories. The timestamp should be updated when any of the member files. cmd_gen_order = { $(foreach m, $(real-prereqs), \ $(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \ @@ -405,9 +399,6 @@ cmd_gen_order = { $(foreach m, $(real-prereqs), \ $(obj)/modules.order: $(obj-m) FORCE $(call if_changed,gen_order) -$(obj)/dtbs-list: $(dtb-y) FORCE - $(call if_changed,gen_order) - # # Rule to compile a set of .o files into one .a file (with symbol table) # @@ -436,11 +427,7 @@ intermediate_targets = $(foreach sfx, $(2), \ $(patsubst %$(strip $(1)),%$(sfx), \ $(filter %$(strip $(1)), $(targets)))) # %.asn1.o <- %.asn1.[ch] <- %.asn1 -# %.dtb.o <- %.dtb.S <- %.dtb <- %.dts -# %.dtbo.o <- %.dtbo.S <- %.dtbo <- %.dtso -targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \ - $(call intermediate_targets, .dtb.o, .dtb.S .dtb) \ - $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo) +targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) # Include additional build rules when necessary # --------------------------------------------------------------------------- @@ -457,6 +444,10 @@ ifneq ($(userprogs),) include $(srctree)/scripts/Makefile.userprogs endif +ifneq ($(need-dtbslist)$(dtb-y)$(dtb-)$(filter %.dtb %.dtb.o %.dtbo.o,$(targets)),) +include $(srctree)/scripts/Makefile.dtbs +endif + # Build # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.dtbs b/scripts/Makefile.dtbs new file mode 100644 index 000000000000..46009d5f1486 --- /dev/null +++ b/scripts/Makefile.dtbs @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# If CONFIG_OF_ALL_DTBS is enabled, all DT blobs are built +dtb-$(CONFIG_OF_ALL_DTBS) += $(dtb-) + +# Composite DTB (i.e. DTB constructed by overlay) +multi-dtb-y := $(call multi-search, $(dtb-y), .dtb, -dtbs) +# Primitive DTB compiled from *.dts +real-dtb-y := $(call real-search, $(dtb-y), .dtb, -dtbs) +# Base DTB that overlay is applied onto +base-dtb-y := $(filter %.dtb, $(call real-search, $(multi-dtb-y), .dtb, -dtbs)) + +dtb-y := $(addprefix $(obj)/, $(dtb-y)) +multi-dtb-y := $(addprefix $(obj)/, $(multi-dtb-y)) +real-dtb-y := $(addprefix $(obj)/, $(real-dtb-y)) + +always-y += $(dtb-y) +targets += $(real-dtb-y) + +# dtbs-list +# --------------------------------------------------------------------------- + +ifdef need-dtbslist +subdir-dtbslist := $(addsuffix /dtbs-list, $(subdir-ym)) +dtb-y += $(subdir-dtbslist) +always-y += $(obj)/dtbs-list +endif + +$(subdir-dtbslist): $(obj)/%/dtbs-list: $(obj)/% ; + +$(obj)/dtbs-list: $(dtb-y) FORCE + $(call if_changed,gen_order) + +# Assembly file to wrap dtb(o) +# --------------------------------------------------------------------------- + +# Generate an assembly file to wrap the output of the device tree compiler +quiet_cmd_wrap_S_dtb = WRAP $@ + cmd_wrap_S_dtb = { \ + symbase=__$(patsubst .%,%,$(suffix $<))_$(subst -,_,$(notdir $*)); \ + echo '\#include '; \ + echo '.section .dtb.init.rodata,"a"'; \ + echo '.balign STRUCT_ALIGNMENT'; \ + echo ".global $${symbase}_begin"; \ + echo "$${symbase}_begin:"; \ + echo '.incbin "$<" '; \ + echo ".global $${symbase}_end"; \ + echo "$${symbase}_end:"; \ + echo '.balign STRUCT_ALIGNMENT'; \ + } > $@ + +$(obj)/%.dtb.S: $(obj)/%.dtb FORCE + $(call if_changed,wrap_S_dtb) + +$(obj)/%.dtbo.S: $(obj)/%.dtbo FORCE + $(call if_changed,wrap_S_dtb) + +# Schema check +# --------------------------------------------------------------------------- + +ifneq ($(CHECK_DTBS),) +DT_CHECKER ?= dt-validate +DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),-l $(DT_SCHEMA_FILES),-m) +DT_BINDING_DIR := Documentation/devicetree/bindings +DT_TMP_SCHEMA := $(objtree)/$(DT_BINDING_DIR)/processed-schema.json +dtb-check-enabled = $(if $(filter %.dtb, $@),y) +endif + +quiet_dtb_check_tag = $(if $(dtb-check-enabled),[C], ) +cmd_dtb_check = $(if $(dtb-check-enabled),; $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ || true) + +# Overlay +# --------------------------------------------------------------------------- + +# NOTE: +# Do not replace $(filter %.dtb %.dtbo, $^) with $(real-prereqs). When a single +# DTB is turned into a multi-blob DTB, $^ will contain header file dependencies +# recorded in the .*.cmd file. +quiet_cmd_fdtoverlay = OVL $(quiet_dtb_check_tag) $@ + cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(filter %.dtb %.dtbo, $^) $(cmd_dtb_check) + +$(multi-dtb-y): $(DT_TMP_SCHEMA) FORCE + $(call if_changed,fdtoverlay) +$(call multi_depend, $(multi-dtb-y), .dtb, -dtbs) + +# DTC +# --------------------------------------------------------------------------- + +DTC ?= $(objtree)/scripts/dtc/dtc +DTC_FLAGS += -Wno-unique_unit_address + +# Disable noisy checks by default +ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) +DTC_FLAGS += -Wno-unit_address_vs_reg \ + -Wno-avoid_unnecessary_addr_size \ + -Wno-alias_paths \ + -Wno-graph_child_address \ + -Wno-simple_bus_reg +else +DTC_FLAGS += -Wunique_unit_address_if_enabled +endif + +ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),) +DTC_FLAGS += -Wnode_name_chars_strict \ + -Wproperty_name_chars_strict \ + -Wunique_unit_address +endif + +DTC_FLAGS += $(DTC_FLAGS_$(target-stem)) + +# Set -@ if the target is a base DTB that overlay is applied onto +DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@) + +DTC_INCLUDE := $(srctree)/scripts/dtc/include-prefixes + +dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc -I $(DTC_INCLUDE) -undef -D__DTS__ + +dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) + +quiet_cmd_dtc = DTC $(quiet_dtb_check_tag) $@ + cmd_dtc = \ + $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ + $(DTC) -o $@ -b 0 $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) \ + $(DTC_FLAGS) -d $(depfile).dtc.tmp $(dtc-tmp) ; \ + cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) \ + $(cmd_dtb_check) + +$(obj)/%.dtb: $(obj)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE + $(call if_changed_dep,dtc) + +$(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE + $(call if_changed_dep,dtc) + +# targets +# --------------------------------------------------------------------------- + +targets += $(always-y) + +# %.dtb.o <- %.dtb.S <- %.dtb <- %.dts +# %.dtbo.o <- %.dtbo.S <- %.dtbo <- %.dtso +targets += $(call intermediate_targets, .dtb.o, .dtb.S .dtb) \ + $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 207325eaf1d1..4fea9e9bec3c 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -45,11 +45,6 @@ else obj-y := $(filter-out %/, $(obj-y)) endif -ifdef need-dtbslist -dtb-y += $(addsuffix /dtbs-list, $(subdir-ym)) -always-y += dtbs-list -endif - # Expand $(foo-objs) $(foo-y) etc. by replacing their individuals suffix-search = $(strip $(foreach s, $3, $($(1:%$(strip $2)=%$s)))) # List composite targets that are constructed by combining other targets @@ -80,19 +75,6 @@ always-y += $(hostprogs-always-y) $(hostprogs-always-m) userprogs += $(userprogs-always-y) $(userprogs-always-m) always-y += $(userprogs-always-y) $(userprogs-always-m) -# DTB -# If CONFIG_OF_ALL_DTBS is enabled, all DT blobs are built -dtb-$(CONFIG_OF_ALL_DTBS) += $(dtb-) - -# Composite DTB (i.e. DTB constructed by overlay) -multi-dtb-y := $(call multi-search, $(dtb-y), .dtb, -dtbs) -# Primitive DTB compiled from *.dts -real-dtb-y := $(call real-search, $(dtb-y), .dtb, -dtbs) -# Base DTB that overlay is applied onto -base-dtb-y := $(filter %.dtb, $(call real-search, $(multi-dtb-y), .dtb, -dtbs)) - -always-y += $(dtb-y) - # Add subdir path ifneq ($(obj),.) @@ -104,9 +86,6 @@ lib-y := $(addprefix $(obj)/,$(lib-y)) real-obj-y := $(addprefix $(obj)/,$(real-obj-y)) real-obj-m := $(addprefix $(obj)/,$(real-obj-m)) multi-obj-m := $(addprefix $(obj)/, $(multi-obj-m)) -dtb-y := $(addprefix $(obj)/, $(dtb-y)) -multi-dtb-y := $(addprefix $(obj)/, $(multi-dtb-y)) -real-dtb-y := $(addprefix $(obj)/, $(real-dtb-y)) subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) endif @@ -255,12 +234,6 @@ cpp_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ ld_flags = $(KBUILD_LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) -DTC_INCLUDE := $(srctree)/scripts/dtc/include-prefixes - -dtc_cpp_flags = -Wp,-MMD,$(depfile).pre.tmp -nostdinc \ - $(addprefix -I,$(DTC_INCLUDE)) \ - -undef -D__DTS__ - ifdef CONFIG_OBJTOOL objtool := $(objtree)/tools/objtool/objtool @@ -350,94 +323,6 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ quiet_cmd_gzip = GZIP $@ cmd_gzip = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@ -# DTC -# --------------------------------------------------------------------------- -DTC ?= $(objtree)/scripts/dtc/dtc -DTC_FLAGS += \ - -Wno-unique_unit_address - -# Disable noisy checks by default -ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),) -DTC_FLAGS += -Wno-unit_address_vs_reg \ - -Wno-avoid_unnecessary_addr_size \ - -Wno-alias_paths \ - -Wno-graph_child_address \ - -Wno-simple_bus_reg -else -DTC_FLAGS += \ - -Wunique_unit_address_if_enabled -endif - -ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),) -DTC_FLAGS += -Wnode_name_chars_strict \ - -Wproperty_name_chars_strict \ - -Wunique_unit_address -endif - -DTC_FLAGS += $(DTC_FLAGS_$(target-stem)) - -# Set -@ if the target is a base DTB that overlay is applied onto -DTC_FLAGS += $(if $(filter $(patsubst $(obj)/%,%,$@), $(base-dtb-y)), -@) - -# Generate an assembly file to wrap the output of the device tree compiler -quiet_cmd_wrap_S_dtb = WRAP $@ - cmd_wrap_S_dtb = { \ - symbase=__$(patsubst .%,%,$(suffix $<))_$(subst -,_,$(notdir $*)); \ - echo '\#include '; \ - echo '.section .dtb.init.rodata,"a"'; \ - echo '.balign STRUCT_ALIGNMENT'; \ - echo ".global $${symbase}_begin"; \ - echo "$${symbase}_begin:"; \ - echo '.incbin "$<" '; \ - echo ".global $${symbase}_end"; \ - echo "$${symbase}_end:"; \ - echo '.balign STRUCT_ALIGNMENT'; \ - } > $@ - -$(obj)/%.dtb.S: $(obj)/%.dtb FORCE - $(call if_changed,wrap_S_dtb) - -$(obj)/%.dtbo.S: $(obj)/%.dtbo FORCE - $(call if_changed,wrap_S_dtb) - -quiet_dtb_check_tag = $(if $(dtb-check-enabled),[C], ) -cmd_dtb_check = $(if $(dtb-check-enabled),; $(DT_CHECKER) $(DT_CHECKER_FLAGS) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ || true) - -quiet_cmd_dtc = DTC $(quiet_dtb_check_tag) $@ -cmd_dtc = $(HOSTCC) -E $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ - $(DTC) -o $@ -b 0 \ - $(addprefix -i,$(dir $<) $(DTC_INCLUDE)) $(DTC_FLAGS) \ - -d $(depfile).dtc.tmp $(dtc-tmp) ; \ - cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) \ - $(cmd_dtb_check) - -# NOTE: -# Do not replace $(filter %.dtb %.dtbo, $^) with $(real-prereqs). When a single -# DTB is turned into a multi-blob DTB, $^ will contain header file dependencies -# recorded in the .*.cmd file. -quiet_cmd_fdtoverlay = OVL $(quiet_dtb_check_tag) $@ - cmd_fdtoverlay = $(objtree)/scripts/dtc/fdtoverlay -o $@ -i $(filter %.dtb %.dtbo, $^) $(cmd_dtb_check) - -$(multi-dtb-y): FORCE - $(call if_changed,fdtoverlay) -$(call multi_depend, $(multi-dtb-y), .dtb, -dtbs) - -ifneq ($(CHECK_DTBS),) -DT_CHECKER ?= dt-validate -DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),-l $(DT_SCHEMA_FILES),-m) -DT_BINDING_DIR := Documentation/devicetree/bindings -DT_TMP_SCHEMA := $(objtree)/$(DT_BINDING_DIR)/processed-schema.json -dtb-check-enabled = $(if $(filter %.dtb, $@),y) -endif - -$(obj)/%.dtb: $(obj)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE - $(call if_changed_dep,dtc) - -$(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE - $(call if_changed_dep,dtc) - -dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) - # Bzip2 # --------------------------------------------------------------------------- From 16ff3f606c7e639d815ede92c258b63484242783 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 5 Sep 2024 08:54:48 +0900 Subject: [PATCH 28/51] scripts: import more hash table macros Add more macros used for removing hash table entries. Signed-off-by: Masahiro Yamada --- scripts/include/hashtable.h | 50 +++++++++++++++++++++++++++ scripts/include/list.h | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/scripts/include/hashtable.h b/scripts/include/hashtable.h index a0a2c8f5f639..45abcb12bfce 100644 --- a/scripts/include/hashtable.h +++ b/scripts/include/hashtable.h @@ -15,6 +15,23 @@ #define hash_head(table, key) (&(table)[(key) % HASH_SIZE(table)]) +static inline void __hash_init(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + INIT_HLIST_HEAD(&ht[i]); +} + +/** + * hash_init - initialize a hash table + * @table: hashtable to be initialized + * + * This has to be a macro since HASH_SIZE() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_init(table) __hash_init(table, HASH_SIZE(table)) + /** * hash_add - add an object to a hashtable * @table: hashtable to add to @@ -24,6 +41,15 @@ #define hash_add(table, node, key) \ hlist_add_head(node, hash_head(table, key)) +/** + * hash_del - remove an object from a hashtable + * @node: &struct hlist_node of the object to remove + */ +static inline void hash_del(struct hlist_node *node) +{ + hlist_del_init(node); +} + /** * hash_for_each - iterate over a hashtable * @table: hashtable to iterate @@ -34,6 +60,18 @@ for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \ hlist_for_each_entry(obj, &table[_bkt], member) +/** + * hash_for_each_safe - iterate over a hashtable safe against removal of + * hash entry + * @table: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @tmp: a &struct hlist_node used for temporary storage + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each_safe(table, obj, tmp, member) \ + for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \ + hlist_for_each_entry_safe(obj, tmp, &table[_bkt], member) + /** * hash_for_each_possible - iterate over all possible objects hashing to the * same bucket @@ -45,4 +83,16 @@ #define hash_for_each_possible(table, obj, member, key) \ hlist_for_each_entry(obj, hash_head(table, key), member) +/** + * hash_for_each_possible_safe - iterate over all possible objects hashing to the + * same bucket safe against removals + * @table: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @tmp: a &struct hlist_node used for temporary storage + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible_safe(table, obj, tmp, member, key) \ + hlist_for_each_entry_safe(obj, tmp, hash_head(table, key), member) + #endif /* HASHTABLE_H */ diff --git a/scripts/include/list.h b/scripts/include/list.h index 409201cd495b..fea1e2b79063 100644 --- a/scripts/include/list.h +++ b/scripts/include/list.h @@ -268,6 +268,63 @@ static inline int list_empty(const struct list_head *head) */ #define HLIST_HEAD_INIT { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +/** + * hlist_unhashed - Has node been removed from list and reinitialized? + * @h: Node to be checked + * + * Not that not all removal functions will leave a node in unhashed + * state. For example, hlist_nulls_del_init_rcu() does leave the + * node in unhashed state, but hlist_nulls_del() does not. + */ +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + + *pprev = next; + if (next) + next->pprev = pprev; +} + +/** + * hlist_del - Delete the specified hlist_node from its list + * @n: Node to delete. + * + * Note that this function leaves the node in hashed state. Use + * hlist_del_init() or similar instead to unhash @n. + */ +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_init - Delete the specified hlist_node from its list and initialize + * @n: Node to delete. + * + * Note that this function leaves the node in unhashed state. + */ +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} /** * hlist_add_head - add a new entry at the beginning of the hlist @@ -306,4 +363,16 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) pos; \ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: a &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(pos, n, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ + pos && ({ n = pos->member.next; 1; }); \ + pos = hlist_entry_safe(n, typeof(*pos), member)) + #endif /* LIST_H */ From 8a62d44588451095fd6645d6ed7ff8761edf62aa Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 6 Sep 2024 13:01:28 +0200 Subject: [PATCH 29/51] scripts: subarch.include: fix SUBARCH on macOS hosts When building the Linux kernel on an aarch64 macOS based host, if we don't specify a value for ARCH when invoking make, we default to arm and thus multi_v7_defconfig rather than the expected arm64 and arm64's defconfig. This is because subarch.include invokes `uname -m` which on MacOS hosts evaluates to `arm64` but on Linux hosts evaluates to `aarch64`, This allows us to build ARCH=arm64 natively on macOS (as in ARCH need not be specified on an aarch64-based system). Avoid matching arm64 by excluding it from the arm.* sed expression. Signed-off-by: Nick Desaulniers Suggested-by: Nicolas Schier Signed-off-by: Daniel Gomez Signed-off-by: Masahiro Yamada --- scripts/subarch.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/subarch.include b/scripts/subarch.include index 4bd327d0ae42..c4592d59d69b 100644 --- a/scripts/subarch.include +++ b/scripts/subarch.include @@ -6,7 +6,7 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e s/sun4u/sparc64/ \ - -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e /^arm64$$/!s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ From 23d93aa4b3b90b6e3dc8e6b6bb36580c1068bc07 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Fri, 6 Sep 2024 10:45:02 -0400 Subject: [PATCH 30/51] kbuild: add mod(name,file)_flags to assembler flags for module objects In order to create the file at build time, modules.builtin.ranges, that contains the range of addresses for all built-in modules, there needs to be a way to identify what code is compiled into modules. To identify what code is compiled into modules during a kernel build, one can look for the presence of the -DKBUILD_MODFILE and -DKBUILD_MODNAME options in the compile command lines. A simple grep in .*.cmd files for those options is sufficient for this. Unfortunately, these options are only passed when compiling C source files. Various modules also include objects built from assembler source, and these options are not passed in that case. Adding $(modfile_flags) to modkern_aflags (similar to modkern_cflags), and adding $(modname_flags) to a_flags (similar to c_flags) makes it possible to identify which objects are compiled into modules for both C and assembler source files. While KBUILD_MODFILE is sufficient to generate the modules ranges data, KBUILD_MODNAME is passed as well for consistency with the C source code case. Signed-off-by: Kris Van Hees Reviewed-by: Steven Rostedt (Google) Tested-by: Sam James Reviewed-by: Sami Tolvanen Tested-by: Sami Tolvanen Signed-off-by: Masahiro Yamada --- scripts/Makefile.lib | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 4fea9e9bec3c..1bdd77f42289 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -217,7 +217,7 @@ modkern_rustflags = \ modkern_aflags = $(if $(part-of-module), \ $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE), \ - $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)) + $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL) $(modfile_flags)) c_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ -include $(srctree)/include/linux/compiler_types.h \ @@ -227,7 +227,7 @@ c_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ rust_flags = $(_rust_flags) $(modkern_rustflags) @$(objtree)/include/generated/rustc_cfg a_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ - $(_a_flags) $(modkern_aflags) + $(_a_flags) $(modkern_aflags) $(modname_flags) cpp_flags = -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ $(_cpp_flags) From 5f5e7344322f0b0676579af054c787ed57d1c1df Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Fri, 6 Sep 2024 10:45:03 -0400 Subject: [PATCH 31/51] kbuild: generate offset range data for builtin modules Create file module.builtin.ranges that can be used to find where built-in modules are located by their addresses. This will be useful for tracing tools to find what functions are for various built-in modules. The offset range data for builtin modules is generated using: - modules.builtin: associates object files with module names - vmlinux.map: provides load order of sections and offset of first member per section - vmlinux.o.map: provides offset of object file content per section - .*.cmd: build cmd file with KBUILD_MODFILE The generated data will look like: .text 00000000-00000000 = _text .text 0000baf0-0000cb10 amd_uncore .text 0009bd10-0009c8e0 iosf_mbi ... .text 00b9f080-00ba011a intel_skl_int3472_discrete .text 00ba0120-00ba03c0 intel_skl_int3472_discrete intel_skl_int3472_tps68470 .text 00ba03c0-00ba08d6 intel_skl_int3472_tps68470 ... .data 00000000-00000000 = _sdata .data 0000f020-0000f680 amd_uncore For each ELF section, it lists the offset of the first symbol. This can be used to determine the base address of the section at runtime. Next, it lists (in strict ascending order) offset ranges in that section that cover the symbols of one or more builtin modules. Multiple ranges can apply to a single module, and ranges can be shared between modules. The CONFIG_BUILTIN_MODULE_RANGES option controls whether offset range data is generated for kernel modules that are built into the kernel image. How it works: 1. The modules.builtin file is parsed to obtain a list of built-in module names and their associated object names (the .ko file that the module would be in if it were a loadable module, hereafter referred to as ). This object name can be used to identify objects in the kernel compile because any C or assembler code that ends up into a built-in module will have the option -DKBUILD_MODFILE= present in its build command, and those can be found in the ..cmd file in the kernel build tree. If an object is part of multiple modules, they will all be listed in the KBUILD_MODFILE option argument. This allows us to conclusively determine whether an object in the kernel build belong to any modules, and which. 2. The vmlinux.map is parsed next to determine the base address of each top level section so that all addresses into the section can be turned into offsets. This makes it possible to handle sections getting loaded at different addresses at system boot. We also determine an 'anchor' symbol at the beginning of each section to make it possible to calculate the true base address of a section at runtime (i.e. symbol address - symbol offset). We collect start addresses of sections that are included in the top level section. This is used when vmlinux is linked using vmlinux.o, because in that case, we need to look at the vmlinux.o linker map to know what object a symbol is found in. And finally, we process each symbol that is listed in vmlinux.map (or vmlinux.o.map) based on the following structure: vmlinux linked from vmlinux.a: vmlinux.map: -- might be same as top level section) -- built-in association known -- belongs to module(s) object belongs to ... vmlinux linked from vmlinux.o: vmlinux.map: -- might be same as top level section) vmlinux.o -- need to use vmlinux.o.map -- ignored ... vmlinux.o.map:
-- built-in association known -- belongs to module(s) object belongs to ... 3. As sections, objects, and symbols are processed, offset ranges are constructed in a straight-forward way: - If the symbol belongs to one or more built-in modules: - If we were working on the same module(s), extend the range to include this object - If we were working on another module(s), close that range, and start the new one - If the symbol does not belong to any built-in modules: - If we were working on a module(s) range, close that range Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Reviewed-by: Alan Maguire Reviewed-by: Steven Rostedt (Google) Tested-by: Sam James Reviewed-by: Sami Tolvanen Tested-by: Sami Tolvanen Signed-off-by: Masahiro Yamada --- .gitignore | 1 + Documentation/dontdiff | 1 + Documentation/kbuild/kbuild.rst | 5 + Documentation/process/changes.rst | 7 + Makefile | 1 + lib/Kconfig.debug | 15 + scripts/Makefile.vmlinux | 18 + scripts/Makefile.vmlinux_o | 3 + scripts/generate_builtin_ranges.awk | 508 ++++++++++++++++++++++++++++ 9 files changed, 559 insertions(+) create mode 100755 scripts/generate_builtin_ranges.awk diff --git a/.gitignore b/.gitignore index c06a3ef6d6c6..625bf59ad845 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ modules.order /Module.markers /modules.builtin /modules.builtin.modinfo +/modules.builtin.ranges /modules.nsdeps # diff --git a/Documentation/dontdiff b/Documentation/dontdiff index 3c399f132e2d..a867aea95c40 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -180,6 +180,7 @@ modpost modules-only.symvers modules.builtin modules.builtin.modinfo +modules.builtin.ranges modules.nsdeps modules.order modversions.h* diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst index 9c8d1d046ea5..a0f7726c46f8 100644 --- a/Documentation/kbuild/kbuild.rst +++ b/Documentation/kbuild/kbuild.rst @@ -22,6 +22,11 @@ modules.builtin.modinfo This file contains modinfo from all modules that are built into the kernel. Unlike modinfo of a separate module, all fields are prefixed with module name. +modules.builtin.ranges +---------------------- +This file contains address offset ranges (per ELF section) for all modules +that are built into the kernel. Together with System.map, it can be used +to associate module names with symbols. Environment variables ===================== diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 3fc63f27c226..00f1ed7c59c3 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -64,6 +64,7 @@ GNU tar 1.28 tar --version gtags (optional) 6.6.5 gtags --version mkimage (optional) 2017.01 mkimage --version Python (optional) 3.5.x python3 --version +GNU AWK (optional) 5.1.0 gawk --version ====================== =============== ======================================== .. [#f1] Sphinx is needed only to build the Kernel documentation @@ -192,6 +193,12 @@ platforms. The tool is available via the ``u-boot-tools`` package or can be built from the U-Boot source code. See the instructions at https://docs.u-boot.org/en/latest/build/tools.html#building-tools-for-linux +GNU AWK +------- + +GNU AWK is needed if you want kernel builds to generate address range data for +builtin modules (CONFIG_BUILTIN_MODULE_RANGES). + System utilities **************** diff --git a/Makefile b/Makefile index 145112bf281a..b4a941a30c73 100644 --- a/Makefile +++ b/Makefile @@ -1482,6 +1482,7 @@ endif # CONFIG_MODULES # Directories & files removed with 'make clean' 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 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index a30c03a66172..5e2f30921cb2 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -571,6 +571,21 @@ config VMLINUX_MAP pieces of code get eliminated with CONFIG_LD_DEAD_CODE_DATA_ELIMINATION. +config BUILTIN_MODULE_RANGES + bool "Generate address range information for builtin modules" + depends on !LTO + depends on VMLINUX_MAP + help + When modules are built into the kernel, there will be no module name + associated with its symbols in /proc/kallsyms. Tracers may want to + identify symbols by module name and symbol name regardless of whether + the module is configured as loadable or not. + + This option generates modules.builtin.ranges in the build tree with + offset ranges (per ELF section) for the module(s) they belong to. + It also records an anchor symbol to determine the load address of the + section. + config DEBUG_FORCE_WEAK_PER_CPU bool "Force weak per-cpu definitions" depends on DEBUG_KERNEL diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index 5ceecbed31eb..1284f05555b9 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -33,6 +33,24 @@ targets += vmlinux vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE +$(call if_changed_dep,link_vmlinux) +# module.builtin.ranges +# --------------------------------------------------------------------------- +ifdef CONFIG_BUILTIN_MODULE_RANGES +__default: modules.builtin.ranges + +quiet_cmd_modules_builtin_ranges = GEN $@ + cmd_modules_builtin_ranges = gawk -f $(real-prereqs) > $@ + +targets += modules.builtin.ranges +modules.builtin.ranges: $(srctree)/scripts/generate_builtin_ranges.awk \ + modules.builtin vmlinux.map vmlinux.o.map FORCE + $(call if_changed,modules_builtin_ranges) + +vmlinux.map: vmlinux + @: + +endif + # Add FORCE to the prerequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o index d64070b6b4bc..0b6e2ebf60dc 100644 --- a/scripts/Makefile.vmlinux_o +++ b/scripts/Makefile.vmlinux_o @@ -45,9 +45,12 @@ objtool-args = $(vmlinux-objtool-args-y) --link # Link of vmlinux.o used for section mismatch analysis # --------------------------------------------------------------------------- +vmlinux-o-ld-args-$(CONFIG_BUILTIN_MODULE_RANGES) += -Map=$@.map + quiet_cmd_ld_vmlinux.o = LD $@ cmd_ld_vmlinux.o = \ $(LD) ${KBUILD_LDFLAGS} -r -o $@ \ + $(vmlinux-o-ld-args-y) \ $(addprefix -T , $(initcalls-lds)) \ --whole-archive vmlinux.a --no-whole-archive \ --start-group $(KBUILD_VMLINUX_LIBS) --end-group \ diff --git a/scripts/generate_builtin_ranges.awk b/scripts/generate_builtin_ranges.awk new file mode 100755 index 000000000000..b9ec761b3bef --- /dev/null +++ b/scripts/generate_builtin_ranges.awk @@ -0,0 +1,508 @@ +#!/usr/bin/gawk -f +# SPDX-License-Identifier: GPL-2.0 +# generate_builtin_ranges.awk: Generate address range data for builtin modules +# Written by Kris Van Hees +# +# Usage: generate_builtin_ranges.awk modules.builtin vmlinux.map \ +# vmlinux.o.map > modules.builtin.ranges +# + +# Return the module name(s) (if any) associated with the given object. +# +# If we have seen this object before, return information from the cache. +# Otherwise, retrieve it from the corresponding .cmd file. +# +function get_module_info(fn, mod, obj, s) { + if (fn in omod) + return omod[fn]; + + if (match(fn, /\/[^/]+$/) == 0) + return ""; + + obj = fn; + mod = ""; + fn = substr(fn, 1, RSTART) "." substr(fn, RSTART + 1) ".cmd"; + if (getline s 0) { + mod = substr(s, RSTART + 16, RLENGTH - 16); + gsub(/['"]/, "", mod); + } else if (match(s, /RUST_MODFILE=[^ ]+/) > 0) + mod = substr(s, RSTART + 13, RLENGTH - 13); + } + close(fn); + + # A single module (common case) also reflects objects that are not part + # of a module. Some of those objects have names that are also a module + # name (e.g. core). We check the associated module file name, and if + # they do not match, the object is not part of a module. + if (mod !~ / /) { + if (!(mod in mods)) + mod = ""; + } + + gsub(/([^/ ]*\/)+/, "", mod); + gsub(/-/, "_", mod); + + # At this point, mod is a single (valid) module name, or a list of + # module names (that do not need validation). + omod[obj] = mod; + + return mod; +} + +# Update the ranges entry for the given module 'mod' in section 'osect'. +# +# We use a modified absolute start address (soff + base) as index because we +# may need to insert an anchor record later that must be at the start of the +# section data, and the first module may very well start at the same address. +# So, we use (addr << 1) + 1 to allow a possible anchor record to be placed at +# (addr << 1). This is safe because the index is only used to sort the entries +# before writing them out. +# +function update_entry(osect, mod, soff, eoff, sect, idx) { + sect = sect_in[osect]; + idx = sprintf("%016x", (soff + sect_base[osect]) * 2 + 1); + entries[idx] = sprintf("%s %08x-%08x %s", sect, soff, eoff, mod); + count[sect]++; +} + +# (1) Build a lookup map of built-in module names. +# +# The first file argument is used as input (modules.builtin). +# +# Lines will be like: +# kernel/crypto/lzo-rle.ko +# and we record the object name "crypto/lzo-rle". +# +ARGIND == 1 { + sub(/kernel\//, ""); # strip off "kernel/" prefix + sub(/\.ko$/, ""); # strip off .ko suffix + + mods[$1] = 1; + next; +} + +# (2) Collect address information for each section. +# +# The second file argument is used as input (vmlinux.map). +# +# We collect the base address of the section in order to convert all addresses +# in the section into offset values. +# +# We collect the address of the anchor (or first symbol in the section if there +# is no explicit anchor) to allow users of the range data to calculate address +# ranges based on the actual load address of the section in the running kernel. +# +# We collect the start address of any sub-section (section included in the top +# level section being processed). This is needed when the final linking was +# done using vmlinux.a because then the list of objects contained in each +# section is to be obtained from vmlinux.o.map. The offset of the sub-section +# is recorded here, to be used as an addend when processing vmlinux.o.map +# later. +# + +# Both GNU ld and LLVM lld linker map format are supported by converting LLVM +# lld linker map records into equivalent GNU ld linker map records. +# +# The first record of the vmlinux.map file provides enough information to know +# which format we are dealing with. +# +ARGIND == 2 && FNR == 1 && NF == 7 && $1 == "VMA" && $7 == "Symbol" { + map_is_lld = 1; + if (dbg) + printf "NOTE: %s uses LLVM lld linker map format\n", FILENAME >"/dev/stderr"; + next; +} + +# (LLD) Convert a section record fronm lld format to ld format. +# +# lld: ffffffff82c00000 2c00000 2493c0 8192 .data +# -> +# ld: .data 0xffffffff82c00000 0x2493c0 load address 0x0000000002c00000 +# +ARGIND == 2 && map_is_lld && NF == 5 && /[0-9] [^ ]+$/ { + $0 = $5 " 0x"$1 " 0x"$3 " load address 0x"$2; +} + +# (LLD) Convert an anchor record from lld format to ld format. +# +# lld: ffffffff81000000 1000000 0 1 _text = . +# -> +# ld: 0xffffffff81000000 _text = . +# +ARGIND == 2 && map_is_lld && !anchor && NF == 7 && raw_addr == "0x"$1 && $6 == "=" && $7 == "." { + $0 = " 0x"$1 " " $5 " = ."; +} + +# (LLD) Convert an object record from lld format to ld format. +# +# lld: 11480 11480 1f07 16 vmlinux.a(arch/x86/events/amd/uncore.o):(.text) +# -> +# ld: .text 0x0000000000011480 0x1f07 arch/x86/events/amd/uncore.o +# +ARGIND == 2 && map_is_lld && NF == 5 && $5 ~ /:\(/ { + gsub(/\)/, ""); + sub(/ vmlinux\.a\(/, " "); + sub(/:\(/, " "); + $0 = " "$6 " 0x"$1 " 0x"$3 " " $5; +} + +# (LLD) Convert a symbol record from lld format to ld format. +# +# We only care about these while processing a section for which no anchor has +# been determined yet. +# +# lld: ffffffff82a859a4 2a859a4 0 1 btf_ksym_iter_id +# -> +# ld: 0xffffffff82a859a4 btf_ksym_iter_id +# +ARGIND == 2 && map_is_lld && sect && !anchor && NF == 5 && $5 ~ /^[_A-Za-z][_A-Za-z0-9]*$/ { + $0 = " 0x"$1 " " $5; +} + +# (LLD) We do not need any other ldd linker map records. +# +ARGIND == 2 && map_is_lld && /^[0-9a-f]{16} / { + next; +} + +# (LD) Section records with just the section name at the start of the line +# need to have the next line pulled in to determine whether it is a +# loadable section. If it is, the next line will contains a hex value +# as first and second items. +# +ARGIND == 2 && !map_is_lld && NF == 1 && /^[^ ]/ { + s = $0; + getline; + if ($1 !~ /^0x/ || $2 !~ /^0x/) + next; + + $0 = s " " $0; +} + +# (LD) Object records with just the section name denote records with a long +# section name for which the remainder of the record can be found on the +# next line. +# +# (This is also needed for vmlinux.o.map, when used.) +# +ARGIND >= 2 && !map_is_lld && NF == 1 && /^ [^ \*]/ { + s = $0; + getline; + $0 = s " " $0; +} + +# Beginning a new section - done with the previous one (if any). +# +ARGIND == 2 && /^[^ ]/ { + sect = 0; +} + +# Process a loadable section (we only care about .-sections). +# +# Record the section name and its base address. +# We also record the raw (non-stripped) address of the section because it can +# be used to identify an anchor record. +# +# Note: +# Since some AWK implementations cannot handle large integers, we strip off the +# first 4 hex digits from the address. This is safe because the kernel space +# is not large enough for addresses to extend into those digits. The portion +# to strip off is stored in addr_prefix as a regexp, so further clauses can +# perform a simple substitution to do the address stripping. +# +ARGIND == 2 && /^\./ { + # Explicitly ignore a few sections that are not relevant here. + if ($1 ~ /^\.orc_/ || $1 ~ /_sites$/ || $1 ~ /\.percpu/) + next; + + # Sections with a 0-address can be ignored as well. + if ($2 ~ /^0x0+$/) + next; + + raw_addr = $2; + addr_prefix = "^" substr($2, 1, 6); + base = $2; + sub(addr_prefix, "0x", base); + base = strtonum(base); + sect = $1; + anchor = 0; + sect_base[sect] = base; + sect_size[sect] = strtonum($3); + + if (dbg) + printf "[%s] BASE %016x\n", sect, base >"/dev/stderr"; + + next; +} + +# If we are not in a section we care about, we ignore the record. +# +ARGIND == 2 && !sect { + next; +} + +# Record the first anchor symbol for the current section. +# +# An anchor record for the section bears the same raw address as the section +# record. +# +ARGIND == 2 && !anchor && NF == 4 && raw_addr == $1 && $3 == "=" && $4 == "." { + anchor = sprintf("%s %08x-%08x = %s", sect, 0, 0, $2); + sect_anchor[sect] = anchor; + + if (dbg) + printf "[%s] ANCHOR %016x = %s (.)\n", sect, 0, $2 >"/dev/stderr"; + + next; +} + +# If no anchor record was found for the current section, use the first symbol +# in the section as anchor. +# +ARGIND == 2 && !anchor && NF == 2 && $1 ~ /^0x/ && $2 !~ /^0x/ { + addr = $1; + sub(addr_prefix, "0x", addr); + addr = strtonum(addr) - base; + anchor = sprintf("%s %08x-%08x = %s", sect, addr, addr, $2); + sect_anchor[sect] = anchor; + + if (dbg) + printf "[%s] ANCHOR %016x = %s\n", sect, addr, $2 >"/dev/stderr"; + + next; +} + +# The first occurrence of a section name in an object record establishes the +# addend (often 0) for that section. This information is needed to handle +# sections that get combined in the final linking of vmlinux (e.g. .head.text +# getting included at the start of .text). +# +# If the section does not have a base yet, use the base of the encapsulating +# section. +# +ARGIND == 2 && sect && NF == 4 && /^ [^ \*]/ && !($1 in sect_addend) { + if (!($1 in sect_base)) { + sect_base[$1] = base; + + if (dbg) + printf "[%s] BASE %016x\n", $1, base >"/dev/stderr"; + } + + addr = $2; + sub(addr_prefix, "0x", addr); + addr = strtonum(addr); + sect_addend[$1] = addr - sect_base[$1]; + sect_in[$1] = sect; + + if (dbg) + printf "[%s] ADDEND %016x - %016x = %016x\n", $1, addr, base, sect_addend[$1] >"/dev/stderr"; + + # If the object is vmlinux.o then we will need vmlinux.o.map to get the + # actual offsets of objects. + if ($4 == "vmlinux.o") + need_o_map = 1; +} + +# (3) Collect offset ranges (relative to the section base address) for built-in +# modules. +# +# If the final link was done using the actual objects, vmlinux.map contains all +# the information we need (see section (3a)). +# If linking was done using vmlinux.a as intermediary, we will need to process +# vmlinux.o.map (see section (3b)). + +# (3a) Determine offset range info using vmlinux.map. +# +# Since we are already processing vmlinux.map, the top level section that is +# being processed is already known. If we do not have a base address for it, +# we do not need to process records for it. +# +# Given the object name, we determine the module(s) (if any) that the current +# object is associated with. +# +# If we were already processing objects for a (list of) module(s): +# - If the current object belongs to the same module(s), update the range data +# to include the current object. +# - Otherwise, ensure that the end offset of the range is valid. +# +# If the current object does not belong to a built-in module, ignore it. +# +# If it does, we add a new built-in module offset range record. +# +ARGIND == 2 && !need_o_map && /^ [^ ]/ && NF == 4 && $3 != "0x0" { + if (!(sect in sect_base)) + next; + + # Turn the address into an offset from the section base. + soff = $2; + sub(addr_prefix, "0x", soff); + soff = strtonum(soff) - sect_base[sect]; + eoff = soff + strtonum($3); + + # Determine which (if any) built-in modules the object belongs to. + mod = get_module_info($4); + + # If we are processing a built-in module: + # - If the current object is within the same module, we update its + # entry by extending the range and move on + # - Otherwise: + # + If we are still processing within the same main section, we + # validate the end offset against the start offset of the + # current object (e.g. .rodata.str1.[18] objects are often + # listed with an incorrect size in the linker map) + # + Otherwise, we validate the end offset against the section + # size + if (mod_name) { + if (mod == mod_name) { + mod_eoff = eoff; + update_entry(mod_sect, mod_name, mod_soff, eoff); + + next; + } else if (sect == sect_in[mod_sect]) { + if (mod_eoff > soff) + update_entry(mod_sect, mod_name, mod_soff, soff); + } else { + v = sect_size[sect_in[mod_sect]]; + if (mod_eoff > v) + update_entry(mod_sect, mod_name, mod_soff, v); + } + } + + mod_name = mod; + + # If we encountered an object that is not part of a built-in module, we + # do not need to record any data. + if (!mod) + next; + + # At this point, we encountered the start of a new built-in module. + mod_name = mod; + mod_soff = soff; + mod_eoff = eoff; + mod_sect = $1; + update_entry($1, mod, soff, mod_eoff); + + next; +} + +# If we do not need to parse the vmlinux.o.map file, we are done. +# +ARGIND == 3 && !need_o_map { + if (dbg) + printf "Note: %s is not needed.\n", FILENAME >"/dev/stderr"; + exit; +} + +# (3) Collect offset ranges (relative to the section base address) for built-in +# modules. +# + +# (LLD) Convert an object record from lld format to ld format. +# +ARGIND == 3 && map_is_lld && NF == 5 && $5 ~ /:\(/ { + gsub(/\)/, ""); + sub(/:\(/, " "); + + sect = $6; + if (!(sect in sect_addend)) + next; + + sub(/ vmlinux\.a\(/, " "); + $0 = " "sect " 0x"$1 " 0x"$3 " " $5; +} + +# (3b) Determine offset range info using vmlinux.o.map. +# +# If we do not know an addend for the object's section, we are interested in +# anything within that section. +# +# Determine the top-level section that the object's section was included in +# during the final link. This is the section name offset range data will be +# associated with for this object. +# +# The remainder of the processing of the current object record follows the +# procedure outlined in (3a). +# +ARGIND == 3 && /^ [^ ]/ && NF == 4 && $3 != "0x0" { + osect = $1; + if (!(osect in sect_addend)) + next; + + # We need to work with the main section. + sect = sect_in[osect]; + + # Turn the address into an offset from the section base. + soff = $2; + sub(addr_prefix, "0x", soff); + soff = strtonum(soff) + sect_addend[osect]; + eoff = soff + strtonum($3); + + # Determine which (if any) built-in modules the object belongs to. + mod = get_module_info($4); + + # If we are processing a built-in module: + # - If the current object is within the same module, we update its + # entry by extending the range and move on + # - Otherwise: + # + If we are still processing within the same main section, we + # validate the end offset against the start offset of the + # current object (e.g. .rodata.str1.[18] objects are often + # listed with an incorrect size in the linker map) + # + Otherwise, we validate the end offset against the section + # size + if (mod_name) { + if (mod == mod_name) { + mod_eoff = eoff; + update_entry(mod_sect, mod_name, mod_soff, eoff); + + next; + } else if (sect == sect_in[mod_sect]) { + if (mod_eoff > soff) + update_entry(mod_sect, mod_name, mod_soff, soff); + } else { + v = sect_size[sect_in[mod_sect]]; + if (mod_eoff > v) + update_entry(mod_sect, mod_name, mod_soff, v); + } + } + + mod_name = mod; + + # If we encountered an object that is not part of a built-in module, we + # do not need to record any data. + if (!mod) + next; + + # At this point, we encountered the start of a new built-in module. + mod_name = mod; + mod_soff = soff; + mod_eoff = eoff; + mod_sect = osect; + update_entry(osect, mod, soff, mod_eoff); + + next; +} + +# (4) Generate the output. +# +# Anchor records are added for each section that contains offset range data +# records. They are added at an adjusted section base address (base << 1) to +# ensure they come first in the second records (see update_entry() above for +# more information). +# +# All entries are sorted by (adjusted) address to ensure that the output can be +# parsed in strict ascending address order. +# +END { + for (sect in count) { + if (sect in sect_anchor) { + idx = sprintf("%016x", sect_base[sect] * 2); + entries[idx] = sect_anchor[sect]; + } + } + + n = asorti(entries, indices); + for (i = 1; i <= n; i++) + print entries[indices[i]]; +} From ac7bd0945e3db5253bd03bfc40e71afafb08d225 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Fri, 6 Sep 2024 10:45:04 -0400 Subject: [PATCH 32/51] scripts: add verifier script for builtin module range data The modules.builtin.ranges offset range data for builtin modules is generated at compile time based on the list of built-in modules and the vmlinux.map and vmlinux.o.map linker maps. This data can be used to determine whether a symbol at a particular address belongs to module code that was configured to be compiled into the kernel proper as a built-in module (rather than as a standalone module). This patch adds a script that uses the generated modules.builtin.ranges data to annotate the symbols in the System.map with module names if their address falls within a range that belongs to one or more built-in modules. It then processes the vmlinux.map (and if needed, vmlinux.o.map) to verify the annotation: - For each top-level section: - For each object in the section: - Determine whether the object is part of a built-in module (using modules.builtin and the .*.cmd file used to compile the object as suggested in [0]) - For each symbol in that object, verify that the built-in module association (or lack thereof) matches the annotation given to the symbol. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Reviewed-by: Alan Maguire Tested-by: Sam James Reviewed-by: Sami Tolvanen Tested-by: Sami Tolvanen Signed-off-by: Masahiro Yamada --- scripts/verify_builtin_ranges.awk | 370 ++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100755 scripts/verify_builtin_ranges.awk diff --git a/scripts/verify_builtin_ranges.awk b/scripts/verify_builtin_ranges.awk new file mode 100755 index 000000000000..0de7ed521601 --- /dev/null +++ b/scripts/verify_builtin_ranges.awk @@ -0,0 +1,370 @@ +#!/usr/bin/gawk -f +# SPDX-License-Identifier: GPL-2.0 +# verify_builtin_ranges.awk: Verify address range data for builtin modules +# Written by Kris Van Hees +# +# Usage: verify_builtin_ranges.awk modules.builtin.ranges System.map \ +# modules.builtin vmlinux.map vmlinux.o.map +# + +# Return the module name(s) (if any) associated with the given object. +# +# If we have seen this object before, return information from the cache. +# Otherwise, retrieve it from the corresponding .cmd file. +# +function get_module_info(fn, mod, obj, s) { + if (fn in omod) + return omod[fn]; + + if (match(fn, /\/[^/]+$/) == 0) + return ""; + + obj = fn; + mod = ""; + fn = substr(fn, 1, RSTART) "." substr(fn, RSTART + 1) ".cmd"; + if (getline s 0) { + mod = substr(s, RSTART + 16, RLENGTH - 16); + gsub(/['"]/, "", mod); + } else if (match(s, /RUST_MODFILE=[^ ]+/) > 0) + mod = substr(s, RSTART + 13, RLENGTH - 13); + } else { + print "ERROR: Failed to read: " fn "\n\n" \ + " For kernels built with O=, cd to \n" \ + " and execute this script as ./source/scripts/..." \ + >"/dev/stderr"; + close(fn); + total = 0; + exit(1); + } + close(fn); + + # A single module (common case) also reflects objects that are not part + # of a module. Some of those objects have names that are also a module + # name (e.g. core). We check the associated module file name, and if + # they do not match, the object is not part of a module. + if (mod !~ / /) { + if (!(mod in mods)) + mod = ""; + } + + gsub(/([^/ ]*\/)+/, "", mod); + gsub(/-/, "_", mod); + + # At this point, mod is a single (valid) module name, or a list of + # module names (that do not need validation). + omod[obj] = mod; + + return mod; +} + +# Return a representative integer value for a given hexadecimal address. +# +# Since all kernel addresses fall within the same memory region, we can safely +# strip off the first 6 hex digits before performing the hex-to-dec conversion, +# thereby avoiding integer overflows. +# +function addr2val(val) { + sub(/^0x/, "", val); + if (length(val) == 16) + val = substr(val, 5); + return strtonum("0x" val); +} + +# Determine the kernel build directory to use (default is .). +# +BEGIN { + if (ARGC < 6) { + print "Syntax: verify_builtin_ranges.awk \n" \ + " \n" \ + >"/dev/stderr"; + total = 0; + exit(1); + } +} + +# (1) Load the built-in module address range data. +# +ARGIND == 1 { + ranges[FNR] = $0; + rcnt++; + next; +} + +# (2) Annotate System.map symbols with module names. +# +ARGIND == 2 { + addr = addr2val($1); + name = $3; + + while (addr >= mod_eaddr) { + if (sect_symb) { + if (sect_symb != name) + next; + + sect_base = addr - sect_off; + if (dbg) + printf "[%s] BASE (%s) %016x - %016x = %016x\n", sect_name, sect_symb, addr, sect_off, sect_base >"/dev/stderr"; + sect_symb = 0; + } + + if (++ridx > rcnt) + break; + + $0 = ranges[ridx]; + sub(/-/, " "); + if ($4 != "=") { + sub(/-/, " "); + mod_saddr = strtonum("0x" $2) + sect_base; + mod_eaddr = strtonum("0x" $3) + sect_base; + $1 = $2 = $3 = ""; + sub(/^ +/, ""); + mod_name = $0; + + if (dbg) + printf "[%s] %s from %016x to %016x\n", sect_name, mod_name, mod_saddr, mod_eaddr >"/dev/stderr"; + } else { + sect_name = $1; + sect_off = strtonum("0x" $2); + sect_symb = $5; + } + } + + idx = addr"-"name; + if (addr >= mod_saddr && addr < mod_eaddr) + sym2mod[idx] = mod_name; + + next; +} + +# Once we are done annotating the System.map, we no longer need the ranges data. +# +FNR == 1 && ARGIND == 3 { + delete ranges; +} + +# (3) Build a lookup map of built-in module names. +# +# Lines from modules.builtin will be like: +# kernel/crypto/lzo-rle.ko +# and we record the object name "crypto/lzo-rle". +# +ARGIND == 3 { + sub(/kernel\//, ""); # strip off "kernel/" prefix + sub(/\.ko$/, ""); # strip off .ko suffix + + mods[$1] = 1; + next; +} + +# (4) Get a list of symbols (per object). +# +# Symbols by object are read from vmlinux.map, with fallback to vmlinux.o.map +# if vmlinux is found to have inked in vmlinux.o. +# + +# If we were able to get the data we need from vmlinux.map, there is no need to +# process vmlinux.o.map. +# +FNR == 1 && ARGIND == 5 && total > 0 { + if (dbg) + printf "Note: %s is not needed.\n", FILENAME >"/dev/stderr"; + exit; +} + +# First determine whether we are dealing with a GNU ld or LLVM lld linker map. +# +ARGIND >= 4 && FNR == 1 && NF == 7 && $1 == "VMA" && $7 == "Symbol" { + map_is_lld = 1; + next; +} + +# (LLD) Convert a section record fronm lld format to ld format. +# +ARGIND >= 4 && map_is_lld && NF == 5 && /[0-9] [^ ]+$/ { + $0 = $5 " 0x"$1 " 0x"$3 " load address 0x"$2; +} + +# (LLD) Convert an object record from lld format to ld format. +# +ARGIND >= 4 && map_is_lld && NF == 5 && $5 ~ /:\(/ { + if (/\.a\(/ && !/ vmlinux\.a\(/) + next; + + gsub(/\)/, ""); + sub(/:\(/, " "); + sub(/ vmlinux\.a\(/, " "); + $0 = " "$6 " 0x"$1 " 0x"$3 " " $5; +} + +# (LLD) Convert a symbol record from lld format to ld format. +# +ARGIND >= 4 && map_is_lld && NF == 5 && $5 ~ /^[A-Za-z_][A-Za-z0-9_]*$/ { + $0 = " 0x" $1 " " $5; +} + +# (LLD) We do not need any other ldd linker map records. +# +ARGIND >= 4 && map_is_lld && /^[0-9a-f]{16} / { + next; +} + +# Handle section records with long section names (spilling onto a 2nd line). +# +ARGIND >= 4 && !map_is_lld && NF == 1 && /^[^ ]/ { + s = $0; + getline; + $0 = s " " $0; +} + +# Next section - previous one is done. +# +ARGIND >= 4 && /^[^ ]/ { + sect = 0; +} + +# Get the (top level) section name. +# +ARGIND >= 4 && /^\./ { + # Explicitly ignore a few sections that are not relevant here. + if ($1 ~ /^\.orc_/ || $1 ~ /_sites$/ || $1 ~ /\.percpu/) + next; + + # Sections with a 0-address can be ignored as well (in vmlinux.map). + if (ARGIND == 4 && $2 ~ /^0x0+$/) + next; + + sect = $1; + + next; +} + +# If we are not currently in a section we care about, ignore records. +# +!sect { + next; +} + +# Handle object records with long section names (spilling onto a 2nd line). +# +ARGIND >= 4 && /^ [^ \*]/ && NF == 1 { + # If the section name is long, the remainder of the entry is found on + # the next line. + s = $0; + getline; + $0 = s " " $0; +} + +# Objects linked in from static libraries are ignored. +# If the object is vmlinux.o, we need to consult vmlinux.o.map for per-object +# symbol information +# +ARGIND == 4 && /^ [^ ]/ && NF == 4 { + if ($4 ~ /\.a\(/) + next; + + idx = sect":"$1; + if (!(idx in sect_addend)) { + sect_addend[idx] = addr2val($2); + if (dbg) + printf "ADDEND %s = %016x\n", idx, sect_addend[idx] >"/dev/stderr"; + } + if ($4 == "vmlinux.o") { + need_o_map = 1; + next; + } +} + +# If data from vmlinux.o.map is needed, we only process section and object +# records from vmlinux.map to determine which section we need to pay attention +# to in vmlinux.o.map. So skip everything else from vmlinux.map. +# +ARGIND == 4 && need_o_map { + next; +} + +# Get module information for the current object. +# +ARGIND >= 4 && /^ [^ ]/ && NF == 4 { + msect = $1; + mod_name = get_module_info($4); + mod_eaddr = addr2val($2) + addr2val($3); + + next; +} + +# Process a symbol record. +# +# Evaluate the module information obtained from vmlinux.map (or vmlinux.o.map) +# as follows: +# - For all symbols in a given object: +# - If the symbol is annotated with the same module name(s) that the object +# belongs to, count it as a match. +# - Otherwise: +# - If the symbol is known to have duplicates of which at least one is +# in a built-in module, disregard it. +# - If the symbol us not annotated with any module name(s) AND the +# object belongs to built-in modules, count it as missing. +# - Otherwise, count it as a mismatch. +# +ARGIND >= 4 && /^ / && NF == 2 && $1 ~ /^0x/ { + idx = sect":"msect; + if (!(idx in sect_addend)) + next; + + addr = addr2val($1); + + # Handle the rare but annoying case where a 0-size symbol is placed at + # the byte *after* the module range. Based on vmlinux.map it will be + # considered part of the current object, but it falls just beyond the + # module address range. Unfortunately, its address could be at the + # start of another built-in module, so the only safe thing to do is to + # ignore it. + if (mod_name && addr == mod_eaddr) + next; + + # If we are processing vmlinux.o.map, we need to apply the base address + # of the section to the relative address on the record. + # + if (ARGIND == 5) + addr += sect_addend[idx]; + + idx = addr"-"$2; + mod = ""; + if (idx in sym2mod) { + mod = sym2mod[idx]; + if (sym2mod[idx] == mod_name) { + mod_matches++; + matches++; + } else if (mod_name == "") { + print $2 " in " mod " (should NOT be)"; + mismatches++; + } else { + print $2 " in " mod " (should be " mod_name ")"; + mismatches++; + } + } else if (mod_name != "") { + print $2 " should be in " mod_name; + missing++; + } else + matches++; + + total++; + + next; +} + +# Issue the comparison report. +# +END { + if (total) { + printf "Verification of %s:\n", ARGV[1]; + printf " Correct matches: %6d (%d%% of total)\n", matches, 100 * matches / total; + printf " Module matches: %6d (%d%% of matches)\n", mod_matches, 100 * mod_matches / matches; + printf " Mismatches: %6d (%d%% of total)\n", mismatches, 100 * mismatches / total; + printf " Missing: %6d (%d%% of total)\n", missing, 100 * missing / total; + + if (mismatches || missing) + exit(1); + } +} From ae70d708c932e7bc08b6c1975e1a010ee0b4e272 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Fri, 6 Sep 2024 10:45:05 -0400 Subject: [PATCH 33/51] kbuild: add install target for modules.builtin.ranges When CONFIG_BUILTIN_MODULE_RANGES is enabled, the modules.builtin.ranges file should be installed in the module install location. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Tested-by: Sam James Reviewed-by: Sami Tolvanen Tested-by: Sami Tolvanen Signed-off-by: Masahiro Yamada --- scripts/Makefile.modinst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index 04f5229efa6b..4d81ed9af294 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -30,10 +30,12 @@ $(MODLIB)/modules.order: modules.order FORCE quiet_cmd_install_modorder = INSTALL $@ cmd_install_modorder = sed 's:^\(.*\)\.o$$:kernel/\1.ko:' $< > $@ -# Install modules.builtin(.modinfo) even when CONFIG_MODULES is disabled. +# Install modules.builtin(.modinfo,.ranges) even when CONFIG_MODULES is disabled. install-y += $(addprefix $(MODLIB)/, modules.builtin modules.builtin.modinfo) -$(addprefix $(MODLIB)/, modules.builtin modules.builtin.modinfo): $(MODLIB)/%: % FORCE +install-$(CONFIG_BUILTIN_MODULE_RANGES) += $(MODLIB)/modules.builtin.ranges + +$(addprefix $(MODLIB)/, modules.builtin modules.builtin.modinfo modules.builtin.ranges): $(MODLIB)/%: % FORCE $(call cmd,install) endif From 327df5bf540e1cde17ae35d5a043ece773c80ff6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 7 Sep 2024 17:53:22 +0900 Subject: [PATCH 34/51] kallsyms: squash output_address() After commit 64e166099b69 ("kallsyms: get rid of code for absolute, kallsyms"), there is only one call site for output_address(). Squash it. Signed-off-by: Masahiro Yamada --- scripts/kallsyms.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index c70458e68ece..f6bb7fb2536b 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -292,15 +292,6 @@ static void output_label(const char *label) printf("%s:\n", label); } -/* Provide proper symbols relocatability by their '_text' relativeness. */ -static void output_address(unsigned long long addr) -{ - if (_text <= addr) - printf("\tPTR\t_text + %#llx\n", addr - _text); - else - printf("\tPTR\t_text - %#llx\n", _text - addr); -} - /* uncompress a compressed symbol. When this function is called, the best table * might still be compressed itself, so the function needs to be recursive */ static int expand_symbol(const unsigned char *data, int len, char *result) @@ -488,7 +479,11 @@ static void write_src(void) printf("\n"); output_label("kallsyms_relative_base"); - output_address(relative_base); + /* Provide proper symbols relocatability by their '_text' relativeness. */ + if (_text <= relative_base) + printf("\tPTR\t_text + %#llx\n", relative_base - _text); + else + printf("\tPTR\t_text - %#llx\n", _text - relative_base); printf("\n"); sort_symbols_by_name(); From 9a418218dadf913fe78dbe6ad6b2e31e721b84ef Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 7 Sep 2024 17:53:23 +0900 Subject: [PATCH 35/51] kallsyms: change overflow variable to bool type Change the 'overflow' variable to bool. Also, remove unnecessary parentheses. Signed-off-by: Masahiro Yamada --- scripts/kallsyms.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index f6bb7fb2536b..03852da3d249 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -455,17 +455,17 @@ static void write_src(void) */ long long offset; - int overflow; + bool overflow; if (!absolute_percpu) { offset = table[i]->addr - relative_base; - overflow = (offset < 0 || offset > UINT_MAX); + overflow = offset < 0 || offset > UINT_MAX; } else if (symbol_absolute(table[i])) { offset = table[i]->addr; - overflow = (offset < 0 || offset > INT_MAX); + overflow = offset < 0 || offset > INT_MAX; } else { offset = relative_base - table[i]->addr - 1; - overflow = (offset < INT_MIN || offset >= 0); + overflow = offset < INT_MIN || offset >= 0; } if (overflow) { fprintf(stderr, "kallsyms failure: " From a16219bdd34777cce35b9b6a704bfbaad28adb72 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 8 Sep 2024 21:43:16 +0900 Subject: [PATCH 36/51] scripts: move hash function from scripts/kconfig/ to scripts/include/ This function was originally added by commit 8af27e1dc4e4 ("fixdep: use hash table instead of a single array"). Move it to scripts/include/ so that other host programs can use it. Signed-off-by: Masahiro Yamada --- scripts/include/hash.h | 15 +++++++++++++++ scripts/kconfig/lkc.h | 1 - scripts/kconfig/symbol.c | 5 +++-- scripts/kconfig/util.c | 13 ++----------- 4 files changed, 20 insertions(+), 14 deletions(-) create mode 100644 scripts/include/hash.h diff --git a/scripts/include/hash.h b/scripts/include/hash.h new file mode 100644 index 000000000000..ce2bc43b308b --- /dev/null +++ b/scripts/include/hash.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef HASH_H +#define HASH_H + +static inline unsigned int hash_str(const char *s) +{ + /* fnv32 hash */ + unsigned int hash = 2166136261U; + + for (; *s; s++) + hash = (hash ^ *s) * 0x01000193; + return hash; +} + +#endif /* HASH_H */ diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index ddfb2b1cb737..b8ebc3094a23 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -51,7 +51,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) } /* util.c */ -unsigned int strhash(const char *s); const char *file_lookup(const char *name); /* lexer.l */ diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 6793f016af5e..6243f0143ecf 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "internal.h" #include "lkc.h" @@ -893,7 +894,7 @@ struct symbol *sym_lookup(const char *name, int flags) case 'n': return &symbol_no; } } - hash = strhash(name); + hash = hash_str(name); hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && @@ -936,7 +937,7 @@ struct symbol *sym_find(const char *name) case 'n': return &symbol_no; } } - hash = strhash(name); + hash = hash_str(name); hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 50698fff5b9d..5cdcee144b58 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -8,20 +8,11 @@ #include #include +#include #include #include #include "lkc.h" -unsigned int strhash(const char *s) -{ - /* fnv32 hash */ - unsigned int hash = 2166136261U; - - for (; *s; s++) - hash = (hash ^ *s) * 0x01000193; - return hash; -} - /* hash table of all parsed Kconfig files */ static HASHTABLE_DEFINE(file_hashtable, 1U << 11); @@ -35,7 +26,7 @@ const char *file_lookup(const char *name) { struct file *file; size_t len; - int hash = strhash(name); + int hash = hash_str(name); hash_for_each_possible(file_hashtable, file, node, hash) if (!strcmp(name, file->name)) From d607e0e7a8d2ea6565f11064d28b0825a95748aa Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 8 Sep 2024 21:43:17 +0900 Subject: [PATCH 37/51] kconfig: change some expr_*() functions to bool This clarifies the behavior of these functions. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.c | 15 ++++++++------- scripts/kconfig/expr.h | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index a16451347f63..d5dc682f7dc6 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -243,9 +243,10 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) * equals some operand in the other (operands do not need to appear in the same * order), recursively. */ -int expr_eq(struct expr *e1, struct expr *e2) +bool expr_eq(struct expr *e1, struct expr *e2) { - int res, old_count; + int old_count; + bool res; /* * A NULL expr is taken to be yes, but there's also a different way to @@ -255,7 +256,7 @@ int expr_eq(struct expr *e1, struct expr *e2) return expr_is_yes(e1) && expr_is_yes(e2); if (e1->type != e2->type) - return 0; + return false; switch (e1->type) { case E_EQUAL: case E_GEQ: @@ -292,7 +293,7 @@ int expr_eq(struct expr *e1, struct expr *e2) printf(" ?\n"); } - return 0; + return false; } /* @@ -804,10 +805,10 @@ struct expr *expr_transform(struct expr *e) return e; } -int expr_contains_symbol(struct expr *dep, struct symbol *sym) +bool expr_contains_symbol(struct expr *dep, struct symbol *sym) { if (!dep) - return 0; + return false; switch (dep->type) { case E_AND: @@ -829,7 +830,7 @@ int expr_contains_symbol(struct expr *dep, struct symbol *sym) default: ; } - return 0; + return false; } bool expr_depends_symbol(struct expr *dep, struct symbol *sym) diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index c82d08bbd704..4ab7422ddbd8 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -278,11 +278,11 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); struct expr *expr_copy(const struct expr *org); void expr_free(struct expr *e); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); -int expr_eq(struct expr *e1, struct expr *e2); +bool expr_eq(struct expr *e1, struct expr *e2); tristate expr_calc_value(struct expr *e); struct expr *expr_eliminate_dups(struct expr *e); struct expr *expr_transform(struct expr *e); -int expr_contains_symbol(struct expr *dep, struct symbol *sym); +bool expr_contains_symbol(struct expr *dep, struct symbol *sym); bool expr_depends_symbol(struct expr *dep, struct symbol *sym); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); @@ -292,7 +292,7 @@ void expr_gstr_print(const struct expr *e, struct gstr *gs); void expr_gstr_print_revdep(struct expr *e, struct gstr *gs, tristate pr_type, const char *title); -static inline int expr_is_yes(const struct expr *e) +static inline bool expr_is_yes(const struct expr *e) { return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); } From 4fa146eaecaee6301e8f5b104fe63b41afdf83e6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 8 Sep 2024 21:43:18 +0900 Subject: [PATCH 38/51] kconfig: add comments to expression transformations Provide explanations for complex transformations. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.c | 43 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index d5dc682f7dc6..e83fe0c3d62f 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -442,6 +442,7 @@ static struct expr *expr_join_or(struct expr *e1, struct expr *e2) } } if (sym1->type == S_BOOLEAN) { + // a || !a -> y if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) return expr_alloc_symbol(&symbol_yes); @@ -647,6 +648,30 @@ struct expr *expr_eliminate_dups(struct expr *e) * Performs various simplifications involving logical operators and * comparisons. * + * For bool type: + * A=n -> !A + * A=m -> n + * A=y -> A + * A!=n -> A + * A!=m -> y + * A!=y -> !A + * + * For any type: + * !!A -> A + * !(A=B) -> A!=B + * !(A!=B) -> A=B + * !(A<=B) -> A>B + * !(A>=B) -> A A>=B + * !(A>B) -> A<=B + * !(A || B) -> !A && !B + * !(A && B) -> !A || !B + * + * For constant: + * !y -> n + * !m -> m + * !n -> y + * * Allocates and returns a new expression. */ struct expr *expr_transform(struct expr *e) @@ -674,12 +699,14 @@ struct expr *expr_transform(struct expr *e) if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { + // A=n -> !A e->type = E_NOT; e->left.expr = expr_alloc_symbol(e->left.sym); e->right.sym = NULL; break; } if (e->right.sym == &symbol_mod) { + // A=m -> n printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); e->type = E_SYMBOL; e->left.sym = &symbol_no; @@ -687,6 +714,7 @@ struct expr *expr_transform(struct expr *e) break; } if (e->right.sym == &symbol_yes) { + // A=y -> A e->type = E_SYMBOL; e->right.sym = NULL; break; @@ -696,11 +724,13 @@ struct expr *expr_transform(struct expr *e) if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { + // A!=n -> A e->type = E_SYMBOL; e->right.sym = NULL; break; } if (e->right.sym == &symbol_mod) { + // A!=m -> y printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); e->type = E_SYMBOL; e->left.sym = &symbol_yes; @@ -708,6 +738,7 @@ struct expr *expr_transform(struct expr *e) break; } if (e->right.sym == &symbol_yes) { + // A!=y -> !A e->type = E_NOT; e->left.expr = expr_alloc_symbol(e->left.sym); e->right.sym = NULL; @@ -717,7 +748,7 @@ struct expr *expr_transform(struct expr *e) case E_NOT: switch (e->left.expr->type) { case E_NOT: - // !!a -> a + // !!A -> A tmp = e->left.expr->left.expr; free(e->left.expr); free(e); @@ -726,7 +757,7 @@ struct expr *expr_transform(struct expr *e) break; case E_EQUAL: case E_UNEQUAL: - // !a='x' -> a!='x' + // !(A=B) -> A!=B tmp = e->left.expr; free(e); e = tmp; @@ -734,7 +765,7 @@ struct expr *expr_transform(struct expr *e) break; case E_LEQ: case E_GEQ: - // !a<='x' -> a>'x' + // !(A<=B) -> A>B tmp = e->left.expr; free(e); e = tmp; @@ -742,14 +773,14 @@ struct expr *expr_transform(struct expr *e) break; case E_LTH: case E_GTH: - // !a<'x' -> a>='x' + // !(A A>=B tmp = e->left.expr; free(e); e = tmp; e->type = e->type == E_LTH ? E_GEQ : E_LEQ; break; case E_OR: - // !(a || b) -> !a && !b + // !(A || B) -> !A && !B tmp = e->left.expr; e->type = E_AND; e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); @@ -758,7 +789,7 @@ struct expr *expr_transform(struct expr *e) e = expr_transform(e); break; case E_AND: - // !(a && b) -> !a || !b + // !(A && B) -> !A || !B tmp = e->left.expr; e->type = E_OR; e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); From 440f67ccdcd31ca33d8d0439b16e4b6d4d7aba17 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 8 Sep 2024 21:43:19 +0900 Subject: [PATCH 39/51] kconfig: refactor expr_eliminate_dups() Currently, expr_eliminate_dups() passes two identical pointers down to expr_eliminate_dups1(), which later skips processing identical leaves. This approach is somewhat tricky and, more importantly, it will not work with the refactoring made in the next commit. This commit slightly changes the recursion logic; it deduplicates both the left and right arms, and then passes them to expr_eliminate_dups1(). expr_eliminate_dups() should produce the same result. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index e83fe0c3d62f..5b826d197f12 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -578,16 +578,6 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct /* *ep1 and *ep2 are leaves. Compare and process them. */ - if (*ep1 == *ep2) - return; - - switch ((*ep1)->type) { - case E_OR: case E_AND: - expr_eliminate_dups1((*ep1)->type, ep1, ep1); - default: - ; - } - switch (type) { case E_OR: tmp = expr_join_or(*ep1, *ep2); @@ -634,7 +624,9 @@ struct expr *expr_eliminate_dups(struct expr *e) trans_count = 0; switch (e->type) { case E_OR: case E_AND: - expr_eliminate_dups1(e->type, &e, &e); + e->left.expr = expr_eliminate_dups(e->left.expr); + e->right.expr = expr_eliminate_dups(e->right.expr); + expr_eliminate_dups1(e->type, &e->left.expr, &e->right.expr); default: ; } From f93d6bfbd2f74d79041c153a59df5336f6e9a14a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 8 Sep 2024 21:43:20 +0900 Subject: [PATCH 40/51] kconfig: use hash table to reuse expressions Currently, every expression in Kconfig files produces a new abstract syntax tree (AST), even if it is identical to a previously encountered one. Consider the following code: config FOO bool "FOO" depends on (A || B) && C config BAR bool "BAR" depends on (A || B) && C config BAZ bool "BAZ" depends on A || B The "depends on" lines are similar, but currently a separate AST is allocated for each one. The current data structure looks like this: FOO->dep ==> AND BAR->dep ==> AND BAZ->dep ==> OR / \ / \ / \ OR C OR C A B / \ / \ A B A B This is redundant; FOO->dep and BAR->dep have identical ASTs but different memory instances. We can optimize this; FOO->dep and BAR->dep can share the same AST, and BAZ->dep can reference its sub tree. The optimized data structure looks like this: FOO->dep, BAR->dep ==> AND / \ BAZ->dep ==> OR C / \ A B This commit introduces a hash table to keep track of allocated expressions. If an identical expression is found, it is reused. This does not necessarily result in memory savings, as menu_finalize() transforms expressions without freeing up stale ones. This will be addressed later. One optimization that can be easily implemented is caching the expression's value. Once FOO's dependency, (A || B) && C, is calculated, it can be cached, eliminating the need to recalculate it for BAR. This commit also reverts commit e983b7b17ad1 ("kconfig/menu.c: fix multiple references to expressions in menu_add_prop()"). Signed-off-by: Masahiro Yamada --- scripts/include/hash.h | 13 ++ scripts/kconfig/expr.c | 381 +++++++++++++------------------------ scripts/kconfig/expr.h | 16 +- scripts/kconfig/internal.h | 4 + scripts/kconfig/menu.c | 33 +--- 5 files changed, 170 insertions(+), 277 deletions(-) diff --git a/scripts/include/hash.h b/scripts/include/hash.h index ce2bc43b308b..efa904368a62 100644 --- a/scripts/include/hash.h +++ b/scripts/include/hash.h @@ -12,4 +12,17 @@ static inline unsigned int hash_str(const char *s) return hash; } +/* simplified version of functions from include/linux/hash.h */ +#define GOLDEN_RATIO_32 0x61C88647 + +static inline unsigned int hash_32(unsigned int val) +{ + return 0x61C88647 * val; +} + +static inline unsigned int hash_ptr(const void *ptr) +{ + return hash_32((unsigned int)(unsigned long)ptr); +} + #endif /* HASH_H */ diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 5b826d197f12..476dcaa9078e 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -9,45 +9,68 @@ #include #include +#include #include +#include "internal.h" #include "lkc.h" #define DEBUG_EXPR 0 +HASHTABLE_DEFINE(expr_hashtable, EXPR_HASHSIZE); + static struct expr *expr_eliminate_yn(struct expr *e); +/** + * expr_lookup - return the expression with the given type and sub-nodes + * This looks up an expression with the specified type and sub-nodes. If such + * an expression is found in the hash table, it is returned. Otherwise, a new + * expression node is allocated and added to the hash table. + * @type: expression type + * @l: left node + * @r: right node + * return: expression + */ +static struct expr *expr_lookup(enum expr_type type, void *l, void *r) +{ + struct expr *e; + int hash; + + hash = hash_32((unsigned int)type ^ hash_ptr(l) ^ hash_ptr(r)); + + hash_for_each_possible(expr_hashtable, e, node, hash) { + if (e->type == type && e->left._initdata == l && + e->right._initdata == r) + return e; + } + + e = xmalloc(sizeof(*e)); + e->type = type; + e->left._initdata = l; + e->right._initdata = r; + + hash_add(expr_hashtable, &e->node, hash); + + return e; +} + struct expr *expr_alloc_symbol(struct symbol *sym) { - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = E_SYMBOL; - e->left.sym = sym; - return e; + return expr_lookup(E_SYMBOL, sym, NULL); } struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) { - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.expr = ce; - return e; + return expr_lookup(type, ce, NULL); } struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) { - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.expr = e1; - e->right.expr = e2; - return e; + return expr_lookup(type, e1, e2); } struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) { - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.sym = s1; - e->right.sym = s2; - return e; + return expr_lookup(type, s1, s2); } struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) @@ -64,76 +87,6 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; } -struct expr *expr_copy(const struct expr *org) -{ - struct expr *e; - - if (!org) - return NULL; - - e = xmalloc(sizeof(*org)); - memcpy(e, org, sizeof(*org)); - switch (org->type) { - case E_SYMBOL: - e->left = org->left; - break; - case E_NOT: - e->left.expr = expr_copy(org->left.expr); - break; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - e->left.sym = org->left.sym; - e->right.sym = org->right.sym; - break; - case E_AND: - case E_OR: - e->left.expr = expr_copy(org->left.expr); - e->right.expr = expr_copy(org->right.expr); - break; - default: - fprintf(stderr, "can't copy type %d\n", e->type); - free(e); - e = NULL; - break; - } - - return e; -} - -void expr_free(struct expr *e) -{ - if (!e) - return; - - switch (e->type) { - case E_SYMBOL: - break; - case E_NOT: - expr_free(e->left.expr); - break; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - break; - case E_OR: - case E_AND: - expr_free(e->left.expr); - expr_free(e->right.expr); - break; - default: - fprintf(stderr, "how to free type %d?\n", e->type); - break; - } - free(e); -} - static int trans_count; /* @@ -146,16 +99,24 @@ static int trans_count; */ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) { + struct expr *l, *r; + /* Recurse down to leaves */ if ((*ep1)->type == type) { - __expr_eliminate_eq(type, &(*ep1)->left.expr, ep2); - __expr_eliminate_eq(type, &(*ep1)->right.expr, ep2); + l = (*ep1)->left.expr; + r = (*ep1)->right.expr; + __expr_eliminate_eq(type, &l, ep2); + __expr_eliminate_eq(type, &r, ep2); + *ep1 = expr_alloc_two(type, l, r); return; } if ((*ep2)->type == type) { - __expr_eliminate_eq(type, ep1, &(*ep2)->left.expr); - __expr_eliminate_eq(type, ep1, &(*ep2)->right.expr); + l = (*ep2)->left.expr; + r = (*ep2)->right.expr; + __expr_eliminate_eq(type, ep1, &l); + __expr_eliminate_eq(type, ep1, &r); + *ep2 = expr_alloc_two(type, l, r); return; } @@ -171,7 +132,6 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e /* *ep1 and *ep2 are equal leaves. Prepare them for elimination. */ trans_count++; - expr_free(*ep1); expr_free(*ep2); switch (type) { case E_OR: *ep1 = expr_alloc_symbol(&symbol_no); @@ -271,14 +231,10 @@ bool expr_eq(struct expr *e1, struct expr *e2) return expr_eq(e1->left.expr, e2->left.expr); case E_AND: case E_OR: - e1 = expr_copy(e1); - e2 = expr_copy(e2); old_count = trans_count; expr_eliminate_eq(&e1, &e2); res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && e1->left.sym == e2->left.sym); - expr_free(e1); - expr_free(e2); trans_count = old_count; return res; case E_RANGE: @@ -297,7 +253,7 @@ bool expr_eq(struct expr *e1, struct expr *e2) } /* - * Recursively performs the following simplifications in-place (as well as the + * Recursively performs the following simplifications (as well as the * corresponding simplifications with swapped operands): * * expr && n -> n @@ -309,79 +265,39 @@ bool expr_eq(struct expr *e1, struct expr *e2) */ static struct expr *expr_eliminate_yn(struct expr *e) { - struct expr *tmp; + struct expr *l, *r; if (e) switch (e->type) { case E_AND: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } + l = expr_eliminate_yn(e->left.expr); + r = expr_eliminate_yn(e->right.expr); + if (l->type == E_SYMBOL) { + if (l->left.sym == &symbol_no) + return l; + else if (l->left.sym == &symbol_yes) + return r; } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } + if (r->type == E_SYMBOL) { + if (r->left.sym == &symbol_no) + return r; + else if (r->left.sym == &symbol_yes) + return l; } break; case E_OR: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } + l = expr_eliminate_yn(e->left.expr); + r = expr_eliminate_yn(e->right.expr); + if (l->type == E_SYMBOL) { + if (l->left.sym == &symbol_no) + return r; + else if (l->left.sym == &symbol_yes) + return l; } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } + if (r->type == E_SYMBOL) { + if (r->left.sym == &symbol_no) + return l; + else if (r->left.sym == &symbol_yes) + return r; } break; default: @@ -399,7 +315,7 @@ static struct expr *expr_join_or(struct expr *e1, struct expr *e2) struct symbol *sym1, *sym2; if (expr_eq(e1, e2)) - return expr_copy(e1); + return e1; if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) return NULL; if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) @@ -464,7 +380,7 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2) struct symbol *sym1, *sym2; if (expr_eq(e1, e2)) - return expr_copy(e1); + return e1; if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) return NULL; if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) @@ -561,18 +477,24 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2) */ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) { - struct expr *tmp; + struct expr *tmp, *l, *r; /* Recurse down to leaves */ if ((*ep1)->type == type) { - expr_eliminate_dups1(type, &(*ep1)->left.expr, ep2); - expr_eliminate_dups1(type, &(*ep1)->right.expr, ep2); + l = (*ep1)->left.expr; + r = (*ep1)->right.expr; + expr_eliminate_dups1(type, &l, ep2); + expr_eliminate_dups1(type, &r, ep2); + *ep1 = expr_alloc_two(type, l, r); return; } if ((*ep2)->type == type) { - expr_eliminate_dups1(type, ep1, &(*ep2)->left.expr); - expr_eliminate_dups1(type, ep1, &(*ep2)->right.expr); + l = (*ep2)->left.expr; + r = (*ep2)->right.expr; + expr_eliminate_dups1(type, ep1, &l); + expr_eliminate_dups1(type, ep1, &r); + *ep2 = expr_alloc_two(type, l, r); return; } @@ -582,7 +504,6 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct case E_OR: tmp = expr_join_or(*ep1, *ep2); if (tmp) { - expr_free(*ep1); expr_free(*ep2); *ep1 = expr_alloc_symbol(&symbol_no); *ep2 = tmp; trans_count++; @@ -591,7 +512,6 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct case E_AND: tmp = expr_join_and(*ep1, *ep2); if (tmp) { - expr_free(*ep1); expr_free(*ep2); *ep1 = expr_alloc_symbol(&symbol_yes); *ep2 = tmp; trans_count++; @@ -621,12 +541,15 @@ struct expr *expr_eliminate_dups(struct expr *e) oldcount = trans_count; do { + struct expr *l, *r; + trans_count = 0; switch (e->type) { case E_OR: case E_AND: - e->left.expr = expr_eliminate_dups(e->left.expr); - e->right.expr = expr_eliminate_dups(e->right.expr); - expr_eliminate_dups1(e->type, &e->left.expr, &e->right.expr); + l = expr_eliminate_dups(e->left.expr); + r = expr_eliminate_dups(e->right.expr); + expr_eliminate_dups1(e->type, &l, &r); + e = expr_alloc_two(e->type, l, r); default: ; } @@ -668,8 +591,6 @@ struct expr *expr_eliminate_dups(struct expr *e) */ struct expr *expr_transform(struct expr *e) { - struct expr *tmp; - if (!e) return NULL; switch (e->type) { @@ -682,8 +603,9 @@ struct expr *expr_transform(struct expr *e) case E_SYMBOL: break; default: - e->left.expr = expr_transform(e->left.expr); - e->right.expr = expr_transform(e->right.expr); + e = expr_alloc_two(e->type, + expr_transform(e->left.expr), + expr_transform(e->right.expr)); } switch (e->type) { @@ -692,23 +614,18 @@ struct expr *expr_transform(struct expr *e) break; if (e->right.sym == &symbol_no) { // A=n -> !A - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; + e = expr_alloc_one(E_NOT, expr_alloc_symbol(e->left.sym)); break; } if (e->right.sym == &symbol_mod) { // A=m -> n printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.sym = NULL; + e = expr_alloc_symbol(&symbol_no); break; } if (e->right.sym == &symbol_yes) { // A=y -> A - e->type = E_SYMBOL; - e->right.sym = NULL; + e = expr_alloc_symbol(e->left.sym); break; } break; @@ -717,23 +634,18 @@ struct expr *expr_transform(struct expr *e) break; if (e->right.sym == &symbol_no) { // A!=n -> A - e->type = E_SYMBOL; - e->right.sym = NULL; + e = expr_alloc_symbol(e->left.sym); break; } if (e->right.sym == &symbol_mod) { // A!=m -> y printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.sym = NULL; + e = expr_alloc_symbol(&symbol_yes); break; } if (e->right.sym == &symbol_yes) { // A!=y -> !A - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; + e = expr_alloc_one(E_NOT, e->left.expr); break; } break; @@ -741,82 +653,51 @@ struct expr *expr_transform(struct expr *e) switch (e->left.expr->type) { case E_NOT: // !!A -> A - tmp = e->left.expr->left.expr; - free(e->left.expr); - free(e); - e = tmp; - e = expr_transform(e); + e = e->left.expr->left.expr; break; case E_EQUAL: case E_UNEQUAL: // !(A=B) -> A!=B - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; + e = expr_alloc_comp(e->left.expr->type == E_EQUAL ? E_UNEQUAL : E_EQUAL, + e->left.expr->left.sym, + e->left.expr->right.sym); break; case E_LEQ: case E_GEQ: // !(A<=B) -> A>B - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_LEQ ? E_GTH : E_LTH; + e = expr_alloc_comp(e->left.expr->type == E_LEQ ? E_GTH : E_LTH, + e->left.expr->left.sym, + e->left.expr->right.sym); break; case E_LTH: case E_GTH: // !(A A>=B - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_LTH ? E_GEQ : E_LEQ; + e = expr_alloc_comp(e->left.expr->type == E_LTH ? E_GEQ : E_LEQ, + e->left.expr->left.sym, + e->left.expr->right.sym); break; case E_OR: // !(A || B) -> !A && !B - tmp = e->left.expr; - e->type = E_AND; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; + e = expr_alloc_and(expr_alloc_one(E_NOT, e->left.expr->left.expr), + expr_alloc_one(E_NOT, e->left.expr->right.expr)); e = expr_transform(e); break; case E_AND: // !(A && B) -> !A || !B - tmp = e->left.expr; - e->type = E_OR; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; + e = expr_alloc_or(expr_alloc_one(E_NOT, e->left.expr->left.expr), + expr_alloc_one(E_NOT, e->left.expr->right.expr)); e = expr_transform(e); break; case E_SYMBOL: - if (e->left.expr->left.sym == &symbol_yes) { + if (e->left.expr->left.sym == &symbol_yes) // !'y' -> 'n' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - break; - } - if (e->left.expr->left.sym == &symbol_mod) { + e = expr_alloc_symbol(&symbol_no); + else if (e->left.expr->left.sym == &symbol_mod) // !'m' -> 'm' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_mod; - break; - } - if (e->left.expr->left.sym == &symbol_no) { + e = expr_alloc_symbol(&symbol_mod); + else if (e->left.expr->left.sym == &symbol_no) // !'n' -> 'y' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - break; - } + e = expr_alloc_symbol(&symbol_yes); break; default: ; @@ -940,18 +821,18 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb case E_EQUAL: if (type == E_EQUAL) { if (sym == &symbol_yes) - return expr_copy(e); + return e; if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_no); if (sym == &symbol_no) - return expr_alloc_one(E_NOT, expr_copy(e)); + return expr_alloc_one(E_NOT, e); } else { if (sym == &symbol_yes) - return expr_alloc_one(E_NOT, expr_copy(e)); + return expr_alloc_one(E_NOT, e); if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_yes); if (sym == &symbol_no) - return expr_copy(e); + return e; } break; case E_SYMBOL: diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 4ab7422ddbd8..a398b2b2dbe0 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -29,11 +29,21 @@ enum expr_type { }; union expr_data { - struct expr *expr; - struct symbol *sym; + struct expr * const expr; + struct symbol * const sym; + void *_initdata; }; +/** + * struct expr - expression + * + * @node: link node for the hash table + * @type: expressoin type + * @left: left node + * @right: right node + */ struct expr { + struct hlist_node node; enum expr_type type; union expr_data left, right; }; @@ -275,8 +285,6 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); -struct expr *expr_copy(const struct expr *org); -void expr_free(struct expr *e); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); bool expr_eq(struct expr *e1, struct expr *e2); tristate expr_calc_value(struct expr *e); diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h index 02106eb7815e..84c2ea0389fd 100644 --- a/scripts/kconfig/internal.h +++ b/scripts/kconfig/internal.h @@ -11,6 +11,10 @@ extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE); #define for_all_symbols(sym) \ hash_for_each(sym_hashtable, sym, node) +#define EXPR_HASHSIZE (1U << 14) + +extern HASHTABLE_DECLARE(expr_hashtable, EXPR_HASHSIZE); + struct menu; extern struct menu *current_menu, *current_entry; diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index f61327fabead..4addd33749bb 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -107,12 +107,13 @@ static struct expr *rewrite_m(struct expr *e) switch (e->type) { case E_NOT: - e->left.expr = rewrite_m(e->left.expr); + e = expr_alloc_one(E_NOT, rewrite_m(e->left.expr)); break; case E_OR: case E_AND: - e->left.expr = rewrite_m(e->left.expr); - e->right.expr = rewrite_m(e->right.expr); + e = expr_alloc_two(e->type, + rewrite_m(e->left.expr), + rewrite_m(e->right.expr)); break; case E_SYMBOL: /* change 'm' into 'm' && MODULES */ @@ -192,21 +193,11 @@ struct property *menu_add_prompt(enum prop_type type, const char *prompt, struct menu *menu = current_entry; while ((menu = menu->parent) != NULL) { - struct expr *dup_expr; if (!menu->visibility) continue; - /* - * Do not add a reference to the menu's visibility - * expression but use a copy of it. Otherwise the - * expression reduction functions will modify - * expressions that have multiple references which - * can cause unwanted side effects. - */ - dup_expr = expr_copy(menu->visibility); - prop->visible.expr = expr_alloc_and(prop->visible.expr, - dup_expr); + menu->visibility); } } @@ -322,7 +313,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) */ basedep = rewrite_m(menu->dep); basedep = expr_transform(basedep); - basedep = expr_alloc_and(expr_copy(parent->dep), basedep); + basedep = expr_alloc_and(parent->dep, basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; @@ -366,7 +357,7 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) */ dep = rewrite_m(prop->visible.expr); dep = expr_transform(dep); - dep = expr_alloc_and(expr_copy(basedep), dep); + dep = expr_alloc_and(basedep, dep); dep = expr_eliminate_dups(dep); prop->visible.expr = dep; @@ -377,11 +368,11 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) if (prop->type == P_SELECT) { struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + expr_alloc_and(expr_alloc_symbol(menu->sym), dep)); } else if (prop->type == P_IMPLY) { struct symbol *es = prop_get_symbol(prop); es->implied.expr = expr_alloc_or(es->implied.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + expr_alloc_and(expr_alloc_symbol(menu->sym), dep)); } } } @@ -441,22 +432,18 @@ static void _menu_finalize(struct menu *parent, bool inside_choice) */ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); - dep2 = expr_copy(basedep); + dep2 = basedep; expr_eliminate_eq(&dep, &dep2); - expr_free(dep); if (!expr_is_yes(dep2)) { /* Not superset, quit */ - expr_free(dep2); break; } /* Superset, put in submenu */ - expr_free(dep2); next: _menu_finalize(menu, false); menu->parent = parent; last_menu = menu; } - expr_free(basedep); if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; From 95573cac25c6b11f02d599d18e9a1c778706e838 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 8 Sep 2024 21:43:21 +0900 Subject: [PATCH 41/51] kconfig: cache expression values Cache expression values to avoid recalculating them repeatedly. Signed-off-by: Masahiro Yamada --- scripts/kconfig/confdata.c | 2 ++ scripts/kconfig/expr.c | 34 ++++++++++++++++++++++++++++++---- scripts/kconfig/expr.h | 4 ++++ scripts/kconfig/internal.h | 2 ++ scripts/kconfig/symbol.c | 1 + 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index d8849dfb06db..4286d5e7f95d 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -396,6 +396,8 @@ int conf_read_simple(const char *name, int def) } } + expr_invalidate_all(); + while (getline_stripped(&line, &line_asize, in) != -1) { struct menu *choice; diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 476dcaa9078e..78738ef412de 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -887,7 +887,7 @@ static enum string_value_kind expr_parse_string(const char *str, ? kind : k_string; } -tristate expr_calc_value(struct expr *e) +static tristate __expr_calc_value(struct expr *e) { tristate val1, val2; const char *str1, *str2; @@ -895,9 +895,6 @@ tristate expr_calc_value(struct expr *e) union string_value lval = {}, rval = {}; int res; - if (!e) - return yes; - switch (e->type) { case E_SYMBOL: sym_calc_value(e->left.sym); @@ -961,6 +958,35 @@ tristate expr_calc_value(struct expr *e) } } +/** + * expr_calc_value - return the tristate value of the given expression + * @e: expression + * return: tristate value of the expression + */ +tristate expr_calc_value(struct expr *e) +{ + if (!e) + return yes; + + if (!e->val_is_valid) { + e->val = __expr_calc_value(e); + e->val_is_valid = true; + } + + return e->val; +} + +/** + * expr_invalidate_all - invalidate all cached expression values + */ +void expr_invalidate_all(void) +{ + struct expr *e; + + hash_for_each(expr_hashtable, e, node) + e->val_is_valid = false; +} + static int expr_compare_type(enum expr_type t1, enum expr_type t2) { if (t1 == t2) diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index a398b2b2dbe0..21578dcd4292 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -39,12 +39,16 @@ union expr_data { * * @node: link node for the hash table * @type: expressoin type + * @val: calculated tristate value + * @val_is_valid: indicate whether the value is valid * @left: left node * @right: right node */ struct expr { struct hlist_node node; enum expr_type type; + tristate val; + bool val_is_valid; union expr_data left, right; }; diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h index 84c2ea0389fd..d0ffce2dfbba 100644 --- a/scripts/kconfig/internal.h +++ b/scripts/kconfig/internal.h @@ -15,6 +15,8 @@ extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE); extern HASHTABLE_DECLARE(expr_hashtable, EXPR_HASHSIZE); +void expr_invalidate_all(void); + struct menu; extern struct menu *current_menu, *current_entry; diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 6243f0143ecf..a3af93aaaf32 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -519,6 +519,7 @@ void sym_clear_all_valid(void) for_all_symbols(sym) sym->flags &= ~SYMBOL_VALID; + expr_invalidate_all(); conf_set_changed(true); sym_calc_value(modules_sym); } From cc6d281fcc7319babc6dde8f95a8b7feb1eeffd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 8 Sep 2024 15:26:00 +0200 Subject: [PATCH 42/51] kbuild: remove append operation on cmd_ld_ko_o MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The append operation was introduced in commit b1a1a1a09b46 ("kbuild: lto: postpone objtool") when the command was created from two parts. In commit 850ded46c642 ("kbuild: Fix TRIM_UNUSED_KSYMS with LTO_CLANG") however the first part was removed again, making the append operation unnecessary. To keep this command definition aligned with all other command definitions, remove the append again. Signed-off-by: Thomas Weißschuh Signed-off-by: Masahiro Yamada --- scripts/Makefile.modfinal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 6b1b72257b29..1482884ec3ca 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -34,7 +34,7 @@ $(extmod_prefix).module-common.o: $(srctree)/scripts/module-common.c FORCE $(call if_changed_dep,cc_o_c) quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o += \ + cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -T scripts/module.lds -o $@ $(filter %.o, $^) From fc1c79be45485565dc145fd03ee38bca89be8fbd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 14 Sep 2024 03:06:20 +0900 Subject: [PATCH 43/51] kbuild: remove unnecessary export of RUST_LIB_SRC If RUST_LIB_SRC is defined in the top-level Makefile (via an environment variable or command line), it is already exported. The only situation where it is defined but not exported is when the top-level Makefile is wrapped by another Makefile (e.g., GNUmakefile). I cannot think of any other use cases. I know some people use this tip to define custom variables. However, even in that case, you can export it directly in the wrapper Makefile. Example GNUmakefile: export RUST_LIB_SRC = /path/to/your/sysroot/lib/rustlib/src/rust/library include Makefile Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier Reviewed-by: Alice Ryhl --- Makefile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Makefile b/Makefile index b4a941a30c73..0d3d45a88a71 100644 --- a/Makefile +++ b/Makefile @@ -578,10 +578,6 @@ else RUSTC_OR_CLIPPY = $(RUSTC) endif -ifdef RUST_LIB_SRC - export RUST_LIB_SRC -endif - # Allows the usage of unstable features in stable compilers. export RUSTC_BOOTSTRAP := 1 From 062a1481cf275d39d3cda99f8357f2f8bdd8f611 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 17 Sep 2024 23:16:29 +0900 Subject: [PATCH 44/51] kbuild: doc: update the description about Kbuild/Makefile split The phrase "In newer versions of the kernel" was added 14 years ago, by commit efdf02cf0651 ("Documentation/kbuild: major edit of modules.txt sections 1-4"). This feature is no longer new, so remove it and update the paragraph. Example 3 was written 20 years ago [1]. There is no need to note about backward compatibility with such an old build system. Remove Example 3 entirely. [1]: https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=65e433436b5794ae056d22ddba60fe9194bba007 Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/modules.rst | 38 +++----------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index 131863142cbb..1014a275a7e1 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -224,10 +224,9 @@ module 8123.ko, which is built from the following files:: 3.2 Separate Kbuild File and Makefile ------------------------------------- - In newer versions of the kernel, kbuild will first look for a - file named "Kbuild," and only if that is not found, will it - then look for a makefile. Utilizing a "Kbuild" file allows us - to split up the makefile from example 1 into two files: + Kbuild will first look for a file named "Kbuild", and if it is not + found, it will then look for "Makefile". Utilizing a "Kbuild" file + allows us to split up the "Makefile" from example 1 into two files: Example 2:: @@ -250,37 +249,6 @@ module 8123.ko, which is built from the following files:: consisting of several hundred lines, and here it really pays off to separate the kbuild part from the rest. - The next example shows a backward compatible version. - - Example 3:: - - --> filename: Kbuild - obj-m := 8123.o - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - --> filename: Makefile - ifneq ($(KERNELRELEASE),) - # kbuild part of makefile - include Kbuild - - else - # normal makefile - KDIR ?= /lib/modules/`uname -r`/build - - default: - $(MAKE) -C $(KDIR) M=$$PWD - - # Module specific targets - genbin: - echo "X" > 8123_bin.o_shipped - - endif - - Here the "Kbuild" file is included from the makefile. This - allows an older version of kbuild, which only knows of - makefiles, to be used when the "make" and kbuild parts are - split into separate files. - 3.3 Binary Blobs ---------------- From 1a59bd3ca5d8fde10d082e56c3073f7fa563e73b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 17 Sep 2024 23:16:30 +0900 Subject: [PATCH 45/51] kbuild: doc: remove description about grepping CONFIG options This description was added 20 years ago [1]. It does not convey any useful information except for a feeling of nostalgia. [1]: https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=65e433436b5794ae056d22ddba60fe9194bba007 Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/modules.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index 1014a275a7e1..268ebbd2ab74 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -521,9 +521,3 @@ build. ext2-y := balloc.o bitmap.o dir.o ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o - - External modules have traditionally used "grep" to check for - specific `CONFIG_` settings directly in .config. This usage is - broken. As introduced before, external modules should use - kbuild for building and can therefore use the same methods as - in-tree modules when testing for `CONFIG_` definitions. From a866eda43f4f0d0c4dd53af81f15375a4b799eb8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 17 Sep 2024 23:16:31 +0900 Subject: [PATCH 46/51] kbuild: doc: remove outdated description of the limitation on -I usage Kbuild used to manipulate header search paths, enforcing the odd limitation of "no space after -I". Commit cdd750bfb1f7 ("kbuild: remove 'addtree' and 'flags' magic for header search paths") stopped doing that. This limitation no longer exists. Instead, you need to accurately specify the header search path. (In this case, $(src)/include) Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/modules.rst | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index 268ebbd2ab74..7eceb9a65e9c 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -328,13 +328,9 @@ according to the following rule: --> filename: Kbuild obj-m := 8123.o - ccflags-y := -Iinclude + ccflags-y := -I $(src)/include 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - Note that in the assignment there is no space between -I and - the path. This is a limitation of kbuild: there must be no - space present. - 4.3 Several Subdirectories -------------------------- From 7813cd68ea7ae909676aea19411b5c9c20436ebb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Sep 2024 02:37:14 +0900 Subject: [PATCH 47/51] kbuild: doc: throw out the local table of contents in modules.rst Do similar to commit 5e8f0ba38a4d ("docs/kbuild/makefiles: throw out the local table of contents"). Signed-off-by: Masahiro Yamada --- Documentation/kbuild/modules.rst | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index 7eceb9a65e9c..4f67e6a27afe 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -4,35 +4,6 @@ Building External Modules This document describes how to build an out-of-tree kernel module. -.. Table of Contents - - === 1 Introduction - === 2 How to Build External Modules - --- 2.1 Command Syntax - --- 2.2 Options - --- 2.3 Targets - --- 2.4 Building Separate Files - === 3. Creating a Kbuild File for an External Module - --- 3.1 Shared Makefile - --- 3.2 Separate Kbuild file and Makefile - --- 3.3 Binary Blobs - --- 3.4 Building Multiple Modules - === 4. Include Files - --- 4.1 Kernel Includes - --- 4.2 Single Subdirectory - --- 4.3 Several Subdirectories - === 5. Module Installation - --- 5.1 INSTALL_MOD_PATH - --- 5.2 INSTALL_MOD_DIR - === 6. Module Versioning - --- 6.1 Symbols From the Kernel (vmlinux + modules) - --- 6.2 Symbols and External Modules - --- 6.3 Symbols From Another External Module - === 7. Tips & Tricks - --- 7.1 Testing for CONFIG_FOO_BAR - - - 1. Introduction =============== From 803d5059529aaabd53aabd5cd2c7b405824601b7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Sep 2024 02:37:15 +0900 Subject: [PATCH 48/51] kbuild: doc: drop section numbering, use references in modules.rst Do similar to commit 1a4c1c9df72e ("docs/kbuild/makefiles: drop section numbering, use references"). Signed-off-by: Masahiro Yamada --- Documentation/kbuild/modules.rst | 101 ++++++++++++++++--------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index 4f67e6a27afe..c4a0598aa276 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -4,8 +4,8 @@ Building External Modules This document describes how to build an out-of-tree kernel module. -1. Introduction -=============== +Introduction +============ "kbuild" is the build system used by the Linux kernel. Modules must use kbuild to stay compatible with changes in the build infrastructure and @@ -19,11 +19,11 @@ in building out-of-tree (or "external") modules. The author of an external module should supply a makefile that hides most of the complexity, so one only has to type "make" to build the module. This is easily accomplished, and a complete example will be presented in -section 3. +section `Creating a Kbuild File for an External Module`_. -2. How to Build External Modules -================================ +How to Build External Modules +============================= To build external modules, you must have a prebuilt kernel available that contains the configuration and header files used in the build. @@ -40,8 +40,8 @@ NOTE: "modules_prepare" will not build Module.symvers even if CONFIG_MODVERSIONS is set; therefore, a full kernel build needs to be executed to make module versioning work. -2.1 Command Syntax -================== +Command Syntax +-------------- The command to build an external module is:: @@ -59,8 +59,8 @@ executed to make module versioning work. $ make -C /lib/modules/`uname -r`/build M=$PWD modules_install -2.2 Options -=========== +Options +------- ($KDIR refers to the path of the kernel source directory.) @@ -77,8 +77,8 @@ executed to make module versioning work. directory where the external module (kbuild file) is located. -2.3 Targets -=========== +Targets +------- When building an external module, only a subset of the "make" targets are available. @@ -100,7 +100,8 @@ executed to make module versioning work. modules_install Install the external module(s). The default location is /lib/modules//updates/, but a prefix may - be added with INSTALL_MOD_PATH (discussed in section 5). + be added with INSTALL_MOD_PATH (discussed in section + `Module Installation`_). clean Remove all generated files in the module directory only. @@ -108,8 +109,8 @@ executed to make module versioning work. help List the available targets for external modules. -2.4 Building Separate Files -=========================== +Building Separate Files +----------------------- It is possible to build single files that are part of a module. This works equally well for the kernel, a module, and even for @@ -123,8 +124,8 @@ executed to make module versioning work. make -C $KDIR M=$PWD ./ -3. Creating a Kbuild File for an External Module -================================================ +Creating a Kbuild File for an External Module +============================================= In the last section we saw the command to build a module for the running kernel. The module is not actually built, however, because a @@ -153,8 +154,8 @@ module 8123.ko, which is built from the following files:: 8123_pci.c 8123_bin.o_shipped <= Binary blob -3.1 Shared Makefile -------------------- +Shared Makefile +--------------- An external module always includes a wrapper makefile that supports building the module using "make" with no arguments. @@ -192,8 +193,8 @@ module 8123.ko, which is built from the following files:: line; the second pass is by the kbuild system, which is initiated by the parameterized "make" in the default target. -3.2 Separate Kbuild File and Makefile -------------------------------------- +Separate Kbuild File and Makefile +--------------------------------- Kbuild will first look for a file named "Kbuild", and if it is not found, it will then look for "Makefile". Utilizing a "Kbuild" file @@ -220,8 +221,8 @@ module 8123.ko, which is built from the following files:: consisting of several hundred lines, and here it really pays off to separate the kbuild part from the rest. -3.3 Binary Blobs ----------------- +Binary Blobs +------------ Some external modules need to include an object file as a blob. kbuild has support for this, but requires the blob file to be @@ -240,8 +241,8 @@ module 8123.ko, which is built from the following files:: files and the binary file, kbuild will pick up different rules when creating the object file for the module. -3.4 Building Multiple Modules -============================= +Building Multiple Modules +------------------------- kbuild supports building multiple modules with a single build file. For example, if you wanted to build two modules, foo.ko @@ -254,8 +255,8 @@ module 8123.ko, which is built from the following files:: It is that simple! -4. Include Files -================ +Include Files +============= Within the kernel, header files are kept in standard locations according to the following rule: @@ -273,8 +274,8 @@ according to the following rule: include/scsi; and architecture specific headers are located under arch/$(SRCARCH)/include/. -4.1 Kernel Includes -------------------- +Kernel Includes +--------------- To include a header file located under include/linux/, simply use:: @@ -284,8 +285,8 @@ according to the following rule: kbuild will add options to "gcc" so the relevant directories are searched. -4.2 Single Subdirectory ------------------------ +Single Subdirectory +------------------- External modules tend to place header files in a separate include/ directory where their source is located, although this @@ -302,8 +303,8 @@ according to the following rule: ccflags-y := -I $(src)/include 8123-y := 8123_if.o 8123_pci.o 8123_bin.o -4.3 Several Subdirectories --------------------------- +Several Subdirectories +---------------------- kbuild can handle files that are spread over several directories. Consider the following example:: @@ -342,8 +343,8 @@ according to the following rule: file is located. -5. Module Installation -====================== +Module Installation +=================== Modules which are included in the kernel are installed in the directory: @@ -354,8 +355,8 @@ And external modules are installed in: /lib/modules/$(KERNELRELEASE)/updates/ -5.1 INSTALL_MOD_PATH --------------------- +INSTALL_MOD_PATH +---------------- Above are the default directories but as always some level of customization is possible. A prefix can be added to the @@ -369,8 +370,8 @@ And external modules are installed in: calling "make." This has effect when installing both in-tree and out-of-tree modules. -5.2 INSTALL_MOD_DIR -------------------- +INSTALL_MOD_DIR +--------------- External modules are by default installed to a directory under /lib/modules/$(KERNELRELEASE)/updates/, but you may wish to @@ -383,8 +384,8 @@ And external modules are installed in: => Install dir: /lib/modules/$(KERNELRELEASE)/gandalf/ -6. Module Versioning -==================== +Module Versioning +================= Module versioning is enabled by the CONFIG_MODVERSIONS tag, and is used as a simple ABI consistency check. A CRC value of the full prototype @@ -396,8 +397,8 @@ module. Module.symvers contains a list of all exported symbols from a kernel build. -6.1 Symbols From the Kernel (vmlinux + modules) ------------------------------------------------ +Symbols From the Kernel (vmlinux + modules) +------------------------------------------- During a kernel build, a file named Module.symvers will be generated. Module.symvers contains all exported symbols from @@ -421,8 +422,8 @@ build. 1) It lists all exported symbols from vmlinux and all modules. 2) It lists the CRC if CONFIG_MODVERSIONS is enabled. -6.2 Symbols and External Modules --------------------------------- +Symbols and External Modules +---------------------------- When building an external module, the build system needs access to the symbols from the kernel to check if all external symbols @@ -431,8 +432,8 @@ build. tree. During the MODPOST step, a new Module.symvers file will be written containing all exported symbols from that external module. -6.3 Symbols From Another External Module ----------------------------------------- +Symbols From Another External Module +------------------------------------ Sometimes, an external module uses exported symbols from another external module. Kbuild needs to have full knowledge of @@ -472,11 +473,11 @@ build. initialization of its symbol tables. -7. Tips & Tricks -================ +Tips & Tricks +============= -7.1 Testing for CONFIG_FOO_BAR ------------------------------- +Testing for CONFIG_FOO_BAR +-------------------------- Modules often need to check for certain `CONFIG_` options to decide if a specific feature is included in the module. In From e873fb948283a595bba6228efc69ed1191f45689 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Sep 2024 02:37:16 +0900 Subject: [PATCH 49/51] kbuild: doc: remove the description about shipped files The use of shipped files is discouraged in the upstream kernel these days. [1] Downstream Makefiles have the freedom to use shipped files or other options to handle binaries, but this should not be advertised in the upstream document. [1]: https://lore.kernel.org/all/CAHk-=wgSEi_ZrHdqr=20xv+d6dr5G895CbOAi8ok+7-CQUN=fQ@mail.gmail.com/ Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/makefiles.rst | 1 - Documentation/kbuild/modules.rst | 35 +++--------------------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst index be43990f1e7f..7964e0c245ae 100644 --- a/Documentation/kbuild/makefiles.rst +++ b/Documentation/kbuild/makefiles.rst @@ -1665,6 +1665,5 @@ Credits TODO ==== -- Describe how kbuild supports shipped files with _shipped. - Generating offset header files. - Add more variables to chapters 7 or 9? diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index c4a0598aa276..080e11372351 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -152,7 +152,6 @@ module 8123.ko, which is built from the following files:: 8123_if.c 8123_if.h 8123_pci.c - 8123_bin.o_shipped <= Binary blob Shared Makefile --------------- @@ -170,7 +169,7 @@ Shared Makefile ifneq ($(KERNELRELEASE),) # kbuild part of makefile obj-m := 8123.o - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + 8123-y := 8123_if.o 8123_pci.o else # normal makefile @@ -179,10 +178,6 @@ Shared Makefile default: $(MAKE) -C $(KDIR) M=$$PWD - # Module specific targets - genbin: - echo "X" > 8123_bin.o_shipped - endif The check for KERNELRELEASE is used to separate the two parts @@ -204,7 +199,7 @@ Separate Kbuild File and Makefile --> filename: Kbuild obj-m := 8123.o - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + 8123-y := 8123_if.o 8123_pci.o --> filename: Makefile KDIR ?= /lib/modules/`uname -r`/build @@ -212,35 +207,11 @@ Separate Kbuild File and Makefile default: $(MAKE) -C $(KDIR) M=$$PWD - # Module specific targets - genbin: - echo "X" > 8123_bin.o_shipped - The split in example 2 is questionable due to the simplicity of each file; however, some external modules use makefiles consisting of several hundred lines, and here it really pays off to separate the kbuild part from the rest. -Binary Blobs ------------- - - Some external modules need to include an object file as a blob. - kbuild has support for this, but requires the blob file to be - named _shipped. When the kbuild rules kick in, a copy - of _shipped is created with _shipped stripped off, - giving us . This shortened filename can be used in - the assignment to the module. - - Throughout this section, 8123_bin.o_shipped has been used to - build the kernel module 8123.ko; it has been included as - 8123_bin.o:: - - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o - - Although there is no distinction between the ordinary source - files and the binary file, kbuild will pick up different rules - when creating the object file for the module. - Building Multiple Modules ------------------------- @@ -301,7 +272,7 @@ Single Subdirectory obj-m := 8123.o ccflags-y := -I $(src)/include - 8123-y := 8123_if.o 8123_pci.o 8123_bin.o + 8123-y := 8123_if.o 8123_pci.o Several Subdirectories ---------------------- From 2eb5d7f2429945aeb4730c7c310a0e1b5ae4c8d0 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Sep 2024 02:37:17 +0900 Subject: [PATCH 50/51] kbuild: doc: describe the -C option precisely for external module builds Building external modules is typically done using this command: $ make -C M= Here, refers to the output directory where the kernel was built, not the kernel source directory. When the kernel is built in the source tree, there is no ambiguity, as the output directory and the source directory are the same. If the kernel was built in a separate build directory, should be the kernel output directory. Otherwise, Kbuild cannot locate necessary build artifacts. This has been the method for building external modules against a pre-built kernel in a separate directory for over 20 years. [1] If you pass the kernel source directory to the -C option, you must also specify the kernel build directory using the O= option. This approach works as well, though it results in a slightly longer command: $ make -C O= M= Some people mistakenly believe that O= should specify a build directory for external modules when used together with M=. This commit adds more clarification to Documentation/kbuild/kbuild.rst. [1]: https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=e321b2ec2eb2993b3d0116e5163c78ad923e3c54 Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/kbuild.rst | 5 +++++ Documentation/kbuild/modules.rst | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Documentation/kbuild/kbuild.rst b/Documentation/kbuild/kbuild.rst index a0f7726c46f8..1796b3eba37b 100644 --- a/Documentation/kbuild/kbuild.rst +++ b/Documentation/kbuild/kbuild.rst @@ -134,6 +134,11 @@ KBUILD_OUTPUT ------------- 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. + The output directory can also be specified using "O=...". Setting "O=..." takes precedence over KBUILD_OUTPUT. diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index 080e11372351..b24448f789b3 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -45,7 +45,7 @@ Command Syntax The command to build an external module is:: - $ make -C M=$PWD + $ make -C M=$PWD The kbuild system knows that an external module is being built due to the "M=" option given in the command. @@ -62,12 +62,15 @@ Command Syntax Options ------- - ($KDIR refers to the path of the kernel source directory.) + ($KDIR refers to the path of the kernel source directory, or the path + of the kernel output directory if the kernel was built in a separate + build directory.) make -C $KDIR M=$PWD -C $KDIR - The directory where the kernel source is located. + The directory that contains the kernel and relevant build + artifacts used for building an external module. "make" will actually change to the specified directory when executing and will change back when finished. From fa911d1f377bbe4cc47e58afbd8fff7750b7ac62 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 20 Sep 2024 02:37:18 +0900 Subject: [PATCH 51/51] kbuild: doc: replace "gcc" in external module description Avoid "gcc" since it is not the only compiler supported by Kbuild. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/modules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index b24448f789b3..cd5a54d91e6d 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -9,7 +9,7 @@ Introduction "kbuild" is the build system used by the Linux kernel. Modules must use kbuild to stay compatible with changes in the build infrastructure and -to pick up the right flags to "gcc." Functionality for building modules +to pick up the right flags to the compiler. Functionality for building modules both in-tree and out-of-tree is provided. The method for building either is similar, and all modules are initially developed and built out-of-tree. @@ -256,7 +256,7 @@ Kernel Includes #include - kbuild will add options to "gcc" so the relevant directories + kbuild will add options to the compiler so the relevant directories are searched. Single Subdirectory