Skip to contentSkip to conversation

alpha: catch up on architecture Kconfig options

PATCH Superseded Matt Turner 3 participants 56 messages Sep 1 – Sep 6 Alpha port

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Matt Turner

author maintainer
#0 lore raw

cover alpha: catch up on architecture Kconfig options

Alpha is missing a long list of Kconfig options that other architectures have picked up over the years, some of them for no better reason than nobody having gone through the list. I diffed the select statements in every other arch/*/Kconfig against arch/alpha/Kconfig and worked through what turned up. This series is the result: two fixes it depends on, and the options that are either free or close to it.

The patches are ordered from least to most contentious, so the front of the series can be applied on its own if the tail needs discussion.

Patches 1-2 are fixes. arch_irqs_disabled_flags() only reported interrupts as disabled at IPL_MAX, but PALcode enters handlers at the IPL of the interrupt being delivered, so a device or timer handler answered that interrupts were enabled. handle_irq() also called irq_to_desc() before irq_enter(), running generic code with the preempt count still saying task context and RCU not yet watching. Both matter on their own; patches 23 and 24 are what made them visible.

Patches 3-11 are one-line selects with no Alpha code behind them:
instrumentation (UBSAN, gcov, kmemleak), EDAC, and four properties Alpha has always had but never declared (LL/SC atomics, hardware multiply, __int128, the existing asm/compiler.h, and the non-overlapping user and kernel address spaces).

Patches 12-17 add a small amount of code: an empty thread_struct whitelist, _PAGE_SPECIAL on a free PTE bit, the page table check helpers, and then the three things that follow from those - the page table helper self test, lockless GUP, and the early memtest. Note that early_memtest() is called from arch_mm_preinit() rather than paging_init(), because Alpha calls paging_init() from setup_arch(), before parse_early_param() has seen the memtest= option.

Patches 18-20 change something visible. Unhandled user faults now print the usual message under the debug.exception-trace sysctl. .eh_frame is
discarded: gcc emits it for Alpha regardless of -fno-asynchronous-unwind-tables, it was allocated in the loaded image, and nothing consumes it, since the stack trace code scans for text addresses rather than unwinding DWARF. That is worth about 1.1MB. With that and the relocation sections placed explicitly, the kernel links with no orphans left, so the last of the three asks the linker to say so.

Patches 21-24 are the ones I expect to draw comment. Patch 22 adds a uapi header, so the perf register numbering is an ABI decision. Patch 23 is SPARSE_IRQ: without it Marvel carries a 12.6MB static irq_desc[] in .data for 32768 possible interrupts, of which a real ES47 uses 87, and the kernel links at a fixed address just above the console reservation where that 12.6MB is the difference between fitting and not. Patch 24 instruments the entry assembly for lockdep hardirq tracking.

Tested with gcc 17 under QEMU (-M clipper -smp 2, an ALPHA_GENERIC build) with PROVE_LOCKING enabled: no splats, early_memtest passes all four patterns over the free memblock ranges with nothing reserved, debug_vm_pgtable validates with no warning, a vmsplice() of an anonymous mapping through pin_user_pages_fast() returns the right data, and an unhandled SIGSEGV prints the new trace line. Patch 23 was tested on an AlphaServer ES47.

Not included, and worth mentioning: ARCH_HAS_KCOV. A kernel with KCOV_INSTRUMENT_ALL boots and runs, but CONFIG_KCOV_SELFTEST panics. The self test deliberately arms kcov with no coverage area so that any instrumented function reached from interrupt context faults, checking that nothing escapes the window before the preempt count says hardirq. On Alpha something does. Patch 2 fixes one such site; the panic survives it, so the entry paths need an audit first.

Also available at:

git://git.kernel.org/pub/scm/linux/kernel/git/mattst88/alpha.git arch-kconfig-options

Matt Turner (24):
alpha: fix arch_irqs_disabled_flags() to treat any raised IPL as
disabled
alpha: enter hardirq context before looking up the irq descriptor
alpha: select ARCH_HAS_UBSAN
alpha: select ARCH_HAS_GCOV_PROFILE_ALL
alpha: select HAVE_DEBUG_KMEMLEAK
alpha: select EDAC_SUPPORT
alpha: select ARCH_SUPPORTS_ATOMIC_RMW
alpha: select ARCH_HAS_FAST_MULTIPLIER
alpha: select ARCH_SUPPORTS_INT128
alpha: select HAVE_ARCH_COMPILER_H
alpha: select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
alpha: add HAVE_ARCH_THREAD_STRUCT_WHITELIST support
alpha: add ARCH_HAS_PTE_SPECIAL support
alpha: add ARCH_SUPPORTS_PAGE_TABLE_CHECK support
alpha: select ARCH_HAS_DEBUG_VM_PGTABLE
alpha: select HAVE_GUP_FAST
alpha: select ARCH_USE_MEMTEST
alpha: select SYSCTL_EXCEPTION_TRACE
alpha: discard .eh_frame and the relocation sections
alpha: select ARCH_WANT_LD_ORPHAN_WARN
alpha: select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
alpha: add HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP support
alpha: select SPARSE_IRQ
alpha: add TRACE_IRQFLAGS_SUPPORT

 arch/alpha/Kconfig                      | 21 ++++++
 arch/alpha/include/asm/irqflags.h       |  2 +-
 arch/alpha/include/asm/perf_regs.h      |  7 ++
 arch/alpha/include/asm/pgtable.h        | 21 +++++-
 arch/alpha/include/asm/processor.h      |  7 ++
 arch/alpha/include/uapi/asm/perf_regs.h | 34 ++++++++++
 arch/alpha/kernel/Makefile              |  1 +

arch/alpha/kernel/entry.S | 54 +++++++++++++Matt Turner (24):
alpha: fix arch_irqs_disabled_flags() to treat any raised IPL as
disabled
alpha: enter hardirq context before looking up the irq descriptor
alpha: select ARCH_HAS_UBSAN
alpha: select ARCH_HAS_GCOV_PROFILE_ALL
alpha: select HAVE_DEBUG_KMEMLEAK
alpha: select EDAC_SUPPORT
alpha: select ARCH_SUPPORTS_ATOMIC_RMW
alpha: select ARCH_HAS_FAST_MULTIPLIER
alpha: select ARCH_SUPPORTS_INT128
alpha: select HAVE_ARCH_COMPILER_H
alpha: select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
alpha: add HAVE_ARCH_THREAD_STRUCT_WHITELIST support
alpha: add ARCH_HAS_PTE_SPECIAL support
alpha: add ARCH_SUPPORTS_PAGE_TABLE_CHECK support
alpha: select ARCH_HAS_DEBUG_VM_PGTABLE
alpha: select HAVE_GUP_FAST
alpha: select ARCH_USE_MEMTEST
alpha: select SYSCTL_EXCEPTION_TRACE
alpha: discard .eh_frame and the relocation sections
alpha: select ARCH_WANT_LD_ORPHAN_WARN
alpha: select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
alpha: add HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP support
alpha: select SPARSE_IRQ
alpha: add TRACE_IRQFLAGS_SUPPORT

 arch/alpha/Kconfig                      | 21 ++++++
 arch/alpha/include/asm/irqflags.h       |  2 +-
 arch/alpha/include/asm/perf_regs.h      |  7 ++
 arch/alpha/include/asm/pgtable.h        | 21 +++++-
 arch/alpha/include/asm/processor.h      |  7 ++
 arch/alpha/include/uapi/asm/perf_regs.h | 34 ++++++++++
 arch/alpha/kernel/Makefile              |  1 +
 arch/alpha/kernel/entry.S               | 54 +++++++++++++---
 arch/alpha/kernel/irq.c                 |  9 ++-
 arch/alpha/kernel/irq_alpha.c           | 13 ++++
 arch/alpha/kernel/perf_regs.c           | 86 +++++++++++++++++++++++++
 arch/alpha/kernel/vmlinux.lds.S         | 11 ++++
 arch/alpha/mm/fault.c                   | 29 +++++++++
 arch/alpha/mm/init.c                    |  5 ++
 14 files changed, 287 insertions(+), 13 deletions(-)
 create mode 100644 arch/alpha/include/asm/perf_regs.h
 create mode 100644 arch/alpha/include/uapi/asm/perf_regs.h
 create mode 100644 arch/alpha/kernel/perf_regs.c
Signature · 1 line
2.54.0
author maintainer
#1 lore raw

PATCH 1/24 alpha: fix arch_irqs_disabled_flags() to treat any raised IPL as disabled

arch_irqs_disabled_flags() only reported interrupts as disabled at IPL_MAX, but the kernel is not the only thing that sets the IPL. PALcode raises PS.IPL to the level of the interrupt being delivered before entering the handler, so a handler entered for a device interrupt runs at IPL_DEV0 or IPL_DEV1, and the timer at IPL_TIMER. Interrupts at and below that level are blocked, but arch_irqs_disabled() answered that interrupts were enabled.

Treat any IPL above IPL_MIN, the level arch_local_irq_enable() restores, as interrupts disabled. This matters as soon as lockdep is asked to track hardirq state, where irqs_disabled() is expected to be true inside an interrupt handler.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/include/asm/irqflags.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/alpha/include/asm/irqflags.h +1 -1
index f207544f52de..ebbf5801f7a5 100644
@@ -57,7 +57,7 @@ static inline void arch_local_irq_restore(unsigned long flags)
 
 static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
-	return (flags & 7) == IPL_MAX;
+	return (flags & 7) > IPL_MIN;
 }
 
 static inline bool arch_irqs_disabled(void)
Signature · 1 line
2.54.0
author maintainer
#3 lore raw

PATCH 2/24 alpha: enter hardirq context before looking up the irq descriptor

In reply to Matt Turner

handle_irq() called irq_to_desc() before irq_enter(), so that lookup ran with the preempt count still saying task context and with RCU not yet watching. Generic code called from an interrupt handler should see hardirq context, and irq_to_desc() is more than an array index once SPARSE_IRQ is in use.

Move irq_enter() to the top of the function and add the matching irq_exit() to the invalid interrupt path.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/kernel/irq.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
arch/alpha/kernel/irq.c +6 -3
index 4a6a8b1d5a8b..5867a1655045 100644
@@ -107,18 +107,21 @@ handle_irq(int irq)
 	 * handled by some other CPU. (or is disabled)
 	 */
 	static unsigned int illegal_count=0;
-	struct irq_desc *desc = irq_to_desc(irq);
-	
+	struct irq_desc *desc;
+
+	irq_enter();
+
+	desc = irq_to_desc(irq);
 	if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
 	    illegal_count < MAX_ILLEGAL_IRQS)) {
 		irq_err_count++;
 		illegal_count++;
 		printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
 		       irq);
+		irq_exit();
 		return;
 	}
 
-	irq_enter();
 	generic_handle_irq_desc(desc);
 	irq_exit();
 }
Signature · 1 line
2.54.0
author maintainer
#7 lore raw

PATCH 3/24 alpha: select ARCH_HAS_UBSAN

In reply to Matt Turner

GCC's undefined behavior sanitizer has no architecture-specific runtime requirements. Enable it for Alpha to allow UBSAN instrumentation of the kernel.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index e53ef2d88463..1aa76a2d9750 100644
@@ -5,6 +5,7 @@ config ALPHA
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_OPS if PCI
+	select ARCH_HAS_UBSAN
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
 	select ARCH_MODULE_NEEDS_WEAK_PER_CPU if SMP
Signature · 1 line
2.54.0
author maintainer
#12 lore raw

PATCH 4/24 alpha: select ARCH_HAS_GCOV_PROFILE_ALL

In reply to Matt Turner

GCC's gcov instrumentation (-fprofile-arcs -ftest-coverage) has no architecture-specific runtime requirements. Enable GCOV_PROFILE_ALL support for Alpha to allow whole-kernel code coverage analysis.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 1aa76a2d9750..a6024590ea6e 100644
@@ -5,6 +5,7 @@ config ALPHA
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_OPS if PCI
+	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_UBSAN
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
Signature · 1 line
2.54.0
author maintainer
#14 lore raw

PATCH 5/24 alpha: select HAVE_DEBUG_KMEMLEAK

In reply to Matt Turner

Kmemleak needs no architecture support beyond the standard linker script symbols for the data and bss sections, which Alpha already provides, and a scan of the kernel stacks, which is done generically.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index a6024590ea6e..a435b71203f0 100644
@@ -17,6 +17,7 @@ config ALPHA
 	select PCI_DOMAINS if PCI
 	select PCI_SYSCALL if PCI
 	select HAVE_ASM_MODVERSIONS
