1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Unified error type library
16 //!
17 //! This crate defines a common error type for all of GBL.
18 //! It is intended to reduce conversion boilerplate and to make
19 //! the various GBL libraries interoperate more cleanly.
20 //!
21 //! Because of its intended broad application, certain error types will
22 //! be highly specific to particular libraries.
23 //! More specific errors can be useful when writing unit tests or when defining
24 //! APIs that third party code may interact with.
25 //! It's a judgement call whether a new variant should be added,
26 //! but if possible try to use an existing variant.
27 //!
28 //! It is a further judgement call whether a new variant should wrap a payload.
29 //! The rule of thumb is that a payload requires one of the following conditions:
30 //! 1) The error will be logged and the payload will help with debugging.
31 //! 2) The error is transient or retriable, and the payload helps with the retry.
32 //!
33 //! New error variants should be inserted alphabetically.
34
35 #![cfg_attr(not(any(test, android_dylib)), no_std)]
36
37 use core::{
38 ffi::{FromBytesUntilNulError, FromBytesWithNulError},
39 str::Utf8Error,
40 };
41
42 use efi_types as efi;
43
44 /// Gpt related errors.
45 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
46 pub enum GptError {
47 /// Secondary header is valid, but different from primary.
48 DifferentFromPrimary,
49 /// Disk size is not enough to accommodate maximum allowed entries.
50 DiskTooSmall,
51 /// GPT entries buffer is too small for the expected number of entries.
52 EntriesTruncated,
53 /// GPT header CRC is not correct.
54 IncorrectHeaderCrc,
55 /// GPT header MAGIC is not correct.
56 IncorrectMagic(u64),
57 /// GPT entries CRC doesn't match.
58 IncorrectEntriesCrc,
59 /// Invalid first and last usable block in the GPT header.
60 InvalidFirstLastUsableBlock {
61 /// The value of first usable block in the GPT header.
62 first: u64,
63 /// The value of last usable block in the GPT header.
64 last: u64,
65 /// Expected range inclusive.
66 range: (u64, u64),
67 },
68 /// Partition range is invalid.
69 InvalidPartitionRange {
70 /// Partition index (1-based).
71 idx: usize,
72 /// Range of the partition, inclusive.
73 part_range: (u64, u64),
74 /// Range of usable block, inclusive.
75 usable_range: (u64, u64),
76 },
77 /// Invalid start block for primary GPT entries.
78 InvalidPrimaryEntriesStart {
79 /// The entry start block value.
80 value: u64,
81 /// Expected range.
82 expect_range: (u64, u64),
83 },
84 /// Invalid start block for secondary GPT entries.
85 InvalidSecondaryEntriesStart {
86 /// The entry start block value.
87 value: u64,
88 /// Expected range.
89 expect_range: (u64, u64),
90 },
91 /// Number of entries greater than maximum allowed.
92 NumberOfEntriesOverflow {
93 /// Actual number of entries,
94 entries: u32,
95 /// Maximum allowed.
96 max_allowed: usize,
97 },
98 /// Two partitions overlap.
99 PartitionRangeOverlap {
100 /// Previous partition in overlap. (partition index, first, last)
101 prev: (usize, u64, u64),
102 /// Next partition in overlap. (partition index, first, last)
103 next: (usize, u64, u64),
104 },
105 /// Unexpected GPT header size.
106 UnexpectedEntrySize {
107 /// The actual entry size in the GPT header.
108 actual: u32,
109 /// The expected size.
110 expect: usize,
111 },
112 /// Unexpected GPT header size.
113 UnexpectedHeaderSize {
114 /// The actual header size in the GPT header.
115 actual: u32,
116 /// The expected size.
117 expect: usize,
118 },
119 /// Zero partition type GUID.
120 ZeroPartitionTypeGUID {
121 /// Partition index (1-based).
122 idx: usize,
123 },
124 /// Zero partition unique GUID.
125 ZeroPartitionUniqueGUID {
126 /// Partition index (1-based).
127 idx: usize,
128 },
129 }
130
131 /// Common, universal error type
132 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
133 pub enum Error {
134 /// An operation has been aborted. Useful for async or IO operations.
135 Aborted,
136 /// Access was denied.
137 AccessDenied,
138 /// The protocol has already been started.
139 AlreadyStarted,
140 /// A checked arithmetic operation has overflowed.
141 ArithmeticOverflow(safemath::Error),
142 /// The buffer was not the proper size for the request (different from BufferTooSmall).
143 BadBufferSize,
144 /// Data verification has encountered an invalid checksum.
145 BadChecksum,
146 /// An operation attempted to access data outside of the valid range.
147 /// Includes the problematic index.
148 BadIndex(usize),
149 /// Data verification has encountered an invalid magic number.
150 BadMagic,
151 /// Generic BlockIO error.
152 BlockIoError,
153 /// Generic boot failure has occurred.
154 BootFailed,
155 /// Buffers provided by third party code overlap.
156 BufferOverlap,
157 /// The provided buffer is too small.
158 /// If Some(n), provides the minimum required buffer size.
159 BufferTooSmall(Option<usize>),
160 /// The security status of the data is unknown or compromised
161 /// and the data must be updated or replaced to restore a valid security status.
162 CompromisedData,
163 /// The remote peer has reset the network connection.
164 ConnectionReset,
165 /// A relevant device encountered an error.
166 DeviceError,
167 /// The connected peripheral or network peer has disconnected.
168 Disconnected,
169 /// The end of the file was reached.
170 EndOfFile,
171 /// Beginning or end of media was reached
172 EndOfMedia,
173 /// A polled operation has finished
174 Finished,
175 /// GPT related errors.
176 GptError(GptError),
177 /// A HTTP error occurred during a network operation.
178 HttpError,
179 /// An ICMP error occurred during a network operation.
180 IcmpError,
181 /// The provided buffer or data structure is invalidly aligned.
182 InvalidAlignment,
183 /// A connected agent failed a multi-stage handshake.
184 InvalidHandshake,
185 /// At least one parameter fails preconditions.
186 InvalidInput,
187 /// The language specified was invalid.
188 InvalidLanguage,
189 /// A state machine has entered an invalid state.
190 InvalidState,
191 /// There was a conflict in IP address allocation.
192 IpAddressConflict,
193 /// Image failed to load
194 LoadError,
195 /// The medium in the device has changed since the last access.
196 MediaChanged,
197 /// Memory map error with error code.
198 MemoryMapCallbackError(i64),
199 /// An image required for system boot is missing.
200 MissingImage,
201 /// A valid Flattened Device Tree was not found.
202 NoFdt,
203 /// The block device does not have a valid GUID Partition Table.
204 NoGpt,
205 /// A mapping to a device does not exist.
206 NoMapping,
207 /// The device does not contain any medium to perform the operation.
208 NoMedia,
209 /// The server was not found or did not respond to the request.
210 NoResponse,
211 /// The requested element (e.g. device, partition, or value) was not found.
212 NotFound,
213 /// The default implementation for a trait method has not been overridden.
214 NotImplemented,
215 /// The polled device or future is not ready.
216 NotReady,
217 /// The protocol has not been started.
218 NotStarted,
219 /// The provided name does not uniquely describe a partition.
220 NotUnique,
221 /// Generic permissions failure.
222 OperationProhibited,
223 /// Catch-all error with optional debugging string.
224 Other(Option<&'static str>),
225 /// Out of range.
226 OutOfRange,
227 /// A resource has run out.
228 OutOfResources,
229 /// A protocol error occurred during the network operation.
230 ProtocolError,
231 /// The function was not performed due to a security violation.
232 SecurityViolation,
233 /// A TFTP error occurred during a network operation.
234 TftpError,
235 /// Operation has timed out.
236 Timeout,
237 /// Exceeds maximum number of partition for verification. The contained value represents the
238 /// maximum allowed number of partitions.
239 TooManyPartitions(usize),
240 /// The remote network endpoint is not addressable.
241 Unaddressable,
242 /// An unknown, unexpected EFI_STATUS error code was returned,
243 UnexpectedEfiError(efi::EfiStatus),
244 /// Return from function that is not expected to return.
245 UnexpectedReturn,
246 /// Operation is unsupported
247 Unsupported,
248 /// Data verification has encountered a version number that is not supported.
249 UnsupportedVersion,
250 /// An inconstancy was detected on the file system causing the operating to fail.
251 VolumeCorrupted,
252 /// There is no more space on the file system.
253 VolumeFull,
254 /// The device cannot be written to.
255 WriteProtected,
256 }
257
258 impl From<Option<&'static str>> for Error {
from(val: Option<&'static str>) -> Self259 fn from(val: Option<&'static str>) -> Self {
260 Self::Other(val)
261 }
262 }
263
264 impl From<&'static str> for Error {
from(val: &'static str) -> Self265 fn from(val: &'static str) -> Self {
266 Self::Other(Some(val))
267 }
268 }
269
270 impl From<safemath::Error> for Error {
from(err: safemath::Error) -> Self271 fn from(err: safemath::Error) -> Self {
272 Self::ArithmeticOverflow(err)
273 }
274 }
275
276 impl From<core::num::TryFromIntError> for Error {
277 #[track_caller]
from(err: core::num::TryFromIntError) -> Self278 fn from(err: core::num::TryFromIntError) -> Self {
279 Self::ArithmeticOverflow(err.into())
280 }
281 }
282
283 impl From<FromBytesUntilNulError> for Error {
from(_: FromBytesUntilNulError) -> Self284 fn from(_: FromBytesUntilNulError) -> Self {
285 Self::InvalidInput
286 }
287 }
288
289 impl From<FromBytesWithNulError> for Error {
from(_: FromBytesWithNulError) -> Self290 fn from(_: FromBytesWithNulError) -> Self {
291 Self::InvalidInput
292 }
293 }
294
295 impl From<Utf8Error> for Error {
from(_: Utf8Error) -> Self296 fn from(_: Utf8Error) -> Self {
297 Self::InvalidInput
298 }
299 }
300
301 impl core::fmt::Display for Error {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result302 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
303 write!(f, "{:#?}", self)
304 }
305 }
306
307 impl From<core::fmt::Error> for Error {
from(_: core::fmt::Error) -> Self308 fn from(_: core::fmt::Error) -> Self {
309 Self::Unsupported
310 }
311 }
312
313 /// Helper type alias.
314 pub type Result<T> = core::result::Result<T, Error>;
315
316 /// Workaround for orphan rule.
efi_status_to_result(e: efi::EfiStatus) -> Result<()>317 pub fn efi_status_to_result(e: efi::EfiStatus) -> Result<()> {
318 match e {
319 efi::EFI_STATUS_SUCCESS => Ok(()),
320 efi::EFI_STATUS_CRC_ERROR => Err(Error::BadChecksum),
321 efi::EFI_STATUS_ABORTED => Err(Error::Aborted),
322 efi::EFI_STATUS_ACCESS_DENIED => Err(Error::AccessDenied),
323 efi::EFI_STATUS_ALREADY_STARTED => Err(Error::AlreadyStarted),
324 efi::EFI_STATUS_BAD_BUFFER_SIZE => Err(Error::BadBufferSize),
325 efi::EFI_STATUS_BUFFER_TOO_SMALL => Err(Error::BufferTooSmall(None)),
326 efi::EFI_STATUS_COMPROMISED_DATA => Err(Error::CompromisedData),
327 efi::EFI_STATUS_CONNECTION_FIN => Err(Error::Disconnected),
328 efi::EFI_STATUS_CONNECTION_REFUSED => Err(Error::OperationProhibited),
329 efi::EFI_STATUS_CONNECTION_RESET => Err(Error::ConnectionReset),
330 efi::EFI_STATUS_DEVICE_ERROR => Err(Error::DeviceError),
331 efi::EFI_STATUS_END_OF_FILE => Err(Error::EndOfFile),
332 efi::EFI_STATUS_END_OF_MEDIA => Err(Error::EndOfMedia),
333 efi::EFI_STATUS_HTTP_ERROR => Err(Error::HttpError),
334 efi::EFI_STATUS_ICMP_ERROR => Err(Error::IcmpError),
335 efi::EFI_STATUS_INCOMPATIBLE_VERSION => Err(Error::UnsupportedVersion),
336 efi::EFI_STATUS_INVALID_LANGUAGE => Err(Error::InvalidLanguage),
337 efi::EFI_STATUS_INVALID_PARAMETER => Err(Error::InvalidInput),
338 efi::EFI_STATUS_IP_ADDRESS_CONFLICT => Err(Error::IpAddressConflict),
339 efi::EFI_STATUS_LOAD_ERROR => Err(Error::LoadError),
340 efi::EFI_STATUS_MEDIA_CHANGED => Err(Error::MediaChanged),
341 efi::EFI_STATUS_NOT_FOUND => Err(Error::NotFound),
342 efi::EFI_STATUS_NOT_READY => Err(Error::NotReady),
343 efi::EFI_STATUS_NOT_STARTED => Err(Error::NotStarted),
344 efi::EFI_STATUS_NO_MAPPING => Err(Error::NoMapping),
345 efi::EFI_STATUS_NO_MEDIA => Err(Error::NoMedia),
346 efi::EFI_STATUS_NO_RESPONSE => Err(Error::NoResponse),
347 efi::EFI_STATUS_OUT_OF_RESOURCES => Err(Error::OutOfResources),
348 efi::EFI_STATUS_PROTOCOL_ERROR => Err(Error::ProtocolError),
349 efi::EFI_STATUS_SECURITY_VIOLATION => Err(Error::SecurityViolation),
350 efi::EFI_STATUS_TFTP_ERROR => Err(Error::TftpError),
351 efi::EFI_STATUS_TIMEOUT => Err(Error::Timeout),
352 efi::EFI_STATUS_UNSUPPORTED => Err(Error::Unsupported),
353 efi::EFI_STATUS_VOLUME_CORRUPTED => Err(Error::VolumeCorrupted),
354 efi::EFI_STATUS_VOLUME_FULL => Err(Error::VolumeFull),
355 efi::EFI_STATUS_WRITE_PROTECTED => Err(Error::WriteProtected),
356 // The UEFI spec reserves part of the error space for
357 // OEM defined errors and warnings.
358 // We can't know in advance what these are or what they mean,
359 // so just preserve them as is.
360 e => Err(Error::UnexpectedEfiError(e)),
361 }
362 }
363
364 #[cfg(test)]
365 mod test {
366 use super::*;
367
368 #[test]
test_from_safemath_error()369 fn test_from_safemath_error() {
370 let n = u8::try_from(safemath::SafeNum::ZERO - 1).unwrap_err();
371 let _e: Error = n.into();
372 }
373
374 #[test]
test_from_str()375 fn test_from_str() {
376 let _e: Error = "error string".into();
377 }
378
379 #[test]
test_from_str_option()380 fn test_from_str_option() {
381 let _e: Error = Some("error string").into();
382 let n: Option<&str> = None;
383 let _e2: Error = n.into();
384 }
385 }
386