NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: port-alpha/60865 (NetBSD-current/alpha panics running getcwd test)
I could reproduce this problem more easily:
```
# ls /proc
[ 12.6627837] CPU 0: fatal kernel trap:
[ 12.6747358] CPU 0 trap entry = 0x2 (memory management fault)
[ 12.6924180] CPU 0 a0 = 0x0
[ 12.7033379] CPU 0 a1 = 0x1
[ 12.7142582] CPU 0 a2 = 0xffffffffffffffff
[ 12.7290796] CPU 0 pc = 0x0
[ 12.7400000] CPU 0 ra = 0x0
[ 12.7509206] CPU 0 pv = 0xfffffc0000a67ea8
[ 12.7657422] CPU 0 curlwp = 0xfffffc007f636a40
[ 12.7805637] CPU 0 pid = 126, comm = ls
[ 12.7940843] panic: trap
[ 12.8013654] cpu0: Begin traceback...
[ 12.8120241] at 0xfffffc00007f79a0 pc 0xfffffc000119eb4c
[ 12.8297761] vpanic() at netbsd:vpanic+0x14c
[ 12.8444251] printf() at netbsd:printf_nostamp+0xf0
[ 12.8594534] --- root of call graph ---
[ 12.8706338] cpu0: End traceback...
Stopped in pid 126.126 (ls) at netbsd:cpu_Debugger+0x4: ret
zero,(ra)
```
TL;DR This is because kernel stack is only aligned to 8-byte
boundaries. If it is properly aligned to 16-byte boundaries,
panic disappears. We fixed user-space stack alignment few years
ago, but we overlooked kernel stack at that time.
Carrying out bisectioning, I've found that this is due to
kern_proc.c::proclist_foreach_call().
(1) If this function is compiled with
__attribute__((optimize("trivial-auto-var-init=uninitialized"))),
panic does not occur.
(2) With
__attribute__((optimize("trivial-auto-var-init=zero"))),
panic occurs.
(3) With
__attribute__((optimize("trivial-auto-var-init=uninitialized"))),
but memset(&marker, 0, sizeof(marker)) in that function,
panic occurs.
So, I guess that marker does not fit within stack frame, and
initialization corrupts caller's stack frame for
-ftrivial-auto-var-init=pattern (default), (2), and (3),
Actually, objdump for (3) reads:
```
0000000000003c60 <proclist_foreach_call>:
{
3c60: 00 00 bb 27 ldah gp,0(t12)
3c64: 00 00 bd 23 lda gp,0(gp)
3c68: 50 fc de 23 lda sp,-944(sp)
3c6c: 00 00 5e b7 stq ra,0(sp)
3c70: 08 00 3e b5 stq s0,8(sp)
3c74: 10 00 5e b5 stq s1,16(sp)
3c78: 18 00 7e b5 stq s2,24(sp)
3c7c: 20 00 9e b5 stq s3,32(sp)
3c80: 28 00 be b5 stq s4,40(sp)
3c84: 30 00 de b5 stq s5,48(sp)
3c88: 38 00 fe b5 stq fp,56(sp)
3c8c: 7f 00 5e 20 lda t1,127(sp)
memset(&marker, 0, sizeof(marker));
3c90: 00 00 7d a7 ldq t12,0(gp)
{
3c94: 0d f1 47 44 andnot t1,0x3f,s4
3c98: 09 04 f0 47 mov a0,s0
3c9c: 0b 04 f1 47 mov a1,s2
memset(&marker, 0, sizeof(marker));
3ca0: 10 04 ed 47 mov s4,a0
3ca4: 11 04 ff 47 clr a1
{
3ca8: 0c 04 f2 47 mov a2,s3
memset(&marker, 0, sizeof(marker));
3cac: 40 03 5f 22 lda a2,832
3cb0: 00 40 5b 6b jsr ra,(t12),3cb4
<proclist_foreach_call+0x54>
```
So, this code does:
sp <-- sp - 944
&marker <-- roundup(sp + 64, 64)
memset(&marker, 0, 832)
If sp is aligned to 16-byte boundaries, as ABI (there's no ELF
ABI for alpha, so ABI means GCC here) requires, marker always
fits within stack frame.
However, if sp is aligned only aligned to 8-byte boundaries,
marker generally does not fit, and memset() corrupts caller's
stack frame.
Actually, inserting this code into proclist_foreach_call()
causes KASSERT failure:
```
uint64_t sp;
__asm__ volatile ("mov $30, %0" : "=r" (sp) ::);
KASSERTMSG((sp & 0xf) == 0, "sp 0x%016" PRIx64, sp);
```
With attached patch below, panic no longer occurs for me.
But, I'm not sure that this fix is enough for proper kernel
stack alignments.
Thanks,
rin
```
commit 23014dd67d0
Author: Rin Okuyama <rokuyama.rk%gmail.com@localhost>
Date: Tue Oct 20 20:32:59 2026 +0900
alpha: Align kernel stack pointer to 16-byte bourndaries
diff --git a/sys/arch/alpha/alpha/machdep.c b/sys/arch/alpha/alpha/machdep.c
index 8a4f98beb1d..79f2bd0c444 100644
--- a/sys/arch/alpha/alpha/machdep.c
+++ b/sys/arch/alpha/alpha/machdep.c
@@ -725,7 +725,8 @@ nobootinfo:
* Set the kernel sp, reserving space for an (empty) trapframe,
* and make lwp0's trapframe pointer point to it for sanity.
*/
- pcb0->pcb_hw.apcb_ksp = v + USPACE - sizeof(struct trapframe);
+ pcb0->pcb_hw.apcb_ksp = (v + USPACE - sizeof(struct trapframe)) &
+ ~STACK_ALIGNBYTES;
lwp0.l_md.md_tf = (struct trapframe *)pcb0->pcb_hw.apcb_ksp;
/* Indicate that lwp0 has a CPU. */
diff --git a/sys/arch/alpha/alpha/vm_machdep.c
b/sys/arch/alpha/alpha/vm_machdep.c
index 3cbaaf6a380..b6dd44c04c3 100644
--- a/sys/arch/alpha/alpha/vm_machdep.c
+++ b/sys/arch/alpha/alpha/vm_machdep.c
@@ -152,8 +152,9 @@ cpu_lwp_fork(struct lwp *l1, struct lwp *l2, void
*stack, size_t stacksize,
* copy trapframe from parent so return to user mode
* will be to right address, with correct registers.
*/
- l2tf = l2->l_md.md_tf = (struct trapframe *)
- (uvm_lwp_getuarea(l2) + USPACE - sizeof(struct trapframe));
+ l2tf = l2->l_md.md_tf = (struct trapframe *)((uintptr_t)
+ (uvm_lwp_getuarea(l2) + USPACE - sizeof(struct trapframe)) &
+ ~STACK_ALIGNBYTES);
memcpy(l2->l_md.md_tf, l1->l_md.md_tf,
sizeof(struct trapframe));
```
Home |
Main Index |
Thread Index |
Old Index