+	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_PAGE_SIZE_8KB
 	select HAVE_PCSPKR_PLATFORM
 	select HAVE_PERF_EVENTS
Signature · 1 line
2.54.0
author maintainer
#16 lore raw

PATCH 6/24 alpha: select EDAC_SUPPORT

In reply to Matt Turner

The EDAC core builds and works on Alpha; it only needs the architecture to declare support. There is no Alpha memory controller driver yet, but the core is what a future driver, or the existing machine check error decoding in err_ev6.c and err_ev7.c, would report through.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index a435b71203f0..d2f9ef592f78 100644
@@ -30,6 +30,7 @@ config ALPHA
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select AUDIT_ARCH
+	select EDAC_SUPPORT
 	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_SMP_IDLE_THREAD
 	select HAS_IOPORT
Signature · 1 line
2.54.0
author maintainer
#18 lore raw

PATCH 7/24 alpha: select ARCH_SUPPORTS_ATOMIC_RMW

In reply to Matt Turner

Alpha has native LL/SC instructions (LDL_L/STL_C, LDQ_L/STQ_C) that provide atomic read-modify-write capability, and already selects ARCH_HAVE_NMI_SAFE_CMPXCHG.

Selecting ARCH_SUPPORTS_ATOMIC_RMW enables MUTEX_SPIN_ON_OWNER and RWSEM_SPIN_ON_OWNER on SMP, allowing optimistic spinning on contended locks rather than immediately sleeping.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index d2f9ef592f78..0655e36608cc 100644
@@ -12,6 +12,7 @@ config ALPHA
 	select ARCH_MODULE_NEEDS_WEAK_PER_CPU if SMP
 	select ARCH_NO_PREEMPT
 	select ARCH_NO_SG_CHAIN
+	select ARCH_SUPPORTS_ATOMIC_RMW
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select FORCE_PCI
 	select PCI_DOMAINS if PCI
Signature · 1 line
2.54.0
author maintainer
#20 lore raw

PATCH 8/24 alpha: select ARCH_HAS_FAST_MULTIPLIER

In reply to Matt Turner

All Alpha CPUs have hardware integer multiply (MULL/MULQ). EV4 and EV5 implement it in microcode; EV56 and later have fast single-cycle multiply. Since no EV4 system is likely to run a modern kernel, select this unconditionally to enable multiply-based fast paths in hweight and string routines.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 0655e36608cc..9e8e571949c4 100644
@@ -5,6 +5,7 @@ config ALPHA
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DMA_OPS if PCI
+	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_UBSAN
 	select ARCH_MIGHT_HAVE_PC_PARPORT
Signature · 1 line
2.54.0
author maintainer
#22 lore raw

PATCH 9/24 alpha: select ARCH_SUPPORTS_INT128

In reply to Matt Turner

gcc supports __int128 on Alpha, and the 64x64 to 128-bit multiply that the users in the scheduler and in lib/ care about maps onto mulq/umulh rather than an out-of-line libgcc helper.

Gate the select on CC_HAS_INT128 as the other 64-bit architectures do.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 9e8e571949c4..00365031ea6e 100644
@@ -14,6 +14,7 @@ config ALPHA
 	select ARCH_NO_PREEMPT
 	select ARCH_NO_SG_CHAIN
 	select ARCH_SUPPORTS_ATOMIC_RMW
+	select ARCH_SUPPORTS_INT128 if CC_HAS_INT128
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select FORCE_PCI
 	select PCI_DOMAINS if PCI
Signature · 1 line
2.54.0
author maintainer
#24 lore raw

PATCH 10/24 alpha: select HAVE_ARCH_COMPILER_H

In reply to Matt Turner

Alpha already provides asm/compiler.h (wrapping uapi/asm/compiler.h) which defines architecture-specific compiler intrinsics like __kernel_cmpbge, __kernel_cttz, __kernel_ctlz, and __kernel_ctpop.

Selecting HAVE_ARCH_COMPILER_H causes linux/compiler_types.h to include asm/compiler.h, making these definitions available consistently.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 00365031ea6e..6ccd03768083 100644
@@ -19,6 +19,7 @@ config ALPHA
 	select FORCE_PCI
 	select PCI_DOMAINS if PCI
 	select PCI_SYSCALL if PCI
+	select HAVE_ARCH_COMPILER_H
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_PAGE_SIZE_8KB
Signature · 1 line
2.54.0
author maintainer
#26 lore raw

PATCH 11/24 alpha: select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE

In reply to Matt Turner

Alpha has a clean split between user and kernel address spaces: user space occupies 0x0000000000000000-0x000003ffffffffff (TASK_SIZE), while kernel space uses KSEG and vmalloc regions near the top of the 64-bit address space. These are strictly non-overlapping.

This enables optimizations in BPF and tracing that can skip address range checks when user and kernel pointers are distinguishable by address alone.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 6ccd03768083..2ae514bea4cf 100644
@@ -7,6 +7,7 @@ config ALPHA
 	select ARCH_HAS_DMA_OPS if PCI
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_GCOV_PROFILE_ALL
+	select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
 	select ARCH_HAS_UBSAN
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
Signature · 1 line
2.54.0
author maintainer
#28 lore raw

PATCH 12/24 alpha: add HAVE_ARCH_THREAD_STRUCT_WHITELIST support

In reply to Matt Turner

Alpha's thread_struct is empty (all per-thread state lives in thread_info), so the whitelist is trivially empty. This is more explicit than the generic fallback, which computes the full thread_struct size as copyable.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig                 | 1 +
 arch/alpha/include/asm/processor.h | 7 +++++++
 2 files changed, 8 insertions(+)
arch/alpha/Kconfig +1 -0
index 2ae514bea4cf..e6fa8da0abff 100644
@@ -42,6 +42,7 @@ config ALPHA
 	select HAVE_ARCH_AUDITSYSCALL
 	select HAVE_ARCH_SECCOMP
 	select HAVE_ARCH_SECCOMP_FILTER
+	select HAVE_ARCH_THREAD_STRUCT_WHITELIST
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_MOD_ARCH_SPECIFIC
 	select LOCK_MM_AND_FIND_VMA
arch/alpha/include/asm/processor.h +7 -0
index 5dce5518a211..c461a26d47b3 100644
@@ -26,6 +26,13 @@
 struct thread_struct { };
 #define INIT_THREAD  { }
 
+static inline void arch_thread_struct_whitelist(unsigned long *offset,
+						unsigned long *size)
+{
+	*offset = 0;
+	*size = 0;
+}
+
 /* Do necessary setup to start up a newly executed thread.  */
 struct pt_regs;
 extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
Signature · 1 line
2.54.0
author maintainer
#30 lore raw

PATCH 13/24 alpha: add ARCH_HAS_PTE_SPECIAL support

In reply to Matt Turner

Add _PAGE_SPECIAL using bit 19 (0x80000), which is unused in the Alpha PTE layout. This enables pte_special()/pte_mkspecial() for marking PTEs that are not backed by struct page (VDSO mappings, zero page, io_remap_pfn_range, etc.).

Include _PAGE_SPECIAL in _PAGE_CHG_MASK so it is preserved across pte_modify() calls.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig               | 1 +
 arch/alpha/include/asm/pgtable.h | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)
arch/alpha/Kconfig +1 -0
index e6fa8da0abff..4c38405cd6cd 100644
@@ -8,6 +8,7 @@ config ALPHA
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_GCOV_PROFILE_ALL
 	select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
+	select ARCH_HAS_PTE_SPECIAL
 	select ARCH_HAS_UBSAN
 	select ARCH_MIGHT_HAVE_PC_PARPORT
 	select ARCH_MIGHT_HAVE_PC_SERIO
arch/alpha/include/asm/pgtable.h +4 -1
index 8e00cf9dc39d..bdff33b505bc 100644
@@ -73,6 +73,7 @@ struct vm_area_struct;
 /* .. and these are ours ... */
 #define _PAGE_DIRTY	0x20000
 #define _PAGE_ACCESSED	0x40000
+#define _PAGE_SPECIAL	0x80000
 
 /* We borrow bit 39 to store the exclusive marker in swap PTEs. */
 #define _PAGE_SWP_EXCLUSIVE	0x8000000000UL
@@ -94,7 +95,7 @@ struct vm_area_struct;
 #define _PFN_MASK	0xFFFFFFFF00000000UL
 
 #define _PAGE_TABLE	(_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
