From b507f65d4461757c577a9f90325967e92a895520 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 30 Mar 2021 18:46:24 +1300 Subject: Support for native riscv64 coroutines. --- configure.ac | 3 ++ coroutine/riscv64/Context.S | 87 +++++++++++++++++++++++++++++++++++++++++++++ coroutine/riscv64/Context.h | 45 +++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 coroutine/riscv64/Context.S create mode 100644 coroutine/riscv64/Context.h diff --git a/configure.ac b/configure.ac index 58aa35a9da..d78964f63b 100644 --- a/configure.ac +++ b/configure.ac @@ -2488,6 +2488,9 @@ AS_CASE([$coroutine_type], [yes|''], [ [powerpc64le-linux*], [ coroutine_type=ppc64le ], + [riscv64-linux*], [ + rb_cv_coroutine=riscv64 + ], [x86_64-openbsd*], [ coroutine_type=amd64 ], diff --git a/coroutine/riscv64/Context.S b/coroutine/riscv64/Context.S new file mode 100644 index 0000000000..cc4e872f84 --- /dev/null +++ b/coroutine/riscv64/Context.S @@ -0,0 +1,87 @@ +#define TOKEN_PASTE(x,y) x##y +#define PREFIXED_SYMBOL(prefix,name) TOKEN_PASTE(prefix,name) + +.text +.align 2 + +.global PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer) +PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer): + + # Make space on the stack for caller registers + addi sp, sp, -0xd0 + + # Save caller registers + sd s0, 0x00(sp) + sd s1, 0x08(sp) + sd s2, 0x10(sp) + sd s3, 0x18(sp) + sd s4, 0x20(sp) + sd s5, 0x28(sp) + sd s6, 0x30(sp) + sd s7, 0x38(sp) + sd s8, 0x40(sp) + sd s9, 0x48(sp) + sd s10, 0x50(sp) + sd s11, 0x58(sp) + fsd fs0, 0x60(sp) + fsd fs1, 0x68(sp) + fsd fs2, 0x70(sp) + fsd fs3, 0x78(sp) + fsd fs4, 0x80(sp) + fsd fs5, 0x88(sp) + fsd fs6, 0x90(sp) + fsd fs7, 0x98(sp) + fsd fs8, 0xa0(sp) + fsd fs9, 0xa8(sp) + fsd fs10, 0xb0(sp) + fsd fs11, 0xb8(sp) + + # Save return address + sd ra, 0xc0(sp) + + # Save stack pointer to a0 (first argument) + mv a2, sp + sd a2, (a0) + + # Load stack pointer from a1 (second argument) + ld a3, (a1) + mv sp, a3 + + # Restore caller registers + ld s0, 0x00(sp) + ld s1, 0x08(sp) + ld s2, 0x10(sp) + ld s3, 0x18(sp) + ld s4, 0x20(sp) + ld s5, 0x28(sp) + ld s6, 0x30(sp) + ld s7, 0x38(sp) + ld s8, 0x40(sp) + ld s9, 0x48(sp) + ld s10, 0x50(sp) + ld s11, 0x58(sp) + fld fs0, 0x60(sp) + fld fs1, 0x68(sp) + fld fs2, 0x70(sp) + fld fs3, 0x78(sp) + fld fs4, 0x80(sp) + fld fs5, 0x88(sp) + fld fs6, 0x90(sp) + fld fs7, 0x98(sp) + fld fs8, 0xa0(sp) + fld fs9, 0xa8(sp) + fld fs10, 0xb0(sp) + fld fs11, 0xb8(sp) + + # Load return address + ld ra, 0xc0(sp) + + # Pop stack frame + addi sp, sp, 0xd0 + + # Jump to return address + ret + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/coroutine/riscv64/Context.h b/coroutine/riscv64/Context.h new file mode 100644 index 0000000000..5ec03266b2 --- /dev/null +++ b/coroutine/riscv64/Context.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include + +#define COROUTINE __attribute__((noreturn)) void + +enum {COROUTINE_REGISTERS = 0xd0 / 8}; + +struct coroutine_context +{ + void **stack_pointer; +}; + +typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self); + +static inline void coroutine_initialize_main(struct coroutine_context * context) { + context->stack_pointer = NULL; +} + +static inline void coroutine_initialize( + struct coroutine_context *context, + coroutine_start start, + void *stack, + size_t size +) { + assert(start && stack && size >= 1024); + + // Stack grows down. Force 16-byte alignment. + char * top = (char*)stack + size; + context->stack_pointer = (void**)((uintptr_t)top & ~0xF); + + context->stack_pointer -= COROUTINE_REGISTERS; + memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS); + + context->stack_pointer[0xc0 / 8] = (void*)start; +} + +struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target); + +static inline void coroutine_destroy(struct coroutine_context * context) +{ +} -- cgit v1.2.3