blob: bae938b10cd413f2829918a16a1f7431a553ee48 [file] [log] [blame]
#[cfg_attr(target_arch = "riscv32", path = "platform_riscv32.rs")]
#[cfg_attr(target_arch = "arm", path = "platform_arm.rs")]
mod platform;
use crate::callback::CallbackSubscription;
use crate::callback::Consumer;
use crate::result::AllowError;
use crate::result::CommandError;
use crate::result::SubscribeError;
use crate::shared_memory::SharedMemory;
pub mod raw {
pub use super::platform::*;
}
pub fn subscribe<C: Consumer<T>, T>(
driver_number: usize,
subscribe_number: usize,
payload: &mut T,
) -> Result<CallbackSubscription, SubscribeError> {
extern "C" fn c_callback<T, C: Consumer<T>>(
arg1: usize,
arg2: usize,
arg3: usize,
data: usize,
) {
let payload = unsafe { &mut *(data as *mut T) };
C::consume(payload, arg1, arg2, arg3);
}
subscribe_fn(
driver_number,
subscribe_number,
c_callback::<T, C>,
payload as *mut _ as usize,
)
.map(|_| CallbackSubscription::new(driver_number, subscribe_number))
}
pub fn subscribe_fn(
driver_number: usize,
subscribe_number: usize,
callback: extern "C" fn(usize, usize, usize, usize),
userdata: usize,
) -> Result<(), SubscribeError> {
let return_code = unsafe {
raw::subscribe(
driver_number,
subscribe_number,
callback as *const _,
userdata,
)
};
if return_code == 0 {
Ok(())
} else {
Err(SubscribeError {
driver_number,
subscribe_number,
return_code,
})
}
}
pub fn command(
driver_number: usize,
command_number: usize,
arg1: usize,
arg2: usize,
) -> Result<usize, CommandError> {
let return_code = unsafe { raw::command(driver_number, command_number, arg1, arg2) };
if return_code >= 0 {
Ok(return_code as usize)
} else {
Err(CommandError {
driver_number,
command_number,
arg1,
arg2,
return_code,
})
}
}
/// [command1_insecure()] is a variant of [command()] that only sets the first
/// argument in the system call interface. It has the benefit of generating
/// simpler assembly than [command()], but it leaves the second argument's register
/// as-is which leaks it to the kernel driver being called. Prefer to use
/// [command()] instead of [command1_insecure()], unless the benefit of generating
/// simpler assembly outweighs the drawbacks of potentially leaking arbitrary
/// information to the driver you are calling.
///
/// At the moment, the only suitable use case for [command1_insecure()] is the low
/// level debug interface.
pub fn command1_insecure(
driver_number: usize,
command_number: usize,
arg: usize,
) -> Result<usize, CommandError> {
let return_code = unsafe { raw::command1(driver_number, command_number, arg) };
if return_code >= 0 {
Ok(return_code as usize)
} else {
Err(CommandError {
driver_number,
command_number,
arg1: arg,
arg2: 0,
return_code,
})
}
}
pub fn allow(
driver_number: usize,
allow_number: usize,
buffer_to_share: &mut [u8],
) -> Result<SharedMemory, AllowError> {
let len = buffer_to_share.len();
let return_code = unsafe {
raw::allow(
driver_number,
allow_number,
buffer_to_share.as_mut_ptr(),
len,
)
};
if return_code == 0 {
Ok(SharedMemory::new(
driver_number,
allow_number,
buffer_to_share,
))
} else {
Err(AllowError {
driver_number,
allow_number,
return_code,
})
}
}