-#define _PAGE_CHG_MASK	(_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
+#define _PAGE_CHG_MASK	(_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_SPECIAL)
 
 /*
  * All the normal masks have the "page accessed" bits on, as any time they are used,
@@ -238,6 +239,8 @@ extern inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~(__ACCESS_BITS); ret
 extern inline pte_t pte_mkwrite_novma(pte_t pte){ pte_val(pte) &= ~_PAGE_FOW; return pte; }
 extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= __DIRTY_BITS; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= __ACCESS_BITS; return pte; }
+extern inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
+extern inline pte_t pte_mkspecial(pte_t pte)	{ pte_val(pte) |= _PAGE_SPECIAL; return pte; }
 
 /*
  * The smp_rmb() in the following functions are required to order the load of
Signature · 1 line
2.54.0
author maintainer
#32 lore raw

PATCH 14/24 alpha: add ARCH_SUPPORTS_PAGE_TABLE_CHECK support

In reply to Matt Turner

Add the page table check helpers needed for CONFIG_PAGE_TABLE_CHECK and select ARCH_SUPPORTS_PAGE_TABLE_CHECK in Kconfig.

Alpha does not support huge pages, so pmd_user_accessible_page() and pud_user_accessible_page() always return false. pte_user_accessible_page() checks for present PTEs with user read access (_PAGE_URE).

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig               |  1 +
 arch/alpha/include/asm/pgtable.h | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)
arch/alpha/Kconfig +1 -0
index 4c38405cd6cd..d7e2859aaedb 100644
@@ -17,6 +17,7 @@ config ALPHA
 	select ARCH_NO_SG_CHAIN
 	select ARCH_SUPPORTS_ATOMIC_RMW
 	select ARCH_SUPPORTS_INT128 if CC_HAS_INT128
+	select ARCH_SUPPORTS_PAGE_TABLE_CHECK
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select FORCE_PCI
 	select PCI_DOMAINS if PCI
arch/alpha/include/asm/pgtable.h +16 -0
index bdff33b505bc..310361920a1f 100644
@@ -232,6 +232,22 @@ extern inline void pud_clear(pud_t * pudp)	{ pud_val(*pudp) = 0; }
 extern inline int pte_write(pte_t pte)		{ return !(pte_val(pte) & _PAGE_FOW); }
 extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_user(pte_t pte)		{ return pte_val(pte) & _PAGE_URE; }
+
+static inline bool pte_user_accessible_page(pte_t pte, unsigned long addr)
+{
+	return pte_present(pte) && pte_user(pte);
+}
+
+static inline bool pmd_user_accessible_page(pmd_t pmd, unsigned long addr)
+{
+	return false;
+}
+
+static inline bool pud_user_accessible_page(pud_t pud, unsigned long addr)
+{
+	return false;
+}
 
 extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOW; return pte; }
 extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
Signature · 1 line
2.54.0
author maintainer
#34 lore raw

PATCH 15/24 alpha: select ARCH_HAS_DEBUG_VM_PGTABLE

In reply to Matt Turner

CONFIG_DEBUG_VM_PGTABLE runs a boot-time self test over the page table
helpers: the protection bit accessors, pte_modify(), the swap entry encoding including the exclusive marker, and, where the architecture supports them, the huge page helpers. Alpha implements everything the test needs for a three-level page table without huge page support.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index d7e2859aaedb..87fe81bc4709 100644
@@ -4,6 +4,7 @@ config ALPHA
 	default y
 	select ARCH_32BIT_USTAT_F_TINODE
 	select ARCH_HAS_CURRENT_STACK_POINTER
+	select ARCH_HAS_DEBUG_VM_PGTABLE
 	select ARCH_HAS_DMA_OPS if PCI
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_GCOV_PROFILE_ALL
Signature · 1 line
2.54.0
author maintainer
#36 lore raw

PATCH 16/24 alpha: select HAVE_GUP_FAST

In reply to Matt Turner

The lockless GUP fast path needs the architecture to distinguish PTEs with no struct page behind them and to keep page table pages alive while a walker holds no lock. Alpha now has ARCH_HAS_PTE_SPECIAL, and it has selected MMU_GATHER_RCU_TABLE_FREE for a long time, so both requirements are met.

PTEs are a single 64-bit word on Alpha, so the lockless reads that the generic walker performs cannot tear, and no arch-specific gup_fast_permitted() or ptep_get_lockless() is needed.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 87fe81bc4709..352615956b1e 100644
@@ -26,6 +26,7 @@ config ALPHA
 	select HAVE_ARCH_COMPILER_H
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_DEBUG_KMEMLEAK
+	select HAVE_GUP_FAST
 	select HAVE_PAGE_SIZE_8KB
 	select HAVE_PCSPKR_PLATFORM
 	select HAVE_PERF_EVENTS
Signature · 1 line
2.54.0
author maintainer
#38 lore raw

PATCH 17/24 alpha: select ARCH_USE_MEMTEST

In reply to Matt Turner

Wire up the generic early memtest from arch_mm_preinit(), which runs after parse_early_param() has picked up the memtest= command line option and before memblock_free_all() hands the memory to the buddy allocator. paging_init() would be the natural place, but Alpha calls it from setup_arch(), before the option is parsed, so the test would never run.

The test range starts at the first DRAM address rather than physical zero because low memory on Alpha is owned by the console and PALcode.

Tested under QEMU with memtest=4: all four patterns pass over the free memblock ranges, with no bad memory reserved.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig   | 1 +
 arch/alpha/mm/init.c | 5 +++++
 2 files changed, 6 insertions(+)
arch/alpha/Kconfig +1 -0
index 352615956b1e..c4b4a9b8d770 100644
@@ -20,6 +20,7 @@ config ALPHA
 	select ARCH_SUPPORTS_INT128 if CC_HAS_INT128
 	select ARCH_SUPPORTS_PAGE_TABLE_CHECK
 	select ARCH_USE_CMPXCHG_LOCKREF
+	select ARCH_USE_MEMTEST
 	select FORCE_PCI
 	select PCI_DOMAINS if PCI
 	select PCI_SYSCALL if PCI
arch/alpha/mm/init.c +5 -0
index f4d65a60c869..6c28947d6e2d 100644
@@ -226,6 +226,11 @@ void __init paging_init(void)
 	memset(absolute_pointer(ZERO_PGE), 0, PAGE_SIZE);
 }
 
+void __init arch_mm_preinit(void)
+{
+	early_memtest(memblock_start_of_DRAM(), PFN_PHYS(max_low_pfn));
+}
+
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
 void
 srm_paging_stop (void)
Signature · 1 line
2.54.0
author maintainer
#40 lore raw

PATCH 18/24 alpha: select SYSCTL_EXCEPTION_TRACE

In reply to Matt Turner

Report unhandled user faults the way other architectures do, and hook up the debug.exception-trace sysctl that controls the reporting.

The message gives the faulting address, the PC and the user stack pointer, and is rate limited.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig    |  1 +
 arch/alpha/mm/fault.c | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)
arch/alpha/Kconfig +1 -0
index c4b4a9b8d770..4c60c442207c 100644
@@ -59,6 +59,7 @@ config ALPHA
 	select MMU_GATHER_NO_RANGE
 	select MMU_GATHER_RCU_TABLE_FREE
 	select SPARSEMEM_EXTREME if SPARSEMEM
+	select SYSCTL_EXCEPTION_TRACE
 	select ZONE_DMA
 	select TRACE_IRQFLAGS_SUPPORT
 	select ARCH_WANT_FRAME_POINTERS
arch/alpha/mm/fault.c +29 -0
index a9816bbc9f34..dfe427d93072 100644
@@ -27,8 +27,32 @@
 #include <linux/uaccess.h>
 #include <linux/perf_event.h>
 
+#include <asm/pal.h>
+
 extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);
 
+int show_unhandled_signals = 1;
+
+static void
+show_signal_msg(struct pt_regs *regs, unsigned long address, int signo,
+		const char *desc)
+{
+	const char *level;
+
+	if (!show_unhandled_signals || !unhandled_signal(current, signo))
+		return;
+	if (!printk_ratelimit())
+		return;
+
+	/* Losing init is fatal, so shout about it.  */
+	level = task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG;
+
+	printk("%s%s[%d]: %s at %016lx pc %016lx sp %016lx\n",
+	       level, current->comm, task_pid_nr(current), desc,
+	       address, regs->pc, rdusp());
+	print_vma_addr(KERN_CONT "  in ", regs->pc);
+	printk(KERN_CONT "\n");
+}
 
 /*
  * Force a new ASN for a task.
@@ -217,12 +241,17 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
 	mmap_read_unlock(mm);
 	/* Send a sigbus, regardless of whether we were in kernel
 	   or user mode.  */
+	if (user_mode(regs))
+		show_signal_msg(regs, address, SIGBUS, "bus error");
 	force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *) address);
 	if (!user_mode(regs))
 		goto no_context;
 	return;
 
  do_sigsegv:
+	show_signal_msg(regs, address, SIGSEGV,
+			si_code == SEGV_MAPERR ? "unmapped access"
+					       : "access violation");
 	force_sig_fault(SIGSEGV, si_code, (void __user *) address);
 	return;
 
Signature · 1 line
2.54.0
author maintainer
#42 lore raw

PATCH 19/24 alpha: discard .eh_frame and the relocation sections

In reply to Matt Turner

gcc emits .eh_frame for Alpha even though the kernel builds with -fno-asynchronous-unwind-tables, and nothing in the kernel consumes it:
the stack trace code scans the stack for text addresses rather than unwinding DWARF. It was allocated in the loaded image, so dropping it shrinks vmlinux by about 1.1MB for a Marvel SMP configuration.

The .rela* sections are equally useless, as the kernel image is not relocatable. The linker was already dropping their contents.

Both were being placed as orphan sections, which is what drew attention to them.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/kernel/vmlinux.lds.S | 11 +++++++++++
 1 file changed, 11 insertions(+)
arch/alpha/kernel/vmlinux.lds.S +11 -0
index 95704e64b6a6..c44941d3b874 100644
@@ -76,5 +76,16 @@ SECTIONS
 	MODINFO
 	ELF_DETAILS
 
+	/*
+	 * gcc emits .eh_frame for Alpha even with
+	 * -fno-asynchronous-unwind-tables, and the kernel has no DWARF
+	 * unwinder to consume it.  The relocation sections are likewise
+	 * useless as the kernel image is not relocatable.
+	 */
+	/DISCARD/ : {
+		*(.eh_frame)
+		*(.rela .rela*)
+	}
+
 	DISCARDS
 }
Signature · 1 line
2.54.0
author maintainer
#44 lore raw

PATCH 20/24 alpha: select ARCH_WANT_LD_ORPHAN_WARN

In reply to Matt Turner

With .eh_frame and the relocation sections now placed explicitly, an Alpha kernel links with no orphan sections left, so ask the linker to warn if new ones appear.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 4c60c442207c..827b224f2f8a 100644
@@ -38,6 +38,7 @@ config ALPHA
 	select AUTO_IRQ_AFFINITY if SMP
 	select GENERIC_IRQ_SHOW
 	select ARCH_WANT_IPC_PARSE_VERSION
+	select ARCH_WANT_LD_ORPHAN_WARN
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select AUDIT_ARCH
 	select EDAC_SUPPORT
Signature · 1 line
2.54.0
author maintainer
#46 lore raw

PATCH 21/24 alpha: select ARCH_WANT_IRQS_OFF_ACTIVATE_MM

In reply to Matt Turner

activate_mm() on Alpha calls __load_new_mm_context() which assigns a new ASID and invokes PALcode swpctx. On SMP, an interrupt arriving between the ASID update and the page table switch could see inconsistent state. Ensure activate_mm() is called with interrupts disabled during exec.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -0
index 827b224f2f8a..bda8443a7323 100644
@@ -37,6 +37,7 @@ config ALPHA
 	select GENERIC_PCI_IOMAP
 	select AUTO_IRQ_AFFINITY if SMP
 	select GENERIC_IRQ_SHOW
+	select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
 	select ARCH_WANT_IPC_PARSE_VERSION
 	select ARCH_WANT_LD_ORPHAN_WARN
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
Signature · 1 line
2.54.0
author maintainer
#48 lore raw

PATCH 22/24 alpha: add HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP support

In reply to Matt Turner

Implement the perf register sampling interface for Alpha. This enables perf to capture register state and user stack dumps with samples, supporting --call-graph dwarf.

The perf_regs enum exposes the registers available in pt_regs: r0-r8, r16-r28, gp, pc, and ps. Registers r9-r15 are callee-saved and live in switch_stack, not pt_regs, so they are not included.

A switch statement maps perf register indices to pt_regs fields since Alpha's pt_regs layout is non-contiguous (unlike architectures where direct array indexing works).

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig                      |  2 +
 arch/alpha/include/asm/perf_regs.h      |  7 ++
 arch/alpha/include/uapi/asm/perf_regs.h | 34 ++++++++++
 arch/alpha/kernel/Makefile              |  1 +
 arch/alpha/kernel/perf_regs.c           | 86 +++++++++++++++++++++++++
 5 files changed, 130 insertions(+)
 create mode 100644 arch/alpha/include/asm/perf_regs.h
 create mode 100644 arch/alpha/include/uapi/asm/perf_regs.h
 create mode 100644 arch/alpha/kernel/perf_regs.c
arch/alpha/Kconfig +2 -0
index bda8443a7323..74d13a29b8a9 100644
@@ -31,6 +31,8 @@ config ALPHA
 	select HAVE_PAGE_SIZE_8KB
 	select HAVE_PCSPKR_PLATFORM
 	select HAVE_PERF_EVENTS
+	select HAVE_PERF_REGS
+	select HAVE_PERF_USER_STACK_DUMP
 	select NEED_DMA_MAP_STATE
 	select NEED_SG_DMA_LENGTH
 	select GENERIC_IRQ_PROBE
arch/alpha/include/asm/perf_regs.h new file +7 -0
new file mode 100644
index 000000000000..6045da1a2a4f
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ALPHA_PERF_REGS_H
+#define _ASM_ALPHA_PERF_REGS_H
+
+#include <uapi/asm/perf_regs.h>
+
+#endif /* _ASM_ALPHA_PERF_REGS_H */
arch/alpha/include/uapi/asm/perf_regs.h new file +34 -0
new file mode 100644
index 000000000000..afeb6a1584cd
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_ALPHA_PERF_REGS_H
+#define _UAPI_ASM_ALPHA_PERF_REGS_H
+
+enum perf_event_alpha_regs {
+	PERF_REG_ALPHA_R0,
+	PERF_REG_ALPHA_R1,
+	PERF_REG_ALPHA_R2,
+	PERF_REG_ALPHA_R3,
+	PERF_REG_ALPHA_R4,
+	PERF_REG_ALPHA_R5,
+	PERF_REG_ALPHA_R6,
+	PERF_REG_ALPHA_R7,
+	PERF_REG_ALPHA_R8,
+	PERF_REG_ALPHA_R16,
+	PERF_REG_ALPHA_R17,
+	PERF_REG_ALPHA_R18,
+	PERF_REG_ALPHA_R19,
+	PERF_REG_ALPHA_R20,
+	PERF_REG_ALPHA_R21,
+	PERF_REG_ALPHA_R22,
+	PERF_REG_ALPHA_R23,
+	PERF_REG_ALPHA_R24,
+	PERF_REG_ALPHA_R25,
+	PERF_REG_ALPHA_R26,
+	PERF_REG_ALPHA_R27,
+	PERF_REG_ALPHA_R28,
+	PERF_REG_ALPHA_GP,
+	PERF_REG_ALPHA_PC,
+	PERF_REG_ALPHA_PS,
+	PERF_REG_ALPHA_MAX,
+};
+
+#endif /* _UAPI_ASM_ALPHA_PERF_REGS_H */
arch/alpha/kernel/Makefile +1 -0
index 4ea5c189e60e..0c04b89676ed 100644
@@ -18,6 +18,7 @@ obj-$(CONFIG_PCI)	+= pci.o pci_iommu.o pci-sysfs.o
 obj-$(CONFIG_SRM_ENV)	+= srm_env.o
 obj-$(CONFIG_MODULES)	+= module.o
 obj-$(CONFIG_PERF_EVENTS) += perf_event.o
+obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o
 obj-$(CONFIG_RTC_DRV_ALPHA) += rtc.o
 obj-$(CONFIG_AUDIT)	+= audit.o
 
arch/alpha/kernel/perf_regs.c new file +86 -0

86 lines not on this page · raw message

Signature · 1 line
2.54.0
author maintainer
#50 lore raw

PATCH 23/24 alpha: select SPARSE_IRQ

In reply to Matt Turner

