Skip to main content

kernel/
syscall_driver.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! System call interface for userspace processes implemented by capsules.
6//!
7//! Drivers implement these interfaces to expose operations to processes.
8
9use crate::errorcode::ErrorCode;
10use crate::process;
11use crate::process::ProcessId;
12use crate::processbuffer::UserspaceReadableProcessBuffer;
13use crate::syscall::SyscallReturn;
14
15/// Possible return values of a `command` driver method, as specified in TRD104.
16///
17/// This is just a wrapper around [`SyscallReturn`] since a `command` driver
18/// method may only return primitive integer types as payload.
19///
20/// It is important for this wrapper to only be constructable over variants of
21/// [`SyscallReturn`] that are deemed safe for a capsule to construct and return
22/// to an application (e.g. not
23/// [`SubscribeSuccess`](crate::syscall::SyscallReturn::SubscribeSuccess)). This
24/// means that the inner value **must** remain private.
25pub struct CommandReturn(SyscallReturn);
26
27impl CommandReturn {
28    pub(crate) fn into_inner(self) -> SyscallReturn {
29        self.0
30    }
31
32    /// Command error
33    pub fn failure(rc: ErrorCode) -> Self {
34        CommandReturn(SyscallReturn::Failure(rc))
35    }
36
37    /// Command error with an additional 32-bit data field
38    pub fn failure_u32(rc: ErrorCode, data0: u32) -> Self {
39        CommandReturn(SyscallReturn::FailureU32(rc, data0))
40    }
41
42    /// Command error with two additional 32-bit data fields
43    pub fn failure_u32_u32(rc: ErrorCode, data0: u32, data1: u32) -> Self {
44        CommandReturn(SyscallReturn::FailureU32U32(rc, data0, data1))
45    }
46
47    /// Command error with an additional 64-bit data field
48    pub fn failure_u64(rc: ErrorCode, data0: u64) -> Self {
49        CommandReturn(SyscallReturn::FailureU64(rc, data0))
50    }
51
52    /// Successful command
53    pub fn success() -> Self {
54        CommandReturn(SyscallReturn::Success)
55    }
56
57    /// Successful command with an additional 32-bit data field
58    pub fn success_u32(data0: u32) -> Self {
59        CommandReturn(SyscallReturn::SuccessU32(data0))
60    }
61
62    /// Successful command with two additional 32-bit data fields
63    pub fn success_u32_u32(data0: u32, data1: u32) -> Self {
64        CommandReturn(SyscallReturn::SuccessU32U32(data0, data1))
65    }
66
67    /// Successful command with three additional 32-bit data fields
68    pub fn success_u32_u32_u32(data0: u32, data1: u32, data2: u32) -> Self {
69        CommandReturn(SyscallReturn::SuccessU32U32U32(data0, data1, data2))
70    }
71
72    /// Successful command with an additional 64-bit data field
73    pub fn success_u64(data0: u64) -> Self {
74        CommandReturn(SyscallReturn::SuccessU64(data0))
75    }
76
77    /// Successful command with an additional 64-bit and 32-bit data field
78    pub fn success_u32_u64(data0: u32, data1: u64) -> Self {
79        CommandReturn(SyscallReturn::SuccessU32U64(data0, data1))
80    }
81
82    /// Returns true if this [`CommandReturn`] is of type
83    /// [`SyscallReturn::Failure`].
84    pub fn is_failure(&self) -> bool {
85        matches!(self.0, SyscallReturn::Failure(_))
86    }
87
88    /// Returns true if this [`CommandReturn`] is of type
89    /// [`SyscallReturn::FailureU32`].
90    pub fn is_failure_u32(&self) -> bool {
91        matches!(self.0, SyscallReturn::FailureU32(_, _))
92    }
93
94    /// Returns true if this [`CommandReturn`] is of type
95    /// [`SyscallReturn::FailureU32U32`].
96    pub fn is_failure_2_u32(&self) -> bool {
97        matches!(self.0, SyscallReturn::FailureU32U32(_, _, _))
98    }
99
100    /// Returns true if this [`CommandReturn`] is of type
101    /// [`SyscallReturn::FailureU64`].
102    pub fn is_failure_u64(&self) -> bool {
103        matches!(self.0, SyscallReturn::FailureU64(_, _))
104    }
105
106    /// Returns true if this [`CommandReturn`] is of type
107    /// [`SyscallReturn::Success`]. Note that this does not return true for
108    /// other success types, such as [`SyscallReturn::SuccessU32`].
109    pub fn is_success(&self) -> bool {
110        matches!(self.0, SyscallReturn::Success)
111    }
112
113    /// Returns true if this [`CommandReturn`] is of type
114    /// [`SyscallReturn::SuccessU32`].
115    pub fn is_success_u32(&self) -> bool {
116        matches!(self.0, SyscallReturn::SuccessU32(_))
117    }
118
119    /// Returns true if this [`CommandReturn`] is of type
120    /// [`SyscallReturn::SuccessU32U32`].
121    pub fn is_success_2_u32(&self) -> bool {
122        matches!(self.0, SyscallReturn::SuccessU32U32(_, _))
123    }
124
125    /// Returns true if this [`CommandReturn`] is of type
126    /// [`SyscallReturn::SuccessU64`].
127    pub fn is_success_u64(&self) -> bool {
128        matches!(self.0, SyscallReturn::SuccessU64(_))
129    }
130
131    /// Returns true if this [`CommandReturn`] is of type
132    /// [`SyscallReturn::SuccessU32U32U32`].
133    pub fn is_success_3_u32(&self) -> bool {
134        matches!(self.0, SyscallReturn::SuccessU32U32U32(_, _, _))
135    }
136
137    /// Returns true if this CommandReturn is of type
138    /// [`SyscallReturn::SuccessU32U64`].
139    pub fn is_success_u32_u64(&self) -> bool {
140        matches!(self.0, SyscallReturn::SuccessU32U64(_, _))
141    }
142
143    /// Returns the [`ErrorCode`] if this [`CommandReturn`] is of type
144    /// [`SyscallReturn::Failure`].
145    pub fn get_failure(&self) -> Option<ErrorCode> {
146        match self.0 {
147            SyscallReturn::Failure(r1) => Some(r1),
148            _ => None,
149        }
150    }
151
152    /// Returns the [`ErrorCode`] and value if this [`CommandReturn`] is of type
153    /// [`SyscallReturn::FailureU32`].
154    pub fn get_failure_u32(&self) -> Option<(ErrorCode, u32)> {
155        match self.0 {
156            SyscallReturn::FailureU32(r1, r2) => Some((r1, r2)),
157            _ => None,
158        }
159    }
160
161    /// Returns the [`ErrorCode`] and values if this [`CommandReturn`] is of type
162    /// [`SyscallReturn::FailureU32U32`].
163    pub fn get_failure_2_u32(&self) -> Option<(ErrorCode, u32, u32)> {
164        match self.0 {
165            SyscallReturn::FailureU32U32(r1, r2, r3) => Some((r1, r2, r3)),
166            _ => None,
167        }
168    }
169
170    /// Returns the [`ErrorCode`] and value if this [`CommandReturn`] is of type
171    ///  [`SyscallReturn::FailureU64`].
172    pub fn get_failure_u64(&self) -> Option<(ErrorCode, u64)> {
173        match self.0 {
174            SyscallReturn::FailureU64(r1, r2) => Some((r1, r2)),
175            _ => None,
176        }
177    }
178
179    /// Returns the value if this [`CommandReturn`] is of type
180    /// [`SyscallReturn::SuccessU32`].
181    pub fn get_success_u32(&self) -> Option<u32> {
182        match self.0 {
183            SyscallReturn::SuccessU32(r1) => Some(r1),
184            _ => None,
185        }
186    }
187
188    /// Returns the values if this [`CommandReturn`] is of type
189    /// [`SyscallReturn::SuccessU32U32`].
190    pub fn get_success_2_u32(&self) -> Option<(u32, u32)> {
191        match self.0 {
192            SyscallReturn::SuccessU32U32(r1, r2) => Some((r1, r2)),
193            _ => None,
194        }
195    }
196
197    /// Returns the value if this [`CommandReturn`] is of type
198    /// [`SyscallReturn::SuccessU64`].
199    pub fn get_success_u64(&self) -> Option<u64> {
200        match self.0 {
201            SyscallReturn::SuccessU64(r1) => Some(r1),
202            _ => None,
203        }
204    }
205
206    /// Returns the values if this [`CommandReturn`] is of type
207    /// [`SyscallReturn::SuccessU32U32U32`].
208    pub fn get_success_3_u32(&self) -> Option<(u32, u32, u32)> {
209        match self.0 {
210            SyscallReturn::SuccessU32U32U32(r1, r2, r3) => Some((r1, r2, r3)),
211            _ => None,
212        }
213    }
214
215    /// Returns the values if this [`CommandReturn`] is of type
216    /// [`SyscallReturn::SuccessU32U64`].
217    pub fn get_success_u32_u64(&self) -> Option<(u32, u64)> {
218        match self.0 {
219            SyscallReturn::SuccessU32U64(r1, r2) => Some((r1, r2)),
220            _ => None,
221        }
222    }
223}
224
225impl From<Result<(), ErrorCode>> for CommandReturn {
226    fn from(rc: Result<(), ErrorCode>) -> Self {
227        match rc {
228            Ok(()) => CommandReturn::success(),
229            Err(e) => CommandReturn::failure(e),
230        }
231    }
232}
233
234impl From<process::Error> for CommandReturn {
235    fn from(perr: process::Error) -> Self {
236        CommandReturn::failure(perr.into())
237    }
238}
239
240/// Trait for capsules implementing peripheral driver system calls specified in
241/// TRD104.
242///
243/// The kernel translates the values passed from userspace into Rust
244/// types and includes which process is making the call. All of these
245/// system calls perform very little synchronous work; long running
246/// computations or I/O should be split-phase, with an upcall
247/// indicating their completion.
248///
249/// The exact instances of each of these methods (which identifiers are valid
250/// and what they represents) are specific to the peripheral system call driver.
251///
252/// Note about `subscribe`, `read-only allow`, and `read-write allow` syscalls:
253/// those are handled entirely by the core kernel, and there is no corresponding
254/// function for capsules to implement. However, capsules implementing
255/// [`SyscallDriver`] that use upcalls _must_ ensure that the grant region is
256/// allocated for every app that is using the driver and may ever need an
257/// upcall. This is because if the app uses the Yield-WaitFor system call,
258/// the automatic allocation of the grant due to a subscribe call won't
259/// happen, and the capsule will not be able to schedule an upcall if the
260/// grant region isn't allocated.
261#[allow(unused_variables)]
262pub trait SyscallDriver {
263    /// System call for a process to perform a short synchronous operation or
264    /// start a long-running split-phase operation (whose completion is signaled
265    /// with an upcall). Command 0 is a reserved command to detect if a
266    /// peripheral system call driver is installed and must always return a
267    /// [`CommandReturn::success`].
268    fn command(
269        &self,
270        command_num: usize,
271        r2: usize,
272        r3: usize,
273        process_id: ProcessId,
274    ) -> CommandReturn {
275        CommandReturn::failure(ErrorCode::NOSUPPORT)
276    }
277
278    /// System call for a process to pass a buffer (a
279    /// [`UserspaceReadableProcessBuffer`]) to the kernel that the kernel can
280    /// either read or write. The kernel calls this method only after it checks
281    /// that the entire buffer is within memory the process can both read and
282    /// write.
283    ///
284    /// This is different to `allow_readwrite` in that the app is allowed to
285    /// read the buffer once it has been passed to the kernel. For more details
286    /// on how this can be done safely see the userspace readable allow syscalls
287    /// TRDXXX.
288    fn allow_userspace_readable(
289        &self,
290        app: ProcessId,
291        which: usize,
292        slice: UserspaceReadableProcessBuffer,
293    ) -> Result<UserspaceReadableProcessBuffer, (UserspaceReadableProcessBuffer, ErrorCode)> {
294        Err((slice, ErrorCode::NOSUPPORT))
295    }
296
297    /// Request to allocate a capsule's grant for a specific process.
298    ///
299    /// The core kernel uses this function to instruct a capsule to ensure its
300    /// grant (if it has one) is allocated for a specific process. The core
301    /// kernel needs the capsule to initiate the allocation because only the
302    /// capsule knows the type `T` (and therefore the size of `T`) that will be
303    /// stored in the grant.
304    ///
305    /// The typical implementation will look like:
306    /// ```rust, ignore
307    /// fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
308    ///    self.apps.enter(processid, |_, _| {})
309    /// }
310    /// ```
311    ///
312    /// No default implementation is provided to help prevent accidentally
313    /// forgetting to implement this function.
314    ///
315    /// If a capsule fails to successfully implement this function, subscribe
316    /// calls from userspace for the [`SyscallDriver`] may fail.
317    //
318    // The inclusion of this function originates from the method for ensuring
319    // correct upcall swapping semantics in the kernel starting with Tock 2.0.
320    // To ensure upcalls are always swapped correctly all upcall handling is
321    // done in the core kernel. Capsules only have access to a handle which
322    // permits them to schedule upcalls, but capsules no longer manage upcalls.
323    //
324    // The core kernel stores upcalls in the process's grant region along with
325    // the capsule's grant object. A simultaneous Tock 2.0 change requires that
326    // capsules wishing to use upcalls must also use grants. Storing upcalls in
327    // the grant requires that the grant be allocated for that capsule in that
328    // process. This presents a challenge as grants are dynamically allocated
329    // only when actually used by a process. If a subscribe syscall happens
330    // first, before the capsule has allocated the grant, the kernel has no way
331    // to store the upcall. The kernel cannot allocate the grant itself because
332    // it does not know the type T the capsule will use for the grant (or more
333    // specifically the kernel does not know the size of T to use for the memory
334    // allocation).
335    //
336    // There are a few ideas on how to handle this case where the kernel must
337    // store an upcall before the capsule has allocated the grant.
338    //
339    // 1. The kernel could allocate space for the grant type T, but not actually
340    //    initialize it, based only on the size of T. However, this would
341    //    require the kernel to keep track of the size of T for each grant, and
342    //    there is no convenient place to store that information.
343    //
344    // 2. The kernel could store upcalls and grant types separately in the grant
345    //    region.
346    //
347    //    a. One approach is to store upcalls completely dynamically. That is,
348    //       whenever a new subscribe_num is used for a particular driver the
349    //       core kernel allocates new memory from the grant region to store it.
350    //       This would work, but would have high memory and runtime overhead to
351    //       manage all of the dynamic upcall stores.
352    //    b. To reduce the tracking overhead, all upcalls for a particular
353    //       driver could be stored together as one allocation. This would only
354    //       cost one additional pointer per grant to point to the upcall array.
355    //       However, the kernel does not know how many upcalls a particular
356    //       driver needs, and there is no convenient place for it to store that
357    //       information.
358    //
359    // 3. The kernel could allocate a fixed region for all upcalls across all
360    //    drivers in the grant region. When each grant is created it could tell
361    //    the kernel how many upcalls it will use and the kernel could easily
362    //    keep track of the total. Then, when a process's memory is allocated
363    //    the kernel would reserve room for that many upcalls. There are two
364    //    issues, however. The kernel would not know how many upcalls each
365    //    driver individually requires, so it would not be able to index into
366    //    this array properly to store each upcall. Second, the upcall array
367    //    memory would be statically allocated, and would be wasted for drivers
368    //    the process never uses.
369    //
370    //    A version of this approach would assume a maximum limit of a certain
371    //    number of upcalls per driver. This would address the indexing
372    //    challenge, but would still have the memory overhead problem. It would
373    //    also limit capsule flexibility by capping the number of upcalls any
374    //    capsule could ever use.
375    //
376    // 4. The kernel could have some mechanism to ask a capsule to allocate its
377    //    grant, and since the capsule knows the size of T and the number of
378    //    upcalls it uses the grant type and upcall storage could be allocated
379    //    together.
380    //
381    // Based on the available options, the Tock developers decided go with
382    // option 4 and add the `allocate_grant` method to the `SyscallDriver`
383    // trait. This mechanism may find more uses in the future if the kernel
384    // needs to store additional state on a per-driver basis and therefore needs
385    // a mechanism to force a grant allocation.
386    //
387    // This same mechanism was later extended to handle allow calls as well.
388    // Capsules that do not need upcalls but do use process buffers must also
389    // implement this function.
390    fn allocate_grant(&self, process_id: ProcessId) -> Result<(), crate::process::Error>;
391}
392
393#[cfg(test)]
394mod test {
395    use crate::ErrorCode;
396    use crate::syscall_driver::CommandReturn;
397
398    #[test]
399    fn failure() {
400        let command_return = CommandReturn::failure(ErrorCode::RESERVE);
401        assert!(command_return.is_failure());
402        assert!(!command_return.is_failure_u32());
403        assert!(!command_return.is_failure_2_u32());
404        assert!(!command_return.is_failure_u64());
405        assert!(!command_return.is_success());
406        assert!(!command_return.is_success_u32());
407        assert!(!command_return.is_success_2_u32());
408        assert!(!command_return.is_success_u64());
409        assert!(!command_return.is_success_3_u32());
410        assert!(!command_return.is_success_u32_u64());
411        assert_eq!(command_return.get_failure(), Some(ErrorCode::RESERVE));
412        assert_eq!(command_return.get_failure_u32(), None);
413        assert_eq!(command_return.get_failure_2_u32(), None);
414        assert_eq!(command_return.get_failure_u64(), None);
415        assert_eq!(command_return.get_success_u32(), None);
416        assert_eq!(command_return.get_success_2_u32(), None);
417        assert_eq!(command_return.get_success_u64(), None);
418        assert_eq!(command_return.get_success_3_u32(), None);
419        assert_eq!(command_return.get_success_u32_u64(), None);
420    }
421
422    #[test]
423    fn failure_u32() {
424        let command_return = CommandReturn::failure_u32(ErrorCode::OFF, 1002);
425        assert!(!command_return.is_failure());
426        assert!(command_return.is_failure_u32());
427        assert!(!command_return.is_failure_2_u32());
428        assert!(!command_return.is_failure_u64());
429        assert!(!command_return.is_success());
430        assert!(!command_return.is_success_u32());
431        assert!(!command_return.is_success_2_u32());
432        assert!(!command_return.is_success_u64());
433        assert!(!command_return.is_success_3_u32());
434        assert!(!command_return.is_success_u32_u64());
435        assert_eq!(command_return.get_failure(), None);
436        assert_eq!(
437            command_return.get_failure_u32(),
438            Some((ErrorCode::OFF, 1002))
439        );
440        assert_eq!(command_return.get_failure_2_u32(), None);
441        assert_eq!(command_return.get_failure_u64(), None);
442        assert_eq!(command_return.get_success_u32(), None);
443        assert_eq!(command_return.get_success_2_u32(), None);
444        assert_eq!(command_return.get_success_u64(), None);
445        assert_eq!(command_return.get_success_3_u32(), None);
446        assert_eq!(command_return.get_success_u32_u64(), None);
447    }
448
449    #[test]
450    fn failure_2_u32() {
451        let command_return = CommandReturn::failure_u32_u32(ErrorCode::ALREADY, 1002, 1003);
452        assert!(!command_return.is_failure());
453        assert!(!command_return.is_failure_u32());
454        assert!(command_return.is_failure_2_u32());
455        assert!(!command_return.is_failure_u64());
456        assert!(!command_return.is_success());
457        assert!(!command_return.is_success_u32());
458        assert!(!command_return.is_success_2_u32());
459        assert!(!command_return.is_success_u64());
460        assert!(!command_return.is_success_3_u32());
461        assert!(!command_return.is_success_u32_u64());
462        assert_eq!(command_return.get_failure(), None);
463        assert_eq!(command_return.get_failure_u32(), None);
464        assert_eq!(
465            command_return.get_failure_2_u32(),
466            Some((ErrorCode::ALREADY, 1002, 1003))
467        );
468        assert_eq!(command_return.get_failure_u64(), None);
469        assert_eq!(command_return.get_success_u32(), None);
470        assert_eq!(command_return.get_success_2_u32(), None);
471        assert_eq!(command_return.get_success_u64(), None);
472        assert_eq!(command_return.get_success_3_u32(), None);
473        assert_eq!(command_return.get_success_u32_u64(), None);
474    }
475
476    #[test]
477    fn failure_u64() {
478        let command_return = CommandReturn::failure_u64(ErrorCode::BUSY, 0x0000_1003_0000_1002);
479        assert!(!command_return.is_failure());
480        assert!(!command_return.is_failure_u32());
481        assert!(!command_return.is_failure_2_u32());
482        assert!(command_return.is_failure_u64());
483        assert!(!command_return.is_success());
484        assert!(!command_return.is_success_u32());
485        assert!(!command_return.is_success_2_u32());
486        assert!(!command_return.is_success_u64());
487        assert!(!command_return.is_success_3_u32());
488        assert!(!command_return.is_success_u32_u64());
489        assert_eq!(command_return.get_failure(), None);
490        assert_eq!(command_return.get_failure_u32(), None);
491        assert_eq!(command_return.get_failure_2_u32(), None);
492        assert_eq!(
493            command_return.get_failure_u64(),
494            Some((ErrorCode::BUSY, 0x0000_1003_0000_1002))
495        );
496        assert_eq!(command_return.get_success_u32(), None);
497        assert_eq!(command_return.get_success_2_u32(), None);
498        assert_eq!(command_return.get_success_u64(), None);
499        assert_eq!(command_return.get_success_3_u32(), None);
500        assert_eq!(command_return.get_success_u32_u64(), None);
501    }
502
503    #[test]
504    fn success() {
505        let command_return = CommandReturn::success();
506        assert!(!command_return.is_failure());
507        assert!(!command_return.is_failure_u32());
508        assert!(!command_return.is_failure_2_u32());
509        assert!(!command_return.is_failure_u64());
510        assert!(command_return.is_success());
511        assert!(!command_return.is_success_u32());
512        assert!(!command_return.is_success_2_u32());
513        assert!(!command_return.is_success_u64());
514        assert!(!command_return.is_success_3_u32());
515        assert!(!command_return.is_success_u32_u64());
516        assert_eq!(command_return.get_failure(), None);
517        assert_eq!(command_return.get_failure_u32(), None);
518        assert_eq!(command_return.get_failure_2_u32(), None);
519        assert_eq!(command_return.get_failure_u64(), None);
520        assert_eq!(command_return.get_success_u32(), None);
521        assert_eq!(command_return.get_success_2_u32(), None);
522        assert_eq!(command_return.get_success_u64(), None);
523        assert_eq!(command_return.get_success_3_u32(), None);
524        assert_eq!(command_return.get_success_u32_u64(), None);
525    }
526
527    #[test]
528    fn success_u32() {
529        let command_return = CommandReturn::success_u32(1001);
530        assert!(!command_return.is_failure());
531        assert!(!command_return.is_failure_u32());
532        assert!(!command_return.is_failure_2_u32());
533        assert!(!command_return.is_failure_u64());
534        assert!(!command_return.is_success());
535        assert!(command_return.is_success_u32());
536        assert!(!command_return.is_success_2_u32());
537        assert!(!command_return.is_success_u64());
538        assert!(!command_return.is_success_3_u32());
539        assert!(!command_return.is_success_u32_u64());
540        assert_eq!(command_return.get_failure(), None);
541        assert_eq!(command_return.get_failure_u32(), None);
542        assert_eq!(command_return.get_failure_2_u32(), None);
543        assert_eq!(command_return.get_failure_u64(), None);
544        assert_eq!(command_return.get_success_u32(), Some(1001));
545        assert_eq!(command_return.get_success_2_u32(), None);
546        assert_eq!(command_return.get_success_u64(), None);
547        assert_eq!(command_return.get_success_3_u32(), None);
548        assert_eq!(command_return.get_success_u32_u64(), None);
549    }
550
551    #[test]
552    fn success_2_u32() {
553        let command_return = CommandReturn::success_u32_u32(1001, 1002);
554        assert!(!command_return.is_failure());
555        assert!(!command_return.is_failure_u32());
556        assert!(!command_return.is_failure_2_u32());
557        assert!(!command_return.is_failure_u64());
558        assert!(!command_return.is_success());
559        assert!(!command_return.is_success_u32());
560        assert!(command_return.is_success_2_u32());
561        assert!(!command_return.is_success_u64());
562        assert!(!command_return.is_success_3_u32());
563        assert!(!command_return.is_success_u32_u64());
564        assert_eq!(command_return.get_failure(), None);
565        assert_eq!(command_return.get_failure_u32(), None);
566        assert_eq!(command_return.get_failure_2_u32(), None);
567        assert_eq!(command_return.get_failure_u64(), None);
568        assert_eq!(command_return.get_success_u32(), None);
569        assert_eq!(command_return.get_success_2_u32(), Some((1001, 1002)));
570        assert_eq!(command_return.get_success_u64(), None);
571        assert_eq!(command_return.get_success_3_u32(), None);
572        assert_eq!(command_return.get_success_u32_u64(), None);
573    }
574
575    #[test]
576    fn success_u64() {
577        let command_return = CommandReturn::success_u64(0x0000_1002_0000_1001);
578        assert!(!command_return.is_failure());
579        assert!(!command_return.is_failure_u32());
580        assert!(!command_return.is_failure_2_u32());
581        assert!(!command_return.is_failure_u64());
582        assert!(!command_return.is_success());
583        assert!(!command_return.is_success_u32());
584        assert!(!command_return.is_success_2_u32());
585        assert!(command_return.is_success_u64());
586        assert!(!command_return.is_success_3_u32());
587        assert!(!command_return.is_success_u32_u64());
588        assert_eq!(command_return.get_failure(), None);
589        assert_eq!(command_return.get_failure_u32(), None);
590        assert_eq!(command_return.get_failure_2_u32(), None);
591        assert_eq!(command_return.get_failure_u64(), None);
592        assert_eq!(command_return.get_success_u32(), None);
593        assert_eq!(command_return.get_success_2_u32(), None);
594        assert_eq!(
595            command_return.get_success_u64(),
596            Some(0x0000_1002_0000_1001)
597        );
598        assert_eq!(command_return.get_success_3_u32(), None);
599        assert_eq!(command_return.get_success_u32_u64(), None);
600    }
601
602    #[test]
603    fn success_3_u32() {
604        let command_return = CommandReturn::success_u32_u32_u32(1001, 1002, 1003);
605        assert!(!command_return.is_failure());
606        assert!(!command_return.is_failure_u32());
607        assert!(!command_return.is_failure_2_u32());
608        assert!(!command_return.is_failure_u64());
609        assert!(!command_return.is_success());
610        assert!(!command_return.is_success_u32());
611        assert!(!command_return.is_success_2_u32());
612        assert!(!command_return.is_success_u64());
613        assert!(command_return.is_success_3_u32());
614        assert!(!command_return.is_success_u32_u64());
615        assert_eq!(command_return.get_failure(), None);
616        assert_eq!(command_return.get_failure_u32(), None);
617        assert_eq!(command_return.get_failure_2_u32(), None);
618        assert_eq!(command_return.get_failure_u64(), None);
619        assert_eq!(command_return.get_success_u32(), None);
620        assert_eq!(command_return.get_success_2_u32(), None);
621        assert_eq!(command_return.get_success_u64(), None);
622        assert_eq!(command_return.get_success_3_u32(), Some((1001, 1002, 1003)));
623        assert_eq!(command_return.get_success_u32_u64(), None);
624    }
625
626    #[test]
627    fn success_u32_u64() {
628        let command_return = CommandReturn::success_u32_u64(1001, 0x0000_1003_0000_1002);
629        assert!(!command_return.is_failure());
630        assert!(!command_return.is_failure_u32());
631        assert!(!command_return.is_failure_2_u32());
632        assert!(!command_return.is_failure_u64());
633        assert!(!command_return.is_success());
634        assert!(!command_return.is_success_u32());
635        assert!(!command_return.is_success_2_u32());
636        assert!(!command_return.is_success_u64());
637        assert!(!command_return.is_success_3_u32());
638        assert!(command_return.is_success_u32_u64());
639        assert_eq!(command_return.get_failure(), None);
640        assert_eq!(command_return.get_failure_u32(), None);
641        assert_eq!(command_return.get_failure_2_u32(), None);
642        assert_eq!(command_return.get_failure_u64(), None);
643        assert_eq!(command_return.get_success_u32(), None);
644        assert_eq!(command_return.get_success_2_u32(), None);
645        assert_eq!(command_return.get_success_u64(), None);
646        assert_eq!(command_return.get_success_3_u32(), None);
647        assert_eq!(
648            command_return.get_success_u32_u64(),
649            Some((1001, 0x0000_1003_0000_1002))
650        );
651    }
652}