bern_arch/cortex_m/syscall.rs
1//! ARM Cortex-M implementation of [`ISyscall`].
2
3use crate::arch::Arch;
4use crate::syscall::ISyscall;
5use core::arch::{asm, global_asm, naked_asm};
6
7impl ISyscall for Arch {
8 #[inline(always)]
9 fn syscall(service: u8, arg0: usize, arg1: usize, arg2: usize) -> usize {
10 // we need to move the arguments to the correct registers, because the
11 // function is inlined
12 let ret;
13 unsafe {
14 asm!(
15 "push {{r4}}",
16 "svc 0",
17 "mov r0, r4",
18 "pop {{r4}}",
19 in("r0") service,
20 in("r1") arg0,
21 in("r2") arg1,
22 in("r3") arg2,
23 lateout("r0") ret,
24 )
25 }
26 ret
27 }
28}
29
30/// Extract and prepare system call for Rust handler.
31/// r0 is used to store the service id, r1-r3 can contain call parameter.
32///
33/// The system call service id (`svc xy`) is not passed on, we have to
34/// retrieve it from code memory. Thus we load the stack pointer from the
35/// callee and read the link register. The link register is pointing to
36/// instruction just after the system call, the system call service id is
37/// placed two bytes before that.
38///
39/// The exception link register tells SVC which privilege mode the callee used
40/// | EXC_RETURN (lr) | Privilege Mode | Stack |
41/// |-----------------|--------------------|------ |
42/// | 0xFFFFFFF1 | Handler Mode | MSP |
43/// | 0xFFFFFFF9 | Thread Mode | MSP |
44/// | 0xFFFFFFFD | Thread Mode | PSP |
45/// | 0xFFFFFFE1 | Handler Mode (FPU) | MSP |
46/// | 0xFFFFFFE9 | Thread Mode (FPU) | MSP |
47/// | 0xFFFFFFED | Thread Mode (FPU) | PSP |
48
49#[no_mangle]
50#[unsafe(naked)]
51unsafe extern "C" fn SVCall() {
52 naked_asm!(
53 "push {{lr}}",
54 "bl syscall_handler",
55 "mov r4, r0", // let's use r4 as return value, because r0 is popped from stack
56 "pop {{lr}}",
57 "bx lr",
58 );
59}