Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions arch/arm/src/armv7-m/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,15 @@ config ARMV7M_SYSTICK_IRQ_THREAD_STACK_SIZE
default DEFAULT_TASK_STACKSIZE

endif # ARMV7M_SYSTICK_IRQ_WQUEUE

config ARMV7M_SP_CONTEXT_RESTORE
bool "Honor SP modifications in signal context"
default n
---help---
On ARMv7-M, the hardware exception return determines the
final SP from the physical location of the HW exception
frame, ignoring any software modification to REG_R13 in
the saved context. Enable this to relocate the HW frame
when the desired SP differs from the implied SP, allowing
signal handlers to modify SP (e.g., for managed runtime
stack unwinding).
73 changes: 73 additions & 0 deletions arch/arm/src/armv7-m/arm_exception.S
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,79 @@ exception_common:
addne r0, #(4*SW_FPU_REGS)
#endif

#ifdef CONFIG_ARMV7M_SP_CONTEXT_RESTORE
/* Check if the desired SP (r2) differs from the implied SP.
* The implied SP after exception return = r0 + hw_frame_size,
* where hw_frame_size depends on whether the frame includes FPU
* state (determined by EXC_RETURN bit 4 in r14).
* If they differ, we must relocate the HW frame so that the final
* SP after hardware pop equals the desired value (r2).
*/

#ifdef CONFIG_ARCH_FPU
/* Determine actual HW frame size from EXC_RETURN:
* bit 4 set (STD_CONTEXT): 8 words = 32 bytes (no FPU)
* bit 4 clear: 26 words = 104 bytes (with FPU)
*/

tst r14, #EXC_RETURN_STD_CONTEXT
ite ne
movne r1, #(4*HW_INT_REGS) /* Standard frame: 32 bytes */
moveq r1, #HW_XCPT_SIZE /* Extended frame: 104 bytes */
#else
mov r1, #HW_XCPT_SIZE /* Always 32 bytes without FPU */
#endif
/* r1 = actual HW frame size in bytes */

add r1, r0, r1 /* r1 = implied SP = r0 + frame_size */
cmp r2, r1 /* desired SP == implied SP? */
beq .Lno_sp_relocate /* Yes, skip relocation */

/* Relocate HW exception frame from r0 to (r2 - frame_size).
* frame_size = r1 - r0. We have r0 (source), r2 (desired SP).
* r4-r11 are already restored. Available scratch: r1, r2, r3.
* r3 holds basepri which we need to preserve — push to MSP.
*
* Copy direction matters for overlapping regions:
* dest < source: forward copy (low to high)
* dest > source: backward copy (high to low)
*/

push {r3} /* Save basepri on MSP */
sub r3, r1, r0 /* r3 = frame_size = implied_SP - src */
sub r2, r2, r3 /* r2 = dest = desired_SP - frame_size */
cmp r2, r0 /* dest vs source? */
bhs .Lsp_copy_backward /* dest >= source: copy backward */

/* Forward copy (dest < source) */

push {r2} /* Save dest start for later */
.Lsp_copy_fwd:
ldr r1, [r0], #4
str r1, [r2], #4
subs r3, r3, #4
bne .Lsp_copy_fwd
pop {r0} /* r0 = dest start = relocated frame */
pop {r3} /* Restore basepri */
b .Lno_sp_relocate

.Lsp_copy_backward:
/* Backward copy (dest >= source) */

