summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2021-03-30 18:46:24 +1300
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2021-03-30 19:23:17 +1300
commitb507f65d4461757c577a9f90325967e92a895520 (patch)
treeb9131b800680676411aca084c52cd2155ae514d5
parent3d32c217586a48c709b762865a8abc46f9098455 (diff)
Support for native riscv64 coroutines.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4337
-rw-r--r--configure.ac3
-rw-r--r--coroutine/riscv64/Context.S87
-rw-r--r--coroutine/riscv64/Context.h45
3 files changed, 135 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 58aa35a..d78964f 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 0000000..cc4e872
--- /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 0000000..5ec0326
--- /dev/null
+++ b/coroutine/riscv64/Context.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#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)
+{
+}