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 use core::arch::naked_asm; 9 10 #[unsafe(naked)] 11 pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8 /* x0 */) { 12 naked_asm!( 13 " 14 // Save all callee-saved registers on the stack since we're assuming 15 // they're clobbered as a result of the stack switch. 16 stmg %r6, %r15, 48(%r15) 17 aghi %r15, -64 18 std %f8, 0(%r15) 19 std %f9, 8(%r15) 20 std %f10, 16(%r15) 21 std %f11, 24(%r15) 22 std %f12, 32(%r15) 23 std %f13, 40(%r15) 24 std %f14, 48(%r15) 25 std %f15, 56(%r15) 26 27 // Load our previously saved stack pointer to resume to, and save off our 28 // current stack pointer on where to come back to eventually. 29 lg %r1, -16(%r2) 30 stg %r15, -16(%r2) 31 32 // Switch to the new stack and restore all our callee-saved registers after 33 // the switch and return to our new stack. 34 ld %f8, 0(%r1) 35 ld %f9, 8(%r1) 36 ld %f10, 16(%r1) 37 ld %f11, 24(%r1) 38 ld %f12, 32(%r1) 39 ld %f13, 40(%r1) 40 ld %f14, 48(%r1) 41 ld %f15, 56(%r1) 42 lmg %r6, %r15, 112(%r1) 43 br %r14 44 ", 45 ); 46 } 47 48 #[unsafe(naked)] 49 pub(crate) unsafe extern "C" fn wasmtime_fiber_init( 50 top_of_stack: *mut u8, // x0 51 entry_point: extern "C" fn(*mut u8, *mut u8), // x1 52 entry_arg0: *mut u8, // x2 53 ) { 54 naked_asm!( 55 " 56 larl %r1, {} 57 stg %r1, -48(%r2) // wasmtime_fiber_start - restored into %r14 58 stg %r2, -112(%r2) // top_of_stack - restored into %r6 59 stg %r3, -104(%r2) // entry_point - restored into %r7 60 stg %r4, -96(%r2) // entry_arg0 - restored into %r8 61 aghi %r2, -160 // 160 bytes register save area 62 stg %r2, 120(%r2) // bottom of register save area - restored into %r15 63 64 // `wasmtime_fiber_switch` has a 64 byte stack. 65 aghi %r2, -64 66 stg %r2, 208(%r2) 67 br %r14 68 ", 69 sym wasmtime_fiber_start, 70 ); 71 } 72 73 #[unsafe(naked)] 74 unsafe extern "C" fn wasmtime_fiber_start() -> ! { 75 naked_asm!( 76 " 77 .cfi_startproc simple 78 .cfi_def_cfa_offset 0 79 80 // See the x86_64 file for more commentary on what these CFI directives are 81 // doing. Like over there note that the relative offsets to registers here 82 // match the frame layout in `wasmtime_fiber_switch`. 83 .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \ 84 7, /* the byte length of this expression */ \ 85 0x7f, 0x90, 0x1, /* DW_OP_breg15 0x90 */ \ 86 0x06, /* DW_OP_deref */ \ 87 0x23, 0xe0, 0x1 /* DW_OP_plus_uconst 0xe0 */ 88 89 .cfi_rel_offset 6, -112 90 .cfi_rel_offset 7, -104 91 .cfi_rel_offset 8, -96 92 .cfi_rel_offset 9, -88 93 .cfi_rel_offset 10, -80 94 .cfi_rel_offset 11, -72 95 .cfi_rel_offset 12, -64 96 .cfi_rel_offset 13, -56 97 .cfi_rel_offset 14, -48 98 .cfi_rel_offset 15, -40 99 100 // Load our two arguments prepared by `wasmtime_fiber_init`. 101 lgr %r2, %r8 // entry_arg0 102 lgr %r3, %r6 // top_of_stack 103 104 // ... and then we call the function! Note that this is a function call so 105 // our frame stays on the stack to backtrace through. 106 basr %r14, %r7 // entry_point 107 // .. technically we shouldn't get here, so just trap. 108 .word 0x0000 109 .cfi_endproc 110 ", 111 ); 112 } 113