summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2011-09-16 10:25:22 +0000
committerSebastian Huber <sebastian.huber@embedded-brains.de>2011-09-16 10:25:22 +0000
commit9f1412b9dc37a3919f21794f29b0199dc9ec4ea4 (patch)
treec5c576f66845f317f9835cb8a8d2391a449f2143 /cpukit/score/cpu
parent2011-09-16 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff)
downloadrtems-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 'cpukit/score/cpu')
-rw-r--r--cpukit/score/cpu/nios2/ChangeLog8
-rw-r--r--cpukit/score/cpu/nios2/Makefile.am2
-rw-r--r--cpukit/score/cpu/nios2/nios2-context-switch.S4
-rw-r--r--cpukit/score/cpu/nios2/nios2-eic-il-low-level.S212
-rw-r--r--cpukit/score/cpu/nios2/nios2-eic-rsie-low-level.S169
-rw-r--r--cpukit/score/cpu/nios2/nios2-thread-dispatch-disabled.c4
-rw-r--r--cpukit/score/cpu/nios2/rtems/score/cpu.h2
-rw-r--r--cpukit/score/cpu/nios2/rtems/score/nios2-utility.h4
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