push {r2} /* Save dest start for later */
add r0, r0, r3 /* r0 = source end (one past) */
add r2, r2, r3 /* r2 = dest end (one past) */
.Lsp_copy_bwd:
ldr r1, [r0, #-4]! /* Pre-decrement, load */
str r1, [r2, #-4]! /* Pre-decrement, store */
subs r3, r3, #4
bne .Lsp_copy_bwd
pop {r0} /* r0 = dest start = relocated frame */
pop {r3} /* Restore basepri */

.Lno_sp_relocate:
#endif /* CONFIG_ARMV7M_SP_CONTEXT_RESTORE */

/* The EXC_RETURN value tells us whether we are returning on the MSP or PSP
*/

Expand Down
12 changes: 12 additions & 0 deletions arch/arm/src/armv8-m/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,15 @@ config ARMV8M_CMSE
bool "ARMv8-M Security Extensions"
---help---
Enable ARMv8-M Security Extensions.

config ARMV8M_SP_CONTEXT_RESTORE
bool "Honor SP modifications in signal context"
default n
---help---
On ARMv8-M, the hardware exception return determines the
final SP from the physical location of the HW exception
frame, ignoring any software modification to REG_R13 in
the saved context. Enable this to relocate the HW frame
when the desired SP differs from the implied SP, allowing
signal handlers to modify SP (e.g., for managed runtime
stack unwinding).
72 changes: 72 additions & 0 deletions arch/arm/src/armv8-m/arm_exception.S
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,78 @@ exception_common:
ldmia r0!, {r1} /* Get psplim/msplim */
#endif

#ifdef CONFIG_ARMV8M_SP_CONTEXT_RESTORE
/* Check if the desired SP (r2) differs from the implied SP.
* The implied SP after exception return = r0 + hw_frame_size,
* where hw_frame_size depends on whether the frame includes FPU
* state (determined by EXC_RETURN bit 4 in r14).
* If they differ, we must relocate the HW frame so that the final
* SP after hardware pop equals the desired value (r2).
*/

push {r1, r3} /* Save psplim + basepri on MSP */

#ifdef CONFIG_ARCH_FPU
/* Determine actual HW frame size from EXC_RETURN:
* bit 4 set (STD_CONTEXT): 8 words = 32 bytes (no FPU)
* bit 4 clear: 26 words = 104 bytes (with FPU)
*/

tst r14, #EXC_RETURN_STD_CONTEXT
ite ne
movne r1, #(4*HW_INT_REGS) /* Standard frame: 32 bytes */
moveq r1, #HW_XCPT_SIZE /* Extended frame: 104 bytes */
#else
mov r1, #HW_XCPT_SIZE /* Always 32 bytes without FPU */
#endif
/* r1 = actual HW frame size in bytes */

add r1, r0, r1 /* r1 = implied SP = r0 + frame_size */
cmp r2, r1 /* desired SP == implied SP? */
beq .Lno_sp_relocate /* Yes, skip relocation */

/* Relocate HW exception frame from r0 to (r2 - frame_size).
* frame_size = r1 - r0. We have r0 (source), r2 (desired SP).
* r4-r11 are already restored. Available scratch: r1, r2, r3.
*
* Copy direction matters for overlapping regions:
* dest < source: forward copy (low to high)
* dest > source: backward copy (high to low)
*/

sub r3, r1, r0 /* r3 = frame_size = implied_SP - src */
sub r2, r2, r3 /* r2 = dest = desired_SP - frame_size */
cmp r2, r0 /* dest vs source? */
bhs .Lsp_copy_backward /* dest >= source: copy backward */

/* Forward copy (dest < source) */

push {r2} /* Save dest start for later */
.Lsp_copy_fwd:
ldr r1, [r0], #4
str r1, [r2], #4
subs r3, r3, #4
bne .Lsp_copy_fwd
pop {r0} /* r0 = dest start = relocated frame */
b .Lno_sp_relocate

.Lsp_copy_backward:
/* Backward copy (dest >= source) */

push {r2} /* Save dest start for later */
add r0, r0, r3 /* r0 = source end (one past) */
add r2, r2, r3 /* r2 = dest end (one past) */
.Lsp_copy_bwd:
ldr r1, [r0, #-4]! /* Pre-decrement, load */
str r1, [r2, #-4]! /* Pre-decrement, store */
subs r3, r3, #4
bne .Lsp_copy_bwd
pop {r0} /* r0 = dest start = relocated frame */

.Lno_sp_relocate:
pop {r1, r3} /* Restore psplim + basepri */
#endif /* CONFIG_ARMV8M_SP_CONTEXT_RESTORE */

/* The EXC_RETURN value tells us whether we are returning on the MSP or PSP
*/

Expand Down
Loading