Skip to main content

xous/
syscall.rs

1use core::convert::{TryFrom, TryInto};
2
3/* https://github.com/betrusted-io/xous-core/issues/90
4use crate::Exception
5*/
6// use num_derive::FromPrimitive;
7// use num_traits::FromPrimitive;
8#[cfg(feature = "processes-as-threads")]
9pub use crate::arch::ProcessArgsAsThread;
10use crate::{
11    CID, CpuID, Error, MemoryAddress, MemoryFlags, MemoryMessage, MemoryRange, MemorySize, MemoryType,
12    Message, MessageEnvelope, MessageSender, PID, ProcessArgs, ProcessInit, Result, SID, ScalarMessage,
13    SysCallResult, TID, ThreadInit, pid_from_usize,
14};
15
16#[derive(Debug, PartialEq)]
17pub enum SysCall {
18    /// Allocates pages of memory, equal to a total of `size` bytes.  A physical
19    /// address may be specified, which can be used to allocate regions such as
20    /// memory-mapped I/O.
21    ///
22    /// If a virtual address is specified, then the returned pages are located
23    /// at that address.  Otherwise, they are located at the Default offset.
24    ///
25    /// # Returns
26    ///
27    /// * **MemoryRange**: A memory range containing zeroed bytes.
28    ///
29    /// # Errors
30    ///
31    /// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, or the size isn't a
32    ///   multiple of the page width.
33    /// * **OutOfMemory**: A contiguous chunk of memory couldn't be found, or the system's memory size has
34    ///   been exceeded.
35    MapMemory(
36        Option<MemoryAddress>, /* phys */
37        Option<MemoryAddress>, /* virt */
38        MemorySize,            /* region size */
39        MemoryFlags,           /* flags */
40    ),
41
42    /// Release the memory back to the operating system.
43    ///
44    /// # Errors
45    ///
46    /// * **BadAlignment**: The memory range was not page-aligned
47    /// * **BadAddress**: A page in the range was not mapped
48    UnmapMemory(MemoryRange),
49
50    /// Sets the offset and size of a given memory region.  This call may only
51    /// be made by processes that have not yet started, or processes that have a
52    /// PPID of 1. Care must be taken to ensure this region doesn't run into
53    /// other regions. Additionally, the base address must avoid the kernel
54    /// regions.
55    ///
56    /// # Errors
57    ///
58    /// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, or the size isn't a
59    ///   multiple of the page width.
60    /// * **BadAddress**: The address conflicts with the kernel
61    SetMemRegion(
62        PID,           /* pid */
63        MemoryType,    /* region type */
64        MemoryAddress, /* region address */
65        usize,         /* region size */
66    ),
67
68    /// Add the given number of bytes to the heap.  The number of bytes must be
69    /// divisible by the page size.  The newly-allocated pages will have the
70    /// specified flags.  To get the current heap base, call this with a size of
71    /// `0`, which will return a `MemoryRange` containing the heap base and the size.
72    ///
73    /// # Returns
74    ///
75    /// * **MemoryRange( *mut usize, /* The newly-allocated offset */ usize,      /* The amount of data added
76    ///   */ )**
77    ///
78    /// # Errors
79    ///
80    /// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, or the size isn't a
81    ///   multiple of the page width.
82    /// * **OutOfMemory**: A contiguous chunk of memory couldn't be found, or the system's memory size has
83    ///   been exceeded.
84    IncreaseHeap(usize /* number of bytes to add */, MemoryFlags),
85
86    /// Remove the given number of bytes from the heap.
87    ///
88    /// # Returns
89    ///
90    /// * **MemoryRange(*mut usize /* The base of the heap */, usize /* the new size of the heap */)
91    ///
92    /// # Errors
93    ///
94    /// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, or the size isn't a
95    ///   multiple of the page width.
96    /// * **OutOfMemory**: A contiguous chunk of memory couldn't be found, or the system's memory size has
97    ///   been exceeded.
98    DecreaseHeap(usize /* desired heap size */),
99
100    /// Set the specified flags on the virtual address range. This can be used
101    /// to REMOVE flags on a memory region, for example to mark it as no-execute
102    /// after writing program data.
103    ///
104    /// If `PID` is `None`, then modifies this process. Note that it is not legal
105    /// to modify the memory range of another process that has been started already.
106    ///
107    /// # Returns
108    ///
109    /// * **Ok**: The call completed successfully
110    ///
111    /// # Errors
112    ///
113    /// * **ProcessNotChild**: The given PID is not a child of the current process.
114    /// * **MemoryInUse**: The given PID has already been started, and it is not legal to modify memory flags
115    ///   anymore.
116    UpdateMemoryFlags(
117        MemoryRange, /* range of memory to update flags for */
118        MemoryFlags, /* new flags */
119        Option<PID>, /* if present, indicates the process to modify */
120    ),
121
122    /// Pauses execution of the current thread and returns execution to the parent
123    /// process.  This may return at any time in the future, including immediately.
124    ///
125    /// # Returns
126    ///
127    /// * **Ok**: The call completed successfully
128    ///
129    /// # Errors
130    ///
131    /// This syscall will never return an error.
132    Yield,
133
134    /// This process will now wait for an event such as an IRQ or Message.
135    ///
136    /// # Returns
137    ///
138    /// * **Ok**: The call completed successfully
139    ///
140    /// # Errors
141    ///
142    /// This syscall will never error.
143    WaitEvent,
144
145    /// This thread will now wait for a message with the given server ID. You
146    /// can set up a pool by having multiple threads call `ReceiveMessage` with
147    /// the same SID.
148    ///
149    /// # Returns
150    ///
151    /// * **MessageEnvelope**: A valid message from the queue
152    ///
153    /// # Errors
154    ///
155    /// * **ServerNotFound**: The given SID is not active or has terminated
156    /// * **ProcessNotFound**: The parent process terminated when we were getting ready to block. This is an
157    ///   internal error.
158    /// * **BlockedProcess**: When running in Hosted mode, this indicates that this thread is blocking.
159    ReceiveMessage(SID),
160
161    /// If a message is available for the specified server, return that message
162    /// and resume execution. If no message is available, return `Result::None`
163    /// immediately without blocking.
164    ///
165    /// # Returns
166    ///
167    /// * **Message**: A valid message from the queue
168    /// * **None**: Indicates that no message was in the queue
169    ///
170    /// # Errors
171    ///
172    /// * **ServerNotFound**: The given SID is not active or has terminated
173    /// * **ProcessNotFound**: The parent process terminated when we were getting ready to block. This is an
174    ///   internal error.
175    TryReceiveMessage(SID),
176
177    /// Stop running the given process and return control to the parent. This
178    /// will force a Yield on the process currently running on the target CPU.
179    /// This can be run during an Interrupt context.
180    ///
181    /// # Errors
182    ///
183    /// * **ProcessNotChild**: The given PID is not a child of the current process
184    ReturnToParent(PID, CpuID),
185
186    /// Claims an interrupt and unmasks it immediately.  The provided function
187    /// will be called from within an interrupt context, but using the ordinary
188    /// privilege level of the process.
189    ///
190    /// # Returns
191    ///
192    /// * **Ok**: The interrupt has been mapped to this process
193    ///
194    /// # Errors
195    ///
196    /// * **InterruptNotFound**: The specified interrupt isn't valid on this system
197    /// * **InterruptInUse**: The specified interrupt has already been claimed
198    ClaimInterrupt(
199        usize,                 /* IRQ number */
200        MemoryAddress,         /* function pointer */
201        Option<MemoryAddress>, /* argument */
202    ),
203
204    /// Returns the interrupt back to the operating system and masks it again.
205    /// This function is implicitly called when a process exits.
206    ///
207    /// # Errors
208    ///
209    /// * **InterruptNotFound**: The specified interrupt doesn't exist, or isn't assigned to this process.
210    FreeInterrupt(usize /* IRQ number */),
211
212    /// Resumes a process using the given context.  A parent could use this
213    /// function to implement multi-threading inside a child process, or to
214    /// create a task switcher.
215    ///
216    /// To resume a process exactly where it left off, set `context_id` to `0`.
217    /// This would be done in a very simple system that has no threads.
218    ///
219    /// If no more contexts are available when one is required, then the child
220    /// automatically relinquishes its quantum.
221    ///
222    /// # Returns
223    ///
224    /// When this function returns, it provides a list of the processes and
225    /// contexts that are ready to be run.  Three can fit as return values.
226    ///
227    /// # Examples
228    ///
229    /// If a process called `yield()`, or if its quantum expired normally, then
230    /// a single pair is returned: (pid, context).
231    ///
232    /// If the child process called `client_send()` and ended up blocking due to
233    /// the server not being ready, then this would return no pairs. This thread
234    /// or process should not be scheduled to run.
235    ///
236    /// If the child called `client_send()` and the server was ready, then the
237    /// server process would be run immediately.  If the child process' quantum
238    /// expired while the server was running, then this function would return a
239    /// single pair containing the PID of the server, and the context number.
240    ///
241    /// If the child called `client_send()` and the server was ready, then the
242    /// server process would be run immediately.  If the server then finishes,
243    /// execution flow is returned to the child process.  If the quantum then
244    /// expires, this would return two pairs: the server's PID and its context
245    /// when it called `client_reply()`, and the child's PID with its current
246    /// context.
247    ///
248    /// If the server in turn called another server, and both servers ended up
249    /// returning to the child before the quantum expired, then there would be
250    /// three pairs returned.
251    ///
252    /// # Errors
253    ///
254    /// * **ProcessNotFound**: The requested process does not exist
255    /// * **ProcessNotChild**: The given process was not a child process, and therefore couldn't be resumed.
256    /// * **ProcessTerminated**: The process has crashed.
257    SwitchTo(PID, usize /* context ID */),
258
259    /// Get a list of contexts that can be run in the given PID.
260    ///
261    /// # Errors
262    ///
263    /// * **UnhandledSyscall**: This syscall is currently unimplemented.
264    ReadyThreads(PID),
265
266    /// Create a new Server with a specified address
267    ///
268    /// This will return a 128-bit Server ID that can be used to send messages
269    /// to this server, as well as a connection ID.  This connection ID will be
270    /// unique per process, while the server ID is available globally.
271    ///
272    /// # Returns
273    ///
274    /// * **NewServerID(sid, cid)**: The specified SID, along with the connection ID for this process to talk
275    ///   to the server.
276    ///
277    /// # Errors
278    ///
279    /// * **OutOfMemory**: The server table was full and a new server couldn't be created.
280    /// * **ServerExists**: The server hash is already in use.
281    CreateServerWithAddress(SID /* server hash */),
282
283    /// Connect to a server.   This turns a 128-bit Server ID into a 32-bit
284    /// Connection ID. Blocks until the server is available.
285    ///
286    /// # Returns
287    ///
288    /// * **ConnectionID(cid)**: The new connection ID for communicating with the server.
289    ///
290    /// # Errors
291    ///
292    /// None
293    Connect(SID /* server id */),
294
295    /// Try to connect to a server.   This turns a 128-bit Server ID into a 32-bit
296    /// Connection ID.
297    ///
298    /// # Returns
299    ///
300    /// * **ConnectionID(cid)**: The new connection ID for communicating with the server.
301    ///
302    /// # Errors
303    ///
304    /// * **ServerNotFound**: The server could not be found.
305    TryConnect(SID /* server id */),
306
307    /// Send a message to a server (blocking until it's ready)
308    ///
309    /// # Returns
310    ///
311    /// * **Ok**: The Scalar / Send message was successfully sent
312    /// * **Scalar1**: The Server returned a `Scalar1` value
313    /// * **Scalar2**: The Server returned a `Scalar2` value
314    /// * **Scalar5**: The Server returned a `Scalar5` value
315    /// * **BlockedProcess**: In Hosted mode, the target process is now blocked
316    /// * **Message**: For Scalar messages, this includes the args as returned by the server. For
317    ///   MemoryMessages, this will include the Opcode, Offset, and Valid fields.
318    ///
319    /// # Errors
320    ///
321    /// * **ServerNotFound**: The server could not be found.
322    /// * **ProcessNotFound**: Internal error -- the parent process couldn't be found when blocking
323    SendMessage(CID, Message),
324
325    /// Try to send a message to a server
326    ///
327    /// # Returns
328    ///
329    /// * **Ok**: The Scalar / Send message was successfully sent, or the Borrow has finished
330    /// * **Scalar1**: The Server returned a `Scalar1` value
331    /// * **Scalar2**: The Server returned a `Scalar2` value
332    /// * **Scalar5**: The Server returned a `Scalar5` value
333    /// * **BlockedProcess**: In Hosted mode, the target process is now blocked
334    ///
335    /// # Errors
336    ///
337    /// * **ServerNotFound**: The server could not be found.
338    /// * **ServerQueueFull**: The server's mailbox is full
339    /// * **ProcessNotFound**: Internal error -- the parent process couldn't be found when blocking
340    TrySendMessage(CID, Message),
341
342    /// Return a Borrowed memory region to the sender
343    ReturnMemory(
344        MessageSender,      /* source of this message */
345        MemoryRange,        /* address of range */
346        Option<MemorySize>, /* offset */
347        Option<MemorySize>, /* valid */
348    ),
349
350    /// Return a scalar to the sender
351    ReturnScalar1(MessageSender, usize),
352
353    /// Return two scalars to the sender
354    ReturnScalar2(MessageSender, usize, usize),
355
356    /// Spawn a new thread
357    CreateThread(ThreadInit),
358
359    /// Create a new process, setting the current process as the parent ID.
360    /// Starts the process immediately and returns a `ProcessStartup` value.
361    CreateProcess(ProcessInit),
362
363    /// Terminate the current process, closing all server connections.
364    TerminateProcess(u32),
365
366    /// Shut down the entire system
367    Shutdown,
368
369    /// Create a new Server
370    ///
371    /// This will return a 128-bit Server ID that can be used to send messages
372    /// to this server. The returned Server ID is random.
373    ///
374    /// # Returns
375    ///
376    /// The SID, along with a Connection ID that can be used to immediately
377    /// communicate with this process.
378    ///
379    /// # Errors
380    ///
381    /// * **OutOfMemory**: The server table was full and a new server couldn't be created.
382    CreateServer,
383
384    /// Returns a 128-bit server ID, but does not create the server itself.
385    /// basically an API to access the TRNG inside the kernel.
386    CreateServerId,
387
388    /// Establish a connection in the given process to the given server. This
389    /// call can be used by a nameserver to make server connections without
390    /// disclosing SIDs.
391    ConnectForProcess(PID, SID),
392
393    /// Get the current Thread ID
394    GetThreadId,
395
396    /// Get the current Process ID
397    GetProcessId,
398
399    /// Destroys the given Server ID. All clients that are waiting will be woken
400    /// up and will receive a `ServerNotFound` response.
401    DestroyServer(SID),
402
403    /// Disconnects from a Server. This invalidates the CID, which may be reused
404    /// in a future reconnection.
405    Disconnect(CID),
406
407    /// Waits for a thread to finish, and returns the return value of that thread.
408    JoinThread(TID),
409
410    /// A function to call when there is an exception such as a memory fault
411    /// or illegal instruction.
412    SetExceptionHandler(usize /* function pointer */, usize /* stack pointer */),
413
414    /// Adjust one of the limits within this process. Note that you must pass
415    /// the current limit value in order to set the new limit. The current limit
416    /// value is always returned, so this function may need to be called twice --
417    /// once in order to get the current limit, and again to set the new limit.
418    ///
419    /// ## Arguments
420    ///
421    /// * **Index**: The item to adjust. Currently the following limits are supported: 1: Maximum heap size 2:
422    ///   Current heap size
423    /// * **Current Limit**: Pass the current limit value here. The current limit must match in order for the
424    ///   new limit to take effect. This is used to avoid a race condition if two threads try to set the same
425    ///   limit.
426    /// * **Proposed Limit**: The new value that you would like to use.
427    ///
428    /// ## Returns
429    ///
430    /// Returns a Scalar2 containing `(Index, Limit)`.
431    ///
432    /// ## Errors
433    ///
434    /// * **InvalidLimit**: The specified index was not valid
435    AdjustProcessLimit(
436        usize, /* process limit index */
437        usize, /* expected current limit */
438        usize, /* proposed new limit */
439    ),
440
441    /// Returns the physical address corresponding to a virtual address, if such a mapping exists.
442    ///
443    /// ## Arguments
444    ///     * **vaddr**: The virtual address to inspect
445    ///
446    /// ## Returns
447    /// Returns a Scalar1 containing the physical address
448    ///
449    /// ## Errors
450    ///     * **BadAddress**: The mapping does not exist
451    #[cfg(feature = "v2p")]
452    VirtToPhys(usize /* virtual address */),
453
454    /// Return five scalars to the sender
455    ReturnScalar5(MessageSender, usize, usize, usize, usize, usize),
456
457    /// Return a message with the given Message ID and the provided parameters,
458    /// and listen for another message on the server ID that sent this message.
459    /// This call is meant to be used in the main loop of a server in order to
460    /// reduce latency when that server is called frequently.
461    ///
462    /// This call works on both `MemoryMessages` and `BlockingScalars`, and does
463    /// not distinguish between the two from the API.
464    ///
465    /// ## Arguments
466    ///
467    /// * **MessageSender**: This is the `sender` from the message envelope. It is a unique ID that identifies
468    ///   this message, as well as the server it came from.
469    ///
470    /// The remaining arguments depend on whether the message was a `BlockingScalar`
471    /// message or a `MemoryMessage`. Note that this function should NOT be called
472    /// on non-blocking messages such as `Send` or `Scalar`.
473    ///
474    /// ## Returns
475    ///
476    /// * **Message**: A valid message from the queue
477    ///
478    /// # Errors
479    ///
480    /// * **ServerNotFound**: The given SID is not active or has terminated
481    /// * **ProcessNotFound**: The parent process terminated when we were getting ready to block. This is an
482    ///   internal error.
483    /// * **BlockedProcess**: When running in Hosted mode, this indicates that this thread is blocking.
484    ReplyAndReceiveNext(
485        MessageSender, /* ID if the sender that sent this message */
486        usize,         /* Return code to the caller */
487        usize,         /* arg1 (BlockingScalar) or the memory address (MemoryMessage) */
488        usize,         /* arg2 (BlockingScalar) or the memory length (MemoryMessage) */
489        usize,         /* arg3 (BlockingScalar) or the memory offset (MemoryMessage) */
490        usize,         /* arg4 (BlockingScalar) or the memory valid (MemoryMessage) */
491        usize,         /* how many args are valid (BlockingScalar) or usize::MAX (MemoryMessage) */
492    ),
493
494    /// Returns the physical address corresponding to a virtual address for a given process, if such a
495    /// mapping exists.
496    ///
497    /// ## Arguments
498    ///     * **pid**: The PID
499    ///     * **vaddr**: The virtual address to inspect
500    ///
501    /// ## Returns
502    /// Returns a Scalar1 containing the physical address
503    ///
504    /// ## Errors
505    ///     * **BadAddress**: The mapping does not exist
506    #[cfg(feature = "v2p")]
507    VirtToPhysPid(PID /* Process ID */, usize /* virtual address */),
508
509    /// Registers a swapper.
510    ///
511    /// ## Arguments
512    ///   * **sid0**, **sid1**, **sid2**, **sid3**: 128-bit SID as four u32
513    ///   * **handler**: address of the blocking swap handler
514    ///   * **state**: address of the process-local state of the swap handler
515    ///
516    /// ## Returns
517    /// Returns a Scalar5 with raw pointers as follows:
518    ///   - `arg1`: A pointer to the SPT
519    ///   - `arg2`: A pointer to the SMT
520    ///   - `arg3`: A pointer to the RPT
521    #[cfg(feature = "swap")]
522    RegisterSwapper(u32, u32, u32, u32, usize, usize),
523
524    /// Swapper operation.
525    ///
526    /// This syscall can only be called by PID 2, the swapper. The form of the
527    /// call is deliberately left flexible, so that the swapper ABI can evolve
528    /// without impacting version compatibility with application ABIs.
529    ///
530    /// ## Arguments
531    ///     * Up to 7 `usize` values, whose ABI is determined by the swapper's implementation.
532    ///
533    /// ## Returns
534    /// Returns a Scalar5, whose ABI is determined by the swapper's implementation.
535    ///
536    /// ## Errors
537    ///     * **BadAddress**: The mapping does not exist
538    ///     * **AccessDenied**: Called by a PID that does not belong to the swapper
539    ///     * **MappingInUse**: A requested operation could not be performed because the mapping is wired
540    ///     * **UnhandledSyscall**: The ABI encoding doesn't map to the current implementation
541    ///     * Other errors may be added as the swapper ABI evolves
542    #[cfg(feature = "swap")]
543    SwapOp(usize, usize, usize, usize, usize, usize, usize),
544
545    /// Retrieve four u32's from the hardware TRNG. These values are not used
546    /// by the kernel, and so should be generally safe to inspect so long as the TRNG
547    /// itself does not leak state through such inspections. Enabling this feature
548    /// is a trade-off between paranoia about leaked TRNG state, and paranoia about
549    /// the TRNG itself being unhealthy.
550    ///
551    /// In the case of a weak TRNG, it's recommended to enable this feature, so that its health can be
552    /// actively monitored.
553    ///
554    /// ## Arguments
555    ///   * The arguments have an implementation-specific meaning. Generally, they are provided to tune the
556    ///     TRNG into different modes to inspect its operation.
557    ///
558    /// ## Returns
559    /// Returns a Scalar5, where the first four values are outputs from the TRNG, and
560    /// the last one is 0.
561    #[cfg(feature = "raw-trng")]
562    RawTrng(usize, usize, usize, usize, usize, usize, usize),
563
564    /// Used for platform specific kernel ABIs. Generally reserved for things like debug,
565    /// performance-monitoring, and power management.
566    ///
567    /// ## Arguments
568    ///   * In general, the first `usize` is a meta-opcode that helps dispatch what the nature of the
569    ///     remaining arguments should be.
570    ///
571    /// ## Returns
572    /// Returns a Scalar5, whose ABI is determined by the meta-opcode
573    PlatformSpecific(usize, usize, usize, usize, usize, usize, usize),
574
575    /// This syscall does not exist. It captures all possible
576    /// arguments so detailed analysis can be performed.
577    Invalid(usize, usize, usize, usize, usize, usize, usize),
578}
579
580// #[derive(FromPrimitive)]
581pub enum SysCallNumber {
582    Invalid = 0,
583    MapMemory = 2,
584    Yield = 3,
585    ReturnToParent = 4,
586    ClaimInterrupt = 5,
587    FreeInterrupt = 6,
588    SwitchTo = 7,
589    ReadyThreads = 8,
590    WaitEvent = 9,
591    IncreaseHeap = 10,
592    DecreaseHeap = 11,
593    UpdateMemoryFlags = 12,
594    SetMemRegion = 13,
595    CreateServerWithAddress = 14,
596    ReceiveMessage = 15,
597    SendMessage = 16,
598    Connect = 17,
599    CreateThread = 18,
600    UnmapMemory = 19,
601    ReturnMemory = 20,
602    CreateProcess = 21,
603    TerminateProcess = 22,
604    Shutdown = 23,
605    TrySendMessage = 24,
606    TryConnect = 25,
607    ReturnScalar1 = 26,
608    ReturnScalar2 = 27,
609    TryReceiveMessage = 28,
610    CreateServer = 29,
611    ConnectForProcess = 30,
612    CreateServerId = 31,
613    GetThreadId = 32,
614    GetProcessId = 33,
615    DestroyServer = 34,
616    Disconnect = 35,
617    JoinThread = 36,
618    SetExceptionHandler = 37,
619    AdjustProcessLimit = 38,
620    #[cfg(feature = "v2p")]
621    VirtToPhys = 39,
622    ReturnScalar5 = 40,
623    ReplyAndReceiveNext = 41,
624    #[cfg(feature = "v2p")]
625    VirtToPhysPid = 42,
626    #[cfg(feature = "swap")]
627    RegisterSwapper = 43,
628    #[cfg(feature = "swap")]
629    SwapOp = 44,
630    #[cfg(feature = "raw-trng")]
631    RawTrng = 45,
632    PlatformSpecific = 46,
633}
634
635impl SysCallNumber {
636    pub fn from(val: usize) -> SysCallNumber {
637        use SysCallNumber::*;
638        match val {
639            2 => MapMemory,
640            3 => Yield,
641            4 => ReturnToParent,
642            5 => ClaimInterrupt,
643            6 => FreeInterrupt,
644            7 => SwitchTo,
645            8 => ReadyThreads,
646            9 => WaitEvent,
647            10 => IncreaseHeap,
648            11 => DecreaseHeap,
649            12 => UpdateMemoryFlags,
650            13 => SetMemRegion,
651            14 => CreateServerWithAddress,
652            15 => ReceiveMessage,
653            16 => SendMessage,
654            17 => Connect,
655            18 => CreateThread,
656            19 => UnmapMemory,
657            20 => ReturnMemory,
658            21 => CreateProcess,
659            22 => TerminateProcess,
660            23 => Shutdown,
661            24 => TrySendMessage,
662            25 => TryConnect,
663            26 => ReturnScalar1,
664            27 => ReturnScalar2,
665            28 => TryReceiveMessage,
666            29 => CreateServer,
667            30 => ConnectForProcess,
668            31 => CreateServerId,
669            32 => GetThreadId,
670            33 => GetProcessId,
671            34 => DestroyServer,
672            35 => Disconnect,
673            36 => JoinThread,
674            37 => SetExceptionHandler,
675            38 => AdjustProcessLimit,
676            #[cfg(feature = "v2p")]
677            39 => VirtToPhys,
678            40 => ReturnScalar5,
679            41 => ReplyAndReceiveNext,
680            #[cfg(feature = "v2p")]
681            42 => VirtToPhysPid,
682            #[cfg(feature = "swap")]
683            43 => RegisterSwapper,
684            #[cfg(feature = "swap")]
685            44 => SwapOp,
686            #[cfg(feature = "raw-trng")]
687            45 => RawTrng,
688            46 => PlatformSpecific,
689            _ => Invalid,
690        }
691    }
692}
693
694impl SysCall {
695    fn add_opcode(opcode: SysCallNumber, args: [usize; 7]) -> [usize; 8] {
696        [opcode as usize, args[0], args[1], args[2], args[3], args[4], args[5], args[6]]
697    }
698
699    /// Convert the SysCall into an array of eight `usize` elements,
700    /// suitable for passing to the kernel.
701    pub fn as_args(&self) -> [usize; 8] {
702        use core::mem;
703        assert!(
704            mem::size_of::<SysCall>() == mem::size_of::<usize>() * 8,
705            "SysCall is not the expected size (expected {}, got {})",
706            mem::size_of::<usize>() * 8,
707            mem::size_of::<SysCall>()
708        );
709        match self {
710            SysCall::MapMemory(a1, a2, a3, a4) => [
711                SysCallNumber::MapMemory as usize,
712                a1.map(|x| x.get()).unwrap_or_default(),
713                a2.map(|x| x.get()).unwrap_or_default(),
714                a3.get(),
715                a4.bits(),
716                0,
717                0,
718                0,
719            ],
720            SysCall::UnmapMemory(range) => {
721                [SysCallNumber::UnmapMemory as usize, range.as_ptr() as usize, range.len(), 0, 0, 0, 0, 0]
722            }
723            SysCall::Yield => [SysCallNumber::Yield as usize, 0, 0, 0, 0, 0, 0, 0],
724            SysCall::WaitEvent => [SysCallNumber::WaitEvent as usize, 0, 0, 0, 0, 0, 0, 0],
725            SysCall::ReceiveMessage(sid) => {
726                let s = sid.to_u32();
727                [SysCallNumber::ReceiveMessage as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
728            }
729            SysCall::TryReceiveMessage(sid) => {
730                let s = sid.to_u32();
731                [SysCallNumber::TryReceiveMessage as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
732            }
733            SysCall::ConnectForProcess(pid, sid) => {
734                let s = sid.to_u32();
735                [
736                    SysCallNumber::ConnectForProcess as usize,
737                    pid.get() as _,
738                    s.0 as _,
739                    s.1 as _,
740                    s.2 as _,
741                    s.3 as _,
742                    0,
743                    0,
744                ]
745            }
746            SysCall::CreateServerId => [SysCallNumber::CreateServerId as usize, 0, 0, 0, 0, 0, 0, 0],
747            SysCall::ReturnToParent(a1, a2) => {
748                [SysCallNumber::ReturnToParent as usize, a1.get() as usize, *a2, 0, 0, 0, 0, 0]
749            }
750            SysCall::ClaimInterrupt(a1, a2, a3) => [
751                SysCallNumber::ClaimInterrupt as usize,
752                *a1,
753                a2.get(),
754                a3.map(|x| x.get()).unwrap_or_default(),
755                0,
756                0,
757                0,
758                0,
759            ],
760            SysCall::FreeInterrupt(a1) => [SysCallNumber::FreeInterrupt as usize, *a1, 0, 0, 0, 0, 0, 0],
761            SysCall::SwitchTo(a1, a2) => {
762                [SysCallNumber::SwitchTo as usize, a1.get() as usize, *a2, 0, 0, 0, 0, 0]
763            }
764            SysCall::ReadyThreads(a1) => {
765                [SysCallNumber::ReadyThreads as usize, a1.get() as usize, 0, 0, 0, 0, 0, 0]
766            }
767            SysCall::IncreaseHeap(a1, a2) => {
768                [SysCallNumber::IncreaseHeap as usize, *a1, a2.bits(), 0, 0, 0, 0, 0]
769            }
770            SysCall::DecreaseHeap(a1) => [SysCallNumber::DecreaseHeap as usize, *a1, 0, 0, 0, 0, 0, 0],
771            SysCall::UpdateMemoryFlags(a1, a2, a3) => [
772                SysCallNumber::UpdateMemoryFlags as usize,
773                a1.as_mut_ptr() as usize,
774                a1.len(),
775                a2.bits(),
776                a3.map(|m| m.get() as usize).unwrap_or(0),
777                0,
778                0,
779                0,
780            ],
781            SysCall::SetMemRegion(a1, a2, a3, a4) => [
782                SysCallNumber::SetMemRegion as usize,
783                a1.get() as usize,
784                *a2 as usize,
785                a3.get(),
786                *a4,
787                0,
788                0,
789                0,
790            ],
791
792            SysCall::CreateServerWithAddress(sid) => {
793                let s = sid.to_u32();
794                [
795                    SysCallNumber::CreateServerWithAddress as usize,
796                    s.0 as _,
797                    s.1 as _,
798                    s.2 as _,
799                    s.3 as _,
800                    0,
801                    0,
802                    0,
803                ]
804            }
805            SysCall::CreateServer => [SysCallNumber::CreateServer as usize, 0, 0, 0, 0, 0, 0, 0],
806            SysCall::Connect(sid) => {
807                let s = sid.to_u32();
808                [SysCallNumber::Connect as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
809            }
810            SysCall::SendMessage(a1, ref a2) => match a2 {
811                Message::MutableBorrow(mm) | Message::Borrow(mm) | Message::Move(mm) => [
812                    SysCallNumber::SendMessage as usize,
813                    *a1 as usize,
814                    a2.message_type(),
815                    mm.id,
816                    mm.buf.as_ptr() as usize,
817                    mm.buf.len(),
818                    mm.offset.map(|x| x.get()).unwrap_or(0),
819                    mm.valid.map(|x| x.get()).unwrap_or(0),
820                ],
821                Message::Scalar(sc) | Message::BlockingScalar(sc) => [
822                    SysCallNumber::SendMessage as usize,
823                    *a1 as usize,
824                    a2.message_type(),
825                    sc.id,
826                    sc.arg1,
827                    sc.arg2,
828                    sc.arg3,
829                    sc.arg4,
830                ],
831            },
832            SysCall::ReturnMemory(sender, buf, offset, valid) => [
833                SysCallNumber::ReturnMemory as usize,
834                sender.to_usize(),
835                buf.as_ptr() as usize,
836                buf.len(),
837                offset.map(|o| o.get()).unwrap_or_default(),
838                valid.map(|v| v.get()).unwrap_or_default(),
839                0,
840                0,
841            ],
842            SysCall::ReplyAndReceiveNext(sender, arg0, arg1, arg2, arg3, arg4, return_type) => [
843                SysCallNumber::ReplyAndReceiveNext as usize,
844                sender.to_usize(),
845                *arg0,
846                *arg1,
847                *arg2,
848                *arg3,
849                *arg4,
850                *return_type,
851            ],
852
853            SysCall::CreateThread(init) => {
854                crate::arch::thread_to_args(SysCallNumber::CreateThread as usize, init)
855            }
856            SysCall::CreateProcess(init) => Self::add_opcode(SysCallNumber::CreateProcess, init.into()),
857            SysCall::TerminateProcess(exit_code) => {
858                [SysCallNumber::TerminateProcess as usize, *exit_code as usize, 0, 0, 0, 0, 0, 0]
859            }
860            SysCall::Shutdown => [SysCallNumber::Shutdown as usize, 0, 0, 0, 0, 0, 0, 0],
861            SysCall::TryConnect(sid) => {
862                let s = sid.to_u32();
863                [SysCallNumber::TryConnect as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
864            }
865            SysCall::TrySendMessage(a1, ref a2) => match a2 {
866                Message::MutableBorrow(mm) | Message::Borrow(mm) | Message::Move(mm) => [
867                    SysCallNumber::TrySendMessage as usize,
868                    *a1 as usize,
869                    a2.message_type(),
870                    mm.id,
871                    mm.buf.as_ptr() as usize,
872                    mm.buf.len(),
873                    mm.offset.map(|x| x.get()).unwrap_or(0),
874                    mm.valid.map(|x| x.get()).unwrap_or(0),
875                ],
876                Message::Scalar(sc) | Message::BlockingScalar(sc) => [
877                    SysCallNumber::TrySendMessage as usize,
878                    *a1 as usize,
879                    a2.message_type(),
880                    sc.id,
881                    sc.arg1,
882                    sc.arg2,
883                    sc.arg3,
884                    sc.arg4,
885                ],
886            },
887            SysCall::ReturnScalar1(sender, arg1) => {
888                [SysCallNumber::ReturnScalar1 as usize, sender.to_usize(), *arg1, 0, 0, 0, 0, 0]
889            }
890            SysCall::ReturnScalar2(sender, arg1, arg2) => {
891                [SysCallNumber::ReturnScalar2 as usize, sender.to_usize(), *arg1, *arg2, 0, 0, 0, 0]
892            }
893            SysCall::GetThreadId => [SysCallNumber::GetThreadId as usize, 0, 0, 0, 0, 0, 0, 0],
894            SysCall::GetProcessId => [SysCallNumber::GetProcessId as usize, 0, 0, 0, 0, 0, 0, 0],
895            SysCall::DestroyServer(sid) => {
896                let s = sid.to_u32();
897                [SysCallNumber::DestroyServer as usize, s.0 as _, s.1 as _, s.2 as _, s.3 as _, 0, 0, 0]
898            }
899            SysCall::Disconnect(cid) => [SysCallNumber::Disconnect as usize, *cid as usize, 0, 0, 0, 0, 0, 0],
900            SysCall::JoinThread(tid) => [SysCallNumber::JoinThread as usize, *tid, 0, 0, 0, 0, 0, 0],
901            SysCall::SetExceptionHandler(pc, sp) => {
902                [SysCallNumber::SetExceptionHandler as usize, *pc, *sp, 0, 0, 0, 0, 0]
903            }
904            SysCall::AdjustProcessLimit(index, current, new) => {
905                [SysCallNumber::AdjustProcessLimit as usize, *index, *current, *new, 0, 0, 0, 0]
906            }
907            #[cfg(feature = "v2p")]
908            SysCall::VirtToPhys(vaddr) => [SysCallNumber::VirtToPhys as usize, *vaddr, 0, 0, 0, 0, 0, 0],
909            SysCall::ReturnScalar5(sender, arg1, arg2, arg3, arg4, arg5) => [
910                SysCallNumber::ReturnScalar5 as usize,
911                sender.to_usize(),
912                *arg1,
913                *arg2,
914                *arg3,
915                *arg4,
916                *arg5,
917                0,
918            ],
919            #[cfg(feature = "v2p")]
920            SysCall::VirtToPhysPid(pid, vaddr) => {
921                [SysCallNumber::VirtToPhysPid as usize, pid.get() as usize, *vaddr, 0, 0, 0, 0, 0]
922            }
923            #[cfg(feature = "swap")]
924            SysCall::RegisterSwapper(s0, s1, s2, s3, handler, state) => [
925                SysCallNumber::RegisterSwapper as usize,
926                *s0 as usize,
927                *s1 as usize,
928                *s2 as usize,
929                *s3 as usize,
930                *handler,
931                *state,
932                0,
933            ],
934            #[cfg(feature = "swap")]
935            SysCall::SwapOp(a1, a2, a3, a4, a5, a6, a7) => {
936                [SysCallNumber::SwapOp as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
937            }
938            #[cfg(feature = "raw-trng")]
939            SysCall::RawTrng(a1, a2, a3, a4, a5, a6, a7) => {
940                [SysCallNumber::RawTrng as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
941            }
942            SysCall::PlatformSpecific(a1, a2, a3, a4, a5, a6, a7) => {
943                [SysCallNumber::PlatformSpecific as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
944            }
945            SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7) => {
946                [SysCallNumber::Invalid as usize, *a1, *a2, *a3, *a4, *a5, *a6, *a7]
947            }
948        }
949    }
950
951    #[allow(clippy::too_many_arguments)]
952    pub fn from_args(
953        a0: usize,
954        a1: usize,
955        a2: usize,
956        a3: usize,
957        a4: usize,
958        a5: usize,
959        a6: usize,
960        a7: usize,
961    ) -> core::result::Result<Self, Error> {
962        Ok(match SysCallNumber::from(a0) {
963            SysCallNumber::MapMemory => SysCall::MapMemory(
964                MemoryAddress::new(a1),
965                MemoryAddress::new(a2),
966                MemoryAddress::new(a3).ok_or(Error::InvalidSyscall)?,
967                crate::MemoryFlags::from_bits(a4).ok_or(Error::InvalidSyscall)?,
968            ),
969            SysCallNumber::UnmapMemory => {
970                SysCall::UnmapMemory(unsafe { MemoryRange::new(a1, a2).or(Err(Error::InvalidSyscall)) }?)
971            }
972            SysCallNumber::Yield => SysCall::Yield,
973            SysCallNumber::WaitEvent => SysCall::WaitEvent,
974            SysCallNumber::ReceiveMessage => {
975                SysCall::ReceiveMessage(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
976            }
977            SysCallNumber::TryReceiveMessage => {
978                SysCall::TryReceiveMessage(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
979            }
980            SysCallNumber::ReturnToParent => SysCall::ReturnToParent(pid_from_usize(a1)?, a2),
981            SysCallNumber::ClaimInterrupt => SysCall::ClaimInterrupt(
982                a1,
983                MemoryAddress::new(a2).ok_or(Error::InvalidSyscall)?,
984                MemoryAddress::new(a3),
985            ),
986            SysCallNumber::FreeInterrupt => SysCall::FreeInterrupt(a1),
987            SysCallNumber::SwitchTo => SysCall::SwitchTo(pid_from_usize(a1)?, a2),
988            SysCallNumber::ReadyThreads => SysCall::ReadyThreads(pid_from_usize(a1)?),
989            SysCallNumber::IncreaseHeap => {
990                SysCall::IncreaseHeap(a1, crate::MemoryFlags::from_bits(a2).ok_or(Error::InvalidSyscall)?)
991            }
992            SysCallNumber::DecreaseHeap => SysCall::DecreaseHeap(a1),
993            SysCallNumber::UpdateMemoryFlags => SysCall::UpdateMemoryFlags(
994                unsafe { MemoryRange::new(a1, a2) }?,
995                crate::MemoryFlags::from_bits(a3).ok_or(Error::InvalidSyscall)?,
996                PID::new(a4 as _),
997            ),
998            SysCallNumber::SetMemRegion => SysCall::SetMemRegion(
999                pid_from_usize(a1)?,
1000                MemoryType::from(a2),
1001                MemoryAddress::new(a3).ok_or(Error::InvalidSyscall)?,
1002                a4,
1003            ),
1004            SysCallNumber::CreateServerWithAddress => {
1005                SysCall::CreateServerWithAddress(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
1006            }
1007            SysCallNumber::CreateServer => SysCall::CreateServer,
1008            SysCallNumber::Connect => SysCall::Connect(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _)),
1009            SysCallNumber::SendMessage => Message::try_from((a2, a3, a4, a5, a6, a7))
1010                .map(|m| SysCall::SendMessage(a1.try_into().unwrap(), m))
1011                .unwrap_or_else(|_| SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7)),
1012            SysCallNumber::ReturnMemory => SysCall::ReturnMemory(
1013                MessageSender::from_usize(a1),
1014                unsafe { MemoryRange::new(a2, a3) }?,
1015                MemorySize::new(a4),
1016                MemorySize::new(a5),
1017            ),
1018            SysCallNumber::ReplyAndReceiveNext => {
1019                SysCall::ReplyAndReceiveNext(MessageSender::from_usize(a1), a2, a3, a4, a5, a6, a7)
1020            }
1021            SysCallNumber::CreateThread => {
1022                SysCall::CreateThread(crate::arch::args_to_thread(a1, a2, a3, a4, a5, a6, a7)?)
1023            }
1024            SysCallNumber::CreateProcess => SysCall::CreateProcess([a1, a2, a3, a4, a5, a6, a7].try_into()?),
1025            SysCallNumber::TerminateProcess => SysCall::TerminateProcess(a1 as u32),
1026            SysCallNumber::Shutdown => SysCall::Shutdown,
1027            SysCallNumber::TryConnect => {
1028                SysCall::TryConnect(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
1029            }
1030            SysCallNumber::TrySendMessage => match a2 {
1031                1 => SysCall::TrySendMessage(
1032                    a1 as u32,
1033                    Message::MutableBorrow(MemoryMessage {
1034                        id: a3,
1035                        buf: unsafe { MemoryRange::new(a4, a5) }?,
1036                        offset: MemoryAddress::new(a6),
1037                        valid: MemorySize::new(a7),
1038                    }),
1039                ),
1040                2 => SysCall::TrySendMessage(
1041                    a1 as u32,
1042                    Message::Borrow(MemoryMessage {
1043                        id: a3,
1044                        buf: unsafe { MemoryRange::new(a4, a5) }?,
1045                        offset: MemoryAddress::new(a6),
1046                        valid: MemorySize::new(a7),
1047                    }),
1048                ),
1049                3 => SysCall::TrySendMessage(
1050                    a1 as u32,
1051                    Message::Move(MemoryMessage {
1052                        id: a3,
1053                        buf: unsafe { MemoryRange::new(a4, a5) }?,
1054                        offset: MemoryAddress::new(a6),
1055                        valid: MemorySize::new(a7),
1056                    }),
1057                ),
1058                4 => SysCall::TrySendMessage(
1059                    a1 as u32,
1060                    Message::Scalar(ScalarMessage { id: a3, arg1: a4, arg2: a5, arg3: a6, arg4: a7 }),
1061                ),
1062                5 => SysCall::TrySendMessage(
1063                    a1.try_into().unwrap(),
1064                    Message::BlockingScalar(ScalarMessage { id: a3, arg1: a4, arg2: a5, arg3: a6, arg4: a7 }),
1065                ),
1066                _ => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
1067            },
1068            SysCallNumber::ReturnScalar1 => SysCall::ReturnScalar1(MessageSender::from_usize(a1), a2),
1069            SysCallNumber::ReturnScalar2 => SysCall::ReturnScalar2(MessageSender::from_usize(a1), a2, a3),
1070            SysCallNumber::ConnectForProcess => SysCall::ConnectForProcess(
1071                PID::new(a1 as _).ok_or(Error::InvalidSyscall)?,
1072                SID::from_u32(a2 as _, a3 as _, a4 as _, a5 as _),
1073            ),
1074            SysCallNumber::CreateServerId => SysCall::CreateServerId,
1075            SysCallNumber::GetThreadId => SysCall::GetThreadId,
1076            SysCallNumber::GetProcessId => SysCall::GetProcessId,
1077            SysCallNumber::DestroyServer => {
1078                SysCall::DestroyServer(SID::from_u32(a1 as _, a2 as _, a3 as _, a4 as _))
1079            }
1080            SysCallNumber::Disconnect => SysCall::Disconnect(a1 as _),
1081            SysCallNumber::JoinThread => SysCall::JoinThread(a1 as _),
1082            SysCallNumber::SetExceptionHandler => SysCall::SetExceptionHandler(a1 as _, a2 as _),
1083            SysCallNumber::AdjustProcessLimit => SysCall::AdjustProcessLimit(a1, a2, a3),
1084            #[cfg(feature = "v2p")]
1085            SysCallNumber::VirtToPhys => SysCall::VirtToPhys(a1 as _),
1086            #[cfg(feature = "v2p")]
1087            SysCallNumber::VirtToPhysPid => SysCall::VirtToPhysPid(pid_from_usize(a1)?, a2 as _),
1088            SysCallNumber::ReturnScalar5 => {
1089                SysCall::ReturnScalar5(MessageSender::from_usize(a1), a2, a3, a4, a5, a6)
1090            }
1091            #[cfg(feature = "swap")]
1092            SysCallNumber::RegisterSwapper => {
1093                SysCall::RegisterSwapper(a1 as u32, a2 as u32, a3 as u32, a4 as u32, a5 as usize, a6 as usize)
1094            }
1095            #[cfg(feature = "swap")]
1096            SysCallNumber::SwapOp => SysCall::SwapOp(a1, a2, a3, a4, a5, a6, a7),
1097            #[cfg(feature = "raw-trng")]
1098            SysCallNumber::RawTrng => SysCall::RawTrng(a1, a2, a3, a4, a5, a6, a7),
1099            SysCallNumber::PlatformSpecific => SysCall::PlatformSpecific(a1, a2, a3, a4, a5, a6, a7),
1100            SysCallNumber::Invalid => SysCall::Invalid(a1, a2, a3, a4, a5, a6, a7),
1101        })
1102    }
1103
1104    /// Returns `true` if the associated syscall is a message that has memory attached to it
1105    pub fn has_memory(&self) -> bool {
1106        match self {
1107            SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
1108                matches!(msg, Message::Move(_) | Message::Borrow(_) | Message::MutableBorrow(_))
1109            }
1110            SysCall::ReturnMemory(_, _, _, _) => true,
1111            SysCall::ReplyAndReceiveNext(_, _, _, _, _, _, usize::MAX) => true,
1112            _ => false,
1113        }
1114    }
1115
1116    /// Returns `true` if the associated syscall is a message that is a Move
1117    pub fn is_move(&self) -> bool {
1118        match self {
1119            SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
1120                matches!(msg, Message::Move(_))
1121            }
1122            _ => false,
1123        }
1124    }
1125
1126    /// Returns `true` if the associated syscall is a message that is a Borrow
1127    pub fn is_borrow(&self) -> bool {
1128        match self {
1129            SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
1130                matches!(msg, Message::Borrow(_))
1131            }
1132            _ => false,
1133        }
1134    }
1135
1136    /// Returns `true` if the associated syscall is a message that is a MutableBorrow
1137    pub fn is_mutableborrow(&self) -> bool {
1138        match self {
1139            SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => {
1140                matches!(msg, Message::MutableBorrow(_))
1141            }
1142            _ => false,
1143        }
1144    }
1145
1146    /// Returns `true` if the associated syscall is returning memory
1147    pub fn is_return_memory(&self) -> bool {
1148        matches!(self, SysCall::ReturnMemory(..) | SysCall::ReplyAndReceiveNext(_, _, _, _, _, _, usize::MAX))
1149    }
1150
1151    /// If the syscall has memory attached to it, return the memory
1152    pub fn memory(&self) -> Option<MemoryRange> {
1153        match self {
1154            SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => match msg {
1155                Message::Move(memory_message)
1156                | Message::Borrow(memory_message)
1157                | Message::MutableBorrow(memory_message) => Some(memory_message.buf),
1158                _ => None,
1159            },
1160            SysCall::ReturnMemory(_, range, _, _) => Some(*range),
1161            SysCall::ReplyAndReceiveNext(_, _, a1, a2, _, _, usize::MAX) => unsafe {
1162                MemoryRange::new(*a1, *a2).ok()
1163            },
1164            _ => None,
1165        }
1166    }
1167
1168    /// If the syscall has memory attached to it, replace the memory.
1169    ///
1170    /// # Safety
1171    ///
1172    /// This function is only safe to call to fixup the pointer, particularly
1173    /// when running in hosted mode. It should not be used for any other purpose.
1174    pub unsafe fn replace_memory(&mut self, new: MemoryRange) {
1175        match self {
1176            SysCall::TrySendMessage(_, msg) | SysCall::SendMessage(_, msg) => match msg {
1177                Message::Move(memory_message)
1178                | Message::Borrow(memory_message)
1179                | Message::MutableBorrow(memory_message) => memory_message.buf = new,
1180                _ => (),
1181            },
1182            SysCall::ReturnMemory(_, range, _, _) => *range = new,
1183            SysCall::ReplyAndReceiveNext(_, _, a1, a2, _, _, usize::MAX) => {
1184                *a1 = new.addr.get();
1185                *a2 = new.size.get();
1186            }
1187            _ => (),
1188        }
1189    }
1190
1191    /// Returns `true` if the given syscall may be called from an IRQ context
1192    pub fn can_call_from_interrupt(&self) -> bool {
1193        if let SysCall::TrySendMessage(_cid, msg) = self {
1194            return !msg.is_blocking();
1195        }
1196        #[cfg(feature = "swap")]
1197        if let SysCall::SwapOp(_, _, _, _, _, _, _) = self {
1198            return true;
1199        }
1200        matches!(
1201            self,
1202            SysCall::TryConnect(_)
1203                | SysCall::FreeInterrupt(_)
1204                | SysCall::ClaimInterrupt(_, _, _)
1205                | SysCall::TryReceiveMessage(_)
1206                | SysCall::ReturnToParent(_, _)
1207                | SysCall::ReturnScalar5(_, _, _, _, _, _)
1208                | SysCall::ReturnScalar2(_, _, _)
1209                | SysCall::ReturnScalar1(_, _)
1210                | SysCall::ReturnMemory(_, _, _, _)
1211        )
1212    }
1213}
1214
1215/// Map the given physical address to the given virtual address.
1216/// The `size` field must be page-aligned.
1217pub fn map_memory(
1218    phys: Option<MemoryAddress>,
1219    virt: Option<MemoryAddress>,
1220    size: usize,
1221    flags: MemoryFlags,
1222) -> core::result::Result<MemoryRange, Error> {
1223    crate::arch::map_memory_pre(&phys, &virt, size, flags)?;
1224    let result =
1225        rsyscall(SysCall::MapMemory(phys, virt, MemorySize::new(size).ok_or(Error::InvalidSyscall)?, flags))?;
1226    if let Result::MemoryRange(range) = result {
1227        Ok(crate::arch::map_memory_post(phys, virt, size, flags, range)?)
1228    } else if let Result::Error(e) = result {
1229        Err(e)
1230    } else {
1231        Err(Error::InternalError)
1232    }
1233}
1234
1235/// Map the given physical address to the given virtual address.
1236/// The `size` field must be page-aligned.
1237pub fn unmap_memory(range: MemoryRange) -> core::result::Result<(), Error> {
1238    crate::arch::unmap_memory_pre(&range)?;
1239    let result = rsyscall(SysCall::UnmapMemory(range))?;
1240    if let crate::Result::Ok = result {
1241        crate::arch::unmap_memory_post(range)?;
1242        Ok(())
1243    } else if let Result::Error(e) = result {
1244        Err(e)
1245    } else {
1246        Err(Error::InternalError)
1247    }
1248}
1249
1250/// Update the permissions on the given memory range. Note that permissions may
1251/// only be stripped here -- they may never be added.
1252pub fn update_memory_flags(range: MemoryRange, flags: MemoryFlags) -> core::result::Result<Result, Error> {
1253    let result = rsyscall(SysCall::UpdateMemoryFlags(range, flags, None))?;
1254    if let Result::Ok = result {
1255        Ok(Result::Ok)
1256    } else if let Result::Error(e) = result {
1257        Err(e)
1258    } else {
1259        Err(Error::InternalError)
1260    }
1261}
1262
1263/// Map the given physical address to the given virtual address.
1264/// The `size` field must be page-aligned.
1265pub fn return_memory(sender: MessageSender, mem: MemoryRange) -> core::result::Result<(), Error> {
1266    let result = rsyscall(SysCall::ReturnMemory(sender, mem, None, None))?;
1267    if let crate::Result::Ok = result {
1268        Ok(())
1269    } else if let Result::Error(e) = result {
1270        Err(e)
1271    } else {
1272        Err(Error::InternalError)
1273    }
1274}
1275
1276/// Map the given physical address to the given virtual address.
1277/// The `size` field must be page-aligned.
1278pub fn return_memory_offset(
1279    sender: MessageSender,
1280    mem: MemoryRange,
1281    offset: Option<MemorySize>,
1282) -> core::result::Result<(), Error> {
1283    let result = rsyscall(SysCall::ReturnMemory(sender, mem, offset, None))?;
1284    if let crate::Result::Ok = result {
1285        Ok(())
1286    } else if let Result::Error(e) = result {
1287        Err(e)
1288    } else {
1289        Err(Error::InternalError)
1290    }
1291}
1292
1293/// Map the given physical address to the given virtual address.
1294/// The `size` field must be page-aligned.
1295pub fn return_memory_offset_valid(
1296    sender: MessageSender,
1297    mem: MemoryRange,
1298    offset: Option<MemorySize>,
1299    valid: Option<MemorySize>,
1300) -> core::result::Result<(), Error> {
1301    let result = rsyscall(SysCall::ReturnMemory(sender, mem, offset, valid))?;
1302    if let crate::Result::Ok = result {
1303        Ok(())
1304    } else if let Result::Error(e) = result {
1305        Err(e)
1306    } else {
1307        Err(Error::InternalError)
1308    }
1309}
1310
1311/// Map the given physical address to the given virtual address.
1312/// The `size` field must be page-aligned.
1313pub fn return_scalar(sender: MessageSender, val: usize) -> core::result::Result<(), Error> {
1314    let result = rsyscall(SysCall::ReturnScalar1(sender, val))?;
1315    if let crate::Result::Ok = result {
1316        Ok(())
1317    } else if let Result::Error(e) = result {
1318        Err(e)
1319    } else {
1320        Err(Error::InternalError)
1321    }
1322}
1323
1324/// Map the given physical address to the given virtual address.
1325/// The `size` field must be page-aligned.
1326pub fn return_scalar2(sender: MessageSender, val1: usize, val2: usize) -> core::result::Result<(), Error> {
1327    let result = rsyscall(SysCall::ReturnScalar2(sender, val1, val2))?;
1328    if let crate::Result::Ok = result {
1329        Ok(())
1330    } else if let Result::Error(e) = result {
1331        Err(e)
1332    } else {
1333        Err(Error::InternalError)
1334    }
1335}
1336
1337/// Return 5 scalars to the provided message.
1338pub fn return_scalar5(
1339    sender: MessageSender,
1340    val1: usize,
1341    val2: usize,
1342    val3: usize,
1343    val4: usize,
1344    val5: usize,
1345) -> core::result::Result<(), Error> {
1346    let result = rsyscall(SysCall::ReturnScalar5(sender, val1, val2, val3, val4, val5))?;
1347    if let crate::Result::Ok = result {
1348        Ok(())
1349    } else if let Result::Error(e) = result {
1350        Err(e)
1351    } else {
1352        Err(Error::InternalError)
1353    }
1354}
1355
1356/// Claim a hardware interrupt for this process.
1357pub fn claim_interrupt(
1358    irq_no: usize,
1359    callback: fn(irq_no: usize, arg: *mut usize),
1360    arg: *mut usize,
1361) -> core::result::Result<(), Error> {
1362    let result = rsyscall(SysCall::ClaimInterrupt(
1363        irq_no,
1364        MemoryAddress::new(callback as *mut usize as usize).ok_or(Error::InvalidSyscall)?,
1365        MemoryAddress::new(arg as *mut usize as usize),
1366    ))?;
1367    if let crate::Result::Ok = result {
1368        Ok(())
1369    } else if let Result::Error(e) = result {
1370        Err(e)
1371    } else {
1372        Err(Error::InternalError)
1373    }
1374}
1375
1376/// Create a new server with the given name.  This enables other processes to
1377/// connect to this server to send messages.  The name is a UTF-8 token that
1378/// will be mixed with other random data that is unique to each process.
1379/// That way, if a process crashes and is restarted, it can keep the same
1380/// name.  However, other processes cannot spoof this process.
1381///
1382/// # Errors
1383///
1384/// * **OutOfMemory**: No more servers may be created because the server count limit has been reached, or the
1385///   system does not have enough memory for the backing store.
1386/// * **ServerExists**: A server has already registered with that name
1387/// * **InvalidString**: The name was not a valid UTF-8 string
1388pub fn create_server_with_address(name_bytes: &[u8; 16]) -> core::result::Result<SID, Error> {
1389    let sid = SID::from_bytes(name_bytes).ok_or(Error::InvalidString)?;
1390
1391    let result = rsyscall(SysCall::CreateServerWithAddress(sid))?;
1392    if let Result::NewServerID(sid, _cid) = result {
1393        Ok(sid)
1394    } else if let Result::Error(e) = result {
1395        Err(e)
1396    } else {
1397        Err(Error::InternalError)
1398    }
1399}
1400
1401/// Create a new server with the given SID.  This enables other processes to
1402/// connect to this server to send messages.  The name is a unique 128-bit SID.
1403/// That way, if a process crashes and is restarted, it can keep the same
1404/// name.  However, other processes cannot spoof this process.
1405///
1406/// # Errors
1407///
1408/// * **OutOfMemory**: No more servers may be created because the server count limit has been reached, or the
1409///   system does not have enough memory for the backing store.
1410/// * **ServerExists**: A server has already registered with that name
1411/// * **InvalidString**: The name was not a valid UTF-8 string
1412pub fn create_server_with_sid(sid: SID) -> core::result::Result<SID, Error> {
1413    let result = rsyscall(SysCall::CreateServerWithAddress(sid))?;
1414    if let Result::NewServerID(sid, _cid) = result {
1415        Ok(sid)
1416    } else if let Result::Error(e) = result {
1417        Err(e)
1418    } else {
1419        Err(Error::InternalError)
1420    }
1421}
1422
1423/// Create a new server with a random name.  This enables other processes to
1424/// connect to this server to send messages.  A random server ID is generated
1425/// by the kernel and returned to the caller. This address can then be registered
1426/// to a nameserver.
1427///
1428/// # Errors
1429///
1430/// * **ServerNotFound**: No more servers may be created
1431/// * **OutOfMemory**: No more servers may be created because the server count limit has been reached, or the
1432///   system does not have enough memory for the backing store.
1433pub fn create_server() -> core::result::Result<SID, Error> {
1434    let result = rsyscall(SysCall::CreateServer)?;
1435    if let Result::NewServerID(sid, _cid) = result {
1436        Ok(sid)
1437    } else if let Result::Error(e) = result {
1438        Err(e)
1439    } else {
1440        Err(Error::InternalError)
1441    }
1442}
1443
1444/// Fetch a random server ID from the kernel. This is used
1445/// exclusively by the name server and the suspend/resume server.  A random server ID is generated
1446/// by the kernel and returned to the caller. This address can then be registered
1447/// to a nameserver by the caller in their memory space.
1448///
1449/// The implementation is just a call to the kernel-exclusive TRNG to fetch random numbers.
1450///
1451/// # Errors
1452pub fn create_server_id() -> core::result::Result<SID, Error> {
1453    let result = rsyscall(SysCall::CreateServerId)?;
1454    if let Result::ServerID(sid) = result {
1455        Ok(sid)
1456    } else if let Result::Error(e) = result {
1457        Err(e)
1458    } else {
1459        Err(Error::InternalError)
1460    }
1461}
1462
1463/// Connect to a server with the given SID
1464pub fn connect(server: SID) -> core::result::Result<CID, Error> {
1465    let result = rsyscall(SysCall::Connect(server))?;
1466    if let Result::ConnectionID(cid) = result {
1467        Ok(cid)
1468    } else if let Result::Error(e) = result {
1469        Err(e)
1470    } else {
1471        Err(Error::InternalError)
1472    }
1473}
1474
1475/// Connect to a server with the given SID
1476pub fn try_connect(server: SID) -> core::result::Result<CID, Error> {
1477    let result = rsyscall(SysCall::TryConnect(server))?;
1478    if let Result::ConnectionID(cid) = result {
1479        Ok(cid)
1480    } else if let Result::Error(e) = result {
1481        Err(e)
1482    } else {
1483        Err(Error::InternalError)
1484    }
1485}
1486
1487/// Suspend the current process until a message is received.  This thread will
1488/// block until a message is received.
1489///
1490/// # Errors
1491pub fn receive_message(server: SID) -> core::result::Result<MessageEnvelope, Error> {
1492    let result = rsyscall(SysCall::ReceiveMessage(server)).expect("Couldn't call ReceiveMessage");
1493    if let Result::MessageEnvelope(envelope) = result {
1494        Ok(envelope)
1495    } else if let Result::Error(e) = result {
1496        Err(e)
1497    } else {
1498        Err(Error::InternalError)
1499    }
1500}
1501
1502/// Retrieve a message from the message queue for the provided server. If no message
1503/// is available, returns `Ok(None)` without blocking
1504///
1505/// # Errors
1506pub fn try_receive_message(server: SID) -> core::result::Result<Option<MessageEnvelope>, Error> {
1507    let result = rsyscall(SysCall::TryReceiveMessage(server)).expect("Couldn't call ReceiveMessage");
1508    if let Result::MessageEnvelope(envelope) = result {
1509        Ok(Some(envelope))
1510    } else if result == Result::None {
1511        Ok(None)
1512    } else if let Result::Error(e) = result {
1513        Err(e)
1514    } else {
1515        Err(Error::InternalError)
1516    }
1517}
1518
1519/// Send a message to a server.  Depending on the message type (move or borrow), it
1520/// will either block (borrow) or return immediately (move).
1521/// If the message type is `borrow`, then the memory addresses pointed to will be
1522/// unavailable to this process until this function returns.
1523///
1524/// # Errors
1525///
1526/// * **ServerNotFound**: The server does not exist so the connection is now invalid
1527/// * **BadAddress**: The client tried to pass a Memory message using an address it doesn't own
1528/// * **ServerQueueFull**: The queue in the server is full, and this call would block
1529/// * **Timeout**: The timeout limit has been reached
1530pub fn try_send_message(connection: CID, message: Message) -> core::result::Result<Result, Error> {
1531    let result = rsyscall(SysCall::TrySendMessage(connection, message));
1532    match result {
1533        Ok(Result::Ok) => Ok(Result::Ok),
1534        Ok(Result::Scalar1(a)) => Ok(Result::Scalar1(a)),
1535        Ok(Result::Scalar2(a, b)) => Ok(Result::Scalar2(a, b)),
1536        Ok(Result::Scalar5(a, b, c, d, e)) => Ok(Result::Scalar5(a, b, c, d, e)),
1537        Ok(Result::MemoryReturned(offset, valid)) => Ok(Result::MemoryReturned(offset, valid)),
1538        Ok(Result::MessageEnvelope(msg)) => Ok(Result::MessageEnvelope(msg)),
1539        Err(e) => Err(e),
1540        v => panic!("Unexpected return value: {:?}", v),
1541    }
1542}
1543
1544/// Connect to a server on behalf of another process. This can be used by a name
1545/// resolution server to securely create connections without disclosing a SID.
1546///
1547/// # Errors
1548///
1549/// * **ServerNotFound**: The server does not exist so the connection is now invalid
1550/// * **BadAddress**: The client tried to pass a Memory message using an address it doesn't own
1551/// * **ServerQueueFull**: The queue in the server is full, and this call would block
1552/// * **Timeout**: The timeout limit has been reached
1553pub fn connect_for_process(pid: PID, sid: SID) -> core::result::Result<Result, Error> {
1554    let result = rsyscall(SysCall::ConnectForProcess(pid, sid));
1555    match result {
1556        Ok(Result::ConnectionID(cid)) => Ok(Result::ConnectionID(cid)),
1557        Err(e) => Err(e),
1558        v => panic!("Unexpected return value: {:?}", v),
1559    }
1560}
1561
1562/// Send a message to a server.  Depending on the message type (move or borrow), it
1563/// will either block (borrow) or return immediately (move).
1564/// If the message type is `borrow`, then the memory addresses pointed to will be
1565/// unavailable to this process until this function returns.
1566///
1567/// If the server queue is full, this will block.
1568///
1569/// # Errors
1570///
1571/// * **ServerNotFound**: The server does not exist so the connection is now invalid
1572/// * **BadAddress**: The client tried to pass a Memory message using an address it doesn't own
1573/// * **Timeout**: The timeout limit has been reached
1574pub fn send_message(connection: CID, message: Message) -> core::result::Result<Result, Error> {
1575    let result = rsyscall(SysCall::SendMessage(connection, message));
1576    match result {
1577        Ok(Result::Ok) => Ok(Result::Ok),
1578        Ok(Result::Scalar1(a)) => Ok(Result::Scalar1(a)),
1579        Ok(Result::Scalar2(a, b)) => Ok(Result::Scalar2(a, b)),
1580        Ok(Result::Scalar5(a, b, c, d, e)) => Ok(Result::Scalar5(a, b, c, d, e)),
1581        Ok(Result::MemoryReturned(offset, valid)) => Ok(Result::MemoryReturned(offset, valid)),
1582        Err(e) => Err(e),
1583        v => panic!("Unexpected return value: {:?}", v),
1584    }
1585}
1586
1587pub fn terminate_process(exit_code: u32) -> ! {
1588    rsyscall(SysCall::TerminateProcess(exit_code)).expect("terminate_process returned an error");
1589    panic!("process didn't terminate");
1590}
1591
1592/// Return execution to the kernel. This function may return at any time,
1593/// including immediately
1594pub fn yield_slice() { rsyscall(SysCall::Yield).ok(); }
1595
1596/// Return execution to the kernel and wait for a message or an interrupt.
1597pub fn wait_event() { rsyscall(SysCall::WaitEvent).ok(); }
1598
1599#[deprecated(since = "0.2.0", note = "Please use create_thread_n() or create_thread()")]
1600pub fn create_thread_simple<T, U>(
1601    f: fn(T) -> U,
1602    arg: T,
1603) -> core::result::Result<crate::arch::WaitHandle<U>, Error>
1604where
1605    T: Send + 'static,
1606    U: Send + 'static,
1607{
1608    let thread_info = crate::arch::create_thread_simple_pre(&f, &arg)?;
1609    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1610        if let Result::ThreadID(thread_id) = result {
1611            crate::arch::create_thread_simple_post(f, arg, thread_id)
1612        } else {
1613            Err(Error::InternalError)
1614        }
1615    })
1616}
1617
1618pub fn create_thread_0<T>(f: fn() -> T) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
1619where
1620    T: Send + 'static,
1621{
1622    let thread_info = crate::arch::create_thread_0_pre(&f)?;
1623    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1624        if let Result::ThreadID(thread_id) = result {
1625            crate::arch::create_thread_0_post(f, thread_id)
1626        } else {
1627            Err(Error::InternalError)
1628        }
1629    })
1630}
1631
1632pub fn create_thread_1<T>(
1633    f: fn(usize) -> T,
1634    arg1: usize,
1635) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
1636where
1637    T: Send + 'static,
1638{
1639    let thread_info = crate::arch::create_thread_1_pre(&f, &arg1)?;
1640    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1641        if let Result::ThreadID(thread_id) = result {
1642            crate::arch::create_thread_1_post(f, arg1, thread_id)
1643        } else {
1644            Err(Error::InternalError)
1645        }
1646    })
1647}
1648
1649pub fn create_thread_2<T>(
1650    f: fn(usize, usize) -> T,
1651    arg1: usize,
1652    arg2: usize,
1653) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
1654where
1655    T: Send + 'static,
1656{
1657    let thread_info = crate::arch::create_thread_2_pre(&f, &arg1, &arg2)?;
1658    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1659        if let Result::ThreadID(thread_id) = result {
1660            crate::arch::create_thread_2_post(f, arg1, arg2, thread_id)
1661        } else {
1662            Err(Error::InternalError)
1663        }
1664    })
1665}
1666
1667pub fn create_thread_3<T>(
1668    f: fn(usize, usize, usize) -> T,
1669    arg1: usize,
1670    arg2: usize,
1671    arg3: usize,
1672) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
1673where
1674    T: Send + 'static,
1675{
1676    let thread_info = crate::arch::create_thread_3_pre(&f, &arg1, &arg2, &arg3)?;
1677    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1678        if let Result::ThreadID(thread_id) = result {
1679            crate::arch::create_thread_3_post(f, arg1, arg2, arg3, thread_id)
1680        } else {
1681            Err(Error::InternalError)
1682        }
1683    })
1684}
1685
1686pub fn create_thread_4<T>(
1687    f: fn(usize, usize, usize, usize) -> T,
1688    arg1: usize,
1689    arg2: usize,
1690    arg3: usize,
1691    arg4: usize,
1692) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
1693where
1694    T: Send + 'static,
1695{
1696    let thread_info = crate::arch::create_thread_4_pre(&f, &arg1, &arg2, &arg3, &arg4)?;
1697    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1698        if let Result::ThreadID(thread_id) = result {
1699            crate::arch::create_thread_4_post(f, arg1, arg2, arg3, arg4, thread_id)
1700        } else {
1701            Err(Error::InternalError)
1702        }
1703    })
1704}
1705
1706/// Create a new thread with the given closure.
1707pub fn create_thread<F, T>(f: F) -> core::result::Result<crate::arch::WaitHandle<T>, Error>
1708where
1709    F: FnOnce() -> T,
1710    F: Send + 'static,
1711    T: Send + 'static,
1712{
1713    let thread_info = crate::arch::create_thread_pre(&f)?;
1714    rsyscall(SysCall::CreateThread(thread_info)).and_then(|result| {
1715        if let Result::ThreadID(thread_id) = result {
1716            crate::arch::create_thread_post(f, thread_id)
1717        } else {
1718            Err(Error::InternalError)
1719        }
1720    })
1721}
1722
1723/// Wait for a thread to finish. This is equivalent to `join_thread`
1724pub fn wait_thread<T>(joiner: crate::arch::WaitHandle<T>) -> SysCallResult {
1725    crate::arch::wait_thread(joiner)
1726}
1727
1728/// Create a new process by running it in its own thread
1729#[cfg(feature = "processes-as-threads")]
1730pub fn create_process_as_thread<F>(
1731    args: ProcessArgsAsThread<F>,
1732) -> core::result::Result<crate::arch::ProcessHandleAsThread, Error>
1733where
1734    F: FnOnce() + Send + 'static,
1735{
1736    let process_init = crate::arch::create_process_pre_as_thread(&args)?;
1737    rsyscall(SysCall::CreateProcess(process_init)).and_then(|result| {
1738        if let Result::NewProcess(startup) = result {
1739            crate::arch::create_process_post_as_thread(args, process_init, startup)
1740        } else {
1741            Err(Error::InternalError)
1742        }
1743    })
1744}
1745
1746/// Wait for a thread to finish
1747#[cfg(feature = "processes-as-threads")]
1748pub fn wait_process_as_thread(joiner: crate::arch::ProcessHandleAsThread) -> SysCallResult {
1749    crate::arch::wait_process_as_thread(joiner)
1750}
1751
1752pub fn create_process(args: ProcessArgs) -> core::result::Result<crate::arch::ProcessHandle, Error> {
1753    let process_init = crate::arch::create_process_pre(&args)?;
1754    rsyscall(SysCall::CreateProcess(process_init)).and_then(|result| {
1755        if let Result::NewProcess(startup) = result {
1756            crate::arch::create_process_post(args, process_init, startup)
1757        } else {
1758            Err(Error::InternalError)
1759        }
1760    })
1761}
1762
1763/// Wait for a thread to finish
1764pub fn wait_process(joiner: crate::arch::ProcessHandle) -> SysCallResult { crate::arch::wait_process(joiner) }
1765
1766/// Get the current process ID
1767pub fn current_pid() -> core::result::Result<PID, Error> {
1768    rsyscall(SysCall::GetProcessId).and_then(|result| {
1769        if let Result::ProcessID(pid) = result { Ok(pid) } else { Err(Error::InternalError) }
1770    })
1771}
1772
1773/// Get the current thread ID
1774pub fn current_tid() -> core::result::Result<TID, Error> {
1775    rsyscall(SysCall::GetThreadId).and_then(|result| {
1776        if let Result::ThreadID(tid) = result { Ok(tid) } else { Err(Error::InternalError) }
1777    })
1778}
1779
1780pub fn destroy_server(sid: SID) -> core::result::Result<(), Error> {
1781    rsyscall(SysCall::DestroyServer(sid))
1782        .and_then(|result| if let Result::Ok = result { Ok(()) } else { Err(Error::InternalError) })
1783}
1784
1785/// Disconnect the specified connection ID and mark it as free. This
1786/// connection ID may be reused by the server in the future, so ensure
1787/// no other threads are using the connection ID before disposing of it.
1788///
1789/// # Safety
1790///
1791/// This function must only be called when the connection is no longer in
1792/// use. Calling this function when the connection ID is in use will result
1793/// in kernel errors or, if the CID is reused, silent failures due to
1794/// messages going to the wrong server.
1795pub unsafe fn disconnect(cid: CID) -> core::result::Result<(), Error> {
1796    rsyscall(SysCall::Disconnect(cid))
1797        .and_then(|result| if let Result::Ok = result { Ok(()) } else { Err(Error::InternalError) })
1798}
1799
1800/// Block the current thread and wait for the specified thread to
1801/// return. Returns the return value of the thread.
1802///
1803/// # Errors
1804///
1805/// * **ThreadNotAvailable**: The thread could not be found, or was not sleeping.
1806pub fn join_thread(tid: TID) -> core::result::Result<usize, Error> {
1807    rsyscall(SysCall::JoinThread(tid)).and_then(|result| {
1808        if let Result::Scalar1(val) = result {
1809            Ok(val)
1810        } else if let Result::Error(Error::ThreadNotAvailable) = result {
1811            Err(Error::ThreadNotAvailable)
1812        } else {
1813            Err(Error::InternalError)
1814        }
1815    })
1816}
1817
1818/// Reply to the message, if one exists, and receive the next one.
1819/// If no message exists, delegate the call to `receive_syscall()`.
1820pub fn reply_and_receive_next(
1821    server: SID,
1822    msg: &mut Option<MessageEnvelope>,
1823) -> core::result::Result<(), crate::Error> {
1824    reply_and_receive_next_legacy(server, msg, &mut 0)
1825}
1826
1827/// Reply to the message, if one exists, and receive the next one.
1828/// If no message exists, delegate the call to `receive_syscall()`.
1829/// Allow specifying the scalar return type.
1830///
1831/// This is named `_legacy` because it is meant to work with calls that
1832/// expect both `Scalar1` and `Scalar2` values, in addition to `Scalar5`.
1833///
1834/// ## Arguments
1835///
1836///  * **server**: The SID of the server to receive messages from
1837///  * **msg**: An `Option<MessageEnvelope>` specifying the message to return.
1838///  * **return_type**: If 1 or 2, responds to a BlockingScalarMessage with a Scalar1 or a Scalar2. Otherwise,
1839///    will respond as normal.
1840pub fn reply_and_receive_next_legacy(
1841    server: SID,
1842    msg: &mut Option<MessageEnvelope>,
1843    return_type: &mut usize,
1844) -> core::result::Result<(), crate::Error> {
1845    let mut rt = *return_type;
1846    *return_type = 0;
1847    if let Some(envelope) = msg.take() {
1848        // If the message inside is nonblocking, then there's nothing to return.
1849        // Delegate reception to the `receive_message()` call
1850        if !envelope.body.is_blocking() {
1851            *msg = Some(receive_message(server)?);
1852            return Ok(());
1853        }
1854
1855        let args = if let Some(mem) = envelope.body.memory_message() {
1856            // Allow hosted mode to detect this is a memory message by giving a sentinel value here
1857            rt = usize::MAX;
1858            mem.to_usize()
1859        } else if let Some(scalar) = envelope.body.scalar_message() {
1860            scalar.to_usize()
1861        } else {
1862            panic!("unrecognized message type")
1863        };
1864        let sender = envelope.sender;
1865        core::mem::forget(envelope);
1866        let call = SysCall::ReplyAndReceiveNext(sender, args[0], args[1], args[2], args[3], args[4], rt);
1867        match rsyscall(call) {
1868            Ok(crate::Result::MessageEnvelope(envelope)) => {
1869                *msg = Some(envelope);
1870                Ok(())
1871            }
1872            Ok(crate::Result::Error(e)) => Err(e),
1873            _ => Err(crate::Error::InternalError),
1874        }
1875    } else {
1876        // No waiting message -- call the existing `receive_message()` function
1877        *msg = Some(receive_message(server)?);
1878        Ok(())
1879    }
1880}
1881
1882/* https://github.com/betrusted-io/xous-core/issues/90
1883static EXCEPTION_HANDLER: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
1884fn handle_exception(exception_type: usize, arg1: usize, arg2: usize) -> isize {
1885    let exception = crate::exceptions::Exception::new(exception_type, arg1, arg2);
1886    let f = EXCEPTION_HANDLER.load(core::sync::atomic::Ordering::SeqCst);
1887    let f = unsafe { core::mem::transmute::<usize, fn(Exception) -> isize>(f) };
1888    f(exception)
1889}
1890/// Sets the given function as this process' Exception handler. This function
1891/// will be called whenever an Exception occurs such as a memory fault,
1892/// illegal instruction, or a child process terminating.
1893pub fn set_exception_handler(
1894    handler: fn(crate::Exception) -> isize,
1895) -> core::result::Result<(), Error> {
1896    let flags = crate::MemoryFlags::R | crate::MemoryFlags::W | crate::MemoryFlags::RESERVE;
1897
1898    let stack = crate::map_memory(None, None, 131_072, flags)?;
1899    EXCEPTION_HANDLER.store(handler as usize, core::sync::atomic::Ordering::SeqCst);
1900    rsyscall(SysCall::SetExceptionHandler(
1901        handle_exception as usize,
1902        stack.as_ptr() as usize,
1903    ))
1904    .and_then(|result| {
1905        if let Result::Ok = result {
1906            Ok(())
1907        } else if let Result::Error(Error::ThreadNotAvailable) = result {
1908            Err(Error::ThreadNotAvailable)
1909        } else {
1910            Err(Error::InternalError)
1911        }
1912    })
1913}
1914*/
1915
1916/// Translate a virtual address to a physical address
1917#[cfg(feature = "v2p")]
1918pub fn virt_to_phys(va: usize) -> core::result::Result<usize, Error> {
1919    rsyscall(SysCall::VirtToPhys(va))
1920        .and_then(|result| if let Result::Scalar1(pa) = result { Ok(pa) } else { Err(Error::BadAddress) })
1921}
1922
1923/// Translate a virtual address to a physical address for a given process
1924#[cfg(feature = "v2p")]
1925pub fn virt_to_phys_pid(pid: PID, va: usize) -> core::result::Result<usize, Error> {
1926    rsyscall(SysCall::VirtToPhysPid(pid, va))
1927        .and_then(|result| if let Result::Scalar1(pa) = result { Ok(pa) } else { Err(Error::BadAddress) })
1928}
1929
1930pub fn increase_heap(bytes: usize, flags: MemoryFlags) -> core::result::Result<MemoryRange, ()> {
1931    let res = crate::arch::syscall(SysCall::IncreaseHeap(bytes, flags));
1932    if let Ok(Result::MemoryRange(range)) = res {
1933        return Ok(range);
1934    }
1935
1936    Err(())
1937}
1938
1939/// Perform a raw syscall and return the result. This will transform
1940/// `xous::Result::Error(e)` into an `Err(e)`.
1941pub fn rsyscall(call: SysCall) -> SysCallResult { crate::arch::syscall(call) }
1942
1943// /// This is dangerous, but fast.
1944// pub unsafe fn dangerous_syscall(call: SysCall) -> SyscallResult {
1945//     use core::mem::{transmute, MaybeUninit};
1946//     let mut ret = MaybeUninit::uninit().assume_init();
1947//     let presto = transmute::<_, (usize, usize, usize, usize, usize, usize, usize, usize)>(call);
1948//     _xous_syscall_rust(
1949//         presto.0, presto.1, presto.2, presto.3, presto.4, presto.5, presto.6, presto.7, &mut ret,
1950//     );
1951//     match ret {
1952//         Result::Error(e) => Err(e),
1953//         other => Ok(other),
1954//     }
1955// }