summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/nios2
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2011-10-21 08:44:23 +0000
committerSebastian Huber <sebastian.huber@embedded-brains.de>2011-10-21 08:44:23 +0000
commitd4a95940391a1ee8c1e36a8b10b8800ee526c0e6 (patch)
treedc2dd05a6e7cc7b8d3bcbf53b10d3a4bfa425f7a /cpukit/score/cpu/nios2
parent2011-10-21 Ralf Corsépius <ralf.corsepius@rtems.org> (diff)
downloadrtems-d4a95940391a1ee8c1e36a8b10b8800ee526c0e6.tar.bz2
2011-10-21 Sebastian Huber <sebastian.huber@embedded-brains.de>
* nios2-mpu-configuration.c, nios2-mpu-descriptor.c, nios2-mpu-disable-protected.c, nios2-mpu-reset.c: New files. * Makefile.am: Reflect changes above. * rtems/score/nios2-utility.h, nios2-context-initialize.c: Added support for the memory protection unit (MPU).
Diffstat (limited to 'cpukit/score/cpu/nios2')
-rw-r--r--cpukit/score/cpu/nios2/ChangeLog8
-rw-r--r--cpukit/score/cpu/nios2/Makefile.am4
-rw-r--r--cpukit/score/cpu/nios2/nios2-context-initialize.c27
-rw-r--r--cpukit/score/cpu/nios2/nios2-mpu-configuration.c33
-rw-r--r--cpukit/score/cpu/nios2/nios2-mpu-descriptor.c121
-rw-r--r--cpukit/score/cpu/nios2/nios2-mpu-disable-protected.c34
-rw-r--r--cpukit/score/cpu/nios2/nios2-mpu-reset.c48
-rw-r--r--cpukit/score/cpu/nios2/rtems/score/nios2-utility.h136
8 files changed, 409 insertions, 2 deletions
diff --git a/cpukit/score/cpu/nios2/ChangeLog b/cpukit/score/cpu/nios2/ChangeLog
index c321c5ab2e..39c096c21e 100644
--- a/cpukit/score/cpu/nios2/ChangeLog
+++ b/cpukit/score/cpu/nios2/ChangeLog
@@ -1,3 +1,11 @@
+2011-10-21 Sebastian Huber <sebastian.huber@embedded-brains.de>
+
+ * nios2-mpu-configuration.c, nios2-mpu-descriptor.c,
+ nios2-mpu-disable-protected.c, nios2-mpu-reset.c: New files.
+ * Makefile.am: Reflect changes above.
+ * rtems/score/nios2-utility.h, nios2-context-initialize.c: Added
+ support for the memory protection unit (MPU).
+
2011-09-30 Sebastian Huber <sebastian.huber@embedded-brains.de>
* nios2-context-switch.S: Use small-data area access for
diff --git a/cpukit/score/cpu/nios2/Makefile.am b/cpukit/score/cpu/nios2/Makefile.am
index 125dd1fb99..11bf3bdcb0 100644
--- a/cpukit/score/cpu/nios2/Makefile.am
+++ b/cpukit/score/cpu/nios2/Makefile.am
@@ -37,6 +37,10 @@ libscorecpu_a_SOURCES += nios2-isr-install-raw-handler.c
libscorecpu_a_SOURCES += nios2-isr-install-vector.c
libscorecpu_a_SOURCES += nios2-isr-is-in-progress.c
libscorecpu_a_SOURCES += nios2-isr-set-level.c
+libscorecpu_a_SOURCES += nios2-mpu-configuration.c
+libscorecpu_a_SOURCES += nios2-mpu-descriptor.c
+libscorecpu_a_SOURCES += nios2-mpu-disable-protected.c
+libscorecpu_a_SOURCES += nios2-mpu-reset.c
libscorecpu_a_SOURCES += nios2-thread-dispatch-disabled.c
libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/cpukit/score/cpu/nios2/nios2-context-initialize.c b/cpukit/score/cpu/nios2/nios2-context-initialize.c
index 82e84ffb77..637d39d0cf 100644
--- a/cpukit/score/cpu/nios2/nios2-context-initialize.c
+++ b/cpukit/score/cpu/nios2/nios2-context-initialize.c
@@ -21,6 +21,7 @@
#include <rtems/score/cpu.h>
#include <rtems/score/nios2-utility.h>
+#include <rtems/score/interr.h>
void _CPU_Context_Initialize(
Context_Control *context,
@@ -31,6 +32,7 @@ void _CPU_Context_Initialize(
bool is_fp
)
{
+ const Nios2_MPU_Configuration *mpu_config = _Nios2_MPU_Get_configuration();
uint32_t stack = (uint32_t) stack_area_begin + stack_area_size - 4;
memset(context, 0, sizeof(*context));
@@ -39,4 +41,29 @@ void _CPU_Context_Initialize(
context->status = _Nios2_ISR_Set_level( new_level, NIOS2_STATUS_PIE );
context->sp = stack;
context->ra = (uint32_t) entry_point;
+
+ if ( mpu_config != NULL ) {
+ Nios2_MPU_Region_descriptor desc = {
+ .index = mpu_config->data_index_for_stack_protection,
+ /* FIXME: Brocken stack allocator */
+ .base = (void *) ((int) stack_area_begin & ~((1 << mpu_config->data_region_size_log2) - 1)),
+ .end = (char *) stack_area_begin + stack_area_size,
+ .perm = NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE,
+ .data = true,
+ .cacheable = mpu_config->enable_data_cache_for_stack,
+ .read = false,
+ .write = true
+ };
+ bool ok = _Nios2_MPU_Setup_region_registers(
+ mpu_config,
+ &desc,
+ &context->stack_mpubase,
+ &context->stack_mpuacc
+ );
+
+ if ( !ok ) {
+ /* The task stack allocator must ensure that the stack area is valid */
+ _Internal_error_Occurred( INTERNAL_ERROR_CORE, false, 0xdeadbeef );
+ }
+ }
}
diff --git a/cpukit/score/cpu/nios2/nios2-mpu-configuration.c b/cpukit/score/cpu/nios2/nios2-mpu-configuration.c
new file mode 100644
index 0000000000..abd7292734
--- /dev/null
+++ b/cpukit/score/cpu/nios2/nios2-mpu-configuration.c
@@ -0,0 +1,33 @@
+/*
+ * 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$
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <rtems/score/nios2-utility.h>
+
+static const Nios2_MPU_Configuration *_Nios2_MPU_Configuration;
+
+void _Nios2_MPU_Set_configuration( const Nios2_MPU_Configuration *config )
+{
+ _Nios2_MPU_Configuration = config;
+}
+
+const Nios2_MPU_Configuration *_Nios2_MPU_Get_configuration( void )
+{
+ return _Nios2_MPU_Configuration;
+}
diff --git a/cpukit/score/cpu/nios2/nios2-mpu-descriptor.c b/cpukit/score/cpu/nios2/nios2-mpu-descriptor.c
new file mode 100644
index 0000000000..2b3cc41564
--- /dev/null
+++ b/cpukit/score/cpu/nios2/nios2-mpu-descriptor.c
@@ -0,0 +1,121 @@
+/*
+ * 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$
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <rtems/score/nios2-utility.h>
+
+static bool _Nios2_Is_power_of_two( uint32_t size )
+{
+ bool ok = false;
+ int i = 0;
+
+ for ( i = 0; !ok && i < 32; ++i ) {
+ ok = size == (1U << i);
+ }
+
+ return ok;
+}
+
+static bool _Nios2_Is_valid_base_and_end(
+ const Nios2_MPU_Configuration *config,
+ bool data,
+ uint32_t base,
+ uint32_t end,
+ uint32_t *mask_or_limit
+)
+{
+ uint32_t size = end - base;
+ uint32_t end_limit = data ?
+ (1U << config->data_address_width)
+ : (1U << config->instruction_address_width);
+ uint32_t mask = data ?
+ ((1U << config->data_region_size_log2)) - 1
+ : ((1U << config->instruction_region_size_log2)) - 1;
+ bool ok = base < end && end <= end_limit
+ && (base & mask) == 0 && (end & mask) == 0;
+
+ if ( config->region_uses_limit ) {
+ *mask_or_limit = end;
+ } else {
+ ok = ok && _Nios2_Is_power_of_two( size );
+ *mask_or_limit = (~(size - 1)) & NIOS2_MPUACC_MASK_MASK;
+ }
+
+ return ok;
+}
+
+static bool _Nios2_Is_valid_index(
+ const Nios2_MPU_Configuration *config,
+ bool data,
+ int index
+)
+{
+ int count = data ?
+ config->data_region_count
+ : config->instruction_region_count;
+
+ return 0 <= index && index < count;
+}
+
+static bool _Nios2_Is_valid_permission(
+ bool data,
+ int perm
+)
+{
+ int max = data ? 6 : 2;
+
+ return 0 <= perm && perm <= max && (!data || (data && perm != 3));
+}
+
+bool _Nios2_MPU_Setup_region_registers(
+ const Nios2_MPU_Configuration *config,
+ const Nios2_MPU_Region_descriptor *desc,
+ uint32_t *mpubase,
+ uint32_t *mpuacc
+)
+{
+ uint32_t base = (uint32_t) desc->base;
+ uint32_t end = (uint32_t) desc->end;
+ uint32_t mask_or_limit = 0;
+ bool is_valid_base_and_end = _Nios2_Is_valid_base_and_end(
+ config,
+ desc->data,
+ base,
+ end,
+ &mask_or_limit
+ );
+ bool ok = is_valid_base_and_end
+ && _Nios2_Is_valid_index( config, desc->data, desc->index )
+ && _Nios2_Is_valid_permission( desc->data, desc->perm )
+ && !(!desc->data && desc->cacheable)
+ && !(desc->read && desc->write);
+
+ if ( ok ) {
+ *mpubase = (base & NIOS2_MPUBASE_BASE_MASK)
+ | ((desc->index << NIOS2_MPUBASE_INDEX_OFFSET) & NIOS2_MPUBASE_INDEX_MASK)
+ | (desc->data ? NIOS2_MPUBASE_D : 0);
+ *mpuacc = mask_or_limit
+ | (desc->cacheable ? NIOS2_MPUACC_C : 0)
+ | ((desc->perm << NIOS2_MPUACC_PERM_OFFSET) & NIOS2_MPUACC_PERM_MASK)
+ | (desc->read ? NIOS2_MPUACC_RD : 0)
+ | (desc->write ? NIOS2_MPUACC_WR : 0);
+ }
+
+ return ok;
+}
diff --git a/cpukit/score/cpu/nios2/nios2-mpu-disable-protected.c b/cpukit/score/cpu/nios2/nios2-mpu-disable-protected.c
new file mode 100644
index 0000000000..797a2072e8
--- /dev/null
+++ b/cpukit/score/cpu/nios2/nios2-mpu-disable-protected.c
@@ -0,0 +1,34 @@
+/*
+ * 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$
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <rtems/score/isr.h>
+#include <rtems/score/nios2-utility.h>
+
+uint32_t _Nios2_MPU_Disable_protected( void )
+{
+ ISR_Level level;
+ uint32_t config;
+
+ _ISR_Disable( level );
+ config = _Nios2_MPU_Disable();
+ _ISR_Enable( level );
+
+ return config;
+}
diff --git a/cpukit/score/cpu/nios2/nios2-mpu-reset.c b/cpukit/score/cpu/nios2/nios2-mpu-reset.c
new file mode 100644
index 0000000000..5431b7da75
--- /dev/null
+++ b/cpukit/score/cpu/nios2/nios2-mpu-reset.c
@@ -0,0 +1,48 @@
+/*
+ * 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$
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include <rtems/score/nios2-utility.h>
+
+void _Nios2_MPU_Reset( const Nios2_MPU_Configuration *config )
+{
+ uint32_t data_mpubase = (1U << config->data_region_size_log2)
+ | NIOS2_MPUBASE_D;
+ uint32_t inst_mpubase = 1U << config->instruction_region_size_log2;
+ uint32_t mpuacc = NIOS2_MPUACC_WR;
+ int data_count = config->data_region_count;
+ int inst_count = config->instruction_region_count;
+ int i = 0;
+
+ _Nios2_MPU_Disable();
+
+ for ( i = 0; i < data_count; ++i ) {
+ uint32_t index = ((uint32_t) i) << NIOS2_MPUBASE_INDEX_OFFSET;
+
+ _Nios2_Set_ctlreg_mpubase( data_mpubase | index );
+ _Nios2_Set_ctlreg_mpuacc( mpuacc );
+ }
+
+ for ( i = 0; i < inst_count; ++i ) {
+ uint32_t index = ((uint32_t) i) << NIOS2_MPUBASE_INDEX_OFFSET;
+
+ _Nios2_Set_ctlreg_mpubase( inst_mpubase | index );
+ _Nios2_Set_ctlreg_mpuacc( mpuacc );
+ }
+}
diff --git a/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h b/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h
index f417aec340..83909c3305 100644
--- a/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h
+++ b/cpukit/score/cpu/nios2/rtems/score/nios2-utility.h
@@ -102,7 +102,7 @@
#define NIOS2_CONFIG_ANI (1 << 1)
#define NIOS2_CONFIG_PE (1 << 0)
-#define NIOS2_MPUBASE_BASE_OFFSET 5
+#define NIOS2_MPUBASE_BASE_OFFSET 6
#define NIOS2_MPUBASE_BASE_MASK (0x1ffffff << NIOS2_MPUBASE_BASE_OFFSET)
#define NIOS2_MPUBASE_INDEX_OFFSET 1
@@ -132,6 +132,7 @@
#ifndef ASM
+#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
@@ -168,6 +169,14 @@ extern char _Nios2_ISR_Status_mask [];
*/
extern char _Nios2_ISR_Status_bits [];
+/**
+ * @brief This global variable indicates that the Nios2 MPU is active
+ *
+ * This global variable is set to 1 when the board support package
+ * initializes the MPU during startup.
+ */
+extern uint32_t _Nios2_Mpu_active;
+
static inline uint32_t _Nios2_Get_ctlreg_status( void )
{
return (uint32_t) __builtin_rdctl( NIOS2_CTLREG_INDEX_STATUS );
@@ -305,10 +314,133 @@ static inline bool _Nios2_Has_internal_interrupt_controller( void )
uint32_t _Nios2_ISR_Set_level( uint32_t new_level, uint32_t status );
+typedef struct {
+ int data_address_width;
+ int instruction_address_width;
+ int data_region_size_log2;
+ int instruction_region_size_log2;
+ int data_region_count;
+ int instruction_region_count;
+ int data_index_for_stack_protection;
+ bool region_uses_limit;
+ bool enable_data_cache_for_stack;
+} Nios2_MPU_Configuration;
+
+void _Nios2_MPU_Set_configuration( const Nios2_MPU_Configuration *config );
+
+const Nios2_MPU_Configuration *_Nios2_MPU_Get_configuration( void );
+
+typedef enum {
+ NIOS2_MPU_INST_PERM_SVR_NONE_USER_NONE = 0,
+ NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_NONE,
+ NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_EXECUTE,
+ NIOS2_MPU_DATA_PERM_SVR_NONE_USER_NONE = 0,
+ NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_NONE,
+ NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_READONLY,
+ NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE = 4,
+ NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_READONLY,
+ NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_READWRITE
+} Nios2_MPU_Region_permissions;
+
+typedef struct {
+ int index;
+ const void *base;
+ const void *end;
+ Nios2_MPU_Region_permissions perm;
+ bool data;
+ bool cacheable;
+ bool read;
+ bool write;
+} Nios2_MPU_Region_descriptor;
+
+#define NIOS2_MPU_REGION_DESC_INST( index, base, end ) \
+ { \
+ (index), (base), (end), NIOS2_MPU_INST_PERM_SVR_EXECUTE_USER_NONE, \
+ false, false, false, true \
+ }
+
+#define NIOS2_MPU_REGION_DESC_DATA_RO( index, base, end ) \
+ { \
+ (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READONLY_USER_NONE, \
+ true, true, false, true \
+ }
+
+#define NIOS2_MPU_REGION_DESC_DATA_RW( index, base, end ) \
+ { \
+ (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE, \
+ true, true, false, true \
+ }
+
+#define NIOS2_MPU_REGION_DESC_DATA_IO( index, base, end ) \
+ { \
+ (index), (base), (end), NIOS2_MPU_DATA_PERM_SVR_READWRITE_USER_NONE, \
+ true, false, false, true \
+ }
+
+bool _Nios2_MPU_Setup_region_registers(
+ const Nios2_MPU_Configuration *config,
+ const Nios2_MPU_Region_descriptor *desc,
+ uint32_t *mpubase,
+ uint32_t *mpuacc
+);
+
+static inline void _Nios2_MPU_Get_region_registers(
+ int index,
+ bool data,
+ uint32_t *mpubase,
+ uint32_t *mpuacc
+)
+{
+ uint32_t base = (uint32_t)
+ (((index << NIOS2_MPUBASE_INDEX_OFFSET) & NIOS2_MPUBASE_INDEX_MASK)
+ | (data ? NIOS2_MPUBASE_D : 0));
+
+ _Nios2_Set_ctlreg_mpubase( base );
+ _Nios2_Set_ctlreg_mpuacc( NIOS2_MPUACC_RD );
+ *mpubase = _Nios2_Get_ctlreg_mpubase() | base;
+ *mpuacc = _Nios2_Get_ctlreg_mpuacc();
+}
+
+static inline void _Nios2_MPU_Enable( void )
+{
+ uint32_t config = _Nios2_Get_ctlreg_config();
+
+ _Nios2_Set_ctlreg_config( config | NIOS2_CONFIG_PE );
+}
+
+static inline uint32_t _Nios2_MPU_Disable( void )
+{
+ uint32_t config = _Nios2_Get_ctlreg_config();
+ uint32_t config_pe = NIOS2_CONFIG_PE;
+
+ _Nios2_Set_ctlreg_config( config & ~config_pe );
+
+ return config;
+}
+
+static inline void _Nios2_MPU_Restore( uint32_t config )
+{
+ _Nios2_Set_ctlreg_config( config );
+}
+
+uint32_t _Nios2_MPU_Disable_protected( void );
+
+void _Nios2_MPU_Reset( const Nios2_MPU_Configuration *config );
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
-#endif /* !ASM */
+#else /* ASM */
+
+ .macro NIOS2_ASM_DISABLE_INTERRUPTS new_status, current_status
+ movhi \new_status, %hiadj(_Nios2_ISR_Status_mask)
+ addi \new_status, \new_status, %lo(_Nios2_ISR_Status_mask)
+ and \new_status, \current_status, \new_status
+ ori \new_status, \new_status, %lo(_Nios2_ISR_Status_bits)
+ wrctl status, \new_status
+ .endm
+
+#endif /* ASM */
#endif /* _RTEMS_SCORE_NIOS2_UTILITY_H */