ares-openbsd/libco/riscv.c

151 行
3.7 KiB
C
Raw 通常表示 履歴

#define LIBCO_C
#include "libco.h"
#include "settings.h"
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local uint64_t co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
#if __riscv_xlen == 32
#define I_STORE "sw"
#define I_LOAD "lw"
#elif __riscv_xlen == 64
#define I_STORE "sd"
#define I_LOAD "ld"
#else
#error Unsupported RISC-V XLEN
#endif
#if !defined(__riscv_flen)
#define F_STORE "#"
#define F_LOAD "#"
#elif __riscv_flen == 32
#define F_STORE "fsw"
#define F_LOAD "flw"
#elif __riscv_flen == 64
#define F_STORE "fsd"
#define F_LOAD "fld"
#else
#error Unsupported RISC-V FLEN
#endif
__attribute__((naked))
static void co_swap(cothread_t active, cothread_t previous) {
__asm__(
I_STORE " ra, 0 *8(a1)\n"
I_STORE " sp, 1 *8(a1)\n"
I_STORE " s0, 2 *8(a1)\n"
I_STORE " s1, 3 *8(a1)\n"
I_STORE " s2, 4 *8(a1)\n"
I_STORE " s3, 5 *8(a1)\n"
I_STORE " s4, 6 *8(a1)\n"
I_STORE " s5, 7 *8(a1)\n"
I_STORE " s6, 8 *8(a1)\n"
I_STORE " s7, 9 *8(a1)\n"
I_STORE " s8, 10*8(a1)\n"
I_STORE " s9, 11*8(a1)\n"
I_STORE " s10, 12*8(a1)\n"
I_STORE " s11, 13*8(a1)\n"
F_STORE " fs0, 14*8(a1)\n"
F_STORE " fs1, 15*8(a1)\n"
F_STORE " fs2, 16*8(a1)\n"
F_STORE " fs3, 17*8(a1)\n"
F_STORE " fs4, 18*8(a1)\n"
F_STORE " fs5, 19*8(a1)\n"
F_STORE " fs6, 20*8(a1)\n"
F_STORE " fs7, 21*8(a1)\n"
F_STORE " fs8, 22*8(a1)\n"
F_STORE " fs9, 23*8(a1)\n"
F_STORE " fs10, 24*8(a1)\n"
F_STORE " fs11, 25*8(a1)\n"
I_LOAD " ra, 0 *8(a0)\n"
I_LOAD " sp, 1 *8(a0)\n"
I_LOAD " s0, 2 *8(a0)\n"
I_LOAD " s1, 3 *8(a0)\n"
I_LOAD " s2, 4 *8(a0)\n"
I_LOAD " s3, 5 *8(a0)\n"
I_LOAD " s4, 6 *8(a0)\n"
I_LOAD " s5, 7 *8(a0)\n"
I_LOAD " s6, 8 *8(a0)\n"
I_LOAD " s7, 9 *8(a0)\n"
I_LOAD " s8, 10*8(a0)\n"
I_LOAD " s9, 11*8(a0)\n"
I_LOAD " s10, 12*8(a0)\n"
I_LOAD " s11, 13*8(a0)\n"
F_LOAD " fs0, 14*8(a0)\n"
F_LOAD " fs1, 15*8(a0)\n"
F_LOAD " fs2, 16*8(a0)\n"
F_LOAD " fs3, 17*8(a0)\n"
F_LOAD " fs4, 18*8(a0)\n"
F_LOAD " fs5, 19*8(a0)\n"
F_LOAD " fs6, 20*8(a0)\n"
F_LOAD " fs7, 21*8(a0)\n"
F_LOAD " fs8, 22*8(a0)\n"
F_LOAD " fs9, 23*8(a0)\n"
F_LOAD " fs10, 24*8(a0)\n"
F_LOAD " fs11, 25*8(a0)\n"
"ret\n"
);
}
static void co_entrypoint(cothread_t handle) {
uint64_t* buffer = (uint64_t*)handle;
void (*entrypoint)(void) = (void (*)(void))(uintptr_t)buffer[3];
entrypoint();
abort(); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_derive(void* memory, unsigned int size, void (*entrypoint)(void)) {
uint64_t* handle;
if(!co_active_handle) co_active_handle = &co_active_buffer;
if(handle = (uint64_t*)memory) {
unsigned int offset = (size & ~15);
uint64_t* p = (uint64_t*)((uint8_t*)handle + offset);
*(uintptr_t*)&handle[0] = (uintptr_t)co_entrypoint; /* ra (return address) */
*(uintptr_t*)&handle[1] = (uintptr_t)p; /* sp (stack pointer) */
*(uintptr_t*)&handle[2] = (uintptr_t)p; /* s0 (frame pointer) */
*(uintptr_t*)&handle[3] = (uintptr_t)entrypoint; /* s1 (entry point) */
}
return handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
void* memory = malloc(size);
if(!memory) return (cothread_t)0;
return co_derive(memory, size, entrypoint);
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t handle) {
cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
int co_serializable() {
return 1;
}
#ifdef __cplusplus
}
#endif