Skip to content

Commit

Permalink
Add mpu_demo in pmp-test
Browse files Browse the repository at this point in the history
  • Loading branch information
chinglee-iot committed Aug 31, 2023
1 parent d797840 commit 6790372
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 11 deletions.
1 change: 1 addition & 0 deletions FreeRTOS/Demo/PMP-test/FreeRTOSConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,6 @@ to exclude the API function. */

#define configENABLE_MPU 1
#define configUSE_MPU_WRAPPERS_V1 1
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1

#endif /* FREERTOS_CONFIG_H */
1 change: 1 addition & 0 deletions FreeRTOS/Demo/PMP-test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ SRCS = main.c \
pmp_stage0_demo.c \
pmp_stage1_demo.c \
pmp_stage2_demo.c \
mpu_demo.c \
$(RTOS_SOURCE_DIR)/event_groups.c \
$(RTOS_SOURCE_DIR)/list.c \
$(RTOS_SOURCE_DIR)/queue.c \
Expand Down
25 changes: 24 additions & 1 deletion FreeRTOS/Demo/PMP-test/exception_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ static void user_mode_trap_handler( int xSyscallNumber )
char temp[64];
uint32_t * uxTaskStackPointer;

#if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
extern uint32_t __syscalls_flash_start__[];
extern uint32_t __syscalls_flash_end__[];
#endif

/* Get the mstatus from the stack. */
uxTaskStackPointer = pxCurrentTCB[ 0 ];

Expand All @@ -56,11 +61,20 @@ static void user_mode_trap_handler( int xSyscallNumber )
}
else if( xSyscallNumber == portECALL_RAISE_PRIORITY )
{
#if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
if( ( uxTaskStackPointer[ 0 ] >= ( uint32_t ) __syscalls_flash_start__ ) &&
( uxTaskStackPointer[ 0 ] <= ( uint32_t ) __syscalls_flash_end__ ) )
#endif
/* Update the mstatus.MPP on to stack to return to M-mode. */
uxTaskStackPointer[ 30 ] = uxTaskStackPointer[ 30 ] | ( 0x3 << 11 );
{
uxTaskStackPointer[ 30 ] = uxTaskStackPointer[ 30 ] | ( 0x3 << 11 );
}
}
}

