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 /// A resource has run out.
226 OutOfResources,
227 /// A protocol error occurred during the network operation.
228 ProtocolError,
229 /// The function was not performed due to a security violation.
230 SecurityViolation,
231 /// A TFTP error occurred during a network operation.
232 TftpError,
233 /// Operation has timed out.
234 Timeout,
235 /// The remote network endpoint is not addressable.
236 Unaddressable,
237 /// An unknown, unexpected EFI_STATUS error code was returned,
238 UnexpectedEfiError(efi::EfiStatus),
239 /// Operation is unsupported
240 Unsupported,
241 /// Data verification has encountered a version number that is not supported.
242 UnsupportedVersion,
243 /// An inconstancy was detected on the file system causing the operating to fail.
244 VolumeCorrupted,
245 /// There is no more space on the file system.
246 VolumeFull,
247 /// The device cannot be written to.
248 WriteProtected,
249 }
250
251 impl From<Option<&'static str>> for Error {
from(val: Option<&'static str>) -> Self252 fn from(val: Option<&'static str>) -> Self {
253 Self::Other(val)
254 }
255 }
256
257 impl From<&'static str> for Error {
from(val: &'static str) -> Self258 fn from(val: &'static str) -> Self {
259 Self::Other(Some(val))
260 }
261 }
262
263 impl From<safemath::Error> for Error {
from(err: safemath::Error) -> Self264 fn from(err: safemath::Error) -> Self {
265 Self::ArithmeticOverflow(err)
266 }
267 }
268
269 impl From<core::num::TryFromIntError> for Error {
270 #[track_caller]
from(err: core::num::TryFromIntError) -> Self271 fn from(err: core::num::TryFromIntError) -> Self {
272 Self::ArithmeticOverflow(err.into())
273 }
274 }
275
276 impl From<FromBytesUntilNulError> for Error {
from(_: FromBytesUntilNulError) -> Self277 fn from(_: FromBytesUntilNulError) -> Self {
278 Self::InvalidInput
279 }
280 }
281
282 impl From<FromBytesWithNulError> for Error {
from(_: FromBytesWithNulError) -> Self283 fn from(_: FromBytesWithNulError) -> Self {
284 Self::InvalidInput
285 }
286 }
287
288 impl From<Utf8Error> for Error {
from(_: Utf8Error) -> Self289 fn from(_: Utf8Error) -> Self {
290 Self::InvalidInput
291 }
292 }
293
294 impl core::fmt::Display for Error {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result295 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
296 write!(f, "{:#?}", self)
297 }
298 }
299
300 impl From<core::fmt::Error> for Error {
from(_: core::fmt::Error) -> Self301 fn from(_: core::fmt::Error) -> Self {
302 Self::Unsupported
303 }
304 }
305
306 /// Helper type alias.
307 pub type Result<T> = core::result::Result<T, Error>;
308
309 /// Workaround for orphan rule.
efi_status_to_result(e: efi::EfiStatus) -> Result<()>310 pub fn efi_status_to_result(e: efi::EfiStatus) -> Result<()> {
311 match e {
312 efi::EFI_STATUS_SUCCESS => Ok(()),
313 efi::EFI_STATUS_CRC_ERROR => Err(Error::BadChecksum),
314 efi::EFI_STATUS_ABORTED => Err(Error::Aborted),
315 efi::EFI_STATUS_ACCESS_DENIED => Err(Error::AccessDenied),
316 efi::EFI_STATUS_ALREADY_STARTED => Err(Error::AlreadyStarted),
317 efi::EFI_STATUS_BAD_BUFFER_SIZE => Err(Error::BadBufferSize),
318 efi::EFI_STATUS_BUFFER_TOO_SMALL => Err(Error::BufferTooSmall(None)),
319 efi::EFI_STATUS_COMPROMISED_DATA => Err(Error::CompromisedData),
320 efi::EFI_STATUS_CONNECTION_FIN => Err(Error::Disconnected),
321 efi::EFI_STATUS_CONNECTION_REFUSED => Err(Error::OperationProhibited),
322 efi::EFI_STATUS_CONNECTION_RESET => Err(Error::ConnectionReset),
323 efi::EFI_STATUS_DEVICE_ERROR => Err(Error::DeviceError),
324 efi::EFI_STATUS_END_OF_FILE => Err(Error::EndOfFile),
325 efi::EFI_STATUS_END_OF_MEDIA => Err(Error::EndOfMedia),
326 efi::EFI_STATUS_HTTP_ERROR => Err(Error::HttpError),
327 efi::EFI_STATUS_ICMP_ERROR => Err(Error::IcmpError),
328 efi::EFI_STATUS_INCOMPATIBLE_VERSION => Err(Error::UnsupportedVersion),
329 efi::EFI_STATUS_INVALID_LANGUAGE => Err(Error::InvalidLanguage),
330 efi::EFI_STATUS_INVALID_PARAMETER => Err(Error::InvalidInput),
331 efi::EFI_STATUS_IP_ADDRESS_CONFLICT => Err(Error::IpAddressConflict),
332 efi::EFI_STATUS_LOAD_ERROR => Err(Error::LoadError),
333 efi::EFI_STATUS_MEDIA_CHANGED => Err(Error::MediaChanged),
334 efi::EFI_STATUS_NOT_FOUND => Err(Error::NotFound),
335 efi::EFI_STATUS_NOT_READY => Err(Error::NotReady),
336 efi::EFI_STATUS_NOT_STARTED => Err(Error::NotStarted),
337 efi::EFI_STATUS_NO_MAPPING => Err(Error::NoMapping),
338 efi::EFI_STATUS_NO_MEDIA => Err(Error::NoMedia),
339 efi::EFI_STATUS_NO_RESPONSE => Err(Error::NoResponse),
340 efi::EFI_STATUS_OUT_OF_RESOURCES => Err(Error::OutOfResources),
341 efi::EFI_STATUS_PROTOCOL_ERROR => Err(Error::ProtocolError),
342 efi::EFI_STATUS_SECURITY_VIOLATION => Err(Error::SecurityViolation),
343 efi::EFI_STATUS_TFTP_ERROR => Err(Error::TftpError),
344 efi::EFI_STATUS_TIMEOUT => Err(Error::Timeout),
345 efi::EFI_STATUS_UNSUPPORTED => Err(Error::Unsupported),
346 efi::EFI_STATUS_VOLUME_CORRUPTED => Err(Error::VolumeCorrupted),
347 efi::EFI_STATUS_VOLUME_FULL => Err(Error::VolumeFull),
348 efi::EFI_STATUS_WRITE_PROTECTED => Err(Error::WriteProtected),
349 // The UEFI spec reserves part of the error space for
350 // OEM defined errors and warnings.
351 // We can't know in advance what these are or what they mean,
352 // so just preserve them as is.
353 e => Err(Error::UnexpectedEfiError(e)),
354 }
355 }
356
357 #[cfg(test)]
358 mod test {
359 use super::*;
360
361 #[test]
test_from_safemath_error()362 fn test_from_safemath_error() {
363 let n = u8::try_from(safemath::SafeNum::ZERO - 1).unwrap_err();
364 let _e: Error = n.into();
365 }
366
367 #[test]
test_from_str()368 fn test_from_str() {
369 let _e: Error = "error string".into();
370 }
371
372 #[test]
test_from_str_option()373 fn test_from_str_option() {
374 let _e: Error = Some("error string").into();
375 let n: Option<&str> = None;
376 let _e2: Error = n.into();
377 }
378 }
379