feat: userspace round-trip — syscall stubs, ecall dispatch, U-mode entry and exit on QEMU
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"crates/adapter-riscv",
|
"crates/adapter-riscv",
|
||||||
|
"crates/apps/hello",
|
||||||
"crates/apps/snake",
|
"crates/apps/snake",
|
||||||
"crates/domain",
|
"crates/domain",
|
||||||
"crates/elf",
|
"crates/elf",
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ mod trap;
|
|||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
use hw::uart::Uart;
|
use hw::uart::Uart;
|
||||||
|
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
|
|
||||||
|
static mut KERNEL: Option<kernel::Kernel<platform::RiscVPlatform>> = None;
|
||||||
|
|
||||||
|
pub fn kernel_mut() -> &'static mut kernel::Kernel<platform::RiscVPlatform> {
|
||||||
|
unsafe { (*addr_of_mut!(KERNEL)).as_mut() }.unwrap_or_else(|| unreachable!())
|
||||||
|
}
|
||||||
|
|
||||||
global_asm!(
|
global_asm!(
|
||||||
r#"
|
r#"
|
||||||
.section .text.entry
|
.section .text.entry
|
||||||
@@ -61,18 +69,16 @@ extern "C" fn kmain() -> ! {
|
|||||||
types::address::PhysicalAddress::from_raw(board::USER_POOL_BASE),
|
types::address::PhysicalAddress::from_raw(board::USER_POOL_BASE),
|
||||||
board::USER_POOL_PAGES,
|
board::USER_POOL_PAGES,
|
||||||
);
|
);
|
||||||
let mut kern = kernel::Kernel::new(riscv_platform, pool);
|
let kern = kernel::Kernel::new(riscv_platform, pool);
|
||||||
let (pid, tid) = kern
|
unsafe { *addr_of_mut!(KERNEL) = Some(kern); }
|
||||||
|
let kern = kernel_mut();
|
||||||
|
|
||||||
|
let (_pid, _tid) = kern
|
||||||
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
||||||
.unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; });
|
.unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; });
|
||||||
|
uart.write_str("k-os: kernel started\n");
|
||||||
|
|
||||||
uart.write_str("k-os: kernel started (pid=");
|
userspace_demo(kern, &uart, kernel_pt);
|
||||||
uart.write_dec(pid.raw() as usize);
|
|
||||||
uart.write_str(", tid=");
|
|
||||||
uart.write_dec(tid.raw() as usize);
|
|
||||||
uart.write_str(")\n");
|
|
||||||
|
|
||||||
ipc_demo(&mut kern, &uart, pid);
|
|
||||||
|
|
||||||
uart.write_str("k-os: demo complete\n");
|
uart.write_str("k-os: demo complete\n");
|
||||||
loop {
|
loop {
|
||||||
@@ -80,100 +86,70 @@ extern "C" fn kmain() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ipc_demo(
|
// Tiny userspace program: li a7, SYS_EXIT; ecall; j -4
|
||||||
kern: &mut kernel::Kernel<platform::RiscVPlatform>,
|
// SYS_EXIT = 16 = 0x10
|
||||||
|
// RISC-V instructions (little-endian):
|
||||||
|
// li a7, 16 → addi a7, zero, 16 → 0x01000893
|
||||||
|
// ecall → 0x00000073
|
||||||
|
// j -4 → 0xffdff06f
|
||||||
|
static USER_EXIT_PROGRAM: [u8; 12] = [
|
||||||
|
0x93, 0x08, 0x00, 0x01, // addi a7, zero, 16
|
||||||
|
0x73, 0x00, 0x00, 0x00, // ecall
|
||||||
|
0x6f, 0xf0, 0xdf, 0xff, // j -4
|
||||||
|
];
|
||||||
|
|
||||||
|
const USER_VA: usize = 0x10000;
|
||||||
|
|
||||||
|
fn userspace_demo(
|
||||||
|
_kern: &mut kernel::Kernel<platform::RiscVPlatform>,
|
||||||
uart: &Uart,
|
uart: &Uart,
|
||||||
init_pid: types::id::ProcessId,
|
kernel_pt: &mmu::PageTable,
|
||||||
) {
|
) {
|
||||||
use domain::message::Message;
|
uart.write_str("k-os: --- userspace demo ---\n");
|
||||||
use domain::resource::Resource;
|
|
||||||
use domain::syscall::Syscall;
|
|
||||||
use kernel::{SyscallOutcome, SyscallResult};
|
|
||||||
use types::address::DataRef;
|
|
||||||
use types::bounded::CapSlot;
|
|
||||||
use types::id::ThreadId;
|
|
||||||
use types::permission::{Permission, PermissionSet};
|
|
||||||
|
|
||||||
uart.write_str("k-os: --- IPC demo ---\n");
|
// Allocate a page for the user program and copy code into it
|
||||||
|
let program_page = mmu::allocator::alloc_zeroed_page();
|
||||||
let _proc_b_slot = match kern.handle_syscall(Syscall::CreateProcess {
|
unsafe {
|
||||||
create_cap: CapSlot::new(0).unwrap_or_else(|| unreachable!()),
|
core::ptr::copy_nonoverlapping(
|
||||||
image: DataRef::empty(),
|
USER_EXIT_PROGRAM.as_ptr(),
|
||||||
}) {
|
program_page as *mut u8,
|
||||||
SyscallOutcome::Complete(SyscallResult::Slot(s)) => s,
|
USER_EXIT_PROGRAM.len(),
|
||||||
_ => {
|
);
|
||||||
uart.write_str("k-os: FAIL creating process B\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let pid_b = types::id::ProcessId::from_raw(1);
|
|
||||||
let tid_b = ThreadId::from_raw(1);
|
|
||||||
uart.write_str("k-os: process B created\n");
|
|
||||||
|
|
||||||
let ep_id = kern.create_endpoint().unwrap_or_else(|_| unreachable!());
|
|
||||||
|
|
||||||
let ep_cap_a = kern.grant_capability(
|
|
||||||
init_pid,
|
|
||||||
Resource::Endpoint(ep_id),
|
|
||||||
PermissionSet::empty()
|
|
||||||
.with(Permission::Execute)
|
|
||||||
.with(Permission::Read),
|
|
||||||
).unwrap_or_else(|_| unreachable!());
|
|
||||||
|
|
||||||
let ep_cap_b = kern.grant_capability(
|
|
||||||
pid_b,
|
|
||||||
Resource::Endpoint(ep_id),
|
|
||||||
PermissionSet::empty()
|
|
||||||
.with(Permission::Execute)
|
|
||||||
.with(Permission::Read),
|
|
||||||
).unwrap_or_else(|_| unreachable!());
|
|
||||||
|
|
||||||
uart.write_str("k-os: endpoint created, caps granted\n");
|
|
||||||
|
|
||||||
kern.switch_to_thread(tid_b);
|
|
||||||
match kern.handle_syscall(Syscall::Receive { endpoint: ep_cap_b }) {
|
|
||||||
SyscallOutcome::BlockCaller(_) => {
|
|
||||||
uart.write_str("k-os: process B blocked on Receive\n");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
uart.write_str("k-os: UNEXPECTED outcome for Receive\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tid_a = ThreadId::from_raw(0);
|
// Create user page table with program mapped at USER_VA
|
||||||
kern.switch_to_thread(tid_a);
|
let user_pt = mmu::create_user_page_table(
|
||||||
let msg = Message::from_words([42, 7, 0, 0]);
|
kernel_pt,
|
||||||
match kern.handle_syscall(Syscall::Send {
|
program_page,
|
||||||
endpoint: ep_cap_a,
|
1,
|
||||||
message: msg,
|
USER_VA,
|
||||||
}) {
|
);
|
||||||
SyscallOutcome::SwitchTo(target) => {
|
|
||||||
uart.write_str("k-os: Send delivered, switching to thread ");
|
|
||||||
uart.write_dec(target.raw() as usize);
|
|
||||||
uart.put_char(b'\n');
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
uart.write_str("k-os: UNEXPECTED outcome for Send\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match kern.pending_result(tid_b) {
|
uart.write_str("k-os: user page table created, entering U-mode\n");
|
||||||
Some(SyscallResult::Message(m)) => {
|
|
||||||
uart.write_str("k-os: IPC complete — received: [");
|
// Activate user page table
|
||||||
uart.write_dec(m.word(0));
|
mmu::activate(user_pt);
|
||||||
uart.write_str(", ");
|
|
||||||
uart.write_dec(m.word(1));
|
// Set sscratch to kernel stack so trap vector can switch stacks
|
||||||
uart.write_str(", ");
|
let kernel_sp: usize;
|
||||||
uart.write_dec(m.word(2));
|
unsafe { core::arch::asm!("mv {0}, sp", out(reg) kernel_sp) };
|
||||||
uart.write_str(", ");
|
trap::set_kernel_stack(kernel_sp);
|
||||||
uart.write_dec(m.word(3));
|
|
||||||
uart.write_str("]\n");
|
// Enter user mode: set sstatus.SPP=0 (U-mode), sepc=USER_VA, sret
|
||||||
}
|
let user_stack = USER_VA - 8; // stack below program
|
||||||
_ => {
|
unsafe {
|
||||||
uart.write_str("k-os: FAIL — no message in pending result\n");
|
core::arch::asm!(
|
||||||
}
|
"csrc sstatus, {spp}", // clear SPP → return to U-mode
|
||||||
|
"csrs sstatus, {spie}", // set SPIE → enable interrupts after sret
|
||||||
|
"csrw sepc, {entry}", // return address = user entry
|
||||||
|
"mv sp, {stack}", // user stack pointer (will be saved to sscratch on swap)
|
||||||
|
"sret",
|
||||||
|
spp = in(reg) 1usize << 8,
|
||||||
|
spie = in(reg) 1usize << 5,
|
||||||
|
entry = in(reg) USER_VA,
|
||||||
|
stack = in(reg) user_stack,
|
||||||
|
options(noreturn),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,19 @@ pub fn init_allocator(start: usize) {
|
|||||||
unsafe { NEXT_FREE = start; }
|
unsafe { NEXT_FREE = start; }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alloc_page_table() -> &'static mut PageTable {
|
pub fn alloc_zeroed_page() -> usize {
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = NEXT_FREE;
|
let addr = NEXT_FREE;
|
||||||
NEXT_FREE += PAGE_SIZE;
|
NEXT_FREE += PAGE_SIZE;
|
||||||
|
core::ptr::write_bytes(addr as *mut u8, 0, PAGE_SIZE);
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_page_table() -> &'static mut PageTable {
|
||||||
|
unsafe {
|
||||||
|
let addr = alloc_zeroed_page();
|
||||||
let table = &mut *(addr as *mut PageTable);
|
let table = &mut *(addr as *mut PageTable);
|
||||||
table.zero();
|
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ impl TrapFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode.
|
|
||||||
// On trap: swap sp/sscratch. If sp==0 after swap, we came from S-mode (undo swap).
|
|
||||||
global_asm!(r#"
|
global_asm!(r#"
|
||||||
.align 4
|
.align 4
|
||||||
.globl trap_vector
|
.globl trap_vector
|
||||||
@@ -149,6 +147,68 @@ pub fn set_kernel_stack(kernel_sp: usize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_syscall(frame: &TrapFrame) -> Option<domain::syscall::Syscall> {
|
||||||
|
use domain::message::Message;
|
||||||
|
use domain::syscall::Syscall;
|
||||||
|
use types::syscall_abi::*;
|
||||||
|
|
||||||
|
let nr = frame.regs[17]; // a7
|
||||||
|
let a0 = frame.regs[10]; // a0
|
||||||
|
let a1 = frame.regs[11]; // a1
|
||||||
|
let a2 = frame.regs[12]; // a2
|
||||||
|
let a3 = frame.regs[13]; // a3
|
||||||
|
let a4 = frame.regs[14]; // a4
|
||||||
|
|
||||||
|
match nr {
|
||||||
|
SYS_EXIT => Some(Syscall::Exit),
|
||||||
|
SYS_EXIT_THREAD => Some(Syscall::ExitThread),
|
||||||
|
SYS_YIELD => Some(Syscall::Yield),
|
||||||
|
SYS_GET_TIME => Some(Syscall::GetTime),
|
||||||
|
SYS_GET_PROCESS_ID => Some(Syscall::GetProcessId),
|
||||||
|
SYS_SEND => {
|
||||||
|
let slot = types::bounded::CapSlot::new(a0 as u8)?;
|
||||||
|
let msg = Message::from_words([a1, a2, a3, a4]);
|
||||||
|
Some(Syscall::Send { endpoint: slot, message: msg })
|
||||||
|
}
|
||||||
|
SYS_RECEIVE => {
|
||||||
|
let slot = types::bounded::CapSlot::new(a0 as u8)?;
|
||||||
|
Some(Syscall::Receive { endpoint: slot })
|
||||||
|
}
|
||||||
|
SYS_SPAWN_THREAD => Some(Syscall::SpawnThread {
|
||||||
|
entry: types::address::EntryPoint::from_raw(a0),
|
||||||
|
stack: types::address::StackPointer::from_raw(a1),
|
||||||
|
}),
|
||||||
|
SYS_REQUEST_PAGES => {
|
||||||
|
let count = types::bounded::PageCount::new(a0 as u16)?;
|
||||||
|
Some(Syscall::RequestPages { count })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_result(frame: &mut TrapFrame, outcome: &kernel::SyscallOutcome) {
|
||||||
|
use kernel::{SyscallOutcome, SyscallResult};
|
||||||
|
|
||||||
|
match outcome {
|
||||||
|
SyscallOutcome::Complete(result) => match result {
|
||||||
|
SyscallResult::Ok => frame.regs[10] = 0,
|
||||||
|
SyscallResult::Value(v) => frame.regs[10] = *v,
|
||||||
|
SyscallResult::Slot(s) => frame.regs[10] = s.value() as usize,
|
||||||
|
SyscallResult::Message(m) => {
|
||||||
|
frame.regs[10] = m.word(0);
|
||||||
|
frame.regs[11] = m.word(1);
|
||||||
|
frame.regs[12] = m.word(2);
|
||||||
|
frame.regs[13] = m.word(3);
|
||||||
|
}
|
||||||
|
SyscallResult::Error(_) => frame.regs[10] = usize::MAX,
|
||||||
|
SyscallResult::WakeReason(_) => frame.regs[10] = 0,
|
||||||
|
},
|
||||||
|
SyscallOutcome::BlockCaller(_) => {}
|
||||||
|
SyscallOutcome::SwitchTo(_) => frame.regs[10] = 0,
|
||||||
|
SyscallOutcome::TerminateCaller => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||||
let scause: usize;
|
let scause: usize;
|
||||||
@@ -171,7 +231,19 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
|||||||
match scause {
|
match scause {
|
||||||
CAUSE_ECALL_U => {
|
CAUSE_ECALL_U => {
|
||||||
frame.sepc += 4;
|
frame.sepc += 4;
|
||||||
uart.write_str("[ecall]\n");
|
|
||||||
|
if let Some(syscall) = decode_syscall(frame) {
|
||||||
|
let kern = crate::kernel_mut();
|
||||||
|
let outcome = kern.handle_syscall(syscall);
|
||||||
|
write_result(frame, &outcome);
|
||||||
|
|
||||||
|
match &outcome {
|
||||||
|
kernel::SyscallOutcome::TerminateCaller => {
|
||||||
|
uart.write_str("k-os: process exited\n");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
uart.write_str("FAULT: scause=");
|
uart.write_str("FAULT: scause=");
|
||||||
|
|||||||
14
crates/apps/hello/Cargo.toml
Normal file
14
crates/apps/hello/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "hello"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
userspace = { workspace = true }
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
panic = "abort"
|
||||||
|
opt-level = "s"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
panic = "abort"
|
||||||
24
crates/apps/hello/src/main.rs
Normal file
24
crates/apps/hello/src/main.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
global_asm!(
|
||||||
|
r#"
|
||||||
|
.section .text.entry
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
call main
|
||||||
|
j _start
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
extern "C" fn main() -> ! {
|
||||||
|
userspace::syscall::exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(_: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
@@ -8,4 +8,5 @@ pub mod macros;
|
|||||||
pub mod permission;
|
pub mod permission;
|
||||||
#[cfg(kani)]
|
#[cfg(kani)]
|
||||||
pub mod proofs;
|
pub mod proofs;
|
||||||
|
pub mod syscall_abi;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
|||||||
17
crates/types/src/syscall_abi.rs
Normal file
17
crates/types/src/syscall_abi.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
pub const SYS_SEND: usize = 0;
|
||||||
|
pub const SYS_RECEIVE: usize = 1;
|
||||||
|
pub const SYS_DELEGATE: usize = 2;
|
||||||
|
pub const SYS_WAIT_FOR_INTERRUPT: usize = 3;
|
||||||
|
pub const SYS_ACKNOWLEDGE_INTERRUPT: usize = 4;
|
||||||
|
pub const SYS_WAIT_ANY: usize = 5;
|
||||||
|
pub const SYS_CREATE_PROCESS: usize = 6;
|
||||||
|
pub const SYS_KILL: usize = 7;
|
||||||
|
pub const SYS_REVOKE: usize = 8;
|
||||||
|
pub const SYS_SPAWN_THREAD: usize = 9;
|
||||||
|
pub const SYS_EXIT_THREAD: usize = 10;
|
||||||
|
pub const SYS_REQUEST_PAGES: usize = 11;
|
||||||
|
pub const SYS_RELEASE_PAGES: usize = 12;
|
||||||
|
pub const SYS_GET_TIME: usize = 13;
|
||||||
|
pub const SYS_GET_PROCESS_ID: usize = 14;
|
||||||
|
pub const SYS_YIELD: usize = 15;
|
||||||
|
pub const SYS_EXIT: usize = 16;
|
||||||
@@ -4,3 +4,4 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
types = { workspace = true }
|
||||||
|
|||||||
@@ -1,14 +1,3 @@
|
|||||||
pub fn add(left: u64, right: u64) -> u64 {
|
#![no_std]
|
||||||
left + right
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
pub mod syscall;
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
let result = add(2, 2);
|
|
||||||
assert_eq!(result, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
105
crates/userspace/src/syscall.rs
Normal file
105
crates/userspace/src/syscall.rs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
use types::syscall_abi::*;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn ecall0(nr: usize) -> usize {
|
||||||
|
let ret: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") nr,
|
||||||
|
lateout("a0") ret,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn ecall1(nr: usize, a0: usize) -> usize {
|
||||||
|
let ret: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") nr,
|
||||||
|
inlateout("a0") a0 => ret,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn ecall2(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
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit() -> ! {
|
||||||
|
ecall0(SYS_EXIT);
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit_thread() -> ! {
|
||||||
|
ecall0(SYS_EXIT_THREAD);
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn yield_now() {
|
||||||
|
ecall0(SYS_YIELD);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_time() -> usize {
|
||||||
|
ecall0(SYS_GET_TIME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_process_id() -> usize {
|
||||||
|
ecall0(SYS_GET_PROCESS_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_thread(entry: usize, stack: usize) -> usize {
|
||||||
|
ecall2(SYS_SPAWN_THREAD, entry, stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn request_pages(count: usize) -> usize {
|
||||||
|
ecall1(SYS_REQUEST_PAGES, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(endpoint: usize, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
|
||||||
|
let ret: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") SYS_SEND,
|
||||||
|
inlateout("a0") endpoint => ret,
|
||||||
|
in("a1") w0,
|
||||||
|
in("a2") w1,
|
||||||
|
in("a3") w2,
|
||||||
|
in("a4") w3,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive(endpoint: usize) -> (usize, usize, usize, usize) {
|
||||||
|
let r0: usize;
|
||||||
|
let r1: usize;
|
||||||
|
let r2: usize;
|
||||||
|
let r3: usize;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"ecall",
|
||||||
|
in("a7") SYS_RECEIVE,
|
||||||
|
inlateout("a0") endpoint => r0,
|
||||||
|
lateout("a1") r1,
|
||||||
|
lateout("a2") r2,
|
||||||
|
lateout("a3") r3,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(r0, r1, r2, r3)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user