From ff2071a7b7fd77908417603c4a785822939b3841 Mon Sep 17 00:00:00 2001 From: Jose E. Marchesi Date: Sat, 27 Jan 2024 19:50:31 +0100 Subject: bpf: Generate const static pointers for kernel helpers The generated bpf_helper_defs.h file currently contains definitions like this for the kernel helpers, which are static objects: static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1; These work well in both clang and GCC because both compilers do constant propagation with -O1 and higher optimization, resulting in `call 1' BPF instructions being generated, which are calls to kernel helpers. However, there is a discrepancy on how the -Wunused-variable warning (activated by -Wall) is handled in these compilers: - clang will not emit -Wunused-variable warnings for static variables defined in C header files, be them constant or not constant. - GCC will not emit -Wunused-variable warnings for _constant_ static variables defined in header files, but it will emit warnings for non-constant static variables defined in header files. There is no reason for these bpf_helpers_def.h pointers to not be declared constant, and it is actually desirable to do so, since their values are not to be changed. So this patch modifies bpf_doc.py to generate prototypes like: static void *(* const bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1; This allows GCC to not error while compiling BPF programs with `-Wall -Werror', while still being able to detect and error on legitimate unused variables in the program themselves. This change doesn't impact the desired constant propagation in neither Clang nor GCC with -O1 and higher. On the contrary, being declared as constant may increase the odds they get constant folded when used/referred to in certain circumstances. Tested in bpf-next master. No regressions. Signed-off-by: Jose E. Marchesi Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20240127185031.29854-1-jose.marchesi@oracle.com --- scripts/bpf_doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index 61b7dddedc46..2b94749c99cc 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -827,7 +827,7 @@ class PrinterHelpers(Printer): print(' *{}{}'.format(' \t' if line else '', line)) print(' */') - print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), + print('static %s %s(* const %s)(' % (self.map_type(proto['ret_type']), proto['ret_star'], proto['name']), end='') comma = '' for i, a in enumerate(proto['args']): -- cgit v1.2.3 From e5a5276695b0df12eea8a694afc8bca87a8162a4 Mon Sep 17 00:00:00 2001 From: Anna-Maria Behnsen Date: Mon, 22 Jan 2024 10:31:52 +0100 Subject: scripts/kernel-doc: Do not process backslash lines in comments To prevent this, do the pre-processing only for lines which are no comments, e.g. do not start with ' *'. Suggested-by: Matthew Wilcox Signed-off-by: Anna-Maria Behnsen Tested-by: Randy Dunlap Acked-by: Daniel Vetter Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240122093152.22536-3-anna-maria@linutronix.de --- scripts/kernel-doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index e8aefd258a29..4277af79de86 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -2331,7 +2331,7 @@ sub process_file($) { $section_counter = 0; while () { - while (s/\\\s*$//) { + while (!/^ \*/ && s/\\\s*$//) { $_ .= ; } # Replace tabs by spaces -- cgit v1.2.3 From d2a70e28ef738765f9226731dfdb3b6c06565456 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 7 Jan 2024 16:37:00 -0800 Subject: kernel-doc: drop looking for "MACDOC" Linux kernel does not use "MACDOC" in any documenation or any source files, so stop searching for it. Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240108003700.13418-1-rdunlap@infradead.org --- scripts/kernel-doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 4277af79de86..915e7bd97486 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1907,7 +1907,7 @@ sub process_proto_function($$) { $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line - if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) { + if ($x =~ /^#/ && $x !~ /^#\s*define/) { # do nothing } elsif ($x =~ /([^\{]*)/) { -- cgit v1.2.3 From 36443018a2fa37461baf1aefd2eee10e6dc1c30f Mon Sep 17 00:00:00 2001 From: Andrew Ballance Date: Tue, 23 Jan 2024 22:39:18 -0600 Subject: docs: sphinx-pre-install fix-noto-sans-cjk on fedora fedora 38 and later changed the directory and package name that provides NotoSansCJK-Regular.ttc. this adds the new search path and suggests the correct package if on fedora 38 or later. Signed-off-by: Andrew Ballance Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240124043918.31771-1-andrewjballance@gmail.com --- scripts/sphinx-pre-install | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 25aefbb35377..948f284bfc8b 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -421,6 +421,7 @@ sub give_redhat_hints() # my $old = 0; my $rel; + my $noto_sans_redhat = "google-noto-sans-cjk-ttc-fonts"; $rel = $1 if ($system_release =~ /release\s+(\d+)/); if (!($system_release =~ /Fedora/)) { @@ -438,6 +439,9 @@ sub give_redhat_hints() if ($rel && $rel < 26) { $old = 1; } + if ($rel && $rel >= 38) { + $noto_sans_redhat = "google-noto-sans-cjk-fonts"; + } } if (!$rel) { printf("Couldn't identify release number\n"); @@ -446,8 +450,9 @@ sub give_redhat_hints() } if ($pdf) { - check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc"], - "google-noto-sans-cjk-ttc-fonts", 2); + check_missing_file(["/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc", + "/usr/share/fonts/google-noto-sans-cjk-fonts/NotoSansCJK-Regular.ttc"], + $noto_sans_redhat, 2); } check_rpm_missing(\@fedora26_opt_pkgs, 2) if ($pdf && !$old); -- cgit v1.2.3 From bbf00be93e09081ffa06e6fd84ed8f4e469a99d0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 31 Jan 2024 10:49:34 +0200 Subject: kernel-doc: Support arrays of pointers struct fields In a rather unusual arrangement in include/media/v4l2-vp9.h struct v4l2_vp9_frame_symbol_counts has fields that are arrays of pointers, not a pointer to an array, which is what's usually done. Add support for such arrays of pointers to kernel-doc. Signed-off-by: Sakari Ailus Acked-by: Randy Dunlap Tested-by: Randy Dunlap Tested-by: Ricardo Ribalda Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240131084934.191226-1-sakari.ailus@linux.intel.com --- scripts/kernel-doc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 915e7bd97486..014ef55351be 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1509,6 +1509,15 @@ sub create_parameterlist($$$$) { $type =~ s/([^\(]+\(\*?)\s*$param/$1/; save_struct_actual($param); push_parameter($param, $type, $arg, $file, $declaration_name); + } elsif ($arg =~ m/\(.+\)\s*\[/) { + # array-of-pointers + $arg =~ tr/#/,/; + $arg =~ m/[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)/; + $param = $1; + $type = $arg; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); } elsif ($arg) { $arg =~ s/\s*:\s*/:/g; $arg =~ s/\s*\[/\[/g; -- cgit v1.2.3 From 167ebeda36fae4bb47ace32bcacecde7d24d2850 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 23 Jan 2024 16:32:54 -0800 Subject: ubsan: Use Clang's -fsanitize-trap=undefined option Clang changed the way it enables UBSan trapping mode. Update the Makefile logic to discover it. Suggested-by: Fangrui Song Link: https://lore.kernel.org/lkml/CAFP8O3JivZh+AAV7N90Nk7U2BHRNST6MRP0zHtfQ-Vj0m4+pDA@mail.gmail.com/ Reviewed-by: Fangrui Song Reviewed-by: Justin Stitt Cc: Nathan Chancellor Cc: Masahiro Yamada Cc: Nicolas Schier Cc: Nick Desaulniers Cc: Bill Wendling Cc: linux-kbuild@vger.kernel.org Cc: llvm@lists.linux.dev Signed-off-by: Kees Cook --- scripts/Makefile.ubsan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 4749865c1b2c..7cf42231042b 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -10,6 +10,6 @@ ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum -ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error +ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error) export CFLAGS_UBSAN := $(ubsan-cflags-y) -- cgit v1.2.3 From 918327e9b7ffb45321cbb4b9b86b58ec555fe6b3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 28 Jan 2024 10:45:29 -0800 Subject: ubsan: Remove CONFIG_UBSAN_SANITIZE_ALL For simplicity in splitting out UBSan options into separate rules, remove CONFIG_UBSAN_SANITIZE_ALL, effectively defaulting to "y", which is how it is generally used anyway. (There are no ":= y" cases beyond where a specific file is enabled when a top-level ":= n" is in effect.) Cc: Andrey Konovalov Cc: Marco Elver Cc: linux-doc@vger.kernel.org Cc: linux-kbuild@vger.kernel.org Signed-off-by: Kees Cook --- Documentation/dev-tools/ubsan.rst | 28 ++++++++-------------------- arch/arm/Kconfig | 2 +- arch/arm64/Kconfig | 2 +- arch/mips/Kconfig | 2 +- arch/parisc/Kconfig | 2 +- arch/powerpc/Kconfig | 2 +- arch/riscv/Kconfig | 2 +- arch/s390/Kconfig | 2 +- arch/x86/Kconfig | 2 +- lib/Kconfig.ubsan | 13 +------------ scripts/Makefile.lib | 2 +- 11 files changed, 18 insertions(+), 41 deletions(-) (limited to 'scripts') diff --git a/Documentation/dev-tools/ubsan.rst b/Documentation/dev-tools/ubsan.rst index 2de7c63415da..e3591f8e9d5b 100644 --- a/Documentation/dev-tools/ubsan.rst +++ b/Documentation/dev-tools/ubsan.rst @@ -49,34 +49,22 @@ Report example Usage ----- -To enable UBSAN configure kernel with:: +To enable UBSAN, configure the kernel with:: - CONFIG_UBSAN=y + CONFIG_UBSAN=y -and to check the entire kernel:: - - CONFIG_UBSAN_SANITIZE_ALL=y - -To enable instrumentation for specific files or directories, add a line -similar to the following to the respective kernel Makefile: - -- For a single file (e.g. main.o):: - - UBSAN_SANITIZE_main.o := y - -- For all files in one directory:: - - UBSAN_SANITIZE := y - -To exclude files from being instrumented even if -``CONFIG_UBSAN_SANITIZE_ALL=y``, use:: +To exclude files from being instrumented use:: UBSAN_SANITIZE_main.o := n -and:: +and to exclude all targets in one directory use:: UBSAN_SANITIZE := n +When disabled for all targets, specific files can be enabled using:: + + UBSAN_SANITIZE_main.o := y + Detection of unaligned accesses controlled through the separate option - CONFIG_UBSAN_ALIGNMENT. It's off by default on architectures that support unaligned accesses (CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y). One could diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0af6709570d1..287e62522064 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -29,7 +29,7 @@ config ARM select ARCH_HAVE_NMI_SAFE_CMPXCHG if CPU_V7 || CPU_V7M || CPU_V6K select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_KEEP_MEMBLOCK - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7 diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index aa7c1d435139..78533d1b7f35 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -107,7 +107,7 @@ config ARM64 select ARCH_WANT_LD_ORPHAN_WARN select ARCH_WANTS_NO_INSTR select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARM_AMBA select ARM_ARCH_TIMER select ARM_GIC diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 797ae590ebdb..9750ce3e40d5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -14,7 +14,7 @@ config MIPS select ARCH_HAS_STRNCPY_FROM_USER select ARCH_HAS_STRNLEN_USER select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_KEEP_MEMBLOCK select ARCH_USE_BUILTIN_BSWAP diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index d14ccc948a29..dbc9027ea2f4 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -12,7 +12,7 @@ config PARISC select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_MODULE_RWX - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_HAS_PTE_SPECIAL select ARCH_NO_SG_CHAIN select ARCH_SUPPORTS_HUGETLBFS if PA20 diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b9fc064d38d2..2065973e09d2 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -154,7 +154,7 @@ config PPC select ARCH_HAS_SYSCALL_WRAPPER if !SPU_BASE && !COMPAT select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_UACCESS_FLUSHCACHE - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_KEEP_MEMBLOCK select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE if PPC_RADIX_MMU diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bffbd869a068..d824d113a02d 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -37,7 +37,7 @@ config RISCV select ARCH_HAS_STRICT_MODULE_RWX if MMU && !XIP_KERNEL select ARCH_HAS_SYSCALL_WRAPPER select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_HAS_VDSO_DATA select ARCH_KEEP_MEMBLOCK if ACPI select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index fe565f3a3a91..97dd25521617 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -82,7 +82,7 @@ config S390 select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_MODULE_RWX select ARCH_HAS_SYSCALL_WRAPPER - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_HAS_VDSO_DATA select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_INLINE_READ_LOCK diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5edec175b9bf..1c4c326a3640 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -100,7 +100,7 @@ config X86 select ARCH_HAS_STRICT_MODULE_RWX select ARCH_HAS_SYNC_CORE_BEFORE_USERMODE select ARCH_HAS_SYSCALL_WRAPPER - select ARCH_HAS_UBSAN_SANITIZE_ALL + select ARCH_HAS_UBSAN select ARCH_HAS_DEBUG_WX select ARCH_HAS_ZONE_DMA_SET if EXPERT select ARCH_HAVE_NMI_SAFE_CMPXCHG diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index 59e21bfec188..56d7653f4941 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -config ARCH_HAS_UBSAN_SANITIZE_ALL +config ARCH_HAS_UBSAN bool menuconfig UBSAN @@ -142,17 +142,6 @@ config UBSAN_ALIGNMENT Enabling this option on architectures that support unaligned accesses may produce a lot of false positives. -config UBSAN_SANITIZE_ALL - bool "Enable instrumentation for the entire kernel" - depends on ARCH_HAS_UBSAN_SANITIZE_ALL - default y - help - This option activates instrumentation for the entire kernel. - If you don't enable this option, you have to explicitly specify - UBSAN_SANITIZE := y for the files/directories you want to check for UB. - Enabling this option will get kernel image size increased - significantly. - config TEST_UBSAN tristate "Module for testing for undefined behavior detection" depends on m diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index cd5b181060f1..52efc520ae4f 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -175,7 +175,7 @@ endif ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \ + $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)y), \ $(CFLAGS_UBSAN)) endif -- cgit v1.2.3 From dcf0926e9b899eca754a07c4064de69815b85a38 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Jan 2024 15:15:43 -0500 Subject: x86: replace CONFIG_HAVE_KVM with IS_ENABLED(CONFIG_KVM) It is more accurate to check if KVM is enabled, instead of having the architecture say so. Architectures always "have" KVM, so for example checking CONFIG_HAVE_KVM in x86 code is pointless, but if KVM is disabled in a specific build, there is no need for support code. Alternatively, many of the #ifdefs could simply be deleted. However, this would add completely dead code. For example, when KVM is disabled, there should not be any posted interrupts, i.e. NOT wiring up the "dummy" handlers and treating IRQs on those vectors as spurious is the right thing to do. Cc: x86@kernel.org Cc: kbingham@kernel.org Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/hardirq.h | 2 +- arch/x86/include/asm/idtentry.h | 2 +- arch/x86/include/asm/irq.h | 2 +- arch/x86/include/asm/irq_vectors.h | 2 +- arch/x86/kernel/idt.c | 2 +- arch/x86/kernel/irq.c | 4 ++-- scripts/gdb/linux/constants.py.in | 6 +++++- scripts/gdb/linux/interrupts.py | 2 +- tools/arch/x86/include/asm/irq_vectors.h | 2 +- 9 files changed, 14 insertions(+), 10 deletions(-) (limited to 'scripts') diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 66837b8c67f1..fbc7722b87d1 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -15,7 +15,7 @@ typedef struct { unsigned int irq_spurious_count; unsigned int icr_read_retry_count; #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) unsigned int kvm_posted_intr_ipis; unsigned int kvm_posted_intr_wakeup_ipis; unsigned int kvm_posted_intr_nested_ipis; diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 13639e57e1f8..d9c86733d0db 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -675,7 +675,7 @@ DECLARE_IDTENTRY_SYSVEC(IRQ_WORK_VECTOR, sysvec_irq_work); # endif #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_VECTOR, sysvec_kvm_posted_intr_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_WAKEUP_VECTOR, sysvec_kvm_posted_intr_wakeup_ipi); DECLARE_IDTENTRY_SYSVEC(POSTED_INTR_NESTED_VECTOR, sysvec_kvm_posted_intr_nested_ipi); diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 836c170d3087..194dfff84cb1 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -29,7 +29,7 @@ struct irq_desc; extern void fixup_irqs(void); -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void)); #endif diff --git a/arch/x86/include/asm/irq_vectors.h b/arch/x86/include/asm/irq_vectors.h index 3a19904c2db6..3f73ac3ed3a0 100644 --- a/arch/x86/include/asm/irq_vectors.h +++ b/arch/x86/include/asm/irq_vectors.h @@ -84,7 +84,7 @@ #define HYPERVISOR_CALLBACK_VECTOR 0xf3 /* Vector for KVM to deliver posted interrupt IPI */ -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) #define POSTED_INTR_VECTOR 0xf2 #define POSTED_INTR_WAKEUP_VECTOR 0xf1 #define POSTED_INTR_NESTED_VECTOR 0xf0 diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index 660b601f1d6c..d2bc67cbaf92 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -153,7 +153,7 @@ static const __initconst struct idt_data apic_idts[] = { #ifdef CONFIG_X86_LOCAL_APIC INTG(LOCAL_TIMER_VECTOR, asm_sysvec_apic_timer_interrupt), INTG(X86_PLATFORM_IPI_VECTOR, asm_sysvec_x86_platform_ipi), -# ifdef CONFIG_HAVE_KVM +# if IS_ENABLED(CONFIG_KVM) INTG(POSTED_INTR_VECTOR, asm_sysvec_kvm_posted_intr_ipi), INTG(POSTED_INTR_WAKEUP_VECTOR, asm_sysvec_kvm_posted_intr_wakeup_ipi), INTG(POSTED_INTR_NESTED_VECTOR, asm_sysvec_kvm_posted_intr_nested_ipi), diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 11761c124545..35fde0107901 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -164,7 +164,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) #if defined(CONFIG_X86_IO_APIC) seq_printf(p, "%*s: %10u\n", prec, "MIS", atomic_read(&irq_mis_count)); #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) seq_printf(p, "%*s: ", prec, "PIN"); for_each_online_cpu(j) seq_printf(p, "%10u ", irq_stats(j)->kvm_posted_intr_ipis); @@ -290,7 +290,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platform_ipi) } #endif -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) static void dummy_handler(void) {} static void (*kvm_posted_intr_wakeup_handler)(void) = dummy_handler; diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in index e810e0c27ff1..5cace7588e24 100644 --- a/scripts/gdb/linux/constants.py.in +++ b/scripts/gdb/linux/constants.py.in @@ -130,7 +130,11 @@ LX_CONFIG(CONFIG_X86_MCE_THRESHOLD) LX_CONFIG(CONFIG_X86_MCE_AMD) LX_CONFIG(CONFIG_X86_MCE) LX_CONFIG(CONFIG_X86_IO_APIC) -LX_CONFIG(CONFIG_HAVE_KVM) +/* + * CONFIG_KVM can be "m" but it affects common code too. Use CONFIG_KVM_COMMON + * as a proxy for IS_ENABLED(CONFIG_KVM). + */ +LX_CONFIG_KVM = IS_BUILTIN(CONFIG_KVM_COMMON) LX_CONFIG(CONFIG_NUMA) LX_CONFIG(CONFIG_ARM64) LX_CONFIG(CONFIG_ARM64_4K_PAGES) diff --git a/scripts/gdb/linux/interrupts.py b/scripts/gdb/linux/interrupts.py index ef478e273791..66ae5c7690cf 100644 --- a/scripts/gdb/linux/interrupts.py +++ b/scripts/gdb/linux/interrupts.py @@ -151,7 +151,7 @@ def x86_show_interupts(prec): if cnt is not None: text += "%*s: %10u\n" % (prec, "MIS", cnt['counter']) - if constants.LX_CONFIG_HAVE_KVM: + if constants.LX_CONFIG_KVM: text += x86_show_irqstat(prec, "PIN", 'kvm_posted_intr_ipis', 'Posted-interrupt notification event') text += x86_show_irqstat(prec, "NPI", 'kvm_posted_intr_nested_ipis', 'Nested posted-interrupt event') text += x86_show_irqstat(prec, "PIW", 'kvm_posted_intr_wakeup_ipis', 'Posted-interrupt wakeup event') diff --git a/tools/arch/x86/include/asm/irq_vectors.h b/tools/arch/x86/include/asm/irq_vectors.h index 3a19904c2db6..3f73ac3ed3a0 100644 --- a/tools/arch/x86/include/asm/irq_vectors.h +++ b/tools/arch/x86/include/asm/irq_vectors.h @@ -84,7 +84,7 @@ #define HYPERVISOR_CALLBACK_VECTOR 0xf3 /* Vector for KVM to deliver posted interrupt IPI */ -#ifdef CONFIG_HAVE_KVM +#if IS_ENABLED(CONFIG_KVM) #define POSTED_INTR_VECTOR 0xf2 #define POSTED_INTR_WAKEUP_VECTOR 0xf1 #define POSTED_INTR_NESTED_VECTOR 0xf0 -- cgit v1.2.3 From f82811e22b480a203a438d8e1f29af9c93ccbb0c Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Fri, 20 Oct 2023 16:50:55 +0100 Subject: rust: Refactor the build target to allow the use of builtin targets Eventually we want all architectures to be using the target as defined by rustc. However currently some architectures can't do that and are using the target.json specification. This puts in place the foundation to allow the use of the builtin target definition or a target.json specification. Signed-off-by: Jamie Cunliffe Acked-by: Masahiro Yamada Tested-by: Alice Ryhl Link: https://lore.kernel.org/r/20231020155056.3495121-2-Jamie.Cunliffe@arm.com [catalin.marinas@arm.com: squashed loongarch ifneq fix from WANG Rui] Signed-off-by: Catalin Marinas --- Makefile | 1 - arch/loongarch/Makefile | 1 + arch/x86/Makefile | 1 + rust/Makefile | 5 ++++- scripts/Makefile | 4 +++- 5 files changed, 9 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/Makefile b/Makefile index a171eafce2a3..c951c14fd4e7 100644 --- a/Makefile +++ b/Makefile @@ -561,7 +561,6 @@ KBUILD_CFLAGS += -fno-strict-aliasing KBUILD_CPPFLAGS := -D__KERNEL__ KBUILD_RUSTFLAGS := $(rust_common_flags) \ - --target=$(objtree)/scripts/target.json \ -Cpanic=abort -Cembed-bitcode=n -Clto=n \ -Cforce-unwind-tables=n -Ccodegen-units=1 \ -Csymbol-mangling-version=v0 \ diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index 983aa2b1629a..fa4fb09909ae 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -82,6 +82,7 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs endif +KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json KBUILD_RUSTFLAGS_MODULE += -Crelocation-model=pic ifeq ($(CONFIG_RELOCATABLE),y) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 2264db14a25d..18cf8f0cf7cd 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -68,6 +68,7 @@ export BITS # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53383 # KBUILD_CFLAGS += -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx +KBUILD_RUSTFLAGS += --target=$(objtree)/scripts/target.json KBUILD_RUSTFLAGS += -Ctarget-feature=-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2 ifeq ($(CONFIG_X86_KERNEL_IBT),y) diff --git a/rust/Makefile b/rust/Makefile index 9d2a16cc91cb..88f88a26e503 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -434,8 +434,11 @@ $(obj)/core.o: private skip_clippy = 1 $(obj)/core.o: private skip_flags = -Dunreachable_pub $(obj)/core.o: private rustc_objcopy = $(foreach sym,$(redirect-intrinsics),--redefine-sym $(sym)=__rust$(sym)) $(obj)/core.o: private rustc_target_flags = $(core-cfgs) -$(obj)/core.o: $(RUST_LIB_SRC)/core/src/lib.rs scripts/target.json FORCE +$(obj)/core.o: $(RUST_LIB_SRC)/core/src/lib.rs FORCE $(call if_changed_dep,rustc_library) +ifneq ($(or $(CONFIG_X86_64),$(CONFIG_LOONGARCH)),) +$(obj)/core.o: scripts/target.json +endif $(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*' $(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE diff --git a/scripts/Makefile b/scripts/Makefile index 576cf64be667..6673cbb6194f 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -11,12 +11,14 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen -always-$(CONFIG_RUST) += target.json +ifneq ($(or $(CONFIG_X86_64),$(CONFIG_LOONGARCH)),) +always-$(CONFIG_RUST) += target.json filechk_rust_target = $< < include/config/auto.conf $(obj)/target.json: scripts/generate_rust_target include/config/auto.conf FORCE $(call filechk,rust_target) +endif hostprogs += generate_rust_target generate_rust_target-rust := y -- cgit v1.2.3 From 724a75ac9542fe1f8aaa587da4d3863d8ea292fc Mon Sep 17 00:00:00 2001 From: Jamie Cunliffe Date: Fri, 20 Oct 2023 16:50:56 +0100 Subject: arm64: rust: Enable Rust support for AArch64 This commit provides the build flags for Rust for AArch64. The core Rust support already in the kernel does the rest. This enables the PAC ret and BTI options in the Rust build flags to match the options that are used when building C. The Rust samples have been tested with this commit. Signed-off-by: Jamie Cunliffe Acked-by: Will Deacon Tested-by: Dirk Behme Tested-by: Boqun Feng Acked-by: Miguel Ojeda Acked-by: Catalin Marinas Tested-by: Alice Ryhl Tested-by: Fabien Parent Link: https://lore.kernel.org/r/20231020155056.3495121-3-Jamie.Cunliffe@arm.com Signed-off-by: Catalin Marinas --- Documentation/rust/arch-support.rst | 1 + arch/arm64/Kconfig | 1 + arch/arm64/Makefile | 4 ++++ rust/Makefile | 1 + scripts/generate_rust_target.rs | 4 +++- 5 files changed, 10 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/Documentation/rust/arch-support.rst b/Documentation/rust/arch-support.rst index 73203ba1e901..5c4fa9f5d1cd 100644 --- a/Documentation/rust/arch-support.rst +++ b/Documentation/rust/arch-support.rst @@ -15,6 +15,7 @@ support corresponds to ``S`` values in the ``MAINTAINERS`` file. ============= ================ ============================================== Architecture Level of support Constraints ============= ================ ============================================== +``arm64`` Maintained Little Endian only. ``loongarch`` Maintained - ``um`` Maintained ``x86_64`` only. ``x86`` Maintained ``x86_64`` only. diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index aa7c1d435139..8a5f3823242c 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -229,6 +229,7 @@ config ARM64 select HAVE_FUNCTION_ARG_ACCESS_API select MMU_GATHER_RCU_TABLE_FREE select HAVE_RSEQ + select HAVE_RUST if CPU_LITTLE_ENDIAN select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index a88cdf910687..0e075d3c546b 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -41,6 +41,8 @@ KBUILD_CFLAGS += -mgeneral-regs-only \ KBUILD_CFLAGS += $(call cc-disable-warning, psabi) KBUILD_AFLAGS += $(compat_vdso) +KBUILD_RUSTFLAGS += --target=aarch64-unknown-none -Ctarget-feature="-neon" + KBUILD_CFLAGS += $(call cc-option,-mabi=lp64) KBUILD_AFLAGS += $(call cc-option,-mabi=lp64) @@ -65,7 +67,9 @@ endif ifeq ($(CONFIG_ARM64_BTI_KERNEL),y) KBUILD_CFLAGS += -mbranch-protection=pac-ret+bti + KBUILD_RUSTFLAGS += -Zbranch-protection=bti,pac-ret else ifeq ($(CONFIG_ARM64_PTR_AUTH_KERNEL),y) + KBUILD_RUSTFLAGS += -Zbranch-protection=pac-ret ifeq ($(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET),y) KBUILD_CFLAGS += -mbranch-protection=pac-ret else diff --git a/rust/Makefile b/rust/Makefile index 88f88a26e503..fe045dbc701e 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -297,6 +297,7 @@ bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \ # Derived from `scripts/Makefile.clang`. BINDGEN_TARGET_x86 := x86_64-linux-gnu +BINDGEN_TARGET_arm64 := aarch64-linux-gnu BINDGEN_TARGET := $(BINDGEN_TARGET_$(SRCARCH)) # All warnings are inhibited since GCC builds are very experimental, diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 0da52b548ba5..9e117957ea7b 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -148,7 +148,9 @@ fn main() { let mut ts = TargetSpec::new(); // `llvm-target`s are taken from `scripts/Makefile.clang`. - if cfg.has("X86_64") { + if cfg.has("ARM64") { + panic!("arm64 uses the builtin rustc aarch64-unknown-none target"); + } else if cfg.has("X86_64") { ts.push("arch", "x86_64"); ts.push( "data-layout", -- cgit v1.2.3 From 84b4cc8189f222ff3e32ea9d09afb7ae4a4a4205 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Thu, 8 Feb 2024 21:55:51 +0100 Subject: docs: scripts: sphinx-pre-install: Fix building docs with pyyaml package The Python module pyyaml is required to build the docs, but it is only listed in Documentation/sphinx/requirements.txt and is therefore missing when Sphinx is installed as a package and not via pip/pypi. Add pyyaml as an optional package for multiple distros to fix building the docs if you prefer to install Sphinx as a package. Signed-off-by: Thorsten Blum Reviewed-by: Vegard Nossum Tested-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240208205550.984-1-thorsten.blum@toblux.com --- scripts/sphinx-pre-install | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'scripts') diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index 948f284bfc8b..de0de5dd676e 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -361,6 +361,7 @@ sub give_debian_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-yaml", "ensurepip" => "python3-venv", "virtualenv" => "virtualenv", "dot" => "graphviz", @@ -395,6 +396,7 @@ sub give_redhat_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-pyyaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -477,6 +479,7 @@ sub give_opensuse_hints() { my %map = ( "python-sphinx" => "python3-sphinx", + "yaml" => "python3-pyyaml", "virtualenv" => "python3-virtualenv", "dot" => "graphviz", "convert" => "ImageMagick", @@ -956,6 +959,7 @@ sub check_needs() # Check for needed programs/tools check_perl_module("Pod::Usage", 0); + check_python_module("yaml", 0); check_program("make", 0); check_program("gcc", 0); check_program("dot", 1); -- cgit v1.2.3 From af404fb1ed2a19bd30f5e50bfb4f93a42737a6eb Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 8 Feb 2024 17:17:05 +0100 Subject: scripts/kernel-doc: reindent This file is using an ungodly mixture of 4 spaces, 2-wide tabs, 4-wide tabs, _and_ 8-wide tabs, making it really hard to find good editor settings for working with this file. Bite the bullet and reindent it by hand. I tried using both perltidy and vim, but neither of them were up to the task without changing too much or getting confused about what they were supposed to be doing. I did change a few instances of } else into } else (and same for elsif); the file is again written using both styles, and I left functions which already seemed self-consistent alone. You can verify that this commit only changes whitespace using e.g.: git diff --ignore-all-space --word-diff or to see (only) the instances where newlines were added/removed: git diff --ignore-all-space You can also see the delta from what perltidy would have wanted to do to this file (when asked to only indent it), which isn't that much in the end: perltidy -io -fnl scripts/kernel-doc git diff --no-index scripts/kernel-doc{,.tdy} Signed-off-by: Vegard Nossum Acked-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240208161705.888385-1-vegard.nossum@oracle.com --- scripts/kernel-doc | 2522 ++++++++++++++++++++++++++-------------------------- 1 file changed, 1258 insertions(+), 1264 deletions(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 014ef55351be..a9947080ead3 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -81,49 +81,51 @@ my $type_member_func = $type_member . '\(\)'; # these are pretty rough my @highlights_man = ( - [$type_constant, "\$1"], - [$type_constant2, "\$1"], - [$type_func, "\\\\fB\$1\\\\fP"], - [$type_enum, "\\\\fI\$1\\\\fP"], - [$type_struct, "\\\\fI\$1\\\\fP"], - [$type_typedef, "\\\\fI\$1\\\\fP"], - [$type_union, "\\\\fI\$1\\\\fP"], - [$type_param, "\\\\fI\$1\\\\fP"], - [$type_param_ref, "\\\\fI\$1\$2\\\\fP"], - [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], - [$type_fallback, "\\\\fI\$1\\\\fP"] - ); + [$type_constant, "\$1"], + [$type_constant2, "\$1"], + [$type_func, "\\\\fB\$1\\\\fP"], + [$type_enum, "\\\\fI\$1\\\\fP"], + [$type_struct, "\\\\fI\$1\\\\fP"], + [$type_typedef, "\\\\fI\$1\\\\fP"], + [$type_union, "\\\\fI\$1\\\\fP"], + [$type_param, "\\\\fI\$1\\\\fP"], + [$type_param_ref, "\\\\fI\$1\$2\\\\fP"], + [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], + [$type_fallback, "\\\\fI\$1\\\\fP"] + ); my $blankline_man = ""; # rst-mode my @highlights_rst = ( - [$type_constant, "``\$1``"], - [$type_constant2, "``\$1``"], - # Note: need to escape () to avoid func matching later - [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], - [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], - [$type_fp_param, "**\$1\\\\(\\\\)**"], - [$type_fp_param2, "**\$1\\\\(\\\\)**"], - [$type_func, "\$1()"], - [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], - [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], - [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], - [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], - # in rst this can refer to any type - [$type_fallback, "\\:c\\:type\\:`\$1`"], - [$type_param_ref, "**\$1\$2**"] - ); + [$type_constant, "``\$1``"], + [$type_constant2, "``\$1``"], + + # Note: need to escape () to avoid func matching later + [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], + [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], + [$type_fp_param, "**\$1\\\\(\\\\)**"], + [$type_fp_param2, "**\$1\\\\(\\\\)**"], + [$type_func, "\$1()"], + [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], + + # in rst this can refer to any type + [$type_fallback, "\\:c\\:type\\:`\$1`"], + [$type_param_ref, "**\$1\$2**"] + ); my $blankline_rst = "\n"; # read arguments if ($#ARGV == -1) { - pod2usage( - -message => "No arguments!\n", - -exitval => 1, - -verbose => 99, - -sections => 'SYNOPSIS', - -output => \*STDERR, - ); + pod2usage( + -message => "No arguments!\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } my $kernelversion; @@ -164,9 +166,9 @@ if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && } my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', - 'November', 'December')[$build_time[4]] . - " " . ($build_time[5]+1900); + 'July', 'August', 'September', 'October', + 'November', 'December')[$build_time[4]] . + " " . ($build_time[5]+1900); # Essentially these are globals. # They probably want to be tidied up, made more localised or something. @@ -179,22 +181,22 @@ my ($type, $declaration_name, $return_type); my ($newsection, $newcontents, $prototype, $brcount, %source_map); if (defined($ENV{'KBUILD_VERBOSE'}) && $ENV{'KBUILD_VERBOSE'} =~ '1') { - $verbose = 1; + $verbose = 1; } if (defined($ENV{'KCFLAGS'})) { - my $kcflags = "$ENV{'KCFLAGS'}"; + my $kcflags = "$ENV{'KCFLAGS'}"; - if ($kcflags =~ /(\s|^)-Werror(\s|$)/) { - $Werror = 1; - } + if ($kcflags =~ /(\s|^)-Werror(\s|$)/) { + $Werror = 1; + } } # reading this variable is for backwards compat just in case # someone was calling it with the variable from outside the # kernel's build system if (defined($ENV{'KDOC_WERROR'})) { - $Werror = "$ENV{'KDOC_WERROR'}"; + $Werror = "$ENV{'KDOC_WERROR'}"; } # other environment variables are converted to command-line # arguments in cmd_checkdoc in the build system @@ -295,90 +297,90 @@ while ($ARGV[0] =~ m/^--?(.*)/) { my $cmd = $1; shift @ARGV; if ($cmd eq "man") { - $output_mode = "man"; - @highlights = @highlights_man; - $blankline = $blankline_man; + $output_mode = "man"; + @highlights = @highlights_man; + $blankline = $blankline_man; } elsif ($cmd eq "rst") { - $output_mode = "rst"; - @highlights = @highlights_rst; - $blankline = $blankline_rst; + $output_mode = "rst"; + @highlights = @highlights_rst; + $blankline = $blankline_rst; } elsif ($cmd eq "none") { - $output_mode = "none"; + $output_mode = "none"; } elsif ($cmd eq "module") { # not needed for XML, inherits from calling document - $modulename = shift @ARGV; + $modulename = shift @ARGV; } elsif ($cmd eq "function") { # to only output specific functions - $output_selection = OUTPUT_INCLUDE; - $function = shift @ARGV; - $function_table{$function} = 1; + $output_selection = OUTPUT_INCLUDE; + $function = shift @ARGV; + $function_table{$function} = 1; } elsif ($cmd eq "nosymbol") { # Exclude specific symbols - my $symbol = shift @ARGV; - $nosymbol_table{$symbol} = 1; + my $symbol = shift @ARGV; + $nosymbol_table{$symbol} = 1; } elsif ($cmd eq "export") { # only exported symbols - $output_selection = OUTPUT_EXPORTED; - %function_table = (); + $output_selection = OUTPUT_EXPORTED; + %function_table = (); } elsif ($cmd eq "internal") { # only non-exported symbols - $output_selection = OUTPUT_INTERNAL; - %function_table = (); + $output_selection = OUTPUT_INTERNAL; + %function_table = (); } elsif ($cmd eq "export-file") { - my $file = shift @ARGV; - push(@export_file_list, $file); + my $file = shift @ARGV; + push(@export_file_list, $file); } elsif ($cmd eq "v") { - $verbose = 1; + $verbose = 1; } elsif ($cmd eq "Werror") { - $Werror = 1; + $Werror = 1; } elsif ($cmd eq "Wreturn") { - $Wreturn = 1; + $Wreturn = 1; } elsif ($cmd eq "Wshort-desc" or $cmd eq "Wshort-description") { - $Wshort_desc = 1; + $Wshort_desc = 1; } elsif ($cmd eq "Wcontents-before-sections") { - $Wcontents_before_sections = 1; + $Wcontents_before_sections = 1; } elsif ($cmd eq "Wall") { $Wreturn = 1; $Wshort_desc = 1; $Wcontents_before_sections = 1; } elsif (($cmd eq "h") || ($cmd eq "help")) { - pod2usage(-exitval => 0, -verbose => 2); + pod2usage(-exitval => 0, -verbose => 2); } elsif ($cmd eq 'no-doc-sections') { - $no_doc_sections = 1; + $no_doc_sections = 1; } elsif ($cmd eq 'enable-lineno') { - $enable_lineno = 1; + $enable_lineno = 1; } elsif ($cmd eq 'show-not-found') { - $show_not_found = 1; # A no-op but don't fail + $show_not_found = 1; # A no-op but don't fail } elsif ($cmd eq "sphinx-version") { - my $ver_string = shift @ARGV; - if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) { - $sphinx_major = $1; - if (defined($2)) { - $sphinx_minor = substr($2,1); - } else { - $sphinx_minor = 0; - } - if (defined($3)) { - $sphinx_patch = substr($3,1) - } else { - $sphinx_patch = 0; - } - } else { - die "Sphinx version should either major.minor or major.minor.patch format\n"; - } + my $ver_string = shift @ARGV; + if ($ver_string =~ m/^(\d+)(\.\d+)?(\.\d+)?/) { + $sphinx_major = $1; + if (defined($2)) { + $sphinx_minor = substr($2,1); + } else { + $sphinx_minor = 0; + } + if (defined($3)) { + $sphinx_patch = substr($3,1) + } else { + $sphinx_patch = 0; + } + } else { + die "Sphinx version should either major.minor or major.minor.patch format\n"; + } } else { - # Unknown argument - pod2usage( - -message => "Argument unknown!\n", - -exitval => 1, - -verbose => 99, - -sections => 'SYNOPSIS', - -output => \*STDERR, - ); + # Unknown argument + pod2usage( + -message => "Argument unknown!\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } if ($#ARGV < 0){ - pod2usage( - -message => "FILE argument missing\n", - -exitval => 1, - -verbose => 99, - -sections => 'SYNOPSIS', - -output => \*STDERR, - ); + pod2usage( + -message => "FILE argument missing\n", + -exitval => 1, + -verbose => 99, + -sections => 'SYNOPSIS', + -output => \*STDERR, + ); } } @@ -388,45 +390,45 @@ while ($ARGV[0] =~ m/^--?(.*)/) { # version in order to produce the right tags. sub findprog($) { - foreach(split(/:/, $ENV{PATH})) { - return "$_/$_[0]" if(-x "$_/$_[0]"); - } + foreach(split(/:/, $ENV{PATH})) { + return "$_/$_[0]" if(-x "$_/$_[0]"); + } } sub get_sphinx_version() { - my $ver; - - my $cmd = "sphinx-build"; - if (!findprog($cmd)) { - my $cmd = "sphinx-build3"; - if (!findprog($cmd)) { - $sphinx_major = 1; - $sphinx_minor = 2; - $sphinx_patch = 0; - printf STDERR "Warning: Sphinx version not found. Using default (Sphinx version %d.%d.%d)\n", - $sphinx_major, $sphinx_minor, $sphinx_patch; - return; - } - } - - open IN, "$cmd --version 2>&1 |"; - while () { - if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) { - $sphinx_major = $1; - $sphinx_minor = $2; - $sphinx_patch = $3; - last; - } - # Sphinx 1.2.x uses a different format - if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) { - $sphinx_major = $1; - $sphinx_minor = $2; - $sphinx_patch = $3; - last; - } - } - close IN; + my $ver; + + my $cmd = "sphinx-build"; + if (!findprog($cmd)) { + my $cmd = "sphinx-build3"; + if (!findprog($cmd)) { + $sphinx_major = 1; + $sphinx_minor = 2; + $sphinx_patch = 0; + printf STDERR "Warning: Sphinx version not found. Using default (Sphinx version %d.%d.%d)\n", + $sphinx_major, $sphinx_minor, $sphinx_patch; + return; + } + } + + open IN, "$cmd --version 2>&1 |"; + while () { + if (m/^\s*sphinx-build\s+([\d]+)\.([\d\.]+)(\+\/[\da-f]+)?$/) { + $sphinx_major = $1; + $sphinx_minor = $2; + $sphinx_patch = $3; + last; + } + # Sphinx 1.2.x uses a different format + if (m/^\s*Sphinx.*\s+([\d]+)\.([\d\.]+)$/) { + $sphinx_major = $1; + $sphinx_minor = $2; + $sphinx_patch = $3; + last; + } + } + close IN; } # get kernel version from env @@ -434,7 +436,7 @@ sub get_kernel_version() { my $version = 'unknown kernel version'; if (defined($ENV{'KERNELVERSION'})) { - $version = $ENV{'KERNELVERSION'}; + $version = $ENV{'KERNELVERSION'}; } return $version; } @@ -462,30 +464,30 @@ sub dump_section { my $contents = join "\n", @_; if ($name =~ m/$type_param/) { - $name = $1; - $parameterdescs{$name} = $contents; - $sectcheck = $sectcheck . $name . " "; + $name = $1; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; $parameterdesc_start_lines{$name} = $new_start_line; $new_start_line = 0; } elsif ($name eq "@\.\.\.") { - $name = "..."; - $parameterdescs{$name} = $contents; - $sectcheck = $sectcheck . $name . " "; + $name = "..."; + $parameterdescs{$name} = $contents; + $sectcheck = $sectcheck . $name . " "; $parameterdesc_start_lines{$name} = $new_start_line; $new_start_line = 0; } else { - if (defined($sections{$name}) && ($sections{$name} ne "")) { - # Only warn on user specified duplicate section names. - if ($name ne $section_default) { - emit_warning("${file}:$.", "duplicate section name '$name'\n"); - } - $sections{$name} .= $contents; - } else { - $sections{$name} = $contents; - push @sectionlist, $name; + if (defined($sections{$name}) && ($sections{$name} ne "")) { + # Only warn on user specified duplicate section names. + if ($name ne $section_default) { + emit_warning("${file}:$.", "duplicate section name '$name'\n"); + } + $sections{$name} .= $contents; + } else { + $sections{$name} = $contents; + push @sectionlist, $name; $section_start_lines{$name} = $new_start_line; $new_start_line = 0; - } + } } } @@ -504,14 +506,14 @@ sub dump_doc_section { return if (defined($nosymbol_table{$name})); if (($output_selection == OUTPUT_ALL) || - (($output_selection == OUTPUT_INCLUDE) && - defined($function_table{$name}))) + (($output_selection == OUTPUT_INCLUDE) && + defined($function_table{$name}))) { - dump_section($file, $name, $contents); - output_blockhead({'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'module' => $modulename, - 'content-only' => ($output_selection != OUTPUT_ALL), }); + dump_section($file, $name, $contents); + output_blockhead({'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'module' => $modulename, + 'content-only' => ($output_selection != OUTPUT_ALL), }); } } @@ -542,21 +544,21 @@ sub output_highlight { # print STDERR "contents af:$contents\n"; foreach $line (split "\n", $contents) { - if (! $output_preformatted) { - $line =~ s/^\s*//; - } - if ($line eq ""){ - if (! $output_preformatted) { - print $lineprefix, $blankline; - } - } else { - if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { - print "\\&$line"; - } else { - print $lineprefix, $line; - } - } - print "\n"; + if (! $output_preformatted) { + $line =~ s/^\s*//; + } + if ($line eq ""){ + if (! $output_preformatted) { + print $lineprefix, $blankline; + } + } else { + if ($output_mode eq "man" && substr($line, 0, 1) eq ".") { + print "\\&$line"; + } else { + print $lineprefix, $line; + } + } + print "\n"; } } @@ -574,40 +576,40 @@ sub output_function_man(%) { print ".SH SYNOPSIS\n"; if ($args{'functiontype'} ne "") { - print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; + print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n"; } else { - print ".B \"" . $args{'function'} . "\n"; + print ".B \"" . $args{'function'} . "\n"; } $count = 0; my $parenth = "("; my $post = ","; foreach my $parameter (@{$args{'parameterlist'}}) { - if ($count == $#{$args{'parameterlist'}}) { - $post = ");"; - } - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/$function_pointer/) { - # pointer-to-function - print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n"; - } else { - $type =~ s/([^\*])$/$1 /; - print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n"; - } - $count++; - $parenth = ""; + if ($count == $#{$args{'parameterlist'}}) { + $post = ");"; + } + $type = $args{'parametertypes'}{$parameter}; + if ($type =~ m/$function_pointer/) { + # pointer-to-function + print ".BI \"" . $parenth . $1 . "\" " . " \") (" . $2 . ")" . $post . "\"\n"; + } else { + $type =~ s/([^\*])$/$1 /; + print ".BI \"" . $parenth . $type . "\" " . " \"" . $post . "\"\n"; + } + $count++; + $parenth = ""; } print ".SH ARGUMENTS\n"; foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - print ".IP \"" . $parameter . "\" 12\n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"", uc $section, "\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"", uc $section, "\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -627,28 +629,27 @@ sub output_enum_man(%) { print "enum " . $args{'enum'} . " {\n"; $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { - print ".br\n.BI \" $parameter\"\n"; - if ($count == $#{$args{'parameterlist'}}) { - print "\n};\n"; - last; - } - else { - print ", \n.br\n"; - } - $count++; + print ".br\n.BI \" $parameter\"\n"; + if ($count == $#{$args{'parameterlist'}}) { + print "\n};\n"; + last; + } else { + print ", \n.br\n"; + } + $count++; } print ".SH Constants\n"; foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - print ".IP \"" . $parameter . "\" 12\n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -672,18 +673,18 @@ sub output_struct_man(%) { print ".SH Members\n"; foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; + ($parameter =~ /^#/) && next; - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print ".IP \"" . $parameter . "\" 12\n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + print ".IP \"" . $parameter . "\" 12\n"; + output_highlight($args{'parameterdescs'}{$parameter_name}); } foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -699,8 +700,8 @@ sub output_typedef_man(%) { print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n"; foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -712,8 +713,8 @@ sub output_blockhead_man(%) { print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n"; foreach $section (@{$args{'sectionlist'}}) { - print ".SH \"$section\"\n"; - output_highlight($args{'sections'}{$section}); + print ".SH \"$section\"\n"; + output_highlight($args{'sections'}{$section}); } } @@ -731,15 +732,15 @@ sub output_blockhead_rst(%) { my ($parameter, $section); foreach $section (@{$args{'sectionlist'}}) { - next if (defined($nosymbol_table{$section})); + next if (defined($nosymbol_table{$section})); - if ($output_selection != OUTPUT_INCLUDE) { - print ".. _$section:\n\n"; - print "**$section**\n\n"; - } + if ($output_selection != OUTPUT_INCLUDE) { + print ".. _$section:\n\n"; + print "**$section**\n\n"; + } print_lineno($section_start_lines{$section}); - output_highlight_rst($args{'sections'}{$section}); - print "\n"; + output_highlight_rst($args{'sections'}{$section}); + print "\n"; } } @@ -769,48 +770,48 @@ sub output_highlight_rst { my $block = ""; foreach $line (split "\n",$input) { - # - # If we're in a literal block, see if we should drop out - # of it. Otherwise pass the line straight through unmunged. - # - if ($in_literal) { - if (! ($line =~ /^\s*$/)) { - # - # If this is the first non-blank line in a literal - # block we need to figure out what the proper indent is. - # - if ($litprefix eq "") { - $line =~ /^(\s*)/; - $litprefix = '^' . $1; - $output .= $line . "\n"; - } elsif (! ($line =~ /$litprefix/)) { - $in_literal = 0; - } else { - $output .= $line . "\n"; - } - } else { - $output .= $line . "\n"; - } - } - # - # Not in a literal block (or just dropped out) - # - if (! $in_literal) { - $block .= $line . "\n"; - if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { - $in_literal = 1; - $litprefix = ""; - $output .= highlight_block($block); - $block = "" - } - } + # + # If we're in a literal block, see if we should drop out + # of it. Otherwise pass the line straight through unmunged. + # + if ($in_literal) { + if (! ($line =~ /^\s*$/)) { + # + # If this is the first non-blank line in a literal + # block we need to figure out what the proper indent is. + # + if ($litprefix eq "") { + $line =~ /^(\s*)/; + $litprefix = '^' . $1; + $output .= $line . "\n"; + } elsif (! ($line =~ /$litprefix/)) { + $in_literal = 0; + } else { + $output .= $line . "\n"; + } + } else { + $output .= $line . "\n"; + } + } + # + # Not in a literal block (or just dropped out) + # + if (! $in_literal) { + $block .= $line . "\n"; + if (($line =~ /$sphinx_literal/) || ($line =~ /$sphinx_cblock/)) { + $in_literal = 1; + $litprefix = ""; + $output .= highlight_block($block); + $block = "" + } + } } if ($block) { - $output .= highlight_block($block); + $output .= highlight_block($block); } foreach $line (split "\n", $output) { - print $lineprefix . $line . "\n"; + print $lineprefix . $line . "\n"; } } @@ -822,67 +823,67 @@ sub output_function_rst(%) { my $is_macro = 0; if ($sphinx_major < 3) { - if ($args{'typedef'}) { - print ".. c:type:: ". $args{'function'} . "\n\n"; - print_lineno($declaration_start_line); - print " **Typedef**: "; - $lineprefix = ""; - output_highlight_rst($args{'purpose'}); - $start = "\n\n**Syntax**\n\n ``"; - $is_macro = 1; - } else { - print ".. c:function:: "; - } + if ($args{'typedef'}) { + print ".. c:type:: ". $args{'function'} . "\n\n"; + print_lineno($declaration_start_line); + print " **Typedef**: "; + $lineprefix = ""; + output_highlight_rst($args{'purpose'}); + $start = "\n\n**Syntax**\n\n ``"; + $is_macro = 1; + } else { + print ".. c:function:: "; + } } else { - if ($args{'typedef'} || $args{'functiontype'} eq "") { - $is_macro = 1; - print ".. c:macro:: ". $args{'function'} . "\n\n"; - } else { - print ".. c:function:: "; - } - - if ($args{'typedef'}) { - print_lineno($declaration_start_line); - print " **Typedef**: "; - $lineprefix = ""; - output_highlight_rst($args{'purpose'}); - $start = "\n\n**Syntax**\n\n ``"; - } else { - print "``" if ($is_macro); - } + if ($args{'typedef'} || $args{'functiontype'} eq "") { + $is_macro = 1; + print ".. c:macro:: ". $args{'function'} . "\n\n"; + } else { + print ".. c:function:: "; + } + + if ($args{'typedef'}) { + print_lineno($declaration_start_line); + print " **Typedef**: "; + $lineprefix = ""; + output_highlight_rst($args{'purpose'}); + $start = "\n\n**Syntax**\n\n ``"; + } else { + print "``" if ($is_macro); + } } if ($args{'functiontype'} ne "") { - $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; + $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; } else { - $start .= $args{'function'} . " ("; + $start .= $args{'function'} . " ("; } print $start; my $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { - if ($count ne 0) { - print ", "; - } - $count++; - $type = $args{'parametertypes'}{$parameter}; - - if ($type =~ m/$function_pointer/) { - # pointer-to-function - print $1 . $parameter . ") (" . $2 . ")"; - } else { - print $type; - } + if ($count ne 0) { + print ", "; + } + $count++; + $type = $args{'parametertypes'}{$parameter}; + + if ($type =~ m/$function_pointer/) { + # pointer-to-function + print $1 . $parameter . ") (" . $2 . ")"; + } else { + print $type; + } } if ($is_macro) { - print ")``\n\n"; + print ")``\n\n"; } else { - print ")\n\n"; + print ")\n\n"; } if (!$args{'typedef'}) { - print_lineno($declaration_start_line); - $lineprefix = " "; - output_highlight_rst($args{'purpose'}); - print "\n"; + print_lineno($declaration_start_line); + $lineprefix = " "; + output_highlight_rst($args{'purpose'}); + print "\n"; } # @@ -893,27 +894,27 @@ sub output_function_rst(%) { $lineprefix = " "; print $lineprefix . "**Parameters**\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - $type = $args{'parametertypes'}{$parameter}; - - if ($type ne "") { - print $lineprefix . "``$type``\n"; - } else { - print $lineprefix . "``$parameter``\n"; - } + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; + $type = $args{'parametertypes'}{$parameter}; + + if ($type ne "") { + print $lineprefix . "``$type``\n"; + } else { + print $lineprefix . "``$parameter``\n"; + } print_lineno($parameterdesc_start_lines{$parameter_name}); - $lineprefix = " "; - if (defined($args{'parameterdescs'}{$parameter_name}) && - $args{'parameterdescs'}{$parameter_name} ne $undescribed) { - output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - } else { - print $lineprefix . "*undescribed*\n"; - } - $lineprefix = " "; - print "\n"; + $lineprefix = " "; + if (defined($args{'parameterdescs'}{$parameter_name}) && + $args{'parameterdescs'}{$parameter_name} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + } else { + print $lineprefix . "*undescribed*\n"; + } + $lineprefix = " "; + print "\n"; } output_section_rst(@_); @@ -926,10 +927,10 @@ sub output_section_rst(%) { my $oldprefix = $lineprefix; foreach $section (@{$args{'sectionlist'}}) { - print $lineprefix . "**$section**\n\n"; + print $lineprefix . "**$section**\n\n"; print_lineno($section_start_lines{$section}); - output_highlight_rst($args{'sections'}{$section}); - print "\n"; + output_highlight_rst($args{'sections'}{$section}); + print "\n"; } print "\n"; } @@ -942,11 +943,11 @@ sub output_enum_rst(%) { my $outer; if ($sphinx_major < 3) { - my $name = "enum " . $args{'enum'}; - print "\n\n.. c:type:: " . $name . "\n\n"; + my $name = "enum " . $args{'enum'}; + print "\n\n.. c:type:: " . $name . "\n\n"; } else { - my $name = $args{'enum'}; - print "\n\n.. c:enum:: " . $name . "\n\n"; + my $name = $args{'enum'}; + print "\n\n.. c:enum:: " . $name . "\n\n"; } print_lineno($declaration_start_line); $lineprefix = " "; @@ -958,14 +959,14 @@ sub output_enum_rst(%) { $lineprefix = $outer . " "; print $outer . "**Constants**\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { - print $outer . "``$parameter``\n"; + print $outer . "``$parameter``\n"; - if ($args{'parameterdescs'}{$parameter} ne $undescribed) { - output_highlight_rst($args{'parameterdescs'}{$parameter}); - } else { - print $lineprefix . "*undescribed*\n"; - } - print "\n"; + if ($args{'parameterdescs'}{$parameter} ne $undescribed) { + output_highlight_rst($args{'parameterdescs'}{$parameter}); + } else { + print $lineprefix . "*undescribed*\n"; + } + print "\n"; } print "\n"; $lineprefix = $oldprefix; @@ -979,9 +980,9 @@ sub output_typedef_rst(%) { my $name; if ($sphinx_major < 3) { - $name = "typedef " . $args{'typedef'}; + $name = "typedef " . $args{'typedef'}; } else { - $name = $args{'typedef'}; + $name = $args{'typedef'}; } print "\n\n.. c:type:: " . $name . "\n\n"; print_lineno($declaration_start_line); @@ -999,15 +1000,15 @@ sub output_struct_rst(%) { my $oldprefix = $lineprefix; if ($sphinx_major < 3) { - my $name = $args{'type'} . " " . $args{'struct'}; - print "\n\n.. c:type:: " . $name . "\n\n"; + my $name = $args{'type'} . " " . $args{'struct'}; + print "\n\n.. c:type:: " . $name . "\n\n"; } else { - my $name = $args{'struct'}; - if ($args{'type'} eq 'union') { - print "\n\n.. c:union:: " . $name . "\n\n"; - } else { - print "\n\n.. c:struct:: " . $name . "\n\n"; - } + my $name = $args{'struct'}; + if ($args{'type'} eq 'union') { + print "\n\n.. c:union:: " . $name . "\n\n"; + } else { + print "\n\n.. c:struct:: " . $name . "\n\n"; + } } print_lineno($declaration_start_line); $lineprefix = " "; @@ -1024,19 +1025,19 @@ sub output_struct_rst(%) { $lineprefix = " "; print $lineprefix . "**Members**\n\n"; foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; + ($parameter =~ /^#/) && next; - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; + my $parameter_name = $parameter; + $parameter_name =~ s/\[.*//; - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - $type = $args{'parametertypes'}{$parameter}; + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; print_lineno($parameterdesc_start_lines{$parameter_name}); - print $lineprefix . "``" . $parameter . "``\n"; - $lineprefix = " "; - output_highlight_rst($args{'parameterdescs'}{$parameter_name}); - $lineprefix = " "; - print "\n"; + print $lineprefix . "``" . $parameter . "``\n"; + $lineprefix = " "; + output_highlight_rst($args{'parameterdescs'}{$parameter_name}); + $lineprefix = " "; + print "\n"; } print "\n"; @@ -1074,14 +1075,14 @@ sub output_declaration { return if (defined($nosymbol_table{$name})); if (($output_selection == OUTPUT_ALL) || - (($output_selection == OUTPUT_INCLUDE || - $output_selection == OUTPUT_EXPORTED) && - defined($function_table{$name})) || - ($output_selection == OUTPUT_INTERNAL && - !($functype eq "function" && defined($function_table{$name})))) + (($output_selection == OUTPUT_INCLUDE || + $output_selection == OUTPUT_EXPORTED) && + defined($function_table{$name})) || + ($output_selection == OUTPUT_INTERNAL && + !($functype eq "function" && defined($function_table{$name})))) { - &$func(@_); - $section_counter++; + &$func(@_); + $section_counter++; } } @@ -1120,203 +1121,202 @@ sub dump_struct($$) { my $struct_members = qr{($type)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;}; if ($x =~ /($type)\s+(\w+)\s*$definition_body/) { - $decl_type = $1; - $declaration_name = $2; - $members = $3; + $decl_type = $1; + $declaration_name = $2; + $members = $3; } elsif ($x =~ /typedef\s+($type)\s*$definition_body\s*(\w+)\s*;/) { - $decl_type = $1; - $declaration_name = $3; - $members = $2; + $decl_type = $1; + $declaration_name = $3; + $members = $2; } if ($members) { - if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"); - return; - } - - # ignore members marked private: - $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; - $members =~ s/\/\*\s*private:.*//gosi; - # strip comments: - $members =~ s/\/\*.*?\*\///gos; - # strip attributes - $members =~ s/\s*$attribute/ /gi; - $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; - $members =~ s/\s*__counted_by\s*\([^;]*\)/ /gos; - $members =~ s/\s*__packed\s*/ /gos; - $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; - $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; - $members =~ s/\s*____cacheline_aligned/ /gos; - # unwrap struct_group(): - # - first eat non-declaration parameters and rewrite for final match - # - then remove macro, outer parens, and trailing semicolon - $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos; - $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos; - $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos; - $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos; - - my $args = qr{([^,)]+)}; - # replace DECLARE_BITMAP - $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; - $members =~ s/DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, PHY_INTERFACE_MODE_MAX)/gos; - $members =~ s/DECLARE_BITMAP\s*\($args,\s*$args\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; - # replace DECLARE_HASHTABLE - $members =~ s/DECLARE_HASHTABLE\s*\($args,\s*$args\)/unsigned long $1\[1 << (($2) - 1)\]/gos; - # replace DECLARE_KFIFO - $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos; - # replace DECLARE_KFIFO_PTR - $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos; - # replace DECLARE_FLEX_ARRAY - $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos; - #replace DEFINE_DMA_UNMAP_ADDR - $members =~ s/DEFINE_DMA_UNMAP_ADDR\s*\($args\)/dma_addr_t $1/gos; - #replace DEFINE_DMA_UNMAP_LEN - $members =~ s/DEFINE_DMA_UNMAP_LEN\s*\($args\)/__u32 $1/gos; - my $declaration = $members; - - # Split nested struct/union elements as newer ones - while ($members =~ m/$struct_members/) { - my $newmember; - my $maintype = $1; - my $ids = $4; - my $content = $3; - foreach my $id(split /,/, $ids) { - $newmember .= "$maintype $id; "; - - $id =~ s/[:\[].*//; - $id =~ s/^\s*\**(\S+)\s*/$1/; - foreach my $arg (split /;/, $content) { - next if ($arg =~ m/^\s*$/); - if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { - # pointer-to-function - my $type = $1; - my $name = $2; - my $extra = $3; - next if (!$name); - if ($id =~ m/^\s*$/) { - # anonymous struct/union - $newmember .= "$type$name$extra; "; - } else { - $newmember .= "$type$id.$name$extra; "; - } - } else { - my $type; - my $names; - $arg =~ s/^\s+//; - $arg =~ s/\s+$//; - # Handle bitmaps - $arg =~ s/:\s*\d+\s*//g; - # Handle arrays - $arg =~ s/\[.*\]//g; - # The type may have multiple words, - # and multiple IDs can be defined, like: - # const struct foo, *bar, foobar - # So, we remove spaces when parsing the - # names, in order to match just names - # and commas for the names - $arg =~ s/\s*,\s*/,/g; - if ($arg =~ m/(.*)\s+([\S+,]+)/) { - $type = $1; - $names = $2; - } else { - $newmember .= "$arg; "; - next; - } - foreach my $name (split /,/, $names) { - $name =~ s/^\s*\**(\S+)\s*/$1/; - next if (($name =~ m/^\s*$/)); - if ($id =~ m/^\s*$/) { - # anonymous struct/union - $newmember .= "$type $name; "; - } else { - $newmember .= "$type $id.$name; "; - } - } - } - } - } - $members =~ s/$struct_members/$newmember/; - } - - # Ignore other nested elements, like enums - $members =~ s/(\{[^\{\}]*\})//g; - - create_parameterlist($members, ';', $file, $declaration_name); - check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); - - # Adjust declaration for better display - $declaration =~ s/([\{;])/$1\n/g; - $declaration =~ s/\}\s+;/};/g; - # Better handle inlined enums - do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); - - my @def_args = split /\n/, $declaration; - my $level = 1; - $declaration = ""; - foreach my $clause (@def_args) { - $clause =~ s/^\s+//; - $clause =~ s/\s+$//; - $clause =~ s/\s+/ /; - next if (!$clause); - $level-- if ($clause =~ m/(\})/ && $level > 1); - if (!($clause =~ m/^\s*#/)) { - $declaration .= "\t" x $level; - } - $declaration .= "\t" . $clause . "\n"; - $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); - } - output_declaration($declaration_name, - 'struct', - {'struct' => $declaration_name, - 'module' => $modulename, - 'definition' => $declaration, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose, - 'type' => $decl_type - }); - } - else { - print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; - ++$errors; + if ($identifier ne $declaration_name) { + emit_warning("${file}:$.", "expecting prototype for $decl_type $identifier. Prototype was for $decl_type $declaration_name instead\n"); + return; + } + + # ignore members marked private: + $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi; + $members =~ s/\/\*\s*private:.*//gosi; + # strip comments: + $members =~ s/\/\*.*?\*\///gos; + # strip attributes + $members =~ s/\s*$attribute/ /gi; + $members =~ s/\s*__aligned\s*\([^;]*\)/ /gos; + $members =~ s/\s*__counted_by\s*\([^;]*\)/ /gos; + $members =~ s/\s*__packed\s*/ /gos; + $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; + $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; + $members =~ s/\s*____cacheline_aligned/ /gos; + # unwrap struct_group(): + # - first eat non-declaration parameters and rewrite for final match + # - then remove macro, outer parens, and trailing semicolon + $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos; + $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos; + $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos; + $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos; + + my $args = qr{([^,)]+)}; + # replace DECLARE_BITMAP + $members =~ s/__ETHTOOL_DECLARE_LINK_MODE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, __ETHTOOL_LINK_MODE_MASK_NBITS)/gos; + $members =~ s/DECLARE_PHY_INTERFACE_MASK\s*\(([^\)]+)\)/DECLARE_BITMAP($1, PHY_INTERFACE_MODE_MAX)/gos; + $members =~ s/DECLARE_BITMAP\s*\($args,\s*$args\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos; + # replace DECLARE_HASHTABLE + $members =~ s/DECLARE_HASHTABLE\s*\($args,\s*$args\)/unsigned long $1\[1 << (($2) - 1)\]/gos; + # replace DECLARE_KFIFO + $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos; + # replace DECLARE_KFIFO_PTR + $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos; + # replace DECLARE_FLEX_ARRAY + $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos; + #replace DEFINE_DMA_UNMAP_ADDR + $members =~ s/DEFINE_DMA_UNMAP_ADDR\s*\($args\)/dma_addr_t $1/gos; + #replace DEFINE_DMA_UNMAP_LEN + $members =~ s/DEFINE_DMA_UNMAP_LEN\s*\($args\)/__u32 $1/gos; + my $declaration = $members; + + # Split nested struct/union elements as newer ones + while ($members =~ m/$struct_members/) { + my $newmember; + my $maintype = $1; + my $ids = $4; + my $content = $3; + foreach my $id(split /,/, $ids) { + $newmember .= "$maintype $id; "; + + $id =~ s/[:\[].*//; + $id =~ s/^\s*\**(\S+)\s*/$1/; + foreach my $arg (split /;/, $content) { + next if ($arg =~ m/^\s*$/); + if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) { + # pointer-to-function + my $type = $1; + my $name = $2; + my $extra = $3; + next if (!$name); + if ($id =~ m/^\s*$/) { + # anonymous struct/union + $newmember .= "$type$name$extra; "; + } else { + $newmember .= "$type$id.$name$extra; "; + } + } else { + my $type; + my $names; + $arg =~ s/^\s+//; + $arg =~ s/\s+$//; + # Handle bitmaps + $arg =~ s/:\s*\d+\s*//g; + # Handle arrays + $arg =~ s/\[.*\]//g; + # The type may have multiple words, + # and multiple IDs can be defined, like: + # const struct foo, *bar, foobar + # So, we remove spaces when parsing the + # names, in order to match just names + # and commas for the names + $arg =~ s/\s*,\s*/,/g; + if ($arg =~ m/(.*)\s+([\S+,]+)/) { + $type = $1; + $names = $2; + } else { + $newmember .= "$arg; "; + next; + } + foreach my $name (split /,/, $names) { + $name =~ s/^\s*\**(\S+)\s*/$1/; + next if (($name =~ m/^\s*$/)); + if ($id =~ m/^\s*$/) { + # anonymous struct/union + $newmember .= "$type $name; "; + } else { + $newmember .= "$type $id.$name; "; + } + } + } + } + } + $members =~ s/$struct_members/$newmember/; + } + + # Ignore other nested elements, like enums + $members =~ s/(\{[^\{\}]*\})//g; + + create_parameterlist($members, ';', $file, $declaration_name); + check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual); + + # Adjust declaration for better display + $declaration =~ s/([\{;])/$1\n/g; + $declaration =~ s/\}\s+;/};/g; + # Better handle inlined enums + do {} while ($declaration =~ s/(enum\s+\{[^\}]+),([^\n])/$1,\n$2/); + + my @def_args = split /\n/, $declaration; + my $level = 1; + $declaration = ""; + foreach my $clause (@def_args) { + $clause =~ s/^\s+//; + $clause =~ s/\s+$//; + $clause =~ s/\s+/ /; + next if (!$clause); + $level-- if ($clause =~ m/(\})/ && $level > 1); + if (!($clause =~ m/^\s*#/)) { + $declaration .= "\t" x $level; + } + $declaration .= "\t" . $clause . "\n"; + $level++ if ($clause =~ m/(\{)/ && !($clause =~m/\}/)); + } + output_declaration($declaration_name, + 'struct', + {'struct' => $declaration_name, + 'module' => $modulename, + 'definition' => $declaration, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose, + 'type' => $decl_type + }); + } else { + print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; + ++$errors; } } sub show_warnings($$) { - my $functype = shift; - my $name = shift; - - return 0 if (defined($nosymbol_table{$name})); - - return 1 if ($output_selection == OUTPUT_ALL); - - if ($output_selection == OUTPUT_EXPORTED) { - if (defined($function_table{$name})) { - return 1; - } else { - return 0; - } - } - if ($output_selection == OUTPUT_INTERNAL) { - if (!($functype eq "function" && defined($function_table{$name}))) { - return 1; - } else { - return 0; - } - } - if ($output_selection == OUTPUT_INCLUDE) { - if (defined($function_table{$name})) { - return 1; - } else { - return 0; - } - } - die("Please add the new output type at show_warnings()"); + my $functype = shift; + my $name = shift; + + return 0 if (defined($nosymbol_table{$name})); + + return 1 if ($output_selection == OUTPUT_ALL); + + if ($output_selection == OUTPUT_EXPORTED) { + if (defined($function_table{$name})) { + return 1; + } else { + return 0; + } + } + if ($output_selection == OUTPUT_INTERNAL) { + if (!($functype eq "function" && defined($function_table{$name}))) { + return 1; + } else { + return 0; + } + } + if ($output_selection == OUTPUT_INCLUDE) { + if (defined($function_table{$name})) { + return 1; + } else { + return 0; + } + } + die("Please add the new output type at show_warnings()"); } sub dump_enum($$) { @@ -1333,62 +1333,62 @@ sub dump_enum($$) { $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; if ($x =~ /typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;/) { - $declaration_name = $2; - $members = $1; + $declaration_name = $2; + $members = $1; } elsif ($x =~ /enum\s+(\w*)\s*\{(.*)\}/) { - $declaration_name = $1; - $members = $2; + $declaration_name = $1; + $members = $2; } if ($members) { - if ($identifier ne $declaration_name) { - if ($identifier eq "") { - emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n"); - } else { - emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"); - } - return; - } - $declaration_name = "(anonymous)" if ($declaration_name eq ""); - - my %_members; - - $members =~ s/\s+$//; - $members =~ s/\([^;]*?[\)]//g; - - foreach my $arg (split ',', $members) { - $arg =~ s/^\s*(\w+).*/$1/; - push @parameterlist, $arg; - if (!$parameterdescs{$arg}) { - $parameterdescs{$arg} = $undescribed; - if (show_warnings("enum", $declaration_name)) { - emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n"); - } - } - $_members{$arg} = 1; - } - - while (my ($k, $v) = each %parameterdescs) { - if (!exists($_members{$k})) { - if (show_warnings("enum", $declaration_name)) { - emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n"); - } - } - } - - output_declaration($declaration_name, - 'enum', - {'enum' => $declaration_name, - 'module' => $modulename, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); + if ($identifier ne $declaration_name) { + if ($identifier eq "") { + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n"); + } else { + emit_warning("${file}:$.", "expecting prototype for enum $identifier. Prototype was for enum $declaration_name instead\n"); + } + return; + } + $declaration_name = "(anonymous)" if ($declaration_name eq ""); + + my %_members; + + $members =~ s/\s+$//; + $members =~ s/\([^;]*?[\)]//g; + + foreach my $arg (split ',', $members) { + $arg =~ s/^\s*(\w+).*/$1/; + push @parameterlist, $arg; + if (!$parameterdescs{$arg}) { + $parameterdescs{$arg} = $undescribed; + if (show_warnings("enum", $declaration_name)) { + emit_warning("${file}:$.", "Enum value '$arg' not described in enum '$declaration_name'\n"); + } + } + $_members{$arg} = 1; + } + + while (my ($k, $v) = each %parameterdescs) { + if (!exists($_members{$k})) { + if (show_warnings("enum", $declaration_name)) { + emit_warning("${file}:$.", "Excess enum value '$k' description in '$declaration_name'\n"); + } + } + } + + output_declaration($declaration_name, + 'enum', + {'enum' => $declaration_name, + 'module' => $modulename, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); } else { - print STDERR "${file}:$.: error: Cannot parse enum!\n"; - ++$errors; + print STDERR "${file}:$.: error: Cannot parse enum!\n"; + ++$errors; } } @@ -1407,59 +1407,58 @@ sub dump_typedef($$) { # Parse function typedef prototypes if ($x =~ $typedef1 || $x =~ $typedef2) { - $return_type = $1; - $declaration_name = $2; - my $args = $3; - $return_type =~ s/^\s+//; - - if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); - return; - } - - create_parameterlist($args, ',', $file, $declaration_name); - - output_declaration($declaration_name, - 'function', - {'function' => $declaration_name, - 'typedef' => 1, - 'module' => $modulename, - 'functiontype' => $return_type, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); - return; + $return_type = $1; + $declaration_name = $2; + my $args = $3; + $return_type =~ s/^\s+//; + + if ($identifier ne $declaration_name) { + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); + return; + } + + create_parameterlist($args, ',', $file, $declaration_name); + + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'typedef' => 1, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); + return; } while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) { - $x =~ s/\(*.\)\s*;$/;/; - $x =~ s/\[*.\]\s*;$/;/; + $x =~ s/\(*.\)\s*;$/;/; + $x =~ s/\[*.\]\s*;$/;/; } if ($x =~ /typedef.*\s+(\w+)\s*;/) { - $declaration_name = $1; + $declaration_name = $1; - if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); - return; - } + if ($identifier ne $declaration_name) { + emit_warning("${file}:$.", "expecting prototype for typedef $identifier. Prototype was for typedef $declaration_name instead\n"); + return; + } - output_declaration($declaration_name, - 'typedef', - {'typedef' => $declaration_name, - 'module' => $modulename, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); - } - else { - print STDERR "${file}:$.: error: Cannot parse typedef!\n"; - ++$errors; + output_declaration($declaration_name, + 'typedef', + {'typedef' => $declaration_name, + 'module' => $modulename, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); + } else { + print STDERR "${file}:$.: error: Cannot parse typedef!\n"; + ++$errors; } } @@ -1482,223 +1481,220 @@ sub create_parameterlist($$$$) { # temporarily replace commas inside function pointer definition my $arg_expr = qr{\([^\),]+}; while ($args =~ /$arg_expr,/) { - $args =~ s/($arg_expr),/$1#/g; + $args =~ s/($arg_expr),/$1#/g; } foreach my $arg (split($splitter, $args)) { - # strip comments - $arg =~ s/\/\*.*\*\///; - # ignore argument attributes - $arg =~ s/\sPOS0?\s/ /; - # strip leading/trailing spaces - $arg =~ s/^\s*//; - $arg =~ s/\s*$//; - $arg =~ s/\s+/ /; - - if ($arg =~ /^#/) { - # Treat preprocessor directive as a typeless variable just to fill - # corresponding data structures "correctly". Catch it later in - # output_* subs. - push_parameter($arg, "", "", $file); - } elsif ($arg =~ m/\(.+\)\s*\(/) { - # pointer-to-function - $arg =~ tr/#/,/; - $arg =~ m/[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)/; - $param = $1; - $type = $arg; - $type =~ s/([^\(]+\(\*?)\s*$param/$1/; - save_struct_actual($param); - push_parameter($param, $type, $arg, $file, $declaration_name); - } elsif ($arg =~ m/\(.+\)\s*\[/) { - # array-of-pointers - $arg =~ tr/#/,/; - $arg =~ m/[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)/; - $param = $1; - $type = $arg; - $type =~ s/([^\(]+\(\*?)\s*$param/$1/; - save_struct_actual($param); - push_parameter($param, $type, $arg, $file, $declaration_name); - } elsif ($arg) { - $arg =~ s/\s*:\s*/:/g; - $arg =~ s/\s*\[/\[/g; - - my @args = split('\s*,\s*', $arg); - if ($args[0] =~ m/\*/) { - $args[0] =~ s/(\*+)\s*/ $1/; - } - - my @first_arg; - if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { - shift @args; - push(@first_arg, split('\s+', $1)); - push(@first_arg, $2); - } else { - @first_arg = split('\s+', shift @args); - } - - unshift(@args, pop @first_arg); - $type = join " ", @first_arg; - - foreach $param (@args) { - if ($param =~ m/^(\*+)\s*(.*)/) { - save_struct_actual($2); - - push_parameter($2, "$type $1", $arg, $file, $declaration_name); - } - elsif ($param =~ m/(.*?):(\d+)/) { - if ($type ne "") { # skip unnamed bit-fields - save_struct_actual($1); - push_parameter($1, "$type:$2", $arg, $file, $declaration_name) - } - } - else { - save_struct_actual($param); - push_parameter($param, $type, $arg, $file, $declaration_name); - } - } - } + # strip comments + $arg =~ s/\/\*.*\*\///; + # ignore argument attributes + $arg =~ s/\sPOS0?\s/ /; + # strip leading/trailing spaces + $arg =~ s/^\s*//; + $arg =~ s/\s*$//; + $arg =~ s/\s+/ /; + + if ($arg =~ /^#/) { + # Treat preprocessor directive as a typeless variable just to fill + # corresponding data structures "correctly". Catch it later in + # output_* subs. + push_parameter($arg, "", "", $file); + } elsif ($arg =~ m/\(.+\)\s*\(/) { + # pointer-to-function + $arg =~ tr/#/,/; + $arg =~ m/[^\(]+\(\*?\s*([\w\[\]\.]*)\s*\)/; + $param = $1; + $type = $arg; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); + } elsif ($arg =~ m/\(.+\)\s*\[/) { + # array-of-pointers + $arg =~ tr/#/,/; + $arg =~ m/[^\(]+\(\s*\*\s*([\w\[\]\.]*?)\s*(\s*\[\s*[\w]+\s*\]\s*)*\)/; + $param = $1; + $type = $arg; + $type =~ s/([^\(]+\(\*?)\s*$param/$1/; + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); + } elsif ($arg) { + $arg =~ s/\s*:\s*/:/g; + $arg =~ s/\s*\[/\[/g; + + my @args = split('\s*,\s*', $arg); + if ($args[0] =~ m/\*/) { + $args[0] =~ s/(\*+)\s*/ $1/; + } + + my @first_arg; + if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) { + shift @args; + push(@first_arg, split('\s+', $1)); + push(@first_arg, $2); + } else { + @first_arg = split('\s+', shift @args); + } + + unshift(@args, pop @first_arg); + $type = join " ", @first_arg; + + foreach $param (@args) { + if ($param =~ m/^(\*+)\s*(.*)/) { + save_struct_actual($2); + + push_parameter($2, "$type $1", $arg, $file, $declaration_name); + } elsif ($param =~ m/(.*?):(\d+)/) { + if ($type ne "") { # skip unnamed bit-fields + save_struct_actual($1); + push_parameter($1, "$type:$2", $arg, $file, $declaration_name) + } + } else { + save_struct_actual($param); + push_parameter($param, $type, $arg, $file, $declaration_name); + } + } + } } } sub push_parameter($$$$$) { - my $param = shift; - my $type = shift; - my $org_arg = shift; - my $file = shift; - my $declaration_name = shift; - - if (($anon_struct_union == 1) && ($type eq "") && - ($param eq "}")) { - return; # ignore the ending }; from anon. struct/union - } - - $anon_struct_union = 0; - $param =~ s/[\[\)].*//; - - if ($type eq "" && $param =~ /\.\.\.$/) - { - if (!$param =~ /\w\.\.\.$/) { - # handles unnamed variable parameters - $param = "..."; - } - elsif ($param =~ /\w\.\.\.$/) { - # for named variable parameters of the form `x...`, remove the dots - $param =~ s/\.\.\.$//; - } - if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { - $parameterdescs{$param} = "variable arguments"; - } - } - elsif ($type eq "" && ($param eq "" or $param eq "void")) - { - $param="void"; - $parameterdescs{void} = "no arguments"; - } - elsif ($type eq "" && ($param eq "struct" or $param eq "union")) - # handle unnamed (anonymous) union or struct: - { - $type = $param; - $param = "{unnamed_" . $param . "}"; - $parameterdescs{$param} = "anonymous\n"; - $anon_struct_union = 1; - } - elsif ($param =~ "__cacheline_group" ) - # handle cache group enforcing variables: they do not need be described in header files - { - return; # ignore __cacheline_group_begin and __cacheline_group_end - } - - # warn if parameter has no description - # (but ignore ones starting with # as these are not parameters - # but inline preprocessor statements); - # Note: It will also ignore void params and unnamed structs/unions - if (!defined $parameterdescs{$param} && $param !~ /^#/) { - $parameterdescs{$param} = $undescribed; - - if (show_warnings($type, $declaration_name) && $param !~ /\./) { - emit_warning("${file}:$.", "Function parameter or struct member '$param' not described in '$declaration_name'\n"); - } - } - - # strip spaces from $param so that it is one continuous string - # on @parameterlist; - # this fixes a problem where check_sections() cannot find - # a parameter like "addr[6 + 2]" because it actually appears - # as "addr[6", "+", "2]" on the parameter list; - # but it's better to maintain the param string unchanged for output, - # so just weaken the string compare in check_sections() to ignore - # "[blah" in a parameter string; - ###$param =~ s/\s*//g; - push @parameterlist, $param; - $org_arg =~ s/\s\s+/ /g; - $parametertypes{$param} = $org_arg; + my $param = shift; + my $type = shift; + my $org_arg = shift; + my $file = shift; + my $declaration_name = shift; + + if (($anon_struct_union == 1) && ($type eq "") && + ($param eq "}")) { + return; # ignore the ending }; from anon. struct/union + } + + $anon_struct_union = 0; + $param =~ s/[\[\)].*//; + + if ($type eq "" && $param =~ /\.\.\.$/) + { + if (!$param =~ /\w\.\.\.$/) { + # handles unnamed variable parameters + $param = "..."; + } elsif ($param =~ /\w\.\.\.$/) { + # for named variable parameters of the form `x...`, remove the dots + $param =~ s/\.\.\.$//; + } + if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") { + $parameterdescs{$param} = "variable arguments"; + } + } + elsif ($type eq "" && ($param eq "" or $param eq "void")) + { + $param="void"; + $parameterdescs{void} = "no arguments"; + } + elsif ($type eq "" && ($param eq "struct" or $param eq "union")) + # handle unnamed (anonymous) union or struct: + { + $type = $param; + $param = "{unnamed_" . $param . "}"; + $parameterdescs{$param} = "anonymous\n"; + $anon_struct_union = 1; + } + elsif ($param =~ "__cacheline_group" ) + # handle cache group enforcing variables: they do not need be described in header files + { + return; # ignore __cacheline_group_begin and __cacheline_group_end + } + + # warn if parameter has no description + # (but ignore ones starting with # as these are not parameters + # but inline preprocessor statements); + # Note: It will also ignore void params and unnamed structs/unions + if (!defined $parameterdescs{$param} && $param !~ /^#/) { + $parameterdescs{$param} = $undescribed; + + if (show_warnings($type, $declaration_name) && $param !~ /\./) { + emit_warning("${file}:$.", "Function parameter or struct member '$param' not described in '$declaration_name'\n"); + } + } + + # strip spaces from $param so that it is one continuous string + # on @parameterlist; + # this fixes a problem where check_sections() cannot find + # a parameter like "addr[6 + 2]" because it actually appears + # as "addr[6", "+", "2]" on the parameter list; + # but it's better to maintain the param string unchanged for output, + # so just weaken the string compare in check_sections() to ignore + # "[blah" in a parameter string; + ###$param =~ s/\s*//g; + push @parameterlist, $param; + $org_arg =~ s/\s\s+/ /g; + $parametertypes{$param} = $org_arg; } sub check_sections($$$$$) { - my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_; - my @sects = split ' ', $sectcheck; - my @prms = split ' ', $prmscheck; - my $err; - my ($px, $sx); - my $prm_clean; # strip trailing "[array size]" and/or beginning "*" - - foreach $sx (0 .. $#sects) { - $err = 1; - foreach $px (0 .. $#prms) { - $prm_clean = $prms[$px]; - $prm_clean =~ s/\[.*\]//; - $prm_clean =~ s/$attribute//i; - # ignore array size in a parameter string; - # however, the original param string may contain - # spaces, e.g.: addr[6 + 2] - # and this appears in @prms as "addr[6" since the - # parameter list is split at spaces; - # hence just ignore "[..." for the sections check; - $prm_clean =~ s/\[.*//; - - ##$prm_clean =~ s/^\**//; - if ($prm_clean eq $sects[$sx]) { - $err = 0; - last; - } - } - if ($err) { - if ($decl_type eq "function") { - emit_warning("${file}:$.", - "Excess function parameter " . - "'$sects[$sx]' " . - "description in '$decl_name'\n"); - } - elsif (($decl_type eq "struct") or - ($decl_type eq "union")) { - emit_warning("${file}:$.", - "Excess $decl_type member " . - "'$sects[$sx]' " . - "description in '$decl_name'\n"); - } - } - } + my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_; + my @sects = split ' ', $sectcheck; + my @prms = split ' ', $prmscheck; + my $err; + my ($px, $sx); + my $prm_clean; # strip trailing "[array size]" and/or beginning "*" + + foreach $sx (0 .. $#sects) { + $err = 1; + foreach $px (0 .. $#prms) { + $prm_clean = $prms[$px]; + $prm_clean =~ s/\[.*\]//; + $prm_clean =~ s/$attribute//i; + # ignore array size in a parameter string; + # however, the original param string may contain + # spaces, e.g.: addr[6 + 2] + # and this appears in @prms as "addr[6" since the + # parameter list is split at spaces; + # hence just ignore "[..." for the sections check; + $prm_clean =~ s/\[.*//; + + ##$prm_clean =~ s/^\**//; + if ($prm_clean eq $sects[$sx]) { + $err = 0; + last; + } + } + if ($err) { + if ($decl_type eq "function") { + emit_warning("${file}:$.", + "Excess function parameter " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"); + } elsif (($decl_type eq "struct") or + ($decl_type eq "union")) { + emit_warning("${file}:$.", + "Excess $decl_type member " . + "'$sects[$sx]' " . + "description in '$decl_name'\n"); + } + } + } } ## # Checks the section describing the return value of a function. sub check_return_section { - my $file = shift; - my $declaration_name = shift; - my $return_type = shift; + my $file = shift; + my $declaration_name = shift; + my $return_type = shift; - # Ignore an empty return type (It's a macro) - # Ignore functions with a "void" return type. (But don't ignore "void *") - if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { - return; - } + # Ignore an empty return type (It's a macro) + # Ignore functions with a "void" return type. (But don't ignore "void *") + if (($return_type eq "") || ($return_type =~ /void\s*\w*\s*$/)) { + return; + } - if (!defined($sections{$section_return}) || - $sections{$section_return} eq "") { - emit_warning("${file}:$.", - "No description found for return value of " . - "'$declaration_name'\n"); - } + if (!defined($sections{$section_return}) || + $sections{$section_return} eq "") + { + emit_warning("${file}:$.", + "No description found for return value of " . + "'$declaration_name'\n"); + } } ## @@ -1773,21 +1769,21 @@ sub dump_function($$) { $declaration_name = $2; $noret = 1; } elsif ($prototype =~ m/^()($name)\s*$prototype_end/ || - $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ || - $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/) { - $return_type = $1; - $declaration_name = $2; - my $args = $3; + $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ || + $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/) { + $return_type = $1; + $declaration_name = $2; + my $args = $3; - create_parameterlist($args, ',', $file, $declaration_name); + create_parameterlist($args, ',', $file, $declaration_name); } else { - emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n"); - return; + emit_warning("${file}:$.", "cannot understand function prototype: '$prototype'\n"); + return; } if ($identifier ne $declaration_name) { - emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"); - return; + emit_warning("${file}:$.", "expecting prototype for $identifier(). Prototype was for $declaration_name() instead\n"); + return; } my $prms = join " ", @parameterlist; @@ -1799,38 +1795,38 @@ sub dump_function($$) { # -Wreturn mode. # TODO: always perform the check. if ($Wreturn && !$noret) { - check_return_section($file, $declaration_name, $return_type); + check_return_section($file, $declaration_name, $return_type); } # The function parser can be called with a typedef parameter. # Handle it. if ($return_type =~ /typedef/) { - output_declaration($declaration_name, - 'function', - {'function' => $declaration_name, - 'typedef' => 1, - 'module' => $modulename, - 'functiontype' => $return_type, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'typedef' => 1, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); } else { - output_declaration($declaration_name, - 'function', - {'function' => $declaration_name, - 'module' => $modulename, - 'functiontype' => $return_type, - 'parameterlist' => \@parameterlist, - 'parameterdescs' => \%parameterdescs, - 'parametertypes' => \%parametertypes, - 'sectionlist' => \@sectionlist, - 'sections' => \%sections, - 'purpose' => $declaration_purpose - }); + output_declaration($declaration_name, + 'function', + {'function' => $declaration_name, + 'module' => $modulename, + 'functiontype' => $return_type, + 'parameterlist' => \@parameterlist, + 'parameterdescs' => \%parameterdescs, + 'parametertypes' => \%parametertypes, + 'sectionlist' => \@sectionlist, + 'sections' => \%sections, + 'purpose' => $declaration_purpose + }); } } @@ -1850,64 +1846,64 @@ sub reset_state { } sub tracepoint_munge($) { - my $file = shift; - my $tracepointname = 0; - my $tracepointargs = 0; - - if ($prototype =~ m/TRACE_EVENT\((.*?),/) { - $tracepointname = $1; - } - if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { - $tracepointname = $1; - } - if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { - $tracepointname = $2; - } - $tracepointname =~ s/^\s+//; #strip leading whitespace - if ($prototype =~ m/TP_PROTO\((.*?)\)/) { - $tracepointargs = $1; - } - if (($tracepointname eq 0) || ($tracepointargs eq 0)) { - emit_warning("${file}:$.", "Unrecognized tracepoint format: \n". - "$prototype\n"); - } else { - $prototype = "static inline void trace_$tracepointname($tracepointargs)"; - $identifier = "trace_$identifier"; - } + my $file = shift; + my $tracepointname = 0; + my $tracepointargs = 0; + + if ($prototype =~ m/TRACE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) { + $tracepointname = $1; + } + if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) { + $tracepointname = $2; + } + $tracepointname =~ s/^\s+//; #strip leading whitespace + if ($prototype =~ m/TP_PROTO\((.*?)\)/) { + $tracepointargs = $1; + } + if (($tracepointname eq 0) || ($tracepointargs eq 0)) { + emit_warning("${file}:$.", "Unrecognized tracepoint format: \n". + "$prototype\n"); + } else { + $prototype = "static inline void trace_$tracepointname($tracepointargs)"; + $identifier = "trace_$identifier"; + } } sub syscall_munge() { - my $void = 0; - - $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's -## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { - if ($prototype =~ m/SYSCALL_DEFINE0/) { - $void = 1; -## $prototype = "long sys_$1(void)"; - } - - $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name - if ($prototype =~ m/long (sys_.*?),/) { - $prototype =~ s/,/\(/; - } elsif ($void) { - $prototype =~ s/\)/\(void\)/; - } - - # now delete all of the odd-number commas in $prototype - # so that arg types & arg names don't have a comma between them - my $count = 0; - my $len = length($prototype); - if ($void) { - $len = 0; # skip the for-loop - } - for (my $ix = 0; $ix < $len; $ix++) { - if (substr($prototype, $ix, 1) eq ',') { - $count++; - if ($count % 2 == 1) { - substr($prototype, $ix, 1) = ' '; - } - } - } + my $void = 0; + + $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's +## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) { + if ($prototype =~ m/SYSCALL_DEFINE0/) { + $void = 1; +## $prototype = "long sys_$1(void)"; + } + + $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name + if ($prototype =~ m/long (sys_.*?),/) { + $prototype =~ s/,/\(/; + } elsif ($void) { + $prototype =~ s/\)/\(void\)/; + } + + # now delete all of the odd-number commas in $prototype + # so that arg types & arg names don't have a comma between them + my $count = 0; + my $len = length($prototype); + if ($void) { + $len = 0; # skip the for-loop + } + for (my $ix = 0; $ix < $len; $ix++) { + if (substr($prototype, $ix, 1) eq ',') { + $count++; + if ($count % 2 == 1) { + substr($prototype, $ix, 1) = ' '; + } + } + } } sub process_proto_function($$) { @@ -1917,31 +1913,30 @@ sub process_proto_function($$) { $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line if ($x =~ /^#/ && $x !~ /^#\s*define/) { - # do nothing - } - elsif ($x =~ /([^\{]*)/) { - $prototype .= $1; + # do nothing + } elsif ($x =~ /([^\{]*)/) { + $prototype .= $1; } if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) { - $prototype =~ s@/\*.*?\*/@@gos; # strip comments. - $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. - $prototype =~ s@^\s+@@gos; # strip leading spaces + $prototype =~ s@/\*.*?\*/@@gos; # strip comments. + $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's. + $prototype =~ s@^\s+@@gos; # strip leading spaces - # Handle prototypes for function pointers like: - # int (*pcs_config)(struct foo) - $prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos; + # Handle prototypes for function pointers like: + # int (*pcs_config)(struct foo) + $prototype =~ s@^(\S+\s+)\(\s*\*(\S+)\)@$1$2@gos; - if ($prototype =~ /SYSCALL_DEFINE/) { - syscall_munge(); - } - if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || - $prototype =~ /DEFINE_SINGLE_EVENT/) - { - tracepoint_munge($file); - } - dump_function($prototype, $file); - reset_state(); + if ($prototype =~ /SYSCALL_DEFINE/) { + syscall_munge(); + } + if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ || + $prototype =~ /DEFINE_SINGLE_EVENT/) + { + tracepoint_munge($file); + } + dump_function($prototype, $file); + reset_state(); } } @@ -1955,28 +1950,28 @@ sub process_proto_type($$) { $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line if ($x =~ /^#/) { - # To distinguish preprocessor directive from regular declaration later. - $x .= ";"; + # To distinguish preprocessor directive from regular declaration later. + $x .= ";"; } while (1) { - if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { + if ( $x =~ /([^\{\};]*)([\{\};])(.*)/ ) { if( length $prototype ) { $prototype .= " " } - $prototype .= $1 . $2; - ($2 eq '{') && $brcount++; - ($2 eq '}') && $brcount--; - if (($2 eq ';') && ($brcount == 0)) { - dump_declaration($prototype, $file); - reset_state(); - last; - } - $x = $3; - } else { - $prototype .= $x; - last; - } + $prototype .= $1 . $2; + ($2 eq '{') && $brcount++; + ($2 eq '}') && $brcount--; + if (($2 eq ';') && ($brcount == 0)) { + dump_declaration($prototype, $file); + reset_state(); + last; + } + $x = $3; + } else { + $prototype .= $x; + last; + } } } @@ -1986,13 +1981,13 @@ sub map_filename($) { my ($orig_file) = @_; if (defined($ENV{'SRCTREE'})) { - $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; + $file = "$ENV{'SRCTREE'}" . "/" . $orig_file; } else { - $file = $orig_file; + $file = $orig_file; } if (defined($source_map{$file})) { - $file = $source_map{$file}; + $file = $source_map{$file}; } return $file; @@ -2003,20 +1998,20 @@ sub process_export_file($) { my $file = map_filename($orig_file); if (!open(IN,"<$file")) { - print STDERR "Error: Cannot open file $file\n"; - ++$errors; - return; + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; } while () { - if (/$export_symbol/) { - next if (defined($nosymbol_table{$2})); - $function_table{$2} = 1; - } - if (/$export_symbol_ns/) { - next if (defined($nosymbol_table{$2})); - $function_table{$2} = 1; - } + if (/$export_symbol/) { + next if (defined($nosymbol_table{$2})); + $function_table{$2} = 1; + } + if (/$export_symbol_ns/) { + next if (defined($nosymbol_table{$2})); + $function_table{$2} = 1; + } } close(IN); @@ -2029,9 +2024,9 @@ sub process_export_file($) { # sub process_normal() { if (/$doc_start/o) { - $state = STATE_NAME; # next line is always the function name - $in_doc_sect = 0; - $declaration_start_line = $. + 1; + $state = STATE_NAME; # next line is always the function name + $in_doc_sect = 0; + $declaration_start_line = $. + 1; } } @@ -2043,80 +2038,80 @@ sub process_name($$) { my $descr; if (/$doc_block/o) { - $state = STATE_DOCBLOCK; - $contents = ""; - $new_start_line = $.; - - if ( $1 eq "" ) { - $section = $section_intro; - } else { - $section = $1; - } + $state = STATE_DOCBLOCK; + $contents = ""; + $new_start_line = $.; + + if ( $1 eq "" ) { + $section = $section_intro; + } else { + $section = $1; + } } elsif (/$doc_decl/o) { - $identifier = $1; - my $is_kernel_comment = 0; - my $decl_start = qr{$doc_com}; - # test for pointer declaration type, foo * bar() - desc - my $fn_type = qr{\w+\s*\*\s*}; - my $parenthesis = qr{\(\w*\)}; - my $decl_end = qr{[-:].*}; - if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) { - $identifier = $1; - } - if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) { - $decl_type = $1; - $identifier = $2; - $is_kernel_comment = 1; - } - # Look for foo() or static void foo() - description; or misspelt - # identifier - elsif (/^$decl_start$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ || - /^$decl_start$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) { - $identifier = $1; - $decl_type = 'function'; - $identifier =~ s/^define\s+//; - $is_kernel_comment = 1; - } - $identifier =~ s/\s+$//; - - $state = STATE_BODY; - # if there's no @param blocks need to set up default section - # here - $contents = ""; - $section = $section_default; - $new_start_line = $. + 1; - if (/[-:](.*)/) { - # strip leading/trailing/multiple spaces - $descr= $1; - $descr =~ s/^\s*//; - $descr =~ s/\s*$//; - $descr =~ s/\s+/ /g; - $declaration_purpose = $descr; - $state = STATE_BODY_MAYBE; - } else { - $declaration_purpose = ""; - } - - if (!$is_kernel_comment) { - emit_warning("${file}:$.", "This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n$_"); - $state = STATE_NORMAL; - } - - if (($declaration_purpose eq "") && $Wshort_desc) { - emit_warning("${file}:$.", "missing initial short description on line:\n$_"); - } - - if ($identifier eq "" && $decl_type ne "enum") { - emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_"); - $state = STATE_NORMAL; - } - - if ($verbose) { - print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n"; - } + $identifier = $1; + my $is_kernel_comment = 0; + my $decl_start = qr{$doc_com}; + # test for pointer declaration type, foo * bar() - desc + my $fn_type = qr{\w+\s*\*\s*}; + my $parenthesis = qr{\(\w*\)}; + my $decl_end = qr{[-:].*}; + if (/^$decl_start([\w\s]+?)$parenthesis?\s*$decl_end?$/) { + $identifier = $1; + } + if ($identifier =~ m/^(struct|union|enum|typedef)\b\s*(\S*)/) { + $decl_type = $1; + $identifier = $2; + $is_kernel_comment = 1; + } + # Look for foo() or static void foo() - description; or misspelt + # identifier + elsif (/^$decl_start$fn_type?(\w+)\s*$parenthesis?\s*$decl_end?$/ || + /^$decl_start$fn_type?(\w+.*)$parenthesis?\s*$decl_end$/) { + $identifier = $1; + $decl_type = 'function'; + $identifier =~ s/^define\s+//; + $is_kernel_comment = 1; + } + $identifier =~ s/\s+$//; + + $state = STATE_BODY; + # if there's no @param blocks need to set up default section + # here + $contents = ""; + $section = $section_default; + $new_start_line = $. + 1; + if (/[-:](.*)/) { + # strip leading/trailing/multiple spaces + $descr= $1; + $descr =~ s/^\s*//; + $descr =~ s/\s*$//; + $descr =~ s/\s+/ /g; + $declaration_purpose = $descr; + $state = STATE_BODY_MAYBE; + } else { + $declaration_purpose = ""; + } + + if (!$is_kernel_comment) { + emit_warning("${file}:$.", "This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst\n$_"); + $state = STATE_NORMAL; + } + + if (($declaration_purpose eq "") && $Wshort_desc) { + emit_warning("${file}:$.", "missing initial short description on line:\n$_"); + } + + if ($identifier eq "" && $decl_type ne "enum") { + emit_warning("${file}:$.", "wrong kernel-doc identifier on line:\n$_"); + $state = STATE_NORMAL; + } + + if ($verbose) { + print STDERR "${file}:$.: info: Scanning doc for $decl_type $identifier\n"; + } } else { - emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n"); - $state = STATE_NORMAL; + emit_warning("${file}:$.", "Cannot understand $_ on line $. - I thought it was a doc line\n"); + $state = STATE_NORMAL; } } @@ -2128,102 +2123,102 @@ sub process_body($$) { my $file = shift; if ($state == STATE_BODY_WITH_BLANK_LINE && /^\s*\*\s?\S/) { - dump_section($file, $section, $contents); - $section = $section_default; - $new_start_line = $.; - $contents = ""; + dump_section($file, $section, $contents); + $section = $section_default; + $new_start_line = $.; + $contents = ""; } if (/$doc_sect/i) { # case insensitive for supported section names - $in_doc_sect = 1; - $newsection = $1; - $newcontents = $2; - - # map the supported section names to the canonical names - if ($newsection =~ m/^description$/i) { - $newsection = $section_default; - } elsif ($newsection =~ m/^context$/i) { - $newsection = $section_context; - } elsif ($newsection =~ m/^returns?$/i) { - $newsection = $section_return; - } elsif ($newsection =~ m/^\@return$/) { - # special: @return is a section, not a param description - $newsection = $section_return; - } - - if (($contents ne "") && ($contents ne "\n")) { - if (!$in_doc_sect && $Wcontents_before_sections) { - emit_warning("${file}:$.", "contents before sections\n"); - } - dump_section($file, $section, $contents); - $section = $section_default; - } - - $in_doc_sect = 1; - $state = STATE_BODY; - $contents = $newcontents; - $new_start_line = $.; - while (substr($contents, 0, 1) eq " ") { - $contents = substr($contents, 1); - } - if ($contents ne "") { - $contents .= "\n"; - } - $section = $newsection; - $leading_space = undef; + $in_doc_sect = 1; + $newsection = $1; + $newcontents = $2; + + # map the supported section names to the canonical names + if ($newsection =~ m/^description$/i) { + $newsection = $section_default; + } elsif ($newsection =~ m/^context$/i) { + $newsection = $section_context; + } elsif ($newsection =~ m/^returns?$/i) { + $newsection = $section_return; + } elsif ($newsection =~ m/^\@return$/) { + # special: @return is a section, not a param description + $newsection = $section_return; + } + + if (($contents ne "") && ($contents ne "\n")) { + if (!$in_doc_sect && $Wcontents_before_sections) { + emit_warning("${file}:$.", "contents before sections\n"); + } + dump_section($file, $section, $contents); + $section = $section_default; + } + + $in_doc_sect = 1; + $state = STATE_BODY; + $contents = $newcontents; + $new_start_line = $.; + while (substr($contents, 0, 1) eq " ") { + $contents = substr($contents, 1); + } + if ($contents ne "") { + $contents .= "\n"; + } + $section = $newsection; + $leading_space = undef; } elsif (/$doc_end/) { - if (($contents ne "") && ($contents ne "\n")) { - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - } - # look for doc_com + + doc_end: - if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { - emit_warning("${file}:$.", "suspicious ending line: $_"); - } - - $prototype = ""; - $state = STATE_PROTO; - $brcount = 0; + if (($contents ne "") && ($contents ne "\n")) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + # look for doc_com + + doc_end: + if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { + emit_warning("${file}:$.", "suspicious ending line: $_"); + } + + $prototype = ""; + $state = STATE_PROTO; + $brcount = 0; $new_start_line = $. + 1; } elsif (/$doc_content/) { - if ($1 eq "") { - if ($section eq $section_context) { - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - $new_start_line = $.; - $state = STATE_BODY; - } else { - if ($section ne $section_default) { - $state = STATE_BODY_WITH_BLANK_LINE; - } else { - $state = STATE_BODY; - } - $contents .= "\n"; - } - } elsif ($state == STATE_BODY_MAYBE) { - # Continued declaration purpose - chomp($declaration_purpose); - $declaration_purpose .= " " . $1; - $declaration_purpose =~ s/\s+/ /g; - } else { - my $cont = $1; - if ($section =~ m/^@/ || $section eq $section_context) { - if (!defined $leading_space) { - if ($cont =~ m/^(\s+)/) { - $leading_space = $1; - } else { - $leading_space = ""; - } - } - $cont =~ s/^$leading_space//; - } - $contents .= $cont . "\n"; - } + if ($1 eq "") { + if ($section eq $section_context) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + $new_start_line = $.; + $state = STATE_BODY; + } else { + if ($section ne $section_default) { + $state = STATE_BODY_WITH_BLANK_LINE; + } else { + $state = STATE_BODY; + } + $contents .= "\n"; + } + } elsif ($state == STATE_BODY_MAYBE) { + # Continued declaration purpose + chomp($declaration_purpose); + $declaration_purpose .= " " . $1; + $declaration_purpose =~ s/\s+/ /g; + } else { + my $cont = $1; + if ($section =~ m/^@/ || $section eq $section_context) { + if (!defined $leading_space) { + if ($cont =~ m/^(\s+)/) { + $leading_space = $1; + } else { + $leading_space = ""; + } + } + $cont =~ s/^$leading_space//; + } + $contents .= $cont . "\n"; + } } else { - # i dont know - bad line? ignore. - emit_warning("${file}:$.", "bad line: $_"); + # i dont know - bad line? ignore. + emit_warning("${file}:$.", "bad line: $_"); } } @@ -2235,21 +2230,21 @@ sub process_proto($$) { my $file = shift; if (/$doc_inline_oneline/) { - $section = $1; - $contents = $2; - if ($contents ne "") { - $contents .= "\n"; - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - } + $section = $1; + $contents = $2; + if ($contents ne "") { + $contents .= "\n"; + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } } elsif (/$doc_inline_start/) { - $state = STATE_INLINE; - $inline_doc_state = STATE_INLINE_NAME; + $state = STATE_INLINE; + $inline_doc_state = STATE_INLINE_NAME; } elsif ($decl_type eq 'function') { - process_proto_function($_, $file); + process_proto_function($_, $file); } else { - process_proto_type($_, $file); + process_proto_type($_, $file); } } @@ -2260,23 +2255,23 @@ sub process_docblock($$) { my $file = shift; if (/$doc_end/) { - dump_doc_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - $function = ""; - %parameterdescs = (); - %parametertypes = (); - @parameterlist = (); - %sections = (); - @sectionlist = (); - $prototype = ""; - $state = STATE_NORMAL; + dump_doc_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + $function = ""; + %parameterdescs = (); + %parametertypes = (); + @parameterlist = (); + %sections = (); + @sectionlist = (); + $prototype = ""; + $state = STATE_NORMAL; } elsif (/$doc_content/) { - if ( $1 eq "" ) { - $contents .= $blankline; - } else { - $contents .= $1 . "\n"; - } + if ( $1 eq "" ) { + $contents .= $blankline; + } else { + $contents .= $1 . "\n"; + } } } @@ -2288,37 +2283,37 @@ sub process_inline($$) { # First line (state 1) needs to be a @parameter if ($inline_doc_state == STATE_INLINE_NAME && /$doc_inline_sect/o) { - $section = $1; - $contents = $2; - $new_start_line = $.; - if ($contents ne "") { - while (substr($contents, 0, 1) eq " ") { - $contents = substr($contents, 1); - } - $contents .= "\n"; - } - $inline_doc_state = STATE_INLINE_TEXT; - # Documentation block end */ + $section = $1; + $contents = $2; + $new_start_line = $.; + if ($contents ne "") { + while (substr($contents, 0, 1) eq " ") { + $contents = substr($contents, 1); + } + $contents .= "\n"; + } + $inline_doc_state = STATE_INLINE_TEXT; + # Documentation block end */ } elsif (/$doc_inline_end/) { - if (($contents ne "") && ($contents ne "\n")) { - dump_section($file, $section, $contents); - $section = $section_default; - $contents = ""; - } - $state = STATE_PROTO; - $inline_doc_state = STATE_INLINE_NA; - # Regular text + if (($contents ne "") && ($contents ne "\n")) { + dump_section($file, $section, $contents); + $section = $section_default; + $contents = ""; + } + $state = STATE_PROTO; + $inline_doc_state = STATE_INLINE_NA; + # Regular text } elsif (/$doc_content/) { - if ($inline_doc_state == STATE_INLINE_TEXT) { - $contents .= $1 . "\n"; - # nuke leading blank lines - if ($contents =~ /^\s*$/) { - $contents = ""; - } - } elsif ($inline_doc_state == STATE_INLINE_NAME) { - $inline_doc_state = STATE_INLINE_ERROR; - emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_"); - } + if ($inline_doc_state == STATE_INLINE_TEXT) { + $contents .= $1 . "\n"; + # nuke leading blank lines + if ($contents =~ /^\s*$/) { + $contents = ""; + } + } elsif ($inline_doc_state == STATE_INLINE_NAME) { + $inline_doc_state = STATE_INLINE_ERROR; + emit_warning("${file}:$.", "Incorrect use of kernel-doc format: $_"); + } } } @@ -2331,54 +2326,53 @@ sub process_file($) { $file = map_filename($orig_file); if (!open(IN_FILE,"<$file")) { - print STDERR "Error: Cannot open file $file\n"; - ++$errors; - return; + print STDERR "Error: Cannot open file $file\n"; + ++$errors; + return; } $. = 1; $section_counter = 0; while () { - while (!/^ \*/ && s/\\\s*$//) { - $_ .= ; - } - # Replace tabs by spaces + while (!/^ \*/ && s/\\\s*$//) { + $_ .= ; + } + # Replace tabs by spaces while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {}; - # Hand this line to the appropriate state handler - if ($state == STATE_NORMAL) { - process_normal(); - } elsif ($state == STATE_NAME) { - process_name($file, $_); - } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE || - $state == STATE_BODY_WITH_BLANK_LINE) { - process_body($file, $_); - } elsif ($state == STATE_INLINE) { # scanning for inline parameters - process_inline($file, $_); - } elsif ($state == STATE_PROTO) { - process_proto($file, $_); - } elsif ($state == STATE_DOCBLOCK) { - process_docblock($file, $_); - } + # Hand this line to the appropriate state handler + if ($state == STATE_NORMAL) { + process_normal(); + } elsif ($state == STATE_NAME) { + process_name($file, $_); + } elsif ($state == STATE_BODY || $state == STATE_BODY_MAYBE || + $state == STATE_BODY_WITH_BLANK_LINE) { + process_body($file, $_); + } elsif ($state == STATE_INLINE) { # scanning for inline parameters + process_inline($file, $_); + } elsif ($state == STATE_PROTO) { + process_proto($file, $_); + } elsif ($state == STATE_DOCBLOCK) { + process_docblock($file, $_); + } } # Make sure we got something interesting. if ($initial_section_counter == $section_counter && $ - output_mode ne "none") { - if ($output_selection == OUTPUT_INCLUDE) { - emit_warning("${file}:1", "'$_' not found\n") - for keys %function_table; - } - else { - emit_warning("${file}:1", "no structured comments found\n"); - } + output_mode ne "none") { + if ($output_selection == OUTPUT_INCLUDE) { + emit_warning("${file}:1", "'$_' not found\n") + for keys %function_table; + } else { + emit_warning("${file}:1", "no structured comments found\n"); + } } close IN_FILE; } if ($output_mode eq "rst") { - get_sphinx_version() if (!$sphinx_major); + get_sphinx_version() if (!$sphinx_major); } $kernelversion = get_kernel_version(); @@ -2395,14 +2389,14 @@ for (my $k = 0; $k < @highlights; $k++) { # Read the file that maps relative names to absolute names for # separate source and object directories and for shadow trees. if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { - my ($relname, $absname); - while() { - chop(); - ($relname, $absname) = (split())[0..1]; - $relname =~ s:^/+::; - $source_map{$relname} = $absname; - } - close(SOURCE_MAP); + my ($relname, $absname); + while() { + chop(); + ($relname, $absname) = (split())[0..1]; + $relname =~ s:^/+::; + $source_map{$relname} = $absname; + } + close(SOURCE_MAP); } if ($output_selection == OUTPUT_EXPORTED || @@ -2411,8 +2405,8 @@ if ($output_selection == OUTPUT_EXPORTED || push(@export_file_list, @ARGV); foreach (@export_file_list) { - chomp; - process_export_file($_); + chomp; + process_export_file($_); } } @@ -2421,10 +2415,10 @@ foreach (@ARGV) { process_file($_); } if ($verbose && $errors) { - print STDERR "$errors errors\n"; + print STDERR "$errors errors\n"; } if ($verbose && $warnings) { - print STDERR "$warnings warnings\n"; + print STDERR "$warnings warnings\n"; } if ($Werror && $warnings) { -- cgit v1.2.3 From f1cebae1dbf85f9de65c13a2d9f5cc3be7e51dc4 Mon Sep 17 00:00:00 2001 From: Nícolas F. R. A. Prado Date: Mon, 12 Feb 2024 09:50:06 -0500 Subject: firmware: coreboot: Generate aliases for coreboot modules Generate aliases for coreboot modules to allow automatic module probing. Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Brian Norris Signed-off-by: Nícolas F. R. A. Prado Acked-by: Masahiro Yamada Link: https://lore.kernel.org/r/20240212-coreboot-mod-defconfig-v4-2-d14172676f6d@collabora.com Signed-off-by: Tzung-Bi Shih --- include/linux/mod_devicetable.h | 10 ++++++++++ scripts/mod/devicetable-offsets.c | 3 +++ scripts/mod/file2alias.c | 10 ++++++++++ 3 files changed, 23 insertions(+) (limited to 'scripts') diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index f458469c5ce5..7a9a07ea451b 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -960,4 +960,14 @@ struct vchiq_device_id { char name[32]; }; +/** + * struct coreboot_device_id - Identifies a coreboot table entry + * @tag: tag ID + * @driver_data: driver specific data + */ +struct coreboot_device_id { + __u32 tag; + kernel_ulong_t driver_data; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index e91a3c38143b..518200813d4e 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -274,5 +274,8 @@ int main(void) DEVID(vchiq_device_id); DEVID_FIELD(vchiq_device_id, name); + DEVID(coreboot_device_id); + DEVID_FIELD(coreboot_device_id, tag); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 4829680a0a6d..5d1c61fa5a55 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1494,6 +1494,15 @@ static int do_vchiq_entry(const char *filename, void *symval, char *alias) return 1; } +/* Looks like: coreboot:tN */ +static int do_coreboot_entry(const char *filename, void *symval, char *alias) +{ + DEF_FIELD(symval, coreboot_device_id, tag); + sprintf(alias, "coreboot:t%08X", tag); + + return 1; +} + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { @@ -1575,6 +1584,7 @@ static const struct devtable devtable[] = { {"ishtp", SIZE_ishtp_device_id, do_ishtp_entry}, {"cdx", SIZE_cdx_device_id, do_cdx_entry}, {"vchiq", SIZE_vchiq_device_id, do_vchiq_entry}, + {"coreboot", SIZE_coreboot_device_id, do_coreboot_entry}, }; /* Create MODULE_ALIAS() statements. -- cgit v1.2.3 From 173f6cd384ae27bb57af8cc5201b4f4a137d6e55 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Sun, 18 Feb 2024 16:00:54 +0800 Subject: coccinelle: device_attr_show: Remove useless expression STR Commit ff82e84e80fc ("coccinelle: device_attr_show: simplify patch case") simplifies the patch case, as a result, STR is no longer needed. This also helps to fix below coccicheck warning: > warning: rp: metavariable STR not used in the - or context code CC: Julia Lawall CC: Nicolas Palix CC: cocci@inria.fr Fixes: ff82e84e80fc ("coccinelle: device_attr_show: simplify patch case") Signed-off-by: Li Zhijian Signed-off-by: Julia Lawall --- scripts/coccinelle/api/device_attr_show.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/coccinelle/api/device_attr_show.cocci b/scripts/coccinelle/api/device_attr_show.cocci index 550d1d2fc02a..dfcf9304195f 100644 --- a/scripts/coccinelle/api/device_attr_show.cocci +++ b/scripts/coccinelle/api/device_attr_show.cocci @@ -28,7 +28,7 @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) @rp depends on patch@ identifier show, dev, attr, buf; -expression BUF, SZ, FORMAT, STR; +expression BUF, SZ, FORMAT; @@ ssize_t show(struct device *dev, struct device_attribute *attr, char *buf) -- cgit v1.2.3 From 12e3342fc7b0ec7fcb03f41bb49a1a6e3dcc0663 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 7 Jan 2024 22:19:47 +0900 Subject: kconfig: remove unneeded buffer allocation in zconf_initscan() In Kconfig, there is a stack to save the lexer state for each inclusion level. Currently, it operates as an empty stack, with the 'current_buf' always pointing to an empty buffer. There is no need to preallocate the buffer. Change it to a full stack. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index cc386e443683..d75423ec4eae 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -391,9 +391,6 @@ void zconf_initscan(const char *name) exit(1); } - current_buf = xmalloc(sizeof(*current_buf)); - memset(current_buf, 0, sizeof(*current_buf)); - current_file = file_lookup(name); yylineno = 1; } @@ -403,9 +400,10 @@ void zconf_nextfile(const char *name) struct file *iter; struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); - memset(buf, 0, sizeof(*buf)); - current_buf->state = YY_CURRENT_BUFFER; + buf->state = YY_CURRENT_BUFFER; + buf->parent = current_buf; + current_buf = buf; yyin = zconf_fopen(file->name); if (!yyin) { fprintf(stderr, "%s:%d: can't open file \"%s\"\n", @@ -413,8 +411,6 @@ void zconf_nextfile(const char *name) exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - buf->parent = current_buf; - current_buf = buf; current_file->lineno = yylineno; file->parent = current_file; @@ -441,20 +437,21 @@ void zconf_nextfile(const char *name) static void zconf_endfile(void) { - struct buffer *parent; + struct buffer *tmp; current_file = current_file->parent; if (current_file) yylineno = current_file->lineno; - parent = current_buf->parent; - if (parent) { - fclose(yyin); - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(parent->state); - } - free(current_buf); - current_buf = parent; + if (!current_buf) + return; + + fclose(yyin); + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(current_buf->state); + tmp = current_buf; + current_buf = current_buf->parent; + free(tmp); } int zconf_lineno(void) -- cgit v1.2.3 From 93c432e8c974dfd609a9c7777f731073e4de0c8e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 7 Jan 2024 22:19:48 +0900 Subject: kconfig: fix line number in recursive inclusion detection The error message shows a wrong line number if the 'source' directive is wrapped to the following line. [Test Code] source \ "Kconfig" This results in the following error message: Recursive inclusion detected. Inclusion path: current file : Kconfig included from: Kconfig:2 The correct message should be as follows: Recursive inclusion detected. Inclusion path: current file : Kconfig included from: Kconfig:1 Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index d75423ec4eae..f93b535a080c 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -33,6 +33,7 @@ static int text_size, text_asize; struct buffer { struct buffer *parent; YY_BUFFER_STATE state; + int yylineno; }; static struct buffer *current_buf; @@ -402,6 +403,7 @@ void zconf_nextfile(const char *name) struct buffer *buf = xmalloc(sizeof(*buf)); buf->state = YY_CURRENT_BUFFER; + buf->yylineno = yylineno; buf->parent = current_buf; current_buf = buf; yyin = zconf_fopen(file->name); @@ -412,7 +414,7 @@ void zconf_nextfile(const char *name) } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - current_file->lineno = yylineno; + current_file->lineno = zconf_lineno(); file->parent = current_file; for (iter = current_file; iter; iter = iter->parent) { @@ -425,7 +427,7 @@ void zconf_nextfile(const char *name) do { iter = iter->parent; fprintf(stderr, " included from: %s:%d\n", - iter->name, iter->lineno - 1); + iter->name, iter->lineno); } while (strcmp(iter->name, file->name)); exit(1); } @@ -440,8 +442,6 @@ static void zconf_endfile(void) struct buffer *tmp; current_file = current_file->parent; - if (current_file) - yylineno = current_file->lineno; if (!current_buf) return; @@ -449,6 +449,7 @@ static void zconf_endfile(void) fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(current_buf->state); + yylineno = current_buf->yylineno; tmp = current_buf; current_buf = current_buf->parent; free(tmp); -- cgit v1.2.3 From 24507871c3c6ae4f6b460b016da7ff434cd34149 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Jan 2024 21:07:34 +0900 Subject: kbuild: create a list of all built DTB files It is useful to have a list of all *.dtb and *.dtbo files generated from the current build. With this commit, 'make dtbs' creates arch/*/boot/dts/dtbs-list, which lists the dtb(o) files created in the current build. It maintains the order of the dtb-y additions in Makefiles although the order is not important for DTBs. It is a (good) side effect through the reuse of the modules.order rule. Please note this list only includes the files directly added to dtb-y. For example, consider this case: foo-dtbs := foo_base.dtb foo_overlay.dtbo dtb-y := foo.dtb In this example, the list will include foo.dtb, but not foo_base.dtb or foo_overlay.dtbo. Signed-off-by: Masahiro Yamada --- .gitignore | 1 + Makefile | 4 ++-- scripts/Makefile.build | 20 ++++++++++++-------- scripts/Makefile.lib | 6 ++++++ 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'scripts') diff --git a/.gitignore b/.gitignore index 689a4fa3f547..c59dc60ba62e 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ *.xz *.zst Module.symvers +dtbs-list modules.order # diff --git a/Makefile b/Makefile index 41fa8a2565f5..f5755b81591b 100644 --- a/Makefile +++ b/Makefile @@ -1393,7 +1393,7 @@ ifneq ($(dtstree),) PHONY += dtbs dtbs_prepare dtbs_install dtbs_check dtbs: dtbs_prepare - $(Q)$(MAKE) $(build)=$(dtstree) + $(Q)$(MAKE) $(build)=$(dtstree) need-dtbslist=1 # include/config/kernel.release is actually needed when installing DTBs because # INSTALL_DTBS_PATH contains $(KERNELRELEASE). However, we do not want to make @@ -1932,7 +1932,7 @@ clean: $(clean-dirs) -o -name '*.ko.*' \ -o -name '*.dtb' -o -name '*.dtbo' \ -o -name '*.dtb.S' -o -name '*.dtbo.S' \ - -o -name '*.dt.yaml' \ + -o -name '*.dt.yaml' -o -name 'dtbs-list' \ -o -name '*.dwo' -o -name '*.lst' \ -o -name '*.su' -o -name '*.mod' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ diff --git a/scripts/Makefile.build b/scripts/Makefile.build index dae447a1ad30..4971f54c855e 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -71,6 +71,7 @@ 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) @@ -388,6 +389,7 @@ $(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) @@ -404,19 +406,21 @@ $(obj)/built-in.a: $(real-obj-y) FORCE $(call if_changed,ar_builtin) # -# Rule to create modules.order file +# Rule to create modules.order and dtbs-list # -# Create commands to either record .ko file or cat modules.order from -# a subdirectory -# Add $(obj-m) as the prerequisite to avoid updating the timestamp of -# modules.order unless contained modules are updated. +# 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. -cmd_modules_order = { $(foreach m, $(real-prereqs), \ - $(if $(filter %/modules.order, $m), cat $m, echo $m);) :; } \ +cmd_gen_order = { $(foreach m, $(real-prereqs), \ + $(if $(filter %/$(notdir $@), $m), cat $m, echo $m);) :; } \ > $@ $(obj)/modules.order: $(obj-m) FORCE - $(call if_changed,modules_order) + $(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) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index cd5b181060f1..b35d39022a30 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -45,6 +45,11 @@ 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 @@ -99,6 +104,7 @@ 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)) -- cgit v1.2.3 From 8f66864cee447835889ec0d91d52ff39bf2deabc Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Jan 2024 21:07:35 +0900 Subject: kbuild: simplify dtbs_install by reading the list of compiled DTBs Retrieve the list of *.dtb(o) files from arch/*/boot/dts/dtbs-list instead of traversing the directory tree again. Please note that 'make dtbs_install' installs *.dtb(o) files directly added to dtb-y because scripts/Makefile.dtbinst installs $(dtb-y) without expanding the -dtbs suffix. This commit preserves this behavior. Signed-off-by: Masahiro Yamada --- Makefile | 2 +- scripts/Kbuild.include | 6 ------ scripts/Makefile.dtbinst | 32 ++++++++++++++++++-------------- 3 files changed, 19 insertions(+), 21 deletions(-) (limited to 'scripts') diff --git a/Makefile b/Makefile index f5755b81591b..bc54a6cc8dc5 100644 --- a/Makefile +++ b/Makefile @@ -1411,7 +1411,7 @@ endif dtbs_check: dtbs dtbs_install: - $(Q)$(MAKE) $(dtbinst)=$(dtstree) dst=$(INSTALL_DTBS_PATH) + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.dtbinst obj=$(dtstree) ifdef CONFIG_OF_EARLY_FLATTREE all: dtbs diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 7778cc97a4e0..2f331879816b 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -113,12 +113,6 @@ endef # $(Q)$(MAKE) $(build)=dir build := -f $(srctree)/scripts/Makefile.build obj -### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= -# Usage: -# $(Q)$(MAKE) $(dtbinst)=dir -dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj - ### # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= # Usage: diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst index 4405d5b67578..67956f6496a5 100644 --- a/scripts/Makefile.dtbinst +++ b/scripts/Makefile.dtbinst @@ -8,32 +8,36 @@ # $INSTALL_PATH/dtbs/$KERNELRELEASE # ========================================================================== -src := $(obj) - PHONY := __dtbs_install __dtbs_install: include include/config/auto.conf include $(srctree)/scripts/Kbuild.include -include $(kbuild-file) - -dtbs := $(addprefix $(dst)/, $(dtb-y) $(if $(CONFIG_OF_ALL_DTBS),$(dtb-))) -subdirs := $(addprefix $(obj)/, $(subdir-y) $(subdir-m)) -__dtbs_install: $(dtbs) $(subdirs) - @: +dst := $(INSTALL_DTBS_PATH) quiet_cmd_dtb_install = INSTALL $@ cmd_dtb_install = install -D $< $@ -$(dst)/%.dtb: $(obj)/%.dtb +$(dst)/%: $(obj)/% $(call cmd,dtb_install) -$(dst)/%.dtbo: $(obj)/%.dtbo - $(call cmd,dtb_install) +dtbs := $(patsubst $(obj)/%,%,$(call read-file, $(obj)/dtbs-list)) + +ifdef CONFIG_ARCH_WANT_FLAT_DTB_INSTALL -PHONY += $(subdirs) -$(subdirs): - $(Q)$(MAKE) $(dtbinst)=$@ dst=$(if $(CONFIG_ARCH_WANT_FLAT_DTB_INSTALL),$(dst),$(patsubst $(obj)/%,$(dst)/%,$@)) +define gen_install_rules +$(dst)/%: $(obj)/$(1)% + $$(call cmd,dtb_install) +endef + +$(foreach d, $(sort $(dir $(dtbs))), $(eval $(call gen_install_rules,$(d)))) + +dtbs := $(notdir $(dtbs)) + +endif # CONFIG_ARCH_WANT_FLAT_DTB_INSTALL + +__dtbs_install: $(addprefix $(dst)/, $(dtbs)) + @: .PHONY: $(PHONY) -- cgit v1.2.3 From cc3df32c9f3a99f715c551f76b040fcf2e5050a5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 13 Jan 2024 19:43:36 +0900 Subject: kbuild: deb-pkg: show verbose log for direct package builds When the Debian package build is initiated by Kbuild ('make deb-pkg' or 'make bindeb-pkg'), the log messages are displayed in the short form, which is the Kbuild default. Otherwise, let's show verbose messages (unless the 'terse' tag is set in DEB_BUILD_OPTION), as suggested by Debian Policy: "The package build should be as verbose as reasonably possible, except where the terse tag is included in DEB_BUILD_OPTIONS." [1] This is what the Debian kernel also does. [2] [1]: https://www.debian.org/doc/debian-policy/ch-source.html#main-building-script-debian-rules [2]: https://salsa.debian.org/kernel-team/linux/-/blob/debian/6.7-1_exp1/debian/rules.real#L36 Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/debian/rules | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'scripts') diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules index 098307780062..697fbfa7595f 100755 --- a/scripts/package/debian/rules +++ b/scripts/package/debian/rules @@ -11,6 +11,14 @@ ifneq (,$(filter-out parallel=1,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))) MAKEFLAGS += -j$(NUMJOBS) endif +# When KBUILD_VERBOSE is undefined (presumably you are directly working with +# the debianized tree), show verbose logs unless DEB_BUILD_OPTION=terse is set. +ifeq ($(origin KBUILD_VERBOSE),undefined) + ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS))) + export KBUILD_VERBOSE := 1 + endif +endif + revision = $(lastword $(subst -, ,$(shell dpkg-parsechangelog -S Version))) CROSS_COMPILE ?= $(filter-out $(DEB_BUILD_GNU_TYPE)-, $(DEB_HOST_GNU_TYPE)-) make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(revision) $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE)) -- cgit v1.2.3 From caf400c8b68af29568e39ef99b12d25966c3e76b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 13 Jan 2024 19:43:37 +0900 Subject: kbuild: deb-pkg: make debian/rules quiet for 'make deb-pkg' Add $(Q) to the commands in debian/rules to make them quiet when the package built is initiated by 'make deb-pkg' or when the 'terse' tag is set to DEB_BUILD_OPTIONS. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/debian/rules | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'scripts') diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules index 697fbfa7595f..a183e95886e6 100755 --- a/scripts/package/debian/rules +++ b/scripts/package/debian/rules @@ -16,6 +16,8 @@ endif ifeq ($(origin KBUILD_VERBOSE),undefined) ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS))) export KBUILD_VERBOSE := 1 + else + Q := @ endif endif @@ -27,20 +29,20 @@ make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(r binary: binary-arch binary-indep binary-indep: build-indep binary-arch: build-arch - $(MAKE) $(make-opts) \ + $(Q)$(MAKE) $(make-opts) \ run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb' .PHONY: build build-indep build-arch build: build-arch build-indep build-indep: build-arch: - $(MAKE) $(make-opts) olddefconfig - $(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all + $(Q)$(MAKE) $(make-opts) olddefconfig + $(Q)$(MAKE) $(make-opts) $(if $(filter um,$(ARCH)),,headers) all .PHONY: clean clean: - rm -rf debian/files debian/linux-* debian/deb-env.vars* - $(MAKE) ARCH=$(ARCH) clean + $(Q)rm -rf debian/files debian/linux-* debian/deb-env.vars* + $(Q)$(MAKE) ARCH=$(ARCH) clean # If DEB_HOST_ARCH is empty, it is likely that debian/rules was executed # directly. Run 'dpkg-architecture --print-set --print-format=make' to @@ -49,6 +51,6 @@ ifndef DEB_HOST_ARCH include debian/deb-env.vars debian/deb-env.vars: - dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp - mv $@.tmp $@ + $(Q)dpkg-architecture -a$$(cat debian/arch) --print-set --print-format=make > $@.tmp + $(Q)mv $@.tmp $@ endif -- cgit v1.2.3 From 1d7bae8f8c85ddf153f302cd8d2f33d34762b0fd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 13 Jan 2024 19:43:38 +0900 Subject: kbuild: deb-pkg: build binary-arch in parallel 'make deb-pkg' builds build-arch in parallel, but binary-arch serially. Given that all binary packages are independent of one another, they can be built in parallel. I am uncertain whether debian/files is robust against a race condition. Just in case, make dh_gencontrol (dpkg-gencontrol) output to separate debian/*.files, which are then concatenated into debian/files. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/builddeb | 42 ++++++++++++------------------------------ scripts/package/debian/rules | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 34 deletions(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index bf96a3c24608..d31b16afe0db 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -24,18 +24,6 @@ if_enabled_echo() { fi } -create_package() { - export DH_OPTIONS="-p${1}" - - dh_installdocs - dh_installchangelogs - dh_compress - dh_fixperms - dh_gencontrol - dh_md5sums - dh_builddeb -- ${KDEB_COMPRESS:+-Z$KDEB_COMPRESS} -} - install_linux_image () { pname=$1 pdir=debian/$1 @@ -161,21 +149,15 @@ install_libc_headers () { mv "$pdir/usr/include/asm" "$pdir/usr/include/${DEB_HOST_MULTIARCH}" } -rm -f debian/files - -packages_enabled=$(dh_listpackages) - -for package in ${packages_enabled} -do - case ${package} in - *-dbg) - install_linux_image_dbg "${package}";; - linux-image-*|user-mode-linux-*) - install_linux_image "${package}";; - linux-libc-dev) - install_libc_headers "${package}";; - linux-headers-*) - install_kernel_headers "${package}";; - esac - create_package "${package}" -done +package=$1 + +case "${package}" in +*-dbg) + install_linux_image_dbg "${package}";; +linux-image-*|user-mode-linux-*) + install_linux_image "${package}";; +linux-libc-dev) + install_libc_headers "${package}";; +linux-headers-*) + install_kernel_headers "${package}";; +esac diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules index a183e95886e6..57f1cf7c6b32 100755 --- a/scripts/package/debian/rules +++ b/scripts/package/debian/rules @@ -25,12 +25,43 @@ revision = $(lastword $(subst -, ,$(shell dpkg-parsechangelog -S Version))) CROSS_COMPILE ?= $(filter-out $(DEB_BUILD_GNU_TYPE)-, $(DEB_HOST_GNU_TYPE)-) make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(revision) $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE)) +binary-targets := $(addprefix binary-, image image-dbg headers libc-dev) + +all-packages = $(shell dh_listpackages) +image-package = $(filter linux-image-% user-%, $(filter-out %-dbg, $(all-packages))) +image-dbg-package = $(filter %-dbg, $(all-packages)) +libc-dev-package = $(filter linux-libc-dev, $(all-packages)) +headers-package = $(filter linux-headers-%, $(all-packages)) + +mk-files = $(patsubst binary-%,debian/%.files,$1) +package = $($(@:binary-%=%-package)) + +# DH_OPTION is an environment variable common for all debhelper commands. +# We could 'export' it, but here it is passed from the command line to clarify +# which package is being processed in the build log. +DH_OPTIONS = -p$(package) + +define binary + $(Q)+$(MAKE) $(make-opts) run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb $(package)' + $(Q)dh_installdocs $(DH_OPTIONS) + $(Q)dh_installchangelogs $(DH_OPTIONS) + $(Q)dh_compress $(DH_OPTIONS) + $(Q)dh_fixperms $(DH_OPTIONS) + $(Q)dh_gencontrol $(DH_OPTIONS) -- -f$(call mk-files,$@) + $(Q)dh_md5sums $(DH_OPTIONS) + $(Q)dh_builddeb $(DH_OPTIONS) -- $(addprefix -Z,$(KDEB_COMPRESS)) +endef + +.PHONY: $(binary-targets) +$(binary-targets): build-arch + $(Q)truncate -s0 $(call mk-files,$@) + $(if $(package),$(binary)) + .PHONY: binary binary-indep binary-arch binary: binary-arch binary-indep binary-indep: build-indep -binary-arch: build-arch - $(Q)$(MAKE) $(make-opts) \ - run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb' +binary-arch: $(binary-targets) + $(Q)cat $(call mk-files,$^) > debian/files .PHONY: build build-indep build-arch build: build-arch build-indep @@ -41,7 +72,7 @@ build-arch: .PHONY: clean clean: - $(Q)rm -rf debian/files debian/linux-* debian/deb-env.vars* + $(Q)rm -rf debian/files debian/linux-* debian/deb-env.vars* debian/*.files $(Q)$(MAKE) ARCH=$(ARCH) clean # If DEB_HOST_ARCH is empty, it is likely that debian/rules was executed -- cgit v1.2.3 From f96beb84eff698aefde7cea2bbf1de4f688c4750 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 13 Jan 2024 19:43:39 +0900 Subject: kbuild: deb-pkg: call more misc debhelper commands Use dh_prep instead of removing old build directories manually. Use dh_clean instead of removing build directories and debian/files manually. Call dh_testdir and dh_testroot for preliminary checks. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/package/builddeb | 8 -------- scripts/package/debian/rules | 6 +++++- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index d31b16afe0db..e797ad360f7a 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -28,8 +28,6 @@ install_linux_image () { pname=$1 pdir=debian/$1 - rm -rf ${pdir} - # Only some architectures with OF support have this target if is_enabled CONFIG_OF_EARLY_FLATTREE && [ -d "${srctree}/arch/${SRCARCH}/boot/dts" ]; then ${MAKE} -f ${srctree}/Makefile INSTALL_DTBS_PATH="${pdir}/usr/lib/linux-image-${KERNELRELEASE}" dtbs_install @@ -97,8 +95,6 @@ install_linux_image () { install_linux_image_dbg () { pdir=debian/$1 - rm -rf ${pdir} - # Parse modules.order directly because 'make modules_install' may sign, # compress modules, and then run unneeded depmod. while read -r mod; do @@ -128,8 +124,6 @@ install_kernel_headers () { pdir=debian/$1 version=${1#linux-headers-} - rm -rf $pdir - "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" mkdir -p $pdir/lib/modules/$version/ @@ -139,8 +133,6 @@ install_kernel_headers () { install_libc_headers () { pdir=debian/$1 - rm -rf $pdir - $MAKE -f $srctree/Makefile headers_install INSTALL_HDR_PATH=$pdir/usr # move asm headers to /usr/include//asm to match the structure diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules index 57f1cf7c6b32..ca07243bd5cd 100755 --- a/scripts/package/debian/rules +++ b/scripts/package/debian/rules @@ -42,6 +42,9 @@ package = $($(@:binary-%=%-package)) DH_OPTIONS = -p$(package) define binary + $(Q)dh_testdir $(DH_OPTIONS) + $(Q)dh_testroot $(DH_OPTIONS) + $(Q)dh_prep $(DH_OPTIONS) $(Q)+$(MAKE) $(make-opts) run-command KBUILD_RUN_COMMAND='+$$(srctree)/scripts/package/builddeb $(package)' $(Q)dh_installdocs $(DH_OPTIONS) $(Q)dh_installchangelogs $(DH_OPTIONS) @@ -72,7 +75,8 @@ build-arch: .PHONY: clean clean: - $(Q)rm -rf debian/files debian/linux-* debian/deb-env.vars* debian/*.files + $(Q)dh_clean + $(Q)rm -rf debian/deb-env.vars* debian/*.files $(Q)$(MAKE) ARCH=$(ARCH) clean # If DEB_HOST_ARCH is empty, it is likely that debian/rules was executed -- cgit v1.2.3 From 615b3a3d2d41bf897168210a092811872561259f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 2 Feb 2024 22:35:17 +0900 Subject: kbuild: rpm-pkg: do not include depmod-generated files Installing the kernel package is fine, but when uninstalling it, the following warnings are shown: warning: file modules.symbols.bin: remove failed: No such file or directory warning: file modules.symbols: remove failed: No such file or directory warning: file modules.softdep: remove failed: No such file or directory warning: file modules.devname: remove failed: No such file or directory warning: file modules.dep.bin: remove failed: No such file or directory warning: file modules.dep: remove failed: No such file or directory warning: file modules.builtin.bin: remove failed: No such file or directory warning: file modules.builtin.alias.bin: remove failed: No such file or directory warning: file modules.alias.bin: remove failed: No such file or directory warning: file modules.alias: remove failed: No such file or directory The %preun scriptlet runs 'kernel-install remove', which in turn invokes /usr/lib/kernel/install.d/50-depmod.install to remove those files before the actual package removal. RPM-based distributions do not ship files generated by depmod. Mark them as %ghost in order to exclude them from the package, but still claim the ownership on them. Signed-off-by: Masahiro Yamada Tested-by: Nathan Chancellor --- scripts/package/kernel.spec | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index f58726671fb3..aaedb6d1b26f 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -66,6 +66,20 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}' %endif +{ + for x in System.map config kernel modules.builtin \ + modules.builtin.modinfo modules.order vmlinuz; do + echo "/lib/modules/%{KERNELRELEASE}/${x}" + done + + for x in alias alias.bin builtin.alias.bin builtin.bin dep dep.bin \ + devname softdep symbols symbols.bin; do + echo "%ghost /lib/modules/%{KERNELRELEASE}/modules.${x}" + done + + echo "%exclude /lib/modules/%{KERNELRELEASE}/build" +} > %{buildroot}/kernel.list + %clean rm -rf %{buildroot} @@ -78,6 +92,9 @@ for file in vmlinuz System.map config; do cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}" fi done +if [ ! -e "/lib/modules/%{KERNELRELEASE}/modules.dep" ]; then + /usr/sbin/depmod %{KERNELRELEASE} +fi %preun if [ -x /sbin/new-kernel-pkg ]; then @@ -91,10 +108,9 @@ if [ -x /sbin/update-bootloader ]; then /sbin/update-bootloader --remove %{KERNELRELEASE} fi -%files +%files -f %{buildroot}/kernel.list %defattr (-, root, root) -/lib/modules/%{KERNELRELEASE} -%exclude /lib/modules/%{KERNELRELEASE}/build +%exclude /kernel.list %files headers %defattr (-, root, root) -- cgit v1.2.3 From bca17edb24cb0e9ebc9269a77fc0a15f4b526f65 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 2 Feb 2024 22:35:18 +0900 Subject: kbuild: rpm-pkg: mark installed files in /boot as %ghost Mark the files installed to /boot as %ghost to make sure they will be removed when the package is uninstalled. Signed-off-by: Masahiro Yamada Tested-by: Nathan Chancellor --- scripts/package/kernel.spec | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'scripts') diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index aaedb6d1b26f..ecedcfc11e73 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -77,6 +77,10 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA echo "%ghost /lib/modules/%{KERNELRELEASE}/modules.${x}" done + for x in System.map config vmlinuz; do + echo "%ghost /boot/${x}-%{KERNELRELEASE}" + done + echo "%exclude /lib/modules/%{KERNELRELEASE}/build" } > %{buildroot}/kernel.list -- cgit v1.2.3 From 435e86998edf2a2308e7917c6368427f89664c61 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 2 Feb 2024 22:35:19 +0900 Subject: Revert "kbuild/mkspec: support 'update-bootloader'-based systems" This reverts commit 27c3bffd230abd0a598586aed0fe0ba7b61e0e2e. If this is still needed, we can bring it back. However, I'd like to understand why 'update-bootloader --remove' is needed for uninstallation, while 'update-bootloader --add' was not called during the installation. Signed-off-by: Masahiro Yamada --- scripts/package/kernel.spec | 5 ----- 1 file changed, 5 deletions(-) (limited to 'scripts') diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index ecedcfc11e73..c1b745967f64 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -107,11 +107,6 @@ elif [ -x /usr/bin/kernel-install ]; then kernel-install remove %{KERNELRELEASE} fi -%postun -if [ -x /sbin/update-bootloader ]; then -/sbin/update-bootloader --remove %{KERNELRELEASE} -fi - %files -f %{buildroot}/kernel.list %defattr (-, root, root) %exclude /kernel.list -- cgit v1.2.3 From fee9b6d14acde447805d14c0a0a926ced18aa8fa Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 2 Feb 2024 22:35:20 +0900 Subject: Revert "kbuild/mkspec: clean boot loader configuration on rpm removal" This reverts commit 6ef41e22a320d95a246d45b673aa7247cc1bbf7b. If this is still needed, we can bring it back. However, I'd like to understand why 'new-kernel-pkg --remove' is needed for uninstallation, while 'new-kernel-pkg --install' was not called during the installation. Signed-off-by: Masahiro Yamada --- scripts/package/kernel.spec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index c1b745967f64..c256b73cca3e 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -101,9 +101,7 @@ if [ ! -e "/lib/modules/%{KERNELRELEASE}/modules.dep" ]; then fi %preun -if [ -x /sbin/new-kernel-pkg ]; then -new-kernel-pkg --remove %{KERNELRELEASE} --rminitrd --initrdfile=/boot/initramfs-%{KERNELRELEASE}.img -elif [ -x /usr/bin/kernel-install ]; then +if [ -x /usr/bin/kernel-install ]; then kernel-install remove %{KERNELRELEASE} fi -- cgit v1.2.3 From af8bbce92044dc58e4cc039ab94ee5d470a621f5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:57:59 +0900 Subject: kconfig: fix infinite loop when expanding a macro at the end of file A macro placed at the end of a file with no newline causes an infinite loop. [Test Kconfig] $(info,hello) \ No newline at end of file I realized that flex-provided input() returns 0 instead of EOF when it reaches the end of a file. Fixes: 104daea149c4 ("kconfig: reference environment variables directly and remove 'option env='") Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index f93b535a080c..5f1bc3320307 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -303,8 +303,11 @@ static char *expand_token(const char *in, size_t n) new_string(); append_string(in, n); - /* get the whole line because we do not know the end of token. */ - while ((c = input()) != EOF) { + /* + * get the whole line because we do not know the end of token. + * input() returns 0 (not EOF!) when it reachs the end of file. + */ + while ((c = input()) != 0) { if (c == '\n') { unput(c); break; -- cgit v1.2.3 From 313c6cd3c2d538073b71f15a46c2cbcde5712f46 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:00 +0900 Subject: kconfig: fix off-by-one in zconf_error() yyerror() reports the line number of the next line. This +1 adjustment was introduced more than 20 years ago [1]. At that time, the line number was decremented then incremented back and forth. The line number management was refactored in a more maintainable way. Such compensation is no longer needed. [1]: https://git.kernel.org/pub/scm/linux/kernel/git/history/history.git/commit/?id=d4f8a4530eb07a1385fd17b0e62a7dce97486f49 Signed-off-by: Masahiro Yamada --- scripts/kconfig/parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 2af7ce4e1531..5ab2e3f7ca33 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -557,7 +557,7 @@ static void zconf_error(const char *err, ...) static void yyerror(const char *err) { - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err); } static void print_quoted_string(FILE *out, const char *str) -- cgit v1.2.3 From 17787468d4e73dc478738a4e6d2809d907c50c25 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:01 +0900 Subject: kconfig: remove orphan lookup_file() declaration There is no definition, no caller for lookup_file(). Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 1 - 1 file changed, 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 4a9a23b1b7e1..e0d866569155 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -279,7 +279,6 @@ struct jump_key { extern struct file *file_list; extern struct file *current_file; -struct file *lookup_file(const char *name); extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; -- cgit v1.2.3 From aa8427fb130f323e5e27dfe25dee9b514462dde7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:02 +0900 Subject: kconfig: remove compat_getline() Commit 1a7a8c6fd8ca ("kconfig: allow long lines in config file") added a self-implemented getline() for better portability. However, getline() is standardized [1] and already used in other programs such as scripts/kallsyms.c. Use getline() provided by libc. [1]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html Signed-off-by: Masahiro Yamada --- scripts/kconfig/confdata.c | 53 +--------------------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index f53dcdd44597..7f0aa39b68c1 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -293,63 +293,12 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) return 0; } -#define LINE_GROWTH 16 -static int add_byte(int c, char **lineptr, size_t slen, size_t *n) -{ - size_t new_size = slen + 1; - - if (new_size > *n) { - new_size += LINE_GROWTH - 1; - new_size *= 2; - *lineptr = xrealloc(*lineptr, new_size); - *n = new_size; - } - - (*lineptr)[slen] = c; - - return 0; -} - -static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) -{ - char *line = *lineptr; - size_t slen = 0; - - for (;;) { - int c = getc(stream); - - switch (c) { - case '\n': - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - /* fall through */ - case EOF: - if (add_byte('\0', &line, slen, n) < 0) - goto e_out; - *lineptr = line; - if (slen == 0) - return -1; - return slen; - default: - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - } - } - -e_out: - line[slen-1] = '\0'; - *lineptr = line; - return -1; -} - /* like getline(), but the newline character is stripped away */ static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream) { ssize_t len; - len = compat_getline(lineptr, n, stream); + len = getline(lineptr, n, stream); if (len > 0 && (*lineptr)[len - 1] == '\n') { len--; -- cgit v1.2.3 From 73a6afc5a541f74ca84c72aad017866dfcf43680 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:03 +0900 Subject: kconfig: remove unneeded sym_find() call in conf_parse() sym_find("n") is equivalent to &symbol_no. Signed-off-by: Masahiro Yamada --- scripts/kconfig/parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 5ab2e3f7ca33..625224973c51 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -494,7 +494,7 @@ void conf_parse(const char *name) if (yynerrs) exit(1); if (!modules_sym) - modules_sym = sym_find( "n" ); + modules_sym = &symbol_no; if (!menu_has_prompt(&rootmenu)) { current_entry = &rootmenu; -- cgit v1.2.3 From 526396b723a38dbeed35cb9e80814084b9f56329 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:04 +0900 Subject: kconfig: write Kconfig files to autoconf.cmd in order Currently, include/config/autoconf.cmd saves included Kconfig files in reverse order. While this is not a big deal, it is inconsistent with other *.cmd files generated by fixdep. Output the included Kconfig files in the included order. Signed-off-by: Masahiro Yamada --- scripts/kconfig/confdata.c | 7 +++---- scripts/kconfig/lkc.h | 1 + scripts/kconfig/parser.y | 4 ++++ scripts/kconfig/util.c | 3 +++ 4 files changed, 11 insertions(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 7f0aa39b68c1..f6a96fdddb7e 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -20,6 +20,8 @@ #include "lkc.h" +struct gstr autoconf_cmd; + /* return true if 'path' exists, false otherwise */ static bool is_present(const char *path) { @@ -972,7 +974,6 @@ end_check: static int conf_write_autoconf_cmd(const char *autoconf_name) { char name[PATH_MAX], tmp[PATH_MAX]; - struct file *file; FILE *out; int ret; @@ -993,9 +994,7 @@ static int conf_write_autoconf_cmd(const char *autoconf_name) return -1; } - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) - fprintf(out, "\t%s \\\n", file->name); + fputs(str_get(&autoconf_cmd), out); fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name); diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 5cdc8f5e6446..8616ad83be6d 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -40,6 +40,7 @@ int zconf_lineno(void); const char *zconf_curname(void); /* confdata.c */ +extern struct gstr autoconf_cmd; const char *conf_get_configname(void); void set_all_choice_values(struct symbol *csym); diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 625224973c51..611038c502fc 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -480,6 +480,10 @@ void conf_parse(const char *name) struct symbol *sym; int i; + autoconf_cmd = str_new(); + + str_printf(&autoconf_cmd, "deps_config := \\\n"); + zconf_initscan(name); _menu_init(); diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 92e5b2b9761d..958543bb0a37 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -25,6 +25,9 @@ struct file *file_lookup(const char *name) file->name = xstrdup(name); file->next = file_list; file_list = file; + + str_printf(&autoconf_cmd, "\t%s \\\n", name); + return file; } -- cgit v1.2.3 From 56e634b06fd554b819ac9c45fc77a41500861ced Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:05 +0900 Subject: kconfig: call env_write_dep() right after yyparse() This allows preprocess.c to free up all of its resources when the parse stage is finished. It also ensures conf_write_autoconf_cmd() produces consistent results even if called multiple times for any reason. Signed-off-by: Masahiro Yamada --- scripts/kconfig/confdata.c | 8 ++------ scripts/kconfig/lkc_proto.h | 2 +- scripts/kconfig/parser.y | 9 ++++++++- scripts/kconfig/preprocess.c | 11 +++++++---- 4 files changed, 18 insertions(+), 12 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index f6a96fdddb7e..dafc572e7b7e 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -994,13 +994,9 @@ static int conf_write_autoconf_cmd(const char *autoconf_name) return -1; } - fputs(str_get(&autoconf_cmd), out); - - fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name); + fprintf(out, "autoconfig := %s\n", autoconf_name); - env_write_dep(out, autoconf_name); - - fprintf(out, "\n$(deps_config): ;\n"); + fputs(str_get(&autoconf_cmd), out); fflush(out); ret = ferror(out); /* error check for all fprintf() calls */ diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index a4ae5e9eadad..85491d74a094 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -46,7 +46,7 @@ enum variable_flavor { VAR_RECURSIVE, VAR_APPEND, }; -void env_write_dep(FILE *f, const char *auto_conf_name); +void env_write_dep(struct gstr *gs); void variable_add(const char *name, const char *value, enum variable_flavor flavor); void variable_all_del(void); diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 611038c502fc..cfb82ba09037 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -482,7 +482,7 @@ void conf_parse(const char *name) autoconf_cmd = str_new(); - str_printf(&autoconf_cmd, "deps_config := \\\n"); + str_printf(&autoconf_cmd, "\ndeps_config := \\\n"); zconf_initscan(name); @@ -492,6 +492,13 @@ void conf_parse(const char *name) yydebug = 1; yyparse(); + str_printf(&autoconf_cmd, + "\n" + "$(autoconfig): $(deps_config)\n" + "$(deps_config): ;\n"); + + env_write_dep(&autoconf_cmd); + /* Variables are expanded in the parse phase. We can free them here. */ variable_all_del(); diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index d1f5bcff4b62..b9853d4a891c 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -87,14 +87,17 @@ static char *env_expand(const char *name) return xstrdup(value); } -void env_write_dep(FILE *f, const char *autoconfig_name) +void env_write_dep(struct gstr *s) { struct env *e, *tmp; list_for_each_entry_safe(e, tmp, &env_list, node) { - fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value); - fprintf(f, "%s: FORCE\n", autoconfig_name); - fprintf(f, "endif\n"); + str_printf(s, + "\n" + "ifneq \"$(%s)\" \"%s\"\n" + "$(autoconfig): FORCE\n" + "endif\n", + e->name, e->value); env_del(e); } } -- cgit v1.2.3 From d3d16228a520ce49884d3bb90b67c12726c63020 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:06 +0900 Subject: kconfig: split preprocessor prototypes into preprocess.h These are needed only for the parse stage. Move the prototypes into a separate header to make sure they are not used after that. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 2 ++ scripts/kconfig/lkc_proto.h | 13 ------------- scripts/kconfig/parser.y | 1 + scripts/kconfig/preprocess.c | 1 + scripts/kconfig/preprocess.h | 19 +++++++++++++++++++ 5 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 scripts/kconfig/preprocess.h (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 5f1bc3320307..1bb372868ecf 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -14,6 +14,8 @@ #include #include "lkc.h" +#include "preprocess.h" + #include "parser.tab.h" #define YY_DECL static int yylex1(void) diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 85491d74a094..94299e42402f 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -40,19 +40,6 @@ const char * sym_get_string_value(struct symbol *sym); const char * prop_get_type_name(enum prop_type type); -/* preprocess.c */ -enum variable_flavor { - VAR_SIMPLE, - VAR_RECURSIVE, - VAR_APPEND, -}; -void env_write_dep(struct gstr *gs); -void variable_add(const char *name, const char *value, - enum variable_flavor flavor); -void variable_all_del(void); -char *expand_dollar(const char **str); -char *expand_one_token(const char **str); - /* expr.c */ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index cfb82ba09037..ff68def09a2b 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -13,6 +13,7 @@ #include "lkc.h" #include "internal.h" +#include "preprocess.h" #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index b9853d4a891c..12665b981c3e 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -11,6 +11,7 @@ #include "list.h" #include "lkc.h" +#include "preprocess.h" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) diff --git a/scripts/kconfig/preprocess.h b/scripts/kconfig/preprocess.h new file mode 100644 index 000000000000..a7e4a550638c --- /dev/null +++ b/scripts/kconfig/preprocess.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef PREPROCESS_H +#define PREPROCESS_H + +enum variable_flavor { + VAR_SIMPLE, + VAR_RECURSIVE, + VAR_APPEND, +}; + +struct gstr; +void env_write_dep(struct gstr *gs); +void variable_add(const char *name, const char *value, + enum variable_flavor flavor); +void variable_all_del(void); +char *expand_dollar(const char **str); +char *expand_one_token(const char **str); + +#endif /* PREPROCESS_H */ -- cgit v1.2.3 From 52907c07c49b7b820924773d596c5eec5eaf7469 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:07 +0900 Subject: kconfig: replace current_pos with separate cur_{filename,lineno} Replace current_pos with separate variables representing the file name and the line number, respectively. No functional change is intended. By the way, you might wonder why the "" fallback exists in zconf_curname(). menu_add_symbol() saves the current file and the line number. It is intended to be called only during the yyparse() time. However, menu_finalize() calls it, where there is no file being parsed. This is a long-standing hack that should be fixed later. I left a FIXME comment. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 1bb372868ecf..540098435a3b 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -22,10 +22,14 @@ #define START_STRSIZE 16 -static struct { - struct file *file; - int lineno; -} current_pos; +/* The Kconfig file currently being parsed. */ +static const char *cur_filename; + +/* + * The line number of the current statement. This does not match yylineno. + * yylineno is used by the lexer, while cur_lineno is used by the parser. + */ +static int cur_lineno; static int prev_prev_token = T_EOL; static int prev_token = T_EOL; @@ -279,9 +283,14 @@ repeat: * of each statement. Generally, \n is a statement * terminator in Kconfig, but it is not always true * because \n could be escaped by a backslash. + * + * FIXME: + * cur_filename and cur_lineno are used even after + * yyparse(); menu_finalize() calls menu_add_symbol(). + * This should be fixed. */ - current_pos.file = current_file; - current_pos.lineno = yylineno; + cur_filename = current_file ? current_file->name : ""; + cur_lineno = yylineno; } } @@ -462,10 +471,10 @@ static void zconf_endfile(void) int zconf_lineno(void) { - return current_pos.lineno; + return cur_lineno; } const char *zconf_curname(void) { - return current_pos.file ? current_pos.file->name : ""; + return cur_filename; } -- cgit v1.2.3 From 1d7c4f10baacbc658918f7ddec31e1d1962df6fc Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:08 +0900 Subject: kconfig: remove zconf_curname() and zconf_lineno() Now zconf_curname() and zconf_lineno() are so simple that they just return cur_filename, cur_lineno, respectively. Remove these functions, and then use cur_filename and cur_lineno directly. Signed-off-by: Masahiro Yamada --- scripts/kconfig/internal.h | 3 +++ scripts/kconfig/lexer.l | 20 ++++------------ scripts/kconfig/lkc.h | 2 -- scripts/kconfig/menu.c | 4 ++-- scripts/kconfig/parser.y | 59 +++++++++++++++++++++------------------------- 5 files changed, 37 insertions(+), 51 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h index 2f7298c21b64..788401cd5d6f 100644 --- a/scripts/kconfig/internal.h +++ b/scripts/kconfig/internal.h @@ -6,4 +6,7 @@ struct menu; extern struct menu *current_menu, *current_entry; +extern const char *cur_filename; +extern int cur_lineno; + #endif /* INTERNAL_H */ diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 540098435a3b..3b3893f673dc 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -23,13 +23,13 @@ #define START_STRSIZE 16 /* The Kconfig file currently being parsed. */ -static const char *cur_filename; +const char *cur_filename; /* * The line number of the current statement. This does not match yylineno. * yylineno is used by the lexer, while cur_lineno is used by the parser. */ -static int cur_lineno; +int cur_lineno; static int prev_prev_token = T_EOL; static int prev_token = T_EOL; @@ -187,7 +187,7 @@ n [A-Za-z0-9_-] \n { fprintf(stderr, "%s:%d:warning: multi-line strings not supported\n", - zconf_curname(), zconf_lineno()); + cur_filename, cur_lineno); unput('\n'); BEGIN(INITIAL); yylval.string = text; @@ -423,12 +423,12 @@ void zconf_nextfile(const char *name) yyin = zconf_fopen(file->name); if (!yyin) { fprintf(stderr, "%s:%d: can't open file \"%s\"\n", - zconf_curname(), zconf_lineno(), file->name); + cur_filename, cur_lineno, file->name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - current_file->lineno = zconf_lineno(); + current_file->lineno = cur_lineno; file->parent = current_file; for (iter = current_file; iter; iter = iter->parent) { @@ -468,13 +468,3 @@ static void zconf_endfile(void) current_buf = current_buf->parent; free(tmp); } - -int zconf_lineno(void) -{ - return cur_lineno; -} - -const char *zconf_curname(void) -{ - return cur_filename; -} diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 8616ad83be6d..d8249052f2e3 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -36,8 +36,6 @@ void zconf_starthelp(void); FILE *zconf_fopen(const char *name); void zconf_initscan(const char *name); void zconf_nextfile(const char *name); -int zconf_lineno(void); -const char *zconf_curname(void); /* confdata.c */ extern struct gstr autoconf_cmd; diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 2cce8b651f61..ddca95879631 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -54,7 +54,7 @@ void menu_add_entry(struct symbol *sym) menu->sym = sym; menu->parent = current_menu; menu->file = current_file; - menu->lineno = zconf_lineno(); + menu->lineno = cur_lineno; *last_entry_ptr = menu; last_entry_ptr = &menu->next; @@ -135,7 +135,7 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr, memset(prop, 0, sizeof(*prop)); prop->type = type; prop->file = current_file; - prop->lineno = zconf_lineno(); + prop->lineno = cur_lineno; prop->menu = current_entry; prop->expr = expr; prop->visible.expr = dep; diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index ff68def09a2b..b9d7e26fc160 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -144,19 +144,19 @@ config_entry_start: T_CONFIG nonconst_symbol T_EOL { $2->flags |= SYMBOL_OPTIONAL; menu_add_entry($2); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name); + printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name); }; config_stmt: config_entry_start config_option_list { - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); }; menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL { $2->flags |= SYMBOL_OPTIONAL; menu_add_entry($2); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name); }; menuconfig_stmt: menuconfig_entry_start config_option_list @@ -165,7 +165,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list current_entry->prompt->type = P_MENU; else zconfprint("warning: menuconfig statement without prompt"); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); }; config_option_list: @@ -178,15 +178,13 @@ config_option_list: config_option: type prompt_stmt_opt T_EOL { menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), - $1); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1); }; config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); }; config_option: default expr if_expr T_EOL @@ -194,27 +192,26 @@ config_option: default expr if_expr T_EOL menu_add_expr(P_DEFAULT, $2, $3); if ($1 != S_UNKNOWN) menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:default(%u)\n", - zconf_curname(), zconf_lineno(), + printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno, $1); }; config_option: T_SELECT nonconst_symbol if_expr T_EOL { menu_add_symbol(P_SELECT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno); }; config_option: T_IMPLY nonconst_symbol if_expr T_EOL { menu_add_symbol(P_IMPLY, $2, $3); - printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno); }; config_option: T_RANGE symbol symbol if_expr T_EOL { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); - printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno); }; config_option: T_MODULES T_EOL @@ -234,7 +231,7 @@ choice: T_CHOICE word_opt T_EOL menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); free($2); - printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno); }; choice_entry: choice choice_option_list @@ -246,7 +243,7 @@ choice_end: end { if (zconf_endtoken($1, "choice")) { menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno); } }; @@ -263,27 +260,25 @@ choice_option_list: choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); }; choice_option: logic_type prompt_stmt_opt T_EOL { menu_set_type($1); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), $1); + printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1); }; choice_option: T_OPTIONAL T_EOL { current_entry->sym->flags |= SYMBOL_OPTIONAL; - printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:optional\n", cur_filename, cur_lineno); }; choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL { menu_add_symbol(P_DEFAULT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:default\n", - zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno); }; type: @@ -305,7 +300,7 @@ default: if_entry: T_IF expr T_EOL { - printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno); menu_add_entry(NULL); menu_add_dep($2); $$ = menu_add_menu(); @@ -315,7 +310,7 @@ if_end: end { if (zconf_endtoken($1, "if")) { menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno); } }; @@ -331,7 +326,7 @@ menu: T_MENU T_WORD_QUOTE T_EOL { menu_add_entry(NULL); menu_add_prompt(P_MENU, $2, NULL); - printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno); }; menu_entry: menu menu_option_list @@ -343,7 +338,7 @@ menu_end: end { if (zconf_endtoken($1, "menu")) { menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno); } }; @@ -358,7 +353,7 @@ menu_option_list: source_stmt: T_SOURCE T_WORD_QUOTE T_EOL { - printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); + printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2); zconf_nextfile($2); free($2); }; @@ -369,7 +364,7 @@ comment: T_COMMENT T_WORD_QUOTE T_EOL { menu_add_entry(NULL); menu_add_prompt(P_COMMENT, $2, NULL); - printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno); }; comment_stmt: comment comment_option_list @@ -384,7 +379,7 @@ comment_option_list: help_start: T_HELP T_EOL { - printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno); zconf_starthelp(); }; @@ -409,7 +404,7 @@ help: help_start T_HELPTEXT depends: T_DEPENDS T_ON expr T_EOL { menu_add_dep($3); - printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); + printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno); }; /* visibility option */ @@ -548,7 +543,7 @@ static void zconfprint(const char *err, ...) { va_list ap; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); @@ -560,7 +555,7 @@ static void zconf_error(const char *err, ...) va_list ap; yynerrs++; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); @@ -569,7 +564,7 @@ static void zconf_error(const char *err, ...) static void yyerror(const char *err) { - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err); + fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err); } static void print_quoted_string(FILE *out, const char *str) -- cgit v1.2.3 From 40bab83a6595b3ab8afcfdb57903470f64fdbdb9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:09 +0900 Subject: kconfig: associate struct menu with file name directly struct menu is linked to struct file for diagnostic purposes. It is always used to retrieve the file name through menu->file->name. Associate struct menu with the file name directly. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 2 +- scripts/kconfig/menu.c | 6 +++--- scripts/kconfig/parser.y | 6 +++--- scripts/kconfig/qconf.cc | 2 +- scripts/kconfig/symbol.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index e0d866569155..e8fc85d98cdd 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -256,7 +256,7 @@ struct menu { char *help; /* The location where the menu node appears in the Kconfig files */ - struct file *file; + const char *filename; int lineno; /* For use by front ends that need to store auxiliary data */ diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index ddca95879631..5ad4d2b9fb82 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -23,7 +23,7 @@ void menu_warn(struct menu *menu, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); + fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -53,7 +53,7 @@ void menu_add_entry(struct symbol *sym) memset(menu, 0, sizeof(*menu)); menu->sym = sym; menu->parent = current_menu; - menu->file = current_file; + menu->filename = cur_filename; menu->lineno = cur_lineno; *last_entry_ptr = menu; @@ -676,7 +676,7 @@ struct menu *menu_get_parent_menu(struct menu *menu) static void get_def_str(struct gstr *r, struct menu *menu) { str_printf(r, "Defined at %s:%d\n", - menu->file->name, menu->lineno); + menu->filename, menu->lineno); } static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index b9d7e26fc160..d1d05c8cd89d 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -101,7 +101,7 @@ struct menu *current_menu, *current_entry; %destructor { fprintf(stderr, "%s:%d: missing end statement for this entry\n", - $$->file->name, $$->lineno); + $$->filename, $$->lineno); if (current_menu == $$) menu_end_menu(); } if_entry menu_entry choice_entry @@ -527,11 +527,11 @@ static bool zconf_endtoken(const char *tokenname, yynerrs++; return false; } - if (current_menu->file != current_file) { + if (strcmp(current_menu->filename, cur_filename)) { zconf_error("'%s' in different file than '%s'", tokenname, expected_tokenname); fprintf(stderr, "%s:%d: location of the '%s'\n", - current_menu->file->name, current_menu->lineno, + current_menu->filename, current_menu->lineno, expected_tokenname); yynerrs++; return false; diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 620a3527c767..c6c42c0f4e5d 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1058,7 +1058,7 @@ void ConfigInfoView::menuInfo(void) stream << "

"; } - stream << "defined at " << _menu->file->name << ":" + stream << "defined at " << _menu->filename << ":" << _menu->lineno << "

"; } } diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index e9e9fb8d8674..7647e3e87cd5 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -1045,12 +1045,12 @@ static void sym_check_print_recursive(struct symbol *last_sym) if (sym_is_choice(sym)) { fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, + menu->filename, menu->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (sym_is_choice_value(sym)) { fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", - menu->file->name, menu->lineno, + menu->filename, menu->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (stack->expr == &sym->dir_dep.expr) { -- cgit v1.2.3 From 1a90b0cdc02a9efba97a2ea49e4b851958137053 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:10 +0900 Subject: kconfig: associate struct property with file name directly struct property is linked to struct file for diagnostic purposes. It is always used to retrieve the file name through prop->file->name. Associate struct property with the file name directly. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 2 +- scripts/kconfig/menu.c | 4 ++-- scripts/kconfig/symbol.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index e8fc85d98cdd..037db39c5bf0 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -195,7 +195,7 @@ struct property { struct menu *menu; /* the menu the property are associated with * valid for: P_SELECT, P_RANGE, P_CHOICE, * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ - struct file *file; /* what file was this property defined */ + const char *filename; /* what file was this property defined */ int lineno; /* what lineno was this property defined */ }; diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 5ad4d2b9fb82..0ded0b1830d0 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -33,7 +33,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); + fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -134,7 +134,7 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr, prop = xmalloc(sizeof(*prop)); memset(prop, 0, sizeof(*prop)); prop->type = type; - prop->file = current_file; + prop->filename = cur_filename; prop->lineno = cur_lineno; prop->menu = current_entry; prop->expr = expr; diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 7647e3e87cd5..dae630a74e50 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -1041,7 +1041,7 @@ static void sym_check_print_recursive(struct symbol *last_sym) } if (stack->sym == last_sym) fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", - prop->file->name, prop->lineno); + prop->filename, prop->lineno); if (sym_is_choice(sym)) { fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", @@ -1055,28 +1055,28 @@ static void sym_check_print_recursive(struct symbol *last_sym) next_sym->name ? next_sym->name : ""); } else if (stack->expr == &sym->dir_dep.expr) { fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (stack->expr == &sym->rev_dep.expr) { fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (stack->expr == &sym->implied.expr) { fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "", next_sym->name ? next_sym->name : ""); } else if (stack->expr) { fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "", prop_get_type_name(prop->type), next_sym->name ? next_sym->name : ""); } else { fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", - prop->file->name, prop->lineno, + prop->filename, prop->lineno, sym->name ? sym->name : "", prop_get_type_name(prop->type), next_sym->name ? next_sym->name : ""); -- cgit v1.2.3 From fe273c6fc318da07bdbb42d26d8e6e150aa947af Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:11 +0900 Subject: kconfig: replace file->name with name in zconf_nextfile() The 'file->name' and 'name' are the same in this function. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 3b3893f673dc..35ad1b256470 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -420,10 +420,10 @@ void zconf_nextfile(const char *name) buf->yylineno = yylineno; buf->parent = current_buf; current_buf = buf; - yyin = zconf_fopen(file->name); + yyin = zconf_fopen(name); if (!yyin) { fprintf(stderr, "%s:%d: can't open file \"%s\"\n", - cur_filename, cur_lineno, file->name); + cur_filename, cur_lineno, name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); @@ -432,17 +432,17 @@ void zconf_nextfile(const char *name) file->parent = current_file; for (iter = current_file; iter; iter = iter->parent) { - if (!strcmp(iter->name, file->name)) { + if (!strcmp(iter->name, name)) { fprintf(stderr, "Recursive inclusion detected.\n" "Inclusion path:\n" - " current file : %s\n", file->name); + " current file : %s\n", name); iter = file; do { iter = iter->parent; fprintf(stderr, " included from: %s:%d\n", iter->name, iter->lineno); - } while (strcmp(iter->name, file->name)); + } while (strcmp(iter->name, name)); exit(1); } } -- cgit v1.2.3 From d3e4a68fe20f3c05de77f5e300e3d76a9f68d942 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:12 +0900 Subject: kconfig: do not delay the cur_filename update Currently, cur_filename is updated at the first token of each statement. However, this seems unnecessary based on my understanding; the parser can use the same variable as the lexer tracks. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 17 +++++++---------- scripts/kconfig/parser.y | 8 ++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 35ad1b256470..28e279cd5a22 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -274,24 +274,17 @@ repeat: token = yylex1(); if (prev_token == T_EOL || prev_token == T_HELPTEXT) { - if (token == T_EOL) { + if (token == T_EOL) /* Do not pass unneeded T_EOL to the parser. */ goto repeat; - } else { + else /* - * For the parser, update file/lineno at the first token + * For the parser, update lineno at the first token * of each statement. Generally, \n is a statement * terminator in Kconfig, but it is not always true * because \n could be escaped by a backslash. - * - * FIXME: - * cur_filename and cur_lineno are used even after - * yyparse(); menu_finalize() calls menu_add_symbol(). - * This should be fixed. */ - cur_filename = current_file ? current_file->name : ""; cur_lineno = yylineno; - } } if (prev_prev_token == T_EOL && prev_token == T_WORD && @@ -407,6 +400,7 @@ void zconf_initscan(const char *name) } current_file = file_lookup(name); + cur_filename = current_file->name; yylineno = 1; } @@ -448,6 +442,7 @@ void zconf_nextfile(const char *name) } yylineno = 1; + cur_filename = file->name; current_file = file; } @@ -456,6 +451,8 @@ static void zconf_endfile(void) struct buffer *tmp; current_file = current_file->parent; + if (current_file) + cur_filename = current_file->name; if (!current_buf) return; diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index d1d05c8cd89d..e58c24d2e5ab 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -488,6 +488,14 @@ 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" -- cgit v1.2.3 From 4ff7ceae83bea6afcd0325b88e3f3d9f168cc432 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:13 +0900 Subject: kconfig: replace remaining current_file->name with cur_filename Replace the remaining current_file->name in the lexer context. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lexer.l | 4 ++-- scripts/kconfig/preprocess.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 28e279cd5a22..db2397c4e343 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -84,7 +84,7 @@ static void warn_ignored_character(char chr) { fprintf(stderr, "%s:%d:warning: ignoring unsupported character '%c'\n", - current_file->name, yylineno, chr); + cur_filename, yylineno, chr); } %} @@ -253,7 +253,7 @@ n [A-Za-z0-9_-] if (prev_token != T_EOL && prev_token != T_HELPTEXT) fprintf(stderr, "%s:%d:warning: no new line at end of file\n", - current_file->name, yylineno); + cur_filename, yylineno); if (current_file) { zconf_endfile(); diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index 12665b981c3e..69b806a6d8b7 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -9,6 +9,7 @@ #include #include +#include "internal.h" #include "list.h" #include "lkc.h" #include "preprocess.h" @@ -22,7 +23,7 @@ static void __attribute__((noreturn)) pperror(const char *format, ...) { va_list ap; - fprintf(stderr, "%s:%d: ", current_file->name, yylineno); + fprintf(stderr, "%s:%d: ", cur_filename, yylineno); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); @@ -123,7 +124,7 @@ static char *do_error_if(int argc, char *argv[]) static char *do_filename(int argc, char *argv[]) { - return xstrdup(current_file->name); + return xstrdup(cur_filename); } static char *do_info(int argc, char *argv[]) @@ -185,8 +186,7 @@ static char *do_shell(int argc, char *argv[]) static char *do_warning_if(int argc, char *argv[]) { if (!strcmp(argv[0], "y")) - fprintf(stderr, "%s:%d: %s\n", - current_file->name, yylineno, argv[1]); + fprintf(stderr, "%s:%d: %s\n", cur_filename, yylineno, argv[1]); return xstrdup(""); } -- cgit v1.2.3 From 8facc5f31954d5fddc2759de474eb6fae1135ced Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:14 +0900 Subject: kconfig: move the file and lineno in struct file to struct buffer struct file has two link nodes, 'next' and 'parent'. The former is used to link files in the 'file_list' linked list, which manages the list of Kconfig files seen so far. The latter is used to link files in the 'current_file' linked list, which manages the inclusion ("source") tree. The latter should be tracked together with the lexer state. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 3 --- scripts/kconfig/lexer.l | 52 ++++++++++++++++++++++--------------------------- scripts/kconfig/menu.c | 1 - 3 files changed, 23 insertions(+), 33 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 037db39c5bf0..85e0d1ab3c8a 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -19,9 +19,7 @@ extern "C" { struct file { struct file *next; - struct file *parent; const char *name; - int lineno; }; typedef enum tristate { @@ -278,7 +276,6 @@ struct jump_key { }; extern struct file *file_list; -extern struct file *current_file; extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index db2397c4e343..71f651bb82ba 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -40,6 +40,8 @@ struct buffer { struct buffer *parent; YY_BUFFER_STATE state; int yylineno; + const char *filename; + int source_lineno; }; static struct buffer *current_buf; @@ -255,7 +257,7 @@ n [A-Za-z0-9_-] fprintf(stderr, "%s:%d:warning: no new line at end of file\n", cur_filename, yylineno); - if (current_file) { + if (current_buf) { zconf_endfile(); return T_EOL; } @@ -399,19 +401,20 @@ void zconf_initscan(const char *name) exit(1); } - current_file = file_lookup(name); - cur_filename = current_file->name; + cur_filename = file_lookup(name)->name; yylineno = 1; } void zconf_nextfile(const char *name) { - struct file *iter; struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); + bool recur_include = false; buf->state = YY_CURRENT_BUFFER; buf->yylineno = yylineno; + buf->filename = cur_filename; + buf->source_lineno = cur_lineno; buf->parent = current_buf; current_buf = buf; yyin = zconf_fopen(name); @@ -422,45 +425,36 @@ void zconf_nextfile(const char *name) } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); - current_file->lineno = cur_lineno; - file->parent = current_file; - - for (iter = current_file; iter; iter = iter->parent) { - if (!strcmp(iter->name, name)) { - fprintf(stderr, - "Recursive inclusion detected.\n" - "Inclusion path:\n" - " current file : %s\n", name); - iter = file; - do { - iter = iter->parent; - fprintf(stderr, " included from: %s:%d\n", - iter->name, iter->lineno); - } while (strcmp(iter->name, name)); - exit(1); - } + for (buf = current_buf; buf; buf = buf->parent) { + if (!strcmp(buf->filename, name)) + recur_include = true; + } + + if (recur_include) { + fprintf(stderr, + "Recursive inclusion detected.\n" + "Inclusion path:\n" + " current file : %s\n", name); + + for (buf = current_buf; buf; buf = buf->parent) + fprintf(stderr, " included from: %s:%d\n", + buf->filename, buf->source_lineno); + exit(1); } yylineno = 1; cur_filename = file->name; - current_file = file; } static void zconf_endfile(void) { struct buffer *tmp; - current_file = current_file->parent; - if (current_file) - cur_filename = current_file->name; - - if (!current_buf) - return; - fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(current_buf->state); yylineno = current_buf->yylineno; + cur_filename = current_buf->filename; tmp = current_buf; current_buf = current_buf->parent; free(tmp); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 0ded0b1830d0..b879576d1ab4 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -17,7 +17,6 @@ struct menu rootmenu; static struct menu **last_entry_ptr; struct file *file_list; -struct file *current_file; void menu_warn(struct menu *menu, const char *fmt, ...) { -- cgit v1.2.3 From 6676c5bc15e66268c9c9669d5852aa779689c74e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:15 +0900 Subject: kconfig: make file::name a flexible array member Call malloc() just once to allocate needed memory. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 2 +- scripts/kconfig/util.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 85e0d1ab3c8a..760b1e681b43 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -19,7 +19,7 @@ extern "C" { struct file { struct file *next; - const char *name; + char name[]; }; typedef enum tristate { diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 958543bb0a37..2636dccea0c9 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -13,6 +13,7 @@ struct file *file_lookup(const char *name) { struct file *file; + size_t len; for (file = file_list; file; file = file->next) { if (!strcmp(name, file->name)) { @@ -20,9 +21,11 @@ struct file *file_lookup(const char *name) } } - file = xmalloc(sizeof(*file)); + len = strlen(name); + file = xmalloc(sizeof(*file) + len + 1); memset(file, 0, sizeof(*file)); - file->name = xstrdup(name); + memcpy(file->name, name, len); + file->name[len] = '\0'; file->next = file_list; file_list = file; -- cgit v1.2.3 From 5b058034e3aa600802ab609e8264dc2ca1300ebe Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:16 +0900 Subject: kconfig: change file_lookup() to return the file name Currently, file_lookup() returns a pointer to (struct file), but the callers use only file->name. Make it return the ->name member directly. This adjustment encapsulates struct file and file_list as internal implementation. Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 7 ------- scripts/kconfig/lexer.l | 5 ++--- scripts/kconfig/lkc.h | 2 +- scripts/kconfig/menu.c | 2 -- scripts/kconfig/util.c | 13 ++++++++++--- 5 files changed, 13 insertions(+), 16 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 760b1e681b43..d667f9aa041e 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -17,11 +17,6 @@ extern "C" { #include #endif -struct file { - struct file *next; - char name[]; -}; - typedef enum tristate { no, mod, yes } tristate; @@ -275,8 +270,6 @@ struct jump_key { struct menu *target; }; -extern struct file *file_list; - extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; extern int cdebug; diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 71f651bb82ba..89544c3a1a29 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -401,13 +401,12 @@ void zconf_initscan(const char *name) exit(1); } - cur_filename = file_lookup(name)->name; + cur_filename = file_lookup(name); yylineno = 1; } void zconf_nextfile(const char *name) { - struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); bool recur_include = false; @@ -443,7 +442,7 @@ void zconf_nextfile(const char *name) } yylineno = 1; - cur_filename = file->name; + cur_filename = file_lookup(name); } static void zconf_endfile(void) diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index d8249052f2e3..71afcbd56273 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -52,7 +52,7 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) } /* util.c */ -struct file *file_lookup(const char *name); +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); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index b879576d1ab4..f701382f8a69 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -16,8 +16,6 @@ static const char nohelp_text[] = "There is no help available for this option."; struct menu rootmenu; static struct menu **last_entry_ptr; -struct file *file_list; - void menu_warn(struct menu *menu, const char *fmt, ...) { va_list ap; diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 2636dccea0c9..610d64c01479 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -9,15 +9,22 @@ #include #include "lkc.h" +struct file { + struct file *next; + char name[]; +}; + +static struct file *file_list; + /* file already present in list? If not add it */ -struct file *file_lookup(const char *name) +const char *file_lookup(const char *name) { struct file *file; size_t len; for (file = file_list; file; file = file->next) { if (!strcmp(name, file->name)) { - return file; + return file->name; } } @@ -31,7 +38,7 @@ struct file *file_lookup(const char *name) str_printf(&autoconf_cmd, "\t%s \\\n", name); - return file; + return file->name; } /* Allocate initial growable string */ -- cgit v1.2.3 From 4dae9cf5cbb863c7ca23899446885dbc457f81ae Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:17 +0900 Subject: kconfig: split list_head into a separate header The struct list_head is often embedded in other structures, while other code is used in C functions. By separating struct list_head into its own header, other headers are no longer required to include the entire list.h. This is similar to the kernel space, where struct list_head is defined in instead of . Signed-off-by: Masahiro Yamada --- scripts/kconfig/expr.h | 2 +- scripts/kconfig/list.h | 8 ++------ scripts/kconfig/list_types.h | 9 +++++++++ scripts/kconfig/mconf.c | 1 + scripts/kconfig/menu.c | 1 + scripts/kconfig/nconf.c | 1 + 6 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 scripts/kconfig/list_types.h (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index d667f9aa041e..dd3350aed302 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -12,7 +12,7 @@ extern "C" { #include #include -#include "list.h" +#include "list_types.h" #ifndef __cplusplus #include #endif diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h index 45cb237ab7ef..babed0baf4ae 100644 --- a/scripts/kconfig/list.h +++ b/scripts/kconfig/list.h @@ -2,6 +2,8 @@ #ifndef LIST_H #define LIST_H +#include "list_types.h" + /* * Copied from include/linux/... */ @@ -20,12 +22,6 @@ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) - -struct list_head { - struct list_head *next, *prev; -}; - - #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ diff --git a/scripts/kconfig/list_types.h b/scripts/kconfig/list_types.h new file mode 100644 index 000000000000..32899f424983 --- /dev/null +++ b/scripts/kconfig/list_types.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LIST_TYPES_H +#define LIST_TYPES_H + +struct list_head { + struct list_head *next, *prev; +}; + +#endif /* LIST_TYPES_H */ diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 5df32148a869..f4bb391d50cf 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -19,6 +19,7 @@ #include #include +#include "list.h" #include "lkc.h" #include "lxdialog/dialog.h" #include "mnconf-common.h" diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index f701382f8a69..696803d944e0 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -10,6 +10,7 @@ #include "lkc.h" #include "internal.h" +#include "list.h" static const char nohelp_text[] = "There is no help available for this option."; diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 1148163cfa7e..9d22b0f3197b 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -11,6 +11,7 @@ #include #include +#include "list.h" #include "lkc.h" #include "mnconf-common.h" #include "nconf.h" -- cgit v1.2.3 From 55f649b73de1585de8608ad5afa764cd7646f9c2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:18 +0900 Subject: kconfig: resync list.h Update the existing macros and inline functions based on include/linux/list.h. The variable name '_new' can be reverted to 'new' because this header is no longer included from the C++ file, scripts/kconfig/qconf.cc. Signed-off-by: Masahiro Yamada --- scripts/kconfig/list.h | 183 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 62 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h index babed0baf4ae..2bce2b8f21d1 100644 --- a/scripts/kconfig/list.h +++ b/scripts/kconfig/list.h @@ -2,71 +2,56 @@ #ifndef LIST_H #define LIST_H -#include "list_types.h" +#include -/* - * Copied from include/linux/... - */ +#include "list_types.h" -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +/* Are two types/vars the same type (ignoring qualifiers)? */ +#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) /** * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. * */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define LIST_HEAD_INIT(name) { &(name), &(name) } +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + _Static_assert(__same_type(*(ptr), ((type *)0)->member) || \ + __same_type(*(ptr), void), \ + "pointer type mismatch in container_of()"); \ + ((type *)(__mptr - offsetof(type, member))); }) -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) +#define LIST_POISON1 ((void *) 0x100) +#define LIST_POISON2 ((void *) 0x122) -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. +/* + * Circular doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) +#define LIST_HEAD_INIT(name) { &(name), &(name) } -/** - * list_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: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) /** - * list_empty - tests whether a list is empty - * @head: the list to test. + * INIT_LIST_HEAD - Initialize a list_head structure + * @list: list_head structure to be initialized. + * + * Initializes the list_head to point to itself. If it is a list header, + * the result is an empty list. */ -static inline int list_empty(const struct list_head *head) +static inline void INIT_LIST_HEAD(struct list_head *list) { - return head->next == head; + list->next = list; + list->prev = list; } /* @@ -75,14 +60,14 @@ static inline int list_empty(const struct list_head *head) * This is only for internal list manipulation where we know * the prev/next entries already! */ -static inline void __list_add(struct list_head *_new, +static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { - next->prev = _new; - _new->next = next; - _new->prev = prev; - prev->next = _new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } /** @@ -93,9 +78,9 @@ static inline void __list_add(struct list_head *_new, * Insert a new entry before the specified head. * This is useful for implementing queues. */ -static inline void list_add_tail(struct list_head *_new, struct list_head *head) +static inline void list_add_tail(struct list_head *new, struct list_head *head) { - __list_add(_new, head->prev, head); + __list_add(new, head->prev, head); } /* @@ -111,8 +96,11 @@ static inline void __list_del(struct list_head *prev, struct list_head *next) prev->next = next; } -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + /** * list_del - deletes entry from list. * @entry: the element to delete from the list. @@ -121,8 +109,79 @@ static inline void __list_del(struct list_head *prev, struct list_head *next) */ static inline void list_del(struct list_head *entry) { - __list_del(entry->prev, entry->next); - entry->next = (struct list_head*)LIST_POISON1; - entry->prev = (struct list_head*)LIST_POISON2; + __list_del_entry(entry); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; } -#endif + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * list_entry_is_head - test if the entry points to the head of the list + * @pos: the type * to cursor + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_entry_is_head(pos, head, member) \ + (&pos->member == (head)) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + !list_entry_is_head(pos, head, member); \ + pos = list_next_entry(pos, member)) + +/** + * list_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: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = n, n = list_next_entry(n, member)) + +#endif /* LIST_H */ -- cgit v1.2.3 From 5e3cf304a0bdc7a3d7ba4805bb2bb05c5e6916ff Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:19 +0900 Subject: kconfig: import more list macros and inline functions Import more macros and inline functions from include/linux/list.h and include/linux/types.h. Signed-off-by: Masahiro Yamada --- scripts/kconfig/list.h | 69 ++++++++++++++++++++++++++++++++++++++++++++ scripts/kconfig/list_types.h | 8 +++++ 2 files changed, 77 insertions(+) (limited to 'scripts') diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h index 2bce2b8f21d1..882859ddf9f4 100644 --- a/scripts/kconfig/list.h +++ b/scripts/kconfig/list.h @@ -70,6 +70,19 @@ static inline void __list_add(struct list_head *new, prev->next = new; } +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + /** * list_add_tail - add a new entry * @new: new entry to be added @@ -114,6 +127,16 @@ static inline void list_del(struct list_head *entry) entry->prev = LIST_POISON2; } +/** + * list_is_head - tests whether @list is the list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_head(const struct list_head *list, const struct list_head *head) +{ + return list == head; +} + /** * list_empty - tests whether a list is empty * @head: the list to test. @@ -184,4 +207,50 @@ static inline int list_empty(const struct list_head *head) !list_entry_is_head(pos, head, member); \ pos = n, n = list_next_entry(n, member)) +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#define HLIST_HEAD_INIT { .first = NULL } + +/** + * hlist_add_head - add a new entry at the beginning of the hlist + * @n: new entry to be added + * @h: hlist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +#define hlist_entry(ptr, type, member) container_of(ptr, type, member) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +/** + * hlist_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + #endif /* LIST_H */ diff --git a/scripts/kconfig/list_types.h b/scripts/kconfig/list_types.h index 32899f424983..d935b7c5aa81 100644 --- a/scripts/kconfig/list_types.h +++ b/scripts/kconfig/list_types.h @@ -6,4 +6,12 @@ struct list_head { struct list_head *next, *prev; }; +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + #endif /* LIST_TYPES_H */ -- cgit v1.2.3 From 0a3128e75108cc23401aa5059b851ed047bfff0e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:20 +0900 Subject: kconfig: add macros useful for hashtable This is similar to include/linux/hashtable.h, but the implementation has been simplified. Signed-off-by: Masahiro Yamada --- scripts/kconfig/hashtable.h | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 scripts/kconfig/hashtable.h (limited to 'scripts') diff --git a/scripts/kconfig/hashtable.h b/scripts/kconfig/hashtable.h new file mode 100644 index 000000000000..a0a2c8f5f639 --- /dev/null +++ b/scripts/kconfig/hashtable.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef HASHTABLE_H +#define HASHTABLE_H + +#include "array_size.h" +#include "list.h" + +#define HASH_SIZE(name) (ARRAY_SIZE(name)) + +#define HASHTABLE_DECLARE(name, size) struct hlist_head name[size] + +#define HASHTABLE_DEFINE(name, size) \ + HASHTABLE_DECLARE(name, size) = \ + { [0 ... ((size) - 1)] = HLIST_HEAD_INIT } + +#define hash_head(table, key) (&(table)[(key) % HASH_SIZE(table)]) + +/** + * hash_add - add an object to a hashtable + * @table: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add(table, node, key) \ + hlist_add_head(node, hash_head(table, key)) + +/** + * hash_for_each - iterate over a hashtable + * @table: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each(table, obj, member) \ + for (int _bkt = 0; _bkt < HASH_SIZE(table); _bkt++) \ + hlist_for_each_entry(obj, &table[_bkt], member) + +/** + * hash_for_each_possible - iterate over all possible objects hashing to the + * same bucket + * @table: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible(table, obj, member, key) \ + hlist_for_each_entry(obj, hash_head(table, key), member) + +#endif /* HASHTABLE_H */ -- cgit v1.2.3 From a6dac4002b88f0ad242ac20d9de86d11321ecf84 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:21 +0900 Subject: kconfig: move ARRAY_SIZE to a header To use ARRAY_SIZE from other files, move it to its own header, just like include/linux/array_size.h. Signed-off-by: Masahiro Yamada --- scripts/kconfig/array_size.h | 11 +++++++++++ scripts/kconfig/preprocess.c | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 scripts/kconfig/array_size.h (limited to 'scripts') diff --git a/scripts/kconfig/array_size.h b/scripts/kconfig/array_size.h new file mode 100644 index 000000000000..26ba78d867d1 --- /dev/null +++ b/scripts/kconfig/array_size.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ARRAY_SIZE_H +#define ARRAY_SIZE_H + +/** + * ARRAY_SIZE - get the number of elements in array @arr + * @arr: array to be sized + */ +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#endif /* ARRAY_SIZE_H */ diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index 69b806a6d8b7..f0a4a218c4a5 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -9,13 +9,12 @@ #include #include +#include "array_size.h" #include "internal.h" #include "list.h" #include "lkc.h" #include "preprocess.h" -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - static char *expand_string_with_args(const char *in, int argc, char *argv[]); static char *expand_string(const char *in); -- cgit v1.2.3 From 7c4aa901bd9d7e95be95a5c888d026b3214bae05 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:22 +0900 Subject: kconfig: move strhash() to util.c as a global function Remove the 'static' qualifier from strhash() so that it can be accessed from other files. Move it to util.c, which is a more appropriate location. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lkc.h | 1 + scripts/kconfig/symbol.c | 9 --------- scripts/kconfig/util.c | 10 ++++++++++ 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 71afcbd56273..e69d7c59d930 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -52,6 +52,7 @@ 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); diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index dae630a74e50..3dbe3a19622b 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -803,15 +803,6 @@ bool sym_is_changeable(struct symbol *sym) return sym->visible > sym->rev_dep.tri; } -static unsigned strhash(const char *s) -{ - /* fnv32 hash */ - unsigned hash = 2166136261U; - for (; *s; s++) - hash = (hash ^ *s) * 0x01000193; - return hash; -} - struct symbol *sym_lookup(const char *name, int flags) { struct symbol *symbol; diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index 610d64c01479..d6172f2f64c9 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -9,6 +9,16 @@ #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; +} + struct file { struct file *next; char name[]; -- cgit v1.2.3 From 980c9e198f1c5563380bed2a2672e592edf9efaa Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:23 +0900 Subject: kconfig: convert linked list of files to hash table Currently, a linked list is used to keep track of all the Kconfig files that have ever been parsed. Every time the "source" statement is encountered, the linked list is traversed to check if the file has been opened before. This prevents the same file from being recorded in include/config/auto.conf.cmd again. Given 1500+ Kconfig files parsed, a hashtable is now a more optimal data structure. By the way, you may wonder why we check this in the first place. It matters only when the same file is included multiple times. In old days, such a use case was forbidden, but commit f094f8a1b273 ("kconfig: allow multiple inclusion of the same file") provided a bit more flexibility. Of course, it is almost hypothetical... Signed-off-by: Masahiro Yamada --- scripts/kconfig/util.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index d6172f2f64c9..439c131b424e 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -7,6 +7,8 @@ #include #include #include + +#include "hashtable.h" #include "lkc.h" unsigned int strhash(const char *s) @@ -19,32 +21,32 @@ unsigned int strhash(const char *s) return hash; } +/* hash table of all parsed Kconfig files */ +static HASHTABLE_DEFINE(file_hashtable, 1U << 11); + struct file { - struct file *next; + struct hlist_node node; char name[]; }; -static struct file *file_list; - /* file already present in list? If not add it */ const char *file_lookup(const char *name) { struct file *file; size_t len; + int hash = strhash(name); - for (file = file_list; file; file = file->next) { - if (!strcmp(name, file->name)) { + hash_for_each_possible(file_hashtable, file, node, hash) + if (!strcmp(name, file->name)) return file->name; - } - } len = strlen(name); file = xmalloc(sizeof(*file) + len + 1); memset(file, 0, sizeof(*file)); memcpy(file->name, name, len); file->name[len] = '\0'; - file->next = file_list; - file_list = file; + + hash_add(file_hashtable, &file->node, hash); str_printf(&autoconf_cmd, "\t%s \\\n", name); -- cgit v1.2.3 From 7d5f52a4334c5227408b14c2e76d8840aa26f132 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 3 Feb 2024 00:58:25 +0900 Subject: kconfig: do not imply the type of choice value Do not feed back the choice type to choice values. Each choice value should explicitly specify 'bool' or 'tristate', as all the Kconfig files already do. If the type were missing, "config symbol defined without type" would be shown. Signed-off-by: Masahiro Yamada --- scripts/kconfig/menu.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 696803d944e0..44465945d6b1 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -305,12 +305,6 @@ void menu_finalize(struct menu *parent) } } } - /* set the type of the remaining choice values */ - for (menu = parent->list; menu; menu = menu->next) { - current_entry = menu; - if (menu->sym && menu->sym->type == S_UNKNOWN) - menu_set_type(sym->type); - } /* * Use the choice itself as the parent dependency of -- cgit v1.2.3 From cc25cfc563adc48c84f1eec6432b369bcab73ca6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 11 Feb 2024 21:41:04 +0900 Subject: kconfig: print recursive dependency errors in the parsed order for_all_symbols() iterates in the symbol hash table. The order of iteration depends on the hash table implementation. If you use it for printing errors, they are shown in random order. For example, the order of following test input and the corresponding error do not match: - scripts/kconfig/tests/err_recursive_dep/Kconfig - scripts/kconfig/tests/err_recursive_dep/expected_stderr Signed-off-by: Masahiro Yamada --- scripts/kconfig/parser.y | 20 ++++++++++++++++---- .../tests/err_recursive_dep/expected_stderr | 22 +++++++++++----------- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index e58c24d2e5ab..efd0e234e0d2 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -473,8 +473,7 @@ assign_val: void conf_parse(const char *name) { - struct symbol *sym; - int i; + struct menu *menu; autoconf_cmd = str_new(); @@ -517,10 +516,23 @@ void conf_parse(const char *name) } menu_finalize(&rootmenu); - for_all_symbols(i, sym) { - if (sym_check_deps(sym)) + + menu = &rootmenu; + while (menu) { + if (menu->sym && sym_check_deps(menu->sym)) yynerrs++; + + if (menu->list) { + menu = menu->list; + continue; + } + + while (!menu->next && menu->parent) + menu = menu->parent; + + menu = menu->next; } + if (yynerrs) exit(1); conf_set_changed(true); diff --git a/scripts/kconfig/tests/err_recursive_dep/expected_stderr b/scripts/kconfig/tests/err_recursive_dep/expected_stderr index c9f4abf9a791..05d4ced70320 100644 --- a/scripts/kconfig/tests/err_recursive_dep/expected_stderr +++ b/scripts/kconfig/tests/err_recursive_dep/expected_stderr @@ -1,10 +1,10 @@ -Kconfig:11:error: recursive dependency detected! -Kconfig:11: symbol B is selected by B +Kconfig:5:error: recursive dependency detected! +Kconfig:5: symbol A depends on A For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:5:error: recursive dependency detected! -Kconfig:5: symbol A depends on A +Kconfig:11:error: recursive dependency detected! +Kconfig:11: symbol B is selected by B For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" @@ -14,9 +14,9 @@ Kconfig:21: symbol C2 depends on C1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:32:error: recursive dependency detected! -Kconfig:32: symbol D2 is selected by D1 +Kconfig:27:error: recursive dependency detected! Kconfig:27: symbol D1 depends on D2 +Kconfig:32: symbol D2 is selected by D1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" @@ -26,13 +26,13 @@ Kconfig:42: symbol E2 is implied by E1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:60:error: recursive dependency detected! -Kconfig:60: symbol G depends on G +Kconfig:49:error: recursive dependency detected! +Kconfig:49: symbol F1 default value contains F2 +Kconfig:51: symbol F2 depends on F1 For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -Kconfig:51:error: recursive dependency detected! -Kconfig:51: symbol F2 depends on F1 -Kconfig:49: symbol F1 default value contains F2 +Kconfig:60:error: recursive dependency detected! +Kconfig:60: symbol G depends on G For a resolution refer to Documentation/kbuild/kconfig-language.rst subsection "Kconfig recursive dependency limitations" -- cgit v1.2.3 From 91b69454f93d1c905f3a56bb39856db9a220c791 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 11 Feb 2024 21:41:05 +0900 Subject: kconfig: use generic macros to implement symbol hashtable Use helper macros in hashtable.h for generic hashtable implementation. We can git rid of the hash head index of for_all_symbols(). Signed-off-by: Masahiro Yamada --- scripts/kconfig/conf.c | 12 ++++++------ scripts/kconfig/confdata.c | 25 ++++++++++++------------- scripts/kconfig/expr.h | 9 ++++----- scripts/kconfig/internal.h | 9 +++++++++ scripts/kconfig/lkc_proto.h | 2 -- scripts/kconfig/parser.y | 2 -- scripts/kconfig/symbol.c | 22 +++++++++++----------- 7 files changed, 42 insertions(+), 39 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 662a5e7c37c2..b5730061872b 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -14,6 +14,7 @@ #include #include +#include "internal.h" #include "lkc.h" static void conf(struct menu *menu); @@ -171,7 +172,7 @@ enum conf_def_mode { static bool conf_set_all_new_symbols(enum conf_def_mode mode) { struct symbol *sym, *csym; - int i, cnt; + int cnt; /* * can't go as the default in switch-case below, otherwise gcc whines * about -Wmaybe-uninitialized @@ -226,7 +227,7 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) } } - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym_has_value(sym) || sym->flags & SYMBOL_VALID) continue; switch (sym_get_type(sym)) { @@ -278,14 +279,14 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) * and the rest to no. */ if (mode != def_random) { - for_all_symbols(i, csym) { + for_all_symbols(csym) { if ((sym_is_choice(csym) && !sym_has_value(csym)) || sym_is_choice_value(csym)) csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; } } - for_all_symbols(i, csym) { + for_all_symbols(csym) { if (sym_has_value(csym) || !sym_is_choice(csym)) continue; @@ -304,9 +305,8 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) static void conf_rewrite_tristates(tristate old_val, tristate new_val) { struct symbol *sym; - int i; - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym_get_type(sym) == S_TRISTATE && sym->def[S_DEF_USER].tri == old_val) sym->def[S_DEF_USER].tri = new_val; diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index dafc572e7b7e..c5b6487d68ac 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -18,6 +18,7 @@ #include #include +#include "internal.h" #include "lkc.h" struct gstr autoconf_cmd; @@ -322,7 +323,7 @@ int conf_read_simple(const char *name, int def) size_t line_asize = 0; char *p, *val; struct symbol *sym; - int i, def_flags; + int def_flags; const char *warn_unknown, *sym_name; warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS"); @@ -380,7 +381,7 @@ load: conf_warnings = 0; def_flags = SYMBOL_DEF << def; - for_all_symbols(i, sym) { + for_all_symbols(sym) { sym->flags |= SYMBOL_CHANGED; sym->flags &= ~(def_flags|SYMBOL_VALID); if (sym_is_choice(sym)) @@ -489,7 +490,6 @@ int conf_read(const char *name) { struct symbol *sym; int conf_unsaved = 0; - int i; conf_set_changed(false); @@ -500,7 +500,7 @@ int conf_read(const char *name) sym_calc_value(modules_sym); - for_all_symbols(i, sym) { + for_all_symbols(sym) { sym_calc_value(sym); if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE)) continue; @@ -524,7 +524,7 @@ int conf_read(const char *name) /* maybe print value in verbose mode... */ } - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym_has_value(sym) && !sym_is_choice_value(sym)) { /* Reset values of generates values, so they'll appear * as new, if they should become visible, but that @@ -862,7 +862,6 @@ int conf_write(const char *name) const char *str; char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; char *env; - int i; bool need_newline = false; if (!name) @@ -946,7 +945,7 @@ end_check: } fclose(out); - for_all_symbols(i, sym) + for_all_symbols(sym) sym->flags &= ~SYMBOL_WRITTEN; if (*tmpname) { @@ -1016,7 +1015,7 @@ static int conf_touch_deps(void) { const char *name, *tmp; struct symbol *sym; - int res, i; + int res; name = conf_get_autoconfig_name(); tmp = strrchr(name, '/'); @@ -1030,7 +1029,7 @@ static int conf_touch_deps(void) conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); - for_all_symbols(i, sym) { + for_all_symbols(sym) { sym_calc_value(sym); if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name) continue; @@ -1096,7 +1095,7 @@ static int __conf_write_autoconf(const char *filename, char tmp[PATH_MAX]; FILE *file; struct symbol *sym; - int ret, i; + int ret; if (make_parent_dir(filename)) return -1; @@ -1113,7 +1112,7 @@ static int __conf_write_autoconf(const char *filename, conf_write_heading(file, comment_style); - for_all_symbols(i, sym) + for_all_symbols(sym) if ((sym->flags & SYMBOL_WRITE) && sym->name) print_symbol(file, sym); @@ -1136,7 +1135,7 @@ int conf_write_autoconf(int overwrite) { struct symbol *sym; const char *autoconf_name = conf_get_autoconfig_name(); - int ret, i; + int ret; if (!overwrite && is_present(autoconf_name)) return 0; @@ -1148,7 +1147,7 @@ int conf_write_autoconf(int overwrite) if (conf_touch_deps()) return 1; - for_all_symbols(i, sym) + for_all_symbols(sym) sym_calc_value(sym); ret = __conf_write_autoconf(conf_get_autoheader_name(), diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index dd3350aed302..3bc375f1a1cd 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -17,6 +17,8 @@ extern "C" { #include #endif +#include "list_types.h" + typedef enum tristate { no, mod, yes } tristate; @@ -74,8 +76,8 @@ enum { * SYMBOL_CHOICE bit set in 'flags'. */ struct symbol { - /* The next symbol in the same bucket in the symbol hash table */ - struct symbol *next; + /* link node for the hash table */ + struct hlist_node node; /* The name of the symbol, e.g. "FOO" for 'config FOO' */ char *name; @@ -124,8 +126,6 @@ struct symbol { struct expr_value implied; }; -#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) - #define SYMBOL_CONST 0x0001 /* symbol is const */ #define SYMBOL_CHECK 0x0008 /* used during dependency checking */ #define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ @@ -150,7 +150,6 @@ struct symbol { #define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 #define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 9973 /* A property represent the config options that can be associated * with a config "symbol". diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h index 788401cd5d6f..6c721c4cfd72 100644 --- a/scripts/kconfig/internal.h +++ b/scripts/kconfig/internal.h @@ -2,6 +2,15 @@ #ifndef INTERNAL_H #define INTERNAL_H +#include "hashtable.h" + +#define SYMBOL_HASHSIZE (1U << 14) + +extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE); + +#define for_all_symbols(sym) \ + hash_for_each(sym_hashtable, sym, node) + struct menu; extern struct menu *current_menu, *current_entry; diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 94299e42402f..2807fa584c2b 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -18,8 +18,6 @@ void conf_set_message_callback(void (*fn)(const char *s)); bool conf_errors(void); /* symbol.c */ -extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; - struct symbol * sym_lookup(const char *name, int flags); struct symbol * sym_find(const char *name); void print_symbol_for_listconfig(struct symbol *sym); diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index efd0e234e0d2..b505e43e0d02 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -28,8 +28,6 @@ static void zconf_error(const char *err, ...); static bool zconf_endtoken(const char *tokenname, const char *expected_tokenname); -struct symbol *symbol_hash[SYMBOL_HASHSIZE]; - struct menu *current_menu, *current_entry; %} diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 3dbe3a19622b..dd5cf9727a9a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -9,6 +9,7 @@ #include #include +#include "internal.h" #include "lkc.h" struct symbol symbol_yes = { @@ -160,9 +161,8 @@ static void sym_set_changed(struct symbol *sym) static void sym_set_all_changed(void) { struct symbol *sym; - int i; - for_all_symbols(i, sym) + for_all_symbols(sym) sym_set_changed(sym); } @@ -475,9 +475,8 @@ void sym_calc_value(struct symbol *sym) void sym_clear_all_valid(void) { struct symbol *sym; - int i; - for_all_symbols(i, sym) + for_all_symbols(sym) sym->flags &= ~SYMBOL_VALID; conf_set_changed(true); sym_calc_value(modules_sym); @@ -803,6 +802,8 @@ bool sym_is_changeable(struct symbol *sym) return sym->visible > sym->rev_dep.tri; } +HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE); + struct symbol *sym_lookup(const char *name, int flags) { struct symbol *symbol; @@ -817,9 +818,9 @@ struct symbol *sym_lookup(const char *name, int flags) case 'n': return &symbol_no; } } - hash = strhash(name) % SYMBOL_HASHSIZE; + hash = strhash(name); - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && !strcmp(symbol->name, name) && (flags ? symbol->flags & flags @@ -838,8 +839,7 @@ struct symbol *sym_lookup(const char *name, int flags) symbol->type = S_UNKNOWN; symbol->flags = flags; - symbol->next = symbol_hash[hash]; - symbol_hash[hash] = symbol; + hash_add(sym_hashtable, &symbol->node, hash); return symbol; } @@ -859,9 +859,9 @@ struct symbol *sym_find(const char *name) case 'n': return &symbol_no; } } - hash = strhash(name) % SYMBOL_HASHSIZE; + hash = strhash(name); - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && !strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) @@ -921,7 +921,7 @@ struct symbol **sym_re_search(const char *pattern) if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) return NULL; - for_all_symbols(i, sym) { + for_all_symbols(sym) { if (sym->flags & SYMBOL_CONST || !sym->name) continue; if (regexec(&re, sym->name, 1, match, 0)) -- cgit v1.2.3 From ba3b759fb688c09cd9b09852d2728b012cf040ba Mon Sep 17 00:00:00 2001 From: Matthew Bystrin Date: Fri, 16 Feb 2024 17:10:14 +0300 Subject: kconfig: lxdialog: fix cursor render in checklist When a checklist is opened, the cursor is rendered in a wrong position (after the last list element on the screen). You can observe it by opening any checklist in menuconfig. Added wmove() to set the cursor in the proper position, just like in menubox.c. Removed wnoutrefresh(dialog) because dialog window has already been updated in print_buttons(). Replaced wnoutrefresh(list) and doupdate() calls with one wrefresh(list) call. Signed-off-by: Matthew Bystrin Signed-off-by: Masahiro Yamada --- scripts/kconfig/lxdialog/checklist.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c index fd161cfff121..31d0a89fbeb7 100644 --- a/scripts/kconfig/lxdialog/checklist.c +++ b/scripts/kconfig/lxdialog/checklist.c @@ -188,9 +188,8 @@ do_resize: print_buttons(dialog, height, width, 0); - wnoutrefresh(dialog); - wnoutrefresh(list); - doupdate(); + wmove(list, choice, check_x + 1); + wrefresh(list); while (key != KEY_ESC) { key = wgetch(dialog); -- cgit v1.2.3 From 557f8c582a9ba8abe6aa0fd734b6f342af106b26 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 18 Jan 2024 15:06:05 -0800 Subject: ubsan: Reintroduce signed overflow sanitizer In order to mitigate unexpected signed wrap-around[1], bring back the signed integer overflow sanitizer. It was removed in commit 6aaa31aeb9cf ("ubsan: remove overflow checks") because it was effectively a no-op when combined with -fno-strict-overflow (which correctly changes signed overflow from being "undefined" to being explicitly "wrap around"). Compilers are adjusting their sanitizers to trap wrap-around and to detecting common code patterns that should not be instrumented (e.g. "var + offset < var"). Prepare for this and explicitly rename the option from "OVERFLOW" to "WRAP" to more accurately describe the behavior. To annotate intentional wrap-around arithmetic, the helpers wrapping_add/sub/mul_wrap() can be used for individual statements. At the function level, the __signed_wrap attribute can be used to mark an entire function as expecting its signed arithmetic to wrap around. For a single object file the Makefile can use "UBSAN_SIGNED_WRAP_target.o := n" to mark it as wrapping, and for an entire directory, "UBSAN_SIGNED_WRAP := n" can be used. Additionally keep these disabled under CONFIG_COMPILE_TEST for now. Link: https://github.com/KSPP/linux/issues/26 [1] Cc: Miguel Ojeda Cc: Nathan Chancellor Cc: Peter Zijlstra Cc: Hao Luo Reviewed-by: Marco Elver Reviewed-by: Justin Stitt Signed-off-by: Kees Cook --- include/linux/compiler_types.h | 9 +++++- lib/Kconfig.ubsan | 15 +++++++++- lib/test_ubsan.c | 37 +++++++++++++++++++++++ lib/ubsan.c | 68 ++++++++++++++++++++++++++++++++++++++++++ lib/ubsan.h | 4 +++ scripts/Makefile.lib | 3 ++ scripts/Makefile.ubsan | 3 ++ 7 files changed, 137 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 6f1ca49306d2..ee9d272008a5 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -282,11 +282,18 @@ struct ftrace_likely_data { #define __no_sanitize_or_inline __always_inline #endif +/* Do not trap wrapping arithmetic within an annotated function. */ +#ifdef CONFIG_UBSAN_SIGNED_WRAP +# define __signed_wrap __attribute__((no_sanitize("signed-integer-overflow"))) +#else +# define __signed_wrap +#endif + /* Section for code which can't be instrumented at all */ #define __noinstr_section(section) \ noinline notrace __attribute((__section__(section))) \ __no_kcsan __no_sanitize_address __no_profile __no_sanitize_coverage \ - __no_sanitize_memory + __no_sanitize_memory __signed_wrap #define noinstr __noinstr_section(".noinstr.text") diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index 56d7653f4941..48a67058f84e 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -87,7 +87,6 @@ config UBSAN_LOCAL_BOUNDS config UBSAN_SHIFT bool "Perform checking for bit-shift overflows" - default UBSAN depends on $(cc-option,-fsanitize=shift) help This option enables -fsanitize=shift which checks for bit-shift @@ -116,6 +115,20 @@ config UBSAN_UNREACHABLE This option enables -fsanitize=unreachable which checks for control flow reaching an expected-to-be-unreachable position. +config UBSAN_SIGNED_WRAP + bool "Perform checking for signed arithmetic wrap-around" + default UBSAN + depends on !COMPILE_TEST + depends on $(cc-option,-fsanitize=signed-integer-overflow) + help + This option enables -fsanitize=signed-integer-overflow which checks + for wrap-around of any arithmetic operations with signed integers. + This currently performs nearly no instrumentation due to the + kernel's use of -fno-strict-overflow which converts all would-be + arithmetic undefined behavior into wrap-around arithmetic. Future + sanitizer versions will allow for wrap-around checking (rather than + exclusively undefined behavior). + config UBSAN_BOOL bool "Perform checking for non-boolean values used as boolean" default UBSAN diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c index f4ee2484d4b5..276c12140ee2 100644 --- a/lib/test_ubsan.c +++ b/lib/test_ubsan.c @@ -11,6 +11,39 @@ typedef void(*test_ubsan_fp)(void); #config, IS_ENABLED(config) ? "y" : "n"); \ } while (0) +static void test_ubsan_add_overflow(void) +{ + volatile int val = INT_MAX; + + UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + val += 2; +} + +static void test_ubsan_sub_overflow(void) +{ + volatile int val = INT_MIN; + volatile int val2 = 2; + + UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + val -= val2; +} + +static void test_ubsan_mul_overflow(void) +{ + volatile int val = INT_MAX / 2; + + UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + val *= 3; +} + +static void test_ubsan_negate_overflow(void) +{ + volatile int val = INT_MIN; + + UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + val = -val; +} + static void test_ubsan_divrem_overflow(void) { volatile int val = 16; @@ -90,6 +123,10 @@ static void test_ubsan_misaligned_access(void) } static const test_ubsan_fp test_ubsan_array[] = { + test_ubsan_add_overflow, + test_ubsan_sub_overflow, + test_ubsan_mul_overflow, + test_ubsan_negate_overflow, test_ubsan_shift_out_of_bounds, test_ubsan_out_of_bounds, test_ubsan_load_invalid_value, diff --git a/lib/ubsan.c b/lib/ubsan.c index df4f8d1354bb..5fc107f61934 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c @@ -222,6 +222,74 @@ static void ubsan_epilogue(void) check_panic_on_warn("UBSAN"); } +static void handle_overflow(struct overflow_data *data, void *lhs, + void *rhs, char op) +{ + + struct type_descriptor *type = data->type; + char lhs_val_str[VALUE_LENGTH]; + char rhs_val_str[VALUE_LENGTH]; + + if (suppress_report(&data->location)) + return; + + ubsan_prologue(&data->location, type_is_signed(type) ? + "signed-integer-overflow" : + "unsigned-integer-overflow"); + + val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs); + val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs); + pr_err("%s %c %s cannot be represented in type %s\n", + lhs_val_str, + op, + rhs_val_str, + type->type_name); + + ubsan_epilogue(); +} + +void __ubsan_handle_add_overflow(void *data, + void *lhs, void *rhs) +{ + + handle_overflow(data, lhs, rhs, '+'); +} +EXPORT_SYMBOL(__ubsan_handle_add_overflow); + +void __ubsan_handle_sub_overflow(void *data, + void *lhs, void *rhs) +{ + handle_overflow(data, lhs, rhs, '-'); +} +EXPORT_SYMBOL(__ubsan_handle_sub_overflow); + +void __ubsan_handle_mul_overflow(void *data, + void *lhs, void *rhs) +{ + handle_overflow(data, lhs, rhs, '*'); +} +EXPORT_SYMBOL(__ubsan_handle_mul_overflow); + +void __ubsan_handle_negate_overflow(void *_data, void *old_val) +{ + struct overflow_data *data = _data; + char old_val_str[VALUE_LENGTH]; + + if (suppress_report(&data->location)) + return; + + ubsan_prologue(&data->location, "negation-overflow"); + + val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val); + + pr_err("negation of %s cannot be represented in type %s:\n", + old_val_str, data->type->type_name); + + ubsan_epilogue(); +} +EXPORT_SYMBOL(__ubsan_handle_negate_overflow); + + void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs) { struct overflow_data *data = _data; diff --git a/lib/ubsan.h b/lib/ubsan.h index 5d99ab81913b..0abbbac8700d 100644 --- a/lib/ubsan.h +++ b/lib/ubsan.h @@ -124,6 +124,10 @@ typedef s64 s_max; typedef u64 u_max; #endif +void __ubsan_handle_add_overflow(void *data, void *lhs, void *rhs); +void __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs); +void __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs); +void __ubsan_handle_negate_overflow(void *_data, void *old_val); void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs); void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr); void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr); diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 52efc520ae4f..b4a248c20654 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -177,6 +177,9 @@ ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \ $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)y), \ $(CFLAGS_UBSAN)) +_c_flags += $(if $(patsubst n%,, \ + $(UBSAN_SIGNED_WRAP_$(basetarget).o)$(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SIGNED_WRAP)$(UBSAN_SANITIZE)y), \ + $(CFLAGS_UBSAN_SIGNED_WRAP)) endif ifeq ($(CONFIG_KCOV),y) diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan index 7cf42231042b..b2d3b273b802 100644 --- a/scripts/Makefile.ubsan +++ b/scripts/Makefile.ubsan @@ -13,3 +13,6 @@ ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum ubsan-cflags-$(CONFIG_UBSAN_TRAP) += $(call cc-option,-fsanitize-trap=undefined,-fsanitize-undefined-trap-on-error) export CFLAGS_UBSAN := $(ubsan-cflags-y) + +ubsan-signed-wrap-cflags-$(CONFIG_UBSAN_SIGNED_WRAP) += -fsanitize=signed-integer-overflow +export CFLAGS_UBSAN_SIGNED_WRAP := $(ubsan-signed-wrap-cflags-y) -- cgit v1.2.3 From a3a23d360cdd853b1038deda05e8d8c134a49a90 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 15 Feb 2024 14:48:24 +0100 Subject: scripts/kernel-doc: add modeline for vim users Set 'softtabstop' to 4 spaces, which will hopefully help keep the indentation in this file consistent going forwards. This mirrors the modeline in scripts such as recordmcount.pl, ktest.pl, and others. Emacs seems to use 4 spaces to indent by default, so it doesn't require anything special here. No functional change. Signed-off-by: Vegard Nossum Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240215134828.1277109-2-vegard.nossum@oracle.com --- scripts/kernel-doc | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index a9947080ead3..4dc5c3909d8c 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1,5 +1,6 @@ #!/usr/bin/env perl # SPDX-License-Identifier: GPL-2.0 +# vim: softtabstop=4 use warnings; use strict; -- cgit v1.2.3 From e8ebb853eb5751168cfd87c706fb1c38e053d4fb Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 15 Feb 2024 14:48:25 +0100 Subject: scripts/kernel-doc: simplify function printing Get rid of the $start variable, since it's really not necessary. No functional change. Signed-off-by: Vegard Nossum Reviewed-by: Randy Dunlap Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240215134828.1277109-3-vegard.nossum@oracle.com --- scripts/kernel-doc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 4dc5c3909d8c..9b7441e77669 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -820,7 +820,6 @@ sub output_function_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); my $oldprefix = $lineprefix; - my $start = ""; my $is_macro = 0; if ($sphinx_major < 3) { @@ -830,7 +829,7 @@ sub output_function_rst(%) { print " **Typedef**: "; $lineprefix = ""; output_highlight_rst($args{'purpose'}); - $start = "\n\n**Syntax**\n\n ``"; + print "\n\n**Syntax**\n\n ``"; $is_macro = 1; } else { print ".. c:function:: "; @@ -848,17 +847,16 @@ sub output_function_rst(%) { print " **Typedef**: "; $lineprefix = ""; output_highlight_rst($args{'purpose'}); - $start = "\n\n**Syntax**\n\n ``"; + print "\n\n**Syntax**\n\n ``"; } else { print "``" if ($is_macro); } } if ($args{'functiontype'} ne "") { - $start .= $args{'functiontype'} . " " . $args{'function'} . " ("; + print $args{'functiontype'} . " " . $args{'function'} . " ("; } else { - $start .= $args{'function'} . " ("; + print $args{'function'} . " ("; } - print $start; my $count = 0; foreach my $parameter (@{$args{'parameterlist'}}) { -- cgit v1.2.3 From d3c55a710f95e11e2369a57cb53d4a7f3280aa57 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 15 Feb 2024 14:48:26 +0100 Subject: scripts/kernel-doc: separate out function signature Format the entire function signature and place it in a separate variable; this both makes it easier to understand what these lines of code are doing and will allow us to simplify the code further in the following patch. No functional change. Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240215134828.1277109-4-vegard.nossum@oracle.com --- scripts/kernel-doc | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 9b7441e77669..1af2c68f6bd8 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -822,6 +822,31 @@ sub output_function_rst(%) { my $oldprefix = $lineprefix; my $is_macro = 0; + my $signature = ""; + if ($args{'functiontype'} ne "") { + $signature = $args{'functiontype'} . " " . $args{'function'} . " ("; + } else { + $signature = $args{'function'} . " ("; + } + + my $count = 0; + foreach my $parameter (@{$args{'parameterlist'}}) { + if ($count ne 0) { + $signature .= ", "; + } + $count++; + $type = $args{'parametertypes'}{$parameter}; + + if ($type =~ m/$function_pointer/) { + # pointer-to-function + $signature .= $1 . $parameter . ") (" . $2 . ")"; + } else { + $signature .= $type; + } + } + + $signature .= ")"; + if ($sphinx_major < 3) { if ($args{'typedef'}) { print ".. c:type:: ". $args{'function'} . "\n\n"; @@ -852,31 +877,13 @@ sub output_function_rst(%) { print "``" if ($is_macro); } } - if ($args{'functiontype'} ne "") { - print $args{'functiontype'} . " " . $args{'function'} . " ("; - } else { - print $args{'function'} . " ("; - } - my $count = 0; - foreach my $parameter (@{$args{'parameterlist'}}) { - if ($count ne 0) { - print ", "; - } - $count++; - $type = $args{'parametertypes'}{$parameter}; + print $signature; - if ($type =~ m/$function_pointer/) { - # pointer-to-function - print $1 . $parameter . ") (" . $2 . ")"; - } else { - print $type; - } - } if ($is_macro) { - print ")``\n\n"; + print "``\n\n"; } else { - print ")\n\n"; + print "\n\n"; } if (!$args{'typedef'}) { print_lineno($declaration_start_line); -- cgit v1.2.3 From 9f6f4c110c95a96942004547c84ab22384d9e723 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 15 Feb 2024 14:48:27 +0100 Subject: scripts/kernel-doc: simplify signature printing Untangle some of the $is_macro logic and the nested conditionals. This makes it easier to see where and how the signature is actually printed. No functional change. Signed-off-by: Vegard Nossum Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240215134828.1277109-5-vegard.nossum@oracle.com --- scripts/kernel-doc | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 1af2c68f6bd8..7acb7554abb9 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -820,7 +820,6 @@ sub output_function_rst(%) { my %args = %{$_[0]}; my ($parameter, $section); my $oldprefix = $lineprefix; - my $is_macro = 0; my $signature = ""; if ($args{'functiontype'} ne "") { @@ -854,37 +853,30 @@ sub output_function_rst(%) { print " **Typedef**: "; $lineprefix = ""; output_highlight_rst($args{'purpose'}); - print "\n\n**Syntax**\n\n ``"; - $is_macro = 1; + print "\n\n**Syntax**\n\n"; + print " ``$signature``\n\n"; } else { - print ".. c:function:: "; + print ".. c:function:: $signature\n\n"; } } else { if ($args{'typedef'} || $args{'functiontype'} eq "") { - $is_macro = 1; print ".. c:macro:: ". $args{'function'} . "\n\n"; - } else { - print ".. c:function:: "; - } - if ($args{'typedef'}) { - print_lineno($declaration_start_line); - print " **Typedef**: "; - $lineprefix = ""; - output_highlight_rst($args{'purpose'}); - print "\n\n**Syntax**\n\n ``"; + if ($args{'typedef'}) { + print_lineno($declaration_start_line); + print " **Typedef**: "; + $lineprefix = ""; + output_highlight_rst($args{'purpose'}); + print "\n\n**Syntax**\n\n"; + print " ``$signature``\n\n"; + } else { + print "``$signature``\n\n"; + } } else { - print "``" if ($is_macro); + print ".. c:function:: $signature\n\n"; } } - print $signature; - - if ($is_macro) { - print "``\n\n"; - } else { - print "\n\n"; - } if (!$args{'typedef'}) { print_lineno($declaration_start_line); $lineprefix = " "; -- cgit v1.2.3 From 8e93cb78a4f68c3c3c718e5388f0593227101393 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Feb 2024 14:29:38 +0100 Subject: kernel-doc: handle #if in enums as well In addition to #ifdef, #define and #endif, also handle any #if since we may be using e.g. #if IS_ENABLED(...). I didn't find any instances of this in the kernel now, there are enums with such ifs inside, but I didn't find any with kernel-doc as well. However, it came up as we were adding such a construct in our driver and warnings from kernel-doc were the result. Signed-off-by: Johannes Berg Signed-off-by: Jonathan Corbet Link: https://lore.kernel.org/r/20240214142937.80ee86a3beae.Ibcc5bd97a20cd10a792663e4b254cd46c7e8b520@changeid --- scripts/kernel-doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 7acb7554abb9..71a89d8832c1 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1328,7 +1328,7 @@ sub dump_enum($$) { $x =~ s@/\*.*?\*/@@gos; # strip comments. # strip #define macros inside enums - $x =~ s@#\s*((define|ifdef)\s+|endif)[^;]*;@@gos; + $x =~ s@#\s*((define|ifdef|if)\s+|endif)[^;]*;@@gos; if ($x =~ /typedef\s+enum\s*\{(.*)\}\s*(\w*)\s*;/) { $declaration_name = $2; -- cgit v1.2.3 From 0040f2c5531fe852505b3786992e41a5b40f8db6 Mon Sep 17 00:00:00 2001 From: Kuan-Ying Lee Date: Wed, 7 Feb 2024 16:58:51 +0800 Subject: scripts/gdb/vmalloc: fix vmallocinfo error The patch series "Mitigate a vmap lock contention" removes vmap_area_list, which will break the gdb vmallocinfo command: (gdb) lx-vmallocinfo Python Exception : No symbol "vmap_area_list" in current context. Error occurred in Python: No symbol "vmap_area_list" in current context. So we can instead use vmap_nodes to iterate all vmallocinfo. Link: https://lkml.kernel.org/r/20240207085856.11190-1-Kuan-Ying.Lee@mediatek.com Signed-off-by: Kuan-Ying Lee Cc: Casper Li Cc: AngeloGioacchino Del Regno Cc: Chinwen Chang Cc: Jan Kiszka Cc: Kieran Bingham Cc: Matthias Brugger Cc: Qun-Wei Lin Cc: Uladzislau Rezki (Sony) Signed-off-by: Andrew Morton --- scripts/gdb/linux/vmalloc.py | 56 +++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'scripts') diff --git a/scripts/gdb/linux/vmalloc.py b/scripts/gdb/linux/vmalloc.py index d3c8a0274d1e..803f17371052 100644 --- a/scripts/gdb/linux/vmalloc.py +++ b/scripts/gdb/linux/vmalloc.py @@ -29,32 +29,34 @@ class LxVmallocInfo(gdb.Command): if not constants.LX_CONFIG_MMU: raise gdb.GdbError("Requires MMU support") - vmap_area_list = gdb.parse_and_eval('vmap_area_list') - for vmap_area in lists.list_for_each_entry(vmap_area_list, vmap_area_ptr_type, "list"): - if not vmap_area['vm']: - gdb.write("0x%x-0x%x %10d vm_map_ram\n" % (vmap_area['va_start'], vmap_area['va_end'], - vmap_area['va_end'] - vmap_area['va_start'])) - continue - v = vmap_area['vm'] - gdb.write("0x%x-0x%x %10d" % (v['addr'], v['addr'] + v['size'], v['size'])) - if v['caller']: - gdb.write(" %s" % str(v['caller']).split(' ')[-1]) - if v['nr_pages']: - gdb.write(" pages=%d" % v['nr_pages']) - if v['phys_addr']: - gdb.write(" phys=0x%x" % v['phys_addr']) - if v['flags'] & constants.LX_VM_IOREMAP: - gdb.write(" ioremap") - if v['flags'] & constants.LX_VM_ALLOC: - gdb.write(" vmalloc") - if v['flags'] & constants.LX_VM_MAP: - gdb.write(" vmap") - if v['flags'] & constants.LX_VM_USERMAP: - gdb.write(" user") - if v['flags'] & constants.LX_VM_DMA_COHERENT: - gdb.write(" dma-coherent") - if is_vmalloc_addr(v['pages']): - gdb.write(" vpages") - gdb.write("\n") + nr_vmap_nodes = gdb.parse_and_eval('nr_vmap_nodes') + for i in range(0, nr_vmap_nodes): + vn = gdb.parse_and_eval('&vmap_nodes[%d]' % i) + for vmap_area in lists.list_for_each_entry(vn['busy']['head'], vmap_area_ptr_type, "list"): + if not vmap_area['vm']: + gdb.write("0x%x-0x%x %10d vm_map_ram\n" % (vmap_area['va_start'], vmap_area['va_end'], + vmap_area['va_end'] - vmap_area['va_start'])) + continue + v = vmap_area['vm'] + gdb.write("0x%x-0x%x %10d" % (v['addr'], v['addr'] + v['size'], v['size'])) + if v['caller']: + gdb.write(" %s" % str(v['caller']).split(' ')[-1]) + if v['nr_pages']: + gdb.write(" pages=%d" % v['nr_pages']) + if v['phys_addr']: + gdb.write(" phys=0x%x" % v['phys_addr']) + if v['flags'] & constants.LX_VM_IOREMAP: + gdb.write(" ioremap") + if v['flags'] & constants.LX_VM_ALLOC: + gdb.write(" vmalloc") + if v['flags'] & constants.LX_VM_MAP: + gdb.write(" vmap") + if v['flags'] & constants.LX_VM_USERMAP: + gdb.write(" user") + if v['flags'] & constants.LX_VM_DMA_COHERENT: + gdb.write(" dma-coherent") + if is_vmalloc_addr(v['pages']): + gdb.write(" vpages") + gdb.write("\n") LxVmallocInfo() -- cgit v1.2.3 From 9c1b86f8ce04ec4aa22c1119480b3950bf4724c8 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 25 Jan 2024 15:55:07 -0700 Subject: kbuild: raise the minimum supported version of LLVM to 13.0.1 Patch series "Bump the minimum supported version of LLVM to 13.0.1". This series bumps the minimum supported version of LLVM for building the kernel to 13.0.1. The first patch does the bump and all subsequent patches clean up all the various workarounds and checks for earlier versions. Quoting the first patch's commit message for those that were only on CC for the clean ups: When __builtin_mul_overflow() has arguments that differ in terms of signedness and width, LLVM may generate a libcall to __muloti4 because it performs the checks in terms of 65-bit multiplication. This issue becomes harder to hit (but still possible) after LLVM 12.0.0, which includes a special case for matching widths but different signs. To gain access to this special case, which the kernel can take advantage of when calls to __muloti4 appear, bump the minimum supported version of LLVM for building the kernel to 13.0.1. 13.0.1 was chosen because there is minimal impact to distribution support while allowing a few more workarounds to be dropped in the kernel source than if 12.0.0 were chosen. Looking at container images of up to date distribution versions: archlinux:latest clang version 16.0.6 debian:oldoldstable-slim clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final) debian:oldstable-slim Debian clang version 11.0.1-2 debian:stable-slim Debian clang version 14.0.6 debian:testing-slim Debian clang version 16.0.6 (19) debian:unstable-slim Debian clang version 16.0.6 (19) fedora:38 clang version 16.0.6 (Fedora 16.0.6-3.fc38) fedora:latest clang version 17.0.6 (Fedora 17.0.6-1.fc39) fedora:rawhide clang version 17.0.6 (Fedora 17.0.6-1.fc40) opensuse/leap:latest clang version 15.0.7 opensuse/tumbleweed:latest clang version 17.0.6 ubuntu:focal clang version 10.0.0-4ubuntu1 ubuntu:latest Ubuntu clang version 14.0.0-1ubuntu1.1 ubuntu:rolling Ubuntu clang version 16.0.6 (15) ubuntu:devel Ubuntu clang version 17.0.6 (3) The only distribution that gets left behind is Debian Bullseye, as the default version is 11.0.1; other distributions either have a newer version than 13.0.1 or one older than the current minimum of 11.0.0. Debian has easy access to more recent LLVM versions through apt.llvm.org, so this is not as much of a concern. There are also the kernel.org LLVM toolchains, which should work with distributions with glibc 2.28 and newer. Another benefit of slimming up the number of supported versions of LLVM for building the kernel is reducing the build capacity needed to support a matrix that builds with each supported version, which allows a matrix to reallocate the freed up build capacity towards something else, such as more configuration combinations. This passes my build matrix with all supported versions. This is based on Andrew's mm-nonmm-unstable to avoid trivial conflicts with my series to update the LLVM links across the repository [1] but I can easily rebase it to linux-kbuild if Masahiro would rather these patches go through there (and defer the conflict resolution to the merge window). [1]: https://lore.kernel.org/20240109-update-llvm-links-v1-0-eb09b59db071@kernel.org/ This patch (of 11): When __builtin_mul_overflow() has arguments that differ in terms of signedness and width, LLVM may generate a libcall to __muloti4 because it performs the checks in terms of 65-bit multiplication. This issue becomes harder to hit (but still possible) after LLVM 12.0.0, which includes a special case for matching widths but different signs. To gain access to this special case, which the kernel can take advantage of when calls to __muloti4 appear, bump the minimum supported version of LLVM for building the kernel to 13.0.1. 13.0.1 was chosen because there is minimal impact to distribution support while allowing a few more workarounds to be dropped in the kernel source than if 12.0.0 were chosen. Looking at container images of up to date distribution versions: archlinux:latest clang version 16.0.6 debian:oldoldstable-slim clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final) debian:oldstable-slim Debian clang version 11.0.1-2 debian:stable-slim Debian clang version 14.0.6 debian:testing-slim Debian clang version 16.0.6 (19) debian:unstable-slim Debian clang version 16.0.6 (19) fedora:38 clang version 16.0.6 (Fedora 16.0.6-3.fc38) fedora:latest clang version 17.0.6 (Fedora 17.0.6-1.fc39) fedora:rawhide clang version 17.0.6 (Fedora 17.0.6-1.fc40) opensuse/leap:latest clang version 15.0.7 opensuse/tumbleweed:latest clang version 17.0.6 ubuntu:focal clang version 10.0.0-4ubuntu1 ubuntu:latest Ubuntu clang version 14.0.0-1ubuntu1.1 ubuntu:rolling Ubuntu clang version 16.0.6 (15) ubuntu:devel Ubuntu clang version 17.0.6 (3) The only distribution that gets left behind is Debian Bullseye, as the default version is 11.0.1; other distributions either have a newer version than 13.0.1 or one older than the current minimum of 11.0.0. Debian has easy access to more recent LLVM versions through apt.llvm.org, so this is not as much of a concern. There are also the kernel.org LLVM toolchains, which should work with distributions with glibc 2.28 and newer. Another benefit of slimming up the number of supported versions of LLVM for building the kernel is reducing the build capacity needed to support a matrix that builds with each supported version, which allows a matrix to reallocate the freed up build capacity towards something else, such as more configuration combinations. Link: https://lkml.kernel.org/r/20240125-bump-min-llvm-ver-to-13-0-1-v1-0-f5ff9bda41c5@kernel.org Closes: https://github.com/ClangBuiltLinux/linux/issues/1975 Link: https://github.com/llvm/llvm-project/issues/38013 Link: https://github.com/llvm/llvm-project/commit/3203143f1356a4e4e3ada231156fc6da6e1a9f9d Link: https://mirrors.edge.kernel.org/pub/tools/llvm/ Link: https://lkml.kernel.org/r/20240125-bump-min-llvm-ver-to-13-0-1-v1-1-f5ff9bda41c5@kernel.org Signed-off-by: Nathan Chancellor Reviewed-by: Kees Cook Cc: Albert Ou Cc: "Aneesh Kumar K.V (IBM)" Cc: Ard Biesheuvel Cc: Borislav Petkov (AMD) Cc: Catalin Marinas Cc: Conor Dooley Cc: Dave Hansen Cc: Ingo Molnar Cc: Mark Rutland Cc: Masahiro Yamada Cc: Michael Ellerman Cc: Nathan Chancellor Cc: "Naveen N. Rao" Cc: Nicholas Piggin Cc: Nicolas Schier Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Signed-off-by: Andrew Morton --- Documentation/process/changes.rst | 2 +- scripts/min-tool-version.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 50b3d1cb1115..d7306b8cad13 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -30,7 +30,7 @@ you probably needn't concern yourself with pcmciautils. Program Minimal version Command to check the version ====================== =============== ======================================== GNU C 5.1 gcc --version -Clang/LLVM (optional) 11.0.0 clang --version +Clang/LLVM (optional) 13.0.1 clang --version Rust (optional) 1.74.1 rustc --version bindgen (optional) 0.65.1 bindgen --version GNU make 3.82 make --version diff --git a/scripts/min-tool-version.sh b/scripts/min-tool-version.sh index 9faa4d3d91e3..5d17022ee1f6 100755 --- a/scripts/min-tool-version.sh +++ b/scripts/min-tool-version.sh @@ -29,7 +29,7 @@ llvm) elif [ "$SRCARCH" = loongarch ]; then echo 18.0.0 else - echo 11.0.0 + echo 13.0.1 fi ;; rustc) -- cgit v1.2.3 From de5f3984664e55bdb5f29108d579857facd407ac Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 25 Jan 2024 15:55:13 -0700 Subject: riscv: remove MCOUNT_NAME workaround Now that the minimum supported version of LLVM for building the kernel has been bumped to 13.0.1, the condition for using _mcount as MCOUNT_NAME is always true, as the build will fail during the configuration stage for older LLVM versions. Replace MCOUNT_NAME with _mcount directly. This effectively reverts commit 7ce047715030 ("riscv: Workaround mcount name prior to clang-13"). Link: https://lkml.kernel.org/r/20240125-bump-min-llvm-ver-to-13-0-1-v1-7-f5ff9bda41c5@kernel.org Signed-off-by: Nathan Chancellor Reviewed-by: Kees Cook Cc: Albert Ou Cc: "Aneesh Kumar K.V (IBM)" Cc: Ard Biesheuvel Cc: Borislav Petkov (AMD) Cc: Catalin Marinas Cc: Conor Dooley Cc: Dave Hansen Cc: Ingo Molnar Cc: Mark Rutland Cc: Masahiro Yamada Cc: Michael Ellerman Cc: "Naveen N. Rao" Cc: Nicholas Piggin Cc: Nicolas Schier Cc: Palmer Dabbelt Cc: Paul Walmsley Cc: Russell King Cc: Thomas Gleixner Cc: Will Deacon Signed-off-by: Andrew Morton --- arch/riscv/include/asm/ftrace.h | 14 ++------------ arch/riscv/kernel/mcount.S | 10 +++++----- scripts/recordmcount.pl | 2 +- 3 files changed, 8 insertions(+), 18 deletions(-) (limited to 'scripts') diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 06874fb1311e..cf5b63e789fa 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -13,19 +13,9 @@ #endif #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR -/* - * Clang prior to 13 had "mcount" instead of "_mcount": - * https://github.com/llvm/llvm-project/commit/ef58ae86ba778ed7d01cd3f6bd6d08f943abab44 - */ -#if defined(CONFIG_CC_IS_GCC) || CONFIG_CLANG_VERSION >= 130000 -#define MCOUNT_NAME _mcount -#else -#define MCOUNT_NAME mcount -#endif - #define ARCH_SUPPORTS_FTRACE_OPS 1 #ifndef __ASSEMBLY__ -void MCOUNT_NAME(void); +void _mcount(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) { return addr; @@ -75,7 +65,7 @@ struct dyn_arch_ftrace { * both auipc and jalr at the same time. */ -#define MCOUNT_ADDR ((unsigned long)MCOUNT_NAME) +#define MCOUNT_ADDR ((unsigned long)_mcount) #define JALR_SIGN_MASK (0x00000800) #define JALR_OFFSET_MASK (0x00000fff) #define AUIPC_OFFSET_MASK (0xfffff000) diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S index d7ec69ac6910..3a42f6287909 100644 --- a/arch/riscv/kernel/mcount.S +++ b/arch/riscv/kernel/mcount.S @@ -50,8 +50,8 @@ SYM_TYPED_FUNC_START(ftrace_stub) #ifdef CONFIG_DYNAMIC_FTRACE - .global MCOUNT_NAME - .set MCOUNT_NAME, ftrace_stub + .global _mcount + .set _mcount, ftrace_stub #endif ret SYM_FUNC_END(ftrace_stub) @@ -80,7 +80,7 @@ SYM_FUNC_END(return_to_handler) #endif #ifndef CONFIG_DYNAMIC_FTRACE -SYM_FUNC_START(MCOUNT_NAME) +SYM_FUNC_START(_mcount) la t4, ftrace_stub #ifdef CONFIG_FUNCTION_GRAPH_TRACER la t0, ftrace_graph_return @@ -126,6 +126,6 @@ SYM_FUNC_START(MCOUNT_NAME) jalr t5 RESTORE_ABI_STATE ret -SYM_FUNC_END(MCOUNT_NAME) +SYM_FUNC_END(_mcount) #endif -EXPORT_SYMBOL(MCOUNT_NAME) +EXPORT_SYMBOL(_mcount) diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index f84df9e383fd..0871b2e92584 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -352,7 +352,7 @@ if ($arch eq "x86_64") { $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; } elsif ($arch eq "riscv") { $function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; - $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_?mcount\$"; + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL(_PLT)?\\s_mcount\$"; $type = ".quad"; $alignment = 2; } elsif ($arch eq "csky") { -- cgit v1.2.3 From a1fb1c77950fbe47eb4a8f5be303bea4ee753b93 Mon Sep 17 00:00:00 2001 From: Ricardo B. Marliere Date: Sun, 4 Feb 2024 19:39:57 -0300 Subject: const_structs.checkpatch: add bus_type Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type. Make sure that new usages of the struct already enter the tree as const. Link: https://lkml.kernel.org/r/20240204-bus_cleanup-checkpatch-v1-1-8d51dcecda20@marliere.net Signed-off-by: Ricardo B. Marliere Suggested-by: Thomas Weißschuh Reviewed-by: Thomas Weißschuh Reviewed-by: Greg Kroah-Hartman Cc: Joe Perches Cc: Andy Whitcroft Cc: Dwaipayan Ray Cc: Lukas Bulwahn Signed-off-by: Andrew Morton --- scripts/const_structs.checkpatch | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index 188412aa2757..7427313adc7a 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -2,6 +2,7 @@ acpi_dock_ops address_space_operations backlight_ops block_device_operations +bus_type clk_ops comedi_lrange component_ops -- cgit v1.2.3 From 0f6588b351d4fbec8f8e63e99df20fec6f121e4a Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 19 Feb 2024 21:19:22 +0100 Subject: scripts: check-sysctl-docs: adapt to new API The script expects the old sysctl_register_paths() API which was removed some time ago. Adapt it to work with the new sysctl_register()/sysctl_register_sz()/sysctl_register_init() APIs. Signed-off-by: Thomas Weißschuh Reviewed-by: Joel Granados Signed-off-by: Joel Granados --- scripts/check-sysctl-docs | 45 ++++++++++++--------------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) (limited to 'scripts') diff --git a/scripts/check-sysctl-docs b/scripts/check-sysctl-docs index 4f163e0bf6a4..739afd766708 100755 --- a/scripts/check-sysctl-docs +++ b/scripts/check-sysctl-docs @@ -8,7 +8,7 @@ # Example invocation: # scripts/check-sysctl-docs -vtable="kernel" \ # Documentation/admin-guide/sysctl/kernel.rst \ -# $(git grep -l register_sysctl_) +# $(git grep -l register_sysctl) # # Specify -vdebug=1 to see debugging information @@ -20,14 +20,10 @@ BEGIN { } # The following globals are used: -# children: maps ctl_table names and procnames to child ctl_table names # documented: maps documented entries (each key is an entry) # entries: maps ctl_table names and procnames to counts (so # enumerating the subkeys for a given ctl_table lists its # procnames) -# files: maps procnames to source file names -# paths: maps ctl_path names to paths -# curpath: the name of the current ctl_path struct # curtable: the name of the current ctl_table struct # curentry: the name of the current proc entry (procname when parsing # a ctl_table, constructed path when parsing a ctl_path) @@ -94,44 +90,23 @@ FNR == NR { # Stage 2: process each file and find all sysctl tables BEGINFILE { - delete children delete entries - delete paths - curpath = "" curtable = "" curentry = "" if (debug) print "Processing file " FILENAME } -/^static struct ctl_path/ { - match($0, /static struct ctl_path ([^][]+)/, tables) - curpath = tables[1] - if (debug) print "Processing path " curpath -} - -/^static struct ctl_table/ { - match($0, /static struct ctl_table ([^][]+)/, tables) - curtable = tables[1] +/^static( const)? struct ctl_table/ { + match($0, /static( const)? struct ctl_table ([^][]+)/, tables) + curtable = tables[2] if (debug) print "Processing table " curtable } /^};$/ { - curpath = "" curtable = "" curentry = "" } -curpath && /\.procname[\t ]*=[\t ]*".+"/ { - match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) - if (curentry) { - curentry = curentry "/" names[1] - } else { - curentry = names[1] - } - if (debug) print "Setting path " curpath " to " curentry - paths[curpath] = curentry -} - curtable && /\.procname[\t ]*=[\t ]*".+"/ { match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names) curentry = names[1] @@ -140,10 +115,14 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ { file[curentry] = FILENAME } -/\.child[\t ]*=/ { - child = trimpunct($NF) - if (debug) print "Linking child " child " to table " curtable " entry " curentry - children[curtable][curentry] = child +/register_sysctl.*/ { + match($0, /register_sysctl(|_init|_sz)\("([^"]+)" *, *([^,)]+)/, tables) + if (debug) print "Registering table " tables[3] " at " tables[2] + if (tables[2] == table) { + for (entry in entries[tables[3]]) { + printentry(entry) + } + } } END { -- cgit v1.2.3 From 4f1136a55dc8e2c27d51e934d0675e12331c7291 Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Mon, 19 Feb 2024 21:19:24 +0100 Subject: scripts: check-sysctl-docs: handle per-namespace sysctls Some sysctl tables are registered for each namespace. (Like in ipc/ipc_sysctl.c) These need special handling to track the variable assignments. Signed-off-by: Thomas Weißschuh Reviewed-by: Joel Granados Signed-off-by: Joel Granados --- scripts/check-sysctl-docs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'scripts') diff --git a/scripts/check-sysctl-docs b/scripts/check-sysctl-docs index 739afd766708..20274c63e745 100755 --- a/scripts/check-sysctl-docs +++ b/scripts/check-sysctl-docs @@ -93,6 +93,7 @@ BEGINFILE { delete entries curtable = "" curentry = "" + delete vars if (debug) print "Processing file " FILENAME } @@ -105,6 +106,7 @@ BEGINFILE { /^};$/ { curtable = "" curentry = "" + delete vars } curtable && /\.procname[\t ]*=[\t ]*".+"/ { @@ -125,6 +127,24 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ { } } +/kmemdup.*/ { + match($0, /([^ \t]+) *= *kmemdup\(([^,]+) *,/, names) + if (debug) print "Found variable " names[1] " for table " names[2] + if (names[2] in entries) { + vars[names[1]] = names[2] + } +} + +/__register_sysctl_table.*/ { + match($0, /__register_sysctl_table\([^,]+, *"([^"]+)" *, *([^,]+)/, tables) + if (debug) print "Registering variable table " tables[2] " at " tables[1] + if (tables[1] == table && tables[2] in vars) { + for (entry in entries[vars[tables[2]]]) { + printentry(entry) + } + } +} + END { for (entry in documented) { if (!seen[entry]) { -- cgit v1.2.3 From bf48d9b756b91e3c656511fa8b63eaba1f50dbd0 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 17 Feb 2024 14:55:03 +0900 Subject: kbuild: change tool coverage variables to take the path relative to $(obj) Commit 54b8ae66ae1a ("kbuild: change *FLAGS_.o to take the path relative to $(obj)") changed the syntax of per-file compiler flags. The situation is the same for the following variables: OBJECT_FILES_NON_STANDARD_.o GCOV_PROFILE_.o KASAN_SANITIZE_.o KMSAN_SANITIZE_.o KMSAN_ENABLE_CHECKS_.o UBSAN_SANITIZE_.o KCOV_INSTRUMENT_.o KCSAN_SANITIZE_.o KCSAN_INSTRUMENT_BARRIERS_.o The is the filename of the target with its directory and suffix stripped. This syntax comes into a trouble when two files with the same basename appear in one Makefile, for example: obj-y += dir1/foo.o obj-y += dir2/foo.o OBJECT_FILES_NON_STANDARD_foo.o := y OBJECT_FILES_NON_STANDARD_foo.o is applied to both dir1/foo.o and dir2/foo.o. This syntax is not flexbile enough to handle cases where one of them is a standard object, but the other is not. It is more sensible to use the relative path to the Makefile, like this: obj-y += dir1/foo.o OBJECT_FILES_NON_STANDARD_dir1/foo.o := y obj-y += dir2/foo.o OBJECT_FILES_NON_STANDARD_dir2/foo.o := y To maintain the current behavior, I made adjustments to the following two Makefiles: - arch/x86/entry/vdso/Makefile, which compiles vclock_gettime.o, vgetcpu.o, and their vdso32 variants. - arch/x86/kvm/Makefile, which compiles vmx/vmenter.o and svm/vmenter.o Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier Acked-by: Sean Christopherson --- arch/x86/entry/vdso/Makefile | 2 ++ arch/x86/kvm/Makefile | 3 ++- scripts/Makefile.build | 2 +- scripts/Makefile.lib | 16 ++++++++-------- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'scripts') diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index b1b8dd1608f7..fa0a27503606 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -9,7 +9,9 @@ include $(srctree)/lib/vdso/Makefile # Sanitizer runtimes are unavailable and cannot be linked here. KASAN_SANITIZE := n KMSAN_SANITIZE_vclock_gettime.o := n +KMSAN_SANITIZE_vdso32/vclock_gettime.o := n KMSAN_SANITIZE_vgetcpu.o := n +KMSAN_SANITIZE_vdso32/vgetcpu.o := n UBSAN_SANITIZE := n KCSAN_SANITIZE := n diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 475b5fa917a6..a88bb14266b6 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -4,7 +4,8 @@ ccflags-y += -I $(srctree)/arch/x86/kvm ccflags-$(CONFIG_KVM_WERROR) += -Werror ifeq ($(CONFIG_FRAME_POINTER),y) -OBJECT_FILES_NON_STANDARD_vmenter.o := y +OBJECT_FILES_NON_STANDARD_vmx/vmenter.o := y +OBJECT_FILES_NON_STANDARD_svm/vmenter.o := y endif include $(srctree)/virt/kvm/Makefile.kvm diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 4971f54c855e..256db2a0e984 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -214,7 +214,7 @@ endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file # 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file -is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n),y) +is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(target-stem).o)$(OBJECT_FILES_NON_STANDARD)n),y) $(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y)) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index b35d39022a30..328c0d77ed48 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -154,7 +154,7 @@ _cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds) # ifeq ($(CONFIG_GCOV_KERNEL),y) _c_flags += $(if $(patsubst n%,, \ - $(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \ + $(GCOV_PROFILE_$(target-stem).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \ $(CFLAGS_GCOV)) endif @@ -165,29 +165,29 @@ endif ifeq ($(CONFIG_KASAN),y) ifneq ($(CONFIG_KASAN_HW_TAGS),y) _c_flags += $(if $(patsubst n%,, \ - $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ + $(KASAN_SANITIZE_$(target-stem).o)$(KASAN_SANITIZE)y), \ $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE)) endif endif ifeq ($(CONFIG_KMSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(KMSAN_SANITIZE_$(basetarget).o)$(KMSAN_SANITIZE)y), \ + $(KMSAN_SANITIZE_$(target-stem).o)$(KMSAN_SANITIZE)y), \ $(CFLAGS_KMSAN)) _c_flags += $(if $(patsubst n%,, \ - $(KMSAN_ENABLE_CHECKS_$(basetarget).o)$(KMSAN_ENABLE_CHECKS)y), \ + $(KMSAN_ENABLE_CHECKS_$(target-stem).o)$(KMSAN_ENABLE_CHECKS)y), \ , -mllvm -msan-disable-checks=1) endif ifeq ($(CONFIG_UBSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \ + $(UBSAN_SANITIZE_$(target-stem).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \ $(CFLAGS_UBSAN)) endif ifeq ($(CONFIG_KCOV),y) _c_flags += $(if $(patsubst n%,, \ - $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \ + $(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \ $(CFLAGS_KCOV)) endif @@ -197,12 +197,12 @@ endif # ifeq ($(CONFIG_KCSAN),y) _c_flags += $(if $(patsubst n%,, \ - $(KCSAN_SANITIZE_$(basetarget).o)$(KCSAN_SANITIZE)y), \ + $(KCSAN_SANITIZE_$(target-stem).o)$(KCSAN_SANITIZE)y), \ $(CFLAGS_KCSAN)) # Some uninstrumented files provide implied barriers required to avoid false # positives: set KCSAN_INSTRUMENT_BARRIERS for barrier instrumentation only. _c_flags += $(if $(patsubst n%,, \ - $(KCSAN_INSTRUMENT_BARRIERS_$(basetarget).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \ + $(KCSAN_INSTRUMENT_BARRIERS_$(target-stem).o)$(KCSAN_INSTRUMENT_BARRIERS)n), \ -D__KCSAN_INSTRUMENT_BARRIERS__) endif -- cgit v1.2.3 From 223390b1c4d266c3b684b99d0a1980c49ebccf0d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 17 Feb 2024 14:55:04 +0900 Subject: kbuild: change DTC_FLAGS_.o to take the path relative to $(obj) For the same rationale as commit 54b8ae66ae1a ("kbuild: change *FLAGS_.o to take the path relative to $(obj)"). Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/Makefile.lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 328c0d77ed48..56f7fe2b476d 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -368,7 +368,7 @@ DTC_FLAGS += -Wnode_name_chars_strict \ -Wunique_unit_address endif -DTC_FLAGS += $(DTC_FLAGS_$(basetarget)) +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)), -@) -- cgit v1.2.3 From 69fc23efc7e5030194ecaf4c108d4c23cfcd1a21 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa Date: Tue, 27 Feb 2024 14:03:30 +0900 Subject: kernel-doc: Add unary operator * to $type_param_ref In kernel-doc comments, unary operator * collides with Sphinx/ docutil's markdown for emphasizing. This resulted in additional warnings from "make htmldocs": WARNING: Inline emphasis start-string without end-string. , as reported recently [1]. Those have been worked around either by escaping * (like \*param) or by using inline-literal form of ``*param``, both of which are specific to Sphinx/docutils. Such workarounds are against the kenrel-doc's ideal and should better be avoided. Instead, add "*" to the list of unary operators kernel-doc recognizes and make the form of *@param available in kernel-doc comments. Reported-by: Stephen Rothwell Link: [1] https://lore.kernel.org/r/20240223153636.41358be5@canb.auug.org.au/ Acked-by: Christoph Hellwig Signed-off-by: Akira Yokosawa Cc: Jonathan Corbet Cc: Mauro Carvalho Chehab Acked-by: Jonathan Corbet Signed-off-by: Chandan Babu R --- scripts/kernel-doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index e8aefd258a29..d2f3fa3505c6 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -64,7 +64,7 @@ my $type_constant = '\b``([^\`]+)``\b'; my $type_constant2 = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; my $type_param = '\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; -my $type_param_ref = '([\!~]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; +my $type_param_ref = '([\!~\*]?)\@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)'; my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params my $type_fp_param2 = '\@(\w+->\S+)\(\)'; # Special RST handling for structs with func ptr params my $type_env = '(\$\w+)'; -- cgit v1.2.3 From a8528f7f31abf792f188d3f397b15aae7ed8564c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Feb 2024 13:34:30 -0600 Subject: dtc: Enable dtc interrupt_provider check Now that all the interrupt warnings have been fixed, enable 'interrupt_provider' check by default. This will also enable 'interrupt_map' check. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20240213-arm-dt-cleanups-v1-6-f2dee1292525@kernel.org Signed-off-by: Arnd Bergmann --- scripts/Makefile.lib | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index cd5b181060f1..fce35e4657f5 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -340,7 +340,7 @@ quiet_cmd_gzip = GZIP $@ # DTC # --------------------------------------------------------------------------- DTC ?= $(objtree)/scripts/dtc/dtc -DTC_FLAGS += -Wno-interrupt_provider \ +DTC_FLAGS += \ -Wno-unique_unit_address # Disable noisy checks by default @@ -358,7 +358,6 @@ endif ifneq ($(findstring 2,$(KBUILD_EXTRA_WARN)),) DTC_FLAGS += -Wnode_name_chars_strict \ -Wproperty_name_chars_strict \ - -Winterrupt_provider \ -Wunique_unit_address endif -- cgit v1.2.3 From 1d02f252339e2eaf3ba35b9dc77e7a1a9aa7414c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 15 Feb 2024 09:58:10 -0800 Subject: coccinelle: Add rules to find str_plural() replacements Add rules for finding places where str_plural() can be used. This currently finds: 54 files changed, 62 insertions(+), 61 deletions(-) Co-developed-by: Michal Wajdeczko Signed-off-by: Michal Wajdeczko Link: https://lore.kernel.org/all/fc1b25a8-6381-47c2-831c-ab6b8201a82b@intel.com/ Signed-off-by: Kees Cook --- MAINTAINERS | 1 + scripts/coccinelle/api/string_choices.cocci | 41 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 scripts/coccinelle/api/string_choices.cocci (limited to 'scripts') diff --git a/MAINTAINERS b/MAINTAINERS index d0df728734c1..216d02a3fed5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8979,6 +8979,7 @@ F: lib/string.c F: lib/string_helpers.c F: lib/test-string_helpers.c F: lib/test_string.c +F: scripts/coccinelle/api/string_choices.cocci GENERIC UIO DRIVER FOR PCI DEVICES M: "Michael S. Tsirkin" diff --git a/scripts/coccinelle/api/string_choices.cocci b/scripts/coccinelle/api/string_choices.cocci new file mode 100644 index 000000000000..a71966c0494e --- /dev/null +++ b/scripts/coccinelle/api/string_choices.cocci @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// Find places to use string_choices.h's various helpers. +// +// Confidence: Medium +// Options: --no-includes --include-headers +virtual patch +virtual context +virtual report + +@str_plural depends on patch@ +expression E; +@@ +( +- ((E == 1) ? "" : "s") ++ str_plural(E) +| +- ((E != 1) ? "s" : "") ++ str_plural(E) +| +- ((E > 1) ? "s" : "") ++ str_plural(E) +) + +@str_plural_r depends on !patch exists@ +expression E; +position P; +@@ +( +* ((E@P == 1) ? "" : "s") +| +* ((E@P != 1) ? "s" : "") +| +* ((E@P > 1) ? "s" : "") +) + +@script:python depends on report@ +p << str_plural_r.P; +e << str_plural_r.E; +@@ + +coccilib.report.print_report(p[0], "opportunity for str_plural(%s)" % e) -- cgit v1.2.3 From e7549481255167dcdab355c539562c7ace17e111 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 27 Feb 2023 12:24:28 -0800 Subject: coccinelle: semantic patch to check for potential struct_size calls include/linux/overflow.h includes helper macros intended for calculating sizes of allocations. These macros prevent accidental overflow by saturating at SIZE_MAX. In general when calculating such sizes use of the macros is preferred. Add a semantic patch which can detect code patterns which can be replaced by struct_size. Note that I set the confidence to medium because this patch doesn't make an attempt to ensure that the relevant array is actually a flexible array. The struct_size macro does specifically require a flexible array. In many cases the detected code could be refactored to a flexible array, but this is not always possible (such as if there are multiple over-allocations). Signed-off-by: Jacob Keller Link: https://lore.kernel.org/r/20230227202428.3657443-1-jacob.e.keller@intel.com Signed-off-by: Kees Cook --- scripts/coccinelle/misc/struct_size.cocci | 74 +++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 scripts/coccinelle/misc/struct_size.cocci (limited to 'scripts') diff --git a/scripts/coccinelle/misc/struct_size.cocci b/scripts/coccinelle/misc/struct_size.cocci new file mode 100644 index 000000000000..9b02c37438e4 --- /dev/null +++ b/scripts/coccinelle/misc/struct_size.cocci @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +/// +/// Check for code that could use struct_size(). +/// +// Confidence: Medium +// Author: Jacob Keller +// Copyright: (C) 2023 Intel Corporation +// Options: --no-includes --include-headers + +virtual patch +virtual context +virtual org +virtual report + +// the overflow Kunit tests have some code which intentionally does not use +// the macros, so we want to ignore this code when reporting potential +// issues. +@overflow_tests@ +identifier f = overflow_size_helpers_test; +@@ + +f + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on !overflow_tests && context@ +expression E1, E2; +identifier m; +@@ +( +* (sizeof(*E1) + (E2 * sizeof(*E1->m))) +) + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on !overflow_tests && patch@ +expression E1, E2; +identifier m; +@@ +( +- (sizeof(*E1) + (E2 * sizeof(*E1->m))) ++ struct_size(E1, m, E2) +) + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on !overflow_tests && (org || report)@ +expression E1, E2; +identifier m; +position p; +@@ +( + (sizeof(*E1)@p + (E2 * sizeof(*E1->m))) +) + +@script:python depends on org@ +p << r.p; +@@ + +coccilib.org.print_todo(p[0], "WARNING should use struct_size") + +@script:python depends on report@ +p << r.p; +@@ + +msg="WARNING: Use struct_size" +coccilib.report.print_report(p[0], msg) + -- cgit v1.2.3 From 1b1bcbf454f8e422c1e8e36bb21d726c39833576 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 22 Feb 2024 14:00:49 -0800 Subject: leaking_addresses: Use File::Temp for /tmp files Instead of using a statically named path in /tmp, use File::Temp to create (and remove) the temporary file used for parsing /proc/config.gz. Reviewed-by: Tycho Andersen Link: https://lore.kernel.org/r/20240222220053.1475824-2-keescook@chromium.org Signed-off-by: Kees Cook --- scripts/leaking_addresses.pl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl index e695634d153d..dd05fbcf15c5 100755 --- a/scripts/leaking_addresses.pl +++ b/scripts/leaking_addresses.pl @@ -23,6 +23,7 @@ use strict; use POSIX; use File::Basename; use File::Spec; +use File::Temp qw/tempfile/; use Cwd 'abs_path'; use Term::ANSIColor qw(:constants); use Getopt::Long qw(:config no_auto_abbrev); @@ -221,6 +222,7 @@ sub get_kernel_config_option { my ($option) = @_; my $value = ""; + my $tmp_fh; my $tmp_file = ""; my @config_files; @@ -228,7 +230,8 @@ sub get_kernel_config_option if ($kernel_config_file ne "") { @config_files = ($kernel_config_file); } elsif (-R "/proc/config.gz") { - my $tmp_file = "/tmp/tmpkconf"; + ($tmp_fh, $tmp_file) = tempfile("config.gz-XXXXXX", + UNLINK => 1); if (system("gunzip < /proc/config.gz > $tmp_file")) { dprint("system(gunzip < /proc/config.gz) failed\n"); @@ -250,10 +253,6 @@ sub get_kernel_config_option } } - if ($tmp_file ne "") { - system("rm -f $tmp_file"); - } - return $value; } -- cgit v1.2.3 From 3e389d457badb1dc07f9fb3197bd7cb5c2833e36 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 22 Feb 2024 14:00:50 -0800 Subject: leaking_addresses: Ignore input device status lines These are false positives from the input subsystem: /proc/bus/input/devices: B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe /sys/devices/platform/i8042/serio0/input/input1/uevent: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe /sys/devices/platform/i8042/serio0/input/input1/capabilities/key: 402000000 3803078f800d001 feffffdf Pass in the filename for more context and expand the "ignored pattern" matcher to notice these. Reviewed-by: Tycho Andersen Link: https://lore.kernel.org/r/20240222220053.1475824-3-keescook@chromium.org Signed-off-by: Kees Cook --- scripts/leaking_addresses.pl | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'scripts') diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl index dd05fbcf15c5..73cfcc5c8854 100755 --- a/scripts/leaking_addresses.pl +++ b/scripts/leaking_addresses.pl @@ -284,9 +284,10 @@ sub is_false_positive return is_false_positive_32bit($match); } - # 64 bit false positives. - - if ($match =~ '\b(0x)?(f|F){16}\b' or + # Ignore 64 bit false positives: + # 0xfffffffffffffff[0-f] + # 0x0000000000000000 + if ($match =~ '\b(0x)?(f|F){15}[0-9a-f]\b' or $match =~ '\b(0x)?0{16}\b') { return 1; } @@ -303,7 +304,7 @@ sub is_false_positive_32bit my ($match) = @_; state $page_offset = get_page_offset(); - if ($match =~ '\b(0x)?(f|F){8}\b') { + if ($match =~ '\b(0x)?(f|F){7}[0-9a-f]\b') { return 1; } @@ -346,18 +347,23 @@ sub is_in_vsyscall_memory_region # True if argument potentially contains a kernel address. sub may_leak_address { - my ($line) = @_; + my ($path, $line) = @_; my $address_re; - # Signal masks. + # Ignore Signal masks. if ($line =~ '^SigBlk:' or $line =~ '^SigIgn:' or $line =~ '^SigCgt:') { return 0; } - if ($line =~ '\bKEY=[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or - $line =~ '\b[[:xdigit:]]{14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b') { + # Ignore input device reporting. + # /proc/bus/input/devices: B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe + # /sys/devices/platform/i8042/serio0/input/input1/uevent: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe + # /sys/devices/platform/i8042/serio0/input/input1/capabilities/key: 402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe + if ($line =~ '\bKEY=[[:xdigit:]]{9,14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b' or + ($path =~ '\bkey$' and + $line =~ '\b[[:xdigit:]]{9,14} [[:xdigit:]]{16} [[:xdigit:]]{16}\b')) { return 0; } @@ -400,7 +406,7 @@ sub parse_dmesg { open my $cmd, '-|', 'dmesg'; while (<$cmd>) { - if (may_leak_address($_)) { + if (may_leak_address("dmesg", $_)) { print 'dmesg: ' . $_; } } @@ -456,7 +462,7 @@ sub parse_file open my $fh, "<", $file or return; while ( <$fh> ) { chomp; - if (may_leak_address($_)) { + if (may_leak_address($file, $_)) { printf("$file: $_\n"); } } @@ -468,7 +474,7 @@ sub check_path_for_leaks { my ($path) = @_; - if (may_leak_address($path)) { + if (may_leak_address($path, $path)) { printf("Path name may contain address: $path\n"); } } -- cgit v1.2.3 From 67bbd2f00735d7f5ad6c3d08eff6c5403c3a9c33 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 22 Feb 2024 14:00:51 -0800 Subject: leaking_addresses: Provide mechanism to scan binary files Introduce --kallsyms argument for scanning binary files for known symbol addresses. This would have found the exposure in /sys/kernel/notes: $ scripts/leaking_addresses.pl --kallsyms=<(sudo cat /proc/kallsyms) /sys/kernel/notes: hypercall_page @ 156 /sys/kernel/notes: xen_hypercall_set_trap_table @ 156 /sys/kernel/notes: startup_xen @ 132 Acked-by: Greg Kroah-Hartman Reviewed-by: Tycho Andersen Link: https://lore.kernel.org/r/20240222220053.1475824-4-keescook@chromium.org Signed-off-by: Kees Cook --- scripts/leaking_addresses.pl | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'scripts') diff --git a/scripts/leaking_addresses.pl b/scripts/leaking_addresses.pl index 73cfcc5c8854..8e992b18bcd9 100755 --- a/scripts/leaking_addresses.pl +++ b/scripts/leaking_addresses.pl @@ -52,10 +52,13 @@ my $input_raw = ""; # Read raw results from file instead of scanning. my $suppress_dmesg = 0; # Don't show dmesg in output. my $squash_by_path = 0; # Summary report grouped by absolute path. my $squash_by_filename = 0; # Summary report grouped by filename. +my $kallsyms_file = ""; # Kernel symbols file. my $kernel_config_file = ""; # Kernel configuration file. my $opt_32bit = 0; # Scan 32-bit kernel. my $page_offset_32bit = 0; # Page offset for 32-bit kernel. +my @kallsyms = (); + # Skip these absolute paths. my @skip_abs = ( '/proc/kmsg', @@ -96,6 +99,8 @@ Options: --squash-by-path Show one result per unique path. --squash-by-filename Show one result per unique filename. --kernel-config-file= Kernel configuration file (e.g /boot/config) + --kallsyms= Read kernel symbol addresses from file (for + scanning binary files). --32-bit Scan 32-bit kernel. --page-offset-32-bit=o Page offset (for 32-bit kernel 0xABCD1234). -d, --debug Display debugging output. @@ -116,6 +121,7 @@ GetOptions( 'squash-by-path' => \$squash_by_path, 'squash-by-filename' => \$squash_by_filename, 'raw' => \$raw, + 'kallsyms=s' => \$kallsyms_file, 'kernel-config-file=s' => \$kernel_config_file, '32-bit' => \$opt_32bit, 'page-offset-32-bit=o' => \$page_offset_32bit, @@ -156,6 +162,25 @@ if ($output_raw) { select $fh; } +if ($kallsyms_file) { + open my $fh, '<', $kallsyms_file or die "$0: $kallsyms_file: $!\n"; + while (<$fh>) { + chomp; + my @entry = split / /, $_; + my $addr_text = $entry[0]; + if ($addr_text !~ /^0/) { + # TODO: Why is hex() so impossibly slow? + my $addr = hex($addr_text); + my $symbol = $entry[2]; + # Only keep kernel text addresses. + my $long = pack("J", $addr); + my $entry = [$long, $symbol]; + push @kallsyms, $entry; + } + } + close $fh; +} + parse_dmesg(); walk(@DIRS); @@ -447,6 +472,25 @@ sub timed_parse_file } } +sub parse_binary +{ + my ($file) = @_; + + open my $fh, "<:raw", $file or return; + local $/ = undef; + my $bytes = <$fh>; + close $fh; + + foreach my $entry (@kallsyms) { + my $addr = $entry->[0]; + my $symbol = $entry->[1]; + my $offset = index($bytes, $addr); + if ($offset != -1) { + printf("$file: $symbol @ $offset\n"); + } + } +} + sub parse_file { my ($file) = @_; @@ -456,6 +500,15 @@ sub parse_file } if (! -T $file) { + if ($file =~ m|^/sys/kernel/btf/| or + $file =~ m|^/sys/devices/pci| or + $file =~ m|^/sys/firmware/efi/efivars/| or + $file =~ m|^/proc/bus/pci/|) { + return; + } + if (scalar @kallsyms > 0) { + parse_binary($file); + } return; } -- cgit v1.2.3 From b31274d58d2156cf884551426ec51315b7cc1ac9 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Fri, 1 Mar 2024 15:18:00 +0100 Subject: docs: drop the version constraints for sphinx and dependencies As discussed (see Links), there is some inertia to move to the recent Sphinx versions for the doc build environment. As first step, drop the version constraints and the related comments. As sphinx depends on jinja2, jinja2 is pulled in automatically. So drop that. Then, the sphinx-pre-install script will fail though with: Can't get default sphinx version from ./Documentation/sphinx/requirements.txt at ./scripts/sphinx-pre-install line 305. The script simply expects to parse a version constraint with Sphinx in the requirements.txt. That version is used in the script for suggesting the virtualenv directory name. To suggest a virtualenv directory name, when there is no version given in the requirements.txt, one could try to guess the version that would be downloaded with 'pip install -r Documentation/sphinx/requirements.txt'. However, there seems no simple way to get that version without actually setting up the venv and running pip. So, instead, name the directory with the fixed name 'sphinx_latest'. Finally update the Sphinx build documentation to reflect this directory name change. Link: https://lore.kernel.org/linux-doc/874jf4m384.fsf@meer.lwn.net/ Link: https://lore.kernel.org/linux-doc/20240226093854.47830-1-lukas.bulwahn@gmail.com/ Reviewed-by: Akira Yokosawa Tested-by: Vegard Nossum Signed-off-by: Lukas Bulwahn Signed-off-by: Jonathan Corbet Message-ID: <20240301141800.30218-1-lukas.bulwahn@gmail.com> --- Documentation/doc-guide/sphinx.rst | 11 ++++++----- Documentation/sphinx/requirements.txt | 7 ++----- scripts/sphinx-pre-install | 19 +++---------------- 3 files changed, 11 insertions(+), 26 deletions(-) (limited to 'scripts') diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst index 709e19821a16..8081ebfe48bc 100644 --- a/Documentation/doc-guide/sphinx.rst +++ b/Documentation/doc-guide/sphinx.rst @@ -48,13 +48,14 @@ or ``virtualenv``, depending on how your distribution packaged Python 3. on the Sphinx version, it should be installed separately, with ``pip install sphinx_rtd_theme``. -In summary, if you want to install Sphinx version 2.4.4, you should do:: +In summary, if you want to install the latest version of Sphinx, you +should do:: - $ virtualenv sphinx_2.4.4 - $ . sphinx_2.4.4/bin/activate - (sphinx_2.4.4) $ pip install -r Documentation/sphinx/requirements.txt + $ virtualenv sphinx_latest + $ . sphinx_latest/bin/activate + (sphinx_latest) $ pip install -r Documentation/sphinx/requirements.txt -After running ``. sphinx_2.4.4/bin/activate``, the prompt will change, +After running ``. sphinx_latest/bin/activate``, the prompt will change, in order to indicate that you're using the new environment. If you open a new shell, you need to rerun this command to enter again at the virtual environment before building the documentation. diff --git a/Documentation/sphinx/requirements.txt b/Documentation/sphinx/requirements.txt index 5d47ed443949..5017f307c8a4 100644 --- a/Documentation/sphinx/requirements.txt +++ b/Documentation/sphinx/requirements.txt @@ -1,6 +1,3 @@ -# jinja2>=3.1 is not compatible with Sphinx<4.0 -jinja2<3.1 -# alabaster>=0.7.14 is not compatible with Sphinx<=3.3 -alabaster<0.7.14 -Sphinx==2.4.4 +alabaster +Sphinx pyyaml diff --git a/scripts/sphinx-pre-install b/scripts/sphinx-pre-install index de0de5dd676e..4c781617ffe6 100755 --- a/scripts/sphinx-pre-install +++ b/scripts/sphinx-pre-install @@ -280,8 +280,6 @@ sub get_sphinx_version($) sub check_sphinx() { - my $default_version; - open IN, $conf or die "Can't open $conf"; while () { if (m/^\s*needs_sphinx\s*=\s*[\'\"]([\d\.]+)[\'\"]/) { @@ -293,18 +291,7 @@ sub check_sphinx() die "Can't get needs_sphinx version from $conf" if (!$min_version); - open IN, $requirement_file or die "Can't open $requirement_file"; - while () { - if (m/^\s*Sphinx\s*==\s*([\d\.]+)$/) { - $default_version=$1; - last; - } - } - close IN; - - die "Can't get default sphinx version from $requirement_file" if (!$default_version); - - $virtenv_dir = $virtenv_prefix . $default_version; + $virtenv_dir = $virtenv_prefix . "latest"; my $sphinx = get_sphinx_fname(); if ($sphinx eq "") { @@ -318,8 +305,8 @@ sub check_sphinx() die "$sphinx didn't return its version" if (!$cur_version); if ($cur_version lt $min_version) { - printf "ERROR: Sphinx version is %s. It should be >= %s (recommended >= %s)\n", - $cur_version, $min_version, $default_version; + printf "ERROR: Sphinx version is %s. It should be >= %s\n", + $cur_version, $min_version; $need_sphinx = 1; return; } -- cgit v1.2.3 From d3e5bab923d35f73c74f6dbbb761988d4f58f878 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 26 Feb 2024 17:14:12 +0100 Subject: arch: simplify architecture specific page size configuration arc, arm64, parisc and powerpc all have their own Kconfig symbols in place of the common CONFIG_PAGE_SIZE_4KB symbols. Change these so the common symbols are the ones that are actually used, while leaving the arhcitecture specific ones as the user visible place for configuring it, to avoid breaking user configs. Reviewed-by: Christophe Leroy (powerpc32) Acked-by: Catalin Marinas Acked-by: Helge Deller # parisc Reviewed-by: Thomas Gleixner Signed-off-by: Arnd Bergmann --- arch/arc/Kconfig | 3 +++ arch/arc/include/uapi/asm/page.h | 6 ++---- arch/arm64/Kconfig | 29 +++++++++++++---------------- arch/arm64/include/asm/page-def.h | 2 +- arch/parisc/Kconfig | 3 +++ arch/parisc/include/asm/page.h | 10 +--------- arch/powerpc/Kconfig | 31 ++++++------------------------- arch/powerpc/include/asm/page.h | 2 +- scripts/gdb/linux/constants.py.in | 2 +- scripts/gdb/linux/mm.py | 2 +- 10 files changed, 32 insertions(+), 58 deletions(-) (limited to 'scripts') diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 1b0483c51cc1..4092bec198be 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -284,14 +284,17 @@ choice config ARC_PAGE_SIZE_8K bool "8KB" + select HAVE_PAGE_SIZE_8KB help Choose between 8k vs 16k config ARC_PAGE_SIZE_16K + select HAVE_PAGE_SIZE_16KB bool "16KB" config ARC_PAGE_SIZE_4K bool "4KB" + select HAVE_PAGE_SIZE_4KB depends on ARC_MMU_V3 || ARC_MMU_V4 endchoice diff --git a/arch/arc/include/uapi/asm/page.h b/arch/arc/include/uapi/asm/page.h index 2a4ad619abfb..7fd9e741b527 100644 --- a/arch/arc/include/uapi/asm/page.h +++ b/arch/arc/include/uapi/asm/page.h @@ -13,10 +13,8 @@ #include /* PAGE_SHIFT determines the page size */ -#if defined(CONFIG_ARC_PAGE_SIZE_16K) -#define PAGE_SHIFT 14 -#elif defined(CONFIG_ARC_PAGE_SIZE_4K) -#define PAGE_SHIFT 12 +#ifdef __KERNEL__ +#define PAGE_SHIFT CONFIG_PAGE_SHIFT #else /* * Default 8k diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index aa7c1d435139..29290b8cb36d 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -277,27 +277,21 @@ config 64BIT config MMU def_bool y -config ARM64_PAGE_SHIFT - int - default 16 if ARM64_64K_PAGES - default 14 if ARM64_16K_PAGES - default 12 - config ARM64_CONT_PTE_SHIFT int - default 5 if ARM64_64K_PAGES - default 7 if ARM64_16K_PAGES + default 5 if PAGE_SIZE_64KB + default 7 if PAGE_SIZE_16KB default 4 config ARM64_CONT_PMD_SHIFT int - default 5 if ARM64_64K_PAGES - default 5 if ARM64_16K_PAGES + default 5 if PAGE_SIZE_64KB + default 5 if PAGE_SIZE_16KB default 4 config ARCH_MMAP_RND_BITS_MIN - default 14 if ARM64_64K_PAGES - default 16 if ARM64_16K_PAGES + default 14 if PAGE_SIZE_64KB + default 16 if PAGE_SIZE_16KB default 18 # max bits determined by the following formula: @@ -1259,11 +1253,13 @@ choice config ARM64_4K_PAGES bool "4KB" + select HAVE_PAGE_SIZE_4KB help This feature enables 4KB pages support. config ARM64_16K_PAGES bool "16KB" + select HAVE_PAGE_SIZE_16KB help The system will use 16KB pages support. AArch32 emulation requires applications compiled with 16K (or a multiple of 16K) @@ -1271,6 +1267,7 @@ config ARM64_16K_PAGES config ARM64_64K_PAGES bool "64KB" + select HAVE_PAGE_SIZE_64KB help This feature enables 64KB pages support (4KB by default) allowing only two levels of page tables and faster TLB @@ -1291,19 +1288,19 @@ choice config ARM64_VA_BITS_36 bool "36-bit" if EXPERT - depends on ARM64_16K_PAGES + depends on PAGE_SIZE_16KB config ARM64_VA_BITS_39 bool "39-bit" - depends on ARM64_4K_PAGES + depends on PAGE_SIZE_4KB config ARM64_VA_BITS_42 bool "42-bit" - depends on ARM64_64K_PAGES + depends on PAGE_SIZE_64KB config ARM64_VA_BITS_47 bool "47-bit" - depends on ARM64_16K_PAGES + depends on PAGE_SIZE_16KB config ARM64_VA_BITS_48 bool "48-bit" diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h index 2403f7b4cdbf..792e9fe881dc 100644 --- a/arch/arm64/include/asm/page-def.h +++ b/arch/arm64/include/asm/page-def.h @@ -11,7 +11,7 @@ #include /* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_ARM64_PAGE_SHIFT +#define PAGE_SHIFT CONFIG_PAGE_SHIFT #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 5c845e8d59d9..b180e684fa0d 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -273,6 +273,7 @@ choice config PARISC_PAGE_SIZE_4KB bool "4KB" + select HAVE_PAGE_SIZE_4KB help This lets you select the page size of the kernel. For best performance, a page size of 16KB is recommended. For best @@ -288,10 +289,12 @@ config PARISC_PAGE_SIZE_4KB config PARISC_PAGE_SIZE_16KB bool "16KB" + select HAVE_PAGE_SIZE_16KB depends on PA8X00 && BROKEN && !KFENCE config PARISC_PAGE_SIZE_64KB bool "64KB" + select HAVE_PAGE_SIZE_64KB depends on PA8X00 && BROKEN && !KFENCE endchoice diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h index 667e703c0e8f..ad4e15d12ed1 100644 --- a/arch/parisc/include/asm/page.h +++ b/arch/parisc/include/asm/page.h @@ -4,15 +4,7 @@ #include -#if defined(CONFIG_PARISC_PAGE_SIZE_4KB) -# define PAGE_SHIFT 12 -#elif defined(CONFIG_PARISC_PAGE_SIZE_16KB) -# define PAGE_SHIFT 14 -#elif defined(CONFIG_PARISC_PAGE_SIZE_64KB) -# define PAGE_SHIFT 16 -#else -# error "unknown default kernel page size" -#endif +#define PAGE_SHIFT CONFIG_PAGE_SHIFT #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b9fc064d38d2..8fad4e5d7ad5 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -212,7 +212,7 @@ config PPC select HAVE_ARCH_HUGE_VMAP if PPC_RADIX_MMU || PPC_8xx select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE - select HAVE_ARCH_KASAN if PPC32 && PPC_PAGE_SHIFT <= 14 + select HAVE_ARCH_KASAN if PPC32 && PAGE_SHIFT <= 14 select HAVE_ARCH_KASAN if PPC_RADIX_MMU select HAVE_ARCH_KASAN if PPC_BOOK3E_64 select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN @@ -809,19 +809,23 @@ choice config PPC_4K_PAGES bool "4k page size" select HAVE_ARCH_SOFT_DIRTY if PPC_BOOK3S_64 + select HAVE_PAGE_SIZE_4KB config PPC_16K_PAGES bool "16k page size" depends on 44x || PPC_8xx + select HAVE_PAGE_SIZE_16KB config PPC_64K_PAGES bool "64k page size" depends on 44x || PPC_BOOK3S_64 select HAVE_ARCH_SOFT_DIRTY if PPC_BOOK3S_64 + select HAVE_PAGE_SIZE_64KB config PPC_256K_PAGES bool "256k page size (Requires non-standard binutils settings)" depends on 44x && !PPC_47x + select HAVE_PAGE_SIZE_256KB help Make the page size 256k. @@ -832,29 +836,6 @@ config PPC_256K_PAGES endchoice -config PAGE_SIZE_4KB - def_bool y - depends on PPC_4K_PAGES - -config PAGE_SIZE_16KB - def_bool y - depends on PPC_16K_PAGES - -config PAGE_SIZE_64KB - def_bool y - depends on PPC_64K_PAGES - -config PAGE_SIZE_256KB - def_bool y - depends on PPC_256K_PAGES - -config PPC_PAGE_SHIFT - int - default 18 if PPC_256K_PAGES - default 16 if PPC_64K_PAGES - default 14 if PPC_16K_PAGES - default 12 - config THREAD_SHIFT int "Thread shift" if EXPERT range 13 15 @@ -891,7 +872,7 @@ config DATA_SHIFT default 23 if (DEBUG_PAGEALLOC || KFENCE) && PPC_8xx && PIN_TLB_DATA default 19 if (DEBUG_PAGEALLOC || KFENCE) && PPC_8xx default 24 if STRICT_KERNEL_RWX && PPC_85xx - default PPC_PAGE_SHIFT + default PAGE_SHIFT help On Book3S 32 (603+), DBATs are used to map kernel text and rodata RO. Smaller is the alignment, greater is the number of necessary DBATs. diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index e5fcc79b5bfb..e411e5a70ea3 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -21,7 +21,7 @@ * page size. When using 64K pages however, whether we are really supporting * 64K pages in HW or not is irrelevant to those definitions. */ -#define PAGE_SHIFT CONFIG_PPC_PAGE_SHIFT +#define PAGE_SHIFT CONFIG_PAGE_SHIFT #define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) #ifndef __ASSEMBLY__ diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in index e810e0c27ff1..10fadc238719 100644 --- a/scripts/gdb/linux/constants.py.in +++ b/scripts/gdb/linux/constants.py.in @@ -139,7 +139,7 @@ LX_CONFIG(CONFIG_ARM64_64K_PAGES) if IS_BUILTIN(CONFIG_ARM64): LX_VALUE(CONFIG_ARM64_PA_BITS) LX_VALUE(CONFIG_ARM64_VA_BITS) - LX_VALUE(CONFIG_ARM64_PAGE_SHIFT) + LX_VALUE(CONFIG_PAGE_SHIFT) LX_VALUE(CONFIG_ARCH_FORCE_MAX_ORDER) LX_CONFIG(CONFIG_SPARSEMEM) LX_CONFIG(CONFIG_SPARSEMEM_EXTREME) diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py index ad5641dcb068..515730fd4c9d 100644 --- a/scripts/gdb/linux/mm.py +++ b/scripts/gdb/linux/mm.py @@ -41,7 +41,7 @@ class aarch64_page_ops(): self.SECTION_SIZE_BITS = 27 self.MAX_PHYSMEM_BITS = constants.LX_CONFIG_ARM64_VA_BITS - self.PAGE_SHIFT = constants.LX_CONFIG_ARM64_PAGE_SHIFT + self.PAGE_SHIFT = constants.LX_CONFIG_PAGE_SHIFT self.PAGE_SIZE = 1 << self.PAGE_SHIFT self.PAGE_MASK = (~(self.PAGE_SIZE - 1)) & ((1 << 64) - 1) -- cgit v1.2.3 From 3606422a28593a33fc7d3b7e25c73bf9688194c6 Mon Sep 17 00:00:00 2001 From: Ricardo B. Marliere Date: Sun, 18 Feb 2024 16:25:51 -0300 Subject: const_structs.checkpatch: add device_type Since commit aed65af1cc2f ("drivers: make device_type const"), the driver core can properly handle constant struct device_type. Make sure that new usages of the struct already enter the tree as const. Link: https://lkml.kernel.org/r/20240218-device_cleanup-checkpatch-v1-1-8b0b89c4f6b1@marliere.net Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Cc: Joe Perches Signed-off-by: Andrew Morton --- scripts/const_structs.checkpatch | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index 7427313adc7a..fa96cfd16e99 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -8,6 +8,7 @@ comedi_lrange component_ops dentry_operations dev_pm_ops +device_type dma_map_ops driver_info drm_connector_funcs -- cgit v1.2.3 From e0492219a6d752942b054cbfbbcbc1e8ab294d26 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 3 Mar 2024 13:00:33 +0900 Subject: kconfig: link menus to a symbol Currently, there is no direct link from (struct symbol) to (struct menu). It is still possible to access associated menus through the P_SYMBOL property, because property::menu is the relevant menu entry, but it results in complex code, as seen in get_symbol_str(). Use a linked list for simpler traversal of relevant menus. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/kconfig/expr.h | 5 +++++ scripts/kconfig/menu.c | 4 +++- scripts/kconfig/symbol.c | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 3bc375f1a1cd..0158f5eac454 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -108,6 +108,9 @@ struct symbol { */ tristate visible; + /* config entries associated with this symbol */ + struct list_head menus; + /* SYMBOL_* flags */ int flags; @@ -222,6 +225,8 @@ struct menu { */ struct symbol *sym; + struct list_head link; /* link to symbol::menus */ + /* * The prompt associated with the node. This holds the prompt for a * symbol as well as the text for a menu or comment, along with the diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 44465945d6b1..571394ed71e0 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -57,8 +57,10 @@ void menu_add_entry(struct symbol *sym) *last_entry_ptr = menu; last_entry_ptr = &menu->next; current_entry = menu; - if (sym) + if (sym) { menu_add_symbol(P_SYMBOL, sym, NULL); + list_add_tail(&menu->link, &sym->menus); + } } struct menu *menu_add_menu(void) diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index dd5cf9727a9a..81fe1884ef8a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -15,18 +15,21 @@ struct symbol symbol_yes = { .name = "y", .curr = { "y", yes }, + .menus = LIST_HEAD_INIT(symbol_yes.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; struct symbol symbol_mod = { .name = "m", .curr = { "m", mod }, + .menus = LIST_HEAD_INIT(symbol_mod.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; struct symbol symbol_no = { .name = "n", .curr = { "n", no }, + .menus = LIST_HEAD_INIT(symbol_no.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; @@ -838,6 +841,7 @@ struct symbol *sym_lookup(const char *name, int flags) symbol->name = new_name; symbol->type = S_UNKNOWN; symbol->flags = flags; + INIT_LIST_HEAD(&symbol->menus); hash_add(sym_hashtable, &symbol->node, hash); -- cgit v1.2.3 From bedf92362317adff1da6ac787b09626d30e60b00 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 3 Mar 2024 13:00:34 +0900 Subject: kconfig: use linked list in get_symbol_str() to iterate over menus Currently, get_symbol_str() uses a tricky approach to traverse the associated menus. With relevant menus now linked to the symbol using a linked list, use list_for_each_entry() for iterating on the menus. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- scripts/kconfig/menu.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 571394ed71e0..840ce642ec43 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -771,6 +771,7 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, struct list_head *head) { struct property *prop; + struct menu *menu; if (sym && sym->name) { str_printf(r, "Symbol: %s [=%s]\n", sym->name, @@ -787,17 +788,17 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, } /* Print the definitions with prompts before the ones without */ - for_all_properties(sym, prop, P_SYMBOL) { - if (prop->menu->prompt) { - get_def_str(r, prop->menu); - get_prompt_str(r, prop->menu->prompt, head); + list_for_each_entry(menu, &sym->menus, link) { + if (menu->prompt) { + get_def_str(r, menu); + get_prompt_str(r, menu->prompt, head); } } - for_all_properties(sym, prop, P_SYMBOL) { - if (!prop->menu->prompt) { - get_def_str(r, prop->menu); - get_dep_str(r, prop->menu->dep, " Depends on: "); + list_for_each_entry(menu, &sym->menus, link) { + if (!menu->prompt) { + get_def_str(r, menu); + get_dep_str(r, menu->dep, " Depends on: "); } } -- cgit v1.2.3 From c83f020973bc72d9eec65474d8c47495191aef20 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 3 Mar 2024 13:00:35 +0900 Subject: kconfig: remove named choice support Commit 5a1aa8a1aff6 ("kconfig: add named choice group") did not provide enough explanation regarding its benefits. A use case was found in another project [1] sometime later, this feature has never been used in the kernel. [1]: https://lore.kernel.org/all/201012150034.01356.yann.morin.1998@anciens.enib.fr/ Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Documentation/kbuild/kconfig-language.rst | 6 +----- scripts/kconfig/parser.y | 10 +++------- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'scripts') diff --git a/Documentation/kbuild/kconfig-language.rst b/Documentation/kbuild/kconfig-language.rst index 0135905c0aa3..79ac2e8184f6 100644 --- a/Documentation/kbuild/kconfig-language.rst +++ b/Documentation/kbuild/kconfig-language.rst @@ -393,7 +393,7 @@ of C0, which doesn't depend on M:: choices:: - "choice" [symbol] + "choice" "endchoice" @@ -412,10 +412,6 @@ the kernel, but all drivers can be compiled as modules. A choice accepts another option "optional", which allows to set the choice to 'n' and no entry needs to be selected. -If no [symbol] is associated with a choice, then you can not have multiple -definitions of that choice. If a [symbol] is associated to the choice, -then you may define the same choice (i.e. with the same entries) in another -place. comment:: diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index b505e43e0d02..22f616334585 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -94,7 +94,7 @@ struct menu *current_menu, *current_entry; %type if_expr %type end %type if_entry menu_entry choice_entry -%type word_opt assign_val +%type assign_val %type assign_op %destructor { @@ -222,13 +222,12 @@ config_option: T_MODULES T_EOL /* choice entry */ -choice: T_CHOICE word_opt T_EOL +choice: T_CHOICE T_EOL { - struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); + struct symbol *sym = sym_lookup(NULL, SYMBOL_CHOICE); sym->flags |= SYMBOL_NO_WRITE; menu_add_entry(sym); menu_add_expr(P_CHOICE, NULL, NULL); - free($2); printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno); }; @@ -449,9 +448,6 @@ symbol: nonconst_symbol | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } ; -word_opt: /* empty */ { $$ = NULL; } - | T_WORD - /* assignment statement */ assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); } -- cgit v1.2.3 From 75b5ab134bb5f657ef7979a59106dce0657e8d87 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 5 Mar 2024 15:12:47 -0700 Subject: kbuild: Move -Wenum-{compare-conditional,enum-conversion} into W=1 Clang enables -Wenum-enum-conversion and -Wenum-compare-conditional under -Wenum-conversion. A recent change in Clang strengthened these warnings and they appear frequently in common builds, primarily due to several instances in common headers but there are quite a few drivers that have individual instances as well. include/linux/vmstat.h:508:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion] 508 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS + | ~~~~~~~~~~~~~~~~~~~~~ ^ 509 | item]; | ~~~~ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c:955:24: warning: conditional expression between different enumeration types ('enum iwl_mac_beacon_flags' and 'enum iwl_mac_beacon_flags_v1') [-Wenum-compare-conditional] 955 | flags |= is_new_rate ? IWL_MAC_BEACON_CCK | ^ ~~~~~~~~~~~~~~~~~~ 956 | : IWL_MAC_BEACON_CCK_V1; | ~~~~~~~~~~~~~~~~~~~~~ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c:1120:21: warning: conditional expression between different enumeration types ('enum iwl_mac_beacon_flags' and 'enum iwl_mac_beacon_flags_v1') [-Wenum-compare-conditional] 1120 | 0) > 10 ? | ^ 1121 | IWL_MAC_BEACON_FILS : | ~~~~~~~~~~~~~~~~~~~ 1122 | IWL_MAC_BEACON_FILS_V1; | ~~~~~~~~~~~~~~~~~~~~~~ Doing arithmetic between or returning two different types of enums could be a bug, so each of the instance of the warning needs to be evaluated. Unfortunately, as mentioned above, there are many instances of this warning in many different configurations, which can break the build when CONFIG_WERROR is enabled. To avoid introducing new instances of the warnings while cleaning up the disruption for the majority of users, disable these warnings for the default build while leaving them on for W=1 builds. Cc: stable@vger.kernel.org Closes: https://github.com/ClangBuiltLinux/linux/issues/2002 Link: https://github.com/llvm/llvm-project/commit/8c2ae42b3e1c6aa7c18f873edcebff7c0b45a37e Acked-by: Yonghong Song Signed-off-by: Nathan Chancellor Acked-by: Arnd Bergmann Signed-off-by: Masahiro Yamada --- scripts/Makefile.extrawarn | 2 ++ 1 file changed, 2 insertions(+) (limited to 'scripts') diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index a9e552a1e910..2f25a1de129d 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -132,6 +132,8 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast) KBUILD_CFLAGS += -Wno-tautological-constant-out-of-range-compare KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access) KBUILD_CFLAGS += $(call cc-disable-warning, cast-function-type-strict) +KBUILD_CFLAGS += -Wno-enum-compare-conditional +KBUILD_CFLAGS += -Wno-enum-enum-conversion endif endif -- cgit v1.2.3 From e2bad142bb3de836c5fbb3dff704578f5a73d8e6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 6 Mar 2024 19:42:22 +0900 Subject: kbuild: unexport abs_srctree and abs_objtree Commit 25b146c5b8ce ("kbuild: allow Kbuild to start from any directory") exported abs_srctree and abs_objtree to avoid recomputation after the sub-make. However, this approach turned out to be fragile. Commit 5fa94ceb793e ("kbuild: set correct abs_srctree and abs_objtree for package builds") moved them above "ifneq ($(sub_make_done),1)", eliminating the need for exporting them. These are only needed in the top Makefile. If an absolute path is required in sub-directories, you can use $(abspath ) or $(realpath ) as needed. Signed-off-by: Masahiro Yamada Reviewed-by: Nicolas Schier --- Makefile | 4 ++-- rust/Makefile | 4 ++-- scripts/Makefile.package | 2 +- tools/lib/bpf/Makefile | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/Makefile b/Makefile index 859b0f52949e..104e62560eed 100644 --- a/Makefile +++ b/Makefile @@ -39,8 +39,8 @@ __all: # prepare rule. this-makefile := $(lastword $(MAKEFILE_LIST)) -export abs_srctree := $(realpath $(dir $(this-makefile))) -export abs_objtree := $(CURDIR) +abs_srctree := $(realpath $(dir $(this-makefile))) +abs_objtree := $(CURDIR) ifneq ($(sub_make_done),1) diff --git a/rust/Makefile b/rust/Makefile index 9d2a16cc91cb..ae691b71d9fc 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -100,7 +100,7 @@ rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \ -e 's:rust-logo-[0-9a-f]+\.svg:logo.svg:g' \ -e 's:favicon-[0-9a-f]+\.svg:logo.svg:g' \ -e 's:::g' \ - -e 's:::g' + -e 's:::g' $(Q)for f in $(rustdoc_output)/static.files/rustdoc-*.css; do \ echo ".logo-container > img { object-fit: contain; }" >> $$f; done @@ -413,7 +413,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L rust-analyzer: $(Q)$(srctree)/scripts/generate_rust_analyzer.py \ --cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \ - $(abs_srctree) $(abs_objtree) \ + $(realpath $(srctree)) $(realpath $(objtree)) \ $(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \ $(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json diff --git a/scripts/Makefile.package b/scripts/Makefile.package index a81dfb1f5181..38653f3e8108 100644 --- a/scripts/Makefile.package +++ b/scripts/Makefile.package @@ -135,7 +135,7 @@ snap-pkg: mkdir $(objtree)/snap $(MAKE) clean sed "s@KERNELRELEASE@$(KERNELRELEASE)@; \ - s@SRCTREE@$(abs_srctree)@" \ + s@SRCTREE@$(realpath $(srctree))@" \ $(srctree)/scripts/package/snapcraft.template > \ $(objtree)/snap/snapcraft.yaml cd $(objtree)/snap && \ diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 4be7144e4803..2cf892774346 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -2,7 +2,7 @@ # Most of this file is copied from tools/lib/traceevent/Makefile RM ?= rm -srctree = $(abs_srctree) +srctree := $(realpath $(srctree)) VERSION_SCRIPT := libbpf.map LIBBPF_VERSION := $(shell \ -- cgit v1.2.3 From 44929bfaceaaa6a854ddc6df6de9433fab1eef92 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 6 Mar 2024 21:47:09 +0900 Subject: kbuild: remove GCC's default -Wpacked-bitfield-compat flag Commit 4a5838ad9d2d ("kbuild: Add extra gcc checks") added the -Wpacked-bitfield-compat flag, but there is no need to add it explicitly. GCC manual says: "This warning is enabled by default. Use -Wno-packed-bitfield-compat to disable this warning." The test code in the manual: struct foo { char a:4; char b:8; } __attribute__ ((packed)); ... emits "note: offset of packed bit-field ‘b’ has changed in GCC 4.4" without W=3. Let's remove it, as it is a default with GCC. Clang does not support this flag, so its removal will not affect Clang builds. Signed-off-by: Masahiro Yamada Reviewed-by: Nathan Chancellor --- scripts/Makefile.extrawarn | 1 - 1 file changed, 1 deletion(-) (limited to 'scripts') diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index 2f25a1de129d..3ce5d503a6da 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -187,7 +187,6 @@ KBUILD_CFLAGS += -Wpointer-arith KBUILD_CFLAGS += -Wredundant-decls KBUILD_CFLAGS += -Wsign-compare KBUILD_CFLAGS += -Wswitch-default -KBUILD_CFLAGS += $(call cc-option, -Wpacked-bitfield-compat) KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN3 -- cgit v1.2.3 From cb8a2ef0848ca80d67d6d56e2df757cfdf6b3355 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Mon, 11 Mar 2024 22:23:47 +0800 Subject: LoongArch: Add ORC stack unwinder support The kernel CONFIG_UNWINDER_ORC option enables the ORC unwinder, which is similar in concept to a DWARF unwinder. The difference is that the format of the ORC data is much simpler than DWARF, which in turn allows the ORC unwinder to be much simpler and faster. The ORC data consists of unwind tables which are generated by objtool. After analyzing all the code paths of a .o file, it determines information about the stack state at each instruction address in the file and outputs that information to the .orc_unwind and .orc_unwind_ip sections. The per-object ORC sections are combined at link time and are sorted and post-processed at boot time. The unwinder uses the resulting data to correlate instruction addresses with their stack states at run time. Most of the logic are similar with x86, in order to get ra info before ra is saved into stack, add ra_reg and ra_offset into orc_entry. At the same time, modify some arch-specific code to silence the objtool warnings. Co-developed-by: Jinyang He Signed-off-by: Jinyang He Co-developed-by: Youling Tang Signed-off-by: Youling Tang Signed-off-by: Tiezhu Yang Signed-off-by: Huacai Chen --- arch/loongarch/Kconfig | 2 + arch/loongarch/Kconfig.debug | 11 + arch/loongarch/Makefile | 23 +- arch/loongarch/include/asm/Kbuild | 2 + arch/loongarch/include/asm/bug.h | 1 + arch/loongarch/include/asm/exception.h | 2 + arch/loongarch/include/asm/module.h | 7 + arch/loongarch/include/asm/orc_header.h | 18 + arch/loongarch/include/asm/orc_lookup.h | 31 ++ arch/loongarch/include/asm/orc_types.h | 58 ++++ arch/loongarch/include/asm/stackframe.h | 3 + arch/loongarch/include/asm/unwind.h | 20 +- arch/loongarch/include/asm/unwind_hints.h | 28 ++ arch/loongarch/kernel/Makefile | 4 + arch/loongarch/kernel/entry.S | 5 + arch/loongarch/kernel/fpu.S | 7 + arch/loongarch/kernel/genex.S | 6 + arch/loongarch/kernel/lbt.S | 3 + arch/loongarch/kernel/mcount_dyn.S | 6 + arch/loongarch/kernel/module.c | 22 +- arch/loongarch/kernel/relocate_kernel.S | 7 +- arch/loongarch/kernel/rethook_trampoline.S | 1 + arch/loongarch/kernel/setup.c | 2 + arch/loongarch/kernel/stacktrace.c | 1 + arch/loongarch/kernel/traps.c | 42 ++- arch/loongarch/kernel/unwind_orc.c | 528 +++++++++++++++++++++++++++++ arch/loongarch/kernel/vmlinux.lds.S | 3 + arch/loongarch/kvm/switch.S | 9 +- arch/loongarch/lib/clear_user.S | 3 + arch/loongarch/lib/copy_user.S | 3 + arch/loongarch/lib/memcpy.S | 3 + arch/loongarch/lib/memset.S | 3 + arch/loongarch/mm/tlb.c | 27 +- arch/loongarch/mm/tlbex.S | 9 + arch/loongarch/vdso/Makefile | 1 + include/linux/compiler.h | 9 + scripts/Makefile | 7 +- 37 files changed, 875 insertions(+), 42 deletions(-) create mode 100644 arch/loongarch/include/asm/orc_header.h create mode 100644 arch/loongarch/include/asm/orc_lookup.h create mode 100644 arch/loongarch/include/asm/orc_types.h create mode 100644 arch/loongarch/include/asm/unwind_hints.h create mode 100644 arch/loongarch/kernel/unwind_orc.c (limited to 'scripts') diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 929f68926b34..8d6725115ac6 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -136,6 +136,7 @@ config LOONGARCH select HAVE_KVM select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI + select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS select HAVE_PCI select HAVE_PERF_EVENTS select HAVE_PERF_REGS @@ -148,6 +149,7 @@ config LOONGARCH select HAVE_SAMPLE_FTRACE_DIRECT select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_SETUP_PER_CPU_AREA if NUMA + select HAVE_STACK_VALIDATION if HAVE_OBJTOOL select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select HAVE_TIF_NOHZ diff --git a/arch/loongarch/Kconfig.debug b/arch/loongarch/Kconfig.debug index 8d36aab53008..98d60630c3d4 100644 --- a/arch/loongarch/Kconfig.debug +++ b/arch/loongarch/Kconfig.debug @@ -26,4 +26,15 @@ config UNWINDER_PROLOGUE Some of the addresses it reports may be incorrect (but better than the Guess unwinder). +config UNWINDER_ORC + bool "ORC unwinder" + select OBJTOOL + help + This option enables the ORC (Oops Rewind Capability) unwinder for + unwinding kernel stack traces. It uses a custom data format which is + a simplified version of the DWARF Call Frame Information standard. + + Enabling this option will increase the kernel's runtime memory usage + by roughly 2-4MB, depending on your kernel config. + endchoice diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index 983aa2b1629a..e3bc02fb7fdc 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -26,6 +26,18 @@ endif 32bit-emul = elf32loongarch 64bit-emul = elf64loongarch +ifdef CONFIG_UNWINDER_ORC +orc_hash_h := arch/$(SRCARCH)/include/generated/asm/orc_hash.h +orc_hash_sh := $(srctree)/scripts/orc_hash.sh +targets += $(orc_hash_h) +quiet_cmd_orc_hash = GEN $@ + cmd_orc_hash = mkdir -p $(dir $@); \ + $(CONFIG_SHELL) $(orc_hash_sh) < $< > $@ +$(orc_hash_h): $(srctree)/arch/loongarch/include/asm/orc_types.h $(orc_hash_sh) FORCE + $(call if_changed,orc_hash) +archprepare: $(orc_hash_h) +endif + ifdef CONFIG_DYNAMIC_FTRACE KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY CC_FLAGS_FTRACE := -fpatchable-function-entry=2 @@ -72,8 +84,6 @@ KBUILD_CFLAGS_KERNEL += $(call cc-option,-mdirect-extern-access) KBUILD_CFLAGS_KERNEL += $(call cc-option,-fdirect-access-external-data) KBUILD_AFLAGS_MODULE += $(call cc-option,-fno-direct-access-external-data) KBUILD_CFLAGS_MODULE += $(call cc-option,-fno-direct-access-external-data) -KBUILD_AFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax) -KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax) else cflags-y += $(call cc-option,-mno-explicit-relocs) KBUILD_AFLAGS_KERNEL += -Wa,-mla-global-with-pcrel @@ -82,6 +92,15 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs endif +KBUILD_AFLAGS += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax) +KBUILD_CFLAGS += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax) +KBUILD_AFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub) +KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub) + +ifdef CONFIG_OBJTOOL +KBUILD_CFLAGS += -fno-jump-tables +endif + KBUILD_RUSTFLAGS_MODULE += -Crelocation-model=pic ifeq ($(CONFIG_RELOCATABLE),y) diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild index 93783fa24f6e..a97c0edbb866 100644 --- a/arch/loongarch/include/asm/Kbuild +++ b/arch/loongarch/include/asm/Kbuild @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +generated-y += orc_hash.h + generic-y += dma-contiguous.h generic-y += mcs_spinlock.h generic-y += parport.h diff --git a/arch/loongarch/include/asm/bug.h b/arch/loongarch/include/asm/bug.h index d4ca3ba25418..08388876ade4 100644 --- a/arch/loongarch/include/asm/bug.h +++ b/arch/loongarch/include/asm/bug.h @@ -44,6 +44,7 @@ do { \ instrumentation_begin(); \ __BUG_FLAGS(BUGFLAG_WARNING|(flags)); \ + annotate_reachable(); \ instrumentation_end(); \ } while (0) diff --git a/arch/loongarch/include/asm/exception.h b/arch/loongarch/include/asm/exception.h index af74a3fdcad1..c6d20736fd92 100644 --- a/arch/loongarch/include/asm/exception.h +++ b/arch/loongarch/include/asm/exception.h @@ -6,6 +6,8 @@ #include #include +extern void *exception_table[]; + void show_registers(struct pt_regs *regs); asmlinkage void cache_parity_error(void); diff --git a/arch/loongarch/include/asm/module.h b/arch/loongarch/include/asm/module.h index 2ecd82bb64e1..f33f3fd32ecc 100644 --- a/arch/loongarch/include/asm/module.h +++ b/arch/loongarch/include/asm/module.h @@ -6,6 +6,7 @@ #define _ASM_MODULE_H #include +#include #include #define RELA_STACK_DEPTH 16 @@ -21,6 +22,12 @@ struct mod_arch_specific { struct mod_section plt; struct mod_section plt_idx; +#ifdef CONFIG_UNWINDER_ORC + unsigned int num_orcs; + int *orc_unwind_ip; + struct orc_entry *orc_unwind; +#endif + /* For CONFIG_DYNAMIC_FTRACE */ struct plt_entry *ftrace_trampolines; }; diff --git a/arch/loongarch/include/asm/orc_header.h b/arch/loongarch/include/asm/orc_header.h new file mode 100644 index 000000000000..f9d509c3fd70 --- /dev/null +++ b/arch/loongarch/include/asm/orc_header.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _ORC_HEADER_H +#define _ORC_HEADER_H + +#include +#include +#include + +/* + * The header is currently a 20-byte hash of the ORC entry definition; see + * scripts/orc_hash.sh. + */ +#define ORC_HEADER \ + __used __section(".orc_header") __aligned(4) \ + static const u8 orc_header[] = { ORC_HASH } + +#endif /* _ORC_HEADER_H */ diff --git a/arch/loongarch/include/asm/orc_lookup.h b/arch/loongarch/include/asm/orc_lookup.h new file mode 100644 index 000000000000..b02e6357def4 --- /dev/null +++ b/arch/loongarch/include/asm/orc_lookup.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _ORC_LOOKUP_H +#define _ORC_LOOKUP_H + +/* + * This is a lookup table for speeding up access to the .orc_unwind table. + * Given an input address offset, the corresponding lookup table entry + * specifies a subset of the .orc_unwind table to search. + * + * Each block represents the end of the previous range and the start of the + * next range. An extra block is added to give the last range an end. + * + * The block size should be a power of 2 to avoid a costly 'div' instruction. + * + * A block size of 256 was chosen because it roughly doubles unwinder + * performance while only adding ~5% to the ORC data footprint. + */ +#define LOOKUP_BLOCK_ORDER 8 +#define LOOKUP_BLOCK_SIZE (1 << LOOKUP_BLOCK_ORDER) + +#ifndef LINKER_SCRIPT + +extern unsigned int orc_lookup[]; +extern unsigned int orc_lookup_end[]; + +#define LOOKUP_START_IP (unsigned long)_stext +#define LOOKUP_STOP_IP (unsigned long)_etext + +#endif /* LINKER_SCRIPT */ + +#endif /* _ORC_LOOKUP_H */ diff --git a/arch/loongarch/include/asm/orc_types.h b/arch/loongarch/include/asm/orc_types.h new file mode 100644 index 000000000000..caf1f71a1057 --- /dev/null +++ b/arch/loongarch/include/asm/orc_types.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _ORC_TYPES_H +#define _ORC_TYPES_H + +#include + +/* + * The ORC_REG_* registers are base registers which are used to find other + * registers on the stack. + * + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the + * address of the previous frame: the caller's SP before it called the current + * function. + * + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in + * the current frame. + * + * The most commonly used base registers are SP and FP -- which the previous SP + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous FP is + * usually based on. + * + * The rest of the base registers are needed for special cases like entry code + * and GCC realigned stacks. + */ +#define ORC_REG_UNDEFINED 0 +#define ORC_REG_PREV_SP 1 +#define ORC_REG_SP 2 +#define ORC_REG_FP 3 +#define ORC_REG_MAX 4 + +#define ORC_TYPE_UNDEFINED 0 +#define ORC_TYPE_END_OF_STACK 1 +#define ORC_TYPE_CALL 2 +#define ORC_TYPE_REGS 3 +#define ORC_TYPE_REGS_PARTIAL 4 + +#ifndef __ASSEMBLY__ +/* + * This struct is more or less a vastly simplified version of the DWARF Call + * Frame Information standard. It contains only the necessary parts of DWARF + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the + * unwinder how to find the previous SP and FP (and sometimes entry regs) on + * the stack for a given code address. Each instance of the struct corresponds + * to one or more code locations. + */ +struct orc_entry { + s16 sp_offset; + s16 fp_offset; + s16 ra_offset; + unsigned int sp_reg:4; + unsigned int fp_reg:4; + unsigned int ra_reg:4; + unsigned int type:3; + unsigned int signal:1; +}; +#endif /* __ASSEMBLY__ */ + +#endif /* _ORC_TYPES_H */ diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h index 4fb1e6408b98..45b507a7b06f 100644 --- a/arch/loongarch/include/asm/stackframe.h +++ b/arch/loongarch/include/asm/stackframe.h @@ -13,6 +13,7 @@ #include #include #include +#include /* Make the addition of cfi info a little easier. */ .macro cfi_rel_offset reg offset=0 docfi=0 @@ -162,6 +163,7 @@ li.w t0, CSR_CRMD_WE csrxchg t0, t0, LOONGARCH_CSR_CRMD #endif + UNWIND_HINT_REGS .endm .macro SAVE_ALL docfi=0 @@ -219,6 +221,7 @@ .macro RESTORE_SP_AND_RET docfi=0 cfi_ld sp, PT_R3, \docfi + UNWIND_HINT_FUNC ertn .endm diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/asm/unwind.h index b9dce87afd2e..40a6763c5aec 100644 --- a/arch/loongarch/include/asm/unwind.h +++ b/arch/loongarch/include/asm/unwind.h @@ -16,6 +16,7 @@ enum unwinder_type { UNWINDER_GUESS, UNWINDER_PROLOGUE, + UNWINDER_ORC, }; struct unwind_state { @@ -24,7 +25,7 @@ struct unwind_state { struct task_struct *task; bool first, error, reset; int graph_idx; - unsigned long sp, pc, ra; + unsigned long sp, fp, pc, ra; }; bool default_next_frame(struct unwind_state *state); @@ -61,14 +62,17 @@ static __always_inline void __unwind_start(struct unwind_state *state, state->sp = regs->regs[3]; state->pc = regs->csr_era; state->ra = regs->regs[1]; + state->fp = regs->regs[22]; } else if (task && task != current) { state->sp = thread_saved_fp(task); state->pc = thread_saved_ra(task); state->ra = 0; + state->fp = 0; } else { state->sp = (unsigned long)__builtin_frame_address(0); state->pc = (unsigned long)__builtin_return_address(0); state->ra = 0; + state->fp = 0; } state->task = task; get_stack_info(state->sp, state->task, &state->stack_info); @@ -77,6 +81,18 @@ static __always_inline void __unwind_start(struct unwind_state *state, static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state) { - return unwind_done(state) ? 0 : state->pc; + if (unwind_done(state)) + return 0; + + return __kernel_text_address(state->pc) ? state->pc : 0; } + +#ifdef CONFIG_UNWINDER_ORC +void unwind_init(void); +void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size); +#else +static inline void unwind_init(void) {} +static inline void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size) {} +#endif + #endif /* _ASM_UNWIND_H */ diff --git a/arch/loongarch/include/asm/unwind_hints.h b/arch/loongarch/include/asm/unwind_hints.h new file mode 100644 index 000000000000..a01086ad9dde --- /dev/null +++ b/arch/loongarch/include/asm/unwind_hints.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_LOONGARCH_UNWIND_HINTS_H +#define _ASM_LOONGARCH_UNWIND_HINTS_H + +#include +#include + +#ifdef __ASSEMBLY__ + +.macro UNWIND_HINT_UNDEFINED + UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED +.endm + +.macro UNWIND_HINT_END_OF_STACK + UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK +.endm + +.macro UNWIND_HINT_REGS + UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_REGS +.endm + +.macro UNWIND_HINT_FUNC + UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index 3c808c680370..3a7620b66bc6 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -3,6 +3,8 @@ # Makefile for the Linux/LoongArch kernel. # +OBJECT_FILES_NON_STANDARD_head.o := y + extra-y := vmlinux.lds obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ @@ -21,6 +23,7 @@ obj-$(CONFIG_ARCH_STRICT_ALIGN) += unaligned.o CFLAGS_module.o += $(call cc-option,-Wno-override-init,) CFLAGS_syscall.o += $(call cc-option,-Wno-override-init,) +CFLAGS_traps.o += $(call cc-option,-Wno-override-init,) CFLAGS_perf_event.o += $(call cc-option,-Wno-override-init,) ifdef CONFIG_FUNCTION_TRACER @@ -62,6 +65,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o +obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S index 1ec8e4c4cc2b..48e7e34e355e 100644 --- a/arch/loongarch/kernel/entry.S +++ b/arch/loongarch/kernel/entry.S @@ -14,11 +14,13 @@ #include #include #include +#include .text .cfi_sections .debug_frame .align 5 SYM_CODE_START(handle_syscall) + UNWIND_HINT_UNDEFINED csrrd t0, PERCPU_BASE_KS la.pcrel t1, kernelsp add.d t1, t1, t0 @@ -57,6 +59,7 @@ SYM_CODE_START(handle_syscall) cfi_st fp, PT_R22 SAVE_STATIC + UNWIND_HINT_REGS #ifdef CONFIG_KGDB li.w t1, CSR_CRMD_WE @@ -75,6 +78,7 @@ SYM_CODE_END(handle_syscall) _ASM_NOKPROBE(handle_syscall) SYM_CODE_START(ret_from_fork) + UNWIND_HINT_REGS bl schedule_tail # a0 = struct task_struct *prev move a0, sp bl syscall_exit_to_user_mode @@ -84,6 +88,7 @@ SYM_CODE_START(ret_from_fork) SYM_CODE_END(ret_from_fork) SYM_CODE_START(ret_from_kernel_thread) + UNWIND_HINT_REGS bl schedule_tail # a0 = struct task_struct *prev move a0, s1 jirl ra, s0, 0 diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S index 4382e36ae3d4..69a85f2479fb 100644 --- a/arch/loongarch/kernel/fpu.S +++ b/arch/loongarch/kernel/fpu.S @@ -15,6 +15,7 @@ #include #include #include +#include #define FPU_REG_WIDTH 8 #define LSX_REG_WIDTH 16 @@ -526,3 +527,9 @@ SYM_FUNC_END(_restore_lasx_context) .L_fpu_fault: li.w a0, -EFAULT # failure jr ra + +#ifdef CONFIG_CPU_HAS_LBT +STACK_FRAME_NON_STANDARD _restore_fp +STACK_FRAME_NON_STANDARD _restore_lsx +STACK_FRAME_NON_STANDARD _restore_lasx +#endif diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S index 2bb3aa2dcfcb..86d5d90ebefe 100644 --- a/arch/loongarch/kernel/genex.S +++ b/arch/loongarch/kernel/genex.S @@ -32,6 +32,7 @@ SYM_FUNC_START(__arch_cpu_idle) SYM_FUNC_END(__arch_cpu_idle) SYM_CODE_START(handle_vint) + UNWIND_HINT_UNDEFINED BACKUP_T0T1 SAVE_ALL la_abs t1, __arch_cpu_idle @@ -49,6 +50,7 @@ SYM_CODE_START(handle_vint) SYM_CODE_END(handle_vint) SYM_CODE_START(except_vec_cex) + UNWIND_HINT_UNDEFINED b cache_parity_error SYM_CODE_END(except_vec_cex) @@ -67,6 +69,7 @@ SYM_CODE_END(except_vec_cex) .macro BUILD_HANDLER exception handler prep .align 5 SYM_CODE_START(handle_\exception) + UNWIND_HINT_UNDEFINED 666: BACKUP_T0T1 SAVE_ALL @@ -77,7 +80,9 @@ SYM_CODE_END(except_vec_cex) 668: RESTORE_ALL_AND_RET SYM_CODE_END(handle_\exception) + .pushsection ".data", "aw", %progbits SYM_DATA(unwind_hint_\exception, .word 668b - 666b) + .popsection .endm BUILD_HANDLER ade ade badv @@ -94,6 +99,7 @@ SYM_CODE_END(except_vec_cex) BUILD_HANDLER reserved reserved none /* others */ SYM_CODE_START(handle_sys) + UNWIND_HINT_UNDEFINED la_abs t0, handle_syscall jr t0 SYM_CODE_END(handle_sys) diff --git a/arch/loongarch/kernel/lbt.S b/arch/loongarch/kernel/lbt.S index 9c75120a26d8..001f061d226a 100644 --- a/arch/loongarch/kernel/lbt.S +++ b/arch/loongarch/kernel/lbt.S @@ -11,6 +11,7 @@ #include #include #include +#include #define SCR_REG_WIDTH 8 @@ -153,3 +154,5 @@ SYM_FUNC_END(_restore_ftop_context) .L_lbt_fault: li.w a0, -EFAULT # failure jr ra + +STACK_FRAME_NON_STANDARD _restore_ftop_context diff --git a/arch/loongarch/kernel/mcount_dyn.S b/arch/loongarch/kernel/mcount_dyn.S index 482aa553aa2d..0c65cf09110c 100644 --- a/arch/loongarch/kernel/mcount_dyn.S +++ b/arch/loongarch/kernel/mcount_dyn.S @@ -73,6 +73,7 @@ SYM_FUNC_START(ftrace_stub) SYM_FUNC_END(ftrace_stub) SYM_CODE_START(ftrace_common) + UNWIND_HINT_UNDEFINED PTR_ADDI a0, ra, -8 /* arg0: ip */ move a1, t0 /* arg1: parent_ip */ la.pcrel t1, function_trace_op @@ -113,12 +114,14 @@ ftrace_common_return: SYM_CODE_END(ftrace_common) SYM_CODE_START(ftrace_caller) + UNWIND_HINT_UNDEFINED ftrace_regs_entry allregs=0 b ftrace_common SYM_CODE_END(ftrace_caller) #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS SYM_CODE_START(ftrace_regs_caller) + UNWIND_HINT_UNDEFINED ftrace_regs_entry allregs=1 b ftrace_common SYM_CODE_END(ftrace_regs_caller) @@ -126,6 +129,7 @@ SYM_CODE_END(ftrace_regs_caller) #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_CODE_START(ftrace_graph_caller) + UNWIND_HINT_UNDEFINED PTR_L a0, sp, PT_ERA PTR_ADDI a0, a0, -8 /* arg0: self_addr */ PTR_ADDI a1, sp, PT_R1 /* arg1: parent */ @@ -134,6 +138,7 @@ SYM_CODE_START(ftrace_graph_caller) SYM_CODE_END(ftrace_graph_caller) SYM_CODE_START(return_to_handler) + UNWIND_HINT_UNDEFINED /* Save return value regs */ PTR_ADDI sp, sp, -FGRET_REGS_SIZE PTR_S a0, sp, FGRET_REGS_A0 @@ -155,6 +160,7 @@ SYM_CODE_END(return_to_handler) #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS SYM_CODE_START(ftrace_stub_direct_tramp) + UNWIND_HINT_UNDEFINED jr t0 SYM_CODE_END(ftrace_stub_direct_tramp) #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c index b13b2858fe39..c7d0338d12c1 100644 --- a/arch/loongarch/kernel/module.c +++ b/arch/loongarch/kernel/module.c @@ -20,6 +20,7 @@ #include #include #include +#include static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top) { @@ -515,15 +516,28 @@ static void module_init_ftrace_plt(const Elf_Ehdr *hdr, int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod) { - const Elf_Shdr *s, *se; const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + const Elf_Shdr *s, *alt = NULL, *orc = NULL, *orc_ip = NULL, *ftrace = NULL; - for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { if (!strcmp(".altinstructions", secstrs + s->sh_name)) - apply_alternatives((void *)s->sh_addr, (void *)s->sh_addr + s->sh_size); + alt = s; + if (!strcmp(".orc_unwind", secstrs + s->sh_name)) + orc = s; + if (!strcmp(".orc_unwind_ip", secstrs + s->sh_name)) + orc_ip = s; if (!strcmp(".ftrace_trampoline", secstrs + s->sh_name)) - module_init_ftrace_plt(hdr, s, mod); + ftrace = s; } + if (alt) + apply_alternatives((void *)alt->sh_addr, (void *)alt->sh_addr + alt->sh_size); + + if (orc && orc_ip) + unwind_module_init(mod, (void *)orc_ip->sh_addr, orc_ip->sh_size, (void *)orc->sh_addr, orc->sh_size); + + if (ftrace) + module_init_ftrace_plt(hdr, ftrace, mod); + return 0; } diff --git a/arch/loongarch/kernel/relocate_kernel.S b/arch/loongarch/kernel/relocate_kernel.S index f49f6b053763..84e6de2fd973 100644 --- a/arch/loongarch/kernel/relocate_kernel.S +++ b/arch/loongarch/kernel/relocate_kernel.S @@ -15,6 +15,7 @@ #include SYM_CODE_START(relocate_new_kernel) + UNWIND_HINT_UNDEFINED /* * a0: EFI boot flag for the new kernel * a1: Command line pointer for the new kernel @@ -90,6 +91,7 @@ SYM_CODE_END(relocate_new_kernel) * then start at the entry point from LOONGARCH_IOCSR_MBUF0. */ SYM_CODE_START(kexec_smp_wait) + UNWIND_HINT_UNDEFINED 1: li.w t0, 0x100 /* wait for init loop */ 2: addi.w t0, t0, -1 /* limit mailbox access */ bnez t0, 2b @@ -106,6 +108,5 @@ SYM_CODE_END(kexec_smp_wait) relocate_new_kernel_end: -SYM_DATA_START(relocate_new_kernel_size) - PTR relocate_new_kernel_end - relocate_new_kernel -SYM_DATA_END(relocate_new_kernel_size) + .section ".data" +SYM_DATA(relocate_new_kernel_size, .long relocate_new_kernel_end - relocate_new_kernel) diff --git a/arch/loongarch/kernel/rethook_trampoline.S b/arch/loongarch/kernel/rethook_trampoline.S index bd5772c96338..d4ceb2fa2a5c 100644 --- a/arch/loongarch/kernel/rethook_trampoline.S +++ b/arch/loongarch/kernel/rethook_trampoline.S @@ -76,6 +76,7 @@ .endm SYM_CODE_START(arch_rethook_trampoline) + UNWIND_HINT_UNDEFINED addi.d sp, sp, -PT_SIZE save_all_base_regs diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c index 634ef17fd38b..7bf9afaeea00 100644 --- a/arch/loongarch/kernel/setup.c +++ b/arch/loongarch/kernel/setup.c @@ -47,6 +47,7 @@ #include #include #include +#include #define SMBIOS_BIOSSIZE_OFFSET 0x09 #define SMBIOS_BIOSEXTERN_OFFSET 0x13 @@ -587,6 +588,7 @@ static void __init prefill_possible_map(void) void __init setup_arch(char **cmdline_p) { cpu_probe(); + unwind_init(); init_environ(); efi_init(); diff --git a/arch/loongarch/kernel/stacktrace.c b/arch/loongarch/kernel/stacktrace.c index f623feb2129f..eaec82e02c92 100644 --- a/arch/loongarch/kernel/stacktrace.c +++ b/arch/loongarch/kernel/stacktrace.c @@ -29,6 +29,7 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, regs->csr_era = thread_saved_ra(task); } regs->regs[1] = 0; + regs->regs[22] = 0; } for (unwind_start(&state, task, regs); diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index aebfc3733a76..f9f4eb00c92e 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -53,6 +53,32 @@ #include "access-helper.h" +void *exception_table[EXCCODE_INT_START] = { + [0 ... EXCCODE_INT_START - 1] = handle_reserved, + + [EXCCODE_TLBI] = handle_tlb_load, + [EXCCODE_TLBL] = handle_tlb_load, + [EXCCODE_TLBS] = handle_tlb_store, + [EXCCODE_TLBM] = handle_tlb_modify, + [EXCCODE_TLBNR] = handle_tlb_protect, + [EXCCODE_TLBNX] = handle_tlb_protect, + [EXCCODE_TLBPE] = handle_tlb_protect, + [EXCCODE_ADE] = handle_ade, + [EXCCODE_ALE] = handle_ale, + [EXCCODE_BCE] = handle_bce, + [EXCCODE_SYS] = handle_sys, + [EXCCODE_BP] = handle_bp, + [EXCCODE_INE] = handle_ri, + [EXCCODE_IPE] = handle_ri, + [EXCCODE_FPDIS] = handle_fpu, + [EXCCODE_LSXDIS] = handle_lsx, + [EXCCODE_LASXDIS] = handle_lasx, + [EXCCODE_FPE] = handle_fpe, + [EXCCODE_WATCH] = handle_watch, + [EXCCODE_BTDIS] = handle_lbt, +}; +EXPORT_SYMBOL_GPL(exception_table); + static void show_backtrace(struct task_struct *task, const struct pt_regs *regs, const char *loglvl, bool user) { @@ -1150,19 +1176,9 @@ void __init trap_init(void) for (i = EXCCODE_INT_START; i <= EXCCODE_INT_END; i++) set_handler(i * VECSIZE, handle_vint, VECSIZE); - set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE); - set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE); - set_handler(EXCCODE_BCE * VECSIZE, handle_bce, VECSIZE); - set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE); - set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE); - set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE); - set_handler(EXCCODE_IPE * VECSIZE, handle_ri, VECSIZE); - set_handler(EXCCODE_FPDIS * VECSIZE, handle_fpu, VECSIZE); - set_handler(EXCCODE_LSXDIS * VECSIZE, handle_lsx, VECSIZE); - set_handler(EXCCODE_LASXDIS * VECSIZE, handle_lasx, VECSIZE); - set_handler(EXCCODE_FPE * VECSIZE, handle_fpe, VECSIZE); - set_handler(EXCCODE_BTDIS * VECSIZE, handle_lbt, VECSIZE); - set_handler(EXCCODE_WATCH * VECSIZE, handle_watch, VECSIZE); + /* Set exception vector handler */ + for (i = EXCCODE_ADE; i <= EXCCODE_BTDIS; i++) + set_handler(i * VECSIZE, exception_table[i], VECSIZE); cache_error_setup(); diff --git a/arch/loongarch/kernel/unwind_orc.c b/arch/loongarch/kernel/unwind_orc.c new file mode 100644 index 000000000000..b25722876331 --- /dev/null +++ b/arch/loongarch/kernel/unwind_orc.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ORC_HEADER; + +#define orc_warn(fmt, ...) \ + printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__) + +extern int __start_orc_unwind_ip[]; +extern int __stop_orc_unwind_ip[]; +extern struct orc_entry __start_orc_unwind[]; +extern struct orc_entry __stop_orc_unwind[]; + +static bool orc_init __ro_after_init; +static unsigned int lookup_num_blocks __ro_after_init; + +/* Fake frame pointer entry -- used as a fallback for generated code */ +static struct orc_entry orc_fp_entry = { + .sp_reg = ORC_REG_FP, + .sp_offset = 16, + .fp_reg = ORC_REG_PREV_SP, + .fp_offset = -16, + .ra_reg = ORC_REG_PREV_SP, + .ra_offset = -8, + .type = ORC_TYPE_CALL +}; + +/* + * If we crash with IP==0, the last successfully executed instruction + * was probably an indirect function call with a NULL function pointer, + * and we don't have unwind information for NULL. + * This hardcoded ORC entry for IP==0 allows us to unwind from a NULL function + * pointer into its parent and then continue normally from there. + */ +static struct orc_entry orc_null_entry = { + .sp_reg = ORC_REG_SP, + .sp_offset = sizeof(long), + .fp_reg = ORC_REG_UNDEFINED, + .type = ORC_TYPE_CALL +}; + +static inline unsigned long orc_ip(const int *ip) +{ + return (unsigned long)ip + *ip; +} + +static struct orc_entry *__orc_find(int *ip_table, struct orc_entry *u_table, + unsigned int num_entries, unsigned long ip) +{ + int *first = ip_table; + int *mid = first, *found = first; + int *last = ip_table + num_entries - 1; + + if (!num_entries) + return NULL; + + /* + * Do a binary range search to find the rightmost duplicate of a given + * starting address. Some entries are section terminators which are + * "weak" entries for ensuring there are no gaps. They should be + * ignored when they conflict with a real entry. + */ + while (first <= last) { + mid = first + ((last - first) / 2); + + if (orc_ip(mid) <= ip) { + found = mid; + first = mid + 1; + } else + last = mid - 1; + } + + return u_table + (found - ip_table); +} + +#ifdef CONFIG_MODULES +static struct orc_entry *orc_module_find(unsigned long ip) +{ + struct module *mod; + + mod = __module_address(ip); + if (!mod || !mod->arch.orc_unwind || !mod->arch.orc_unwind_ip) + return NULL; + + return __orc_find(mod->arch.orc_unwind_ip, mod->arch.orc_unwind, mod->arch.num_orcs, ip); +} +#else +static struct orc_entry *orc_module_find(unsigned long ip) +{ + return NULL; +} +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE +static struct orc_entry *orc_find(unsigned long ip); + +/* + * Ftrace dynamic trampolines do not have orc entries of their own. + * But they are copies of the ftrace entries that are static and + * defined in ftrace_*.S, which do have orc entries. + * + * If the unwinder comes across a ftrace trampoline, then find the + * ftrace function that was used to create it, and use that ftrace + * function's orc entry, as the placement of the return code in + * the stack will be identical. + */ +static struct orc_entry *orc_ftrace_find(unsigned long ip) +{ + struct ftrace_ops *ops; + unsigned long tramp_addr, offset; + + ops = ftrace_ops_trampoline(ip); + if (!ops) + return NULL; + + /* Set tramp_addr to the start of the code copied by the trampoline */ + if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) + tramp_addr = (unsigned long)ftrace_regs_caller; + else + tramp_addr = (unsigned long)ftrace_caller; + + /* Now place tramp_addr to the location within the trampoline ip is at */ + offset = ip - ops->trampoline; + tramp_addr += offset; + + /* Prevent unlikely recursion */ + if (ip == tramp_addr) + return NULL; + + return orc_find(tramp_addr); +} +#else +static struct orc_entry *orc_ftrace_find(unsigned long ip) +{ + return NULL; +} +#endif + +static struct orc_entry *orc_find(unsigned long ip) +{ + static struct orc_entry *orc; + + if (ip == 0) + return &orc_null_entry; + + /* For non-init vmlinux addresses, use the fast lookup table: */ + if (ip >= LOOKUP_START_IP && ip < LOOKUP_STOP_IP) { + unsigned int idx, start, stop; + + idx = (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE; + + if (unlikely((idx >= lookup_num_blocks-1))) { + orc_warn("WARNING: bad lookup idx: idx=%u num=%u ip=%pB\n", + idx, lookup_num_blocks, (void *)ip); + return NULL; + } + + start = orc_lookup[idx]; + stop = orc_lookup[idx + 1] + 1; + + if (unlikely((__start_orc_unwind + start >= __stop_orc_unwind) || + (__start_orc_unwind + stop > __stop_orc_unwind))) { + orc_warn("WARNING: bad lookup value: idx=%u num=%u start=%u stop=%u ip=%pB\n", + idx, lookup_num_blocks, start, stop, (void *)ip); + return NULL; + } + + return __orc_find(__start_orc_unwind_ip + start, + __start_orc_unwind + start, stop - start, ip); + } + + /* vmlinux .init slow lookup: */ + if (is_kernel_inittext(ip)) + return __orc_find(__start_orc_unwind_ip, __start_orc_unwind, + __stop_orc_unwind_ip - __start_orc_unwind_ip, ip); + + /* Module lookup: */ + orc = orc_module_find(ip); + if (orc) + return orc; + + return orc_ftrace_find(ip); +} + +#ifdef CONFIG_MODULES + +static DEFINE_MUTEX(sort_mutex); +static int *cur_orc_ip_table = __start_orc_unwind_ip; +static struct orc_entry *cur_orc_table = __start_orc_unwind; + +static void orc_sort_swap(void *_a, void *_b, int size) +{ + int delta = _b - _a; + int *a = _a, *b = _b, tmp; + struct orc_entry *orc_a, *orc_b; + + /* Swap the .orc_unwind_ip entries: */ + tmp = *a; + *a = *b + delta; + *b = tmp - delta; + + /* Swap the corresponding .orc_unwind entries: */ + orc_a = cur_orc_table + (a - cur_orc_ip_table); + orc_b = cur_orc_table + (b - cur_orc_ip_table); + swap(*orc_a, *orc_b); +} + +static int orc_sort_cmp(const void *_a, const void *_b) +{ + const int *a = _a, *b = _b; + unsigned long a_val = orc_ip(a); + unsigned long b_val = orc_ip(b); + struct orc_entry *orc_a; + + if (a_val > b_val) + return 1; + if (a_val < b_val) + return -1; + + /* + * The "weak" section terminator entries need to always be first + * to ensure the lookup code skips them in favor of real entries. + * These terminator entries exist to handle any gaps created by + * whitelisted .o files which didn't get objtool generation. + */ + orc_a = cur_orc_table + (a - cur_orc_ip_table); + + return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1; +} + +void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_size, + void *_orc, size_t orc_size) +{ + int *orc_ip = _orc_ip; + struct orc_entry *orc = _orc; + unsigned int num_entries = orc_ip_size / sizeof(int); + + WARN_ON_ONCE(orc_ip_size % sizeof(int) != 0 || + orc_size % sizeof(*orc) != 0 || + num_entries != orc_size / sizeof(*orc)); + + /* + * The 'cur_orc_*' globals allow the orc_sort_swap() callback to + * associate an .orc_unwind_ip table entry with its corresponding + * .orc_unwind entry so they can both be swapped. + */ + mutex_lock(&sort_mutex); + cur_orc_ip_table = orc_ip; + cur_orc_table = orc; + sort(orc_ip, num_entries, sizeof(int), orc_sort_cmp, orc_sort_swap); + mutex_unlock(&sort_mutex); + + mod->arch.orc_unwind_ip = orc_ip; + mod->arch.orc_unwind = orc; + mod->arch.num_orcs = num_entries; +} +#endif + +void __init unwind_init(void) +{ + int i; + size_t orc_size = (void *)__stop_orc_unwind - (void *)__start_orc_unwind; + size_t orc_ip_size = (void *)__stop_orc_unwind_ip - (void *)__start_orc_unwind_ip; + size_t num_entries = orc_ip_size / sizeof(int); + struct orc_entry *orc; + + if (!num_entries || orc_ip_size % sizeof(int) != 0 || + orc_size % sizeof(struct orc_entry) != 0 || + num_entries != orc_size / sizeof(struct orc_entry)) { + orc_warn("WARNING: Bad or missing .orc_unwind table. Disabling unwinder.\n"); + return; + } + + /* + * Note, the orc_unwind and orc_unwind_ip tables were already + * sorted at build time via the 'sorttable' tool. + * It's ready for binary search straight away, no need to sort it. + */ + + /* Initialize the fast lookup table: */ + lookup_num_blocks = orc_lookup_end - orc_lookup; + for (i = 0; i < lookup_num_blocks-1; i++) { + orc = __orc_find(__start_orc_unwind_ip, __start_orc_unwind, + num_entries, LOOKUP_START_IP + (LOOKUP_BLOCK_SIZE * i)); + if (!orc) { + orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n"); + return; + } + + orc_lookup[i] = orc - __start_orc_unwind; + } + + /* Initialize the ending block: */ + orc = __orc_find(__start_orc_unwind_ip, __start_orc_unwind, num_entries, LOOKUP_STOP_IP); + if (!orc) { + orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n"); + return; + } + orc_lookup[lookup_num_blocks-1] = orc - __start_orc_unwind; + + orc_init = true; +} + +static inline bool on_stack(struct stack_info *info, unsigned long addr, size_t len) +{ + unsigned long begin = info->begin; + unsigned long end = info->end; + + return (info->type != STACK_TYPE_UNKNOWN && + addr >= begin && addr < end && addr + len > begin && addr + len <= end); +} + +static bool stack_access_ok(struct unwind_state *state, unsigned long addr, size_t len) +{ + struct stack_info *info = &state->stack_info; + + if (on_stack(info, addr, len)) + return true; + + return !get_stack_info(addr, state->task, info) && on_stack(info, addr, len); +} + +unsigned long unwind_get_return_address(struct unwind_state *state) +{ + return __unwind_get_return_address(state); +} +EXPORT_SYMBOL_GPL(unwind_get_return_address); + +void unwind_start(struct unwind_state *state, struct task_struct *task, + struct pt_regs *regs) +{ + __unwind_start(state, task, regs); + state->type = UNWINDER_ORC; + if (!unwind_done(state) && !__kernel_text_address(state->pc)) + unwind_next_frame(state); +} +EXPORT_SYMBOL_GPL(unwind_start); + +static bool is_entry_func(unsigned long addr) +{ + extern u32 kernel_entry; + extern u32 kernel_entry_end; + + return addr >= (unsigned long)&kernel_entry && addr < (unsigned long)&kernel_entry_end; +} + +static inline unsigned long bt_address(unsigned long ra) +{ + extern unsigned long eentry; + + if (__kernel_text_address(ra)) + return ra; + + if (__module_text_address(ra)) + return ra; + + if (ra >= eentry && ra < eentry + EXCCODE_INT_END * VECSIZE) { + unsigned long func; + unsigned long type = (ra - eentry) / VECSIZE; + unsigned long offset = (ra - eentry) % VECSIZE; + + switch (type) { + case 0 ... EXCCODE_INT_START - 1: + func = (unsigned long)exception_table[type]; + break; + case EXCCODE_INT_START ... EXCCODE_INT_END: + func = (unsigned long)handle_vint; + break; + default: + func = (unsigned long)handle_reserved; + break; + } + + return func + offset; + } + + return ra; +} + +bool unwind_next_frame(struct unwind_state *state) +{ + unsigned long *p, pc; + struct pt_regs *regs; + struct orc_entry *orc; + struct stack_info *info = &state->stack_info; + + if (unwind_done(state)) + return false; + + /* Don't let modules unload while we're reading their ORC data. */ + preempt_disable(); + + if (is_entry_func(state->pc)) + goto end; + + orc = orc_find(state->pc); + if (!orc) { + /* + * As a fallback, try to assume this code uses a frame pointer. + * This is useful for generated code, like BPF, which ORC + * doesn't know about. This is just a guess, so the rest of + * the unwind is no longer considered reliable. + */ + orc = &orc_fp_entry; + state->error = true; + } else { + if (orc->type == ORC_TYPE_UNDEFINED) + goto err; + + if (orc->type == ORC_TYPE_END_OF_STACK) + goto end; + } + + switch (orc->sp_reg) { + case ORC_REG_SP: + if (info->type == STACK_TYPE_IRQ && state->sp == info->end) + orc->type = ORC_TYPE_REGS; + else + state->sp = state->sp + orc->sp_offset; + break; + case ORC_REG_FP: + state->sp = state->fp; + break; + default: + orc_warn("unknown SP base reg %d at %pB\n", orc->sp_reg, (void *)state->pc); + goto err; + } + + switch (orc->fp_reg) { + case ORC_REG_PREV_SP: + p = (unsigned long *)(state->sp + orc->fp_offset); + if (!stack_access_ok(state, (unsigned long)p, sizeof(unsigned long))) + goto err; + + state->fp = *p; + break; + case ORC_REG_UNDEFINED: + /* Nothing. */ + break; + default: + orc_warn("unknown FP base reg %d at %pB\n", orc->fp_reg, (void *)state->pc); + goto err; + } + + switch (orc->type) { + case ORC_TYPE_CALL: + if (orc->ra_reg == ORC_REG_PREV_SP) { + p = (unsigned long *)(state->sp + orc->ra_offset); + if (!stack_access_ok(state, (unsigned long)p, sizeof(unsigned long))) + goto err; + + pc = unwind_graph_addr(state, *p, state->sp); + pc -= LOONGARCH_INSN_SIZE; + } else if (orc->ra_reg == ORC_REG_UNDEFINED) { + if (!state->ra || state->ra == state->pc) + goto err; + + pc = unwind_graph_addr(state, state->ra, state->sp); + pc -= LOONGARCH_INSN_SIZE; + state->ra = 0; + } else { + orc_warn("unknown ra base reg %d at %pB\n", orc->ra_reg, (void *)state->pc); + goto err; + } + break; + case ORC_TYPE_REGS: + if (info->type == STACK_TYPE_IRQ && state->sp == info->end) + regs = (struct pt_regs *)info->next_sp; + else + regs = (struct pt_regs *)state->sp; + + if (!stack_access_ok(state, (unsigned long)regs, sizeof(*regs))) + goto err; + + if ((info->end == (unsigned long)regs + sizeof(*regs)) && + !regs->regs[3] && !regs->regs[1]) + goto end; + + if (user_mode(regs)) + goto end; + + pc = regs->csr_era; + if (!__kernel_text_address(pc)) + goto err; + + state->sp = regs->regs[3]; + state->ra = regs->regs[1]; + state->fp = regs->regs[22]; + get_stack_info(state->sp, state->task, info); + + break; + default: + orc_warn("unknown .orc_unwind entry type %d at %pB\n", orc->type, (void *)state->pc); + goto err; + } + + state->pc = bt_address(pc); + if (!state->pc) { + pr_err("cannot find unwind pc at %pK\n", (void *)pc); + goto err; + } + + if (!__kernel_text_address(state->pc)) + goto err; + + preempt_enable(); + return true; + +err: + state->error = true; + +end: + preempt_enable(); + state->stack_info.type = STACK_TYPE_UNKNOWN; + return false; +} +EXPORT_SYMBOL_GPL(unwind_next_frame); diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S index a5d0cd2035da..e8e97dbf9ca4 100644 --- a/arch/loongarch/kernel/vmlinux.lds.S +++ b/arch/loongarch/kernel/vmlinux.lds.S @@ -2,6 +2,7 @@ #include #include #include +#include #define PAGE_SIZE _PAGE_SIZE #define RO_EXCEPTION_TABLE_ALIGN 4 @@ -122,6 +123,8 @@ SECTIONS } #endif + ORC_UNWIND_TABLE + .sdata : { *(.sdata) } diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S index ba976509bfe8..1fcc4b7eda32 100644 --- a/arch/loongarch/kvm/switch.S +++ b/arch/loongarch/kvm/switch.S @@ -8,7 +8,7 @@ #include #include #include -#include +#include #define HGPR_OFFSET(x) (PT_R0 + 8*x) #define GGPR_OFFSET(x) (KVM_ARCH_GGPR + 8*x) @@ -112,6 +112,7 @@ .text .cfi_sections .debug_frame SYM_CODE_START(kvm_exc_entry) + UNWIND_HINT_UNDEFINED csrwr a2, KVM_TEMP_KS csrrd a2, KVM_VCPU_KS addi.d a2, a2, KVM_VCPU_ARCH @@ -279,3 +280,9 @@ SYM_FUNC_END(kvm_restore_lasx) .section ".rodata" SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry) SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest) + +#ifdef CONFIG_CPU_HAS_LBT +STACK_FRAME_NON_STANDARD kvm_restore_fpu +STACK_FRAME_NON_STANDARD kvm_restore_lsx +STACK_FRAME_NON_STANDARD kvm_restore_lasx +#endif diff --git a/arch/loongarch/lib/clear_user.S b/arch/loongarch/lib/clear_user.S index be741544e62b..7a0db643b286 100644 --- a/arch/loongarch/lib/clear_user.S +++ b/arch/loongarch/lib/clear_user.S @@ -10,6 +10,7 @@ #include #include #include +#include SYM_FUNC_START(__clear_user) /* @@ -204,3 +205,5 @@ SYM_FUNC_START(__clear_user_fast) _asm_extable 28b, .Lsmall_fixup _asm_extable 29b, .Lexit SYM_FUNC_END(__clear_user_fast) + +STACK_FRAME_NON_STANDARD __clear_user_fast diff --git a/arch/loongarch/lib/copy_user.S b/arch/loongarch/lib/copy_user.S index feec3d362803..095ce9181c6c 100644 --- a/arch/loongarch/lib/copy_user.S +++ b/arch/loongarch/lib/copy_user.S @@ -10,6 +10,7 @@ #include #include #include +#include SYM_FUNC_START(__copy_user) /* @@ -278,3 +279,5 @@ SYM_FUNC_START(__copy_user_fast) _asm_extable 58b, .Lexit _asm_extable 59b, .Lexit SYM_FUNC_END(__copy_user_fast) + +STACK_FRAME_NON_STANDARD __copy_user_fast diff --git a/arch/loongarch/lib/memcpy.S b/arch/loongarch/lib/memcpy.S index fa1148878d2b..9517a2f961af 100644 --- a/arch/loongarch/lib/memcpy.S +++ b/arch/loongarch/lib/memcpy.S @@ -9,6 +9,7 @@ #include #include #include +#include .section .noinstr.text, "ax" @@ -197,3 +198,5 @@ SYM_FUNC_START(__memcpy_fast) jr ra SYM_FUNC_END(__memcpy_fast) _ASM_NOKPROBE(__memcpy_fast) + +STACK_FRAME_NON_STANDARD __memcpy_small diff --git a/arch/loongarch/lib/memset.S b/arch/loongarch/lib/memset.S index 06d3ca54cbfe..df3846620553 100644 --- a/arch/loongarch/lib/memset.S +++ b/arch/loongarch/lib/memset.S @@ -9,6 +9,7 @@ #include #include #include +#include .macro fill_to_64 r0 bstrins.d \r0, \r0, 15, 8 @@ -166,3 +167,5 @@ SYM_FUNC_START(__memset_fast) jr ra SYM_FUNC_END(__memset_fast) _ASM_NOKPROBE(__memset_fast) + +STACK_FRAME_NON_STANDARD __memset_fast diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c index 0b95d32b30c9..5ac9beb5f093 100644 --- a/arch/loongarch/mm/tlb.c +++ b/arch/loongarch/mm/tlb.c @@ -9,8 +9,9 @@ #include #include -#include #include +#include +#include #include #include #include @@ -266,24 +267,20 @@ static void setup_tlb_handler(int cpu) setup_ptwalker(); local_flush_tlb_all(); + if (cpu_has_ptw) { + exception_table[EXCCODE_TLBI] = handle_tlb_load_ptw; + exception_table[EXCCODE_TLBL] = handle_tlb_load_ptw; + exception_table[EXCCODE_TLBS] = handle_tlb_store_ptw; + exception_table[EXCCODE_TLBM] = handle_tlb_modify_ptw; + } + /* The tlb handlers are generated only once */ if (cpu == 0) { memcpy((void *)tlbrentry, handle_tlb_refill, 0x80); local_flush_icache_range(tlbrentry, tlbrentry + 0x80); - if (!cpu_has_ptw) { - set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load, VECSIZE); - set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load, VECSIZE); - set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store, VECSIZE); - set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify, VECSIZE); - } else { - set_handler(EXCCODE_TLBI * VECSIZE, handle_tlb_load_ptw, VECSIZE); - set_handler(EXCCODE_TLBL * VECSIZE, handle_tlb_load_ptw, VECSIZE); - set_handler(EXCCODE_TLBS * VECSIZE, handle_tlb_store_ptw, VECSIZE); - set_handler(EXCCODE_TLBM * VECSIZE, handle_tlb_modify_ptw, VECSIZE); - } - set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE); - set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE); - set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE); + + for (int i = EXCCODE_TLBL; i <= EXCCODE_TLBPE; i++) + set_handler(i * VECSIZE, exception_table[i], VECSIZE); } else { int vec_sz __maybe_unused; void *addr __maybe_unused; diff --git a/arch/loongarch/mm/tlbex.S b/arch/loongarch/mm/tlbex.S index d5d682f3d29f..a44387b838af 100644 --- a/arch/loongarch/mm/tlbex.S +++ b/arch/loongarch/mm/tlbex.S @@ -18,6 +18,7 @@ .macro tlb_do_page_fault, write SYM_CODE_START(tlb_do_page_fault_\write) + UNWIND_HINT_UNDEFINED SAVE_ALL csrrd a2, LOONGARCH_CSR_BADV move a0, sp @@ -32,6 +33,7 @@ tlb_do_page_fault 1 SYM_CODE_START(handle_tlb_protect) + UNWIND_HINT_UNDEFINED BACKUP_T0T1 SAVE_ALL move a0, sp @@ -44,6 +46,7 @@ SYM_CODE_START(handle_tlb_protect) SYM_CODE_END(handle_tlb_protect) SYM_CODE_START(handle_tlb_load) + UNWIND_HINT_UNDEFINED csrwr t0, EXCEPTION_KS0 csrwr t1, EXCEPTION_KS1 csrwr ra, EXCEPTION_KS2 @@ -190,6 +193,7 @@ nopage_tlb_load: SYM_CODE_END(handle_tlb_load) SYM_CODE_START(handle_tlb_load_ptw) + UNWIND_HINT_UNDEFINED csrwr t0, LOONGARCH_CSR_KS0 csrwr t1, LOONGARCH_CSR_KS1 la_abs t0, tlb_do_page_fault_0 @@ -197,6 +201,7 @@ SYM_CODE_START(handle_tlb_load_ptw) SYM_CODE_END(handle_tlb_load_ptw) SYM_CODE_START(handle_tlb_store) + UNWIND_HINT_UNDEFINED csrwr t0, EXCEPTION_KS0 csrwr t1, EXCEPTION_KS1 csrwr ra, EXCEPTION_KS2 @@ -346,6 +351,7 @@ nopage_tlb_store: SYM_CODE_END(handle_tlb_store) SYM_CODE_START(handle_tlb_store_ptw) + UNWIND_HINT_UNDEFINED csrwr t0, LOONGARCH_CSR_KS0 csrwr t1, LOONGARCH_CSR_KS1 la_abs t0, tlb_do_page_fault_1 @@ -353,6 +359,7 @@ SYM_CODE_START(handle_tlb_store_ptw) SYM_CODE_END(handle_tlb_store_ptw) SYM_CODE_START(handle_tlb_modify) + UNWIND_HINT_UNDEFINED csrwr t0, EXCEPTION_KS0 csrwr t1, EXCEPTION_KS1 csrwr ra, EXCEPTION_KS2 @@ -500,6 +507,7 @@ nopage_tlb_modify: SYM_CODE_END(handle_tlb_modify) SYM_CODE_START(handle_tlb_modify_ptw) + UNWIND_HINT_UNDEFINED csrwr t0, LOONGARCH_CSR_KS0 csrwr t1, LOONGARCH_CSR_KS1 la_abs t0, tlb_do_page_fault_1 @@ -507,6 +515,7 @@ SYM_CODE_START(handle_tlb_modify_ptw) SYM_CODE_END(handle_tlb_modify_ptw) SYM_CODE_START(handle_tlb_refill) + UNWIND_HINT_UNDEFINED csrwr t0, LOONGARCH_CSR_TLBRSAVE csrrd t0, LOONGARCH_CSR_PGD lddir t0, t0, 3 diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile index f597cd08a96b..75c6726382c3 100644 --- a/arch/loongarch/vdso/Makefile +++ b/arch/loongarch/vdso/Makefile @@ -4,6 +4,7 @@ KASAN_SANITIZE := n UBSAN_SANITIZE := n KCOV_INSTRUMENT := n +OBJECT_FILES_NON_STANDARD := y # Include the generic Makefile to check the built vdso. include $(srctree)/lib/vdso/Makefile diff --git a/include/linux/compiler.h b/include/linux/compiler.h index bb1339c7057b..39f2d4a05208 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -116,6 +116,14 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, */ #define __stringify_label(n) #n +#define __annotate_reachable(c) ({ \ + asm volatile(__stringify_label(c) ":\n\t" \ + ".pushsection .discard.reachable\n\t" \ + ".long " __stringify_label(c) "b - .\n\t" \ + ".popsection\n\t"); \ +}) +#define annotate_reachable() __annotate_reachable(__COUNTER__) + #define __annotate_unreachable(c) ({ \ asm volatile(__stringify_label(c) ":\n\t" \ ".pushsection .discard.unreachable\n\t" \ @@ -128,6 +136,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, #define __annotate_jump_table __section(".rodata..c_jump_table") #else /* !CONFIG_OBJTOOL */ +#define annotate_reachable() #define annotate_unreachable() #define __annotate_jump_table #endif /* CONFIG_OBJTOOL */ diff --git a/scripts/Makefile b/scripts/Makefile index 576cf64be667..e4cca53d2285 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -31,9 +31,12 @@ HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null | ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) -ARCH := x86 +SRCARCH := x86 endif -HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include +ifeq ($(ARCH),loongarch) +SRCARCH := loongarch +endif +HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/$(SRCARCH)/include HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED endif -- cgit v1.2.3 From 23dfd914d2bfc4c9938b0084dffd7105de231d98 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 15 Feb 2024 15:13:21 +0100 Subject: modpost: fix null pointer dereference If the find_fromsym() call fails and returns NULL, the warn() call will dereference this NULL pointer and cause the program to crash. This happened when I tried to build with "test_user_copy" module. With this fix, it prints lots of warnings like this: WARNING: modpost: lib/test_user_copy: section mismatch in reference: (unknown)+0x4 (section: .text.fixup) -> (unknown) (section: .init.text) masahiroy@kernel.org: The issue is reproduced with ARCH=arm allnoconfig + CONFIG_MODULES=y + CONFIG_RUNTIME_TESTING_MENU=y + CONFIG_TEST_USER_COPY=m Signed-off-by: Max Kellermann Signed-off-by: Masahiro Yamada --- scripts/mod/modpost.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 267b9a0a3abc..9106fe757946 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1050,7 +1050,9 @@ 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->st_value), fromsec, tosym, tosec); + modname, fromsym, + (unsigned int)(faddr - (from ? from->st_value : 0)), + fromsec, tosym, tosec); if (mismatch->mismatch == EXTABLE_TO_NON_TEXT) { if (match(tosec, mismatch->bad_tosec)) -- cgit v1.2.3 From 137bb8b814be5d0056e8eaf593e71bf340cdc06f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Mar 2024 22:32:57 +0900 Subject: kconfig: lxdialog: fix button color for blackbg theme For MENUCONFIG_COLOR=blackbg, the text in inactive buttons is invisible because both the foreground and background are black. Change the foreground color to white and remove the highlighting. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lxdialog/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index 3f78fb265136..d5315315b066 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -101,7 +101,7 @@ static void set_blackbg_theme(void) DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true); DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false); DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false); - DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true); + DLG_COLOR(button_label_inactive, COLOR_WHITE, COLOR_BLACK, false); DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); -- cgit v1.2.3 From c33a4315c4095be368fe127db3385b248d38df8f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Mar 2024 22:32:58 +0900 Subject: kconfig: lxdialog: remove unused dialog colors Remove inputbox_order, searchbox, searchbox_title, searchbox_border because they are initialized, but not used anywhere. Signed-off-by: Masahiro Yamada --- scripts/kconfig/lxdialog/dialog.h | 4 ---- scripts/kconfig/lxdialog/util.c | 18 ------------------ 2 files changed, 22 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h index a501abf9fa31..2d15ba893fbf 100644 --- a/scripts/kconfig/lxdialog/dialog.h +++ b/scripts/kconfig/lxdialog/dialog.h @@ -91,10 +91,6 @@ struct dialog_info { struct dialog_color button_label_active; struct dialog_color button_label_inactive; struct dialog_color inputbox; - struct dialog_color inputbox_border; - struct dialog_color searchbox; - struct dialog_color searchbox_title; - struct dialog_color searchbox_border; struct dialog_color position_indicator; struct dialog_color menubox; struct dialog_color menubox_border; diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index d5315315b066..3fb7508b68a2 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -29,10 +29,6 @@ static void set_mono_theme(void) dlg.button_label_active.atr = A_REVERSE; dlg.button_label_inactive.atr = A_NORMAL; dlg.inputbox.atr = A_NORMAL; - dlg.inputbox_border.atr = A_NORMAL; - dlg.searchbox.atr = A_NORMAL; - dlg.searchbox_title.atr = A_BOLD; - dlg.searchbox_border.atr = A_NORMAL; dlg.position_indicator.atr = A_BOLD; dlg.menubox.atr = A_NORMAL; dlg.menubox_border.atr = A_NORMAL; @@ -69,10 +65,6 @@ static void set_classic_theme(void) DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true); DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true); DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false); - DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true); - DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true); DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true); DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false); DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true); @@ -104,11 +96,6 @@ static void set_blackbg_theme(void) DLG_COLOR(button_label_inactive, COLOR_WHITE, COLOR_BLACK, false); DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false); - - DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false); - DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true); - DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true); DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false); @@ -136,7 +123,6 @@ static void set_bluetitle_theme(void) DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true); DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true); - DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true); DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true); @@ -189,10 +175,6 @@ static void init_dialog_colors(void) init_one_color(&dlg.button_label_active); init_one_color(&dlg.button_label_inactive); init_one_color(&dlg.inputbox); - init_one_color(&dlg.inputbox_border); - init_one_color(&dlg.searchbox); - init_one_color(&dlg.searchbox_title); - init_one_color(&dlg.searchbox_border); init_one_color(&dlg.position_indicator); init_one_color(&dlg.menubox); init_one_color(&dlg.menubox_border); -- cgit v1.2.3 From 4957515b9c3aa3d32a1ee44ab77f0a44f29263dc Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Mar 2024 22:45:15 +0900 Subject: kconfig: check prompt for choice while parsing This can be checked on-the-fly. Signed-off-by: Masahiro Yamada --- scripts/kconfig/menu.c | 3 --- scripts/kconfig/parser.y | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 840ce642ec43..8498481e6afe 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -561,9 +561,6 @@ void menu_finalize(struct menu *parent) if (sym->type == S_UNKNOWN) menu_warn(parent, "config symbol defined without type"); - if (sym_is_choice(sym) && !parent->prompt) - menu_warn(parent, "choice must have a prompt"); - /* Check properties connected to this symbol */ sym_check_prop(sym); sym->flags |= SYMBOL_WARNED; diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 22f616334585..b45bfaf0a02b 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -233,6 +233,12 @@ choice: T_CHOICE T_EOL choice_entry: choice choice_option_list { + if (!current_entry->prompt) { + fprintf(stderr, "%s:%d: error: choice must have a prompt\n", + current_entry->filename, current_entry->lineno); + yynerrs++; + } + $$ = menu_add_menu(); }; -- cgit v1.2.3 From b27a91383abc4acca39f4402cdcc74ce4a476d8e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 10 Mar 2024 23:16:17 +0900 Subject: kconfig: remove unneeded menu_is_visible() call in conf_write_defconfig() When the condition 'sym == NULL' is met, the code will reach the 'next_menu' label regardless of the return value from menu_is_visible(). menu_is_visible() calculates some symbol values as a side-effect, for instance by calling expr_calc_value(menu->visibility), but all the symbol values will be calculated eventually. Signed-off-by: Masahiro Yamada --- scripts/kconfig/confdata.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index c5b6487d68ac..0e35c4819cf1 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -799,10 +799,7 @@ int conf_write_defconfig(const char *filename) while (menu != NULL) { sym = menu->sym; - if (sym == NULL) { - if (!menu_is_visible(menu)) - goto next_menu; - } else if (!sym_is_choice(sym)) { + if (sym && !sym_is_choice(sym)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) goto next_menu; -- cgit v1.2.3 From 097f1200bf7ea19fb39ccf538a07a153260a7763 Mon Sep 17 00:00:00 2001 From: Jose Ignacio Tornos Martinez Date: Mon, 11 Mar 2024 17:22:38 +0100 Subject: kbuild: rpm-pkg: add dtb files in kernel rpm Some architectures, like aarch64 ones, need a dtb file to configure the hardware. The default dtb file can be preloaded from u-boot, but the final and/or more complete dtb file needs to be able to be loaded later from rootfs. Add the possible dtb files to the kernel rpm and mimic Fedora shipping process, storing the dtb files in the module directory. These dtb files will be copied to /boot directory by the install scripts, but add fallback just in case, checking if the content in /boot directory is correct. Mark the files installed to /boot as %ghost to make sure they will be removed when the package is uninstalled. Tested with Fedora Rawhide (x86_64 and aarch64) with dnf and rpm tools. In addition, fallback was also tested after modifying the install scripts. Signed-off-by: Jose Ignacio Tornos Martinez Tested-by: Nathan Chancellor Signed-off-by: Masahiro Yamada --- scripts/package/kernel.spec | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'scripts') diff --git a/scripts/package/kernel.spec b/scripts/package/kernel.spec index c256b73cca3e..e095eb1e290e 100644 --- a/scripts/package/kernel.spec +++ b/scripts/package/kernel.spec @@ -61,6 +61,9 @@ cp $(%{make} %{makeflags} -s image_name) %{buildroot}/lib/modules/%{KERNELRELEAS %{make} %{makeflags} INSTALL_HDR_PATH=%{buildroot}/usr headers_install cp System.map %{buildroot}/lib/modules/%{KERNELRELEASE} cp .config %{buildroot}/lib/modules/%{KERNELRELEASE}/config +if %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='test -d ${srctree}/arch/${SRCARCH}/boot/dts' 2>/dev/null; then + %{make} %{makeflags} INSTALL_DTBS_PATH=%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb dtbs_install +fi ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEASE}/build %if %{with_devel} %{make} %{makeflags} run-command KBUILD_RUN_COMMAND='${srctree}/scripts/package/install-extmod-build %{buildroot}/usr/src/kernels/%{KERNELRELEASE}' @@ -81,6 +84,11 @@ ln -fns /usr/src/kernels/%{KERNELRELEASE} %{buildroot}/lib/modules/%{KERNELRELEA echo "%ghost /boot/${x}-%{KERNELRELEASE}" done + if [ -d "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" ];then + echo "/lib/modules/%{KERNELRELEASE}/dtb" + find "%{buildroot}/lib/modules/%{KERNELRELEASE}/dtb" -printf "%%%ghost /boot/dtb-%{KERNELRELEASE}/%%P\n" + fi + echo "%exclude /lib/modules/%{KERNELRELEASE}/build" } > %{buildroot}/kernel.list @@ -96,6 +104,11 @@ for file in vmlinuz System.map config; do cp "/lib/modules/%{KERNELRELEASE}/${file}" "/boot/${file}-%{KERNELRELEASE}" fi done +if [ -d "/lib/modules/%{KERNELRELEASE}/dtb" ] && \ + ! diff -rq "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}" >/dev/null 2>&1; then + rm -rf "/boot/dtb-%{KERNELRELEASE}" + cp -r "/lib/modules/%{KERNELRELEASE}/dtb" "/boot/dtb-%{KERNELRELEASE}" +fi if [ ! -e "/lib/modules/%{KERNELRELEASE}/modules.dep" ]; then /usr/sbin/depmod %{KERNELRELEASE} fi -- cgit v1.2.3 From c9aa7d862144f7b5d74cf316fc1172629a3b438f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 21 Mar 2024 01:52:09 +0900 Subject: kconfig: tests: support KCONFIG_SEED for the randconfig runner This will help get consistent results for randconfig tests. Signed-off-by: Masahiro Yamada --- scripts/kconfig/tests/conftest.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py index af8774a5697c..2a2a7e2da060 100644 --- a/scripts/kconfig/tests/conftest.py +++ b/scripts/kconfig/tests/conftest.py @@ -154,12 +154,10 @@ class Conf: defconfig_path = os.path.join(self._test_dir, defconfig) return self._run_conf('--defconfig={}'.format(defconfig_path)) - def _allconfig(self, mode, all_config): + def _allconfig(self, mode, all_config, extra_env={}): if all_config: all_config_path = os.path.join(self._test_dir, all_config) - extra_env = {'KCONFIG_ALLCONFIG': all_config_path} - else: - extra_env = {} + extra_env['KCONFIG_ALLCONFIG'] = all_config_path return self._run_conf('--{}config'.format(mode), extra_env=extra_env) @@ -195,13 +193,19 @@ class Conf: """ return self._allconfig('alldef', all_config) - def randconfig(self, all_config=None): + def randconfig(self, all_config=None, seed=None): """Run randconfig. all_config: fragment config file for KCONFIG_ALLCONFIG (optional) + seed: the seed for randconfig (optional) returncode: exit status of the Kconfig executable """ - return self._allconfig('rand', all_config) + if seed is not None: + extra_env = {'KCONFIG_SEED': hex(seed)} + else: + extra_env = {} + + return self._allconfig('rand', all_config, extra_env=extra_env) def savedefconfig(self, dot_config): """Run savedefconfig. -- cgit v1.2.3 From 47ad16894c4a25e6cb342666f0fa203701a88476 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 21 Mar 2024 01:52:10 +0900 Subject: kconfig: tests: add a test for randconfig with dependent choices Since commit 3b9a19e08960 ("kconfig: loop as long as we changed some symbols in randconfig"), conf_set_all_new_symbols() is repeated until there is no more choice left to be shuffled. The motivation was to shuffle a choice nested in another choice. Although commit 09d5873e4d1f ("kconfig: allow only 'config', 'comment', and 'if' inside 'choice'") disallowed the nested choice structure, we must still keep 3b9a19e08960 because there are still cases where conf_set_all_new_symbols() must iterate. scripts/kconfig/tests/choice_randomize/Kconfig is the test case. The second choice depends on 'B', which is the member of the first choice. With 3b9a19e08960 reverted, we would never get the pattern specified by scripts/kconfig/tests/choice_randomize/expected_config2. A real example can be found in lib/Kconfig.debug. Without 3b9a19e08960, the randconfig would not shuffle the "Compressed Debug information" choice, which depends on DEBUG_INFO, which is derived from another choice "Debug information". My goal is to refactor Kconfig so that randconfig will work more simply, without using the loop. For now, let's add a test case to ensure all dependent choices are shuffled, as it is a somewhat tricky case for the current Kconfig. Signed-off-by: Masahiro Yamada --- scripts/kconfig/tests/choice_randomize/Kconfig | 22 ++++++++++++++ scripts/kconfig/tests/choice_randomize/__init__.py | 34 ++++++++++++++++++++++ .../tests/choice_randomize/expected_config0 | 6 ++++ .../tests/choice_randomize/expected_config1 | 8 +++++ .../tests/choice_randomize/expected_config2 | 8 +++++ 5 files changed, 78 insertions(+) create mode 100644 scripts/kconfig/tests/choice_randomize/Kconfig create mode 100644 scripts/kconfig/tests/choice_randomize/__init__.py create mode 100644 scripts/kconfig/tests/choice_randomize/expected_config0 create mode 100644 scripts/kconfig/tests/choice_randomize/expected_config1 create mode 100644 scripts/kconfig/tests/choice_randomize/expected_config2 (limited to 'scripts') diff --git a/scripts/kconfig/tests/choice_randomize/Kconfig b/scripts/kconfig/tests/choice_randomize/Kconfig new file mode 100644 index 000000000000..93a1699ce3cb --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/Kconfig @@ -0,0 +1,22 @@ +choice + prompt "choose A or B" + +config A + bool "A" + +config B + bool "B" + +endchoice + +choice + prompt "choose X or Y" + depends on B + +config X + bool "X" + +config Y + bool "Y" + +endchoice diff --git a/scripts/kconfig/tests/choice_randomize/__init__.py b/scripts/kconfig/tests/choice_randomize/__init__.py new file mode 100644 index 000000000000..d380045be79c --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/__init__.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only +""" +Randomize all dependent choices + +This is a somewhat tricky case for randconfig; the visibility of one choice is +determined by a member of another choice. Randconfig should be able to generate +all possible patterns. +""" + + +def test(conf): + + expected0 = False + expected1 = False + expected2 = False + + for i in range(100): + assert conf.randconfig(seed=i) == 0 + + if conf.config_matches('expected_config0'): + expected0 = True + elif conf.config_matches('expected_config1'): + expected1 = True + elif conf.config_matches('expected_config2'): + expected2 = True + else: + assert False + + if expected0 and expected1 and expected2: + break + + assert expected0 + assert expected1 + assert expected2 diff --git a/scripts/kconfig/tests/choice_randomize/expected_config0 b/scripts/kconfig/tests/choice_randomize/expected_config0 new file mode 100644 index 000000000000..f69227323759 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/expected_config0 @@ -0,0 +1,6 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +CONFIG_A=y +# CONFIG_B is not set diff --git a/scripts/kconfig/tests/choice_randomize/expected_config1 b/scripts/kconfig/tests/choice_randomize/expected_config1 new file mode 100644 index 000000000000..bf83784c9b2a --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/expected_config1 @@ -0,0 +1,8 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +# CONFIG_A is not set +CONFIG_B=y +CONFIG_X=y +# CONFIG_Y is not set diff --git a/scripts/kconfig/tests/choice_randomize/expected_config2 b/scripts/kconfig/tests/choice_randomize/expected_config2 new file mode 100644 index 000000000000..38f93a8f37bd --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize/expected_config2 @@ -0,0 +1,8 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +# CONFIG_A is not set +CONFIG_B=y +# CONFIG_X is not set +CONFIG_Y=y -- cgit v1.2.3 From f2fd2aad1908554fbc4ad6e8ef23bad3086bebd1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 21 Mar 2024 01:52:11 +0900 Subject: kconfig: tests: test dependency after shuffling choices Commit c8fb7d7e48d1 ("kconfig: fix broken dependency in randconfig- generated .config") fixed the issue, but I did not add a test case. This commit adds a test case that emulates the reported situation. The test would fail without c8fb7d7e48d1. To handle the choice "choose X", FOO must be calculated beforehand. FOO depends on A, which is a member of another choice "choose A or B". Kconfig _temporarily_ assumes the value of A to proceed. The choice "choose A or B" will be shuffled later, but the result may or may not meet "FOO depends on A". Kconfig should invalidate the symbol values and recompute them. In the real example for ARCH=arm64, the choice "Instrumentation type" needs the value of CPU_BIG_ENDIAN. The choice "Endianness" will be shuffled later. Signed-off-by: Masahiro Yamada --- scripts/kconfig/tests/choice_randomize2/Kconfig | 32 ++++++++++++++++++++++ .../kconfig/tests/choice_randomize2/__init__.py | 18 ++++++++++++ .../tests/choice_randomize2/expected_config0 | 8 ++++++ .../tests/choice_randomize2/expected_config1 | 7 +++++ .../tests/choice_randomize2/expected_config2 | 6 ++++ 5 files changed, 71 insertions(+) create mode 100644 scripts/kconfig/tests/choice_randomize2/Kconfig create mode 100644 scripts/kconfig/tests/choice_randomize2/__init__.py create mode 100644 scripts/kconfig/tests/choice_randomize2/expected_config0 create mode 100644 scripts/kconfig/tests/choice_randomize2/expected_config1 create mode 100644 scripts/kconfig/tests/choice_randomize2/expected_config2 (limited to 'scripts') diff --git a/scripts/kconfig/tests/choice_randomize2/Kconfig b/scripts/kconfig/tests/choice_randomize2/Kconfig new file mode 100644 index 000000000000..530cf2ef7f47 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/Kconfig @@ -0,0 +1,32 @@ +choice + prompt "This is always invisible" + depends on n + +config DUMMY + bool "DUMMY" + +endchoice + +choice + prompt "Choose A or B" + +config A + bool "A" + +config B + bool "B" + +endchoice + +config FOO + bool "FOO" + depends on A + +choice + prompt "Choose X" + depends on FOO + +config X + bool "X" + +endchoice diff --git a/scripts/kconfig/tests/choice_randomize2/__init__.py b/scripts/kconfig/tests/choice_randomize2/__init__.py new file mode 100644 index 000000000000..2066757b80b9 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/__init__.py @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +""" +Randomize choices with correct dependencies + +When shuffling a choice may potentially disrupt certain dependencies, symbol +values must be recalculated. + +Related Linux commits: + - c8fb7d7e48d11520ad24808cfce7afb7b9c9f798 +""" + + +def test(conf): + for i in range(20): + assert conf.randconfig(seed=i) == 0 + assert (conf.config_matches('expected_config0') or + conf.config_matches('expected_config1') or + conf.config_matches('expected_config2')) diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config0 b/scripts/kconfig/tests/choice_randomize2/expected_config0 new file mode 100644 index 000000000000..5c9e1c172c15 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/expected_config0 @@ -0,0 +1,8 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +CONFIG_A=y +# CONFIG_B is not set +CONFIG_FOO=y +CONFIG_X=y diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config1 b/scripts/kconfig/tests/choice_randomize2/expected_config1 new file mode 100644 index 000000000000..5b975d91bef1 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/expected_config1 @@ -0,0 +1,7 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +CONFIG_A=y +# CONFIG_B is not set +# CONFIG_FOO is not set diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config2 b/scripts/kconfig/tests/choice_randomize2/expected_config2 new file mode 100644 index 000000000000..5a5ebb90d1d7 --- /dev/null +++ b/scripts/kconfig/tests/choice_randomize2/expected_config2 @@ -0,0 +1,6 @@ +# +# Automatically generated file; DO NOT EDIT. +# Main menu +# +# CONFIG_A is not set +CONFIG_B=y -- cgit v1.2.3