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:
commit
b2bed29683
@ -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
|
||||
|
@ -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
|
||||
|
14
core/sched.c
14
core/sched.c
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
163
cpu/cortexm_common/include/mpu.h
Normal file
163
cpu/cortexm_common/include/mpu.h
Normal 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
72
cpu/cortexm_common/mpu.c
Normal 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
|
||||
}
|
@ -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) */
|
||||
|
41
tests/mpu_stack_guard/Makefile
Normal file
41
tests/mpu_stack_guard/Makefile
Normal 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
|
78
tests/mpu_stack_guard/main.c
Normal file
78
tests/mpu_stack_guard/main.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user