blob: bcd06421a0906b47879eb26e7447896ca9c981cb [file] [log] [blame]
/*
* Copyright 2015, Killian Coddington
* Copyright 2014, NICTA
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(NICTA_BSD)
*/
use static_assertions::assert_cfg;
assert_cfg!(target_arch = "riscv32");
use cfg_if::cfg_if;
pub const seL4_WordBits: usize = 32;
pub const seL4_WordSizeBits: usize = 2;
pub const seL4_PageBits: usize = 12;
pub const seL4_SlotBits: usize = 4;
pub const seL4_TCBBits: usize = 9;
pub const seL4_ReplyBits: usize = 4;
pub const seL4_EndpointBits: usize = 4;
pub const seL4_PageTableEntryBits: usize = 2;
pub const seL4_PageTableIndexBits: usize = 10;
pub const seL4_PageDirIndexBits: usize = seL4_PageTableIndexBits;
pub const seL4_LargePageBits: usize = 22;
pub const seL4_PageTableBits: usize = 12;
pub const seL4_VSpaceBits: usize = seL4_PageTableBits;
pub const seL4_NumASIDPoolBits: usize = 5;
pub const seL4_ASIDPoolIndexBits: usize = 4;
pub const seL4_ASIDPoolBits: usize = 12;
#[cfg(feature = "CONFIG_KERNEL_MCS")]
pub const seL4_NotificationBits: usize = 5;
#[cfg(not(feature = "CONFIG_KERNEL_MCS"))]
pub const seL4_NotificationBits: usize = 4;
pub const seL4_MinUntypedBits: usize = 4;
pub const seL4_MaxUntypedBits: usize = 29;
pub type seL4_RISCV_Page = seL4_CPtr;
pub type seL4_RISCV_PageTable = seL4_CPtr;
pub type seL4_RISCV_ASIDControl = seL4_CPtr;
pub type seL4_RISCV_ASIDPool = seL4_CPtr;
#[cfg(feature = "arch_generic")]
include!("riscv_generic.rs");
error_types!(u32);
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct seL4_UserContext {
pub pc: seL4_Word,
pub ra: seL4_Word,
pub sp: seL4_Word,
pub gp: seL4_Word,
pub s0: seL4_Word,
pub s1: seL4_Word,
pub s2: seL4_Word,
pub s3: seL4_Word,
pub s4: seL4_Word,
pub s5: seL4_Word,
pub s6: seL4_Word,
pub s7: seL4_Word,
pub s8: seL4_Word,
pub s9: seL4_Word,
pub s10: seL4_Word,
pub s11: seL4_Word,
pub a0: seL4_Word,
pub a1: seL4_Word,
pub a2: seL4_Word,
pub a3: seL4_Word,
pub a4: seL4_Word,
pub a5: seL4_Word,
pub a6: seL4_Word,
pub a7: seL4_Word,
pub t0: seL4_Word,
pub t1: seL4_Word,
pub t2: seL4_Word,
pub t3: seL4_Word,
pub t4: seL4_Word,
pub t5: seL4_Word,
pub t6: seL4_Word,
pub tp: seL4_Word,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum seL4_RISCV_VMAttributes {
Default = 0,
ExecuteNever = 0x1,
}
impl From<u32> for seL4_RISCV_VMAttributes {
fn from(val: u32) -> seL4_RISCV_VMAttributes { unsafe { ::core::mem::transmute(val & 1) } }
}
pub const seL4_RISCV_Default_VMAttributes: seL4_RISCV_VMAttributes =
seL4_RISCV_VMAttributes::Default;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
pub enum seL4_ObjectType {
seL4_UntypedObject = 0,
seL4_TCBObject,
seL4_EndpointObject,
seL4_NotificationObject,
seL4_CapTableObject,
#[cfg(feature = "CONFIG_KERNEL_MCS")]
seL4_SchedContextObject,
#[cfg(feature = "CONFIG_KERNEL_MCS")]
seL4_ReplyObject,
seL4_RISCV_4K_Page,
seL4_RISCV_Mega_Page,
seL4_RISCV_PageTableObject,
seL4_LastObjectType,
}
impl seL4_ObjectType {
// Returns the log2 size of fixed-size objects; typically for use
// with seL4_Retype_Untyped. seL4_UntypedObject has no fixed-size,
// callers must specify a size. seL4_CapTableObject has a per-slot
// fixed-size that callers must scale by the #slots.
// seL4_SchedContextObject size must be in the range
// [seL4_MinSchedContextBits..seL4_MaxSchedContextBits].
pub fn size_bits(&self) -> Option<usize> {
match self {
seL4_TCBObject => Some(seL4_TCBBits),
seL4_EndpointObject => Some(seL4_EndpointBits),
seL4_NotificationObject => Some(seL4_EndpointBits),
#[cfg(feature = "CONFIG_KERNEL_MCS")]
seL4_ReplyObject => Some(seL4_ReplyBits),
#[cfg(feature = "CONFIG_KERNEL_MCS")]
seL4_SchedContextObject => Some(seL4_MinSchedContextBits), // XXX maybe None?
// NB: caller must scale by #slots
seL4_CapTableObject => Some(seL4_SlotBits),
seL4_RISCV_4K_Page => Some(seL4_PageBits),
// NB: Arch_get_ObjectSize uses seL4_PageBits which is the
// same for both 32- and 64-bit systems
seL4_RISCV_PageTableObject => Some(seL4_PageTableBits),
seL4_RISCV_Mega_Page => Some(seL4_LargePageBits),
// seL4_RISCV_Giga_Page => Some(seL4_HugePageBits),
// seL4_RISCV_Tera_Page => Some(seL4_TeraPageBits),
_ => None,
}
}
}
impl From<seL4_ObjectType> for seL4_Word {
fn from(type_: seL4_ObjectType) -> seL4_Word { type_ as seL4_Word }
}
#[inline(always)]
pub unsafe fn seL4_GetIPCBuffer() -> *mut seL4_IPCBuffer {
// Use magic external symbol setup by runtime once TLS is primed
enum c_void {}
extern "C" {
#[thread_local]
static __sel4_ipc_buffer: *const c_void;
}
__sel4_ipc_buffer as *mut seL4_IPCBuffer
}
#[inline(always)]
pub unsafe fn seL4_GetMR(regnum: usize) -> seL4_Word { (*seL4_GetIPCBuffer()).msg[regnum] }
#[inline(always)]
pub unsafe fn seL4_SetMR(regnum: usize, value: seL4_Word) {
(*seL4_GetIPCBuffer()).msg[regnum] = value;
}
#[inline(always)]
pub unsafe fn seL4_GetUserData() -> seL4_Word { (*seL4_GetIPCBuffer()).userData }
#[inline(always)]
pub unsafe fn seL4_SetUserData(data: seL4_Word) { (*seL4_GetIPCBuffer()).userData = data; }
#[inline(always)]
pub unsafe fn seL4_GetBadge(index: usize) -> seL4_Word {
(*seL4_GetIPCBuffer()).caps_or_badges[index]
}
#[inline(always)]
pub unsafe fn seL4_GetCap(index: usize) -> seL4_CPtr {
(*seL4_GetIPCBuffer()).caps_or_badges[index] as seL4_CPtr
}
#[inline(always)]
pub unsafe fn seL4_SetCap(index: usize, cptr: seL4_CPtr) {
(*seL4_GetIPCBuffer()).caps_or_badges[index] = cptr as seL4_Word;
}
#[inline(always)]
pub unsafe fn seL4_GetCapReceivePath() -> (seL4_CPtr, seL4_CPtr, seL4_CPtr) {
let ipcbuffer = seL4_GetIPCBuffer();
(
(*ipcbuffer).receiveCNode,
(*ipcbuffer).receiveIndex,
(*ipcbuffer).receiveDepth,
)
}
#[inline(always)]
pub unsafe fn seL4_SetCapReceivePath(
receiveCNode: seL4_CPtr,
receiveIndex: seL4_CPtr,
receiveDepth: seL4_Word,
) {
let ipcbuffer = seL4_GetIPCBuffer();
(*ipcbuffer).receiveCNode = receiveCNode;
(*ipcbuffer).receiveIndex = receiveIndex;
(*ipcbuffer).receiveDepth = receiveDepth;
}
macro_rules! swinum {
($val:expr) => {
$val as seL4_Word
};
}
macro_rules! opt_assign {
($loc:expr, $val:expr) => {
if !$loc.is_null() {
*$loc = $val;
}
};
}
// Syscall asm idioms. MCS-dependent asm wrappers are defined in
// the _mcs.rs & _no_mcs.rs files included below.
// NB: these correspond to riscv_sys_* in libsel4's syscalls.h files
// Fills all message registers. Discards everything returned by the kerrnel.
// Used for 1-way sends like seL4_Send.
macro_rules! asm_send {
($syscall:expr, $dest:expr, $info:expr, $mr0:expr, $mr1:expr, $mr2:expr, $mr3:expr) => {
asm!("ecall",
in("a7") swinum!($syscall),
inout("a0") $dest => _,
inout("a1") $info => _,
inout("a2") $mr0 => _,
inout("a3") $mr1 => _,
inout("a4") $mr2 => _,
inout("a5") $mr3 => _,
)
};
($syscall:expr, $dest:expr, $info:expr => $info_recv:expr, $mr0:expr, $mr1:expr, $mr2:expr, $mr3:expr) => {
asm!("ecall",
in("a7") swinum!($syscall),
inout("a0") $dest => _,
inout("a1") $info => $info_recv,
inout("a2") $mr0 => _,
inout("a3") $mr1 => _,
inout("a4") $mr2 => _,
inout("a5") $mr3 => _,
)
};
}
// Fills no message registers. Discards everything returned by the kernel.
// Used for 1-way sends that contain no data, like seL4_Notify.
macro_rules! asm_send_no_mrs {
($syscall:expr, $dest:expr, $info:expr) => {
asm!("ecall",
in("a7") swinum!($syscall),
inout("a0") $dest => _,
inout("a1") $info => _,
)
};
}
// Fills only the syscall number. Indicates nothing in memory
// is clobbered. Used for calls like seL4_Yield.
macro_rules! asm_no_args {
($syscall:expr) => {
asm!("ecall",
in("a7") swinum!($syscall),
options(nomem, nostack),
)
};
}
include!("syscall_common.rs");
cfg_if! {
if #[cfg(feature = "CONFIG_KERNEL_MCS")] {
include!("riscv32_mcs.rs");
include!("syscall_mcs.rs");
} else {
include!("riscv32_no_mcs.rs");
include!("syscall_no_mcs.rs");
}
}
// TODO(sleffler): move to syscall_common.rs
cfg_if! {
if #[cfg(feature = "CONFIG_PRINTING")] {
#[inline(always)]
pub unsafe fn seL4_DebugPutChar(c: u8) {
asm!("ecall",
in("a7") swinum!(SyscallId::DebugPutChar),
in("a0") c,
options(nostack),
);
}
#[inline(always)]
pub unsafe fn seL4_DebugDumpScheduler() {
asm!("ecall",
in("a7") swinum!(SyscallId::DebugDumpScheduler),
options(nomem, nostack),
);
}
#[inline(always)]
pub unsafe fn seL4_DebugDumpCNode(mut cap: seL4_CPtr) {
asm!("ecall",
in("a7") swinum!(SyscallId::DebugDumpCNode),
inout("a0") cap,
options(nomem, nostack),
);
}
} // CONFIG_PRINTING
}
cfg_if! {
if #[cfg(feature = "CONFIG_DEBUG_BUILD")] {
#[inline(always)]
pub unsafe fn seL4_DebugHalt() {
asm_no_args!(SyscallId::DebugHalt);
}
#[inline(always)]
pub unsafe fn seL4_DebugSnapshot() {
asm_no_args!(SyscallId::DebugSnapshot);
}
#[inline(always)]
pub unsafe fn seL4_DebugCapIdentify(mut cap: seL4_CPtr) -> u32 {
asm!("ecall",
in("a7") swinum!(SyscallId::DebugCapIdentify),
inout("a0") cap,
options(nomem, nostack),
);
cap as _
}
// Note: name MUST be NUL-terminated.
#[inline(always)]
pub unsafe fn seL4_DebugNameThread(tcb: seL4_CPtr, name: &[u8]) {
core::ptr::copy_nonoverlapping(
name.as_ptr() as *mut u8,
(&mut (*seL4_GetIPCBuffer()).msg).as_mut_ptr() as *mut u8,
name.len(),
);
asm!("ecall",
in("a7") swinum!(SyscallId::DebugNameThread),
in("a0") tcb,
);
}
} // CONFIG_DEBUG_BUILD
}
#[cfg(feature = "CONFIG_DANGEROUS_CODE_INJECTION")]
#[inline(always)]
pub unsafe fn seL4_DebugRun(userfn: extern "C" fn(*mut u8), userarg: *mut u8) {
let userfnptr = userfn as *mut ();
asm!("ecall",
in("a7") swinum!(SyscallId::DebugRun),
in("a0") userfnptr,
in("a1") userarg,
);
}
cfg_if! {
if #[cfg(feature = "CONFIG_ENABLE_BENCHMARKS")] {
#[inline(always)]
pub unsafe fn seL4_BenchmarkResetLog() {
asm_no_args!(SyscallId::BenchmarkResetLog);
}
#[inline(always)]
pub unsafe fn seL4_BenchmarkFinalizeLog() {
asm_no_args!(SyscallId::BenchmarkFinalizeLog);
}
// TODO(sleffler): seL4_BenchmarkSetLogBuffer
// TODO(sleffler): seL4_BenchmarkNullSyscall
// TODO(sleffler): seL4_BenchmarkFlushCaches
// TODO(sleffler): seL4_BenchmarkFlushL1Caches
} // CONFIG_ENABLE_BENCHMARKS
}
#[cfg(feature = "CONFIG_SET_TLS_BASE_SELF")]
pub unsafe fn seL4_SetTLSBase(tls_base: seL4_Word) {
let info: seL4_Word = 0; // XXX does this dtrt?
asm!("ecall",
in("a7") swinum!(SyscallId::SetTLSBase),
in("a0") tls_base,
in("a1") info,
);
}