1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #5564 from locicontrols/mpu-rebase2

Cortex-M MPU driver and pseudo-module for guarding against stack overflows
This commit is contained in:
Francisco Acosta 2016-10-25 11:56:40 +02:00 committed by GitHub
commit b2bed29683
10 changed files with 391 additions and 3 deletions

View File

@ -34,6 +34,7 @@ PSEUDOMODULES += lwip_stats
PSEUDOMODULES += lwip_tcp
PSEUDOMODULES += lwip_udp
PSEUDOMODULES += lwip_udplite
PSEUDOMODULES += mpu_stack_guard
PSEUDOMODULES += netdev_default
PSEUDOMODULES += netif
PSEUDOMODULES += netstats

View File

@ -189,7 +189,7 @@ struct _thread {
msg_t *msg_array; /**< memory holding messages */
#endif
#if defined DEVELHELP || defined(SCHED_TEST_STACK)
#if defined(DEVELHELP) || defined(SCHED_TEST_STACK) || defined(MODULE_MPU_STACK_GUARD)
char *stack_start; /**< thread's stack start address */
#endif
#ifdef DEVELHELP

View File

@ -29,6 +29,10 @@
#include "irq.h"
#include "log.h"
#ifdef MODULE_MPU_STACK_GUARD
#include "mpu.h"
#endif
#ifdef MODULE_SCHEDSTATISTICS
#include "xtimer.h"
#endif
@ -115,6 +119,16 @@ int __attribute__((used)) sched_run(void)
sched_active_pid = next_thread->pid;
sched_active_thread = (volatile thread_t *) next_thread;
#ifdef MODULE_MPU_STACK_GUARD
mpu_configure(
1, /* MPU region 1 */
(uintptr_t)sched_active_thread->stack_start + 31, /* Base Address (rounded up) */
MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */
);
mpu_enable();
#endif
DEBUG("sched_run: done, changed sched_active_thread.\n");
return 1;

View File

@ -211,7 +211,7 @@ kernel_pid_t thread_create(char *stack, int stacksize, char priority, int flags,
cb->pid = pid;
cb->sp = thread_stack_init(function, arg, stack, stacksize);
#if defined(DEVELHELP) || defined(SCHED_TEST_STACK)
#if defined(DEVELHELP) || defined(SCHED_TEST_STACK) || defined(MODULE_MPU_STACK_GUARD)
cb->stack_start = stack;
#endif

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2016 Loci Controls Inc.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_cortexm_common
* @{
*
* @file mpu.h
* @brief Cortex-M Memory Protection Unit (MPU) Driver Header File
*
* @author Ian Martin <ian@locicontrols.com>
*
* @}
*/
#ifndef MPU_H_
#define MPU_H_
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Number of MPU regions available (will vary depending on the Cortex-M version)
*/
#define MPU_NUM_REGIONS ( (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos )
/**
* @brief Access Permission words
*/
enum {
AP_NO_NO = 0, /**< no access for all levels */
AP_RW_NO = 1, /**< read/write for privileged level, no access from user level */
AP_RW_RO = 2, /**< read/write for privileged level, read-only for user level */
AP_RW_RW = 3, /**< read/write for all levels */
AP_RO_NO = 5, /**< read-only for privileged level, no access from user level */
AP_RO_RO = 6, /**< read-only for all levels */
};
/**
* @brief MPU region sizes
*/
enum {
MPU_SIZE_32B = 4, /**< 32 bytes */
MPU_SIZE_64B = 5, /**< 64 bytes */
MPU_SIZE_128B = 6, /**< 128 bytes */
MPU_SIZE_256B = 7, /**< 256 bytes */
MPU_SIZE_512B = 8, /**< 512 bytes */
MPU_SIZE_1K = 9, /**< 1 kilobytes */
MPU_SIZE_2K = 10, /**< 2 kilobytes */
MPU_SIZE_4K = 11, /**< 4 kilobytes */
MPU_SIZE_8K = 12, /**< 8 kilobytes */
MPU_SIZE_16K = 13, /**< 16 kilobytes */
MPU_SIZE_32K = 14, /**< 32 kilobytes */
MPU_SIZE_64K = 15, /**< 64 kilobytes */
MPU_SIZE_128K = 16, /**< 128 kilobytes */
MPU_SIZE_256K = 17, /**< 256 kilobytes */
MPU_SIZE_512K = 18, /**< 512 kilobytes */
MPU_SIZE_1M = 19, /**< 1 megabytes */
MPU_SIZE_2M = 20, /**< 2 megabytes */
MPU_SIZE_4M = 21, /**< 4 megabytes */
MPU_SIZE_8M = 22, /**< 8 megabytes */
MPU_SIZE_16M = 23, /**< 16 megabytes */
MPU_SIZE_32M = 24, /**< 32 megabytes */
MPU_SIZE_64M = 25, /**< 64 megabytes */
MPU_SIZE_128M = 26, /**< 128 megabytes */
MPU_SIZE_256M = 27, /**< 256 megabytes */
MPU_SIZE_512M = 28, /**< 512 megabytes */
MPU_SIZE_1G = 29, /**< 1 gigabytes */
MPU_SIZE_2G = 30, /**< 2 gigabytes */
MPU_SIZE_4G = 31, /**< 4 gigabytes */
};
/**
* @brief convert a region size code to a size in bytes
*
* @param[in] size region size code, e.g. MPU_SIZE_32B
*
* @return region size in bytes
*/
#define MPU_SIZE_TO_BYTES(size) ( (uintptr_t)1 << ((size) + 1) )
/**
* @brief generate an MPU attribute word suitable for writing to the RASR register
*
* @param[in] xn eXecute Never flag (forbids instruction fetches)
* @param[in] ap Access Permission word, e.g. AP_RO_RO
* @param[in] tex Type Extension Field
* @param[in] c Cacheable bit
* @param[in] b Bufferable bit
* @param[in] s Sub-Region Disable (SRD) field
* @param[in] size region size code, e.g. MPU_SIZE_32B
*
* @return combined region attribute word
*/
static inline uint32_t MPU_ATTR(
uint32_t xn,
uint32_t ap,
uint32_t tex,
uint32_t c,
uint32_t b,
uint32_t s,
uint32_t size)
{
return
(xn << 28) |
(ap << 24) |
(tex << 19) |
(s << 18) |
(c << 17) |
(b << 16) |
(size << 1);
}
/**
* @brief disable the MPU
*
* @return 0 on success
* @return <0 on failure or no MPU present
*/
int mpu_disable(void);
/**
* @brief enable the MPU
*
* @return 0 on success
* @return <0 on failure or no MPU present
*/
int mpu_enable(void);
/**
* @brief test if the MPU is enabled
*
* @return true if enabled
* @return false if disabled
*/
bool mpu_enabled(void);
/**
* @brief configure the base address and attributes for an MPU region
*
* @param[in] region MPU region to configure (0 <= @p region < MPU_NUM_REGIONS)
* @param[in] base base address in RAM (aligned to the size specified within @p attr)
* @param[in] attr attribute word generated by MPU_ATTR()
*
* @return 0 on success
* @return <0 on failure or no MPU present
*/
int mpu_configure(uint_fast8_t region, uintptr_t base, uint_fast32_t attr);
#ifdef __cplusplus
}
#endif
#endif /* MPU_H_ */

72
cpu/cortexm_common/mpu.c Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2016 Loci Controls Inc.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_cortexm_common
* @{
*
* @file mpu.c
* @brief Cortex-M Memory Protection Unit (MPU) Driver
*
* @author Ian Martin <ian@locicontrols.com>
*
* @}
*/
#include <assert.h>
#include "cpu.h"
#include "mpu.h"
int mpu_disable(void) {
#if __MPU_PRESENT
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
return 0;
#else
return -1;
#endif
}
int mpu_enable(void) {
#if __MPU_PRESENT
MPU->CTRL |= MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
/* Enable the memory fault exception */
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
return 0;
#else
return -1;
#endif
}
bool mpu_enabled(void) {
#if __MPU_PRESENT
return (MPU->CTRL & MPU_CTRL_ENABLE_Msk) != 0;
#else
return false;
#endif
}
int mpu_configure(uint_fast8_t region, uintptr_t base, uint_fast32_t attr) {
#if __MPU_PRESENT
assert(region < MPU_NUM_REGIONS);
MPU->RNR = region;
MPU->RBAR = base & MPU_RBAR_ADDR_Msk;
MPU->RASR = attr | MPU_RASR_ENABLE_Msk;
if (!mpu_enabled()) {
mpu_enable();
}
return 0;
#else
return -1;
#endif
}

View File

@ -28,9 +28,14 @@
#include "cpu.h"
#include "kernel_init.h"
#include "board.h"
#include "mpu.h"
#include "panic.h"
#include "vectors_cortexm.h"
#ifndef SRAM_BASE
#define SRAM_BASE 0
#endif
/**
* @brief Memory markers, defined in the linker script
* @{
@ -48,6 +53,8 @@ extern uint32_t _sram;
extern uint32_t _eram;
/** @} */
static const uintptr_t stack_base = (uintptr_t)&_sstack;
/**
* @brief Allocation of the interrupt stack
*/
@ -94,6 +101,18 @@ void reset_handler_default(void)
*(dst++) = 0;
}
#ifdef MODULE_MPU_STACK_GUARD
if (stack_base != SRAM_BASE) {
mpu_configure(
0, /* MPU region 0 */
stack_base + 31, /* Base Address (rounded up) */
MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */
);
mpu_enable();
}
#endif
post_startup();
/* initialize the board (which also initiates CPU initialization) */

