81 lines
2.6 KiB
C
81 lines
2.6 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
|
|
#define UTASK_ARCH_INCLUDED 1
|
|
|
|
// 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;
|
|
|
|
#define UTASK_ARCH_SPECIFIC_INIT { 0, 0 }
|
|
|
|
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 + (task)->stack_size; \
|
|
__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(¤t_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_decl_stack(name, size) \
|
|
unsigned char __attribute__((aligned(4))) name[size]
|
|
|
|
#define utask_fixup_stack_len(len) ((len) & ~0x3)
|
|
|
|
#endif // !defined(UTASK_RISCV_H)
|