From 2e4a31287705d8437cddd109c12b7e11825192bc Mon Sep 17 00:00:00 2001 From: johannst Date: Wed, 9 Jun 2021 23:05:05 +0200 Subject: added riscv64 --- Makefile | 14 +++++++++ README.md | 4 +++ lib/Makefile | 4 ++- lib/arch/api.h | 2 ++ lib/arch/riscv64/README.md | 12 ++++++++ lib/arch/riscv64/init_stack.cc | 39 +++++++++++++++++++++++++ lib/arch/riscv64/thread_create.s | 19 ++++++++++++ lib/arch/riscv64/yield.s | 63 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 lib/arch/riscv64/README.md create mode 100644 lib/arch/riscv64/init_stack.cc create mode 100644 lib/arch/riscv64/thread_create.s create mode 100644 lib/arch/riscv64/yield.s diff --git a/Makefile b/Makefile index 5c110ec..57bfb22 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,8 @@ ifeq ($(ARCH),arm64) PREFIX := aarch64-linux-gnu- else ifeq ($(ARCH),arm) PREFIX := arm-linux-gnueabi- +else ifeq ($(ARCH),riscv64) +PREFIX := riscv64-linux-gnu- endif CXX := $(PREFIX)g++ @@ -35,6 +37,11 @@ else ifeq ($(ARCH),arm) -L /usr/arm-linux-gnueabi \ -E LD_LIBRARY_PATH=/usr/arm-linux-gnueabi/lib \ $< +else ifeq ($(ARCH),riscv64) + qemu-riscv64 \ + -L /usr/riscv64-linux-gnu \ + -E LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib \ + $< else $< endif @@ -54,6 +61,13 @@ else ifeq ($(ARCH),arm) -g 1234 \ $< & gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' $< +else ifeq ($(ARCH),riscv64) + qemu-riscv64 \ + -L /usr/riscv64-linux-gnu \ + -E LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib \ + -g 1234 \ + $< & + gdb-multiarch -ex 'target remote :1234' -ex 'b main' -ex 'c' $< else which cgdb && cgdb --ex 'start' $< \ || gdb --ex 'start' $< diff --git a/README.md b/README.md index e7ec89d..ac73b38 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,10 @@ The `armv7a` demo can be run as ```bash make ARCH=arm demo1 ``` +The `riscv64` demo can be run as +```bash +make ARCH=riscv64 demo1 +``` > Before starting to compile & run for a different architecture the the current > build artifacts should be removed via `make clean`. diff --git a/lib/Makefile b/lib/Makefile index ab51aa8..6171ac2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Johannes Stoelp +# Copyright (c) 2021 Johannes Stoelp ARCH ?= x86_64 @@ -8,6 +8,8 @@ else ifeq ($(ARCH),arm64) PREFIX := aarch64-linux-gnu- else ifeq ($(ARCH),arm) PREFIX := arm-linux-gnueabi- +else ifeq ($(ARCH),riscv64) +PREFIX := riscv64-linux-gnu- else $(error Unsupported architecture ARCH=$(ARCH)) endif diff --git a/lib/arch/api.h b/lib/arch/api.h index 3dd5c92..1b421cb 100644 --- a/lib/arch/api.h +++ b/lib/arch/api.h @@ -12,6 +12,8 @@ static_assert(false, "Matcha Threads only supported on Linux!"); // fall-through: arm64 support #elif defined(__arm__) // fall-through: armv7 support +#elif defined(__riscv) && __riscv_xlen == 64 +// fall-through: riscv64 support #else static_assert(false, "Unsupported architecture!"); #endif diff --git a/lib/arch/riscv64/README.md b/lib/arch/riscv64/README.md new file mode 100644 index 0000000..517ddb2 --- /dev/null +++ b/lib/arch/riscv64/README.md @@ -0,0 +1,12 @@ +# riscv64 (RISC-V ELF) +Provide an implementation of the platform specific API as required in +[`api.h`](../api.h) according to the `RISC-V ELF ABI`. + +## Notes: RISC-V ABI +- Integer/pointer arguments via `x10 - x17` +- Integer/pointer return values via `x10` - `x11` +- Callee saved registers `x2`, `x8` - `x9`, `x18` - `x27`, `f8` - `f9`, `f18` - `f27` + +## References +- [RISC-V ABI](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md) +- [RISC-V asm manual](https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md) diff --git a/lib/arch/riscv64/init_stack.cc b/lib/arch/riscv64/init_stack.cc new file mode 100644 index 0000000..94dab1c --- /dev/null +++ b/lib/arch/riscv64/init_stack.cc @@ -0,0 +1,39 @@ +/* Copyright (c) 2021 Johannes Stoelp */ + +#include +#include // uintN_t + +extern "C" void thread_create(); + +void* init_stack(void* stack_ptr, void (*entry)(void*), const void* ctx) { + static_assert(sizeof(uint64_t) == sizeof(std::uintptr_t), "Pointer must be 64bit!"); + + // Setup initial stack frame which will be popped when yielding + // first time into the thread. + // Basic idea is to yield into Thread::entry() function which will + // then call the user function. + + uint64_t* stack = static_cast(stack_ptr); + // Arguments for `thread_create`. + *(--stack) = reinterpret_cast(ctx); + *(--stack) = reinterpret_cast(entry); + + // Yield epilogue. + *(--stack) = reinterpret_cast(thread_create); // Return address (ra) + + // Callee saved registers. + *(--stack) = static_cast(0); // x8 + *(--stack) = static_cast(0); // x9 + *(--stack) = static_cast(0); // x18 + *(--stack) = static_cast(0); // x19 + *(--stack) = static_cast(0); // x20 + *(--stack) = static_cast(0); // x21 + *(--stack) = static_cast(0); // x22 + *(--stack) = static_cast(0); // x23 + *(--stack) = static_cast(0); // x24 + *(--stack) = static_cast(0); // x25 + *(--stack) = static_cast(0); // x26 + *(--stack) = static_cast(0); // x27 + + return static_cast(stack); +} diff --git a/lib/arch/riscv64/thread_create.s b/lib/arch/riscv64/thread_create.s new file mode 100644 index 0000000..68c09cd --- /dev/null +++ b/lib/arch/riscv64/thread_create.s @@ -0,0 +1,19 @@ +# Copyright (c) 2021 Johannes Stoelp + + .section .text, "ax", @progbits + + # extern "C" void thread_create(); + .global thread_create + .type thread_create, @function +thread_create: + .cfi_startproc + ld a0, 8(sp) + ld x5, 0(sp) + + jalr x5 + + # FIXME: no return from thread after user fn finished. +1: + j 1b + .cfi_endproc + .size thread_create, .-thread_create diff --git a/lib/arch/riscv64/yield.s b/lib/arch/riscv64/yield.s new file mode 100644 index 0000000..985cb52 --- /dev/null +++ b/lib/arch/riscv64/yield.s @@ -0,0 +1,63 @@ +# Copyright (c) 2021 Johannes Stoelp + + .macro push reg + addi sp, sp, -8 + sd \reg, 0(sp) + .endm + + .macro pop reg + ld \reg, 0(sp) + addi sp, sp, 8 + .endm + + .section .text, "ax", @progbits + + # extern "C" void yield(const void* new_stack, void** old_stack); + # ^^^^^^^^^ ^^^^^^^^^ + # a0 (x10) a1 (x11) + .global yield + .type yield, @function +yield: + .cfi_startproc + # save return address + push ra + + # push callee saved registers + push x8 + push x9 + push x18 + push x19 + push x20 + push x21 + push x22 + push x23 + push x24 + push x25 + push x26 + push x27 + + # arg0: a0 holds new stack + # arg1: a1 holds addr to location current stack must be saved + sd sp, 0(a1) # save current stack ptr + mv sp, a0 # switch to new stack ptr + + # pop callee saved registers + pop x27 + pop x26 + pop x25 + pop x24 + pop x23 + pop x22 + pop x21 + pop x20 + pop x19 + pop x18 + pop x9 + pop x8 + + # restore return address + pop ra + + ret + .cfi_endproc + .size yield, .-yield -- cgit v1.2.3