Skip to main content

xous_sys/
lib.rs

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