kernel/errorcode.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//! Standard errors in Tock.
6
7/// Standard errors in Tock.
8///
9/// Each error code is assigned a fixed [`usize`] nonzero number. In effect, 0
10/// is reserved for "no error" / "success".
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12#[repr(usize)]
13pub enum ErrorCode {
14 // Reserved value, for when "no error" / "success" should be
15 // encoded in the same numeric representation as ErrorCode
16 //
17 // Ok(()) = 0,
18 /// Generic failure condition
19 FAIL = 1,
20 /// Underlying system is busy; retry
21 BUSY = 2,
22 /// The state requested is already set
23 ALREADY = 3,
24 /// The component is powered down
25 OFF = 4,
26 /// Reservation required before use
27 RESERVE = 5,
28 /// An invalid parameter was passed
29 INVAL = 6,
30 /// Parameter passed was too large
31 SIZE = 7,
32 /// Operation canceled by a call
33 CANCEL = 8,
34 /// Memory required not available
35 NOMEM = 9,
36 /// Operation is not supported
37 NOSUPPORT = 10,
38 /// Device is not available
39 NODEVICE = 11,
40 /// Device is not physically installed
41 UNINSTALLED = 12,
42 /// Packet transmission not acknowledged
43 NOACK = 13,
44}
45
46impl From<ErrorCode> for usize {
47 fn from(err: ErrorCode) -> usize {
48 err as usize
49 }
50}
51
52impl TryFrom<Result<(), ErrorCode>> for ErrorCode {
53 type Error = ();
54
55 fn try_from(rc: Result<(), ErrorCode>) -> Result<Self, Self::Error> {
56 match rc {
57 Ok(()) => Err(()),
58 Err(ErrorCode::FAIL) => Ok(ErrorCode::FAIL),
59 Err(ErrorCode::BUSY) => Ok(ErrorCode::BUSY),
60 Err(ErrorCode::ALREADY) => Ok(ErrorCode::ALREADY),
61 Err(ErrorCode::OFF) => Ok(ErrorCode::OFF),
62 Err(ErrorCode::RESERVE) => Ok(ErrorCode::RESERVE),
63 Err(ErrorCode::INVAL) => Ok(ErrorCode::INVAL),
64 Err(ErrorCode::SIZE) => Ok(ErrorCode::SIZE),
65 Err(ErrorCode::CANCEL) => Ok(ErrorCode::CANCEL),
66 Err(ErrorCode::NOMEM) => Ok(ErrorCode::NOMEM),
67 Err(ErrorCode::NOSUPPORT) => Ok(ErrorCode::NOSUPPORT),
68 Err(ErrorCode::NODEVICE) => Ok(ErrorCode::NODEVICE),
69 Err(ErrorCode::UNINSTALLED) => Ok(ErrorCode::UNINSTALLED),
70 Err(ErrorCode::NOACK) => Ok(ErrorCode::NOACK),
71 }
72 }
73}
74
75impl From<ErrorCode> for Result<(), ErrorCode> {
76 fn from(ec: ErrorCode) -> Self {
77 match ec {
78 ErrorCode::FAIL => Err(ErrorCode::FAIL),
79 ErrorCode::BUSY => Err(ErrorCode::BUSY),
80 ErrorCode::ALREADY => Err(ErrorCode::ALREADY),
81 ErrorCode::OFF => Err(ErrorCode::OFF),
82 ErrorCode::RESERVE => Err(ErrorCode::RESERVE),
83 ErrorCode::INVAL => Err(ErrorCode::INVAL),
84 ErrorCode::SIZE => Err(ErrorCode::SIZE),
85 ErrorCode::CANCEL => Err(ErrorCode::CANCEL),
86 ErrorCode::NOMEM => Err(ErrorCode::NOMEM),
87 ErrorCode::NOSUPPORT => Err(ErrorCode::NOSUPPORT),
88 ErrorCode::NODEVICE => Err(ErrorCode::NODEVICE),
89 ErrorCode::UNINSTALLED => Err(ErrorCode::UNINSTALLED),
90 ErrorCode::NOACK => Err(ErrorCode::NOACK),
91 }
92 }
93}
94
95/// Convert a `Result<(), ErrorCode>` to a StatusCode (usize) for userspace.
96///
97/// StatusCode is a useful "pseudotype" (there is no actual Rust type called
98/// StatusCode in Tock) for three reasons:
99///
100/// 1. It can be represented in a single `usize`. This allows StatusCode to be
101/// easily passed across the syscall interface between the kernel and
102/// userspace.
103///
104/// 2. It extends [`ErrorCode`], but keeps the same error-to-number mappings as
105/// ErrorCode. For example, in both StatusCode and [`ErrorCode`], the `SIZE`
106/// error is always represented as 7.
107///
108/// 3. It can encode success values, whereas [`ErrorCode`] can only encode
109/// errors. Number 0 in [`ErrorCode`] is reserved, and is used for `SUCCESS`
110/// in StatusCode.
111///
112/// This helper function converts the Tock and Rust convention for a
113/// success/error type to a StatusCode. StatusCode is represented as a usize
114/// which is sufficient to send to userspace via an upcall.
115///
116/// The key to this conversion and portability between the kernel and userspace
117/// is that [`ErrorCode`], which only expresses errors, is assigned fixed
118/// values, but does not use value 0 by convention. This allows us to use 0 as
119/// success in StatusCode.
120pub fn into_statuscode(r: Result<(), ErrorCode>) -> usize {
121 match r {
122 Ok(()) => 0,
123 Err(e) => e as usize,
124 }
125}