rt 0.19.0

A real-time operating system capable of full preemption
Documentation
#include <rt/arch/dcb.h>
#include <rt/arch/mpu.h>
#include <rt/arch/nvic.h>
#include <rt/arch/scb.h>
#include <rt/arch/semihosting.h>
#include <rt/arch/syscall.h>
#include <rt/arch/systick.h>

#include <rt/log.h>
#include <rt/panic.h>
#include <rt/stack.h>
#include <rt/start.h>
#include <rt/tick.h>
#include <rt/trap.h>

static RT_STACK(stack, 512);

extern char __rx_region__[], __rx_region_size__[];
extern char __priv_rw_region__[], __priv_rw_region_size__[];
extern char __rw_region__[], __rw_region_size__[];

void start(void);

__attribute__((noreturn)) void rt_panic(const char *msg)
{
    semihosting_write0(msg);
    semihosting_write0("\n");
    semihosting_exception(ADP_STOPPED_OS_SPECIFIC);
}

__attribute__((noreturn)) void rt_trap(void)
{
    semihosting_exit(0);
}

__attribute__((noreturn)) static void nmi_handler(void)
{
    semihosting_write0("nmi\n");
    semihosting_exception(ADP_STOPPED_FIQ);
}

__attribute__((noreturn)) static void hardfault_handler(void)
{
    semihosting_write0("hardfault\n");
    semihosting_exception(ADP_STOPPED_INTERNAL_ERROR);
}

__attribute__((noreturn)) static void memmanagefault_handler(void)
{
    semihosting_write0("memmanagefault\n");
    semihosting_exception(ADP_STOPPED_ADDRESS_EXCEPTION);
}

__attribute__((noreturn)) static void busfault_handler(void)
{
    semihosting_write0("busfault\n");
    semihosting_exception(ADP_STOPPED_DATA_ABORT);
}

__attribute__((noreturn)) static void usagefault_handler(void)
{
    semihosting_write0("usagefault\n");
    semihosting_exception(ADP_STOPPED_UNDEFINED_INSTR);
}

__attribute__((noreturn)) static void debugmonitor_handler(void)
{
    semihosting_write0("debugmonitor\n");
    semihosting_exception(ADP_STOPPED_BREAKPOINT);
}

__attribute__((noreturn)) static void spurious_interrupt_handler(void)
{
    semihosting_write0("spurious interrupt\n");
    semihosting_exception(ADP_STOPPED_IRQ);
}

__attribute__((aligned(256), section(".vector")))
const struct nvic_vector vector = {
    .sp_init = &stack[sizeof stack],
    .reset = start,
    .nmi = nmi_handler,
    .hardfault = hardfault_handler,
    .memmanagefault = memmanagefault_handler,
    .busfault = busfault_handler,
    .usagefault = usagefault_handler,
    .svcall = rt_svcall_handler,
    .debugmonitor = debugmonitor_handler,
    .pendsv = rt_pendsv_handler,
    .systick = rt_tick_advance,
    .interrupt_handlers =
        {
            [0 ... 239] = spurious_interrupt_handler,
        },
};

void init(void);
void init(void)
{
    SCB->cpacr |= SCB_CPACR_ENABLE_FPU;

    // Configure static MPU regions (regions 0-3, task regions use 4-7)
    // Region 0: Code + RO data (execute, read-only)
    rt_mpu_region_set(0, (uintptr_t)__rx_region__, (size_t)__rx_region_size__,
                      RT_MPU_ATTR_RO | RT_MPU_ATTR_CACHED_WB_RWALLOC |
                          RT_MPU_ATTR_ENABLE);

    // Region 1: Privileged RW (kernel stack + data)
    rt_mpu_region_set(1, (uintptr_t)__priv_rw_region__,
                      (size_t)__priv_rw_region_size__,
                      RT_MPU_ATTR_RW_PRIV | RT_MPU_ATTR_XN |
                          RT_MPU_ATTR_CACHED_WB_RWALLOC | RT_MPU_ATTR_ENABLE);

    // Region 2: Privileged RW for the PPB.
    // NOTE: The PPB always has strongly-ordered semantics, but for clarity we
    // specify it explicitly here.
    rt_mpu_region_set(2, 0xE0000000UL, 0x20000000UL,
                      RT_MPU_ATTR_RW_PRIV | RT_MPU_ATTR_XN |
                          RT_MPU_ATTR_STRONGLY_ORDERED | RT_MPU_ATTR_ENABLE);

    // Region 3: General RW data (.data, .bss)
    rt_mpu_region_set(3, (uintptr_t)__rw_region__, (size_t)__rw_region_size__,
                      RT_MPU_ATTR_RW | RT_MPU_ATTR_XN |
                          RT_MPU_ATTR_CACHED_WB_RWALLOC | RT_MPU_ATTR_ENABLE);

    rt_mpu_enable();

    SCB->shpr2.svcall = NVIC_PRIORITY_LOWEST;
    SCB->shpr3.pendsv = NVIC_PRIORITY_LOWEST;
    SCB->shpr3.systick = SCB->shpr2.svcall - 1;

    // Enable fault handlers on v7-M
#if !RT_ARM_V6M
    SCB->shcsr |= (SCB_SHCSR_USAGEFAULTENA | SCB_SHCSR_BUSFAULTENA |
                   SCB_SHCSR_MEMFAULTENA);
    DCB->demcr |= DCB_DEMCR_TRCENA | DCB_DEMCR_MON_EN;
#endif

    // Set vector table base to our vector table
    SCB->vtor = &vector;

    // Configure SysTick to 1kHz assuming a 25MHz sysclock.
    SYSTICK->rvr = 25000U - 1U;
    SYSTICK->cvr = 0;
    SYSTICK->csr =
        SYSTICK_CSR_CLKSOURCE | SYSTICK_CSR_TICKINT | SYSTICK_CSR_ENABLE;
}

#if RT_LOG_ENABLE
// Provide rt/log.h stubs so the build succeeds.
void rt_logf(const char *format, ...)
{
    (void)format;
}

void rt_log_flush(void)
{
}
#endif // RT_LOG_ENABLE