kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

riscv32.c (9283B)


      1 /*
      2  * lib/coro/riscv32.c -- RISC-V 32-bit (ILP32/ILP32F/ILP32D) implementations of
      3  *   setjmp / longjmp                       (<setjmp.h>)
      4  *   __kit_coro_ctx_init / __kit_coro_switch / trampoline   (<kit/coro.h>)
      5  *
      6  * Per-target context layout (matches xOS rv32 tick_coro_ctx):
      7  *
      8  *   regs[0]:     ra
      9  *   regs[1]:     sp
     10  *   regs[2..13]: s0-s11
     11  *   fp_regs[0..11]: fs0-fs11
     12  *
     13  * The fp_regs slots are always allocated (12 * 8 = 96 bytes at offset
     14  * 56) so the struct layout is constant regardless of the F/D extension.
     15  * The save/restore code is conditional on __riscv_flen:
     16  *   __riscv_flen == 64 -> fsd/fld (64-bit, fills slots fully)
     17  *   __riscv_flen == 32 -> fsw/flw (32-bit, packs into the low halves)
     18  *   else               -> no FP save/restore
     19  *
     20  * Field bytes = 14*4 + 12*8 = 152; sizeof = 160 after 16-byte align
     21  * tail padding. Fits in the 256-byte storage carved out by jmp_buf
     22  * and coro_ctx.
     23  *
     24  * SAVE_/RESTORE_ are C string-concat macros so the same byte sequence
     25  * is emitted in setjmp, longjmp, and __kit_coro_switch without duplication.
     26  */
     27 
     28 #include <kit/coro.h>
     29 #include <setjmp.h>
     30 #include <stddef.h>
     31 #include <stdint.h>
     32 
     33 struct __kit_riscv32_ctx {
     34   uintptr_t regs[14];
     35   uint64_t fp_regs[12];
     36 } __attribute__((aligned(16)));
     37 
     38 _Static_assert(sizeof(struct __kit_riscv32_ctx) == 160, "layout");
     39 _Static_assert(_Alignof(struct __kit_riscv32_ctx) == 16, "align");
     40 _Static_assert(offsetof(struct __kit_riscv32_ctx, fp_regs) == 56, "fp off");
     41 _Static_assert(sizeof(struct __kit_riscv32_ctx) <= sizeof(coro_ctx),
     42                "fits coro_ctx");
     43 _Static_assert(sizeof(struct __kit_riscv32_ctx) <= sizeof(jmp_buf),
     44                "fits jmp_buf");
     45 _Static_assert(_Alignof(coro_ctx) >= _Alignof(struct __kit_riscv32_ctx),
     46                "align coro_ctx");
     47 
     48 extern void __kit_coro_trampoline(void);
     49 
     50 void __kit_coro_ctx_init(coro_ctx* ctx, void* stack_base, size_t stack_len,
     51                          void (*entry)(uintptr_t)) {
     52   struct __kit_riscv32_ctx* c = (struct __kit_riscv32_ctx*)ctx;
     53 
     54   /* RISC-V stacks grow down; align top to 16. */
     55   uintptr_t top = (uintptr_t)stack_base + stack_len;
     56   top &= ~(uintptr_t)(CORO_STACK_ALIGN - 1);
     57 
     58   for (size_t i = 0; i < sizeof(*c) / sizeof(uintptr_t); ++i)
     59     ((uintptr_t*)c)[i] = 0;
     60 
     61   c->regs[0] = (uintptr_t)__kit_coro_trampoline; /* ra */
     62   c->regs[1] = top;                              /* sp */
     63   c->regs[2] = (uintptr_t)entry;                 /* s0 -- entry fn */
     64 }
     65 
     66 #define STR_(x) #x
     67 #define STR(x) STR_(x)
     68 #define SYM(n) STR(__USER_LABEL_PREFIX__) #n
     69 
     70 /* Integer save: ra, sp, s0-s11 into regs[0..13] at offsets 0..52. */
     71 #define SAVE_GPR(reg)   \
     72   "    sw ra,   0(" reg \
     73   ")\n"                 \
     74   "    sw sp,   4(" reg \
     75   ")\n"                 \
     76   "    sw s0,   8(" reg \
     77   ")\n"                 \
     78   "    sw s1,  12(" reg \
     79   ")\n"                 \
     80   "    sw s2,  16(" reg \
     81   ")\n"                 \
     82   "    sw s3,  20(" reg \
     83   ")\n"                 \
     84   "    sw s4,  24(" reg \
     85   ")\n"                 \
     86   "    sw s5,  28(" reg \
     87   ")\n"                 \
     88   "    sw s6,  32(" reg \
     89   ")\n"                 \
     90   "    sw s7,  36(" reg \
     91   ")\n"                 \
     92   "    sw s8,  40(" reg \
     93   ")\n"                 \
     94   "    sw s9,  44(" reg \
     95   ")\n"                 \
     96   "    sw s10, 48(" reg \
     97   ")\n"                 \
     98   "    sw s11, 52(" reg ")\n"
     99 
    100 #define RESTORE_GPR(reg) \
    101   "    lw ra,   0(" reg  \
    102   ")\n"                  \
    103   "    lw sp,   4(" reg  \
    104   ")\n"                  \
    105   "    lw s0,   8(" reg  \
    106   ")\n"                  \
    107   "    lw s1,  12(" reg  \
    108   ")\n"                  \
    109   "    lw s2,  16(" reg  \
    110   ")\n"                  \
    111   "    lw s3,  20(" reg  \
    112   ")\n"                  \
    113   "    lw s4,  24(" reg  \
    114   ")\n"                  \
    115   "    lw s5,  28(" reg  \
    116   ")\n"                  \
    117   "    lw s6,  32(" reg  \
    118   ")\n"                  \
    119   "    lw s7,  36(" reg  \
    120   ")\n"                  \
    121   "    lw s8,  40(" reg  \
    122   ")\n"                  \
    123   "    lw s9,  44(" reg  \
    124   ")\n"                  \
    125   "    lw s10, 48(" reg  \
    126   ")\n"                  \
    127   "    lw s11, 52(" reg ")\n"
    128 
    129 #if __riscv_flen == 64
    130 #define SAVE_FPR(reg)      \
    131   "    fsd fs0,   56(" reg \
    132   ")\n"                    \
    133   "    fsd fs1,   64(" reg \
    134   ")\n"                    \
    135   "    fsd fs2,   72(" reg \
    136   ")\n"                    \
    137   "    fsd fs3,   80(" reg \
    138   ")\n"                    \
    139   "    fsd fs4,   88(" reg \
    140   ")\n"                    \
    141   "    fsd fs5,   96(" reg \
    142   ")\n"                    \
    143   "    fsd fs6,  104(" reg \
    144   ")\n"                    \
    145   "    fsd fs7,  112(" reg \
    146   ")\n"                    \
    147   "    fsd fs8,  120(" reg \
    148   ")\n"                    \
    149   "    fsd fs9,  128(" reg \
    150   ")\n"                    \
    151   "    fsd fs10, 136(" reg \
    152   ")\n"                    \
    153   "    fsd fs11, 144(" reg ")\n"
    154 #define RESTORE_FPR(reg)   \
    155   "    fld fs0,   56(" reg \
    156   ")\n"                    \
    157   "    fld fs1,   64(" reg \
    158   ")\n"                    \
    159   "    fld fs2,   72(" reg \
    160   ")\n"                    \
    161   "    fld fs3,   80(" reg \
    162   ")\n"                    \
    163   "    fld fs4,   88(" reg \
    164   ")\n"                    \
    165   "    fld fs5,   96(" reg \
    166   ")\n"                    \
    167   "    fld fs6,  104(" reg \
    168   ")\n"                    \
    169   "    fld fs7,  112(" reg \
    170   ")\n"                    \
    171   "    fld fs8,  120(" reg \
    172   ")\n"                    \
    173   "    fld fs9,  128(" reg \
    174   ")\n"                    \
    175   "    fld fs10, 136(" reg \
    176   ")\n"                    \
    177   "    fld fs11, 144(" reg ")\n"
    178 #elif __riscv_flen == 32
    179 #define SAVE_FPR(reg)      \
    180   "    fsw fs0,   56(" reg \
    181   ")\n"                    \
    182   "    fsw fs1,   60(" reg \
    183   ")\n"                    \
    184   "    fsw fs2,   64(" reg \
    185   ")\n"                    \
    186   "    fsw fs3,   68(" reg \
    187   ")\n"                    \
    188   "    fsw fs4,   72(" reg \
    189   ")\n"                    \
    190   "    fsw fs5,   76(" reg \
    191   ")\n"                    \
    192   "    fsw fs6,   80(" reg \
    193   ")\n"                    \
    194   "    fsw fs7,   84(" reg \
    195   ")\n"                    \
    196   "    fsw fs8,   88(" reg \
    197   ")\n"                    \
    198   "    fsw fs9,   92(" reg \
    199   ")\n"                    \
    200   "    fsw fs10,  96(" reg \
    201   ")\n"                    \
    202   "    fsw fs11, 100(" reg ")\n"
    203 #define RESTORE_FPR(reg)   \
    204   "    flw fs0,   56(" reg \
    205   ")\n"                    \
    206   "    flw fs1,   60(" reg \
    207   ")\n"                    \
    208   "    flw fs2,   64(" reg \
    209   ")\n"                    \
    210   "    flw fs3,   68(" reg \
    211   ")\n"                    \
    212   "    flw fs4,   72(" reg \
    213   ")\n"                    \
    214   "    flw fs5,   76(" reg \
    215   ")\n"                    \
    216   "    flw fs6,   80(" reg \
    217   ")\n"                    \
    218   "    flw fs7,   84(" reg \
    219   ")\n"                    \
    220   "    flw fs8,   88(" reg \
    221   ")\n"                    \
    222   "    flw fs9,   92(" reg \
    223   ")\n"                    \
    224   "    flw fs10,  96(" reg \
    225   ")\n"                    \
    226   "    flw fs11, 100(" reg ")\n"
    227 #else
    228 #define SAVE_FPR(reg) ""
    229 #define RESTORE_FPR(reg) ""
    230 #endif
    231 
    232 /* Save: int first, FP second (matches xOS rv32 pattern, and rv64 here).
    233    Restore: FP first, int second -- mirror order, minimizes register
    234    reuse window.  Note none of these loads write to the address-base
    235    register, so the integer/FP order is purely cosmetic. */
    236 #define SAVE_INTO(reg) SAVE_GPR(reg) SAVE_FPR(reg)
    237 #define RESTORE_FROM(reg) RESTORE_FPR(reg) RESTORE_GPR(reg)
    238 
    239 __asm__ (
    240     ".text\n"
    241     ".align 2\n"
    242 
    243     /* setjmp(env) -- env=a0. ra at function entry is the caller's
    244        return address, exactly what longjmp must restore. */
    245     ".weak " SYM(setjmp) "\n"
    246     ".type "  SYM(setjmp) ", @function\n"
    247     SYM(setjmp) ":\n"
    248     SAVE_INTO("a0")
    249     "    li a0, 0\n"
    250     "    ret\n"
    251     ".size " SYM(setjmp) ", .-" SYM(setjmp) "\n"
    252 
    253     /* longjmp(env, val) -- env=a0, val=a1.
    254        longjmp(_, 0) must deliver 1 (C11 7.13.2.1p4); branch-free:
    255          seqz t0, a1   ; t0 = (a1 == 0)
    256          add  a0, a1, t0
    257        so a0 = a1 if a1 != 0, else 1. */
    258     ".weak " SYM(longjmp) "\n"
    259     ".type "  SYM(longjmp) ", @function\n"
    260     SYM(longjmp) ":\n"
    261     RESTORE_FROM("a0")
    262     "    seqz t0, a1\n"
    263     "    add  a0, a1, t0\n"
    264     "    ret\n"
    265     ".size " SYM(longjmp) ", .-" SYM(longjmp) "\n"
    266 
    267     /* __kit_coro_switch(from, to, value) -- a0=from, a1=to, a2=value.
    268        Save into [a0], restore from [a1], deliver a2 in a0 (which is
    269        both the return register and the trampoline's first-arg reg
    270        on a fresh context's first run). */
    271     ".globl " SYM(__kit_coro_switch) "\n"
    272     ".type "  SYM(__kit_coro_switch) ", @function\n"
    273     SYM(__kit_coro_switch) ":\n"
    274     SAVE_INTO("a0")
    275     RESTORE_FROM("a1")
    276     "    mv a0, a2\n"
    277     "    ret\n"
    278     ".size " SYM(__kit_coro_switch) ", .-" SYM(__kit_coro_switch) "\n"
    279 
    280     /* __kit_coro_trampoline -- on first entry: a0=value (delivered
    281        by __kit_coro_switch's `mv a0, a2`), s0=entry (set by __kit_coro_ctx_init via
    282        regs[2]), sp=stack_top. ebreak if entry returns. */
    283     ".globl " SYM(__kit_coro_trampoline) "\n"
    284     ".type "  SYM(__kit_coro_trampoline) ", @function\n"
    285     SYM(__kit_coro_trampoline) ":\n"
    286     "    jalr s0\n"
    287     "    ebreak\n"
    288     ".size " SYM(__kit_coro_trampoline) ", .-" SYM(__kit_coro_trampoline) "\n"
    289 
    290     ".section .note.GNU-stack,\"\",@progbits\n"
    291 );