Skip to main content

xous_sys/
lib.rs

1#![no_std]
2mod definitions;
3pub use definitions::*;
4
5#[cfg(feature = "unstable_mem")]
6mod unstable;
7#[cfg(feature = "unstable_mem")]
8pub use unstable::*;
9
10/// Perform a raw syscall without checking the return value.
11///
12/// Safety: The safety of the function depends on the syscall
13/// passed in `a0`.
14#[inline]
15pub unsafe fn raw_syscall(
16    mut a0: usize,
17    mut a1: usize,
18    mut a2: usize,
19    mut a3: usize,
20    mut a4: usize,
21    mut a5: usize,
22    mut a6: usize,
23    mut a7: usize,
24) -> (usize, usize, usize, usize, usize, usize, usize, usize) {
25    unsafe {
26        core::arch::asm!(
27            "ecall",
28            inlateout("a0") a0,
29            inlateout("a1") a1,
30            inlateout("a2") a2,
31            inlateout("a3") a3,
32            inlateout("a4") a4,
33            inlateout("a5") a5,
34            inlateout("a6") a6,
35            inlateout("a7") a7,
36        )
37    };
38    (a0, a1, a2, a3, a4, a5, a6, a7)
39}
40
41/// Perform a type-checked syscall and check the return value.
42///
43/// Safety: The safety of this function depends on the syscall.
44#[inline]
45pub unsafe fn syscall(
46    a0: Syscall,
47    a1: usize,
48    a2: usize,
49    a3: usize,
50    a4: usize,
51    a5: usize,
52    a6: usize,
53    a7: usize,
54) -> Result<(usize, usize, usize, usize, usize, usize, usize, usize), Error> {
55    let result = unsafe { raw_syscall(a0 as usize, a1, a2, a3, a4, a5, a6, a7) };
56    if result.0 == 1 {
57        return Err(result.1.into());
58    }
59    Ok((
60        result.0, result.1, result.2, result.3, result.4, result.5, result.6, result.7,
61    ))
62}
63
64/// Mutably lend the buffer to the server, blocking if
65/// the mailbox is full.
66pub fn lend_mut(
67    connection: Connection,
68    opcode: usize,
69    data: &mut [u8],
70    arg1: usize,
71    arg2: usize,
72) -> Result<(usize, usize), Error> {
73    let result = unsafe {
74        syscall(
75            Syscall::SendMessage,
76            connection.0 as _,
77            InvokeType::LendMut as _,
78            opcode,
79            data.as_ptr() as usize,
80            data.len(),
81            arg1,
82            arg2,
83        )?
84    };
85    Ok((result.1, result.2))
86}
87
88/// Attempt to mutably lend the buffer to the server.
89/// Returns an error if the server's mailbox is full.
90pub fn try_lend_mut(
91    connection: Connection,
92    opcode: usize,
93    data: &mut [u8],
94    arg1: usize,
95    arg2: usize,
96) -> Result<(usize, usize), Error> {
97    let result = unsafe {
98        syscall(
99            Syscall::TrySendMessage,
100            connection.0 as _,
101            InvokeType::LendMut as _,
102            opcode,
103            data.as_ptr() as usize,
104            data.len(),
105            arg1,
106            arg2,
107        )?
108    };
109    Ok((result.1, result.2))
110}
111
112/// Lend the buffer to the server. Blocks if the mailbox is full.
113pub fn lend(
114    connection: Connection,
115    opcode: usize,
116    data: &[u8],
117    arg1: usize,
118    arg2: usize,
119) -> Result<(usize, usize), Error> {
120    let result = unsafe {
121        syscall(
122            Syscall::SendMessage,
123            connection.0 as _,
124            InvokeType::Lend as _,
125            opcode,
126            data.as_ptr() as usize,
127            data.len(),
128            arg1,
129            arg2,
130        )?
131    };
132    Ok((result.1, result.2))
133}
134
135/// Attempt to lend the slice to the server. Returns an error if
136/// the mailbox is full.
137pub fn try_lend(
138    connection: Connection,
139    opcode: usize,
140    data: &[u8],
141    arg1: usize,
142    arg2: usize,
143) -> Result<(usize, usize), Error> {
144    let result = unsafe {
145        syscall(
146            Syscall::TrySendMessage,
147            connection.0 as _,
148            InvokeType::Lend as _,
149            opcode,
150            data.as_ptr() as usize,
151            data.len(),
152            arg1,
153            arg2,
154        )?
155    };
156    Ok((result.1, result.2))
157}
158
159/// Send 5 scalar values to the server, blocking if the mailbox is full.
160pub fn scalar(connection: Connection, args: [usize; 5]) -> Result<(), Error> {
161    unsafe {
162        syscall(
163            Syscall::SendMessage,
164            connection.0 as _,
165            InvokeType::Scalar as _,
166            args[0],
167            args[1],
168            args[2],
169            args[3],
170            args[4],
171        )?
172    };
173    Ok(())
174}
175
176/// Attempt to send 5 scalar values to the server.
177pub fn try_scalar(connection: Connection, args: [usize; 5]) -> Result<(), Error> {
178    unsafe {
179        syscall(
180            Syscall::TrySendMessage,
181            connection.0 as _,
182            InvokeType::Scalar as _,
183            args[0],
184            args[1],
185            args[2],
186            args[3],
187            args[4],
188        )?
189    };
190    Ok(())
191}
192
193/// Send 5 scalar arguments to a server and wait for a response.
194/// If the server mailbox is full, will block until it is available.
195pub fn blocking_scalar(connection: Connection, args: [usize; 5]) -> Result<[usize; 5], Error> {
196    let result = unsafe {
197        syscall(
198            Syscall::SendMessage,
199            connection.0 as _,
200            InvokeType::BlockingScalar as _,
201            args[0],
202            args[1],
203            args[2],
204            args[3],
205            args[4],
206        )?
207    };
208    Ok([result.1, result.2, result.3, result.4, result.5])
209}
210
211/// Attempt to send 5 scalar arguments to a server. Returns an error
212/// if the server mailbox is full.
213pub fn try_blocking_scalar(connection: Connection, args: [usize; 5]) -> Result<[usize; 5], Error> {
214    let result = unsafe {
215        syscall(
216            Syscall::TrySendMessage,
217            connection.0 as _,
218            InvokeType::BlockingScalar as _,
219            args[0],
220            args[1],
221            args[2],
222            args[3],
223            args[4],
224        )?
225    };
226    Ok([result.1, result.2, result.3, result.4, result.5])
227}
228
229/// Connects to a Xous server represented by the specified `address`.
230///
231/// The current thread will block until the server is available. Returns
232/// an error if the server cannot accept any more connections.
233pub fn connect(address: ServerAddress) -> Result<Connection, Error> {
234    let result = unsafe {
235        syscall(
236            Syscall::Connect,
237            address.0[0] as usize,
238            address.0[1] as usize,
239            address.0[2] as usize,
240            address.0[3] as usize,
241            0,
242            0,
243            0,
244        )?
245    };
246    Ok(Connection(result.1 as u32))
247}
248
249/// Attempts to connect to a Xous server represented by the specified `address`.
250///
251/// If the server does not exist then None is returned.
252pub fn try_connect(address: ServerAddress) -> Result<Option<Connection>, Error> {
253    let result = unsafe {
254        syscall(
255            Syscall::Connect,
256            address.0[0] as usize,
257            address.0[1] as usize,
258            address.0[2] as usize,
259            address.0[3] as usize,
260            0,
261            0,
262            0,
263        )
264    };
265    match result {
266        Ok(val) => Ok(Some(Connection(val.1 as u32))),
267        Err(Error::ServerNotFound) => Ok(None),
268        Err(e) => Err(e),
269    }
270}
271
272/// Attempts to disconnect from the specified Xous server.
273///
274/// Safety: If this connection is in use elsewhere in this program,
275/// then those connections will fail. The internal [Connection] ID
276/// may be reused in a future connection attempt.
277pub unsafe fn disconnect(connection: Connection) -> Result<(), Error> {
278    unsafe { syscall(Syscall::Disconnect, connection.0 as _, 0, 0, 0, 0, 0, 0)? };
279    Ok(())
280}
281
282/// Terminates the current process and returns the specified code to the parent process.
283pub fn exit(exit_code: u32) -> ! {
284    let _ = unsafe { syscall(Syscall::TerminateProcess, exit_code as _, 0, 0, 0, 0, 0, 0) };
285    unreachable!();
286}
287
288/// Suspends the current thread and allow another thread to run. This thread may
289/// continue executing again immediately if there are no other threads available
290/// to run on the system.
291pub fn do_yield() {
292    let _ = unsafe { syscall(Syscall::Yield, 0, 0, 0, 0, 0, 0, 0) };
293}
294
295/// Waits for the given thread to terminate and returns the exit code from that thread.
296pub fn join_thread(thread_id: ThreadId) -> Result<usize, Error> {
297    let result = unsafe { syscall(Syscall::JoinThread, thread_id.into(), 0, 0, 0, 0, 0, 0)? };
298    Ok(result.1)
299}
300
301/// Gets the current thread's ID.
302pub fn thread_id() -> Result<ThreadId, Error> {
303    let result = unsafe { syscall(Syscall::GetThreadId, 0, 0, 0, 0, 0, 0, 0)? };
304    Ok(result.1.into())
305}
306
307/// Adjusts the given `knob` limit to match the new value `new`. The current value must
308/// match the `current` in order for this to take effect.
309///
310/// The new value is returned as a result of this call. If the call fails, then the old
311/// value is returned. In either case, this function returns successfully.
312///
313/// An error is generated if the `knob` is not a valid limit, or if the call
314/// would not succeed.
315pub fn adjust_limit(knob: Limits, current: usize, new: usize) -> Result<usize, Error> {
316    let result = unsafe {
317        syscall(
318            Syscall::AdjustProcessLimit,
319            knob as usize,
320            current,
321            new,
322            0,
323            0,
324            0,
325            0,
326        )?
327    };
328
329    if result.0 == SyscallResult::Scalar2 as usize && result.1 == knob as usize {
330        Ok(result.2)
331    } else if result.0 == SyscallResult::Scalar5 as usize && result.1 == knob as usize {
332        Ok(result.1)
333    } else {
334        Err(Error::InternalError)
335    }
336}