embOS-MPU

embOS-MPU offers memory protection on top of the well-proven real-time operating system embOS. It significantly enhances both stability and safety of your embedded applications and thereby also simplifies any certification process. Due to a fully compatible API, existing embOS applications may be adapted to embOS-MPU with minimal effort.

embOS-MPU can be used in any application from battery-powered, single chip products to systems demanding ultra-fast response, flexibility and multiple tasks. Typical fields include, but are not limited to medical equipment, automation, avionics, and further safety-critical applications.

Features

  • Comprehensive memory protection
  • Suitable for any safety-critical application
  • Available for any microcontroller containing a hardware memory protection unit or memory management unit
  • Simple and straightforward runtime configuration
  • Easy to integrate in both new and existing products
  • Supports device drivers for full control of peripheral accesses
  • MISRA-C:2012 compliant

pdf Documentation download

Subscribe to embOS software notification

Pricing

HTML Release Notes


Basic concepts of embOS-MPU

What is memory protection?

Memory protection is a prevalent mechanism to control memory access rights and is part of most modern processor architectures and operating systems. The main purpose of memory protection is to avert specific tasks from accessing memory that has not been allocated to them, thus preventing possible bugs or even malware contained in one task from affecting the entire system.

In order to achieve this, application tasks that could possibly affect other tasks or the OS itself must be restricted from accessing the whole memory, special function registers and the OS’s control structures. For example, tasks that execute third-party code may be considered unsafe and should be restricted accordingly. Such application tasks must not run on the same privilege state as the OS, which runs in fully privileged mode and has access to all memory, peripheral and CPU features. Instead, these tasks must run in unprivileged state and have restricted access to specific memory locations only.

What is embOS-MPU?

embOS-MPU uses the hardware’s memory protection unit as well as additional software mechanisms implemented with embOS-MPU to prevent one task from affecting the entirety of the system. This guarantees that even in case a bug occurs in one task, all other tasks and the operating system itself continue execution.

With embOS-MPU, all privileged tasks have full access to the whole memory. An unprivileged task, however, has specific access permissions to each distinct memory region. In order to access peripherals, additional memory locations and OS control structures, device drivers as well as specific embOS API may be called from within an unpriviliged task.

An application based on embOS-MPU therefore consists of two distinct parts:

  • The first part runs in privileged state: it initializes the MPU settings and includes the device drivers.
    This part contains critical code and must be verified for full reliability.
  • The second part is the application itself, which does not need to or in some cases even cannot be verified for full reliability.
    As it runs in unprivileged state, this part cannot affect the complete system.

Working with unprivileged tasks

By default, a newly created unprivileged task has read access to RAM and ROM, but may execute code in ROM only, while write access is restricted to its own task stack. In order to access peripherals, additional memory locations and OS control structures, device drivers as well as specific embOS API may be called from within an unpriviliged task.
Access to peripherals

In a default configuration, an unprivileged task has no access to any peripheral. A specific device driver is necessary to access peripherals from within such task, e.g. for using a UART, SPI, or port pins. Device drivers can be provided by SEGGER, but in most cases will be implemented by the user.

With embOS-MPU, a device driver consists of two parts: one part runs in privileged state and the other part runs in unprivileged state. The actual peripheral access is performed in the privileged part only, and embOS-MPU ensures that there is only one explicit and safe way to switch from the unprivileged part to the privileged one.

Access to further memory regions

An unprivileged task may be granted access to additional memory regions, e.g. when a task needs to write LCD data to a framebuffer in RAM and a device driver is deemed inefficient for this purpose. Access permissions are fully configurable in regards to read access, write access and code execution.

Access to OS objects

An unprivileged task has no direct or indirect write access to embOS objects. However, indirect write access to these objects via embOS-MPU API may be granted for each individual object. This requires all objects to be created in privileged state.

MPU violation management

In case an unprivileged task violates its access restrictions or otherwise triggers a fault exception, it is automatically suspended and an optional user callback function is executed to inform the application about this. This callback may also perform further actions in regards to that task, e.g. restarting it or even terminating it completely.

 


Supported cores and compiler

