feat: publish FreeRTOS C FC08 card

This commit is contained in:
2026-07-19 16:36:03 +02:00
commit 2e82515c3b
199 changed files with 59703 additions and 0 deletions
+23
View File
@@ -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
+18
View File
@@ -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
+48
View File
@@ -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 );
}
+16
View File
@@ -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
+30
View File
@@ -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" );
}
}
+10
View File
@@ -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
+34
View File
@@ -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;
}
+250
View File
@@ -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 );
}