fork
Configure Feed
Select the types of activity you want to include in your feed.
Next Generation WASM Microkernel Operating System
wasm
os
rust
microkernel
fork
Configure Feed
Select the types of activity you want to include in your feed.
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8#[macro_export]
9#[doc(hidden)]
10macro_rules! syscall {
11 ($nr:path) => {
12 $crate::semihosting::syscall_inner($nr, 0)
13 };
14 ($nr:path, $a1:expr) => {
15 $crate::semihosting::syscall_inner($nr, ::core::ptr::from_ref(&[$a1 as usize]) as usize)
16 };
17 ($nr:path, $a1:expr, $a2:expr) => {
18 $crate::semihosting::syscall_inner(
19 $nr,
20 ::core::ptr::from_ref(&[$a1 as usize, $a2 as usize]) as usize,
21 )
22 };
23 ($nr:path, $a1:expr, $a2:expr, $a3:expr) => {
24 $crate::semihosting::syscall_inner(
25 $nr,
26 ::core::ptr::from_ref(&[$a1 as usize, $a2 as usize, $a3 as usize]) as usize,
27 )
28 };
29 ($nr:path, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
30 $crate::semihosting::syscall_inner(
31 $nr,
32 ptr::from_ref(&[$a1 as usize, $a2 as usize, $a3 as usize, $a4 as usize]) as usize,
33 )
34 };
35}
36
37#[inline(always)]
38#[expect(
39 clippy::used_underscore_binding,
40 reason = "compiler thinks nr and arg are unused otherwise"
41)]
42pub(crate) unsafe fn syscall_inner(_nr: usize, _arg: usize) -> usize {
43 cfg_if::cfg_if! {
44 if #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] {
45 use core::arch::asm;
46
47 let mut nr = _nr;
48 let arg = _arg;
49 // The instructions below must always be uncompressed, otherwise
50 // it will be treated as a regular break, hence the norvc option.
51 //
52 // See https://github.com/riscv/riscv-semihosting-spec for more details.
53 // Safety: inline assembly
54 unsafe {
55 asm! {
56 ".balign 16",
57 ".option push",
58 ".option norvc",
59 "slli x0, x0, 0x1f",
60 "ebreak",
61 "srai x0, x0, 0x7",
62 ".option pop",
63 inout("a0") nr,
64 inout("a1") arg => _,
65 options(nostack, preserves_flags),
66 };
67 }
68 nr
69 } else {
70 unimplemented!();
71 }
72 }
73}
74
75pub use syscall;
76
77/// [SYS_EXIT (0x18)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#sys_exit-0x18)
78pub const SYS_EXIT: usize = 0x18;
79
80#[cfg(target_pointer_width = "32")]
81/// [SYS_EXIT_EXTENDED (0x20)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#sys_exit_extended-0x20)
82pub const SYS_EXIT_EXTENDED: usize = 0x20;
83
84#[derive(Debug, Clone, Copy)]
85#[repr(usize)]
86#[non_exhaustive]
87pub enum ExitReason {
88 // Reason codes related to hardware exceptions:
89 // AdpStoppedBranchThroughZero = 0x20000,
90 // AdpStoppedUndefinedInstr = 0x20001,
91 // AdpStoppedSoftwareInterrupt = 0x20002,
92 // AdpStoppedPrefetchAbort = 0x20003,
93 // AdpStoppedDataAbort = 0x20004,
94 // AdpStoppedAddressException = 0x20005,
95 // AdpStoppedIrq = 0x20006,
96 // AdpStoppedFiq = 0x20007,
97
98 // Reason codes related to software events:
99 // AdpStoppedBreakPoint = 0x20020,
100 // AdpStoppedWatchPoint = 0x20021,
101 // AdpStoppedStepComplete = 0x20022,
102 AdpStoppedRunTimeErrorUnknown = 0x20023,
103 // AdpStoppedInternalError = 0x20024,
104 // AdpStoppedUserInterruption = 0x20025,
105 AdpStoppedApplicationExit = 0x20026,
106 // AdpStoppedStackOverflow = 0x20027,
107 // AdpStoppedDivisionByZero = 0x20028,
108 // AdpStoppedOsspecific = 0x20029,
109}
110
111#[expect(
112 clippy::cast_sign_loss,
113 reason = "sign extended conversion from i32 to usize"
114)]
115pub(crate) fn exit(code: i32) {
116 // TODO: check sh_ext_exit_extended first
117 sys_exit_extended(
118 ExitReason::AdpStoppedApplicationExit,
119 code as isize as usize,
120 );
121 // If SYS_EXIT_EXTENDED is not supported, above call doesn't exit program,
122 // so try again with SYS_EXIT.
123 let reason = match code {
124 0i32 => ExitReason::AdpStoppedApplicationExit,
125 _ => ExitReason::AdpStoppedRunTimeErrorUnknown,
126 };
127 sys_exit(reason);
128}
129
130/// [SYS_EXIT (0x18)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#sys_exit-0x18)
131pub fn sys_exit(reason: ExitReason) {
132 // Safety: syscall
133 unsafe {
134 #[cfg(target_pointer_width = "32")]
135 syscall!(SYS_EXIT, reason as usize);
136 #[cfg(target_pointer_width = "64")]
137 syscall!(SYS_EXIT, reason as usize, 0);
138 }
139}
140
141/// [SYS_EXIT_EXTENDED (0x20)](https://github.com/ARM-software/abi-aa/blob/HEAD/semihosting/semihosting.rst#sys_exit_extended-0x20)
142pub fn sys_exit_extended(reason: ExitReason, subcode: usize) {
143 // Safety: syscall
144 unsafe {
145 #[cfg(target_pointer_width = "32")]
146 syscall!(SYS_EXIT_EXTENDED, reason as usize, subcode);
147 // On 64-bit system, SYS_EXIT_EXTENDED call is identical to the behavior of the mandatory SYS_EXIT.
148 #[cfg(target_pointer_width = "64")]
149 syscall!(SYS_EXIT, reason as usize, subcode);
150 }
151}