diff options
author | Philippe Rétornaz <philippe.retornaz@epfl.ch> | 2007-10-10 18:52:24 -0400 |
---|---|---|
committer | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-10-11 13:32:56 +0200 |
commit | a7e30b8d91d3291de4543d97849193ebc3ec4c1c (patch) | |
tree | ecf3548140022204214b20f6f69dfc67a6e026b9 /arch | |
parent | bb7aa6d47fcd4f9ab18b4ade2ba078f7719f74ca (diff) | |
download | linux-a7e30b8d91d3291de4543d97849193ebc3ec4c1c.tar.gz linux-a7e30b8d91d3291de4543d97849193ebc3ec4c1c.tar.bz2 linux-a7e30b8d91d3291de4543d97849193ebc3ec4c1c.zip |
[AVR32] Fix random segfault with preemption
As explained on:
http://www.avrfreaks.net/index.php?nameÿphpBB2&fileÿewtopic&tS307
If the current process is preempted before it can copy RAR_SUP and
RSR_SUP both register are lost and the process will segfault as soon
as it return from the syscall since the return adress will be
corrupted.
This patch disable IRQ as soon as we enter the syscall path and
reenable them when the copy is done.
In the interrupt handlers, check if we are interrupting the srrf
instruction, if so disable interrupts and return. The interrupt
handler will be re-called immediatly when the interrupts are
reenabled.
After some stressing workload:
- find / > /dev/null in loop
- top (in ssh)
- ping -f avr32
The segfaults are not seen anymore.
Signed-off-by: Philippe Rétornaz <philippe.retornaz@epfl.ch>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 26 |
1 files changed, 25 insertions, 1 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 42657f1703b2..ccadfd9b438d 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -159,11 +159,18 @@ handle_vmalloc_miss: .section .scall.text,"ax",@progbits system_call: +#ifdef CONFIG_PREEMPT + mask_interrupts +#endif pushm r12 /* r12_orig */ stmts --sp, r0-lr - zero_fp + mfsr r0, SYSREG_RAR_SUP mfsr r1, SYSREG_RSR_SUP +#ifdef CONFIG_PREEMPT + unmask_interrupts +#endif + zero_fp stm --sp, r0-r1 /* check for syscall tracing */ @@ -638,6 +645,13 @@ irq_level\level: stmts --sp,r0-lr mfsr r8, rar_int\level mfsr r9, rsr_int\level + +#ifdef CONFIG_PREEMPT + sub r11, pc, (. - system_call) + cp.w r11, r8 + breq 4f +#endif + pushm r8-r9 mov r11, sp @@ -668,6 +682,16 @@ irq_level\level: sub sp, -4 /* ignore r12_orig */ rete +#ifdef CONFIG_PREEMPT +4: mask_interrupts + mfsr r8, rsr_int\level + sbr r8, 16 + mtsr rsr_int\level, r8 + ldmts sp++, r0-lr + sub sp, -4 /* ignore r12_orig */ + rete +#endif + 2: get_thread_info r0 ld.w r1, r0[TI_flags] bld r1, TIF_CPU_GOING_TO_SLEEP |