Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interrupt nesting is broken on ARMv7-R / LR_svc corrupted. #30517

Closed
remy-luisant opened this issue Dec 8, 2020 · 4 comments · Fixed by #31519
Closed

Interrupt nesting is broken on ARMv7-R / LR_svc corrupted. #30517

remy-luisant opened this issue Dec 8, 2020 · 4 comments · Fixed by #31519
Assignees
Labels
area: ARM ARM (32-bit) Architecture bug The issue is a bug, or the PR is fixing a bug priority: medium Medium impact/importance bug
Milestone

Comments

@remy-luisant
Copy link
Contributor

I have a custom board running a port to ARMv7-A with NEON. This shares much code with the ARMv7-R version and I believe this issue is relevant to your code as well. Please disregard this report should this not be the case.

zephyr/arch/arm/core/aarch32/isr_wrapper.S, edited for clarity, comments starting with // are mine:

        //Entry in MODE_IRQ

	sub lr, lr, #4
	srsdb #MODE_SYS!          //LR_irq saved to the process stack.
	cps #MODE_SYS             //System mode
	push {r0-r3, r12, lr}     //User registers saved to the process stack.

	cps #MODE_SVC             //SVC mode 

	/* Align stack at double-word boundary */
	and r3, sp, #4
	sub sp, sp, r3
	push {r2, r3}

	/* Increment interrupt nesting count */
	ldr r2, =_kernel
	ldr r0, [r2, #_kernel_offset_to_nested]
	add r0, r0, #1
	str r0, [r2, #_kernel_offset_to_nested]

	/* Get active IRQ number from the interrupt controller */
        // !!!! WRITING LR_svc HERE !!!!
	bl arm_gic_get_active  
	push {r0, r1}
	lsl r0, r0, #3	/* table is 8-byte wide */

	/*
	 * Enable interrupts to allow nesting.
        */
	cpsie i

        //Interrupt happens here, starting this code all over again and corrupting LR_svc.

At no point is LR_svc preserved. The fix is to simply store LR_svc before it gets clobbered at the first bl instruction and subsequently restore it before exiting the handler. I have chosen to do this onto the IRQ stack, which appeared to be otherwise unused, to preserve my work on getting OpenOCD to behave on the Cortex-A7 that I work with. It is likely that there is a much better solution as to where to put this register, but I currently lack the resources to investigate that and my fix worked well enough for my needs.

@remy-luisant remy-luisant added the bug The issue is a bug, or the PR is fixing a bug label Dec 8, 2020
@julien-massot
Copy link
Collaborator

Hi Remy, I'm indeed facing an issue with nested interrupt on Cortex-R,
but didn't figured out what is the reason.
Thanks for the report.

As a temporary workaround, I just disabled nested interrupt, as it's done in Cortex M.
iotbzh@a0e4c0a

@nashif nashif added priority: medium Medium impact/importance bug area: ARM ARM (32-bit) Architecture labels Dec 15, 2020
@ioannisg
Copy link
Member

@stephanosio any chance you could take a look?

@stephanosio
Copy link
Member

@ioannisg will do.

@stephanosio stephanosio self-assigned this Jan 22, 2021
@stephanosio
Copy link
Member

With the current implementation, if an ISR is interrupted while executing in a branch, the lr_svc register will indeed be corrupted and, the branch of the interrupted ISR will exit to the return address of the final branch of the interrupting ISR, which may or may not coincide with the return address of the branch of the interrupted ISR (which is why the interrupt nesting test seems to work fine in the QEMU).

I will create a PR to fix this in a few days.

@stephanosio stephanosio added this to the v2.5.0 milestone Jan 22, 2021
stephanosio added a commit to stephanosio/zephyr that referenced this issue Jan 22, 2021
In the current interrupt nesting implementation, if an ISR is
interrupted while executing inside a branch, the lr_svc register will
be corrupted, and the branch of the interrupted ISR will exit to the
return address of the final branch of the interrupting ISR, which may
or may not correspond to the intended return address.

This commit fixes the aforementioned bug by storing the lr_svc register
in the stack at the ISR entry, and restoring its value before exiting
the ISR.

For more details, refer to the issue zephyrproject-rtos#30517.

Signed-off-by: Stephanos Ioannidis <[email protected]>
nashif pushed a commit that referenced this issue Jan 26, 2021
In the current interrupt nesting implementation, if an ISR is
interrupted while executing inside a branch, the lr_svc register will
be corrupted, and the branch of the interrupted ISR will exit to the
return address of the final branch of the interrupting ISR, which may
or may not correspond to the intended return address.

This commit fixes the aforementioned bug by storing the lr_svc register
in the stack at the ISR entry, and restoring its value before exiting
the ISR.

For more details, refer to the issue #30517.

Signed-off-by: Stephanos Ioannidis <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: ARM ARM (32-bit) Architecture bug The issue is a bug, or the PR is fixing a bug priority: medium Medium impact/importance bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants