1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
use core::fmt;
/// A globally unique identifier
///
/// GUIDs are used by UEFI to identify protocols and other objects. They are
/// mostly like variant 2 UUIDs as specified by RFC 4122, but differ from them
/// in that the first 3 fields are little endian instead of big endian.
///
/// The `Display` formatter prints GUIDs in the canonical format defined by
/// RFC 4122, which is also used by UEFI.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct Guid {
/// The low field of the timestamp.
a: u32,
/// The middle field of the timestamp.
b: u16,
/// The high field of the timestamp multiplexed with the version number.
c: u16,
/// Contains, in this order:
/// - The high field of the clock sequence multiplexed with the variant.
/// - The low field of the clock sequence.
/// - The spatially unique node identifier.
d: [u8; 8],
}
impl Guid {
/// Creates a new GUID from its canonical representation
//
// FIXME: An unwieldy array of bytes must be used for the node ID until one
// can assert that an u64 has its high 16-bits cleared in a const fn.
// Once that is done, we can take an u64 to be even closer to the
// canonical UUID/GUID format.
//
pub const fn from_values(
time_low: u32,
time_mid: u16,
time_high_and_version: u16,
clock_seq_and_variant: u16,
node: [u8; 6],
) -> Self {
Guid {
a: time_low,
b: time_mid,
c: time_high_and_version,
d: [
(clock_seq_and_variant / 0x100) as u8,
(clock_seq_and_variant % 0x100) as u8,
node[0],
node[1],
node[2],
node[3],
node[4],
node[5],
],
}
}
}
impl fmt::Display for Guid {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let d = {
let (low, high) = (u16::from(self.d[0]), u16::from(self.d[1]));
(low << 8) | high
};
// Extract and reverse byte order.
let e = self.d[2..8].iter().enumerate().fold(0, |acc, (i, &elem)| {
acc | {
let shift = (5 - i) * 8;
u64::from(elem) << shift
}
});
write!(
fmt,
"{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
self.a, self.b, self.c, d, e
)
}
}
/// Several entities in the UEFI specification can be referred to by their GUID,
/// this trait is a building block to interface them in uefi-rs.
///
/// You should never need to use the `Identify` trait directly, but instead go
/// for more specific traits such as `Protocol` or `FileProtocolInfo`, which
/// indicate in which circumstances an `Identify`-tagged type should be used.
///
/// Implementing `Identify` is unsafe because attaching an incorrect GUID to a
/// type can lead to type unsafety on both the Rust and UEFI side.
///
/// You can derive `Identify` for a type using the `unsafe_guid` procedural
/// macro, which is exported by this module. This macro mostly works like a
/// custom derive, but also supports type aliases. It takes a GUID in canonical
/// textual format as an argument, and is used in the following way:
///
/// ```
/// use uefi::unsafe_guid;
/// #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")]
/// struct Emptiness;
/// ```
pub unsafe trait Identify {
/// Unique protocol identifier.
const GUID: Guid;
}
pub use uefi_macros::unsafe_guid;