La protection mémoire
Cortex-M MPU
La série des processeurs STM32 basés sur les corps Arm® Cortex®-M disposent d’une unité de protection de la mémoire, la MPU (Memory Protection Unit). La mémoire est une zone sensible des systèmes informatiques et tout particulièrement des systèmes embarqués.
L’unité de protection de la mémoire rend le système embarqué plus robuste, fiable et sûr en
- interdisant aux tâches utilisateur de corrompre les données des tâches critiques comme le noyau du système opérationnel,
- interdisant l’exécution de code en mémoire RAM afin de prévenir les attaques par injection de code,
- redéfinissant les attributs des accès en mémoire.
La protection mémoire doit être mise en place avant son utilisation. Le comportement “normal” du système n’est pas affecté par l’activation, ou non, de la protection mémoire.
Principe de fonctionnement de la protection mémoire
La protection se fait par région mémoire. Le nombre de régions disponibles dépend du corps. Elles sont au nombre de 8 pour les Armv6 et Armv7 et de 16 dans les Armv8. Dans le cas du Cortex®-M4 (Armv7) nous disposons de 8 régions.
Chaque région peut encore être découpée en 8 sous-régions de tailles égales, mais au minimum de 32 bytes pour autant que la région soit d’au moins 256 bytes. Les sous-régions sont “activables” indépendamment l’une de l’autre.
Les régions sont numérotées de 0 à 7 (ou 15). Les régions de numérotations supérieures sont prioritaires sur les régions inférieures (la région 1 et prioritaire à la région 0, etc.). Les priorités sont fixes et non modifiables.
Les régions peuvent se chevaucher et se surcharger. Il existe une région de défaut, la région -1 qui est de priorité inférieure aux autres régions.
Dans l’exemple ci-dessous, les régions jaunes sont prioritaires sur les régions vertes, par exemple: s’il est possible d’écrire dans la région 2 et non dans la région 5, le haut de la région 2 surchargée par la région 5 ne sera pas accessible en écriture.
L’unité de protection mémoire est unifiée, c’est-à-dire qu’elle ne fait pas de distinction entre la mémoire de code (ro), la RAM (rw) ou les accès périphériques en interne ou en externe.
Bien que la mémoire cache soit principalement gérée par le registre de contrôle de la cache, la MPU permet également d’étendre les attributs de la mémoire comme le fait qu’il s’agit d’une zone de mémoire cache et ainsi étendre ces caractéristiques vers l’unité de gestion de la mémoire cache ou l’unité de gestion mémoire. La MPU permet de gérer jusqu’à deux niveaux de mémoire cache (“inner” cache et “outer” cache).
Pour rappel, les processeurs Cortex®-M ont une zone d’adressage mémoire fixe de 4 GB. La figure ci-dessous rappelle cette organisation mémoire.
L’organisation mémoire (Memory Map) et la programmation de la MPU découpent la mémoire en régions. Chaque région a un type et un attribut de mémoire.
Types de mémoires
La mémoire peut se découper en trois types:
- Mémoire normale: la mémoire normale ou à accès aléatoire permet la lecture et l’écriture d’octets (8 bits), de demi-mots (16 bits) et de mots (32 bits) selon un ordre déterminé par le CPU afin d’en optimiser l’accès. L’ordre d’accès du CPU peut être différent de l’ordre du programme et le compilateur n’est pas nécessairement au courant des types de régions mémoires.
- Mémoire de périphérique: les accès en lecture et écriture sur les zones mémoires des périphériques doivent se faire strictement dans l’ordre pré-établi afin de garantir la configuration des registres du périphérique.
- Mémoire ordonnée: Les opérations de lecture et d’écriture doivent se faire dans l’ordre programmé. Le CPU attend la fin de l’instruction lecture/écriture (accès bus effectif) avant de passer à l’instruction suivante dans le flux des instructions du programme. Ceci peut induire des baisses de performance du système.
Configuration des régions de mémoire
La configuration des régions de mémoire se fait dans le registre MPU_RASR (MPU Region Attributes and Size Register).
En cas d’accès mémoire en dehors des configurations, une erreur MemManagement est levée.
La table ci-dessous reprend le contenu des registres MPU_RASR.
Les valeurs des champs AP et TEX, C, B et S sont décrits dans les deux tables suivants.
Bits | Nom | Description |
---|---|---|
28 | XN | Ne jamais exécuté |
26:24 | AP | Permission d’accès (RO, RW ou pas d’accès) |
21:19 | TEX | Type d’extension |
18 | S | Partageable |
17 | C | Fonction de cache |
16 | B | Mise en buffer |
15:8 | SRD | Sous-régions désactivée, bit à 1 = désactivée, à 0 = activée |
5:1 | SIZE | Taille de région de protection mémoire |
AP[2:0] | Mode privilégié | Mode non privilégié | Description |
---|---|---|---|
000 | aucun | aucun | Tout accès génère une exception |
001 | RW | aucun | Accès uniquement en mode privilégié |
010 | RW | RO | Ecriture interdite en mode non privilégié |
011 | RW | RW | Plein accès en tous modes |
100 | - | - | Réservé |
101 | RO | aucun | Lecture seulement en mode privilégié |
110 | RO | RO | Lecture uniquement en tous modes |
111 | RO | RO | Lecture uniquement en tous modes |
TEX | C | B | Type | Description | Partageable |
---|---|---|---|---|---|
000 | 0 | 0 | Ordonnée | Mémoire ordonnée | Oui |
000 | 0 | 1 | Périphérique | Périphérique partagé | Oui |
000 | 1 | 0 | Normale | Cache “Write through” sans allocation d’écriture | S bit |
000 | 1 | 1 | Normale | Cache “Write-back” sans allocation d’écriture | S bit |
001 | 0 | 0 | Normale | Sans fonction de cache | S bit |
001 | 0 | 1 | - | Reservé | - |
001 | 1 | 0 | - | Non défini | - |
001 | 1 | 1 | Normale | Cache “Write-back”, avec allocation d’écriture et de lecture | S bit |
010 | 0 | 0 | Périphérique | Périphérique non-partagé | Non |
010 | 0 | 1 | - | Réservé | - |
Pour rappel, le logiciel peut s’exécuter en deux modes sur le CPU:
- Unprivileged: En mode non privilégié, le logiciel à les
restrictions suivantes:
- accès limité aux instructions MSR et MRS, interdiction d’utiliser les instructions CPS.
- pas d’accès au timer du système, au NVIC, au SCB (System Control Block).
- accès réduit à la mémoire et aux périphériques.
- pour accéder une ressource protégée, il doit utiliser l’instruction SVC pour passer la requête à un code en mode privilégié.
- Privileged: En mode privilégié le logiciel a accès à tout le jeu des instructions et à toutes les ressources du système. Il peut écrire dans les registres de contrôle et changer les privilèges d’exécution du logiciel.
En cas d’accès mémoire en dehors des configurations, une exception MemManagement est générée et doit être traitée par le système (Fault Exception handling). Les exceptions MPU ou de non-respect de l’organisation mémoire sont:
- IACCVIOL: Violation d’instruction en cas d’exécution en zone XN.
- DACCVIOL: Violation d’accès en zone de données.
- MSTKERR: Violation lors de l’entrée en mode d’exception.
- MUNSKERR: Violation lors de la sortie en mode d’exception.
- MLSPERR: Violation lors du “lazy floating-point state preservation”.
En cas d’exception, le compteur de programme PC est sauvegardé (stacked) sur l’instruction ayant causé l’exception.
Vous trouverez tous les détails de la programmation de la MPU du STM32 Cortex®-M4 dans le document STM32 Cortex®-M4 MCUs and MPUs programming manual (PM0214)
La protection mémoire dans Mbed OS
Nous voyons bien que l’utilisation de la protection mémoire n’est pas simple à mettre en place, mais qu’elle prend tout son sens lorsque nous utilisons un système opérationnel découpant l’application en tâches.
L’API mpu-management de Mbed OS permet de gérer le MPU du STM32.
La protection mémoire est activée automatiquement et par défaut sur Mbed OS pour autant que le processeur supporte l’API memory. Il n’est donc pas nécessaire de s’en soucier. L’API mpu-management permet de désactiver la protection mémoire si nécessaire. La désactivation de la protection mémoire est réentrante, vous devez la réactiver autant de fois qu’elle a été désactivée pour la réactiver. A noter que Mbed OS gère la mémoire RAM comme une seule région et la mémoire ROM comme une autre région unique.
La protection mémoire avec la MPU sous Mbed OS:
- protège de l’exécution de code en RAM,
- protège de l’écriture en ROM.
Mbed OS gère automatiquement la MPU dans les situations suivantes:
- la protection mémoire est activée au démarrage (séquence de boot),
- la protection mémoire est désactivée au démarrage d’une nouvelle application,
- la protection mémoire est désactivée pour permettre la programmation en mémoire flash.
Vous pouvez également vous référer au module de traitement des erreurs de Mbed OS pour comprendre les différentes options liées au traitement des erreurs. Le traitement des erreurs dans les systèmes embarqués (capture, sauvegarde des états, redémarrage et report) fait cependant l’objet d’un chapitre ultérieur dédié.