NR_IRQS on Alpha is sized for the largest configuration each platform supports, and for Marvel that is 32 PIDs, or 32784 interrupts. Without SPARSE_IRQ that becomes a static irq_desc[] array of 12.6 MB in .data, carried by every Marvel and every generic kernel regardless of how many interrupts the machine actually has. A real ES47 uses 87 of them.

That is not just wasted memory, it constrains where the kernel can be loaded. The image links at a fixed 0xfffffc0001010000, just above the console's low memory reservation, and with memory striping enabled the console leaves only about 16 MB of usable low memory before the rest is relocated to an interleaved aperture. A 12.6 MB array of mostly unused interrupt descriptors is the difference between fitting and not.

Alpha already goes through irq_to_desc() rather than indexing irq_desc[] directly, so nothing stands in the way. The platforms do wire up their interrupts by number, though, which needs the descriptors to exist by then, so provide arch_probe_nr_irqs() returning the machine vector's count instead of taking the NR_IRQS_LEGACY default. Without it every interrupt above 15 would have no descriptor and the handler setup would be silently dropped.

Tested on an ES47 (Marvel, 2 EV7z): boots with all device interrupts working, and .data drops by 12.6 MB, from 15.7 MB to 3.1 MB.

---
 arch/alpha/Kconfig            |  1 +
 arch/alpha/kernel/irq_alpha.c | 13 +++++++++++++
 2 files changed, 14 insertions(+)
arch/alpha/Kconfig +1 -0
index 74d13a29b8a9..06c3e55f01f2 100644
@@ -62,6 +62,7 @@ config ALPHA
 	select CPU_NO_EFFICIENT_FFS if !ALPHA_EV67
 	select MMU_GATHER_NO_RANGE
 	select MMU_GATHER_RCU_TABLE_FREE
+	select SPARSE_IRQ
 	select SPARSEMEM_EXTREME if SPARSEMEM
 	select SYSCTL_EXCEPTION_TRACE
 	select ZONE_DMA
arch/alpha/kernel/irq_alpha.c +13 -0
index 1b799aafb7dc..3274568d6d52 100644
@@ -148,6 +148,19 @@ common_init_isa_dma(void)
 	outb(0, DMA2_CLR_MASK_REG);
 }
 
