diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2011-09-16 10:25:22 +0000 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2011-09-16 10:25:22 +0000 |
commit | 9f1412b9dc37a3919f21794f29b0199dc9ec4ea4 (patch) | |
tree | c5c576f66845f317f9835cb8a8d2391a449f2143 /cpukit/score/cpu/nios2 | |
parent | 2011-09-16 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff) | |
download | rtems-9f1412b9dc37a3919f21794f29b0199dc9ec4ea4.tar.bz2 |
2011-09-16 Sebastian Huber <sebastian.huber@embedded-brains.de>
* nios2-eic-il-low-level.S, nios2-eic-rsie-low-level.S: New files.
* Makefile.am: Reflect changes above.
* rtems/score/cpu.h, rtems/score/nios2-utility.h,
nios2-thread-dispatch-disabled.c, nios2-context-switch.S: Added
support for thread stack protection via the MPU.
Diffstat (limited to '')
-rw-r--r-- | cpukit/score/cpu/nios2/ChangeLog | 8 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/Makefile.am | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/nios2-context-switch.S | 4 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/nios2-eic-il-low-level.S | 212 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S | 169 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/nios2-thread-dispatch-disabled.c | 4 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/rtems/score/cpu.h | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/nios2/rtems/score/nios2-utility.h | 4 |
8 files changed, 401 insertions, 4 deletions
diff --git a/cpukit/score/cpu/nios2/ChangeLog b/cpukit/score/cpu/nios2/ChangeLog index bd9863680b..fa62d1e2c1 100644 --- a/cpukit/score/cpu/nios2/ChangeLog +++ b/cpukit/score/cpu/nios2/ChangeLog @@ -1,3 +1,11 @@ +2011-09-16 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * nios2-eic-il-low-level.S, nios2-eic-rsie-low-level.S: New files. + * Makefile.am: Reflect changes above. + * rtems/score/cpu.h, rtems/score/nios2-utility.h, + nios2-thread-dispatch-disabled.c, nios2-context-switch.S: Added + support for thread stack protection via the MPU. + 2011-09-14 Sebastian Huber <sebastian.huber@embedded-brains.de> * rtems/score/cpu.h: Request cache alignment and small data area in diff --git a/cpukit/score/cpu/nios2/Makefile.am b/cpukit/score/cpu/nios2/Makefile.am index f400204e78..125dd1fb99 100644 --- a/cpukit/score/cpu/nios2/Makefile.am +++ b/cpukit/score/cpu/nios2/Makefile.am @@ -26,6 +26,8 @@ libscorecpu_a_SOURCES = libscorecpu_a_SOURCES += irq.c libscorecpu_a_SOURCES += nios2-context-initialize.c libscorecpu_a_SOURCES += nios2-context-switch.S +libscorecpu_a_SOURCES += nios2-eic-il-low-level.S +libscorecpu_a_SOURCES += nios2-eic-rsie-low-level.S libscorecpu_a_SOURCES += nios2-fatal-halt.c libscorecpu_a_SOURCES += nios2-iic-low-level.S libscorecpu_a_SOURCES += nios2-initialize.c diff --git a/cpukit/score/cpu/nios2/nios2-context-switch.S b/cpukit/score/cpu/nios2/nios2-context-switch.S index bf6b836f6b..71704ae62c 100644 --- a/cpukit/score/cpu/nios2/nios2-context-switch.S +++ b/cpukit/score/cpu/nios2/nios2-context-switch.S @@ -43,11 +43,11 @@ _CPU_Context_switch: stw r8, NIOS2_CONTEXT_OFFSET_STATUS(r4) stw sp, NIOS2_CONTEXT_OFFSET_SP(r4) stw ra, NIOS2_CONTEXT_OFFSET_RA(r4) - stw r9, NIOS2_CONTEXT_OFFSET_TDD(r4) + stw r9, NIOS2_CONTEXT_OFFSET_THREAD_DISPATCH_DISABLED(r4) restore: - ldw r10, NIOS2_CONTEXT_OFFSET_TDD(r5) + ldw r10, NIOS2_CONTEXT_OFFSET_THREAD_DISPATCH_DISABLED(r5) ldw r16, NIOS2_CONTEXT_OFFSET_R16(r5) ldw r17, NIOS2_CONTEXT_OFFSET_R17(r5) ldw r18, NIOS2_CONTEXT_OFFSET_R18(r5) diff --git a/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S b/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S new file mode 100644 index 0000000000..8f8556f825 --- /dev/null +++ b/cpukit/score/cpu/nios2/nios2-eic-il-low-level.S @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <rtems/score/percpu.h> +#include <rtems/score/nios2-utility.h> + +#define FRAME_OFFSET_RA 0 +#define FRAME_OFFSET_AT 4 +#define FRAME_OFFSET_R2 8 +#define FRAME_OFFSET_R3 12 +#define FRAME_OFFSET_R4 16 +#define FRAME_OFFSET_R5 20 +#define FRAME_OFFSET_R6 24 +#define FRAME_OFFSET_R7 28 +#define FRAME_OFFSET_R8 32 +#define FRAME_OFFSET_R9 36 +#define FRAME_OFFSET_R10 40 +#define FRAME_OFFSET_R11 44 +#define FRAME_OFFSET_R12 48 +#define FRAME_OFFSET_R13 52 +#define FRAME_OFFSET_R14 56 +#define FRAME_OFFSET_R15 60 +#define FRAME_OFFSET_STATUS 64 +#define FRAME_OFFSET_EA 68 + +#define FRAME_SIZE (FRAME_OFFSET_EA + 4) + + .set noat + .section .text + + .extern _Per_CPU_Information + .extern _Thread_Dispatch_disable_level + .extern _Nios2_Thread_dispatch_disabled + .extern _Nios2_ISR_Status_interrupts_disabled + + .globl _Nios2_ISR_Dispatch_with_shadow_non_preemptive + +_Nios2_ISR_Dispatch_with_shadow_non_preemptive: + + /* Load thread dispatch disable level */ + ldw r16, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* Load high level handler address and argument */ + ldw r8, 4(et) + ldw r4, 8(et) + + /* Increment and store thread dispatch disable level */ + addi r9, r16, 1 + stw r9, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* Call high level handler with argument */ + callr r8 + + /* Load thread dispatch necessary */ + ldb r12, %gprel(_Per_CPU_Information + PER_CPU_DISPATCH_NEEDED)(gp) + + /* Load Nios II specific thread dispatch disabled */ + ldw r13, %gprel(_Nios2_Thread_dispatch_disabled)(gp) + + /* Fix return address */ + subi ea, ea, 4 + + /* + * Restore the thread dispatch disable level. We must do this before + * we return to the normal register set, because otherwise we have + * problems if someone deletes or restarts the interrupted thread while + * we are in the thread dispatch helper. + */ + stw r16, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* Is thread dispatch allowed? */ + bne r16, zero, no_thread_dispatch + + /* Is thread dispatch necessary? */ + beq r12, zero, no_thread_dispatch + + /* Is outermost interrupt? */ + andhi r14, sstatus, 0x3f + bne r14, zero, no_thread_dispatch + + /* Is Nios II specific thread dispatch allowed? */ + bne r13, zero, no_thread_dispatch + + /* Obtain stack frame in normal register set */ + rdprs r15, sp, -FRAME_SIZE + + /* Disable Nios II specific thread dispatch */ + stw r12, %gprel(_Nios2_Thread_dispatch_disabled)(gp) + + /* Save context */ + stw sstatus, FRAME_OFFSET_STATUS(r15) + stw ea, FRAME_OFFSET_EA(r15) + + /* Set thread dispatch helper address */ + movhi ea, %hiadj(thread_dispatch_helper) + addi ea, ea, %lo(thread_dispatch_helper) + + /* Update stack pointer in normal register set */ + wrprs sp, r15 + +no_thread_dispatch: + + /* + * Return to thread dispatch helper, interrupted thread or interrupted + * lower level interrupt service routine. + */ + eret + +thread_dispatch_helper: + + /* This code executes in the context of the interrupted thread */ + + /* Save volatile registers */ + stw ra, FRAME_OFFSET_RA(sp) + stw at, FRAME_OFFSET_AT(sp) + stw r2, FRAME_OFFSET_R2(sp) + stw r3, FRAME_OFFSET_R3(sp) + stw r4, FRAME_OFFSET_R4(sp) + stw r5, FRAME_OFFSET_R5(sp) + stw r6, FRAME_OFFSET_R6(sp) + stw r7, FRAME_OFFSET_R7(sp) + stw r8, FRAME_OFFSET_R8(sp) + stw r9, FRAME_OFFSET_R9(sp) + stw r10, FRAME_OFFSET_R10(sp) + stw r11, FRAME_OFFSET_R11(sp) + stw r12, FRAME_OFFSET_R12(sp) + stw r13, FRAME_OFFSET_R13(sp) + stw r14, FRAME_OFFSET_R14(sp) + stw r15, FRAME_OFFSET_R15(sp) + +do_thread_dispatch: + + call _Thread_Dispatch + + /* Restore some volatile registers */ + ldw ra, FRAME_OFFSET_RA(sp) + ldw at, FRAME_OFFSET_AT(sp) + ldw r2, FRAME_OFFSET_R2(sp) + ldw r3, FRAME_OFFSET_R3(sp) + ldw r4, FRAME_OFFSET_R4(sp) + ldw r5, FRAME_OFFSET_R5(sp) + ldw r6, FRAME_OFFSET_R6(sp) + ldw r7, FRAME_OFFSET_R7(sp) + ldw r8, FRAME_OFFSET_R8(sp) + ldw r9, FRAME_OFFSET_R9(sp) + ldw r10, FRAME_OFFSET_R10(sp) + ldw r11, FRAME_OFFSET_R11(sp) + ldw r12, FRAME_OFFSET_R12(sp) + ldw r13, FRAME_OFFSET_R13(sp) + + /* + * Disable interrupts. + * + * We have the following invariants: + * 1. status.RSIE == 0: thread context initialization + * 2. status.CRS == 0: thread context initialization + * 3. status.PRS: arbitrary + * 4. status.IL < interrupt disable IL: else we would not be here + * 5. status.IH == 0: thread context initialization + * 6. status.U == 0: thread context initialization + * 7. status.PIE == 1: thread context initialization + * Thus we can use a constant to disable interrupts. + */ + rdctl r14, status + movi r15, %lo(_Nios2_ISR_Status_interrupts_disabled) + wrctl status, r15 + + /* Load thread dispatch necessary */ + ldb r12, %gprel(_Per_CPU_Information + PER_CPU_DISPATCH_NEEDED)(gp) + + /* Is thread dispatch necessary? */ + bne r12, zero, enable_interrupts_before_thread_dispatch + + /* Enable Nios II specific thread dispatch */ + stw zero, %gprel(_Nios2_Thread_dispatch_disabled)(gp) + + /* Restore remaining volatile register */ + ldw r14, FRAME_OFFSET_R14(sp) + ldw r15, FRAME_OFFSET_R15(sp) + + /* Restore context */ + ldw et, FRAME_OFFSET_STATUS(sp) + ldw ea, FRAME_OFFSET_EA(sp) + + /* Release stack frame */ + addi sp, sp, FRAME_SIZE + + /* Restore context */ + wrctl estatus, et + + /* Return to interrupted thread */ + eret + +enable_interrupts_before_thread_dispatch: + + /* Restore status */ + wrctl status, r14 + + br do_thread_dispatch diff --git a/cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S b/cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S new file mode 100644 index 0000000000..efb71ebd0c --- /dev/null +++ b/cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <rtems/score/percpu.h> + +#define FRAME_OFFSET_AT 0 +#define FRAME_OFFSET_R2 4 +#define FRAME_OFFSET_R3 8 +#define FRAME_OFFSET_R4 12 +#define FRAME_OFFSET_R5 16 +#define FRAME_OFFSET_R6 20 +#define FRAME_OFFSET_R7 24 +#define FRAME_OFFSET_R8 28 +#define FRAME_OFFSET_R9 32 +#define FRAME_OFFSET_R10 36 +#define FRAME_OFFSET_R11 40 +#define FRAME_OFFSET_R12 44 +#define FRAME_OFFSET_R13 48 +#define FRAME_OFFSET_R14 52 +#define FRAME_OFFSET_R15 56 +#define FRAME_OFFSET_RA 60 +#define FRAME_OFFSET_EA 64 +#define FRAME_OFFSET_ESTATUS 68 +#define FRAME_OFFSET_R16 72 + +#define FRAME_SIZE (FRAME_OFFSET_R16 + 4) + + .set noat + .section .text + + .extern _Per_CPU_Information + .extern _Thread_Dispatch_disable_level + + .globl _Nios2_ISR_Dispatch_with_shadow_preemptive + +_Nios2_ISR_Dispatch_with_shadow_preemptive: + + /* Obtain stack frame */ + subi sp, sp, FRAME_SIZE + + /* Save volatile registers */ + stw at, FRAME_OFFSET_AT(sp) + stw r2, FRAME_OFFSET_R2(sp) + stw r3, FRAME_OFFSET_R3(sp) + stw r4, FRAME_OFFSET_R4(sp) + stw r5, FRAME_OFFSET_R5(sp) + stw r6, FRAME_OFFSET_R6(sp) + stw r7, FRAME_OFFSET_R7(sp) + stw r8, FRAME_OFFSET_R8(sp) + stw r9, FRAME_OFFSET_R9(sp) + stw r10, FRAME_OFFSET_R10(sp) + stw r11, FRAME_OFFSET_R11(sp) + stw r12, FRAME_OFFSET_R12(sp) + stw r13, FRAME_OFFSET_R13(sp) + stw r14, FRAME_OFFSET_R14(sp) + stw r15, FRAME_OFFSET_R15(sp) + + /* Save context */ + rdctl r2, estatus + subi ea, ea, 4 + stw ra, FRAME_OFFSET_RA(sp) + stw ea, FRAME_OFFSET_EA(sp) + stw r2, FRAME_OFFSET_ESTATUS(sp) + + /* Save one non-volatile register for further usage */ + stw r16, FRAME_OFFSET_R16(sp) + + /* Save stack pointer */ + mov r16, sp + + /* Increment ISR nest level and thread dispatch disable level */ + ldw r9, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + ldw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + addi r11, r9, 1 + addi r10, r10, 1 + stw r11, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + stw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* Switch to interrupt stack if necessary */ + bne r9, zero, switch_to_interrupt_stack_done + ldw sp, %gprel(_Per_CPU_Information + PER_CPU_INTERRUPT_STACK_HIGH)(gp) + +switch_to_interrupt_stack_done: + + /* Load high level handler address and argument */ + ldw r12, 4(et) + ldw r4, 8(et) + + /* Enable interrupts */ + rdctl r13, status + orhi r13, r13, 0x0080 + wrctl status, r13 + + /* Call high level handler with argument */ + callr r12 + + /* Disable interrupts */ + rdctl r12, status + movhi r13, 0xff80 + subi r13, r13, 1 + and r12, r12, r13 + wrctl status, r12 + + /* Decrement ISR nest level and thread dispatch disable level */ + ldw r9, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + ldw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + subi r9, r9, 1 + subi r10, r10, 1 + stw r9, %gprel(_Per_CPU_Information + PER_CPU_ISR_NEST_LEVEL)(gp) + stw r10, %gprel(_Thread_Dispatch_disable_level)(gp) + + /* + * Restore stack pointer. If the ISR nest level is greater than one, + * then this is a nop, else we switch back to the thread stack. + */ + mov sp, r16 + + /* Thread dispatch */ + bne r10, zero, thread_dispatch_done + call _Thread_Dispatch + +thread_dispatch_done: + + /* Restore volatile registers */ + ldw at, FRAME_OFFSET_AT(sp) + ldw r2, FRAME_OFFSET_R2(sp) + ldw r3, FRAME_OFFSET_R3(sp) + ldw r4, FRAME_OFFSET_R4(sp) + ldw r5, FRAME_OFFSET_R5(sp) + ldw r6, FRAME_OFFSET_R6(sp) + ldw r7, FRAME_OFFSET_R7(sp) + ldw r8, FRAME_OFFSET_R8(sp) + ldw r9, FRAME_OFFSET_R9(sp) + ldw r10, FRAME_OFFSET_R10(sp) + ldw r11, FRAME_OFFSET_R11(sp) + ldw r12, FRAME_OFFSET_R12(sp) + ldw r13, FRAME_OFFSET_R13(sp) + ldw r14, FRAME_OFFSET_R14(sp) + ldw r15, FRAME_OFFSET_R15(sp) + + /* Restore context */ + ldw ra, FRAME_OFFSET_RA(sp) + ldw ea, FRAME_OFFSET_EA(sp) + ldw et, FRAME_OFFSET_ESTATUS(sp) + + /* Restore the non-volatile register */ + ldw r16, FRAME_OFFSET_R16(sp) + + /* Release stack frame */ + addi sp, sp, FRAME_SIZE + + /* Restore context */ + wrctl estatus, et + + /* Return */ + eret diff --git a/cpukit/score/cpu/nios2/nios2-thread-dispatch-disabled.c b/cpukit/score/cpu/nios2/nios2-thread-dispatch-disabled.c index 976546c735..512b62d0a6 100644 --- a/cpukit/score/cpu/nios2/nios2-thread-dispatch-disabled.c +++ b/cpukit/score/cpu/nios2/nios2-thread-dispatch-disabled.c @@ -39,6 +39,8 @@ NIOS2_ASSERT_OFFSET(fp, FP); NIOS2_ASSERT_OFFSET(status, STATUS); NIOS2_ASSERT_OFFSET(sp, SP); NIOS2_ASSERT_OFFSET(ra, RA); -NIOS2_ASSERT_OFFSET(thread_dispatch_disabled, TDD); +NIOS2_ASSERT_OFFSET(thread_dispatch_disabled, THREAD_DISPATCH_DISABLED); +NIOS2_ASSERT_OFFSET(stack_mpubase, STACK_MPUBASE); +NIOS2_ASSERT_OFFSET(stack_mpuacc, STACK_MPUACC); uint32_t _Nios2_Thread_dispatch_disabled; diff --git a/cpukit/score/cpu/nios2/rtems/score/cpu.h b/cpukit/score/cpu/nios2/rtems/score/cpu.h index 956294d303..07f1f29179 100644 --- a/cpukit/score/cpu/nios2/rtems/score/cpu.h +++ b/cpukit/score/cpu/nios2/rtems/score/cpu.h @@ -134,6 +134,8 @@ typedef struct { uint32_t sp; uint32_t ra; uint32_t thread_dispatch_disabled; + uint32_t stack_mpubase; + uint32_t stack_mpuacc; } Context_Control; #define _CPU_Context_Get_SP( _context ) \ diff --git a/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h b/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h index 9a990290df..f417aec340 100644 --- a/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h +++ b/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h @@ -44,7 +44,9 @@ #define NIOS2_CONTEXT_OFFSET_STATUS 36 #define NIOS2_CONTEXT_OFFSET_SP 40 #define NIOS2_CONTEXT_OFFSET_RA 44 -#define NIOS2_CONTEXT_OFFSET_TDD 48 +#define NIOS2_CONTEXT_OFFSET_THREAD_DISPATCH_DISABLED 48 +#define NIOS2_CONTEXT_OFFSET_STACK_MPUBASE 52 +#define NIOS2_CONTEXT_OFFSET_STACK_MPUACC 56 #define NIOS2_ISR_STATUS_MASK_IIC 0xfffffffe #define NIOS2_ISR_STATUS_BITS_IIC 0x00000000 |