From d4a95940391a1ee8c1e36a8b10b8800ee526c0e6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 21 Oct 2011 08:44:23 +0000 Subject: 2011-10-21 Sebastian Huber * 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). --- cpukit/score/cpu/nios2/ChangeLog | 8 ++ cpukit/score/cpu/nios2/Makefile.am | 4 + cpukit/score/cpu/nios2/nios2-context-initialize.c | 27 ++++ cpukit/score/cpu/nios2/nios2-mpu-configuration.c | 33 +++++ cpukit/score/cpu/nios2/nios2-mpu-descriptor.c | 121 ++++++++++++++++++ .../score/cpu/nios2/nios2-mpu-disable-protected.c | 34 ++++++ cpukit/score/cpu/nios2/nios2-mpu-reset.c | 48 ++++++++ cpukit/score/cpu/nios2/rtems/score/nios2-utility.h | 136 ++++++++++++++++++++- 8 files changed, 409 insertions(+), 2 deletions(-) create mode 100644 cpukit/score/cpu/nios2/nios2-mpu-configuration.c create mode 100644 cpukit/score/cpu/nios2/nios2-mpu-descriptor.c create mode 100644 cpukit/score/cpu/nios2/nios2-mpu-disable-protected.c create mode 100644 cpukit/score/cpu/nios2/nios2-mpu-reset.c 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 + + * 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 * 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 #include +#include 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 + * + * + * 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 + +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 + * + * + * 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 + +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 + * + * + * 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 +#include + +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 + * + * + * 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 + +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 #include #include @@ -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 */ -- cgit v1.2.3