#[cfg(not(any(
target_arch = "arm",
target_arch = "aarch64",
target_arch = "riscv64",
target_arch = "x86",
target_arch = "x86_64"
)))]
compile_error!("The target architecture is not supported.");
#[cfg(not(target_endian = "little"))]
compile_error!("The target endianness is not supported.");
#[macro_export]
#[doc(hidden)]
macro_rules! eficall_abi {
(($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "efiapi" $($suffix)* };
}
#[macro_export]
macro_rules! eficall {
(@munch(($($prefix:tt)*),(pub $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* pub),($($suffix)*))} };
(@munch(($($prefix:tt)*),(unsafe $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* unsafe),($($suffix)*))} };
(@munch(($($prefix:tt)*),($($suffix:tt)*))) => { eficall_abi!{($($prefix)*),($($suffix)*)} };
($($arg:tt)*) => { eficall!{@munch((),($($arg)*))} };
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct Boolean(u8);
pub type Char8 = u8;
pub type Char16 = u16;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Status(usize);
pub type Handle = *mut core::ffi::c_void;
pub type Event = *mut core::ffi::c_void;
pub type Lba = u64;
pub type Tpl = usize;
pub type PhysicalAddress = u64;
pub type VirtualAddress = u64;
pub type ImageEntryPoint = eficall! {fn(Handle, *mut crate::system::SystemTable) -> Status};
#[repr(C, align(4))]
#[derive(Clone, Copy, Debug)]
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Guid {
time_low: [u8; 4],
time_mid: [u8; 2],
time_hi_and_version: [u8; 2],
clk_seq_hi_res: u8,
clk_seq_low: u8,
node: [u8; 6],
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct MacAddress {
pub addr: [u8; 32],
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Ipv4Address {
pub addr: [u8; 4],
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Ipv6Address {
pub addr: [u8; 16],
}
#[repr(C, align(4))]
#[derive(Clone, Copy)]
pub union IpAddress {
pub addr: [u32; 4],
pub v4: Ipv4Address,
pub v6: Ipv6Address,
}
impl Boolean {
pub const FALSE: Boolean = Boolean(0u8);
pub const TRUE: Boolean = Boolean(1u8);
}
impl From<u8> for Boolean {
fn from(v: u8) -> Self {
Boolean(v)
}
}
impl From<bool> for Boolean {
fn from(v: bool) -> Self {
match v {
false => Boolean::FALSE,
true => Boolean::TRUE,
}
}
}
impl Default for Boolean {
fn default() -> Self {
Self::FALSE
}
}
impl From<Boolean> for u8 {
fn from(v: Boolean) -> Self {
match v.0 {
0 => 0,
_ => 1,
}
}
}
impl From<Boolean> for bool {
fn from(v: Boolean) -> Self {
match v.0 {
0 => false,
_ => true,
}
}
}
impl Eq for Boolean {}
impl core::hash::Hash for Boolean {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
bool::from(*self).hash(state)
}
}
impl Ord for Boolean {
fn cmp(&self, other: &Boolean) -> core::cmp::Ordering {
bool::from(*self).cmp(&(*other).into())
}
}
impl PartialEq for Boolean {
fn eq(&self, other: &Boolean) -> bool {
bool::from(*self).eq(&(*other).into())
}
}
impl PartialEq<bool> for Boolean {
fn eq(&self, other: &bool) -> bool {
bool::from(*self).eq(other)
}
}
impl PartialOrd for Boolean {
fn partial_cmp(&self, other: &Boolean) -> Option<core::cmp::Ordering> {
bool::from(*self).partial_cmp(&(*other).into())
}
}
impl PartialOrd<bool> for Boolean {
fn partial_cmp(&self, other: &bool) -> Option<core::cmp::Ordering> {
bool::from(*self).partial_cmp(other)
}
}
impl Status {
const WIDTH: usize = 8usize * core::mem::size_of::<Status>();
const MASK: usize = 0xc0 << (Status::WIDTH - 8);
const ERROR_MASK: usize = 0x80 << (Status::WIDTH - 8);
const WARNING_MASK: usize = 0x00 << (Status::WIDTH - 8);
pub const SUCCESS: Status = Status::from_usize(0);
pub const LOAD_ERROR: Status = Status::from_usize(1 | Status::ERROR_MASK);
pub const INVALID_PARAMETER: Status = Status::from_usize(2 | Status::ERROR_MASK);
pub const UNSUPPORTED: Status = Status::from_usize(3 | Status::ERROR_MASK);
pub const BAD_BUFFER_SIZE: Status = Status::from_usize(4 | Status::ERROR_MASK);
pub const BUFFER_TOO_SMALL: Status = Status::from_usize(5 | Status::ERROR_MASK);
pub const NOT_READY: Status = Status::from_usize(6 | Status::ERROR_MASK);
pub const DEVICE_ERROR: Status = Status::from_usize(7 | Status::ERROR_MASK);
pub const WRITE_PROTECTED: Status = Status::from_usize(8 | Status::ERROR_MASK);
pub const OUT_OF_RESOURCES: Status = Status::from_usize(9 | Status::ERROR_MASK);
pub const VOLUME_CORRUPTED: Status = Status::from_usize(10 | Status::ERROR_MASK);
pub const VOLUME_FULL: Status = Status::from_usize(11 | Status::ERROR_MASK);
pub const NO_MEDIA: Status = Status::from_usize(12 | Status::ERROR_MASK);
pub const MEDIA_CHANGED: Status = Status::from_usize(13 | Status::ERROR_MASK);
pub const NOT_FOUND: Status = Status::from_usize(14 | Status::ERROR_MASK);
pub const ACCESS_DENIED: Status = Status::from_usize(15 | Status::ERROR_MASK);
pub const NO_RESPONSE: Status = Status::from_usize(16 | Status::ERROR_MASK);
pub const NO_MAPPING: Status = Status::from_usize(17 | Status::ERROR_MASK);
pub const TIMEOUT: Status = Status::from_usize(18 | Status::ERROR_MASK);
pub const NOT_STARTED: Status = Status::from_usize(19 | Status::ERROR_MASK);
pub const ALREADY_STARTED: Status = Status::from_usize(20 | Status::ERROR_MASK);
pub const ABORTED: Status = Status::from_usize(21 | Status::ERROR_MASK);
pub const ICMP_ERROR: Status = Status::from_usize(22 | Status::ERROR_MASK);
pub const TFTP_ERROR: Status = Status::from_usize(23 | Status::ERROR_MASK);
pub const PROTOCOL_ERROR: Status = Status::from_usize(24 | Status::ERROR_MASK);
pub const INCOMPATIBLE_VERSION: Status = Status::from_usize(25 | Status::ERROR_MASK);
pub const SECURITY_VIOLATION: Status = Status::from_usize(26 | Status::ERROR_MASK);
pub const CRC_ERROR: Status = Status::from_usize(27 | Status::ERROR_MASK);
pub const END_OF_MEDIA: Status = Status::from_usize(28 | Status::ERROR_MASK);
pub const END_OF_FILE: Status = Status::from_usize(31 | Status::ERROR_MASK);
pub const INVALID_LANGUAGE: Status = Status::from_usize(32 | Status::ERROR_MASK);
pub const COMPROMISED_DATA: Status = Status::from_usize(33 | Status::ERROR_MASK);
pub const IP_ADDRESS_CONFLICT: Status = Status::from_usize(34 | Status::ERROR_MASK);
pub const HTTP_ERROR: Status = Status::from_usize(35 | Status::ERROR_MASK);
pub const NETWORK_UNREACHABLE: Status = Status::from_usize(100 | Status::ERROR_MASK);
pub const HOST_UNREACHABLE: Status = Status::from_usize(101 | Status::ERROR_MASK);
pub const PROTOCOL_UNREACHABLE: Status = Status::from_usize(102 | Status::ERROR_MASK);
pub const PORT_UNREACHABLE: Status = Status::from_usize(103 | Status::ERROR_MASK);
pub const CONNECTION_FIN: Status = Status::from_usize(104 | Status::ERROR_MASK);
pub const CONNECTION_RESET: Status = Status::from_usize(105 | Status::ERROR_MASK);
pub const CONNECTION_REFUSED: Status = Status::from_usize(106 | Status::ERROR_MASK);
pub const WARN_UNKNOWN_GLYPH: Status = Status::from_usize(1 | Status::WARNING_MASK);
pub const WARN_DELETE_FAILURE: Status = Status::from_usize(2 | Status::WARNING_MASK);
pub const WARN_WRITE_FAILURE: Status = Status::from_usize(3 | Status::WARNING_MASK);
pub const WARN_BUFFER_TOO_SMALL: Status = Status::from_usize(4 | Status::WARNING_MASK);
pub const WARN_STALE_DATA: Status = Status::from_usize(5 | Status::WARNING_MASK);
pub const WARN_FILE_SYSTEM: Status = Status::from_usize(6 | Status::WARNING_MASK);
pub const WARN_RESET_REQUIRED: Status = Status::from_usize(7 | Status::WARNING_MASK);
pub const fn from_usize(v: usize) -> Status {
Status(v)
}
pub const fn as_usize(&self) -> usize {
self.0
}
fn value(&self) -> usize {
self.0
}
fn mask(&self) -> usize {
self.value() & Status::MASK
}
pub fn is_error(&self) -> bool {
self.mask() == Status::ERROR_MASK
}
pub fn is_warning(&self) -> bool {
self.value() != 0 && self.mask() == Status::WARNING_MASK
}
}
impl From<Status> for Result<Status, Status> {
fn from(status: Status) -> Self {
if status.is_error() {
Err(status)
} else {
Ok(status)
}
}
}
impl Guid {
const fn u32_to_bytes_le(num: u32) -> [u8; 4] {
[
num as u8,
(num >> 8) as u8,
(num >> 16) as u8,
(num >> 24) as u8,
]
}
const fn u32_from_bytes_le(bytes: &[u8; 4]) -> u32 {
(bytes[0] as u32)
| ((bytes[1] as u32) << 8)
| ((bytes[2] as u32) << 16)
| ((bytes[3] as u32) << 24)
}
const fn u16_to_bytes_le(num: u16) -> [u8; 2] {
[num as u8, (num >> 8) as u8]
}
const fn u16_from_bytes_le(bytes: &[u8; 2]) -> u16 {
(bytes[0] as u16) | ((bytes[1] as u16) << 8)
}
pub const fn from_fields(
time_low: u32,
time_mid: u16,
time_hi_and_version: u16,
clk_seq_hi_res: u8,
clk_seq_low: u8,
node: &[u8; 6],
) -> Guid {
Guid {
time_low: Self::u32_to_bytes_le(time_low),
time_mid: Self::u16_to_bytes_le(time_mid),
time_hi_and_version: Self::u16_to_bytes_le(time_hi_and_version),
clk_seq_hi_res: clk_seq_hi_res,
clk_seq_low: clk_seq_low,
node: *node,
}
}
pub const fn as_fields(&self) -> (u32, u16, u16, u8, u8, &[u8; 6]) {
(
Self::u32_from_bytes_le(&self.time_low),
Self::u16_from_bytes_le(&self.time_mid),
Self::u16_from_bytes_le(&self.time_hi_and_version),
self.clk_seq_hi_res,
self.clk_seq_low,
&self.node,
)
}
pub const fn from_bytes(bytes: &[u8; 16]) -> Self {
unsafe { core::mem::transmute::<[u8; 16], Guid>(*bytes) }
}
pub const fn as_bytes(&self) -> &[u8; 16] {
unsafe { core::mem::transmute::<&Guid, &[u8; 16]>(self) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::{align_of, size_of};
fn hash<T: core::hash::Hash>(v: &T) -> u64 {
let mut h = std::hash::DefaultHasher::new();
v.hash(&mut h);
core::hash::Hasher::finish(&h)
}
#[test]
fn type_size_and_alignment() {
assert_eq!(size_of::<Boolean>(), 1);
assert_eq!(align_of::<Boolean>(), 1);
assert_eq!(size_of::<Char8>(), 1);
assert_eq!(align_of::<Char8>(), 1);
assert_eq!(size_of::<Char16>(), 2);
assert_eq!(align_of::<Char16>(), 2);
assert_eq!(size_of::<Char8>(), size_of::<u8>());
assert_eq!(align_of::<Char8>(), align_of::<u8>());
assert_eq!(size_of::<Char16>(), size_of::<u16>());
assert_eq!(align_of::<Char16>(), align_of::<u16>());
assert_eq!(size_of::<Status>(), size_of::<usize>());
assert_eq!(align_of::<Status>(), align_of::<usize>());
assert_eq!(size_of::<Handle>(), size_of::<usize>());
assert_eq!(align_of::<Handle>(), align_of::<usize>());
assert_eq!(size_of::<Event>(), size_of::<usize>());
assert_eq!(align_of::<Event>(), align_of::<usize>());
assert_eq!(size_of::<Handle>(), size_of::<*mut ()>());
assert_eq!(align_of::<Handle>(), align_of::<*mut ()>());
assert_eq!(size_of::<Event>(), size_of::<*mut ()>());
assert_eq!(align_of::<Event>(), align_of::<*mut ()>());
assert_eq!(size_of::<Lba>(), size_of::<u64>());
assert_eq!(align_of::<Lba>(), align_of::<u64>());
assert_eq!(size_of::<Tpl>(), size_of::<usize>());
assert_eq!(align_of::<Tpl>(), align_of::<usize>());
assert_eq!(size_of::<PhysicalAddress>(), size_of::<u64>());
assert_eq!(align_of::<PhysicalAddress>(), align_of::<u64>());
assert_eq!(size_of::<VirtualAddress>(), size_of::<u64>());
assert_eq!(align_of::<VirtualAddress>(), align_of::<u64>());
assert_eq!(size_of::<ImageEntryPoint>(), size_of::<fn()>());
assert_eq!(align_of::<ImageEntryPoint>(), align_of::<fn()>());
assert_eq!(size_of::<Guid>(), 16);
assert_eq!(align_of::<Guid>(), 4);
assert_eq!(size_of::<MacAddress>(), 32);
assert_eq!(align_of::<MacAddress>(), 1);
assert_eq!(size_of::<Ipv4Address>(), 4);
assert_eq!(align_of::<Ipv4Address>(), 1);
assert_eq!(size_of::<Ipv6Address>(), 16);
assert_eq!(align_of::<Ipv6Address>(), 1);
assert_eq!(size_of::<IpAddress>(), 16);
assert_eq!(align_of::<IpAddress>(), 4);
}
#[test]
fn eficall() {
let _: eficall! {fn()};
let _: eficall! {unsafe fn()};
let _: eficall! {fn(i32)};
let _: eficall! {fn(i32) -> i32};
let _: eficall! {fn(i32, i32) -> (i32, i32)};
eficall! {fn _unused00() {}}
eficall! {unsafe fn _unused01() {}}
eficall! {pub unsafe fn _unused02() {}}
}
#[test]
fn booleans() {
assert_ne!(Boolean::FALSE, Boolean::TRUE);
assert_eq!(Boolean::FALSE, false);
assert_eq!(Boolean::TRUE, true);
for i in 0u8..=255u8 {
let v1: Boolean = i.into();
let v2: Boolean = unsafe { std::mem::transmute::<u8, Boolean>(i) };
assert_eq!(v1, v2);
assert_eq!(v1, v1);
assert_eq!(v2, v2);
match i {
0 => {
assert_eq!(v1, Boolean::FALSE);
assert_eq!(v1, false);
assert_eq!(v2, Boolean::FALSE);
assert_eq!(v2, false);
assert_ne!(v1, Boolean::TRUE);
assert_ne!(v1, true);
assert_ne!(v2, Boolean::TRUE);
assert_ne!(v2, true);
assert!(v1 < Boolean::TRUE);
assert!(v1 < true);
assert!(v1 >= Boolean::FALSE);
assert!(v1 >= false);
assert!(v1 <= Boolean::FALSE);
assert!(v1 <= false);
assert_eq!(v1.cmp(&true.into()), core::cmp::Ordering::Less);
assert_eq!(v1.cmp(&false.into()), core::cmp::Ordering::Equal);
assert_eq!(hash(&v1), hash(&false));
}
_ => {
assert_eq!(v1, Boolean::TRUE);
assert_eq!(v1, true);
assert_eq!(v2, Boolean::TRUE);
assert_eq!(v2, true);
assert_ne!(v1, Boolean::FALSE);
assert_ne!(v1, false);
assert_ne!(v2, Boolean::FALSE);
assert_ne!(v2, false);
assert!(v1 <= Boolean::TRUE);
assert!(v1 <= true);
assert!(v1 >= Boolean::TRUE);
assert!(v1 >= true);
assert!(v1 > Boolean::FALSE);
assert!(v1 > false);
assert_eq!(v1.cmp(&true.into()), core::cmp::Ordering::Equal);
assert_eq!(v1.cmp(&false.into()), core::cmp::Ordering::Greater);
assert_eq!(hash(&v1), hash(&true));
}
}
}
}
#[test]
fn guid() {
let fields = (
0x550e8400,
0xe29b,
0x41d4,
0xa7,
0x16,
&[0x44, 0x66, 0x55, 0x44, 0x00, 0x00],
);
#[rustfmt::skip]
let bytes = [
0x00, 0x84, 0x0e, 0x55,
0x9b, 0xe2,
0xd4, 0x41,
0xa7,
0x16,
0x44, 0x66, 0x55, 0x44, 0x00, 0x00,
];
let (f0, f1, f2, f3, f4, f5) = fields;
let g_fields = Guid::from_fields(f0, f1, f2, f3, f4, f5);
let g_bytes = Guid::from_bytes(&bytes);
assert_eq!(g_fields, g_bytes);
assert_eq!(g_fields.as_bytes(), &bytes);
assert_eq!(g_bytes.as_fields(), fields);
}
}