View File

@ -0,0 +1,41 @@
APPLICATION = mpu_stack_guard
include ../Makefile.tests_common
BOARD_WHITELIST += arduino-due # cortex-m3
BOARD_WHITELIST += arduino-zero # cortex-m0plus
BOARD_WHITELIST += cc2538dk # cortex-m3
BOARD_WHITELIST += cc2650stk # cortex-m3
BOARD_WHITELIST += ek-lm4f120xl # cortex-m4f
BOARD_WHITELIST += f4vi1 # cortex-m4f
BOARD_WHITELIST += fox # cortex-m3
BOARD_WHITELIST += frdm-k64f # cortex-m4
BOARD_WHITELIST += iotlab-common # cortex-m3
BOARD_WHITELIST += limifrog-v1 # cortex-m3
BOARD_WHITELIST += mbed_lpc1768 # cortex-m3
BOARD_WHITELIST += msbiot # cortex-m4f
BOARD_WHITELIST += mulle # cortex-m4
BOARD_WHITELIST += nrf52dk # cortex-m4f
BOARD_WHITELIST += nucleo-f103 # cortex-m3
BOARD_WHITELIST += nucleo-f207 # cortex-m3
BOARD_WHITELIST += nucleo-f303 # cortex-m4f
BOARD_WHITELIST += nucleo-f334 # cortex-m4f
BOARD_WHITELIST += nucleo-f401 # cortex-m4f
BOARD_WHITELIST += nucleo-f446 # cortex-m4f
BOARD_WHITELIST += nucleo-l1 # cortex-m3
BOARD_WHITELIST += openmote-cc2538 # cortex-m3
BOARD_WHITELIST += pba-d-01-kw2x # cortex-m4
BOARD_WHITELIST += remote # cortex-m3
BOARD_WHITELIST += saml21-xpro # cortex-m0plus
BOARD_WHITELIST += samr21-xpro # cortex-m0plus
BOARD_WHITELIST += slwstk6220a # cortex-m4f
BOARD_WHITELIST += sodaq-autonomo # cortex-m0plus
BOARD_WHITELIST += spark-core # cortex-m3
BOARD_WHITELIST += stm32f3discovery # cortex-m4f
BOARD_WHITELIST += stm32f4discovery # cortex-m4f
BOARD_WHITELIST += udoo # cortex-m3
CFLAGS += -DDEVELHELP
USEMODULE += mpu_stack_guard
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2016 Loci Controls Inc.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the mpu_stack_guard pseudo-module
*
* @author Ian Martin <ian@locicontrols.com>
*
* @}
*/
#include <stdio.h>
#include "cpu.h"
#include "thread.h"
#define CANARY_VALUE 0xdeadbeef
static struct {
unsigned int canary;
char stack[THREAD_STACKSIZE_MAIN];
} buf;
static int recurse(int counter)
{
printf("counter =%4d, SP = 0x%08x, canary = 0x%08x\n", counter, (unsigned int)__get_PSP(), buf.canary);
if (buf.canary != CANARY_VALUE) {
printf("canary = 0x%08x\nTest failed.\n", buf.canary);
for (;;) {
thread_sleep();
}
}
counter++;
/* Recursing twice here prevents the compiler from optimizing-out the recursion. */
return recurse(counter) + recurse(counter);
}
static void *thread(void *arg)
{
(void) arg;
recurse(0);
return NULL;
}
int main(void)
{
puts("\nMPU Stack Guard Test\n");
puts("If the test fails, the canary value will change unexpectedly");
puts("after ~150 iterations. If the test succeeds, the MEM MANAGE HANDLER");
puts("will trigger a RIOT kernel panic before the canary value changes.\n");
#ifdef MODULE_MPU_STACK_GUARD
puts("The mpu_stack_guard module is present. Expect the test to succeed.\n");
#else
puts("The mpu_stack_guard module is missing! Expect the test to fail.\n");
#endif
buf.canary = CANARY_VALUE;
thread_create(buf.stack, sizeof(buf.stack), THREAD_PRIORITY_MAIN - 1, 0, thread, NULL, "thread");
return 0;
}

View File

@ -48,7 +48,7 @@ int main(void)
#ifdef DEVELHELP
P(name);
#endif
#if defined(DEVELHELP) || defined(SCHED_TEST_STACK)
#if defined(DEVELHELP) || defined(SCHED_TEST_STACK) || defined(MODULE_MPU_STACK_GUARD)
P(stack_start);
#endif