rt 0.19.1

A real-time operating system capable of full preemption
Documentation
#include <gic.h>

#include <rt/arch/sysreg.h>

#include <rt/abort.h>
#include <rt/context.h>
#include <rt/cycle.h>
#include <rt/idle.h>
#include <rt/interrupt.h>
#include <rt/mpu.h>
#include <rt/syscall.h>
#include <rt/task.h>
#include <rt/tls.h>
#include <rt/trap.h>

#include <stddef.h>
#include <stdint.h>

struct context
{
    uint64_t cpacr, has_volatile;
    // Non-volatile GPRs.
    uint64_t x19, x20, x21, x22, x23, x24, x25, x26, x27, x28;
    // Volatile GPRs.
    uint64_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
        x15, x16, x17, x18, padding1;
    uint64_t fp, lr, pc, psr;
};

#define SPSR_EL1T 0x04

void *rt_context_init(uintptr_t fn, uintptr_t arg, void *stack,
                      size_t stack_size)
{
    void *const sp = (char *)stack + stack_size;
    struct context *ctx = sp;
    --ctx;
    ctx->cpacr = 0;
    ctx->has_volatile = 1;
    ctx->x0 = arg;
    ctx->x1 = fn;
    ctx->fp = 0;
    ctx->lr = 0;
    ctx->pc = (uint64_t)rt_task_entry;
    ctx->psr = SPSR_EL1T;
    return ctx;
}

__attribute__((noreturn, weak)) void rt_idle(void)
{
    rt_task_drop_privilege();
    for (;;)
    {
        __asm__("wfi" :::);
    }
}

__attribute__((noreturn, weak)) void rt_abort(void)
{
    for (;;)
    {
        __asm__("udf 0" :::);
    }
}

__attribute__((noreturn, weak)) void rt_trap(void)
{
    for (;;)
    {
        __asm__("brk 0" :::);
    }
}

#define SYSCALL_CLOBBERS                                                       \
    "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14",     \
        "x15", "x16", "x17", "x18", "x29", "x30"

/* The svc handler doesn't need to preserve volatile registers, so we declare
 * them as being clobbered. */
void rt_syscall_0(enum rt_syscall syscall)
{
    register enum rt_syscall x0 __asm__("x0") = syscall;
    __asm__ __volatile__("svc 0"
                         : "+r"(x0)
                         :
                         : "x1", "x2", "x3", SYSCALL_CLOBBERS, "memory");
}

void rt_syscall_1(enum rt_syscall syscall, uintptr_t arg0)
{
    register enum rt_syscall x0 __asm__("x0") = syscall;
    register uintptr_t x1 __asm__("x1") = arg0;
    __asm__ __volatile__("svc 0"
                         : "+r"(x0), "+r"(x1)
                         :
                         : "x2", "x3", SYSCALL_CLOBBERS, "memory");
}

void rt_syscall_2(enum rt_syscall syscall, uintptr_t arg0, uintptr_t arg1)
{
    register enum rt_syscall x0 __asm__("x0") = syscall;
    register uintptr_t x1 __asm__("x1") = arg0;
    register uintptr_t x2 __asm__("x2") = arg1;
    __asm__ __volatile__("svc 0"
                         : "+r"(x0), "+r"(x1), "+r"(x2)
                         :
                         : "x3", SYSCALL_CLOBBERS, "memory");
}

void rt_syscall_3(enum rt_syscall syscall, uintptr_t arg0, uintptr_t arg1,
                  uintptr_t arg2)
{
    register enum rt_syscall x0 __asm__("x0") = syscall;
    register uintptr_t x1 __asm__("x1") = arg0;
    register uintptr_t x2 __asm__("x2") = arg1;
    register uintptr_t x3 __asm__("x3") = arg2;
    __asm__ __volatile__("svc 0"
                         : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3)
                         :
                         : SYSCALL_CLOBBERS, "memory");
}

void rt_syscall_pend(void)
{
    gic_syscall_pend();
}

bool rt_interrupt_is_active(void)
{
    return tpidrro_el0() != 0;
}

void rt_task_drop_privilege(void)
{
    /* Clear spsr_el1 which corresponds to returning to EL0 with all condition
     * flags cleared and all interrupts unmasked. */
    uintptr_t elr;
    __asm__ __volatile__("dsb sy;"
                         "adr %[elr], 0f;"
                         "msr spsr_el1, xzr;"
                         "msr elr_el1, %[elr];"
                         "eret;"
                         "0:;"
                         : [elr] "=&r"(elr)
                         :
                         : "memory", "cc");
}

__attribute__((weak)) void rt_cycle_init(void)
{
#if RT_CYCLE_ENABLE
    pmcr_el0_set(PMCR_EL0_E | PMCR_EL0_C);
    pmcntenset_el0_set(PMCNTENSET_EL0_C);
    pmuserenr_el0_set(PMUSERENR_EL0_EN);
    __asm__("isb" :::);
#endif
}

__attribute__((weak)) uint32_t rt_cycle(void)
{
#if RT_CYCLE_ENABLE
    return (uint32_t)pmccntr_el0();
#else
    return 0;
#endif
}

void rt_tls_set(void *tls)
{
    tpidr_el0_set((uintptr_t)tls);
}