#define SHARED_MEMORY_SIZE 32
extern volatile uint8_t ucROTaskFaultTracker[ SHARED_MEMORY_SIZE ];
extern void vHandleMemoryFault( uint32_t * pulFaultStackAddress );
void freertos_risc_v_application_exception_handler( void )
{
volatile int xSyscallNumber;
Expand Down Expand Up @@ -98,9 +112,18 @@ void freertos_risc_v_application_exception_handler( void )

switch( mCause )
{
case METAL_II_EXCEPTION_CODE:
/* User mode tries to set the priority. */
break;
case METAL_LAF_EXCEPTION_CODE:
case METAL_SAMOAF_EXCEPTION_CODE : /* memory access violation. */
xMemoryAcceccExceptionFlag = 1;
// vHandleMemoryFault( uxTaskStackPointer );
if( ucROTaskFaultTracker[ 0 ] == 1 )
{
/* Mark the fault as handled. */
ucROTaskFaultTracker[ 0 ] = 0;
}
break;
case METAL_ECALL_U_EXCEPTION_CODE : /* ECALL from u-mode. */
user_mode_trap_handler( xSyscallNumber );
Expand Down
10 changes: 7 additions & 3 deletions FreeRTOS/Demo/PMP-test/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
/* Run a simple demo just prints 'Blink' */
#define mainVECTOR_MODE_DIRECT 1

#define mainPMP_DEMO_STAGE 2
#define mainPMP_DEMO_STAGE 3

extern void freertos_risc_v_trap_handler( void );
extern void freertos_vector_table( void );
Expand All @@ -44,12 +44,13 @@ void vApplicationTickHook( void );
extern int pmp_stage0_demo( void );
extern int pmp_stage1_demo( void );
extern int pmp_stage2_demo( void );
extern void vStartMPUDemo( void );

/*-----------------------------------------------------------*/

int main( void )
{
int ret;
int ret = 0;
// trap handler initialization
#if( mainVECTOR_MODE_DIRECT == 1 )
{
Expand All @@ -66,8 +67,11 @@ int main( void )
ret = pmp_stage0_demo();
#elif mainPMP_DEMO_STAGE == 1
ret = pmp_stage1_demo();
#else
#elif mainPMP_DEMO_STAGE == 2
ret = pmp_stage2_demo();
#else
vStartMPUDemo();
vTaskStartScheduler();
#endif

return ret;
Expand Down
271 changes: 271 additions & 0 deletions FreeRTOS/Demo/PMP-test/mpu_demo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "task.h"

#include <stdint.h>

/** ARMv7 MPU Details:
*
* - ARMv7 MPU requires that the size of a MPU region is a power of 2.
* - Smallest supported region size is 32 bytes.
* - Start address of a region must be aligned to an integer multiple of the
* region size. For example, if the region size is 4 KB(0x1000), the starting
* address must be N x 0x1000, where N is an integer.
*/

/**
* @brief Size of the shared memory region.
*/
#define SHARED_MEMORY_SIZE 32

/**
* @brief Memory region shared between two tasks.
*/
static volatile uint8_t ucSharedMemory[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( SHARED_MEMORY_SIZE ) ) );

/**
* @brief Memory region used to track Memory Fault intentionally caused by the
* RO Access task.
*
* RO Access task sets ucROTaskFaultTracker[ 0 ] to 1 before accessing illegal
* memory. Illegal memory access causes Memory Fault and the fault handler
* checks ucROTaskFaultTracker[ 0 ] to see if this is an expected fault. We
* recover gracefully from an expected fault by jumping to the next instruction.
*
* @note We are declaring a region of 32 bytes even though we need only one.
* The reason is that the smallest supported MPU region size is 32 bytes.
*/
volatile uint8_t ucROTaskFaultTracker[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( SHARED_MEMORY_SIZE ) ) ) = { 0 };
/*-----------------------------------------------------------*/

/**
* @brief Implements the task which has Read Only access to the memory region
* ucSharedMemory.
*
* @param pvParameters[in] Parameters as passed during task creation.
*/
static void prvROAccessTask( void * pvParameters );

/**
* @brief Implements the task which has Read Write access to the memory region
* ucSharedMemory.
*
* @param pvParameters[in] Parameters as passed during task creation.
*/
static void prvRWAccessTask( void * pvParameters );

/*-----------------------------------------------------------*/

static void prvROAccessTask( void * pvParameters )
{
uint8_t ucVal;

/* Unused parameters. */
( void ) pvParameters;

portRAISE_PRIVILEGE();

for( ; ; )
{
/* This task has RO access to ucSharedMemory and therefore it can read
* it but cannot modify it. */
ucVal = ucSharedMemory[ 0 ];

/* Silent compiler warnings about unused variables. */
( void ) ucVal;

/* Since this task has Read Only access to the ucSharedMemory region,
* writing to it results in Memory Fault. Set ucROTaskFaultTracker[ 0 ]
* to 1 to tell the Memory Fault Handler that this is an expected fault.
* The handler will recover from this fault gracefully by jumping to the
* next instruction. */
ucROTaskFaultTracker[ 0 ] = 1;

/* Illegal access to generate Memory Fault. */
vSendString( "Write memory in RO task sould fail!" );
ucSharedMemory[ 0 ] = 0;

/* Ensure that the above line did generate MemFault and the fault
* handler did clear the ucROTaskFaultTracker[ 0 ]. */
/*configASSERT( ucROTaskFaultTracker[ 0 ] == 0 ); */

#if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
{
/* Generate an SVC to raise the privilege. Since privilege
* escalation is only allowed from kernel code, this request must
* get rejected and the task must remain unprivileged. As a result,
* trying to write to ucSharedMemory will still result in Memory
* Fault. */
portRAISE_PRIVILEGE();

/* Set ucROTaskFaultTracker[ 0 ] to 1 to tell the Memory Fault
* Handler that this is an expected fault. The handler will then be
* able to recover from this fault gracefully by jumping to the
* next instruction.*/
ucROTaskFaultTracker[ 0 ] = 1;

/* The following must still result in Memory Fault since the task
* is still running unprivileged. */
vSendString( "Write memory in RO task sould fail!" );
ucSharedMemory[ 0 ] = 0;

/* Ensure that the above line did generate MemFault and the fault
* handler did clear the ucROTaskFaultTracker[ 0 ]. */
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
}
#else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
{
/* Generate an SVC to raise the privilege. Since
* configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not enabled, the
* task will be able to escalate privilege. */
portRAISE_PRIVILEGE();

/* At this point, the task is running privileged. The following
* access must not result in Memory Fault. If something goes
* wrong and we do get a fault, the execution will stop in fault
* handler as ucROTaskFaultTracker[ 0 ] is not set (i.e.
* un-expected fault). */
vSendString( "Write memory in privileged RO task sould not fail!" );
ucSharedMemory[ 0 ] = 0;

/* Lower down the privilege. */
portSWITCH_TO_USER_MODE();

/* Now the task is running unprivileged and therefore an attempt to
* write to ucSharedMemory will result in a Memory Fault. Set
* ucROTaskFaultTracker[ 0 ] to 1 to tell the Memory Fault Handler
* that this is an expected fault. The handler will then be able to
* recover from this fault gracefully by jumping to the next
* instruction.*/
ucROTaskFaultTracker[ 0 ] = 1;

/* The following must result in Memory Fault since the task is now
* running unprivileged. */
ucSharedMemory[ 0 ] = 0;

/* Ensure that the above line did generate MemFault and the fault
* handler did clear the ucROTaskFaultTracker[ 0 ]. */
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
}
#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */

/* Wait for a second. */
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}

/*-----------------------------------------------------------*/

static void prvRWAccessTask( void * pvParameters )
{
/* Unused parameters. */
( void ) pvParameters;

for( ; ; )
{
vSendString( "Write memory in RW task sould not fail!" );
/* This task has RW access to ucSharedMemory and therefore can write to
* it. */
ucSharedMemory[ 0 ] = 0;

/* Wait for a second. */
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}

/*-----------------------------------------------------------*/

void vStartMPUDemo( void )
{
/**
* Since stack of a task is protected using MPU, it must satisfy MPU
* requirements as mentioned at the top of this file.
*/
static StackType_t xROAccessTaskStack[ 2048 ]
__attribute__( ( aligned( 1024 * sizeof( StackType_t ) ) ) );
static StackType_t xRWAccessTaskStack[ 2048 ]
__attribute__( ( aligned( 1024 * sizeof( StackType_t ) ) ) );

TaskParameters_t xROAccessTaskParameters =
{
.pvTaskCode = prvROAccessTask,
.pcName = "ROAccess",
.usStackDepth = 2048,
.pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xROAccessTaskStack,
.xRegions =
{
{ ucSharedMemory, SHARED_MEMORY_SIZE,
portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY |
portMPU_REGION_EXECUTE_NEVER },
{ ( void * ) ucROTaskFaultTracker, SHARED_MEMORY_SIZE,
portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0},
}
};

TaskParameters_t xRWAccessTaskParameters =
{
.pvTaskCode = prvRWAccessTask,
.pcName = "RWAccess",
.usStackDepth = 2048,
.pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xRWAccessTaskStack,
.xRegions =
{
{ ucSharedMemory, SHARED_MEMORY_SIZE,
portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0 },
{ 0, 0, 0 },
}
};

/* Create an unprivileged task with RO access to ucSharedMemory. */
xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL );

/* Create an unprivileged task with RW access to ucSharedMemory. */
xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL );
}
/*-----------------------------------------------------------*/

portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress )
{
( void )pulFaultStackAddress;

/* Is this an expected fault? */
if( ucROTaskFaultTracker[ 0 ] == 1 )
{
/* Mark the fault as handled. */
ucROTaskFaultTracker[ 0 ] = 0;
}
}
/*-----------------------------------------------------------*/
Loading

0 comments on commit 6790372

Please sign in to comment.