Quellcode durchsuchen

microblaze: use ramin's patchset for Linux Kernel instead of GCC patch

Waldemar Brodkorb vor 1 Woche
Ursprung
Commit
5b3c0298fe

+ 14 - 4
target/linux/patches/6.18.40/microblaze-wire-up-sigaltstack.patch → target/linux/patches/6.18.40/0002-microblaze-wire-up-sigaltstack.patch

@@ -1,5 +1,7 @@
+From 600d06cb443526020efa411053b83fc1697f27dc Mon Sep 17 00:00:00 2001
 From: Ramin Moussavi <ramin.moussavi@yacoub.de>
-Subject: [PATCH] microblaze: wire up sigaltstack
+Date: Fri, 21 Aug 2026 17:18:05 +0200
+Subject: [PATCH 2/6] microblaze: wire up sigaltstack
 
 sigaltstack is wired to sys_ni_syscall - microblaze is the only
 architecture without it - although the microblaze signal delivery code
@@ -9,14 +11,19 @@ sys_rt_sigreturn() calls restore_altstack().
 
 Wire it up to sys_sigaltstack.
 
-Tested on qemu petalogix-s3adsp1800 (microblazeel, kernel 6.5.10 and
-syscall table unchanged in current mainline) with the uClibc-ng test
-suite: the five sigaltstack-dependent NPTL tests (tst-cancel20/21,
+Tested on qemu petalogix-s3adsp1800 (microblazeel) with the uClibc-ng
+test suite: the five sigaltstack-dependent NPTL tests (tst-cancel20/21,
 tst-cancelx20/21, tst-signal6) pass; before this change sigaltstack()
 returned ENOSYS.
 
+Assisted-by: Claude:claude-opus-5
 Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+---
+ arch/microblaze/kernel/syscalls/syscall.tbl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
 
+diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl
+index c55a5c96f49b..76d7cbe2a133 100644
 --- a/arch/microblaze/kernel/syscalls/syscall.tbl
 +++ b/arch/microblaze/kernel/syscalls/syscall.tbl
 @@ -193,7 +193,7 @@
@@ -28,3 +35,6 @@ Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
  187	common	sendfile			sys_sendfile
  188	common	getpmsg				sys_ni_syscall
  189	common	putpmsg				sys_ni_syscall
+-- 
+2.47.3
+

+ 56 - 0
target/linux/patches/6.18.40/0003-microblaze-reserve-the-ABI-argument-home-area-in-the.patch

@@ -0,0 +1,56 @@
+From feb8514a3df395e73702246f649c4a5f0388d11f Mon Sep 17 00:00:00 2001
+From: Ramin Moussavi <ramin.moussavi@yacoub.de>
+Date: Fri, 21 Aug 2026 17:18:06 +0200
+Subject: [PATCH 3/6] microblaze: reserve the ABI argument-home area in the
+ signal frame
+
+The MicroBlaze procedure call standard reserves [r1+0] for the return
+address and lets a callee store its incoming register arguments r5..r10
+into the caller-provided home slots at [r1+4]..[r1+24].  When the kernel
+enters a signal handler it sets r1 to point at struct rt_sigframe, whose
+leading member is the siginfo prepared for the handler.  A handler that
+homes its arguments - which an unoptimised (-O0) build always does -
+therefore overwrites the first 24 bytes of that siginfo, so an
+SA_SIGINFO handler reads corrupted values.  The stores stay within
+siginfo (128 bytes) and do not reach the ucontext behind it.
+
+Reserve the home area by making a seven-word gap -- the return-address
+slot plus the six argument slots, 28 bytes -- the first member of struct
+rt_sigframe, so the handler's argument stores land in scratch space
+instead of clobbering siginfo.
+
+Tested on qemu-system-microblazeel (petalogix-s3adsp1800) with the
+uClibc-ng NPTL test suite: tst-timer4, tst-timer5, tst-mqueue5 and
+tst-signal6 pass; before this change they failed because the handler
+clobbered the signal frame.
+
+Fixes: 2148daa9c45f ("microblaze_v8: Signal support")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-5
+Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+---
+ arch/microblaze/kernel/signal.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
+index c78a0ff48066..4956014a9937 100644
+--- a/arch/microblaze/kernel/signal.c
++++ b/arch/microblaze/kernel/signal.c
+@@ -49,6 +49,14 @@ struct sigframe {
+ };
+ 
+ struct rt_sigframe {
++	/*
++	 * Home area for the handler's register arguments: the MicroBlaze
++	 * ABI reserves [r1+0] for the return address and lets the callee
++	 * store r5..r10 at [r1+4]..[r1+24], and r1 points at this frame
++	 * when the handler is entered.  Without the gap those stores
++	 * corrupt frame->info.
++	 */
++	unsigned long abi_gap[7];
+ 	struct siginfo info;
+ 	struct ucontext uc;
+ 	unsigned long tramp[2];	/* signal trampoline */
+-- 
+2.47.3
+

+ 99 - 0
target/linux/patches/6.18.40/0004-microblaze-don-t-clobber-r3-r4-restored-by-rt_sigret.patch

@@ -0,0 +1,99 @@
+From 962fccaf71c15530defface36a77fa8e0d623472 Mon Sep 17 00:00:00 2001
+From: Ramin Moussavi <ramin.moussavi@yacoub.de>
+Date: Fri, 21 Aug 2026 17:18:07 +0200
+Subject: [PATCH 4/6] microblaze: don't clobber r3/r4 restored by rt_sigreturn
+
+ret_from_trap begins by storing the system call return values r3 and r4
+back into the saved user pt_regs.  That is right for an ordinary system
+call, but sys_rt_sigreturn() returns through the same path and has to be
+transparent: restore_sigcontext() has just filled pt_regs from the signal
+frame, and every register must reach userspace exactly as saved.  The two
+stores overwrite the restored r3/r4 with whatever the C function left in
+those registers.
+
+Only r4 is actually lost, and that follows from how sigreturn is written
+everywhere rather than from chance.  Architectures have sys_rt_sigreturn()
+return the restored return-value register precisely so that this writeback
+stores the restored value -- arm returns regs->ARM_r0, riscv and csky
+regs->a0, arc regs->r0 -- and microblaze does the same through
+*rval_p = regs->r3 in restore_sigcontext().  But the entry macros treat r3
+and r4 as a pair, so ret_from_trap writes back two registers while a C
+function has only one return value; nothing carries the restored r4.
+
+Commit 791d0a169b91 ("microblaze: Fix sys_rt_sigreturn_wrapper") introduced
+this in v2.6.37.  The old wrapper saved r3/r4 before the call and reloaded
+them from pt_regs afterwards; switching brlid to brid removed the only
+point where they were reloaded, and the stores have been overwriting them
+ever since.
+
+Fix it the way the sibling paths already behave: ret_from_irq and
+ret_from_exc restore the full register set and do not perform these stores
+at all.  Label the instruction after the stores ret_from_trap_no_rval and
+enter there, biasing r15 by -8 so that the ABI return "rtsd r15, 8" lands
+on it; naming the entry rather than computing ret_from_trap + 8 keeps it
+correct if the number of stores ever changes.  Restoring the old
+save/reload would work too, but costs four memory accesses and a branch to
+undo damage that is better not done.
+
+Any value the compiler keeps in r4 across a signal is lost.  The tightest
+windows are the lwx/swx compare-and-swap retry loops gcc emits for atomics:
+in uClibc-ng's libc.so alone, 50 of 364 such loops hold the address in r4.
+This is not specific to one libc -- musl passes the address as "r"(p), and
+glibc has no microblaze atomic-machine.h and so uses gcc's __atomic
+builtins, which expand the same way.  Triggering it needs threads plus a
+signal storm, which is why it survived 15 years.
+
+Reproduced on qemu-system-microblazeel (petalogix-s3adsp1800) by running
+the uClibc-ng NPTL test tst-eintr1 40 times against an unchanged userspace:
+on v7.2 built with gcc 16.2.0, 23 of 40 iterations died with SIGSEGV
+without this patch and 0 of 40 with it; on v7.0 built with gcc 12.5.0 the
+same comparison gave 6 of 40 against 0 of 40.  The register dump of a
+failing iteration shows the signature: a zero r4 and a fault at address 0,
+while r3 came back intact.
+
+Fixes: 791d0a169b91 ("microblaze: Fix sys_rt_sigreturn_wrapper")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-5
+Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+---
+ arch/microblaze/kernel/entry.S | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
+index 582d7256d815..fea235f139d7 100644
+--- a/arch/microblaze/kernel/entry.S
++++ b/arch/microblaze/kernel/entry.S
+@@ -434,7 +434,13 @@ C_ENTRY(_user_exception):
+ C_ENTRY(ret_from_trap):
+ 	swi	r3, r1, PT_R3
+ 	swi	r4, r1, PT_R4
+-
++/*
++ * Entry point for returns that must not store r3/r4 back into pt_regs,
++ * i.e. rt_sigreturn, which has already restored them from the signal
++ * context.  Reached as "rtsd r15, 8" with r15 set to this label minus 8,
++ * so it stays correct if the number of stores above ever changes.
++ */
++ret_from_trap_no_rval:
+ 	lwi	r11, r1, PT_MODE;
+ /* See if returning to kernel mode, if so, skip resched &c.  */
+ 	bnei	r11, 2f;
+@@ -518,6 +524,15 @@ C_ENTRY(ret_from_kernel_thread):
+ 
+ C_ENTRY(sys_rt_sigreturn_wrapper):
+ 	addik	r30, r0, 0		/* no restarts */
++	/*
++	 * rt_sigreturn restores the full register set from the signal
++	 * context, so it must skip the r3/r4 syscall-return stores at the
++	 * head of ret_from_trap which would otherwise overwrite the
++	 * just-restored r3/r4.  Every C function returns with "rtsd r15, 8"
++	 * -- the ABI return, where the 8 skips the caller's branch and its
++	 * delay slot -- so bias r15 by -8 to land on ret_from_trap_no_rval.
++	 */
++	addik	r15, r0, ret_from_trap_no_rval - 8
+ 	brid	sys_rt_sigreturn	/* Do real work */
+ 	addik	r5, r1, 0;		/* add user context as 1st arg */
+ 
+-- 
+2.47.3
+

+ 864 - 0
target/linux/patches/6.18.40/0005-microblaze-restore-the-ABI-argument-home-area-below-.patch

@@ -0,0 +1,864 @@
+From 766e785ac2e6e4ff63fac1d7f445eb37ed3ead36 Mon Sep 17 00:00:00 2001
+From: Ramin Moussavi <ramin.moussavi@yacoub.de>
+Date: Fri, 21 Aug 2026 17:18:08 +0200
+Subject: [PATCH 5/6] microblaze: restore the ABI argument home area below
+ pt_regs (PTO)
+
+The MicroBlaze ABI has the caller reserve stack space for the arguments
+it passes in registers: REG_PARM_STACK_SPACE is 24 and
+OUTGOING_REG_PARM_STACK_SPACE is 1 in the gcc backend, so a callee may
+write to [caller_sp + 4, caller_sp + 28).  The kernel calls C functions
+from entry.S with r1 pointing at pt_regs, handing the callee license to
+spill its incoming arguments over the saved registers -- the syscall
+dispatch is the worst case, where the first argument slot is PT_R1, the
+saved user stack pointer.
+
+This was latent until GCC 15: since 3b9b8d6cfdf5 ("ira: Scale
+save/restore costs of callee save registers with block frequency") the
+allocator prefers spilling incoming arguments over copying them into
+callee-saved registers, and a kernel built with gcc >= 15 (without the
+TARGET_CALLEE_SAVE_COST workaround some distributions carry) corrupts
+PT_R1 on the first syscall: init takes SIGSEGV and the kernel panics.
+
+The kernel had exactly this reservation until 2011:
+commit 6e83557c38b4 ("microblaze: Remove r0_ram pointer and PTO alignment")
+removed STATE_SAVE_ARG_SPACE and with it the PTO offset, as part of
+cleaning up what was thought to be copied-from-v850 leftovers.  Restore
+it: the frame is STATE_SAVE_SIZE = PT_SIZE + PTO, r1 stays at the frame
+base through every asm-to-C call, and the saved registers are reached
+at r1 + PTO + PT_*.  PTO is 28 rather than the historic 24, which was
+one word short: FIRST_PARM_OFFSET is 4 and REG_PARM_STACK_SPACE is 24,
+so the area spans [sp+4, sp+28) and needs 28 bytes.  With 24 the last
+argument slot overlapped pt_regs' r0 -- harmless only because r0 is the
+constant-zero register.  STACK_BOUNDARY is 32 bits, so 28 needs no
+further rounding.
+
+Two places deliberately keep their mainline addressing.
+hw_exception_handler.S needs no offset change: its real-mode handler
+saves into the standalone pt_pool_space buffer rather than a stack
+frame, and _unaligned_data_exception works through a pointer to pt_regs
+in r7, where plain PT_* offsets are already right.  And the user-SP
+reload after popping the frame keeps PT_R1 - PT_SIZE because PTO
+cancels there: (PTO + PT_R1) - (PT_SIZE + PTO) = PT_R1 - PT_SIZE.  Both
+are exactly as the pre-2011 code had them.
+
+The instruction count is unchanged -- the same instructions with
+different immediates, no per-call reservation and no trampolines.  The
+cost is 28 bytes more kernel stack per saved frame.
+
+Fixes: 6e83557c38b4 ("microblaze: Remove r0_ram pointer and PTO alignment")
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-5
+Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+---
+ arch/microblaze/include/asm/entry.h           |  13 +
+ arch/microblaze/include/asm/processor.h       |   2 +-
+ arch/microblaze/kernel/entry.S                | 329 +++++++++---------
+ arch/microblaze/kernel/hw_exception_handler.S |   5 +
+ arch/microblaze/kernel/process.c              |   5 +-
+ 5 files changed, 189 insertions(+), 165 deletions(-)
+
+diff --git a/arch/microblaze/include/asm/entry.h b/arch/microblaze/include/asm/entry.h
+index 9efadf12397c..05acf4d7bc4b 100644
+--- a/arch/microblaze/include/asm/entry.h
++++ b/arch/microblaze/include/asm/entry.h
+@@ -21,6 +21,19 @@
+ 
+ #define PER_CPU(var) var
+ 
++/*
++ * The MicroBlaze ABI has the caller reserve an argument home area:
++ * REG_PARM_STACK_SPACE is 24 and OUTGOING_REG_PARM_STACK_SPACE is 1, so a
++ * callee may write to [caller_sp + 4, caller_sp + 28).  The kernel calls C
++ * with r1 at the frame base, so reserve that area below pt_regs and reach
++ * the saved registers through PTO.  This restores what 6e83557c38b4
++ * ("microblaze: Remove r0_ram pointer and PTO alignment") removed; the old
++ * value of 24 was one word short and left the last argument slot
++ * overlapping pt_regs' r0.
++ */
++#define PTO			28
++#define STATE_SAVE_SIZE		(PT_SIZE + PTO)
++
+ # ifndef __ASSEMBLER__
+ DECLARE_PER_CPU(unsigned int, KSP); /* Saved kernel stack pointer */
+ DECLARE_PER_CPU(unsigned int, KM); /* Kernel/user mode */
+diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
+index d59bdfffca7c..595c24db2728 100644
+--- a/arch/microblaze/include/asm/processor.h
++++ b/arch/microblaze/include/asm/processor.h
+@@ -73,7 +73,7 @@ unsigned long __get_wchan(struct task_struct *p);
+ #  define task_regs(task) ((struct pt_regs *)task_tos(task) - 1)
+ 
+ #  define task_pt_regs_plus_args(tsk) \
+-	((void *)task_pt_regs(tsk))
++	(((void *)task_pt_regs(tsk)) - PTO)
+ 
+ #  define task_sp(task)	(task_regs(task)->r1)
+ #  define task_pc(task)	(task_regs(task)->pc)
+diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
+index fea235f139d7..dfca6ce2d628 100644
+--- a/arch/microblaze/kernel/entry.S
++++ b/arch/microblaze/kernel/entry.S
+@@ -177,78 +177,78 @@ syscall_debug_table:
+ 1:
+ 
+ #define SAVE_REGS \
+-	swi	r2, r1, PT_R2;	/* Save SDA */			\
+-	swi	r3, r1, PT_R3;					\
+-	swi	r4, r1, PT_R4;					\
+-	swi	r5, r1, PT_R5;					\
+-	swi	r6, r1, PT_R6;					\
+-	swi	r7, r1, PT_R7;					\
+-	swi	r8, r1, PT_R8;					\
+-	swi	r9, r1, PT_R9;					\
+-	swi	r10, r1, PT_R10;					\
+-	swi	r11, r1, PT_R11;	/* save clobbered regs after rval */\
+-	swi	r12, r1, PT_R12;					\
+-	swi	r13, r1, PT_R13;	/* Save SDA2 */			\
+-	swi	r14, r1, PT_PC;	/* PC, before IRQ/trap */	\
+-	swi	r15, r1, PT_R15;	/* Save LP */			\
+-	swi	r16, r1, PT_R16;					\
+-	swi	r17, r1, PT_R17;					\
+-	swi	r18, r1, PT_R18;	/* Save asm scratch reg */	\
+-	swi	r19, r1, PT_R19;					\
+-	swi	r20, r1, PT_R20;					\
+-	swi	r21, r1, PT_R21;					\
+-	swi	r22, r1, PT_R22;					\
+-	swi	r23, r1, PT_R23;					\
+-	swi	r24, r1, PT_R24;					\
+-	swi	r25, r1, PT_R25;					\
+-	swi	r26, r1, PT_R26;					\
+-	swi	r27, r1, PT_R27;					\
+-	swi	r28, r1, PT_R28;					\
+-	swi	r29, r1, PT_R29;					\
+-	swi	r30, r1, PT_R30;					\
+-	swi	r31, r1, PT_R31;	/* Save current task reg */	\
++	swi	r2, r1, PTO+PT_R2;	/* Save SDA */			\
++	swi	r3, r1, PTO+PT_R3;					\
++	swi	r4, r1, PTO+PT_R4;					\
++	swi	r5, r1, PTO+PT_R5;					\
++	swi	r6, r1, PTO+PT_R6;					\
++	swi	r7, r1, PTO+PT_R7;					\
++	swi	r8, r1, PTO+PT_R8;					\
++	swi	r9, r1, PTO+PT_R9;					\
++	swi	r10, r1, PTO+PT_R10;					\
++	swi	r11, r1, PTO+PT_R11;	/* save clobbered regs after rval */\
++	swi	r12, r1, PTO+PT_R12;					\
++	swi	r13, r1, PTO+PT_R13;	/* Save SDA2 */			\
++	swi	r14, r1, PTO+PT_PC;	/* PC, before IRQ/trap */	\
++	swi	r15, r1, PTO+PT_R15;	/* Save LP */			\
++	swi	r16, r1, PTO+PT_R16;					\
++	swi	r17, r1, PTO+PT_R17;					\
++	swi	r18, r1, PTO+PT_R18;	/* Save asm scratch reg */	\
++	swi	r19, r1, PTO+PT_R19;					\
++	swi	r20, r1, PTO+PT_R20;					\
++	swi	r21, r1, PTO+PT_R21;					\
++	swi	r22, r1, PTO+PT_R22;					\
++	swi	r23, r1, PTO+PT_R23;					\
++	swi	r24, r1, PTO+PT_R24;					\
++	swi	r25, r1, PTO+PT_R25;					\
++	swi	r26, r1, PTO+PT_R26;					\
++	swi	r27, r1, PTO+PT_R27;					\
++	swi	r28, r1, PTO+PT_R28;					\
++	swi	r29, r1, PTO+PT_R29;					\
++	swi	r30, r1, PTO+PT_R30;					\
++	swi	r31, r1, PTO+PT_R31;	/* Save current task reg */	\
+ 	mfs	r11, rmsr;		/* save MSR */			\
+-	swi	r11, r1, PT_MSR;
++	swi	r11, r1, PTO+PT_MSR;
+ 
+ #define RESTORE_REGS_GP \
+-	lwi	r2, r1, PT_R2;	/* restore SDA */		\
+-	lwi	r3, r1, PT_R3;					\
+-	lwi	r4, r1, PT_R4;					\
+-	lwi	r5, r1, PT_R5;					\
+-	lwi	r6, r1, PT_R6;					\
+-	lwi	r7, r1, PT_R7;					\
+-	lwi	r8, r1, PT_R8;					\
+-	lwi	r9, r1, PT_R9;					\
+-	lwi	r10, r1, PT_R10;					\
+-	lwi	r11, r1, PT_R11;	/* restore clobbered regs after rval */\
+-	lwi	r12, r1, PT_R12;					\
+-	lwi	r13, r1, PT_R13;	/* restore SDA2 */		\
+-	lwi	r14, r1, PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\
+-	lwi	r15, r1, PT_R15;	/* restore LP */		\
+-	lwi	r16, r1, PT_R16;					\
+-	lwi	r17, r1, PT_R17;					\
+-	lwi	r18, r1, PT_R18;	/* restore asm scratch reg */	\
+-	lwi	r19, r1, PT_R19;					\
+-	lwi	r20, r1, PT_R20;					\
+-	lwi	r21, r1, PT_R21;					\
+-	lwi	r22, r1, PT_R22;					\
+-	lwi	r23, r1, PT_R23;					\
+-	lwi	r24, r1, PT_R24;					\
+-	lwi	r25, r1, PT_R25;					\
+-	lwi	r26, r1, PT_R26;					\
+-	lwi	r27, r1, PT_R27;					\
+-	lwi	r28, r1, PT_R28;					\
+-	lwi	r29, r1, PT_R29;					\
+-	lwi	r30, r1, PT_R30;					\
+-	lwi	r31, r1, PT_R31;	/* Restore cur task reg */
++	lwi	r2, r1, PTO+PT_R2;	/* restore SDA */		\
++	lwi	r3, r1, PTO+PT_R3;					\
++	lwi	r4, r1, PTO+PT_R4;					\
++	lwi	r5, r1, PTO+PT_R5;					\
++	lwi	r6, r1, PTO+PT_R6;					\
++	lwi	r7, r1, PTO+PT_R7;					\
++	lwi	r8, r1, PTO+PT_R8;					\
++	lwi	r9, r1, PTO+PT_R9;					\
++	lwi	r10, r1, PTO+PT_R10;					\
++	lwi	r11, r1, PTO+PT_R11;	/* restore clobbered regs after rval */\
++	lwi	r12, r1, PTO+PT_R12;					\
++	lwi	r13, r1, PTO+PT_R13;	/* restore SDA2 */		\
++	lwi	r14, r1, PTO+PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\
++	lwi	r15, r1, PTO+PT_R15;	/* restore LP */		\
++	lwi	r16, r1, PTO+PT_R16;					\
++	lwi	r17, r1, PTO+PT_R17;					\
++	lwi	r18, r1, PTO+PT_R18;	/* restore asm scratch reg */	\
++	lwi	r19, r1, PTO+PT_R19;					\
++	lwi	r20, r1, PTO+PT_R20;					\
++	lwi	r21, r1, PTO+PT_R21;					\
++	lwi	r22, r1, PTO+PT_R22;					\
++	lwi	r23, r1, PTO+PT_R23;					\
++	lwi	r24, r1, PTO+PT_R24;					\
++	lwi	r25, r1, PTO+PT_R25;					\
++	lwi	r26, r1, PTO+PT_R26;					\
++	lwi	r27, r1, PTO+PT_R27;					\
++	lwi	r28, r1, PTO+PT_R28;					\
++	lwi	r29, r1, PTO+PT_R29;					\
++	lwi	r30, r1, PTO+PT_R30;					\
++	lwi	r31, r1, PTO+PT_R31;	/* Restore cur task reg */
+ 
+ #define RESTORE_REGS \
+-	lwi	r11, r1, PT_MSR;					\
++	lwi	r11, r1, PTO+PT_MSR;					\
+ 	mts	rmsr , r11;						\
+ 	RESTORE_REGS_GP
+ 
+ #define RESTORE_REGS_RTBD \
+-	lwi	r11, r1, PT_MSR;					\
++	lwi	r11, r1, PTO+PT_MSR;					\
+ 	andni	r11, r11, MSR_EIP;          /* clear EIP */             \
+ 	ori	r11, r11, MSR_EE | MSR_BIP; /* set EE and BIP */        \
+ 	mts	rmsr , r11;						\
+@@ -265,11 +265,11 @@ syscall_debug_table:
+ 	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP));			\
+ 	/* FIXME: I can add these two lines to one */			\
+ 	/* tophys(r1,r1); */						\
+-	/* addik	r1, r1, -PT_SIZE; */				\
+-	addik	r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \
++	/* addik	r1, r1, -STATE_SAVE_SIZE; */				\
++	addik	r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \
+ 	SAVE_REGS							\
+ 	brid	2f;							\
+-	swi	r1, r1, PT_MODE; 	 				\
++	swi	r1, r1, PTO+PT_MODE; 	 				\
+ 1:	/* User-mode state save.  */					\
+ 	lwi	r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\
+ 	tophys(r1,r1);							\
+@@ -277,12 +277,13 @@ syscall_debug_table:
+ 	/* MS these three instructions can be added to one */		\
+ 	/* addik	r1, r1, THREAD_SIZE; */				\
+ 	/* tophys(r1,r1); */						\
+-	/* addik	r1, r1, -PT_SIZE; */			\
+-	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE; \
++	/* addik	r1, r1, -STATE_SAVE_SIZE; */			\
++	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR		\
++		- CONFIG_KERNEL_START - STATE_SAVE_SIZE;		\
+ 	SAVE_REGS							\
+ 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));			\
+-	swi	r11, r1, PT_R1; /* Store user SP.  */		\
+-	swi	r0, r1, PT_MODE; /* Was in user-mode.  */		\
++	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */		\
++	swi	r0, r1, PTO+PT_MODE; /* Was in user-mode.  */		\
+ 	/* MS: I am clearing UMS even in case when I come from kernel space */ \
+ 	clear_ums; 							\
+ 2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+@@ -292,7 +293,7 @@ syscall_debug_table:
+ .extern cpuinfo
+ 
+ C_ENTRY(mb_flush_dcache):
+-	addik	r1, r1, -PT_SIZE
++	addik	r1, r1, -STATE_SAVE_SIZE
+ 	SAVE_REGS
+ 
+ 	addik	r3, r0, cpuinfo
+@@ -305,12 +306,12 @@ C_ENTRY(mb_flush_dcache):
+ 	addk	r9, r9, r8
+ 
+ 	RESTORE_REGS
+-	addik	r1, r1, PT_SIZE
++	addik	r1, r1, STATE_SAVE_SIZE
+ 	rtsd	r15, 8
+ 	nop
+ 
+ C_ENTRY(mb_invalidate_icache):
+-	addik	r1, r1, -PT_SIZE
++	addik	r1, r1, -STATE_SAVE_SIZE
+ 	SAVE_REGS
+ 
+ 	addik	r3, r0, cpuinfo
+@@ -323,7 +324,7 @@ C_ENTRY(mb_invalidate_icache):
+ 	addk	r9, r9, r8
+ 
+ 	RESTORE_REGS
+-	addik	r1, r1, PT_SIZE
++	addik	r1, r1, STATE_SAVE_SIZE
+ 	rtsd	r15, 8
+ 	nop
+ 
+@@ -350,18 +351,18 @@ C_ENTRY(_user_exception):
+ 	addik	r1, r1, THREAD_SIZE;
+ 	tophys(r1,r1);
+ 
+-	addik	r1, r1, -PT_SIZE; /* Make room on the stack.  */
++	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+ 	SAVE_REGS
+-	swi	r0, r1, PT_R3
+-	swi	r0, r1, PT_R4
++	swi	r0, r1, PTO+PT_R3
++	swi	r0, r1, PTO+PT_R4
+ 
+-	swi	r0, r1, PT_MODE;			/* Was in user-mode. */
++	swi	r0, r1, PTO+PT_MODE;			/* Was in user-mode. */
+ 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+-	swi	r11, r1, PT_R1;		/* Store user SP.  */
++	swi	r11, r1, PTO+PT_R1;		/* Store user SP.  */
+ 	clear_ums;
+ 2:	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+ 	/* Save away the syscall number.  */
+-	swi	r12, r1, PT_R0;
++	swi	r12, r1, PTO+PT_R0;
+ 	tovirt(r1,r1)
+ 
+ /* where the trap should return need -8 to adjust for rtsd r15, 8*/
+@@ -380,18 +381,18 @@ C_ENTRY(_user_exception):
+ 	beqi	r11, 4f
+ 
+ 	addik	r3, r0, -ENOSYS
+-	swi	r3, r1, PT_R3
++	swi	r3, r1, PTO+PT_R3
+ 	brlid	r15, do_syscall_trace_enter
+-	addik	r5, r1, PT_R0
++	addik	r5, r1, PTO+PT_R0
+ 
+ 	# do_syscall_trace_enter returns the new syscall nr.
+ 	addk	r12, r0, r3
+-	lwi	r5, r1, PT_R5;
+-	lwi	r6, r1, PT_R6;
+-	lwi	r7, r1, PT_R7;
+-	lwi	r8, r1, PT_R8;
+-	lwi	r9, r1, PT_R9;
+-	lwi	r10, r1, PT_R10;
++	lwi	r5, r1, PTO+PT_R5;
++	lwi	r6, r1, PTO+PT_R6;
++	lwi	r7, r1, PTO+PT_R7;
++	lwi	r8, r1, PTO+PT_R8;
++	lwi	r9, r1, PTO+PT_R9;
++	lwi	r10, r1, PTO+PT_R10;
+ 4:
+ /* Jump to the appropriate function for the system call number in r12
+  * (r12 is not preserved), or return an error if r12 is not valid.
+@@ -432,8 +433,8 @@ C_ENTRY(_user_exception):
+ /* Entry point used to return from a syscall/trap */
+ /* We re-enable BIP bit before state restore */
+ C_ENTRY(ret_from_trap):
+-	swi	r3, r1, PT_R3
+-	swi	r4, r1, PT_R4
++	swi	r3, r1, PTO+PT_R3
++	swi	r4, r1, PTO+PT_R4
+ /*
+  * Entry point for returns that must not store r3/r4 back into pt_regs,
+  * i.e. rt_sigreturn, which has already restored them from the signal
+@@ -441,7 +442,7 @@ C_ENTRY(ret_from_trap):
+  * so it stays correct if the number of stores above ever changes.
+  */
+ ret_from_trap_no_rval:
+-	lwi	r11, r1, PT_MODE;
++	lwi	r11, r1, PTO+PT_MODE;
+ /* See if returning to kernel mode, if so, skip resched &c.  */
+ 	bnei	r11, 2f;
+ 	/* We're returning to user mode, so check for various conditions that
+@@ -453,7 +454,7 @@ ret_from_trap_no_rval:
+ 	beqi	r11, 1f
+ 
+ 	brlid	r15, do_syscall_trace_leave
+-	addik	r5, r1, PT_R0
++	addik	r5, r1, PTO+PT_R0
+ 1:
+ 	/* We're returning to user mode, so check for various conditions that
+ 	 * trigger rescheduling. */
+@@ -472,7 +473,7 @@ ret_from_trap_no_rval:
+ 	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+ 	beqi	r11, 4f;		/* Signals to handle, handle them */
+ 
+-	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
++	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
+ 	bralid	r15, do_notify_resume;	/* Handle any signals */
+ 	add	r6, r30, r0;		/* Arg 2: int in_syscall */
+ 	add	r30, r0, r0		/* no more restarts */
+@@ -484,7 +485,11 @@ ret_from_trap_no_rval:
+ 	VM_OFF;
+ 	tophys(r1,r1);
+ 	RESTORE_REGS_RTBD;
+-	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
++	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
++	/*
++	 * Deliberately PT_SIZE, not STATE_SAVE_SIZE: r1 is back at the stack
++	 * top, so PTO cancels and the saved SP sits at PT_R1 - PT_SIZE.
++	 */
+ 	lwi	r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */
+ 	bri	6f;
+ 
+@@ -493,7 +498,7 @@ ret_from_trap_no_rval:
+ 	VM_OFF;
+ 	tophys(r1,r1);
+ 	RESTORE_REGS_RTBD;
+-	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
++	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+ 	tovirt(r1,r1);
+ 6:
+ TRAP_return:		/* Make global symbol for debugging */
+@@ -534,7 +539,7 @@ C_ENTRY(sys_rt_sigreturn_wrapper):
+ 	 */
+ 	addik	r15, r0, ret_from_trap_no_rval - 8
+ 	brid	sys_rt_sigreturn	/* Do real work */
+-	addik	r5, r1, 0;		/* add user context as 1st arg */
++	addik	r5, r1, PTO;		/* add user context as 1st arg */
+ 
+ /*
+  * HW EXCEPTION rutine start
+@@ -545,7 +550,7 @@ C_ENTRY(full_exception_trap):
+ 	addik	r17, r17, -4
+ 	SAVE_STATE /* Save registers */
+ 	/* PC, before IRQ/trap - this is one instruction above */
+-	swi	r17, r1, PT_PC;
++	swi	r17, r1, PTO+PT_PC;
+ 	tovirt(r1,r1)
+ 	/* FIXME this can be store directly in PT_ESR reg.
+ 	 * I tested it but there is a fault */
+@@ -555,7 +560,7 @@ C_ENTRY(full_exception_trap):
+ 	mfs	r7, rfsr;		/* save FSR */
+ 	mts	rfsr, r0;	/* Clear sticky fsr */
+ 	rted	r0, full_exception
+-	addik	r5, r1, 0		 /* parameter struct pt_regs * regs */
++	addik	r5, r1, PTO		 /* parameter struct pt_regs * regs */
+ 
+ /*
+  * Unaligned data trap.
+@@ -581,14 +586,14 @@ C_ENTRY(unaligned_data_trap):
+ 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+ 	SAVE_STATE		/* Save registers.*/
+ 	/* PC, before IRQ/trap - this is one instruction above */
+-	swi	r17, r1, PT_PC;
++	swi	r17, r1, PTO+PT_PC;
+ 	tovirt(r1,r1)
+ 	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+ 	addik	r15, r0, ret_from_exc-8
+ 	mfs	r3, resr		/* ESR */
+ 	mfs	r4, rear		/* EAR */
+ 	rtbd	r0, _unaligned_data_exception
+-	addik	r7, r1, 0		/* parameter struct pt_regs * regs */
++	addik	r7, r1, PTO		/* parameter struct pt_regs * regs */
+ 
+ /*
+  * Page fault traps.
+@@ -611,30 +616,30 @@ C_ENTRY(unaligned_data_trap):
+ C_ENTRY(page_fault_data_trap):
+ 	SAVE_STATE		/* Save registers.*/
+ 	/* PC, before IRQ/trap - this is one instruction above */
+-	swi	r17, r1, PT_PC;
++	swi	r17, r1, PTO+PT_PC;
+ 	tovirt(r1,r1)
+ 	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+ 	addik	r15, r0, ret_from_exc-8
+ 	mfs	r6, rear		/* parameter unsigned long address */
+ 	mfs	r7, resr		/* parameter unsigned long error_code */
+ 	rted	r0, do_page_fault
+-	addik	r5, r1, 0		/* parameter struct pt_regs * regs */
++	addik	r5, r1, PTO		/* parameter struct pt_regs * regs */
+ 
+ C_ENTRY(page_fault_instr_trap):
+ 	SAVE_STATE		/* Save registers.*/
+ 	/* PC, before IRQ/trap - this is one instruction above */
+-	swi	r17, r1, PT_PC;
++	swi	r17, r1, PTO+PT_PC;
+ 	tovirt(r1,r1)
+ 	/* where the trap should return need -8 to adjust for rtsd r15, 8 */
+ 	addik	r15, r0, ret_from_exc-8
+ 	mfs	r6, rear		/* parameter unsigned long address */
+ 	ori	r7, r0, 0		/* parameter unsigned long error_code */
+ 	rted	r0, do_page_fault
+-	addik	r5, r1, 0		/* parameter struct pt_regs * regs */
++	addik	r5, r1, PTO		/* parameter struct pt_regs * regs */
+ 
+ /* Entry point used to return from an exception.  */
+ C_ENTRY(ret_from_exc):
+-	lwi	r11, r1, PT_MODE;
++	lwi	r11, r1, PTO+PT_MODE;
+ 	bnei	r11, 2f;		/* See if returning to kernel mode, */
+ 					/* ... if so, skip resched &c.  */
+ 
+@@ -666,7 +671,7 @@ C_ENTRY(ret_from_exc):
+ 	 * complete register state.  Here we save anything not saved by
+ 	 * the normal entry sequence, so that it may be safely restored
+ 	 * (in a possibly modified form) after do_notify_resume returns. */
+-	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
++	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
+ 	bralid	r15, do_notify_resume;	/* Handle any signals */
+ 	addi	r6, r0, 0;		/* Arg 2: int in_syscall */
+ 	bri	1b
+@@ -678,7 +683,7 @@ C_ENTRY(ret_from_exc):
+ 	tophys(r1,r1);
+ 
+ 	RESTORE_REGS_RTBD;
+-	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
++	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+ 
+ 	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */
+ 	bri	6f;
+@@ -687,7 +692,7 @@ C_ENTRY(ret_from_exc):
+ 	VM_OFF;
+ 	tophys(r1,r1);
+ 	RESTORE_REGS_RTBD;
+-	addik	r1, r1, PT_SIZE		/* Clean up stack space.  */
++	addik	r1, r1, STATE_SAVE_SIZE		/* Clean up stack space.  */
+ 
+ 	tovirt(r1,r1);
+ 6:
+@@ -720,10 +725,10 @@ C_ENTRY(_interrupt):
+ 	tophys(r1,r1); /* MS: I have in r1 physical address where stack is */
+ 	/* save registers */
+ /* MS: Make room on the stack -> activation record */
+-	addik	r1, r1, -PT_SIZE;
++	addik	r1, r1, -STATE_SAVE_SIZE;
+ 	SAVE_REGS
+ 	brid	2f;
+-	swi	r1, r1, PT_MODE; /* 0 - user mode, 1 - kernel mode */
++	swi	r1, r1, PTO+PT_MODE; /* 0 - user mode, 1 - kernel mode */
+ 1:
+ /* User-mode state save. */
+  /* MS: get the saved current */
+@@ -733,23 +738,23 @@ C_ENTRY(_interrupt):
+ 	addik	r1, r1, THREAD_SIZE;
+ 	tophys(r1,r1);
+ 	/* save registers */
+-	addik	r1, r1, -PT_SIZE;
++	addik	r1, r1, -STATE_SAVE_SIZE;
+ 	SAVE_REGS
+ 	/* calculate mode */
+-	swi	r0, r1, PT_MODE;
++	swi	r0, r1, PTO+PT_MODE;
+ 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+-	swi	r11, r1, PT_R1;
++	swi	r11, r1, PTO+PT_R1;
+ 	clear_ums;
+ 2:
+ 	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+ 	tovirt(r1,r1)
+ 	addik	r15, r0, irq_call;
+ irq_call:rtbd	r0, do_IRQ;
+-	addik	r5, r1, 0;
++	addik	r5, r1, PTO;
+ 
+ /* MS: we are in virtual mode */
+ ret_from_irq:
+-	lwi	r11, r1, PT_MODE;
++	lwi	r11, r1, PTO+PT_MODE;
+ 	bnei	r11, 2f;
+ 
+ 1:
+@@ -765,7 +770,7 @@ ret_from_irq:
+ 5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+ 	beqid	r11, no_intr_resched
+ /* Handle a signal return; Pending signals should be in r18. */
+-	addik	r5, r1, 0; /* Arg 1: struct pt_regs *regs */
++	addik	r5, r1, PTO; /* Arg 1: struct pt_regs *regs */
+ 	bralid	r15, do_notify_resume;	/* Handle any signals */
+ 	addi	r6, r0, 0; /* Arg 2: int in_syscall */
+ 	bri	1b
+@@ -778,7 +783,7 @@ no_intr_resched:
+ 	VM_OFF;
+ 	tophys(r1,r1);
+ 	RESTORE_REGS
+-	addik	r1, r1, PT_SIZE /* MS: Clean up stack space. */
++	addik	r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */
+ 	lwi	r1, r1, PT_R1 - PT_SIZE;
+ 	bri	6f;
+ /* MS: Return to kernel state. */
+@@ -801,7 +806,7 @@ restore:
+ 	VM_OFF /* MS: turn off MMU */
+ 	tophys(r1,r1)
+ 	RESTORE_REGS
+-	addik	r1, r1, PT_SIZE	/* MS: Clean up stack space. */
++	addik	r1, r1, STATE_SAVE_SIZE	/* MS: Clean up stack space. */
+ 	tovirt(r1,r1);
+ 6:
+ IRQ_return: /* MS: Make global symbol for debugging */
+@@ -820,29 +825,29 @@ C_ENTRY(_xtmr_manager_reset):
+ 	lwi	r1, r0, xmb_manager_stackpointer
+ 
+ 	/* Restore MSR */
+-	lwi	r2, r1, PT_MSR
++	lwi	r2, r1, PTO+PT_MSR
+ 	mts	rmsr, r2
+ 	bri	4
+ 
+ 	/* restore Special purpose registers */
+-	lwi	r2, r1, PT_PID
++	lwi	r2, r1, PTO+PT_PID
+ 	mts	rpid, r2
+ 
+-	lwi	r2, r1, PT_TLBI
++	lwi	r2, r1, PTO+PT_TLBI
+ 	mts	rtlbx, r2
+ 
+-	lwi	r2, r1, PT_ZPR
++	lwi	r2, r1, PTO+PT_ZPR
+ 	mts	rzpr, r2
+ 
+ #if CONFIG_XILINX_MICROBLAZE0_USE_FPU
+-	lwi	r2, r1, PT_FSR
++	lwi	r2, r1, PTO+PT_FSR
+ 	mts	rfsr, r2
+ #endif
+ 
+ 	/* restore all the tlb's */
+ 	addik	r3, r0, TOPHYS(tlb_skip)
+-	addik	r6, r0, PT_TLBL0
+-	addik	r7, r0, PT_TLBH0
++	addik	r6, r0, PTO+PT_TLBL0
++	addik	r7, r0, PTO+PT_TLBH0
+ restore_tlb:
+ 	add	r6, r6, r1
+ 	add	r7, r7, r1
+@@ -868,9 +873,9 @@ ret_from_reset:
+ 	VM_OFF
+ 	/* MS: Restore all regs */
+ 	RESTORE_REGS
+-	lwi	r14, r1, PT_R14
+-	lwi	r16, r1, PT_PC
+-	addik	r1, r1, PT_SIZE + 36
++	lwi	r14, r1, PTO+PT_R14
++	lwi	r16, r1, PTO+PT_PC
++	addik	r1, r1, STATE_SAVE_SIZE + 36
+ 	rtbd	r16, 0
+ 	nop
+ 
+@@ -885,11 +890,11 @@ C_ENTRY(_xmb_manager_break):
+ 	 * Reserve memory in the stack for context store/restore
+ 	 * (which includes memory for storing tlbs (max two tlbs))
+ 	 */
+-	addik	r1, r1, -PT_SIZE - 36
++	addik	r1, r1, -STATE_SAVE_SIZE - 36
+ 	swi	r1, r0, xmb_manager_stackpointer
+ 	SAVE_REGS
+-	swi	r14, r1, PT_R14	/* rewrite saved R14 value */
+-	swi	r16, r1, PT_PC; /* PC and r16 are the same */
++	swi	r14, r1, PTO+PT_R14	/* rewrite saved R14 value */
++	swi	r16, r1, PTO+PT_PC; /* PC and r16 are the same */
+ 
+ 	lwi	r6, r0, TOPHYS(xmb_manager_baseaddr)
+ 	lwi	r7, r0, TOPHYS(xmb_manager_crval)
+@@ -903,25 +908,25 @@ C_ENTRY(_xmb_manager_break):
+ 
+ 	/* Save the special purpose registers  */
+ 	mfs	r2, rpid
+-	swi	r2, r1, PT_PID
++	swi	r2, r1, PTO+PT_PID
+ 
+ 	mfs	r2, rtlbx
+-	swi	r2, r1, PT_TLBI
++	swi	r2, r1, PTO+PT_TLBI
+ 
+ 	mfs	r2, rzpr
+-	swi	r2, r1, PT_ZPR
++	swi	r2, r1, PTO+PT_ZPR
+ 
+ #if CONFIG_XILINX_MICROBLAZE0_USE_FPU
+ 	mfs	r2, rfsr
+-	swi	r2, r1, PT_FSR
++	swi	r2, r1, PTO+PT_FSR
+ #endif
+ 	mfs	r2, rmsr
+-	swi	r2, r1, PT_MSR
++	swi	r2, r1, PTO+PT_MSR
+ 
+ 	/* Save all the tlb's */
+ 	addik	r3, r0, TOPHYS(tlb_skip)
+-	addik	r6, r0, PT_TLBL0
+-	addik	r7, r0, PT_TLBH0
++	addik	r6, r0, PTO+PT_TLBL0
++	addik	r7, r0, PTO+PT_TLBH0
+ save_tlb:
+ 	add	r6, r6, r1
+ 	add	r7, r7, r1
+@@ -978,28 +983,28 @@ C_ENTRY(_debug_exception):
+ 	lwi	r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
+ 
+ 	/* BIP bit is set on entry, no interrupts can occur */
+-	addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - PT_SIZE;
++	addik   r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
+ 	SAVE_REGS;
+ 	/* save all regs to pt_reg structure */
+-	swi	r0, r1, PT_R0;	/* R0 must be saved too */
+-	swi	r14, r1, PT_R14	/* rewrite saved R14 value */
+-	swi	r16, r1, PT_PC; /* PC and r16 are the same */
++	swi	r0, r1, PTO+PT_R0;	/* R0 must be saved too */
++	swi	r14, r1, PTO+PT_R14	/* rewrite saved R14 value */
++	swi	r16, r1, PTO+PT_PC; /* PC and r16 are the same */
+ 	/* save special purpose registers to pt_regs */
+ 	mfs	r11, rear;
+-	swi	r11, r1, PT_EAR;
++	swi	r11, r1, PTO+PT_EAR;
+ 	mfs	r11, resr;
+-	swi	r11, r1, PT_ESR;
++	swi	r11, r1, PTO+PT_ESR;
+ 	mfs	r11, rfsr;
+-	swi	r11, r1, PT_FSR;
++	swi	r11, r1, PTO+PT_FSR;
+ 
+ 	/* stack pointer is in physical address at it is decrease
+-	 * by PT_SIZE but we need to get correct R1 value */
+-	addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + PT_SIZE;
+-	swi	r11, r1, PT_R1
++	 * by STATE_SAVE_SIZE but we need to get correct R1 value */
++	addik   r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE;
++	swi	r11, r1, PTO+PT_R1
+ 	/* MS: r31 - current pointer isn't changed */
+ 	tovirt(r1,r1)
+ #ifdef CONFIG_KGDB
+-	addi	r5, r1, 0 /* pass pt_reg address as the first arg */
++	addi	r5, r1, PTO /* pass pt_reg address as the first arg */
+ 	addik	r15, r0, dbtrap_call; /* return address */
+ 	rtbd	r0, microblaze_kgdb_break
+ 	nop;
+@@ -1015,16 +1020,16 @@ C_ENTRY(_debug_exception):
+ 	addik	r1, r1, THREAD_SIZE;	/* calculate kernel stack pointer */
+ 	tophys(r1,r1);
+ 
+-	addik	r1, r1, -PT_SIZE; /* Make room on the stack.  */
++	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
+ 	SAVE_REGS;
+-	swi	r16, r1, PT_PC;	/* Save LP */
+-	swi	r0, r1, PT_MODE; /* Was in user-mode.  */
++	swi	r16, r1, PTO+PT_PC;	/* Save LP */
++	swi	r0, r1, PTO+PT_MODE; /* Was in user-mode.  */
+ 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
+-	swi	r11, r1, PT_R1; /* Store user SP.  */
++	swi	r11, r1, PTO+PT_R1; /* Store user SP.  */
+ 	lwi	CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE));
+ 	tovirt(r1,r1)
+ 	set_vms;
+-	addik	r5, r1, 0;
++	addik	r5, r1, PTO;
+ 	addik	r15, r0, dbtrap_call;
+ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
+ 	rtbd	r0, sw_exception
+@@ -1032,7 +1037,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
+ 
+ 	/* MS: The first instruction for the second part of the gdb/kgdb */
+ 	set_bip; /* Ints masked for state restore */
+-	lwi	r11, r1, PT_MODE;
++	lwi	r11, r1, PTO+PT_MODE;
+ 	bnei	r11, 2f;
+ /* MS: Return to user space - gdb */
+ 1:
+@@ -1051,7 +1056,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
+ 5:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
+ 	beqi	r11, 4f;		/* Signals to handle, handle them */
+ 
+-	addik	r5, r1, 0;		/* Arg 1: struct pt_regs *regs */
++	addik	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
+ 	bralid	r15, do_notify_resume;	/* Handle any signals */
+ 	addi  r6, r0, 0;	/* Arg 2: int in_syscall */
+ 	bri	1b
+@@ -1062,7 +1067,7 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
+ 	tophys(r1,r1);
+ 	/* MS: Restore all regs */
+ 	RESTORE_REGS_RTBD
+-	addik	r1, r1, PT_SIZE	 /* Clean up stack space */
++	addik	r1, r1, STATE_SAVE_SIZE	 /* Clean up stack space */
+ 	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
+ DBTRAP_return_user: /* MS: Make global symbol for debugging */
+ 	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */
+@@ -1073,9 +1078,9 @@ DBTRAP_return_user: /* MS: Make global symbol for debugging */
+ 	tophys(r1,r1);
+ 	/* MS: Restore all regs */
+ 	RESTORE_REGS_RTBD
+-	lwi	r14, r1, PT_R14;
+-	lwi	r16, r1, PT_PC;
+-	addik	r1, r1, PT_SIZE; /* MS: Clean up stack space */
++	lwi	r14, r1, PTO+PT_R14;
++	lwi	r16, r1, PTO+PT_PC;
++	addik	r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
+ 	tovirt(r1,r1);
+ DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
+ 	rtbd	r16, 0; /* MS: Instructions to return from a debug trap */
+@@ -1173,7 +1178,7 @@ ENTRY(_switch_to)
+ .ent xmb_inject_err
+ .type xmb_inject_err, @function
+ xmb_inject_err:
+-	addik	r1, r1, -PT_SIZE
++	addik	r1, r1, -STATE_SAVE_SIZE
+ 	SAVE_REGS
+ 
+ 	/* Switch to real mode */
+@@ -1197,7 +1202,7 @@ xmb_inject_err:
+ 	nop;
+ 1:
+ 	RESTORE_REGS
+-	addik	r1, r1, PT_SIZE
++	addik	r1, r1, STATE_SAVE_SIZE
+ 	rtsd	r15, 8;
+ 	nop;
+ .end xmb_inject_err
+diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
+index 07ea23965f81..4693916be526 100644
+--- a/arch/microblaze/kernel/hw_exception_handler.S
++++ b/arch/microblaze/kernel/hw_exception_handler.S
+@@ -313,6 +313,11 @@ _MB_HW_ExceptionVectorTable:
+ .align 4
+ .ent _hw_exception_handler
+ _hw_exception_handler:
++	/*
++	 * This handler saves into the static pt_pool_space buffer, not into a
++	 * stack frame, so the plain PT_* offsets are right here -- do not add
++	 * the PTO of entry.S's frames.
++	 */
+ 	swi	r1, r0, TOPHYS(pt_pool_space + PT_R1); /* GET_SP */
+ 	/* Save date to kernel memory. Here is the problem
+ 	 * when you came from user space */
+diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
+index 6cbf642d7b80..090e1697ea7a 100644
+--- a/arch/microblaze/kernel/process.c
++++ b/arch/microblaze/kernel/process.c
+@@ -19,6 +19,7 @@
+ #include <linux/bitops.h>
+ #include <linux/ptrace.h>
+ #include <asm/cacheflush.h>
++#include <asm/entry.h>
+ 
+ void show_regs(struct pt_regs *regs)
+ {
+@@ -65,7 +66,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
+ 		 * the registers. That's OK for a brand new thread.*/
+ 		memset(childregs, 0, sizeof(struct pt_regs));
+ 		memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
+-		ti->cpu_context.r1  = (unsigned long)childregs;
++		ti->cpu_context.r1  = (unsigned long)childregs - PTO;
+ 		ti->cpu_context.r20 = (unsigned long)args->fn;
+ 		ti->cpu_context.r19 = (unsigned long)args->fn_arg;
+ 		childregs->pt_mode = 1;
+@@ -79,7 +80,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
+ 		childregs->r1 = usp;
+ 
+ 	memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
+-	ti->cpu_context.r1 = (unsigned long)childregs;
++	ti->cpu_context.r1 = (unsigned long)childregs - PTO;
+ 	childregs->msr |= MSR_UMS;
+ 
+ 	/* we should consider the fact that childregs is a copy of the parent
+-- 
+2.47.3
+

+ 101 - 0
target/linux/patches/6.18.40/0006-microblaze-preserve-the-MSR-carry-flags-across-signa.patch

@@ -0,0 +1,101 @@
+From 871d1697a67642e2b2a3ffb577ef028bde83e483 Mon Sep 17 00:00:00 2001
+From: Sam Price <thesamprice@gmail.com>
+Date: Fri, 21 Aug 2026 17:18:09 +0200
+Subject: [PATCH 6/6] microblaze: preserve the MSR carry flags across signals
+
+setup_sigcontext() and restore_sigcontext() copy r0-r31, pc, ear, esr and
+fsr to and from the signal frame but never touch MSR.  The interrupted
+MSR is therefore dropped from the signal context entirely: the handler's
+ucontext does not expose it, a handler cannot adjust the resumed
+arithmetic flags through uc_mcontext.regs.msr, and -- because
+restore_sigcontext() leaves regs->msr as whatever the rt_sigreturn trap
+left in it -- the interrupted context resumes with the carry produced by
+the syscall entry path (_user_exception does "addi r14, r14, 4", which
+writes carry), not with its own.
+
+Other architectures round-trip the user-visible flags through the signal
+frame (arm's cpsr, csky's carry, x86's eflags), so a handler can both read
+and adjust the resumed flags; purely privileged status registers such as
+riscv's sstatus are left out.  MicroBlaze should do the same for the
+user-writable bits.
+
+Concretely, MSR[C] (carry) is lost across signal delivery.  Code that
+keeps a live carry across a point where a signal can be delivered -- for
+example an lwx/swx compare-and-swap retry loop, between the swx and the
+carry test -- resumes with the handler's carry and mis-evaluates the
+result; the same failure class as the rt_sigreturn r3/r4 clobber, reached
+through a different register.  Demonstrated under qemu-system-microblazeel
+(machine petalogix-s3adsp1800): a handler that sets MSR_C in
+uc_mcontext.regs.msr has no effect before this change (0 of 132 in-window
+signals propagated) and takes effect after (130 of 132).
+
+Save MSR in setup_sigcontext() so the handler's ucontext exposes it.  The
+signal frame is user-writable, so restore_sigcontext() must not restore it
+verbatim: MicroBlaze packs the user-writable carry (MSR_C, MSR_CC) and the
+privileged control bits (MSR_UM, MSR_VM, MSR_IE, MSR_EE, ...) into the one
+register, and a verbatim restore would let userspace alter privileged
+return state -- rtbd derives the resumed mode from MSR_UMS/MSR_VMS.
+Restore only MSR_C | MSR_CC from the frame and keep the rest from the
+current regs->msr.  This mirrors x86's
+restore_sigcontext(), which masks the restored EFLAGS to FIX_EFLAGS for
+the same reason; arches whose status register is purely privileged (e.g.
+riscv sstatus) simply do not restore it at all.
+
+Comment on the exposed MSR reworded: it is not read-only,
+restore_sigcontext() applies MSR_C|MSR_CC from the frame.  Author's
+Signed-off-by kept; he agreed to comment and changelog cleanups.
+
+Fixes: 2148daa9c45f ("microblaze_v8: Signal support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sam Price <thesamprice@gmail.com>
+Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
+---
+ arch/microblaze/kernel/signal.c | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
+index 4956014a9937..6bbc16f98d5e 100644
+--- a/arch/microblaze/kernel/signal.c
++++ b/arch/microblaze/kernel/signal.c
+@@ -33,6 +33,7 @@
+ #include <linux/linkage.h>
+ #include <linux/resume_user_mode.h>
+ #include <asm/entry.h>
++#include <asm/registers.h>
+ #include <asm/ucontext.h>
+ #include <linux/uaccess.h>
+ #include <linux/syscalls.h>
+@@ -81,6 +82,22 @@ static int restore_sigcontext(struct pt_regs *regs,
+ 	COPY(pc);	COPY(ear);	COPY(esr);	COPY(fsr);
+ #undef COPY
+ 
++	/*
++	 * The frame is user-writable, so restore only the user-writable
++	 * status flags (carry) and keep the kernel-controlled MSR bits
++	 * (UMS/VMS/IE/EE/...) from regs->msr: rtbd derives the resumed mode
++	 * from UMS/VMS, so a verbatim restore would hand userspace the
++	 * privileged return state.  Same idea as x86 masking the restored
++	 * EFLAGS to FIX_EFLAGS.
++	 */
++	{
++		unsigned long msr;
++
++		err |= __get_user(msr, &sc->regs.msr);
++		regs->msr = (regs->msr & ~(MSR_C | MSR_CC)) |
++			    (msr & (MSR_C | MSR_CC));
++	}
++
+ 	*rval_p = regs->r3;
+ 
+ 	return err;
+@@ -140,6 +157,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+ 	COPY(r26);	COPY(r27);	COPY(r28);	COPY(r29);
+ 	COPY(r30);	COPY(r31);
+ 	COPY(pc);	COPY(ear);	COPY(esr);	COPY(fsr);
++	COPY(msr);	/* restore_sigcontext() accepts only carry state */
+ #undef COPY
+ 
+ 	err |= __put_user(mask, &sc->oldmask);
+-- 
+2.47.3
+

+ 0 - 55
target/linux/patches/6.18.40/microblaze-rt-sigreturn-restore-r3-r4.patch

@@ -1,55 +0,0 @@
-From: Ramin Moussavi <ramin.moussavi@yacoub.de>
-Subject: [PATCH] microblaze: don't clobber r3/r4 restored by rt_sigreturn
-
-ret_from_trap stores the system call return values r3 and r4 back into
-the saved user pt_regs (swi r3, PT_R3 / swi r4, PT_R4) before restoring
-the register file and returning to userspace.  That is correct for an
-ordinary system call, where r3 (and r4 for a 64-bit result) holds the
-return value and the caller-clobbered registers need not be preserved.
-
-sys_rt_sigreturn() also returns to userspace through this path, but it
-has to be transparent: restore_sigcontext() has already populated the
-whole pt_regs from the saved signal context, and every register must be
-restored exactly so the interrupted code resumes unchanged.  The
-unconditional stores in ret_from_trap instead overwrite the
-just-restored r3/r4.  r3 survives by luck, because sys_rt_sigreturn()
-returns the restored r3 as its value, but r4 is left holding scratch
-from the C function, so the restored r4 is lost.
-
-A signal can interrupt any instruction, so a register that is live
-across the signal - e.g. r4 holding the address operand of an lwx/swx
-compare-and-swap loop - comes back corrupted, surfacing as seemingly
-random NULL dereferences or heap corruption in multithreaded programs
-under signal load.  Found with the uClibc-ng NPTL tst-eintr1 test, where
-__sync_val_compare_and_swap() keeps the counter address in r4 while
-SIGUSR1 storms the worker threads: rt_sigreturn returns r4 == 0 and the
-next lwx faults on address 0.
-
-The interrupt and exception return paths (ret_from_irq, ret_from_exc)
-already restore the full register set and do not perform these stores;
-only the trap/syscall path does.  Make the rt_sigreturn wrapper return
-to ret_from_trap + 8, past the two stores, so the registers restored
-from the signal context survive.  Ordinary system calls are unaffected.
-
-Tested on qemu-system-microblazeel (petalogix-s3adsp1800) with the
-uClibc-ng NPTL tst-eintr1 stress loop: the unpatched kernel faults at
-the compare-and-swap with a zeroed address operand within one iteration;
-with this change it runs 60+ iterations cleanly.
-
-Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
-
---- a/arch/microblaze/kernel/entry.S
-+++ b/arch/microblaze/kernel/entry.S
-@@ -518,6 +518,13 @@ C_ENTRY(ret_from_kernel_thread):
- 
- C_ENTRY(sys_rt_sigreturn_wrapper):
- 	addik	r30, r0, 0		/* no restarts */
-+	/*
-+	 * rt_sigreturn restores the full register set from the signal
-+	 * context, so it must skip the r3/r4 syscall-return stores at the
-+	 * head of ret_from_trap which would otherwise overwrite the
-+	 * just-restored r3/r4.  Return to ret_from_trap + 8 (past them).
-+	 */
-+	addik	r15, r0, ret_from_trap
- 	brid	sys_rt_sigreturn	/* Do real work */
- 	addik	r5, r1, 0;		/* add user context as 1st arg */

+ 0 - 56
toolchain/gcc/patches/15.3.0/gcc-config-microblaze-fix-ira-for-GCC15.patch

@@ -1,56 +0,0 @@
-From d2fdbd8c4abe67eea86877dfb3b3b9d8508c165f Mon Sep 17 00:00:00 2001
-From: Romain Naour <romain.naour@gmail.com>
-Date: Wed, 6 Aug 2025 22:32:30 +0200
-Subject: [PATCH] gcc/config/microblaze: fix ira for GCC15
-
-Add new hooks for callee-save on microblaze defined by [1] and
-return 1 to restore the old behavior prior to the commit [3].
-
-Tested with qemu_microblazeel_mmu_defconfig and used to generate
-Microblaze toolchains for the Bootlin toolchains 2025.08-1 [4][5].
-
-Upstream: suggested in the bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121432#c10
-
-[1] https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=b191e8bdecf881d11c1544c441e38f4c18392a15
-[2] https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/config/i386/i386.cc;h=3128973ba79cccfc6761f451dcb716b9558cc4da;hb=d3ff498c478acefce35de04402f99171b4f64a1a#l20606
-[3] https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=3b9b8d6cfdf59337f4b7ce10ce92a98044b2657b
-[4] https://lore.kernel.org/buildroot/87sehzndtp.fsf@dell.be.48ers.dk/T/#mce7decd0b3f6a41008d5de577538a8525c91b374
-[5] https://toolchains.bootlin.com/
-
-Signed-off-by: Romain Naour <romain.naour@gmail.com>
----
- gcc/config/microblaze/microblaze.cc | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/gcc/config/microblaze/microblaze.cc b/gcc/config/microblaze/microblaze.cc
-index 78b9428ef3b..84ea7e8d55a 100644
---- a/gcc/config/microblaze/microblaze.cc
-+++ b/gcc/config/microblaze/microblaze.cc
-@@ -3228,6 +3228,14 @@ microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
-   return NO_REGS;
- }
- 
-+/* Implement TARGET_CALLEE_SAVE_COST.  */
-+static int
-+microblaze_callee_save_cost (spill_cost_type, unsigned int hard_regno, machine_mode,
-+		       unsigned int, int mem_cost, const HARD_REG_SET &, bool)
-+{
-+  return 1;
-+}
-+
- static void
- microblaze_globalize_label (FILE * stream, const char *name)
- {
-@@ -4066,6 +4074,9 @@ microblaze_starting_frame_offset (void)
- #undef TARGET_SECONDARY_RELOAD
- #define TARGET_SECONDARY_RELOAD		microblaze_secondary_reload
- 
-+#undef TARGET_CALLEE_SAVE_COST
-+#define TARGET_CALLEE_SAVE_COST microblaze_callee_save_cost
-+
- #undef  TARGET_ASM_OUTPUT_MI_THUNK
- #define TARGET_ASM_OUTPUT_MI_THUNK      microblaze_asm_output_mi_thunk
- 
--- 
-2.50.1
-