utask/inc/utask_riscv.h

73 lines
2.4 KiB
C

// intellectual property is bullshit bgdc
#ifndef UTASK_RISCV_H
#define UTASK_RISCV_H
#ifndef IN_UTASK_H
# error "Do not use utask_riscv.h by itself. Instead, include utask.h"
#endif
// To get the fastest possible context switches, this implementation uses a
// special "micro-longjmp". Normally, setjmp/longjmp saves and restores an
// entire context. This isn't really necessary, though. By declaring all the
// normally callee-saved registers as clobbers, we can simply tell the compiler
// that we WON'T save anything, and it's forced to arrange for these values
// to be saved. Because it probably does not have the full complement of saved
// registers in flight at this moment, it is going to emit significantly less
// memory shuffling than we would have to with no knowledge of its register
// allocations.
//
// We're also floating point safe without needing to reserve space for all
// those floating-point registers even when they're unused.
struct utask_arch_specific
{
uintptr_t pc;
uintptr_t sp;
};
extern struct utask_arch_specific utask_ujb;
#define UTASK_ARCH_SPECIFIC_DEFS \
struct utask_arch_specific __attribute__((used)) utask_ujb;
void utask_riscv_start(uintptr_t arg, void * task, void * tas);
void utask_riscv_continue(void * tas);
void utask_riscv_yield(void * tas);
#define utask_start(task) do { \
(task)->_arch.sp = (uintptr_t) (task)->stack_top; \
__sync_synchronize(); \
utask_riscv_start((task)->_arg, (task), &(task)->_arch); \
asm volatile("" ::: "memory", "cc", \
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
"s8", "s9", "s10", "s11", \
"fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", \
"fs8", "fs9", "fs10", "fs11" \
); \
} while (0)
#define utask_continue(task) do { \
__sync_synchronize(); \
utask_riscv_continue(&(task)->_arch); \
asm volatile("" ::: "memory", "cc", \
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
"s8", "s9", "s10", "s11", \
"fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", \
"fs8", "fs9", "fs10", "fs11" \
); \
} while (0)
#define utask_yield() do { \
__sync_synchronize(); \
utask_riscv_yield(&current_task->_arch); \
asm volatile("" ::: "memory", "cc", \
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
"s8", "s9", "s10", "s11", \
"fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", \
"fs8", "fs9", "fs10", "fs11" \
); \
} while (0)
#endif // !defined(UTASK_RISCV_H)