diff --git a/include/fastcontext/riscv-ucontext.h b/include/fastcontext/riscv-ucontext.h new file mode 100644 index 000000000..cbeb3661f --- /dev/null +++ b/include/fastcontext/riscv-ucontext.h @@ -0,0 +1,40 @@ +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ +#include "qthread/common.h" + +#include +#include + +#include "qt_visibility.h" + +#define setcontext(u) qt_setmctxt(&(u)->mc) +#define getcontext(u) qt_getmctxt(&(u)->mc) +typedef struct mctxt mctxt_t; +typedef struct uctxt uctxt_t; + +struct mctxt { + /* Saved main processor registers. */ +#ifdef NEEDARMA64CONTEXT + uint64_t regs[32]; /* callee saves x0-x30, SP */ + uint64_t fpu_regs[32]; /* 32 64 bit FPU Registers */ +#else + uint32_t regs[16]; /* callee saves r0-r15 */ +#endif + char first; +}; + +struct uctxt { + struct { + void *ss_sp; + size_t ss_size; + } uc_stack; + + // sigset_t uc_sigmask; + mctxt_t mc; + struct uctxt *uc_link; /* unused */ +}; + +int INTERNAL qt_swapctxt(uctxt_t *, uctxt_t *); +void INTERNAL qt_makectxt(uctxt_t *, void (*)(void), int, ...); +int INTERNAL qt_getmctxt(mctxt_t *); +void INTERNAL qt_setmctxt(mctxt_t *); +/* vim:set expandtab: */ diff --git a/include/fastcontext/taskimpl.h b/include/fastcontext/taskimpl.h index ca0ff692d..9ad4dc061 100644 --- a/include/fastcontext/taskimpl.h +++ b/include/fastcontext/taskimpl.h @@ -1,3 +1,5 @@ +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ + #ifndef TASKIMPL_H #define TASKIMPL_H @@ -22,6 +24,11 @@ #define NEEDARMMAKECONTEXT #define NEEDSWAPCONTEXT #include "arm-ucontext.h" +#elif (QTHREAD_ASSEMBLY_ARCH == QTHREAD_ARM) +#include +#define NEEDRISCVMAKECONTEXT +#define NEEDSWAPCONTEXT +#include "riscv-ucontext.h" #elif (QTHREAD_ASSEMBLY_ARCH == QTHREAD_ARMV8_A64) #include #define NEEDARMA64MAKECONTEXT diff --git a/include/qt_atomics.h b/include/qt_atomics.h index 4a2a826ef..fea6f2072 100644 --- a/include/qt_atomics.h +++ b/include/qt_atomics.h @@ -1,3 +1,5 @@ +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ + #ifndef QT_ATOMICS_H #define QT_ATOMICS_H @@ -29,6 +31,9 @@ QTHREAD_ASSEMBLY_ARCH == QTHREAD_ARMV8_A64 #define SPINLOCK_BODY() \ do { __asm__ __volatile__("yield" ::: "memory"); } while (0) +#elif QTHREAD_ASSEMBLY_ARCH == QTHREAD_RISCV +#define SPINLOCK_BODY() \ + do { atomic_thread_fence(memory_order_acq_rel); } while (0) #elif QTHREAD_ASSEMBLY_ARCH == QTHREAD_POWERPC64 || \ QTHREAD_ASSEMBLY_ARCH == QTHREAD_POWERPC32 // For whatever reason the 29 (mdoio) version of this instruction performed diff --git a/include/qthread/common.h b/include/qthread/common.h index 12d73e622..5618f8ae9 100644 --- a/include/qthread/common.h +++ b/include/qthread/common.h @@ -4,6 +4,8 @@ * ------------------------------------------------------------------ */ +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ + #ifndef QTHREAD_COMMON_H #define QTHREAD_COMMON_H @@ -53,6 +55,8 @@ #define QTHREAD_ASSEMBLY_ARCH QTHREAD_ARM #elif defined(_ARCHPPC) #define QTHREAD_ASSEMBLY_ARCH QTHREAD_POWERPC32 +#elif defined(__riscv) +#define QTHREAD_ASSEMBLY_ARCH QTHREAD_RISCV #else #error "Unsupported architecture" #endif diff --git a/src/cacheline.c b/src/cacheline.c index 514d92bbd..676f7c019 100644 --- a/src/cacheline.c +++ b/src/cacheline.c @@ -1,3 +1,5 @@ +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ + #ifdef DEBUG_CPUID #include #endif @@ -14,6 +16,23 @@ enum vendor { AMD, Intel, Unknown }; static int cacheline_bytes = 0; #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#if defined(__riscv) + +#include + +// https://matrix89.github.io/writes/writes/experiments-in-riscv/ +// +static unsigned int cpuid() { + register unsigned int hart_id = 0; + __asm__ __volatile__("csrr %0, mhartid" : "=r" (hart_id) : : ); + return hart_id; +} + +static void figure_out_cacheline_size(void) { + cacheline_bytes = sysconf (_SC_LEVEL1_DCACHE_LINESIZE); +} + +#else #if ((QTHREAD_ASSEMBLY_ARCH == QTHREAD_IA32) || \ (QTHREAD_ASSEMBLY_ARCH == QTHREAD_AMD64)) && \ @@ -23,6 +42,8 @@ static void cpuid(unsigned int const op, unsigned int *ebx_ptr, unsigned int *ecx_ptr, unsigned int *edx_ptr) { + + #if (QTHREAD_ASSEMBLY_ARCH == QTHREAD_IA32) && defined(__PIC__) unsigned int eax, ebx, ecx, edx; unsigned int pic_ebx = 0; @@ -43,6 +64,7 @@ static void cpuid(unsigned int const op, : "=a"(*eax_ptr), "=b"(*ebx_ptr), "=c"(*ecx_ptr), "=d"(*edx_ptr) : "a"(op)); #endif /* if (QTHREAD_ASSEMBLY_ARCH == QTHREAD_IA32) && defined(__PIC__) */ + } static void cpuid4(int const cache, @@ -50,6 +72,7 @@ static void cpuid4(int const cache, unsigned int *ebx_ptr, unsigned int *ecx_ptr, unsigned int *edx_ptr) { + #if (QTHREAD_ASSEMBLY_ARCH == QTHREAD_IA32) && defined(__PIC__) unsigned int eax, ebx, ecx, edx; unsigned int pic_ebx = 0; @@ -339,6 +362,8 @@ static void figure_out_cacheline_size(void) { (QTHREAD_ASSEMBLY_ARCH == QTHREAD_POWERPC64) */ } +#endif + /* returns the cache line size */ int API_FUNC qthread_cacheline(void) { if (cacheline_bytes == 0) { diff --git a/src/fastcontext/asm.S b/src/fastcontext/asm.S index 5f3267882..ec562e126 100644 --- a/src/fastcontext/asm.S +++ b/src/fastcontext/asm.S @@ -1,4 +1,5 @@ #if 0 +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ /* Portions of this file are Copyright (c) 2005-2006 Russ Cox, MIT; see COPYRIGHT */ /* Portions of this file are Copyright Sandia National Laboratories */ #endif @@ -50,6 +51,10 @@ # define NEEDARMCONTEXT 1 # define SET qt_setmctxt # define GET qt_getmctxt +# elif (QTHREAD_ASSEMBLY_ARCH == QTHREAD_RISCV) +# define NEEDRISCVCONTEXT 1 +# define SET qt_setmctxt +# define GET qt_getmctxt # elif (QTHREAD_ASSEMBLY_ARCH == QTHREAD_ARMV8_A64) # define NEEDARMA64CONTEXT 1 # define SET qt_setmctxt @@ -636,6 +641,116 @@ SET: bx lr #endif +#ifdef NEEDRISCVCONTEXT +/* Register Usage: + * + * x1/ra - return address + * x2/sp - stack pointer + * x3/gp - global pointer + * x4/tp - thread pointer + * x5/t0 - temporary 0 + * x6/t1 - temporary 1 + * x7/t2 - temporary 2 + * x8/s0/fp - saved register 0 / frame pointer + * x9/s1 - saved register 0 + * x10/a0 - function argument 0 + * x11/a1 - function argument 1 + * x12/a2 - function argument 2 + * x13/a3 - function argument 3 + * x14/a4 - function argument 4 + * x15/a5 - function argument 5 + * x16/a6 - function argument 6 + * x17/a7 - function argument 7 + * x18/s2 - saved register 2 + * x19/s3 - saved register 3 + * x20/s4 - saved register 4 + * x21/s5 - saved register 5 + * x22/s6 - saved register 6 + * x22/s7 - saved register 7 + * x22/s8 - saved register 8 + * x22/s9 - saved register 9 + * x22/s10 - saved register 10 + * x22/s11 - saved register 11 + * x22/t3 - temporary 3 + * x22/t4 - temporary 4 + * x22/t5 - temporary 5 + * x22/t6 - temporary 6 + */ +.globl GET +.global GET +.type GET, %function +GET: + st a1, [a0,#8] _(/* ARG 1 */) + st a2, [a0,#12] _(/* ARG 2 */) + st a3, [a0,#16] _(/* ARG 3 */) + st a4, [a0,#20] _(/* ARG 4 */) + st a5, [a0,#24] _(/* ARG 5 */) + st a6, [a0,#28] _(/* ARG 8 */) + st a7, [a0,#32] _(/* ARG 7 */) + st s2 [a0,#36] _(/* saved registers */ + st s3 [a0,#40] _(/* saved registers */ + st s4 [a0,#44] _(/* saved registers */ + st s5 [a0,#48] _(/* saved registers */ + st s6 [a0,#52] _(/* saved registers */ + st s7 [a0,#56] _(/* saved registers */ + st s8 [a0,#60] _(/* saved registers */ + st s9 [a0,#64] _(/* saved registers */ + st s10 [a0,#68] _(/* saved registers */ + st s11 [a0,#72] _(/* saved registers */ + st t0 [a0,#76] _(/* saved registers */ + st t1 [a0,#80] _(/* saved registers */ + st t2 [a0,#84] _(/* saved registers */ + st t3 [a0,#88] _(/* saved registers */ + st t4 [a0,#92] _(/* saved registers */ + st t5 [a0,#96] _(/* saved registers */ + st t6 [a0,#100] _(/* saved registers */ + st sp, [a0,#104] _(/* SP */) + st ra, [a0,#108] _(/* LR */) + st gp, [a0,#112] + st tp, [a0,#116] + _(/*) store 1 as a0-to-restore */) + mov a1, #1 + st a1, [a0] _(/* arg 1 / RET 1 */) + _(/*) return 0 */) + mov a0, #0 + ret + +.globl SET +.global SET +.type SET, %function +SET: + ld a1, [a0,#4] _(/* ARG 1 */) + ld a2, [a0,#8] _(/* ARG 2 */) + ld a3, [a0,#12] _(/* ARG 3 */) + ld a4, [a0,#16] _(/* ARG 4 */) + ld a5, [a0,#20] _(/* ARG 5 */) + ld a6, [a0,#24] _(/* ARG 8 */) + ld a7, [a0,#28] _(/* ARG 7 */) + ld s2 [a0,#32] _(/* saved registers */ + ld s3 [a0,#36] _(/* saved registers */ + ld s4 [a0,#40] _(/* saved registers */ + ld s5 [a0,#44] _(/* saved registers */ + ld s6 [a0,#48] _(/* saved registers */ + ld s7 [a0,#52] _(/* saved registers */ + ld s8 [a0,#56] _(/* saved registers */ + ld s9 [a0,#60] _(/* saved registers */ + ld s10 [a0,#64] _(/* saved registers */ + ld s11 [a0,#68] _(/* saved registers */ + ld t0 [a0,#72] _(/* saved registers */ + ld t1 [a0,#76] _(/* saved registers */ + ld t2 [a0,#80] _(/* saved registers */ + ld t3 [a0,#84] _(/* saved registers */ + ld t4 [a0,#88] _(/* saved registers */ + ld t5 [a0,#92] _(/* saved registers */ + ld t6 [a0,#96] _(/* saved registers */ + ld sp, [a0,#100] _(/* SP */) + ld ra, [a0,#104] _(/* LR */) + ld gp, [a0,#108] + ld tp, [a0,#112] + ld a0, [a0] + ret +#endif + #if defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif diff --git a/src/syncvar.c b/src/syncvar.c index e446d2c24..a78e25894 100644 --- a/src/syncvar.c +++ b/src/syncvar.c @@ -1,4 +1,5 @@ /* System Headers */ +/* Portions of this file are Copyright (c) 2025 Tactical Computing Labs, LLC; see COPYING */ #include /* for INT_MAX */ #include @@ -80,6 +81,19 @@ extern unsigned int QTHREAD_LOCKING_STRIPES; #if (QTHREAD_ASSEMBLY_ARCH == QTHREAD_AMD64 || \ QTHREAD_ASSEMBLY_ARCH == QTHREAD_ARM || \ QTHREAD_ASSEMBLY_ARCH == QTHREAD_ARMV8_A64) +#define UNLOCK_THIS_UNMODIFIED_SYNCVAR(addr, unlocked) \ + do { \ + atomic_store_explicit( \ + (_Atomic uint64_t *)&(addr)->u.w, (unlocked), memory_order_relaxed); \ + } while (0) +#define UNLOCK_THIS_MODIFIED_SYNCVAR(addr, val, state) \ + do { \ + MACHINE_FENCE; \ + atomic_store_explicit((_Atomic uint64_t *)&(addr)->u.w, \ + BUILD_UNLOCKED_SYNCVAR(val, state), \ + memory_order_relaxed); \ + } while (0) +#elif (QTHREAD_RISCV) #define UNLOCK_THIS_UNMODIFIED_SYNCVAR(addr, unlocked) \ do { \ atomic_store_explicit( \