Skip to content

Instantly share code, notes, and snippets.

@Amanieu
Last active April 2, 2021 07:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Amanieu/d97c420c00cd51fad556b633e0d87af1 to your computer and use it in GitHub Desktop.
Save Amanieu/d97c420c00cd51fad556b633e0d87af1 to your computer and use it in GitHub Desktop.
// Common code for interruptible syscalls
macro_rules! asm_interruptible_syscall {
($interrupted:expr, $interrupt_flag:expr, $result:expr, $nr:expr) => {
asm_snippet!(
// If a signal interrupts us between atomic_begin and atomic_end,
// the signal handler will rewind the PC back to atomic_begin so
// that the interrupt flag check is atomic.
atomic_begin:,
"ldrb {interrupted:w}, [{interrupt_flag}]",
"cbnz {interrupted}, {skip}",
atomic_end:,
"svc #0",
skip:,
// Record the range of instructions which should be atomic.
".section interrupt_restart_list, \"aw\"",
".balign 8",
".quad {atomic_begin}",
".quad {atomic_end}",
".previous",
interrupted = out(reg) $interrupted,
interrupt_flag = in(reg) $interrupt_flag,
lateout("x0") $result,
inout("x8") $nr as u64 => _,
)
};
}
// There are other versions of this function with different numbers of
// arguments, however they all share the same asm code above.
#[inline]
pub unsafe fn interruptible_syscall3(
interrupt_flag: &InterruptFlag,
nr: usize,
arg0: usize,
arg1: usize,
arg2: usize,
) -> Interruptible<usize> {
let result;
let interrupted: u64;
asm!(
asm_interruptible_syscall!(interrupted, interrupt_flag),
in("x0") arg0,
in("x1") arg1,
in("x2") arg2,
);
if interrupted == 0 {
Ok(result)
} else {
Err(Interrupted::from_flag(interrupted))
}
}
// Common code for interruptible syscalls
macro_rules! asm_interruptible_syscall {
() => {
r#"
# If a signal interrupts us between 0 and 1, the signal handler
# will rewind the PC back to 0 so that the interrupt flag check is
# atomic.
0:
ldrb {interrupted:w}, [{interrupt_flag}]
cbnz {interrupted}, 2f
1:
svc #0
2:
# Record the range of instructions which should be atomic.
.section interrupt_restart_list, "aw"
.balign 8
.quad 0b
.quad 1b
.previous
"#
};
}
// There are other versions of this function with different numbers of
// arguments, however they all share the same asm code above.
#[inline]
pub unsafe fn interruptible_syscall3(
interrupt_flag: &InterruptFlag,
nr: usize,
arg0: usize,
arg1: usize,
arg2: usize,
) -> Interruptible<usize> {
let result;
let interrupted: u64;
asm!(
asm_interruptible_syscall!(),
interrupted = out(reg) interrupted,
interrupt_flag = in(reg) interrupt_flag,
lateout("x0") result,
in("x0") arg0,
in("x1") arg1,
in("x2") arg2,
inout("x8") nr as u64 => _,
);
if interrupted == 0 {
Ok(result)
} else {
Err(Interrupted)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment