* FAILED: patch "[PATCH] microblaze: restore the ABI argument home area below pt_regs (PTO)" failed to apply to 5.15-stable tree
@ 2026-11-07 10:57 Sasha Levin
2026-11-10 9:42 ` [PATCH 5.15.y] microblaze: restore the ABI argument home area below pt_regs (PTO) Ramin Moussavi
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-11-07 10:57 UTC (permalink / raw)
To: ramin.moussavi, wbx, michal.simek; +Cc: stable
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x c35d40a3efd2e575ef51a761e983f2bf7113be6c
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107055734-failed-5.15-c35d40a3efd2@kernel.org' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From c35d40a3efd2e575ef51a761e983f2bf7113be6c 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] 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>
Tested-by: Waldemar Brodkorb <wbx@openadk.org>
Link: https://patch.msgid.link/20260821151809.1233057-5-ramin.moussavi@yacoub.de
Signed-off-by: Michal Simek <michal.simek@amd.com>
---
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 9efadf12397ca..05acf4d7bc4b1 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 d59bdfffca7cc..595c24db27283 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 efa4ab056fb5f..ebc8bcb98c522 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 07ea23965f817..4693916be5267 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 6cbf642d7b801..090e1697ea7ae 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.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 5.15.y] microblaze: restore the ABI argument home area below pt_regs (PTO)
2026-11-07 10:57 FAILED: patch "[PATCH] microblaze: restore the ABI argument home area below pt_regs (PTO)" failed to apply to 5.15-stable tree Sasha Levin
@ 2026-11-10 9:42 ` Ramin Moussavi
2026-11-10 20:59 ` Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Ramin Moussavi @ 2026-11-10 9:42 UTC (permalink / raw)
To: stable
commit c35d40a3efd2e575ef51a761e983f2bf7113be6c upstream.
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>
Tested-by: Waldemar Brodkorb <wbx@openadk.org>
Link: https://patch.msgid.link/20260821151809.1233057-5-ramin.moussavi@yacoub.de
Signed-off-by: Michal Simek <michal.simek@amd.com>
---
Prerequisites on this branch. Two are needed for this patch to apply:
c5947d28c209 ("microblaze: reserve the ABI argument-home area in the
signal frame")
da6829138a39 ("microblaze: don't clobber r3/r4 restored by rt_sigreturn")
in that order. Both are queued for this branch but not in it yet. With them
applied entry.S needs no adjustment at all; without them the cherry-pick
conflicts there, which is what the failure report was about.
Two more are needed before the result can be tested:
95fee37be45f ("microblaze: Do loop unrolling for optimized memset
implementation")
8f0f265e6cf5 ("microblaze: Use simple memset implementation from
lib/string.c")
Without them this branch does not boot at all when built with gcc 10 or later,
so the result cannot be verified: the "while (n--)" loop left in
arch/microblaze/lib/memset.c is turned into a call to memset by
-ftree-loop-distribute-patterns, so memset calls itself and never returns --
no oops, no console output. Both are in v5.19-rc1 and cherry-pick cleanly.
Tested: built with gcc 16.2.0 and booted under qemu-system-microblaze 11.1.50
(-M petalogix-s3adsp1800,endianness=little); the kernel reaches userspace and
the test suite runs to completion.
Backport changes: the asm/entry.h guard is still __ASSEMBLY__ here; three
entry.S hunks are dropped because the code does not exist on this branch yet
(mb_flush_dcache/mb_invalidate_icache, the CONFIG_MB_MANAGER block and
xmb_inject_err); in process.c only the "- PTO" is taken, since copy_thread
still has usp/arg instead of args->fn/args->fn_arg.
arch/microblaze/include/asm/entry.h | 13 +
arch/microblaze/include/asm/processor.h | 2 +-
arch/microblaze/kernel/entry.S | 277 +++++++++---------
arch/microblaze/kernel/hw_exception_handler.S | 5 +
arch/microblaze/kernel/process.c | 5 +-
5 files changed, 163 insertions(+), 139 deletions(-)
diff --git a/arch/microblaze/include/asm/entry.h b/arch/microblaze/include/asm/entry.h
index 6c42bed41166..74c5a99a37f8 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 __ASSEMBLY__
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 7e9e92670df3..03a2ae782827 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -78,7 +78,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 18028809250f..7a86ec90295c 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -175,78 +175,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; \
@@ -263,11 +263,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); \
@@ -275,12 +275,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));
@@ -310,18 +311,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*/
@@ -340,18 +341,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.
@@ -392,8 +393,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
@@ -401,7 +402,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
@@ -413,7 +414,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. */
@@ -432,7 +433,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 */
@@ -444,7 +445,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;
@@ -453,7 +458,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 */
@@ -494,7 +499,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
@@ -505,7 +510,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 */
@@ -515,7 +520,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.
@@ -541,14 +546,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.
@@ -571,30 +576,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. */
@@ -626,7 +631,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
@@ -638,7 +643,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;
@@ -647,7 +652,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:
@@ -680,10 +685,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 */
@@ -693,23 +698,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:
@@ -725,7 +730,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
@@ -738,7 +743,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. */
@@ -761,7 +766,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 */
@@ -784,28 +789,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;
@@ -821,16 +826,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
@@ -838,7 +843,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:
@@ -857,7 +862,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
@@ -868,7 +873,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 */
@@ -879,9 +884,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 */
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 5e2b91c1e8ce..578aa49a06e7 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -20,6 +20,7 @@
#include <linux/ptrace.h>
#include <linux/uaccess.h> /* for USER_DS macros */
#include <asm/cacheflush.h>
+#include <asm/entry.h>
void show_regs(struct pt_regs *regs)
{
@@ -64,7 +65,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
* 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)usp; /* fn */
ti->cpu_context.r19 = (unsigned long)arg;
childregs->pt_mode = 1;
@@ -78,7 +79,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
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.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-10 20:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07 10:57 FAILED: patch "[PATCH] microblaze: restore the ABI argument home area below pt_regs (PTO)" failed to apply to 5.15-stable tree Sasha Levin
2026-11-10 9:42 ` [PATCH 5.15.y] microblaze: restore the ABI argument home area below pt_regs (PTO) Ramin Moussavi
2026-11-10 20:59 ` Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox