feat: publish FreeRTOS C FC08 card
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
.section .text
|
||||
.global _start
|
||||
.type _start, @function
|
||||
|
||||
_start:
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
/* Hazard3 init.S has already installed the bootstrap stack. */
|
||||
la a0, __bss_start
|
||||
la a1, __bss_end
|
||||
1:
|
||||
bgeu a0, a1, 2f
|
||||
sb zero, 0(a0)
|
||||
addi a0, a0, 1
|
||||
j 1b
|
||||
2:
|
||||
call main
|
||||
tail _exit
|
||||
|
||||
.size _start, .-_start
|
||||
@@ -0,0 +1,18 @@
|
||||
.section .text.hazard3_freertos_traps, "ax", @progbits
|
||||
|
||||
/*
|
||||
* Hazard3 init.S owns mtvec and exposes weak vector targets. Strong symbols
|
||||
* below route exceptions (including ecall/yield) and the machine timer IRQ to
|
||||
* the official FreeRTOS RISC-V trap handler.
|
||||
*/
|
||||
.global handle_exception
|
||||
.type handle_exception, @function
|
||||
handle_exception:
|
||||
j freertos_risc_v_trap_handler
|
||||
.size handle_exception, .-handle_exception
|
||||
|
||||
.global isr_machine_timer
|
||||
.type isr_machine_timer, @function
|
||||
isr_machine_timer:
|
||||
j freertos_risc_v_trap_handler
|
||||
.size isr_machine_timer, .-isr_machine_timer
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "lab_freertos.h"
|
||||
#include "lab_io.h"
|
||||
|
||||
/* Official heap_4.c uses this application-owned arena. */
|
||||
__attribute__( ( aligned( 16 ) ) ) uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
volatile uint32_t g_failure_code;
|
||||
|
||||
int lab_address_in_heap( const volatile void * address )
|
||||
{
|
||||
const uintptr_t value = ( uintptr_t ) address;
|
||||
const uintptr_t first = ( uintptr_t ) &ucHeap[ 0 ];
|
||||
const uintptr_t past_last = ( uintptr_t ) &ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
|
||||
return ( value >= first ) && ( value < past_last );
|
||||
}
|
||||
|
||||
void lab_heap_initialize( void )
|
||||
{
|
||||
void * probe = pvPortMalloc( 1U );
|
||||
|
||||
if( probe == NULL )
|
||||
{
|
||||
lab_fail( 0xA6000002UL );
|
||||
}
|
||||
vPortFree( probe );
|
||||
}
|
||||
|
||||
void lab_fail( uint32_t code )
|
||||
{
|
||||
g_failure_code = code;
|
||||
lab_puts( "FAIL\n" );
|
||||
lab_put_u32( code );
|
||||
lab_exit( code );
|
||||
}
|
||||
|
||||
void lab_assert_fail( const char * file, int line )
|
||||
{
|
||||
( void ) file;
|
||||
lab_fail( 0xA5000000UL | ( ( uint32_t ) line & 0xFFFFUL ) );
|
||||
}
|
||||
|
||||
void vApplicationMallocFailedHook( void )
|
||||
{
|
||||
lab_fail( 0xA6000001UL );
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef LAB_FREERTOS_H
|
||||
#define LAB_FREERTOS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
extern volatile uint32_t g_failure_code;
|
||||
|
||||
int lab_address_in_heap( const volatile void * address );
|
||||
void lab_heap_initialize( void );
|
||||
void lab_fail( uint32_t code ) __attribute__( ( noreturn ) );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lab_io.h"
|
||||
|
||||
#define H3_IO_BASE ( 0xC0000000UL )
|
||||
#define H3_IO_PRINT_CHAR ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x0UL ) ) )
|
||||
#define H3_IO_PRINT_U32 ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x4UL ) ) )
|
||||
#define H3_IO_EXIT ( *( ( volatile uint32_t * ) ( H3_IO_BASE + 0x8UL ) ) )
|
||||
|
||||
void lab_puts( const char * text )
|
||||
{
|
||||
while( *text != '\0' )
|
||||
{
|
||||
H3_IO_PRINT_CHAR = ( uint32_t ) ( unsigned char ) *text;
|
||||
++text;
|
||||
}
|
||||
}
|
||||
void lab_put_u32( uint32_t value )
|
||||
{
|
||||
H3_IO_PRINT_U32 = value;
|
||||
}
|
||||
|
||||
void lab_exit( uint32_t code )
|
||||
{
|
||||
H3_IO_EXIT = code;
|
||||
for( ; ; )
|
||||
{
|
||||
__asm volatile ( "wfi" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef LAB_IO_H
|
||||
#define LAB_IO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void lab_puts( const char * text );
|
||||
void lab_put_u32( uint32_t value );
|
||||
void lab_exit( uint32_t code ) __attribute__( ( noreturn ) );
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <stddef.h>
|
||||
|
||||
void * memcpy( void * destination, const void * source, size_t count )
|
||||
{
|
||||
unsigned char * out = ( unsigned char * ) destination;
|
||||
const unsigned char * in = ( const unsigned char * ) source;
|
||||
|
||||
for( size_t index = 0; index < count; ++index )
|
||||
{
|
||||
out[ index ] = in[ index ];
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
void * memset( void * destination, int value, size_t count )
|
||||
{
|
||||
unsigned char * out = ( unsigned char * ) destination;
|
||||
|
||||
for( size_t index = 0; index < count; ++index )
|
||||
{
|
||||
out[ index ] = ( unsigned char ) value;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
size_t strlen( const char * text )
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
while( text[ length ] != '\0' )
|
||||
{
|
||||
++length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
#include "lab_freertos.h"
|
||||
#include "lab_io.h"
|
||||
#include "task01_mutex.h"
|
||||
#include "task01_mutex_model.h"
|
||||
|
||||
#define FC08_ACTOR_MAIN 1U
|
||||
#define FC08_ACTOR_LOW 2U
|
||||
#define FC08_ACTOR_HIGH 3U
|
||||
#define FC08_ACTOR_MEDIUM 4U
|
||||
#define FC08_ACTOR_VERIFIER 5U
|
||||
|
||||
MutexExperiment g_fc08;
|
||||
MutexEvidence g_fc08_events[ FC08_EVENT_CAPACITY ];
|
||||
volatile uint32_t g_fc08_event_count;
|
||||
volatile uint32_t g_fc08_last_checkpoint;
|
||||
volatile uint32_t g_fc08_pass;
|
||||
|
||||
static uintptr_t read_sp( void )
|
||||
{
|
||||
uintptr_t value;
|
||||
__asm__ volatile( "mv %0, sp" : "=r"( value ) );
|
||||
return value;
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc08_checkpoint_committed( uint32_t point, const void * subject )
|
||||
{
|
||||
( void ) point;
|
||||
( void ) subject;
|
||||
__asm__ volatile( "" ::: "memory" );
|
||||
}
|
||||
|
||||
static void fc08_publish( uint32_t point,
|
||||
uint32_t actor,
|
||||
uint32_t value,
|
||||
const void * subject )
|
||||
{
|
||||
UBaseType_t critical_state;
|
||||
uint32_t index;
|
||||
MutexEvidence * event;
|
||||
|
||||
critical_state = taskENTER_CRITICAL_FROM_ISR();
|
||||
index = g_fc08_event_count;
|
||||
if( index >= FC08_EVENT_CAPACITY )
|
||||
{
|
||||
taskEXIT_CRITICAL_FROM_ISR( critical_state );
|
||||
lab_fail( 0xFC080001U );
|
||||
}
|
||||
event = &g_fc08_events[ index ];
|
||||
event->sequence = index + 1U;
|
||||
event->event = point;
|
||||
event->tick = ( uint32_t ) xTaskGetTickCount();
|
||||
event->actor = actor;
|
||||
event->value = value;
|
||||
__asm__ volatile( "" ::: "memory" );
|
||||
event->committed = 0xFC080000U | ( index + 1U );
|
||||
g_fc08_event_count = index + 1U;
|
||||
g_fc08_last_checkpoint = point;
|
||||
taskEXIT_CRITICAL_FROM_ISR( critical_state );
|
||||
fc08_checkpoint_committed( point, subject );
|
||||
}
|
||||
|
||||
static TaskHandle_t fc08_create_task( TaskFunction_t entry,
|
||||
const char * name,
|
||||
UBaseType_t priority )
|
||||
{
|
||||
TaskHandle_t handle = NULL;
|
||||
if( xTaskCreate( entry,
|
||||
name,
|
||||
FC08_TASK_STACK_WORDS,
|
||||
&g_fc08,
|
||||
priority,
|
||||
&handle ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC080100U + priority );
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc08_high_entry( void * context )
|
||||
{
|
||||
MutexExperiment * experiment = ( MutexExperiment * ) context;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC080201U );
|
||||
}
|
||||
experiment->high_sp = read_sp();
|
||||
fc08_publish( 3U, FC08_ACTOR_HIGH, FC08_HIGH_PRIORITY, experiment );
|
||||
if( xSemaphoreTake( experiment->mutex, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC080202U );
|
||||
}
|
||||
experiment->high_acquired = 1U;
|
||||
experiment->protected_value = 2U;
|
||||
fc08_publish( 7U, FC08_ACTOR_HIGH, experiment->protected_value, experiment );
|
||||
if( xSemaphoreGive( experiment->mutex ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC080203U );
|
||||
}
|
||||
experiment->high_done = 1U;
|
||||
experiment->high_handle = NULL;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC080204U );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc08_medium_entry( void * context )
|
||||
{
|
||||
MutexExperiment * experiment = ( MutexExperiment * ) context;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC080301U );
|
||||
}
|
||||
experiment->medium_sp = read_sp();
|
||||
experiment->medium_started = 1U;
|
||||
fc08_publish( 8U, FC08_ACTOR_MEDIUM, experiment->protected_value, experiment );
|
||||
experiment->medium_done = 1U;
|
||||
experiment->medium_handle = NULL;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC080302U );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc08_low_entry( void * context )
|
||||
{
|
||||
MutexExperiment * experiment = ( MutexExperiment * ) context;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC080401U );
|
||||
}
|
||||
experiment->low_sp = read_sp();
|
||||
if( xSemaphoreTake( experiment->mutex, 0U ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC080402U );
|
||||
}
|
||||
experiment->protected_value = 1U;
|
||||
fc08_publish( 2U, FC08_ACTOR_LOW, experiment->protected_value, experiment );
|
||||
|
||||
experiment->high_handle =
|
||||
fc08_create_task( fc08_high_entry, "high", FC08_HIGH_PRIORITY );
|
||||
|
||||
experiment->inherited_priority = uxTaskPriorityGet( NULL );
|
||||
experiment->holder_while_contended =
|
||||
xSemaphoreGetMutexHolder( experiment->mutex );
|
||||
fc08_publish( 4U,
|
||||
FC08_ACTOR_LOW,
|
||||
experiment->inherited_priority,
|
||||
experiment->holder_while_contended );
|
||||
|
||||
experiment->medium_handle =
|
||||
fc08_create_task( fc08_medium_entry, "medium", FC08_MEDIUM_PRIORITY );
|
||||
experiment->medium_state_while_inherited =
|
||||
eTaskGetState( experiment->medium_handle );
|
||||
experiment->medium_started_while_inherited = experiment->medium_started;
|
||||
fc08_publish( 5U,
|
||||
FC08_ACTOR_LOW,
|
||||
experiment->medium_started_while_inherited,
|
||||
experiment );
|
||||
fc08_publish( 6U, FC08_ACTOR_LOW, experiment->protected_value, experiment );
|
||||
if( xSemaphoreGive( experiment->mutex ) != pdPASS )
|
||||
{
|
||||
lab_fail( 0xFC080403U );
|
||||
}
|
||||
|
||||
experiment->restored_priority = uxTaskPriorityGet( NULL );
|
||||
fc08_publish( 9U,
|
||||
FC08_ACTOR_LOW,
|
||||
experiment->restored_priority,
|
||||
experiment );
|
||||
experiment->low_done = 1U;
|
||||
vTaskDelete( NULL );
|
||||
lab_fail( 0xFC080404U );
|
||||
}
|
||||
|
||||
__attribute__( ( noinline, used ) )
|
||||
void fc08_verifier_entry( void * context )
|
||||
{
|
||||
MutexExperiment * experiment = ( MutexExperiment * ) context;
|
||||
TickType_t started;
|
||||
|
||||
if( experiment == NULL )
|
||||
{
|
||||
lab_fail( 0xFC080501U );
|
||||
}
|
||||
started = xTaskGetTickCount();
|
||||
while( experiment->low_done == 0U ||
|
||||
experiment->high_done == 0U ||
|
||||
experiment->medium_done == 0U )
|
||||
{
|
||||
if( ( xTaskGetTickCount() - started ) > FC08_TIMEOUT_TICKS )
|
||||
{
|
||||
lab_fail( 0xFC080502U );
|
||||
}
|
||||
vTaskDelay( 1U );
|
||||
}
|
||||
|
||||
experiment->pass =
|
||||
experiment->inherited_priority == FC08_HIGH_PRIORITY &&
|
||||
experiment->restored_priority == FC08_LOW_PRIORITY &&
|
||||
experiment->holder_while_contended == experiment->low_handle &&
|
||||
experiment->medium_state_while_inherited == eReady &&
|
||||
experiment->medium_started_while_inherited == 0U &&
|
||||
experiment->high_acquired == 1U &&
|
||||
experiment->protected_value == 2U &&
|
||||
experiment->low_sp != experiment->high_sp &&
|
||||
experiment->low_sp != experiment->medium_sp &&
|
||||
g_fc08_event_count == 9U;
|
||||
g_fc08_pass = experiment->pass;
|
||||
fc08_publish( 10U, FC08_ACTOR_VERIFIER, experiment->pass, experiment );
|
||||
experiment->evidence_digest = fc08_digest( g_fc08_events,
|
||||
g_fc08_event_count );
|
||||
|
||||
if( experiment->pass == 0U ||
|
||||
fc08_order_is_valid( g_fc08_events, g_fc08_event_count ) == 0 )
|
||||
{
|
||||
lab_fail( 0xFC080503U );
|
||||
}
|
||||
lab_puts( "PASS FC08: mutex owner inherited priority and bounded inversion\n" );
|
||||
lab_put_u32( experiment->evidence_digest );
|
||||
lab_exit( 0U );
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
lab_heap_initialize();
|
||||
fc08_publish( 1U, FC08_ACTOR_MAIN, FC08_LOW_PRIORITY, &g_fc08 );
|
||||
g_fc08.mutex = xSemaphoreCreateMutex();
|
||||
if( g_fc08.mutex == NULL )
|
||||
{
|
||||
lab_fail( 0xFC080601U );
|
||||
}
|
||||
g_fc08.verifier_handle =
|
||||
fc08_create_task( fc08_verifier_entry,
|
||||
"verifier",
|
||||
FC08_VERIFIER_PRIORITY );
|
||||
g_fc08.low_handle =
|
||||
fc08_create_task( fc08_low_entry, "low", FC08_LOW_PRIORITY );
|
||||
vTaskStartScheduler();
|
||||
lab_fail( 0xFC080602U );
|
||||
}
|
||||
Reference in New Issue
Block a user