1 // A WORD OF CAUTION 2 // 3 // This entire file basically needs to be kept in sync with itself. It's not 4 // really possible to modify just one bit of this file without understanding 5 // all the other bits. Documentation tries to reference various bits here and 6 // there but try to make sure to read over everything before tweaking things! 7 // 8 // This file is modelled after riscv64.rs. For reference be sure to review the 9 // other file. 10 11 use core::arch::naked_asm; 12 13 #[inline(never)] // FIXME(rust-lang/rust#148307) 14 pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8) { 15 unsafe { wasmtime_fiber_switch_(top_of_stack) } 16 } 17 18 #[unsafe(naked)] 19 unsafe extern "C" fn wasmtime_fiber_switch_(top_of_stack: *mut u8 /* a0 */) { 20 naked_asm!( 21 " 22 // See https://github.com/rust-lang/rust/issues/80608. 23 .attribute arch, \"rv32i\" // This implementation should work for any 24 // architecture with the same registers as riscv32i, e.g. riscv32imac, 25 // but not riscv32gc. 26 27 // We're switching to arbitrary code somewhere else, so pessimistically 28 // assume that all callee-save register are clobbered. This means we need 29 // to save/restore all of them. 30 // 31 // Note that this order for saving is important since we use CFI directives 32 // below to point to where all the saved registers are. 33 sw ra, -0x4(sp) 34 sw fp, -0x8(sp) // fp is s0 35 sw s1, -0xc(sp) 36 sw s2, -0x10(sp) 37 sw s3, -0x14(sp) 38 sw s4, -0x18(sp) 39 sw s5, -0x1c(sp) 40 sw s6, -0x20(sp) 41 sw s7, -0x24(sp) 42 sw s8, -0x28(sp) 43 sw s9, -0x2c(sp) 44 sw s10, -0x30(sp) 45 sw s11, -0x34(sp) 46 addi sp, sp, -0x40 // Choose 0x40 to be 16-byte aligned 47 48 lw t0, -0x8(a0) 49 sw sp, -0x8(a0) 50 51 // Swap stacks and restore all our callee-saved registers 52 mv sp, t0 53 54 lw s11, 0xc(sp) 55 lw s10, 0x10(sp) 56 lw s9, 0x14(sp) 57 lw s8, 0x18(sp) 58 lw s7, 0x1c(sp) 59 lw s6, 0x20(sp) 60 lw s5, 0x24(sp) 61 lw s4, 0x28(sp) 62 lw s3, 0x2c(sp) 63 lw s2, 0x30(sp) 64 lw s1, 0x34(sp) 65 lw fp, 0x38(sp) 66 lw ra, 0x3c(sp) 67 addi sp, sp, 0x40 68 jr ra 69 ", 70 ); 71 } 72 73 pub(crate) unsafe fn wasmtime_fiber_init( 74 top_of_stack: *mut u8, 75 entry_point: extern "C" fn(*mut u8, *mut u8) -> *mut u8, 76 entry_arg0: *mut u8, 77 ) { 78 #[repr(C)] 79 #[derive(Default)] 80 struct InitialStack { 81 padding: [u8; 12], // 12 bytes of padding for 16-byte alignment 82 83 s11: *mut u8, 84 s10: *mut u8, 85 s9: *mut u8, 86 s8: *mut u8, 87 s7: *mut u8, 88 s6: *mut u8, 89 s5: *mut u8, 90 s4: *mut u8, 91 s3: *mut u8, 92 s2: *mut u8, 93 s1: *mut u8, 94 fp: *mut u8, 95 96 ra: *mut u8, 97 98 // unix.rs reserved space 99 padding_2: [u8; 8], // 8 bytes of padding for 16-byte alignment 100 last_sp: *mut u8, 101 run_result: *mut u8, 102 } 103 104 unsafe { 105 let initial_stack = top_of_stack.cast::<InitialStack>().sub(1); 106 initial_stack.write(InitialStack { 107 s1: entry_point as *mut u8, 108 s2: entry_arg0, 109 s3: wasmtime_fiber_switch_ as *mut u8, 110 fp: top_of_stack, 111 ra: wasmtime_fiber_start as *mut u8, 112 last_sp: initial_stack.cast(), 113 ..InitialStack::default() 114 }); 115 } 116 } 117 118 #[unsafe(naked)] 119 unsafe extern "C" fn wasmtime_fiber_start() -> ! { 120 naked_asm!( 121 " 122 .cfi_startproc simple 123 .cfi_def_cfa_offset 0 124 125 126 .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \ 127 5, /* the byte length of this expression */ \ 128 0x52, /* DW_OP_reg2 (sp) */ \ 129 0x06, /* DW_OP_deref */ \ 130 0x08, 0x40, /* DW_OP_const1u 0x40 */ \ 131 0x22 /* DW_OP_plus */ 132 133 134 .cfi_rel_offset ra, -0x4 135 .cfi_rel_offset fp, -0x8 136 .cfi_rel_offset s1, -0xc 137 .cfi_rel_offset s2, -0x10 138 .cfi_rel_offset s3, -0x14 139 .cfi_rel_offset s4, -0x18 140 .cfi_rel_offset s5, -0x1c 141 .cfi_rel_offset s6, -0x20 142 .cfi_rel_offset s7, -0x24 143 .cfi_rel_offset s8, -0x28 144 .cfi_rel_offset s9, -0x2c 145 .cfi_rel_offset s10, -0x30 146 .cfi_rel_offset s11, -0x34 147 148 mv a0, s2 149 mv a1, fp 150 jalr s1 151 jalr s3 152 // .4byte 0 will cause panic. 153 // for safety just like x86_64.rs and riscv64.rs. 154 .4byte 0 155 .cfi_endproc 156 ", 157 ); 158 } 159