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// }