feat(kernel): seL4-style IPC, notifications, status ABI
- badges + Mint, Call/Reply/ReplyRecv w/ gen-checked reply slot - cap transfer (1/msg, copy, needs Delegate, rechecked at delivery) - notifications: signal/wait/poll/bind, irq -> notification routing - WaitAny/WaitForInterrupt removed; a0=status, ErrorCode - libkos: single ecall primitive, compat wrappers + typed new api - fix: trap return clobbered user t0 on every trap - fix: wait queues FIFO, delegate keeps badge, fault cap checked - docs/ipc.md spec, ipc tests, ipc fuzz, kani ntfn + waitqueue
This commit is contained in:
@@ -80,13 +80,17 @@ impl AllocatorInner {
|
||||
if prev.is_null() {
|
||||
self.free_list = new_block;
|
||||
} else {
|
||||
unsafe { (*prev).next = new_block; }
|
||||
unsafe {
|
||||
(*prev).next = new_block;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if prev.is_null() {
|
||||
self.free_list = block.next;
|
||||
} else {
|
||||
unsafe { (*prev).next = block.next; }
|
||||
unsafe {
|
||||
(*prev).next = block.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,4 @@
|
||||
pub fn syscall0(_nr: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn syscall1(_nr: usize, _a0: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn syscall2(_nr: usize, _a0: usize, _a1: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn syscall3(_nr: usize, _a0: usize, _a1: usize, _a2: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn syscall4(_nr: usize, _a0: usize, _a1: usize, _a2: usize, _a3: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn syscall5(_nr: usize, _a0: usize, _a1: usize, _a2: usize, _a3: usize, _a4: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn syscall_receive(_nr: usize, _a0: usize) -> (usize, usize, usize, usize) {
|
||||
(0, 0, 0, 0)
|
||||
/// Host builds have no kernel; every call reports success with zeroes.
|
||||
pub fn syscall(_nr: usize, _args: [usize; 6]) -> [usize; 8] {
|
||||
[0; 8]
|
||||
}
|
||||
|
||||
@@ -1,106 +1,20 @@
|
||||
/// One `ecall`: syscall number in `a7`, arguments in `a0..a5`. Returns the
|
||||
/// eight result registers `a0..a7` (docs/ipc.md, register ABI).
|
||||
#[inline(always)]
|
||||
pub fn syscall0(nr: usize) -> usize {
|
||||
let ret: usize;
|
||||
pub fn syscall(nr: usize, args: [usize; 6]) -> [usize; 8] {
|
||||
let mut r = [0usize; 8];
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
lateout("a0") ret,
|
||||
inlateout("a0") args[0] => r[0],
|
||||
inlateout("a1") args[1] => r[1],
|
||||
inlateout("a2") args[2] => r[2],
|
||||
inlateout("a3") args[3] => r[3],
|
||||
inlateout("a4") args[4] => r[4],
|
||||
inlateout("a5") args[5] => r[5],
|
||||
lateout("a6") r[6],
|
||||
inlateout("a7") nr => r[7],
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syscall1(nr: usize, a0: usize) -> usize {
|
||||
let ret: usize;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
inlateout("a0") a0 => ret,
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syscall2(nr: usize, a0: usize, a1: usize) -> usize {
|
||||
let ret: usize;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
inlateout("a0") a0 => ret,
|
||||
in("a1") a1,
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syscall3(nr: usize, a0: usize, a1: usize, a2: usize) -> usize {
|
||||
let ret: usize;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
inlateout("a0") a0 => ret,
|
||||
in("a1") a1,
|
||||
in("a2") a2,
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syscall4(nr: usize, a0: usize, a1: usize, a2: usize, a3: usize) -> usize {
|
||||
let ret: usize;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
inlateout("a0") a0 => ret,
|
||||
in("a1") a1,
|
||||
in("a2") a2,
|
||||
in("a3") a3,
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syscall5(nr: usize, a0: usize, a1: usize, a2: usize, a3: usize, a4: usize) -> usize {
|
||||
let ret: usize;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
inlateout("a0") a0 => ret,
|
||||
in("a1") a1,
|
||||
in("a2") a2,
|
||||
in("a3") a3,
|
||||
in("a4") a4,
|
||||
);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn syscall_receive(nr: usize, a0: usize) -> (usize, usize, usize, usize) {
|
||||
let r0: usize;
|
||||
let r1: usize;
|
||||
let r2: usize;
|
||||
let r3: usize;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"ecall",
|
||||
in("a7") nr,
|
||||
inlateout("a0") a0 => r0,
|
||||
lateout("a1") r1,
|
||||
lateout("a2") r2,
|
||||
lateout("a3") r3,
|
||||
);
|
||||
}
|
||||
(r0, r1, r2, r3)
|
||||
r
|
||||
}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
use crate::syscall;
|
||||
use types::bounded::CapSlot;
|
||||
use types::display::{Color, Dimension, ScreenCoord};
|
||||
use crate::syscall;
|
||||
|
||||
fn ipc(ep: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> (usize, usize, usize, usize) {
|
||||
syscall::send(ep, w0, w1, w2, w3);
|
||||
syscall::receive(ep)
|
||||
}
|
||||
|
||||
pub fn draw_rect(ep: CapSlot, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) {
|
||||
pub fn draw_rect(
|
||||
ep: CapSlot,
|
||||
x: ScreenCoord,
|
||||
y: ScreenCoord,
|
||||
w: Dimension,
|
||||
h: Dimension,
|
||||
color: Color,
|
||||
) {
|
||||
let xy = (x.raw() as usize) | ((y.raw() as usize) << 16);
|
||||
let wh = (w.raw() as usize) | ((h.raw() as usize) << 16);
|
||||
ipc(ep, 0, xy, wh, color.raw() as usize);
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
use types::bounded::CapSlot;
|
||||
use crate::syscall;
|
||||
use types::bounded::CapSlot;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct FileHandle(u16);
|
||||
|
||||
impl FileHandle {
|
||||
pub const fn raw(&self) -> u16 { self.0 }
|
||||
pub const fn raw(&self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn pack_path(path: &[u8]) -> (usize, usize) {
|
||||
let mut w0 = [0u8; 8];
|
||||
let mut w1 = [0u8; 8];
|
||||
for (i, &b) in path.iter().enumerate() {
|
||||
if i < 8 { w0[i] = b; }
|
||||
else if i < 16 { w1[i - 8] = b; }
|
||||
if i < 8 {
|
||||
w0[i] = b;
|
||||
} else if i < 16 {
|
||||
w1[i - 8] = b;
|
||||
}
|
||||
}
|
||||
(usize::from_le_bytes(w0), usize::from_le_bytes(w1))
|
||||
}
|
||||
@@ -26,7 +31,11 @@ fn ipc(ep: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> (usize, usize
|
||||
pub fn open(ep: CapSlot, path: &[u8]) -> Option<FileHandle> {
|
||||
let (p0, p1) = pack_path(path);
|
||||
let (tag, handle, _, _) = ipc(ep, 0, p0, p1, 0);
|
||||
if tag == 0 { Some(FileHandle(handle as u16)) } else { None }
|
||||
if tag == 0 {
|
||||
Some(FileHandle(handle as u16))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(ep: CapSlot, handle: FileHandle, max_bytes: usize) -> Option<usize> {
|
||||
@@ -52,7 +61,11 @@ pub fn list_dir(ep: CapSlot, path: &[u8]) -> Option<usize> {
|
||||
pub fn create(ep: CapSlot, path: &[u8]) -> Option<FileHandle> {
|
||||
let (p0, p1) = pack_path(path);
|
||||
let (tag, handle, _, _) = ipc(ep, 5, p0, p1, 0);
|
||||
if tag == 0 { Some(FileHandle(handle as u16)) } else { None }
|
||||
if tag == 0 {
|
||||
Some(FileHandle(handle as u16))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(ep: CapSlot, path: &[u8]) -> bool {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use types::bounded::CapSlot;
|
||||
use crate::syscall;
|
||||
use types::bounded::CapSlot;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Key {
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod arch;
|
||||
pub mod syscall;
|
||||
pub mod alloc_impl;
|
||||
pub mod io;
|
||||
pub mod fs;
|
||||
mod arch;
|
||||
pub mod display;
|
||||
pub mod fs;
|
||||
pub mod input;
|
||||
pub mod io;
|
||||
mod rt;
|
||||
pub mod syscall;
|
||||
|
||||
#[cfg(target_os = "none")]
|
||||
#[global_allocator]
|
||||
|
||||
@@ -1,90 +1,335 @@
|
||||
//! Thin wrappers over the kernel's register ABI (docs/ipc.md). Every call
|
||||
//! returns a status in `a0`; results follow in `a1..`.
|
||||
|
||||
use crate::arch;
|
||||
use types::syscall_abi::*;
|
||||
use types::address::{EntryPoint, StackPointer, VirtualAddress};
|
||||
use types::badge::Badge;
|
||||
use types::bounded::{CapSlot, PageCount};
|
||||
use types::id::ProcessId;
|
||||
use types::permission::PermissionSet;
|
||||
use types::syscall_abi::*;
|
||||
use types::time::Ticks;
|
||||
|
||||
pub use types::syscall_abi::ErrorCode as Error;
|
||||
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
fn raw(nr: usize, args: [usize; 6]) -> Result<[usize; 8]> {
|
||||
let r = arch::syscall(nr, args);
|
||||
match r[0] {
|
||||
0 => Ok(r),
|
||||
code => Err(Error::from_raw(code).unwrap_or(Error::InvalidArgument)),
|
||||
}
|
||||
}
|
||||
|
||||
fn call0(nr: usize) -> Result<[usize; 8]> {
|
||||
raw(nr, [0; 6])
|
||||
}
|
||||
|
||||
fn slot_arg(slot: Option<CapSlot>) -> usize {
|
||||
slot.map_or(NONE, |s| s.value() as usize)
|
||||
}
|
||||
|
||||
fn slot_result(r: usize) -> Option<CapSlot> {
|
||||
if r == NONE {
|
||||
None
|
||||
} else {
|
||||
CapSlot::new(r as u8)
|
||||
}
|
||||
}
|
||||
|
||||
fn slot_of(r: Result<[usize; 8]>) -> Result<CapSlot> {
|
||||
r.and_then(|r| slot_result(r[1]).ok_or(Error::InvalidArgument))
|
||||
}
|
||||
|
||||
/// What a receiving call got.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Received {
|
||||
/// A `Send`. `badge` identifies the sender's capability.
|
||||
Message {
|
||||
badge: usize,
|
||||
words: [usize; 4],
|
||||
cap: Option<CapSlot>,
|
||||
},
|
||||
/// A `Call`; answer it with `reply` or `reply_recv`.
|
||||
Call {
|
||||
badge: usize,
|
||||
words: [usize; 4],
|
||||
cap: Option<CapSlot>,
|
||||
},
|
||||
/// Bits from a notification.
|
||||
Signal { bits: usize },
|
||||
}
|
||||
|
||||
impl Received {
|
||||
fn decode(r: [usize; 8]) -> Self {
|
||||
let words = [r[2], r[3], r[4], r[5]];
|
||||
let cap = slot_result(r[6]);
|
||||
match r[7] {
|
||||
KIND_CALL => Received::Call {
|
||||
badge: r[1],
|
||||
words,
|
||||
cap,
|
||||
},
|
||||
KIND_SIGNAL => Received::Signal { bits: r[1] },
|
||||
_ => Received::Message {
|
||||
badge: r[1],
|
||||
words,
|
||||
cap,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn words(&self) -> [usize; 4] {
|
||||
match self {
|
||||
Received::Message { words, .. } | Received::Call { words, .. } => *words,
|
||||
Received::Signal { .. } => [0; 4],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn message_args(ep: usize, words: [usize; 4], cap: Option<CapSlot>) -> [usize; 6] {
|
||||
[ep, words[0], words[1], words[2], words[3], slot_arg(cap)]
|
||||
}
|
||||
|
||||
// ---- threads, processes, time ----
|
||||
|
||||
pub fn exit() -> ! {
|
||||
arch::syscall0(SYS_EXIT);
|
||||
let _ = call0(SYS_EXIT);
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn exit_thread() -> ! {
|
||||
arch::syscall0(SYS_EXIT_THREAD);
|
||||
let _ = call0(SYS_EXIT_THREAD);
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
arch::syscall0(SYS_YIELD);
|
||||
let _ = call0(SYS_YIELD);
|
||||
}
|
||||
|
||||
pub fn halt() -> ! {
|
||||
arch::syscall0(SYS_HALT);
|
||||
let _ = call0(SYS_HALT);
|
||||
loop {}
|
||||
}
|
||||
|
||||
pub fn get_time() -> Ticks {
|
||||
Ticks::from_raw(arch::syscall0(SYS_GET_TIME) as u64)
|
||||
Ticks::from_raw(call0(SYS_GET_TIME).map_or(0, |r| r[1]) as u64)
|
||||
}
|
||||
|
||||
pub fn get_process_id() -> ProcessId {
|
||||
ProcessId::from_raw(arch::syscall0(SYS_GET_PROCESS_ID) as u16)
|
||||
ProcessId::from_raw(call0(SYS_GET_PROCESS_ID).map_or(0, |r| r[1]) as u16)
|
||||
}
|
||||
|
||||
pub fn create_process(create_cap: CapSlot) -> Option<CapSlot> {
|
||||
let r = arch::syscall1(SYS_CREATE_PROCESS, create_cap.value() as usize);
|
||||
if r == usize::MAX { None } else { CapSlot::new(r as u8) }
|
||||
}
|
||||
|
||||
pub fn create_endpoint() -> Option<CapSlot> {
|
||||
let r = arch::syscall0(SYS_CREATE_ENDPOINT);
|
||||
if r == usize::MAX { None } else { CapSlot::new(r as u8) }
|
||||
slot_of(raw(
|
||||
SYS_CREATE_PROCESS,
|
||||
[create_cap.value() as usize, 0, 0, 0, 0, 0],
|
||||
))
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn spawn_thread(entry: EntryPoint, stack: StackPointer) -> usize {
|
||||
arch::syscall2(SYS_SPAWN_THREAD, entry.raw(), stack.raw())
|
||||
raw(SYS_SPAWN_THREAD, [entry.raw(), stack.raw(), 0, 0, 0, 0]).map_or(NONE, |r| r[1])
|
||||
}
|
||||
|
||||
pub fn spawn_thread_in(process_cap: CapSlot, entry: EntryPoint, stack: StackPointer) -> usize {
|
||||
arch::syscall3(SYS_SPAWN_THREAD_IN, process_cap.value() as usize, entry.raw(), stack.raw())
|
||||
}
|
||||
|
||||
pub fn request_pages(count: PageCount) -> Option<VirtualAddress> {
|
||||
let r = arch::syscall1(SYS_REQUEST_PAGES, count.value() as usize);
|
||||
if r == usize::MAX { None } else { Some(VirtualAddress::from_raw(r)) }
|
||||
}
|
||||
|
||||
pub fn map_page(process_cap: CapSlot, src_va: VirtualAddress, dst_va: VirtualAddress, executable: bool) -> bool {
|
||||
arch::syscall4(SYS_MAP_PAGE, process_cap.value() as usize, src_va.raw(), dst_va.raw(), executable as usize) == 0
|
||||
}
|
||||
|
||||
pub fn send(endpoint: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
|
||||
arch::syscall5(SYS_SEND, endpoint.value() as usize, w0, w1, w2, w3)
|
||||
}
|
||||
|
||||
pub fn receive(endpoint: CapSlot) -> (usize, usize, usize, usize) {
|
||||
arch::syscall_receive(SYS_RECEIVE, endpoint.value() as usize)
|
||||
}
|
||||
|
||||
pub fn delegate(slot: CapSlot, to: CapSlot, permissions: PermissionSet) -> bool {
|
||||
arch::syscall3(SYS_DELEGATE, slot.value() as usize, to.value() as usize, permissions.bits() as usize) == 0
|
||||
raw(
|
||||
SYS_SPAWN_THREAD_IN,
|
||||
[
|
||||
process_cap.value() as usize,
|
||||
entry.raw(),
|
||||
stack.raw(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
)
|
||||
.map_or(NONE, |r| r[1])
|
||||
}
|
||||
|
||||
pub fn kill(process_cap: CapSlot) -> bool {
|
||||
arch::syscall1(SYS_KILL, process_cap.value() as usize) == 0
|
||||
raw(SYS_KILL, [process_cap.value() as usize, 0, 0, 0, 0, 0]).is_ok()
|
||||
}
|
||||
|
||||
// ---- memory ----
|
||||
|
||||
pub fn request_pages(count: PageCount) -> Option<VirtualAddress> {
|
||||
raw(SYS_REQUEST_PAGES, [count.value() as usize, 0, 0, 0, 0, 0])
|
||||
.ok()
|
||||
.map(|r| VirtualAddress::from_raw(r[1]))
|
||||
}
|
||||
|
||||
pub fn map_page(
|
||||
process_cap: CapSlot,
|
||||
src_va: VirtualAddress,
|
||||
dst_va: VirtualAddress,
|
||||
executable: bool,
|
||||
) -> bool {
|
||||
raw(
|
||||
SYS_MAP_PAGE,
|
||||
[
|
||||
process_cap.value() as usize,
|
||||
src_va.raw(),
|
||||
dst_va.raw(),
|
||||
executable as usize,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
// ---- capabilities ----
|
||||
|
||||
pub fn delegate(slot: CapSlot, to: CapSlot, permissions: PermissionSet) -> bool {
|
||||
raw(
|
||||
SYS_DELEGATE,
|
||||
[
|
||||
slot.value() as usize,
|
||||
to.value() as usize,
|
||||
permissions.bits() as usize,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
/// Copies an unbadged endpoint or notification capability with `badge`
|
||||
/// and at most `permissions`.
|
||||
pub fn mint(slot: CapSlot, badge: Badge, permissions: PermissionSet) -> Result<CapSlot> {
|
||||
slot_of(raw(
|
||||
SYS_MINT,
|
||||
[
|
||||
slot.value() as usize,
|
||||
badge.raw(),
|
||||
permissions.bits() as usize,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
))
|
||||
}
|
||||
|
||||
pub fn revoke(slot: CapSlot) -> bool {
|
||||
arch::syscall1(SYS_REVOKE, slot.value() as usize) == 0
|
||||
raw(SYS_REVOKE, [slot.value() as usize, 0, 0, 0, 0, 0]).is_ok()
|
||||
}
|
||||
|
||||
/// Removes a capability from this process's own table, freeing the slot.
|
||||
pub fn drop_cap(slot: CapSlot) -> bool {
|
||||
arch::syscall1(SYS_DROP_CAP, slot.value() as usize) == 0
|
||||
raw(SYS_DROP_CAP, [slot.value() as usize, 0, 0, 0, 0, 0]).is_ok()
|
||||
}
|
||||
|
||||
// ---- endpoints ----
|
||||
|
||||
pub fn create_endpoint() -> Option<CapSlot> {
|
||||
slot_of(call0(SYS_CREATE_ENDPOINT)).ok()
|
||||
}
|
||||
|
||||
/// Sends four words; returns 0 on success (kept for existing callers).
|
||||
pub fn send(endpoint: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
|
||||
match send_msg(endpoint, [w0, w1, w2, w3], None) {
|
||||
Ok(()) => 0,
|
||||
Err(e) => e as usize,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_msg(endpoint: CapSlot, words: [usize; 4], cap: Option<CapSlot>) -> Result<()> {
|
||||
raw(
|
||||
SYS_SEND,
|
||||
message_args(endpoint.value() as usize, words, cap),
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
/// Receives and returns just the words (kept for existing callers).
|
||||
pub fn receive(endpoint: CapSlot) -> (usize, usize, usize, usize) {
|
||||
let w = receive_msg(endpoint).map_or([0; 4], |r| r.words());
|
||||
(w[0], w[1], w[2], w[3])
|
||||
}
|
||||
|
||||
pub fn receive_msg(endpoint: CapSlot) -> Result<Received> {
|
||||
raw(SYS_RECEIVE, [endpoint.value() as usize, 0, 0, 0, 0, 0]).map(Received::decode)
|
||||
}
|
||||
|
||||
/// Sends and waits for the reply.
|
||||
pub fn call(endpoint: CapSlot, words: [usize; 4], cap: Option<CapSlot>) -> Result<Received> {
|
||||
raw(
|
||||
SYS_CALL,
|
||||
message_args(endpoint.value() as usize, words, cap),
|
||||
)
|
||||
.map(Received::decode)
|
||||
}
|
||||
|
||||
/// Answers the last `Call` this thread received.
|
||||
pub fn reply(words: [usize; 4], cap: Option<CapSlot>) -> Result<()> {
|
||||
raw(SYS_REPLY, message_args(0, words, cap)).map(|_| ())
|
||||
}
|
||||
|
||||
/// Replies to the pending `Call` (if any), then receives the next message.
|
||||
pub fn reply_recv(endpoint: CapSlot, words: [usize; 4], cap: Option<CapSlot>) -> Result<Received> {
|
||||
raw(
|
||||
SYS_REPLY_RECV,
|
||||
message_args(endpoint.value() as usize, words, cap),
|
||||
)
|
||||
.map(Received::decode)
|
||||
}
|
||||
|
||||
// ---- notifications and interrupts ----
|
||||
|
||||
pub fn create_notification() -> Result<CapSlot> {
|
||||
slot_of(call0(SYS_CREATE_NOTIFICATION))
|
||||
}
|
||||
|
||||
pub fn signal(notification: CapSlot) -> Result<()> {
|
||||
raw(SYS_SIGNAL, [notification.value() as usize, 0, 0, 0, 0, 0]).map(|_| ())
|
||||
}
|
||||
|
||||
/// Blocks until the notification has bits, then returns and clears them.
|
||||
pub fn wait(notification: CapSlot) -> Result<usize> {
|
||||
raw(SYS_WAIT, [notification.value() as usize, 0, 0, 0, 0, 0]).map(|r| r[1])
|
||||
}
|
||||
|
||||
/// Returns and clears the bits without blocking.
|
||||
pub fn poll(notification: CapSlot) -> Result<usize> {
|
||||
raw(SYS_POLL, [notification.value() as usize, 0, 0, 0, 0, 0]).map(|r| r[1])
|
||||
}
|
||||
|
||||
/// After this, `receive` also returns when the notification is signalled.
|
||||
pub fn bind_notification(notification: CapSlot) -> Result<()> {
|
||||
raw(
|
||||
SYS_BIND_NOTIFICATION,
|
||||
[notification.value() as usize, 0, 0, 0, 0, 0],
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
/// Delivers interrupt `irq` as a signal on `notification`.
|
||||
pub fn set_irq_notification(irq: CapSlot, notification: CapSlot) -> Result<()> {
|
||||
raw(
|
||||
SYS_SET_IRQ_NOTIFICATION,
|
||||
[
|
||||
irq.value() as usize,
|
||||
notification.value() as usize,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub fn ack_interrupt(irq: CapSlot) -> Result<()> {
|
||||
raw(
|
||||
SYS_ACKNOWLEDGE_INTERRUPT,
|
||||
[irq.value() as usize, 0, 0, 0, 0, 0],
|
||||
)
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub fn debug_putchar(byte: u8) {
|
||||
arch::syscall1(SYS_DEBUG_PUTCHAR, byte as usize);
|
||||
let _ = raw(SYS_DEBUG_PUTCHAR, [byte as usize, 0, 0, 0, 0, 0]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user