+/*
+ * The platforms wire up their interrupts by calling into the generic irq
+ * code with fixed interrupt numbers, so the descriptors have to exist by
+ * then.  Preallocate the machine's full complement rather than take the
+ * NR_IRQS_LEGACY default, which would leave everything above IRQ 15
+ * without a descriptor and silently drop the handler setup.
+ */
+int __init
+arch_probe_nr_irqs(void)
+{
+	return alpha_mv.nr_irqs;
+}
+
 void __init
 init_IRQ(void)
 {
Signature · 1 line
2.54.0
author maintainer
#52 lore raw

PATCH 24/24 alpha: add TRACE_IRQFLAGS_SUPPORT

In reply to Matt Turner

Instrument the entry/exit assembly to track hardirq state for lockdep.

TRACE_IRQS_OFF is called after SAVE_ALL at each exception/interrupt entry point and at syscall entry. TRACE_IRQS_ON is called at restore_all before returning to userspace, where PAL_rti will restore the user IPL (re-enabling interrupts).

The function call clobbers caller-saved registers, so the TRACE_IRQS_OFF macro reloads $0 and $16-$18 from the pt_regs frame. $8 (current_thread_info) is preserved because it is declared as a global register variable.

Together with the previously added STACKTRACE_SUPPORT and LOCKDEP_SUPPORT, this enables LOCK_DEBUGGING_SUPPORT on Alpha.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/kernel/entry.S | 54 +++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 8 deletions(-)
arch/alpha/kernel/entry.S +46 -8
index 9f2608de2544..ed5df48503d0 100644
@@ -241,6 +241,36 @@
 	.cfi_adjust_cfa_offset	-SWITCH_STACK_SIZE
 .endm
 
+/*
+ * Trace hardirq state changes for lockdep.  TRACE_IRQS_OFF is called
+ * after SAVE_ALL at each entry point where PALcode enters with IPL
+ * raised (interrupts disabled).  TRACE_IRQS_ON is called before
+ * returning to userspace, where PAL_rti will restore the user IPL.
+ *
+ * The function call clobbers caller-saved registers; $8 is preserved
+ * because it is declared as a global register variable for
+ * current_thread_info.  We reload $0 and $16-$18 from the pt_regs
+ * frame that SAVE_ALL created, since entry points pass those to their
+ * C handlers.
+ */
+.macro TRACE_IRQS_OFF
+#ifdef CONFIG_TRACE_IRQFLAGS
+	jsr	$26, trace_hardirqs_off
+	ldgp	$gp, 0($26)
+	ldq	$0, 0($sp)
+	ldq	$16, 160($sp)
+	ldq	$17, 168($sp)
+	ldq	$18, 176($sp)
+#endif
+.endm
+
+.macro TRACE_IRQS_ON
+#ifdef CONFIG_TRACE_IRQFLAGS
+	jsr	$26, trace_hardirqs_on
+	ldgp	$gp, 0($26)
+#endif
+.endm
+
 /*
  * Non-syscall kernel entry points.
  */
@@ -248,8 +278,9 @@
 CFI_START_OSF_FRAME entInt
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
 	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
+	lda	$26, ret_from_sys_call
 	mov	$sp, $19
 	jsr	$31, do_entInt
 CFI_END_OSF_FRAME entInt
@@ -257,14 +288,18 @@ CFI_END_OSF_FRAME entInt
 CFI_START_OSF_FRAME entArith
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
 	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
+	lda	$26, ret_from_sys_call
 	mov	$sp, $18
 	jsr	$31, do_entArith
 CFI_END_OSF_FRAME entArith
 
 CFI_START_OSF_FRAME entMM
 	SAVE_ALL
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
 /* save $9 - $15 so the inline exception code can manipulate them.  */
 	subq	$sp, 64, $sp
 	.cfi_adjust_cfa_offset	64
@@ -284,8 +319,6 @@ CFI_START_OSF_FRAME entMM
 	.cfi_rel_offset	$15, 48
 	addq	$sp, 64, $19
 /* handle the fault */
-	lda	$8, 0x3fff
-	bic	$sp, $8, $8
 	jsr	$26, do_page_fault
 /* reload the registers after the exception code played.  */
 	ldq	$9, 0($sp)
@@ -311,8 +344,9 @@ CFI_END_OSF_FRAME entMM
 CFI_START_OSF_FRAME entIF
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
 	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
+	lda	$26, ret_from_sys_call
 	mov	$sp, $17
 	jsr	$31, do_entIF
 CFI_END_OSF_FRAME entIF
@@ -451,6 +485,9 @@ entUnaUser:
 	.cfi_restore	$0
 	.cfi_adjust_cfa_offset	-256
 	SAVE_ALL		/* setup normal kernel stack */
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
 	lda	$sp, -64($sp)
 	.cfi_adjust_cfa_offset	64
 	stq	$9, 0($sp)
@@ -467,9 +504,7 @@ entUnaUser:
 	.cfi_rel_offset	$13, 32
 	.cfi_rel_offset	$14, 40
 	.cfi_rel_offset	$15, 48
-	lda	$8, 0x3fff
 	addq	$sp, 64, $19
-	bic	$sp, $8, $8
 	jsr	$26, do_entUnaUser
 	ldq	$9, 0($sp)
 	ldq	$10, 8($sp)
@@ -493,8 +528,9 @@ CFI_END_OSF_FRAME entUna
 CFI_START_OSF_FRAME entDbg
 	SAVE_ALL
 	lda	$8, 0x3fff
-	lda	$26, ret_from_sys_call
 	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
+	lda	$26, ret_from_sys_call
 	mov	$sp, $16
 	jsr	$31, do_entDbg
 CFI_END_OSF_FRAME entDbg
@@ -543,6 +579,7 @@ entSys:
 
 	lda	$8, 0x3fff
 	bic	$sp, $8, $8
+	TRACE_IRQS_OFF
 	lda	$4, NR_syscalls($31)
 	stq	$16, SP_OFF+24($sp)
 	lda	$5, sys_call_table
@@ -586,6 +623,7 @@ ret_to_user:
 	and	$17, _TIF_WORK_MASK, $2
 	bne	$2, work_pending
 restore_all:
+	TRACE_IRQS_ON
 	ldl	$2, TI_STATUS($8)
 	and	$2, TS_SAVED_FP | TS_RESTORE_FP, $3
 	bne	$3, restore_fpu
Signature · 1 line
2.54.0
maintainer Tested-by Reviewed-by on v1 3/24
#8 lore raw

Re: [PATCH 03/24] alpha: select ARCH_HAS_UBSAN

In reply to Matt Turner

Hi Matt,

Quoted 5 lines · Matt Turner

GCC's undefined behavior sanitizer has no architecture-specific runtime requirements. Enable it for Alpha to allow UBSAN instrumentation of the kernel.

I tested this patch on top of my rebased Alpha GENERIC_ENTRY patch on an AlphaServer ES40. The kernel built and booted successfully with CONFIG_UBSAN=y, and the UBSAN instrumentation is active.

CONFIG_UBSAN_ALIGNMENT did expose a misaligned struct bucket_table allocation in lib/rhashtable.c. This appears to be a generic rhashtable allocation-alignment issue rather than an Alpha UBSAN problem.

Regards,
Magnus

maintainer
#33 lore raw

Re: [PATCH 14/24] alpha: add ARCH_SUPPORTS_PAGE_TABLE_CHECK support

In reply to Matt Turner

Hi Matt,

Quoted 8 lines · Matt Turner

Add the page table check helpers needed for CONFIG_PAGE_TABLE_CHECK and select ARCH_SUPPORTS_PAGE_TABLE_CHECK in Kconfig.

Alpha does not support huge pages, so pmd_user_accessible_page() and pud_user_accessible_page() always return false. pte_user_accessible_page() checks for present PTEs with user read access (_PAGE_URE).

This patch does not build with CONFIG_PAGE_TABLE_CHECK enabled on v7.3-rc1.

Commit cf8771ca4cdb ("mm/page_table_check: Pass mm_struct to pxx_user_accessible_page()") changed these helpers from:

pte_user_accessible_page(pte, addr)

to:

pte_user_accessible_page(mm, addr, pte)

The Alpha definitions added here still use the old two-argument API. The same applies to pmd_user_accessible_page() and pud_user_accessible_page().

Could you update the helpers to use the new three-argument signatures?

Regards,
Magnus

maintainer Tested-by Reviewed-by on v1 6/24
#17 lore raw

Re: [PATCH 06/24] alpha: select EDAC_SUPPORT

In reply to Matt Turner

Hi Matt,

Quoted 6 lines · Matt Turner

The EDAC core builds and works on Alpha; it only needs the architecture to declare support. There is no Alpha memory controller driver yet, but the core is what a future driver, or the existing machine check error decoding in err_ev6.c and err_ev7.c, would report through.

I tested this on an AlphaServer ES40 with CONFIG_RAS=y and CONFIG_EDAC=y. The kernel built and booted successfully, and the generic EDAC sysfs hierarchy was created under /sys/devices/system/edac/mc.

Possibly we could adapt this to have EDAC support, I know it was mentioned on the list:

https://lore.kernel.org/linux-alpha/[email protected]/

Either way, this looks good to me,

maintainer
#2 lore raw

Re: [PATCH 01/24] alpha: fix arch_irqs_disabled_flags() to treat any raised IPL as disabled

In reply to Matt Turner

Hi, Matt

Quoted 9 lines · Matt Turner

arch_irqs_disabled_flags() only reported interrupts as disabled at IPL_MAX, but the kernel is not the only thing that sets the IPL. PALcode raises PS.IPL to the level of the interrupt being delivered before entering the handler, so a handler entered for a device interrupt runs at IPL_DEV0 or IPL_DEV1, and the timer at IPL_TIMER. Interrupts at and below that level are blocked, but arch_irqs_disabled() answered that interrupts were enabled.

Quoted 5 lines

Treat any IPL above IPL_MIN, the level arch_local_irq_enable() restores, as interrupts disabled. This matters as soon as lockdep is asked to track hardirq state, where irqs_disabled() is expected to be true inside an interrupt handler.

Hi Matt,

Thanks for the explanation, but I still do not think that treating every raised IPL as "IRQs disabled" is correct.

The Alpha Architecture Reference Manual, Section 19.1.2, says that an interrupt is delivered when its IPL is greater than the IPL in the current PS. Table 19-1 in Section 19.2 documents the OSF PAL IPL range from 0 to 7. An intermediate IPL therefore masks only interrupts at or below that priority; higher-priority interrupts remain enabled. Only IPL 7 masks all OS-visible interrupt levels.

The 21164 Hardware Reference Manual, Section 4.15.3, states the same
rule: an interrupt is enabled when the current IPL is less than the interrupt's target IPL.

Thus, IPL_MIN means interrupts are enabled, an intermediate IPL is only a partial mask, and IPL_MAX masks all interrupt levels.

I therefore think arch_irqs_disabled_flags() should retain the meaning of fully disabled local IRQs:

        return (flags & 7) == IPL_MAX;

If lockdep or generic entry requires IRQs to be disabled on entry, I think the entry code should first raise the live IPL to IPL_MAX, rather than report an intermediate IPL as fully disabled.

Regards,
Magnus

maintainer Tested-by Reviewed-by on v1 5/24
#15 lore raw

Re: [PATCH 05/24] alpha: select HAVE_DEBUG_KMEMLEAK

In reply to Matt Turner

Hi Matt,

Quoted 5 lines · Matt Turner

Kmemleak needs no architecture support beyond the standard linker script symbols for the data and bss sections, which Alpha already provides, and a scan of the kernel stacks, which is done generically.

I tested this on an AlphaServer ES40 with CONFIG_DEBUG_KMEMLEAK=y. The kernel built and booted successfully, and a manual kmemleak scan completed normally.

The scan reported three suspected allocations from the sym53c8xx_2 driver. These appear unrelated to this patch and may be false positives caused by references stored in DMA-coherent memory. Either way, the patch looks good to me.

maintainer Tested-by Reviewed-by on v1 7/24
#19 lore raw

Re: [PATCH 07/24] alpha: select ARCH_SUPPORTS_ATOMIC_RMW

In reply to Matt Turner

Hi Matt,

Quoted 9 lines · Matt Turner

Alpha has native LL/SC instructions (LDL_L/STL_C, LDQ_L/STQ_C) that provide atomic read-modify-write capability, and already selects ARCH_HAVE_NMI_SAFE_CMPXCHG.

Selecting ARCH_SUPPORTS_ATOMIC_RMW enables MUTEX_SPIN_ON_OWNER and RWSEM_SPIN_ON_OWNER on SMP, allowing optimistic spinning on contended locks rather than immediately sleeping.

I tested this on an AlphaServer ES40 with four CPUs and CONFIG_PROVE_LOCKING=y, CONFIG_DEBUG_MUTEXES=y, and CONFIG_DEBUG_RWSEMS=y.

Both the mutex_lock and rwsem_lock locktorture tests completed successfully under contention across all four CPUs.

Regards,
Magnus

maintainer Tested-by Reviewed-by on v1 8/24
#21 lore raw

Re: [PATCH 08/24] alpha: select ARCH_HAS_FAST_MULTIPLIER

In reply to Matt Turner

Hi Matt,

Quoted 7 lines · Matt Turner

All Alpha CPUs have hardware integer multiply (MULL/MULQ). EV4 and EV5 implement it in microcode; EV56 and later have fast single-cycle multiply. Since no EV4 system is likely to run a modern kernel, select this unconditionally to enable multiply-based fast paths in hweight and string routines.

I tested this on an AlphaServer ES40 (EV67). A test module exercised the multiplication-based memchr_inv() path with offsets 0 through 7, buffer lengths from 17 through 257 bytes, four fill values, and mismatches at the beginning, middle, and end of each buffer. All tests passed.

On EV67, hweight uses the native CTPOP instruction, so the generic multiplication-based hweight path is not selected by this configuration.

Regards,
Magnus

maintainer Tested-by Reviewed-by on v1 9/24
#23 lore raw

Re: [PATCH 09/24] alpha: select ARCH_SUPPORTS_INT128

In reply to Matt Turner

Hi Matt,

Quoted 7 lines · Matt Turner

gcc supports __int128 on Alpha, and the 64x64 to 128-bit multiply that the users in the scheduler and in lib/ care about maps onto mulq/umulh rather than an out-of-line libgcc helper.

Gate the select on CC_HAS_INT128 as the other 64-bit architectures do.

I tested this on an AlphaServer ES40 with CONFIG_ARCH_SUPPORTS_INT128=y. The kernel built and booted successfully, and the bits KUnit suite passed, including genmask_u128_test:

# bits-test: pass:6 fail:0 skip:0 total:6
ok 1 bits-test

maintainer Tested-by Reviewed-by on v1 10/24
#25 lore raw

Re: [PATCH 10/24] alpha: select HAVE_ARCH_COMPILER_H

In reply to Matt Turner

Hi Matt,

Quoted 7 lines · Matt Turner

Alpha already provides asm/compiler.h (wrapping uapi/asm/compiler.h) which defines architecture-specific compiler intrinsics like __kernel_cmpbge, __kernel_cttz, __kernel_ctlz, and __kernel_ctpop.

Selecting HAVE_ARCH_COMPILER_H causes linux/compiler_types.h to include asm/compiler.h, making these definitions available consistently.

I tested this on an AlphaServer ES40. The kernel built and booted successfully with CONFIG_HAVE_ARCH_COMPILER_H=y, and the in-tree test_bitops module completed without errors.

While testing this patch, the FFS KUnit suite exposed a separate, pre-existing issue in the EV67 Alpha fls64() implementation. The zero-input tests failed with the contradictory diagnostic:

Expected fls64(input) == 0, but

      fls64(input) == 0 (0x0)

The EV67 implementation passes zero to __kernel_ctlz(), which GCC maps to __builtin_clzl(). The result of __builtin_clzl(0) is undefined, so the compiler can optimize the comparison inconsistently with the value returned by the Alpha ctlz instruction.

I verified the diagnosis by changing fls64() to handle zero explicitly:

  return word ? 64 - __kernel_ctlz(word) : 0;

With that change, the FFS KUnit result improved from 8/9 to 9/9 tests passing.

This appears unrelated to this patch, since asm/bitops.h already included asm/compiler.h directly before HAVE_ARCH_COMPILER_H was selected. I am mentioning it here since this patch led to the issue being discovered.

maintainer Tested-by Reviewed-by on v1 11/24
#27 lore raw

Re: [PATCH 11/24] alpha: select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE

In reply to Matt Turner

Hi Matt,

Quoted 10 lines · Matt Turner

Alpha has a clean split between user and kernel address spaces: user space occupies 0x0000000000000000-0x000003ffffffffff (TASK_SIZE), while kernel space uses KSEG and vmalloc regions near the top of the 64-bit address space. These are strictly non-overlapping.

This enables optimizations in BPF and tracing that can skip address range checks when user and kernel pointers are distinguishable by address alone.

I tested this on an AlphaServer ES40. The kernel built and booted successfully with CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y.

I verified that userspace mappings were below TASK_SIZE (0x0000040000000000), while the kernel text was in the high Alpha kernel address range:

0x000002000025a000 highest observed userspace mapping 0xfffffc0000310000 _stext

This confirms that the observed user and kernel virtual address ranges are non-overlapping.

maintainer Tested-by Reviewed-by on v1 12/24
#29 lore raw

Re: [PATCH 12/24] alpha: add HAVE_ARCH_THREAD_STRUCT_WHITELIST support

In reply to Matt Turner

Hi Matt,

Quoted 8 lines · Matt Turner

Alpha's thread_struct is empty (all per-thread state lives in thread_info), so the whitelist is trivially empty. This is more explicit than the generic fallback, which computes the full thread_struct size as copyable.

Assisted-by Claude:claude-opus-4-6

I tested this on an AlphaServer ES40 with
CONFIG_HARDENED_USERCOPY=y.

The task_struct slab reports a zero-sized usercopy region, as expected for Alpha's empty thread_struct:

  $ cat /sys/kernel/slab/task_struct/usersize
  0

The usercopy KUnit suite also passed all tests:

# usercopy: pass:4 fail:0 skip:0 total:4
ok 1 usercopy

maintainer Tested-by Reviewed-by on v1 13/24
#31 lore raw

Re: [PATCH 13/24] alpha: add ARCH_HAS_PTE_SPECIAL support

In reply to Matt Turner

Hi Matt,

Quoted 11 lines · Matt Turner

Add _PAGE_SPECIAL using bit 19 (0x80000), which is unused in the Alpha PTE layout. This enables pte_special()/pte_mkspecial() for marking PTEs that are not backed by struct page (VDSO mappings, zero page, io_remap_pfn_range, etc.).

Include _PAGE_SPECIAL in _PAGE_CHG_MASK so it is preserved across pte_modify() calls.

Assisted-by Claude:claude-opus-4-6

I tested this on an AlphaServer ES40 with
CONFIG_ARCH_HAS_PTE_SPECIAL=y.

A focused anonymous-memory test faulted in 256 shared zero pages, changed their protections from read-write to read-only and back, and then wrote to every page to trigger replacement with private COW pages.

The test completed successfully, all data checks passed, and no page-table or bad-PTE warnings appeared in dmesg.

maintainer
#54 lore raw
In reply to Matt Turner

Hi Matt,

Quoted 58 lines · Matt Turner

Alpha is missing a long list of Kconfig options that other architectures have picked up over the years, some of them for no better reason than nobody having gone through the list. I diffed the select statements in every other arch/*/Kconfig against arch/alpha/Kconfig and worked through what turned up. This series is the result: two fixes it depends on, and the options that are either free or close to it.

The patches are ordered from least to most contentious, so the front of the series can be applied on its own if the tail needs discussion.

Patches 1-2 are fixes. arch_irqs_disabled_flags() only reported interrupts as disabled at IPL_MAX, but PALcode enters handlers at the IPL of the interrupt being delivered, so a device or timer handler answered that interrupts were enabled. handle_irq() also called irq_to_desc() before irq_enter(), running generic code with the preempt count still saying task context and RCU not yet watching. Both matter on their own; patches 23 and 24 are what made them visible.

Patches 3-11 are one-line selects with no Alpha code behind them:
instrumentation (UBSAN, gcov, kmemleak), EDAC, and four properties Alpha has always had but never declared (LL/SC atomics, hardware multiply, __int128, the existing asm/compiler.h, and the non-overlapping user and kernel address spaces).

Patches 12-17 add a small amount of code: an empty thread_struct whitelist, _PAGE_SPECIAL on a free PTE bit, the page table check helpers, and then the three things that follow from those - the page table helper self test, lockless GUP, and the early memtest. Note that early_memtest() is called from arch_mm_preinit() rather than paging_init(), because Alpha calls paging_init() from setup_arch(), before parse_early_param() has seen the memtest= option.

Patches 18-20 change something visible. Unhandled user faults now print the usual message under the debug.exception-trace sysctl. .eh_frame is
discarded: gcc emits it for Alpha regardless of -fno-asynchronous-unwind-tables, it was allocated in the loaded image, and nothing consumes it, since the stack trace code scans for text addresses rather than unwinding DWARF. That is worth about 1.1MB. With that and the relocation sections placed explicitly, the kernel links with no orphans left, so the last of the three asks the linker to say so.

Patches 21-24 are the ones I expect to draw comment. Patch 22 adds a uapi header, so the perf register numbering is an ABI decision. Patch 23 is SPARSE_IRQ: without it Marvel carries a 12.6MB static irq_desc[] in .data for 32768 possible interrupts, of which a real ES47 uses 87, and the kernel links at a fixed address just above the console reservation where that 12.6MB is the difference between fitting and not. Patch 24 instruments the entry assembly for lockdep hardirq tracking.

Tested with gcc 17 under QEMU (-M clipper -smp 2, an ALPHA_GENERIC build) with PROVE_LOCKING enabled: no splats, early_memtest passes all four patterns over the free memblock ranges with nothing reserved, debug_vm_pgtable validates with no warning, a vmsplice() of an anonymous mapping through pin_user_pages_fast() returns the right data, and an unhandled SIGSEGV prints the new trace line. Patch 23 was tested on an AlphaServer ES47.

Quoted 8 lines

Not included, and worth mentioning: ARCH_HAS_KCOV. A kernel with KCOV_INSTRUMENT_ALL boots and runs, but CONFIG_KCOV_SELFTEST panics. The self test deliberately arms kcov with no coverage area so that any instrumented function reached from interrupt context faults, checking that nothing escapes the window before the preempt count says hardirq. On Alpha something does. Patch 2 fixes one such site; the panic survives it, so the entry paths need an audit first.

Thanks for taking the time to do this! This is a nice collection of patches. I've started on the review and testing, I will keep at it.
As general feedback for the series, I noticed that several of the corresponding architecture feature matrices still list Alpha as TODO. The Alpha entries should be changed to "ok" for:

ARCH_HAS_GCOV_PROFILE_ALL
HAVE_DEBUG_KMEMLEAK
ARCH_HAS_PTE_SPECIAL
ARCH_HAS_DEBUG_VM_PGTABLE
HAVE_PERF_REGS
HAVE_PERF_USER_STACK_DUMP

These correspond to patches 4, 5, 13, 15, and 22. It would probably be best to include each documentation update in the patch which enables the corresponding feature.

It would also be helpful if the next revision were rebased onto v7.3-rc1 and applied cleanly on top of my Alpha GENERIC_ENTRY v5 series. I am currently testing only the patches which applied successfully.

Alpha GENERIC_ENTRY v5 series is available here:
https://lore.kernel.org/linux-alpha/[email protected]/T/#t

Regards,
Magnus

author maintainer
#55 lore raw
Quoted 84 lines · Magnus Lindholm

Hi Matt,

Quoted 58 lines · Matt Turner

Alpha is missing a long list of Kconfig options that other architectures have picked up over the years, some of them for no better reason than nobody having gone through the list. I diffed the select statements in every other arch/*/Kconfig against arch/alpha/Kconfig and worked through what turned up. This series is the result: two fixes it depends on, and the options that are either free or close to it.

The patches are ordered from least to most contentious, so the front of the series can be applied on its own if the tail needs discussion.

Patches 1-2 are fixes. arch_irqs_disabled_flags() only reported interrupts as disabled at IPL_MAX, but PALcode enters handlers at the IPL of the interrupt being delivered, so a device or timer handler answered that interrupts were enabled. handle_irq() also called irq_to_desc() before irq_enter(), running generic code with the preempt count still saying task context and RCU not yet watching. Both matter on their own; patches 23 and 24 are what made them visible.

Patches 3-11 are one-line selects with no Alpha code behind them:
instrumentation (UBSAN, gcov, kmemleak), EDAC, and four properties Alpha has always had but never declared (LL/SC atomics, hardware multiply, __int128, the existing asm/compiler.h, and the non-overlapping user and kernel address spaces).

Patches 12-17 add a small amount of code: an empty thread_struct whitelist, _PAGE_SPECIAL on a free PTE bit, the page table check helpers, and then the three things that follow from those - the page table helper self test, lockless GUP, and the early memtest. Note that early_memtest() is called from arch_mm_preinit() rather than paging_init(), because Alpha calls paging_init() from setup_arch(), before parse_early_param() has seen the memtest= option.

Patches 18-20 change something visible. Unhandled user faults now print the usual message under the debug.exception-trace sysctl. .eh_frame is
discarded: gcc emits it for Alpha regardless of -fno-asynchronous-unwind-tables, it was allocated in the loaded image, and nothing consumes it, since the stack trace code scans for text addresses rather than unwinding DWARF. That is worth about 1.1MB. With that and the relocation sections placed explicitly, the kernel links with no orphans left, so the last of the three asks the linker to say so.

Patches 21-24 are the ones I expect to draw comment. Patch 22 adds a uapi header, so the perf register numbering is an ABI decision. Patch 23 is SPARSE_IRQ: without it Marvel carries a 12.6MB static irq_desc[] in .data for 32768 possible interrupts, of which a real ES47 uses 87, and the kernel links at a fixed address just above the console reservation where that 12.6MB is the difference between fitting and not. Patch 24 instruments the entry assembly for lockdep hardirq tracking.

Tested with gcc 17 under QEMU (-M clipper -smp 2, an ALPHA_GENERIC build) with PROVE_LOCKING enabled: no splats, early_memtest passes all four patterns over the free memblock ranges with nothing reserved, debug_vm_pgtable validates with no warning, a vmsplice() of an anonymous mapping through pin_user_pages_fast() returns the right data, and an unhandled SIGSEGV prints the new trace line. Patch 23 was tested on an AlphaServer ES47.

Quoted 8 lines

Not included, and worth mentioning: ARCH_HAS_KCOV. A kernel with KCOV_INSTRUMENT_ALL boots and runs, but CONFIG_KCOV_SELFTEST panics. The self test deliberately arms kcov with no coverage area so that any instrumented function reached from interrupt context faults, checking that nothing escapes the window before the preempt count says hardirq. On Alpha something does. Patch 2 fixes one such site; the panic survives it, so the entry paths need an audit first.

Thanks for taking the time to do this! This is a nice collection of patches. I've started on the review and testing, I will keep at it.
As general feedback for the series, I noticed that several of the corresponding architecture feature matrices still list Alpha as TODO. The Alpha entries should be changed to "ok" for:

ARCH_HAS_GCOV_PROFILE_ALL
HAVE_DEBUG_KMEMLEAK
ARCH_HAS_PTE_SPECIAL
ARCH_HAS_DEBUG_VM_PGTABLE
HAVE_PERF_REGS
HAVE_PERF_USER_STACK_DUMP

Quoted 3 lines

These correspond to patches 4, 5, 13, 15, and 22. It would probably be best to include each documentation update in the patch which enables the corresponding feature.

Oh, definitely. Thanks for catching that.

Quoted 6 lines

It would also be helpful if the next revision were rebased onto v7.3-rc1 and applied cleanly on top of my Alpha GENERIC_ENTRY v5 series. I am currently testing only the patches which applied successfully.

Alpha GENERIC_ENTRY v5 series is available here:
https://lore.kernel.org/linux-alpha/[email protected]/T/#t

Perfect, I will do it!

maintainer Tested-by Reviewed-by on v1 16/24
#37 lore raw

Re: [PATCH 16/24] alpha: select HAVE_GUP_FAST

In reply to Matt Turner

Hi Matt,

Quoted 7 lines · Matt Turner

The lockless GUP fast path needs the architecture to distinguish PTEs with no struct page behind them and to keep page table pages alive while a walker holds no lock. Alpha now has ARCH_HAS_PTE_SPECIAL, and it has selected MMU_GATHER_RCU_TABLE_FREE for a long time, so both requirements are met.

Quoted 6 lines

PTEs are a single 64-bit word on Alpha, so the lockless reads that the generic walker performs cannot tear, and no arch-specific gup_fast_permitted() or ptep_get_lockless() is needed.

Assisted-by Claude:claude-opus-5

I tested this on an Alpha UP2000 with CONFIG_HAVE_GUP_FAST=y, CONFIG_ARCH_HAS_PTE_SPECIAL=y, and CONFIG_MMU_GATHER_RCU_TABLE_FREE=y.

The in-tree gup_test completed the get_user_pages_fast() and pin_user_pages_fast() benchmarks with both read-only and writable pins. Each case ran ten iterations over a 16 MiB mapping, fetching 123 pages per call.

All four cases completed with ioctl status 0 and no failures.

maintainer Tested-by Reviewed-by on v1 17/24
#39 lore raw

Re: [PATCH 17/24] alpha: select ARCH_USE_MEMTEST

In reply to Matt Turner
Quoted 7 lines · Matt Turner

Wire up the generic early memtest from arch_mm_preinit(), which runs after parse_early_param() has picked up the memtest= command line option and before memblock_free_all() hands the memory to the buddy allocator. paging_init() would be the natural place, but Alpha calls it from setup_arch(), before the option is parsed, so the test would never run.

Quoted 8 lines

The test range starts at the first DRAM address rather than physical zero because low memory on Alpha is owned by the console and PALcode.

Tested under QEMU with memtest=4: all four patterns pass over the free memblock ranges, with no bad memory reserved.

Assisted-by Claude:claude-opus-5

I tested this on an Alpha UP2000 with CONFIG_MEMTEST=y and memtest=4. The early memory test completed successfully and reported:

EarlyMemtestBad: 0 kB

It would also be useful to add ALPHA to the memtest= architecture list in Documentation/admin-guide/kernel-parameters.txt.

maintainer Tested-by Reviewed-by on v1 18/24
#41 lore raw

Re: [PATCH 18/24] alpha: select SYSCTL_EXCEPTION_TRACE

In reply to Matt Turner

Hi Matt,

Quoted 10 lines · Matt Turner

Report unhandled user faults the way other architectures do, and hook up the debug.exception-trace sysctl that controls the reporting.

The message gives the faulting address, the PC and the user stack pointer, and is rate limited.

Assisted-by Claude:claude-opus-5

---

I tested this on an Alpha UP2000. With debug.exception-trace=1, unhandled SEGV_MAPERR and SEGV_ACCERR faults produced the expected "unmapped access" and "access violation" messages.

With debug.exception-trace=0, both processes still received SIGSEGV, but no additional messages were written to the kernel log.

maintainer Tested-by Reviewed-by on v1 19/24
#43 lore raw

Re: [PATCH 19/24] alpha: discard .eh_frame and the relocation sections

In reply to Matt Turner

Hi Matt,

Quoted 10 lines · Matt Turner

gcc emits .eh_frame for Alpha even though the kernel builds with -fno-asynchronous-unwind-tables, and nothing in the kernel consumes it:
the stack trace code scans the stack for text addresses rather than unwinding DWARF. It was allocated in the loaded image, so dropping it shrinks vmlinux by about 1.1MB for a Marvel SMP configuration.

The .rela* sections are equally useless, as the kernel image is not relocatable. The linker was already dropping their contents.

Quoted 6 lines

Both were being placed as orphan sections, which is what drew attention to them.

Assisted-by Claude:claude-opus-5

---

I verified that .eh_frame and .rela* sections were present in the linker input objects but absent from the final vmlinux. The resulting compressed kernel image also booted successfully on an Alpha UP2000.

maintainer Tested-by Reviewed-by on v1 20/24
#45 lore raw

Re: [PATCH 20/24] alpha: select ARCH_WANT_LD_ORPHAN_WARN

In reply to Matt Turner

Hi Matt,

Quoted 7 lines · Matt Turner

With .eh_frame and the relocation sections now placed explicitly, an Alpha kernel links with no orphan sections left, so ask the linker to warn if new ones appear.

Assisted-by Claude:claude-opus-5

Build tested this for Alpla, looks good to me.

Quoted 19 lines
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -1
index 4c60c442207c..827b224f2f8a 100644
@@ -38,6 +38,7 @@ config ALPHA
        select AUTO_IRQ_AFFINITY if SMP
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
+       select ARCH_WANT_LD_ORPHAN_WARN
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select AUDIT_ARCH
        select EDAC_SUPPORT
--

2.54.0

maintainer Tested-by Reviewed-by on v1 21/24
#47 lore raw

Re: [PATCH 21/24] alpha: select ARCH_WANT_IRQS_OFF_ACTIVATE_MM

In reply to Matt Turner

Hi Matt,

Quoted 26 lines · Matt Turner

activate_mm() on Alpha calls __load_new_mm_context() which assigns a new ASID and invokes PALcode swpctx. On SMP, an interrupt arriving between the ASID update and the page table switch could see inconsistent state. Ensure activate_mm() is called with interrupts disabled during exec.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -1
index 827b224f2f8a..bda8443a7323 100644
@@ -37,6 +37,7 @@ config ALPHA
        select GENERIC_PCI_IOMAP
        select AUTO_IRQ_AFFINITY if SMP
        select GENERIC_IRQ_SHOW
+       select ARCH_WANT_IRQS_OFF_ACTIVATE_MM
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_WANT_LD_ORPHAN_WARN
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
--
Quoted 2 lines

2.54.0

I tested this on a two-CPU Alpha UP2000. I ran 20,000 successive execve() operations pinned to each online CPU. All executions completed successfully, with no MMU, ASN, or page-table errors in the kernel log.

Magnus

maintainer
#49 lore raw

Re: [PATCH 22/24] alpha: add HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP support

In reply to Matt Turner

Hi Matt,

Quoted 5 lines · Matt Turner

Implement the perf register sampling interface for Alpha. This enables perf to capture register state and user stack dumps with samples, supporting --call-graph dwarf.

Quoted 8 lines

The perf_regs enum exposes the registers available in pt_regs: r0-r8, r16-r28, gp, pc, and ps. Registers r9-r15 are callee-saved and live in switch_stack, not pt_regs, so they are not included.

A switch statement maps perf register indices to pt_regs fields since Alpha's pt_regs layout is non-contiguous (unlike architectures where direct array indexing works).

I tested this on an Alpha UP2000. Basic perf recording works, but user-register and user-stack sampling still appear to need some additional work.

perf record --user-regs=? reports an empty register list, since tools/perf does not yet provide the Alpha register mask, names, or IP/SP mappings. Adding DWARF call-graph sampling consequently fails with EINVAL. I think the corresponding tools/perf support could be added as a separate patch in this series.

There also appears to be one kernel-side issue with user-stack sampling. The generic code obtains the stack pointer through user_stack_pointer(regs), which returns regs->usp on Alpha.

Alpha already has alpha_snapshot_usp(), which initializes this field for user-mode register frames, but it is currently local to traps.c and is only called from do_entArith() and do_entIF(). The interrupt entry path through do_entInt() does not call it.

Perhaps alpha_snapshot_usp() could be moved to a shared header and called near the beginning of do_entInt(), before dispatching the interrupt. That would ensure that perf_irq() receives a valid regs->usp for interrupts taken from userspace, without adding this work to the SAVE_ALL assembly macro.

The perf register ABI also appears to be missing SP. This could be provided using current_user_stack_pointer(), as in the older Alpha implementation.

I have some older Alpha kernel and tools/perf patches which implement similar support. They target an older API, but I will send them off-list in case any of the code is useful. Please feel free to reuse or adapt whatever helps.

Regards,
Magnus

maintainer
#51 lore raw

Re: [PATCH 23/24] alpha: select SPARSE_IRQ

In reply to Matt Turner

Hi Matt,

Quoted 22 lines · Matt Turner

NR_IRQS on Alpha is sized for the largest configuration each platform supports, and for Marvel that is 32 PIDs, or 32784 interrupts. Without SPARSE_IRQ that becomes a static irq_desc[] array of 12.6 MB in .data, carried by every Marvel and every generic kernel regardless of how many interrupts the machine actually has. A real ES47 uses 87 of them.

That is not just wasted memory, it constrains where the kernel can be loaded. The image links at a fixed 0xfffffc0001010000, just above the console's low memory reservation, and with memory striping enabled the console leaves only about 16 MB of usable low memory before the rest is relocated to an interleaved aperture. A 12.6 MB array of mostly unused interrupt descriptors is the difference between fitting and not.

Alpha already goes through irq_to_desc() rather than indexing irq_desc[] directly, so nothing stands in the way. The platforms do wire up their interrupts by number, though, which needs the descriptors to exist by then, so provide arch_probe_nr_irqs() returning the machine vector's count instead of taking the NR_IRQS_LEGACY default. Without it every interrupt above 15 would have no descriptor and the handler setup would be silently dropped.

Quoted 7 lines

Tested on an ES47 (Marvel, 2 EV7z): boots with all device interrupts working, and .data drops by 12.6 MB, from 15.7 MB to 3.1 MB.

---
 arch/alpha/Kconfig            |  1 +
 arch/alpha/kernel/irq_alpha.c | 13 +++++++++++++
 2 files changed, 14 insertions(+)

This patch appears to be missing your Signed-off-by tag.

Tested on a two-CPU UP2000 with CONFIG_SPARSE_IRQ=y. The kernel booted successfully and created IRQ descriptors 0 through 63. SCSI devices on IRQs 19 and 27 and Ethernet on IRQ 43 operated normally, with their interrupt counts increasing. I observed no IRQ setup failures or other IRQ-related warnings.

Regards

Magnus

maintainer
#4 lore raw

Re: [PATCH 02/24] alpha: enter hardirq context before looking up the irq descriptor

In reply to Matt Turner

Hi Matt,

Quoted 46 lines · Matt Turner

handle_irq() called irq_to_desc() before irq_enter(), so that lookup ran with the preempt count still saying task context and with RCU not yet watching. Generic code called from an interrupt handler should see hardirq context, and irq_to_desc() is more than an array index once SPARSE_IRQ is in use.

Move irq_enter() to the top of the function and add the matching irq_exit() to the invalid interrupt path.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/kernel/irq.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
arch/alpha/kernel/irq.c +6 -4
index 4a6a8b1d5a8b..5867a1655045 100644
@@ -107,18 +107,21 @@ handle_irq(int irq)
         * handled by some other CPU. (or is disabled)
         */
        static unsigned int illegal_count=0;
-       struct irq_desc *desc = irq_to_desc(irq);
-
+       struct irq_desc *desc;
+
+       irq_enter();
+
+       desc = irq_to_desc(irq);
        if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
            illegal_count < MAX_ILLEGAL_IRQS)) {
                irq_err_count++;
                illegal_count++;
                printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
                       irq);
