Skip to content
Snippets Groups Projects
Select Git revision
  • 5da5d72565fecb9b49712d4c0cd8b17b5cdc5ef7
  • master default protected
2 results

mpu_user_console_etu.c

Blame
  • 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;
    }