diff --git a/mpu_user_console_etu/labo5_mpu_user_console_etu/src/assembleur.s b/mpu_user_console_etu/labo5_mpu_user_console_etu/src/assembleur.s index 51901bd8804c8e30693ce2a21203d718aeebdf5b..9a9a679d20d417863abe3dc3f1147adae349060c 100644 --- a/mpu_user_console_etu/labo5_mpu_user_console_etu/src/assembleur.s +++ b/mpu_user_console_etu/labo5_mpu_user_console_etu/src/assembleur.s @@ -9,18 +9,24 @@ .global switch_to_user_mode .extern user_stack DATA // this adress can be read like: ldr Rx, =user_stack +switch_to_user_mode: + // Charge la valeur 3 dans r0 pour configurer le registre CONTROL + mov r0, #3 + // Charge l'adresse du tableau user_stack dans r1 + ldr r1, =user_stack -switch_to_user_mode: - mov r0, #3 - mov r3, USER_STACK_SIZE - lsl r3, #2 // r3 = USER_STACK_SIZE * 4 - ldr r1, =user_stack - add r1, r1, r3 - msr psp, r1 - msr control, r0 + // Déplace l'adresse de user_stack dans le registre PSP (Process Stack Pointer) + msr psp, r1 + + // Configure le registre CONTROL pour passer en mode utilisateur + msr control, r0 // Bits [0:1] pour le mode utilisateur (p.721) + + // Instruction de synchronisation entre les pipelines d'instructions isb - bx lr + + // Saut indirect vers l'adresse contenue dans le registre lr (return address) + bx lr .equ bad_addr,0x90000 diff --git a/mpu_user_console_etu/labo5_mpu_user_console_etu/src/mpu_user_console_etu.c b/mpu_user_console_etu/labo5_mpu_user_console_etu/src/mpu_user_console_etu.c index 5a9af5e541551c1b8bc96f5e57bcbca0d4ce81f7..dbb76fcc652c7cacf6a320f9ec1c039aa2d2c185 100644 --- a/mpu_user_console_etu/labo5_mpu_user_console_etu/src/mpu_user_console_etu.c +++ b/mpu_user_console_etu/labo5_mpu_user_console_etu/src/mpu_user_console_etu.c @@ -23,7 +23,7 @@ #include "user_cmd.h" #include "uart.h" - +// Definition du registre MMFAR #define MMFAR *(unsigned *)0xE000ED34 unsigned user_stack[USER_STACK_SIZE]; @@ -33,17 +33,34 @@ int *p_sram2=(int *)0x2007c000, a, *p_out_of_mem=(int *)0x80000; void switch_to_user_mode(); void asm_test_fault(); +// Tableau global contenant les adresses provoquant une erreur uint32_t error_adresses[100]; uint32_t error_count = 0; uint32_t error_codes[100]; void MemManage_Handler() { + // Sauvegarde de l'adresse de l'erreur error_adresses[error_count] = MMFAR; + + // Sauvegarde du code de l'erreur dans le registre CFSR error_codes[error_count] = SCB->CFSR; - SCB->CFSR = 0xFFFF; + + // Affichage du code d'erreur en binaire sur les LEDs LPC_GPIO2->FIOPIN = error_count; + + // Incrémente l'index de l'erreur error_count++; + + // Acknowledge du registre CFSR + SCB->CFSR = 0xFFFF; + + __asm volatile( + "mrs r0, psp\n" + "ldr r1, =user_starting_address\n" // recup le pointeur vers l'adresse de retour souhaitée + "ldr r1, [r1]\n" // deref le pointeur pour recup l'adresse de retour + "str r1, [r0, #24]\n" + ); } @@ -61,10 +78,10 @@ void test_user_mode() int n; for (n=0; n<3; n++); // OK - LPC_GPIO2->FIOPIN=0xaa; // not OK (read only) +// LPC_GPIO2->FIOPIN=0xaa; // not OK (read only) a=LPC_GPIO2->FIOPIN; // OK a=*p_sram2; // OK (unprivileged read only) - *p_sram2=5; // not OK (privileged only for writing) +// *p_sram2=5; // not OK (privileged only for writing) n=LPC_TIM0->TC; // not OK (privileged access only) } struct __FILE { int handle; /* Add whatever you need here */ }; @@ -76,65 +93,266 @@ unsigned simulated_memory_space[MAX_MEMORY_SIZE]; int main(void) { - - SCB->SHCSR |= (1 << 16); // MPU configuration here... - // Region 0 (Flash) - MPU->RNR = 0; - MPU->RBAR = 0x00000000; - MPU->RASR = 0x5 << 24; - MPU->RASR = 0x01 << 19; - MPU->RASR = 9<<1; //car log2(512) = 9 - MPU->RASR = 0x1; - - // Region 1 (SRAM1) - MPU->RNR = 1; - MPU->RBAR = 0x10000000; - MPU->RASR = 0x3 << 24; - MPU->RASR = 0x01 << 19; - MPU->RASR = 5<<1; //car log2(32) = 5 - MPU->RASR = 0x1; - - // Region 2 (SRAM1) - MPU->RNR = 2; - MPU->RBAR = 0x2007C000; - MPU->RASR = 0x2 << 24; - MPU->RASR = 0x01 << 19; - MPU->RASR = 5<<1; - MPU->RASR = 0x1; - - - // Region 3 (GPIO) - MPU->RNR = 3; - MPU->RBAR = 0x2009C000; - MPU->RASR = 0x2 << 24; - MPU->RASR = 0x02 << 19; - MPU->RASR = 4<<1; - MPU->RASR = 0x1; - - - // Region 4 (périphériques dont timers) - MPU->RNR = 4; - MPU->RBAR = 0x40000000; - MPU->RASR = 0x1 << 24; - MPU->RASR = 0x02 << 19; - MPU->RASR = 5<<1; - MPU->RASR = 0x1; - - - // Region 5 (UART) - MPU->RNR = 5; - MPU->RBAR = 0x4000C000; - MPU->RASR = 0x3 << 24; - MPU->RASR = 0x02 << 19; - MPU->RASR = 9<<1; - MPU->RASR = 0x1; - - - MPU->CTRL |= 0x5; +/*___________________________________________________________________________________________________*/ + // Region 0 (flash) : + // Taille : 512 KB (524288 bytes) + // Type de mémoire : Non partagée, normal + // Type d'accès : Read + + MPU->RNR = 0; // ID de la region + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x00000000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 524288 = 2^(SIZE+1) --> SIZE = 18 + MPU->RASR |= (18<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée + // Outer and inner noncacheable +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b001 << 19); // TEX + + // Read-only avec ou sans permissions + MPU->RASR |= (0b110 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + +/*___________________________________________________________________________________________________*/ + // Region 1 (SRAM1) : + // Taille : 32 KB (32768 bytes) + // Type de mémoire : Non partagée, normal + // Type d'accès : Read / Write + MPU->RNR = 1; // ID de la region + + // Registre RBAR à verifier +// MPU->RBAR = (0 << 4); // RNR modifié manuellement + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x10000000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 32768 = 2^(SIZE+1) --> SIZlrE = 14 + MPU->RASR |= (14<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée + // Outer and inner noncacheable +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b001 << 19); // TEX + + // Full access + MPU->RASR |= (0b011 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + + +/*___________________________________________________________________________________________________*/ + // Region 2 (SRAM2) : + // Taille : 16 KB (16384 bytes) + // Type de mémoire : Non partagée, normal + // Type d'accès : Read / Write en mode privilégié, Read sinon + MPU->RNR = 2; // ID de la region + + // Registre RBAR à verifier +// MPU->RBAR = (0 << 4); // RNR modifié manuellement + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x2007C000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 16384 = 2^(SIZE+1) --> SIZE = 13 + MPU->RASR |= (13<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée + // Outer and inner noncacheable +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b001 << 19); // TEX + + // Read-write avec permissions, read-only sans permissions + MPU->RASR |= (0b010 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + +/*___________________________________________________________________________________________________*/ + // Region 3 (SRAM2) : + // Taille : 16 KB (16384 bytes) + // Type de mémoire : Non partagée, normal + // Type d'accès : Read / Write en mode privilégié, Read sinon + MPU->RNR = 3; // ID de la region + + // Registre RBAR à verifier +// MPU->RBAR = (0 << 4); // RNR modifié manuellement + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x20080000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 16384 = 2^(SIZE+1) --> SIZE = 13 + MPU->RASR |= (13<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée + // Outer and inner noncacheable +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b001 << 19); // TEX + + // Read-write avec permissions, read-only sans permissions + MPU->RASR |= (0b010 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + +/*___________________________________________________________________________________________________*/ + // Region 4 (GPIO) : + // Taille : 16 KB (16384 bytes) + // Type de mémoire : Non partagée, device + // Type d'accès : Read / Write en mode privilégié, Read sinon + MPU->RNR = 4; // ID de la region + + // Registre RBAR à verifier +// MPU->RBAR = (0 << 4); // RNR modifié manuellement + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x2009C000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 16384 = 2^(SIZE+1) --> SIZE = 13 + MPU->RASR |= (13<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b010 << 19); // TEX + + // Read-write avec permissions, read-only sans permissions + MPU->RASR |= (0b010 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + +/*___________________________________________________________________________________________________*/ + // Region 5 (périphériques dont timers) : + // Taille : 32 KB (32768 bytes) + // Type de mémoire : Non partagée, device + // Type d'accès : Read / Write en mode privilégié uniquement + MPU->RNR = 5; // ID de la region + + // Registre RBAR à verifier +// MPU->RBAR = (0 << 4); // RNR modifié manuellement + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x40000000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 32768 = 2^(SIZE+1) --> SIZE = 14 + MPU->RASR |= (14<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée, device +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b010 << 19); // TEX + + // Read-write avec permissions uniquement + MPU->RASR |= (0b001 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + + +/*___________________________________________________________________________________________________*/ + // Region 6 (UART) : + // Taille : 16 KB (16384 bytes) + // Type de mémoire : Non partagée, device + // Type d'accès : Read / Write + MPU->RNR = 6; // ID de la region + + // Registre RBAR à verifier +// MPU->RBAR = (0 << 4); // RNR modifié manuellement + + // N = Log2(Region size in bytes) + MPU->RBAR = (0x4000C000); + + // Reset des bits + enable + MPU->RASR = (1 << 0); // ENABLE + + // Définition taille de région (Region size in bytes) = 2^(SIZE+1) + // 16384 = 2^(SIZE+1) --> SIZE = 13 + MPU->RASR |= (13<<1); // SIZE + + // Active toutes les sub-régions +// MPU->RASR &= (255 << 8); // SRD + + // Mémoire non-partagée +// MPU->RASR |= (0 << 16); // B +// MPU->RASR |= (0 << 17); // C +// MPU->RASR |= (0 << 18); // S + MPU->RASR |= (0b010 << 19); // TEX + + // Full access + MPU->RASR |= (0b011 << 24); // AP + + // Désactivation des instructions +// MPU->RASR |= (0b101 << 28); // XN + + + // Activation de l’exception de gestion d’erreur mémoire MemManage_Handler() + SCB->SHCSR |= (1 << 16); // MEMFAULTENA + MPU->CTRL |= (1<<0); // Enables MPU + + LPC_GPIO2->FIODIR = 0xff; + LPC_GPIO2->FIOPIN = 0xf; // testing memory accesses in supervisor mode: - //test_supervisor_mode(); // to be removed after checking +// test_supervisor_mode(); // to be removed after checking user_start: user_starting_address=&&user_start; // save the address of the label 'user_start' (for exercise 2) @@ -142,7 +360,7 @@ int main(void) switch_to_user_mode(); // to be implemented // testing memory accesses in user mode: - //test_user_mode(); // to be removed after checking +// test_user_mode(); // to be removed after checking for (unsigned i = 0; i < MAX_MEMORY_SIZE; ++i) { simulated_memory_space[i] = i; // Remplissage avec des données factices diff --git a/mpu_user_console_etu/labo5_mpu_user_console_etu/src/user_cmd.c b/mpu_user_console_etu/labo5_mpu_user_console_etu/src/user_cmd.c index 83b5467337435ed2f9c88833cab4da722fbc5aa4..5b03c92f35a0117bb7fdb53ad678031a6296c4e1 100644 --- a/mpu_user_console_etu/labo5_mpu_user_console_etu/src/user_cmd.c +++ b/mpu_user_console_etu/labo5_mpu_user_console_etu/src/user_cmd.c @@ -1,23 +1,21 @@ +/* + * user_interpreter.c + * + * Created on: 12 nov. 2023 + * Author: Vincent + */ + #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdbool.h> +#include <stdarg.h> +#include "uart.h" +#include "user_cmd.h" -#define MAX_INPUT_LENGTH 200 -#define MAX_ERRORS 20 - -// Fausse mémoire et compteur d'erreur pour la simulation -unsigned simulated_memory_space[1024] = {0}; -unsigned fault_address_buffer[MAX_ERRORS] = {0}; -unsigned fault_code_buffer[MAX_ERRORS] = {0}; -unsigned fault_count = 0; -bool is_supervisor_mode = false; // false pour le mode utilisateur, true pour le mode superviseur - -// Prototypes de fonctions pour la commutation de mode et l'affichage des erreurs -void switch_mode(); -void display_status(); -unsigned read_memory(unsigned addr); -void write_memory(unsigned addr, unsigned value); +#define PRINT_SYNTAX_ERROR() PRINT("Syntax error! Expected syntax is either <8 characters hexadecimal address> for reading\n or " \ + "<8 characters hexadecimal address>=<8 characters hexadecimal value> for writing\n"); +bool is_supervisor_mode=false; void SVC_Handler() { @@ -25,72 +23,53 @@ void SVC_Handler() } -// Fonction pour basculer entre les modes utilisateur et superviseur -void switch_mode() { - is_supervisor_mode = !is_supervisor_mode; - printf("Switched to %s mode.\n", is_supervisor_mode ? "Supervisor" : "User"); -} - -// Fonction pour afficher les erreurs d'accès mémoire -void display_status() { - if (fault_count == 0) { - printf("No access errors recorded.\n"); - } else { - printf("Access errors recorded:\n"); - for (unsigned i = 0; i < fault_count; ++i) { - printf("Error %u: Address: 0x%08X, Code: 0x%08X\n", i, fault_address_buffer[i], fault_code_buffer[i]); - } - } -} - -// Modifiez les fonctions read_memory et write_memory pour inclure la validation de la MPU -unsigned read_memory(unsigned addr) { - if (!validate_mpu_address(addr)) { - printf("MPU violation: Read access denied for address 0x%08X.\n", addr); - return 0; // Retourne 0 pour indiquer un échec de lecture - } - return simulated_memory_space[addr]; // Lecture réussie -} +void exec_user_read_write() +{ + char str[200]; + int i=0, coma_nb=0, value_idx; + unsigned addr, value; -void write_memory(unsigned addr, unsigned value) { - if (!validate_mpu_address(addr)) { - printf("MPU violation: Write access denied for address 0x%08X.\n", addr); - return; // Échec de l'écriture, sortie anticipée - } - simulated_memory_space[addr] = value; // Écriture réussie -}void exec_user_read_write() { - char input[MAX_INPUT_LENGTH]; - unsigned addr, value; + PRINT("Write an hexadecimal address for reading <addr> or <addr>,<value> for writing (%s):\n", is_supervisor_mode?"Supervisor":"User"); - printf("Enter command (%s mode): ", is_supervisor_mode ? "Supervisor" : "User"); - if (fgets(input, sizeof(input), stdin) == NULL) { - printf("Error reading input.\n"); - return; - } + fflush(stdin); + fscanf(stdin, "%s",str); - // Enlever le caractère de nouvelle ligne si présent - input[strcspn(input, "\n")] = '\0'; + for (i=0; i<strlen(str); i++) + { + if (str[i] == ',') + { + if (i==0 || ++coma_nb>1) + { + PRINT_SYNTAX_ERROR(); + return; + } + str[i]=0; + value_idx=i+1; + } else if (!isxdigit(str[i])) + { + PRINT_SYNTAX_ERROR(); + return; + } + } + if ((coma_nb&(i<2)) || i>17) + { + PRINT_SYNTAX_ERROR(); + PRINT("(Bad length!)"); + return; + } - // Traitement des commandes "switch" et "status" - if (strcmp(input, "switch") == 0) { - switch_mode(); - } else if (strcmp(input, "status") == 0) { - display_status(); - } else { - char *comma = strchr(input, ','); - if (comma) { - *comma = '\0'; // Séparer la chaîne en deux parties - addr = strtoul(input, NULL, 16); - value = strtoul(comma + 1, NULL, 16); - write_memory(addr, value); - printf("Written 0x%08X to address 0x%08X\n", value, addr); - } else if (isxdigit(input[0])) { - addr = strtoul(input, NULL, 16); - value = read_memory(addr); - printf("Value at address 0x%08X: 0x%08X\n", addr, value); - } else { - printf("Syntax error! Please check your input format.\n"); - } - } + sscanf(str, "%x", &addr); + if (!coma_nb) // if read + { + PRINT("reading address: 0x%08x\n", addr); + PRINT("value read: 0x%08x\n", *(unsigned *)addr); + } + else // write + { + sscanf(str+value_idx, "%x", &value); + PRINT("writing address: 0x%08x with 0x%08x\n", addr, value); + *(unsigned *)addr=value; + } } +