+               irq_exit();
                return;
        }
 
-       irq_enter();
        generic_handle_irq_desc(desc);
        irq_exit();
 }
--
Quoted 2 lines

2.54.0

Going over this code again, I noticed what may be redundant hardirq accounting in the existing device-interrupt path.

For type 3 interrupts, do_entInt() already wraps alpha_mv.device_interrupt() in irq_enter()/irq_exit(). The platform dispatcher then calls handle_irq(), which enters and exits hardirq context again. Therefore, irq_to_desc() is already reached in hardirq context before this patch. The patch moves it from nesting level one to level two rather than from task context to hardirq context.

The RTC path does not have the outer irq_enter(), so the change is needed there.

Would it be cleaner for do_entInt() to own the hardirq context for both paths and remove the pair from handle_irq()? Or is there another caller which requires handle_irq() to manage it itself?

I tested the patch on a two-CPU UP2000 with lockdep, IRQ flag tracing, and sparse IRQs enabled. SCSI and network interrupts operated normally, I observed no lockdep or IRQ-related warnings, and debug_locks remained enabled in /proc/lockdep_stats.

Regards
Magnus

maintainer Tested-by Reviewed-by on v1 4/24
#13 lore raw

Re: [PATCH 04/24] alpha: select ARCH_HAS_GCOV_PROFILE_ALL

