1use super::{Error, Result};
2use core::fmt::Debug;
3
4/// Bit indicating that an UEFI status code is an error
5const ERROR_BIT: usize = 1 << (core::mem::size_of::<usize>() * 8 - 1);
6
7newtype_enum! {
8/// UEFI uses status codes in order to report successes, errors, and warnings.
9///
10/// Unfortunately, the spec allows and encourages implementation-specific
11/// non-portable status codes. Therefore, these cannot be modeled as a Rust
12/// enum, as injecting an unknown value in a Rust enum is undefined behaviour.
13///
14/// For lack of a better option, we therefore model them as a newtype of usize.
15///
16/// For a convenient integration into the Rust ecosystem, there are multiple
17/// factory methods to convert a Status into a [`uefi::Result`]:
18/// - [`Status::into_with`]
19/// - [`Status::into_with_val`]
20/// - [`Status::into_with_err`]
21#[must_use]
22pub enum Status: usize => {
23 /// The operation completed successfully.
24 SUCCESS = 0,
25
26 /// The string contained characters that could not be rendered and were skipped.
27 WARN_UNKNOWN_GLYPH = 1,
28 /// The handle was closed, but the file was not deleted.
29 WARN_DELETE_FAILURE = 2,
30 /// The handle was closed, but the data to the file was not flushed properly.
31 WARN_WRITE_FAILURE = 3,
32 /// The resulting buffer was too small, and the data was truncated.
33 WARN_BUFFER_TOO_SMALL = 4,
34 /// The data has not been updated within the timeframe set by local policy.
35 WARN_STALE_DATA = 5,
36 /// The resulting buffer contains UEFI-compliant file system.
37 WARN_FILE_SYSTEM = 6,
38 /// The operation will be processed across a system reset.
39 WARN_RESET_REQUIRED = 7,
40
41 /// The image failed to load.
42 LOAD_ERROR = ERROR_BIT | 1,
43 /// A parameter was incorrect.
44 INVALID_PARAMETER = ERROR_BIT | 2,
45 /// The operation is not supported.
46 UNSUPPORTED = ERROR_BIT | 3,
47 /// The buffer was not the proper size for the request.
48 BAD_BUFFER_SIZE = ERROR_BIT | 4,
49 /// The buffer is not large enough to hold the requested data.
50 /// The required buffer size is returned in the appropriate parameter.
51 BUFFER_TOO_SMALL = ERROR_BIT | 5,
52 /// There is no data pending upon return.
53 NOT_READY = ERROR_BIT | 6,
54 /// The physical device reported an error while attempting the operation.
55 DEVICE_ERROR = ERROR_BIT | 7,
56 /// The device cannot be written to.
57 WRITE_PROTECTED = ERROR_BIT | 8,
58 /// A resource has run out.
59 OUT_OF_RESOURCES = ERROR_BIT | 9,
60 /// An inconstency was detected on the file system.
61 VOLUME_CORRUPTED = ERROR_BIT | 10,
62 /// There is no more space on the file system.
63 VOLUME_FULL = ERROR_BIT | 11,
64 /// The device does not contain any medium to perform the operation.
65 NO_MEDIA = ERROR_BIT | 12,
66 /// The medium in the device has changed since the last access.
67 MEDIA_CHANGED = ERROR_BIT | 13,
68 /// The item was not found.
69 NOT_FOUND = ERROR_BIT | 14,
70 /// Access was denied.
71 ACCESS_DENIED = ERROR_BIT | 15,
72 /// The server was not found or did not respond to the request.
73 NO_RESPONSE = ERROR_BIT | 16,
74 /// A mapping to a device does not exist.
75 NO_MAPPING = ERROR_BIT | 17,
76 /// The timeout time expired.
77 TIMEOUT = ERROR_BIT | 18,
78 /// The protocol has not been started.
79 NOT_STARTED = ERROR_BIT | 19,
80 /// The protocol has already been started.
81 ALREADY_STARTED = ERROR_BIT | 20,
82 /// The operation was aborted.
83 ABORTED = ERROR_BIT | 21,
84 /// An ICMP error occurred during the network operation.
85 ICMP_ERROR = ERROR_BIT | 22,
86 /// A TFTP error occurred during the network operation.
87 TFTP_ERROR = ERROR_BIT | 23,
88 /// A protocol error occurred during the network operation.
89 PROTOCOL_ERROR = ERROR_BIT | 24,
90 /// The function encountered an internal version that was
91 /// incompatible with a version requested by the caller.
92 INCOMPATIBLE_VERSION = ERROR_BIT | 25,
93 /// The function was not performed due to a security violation.
94 SECURITY_VIOLATION = ERROR_BIT | 26,
95 /// A CRC error was detected.
96 CRC_ERROR = ERROR_BIT | 27,
97 /// Beginning or end of media was reached
98 END_OF_MEDIA = ERROR_BIT | 28,
99 /// The end of the file was reached.
100 END_OF_FILE = ERROR_BIT | 31,
101 /// The language specified was invalid.
102 INVALID_LANGUAGE = ERROR_BIT | 32,
103 /// The security status of the data is unknown or compromised and
104 /// the data must be updated or replaced to restore a valid security status.
105 COMPROMISED_DATA = ERROR_BIT | 33,
106 /// There is an address conflict address allocation
107 IP_ADDRESS_CONFLICT = ERROR_BIT | 34,
108 /// A HTTP error occurred during the network operation.
109 HTTP_ERROR = ERROR_BIT | 35,
110}}
111
112impl Status {
113 /// Returns true if status code indicates success.
114 #[inline]
115 #[must_use]
116 pub fn is_success(self) -> bool {
117 self == Status::SUCCESS
118 }
119
120 /// Returns true if status code indicates a warning.
121 #[inline]
122 #[must_use]
123 pub fn is_warning(self) -> bool {
124 (self != Status::SUCCESS) && (self.0 & ERROR_BIT == 0)
125 }
126
127 /// Returns true if the status code indicates an error.
128 #[inline]
129 #[must_use]
130 pub const fn is_error(self) -> bool {
131 self.0 & ERROR_BIT != 0
132 }
133
134 /// Converts this status code into a [`uefi::Result`] with a given `Ok` value.
135 ///
136 /// If the status does not indicate success, the status representing the specific error
137 /// code is embedded into the `Err` variant of type [`uefi::Error`].
138 #[inline]
139 pub fn into_with_val<T>(self, val: impl FnOnce() -> T) -> Result<T, ()> {
140 if self.is_success() {
141 Ok(val())
142 } else {
143 Err(self.into())
144 }
145 }
146
147 /// Converts this status code into a [`uefi::Result`] with a given `Err` payload.
148 ///
149 /// If the status does not indicate success, the status representing the specific error
150 /// code is embedded into the `Err` variant of type [`uefi::Error`].
151 #[inline]
152 pub fn into_with_err<ErrData: Debug>(
153 self,
154 err: impl FnOnce(Status) -> ErrData,
155 ) -> Result<(), ErrData> {
156 if self.is_success() {
157 Ok(())
158 } else {
159 Err(Error::new(self, err(self)))
160 }
161 }
162
163 /// Convert this status code into a result with a given `Ok` value and `Err` payload.
164 ///
165 /// If the status does not indicate success, the status representing the specific error
166 /// code is embedded into the `Err` variant of type [`uefi::Error`].
167 #[inline]
168 pub fn into_with<T, ErrData: Debug>(
169 self,
170 val: impl FnOnce() -> T,
171 err: impl FnOnce(Status) -> ErrData,
172 ) -> Result<T, ErrData> {
173 if self.is_success() {
174 Ok(val())
175 } else {
176 Err(Error::new(self, err(self)))
177 }
178 }
179}
180
181// An UEFI status is equivalent to a Result with no data or error payload
182impl From<Status> for Result<(), ()> {
183 #[inline]
184 fn from(status: Status) -> Result<(), ()> {
185 status.into_with(|| (), |_| ())
186 }
187}
188
189impl core::fmt::Display for Status {
190 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
191 Debug::fmt(self, f)
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_status_to_result() {
201 assert!(Result::from(Status::SUCCESS).is_ok());
202 assert!(Result::from(Status::WARN_DELETE_FAILURE).is_err());
203 assert!(Result::from(Status::BUFFER_TOO_SMALL).is_err());
204
205 assert_eq!(Status::SUCCESS.into_with_val(|| 123).unwrap(), 123);
206 assert!(Status::WARN_DELETE_FAILURE.into_with_val(|| 123).is_err());
207 assert!(Status::BUFFER_TOO_SMALL.into_with_val(|| 123).is_err());
208
209 assert!(Status::SUCCESS.into_with_err(|_| 123).is_ok());
210 assert_eq!(
211 *Status::WARN_DELETE_FAILURE
212 .into_with_err(|_| 123)
213 .unwrap_err()
214 .data(),
215 123
216 );
217 assert_eq!(
218 *Status::BUFFER_TOO_SMALL
219 .into_with_err(|_| 123)
220 .unwrap_err()
221 .data(),
222 123
223 );
224
225 assert_eq!(Status::SUCCESS.into_with(|| 123, |_| 456).unwrap(), 123);
226 assert_eq!(
227 *Status::WARN_DELETE_FAILURE
228 .into_with(|| 123, |_| 456)
229 .unwrap_err()
230 .data(),
231 456
232 );
233 assert_eq!(
234 *Status::BUFFER_TOO_SMALL
235 .into_with(|| 123, |_| 456)
236 .unwrap_err()
237 .data(),
238 456
239 );
240 }
241}
242