Select Git revision
mpu_user_console_etu.c
mpu_user_console_etu.c 4.50 KiB
/*******************************************************************************************************************
Name : labo_mpu_user_console.c
Author : VP
Date : 11.2023
Description : template file
Notes:
- writing to control register has no effect in user mode!
- the UART must be accessible in both user and supervisor mode
- the timers (and other peripherals) are accessible only in supervisor mode (TCR0:0x40004004, TC0:0x40004008)
********************************************************************************************************************/
#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif
#include <cr_section_macros.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "globals.h"
#include "user_cmd.h"
#include "uart.h"
#include "macro.h"
#define BUF_SIZE 100
#define MMFAR *(unsigned *)0xE000ED34
unsigned user_stack[USER_STACK_SIZE]; // space for user stack
void *user_stating_address;
int *p_sram2 = (int*) 0x2007c000, a, *p_out_of_mem = (int*) 0x80000;
unsigned arr_addr[BUF_SIZE] = { 0 };
unsigned arr_err_code[BUF_SIZE] = { 0 };
volatile static unsigned idx_error;
extern bool is_supervisor_mode;
void reset_user_stack();
void asm_test_fault();
void change_ret(void *addr);
void MemManage_Handler() {
if (idx_error < BUF_SIZE - 1) {
arr_addr[idx_error] = MMFAR;
arr_err_code[idx_error] = SCB->CFSR;
}
idx_error++;
SCB->CFSR = 0xFFFF;
LPC_GPIO2->FIOPIN = idx_error;
change_ret(user_stating_address);
}
void test_supervisor_mode() {
a = *p_sram2; // OK
*p_sram2 = 5; // OK (write in privileged mode)
LPC_GPIO2->FIOPIN = 0xaa; // OK
asm_test_fault(); // not OK
a = *p_out_of_mem; // not OK (out of regions)
}
void ask_user_input(void) {
char buff[USER_INPUT_SIZE] = { 0 };
char switch_cmd[] = "switch";
char status_cmd[] = "status";
PRINT("\r\n(%s) Would you like to `switch` or display `status` errors : ",
is_supervisor_mode ? "Supervisor" : "User")
;
#if UART_ENABLE
uart_scanf(buff);
PRINT("\r\n")
;
#else
fflush(stdin);
fscanf(stdin, "%s", buff);
#endif
if (strncmp(buff, switch_cmd, strlen(switch_cmd)) == 0) {
// permute through svc depending on flag
__asm volatile ("svc 0x69");
return;
}
if (strncmp(buff, status_cmd, strlen(status_cmd)) == 0) {
if (idx_error == 0) {
PRINT("No errors have occurred yet\r\n")
;
return;
}
for (int i = 0; i < idx_error; i++) {
if (i < BUF_SIZE) {
PRINT("Address where error occurred : 0x%x\tError code : 0x%x\r\n",
arr_addr[i], arr_err_code[i])
;
}
}
}
}
void test_user_mode() {
int n;
for (n = 0; n < 3; n++)
; // OK
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)
n = LPC_TIM0->TC; // not OK (privileged access only)
}
int main(void) {
#if UART_ENABLE
uart0_init_ref(9600, NULL, NULL);
#endif
LPC_GPIO2->FIODIR = 0xFF;
LPC_GPIO2->FIOPIN = 0;
// MPU configuration here...
// Region 0 (Flash)
MPU->RNR = 0;
MPU->RBAR = 0x00000000;
MPU->RASR = RO | BTEX_NORMAL_NOT_SHAREABLE | SET_SIZE_512KB | REGION_ENABLE;
// Region 1 (SRAM1)
MPU->RNR = 1;
MPU->RBAR = 0x10000000;
MPU->RASR = RW | BTEX_NORMAL_NOT_SHAREABLE | SET_SIZE_32KB | REGION_ENABLE;
// Region 2 (SRAM1)
MPU->RNR = 2;
MPU->RBAR = 0x2007C000;
MPU->RASR = RW_PRIV_R_UNPRIV | BTEX_NORMAL_NOT_SHAREABLE | SET_SIZE_32KB
| REGION_ENABLE;
// Region 3 (GPIO)
MPU->RNR = 3;
MPU->RBAR = 0x2009C000;
MPU->RASR = RW_PRIV_R_UNPRIV | BTEX_NOT_SHAREABLE_DEVICE | SET_SIZE_16KB
| REGION_ENABLE;
// Region 4 (périphériques dont timers)
MPU->RNR = 4;
MPU->RBAR = 0x40000000;
MPU->RASR = RW_PRIV | BTEX_NOT_SHAREABLE_DEVICE | SET_SIZE_32KB
| REGION_ENABLE;
// Region 5 (UART)
MPU->RNR = 5;
MPU->RBAR = 0x4000C000;
MPU->RASR = RW | BTEX_NOT_SHAREABLE_DEVICE | SET_SIZE_16KB | REGION_ENABLE;
SCB->SHCSR |= (1 << 16);
MPU->CTRL |= 0x1 << 0;
// testing memory accesses in supervisor mode:
// test_supervisor_mode(); // to be removed after checking
user_start: user_stating_address = &&user_start;// save the address of the label 'user_start' (for exercise 2)
reset_user_stack(); // to be implemented
// testing memory accesses in user mode:
//test_user_mode(); // to be removed after checking
while (1) {
ask_user_input();
exec_user_read_write();
}
return 0;
}