In reply to Matt Turner

Hi Matt,

Quoted 24 lines · Matt Turner

GCC's gcov instrumentation (-fprofile-arcs -ftest-coverage) has no architecture-specific runtime requirements. Enable GCOV_PROFILE_ALL support for Alpha to allow whole-kernel code coverage analysis.

Assisted-by Claude:claude-opus-4-6
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -1
index 1aa76a2d9750..a6024590ea6e 100644
@@ -5,6 +5,7 @@ config ALPHA
        select ARCH_32BIT_USTAT_F_TINODE
        select ARCH_HAS_CURRENT_STACK_POINTER
        select ARCH_HAS_DMA_OPS if PCI
+       select ARCH_HAS_GCOV_PROFILE_ALL
        select ARCH_HAS_UBSAN
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
--
Quoted 2 lines

2.54.0

I built and booted this on a two-CPU UP2000 with GCOV_KERNEL and GCOV_PROFILE_ALL enabled. Debugfs exposed 1226 .gcda files, including the expected arch/alpha objects. I observed no GCOV-related errors or kernel warnings.

This also appears to warrant changing Alpha from "TODO" to "ok" in Documentation/features/debug/gcov-profile-all/arch-support.txt.

Regards,
Magnus

maintainer Tested-by Reviewed-by on v1 15/24
#35 lore raw

Re: [PATCH 15/24] alpha: select ARCH_HAS_DEBUG_VM_PGTABLE

In reply to Matt Turner

Hi Matt,

Quoted 26 lines · Matt Turner

CONFIG_DEBUG_VM_PGTABLE runs a boot-time self test over the page table
helpers: the protection bit accessors, pte_modify(), the swap entry encoding including the exclusive marker, and, where the architecture supports them, the huge page helpers. Alpha implements everything the test needs for a three-level page table without huge page support.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/Kconfig | 1 +
 1 file changed, 1 insertion(+)
arch/alpha/Kconfig +1 -1
index d7e2859aaedb..87fe81bc4709 100644
@@ -4,6 +4,7 @@ config ALPHA
        default y
        select ARCH_32BIT_USTAT_F_TINODE
        select ARCH_HAS_CURRENT_STACK_POINTER
+       select ARCH_HAS_DEBUG_VM_PGTABLE
        select ARCH_HAS_DMA_OPS if PCI
        select ARCH_HAS_FAST_MULTIPLIER
        select ARCH_HAS_GCOV_PROFILE_ALL
--
Quoted 2 lines

2.54.0

I applied this manually on top of v7.3-rc1 plus Alpha GENERIC_ENTRY v5. The Kconfig hunk needed a trivial context adjustment.

I built and booted it on a two-CPU UP2000 with ARCH_HAS_DEBUG_VM_PGTABLE and DEBUG_VM_PGTABLE enabled. The boot-time page-table helper validation ran without warnings.

This also appears to warrant changing Alpha from "TODO" to "ok" in Documentation/features/debug/debug-vm-pgtable/arch-support.txt.

Regards,
Magnus

maintainer
#53 lore raw

Re: [PATCH 24/24] alpha: add TRACE_IRQFLAGS_SUPPORT

In reply to Matt Turner

Hi Matt,

Quoted 13 lines · Matt Turner

Instrument the entry/exit assembly to track hardirq state for lockdep.

TRACE_IRQS_OFF is called after SAVE_ALL at each exception/interrupt entry point and at syscall entry. TRACE_IRQS_ON is called at restore_all before returning to userspace, where PAL_rti will restore the user IPL (re-enabling interrupts).

The function call clobbers caller-saved registers, so the TRACE_IRQS_OFF macro reloads $0 and $16-$18 from the pt_regs frame. $8 (current_thread_info) is preserved because it is declared as a global register variable.

Quoted 5 lines

Together with the previously added STACKTRACE_SUPPORT and LOCKDEP_SUPPORT, this enables LOCK_DEBUGGING_SUPPORT on Alpha.

Assisted-by Claude:claude-opus-4-6

I think this patch needs to be rebased on top of Alpha GENERIC_ENTRY v5. Both patches are based on entry.S blob 9f2608de2544 and modify the same entry and return paths, so they cannot currently be applied in either order.

With GENERIC_ENTRY, the syscall IRQ-state transitions are already handled by syscall_enter_from_user_mode_randomize_stack() and syscall_exit_to_user_mode(). Non-syscall user returns go through exit_to_user_mode(), which also performs the final hardirqs-on transition.

The interrupt path already calls raw_local_irq_disable() and updates the lockdep state in do_entInt(), while kernel-mode PAL returns retain the Alpha-specific lockdep_on_restore() handling.

Adding TRACE_IRQS_OFF to entSys and TRACE_IRQS_ON to restore_all would therefore duplicate the generic-entry transitions. I think the patch should instead be rebased and limited to any entry paths which remain uncovered after GENERIC_ENTRY v5 is applied.

Keeping these transitions in the generic C entry helpers where possible would also avoid additional register-save and restore logic in entry.S.

Regards,
Magnus

#9 lore raw

Re: [PATCH 03/24] alpha: select ARCH_HAS_UBSAN

In reply to Magnus Lindholm
Quoted 9 lines · Magnus Lindholm
Quoted 5 lines · Matt Turner

GCC's undefined behavior sanitizer has no architecture-specific runtime requirements. Enable it for Alpha to allow UBSAN instrumentation of the kernel.

I tested this patch on top of my rebased Alpha GENERIC_ENTRY patch on an AlphaServer ES40. The kernel built and booted successfully with CONFIG_UBSAN=y, and the UBSAN instrumentation is active.

So have I, on an XP1000 and ES45.

Quoted 3 lines

CONFIG_UBSAN_ALIGNMENT did expose a misaligned struct bucket_table allocation in lib/rhashtable.c. This appears to be a generic rhashtable allocation-alignment issue rather than an Alpha UBSAN problem.

But in my case the kernel vomited copious misaligned access reports, so many that it took quite a few minutes to boot and I lost much of the kernel log before disks were mounted. A few examples that were recorded later in the boot on the ES45:

Sep 03 21:12:36 electro kernel: UBSAN: misaligned-access in net/core/dev.c:1401:2
Sep 03 21:12:36 electro kernel: member access within misaligned address (____ptrval____) for type 'struct net_device'
Sep 03 21:12:36 electro kernel: which requires 64 byte alignment
Sep 03 21:12:36 electro kernel: UBSAN: misaligned-access in kernel/signal.c:4362:4
Sep 03 21:12:36 electro kernel: member access within misaligned address 0000000058e1e939 for type 'struct task_struct'
Sep 03 21:12:36 electro kernel: which requires 64 byte alignment
Sep 03 21:13:04 electro kernel: UBSAN: misaligned-access in drivers/net/ethernet/intel/e100.c:1941:36
Sep 03 21:13:04 electro kernel: member access within misaligned address 000000001c866fa6 for type 'struct rfd'
Sep 03 21:13:04 electro kernel: which requires 4 byte alignment

Interestingly "kernel unaligned acc" in /proc/cpuinfo remained at zero, which really makes me wonder whether these reports are all false-positives.

This kernel was cross-compiled with: "alpha-linux-gnu-gcc (Debian 14.2.0-19)"

Cheers,
Michael.

maintainer
#10 lore raw

Re: [PATCH 03/24] alpha: select ARCH_HAS_UBSAN

