void xBadTask(void *params) { // The privileged bit is set when this function is started, so it initially // runs in privileged mode. We first turn on an LED (which requires // privileges), lower our privileges to user mode, and again try to access // the LED. LED access happens through raw access to the registers, rather // than through the GPIO driver, because the driver might be privileged. printf("Bad task: started in privileged mode. Turning LED on...\n"); LPC_GPIO1->FIOSET = ( 1UL << 23UL ); vTaskDelay(150); // Now switch to user mode and try again portSWITCH_TO_USER_MODE(); printf("Bad task: switched to user mode. Turning LED off...\n"); LPC_GPIO1->FIOCLR = ( 1UL << 23UL ); printf("Bad task: finished.\n"); for (;;) { vTaskDelay(1000); printf("Bad task: still alive\n"); } }
/** @brief ADC task procedure */ void adc_task (void *) { adc the_adc; char buffer[10] = { 0 }; portSWITCH_TO_USER_MODE(); // now go protected while (true) { uint16_t value = adc_value; for (uint8_t i = 4; i < 0xff; --i) { buffer[i] = (uint8_t) (value % 10) + '0'; value /= 10; } BSP_LCD_SetTextColor(LCD_COLOR_BLUE); BSP_LCD_DisplayStringAtLine (LINE(10), (uint8_t *) buffer); vTaskDelay (1000); } }
static void prvRegTest1Task( void *pvParameters ) { /* This task is created in privileged mode so can access the file scope queue variable. Take a stack copy of this before the task is set into user mode. Once this task is in user mode the file scope queue variable will no longer be accessible but the stack copy will. */ QueueHandle_t xQueue = xFileScopeCheckQueue; /* Now the queue handle has been obtained the task can switch to user mode. This is just one method of passing a handle into a protected task, the other reg test task uses the task parameter instead. */ portSWITCH_TO_USER_MODE(); /* First check that the parameter value is as expected. */ if( pvParameters != ( void * ) 0x12345678 ) { /* Error detected. Delete the task so it stops communicating with the check task. */ prvDeleteMe(); } for( ;; ) { /* This task tests the kernel context switch mechanism by reading and writing directly to registers - which requires the test to be written in assembly code. */ __asm volatile ( " MOV R4, #104 \n" /* Set registers to a known value. R0 to R1 are done in the loop below. */ " MOV R5, #105 \n" " MOV R6, #106 \n" " MOV R8, #108 \n" " MOV R9, #109 \n" " MOV R10, #110 \n" " MOV R11, #111 \n" "reg1loop: \n" " MOV R0, #100 \n" /* Set the scratch registers to known values - done inside the loop as they get clobbered. */ " MOV R1, #101 \n" " MOV R2, #102 \n" " MOV R3, #103 \n" " MOV R12, #112 \n" " SVC #1 \n" /* Yield just to increase test coverage. */ " CMP R0, #100 \n" /* Check all the registers still contain their expected values. */ " BNE prvDeleteMe \n" /* Value was not as expected, delete the task so it stops communicating with the check task. */ " CMP R1, #101 \n" " BNE prvDeleteMe \n" " CMP R2, #102 \n" " BNE prvDeleteMe \n" " CMP R3, #103 \n" " BNE prvDeleteMe \n" " CMP R4, #104 \n" " BNE prvDeleteMe \n" " CMP R5, #105 \n" " BNE prvDeleteMe \n" " CMP R6, #106 \n" " BNE prvDeleteMe \n" " CMP R8, #108 \n" " BNE prvDeleteMe \n" " CMP R9, #109 \n" " BNE prvDeleteMe \n" " CMP R10, #110 \n" " BNE prvDeleteMe \n" " CMP R11, #111 \n" " BNE prvDeleteMe \n" " CMP R12, #112 \n" " BNE prvDeleteMe \n" :::"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r10", "r11", "r12" ); /* Send mainREG_TEST_1_STILL_EXECUTING to the check task to indicate that this task is still functioning. */ prvSendImAlive( xQueue, mainREG_TEST_1_STILL_EXECUTING ); /* Go back to check all the register values again. */ __asm volatile( " B reg1loop " ); } }
static void prvTestMemoryRegions( void ) { long l; char cTemp; /* The check task (from which this function is called) is created in the Privileged mode. The privileged array can be both read from and written to while this task is privileged. */ cPrivilegedOnlyAccessArray[ 0 ] = 'a'; if( cPrivilegedOnlyAccessArray[ 0 ] != 'a' ) { /* Something unexpected happened. Delete this task so the error is apparent (no output will be displayed). */ prvDeleteMe(); } /* Writing off the end of the RAM allocated to this task will *NOT* cause a protection fault because the task is still executing in a privileged mode. Uncomment the following to test. */ /*cPrivilegedOnlyAccessArray[ mainPRIVILEGED_ONLY_ACCESS_ALIGN_SIZE ] = 'a';*/ /* Now set the task into user mode. */ portSWITCH_TO_USER_MODE(); /* Accessing the privileged only array will now cause a fault. Uncomment the following line to test. */ /*cPrivilegedOnlyAccessArray[ 0 ] = 'a';*/ /* The read/write array can still be successfully read and written. */ for( l = 0; l < mainREAD_WRITE_ALIGN_SIZE; l++ ) { cReadWriteArray[ l ] = 'a'; if( cReadWriteArray[ l ] != 'a' ) { /* Something unexpected happened. Delete this task so the error is apparent (no output will be displayed). */ prvDeleteMe(); } } /* But attempting to read or write off the end of the RAM allocated to this task will cause a fault. Uncomment either of the following two lines to test. */ /* cReadWriteArray[ 0 ] = cReadWriteArray[ -1 ]; */ /* cReadWriteArray[ mainREAD_WRITE_ALIGN_SIZE ] = 0x00; */ /* The read only array can be successfully read... */ for( l = 0; l < mainREAD_ONLY_ALIGN_SIZE; l++ ) { cTemp = cReadOnlyArray[ l ]; } /* ...but cannot be written. Uncomment the following line to test. */ /* cReadOnlyArray[ 0 ] = 'a'; */ /* Writing to the first and last locations in the stack array should not cause a protection fault. Note that doing this will cause the kernel to detect a stack overflow if configCHECK_FOR_STACK_OVERFLOW is greater than 1. */ xCheckTaskStack[ 0 ] = 0; xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS - 1 ] = 0; /* Writing off either end of the stack array should cause a protection fault, uncomment either of the following two lines to test. */ /* xCheckTaskStack[ -1 ] = 0; */ /* xCheckTaskStack[ mainCHECK_TASK_STACK_SIZE_WORDS ] = 0; */ ( void ) cTemp; }
static void prvCheckTask( void *pvParameters ) { /* This task is created in privileged mode so can access the file scope queue variable. Take a stack copy of this before the task is set into user mode. Once that task is in user mode the file scope queue variable will no longer be accessible but the stack copy will. */ QueueHandle_t xQueue = xFileScopeCheckQueue; long lMessage; unsigned long ulStillAliveCounts[ 2 ] = { 0 }; const char *pcStatusMessage = "PASS\r\n"; /* The debug_printf() function uses RAM that is outside of the control of the application writer. Therefore the application_defined_privileged_functions.h header file is used to provide a version that executes with privileges. */ extern int MPU_debug_printf( const char *pcMessage ); /* Just to remove compiler warning. */ ( void ) pvParameters; /* Demonstrate how the various memory regions can and can't be accessed. The task privilege level is set down to user mode within this function. */ prvTestMemoryRegions(); /* Tests are done so lower the privilege status. */ portSWITCH_TO_USER_MODE(); /* This loop performs the main function of the task, which is blocking on a message queue then processing each message as it arrives. */ for( ;; ) { /* Wait for the next message to arrive. */ xQueueReceive( xQueue, &lMessage, portMAX_DELAY ); switch( lMessage ) { case mainREG_TEST_1_STILL_EXECUTING : /* Message from task 1, so task 1 must still be executing. */ ( ulStillAliveCounts[ 0 ] )++; break; case mainREG_TEST_2_STILL_EXECUTING : /* Message from task 2, so task 2 must still be executing. */ ( ulStillAliveCounts[ 1 ] )++; break; case mainPRINT_SYSTEM_STATUS : /* Message from tick hook, time to print out the system status. If messages has stopped arriving from either reg test task then the status must be set to fail. */ if( ( ulStillAliveCounts[ 0 ] == 0 ) || ( ulStillAliveCounts[ 1 ] == 0 ) ) { /* One or both of the test tasks are no longer sending 'still alive' messages. */ pcStatusMessage = "FAIL\r\n"; } /* Print a pass/fail message to the terminal. This will be visible in the CrossWorks IDE. */ MPU_debug_printf( pcStatusMessage ); /* Reset the count of 'still alive' messages. */ memset( ulStillAliveCounts, 0x00, sizeof( ulStillAliveCounts ) ); break; default : /* Something unexpected happened. Delete this task so the error is apparent (no output will be displayed). */ prvDeleteMe(); break; } } }
static void prvCheckTask( void *pvParameters ) { /* This task is created in privileged mode so can access the file scope queue variable. Take a stack copy of this before the task is set into user mode. Once that task is in user mode the file scope queue variable will no longer be accessible but the stack copy will. */ QueueHandle_t xQueue = xFileScopeCheckQueue; int32_t lMessage; uint32_t ulStillAliveCounts[ 2 ] = { 0 }; const char *pcStatusMessage = "PASS\r\n"; volatile uint32_t ulStatus = pdPASS; /* Just to remove compiler warning. */ ( void ) pvParameters; /* Demonstrate how the various memory regions can and can't be accessed. The task privilege level is set down to user mode within this function. */ prvTestMemoryRegions(); /* Tests are done so lower the privilege status. */ portSWITCH_TO_USER_MODE(); /* This loop performs the main function of the task, which is blocking on a message queue then processing each message as it arrives. */ for( ;; ) { /* Wait for the next message to arrive. */ xQueueReceive( xQueue, &lMessage, portMAX_DELAY ); switch( lMessage ) { case mainREG_TEST_1_STILL_EXECUTING : /* Message from task 1, so task 1 must still be executing. */ ( ulStillAliveCounts[ 0 ] )++; break; case mainREG_TEST_2_STILL_EXECUTING : /* Message from task 2, so task 2 must still be executing. */ ( ulStillAliveCounts[ 1 ] )++; break; case mainPRINT_SYSTEM_STATUS : /* Message from tick hook, time to print out the system status. If messages has stopped arriving from either reg test task then the status must be set to fail. */ if( ( ulStillAliveCounts[ 0 ] == 0 ) || ( ulStillAliveCounts[ 1 ] == 0 ) ) { /* One or both of the test tasks are no longer sending 'still alive' messages. */ pcStatusMessage = "FAIL\r\n"; /* ulStatus can be viewed (live) in the Keil watch window. */ ulStatus = pdFAIL; ( void ) ulStatus; } /**** print pcStatusMessage here. ****/ ( void ) pcStatusMessage; /* Reset the count of 'still alive' messages. */ memset( ulStillAliveCounts, 0x00, sizeof( ulStillAliveCounts ) ); break; default : /* Something unexpected happened. Delete this task so the error is apparent (no output will be displayed). */ prvDeleteMe(); break; } } }