From 1ad20e03e5373fea8e6c94217894306fee50f9aa Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Mon, 8 Mar 2021 23:59:59 -0700 Subject: [PATCH] add riscv32 port --- README.md | 1 + arch/riscv32/defs.h | 55 +++++++++++++++++ arch/riscv32/getcontext.S | 45 ++++++++++++++ arch/riscv32/include/libucontext/bits.h | 48 +++++++++++++++ arch/riscv32/makecontext.c | 65 ++++++++++++++++++++ arch/riscv32/setcontext.S | 56 +++++++++++++++++ arch/riscv32/swapcontext.S | 81 +++++++++++++++++++++++++ arch/riscv32/trampoline.c | 3 + 8 files changed, 354 insertions(+) create mode 100644 arch/riscv32/defs.h create mode 100644 arch/riscv32/getcontext.S create mode 100644 arch/riscv32/include/libucontext/bits.h create mode 100644 arch/riscv32/makecontext.c create mode 100644 arch/riscv32/setcontext.S create mode 100644 arch/riscv32/swapcontext.S create mode 100644 arch/riscv32/trampoline.c diff --git a/README.md b/README.md index 66d9133..91d27ae 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ target to do it. | mips64 | ✓ | | ✓ | | | ppc | ✓ | ✓ | | | | ppc64 | ✓ | ✓ | | | +| riscv32 | ✓ | | ✓ | ✓ | | riscv64 | ✓ | | ✓ | ✓ | | s390x | ✓ | | ✓ | | | sh | ✓ | | ✓ | ✓ | diff --git a/arch/riscv32/defs.h b/arch/riscv32/defs.h new file mode 100644 index 0000000..3f73711 --- /dev/null +++ b/arch/riscv32/defs.h @@ -0,0 +1,55 @@ +#ifndef __ARCH_RISCV64_DEFS_H +#define __ARCH_RISCV64_DEFS_H + +#define REG_SZ (4) +#define MCONTEXT_GREGS (160) + +/* program counter is saved in x0 as well as x1, similar to mips */ +#ifndef REG_PC +#define REG_PC (0) +#endif + +#ifndef REG_RA +#define REG_RA (1) +#endif + +#ifndef REG_SP +#define REG_SP (2) +#endif + +#ifndef REG_S0 +#define REG_S0 (8) +#endif + +#define REG_S1 (9) + +#ifndef REG_A0 +#define REG_A0 (10) +#endif + +#define REG_A1 (11) +#define REG_A2 (12) +#define REG_A3 (13) +#define REG_A4 (14) +#define REG_A5 (15) +#define REG_A6 (16) +#define REG_A7 (17) +#define REG_S2 (18) +#define REG_S3 (19) +#define REG_S4 (20) +#define REG_S5 (21) +#define REG_S6 (22) +#define REG_S7 (23) +#define REG_S8 (24) +#define REG_S9 (25) +#define REG_S10 (26) +#define REG_S11 (27) + +#define PC_OFFSET REG_OFFSET(REG_PC) + +#define FETCH_LINKPTR(dest) \ + asm("mv %0, s1" : "=r" ((dest))) + +#include "common-defs.h" + +#endif diff --git a/arch/riscv32/getcontext.S b/arch/riscv32/getcontext.S new file mode 100644 index 0000000..888b6ab --- /dev/null +++ b/arch/riscv32/getcontext.S @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "defs.h" + +ALIAS(getcontext, libucontext_getcontext) +ALIAS(__getcontext, libucontext_getcontext) + +FUNC(libucontext_getcontext) + sw ra, REG_OFFSET(REG_PC)(a0) + sw ra, REG_OFFSET(REG_RA)(a0) + sw sp, REG_OFFSET(REG_SP)(a0) + + /* first saved register block */ + sw s0, REG_OFFSET(REG_S0)(a0) + sw s1, REG_OFFSET(REG_S1)(a0) + + /* return register block */ + sw a0, REG_OFFSET(REG_A0)(a0) + sw a1, REG_OFFSET(REG_A1)(a0) + + /* second saved register block */ + sw s2, REG_OFFSET(REG_S2)(a0) + sw s3, REG_OFFSET(REG_S3)(a0) + sw s4, REG_OFFSET(REG_S4)(a0) + sw s5, REG_OFFSET(REG_S5)(a0) + sw s6, REG_OFFSET(REG_S6)(a0) + sw s7, REG_OFFSET(REG_S7)(a0) + sw s8, REG_OFFSET(REG_S8)(a0) + sw s9, REG_OFFSET(REG_S9)(a0) + sw s10, REG_OFFSET(REG_S10)(a0) + sw s11, REG_OFFSET(REG_S11)(a0) + + /* done saving, return */ + ret +END(libucontext_getcontext) diff --git a/arch/riscv32/include/libucontext/bits.h b/arch/riscv32/include/libucontext/bits.h new file mode 100644 index 0000000..8d78676 --- /dev/null +++ b/arch/riscv32/include/libucontext/bits.h @@ -0,0 +1,48 @@ +#ifndef LIBUCONTEXT_BITS_H +#define LIBUCONTEXT_BITS_H + +typedef unsigned long libucontext_greg_t; +typedef unsigned long libucontext__riscv_mc_gp_state[32]; + +struct libucontext__riscv_mc_f_ext_state { + unsigned int __f[32]; + unsigned int __fcsr; +}; + +struct libucontext__riscv_mc_d_ext_state { + unsigned long long __f[32]; + unsigned int __fcsr; +}; + +struct libucontext__riscv_mc_q_ext_state { + unsigned long long __f[64] __attribute__((aligned(16))); + unsigned int __fcsr; + unsigned int __reserved[3]; +}; + +union libucontext__riscv_mc_fp_state { + struct libucontext__riscv_mc_f_ext_state __f; + struct libucontext__riscv_mc_d_ext_state __d; + struct libucontext__riscv_mc_q_ext_state __q; +}; + +typedef struct libucontext_mcontext { + libucontext__riscv_mc_gp_state __gregs; + union libucontext__riscv_mc_fp_state __fpregs; +} libucontext_mcontext_t; + +typedef struct { + void *ss_sp; + int ss_flags; + size_t ss_size; +} libucontext_stack_t; + +typedef struct libucontext_ucontext { + unsigned long uc_flags; + struct libucontext_ucontext *uc_link; + libucontext_stack_t uc_stack; + unsigned char __pad[128]; + libucontext_mcontext_t uc_mcontext; +} libucontext_ucontext_t; + +#endif diff --git a/arch/riscv32/makecontext.c b/arch/riscv32/makecontext.c new file mode 100644 index 0000000..044928f --- /dev/null +++ b/arch/riscv32/makecontext.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include "defs.h" +#include + + +extern void libucontext_trampoline(void); + + +void +libucontext_makecontext(libucontext_ucontext_t *ucp, void (*func)(void), int argc, ...) +{ + libucontext_greg_t *sp, *regp; + va_list va; + int i; + + /* set up and align the stack. */ + sp = (libucontext_greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); + sp -= argc < 8 ? 0 : argc - 8; + sp = (libucontext_greg_t *) (((uintptr_t) sp & -16L)); + + /* set up the ucontext structure */ + ucp->uc_mcontext.__gregs[REG_RA] = (libucontext_greg_t) libucontext_trampoline; + ucp->uc_mcontext.__gregs[REG_S0] = 0; + ucp->uc_mcontext.__gregs[REG_S1] = (libucontext_greg_t) ucp->uc_link; + ucp->uc_mcontext.__gregs[REG_SP] = (libucontext_greg_t) sp; + ucp->uc_mcontext.__gregs[REG_PC] = (libucontext_greg_t) func; + + va_start(va, argc); + + /* first 8 args go in $a0 through $a7. */ + regp = &(ucp->uc_mcontext.__gregs[REG_A0]); + + for (i = 0; (i < argc && i < 8); i++) + *regp++ = va_arg (va, libucontext_greg_t); + + /* remainder overflows into stack */ + for (; i < argc; i++) + *sp++ = va_arg (va, libucontext_greg_t); + + va_end(va); +} + +#ifdef EXPORT_UNPREFIXED +extern __typeof(libucontext_makecontext) makecontext __attribute__((weak, __alias__("libucontext_makecontext"))); +extern __typeof(libucontext_makecontext) __makecontext __attribute__((weak, __alias__("libucontext_makecontext"))); +#endif diff --git a/arch/riscv32/setcontext.S b/arch/riscv32/setcontext.S new file mode 100644 index 0000000..0672785 --- /dev/null +++ b/arch/riscv32/setcontext.S @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "defs.h" + +ALIAS(setcontext, libucontext_setcontext) +ALIAS(__setcontext, libucontext_setcontext) + +FUNC(libucontext_setcontext) + /* move $a0 to $t0 to avoid clobbering. */ + mv t0, a0 + + lw t1, PC_OFFSET(t0) + lw ra, REG_OFFSET(REG_RA)(t0) + lw sp, REG_OFFSET(REG_SP)(t0) + + /* first saved register block */ + lw s0, REG_OFFSET(REG_S0)(t0) + lw s1, REG_OFFSET(REG_S1)(t0) + + /* return register block */ + lw a0, REG_OFFSET(REG_A0)(t0) + lw a1, REG_OFFSET(REG_A1)(t0) + + /* argument register block */ + lw a2, REG_OFFSET(REG_A2)(t0) + lw a3, REG_OFFSET(REG_A3)(t0) + lw a4, REG_OFFSET(REG_A4)(t0) + lw a5, REG_OFFSET(REG_A5)(t0) + lw a6, REG_OFFSET(REG_A6)(t0) + lw a7, REG_OFFSET(REG_A7)(t0) + + /* second saved register block */ + lw s2, REG_OFFSET(REG_S2)(t0) + lw s3, REG_OFFSET(REG_S3)(t0) + lw s4, REG_OFFSET(REG_S4)(t0) + lw s5, REG_OFFSET(REG_S5)(t0) + lw s6, REG_OFFSET(REG_S6)(t0) + lw s7, REG_OFFSET(REG_S7)(t0) + lw s8, REG_OFFSET(REG_S8)(t0) + lw s9, REG_OFFSET(REG_S9)(t0) + lw s10, REG_OFFSET(REG_S10)(t0) + lw s11, REG_OFFSET(REG_S11)(t0) + + /* done restoring, jump to new pc in S1 */ + jr t1 +END(libucontext_setcontext) diff --git a/arch/riscv32/swapcontext.S b/arch/riscv32/swapcontext.S new file mode 100644 index 0000000..a4c7138 --- /dev/null +++ b/arch/riscv32/swapcontext.S @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Ariadne Conill + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "defs.h" + +ALIAS(swapcontext, libucontext_swapcontext) +ALIAS(__swapcontext, libucontext_swapcontext) + +FUNC(libucontext_swapcontext) + /* move $a1 to $t0 to avoid clobbering. */ + mv t0, a1 + + sw ra, REG_OFFSET(REG_PC)(a0) + sw ra, REG_OFFSET(REG_RA)(a0) + sw sp, REG_OFFSET(REG_SP)(a0) + + /* first saved register block */ + sw s0, REG_OFFSET(REG_S0)(a0) + sw s1, REG_OFFSET(REG_S1)(a0) + + /* return register block */ + sw a0, REG_OFFSET(REG_A0)(a0) + sw a1, REG_OFFSET(REG_A1)(a0) + + /* second saved register block */ + sw s2, REG_OFFSET(REG_S2)(a0) + sw s3, REG_OFFSET(REG_S3)(a0) + sw s4, REG_OFFSET(REG_S4)(a0) + sw s5, REG_OFFSET(REG_S5)(a0) + sw s6, REG_OFFSET(REG_S6)(a0) + sw s7, REG_OFFSET(REG_S7)(a0) + sw s8, REG_OFFSET(REG_S8)(a0) + sw s9, REG_OFFSET(REG_S9)(a0) + sw s10, REG_OFFSET(REG_S10)(a0) + sw s11, REG_OFFSET(REG_S11)(a0) + + /* restore the other context from $t0. */ + lw t1, REG_OFFSET(REG_PC)(t0) + lw ra, REG_OFFSET(REG_RA)(t0) + lw sp, REG_OFFSET(REG_SP)(t0) + + /* first saved register block */ + lw s0, REG_OFFSET(REG_S0)(t0) + lw s1, REG_OFFSET(REG_S1)(t0) + + /* return register block */ + lw a0, REG_OFFSET(REG_A0)(t0) + lw a1, REG_OFFSET(REG_A1)(t0) + + /* argument register block */ + lw a2, REG_OFFSET(REG_A2)(t0) + lw a3, REG_OFFSET(REG_A3)(t0) + lw a4, REG_OFFSET(REG_A4)(t0) + lw a5, REG_OFFSET(REG_A5)(t0) + lw a6, REG_OFFSET(REG_A6)(t0) + lw a7, REG_OFFSET(REG_A7)(t0) + + /* second saved register block */ + lw s2, REG_OFFSET(REG_S2)(t0) + lw s3, REG_OFFSET(REG_S3)(t0) + lw s4, REG_OFFSET(REG_S4)(t0) + lw s5, REG_OFFSET(REG_S5)(t0) + lw s6, REG_OFFSET(REG_S6)(t0) + lw s7, REG_OFFSET(REG_S7)(t0) + lw s8, REG_OFFSET(REG_S8)(t0) + lw s9, REG_OFFSET(REG_S9)(t0) + lw s10, REG_OFFSET(REG_S10)(t0) + lw s11, REG_OFFSET(REG_S11)(t0) + + /* done swapping, jump to new PC in S1 */ + jr t1 +END(libucontext_swapcontext) diff --git a/arch/riscv32/trampoline.c b/arch/riscv32/trampoline.c new file mode 100644 index 0000000..699a050 --- /dev/null +++ b/arch/riscv32/trampoline.c @@ -0,0 +1,3 @@ +#include "defs.h" +#include +#include "common-trampoline.c"