Skip to content

Commit

Permalink
Use const operand for ARM syscall implementation
Browse files Browse the repository at this point in the history
`asm_const` feature has been stabilized in Rust 1.82. Using const
operands for inline assembly eliminates a lot of the duplicated code in
the ARM syscall implementation.

This commit has been tested by running a simple application that
periodically blinks and writes a message on Raspberry Pi Pico.
  • Loading branch information
Ioan-Cristian CÎRSTEA committed Dec 17, 2024
1 parent f0fe519 commit 7576183
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 66 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ version = "0.1.0"
[workspace.package]
# This must be kept in sync with rust-toolchain.toml; please see that file for
# more information.
rust-version = "1.77"
rust-version = "1.82"

[features]
rust_embedded = [
Expand Down
92 changes: 28 additions & 64 deletions runtime/src/syscalls_impl_arm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::arch::asm;
use libtock_platform::{syscall_class, RawSyscalls, Register};
use libtock_platform::{RawSyscalls, Register};

unsafe impl RawSyscalls for crate::TockSyscalls {
unsafe fn yield1([Register(r0)]: [Register; 1]) {
Expand Down Expand Up @@ -43,92 +43,56 @@ unsafe impl RawSyscalls for crate::TockSyscalls {
}
}

unsafe fn syscall1<const CLASS: usize>([Register(mut r0)]: [Register; 1]) -> [Register; 2] {
unsafe fn syscall1<const SYSCALL_CLASS_NUMBER: usize>(
[Register(mut r0)]: [Register; 1],
) -> [Register; 2] {
let r1;
// Safety: This matches the invariants required by the documentation on
// RawSyscalls::syscall1
unsafe {
// Syscall class 5 is Memop, the only syscall class that syscall1
// supports.
asm!("svc 5",
inlateout("r0") r0,
lateout("r1") r1,
options(preserves_flags, nostack, nomem),
asm!(
"svc {SYSCALL_CLASS_NUMBER}",
inlateout("r0") r0,
lateout("r1") r1,
options(preserves_flags, nostack, nomem),
SYSCALL_CLASS_NUMBER = const SYSCALL_CLASS_NUMBER,
);
}
[Register(r0), Register(r1)]
}

unsafe fn syscall2<const CLASS: usize>(
unsafe fn syscall2<const SYSCALL_CLASS_NUMBER: usize>(
[Register(mut r0), Register(mut r1)]: [Register; 2],
) -> [Register; 2] {
// Safety: This matches the invariants required by the documentation on
// RawSyscalls::syscall2
unsafe {
// TODO: Replace this match statement with a `const` operand when
// asm_const [1] is stabilized, or redesign RawSyscalls to not need
// this match statement.
//
// [1] https://github.com/rust-lang/rust/issues/93332
match CLASS {
syscall_class::MEMOP => asm!("svc 5",
inlateout("r0") r0,
inlateout("r1") r1,
options(preserves_flags, nostack, nomem)
),
syscall_class::EXIT => asm!("svc 6",
inlateout("r0") r0,
inlateout("r1") r1,
options(preserves_flags, nostack, nomem)
),
_ => unreachable!(),
}
asm!(
"svc {SYSCALL_CLASS_NUMBER}",
inlateout("r0") r0,
inlateout("r1") r1,
options(preserves_flags, nostack, nomem),
SYSCALL_CLASS_NUMBER = const SYSCALL_CLASS_NUMBER,
);
}
[Register(r0), Register(r1)]
}

unsafe fn syscall4<const CLASS: usize>(
unsafe fn syscall4<const SYSCALL_CLASS_NUMBER: usize>(
[Register(mut r0), Register(mut r1), Register(mut r2), Register(mut r3)]: [Register; 4],
) -> [Register; 4] {
// Safety: This matches the invariants required by the documentation on
// RawSyscalls::syscall4
unsafe {
// TODO: Replace this match statement with a `const` operand when
// asm_const [1] is stabilized, or redesign RawSyscalls to not need
// this match statement.
//
// [1] https://github.com/rust-lang/rust/issues/93332
match CLASS {
syscall_class::SUBSCRIBE => asm!("svc 1",
inlateout("r0") r0,
inlateout("r1") r1,
inlateout("r2") r2,
inlateout("r3") r3,
options(preserves_flags, nostack),
),
syscall_class::COMMAND => asm!("svc 2",
inlateout("r0") r0,
inlateout("r1") r1,
inlateout("r2") r2,
inlateout("r3") r3,
options(preserves_flags, nostack),
),
syscall_class::ALLOW_RW => asm!("svc 3",
inlateout("r0") r0,
inlateout("r1") r1,
inlateout("r2") r2,
inlateout("r3") r3,
options(preserves_flags, nostack),
),
syscall_class::ALLOW_RO => asm!("svc 4",
inlateout("r0") r0,
inlateout("r1") r1,
inlateout("r2") r2,
inlateout("r3") r3,
options(preserves_flags, nostack),
),
_ => unreachable!(),
}
asm!(
"svc {SYSCALL_CLASS_NUMBER}",
inlateout("r0") r0,
inlateout("r1") r1,
inlateout("r2") r2,
inlateout("r3") r3,
options(preserves_flags, nostack),
SYSCALL_CLASS_NUMBER = const SYSCALL_CLASS_NUMBER,
);
}
[Register(r0), Register(r1), Register(r2), Register(r3)]
}
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# you'd like to use. When you do so, update this to the first Rust version that
# includes that feature. Whenever this value is updated, the rust-version field
# in Cargo.toml must be updated as well.
channel = "1.77"
channel = "1.82"
components = ["clippy", "rustfmt"]
targets = [
"thumbv6m-none-eabi",
Expand Down
5 changes: 5 additions & 0 deletions syscalls_tests/src/subscribe_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ fn success() {
assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
}

// The toolchain update from 1.78 to 1.82 broke this test. However, this test will start working
// again as of Rust 1.84. See https://github.com/tock/libtock-rs/pull/565#issuecomment-2546915870
// for more details.
/*
#[cfg(not(miri))]
#[test]
fn unwinding_upcall() {
Expand Down Expand Up @@ -131,3 +135,4 @@ fn unwinding_upcall() {
});
assert_eq!(exit, libtock_unittest::ExitCall::Terminate(0));
}
*/

0 comments on commit 7576183

Please sign in to comment.