blob: 066459e53008b985479c19ad1d9c44061d217c24 [file] [log] [blame]
#[inline(always)]
pub unsafe fn yieldk() {
// Note: A process stops yielding when there is a callback ready to run,
// which the kernel executes by modifying the stack frame pushed by the
// hardware. The kernel copies the PC value from the stack frame to the LR
// field, and sets the PC value to callback to run. When this frame is
// unstacked during the interrupt return, the effectively clobbers the LR
// register.
//
// At this point, the callback function is now executing, which may itself
// clobber any of the other caller-saved registers. Thus we mark this
// inline assembly as conservatively clobbering all caller-saved registers,
// forcing yield to save any live registers.
//
// Upon direct observation of this function, the LR is the only register
// that is live across the SVC invocation, however, if the yield call is
// inlined, it is possible that the LR won't be live at all (commonly seen
// for the `loop { yieldk(); }` idiom) or that other registers are live,
// thus it is important to let the compiler do the work here.
//
// According to the AAPCS: A subroutine must preserve the contents of the
// registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate
// r9 as v6) As our compilation flags mark r9 as the PIC base register, it
// does not need to be saved. Thus we must clobber r0-3, r12, and LR
llvm_asm!(
"svc 0"
:
:
: "memory", "r0", "r1", "r2", "r3", "r12", "lr"
: "volatile");
}
#[inline(always)]
// Justification: documentation is generated from mocks
#[allow(clippy::missing_safety_doc)]
pub unsafe fn subscribe(
major: usize,
minor: usize,
cb: *const unsafe extern "C" fn(usize, usize, usize, usize),
ud: usize,
) -> isize {
let res;
llvm_asm!("svc 1" : "={r0}"(res)
: "{r0}"(major) "{r1}"(minor) "{r2}"(cb) "{r3}"(ud)
: "memory"
: "volatile");
res
}
#[inline(always)]
// Justification: documentation is generated from mocks
#[allow(clippy::missing_safety_doc)]
pub unsafe fn command(major: usize, minor: usize, arg1: usize, arg2: usize) -> isize {
let res;
llvm_asm!("svc 2" : "={r0}"(res)
: "{r0}"(major) "{r1}"(minor) "{r2}"(arg1) "{r3}"(arg2)
: "memory"
: "volatile");
res
}
#[inline(always)]
// Justification: documentation is generated from mocks
#[allow(clippy::missing_safety_doc)]
pub unsafe fn command1(major: usize, minor: usize, arg: usize) -> isize {
let res;
llvm_asm!("svc 2" : "={r0}"(res)
: "{r0}"(major) "{r1}"(minor) "{r2}"(arg)
: "memory"
: "volatile");
res
}
#[inline(always)]
// Justification: documentation is generated from mocks
#[allow(clippy::missing_safety_doc)]
pub unsafe fn allow(major: usize, minor: usize, slice: *mut u8, len: usize) -> isize {
let res;
llvm_asm!("svc 3" : "={r0}"(res)
: "{r0}"(major) "{r1}"(minor) "{r2}"(slice) "{r3}"(len)
: "memory"
: "volatile");
res
}
#[inline(always)]
// Justification: documentation is generated from mocks
#[allow(clippy::missing_safety_doc)]
pub unsafe fn memop(major: u32, arg1: usize) -> isize {
let res;
llvm_asm!("svc 4" : "={r0}"(res)
: "{r0}"(major) "{r1}"(arg1)
: "memory"
: "volatile");
res
}