Hi Michael,

Quoted 31 lines · Michael Cree
Quoted 9 lines · Magnus Lindholm
Quoted 5 lines · Matt Turner

GCC's undefined behavior sanitizer has no architecture-specific runtime requirements. Enable it for Alpha to allow UBSAN instrumentation of the kernel.

I tested this patch on top of my rebased Alpha GENERIC_ENTRY patch on an AlphaServer ES40. The kernel built and booted successfully with CONFIG_UBSAN=y, and the UBSAN instrumentation is active.

So have I, on an XP1000 and ES45.

Quoted 3 lines

CONFIG_UBSAN_ALIGNMENT did expose a misaligned struct bucket_table allocation in lib/rhashtable.c. This appears to be a generic rhashtable allocation-alignment issue rather than an Alpha UBSAN problem.

But in my case the kernel vomited copious misaligned access reports, so many that it took quite a few minutes to boot and I lost much of the kernel log before disks were mounted. A few examples that were recorded later in the boot on the ES45:

Sep 03 21:12:36 electro kernel: UBSAN: misaligned-access in net/core/dev.c:1401:2
Sep 03 21:12:36 electro kernel: member access within misaligned address (____ptrval____) for type 'struct net_device'
Sep 03 21:12:36 electro kernel: which requires 64 byte alignment
Sep 03 21:12:36 electro kernel: UBSAN: misaligned-access in kernel/signal.c:4362:4
Sep 03 21:12:36 electro kernel: member access within misaligned address 0000000058e1e939 for type 'struct task_struct'
Sep 03 21:12:36 electro kernel: which requires 64 byte alignment
Quoted 8 lines
Sep 03 21:13:04 electro kernel: UBSAN: misaligned-access in drivers/net/ethernet/intel/e100.c:1941:36
Sep 03 21:13:04 electro kernel: member access within misaligned address 000000001c866fa6 for type 'struct rfd'
Sep 03 21:13:04 electro kernel: which requires 4 byte alignment

Interestingly "kernel unaligned acc" in /proc/cpuinfo remained at zero, which really makes me wonder whether these reports are all false-positives.

Good question, had to dig deeper here,

Not false positives - real UB, but harmless, and I tracked down why. for_each_thread() and for_each_netdev_rcu() are list_for_each_entry
macros: their loop computes container_of() once extra per traversal, unconditionally, to test for end-of-list. That test compares against the list head (&signal->thread_head, &net->dev_base_head), which lives in a different struct entirely (signal_struct, net) - not task_struct/net_device. At the real end of the list, container_of() still subtracts offsetof(task_struct, thread_node) from that head's address anyway, producing a pointer that looks nothing like a real task_struct. It's used only for a pointer-value comparison, never dereferenced - confirmed with a printk inside find_alive_thread()'s loop body that never fired even when UBSAN caught the same line. Zero unaligned-access count follows directly: nothing ever loads or stores through it.

If it's worth fixing rather than living with: the sentinel comparison in list_entry_rcu()/list_for_each_entry_rcu() only needs the raw pointer value, not a type-checked container_of(). Splitting that one use into an unchecked pointer subtraction for the loop-termination test, keeping checked container_of() for the real element on every other iteration, would remove the false trigger without losing any real coverage. Not alpha-specific, so probably wants a wider list than this one if someone wants to pick it up.

e100.c's struct rfd is unrelated: casts skb->data (not guaranteed 4-byte aligned) to struct rfd *, writes via put_unaligned_le32() - UB in the cast, safe access after.
Not alpha-specific either - list_for_each_entry is everywhere. CONFIG_UBSAN_ALIGNMENT just defaults on for us (!HAVE_EFFICIENT_UNALIGNED_ACCESS) and off elsewhere. Confirmed on the UP2000+ rather than assumed: 7 reports, "kernel unaligned acc: 0" never moved.

Magnus

author maintainer
#5 lore raw

Re: [PATCH 02/24] alpha: enter hardirq context before looking up the irq descriptor

In reply to Magnus Lindholm
Quoted 66 lines · Magnus Lindholm

Hi Matt,

Quoted 46 lines · Matt Turner

handle_irq() called irq_to_desc() before irq_enter(), so that lookup ran with the preempt count still saying task context and with RCU not yet watching. Generic code called from an interrupt handler should see hardirq context, and irq_to_desc() is more than an array index once SPARSE_IRQ is in use.

Move irq_enter() to the top of the function and add the matching irq_exit() to the invalid interrupt path.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/kernel/irq.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
arch/alpha/kernel/irq.c +6 -4
index 4a6a8b1d5a8b..5867a1655045 100644
@@ -107,18 +107,21 @@ handle_irq(int irq)
         * handled by some other CPU. (or is disabled)
         */
        static unsigned int illegal_count=0;
-       struct irq_desc *desc = irq_to_desc(irq);
-
+       struct irq_desc *desc;
+
+       irq_enter();
+
+       desc = irq_to_desc(irq);
        if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
            illegal_count < MAX_ILLEGAL_IRQS)) {
                irq_err_count++;
                illegal_count++;
                printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
                       irq);
+               irq_exit();
                return;
        }
 
-       irq_enter();
        generic_handle_irq_desc(desc);
        irq_exit();
 }
--
Quoted 2 lines

2.54.0

Going over this code again, I noticed what may be redundant hardirq accounting in the existing device-interrupt path.

For type 3 interrupts, do_entInt() already wraps alpha_mv.device_interrupt() in irq_enter()/irq_exit(). The platform dispatcher then calls handle_irq(), which enters and exits hardirq context again. Therefore, irq_to_desc() is already reached in hardirq context before this patch. The patch moves it from nesting level one to level two rather than from task context to hardirq context.

The RTC path does not have the outer irq_enter(), so the change is needed there.

Quoted 8 lines

Would it be cleaner for do_entInt() to own the hardirq context for both paths and remove the pair from handle_irq()? Or is there another caller which requires handle_irq() to manage it itself?

I tested the patch on a two-CPU UP2000 with lockdep, IRQ flag tracing, and sparse IRQs enabled. SCSI and network interrupts operated normally, I observed no lockdep or IRQ-related warnings, and debug_locks remained enabled in /proc/lockdep_stats.

Hi Magnus,

Good question. Yes, do_entInt() should own irq_enter()/irq_exit() for the RTC and device-interrupt cases too, same as it already does for IPI, machine-check, and perf. RTC and device-interrupt are the only two that don't, and only because handle_irq() does it internally.

There's a wrinkle. A bunch of device_interrupt() implementations call handle_irq() in a loop over several pending vectors: sys_takara.c, sys_eiger.c, sys_alcor.c, sys_dp264.c, sys_cabriolet.c, sys_noritake.c, sys_mikasa.c, sys_rx164.c, irq_pyxis.c, irq_i8259.c. Right now each of those handle_irq() calls enters and exits hardirq context on its own, so one hardware interrupt that demuxes to N IRQs does N enter/exit pairs. Moving the pair up to do_entInt() collapses that to one per hardware interrupt, matching how the IPI/machine-check/perf cases already work.

I don't see anything in the per-machine device_interrupt() bodies that needs task context before the first handle_irq() call -- it's all vector decode. But I've only got one Marvel box to boot-test on, so I'm not comfortable folding the reshuffle into this patch without at least reading through the other machine types more carefully.

I'll send it as a follow-up on top of the series rather than reworking patch 2. Easier to drop if something turns out to care. Let me know if you think that's wrong.

Thanks,
Matt

maintainer
#6 lore raw

Re: [PATCH 02/24] alpha: enter hardirq context before looking up the irq descriptor

Hi Matt,

Quoted 100 lines · Matt Turner
Quoted 66 lines · Magnus Lindholm

Hi Matt,

Quoted 46 lines · Matt Turner

handle_irq() called irq_to_desc() before irq_enter(), so that lookup ran with the preempt count still saying task context and with RCU not yet watching. Generic code called from an interrupt handler should see hardirq context, and irq_to_desc() is more than an array index once SPARSE_IRQ is in use.

Move irq_enter() to the top of the function and add the matching irq_exit() to the invalid interrupt path.

Assisted-by Claude:claude-opus-5
---
 arch/alpha/kernel/irq.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
arch/alpha/kernel/irq.c +6 -4
index 4a6a8b1d5a8b..5867a1655045 100644
@@ -107,18 +107,21 @@ handle_irq(int irq)
         * handled by some other CPU. (or is disabled)
         */
        static unsigned int illegal_count=0;
-       struct irq_desc *desc = irq_to_desc(irq);
-
+       struct irq_desc *desc;
+
+       irq_enter();
+
+       desc = irq_to_desc(irq);
        if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
            illegal_count < MAX_ILLEGAL_IRQS)) {
                irq_err_count++;
                illegal_count++;
                printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
                       irq);
+               irq_exit();
                return;
        }
 
-       irq_enter();
        generic_handle_irq_desc(desc);
        irq_exit();
 }
--
Quoted 2 lines

2.54.0

Going over this code again, I noticed what may be redundant hardirq accounting in the existing device-interrupt path.

For type 3 interrupts, do_entInt() already wraps alpha_mv.device_interrupt() in irq_enter()/irq_exit(). The platform dispatcher then calls handle_irq(), which enters and exits hardirq context again. Therefore, irq_to_desc() is already reached in hardirq context before this patch. The patch moves it from nesting level one to level two rather than from task context to hardirq context.

The RTC path does not have the outer irq_enter(), so the change is needed there.

Quoted 8 lines

Would it be cleaner for do_entInt() to own the hardirq context for both paths and remove the pair from handle_irq()? Or is there another caller which requires handle_irq() to manage it itself?

I tested the patch on a two-CPU UP2000 with lockdep, IRQ flag tracing, and sparse IRQs enabled. SCSI and network interrupts operated normally, I observed no lockdep or IRQ-related warnings, and debug_locks remained enabled in /proc/lockdep_stats.

Hi Magnus,

Good question. Yes, do_entInt() should own irq_enter()/irq_exit() for the RTC and device-interrupt cases too, same as it already does for IPI, machine-check, and perf. RTC and device-interrupt are the only two that don't, and only because handle_irq() does it internally.

There's a wrinkle. A bunch of device_interrupt() implementations call handle_irq() in a loop over several pending vectors: sys_takara.c, sys_eiger.c, sys_alcor.c, sys_dp264.c, sys_cabriolet.c, sys_noritake.c, sys_mikasa.c, sys_rx164.c, irq_pyxis.c, irq_i8259.c. Right now each of those handle_irq() calls enters and exits hardirq context on its own, so one hardware interrupt that demuxes to N IRQs does N enter/exit pairs. Moving the pair up to do_entInt() collapses that to one per hardware interrupt, matching how the IPI/machine-check/perf cases already work.

I don't see anything in the per-machine device_interrupt() bodies that needs task context before the first handle_irq() call -- it's all vector decode. But I've only got one Marvel box to boot-test on, so I'm not comfortable folding the reshuffle into this patch without at least reading through the other machine types more carefully.

Quoted 4 lines

I'll send it as a follow-up on top of the series rather than reworking patch 2. Easier to drop if something turns out to care. Let me know if you think that's wrong.

That sounds like a good plan, we treat that as a follow-up once this has landed.

Regards

Magnus

#11 lore raw

Re: [PATCH 03/24] alpha: select ARCH_HAS_UBSAN

In reply to Magnus Lindholm

Hi Magnus,

Quoted 20 lines · Magnus Lindholm
Quoted 19 lines · Michael Cree
Quoted 9 lines · Magnus Lindholm
Quoted 5 lines · Matt Turner

GCC's undefined behavior sanitizer has no architecture-specific runtime requirements. Enable it for Alpha to allow UBSAN instrumentation of the kernel.

I tested this patch on top of my rebased Alpha GENERIC_ENTRY patch on an AlphaServer ES40. The kernel built and booted successfully with CONFIG_UBSAN=y, and the UBSAN instrumentation is active.

So have I, on an XP1000 and ES45.

Quoted 3 lines

CONFIG_UBSAN_ALIGNMENT did expose a misaligned struct bucket_table allocation in lib/rhashtable.c. This appears to be a generic rhashtable allocation-alignment issue rather than an Alpha UBSAN problem.

But in my case the kernel vomited copious misaligned access reports,

Quoted 7 lines
Quoted 4 lines

Interestingly "kernel unaligned acc" in /proc/cpuinfo remained at zero, which really makes me wonder whether these reports are all false-positives.

Good question, had to dig deeper here,

Not false positives - real UB, but harmless, and I tracked down why.

Thanks for taking time to find the explanation. So, technical UB but no consequence for operation.

Cheers,
Michael.