Add simple uart driver, more functionality etc etc etc
This commit is contained in:
7
uefi/Cargo.lock
generated
Normal file
7
uefi/Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "uefi"
|
||||
version = "0.1.0"
|
||||
6
uefi/Cargo.toml
Normal file
6
uefi/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "uefi"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
BIN
uefi/libstatus.rlib
Normal file
BIN
uefi/libstatus.rlib
Normal file
Binary file not shown.
317
uefi/src/lib.rs
Normal file
317
uefi/src/lib.rs
Normal file
@@ -0,0 +1,317 @@
|
||||
#![no_std]
|
||||
|
||||
mod memory;
|
||||
mod status;
|
||||
pub use memory::EfiMemoryType;
|
||||
pub use status::UefiStatus;
|
||||
|
||||
use crate::{memory::EfiMemoryDescriptor, status::RawUefiStatus};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct EfiTableHeader {
|
||||
signature: u64,
|
||||
revision: u32,
|
||||
header_size: u32,
|
||||
crc32: u32,
|
||||
reserved: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct EfiSystemTable {
|
||||
efi_table_header: EfiTableHeader,
|
||||
firmware_vendor: *const u16,
|
||||
firmware_revision: u32,
|
||||
console_in_handle: Handle,
|
||||
// TODO: Handle input.
|
||||
efi_simple_text_input_protocol: *mut core::ffi::c_void,
|
||||
console_out_handle: Handle,
|
||||
console_out: *mut SimpleTextOutputProtocol,
|
||||
standard_error_handle: Handle,
|
||||
standard_error: *mut SimpleTextOutputProtocol,
|
||||
runtime_services: *mut core::ffi::c_void,
|
||||
boot_services: *mut EfiBootServices,
|
||||
number_of_table_entries: usize,
|
||||
configuration_table: *mut core::ffi::c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SimpleTextOutputProtocol {
|
||||
reset: extern "efiapi" fn(this: *mut Self, extended_verification: bool) -> RawUefiStatus,
|
||||
output_string: extern "efiapi" fn(this: *mut Self, str: *const u16) -> RawUefiStatus,
|
||||
test_string: extern "efiapi" fn(this: *mut Self, str: *const u16) -> RawUefiStatus,
|
||||
query_mode: extern "efiapi" fn(
|
||||
this: *mut Self,
|
||||
mode_number: usize,
|
||||
n_columns: *mut usize,
|
||||
n_rows: *mut usize,
|
||||
) -> RawUefiStatus,
|
||||
set_mode: extern "efiapi" fn(this: *mut Self, mode_number: usize) -> RawUefiStatus,
|
||||
set_atribute: extern "efiapi" fn(this: *mut Self, attribute: usize) -> RawUefiStatus,
|
||||
clear_screen: extern "efiapi" fn(this: *mut Self) -> RawUefiStatus,
|
||||
set_cursor_position:
|
||||
extern "efiapi" fn(this: *mut Self, column: usize, row: usize) -> RawUefiStatus,
|
||||
enable_cursor: extern "efiapi" fn(this: *mut Self, visible: bool) -> RawUefiStatus,
|
||||
mode: *mut SimpleTextOutputMode,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SimpleTextOutputMode {
|
||||
pub max_mode: i32,
|
||||
pub mode: i32,
|
||||
pub attribute: i32,
|
||||
pub cursor_column: i32,
|
||||
pub cursor_row: i32,
|
||||
pub cursor_visible: bool,
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy)]
|
||||
/// Identifier used by UEFI.
|
||||
pub struct Handle(*mut ());
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct ExitBootServicesKey(usize);
|
||||
|
||||
#[repr(C)]
|
||||
pub struct EfiBootServices {
|
||||
hdr: EfiTableHeader,
|
||||
//
|
||||
// Task Priority Services
|
||||
//
|
||||
raise_tpl: *const core::ffi::c_void,
|
||||
restore_tpl: *const core::ffi::c_void,
|
||||
//
|
||||
// Memory Services
|
||||
//
|
||||
allocate_pages: *const core::ffi::c_void,
|
||||
free_pages: *const core::ffi::c_void,
|
||||
get_memory_map: extern "efiapi" fn(
|
||||
memory_map_size: *mut usize, // Passed by us as core::mem::size_of(descriptors) returned as size in bytes of
|
||||
// allocated descriptors.
|
||||
descriptors: *mut u8,
|
||||
key: *mut ExitBootServicesKey, // Key used to exit bootloader
|
||||
descriptor_size: *mut usize, // This ought to be
|
||||
descriptor_version: *mut u32,
|
||||
) -> RawUefiStatus,
|
||||
allocate_pool: *const core::ffi::c_void, // EFI 1.0
|
||||
free_pool: *const core::ffi::c_void,
|
||||
//
|
||||
// Event & Timer Services
|
||||
//
|
||||
create_event: *const core::ffi::c_void,
|
||||
set_timer: *const core::ffi::c_void,
|
||||
wait_for_event: *const core::ffi::c_void,
|
||||
signal_event: *const core::ffi::c_void,
|
||||
close_event: *const core::ffi::c_void,
|
||||
check_event: *const core::ffi::c_void,
|
||||
//
|
||||
// Protocol Handler Services
|
||||
//
|
||||
install_protocol_interface: *const core::ffi::c_void,
|
||||
reinstall_protocol_interface: *const core::ffi::c_void,
|
||||
uninstall_protocol_interface: *const core::ffi::c_void,
|
||||
handle_protocol: *const core::ffi::c_void,
|
||||
reserved: *const core::ffi::c_void,
|
||||
register_protocol_notify: *const core::ffi::c_void,
|
||||
locate_handle: *const core::ffi::c_void,
|
||||
locate_device_path: *const core::ffi::c_void,
|
||||
install_configuration_table: *const core::ffi::c_void,
|
||||
//
|
||||
// Image Services
|
||||
//
|
||||
load_image: *const core::ffi::c_void,
|
||||
start_image: *const core::ffi::c_void,
|
||||
exit: *const core::ffi::c_void,
|
||||
unload_image: *const core::ffi::c_void,
|
||||
exit_boot_services:
|
||||
extern "efiapi" fn(efi_handle: Handle, key: ExitBootServicesKey) -> RawUefiStatus,
|
||||
//
|
||||
// Miscellaneous Services
|
||||
//
|
||||
get_next_monotonic_count: *const core::ffi::c_void,
|
||||
stall: *const core::ffi::c_void,
|
||||
set_watchdog_timer: *const core::ffi::c_void,
|
||||
//
|
||||
// DriverSupport Services
|
||||
//
|
||||
connect_controller: *const core::ffi::c_void,
|
||||
disconnect_controller: *const core::ffi::c_void,
|
||||
//
|
||||
// Open and Close Protocol Services
|
||||
//
|
||||
open_protocol: *const core::ffi::c_void,
|
||||
close_protocol: *const core::ffi::c_void,
|
||||
open_protocol_information: *const core::ffi::c_void,
|
||||
//
|
||||
// Library Services
|
||||
//
|
||||
protocols_per_handle: *const core::ffi::c_void,
|
||||
locate_handle_buffer: *const core::ffi::c_void,
|
||||
locate_protocol: *const core::ffi::c_void,
|
||||
install_multiple_protocol_interfaces: *const core::ffi::c_void,
|
||||
uninstall_multiple_protocol_interfaces: *const core::ffi::c_void,
|
||||
//
|
||||
// 32-bit CRC Services
|
||||
//
|
||||
calculate_crc32: *const core::ffi::c_void,
|
||||
//
|
||||
// Miscellaneous Services
|
||||
//
|
||||
copy_mem: *const core::ffi::c_void,
|
||||
set_mem: *const core::ffi::c_void,
|
||||
create_event_ex: *const core::ffi::c_void, // UEFI 2.0+
|
||||
}
|
||||
|
||||
impl SimpleTextOutputProtocol {
|
||||
pub fn print(&mut self, text: &str) -> Result<(), Option<UefiStatus>> {
|
||||
let f = self.output_string;
|
||||
|
||||
let data = text.encode_utf16();
|
||||
let mut buffer = [0; 1024];
|
||||
buffer
|
||||
.iter_mut()
|
||||
.zip(data)
|
||||
.for_each(|(target, val)| *target = val);
|
||||
|
||||
if buffer[buffer.len() - 1] != 0 {
|
||||
return Err(Some(UefiStatus::BufferTooSmall));
|
||||
}
|
||||
|
||||
let Some(val) = f(core::ptr::from_mut(self), buffer.as_ptr()).interpret() else {
|
||||
return Err(None);
|
||||
};
|
||||
|
||||
if val.is_success() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(Some(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitBootServicesKey {
|
||||
pub const fn default() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PageIter<'a> {
|
||||
buffer: &'a [u8],
|
||||
size: usize,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> PageIter<'a> {
|
||||
const fn new(buffer: &'a [u8], size: usize) -> Self {
|
||||
Self {
|
||||
buffer,
|
||||
size,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PageIter<'a> {
|
||||
type Item = &'a EfiMemoryDescriptor;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if (self.offset + core::mem::size_of::<EfiMemoryDescriptor>()) >= self.buffer.len() {
|
||||
return None;
|
||||
}
|
||||
let start = self.offset;
|
||||
self.offset += self.size;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
Some(unsafe {
|
||||
self.buffer
|
||||
.as_ptr()
|
||||
.add(start)
|
||||
.cast::<EfiMemoryDescriptor>()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl EfiBootServices {
|
||||
pub fn memory_map<'a, 'b>(
|
||||
&mut self,
|
||||
arena: &'a mut [u8],
|
||||
) -> Result<(ExitBootServicesKey, PageIter<'b>, u32), Option<UefiStatus>>
|
||||
where
|
||||
'a: 'b,
|
||||
{
|
||||
let mut key = ExitBootServicesKey::default();
|
||||
let mut size = 0;
|
||||
let mut version = 0;
|
||||
let mut buffer_size = core::mem::size_of_val(arena);
|
||||
|
||||
let code = (self.get_memory_map)(
|
||||
core::ptr::from_mut(&mut buffer_size),
|
||||
arena.as_mut_ptr(),
|
||||
core::ptr::from_mut(&mut key),
|
||||
core::ptr::from_mut(&mut size),
|
||||
core::ptr::from_mut(&mut version),
|
||||
);
|
||||
|
||||
let Some(code) = code.interpret() else {
|
||||
return Err(None);
|
||||
};
|
||||
|
||||
if !code.is_success() {
|
||||
return Err(Some(code));
|
||||
}
|
||||
|
||||
assert!(
|
||||
size >= core::mem::size_of::<EfiMemoryDescriptor>(),
|
||||
"size {}",
|
||||
size
|
||||
);
|
||||
|
||||
Ok((key, PageIter::new(&arena[..buffer_size], size), version))
|
||||
}
|
||||
|
||||
pub fn exit_boot_services(
|
||||
&mut self,
|
||||
handle: Handle,
|
||||
arena: &mut [u8],
|
||||
) -> Result<(), Option<UefiStatus>> {
|
||||
let (key, ..) = self.memory_map(arena)?;
|
||||
|
||||
let Some(res) = (self.exit_boot_services)(handle, key).interpret() else {
|
||||
return Err(None);
|
||||
};
|
||||
|
||||
if res.is_success() {
|
||||
return Ok(());
|
||||
}
|
||||
Err(Some(res))
|
||||
}
|
||||
}
|
||||
|
||||
impl EfiSystemTable {
|
||||
pub const fn std_out(&mut self) -> &mut SimpleTextOutputProtocol {
|
||||
unsafe { self.console_out.as_mut().unwrap() }
|
||||
}
|
||||
|
||||
pub const fn std_err(&mut self) -> &mut SimpleTextOutputProtocol {
|
||||
unsafe { self.standard_error.as_mut().unwrap() }
|
||||
}
|
||||
|
||||
pub const fn boot_services(&mut self) -> &mut EfiBootServices {
|
||||
unsafe { self.boot_services.as_mut().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Write for SimpleTextOutputProtocol {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
let _ = self.print(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ExitBootServicesKey {
|
||||
fn default() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
99
uefi/src/memory.rs
Normal file
99
uefi/src/memory.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(u32)]
|
||||
pub enum EfiMemoryType {
|
||||
ReservedMemoryType = 0,
|
||||
LoaderCode = 1,
|
||||
LoaderData = 2,
|
||||
BootServicesCode = 3,
|
||||
BootServicesData = 4,
|
||||
RuntimeServicesCode = 5,
|
||||
RuntimeServicesData = 6,
|
||||
ConventionalMemory = 7,
|
||||
UnusableMemory = 8,
|
||||
AcpiReclaimMemory = 9,
|
||||
AcpiMemoryNvs = 10,
|
||||
MemoryMappedIo = 11,
|
||||
MemoryMappedIoPortSpace = 12,
|
||||
PalCode = 13,
|
||||
PersistentMemory = 14,
|
||||
UnacceptedMemoryType = 15,
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RawMemoryType(u32);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct EfiPhysicalAddress(u64);
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct EfiVirtualAddress(u64);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct EfiMemoryDescriptor {
|
||||
pub memory_type: RawMemoryType,
|
||||
pub physical_start: EfiPhysicalAddress,
|
||||
pub virtual_start: EfiVirtualAddress,
|
||||
pub number_of_pages: u64,
|
||||
pub attribute: u64,
|
||||
}
|
||||
|
||||
impl RawMemoryType {
|
||||
#[inline(always)]
|
||||
pub const fn interpret(&self) -> Option<EfiMemoryType> {
|
||||
EfiMemoryType::try_from_raw(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl EfiMemoryType {
|
||||
#[inline(always)]
|
||||
pub const fn try_from_raw(raw: &RawMemoryType) -> Option<Self> {
|
||||
Self::from_u32(raw.0)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
pub const fn as_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
pub const fn from_u32(value: u32) -> Option<Self> {
|
||||
Some(match value {
|
||||
0 => Self::ReservedMemoryType,
|
||||
1 => Self::LoaderCode,
|
||||
2 => Self::LoaderData,
|
||||
3 => Self::BootServicesCode,
|
||||
4 => Self::BootServicesData,
|
||||
5 => Self::RuntimeServicesCode,
|
||||
6 => Self::RuntimeServicesData,
|
||||
7 => Self::ConventionalMemory,
|
||||
8 => Self::UnusableMemory,
|
||||
9 => Self::AcpiReclaimMemory,
|
||||
10 => Self::AcpiMemoryNvs,
|
||||
11 => Self::MemoryMappedIo,
|
||||
12 => Self::MemoryMappedIoPortSpace,
|
||||
13 => Self::PalCode,
|
||||
14 => Self::PersistentMemory,
|
||||
15 => Self::UnacceptedMemoryType,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EfiMemoryType> for u32 {
|
||||
fn from(memory_type: EfiMemoryType) -> Self {
|
||||
memory_type.as_u32()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for EfiMemoryType {
|
||||
type Error = u32;
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
Self::from_u32(value).ok_or(value)
|
||||
}
|
||||
}
|
||||
221
uefi/src/status.rs
Normal file
221
uefi/src/status.rs
Normal file
@@ -0,0 +1,221 @@
|
||||
#![allow(
|
||||
clippy::module_name_repetitions,
|
||||
reason = "UefiStatus is the canonical UEFI name"
|
||||
)]
|
||||
|
||||
/// High bit mask — set on all error codes, clear on warnings and success.
|
||||
const ERROR: usize = 1 << (usize::BITS - 1);
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RawUefiStatus(usize);
|
||||
|
||||
/// UEFI status code (UEFI spec Appendix D).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(usize)]
|
||||
pub enum UefiStatus {
|
||||
// ── Success (Table D.2) ──────────────────────────────────────────
|
||||
/// The operation completed successfully.
|
||||
Success = 0,
|
||||
|
||||
// ── Warnings (Table D.4, high bit clear) ─────────────────────────
|
||||
/// String contained characters the device could not render.
|
||||
WarnUnknownGlyph = 1,
|
||||
/// Handle closed, but file was not deleted.
|
||||
WarnDeleteFailure = 2,
|
||||
/// Handle closed, but data was not flushed properly.
|
||||
WarnWriteFailure = 3,
|
||||
/// Buffer was too small; data was truncated.
|
||||
WarnBufferTooSmall = 4,
|
||||
/// Data has not been updated within local policy timeframe.
|
||||
WarnStaleData = 5,
|
||||
/// Buffer contains UEFI-compliant file system.
|
||||
WarnFileSystem = 6,
|
||||
/// Operation will be processed across a system reset.
|
||||
WarnResetRequired = 7,
|
||||
|
||||
// ── Errors (Table D.3, high bit set) ─────────────────────────────
|
||||
/// Image failed to load.
|
||||
LoadError = ERROR | 1,
|
||||
/// A parameter was incorrect.
|
||||
InvalidParameter = ERROR | 2,
|
||||
/// Operation is not supported.
|
||||
Unsupported = ERROR | 3,
|
||||
/// Buffer was not the proper size for the request.
|
||||
BadBufferSize = ERROR | 4,
|
||||
/// Buffer is not large enough to hold the requested data.
|
||||
BufferTooSmall = ERROR | 5,
|
||||
/// No data pending upon return.
|
||||
NotReady = ERROR | 6,
|
||||
/// Physical device reported an error.
|
||||
DeviceError = ERROR | 7,
|
||||
/// Device cannot be written to.
|
||||
WriteProtected = ERROR | 8,
|
||||
/// A resource has run out.
|
||||
OutOfResources = ERROR | 9,
|
||||
/// File system inconsistency detected.
|
||||
VolumeCorrupted = ERROR | 10,
|
||||
/// No more space on the file system.
|
||||
VolumeFull = ERROR | 11,
|
||||
/// Device does not contain any medium.
|
||||
NoMedia = ERROR | 12,
|
||||
/// Medium in the device has changed since last access.
|
||||
MediaChanged = ERROR | 13,
|
||||
/// Item was not found.
|
||||
NotFound = ERROR | 14,
|
||||
/// Access was denied.
|
||||
AccessDenied = ERROR | 15,
|
||||
/// Server was not found or did not respond.
|
||||
NoResponse = ERROR | 16,
|
||||
/// Mapping to a device does not exist.
|
||||
NoMapping = ERROR | 17,
|
||||
/// Timeout expired.
|
||||
Timeout = ERROR | 18,
|
||||
/// Protocol has not been started.
|
||||
NotStarted = ERROR | 19,
|
||||
/// Protocol has already been started.
|
||||
AlreadyStarted = ERROR | 20,
|
||||
/// Operation was aborted.
|
||||
Aborted = ERROR | 21,
|
||||
/// ICMP error occurred during network operation.
|
||||
IcmpError = ERROR | 22,
|
||||
/// TFTP error occurred during network operation.
|
||||
TftpError = ERROR | 23,
|
||||
/// Protocol error occurred during network operation.
|
||||
ProtocolError = ERROR | 24,
|
||||
/// Internal version incompatible with caller's requested version.
|
||||
IncompatibleVersion = ERROR | 25,
|
||||
/// Operation not performed due to a security violation.
|
||||
SecurityViolation = ERROR | 26,
|
||||
/// CRC error detected.
|
||||
CrcError = ERROR | 27,
|
||||
/// Beginning or end of media was reached.
|
||||
EndOfMedia = ERROR | 28,
|
||||
/// End of file was reached.
|
||||
EndOfFile = ERROR | 31,
|
||||
/// Specified language was invalid.
|
||||
InvalidLanguage = ERROR | 32,
|
||||
/// Security status of data is unknown or compromised.
|
||||
CompromisedData = ERROR | 33,
|
||||
/// Address conflict during address allocation.
|
||||
IpAddressConflict = ERROR | 34,
|
||||
/// HTTP error occurred during network operation.
|
||||
HttpError = ERROR | 35,
|
||||
}
|
||||
|
||||
impl RawUefiStatus {
|
||||
pub const fn interpret(&self) -> Option<UefiStatus> {
|
||||
UefiStatus::try_from_raw(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl UefiStatus {
|
||||
/// Tries to convert from a raw uefi status.
|
||||
pub const fn try_from_raw(raw: &RawUefiStatus) -> Option<Self> {
|
||||
Self::from_usize(raw.0)
|
||||
}
|
||||
|
||||
/// Returns `true` if this status represents an error (high bit set).
|
||||
#[must_use]
|
||||
pub const fn is_error(self) -> bool {
|
||||
self.as_usize() & ERROR != 0
|
||||
}
|
||||
|
||||
/// Returns `true` if this status represents a warning (non-zero, high bit clear).
|
||||
#[must_use]
|
||||
pub const fn is_warning(self) -> bool {
|
||||
let v = self.as_usize();
|
||||
v != 0 && v & ERROR == 0
|
||||
}
|
||||
|
||||
/// Returns `true` if this status is `Success`.
|
||||
#[must_use]
|
||||
pub const fn is_success(self) -> bool {
|
||||
self.as_usize() == 0
|
||||
}
|
||||
|
||||
/// Convert to the raw `usize` representation.
|
||||
#[must_use]
|
||||
pub const fn as_usize(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
|
||||
/// Convert from a raw `usize`. Returns `None` for unrecognised codes.
|
||||
#[must_use]
|
||||
pub const fn from_usize(value: usize) -> Option<Self> {
|
||||
let code = value & !ERROR;
|
||||
if value & ERROR != 0 {
|
||||
Self::from_error_code(code)
|
||||
} else {
|
||||
Self::from_warning_code(code)
|
||||
}
|
||||
}
|
||||
|
||||
const fn from_warning_code(code: usize) -> Option<Self> {
|
||||
Some(match code {
|
||||
0 => Self::Success,
|
||||
1 => Self::WarnUnknownGlyph,
|
||||
2 => Self::WarnDeleteFailure,
|
||||
3 => Self::WarnWriteFailure,
|
||||
4 => Self::WarnBufferTooSmall,
|
||||
5 => Self::WarnStaleData,
|
||||
6 => Self::WarnFileSystem,
|
||||
7 => Self::WarnResetRequired,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
const fn from_error_code(code: usize) -> Option<Self> {
|
||||
Some(match code {
|
||||
1 => Self::LoadError,
|
||||
2 => Self::InvalidParameter,
|
||||
3 => Self::Unsupported,
|
||||
4 => Self::BadBufferSize,
|
||||
5 => Self::BufferTooSmall,
|
||||
6 => Self::NotReady,
|
||||
7 => Self::DeviceError,
|
||||
8 => Self::WriteProtected,
|
||||
9 => Self::OutOfResources,
|
||||
10 => Self::VolumeCorrupted,
|
||||
11 => Self::VolumeFull,
|
||||
12 => Self::NoMedia,
|
||||
13 => Self::MediaChanged,
|
||||
14 => Self::NotFound,
|
||||
15 => Self::AccessDenied,
|
||||
16 => Self::NoResponse,
|
||||
17 => Self::NoMapping,
|
||||
18 => Self::Timeout,
|
||||
19 => Self::NotStarted,
|
||||
20 => Self::AlreadyStarted,
|
||||
21 => Self::Aborted,
|
||||
22 => Self::IcmpError,
|
||||
23 => Self::TftpError,
|
||||
24 => Self::ProtocolError,
|
||||
25 => Self::IncompatibleVersion,
|
||||
26 => Self::SecurityViolation,
|
||||
27 => Self::CrcError,
|
||||
28 => Self::EndOfMedia,
|
||||
31 => Self::EndOfFile,
|
||||
32 => Self::InvalidLanguage,
|
||||
33 => Self::CompromisedData,
|
||||
34 => Self::IpAddressConflict,
|
||||
35 => Self::HttpError,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UefiStatus> for usize {
|
||||
fn from(status: UefiStatus) -> Self {
|
||||
status.as_usize()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<usize> for UefiStatus {
|
||||
type Error = usize;
|
||||
|
||||
/// Returns `Err(raw_value)` if the code is not recognised.
|
||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||
Self::from_usize(value).ok_or(value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user