-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add fiber implementation for riscv32imac #12506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cfallin
merged 3 commits into
bytecodealliance:main
from
COLORADIO-Project:fibers-on-riscv32imac
Feb 3, 2026
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| // A WORD OF CAUTION | ||
| // | ||
| // This entire file basically needs to be kept in sync with itself. It's not | ||
| // really possible to modify just one bit of this file without understanding | ||
| // all the other bits. Documentation tries to reference various bits here and | ||
| // there but try to make sure to read over everything before tweaking things! | ||
| // | ||
| // This file is modelled after riscv64.rs. For reference be sure to review the | ||
| // other file. | ||
|
|
||
| use core::arch::naked_asm; | ||
|
|
||
| #[inline(never)] // FIXME(rust-lang/rust#148307) | ||
| pub(crate) unsafe extern "C" fn wasmtime_fiber_switch(top_of_stack: *mut u8) { | ||
| unsafe { wasmtime_fiber_switch_(top_of_stack) } | ||
| } | ||
|
|
||
| #[unsafe(naked)] | ||
| unsafe extern "C" fn wasmtime_fiber_switch_(top_of_stack: *mut u8 /* a0 */) { | ||
| naked_asm!( | ||
| " | ||
| // See https://github.com/rust-lang/rust/issues/80608. | ||
| .attribute arch, \"rv32i\" // This implementation should work for any | ||
| // architecture with the same registers as riscv32i, e.g. riscv32imac, | ||
| // but not riscv32gc. | ||
|
|
||
| // We're switching to arbitrary code somewhere else, so pessimistically | ||
| // assume that all callee-save register are clobbered. This means we need | ||
| // to save/restore all of them. | ||
| // | ||
| // Note that this order for saving is important since we use CFI directives | ||
| // below to point to where all the saved registers are. | ||
| sw ra, -0x4(sp) | ||
| sw fp, -0x8(sp) // fp is s0 | ||
| sw s1, -0xc(sp) | ||
| sw s2, -0x10(sp) | ||
| sw s3, -0x14(sp) | ||
| sw s4, -0x18(sp) | ||
| sw s5, -0x1c(sp) | ||
| sw s6, -0x20(sp) | ||
| sw s7, -0x24(sp) | ||
| sw s8, -0x28(sp) | ||
| sw s9, -0x2c(sp) | ||
| sw s10, -0x30(sp) | ||
| sw s11, -0x34(sp) | ||
| addi sp, sp, -0x40 // Choose 0x40 to be 16-byte aligned | ||
|
|
||
| lw t0, -0x8(a0) | ||
| sw sp, -0x8(a0) | ||
|
|
||
| // Swap stacks and restore all our callee-saved registers | ||
| mv sp, t0 | ||
|
|
||
| lw s11, 0xc(sp) | ||
| lw s10, 0x10(sp) | ||
| lw s9, 0x14(sp) | ||
| lw s8, 0x18(sp) | ||
| lw s7, 0x1c(sp) | ||
| lw s6, 0x20(sp) | ||
| lw s5, 0x24(sp) | ||
| lw s4, 0x28(sp) | ||
| lw s3, 0x2c(sp) | ||
| lw s2, 0x30(sp) | ||
| lw s1, 0x34(sp) | ||
| lw fp, 0x38(sp) | ||
| lw ra, 0x3c(sp) | ||
| addi sp, sp, 0x40 | ||
| jr ra | ||
| ", | ||
| ); | ||
| } | ||
|
|
||
| pub(crate) unsafe fn wasmtime_fiber_init( | ||
| top_of_stack: *mut u8, | ||
| entry_point: extern "C" fn(*mut u8, *mut u8), | ||
| entry_arg0: *mut u8, | ||
| ) { | ||
| #[repr(C)] | ||
| #[derive(Default)] | ||
| struct InitialStack { | ||
| padding: [u8; 12], // 12 bytes of padding for 16-byte alignment | ||
|
|
||
| s11: *mut u8, | ||
| s10: *mut u8, | ||
| s9: *mut u8, | ||
| s8: *mut u8, | ||
| s7: *mut u8, | ||
| s6: *mut u8, | ||
| s5: *mut u8, | ||
| s4: *mut u8, | ||
| s3: *mut u8, | ||
| s2: *mut u8, | ||
| s1: *mut u8, | ||
| fp: *mut u8, | ||
|
|
||
| ra: *mut u8, | ||
|
|
||
| // unix.rs reserved space | ||
| padding_2: [u8; 8], // 8 bytes of padding for 16-byte alignment | ||
| last_sp: *mut u8, | ||
| run_result: *mut u8, | ||
| } | ||
|
|
||
| unsafe { | ||
| let initial_stack = top_of_stack.cast::<InitialStack>().sub(1); | ||
| initial_stack.write(InitialStack { | ||
| s1: entry_point as *mut u8, | ||
| s2: entry_arg0, | ||
| fp: top_of_stack, | ||
| ra: wasmtime_fiber_start as *mut u8, | ||
| last_sp: initial_stack.cast(), | ||
| ..InitialStack::default() | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| #[unsafe(naked)] | ||
| unsafe extern "C" fn wasmtime_fiber_start() -> ! { | ||
| naked_asm!( | ||
| " | ||
| .cfi_startproc simple | ||
| .cfi_def_cfa_offset 0 | ||
|
|
||
|
|
||
| .cfi_escape 0x0f, /* DW_CFA_def_cfa_expression */ \ | ||
| 5, /* the byte length of this expression */ \ | ||
| 0x52, /* DW_OP_reg2 (sp) */ \ | ||
| 0x06, /* DW_OP_deref */ \ | ||
| 0x08, 0x40, /* DW_OP_const1u 0x40 */ \ | ||
| 0x22 /* DW_OP_plus */ | ||
|
|
||
|
|
||
| .cfi_rel_offset ra, -0x4 | ||
| .cfi_rel_offset fp, -0x8 | ||
| .cfi_rel_offset s1, -0xc | ||
| .cfi_rel_offset s2, -0x10 | ||
| .cfi_rel_offset s3, -0x14 | ||
| .cfi_rel_offset s4, -0x18 | ||
| .cfi_rel_offset s5, -0x1c | ||
| .cfi_rel_offset s6, -0x20 | ||
| .cfi_rel_offset s7, -0x24 | ||
| .cfi_rel_offset s8, -0x28 | ||
| .cfi_rel_offset s9, -0x2c | ||
| .cfi_rel_offset s10, -0x30 | ||
| .cfi_rel_offset s11, -0x34 | ||
|
|
||
| mv a0, s2 | ||
| mv a1, fp | ||
| jalr s1 | ||
| // .4byte 0 will cause panic. | ||
| // for safety just like x86_64.rs and riscv64.rs. | ||
| .4byte 0 | ||
| .cfi_endproc | ||
| ", | ||
| ); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to be 16-byte-aligned, these two fields together are 8 bytes (two 32-bit pointers) so the whole struct is going to be off by 8 bytes, right?
Do we need additional padding between
raandlast_sp?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused about this as well. In
nostd.rs(andunix.rs), only the spot betweenraandlast_spis explicitly documented to be 16-byte aligned. We also only move the stack pointer to that address, not to the very end of the struct.I've tested both a version with and a version without 8 bytes of padding between
raandlast_sp. Both work fine on my device. I'm honestly not sure whether padding is needed there. If you think we should add padding there, I am happy to add a commit introducing this padding.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I think a few things are going on here:
spwill actually cause a trap), but other functions are free to rely on stack alignment; so, for example, if we call some function in the fiber that eventually stores something to the stack with an aligned store, lack of alignment could cause a hard-to-diagnose segfault somewhere else. So we do need to ensure the stack as seen by the entry function to the fiber is aligned.last_spand therun_result-- are both pointers, i.e. 64-bit (8-byte) values.Given all that, I think if we put 8 bytes of padding before
last_sp, we'll have satisfied the alignment requirements.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added the padding in the newest commit, thanks for taking the time to look into this!