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}