The following list gives an overview on cores and compilers which are currently supported by embOS-MPU. We are continously adding new targets. However, if your device is not in the list, we are able to port the system to your target, ensuring high quality and extensive testing. Please feel free to contact us at info@segger.com.

Core Compiler / IDE embOS
 Cortex-M Segger Embedded Studio embOS-MPU Cortex-M ES

Trial version

Download an embOS-MPU trial version and get your first application running within a few minutes!.


embOS-MPU API functions

The table below lists the available embOS-MPU API functions.

 Function Description
OS_MPU_Enable() Enables embOS-MPU.
OS_MPU_EnableEx() Enables embOS-MPU and sets the MPU API list.
OS_MPU_ConfigMem() Configures RAM/ROM and OS regions.
OS_MPU_SetAllowedObjects() Sets a list of allowed OS objects.
OS_MPU_AddRegion() Adds an additonal memory region.
OS_MPU_SetErrorCallback() Sets the error callback function.
OS_MPU_SwitchToUnprivState() Switches a task to unprivileged state.
OS_MPU_SetDeviceDriverList() Sets the device driver list.
OS_MPU_CallDeviceDriver() Calls a device driver.
OS_MPU_GetThreadState() Returns the privilege state.
OS_MPU_ExtendTaskContext() Extends the task context for MPU registers.

emlib-crc.html Detailed descriptions of all functions can be found in the embOS-MPU documentation.


Example application

The following example shows the ease of use of embOS-MPU. Furhermore, it provides a good starting point for your application.

#include "RTOS.h"
#include "BSP.h"
#include <stdio.h>

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/

//
// Task-control-blocks.
//
static OS_TASK TCBHP;
static OS_TASK TCBLP;
//
// Task stacks. With Cortex-M MPU, stack for unprivileged tasks
// requires alignment.
//
static OS_STACKPTR int StackHP[128];
static OS_STACKPTR int StackLP[128] __attribute__ ((aligned (512)));
//
// Linker symbols to get section addresses. embOS-MPU needs to know
// where RAM, ROM and the OS section are located.
//
extern unsigned int __FLASH_segment_start__;
extern unsigned int __FLASH_segment_size__;
extern unsigned int __RAM_segment_start__;
extern unsigned int __RAM_segment_size__;
extern unsigned int __os_start__;
extern unsigned int __os_size__;
//
// User callback function which is called when an unprivileged
// task violates its access permissions.
//
static void _ErrorCallback(OS_TASK* pTask, OS_MPU_ERRORCODE ErrorCode) {
  printf("%s has been stopped due to error %d\n", pTask->Name, ErrorCode);
  OS_TerminateTask(pTask);  // Terminate the violating task
}

/*********************************************************************
*
*       Local functions
*
**********************************************************************
*/

static void _HPTask(void) {
  while (1) {
    BSP_ToggleLED(0);
    OS_Delay(50);
  }
}

static void _LPTask(void) {
  OS_MPU_SwitchToUnprivState();  // Switch task to unprivileged state
  while (1) {
    BSP_ToggleLED(1);
    OS_Delay(200);
  }
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

int main(void) {
  OS_IncDI();                      /* Initially disable interrupts  */
  OS_InitKern();                   /* Initialize OS                 */
  OS_InitHW();                     /* Initialize Hardware for OS    */
  BSP_Init();                      /* Initialize LED ports          */
  //
  // Setup embOS-MPU:
  // 1. Configure memory information, must be done before first task is created.
  // 2. Set optional error callback function.
  // 3. Enable embOS MPU support.
  //
  OS_MPU_ConfigMem((OS_U32)&__FLASH_segment_start__, (OS_U32)&__FLASH_segment_size__,
                   (OS_U32)&__RAM_segment_start__,   (OS_U32)&__RAM_segment_size__,
                   (OS_U32)&__os_start__,            (OS_U32)&__os_size__);
  OS_MPU_SetErrorCallback(&_ErrorCallback);
  OS_MPU_Enable();
  /* You need to create at least one task before calling OS_Start() */
  OS_CREATETASK(&TCBHP, "HP Task", _HPTask, 100, StackHP);
  OS_CREATETASK(&TCBLP, "LP Task", _LPTask,  50, StackLP);
  OS_Start();                      /* Start multitasking            */
  return 0;
}
Pin It