diff --git a/CHANGELOG.md b/CHANGELOG.md index f4534c666..c89077f16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## uefi - [Unreleased] ### Added + - Implementations for the trait `EqStrUntilNul` now allow `?Sized` inputs. This means that you can write `some_cstr16.eq_str_until_nul("test")` instead of `some_cstr16.eq_str_until_nul(&"test")` now. @@ -14,14 +15,22 @@ - Added an `core::error::Error` implementation for `Error` to ease integration with error-handling crates. (requires the **unstable** feature) - Added partial support for the TCG protocols for TPM devices under `uefi::proto::tcg`. +- Added the `unsafe_protocol` macro to provide a slightly nicer way to + implement protocols. ### Changed - `UnalignedSlice` now implements `Clone`, and the `Debug` impl now prints the elements instead of the internal fields. +- The unstable `negative_impls` feature is no longer required to use this library. ### Removed +- The `unsafe_guid` attribute macro and `Protocol` derive macro have + been removed. For implementing protocols, use the `unsafe_protocol` + macro instead. For any other implementations of the `Identify` trait, + implement it directly. + ## uefi-macros - [Unreleased] ## uefi-services - [Unreleased] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 899e28e7b..e5a12cad0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -81,7 +81,7 @@ in the order the UEFI spec requires. Each protocol also has a Globally Unique Identifier (in the C API, they're usually found in a `EFI_*_PROTOCOL_GUID` define). In Rust, we store the GUID as an associated constant, by implementing the unsafe trait `uefi::proto::Identify`. For convenience, -this is done through the `unsafe_guid` macro. +this is done through the `unsafe_protocol` macro. Finally, you should derive the `Protocol` trait. This is a marker trait, extending `Identify`, which is used as a generic bound in the functions which retrieve @@ -92,8 +92,7 @@ An example protocol declaration: ```rust /// Protocol which does something. #[repr(C)] -#[unsafe_guid("abcdefgh-1234-5678-9012-123456789abc")] -#[derive(Protocol)] +#[unsafe_protocol("abcdefgh-1234-5678-9012-123456789abc")] pub struct NewProtocol { some_entry_point: extern "efiapi" fn( this: *const NewProtocol, diff --git a/uefi-macros/src/lib.rs b/uefi-macros/src/lib.rs index d6f7d11c5..08c6df093 100644 --- a/uefi-macros/src/lib.rs +++ b/uefi-macros/src/lib.rs @@ -7,36 +7,10 @@ use proc_macro::TokenStream; use proc_macro2::{TokenStream as TokenStream2, TokenTree}; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ - parse::{Parse, ParseStream}, - parse_macro_input, parse_quote, - spanned::Spanned, - DeriveInput, Error, FnArg, Generics, Ident, ItemFn, ItemType, LitStr, Pat, Visibility, + parse_macro_input, parse_quote, spanned::Spanned, Error, Fields, FnArg, Ident, ItemFn, + ItemStruct, LitStr, Pat, Visibility, }; -/// Parses a type definition, extracts its identifier and generic parameters -struct TypeDefinition { - ident: Ident, - generics: Generics, -} - -impl Parse for TypeDefinition { - fn parse(input: ParseStream) -> syn::Result { - if let Ok(d) = DeriveInput::parse(input) { - Ok(Self { - ident: d.ident, - generics: d.generics, - }) - } else if let Ok(t) = ItemType::parse(input) { - Ok(Self { - ident: t.ident, - generics: t.generics, - }) - } else { - Err(input.error("Input is not an alias, enum, struct or union definition")) - } - } -} - macro_rules! err { ($span:expr, $message:expr $(,)?) => { Error::new($span.span(), $message).to_compile_error() @@ -46,28 +20,70 @@ macro_rules! err { }; } -/// `unsafe_guid` attribute macro, implements the `Identify` trait for any type -/// (mostly works like a custom derive, but also supports type aliases) +/// Attribute macro for marking structs as UEFI protocols. +/// +/// The macro takes one argument, a GUID string. +/// +/// The macro can only be applied to a struct, and the struct must have +/// named fields (i.e. not a unit or tuple struct). It implements the +/// [`Protocol`] trait and the `unsafe` [`Identify`] trait for the +/// struct. It also adds a hidden field that causes the struct to be +/// marked as [`!Send` and `!Sync`][send-and-sync]. +/// +/// # Safety +/// +/// The caller must ensure that the correct GUID is attached to the +/// type. An incorrect GUID could lead to invalid casts and other +/// unsound behavior. +/// +/// # Example +/// +/// ``` +/// use uefi::{Identify, guid}; +/// use uefi::proto::unsafe_protocol; +/// +/// #[unsafe_protocol("12345678-9abc-def0-1234-56789abcdef0")] +/// struct ExampleProtocol {} +/// +/// assert_eq!(ExampleProtocol::GUID, guid!("12345678-9abc-def0-1234-56789abcdef0")); +/// ``` +/// +/// [`Identify`]: https://docs.rs/uefi/latest/uefi/trait.Identify.html +/// [`Protocol`]: https://docs.rs/uefi/latest/uefi/proto/trait.Protocol.html +/// [send-and-sync]: https://doc.rust-lang.org/nomicon/send-and-sync.html #[proc_macro_attribute] -pub fn unsafe_guid(args: TokenStream, input: TokenStream) -> TokenStream { - // Parse the arguments and input using Syn +pub fn unsafe_protocol(args: TokenStream, input: TokenStream) -> TokenStream { + // Parse `args` as a GUID string. let (time_low, time_mid, time_high_and_version, clock_seq_and_variant, node) = match parse_guid(parse_macro_input!(args as LitStr)) { Ok(data) => data, Err(tokens) => return tokens.into(), }; - let mut result: TokenStream2 = input.clone().into(); + let item_struct = parse_macro_input!(input as ItemStruct); - let type_definition = parse_macro_input!(input as TypeDefinition); - - // At this point, we know everything we need to implement Identify - let ident = &type_definition.ident; - let (impl_generics, ty_generics, where_clause) = type_definition.generics.split_for_impl(); + let ident = &item_struct.ident; + let struct_attrs = &item_struct.attrs; + let struct_vis = &item_struct.vis; + let struct_fields = if let Fields::Named(struct_fields) = &item_struct.fields { + &struct_fields.named + } else { + return err!(item_struct, "Protocol struct must used named fields").into(); + }; + let struct_generics = &item_struct.generics; + let (impl_generics, ty_generics, where_clause) = item_struct.generics.split_for_impl(); + + quote! { + #(#struct_attrs)* + #struct_vis struct #ident #struct_generics { + // Add a hidden field with `PhantomData` of a raw + // pointer. This has the implicit side effect of making the + // struct !Send and !Sync. + _no_send_or_sync: ::core::marker::PhantomData<*const u8>, + #struct_fields + } - result.append_all(quote! { unsafe impl #impl_generics ::uefi::Identify for #ident #ty_generics #where_clause { - #[doc(hidden)] const GUID: ::uefi::Guid = ::uefi::Guid::from_values( #time_low, #time_mid, @@ -76,8 +92,10 @@ pub fn unsafe_guid(args: TokenStream, input: TokenStream) -> TokenStream { #node, ); } - }); - result.into() + + impl #impl_generics ::uefi::proto::Protocol for #ident #ty_generics #where_clause {} + } + .into() } /// Create a `Guid` at compile time. @@ -164,28 +182,6 @@ fn parse_guid(guid_lit: LitStr) -> Result<(u32, u16, u16, u16, u64), TokenStream )) } -/// Custom derive for the `Protocol` trait -#[proc_macro_derive(Protocol)] -pub fn derive_protocol(item: TokenStream) -> TokenStream { - // Parse the input using Syn - let item = parse_macro_input!(item as DeriveInput); - - // Then implement Protocol - let ident = item.ident.clone(); - let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); - let result = quote! { - // Mark this as a `Protocol` implementation - impl #impl_generics ::uefi::proto::Protocol for #ident #ty_generics #where_clause {} - - // Most UEFI functions expect to be called on the bootstrap processor. - impl #impl_generics !Send for #ident #ty_generics #where_clause {} - - // Most UEFI functions do not support multithreaded access. - impl #impl_generics !Sync for #ident #ty_generics #where_clause {} - }; - result.into() -} - /// Get the name of a function's argument at `arg_index`. fn get_function_arg_name(f: &ItemFn, arg_index: usize, errors: &mut TokenStream2) -> Option { if let Some(FnArg::Typed(arg)) = f.sig.inputs.iter().nth(arg_index) { diff --git a/uefi-macros/tests/ui/guid.rs b/uefi-macros/tests/ui/guid.rs deleted file mode 100644 index 4f18b21af..000000000 --- a/uefi-macros/tests/ui/guid.rs +++ /dev/null @@ -1,19 +0,0 @@ -use uefi_macros::unsafe_guid; - -// The GUID here is OK. -#[unsafe_guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")] -struct Good; - -// Fail because the length is wrong. -#[unsafe_guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa")] -struct TooShort; - -// Error span should point to the second group. -#[unsafe_guid("aaaaaaaa-Gaaa-aaaa-aaaa-aaaaaaaaaaaa")] -struct BadHexGroup2; - -// Error span should point to the fifth group. -#[unsafe_guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaG")] -struct BadHexGroup5; - -fn main() {} diff --git a/uefi-macros/tests/ui/guid.stderr b/uefi-macros/tests/ui/guid.stderr deleted file mode 100644 index 8337be27e..000000000 --- a/uefi-macros/tests/ui/guid.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa" is not a canonical GUID string (expected 36 bytes, found 35) - --> $DIR/guid.rs:8:15 - | -8 | #[unsafe_guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: GUID component "Gaaa" is not a hexadecimal number - --> $DIR/guid.rs:12:25 - | -12 | #[unsafe_guid("aaaaaaaa-Gaaa-aaaa-aaaa-aaaaaaaaaaaa")] - | ^^^^ - -error: GUID component "aaaaaaaaaaaG" is not a hexadecimal number - --> $DIR/guid.rs:16:40 - | -16 | #[unsafe_guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaG")] - | ^^^^^^^^^^^^ diff --git a/uefi-macros/tests/ui/guid_bad_hex_group2.rs b/uefi-macros/tests/ui/guid_bad_hex_group2.rs new file mode 100644 index 000000000..c13466974 --- /dev/null +++ b/uefi-macros/tests/ui/guid_bad_hex_group2.rs @@ -0,0 +1,7 @@ +use uefi::Guid; +use uefi_macros::guid; + +// Error span should point to the second group. +const BadHexGroup2: Guid = guid!("aaaaaaaa-Gaaa-aaaa-aaaa-aaaaaaaaaaaa"); + +fn main() {} diff --git a/uefi-macros/tests/ui/guid_bad_hex_group2.stderr b/uefi-macros/tests/ui/guid_bad_hex_group2.stderr new file mode 100644 index 000000000..4daacf765 --- /dev/null +++ b/uefi-macros/tests/ui/guid_bad_hex_group2.stderr @@ -0,0 +1,5 @@ +error: GUID component "Gaaa" is not a hexadecimal number + --> tests/ui/guid_bad_hex_group2.rs:5:44 + | +5 | const BadHexGroup2: Guid = guid!("aaaaaaaa-Gaaa-aaaa-aaaa-aaaaaaaaaaaa"); + | ^^^^ diff --git a/uefi-macros/tests/ui/guid_bad_hex_group5.rs b/uefi-macros/tests/ui/guid_bad_hex_group5.rs new file mode 100644 index 000000000..928fb382c --- /dev/null +++ b/uefi-macros/tests/ui/guid_bad_hex_group5.rs @@ -0,0 +1,7 @@ +use uefi::Guid; +use uefi_macros::guid; + +// Error span should point to the fifth group. +const BadHexGroup5: Guid = guid!("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaG"); + +fn main() {} diff --git a/uefi-macros/tests/ui/guid_bad_hex_group5.stderr b/uefi-macros/tests/ui/guid_bad_hex_group5.stderr new file mode 100644 index 000000000..bac7fc803 --- /dev/null +++ b/uefi-macros/tests/ui/guid_bad_hex_group5.stderr @@ -0,0 +1,5 @@ +error: GUID component "aaaaaaaaaaaG" is not a hexadecimal number + --> tests/ui/guid_bad_hex_group5.rs:5:59 + | +5 | const BadHexGroup5: Guid = guid!("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaG"); + | ^^^^^^^^^^^^ diff --git a/uefi-macros/tests/ui/guid_bad_length.rs b/uefi-macros/tests/ui/guid_bad_length.rs new file mode 100644 index 000000000..0d70ff34a --- /dev/null +++ b/uefi-macros/tests/ui/guid_bad_length.rs @@ -0,0 +1,7 @@ +use uefi::Guid; +use uefi_macros::guid; + +// Fail because the length is wrong. +const TooShort: Guid = guid!("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa"); + +fn main() {} diff --git a/uefi-macros/tests/ui/guid_bad_length.stderr b/uefi-macros/tests/ui/guid_bad_length.stderr new file mode 100644 index 000000000..77fbfb790 --- /dev/null +++ b/uefi-macros/tests/ui/guid_bad_length.stderr @@ -0,0 +1,5 @@ +error: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa" is not a canonical GUID string (expected 36 bytes, found 35) + --> tests/ui/guid_bad_length.rs:5:30 + | +5 | const TooShort: Guid = guid!("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/uefi-test-runner/src/boot/misc.rs b/uefi-test-runner/src/boot/misc.rs index 8f45aeaf0..7ee9d6581 100644 --- a/uefi-test-runner/src/boot/misc.rs +++ b/uefi-test-runner/src/boot/misc.rs @@ -1,9 +1,9 @@ use core::ffi::c_void; use core::ptr::{self, NonNull}; -use uefi::proto::Protocol; +use uefi::proto::unsafe_protocol; use uefi::table::boot::{BootServices, EventType, SearchType, TimerTrigger, Tpl}; -use uefi::{unsafe_guid, Event, Identify}; +use uefi::{Event, Identify}; pub fn test(bt: &BootServices) { info!("Testing timer..."); @@ -80,8 +80,7 @@ fn test_watchdog(bt: &BootServices) { } /// Dummy protocol for tests -#[unsafe_guid("1a972918-3f69-4b5d-8cb4-cece2309c7f5")] -#[derive(Protocol)] +#[unsafe_protocol("1a972918-3f69-4b5d-8cb4-cece2309c7f5")] struct TestProtocol {} unsafe extern "efiapi" fn _test_notify(_event: Event, _context: Option>) { diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 7562b895f..ea9558066 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] #![feature(abi_efiapi)] -#![feature(negative_impls)] #[macro_use] extern crate log; diff --git a/uefi/src/data_types/guid.rs b/uefi/src/data_types/guid.rs index 8f718606b..5694919b3 100644 --- a/uefi/src/data_types/guid.rs +++ b/uefi/src/data_types/guid.rs @@ -114,35 +114,29 @@ impl fmt::Display for 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 +/// for more specific traits such as [`Protocol`] or [`FileProtocolInfo`], which /// indicate in which circumstances an `Identify`-tagged type should be used. /// +/// For the common case of implementing this trait for a protocol, use +/// the [`unsafe_protocol`] macro. +/// /// # Safety /// /// 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; -/// ``` +/// [`Protocol`]: crate::proto::Protocol +/// [`FileProtocolInfo`]: crate::proto::media::file::FileProtocolInfo +/// [`unsafe_protocol`]: crate::proto::unsafe_protocol pub unsafe trait Identify { /// Unique protocol identifier. const GUID: Guid; } -pub use uefi_macros::unsafe_guid; - #[cfg(test)] mod tests { use super::*; - use uefi::{guid, unsafe_guid}; + use uefi::guid; #[test] fn test_guid_display() { @@ -163,17 +157,6 @@ mod tests { ); } - #[test] - fn test_unsafe_guid_macro() { - #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")] - struct X; - - assert_eq!( - X::GUID, - Guid::from_values(0x12345678, 0x9abc, 0xdef0, 0x1234, 0x56789abcdef0) - ); - } - #[test] fn test_to_from_bytes() { #[rustfmt::skip] diff --git a/uefi/src/data_types/mod.rs b/uefi/src/data_types/mod.rs index ad6dd4b30..f3df90227 100644 --- a/uefi/src/data_types/mod.rs +++ b/uefi/src/data_types/mod.rs @@ -121,7 +121,7 @@ pub type VirtualAddress = u64; mod guid; pub use self::guid::Guid; -pub use self::guid::{unsafe_guid, Identify}; +pub use self::guid::Identify; pub mod chars; pub use self::chars::{Char16, Char8}; diff --git a/uefi/src/lib.rs b/uefi/src/lib.rs index 4bc2d7cb6..d411fb8d9 100644 --- a/uefi/src/lib.rs +++ b/uefi/src/lib.rs @@ -60,7 +60,6 @@ #![feature(abi_efiapi)] #![feature(maybe_uninit_slice)] -#![feature(negative_impls)] #![feature(ptr_metadata)] #![cfg_attr(feature = "alloc", feature(vec_into_raw_parts))] #![cfg_attr(feature = "unstable", feature(error_in_core))] @@ -85,7 +84,7 @@ extern crate self as uefi; pub mod data_types; #[cfg(feature = "alloc")] pub use self::data_types::CString16; -pub use self::data_types::{unsafe_guid, Identify}; +pub use self::data_types::Identify; pub use self::data_types::{CStr16, CStr8, Char16, Char8, Event, Guid, Handle}; pub use uefi_macros::guid; diff --git a/uefi/src/proto/console/gop.rs b/uefi/src/proto/console/gop.rs index bc6735bd9..c2e87052d 100644 --- a/uefi/src/proto/console/gop.rs +++ b/uefi/src/proto/console/gop.rs @@ -54,8 +54,8 @@ //! You will have to implement your own double buffering if you want to //! avoid tearing with animations. -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; use core::marker::PhantomData; use core::mem; use core::ptr; @@ -65,8 +65,7 @@ use core::ptr; /// The GOP can be used to set the properties of the frame buffer, /// and also allows the app to access the in-memory buffer. #[repr(C)] -#[unsafe_guid("9042a9de-23dc-4a38-96fb-7aded080516a")] -#[derive(Protocol)] +#[unsafe_protocol("9042a9de-23dc-4a38-96fb-7aded080516a")] pub struct GraphicsOutput<'boot> { query_mode: extern "efiapi" fn( &GraphicsOutput, diff --git a/uefi/src/proto/console/pointer/mod.rs b/uefi/src/proto/console/pointer/mod.rs index ea4112232..0ef123263 100644 --- a/uefi/src/proto/console/pointer/mod.rs +++ b/uefi/src/proto/console/pointer/mod.rs @@ -1,13 +1,12 @@ //! Pointer device access. -use crate::proto::Protocol; -use crate::{unsafe_guid, Event, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Event, Result, Status}; use core::mem::MaybeUninit; /// Provides information about a pointer device. #[repr(C)] -#[unsafe_guid("31878c87-0b75-11d5-9a4f-0090273fc14d")] -#[derive(Protocol)] +#[unsafe_protocol("31878c87-0b75-11d5-9a4f-0090273fc14d")] pub struct Pointer<'boot> { reset: extern "efiapi" fn(this: &mut Pointer, ext_verif: bool) -> Status, get_state: extern "efiapi" fn(this: &Pointer, state: *mut PointerState) -> Status, diff --git a/uefi/src/proto/console/serial.rs b/uefi/src/proto/console/serial.rs index ed436edbf..a17403d05 100644 --- a/uefi/src/proto/console/serial.rs +++ b/uefi/src/proto/console/serial.rs @@ -2,8 +2,8 @@ use core::fmt::Write; -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; use bitflags::bitflags; /// Provides access to a serial I/O device. @@ -14,8 +14,7 @@ use bitflags::bitflags; /// Since UEFI drivers are implemented through polling, if you fail to regularly /// check for input/output, some data might be lost. #[repr(C)] -#[unsafe_guid("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd")] -#[derive(Protocol)] +#[unsafe_protocol("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd")] pub struct Serial<'boot> { // Revision of this protocol, only 1.0 is currently defined. // Future versions will be backwards compatible. diff --git a/uefi/src/proto/console/text/input.rs b/uefi/src/proto/console/text/input.rs index cc8f64004..5e4315ff6 100644 --- a/uefi/src/proto/console/text/input.rs +++ b/uefi/src/proto/console/text/input.rs @@ -1,11 +1,10 @@ -use crate::proto::Protocol; -use crate::{unsafe_guid, Char16, Event, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Char16, Event, Result, Status}; use core::mem::MaybeUninit; /// Interface for text-based input devices. #[repr(C)] -#[unsafe_guid("387477c1-69c7-11d2-8e39-00a0c969723b")] -#[derive(Protocol)] +#[unsafe_protocol("387477c1-69c7-11d2-8e39-00a0c969723b")] pub struct Input { reset: extern "efiapi" fn(this: &mut Input, extended: bool) -> Status, read_key_stroke: extern "efiapi" fn(this: &mut Input, key: *mut RawKey) -> Status, diff --git a/uefi/src/proto/console/text/output.rs b/uefi/src/proto/console/text/output.rs index d6b5d78b3..8e6b5addd 100644 --- a/uefi/src/proto/console/text/output.rs +++ b/uefi/src/proto/console/text/output.rs @@ -1,5 +1,5 @@ -use crate::proto::Protocol; -use crate::{unsafe_guid, CStr16, Char16, Result, ResultExt, Status}; +use crate::proto::unsafe_protocol; +use crate::{CStr16, Char16, Result, ResultExt, Status}; use core::fmt; use core::fmt::{Debug, Formatter}; @@ -21,8 +21,7 @@ use core::fmt::{Debug, Formatter}; /// [`SystemTable::stderr`]: crate::table::SystemTable::stderr /// [`BootServices`]: crate::table::boot::BootServices#accessing-protocols #[repr(C)] -#[unsafe_guid("387477c2-69c7-11d2-8e39-00a0c969723b")] -#[derive(Protocol)] +#[unsafe_protocol("387477c2-69c7-11d2-8e39-00a0c969723b")] pub struct Output<'boot> { reset: extern "efiapi" fn(this: &Output, extended: bool) -> Status, output_string: unsafe extern "efiapi" fn(this: &Output, string: *const Char16) -> Status, diff --git a/uefi/src/proto/debug/mod.rs b/uefi/src/proto/debug/mod.rs index 403e3287b..776b43497 100644 --- a/uefi/src/proto/debug/mod.rs +++ b/uefi/src/proto/debug/mod.rs @@ -11,8 +11,8 @@ use core::ffi::c_void; -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; // re-export for ease of use pub use self::context::SystemContext; @@ -30,8 +30,7 @@ mod exception; /// /// NOTE: OVMF only implements this protocol interface for the virtual EBC processor #[repr(C)] -#[unsafe_guid("2755590c-6f3c-42fa-9ea4-a3ba543cda25")] -#[derive(Protocol)] +#[unsafe_protocol("2755590c-6f3c-42fa-9ea4-a3ba543cda25")] pub struct DebugSupport { isa: ProcessorArch, get_maximum_processor_index: diff --git a/uefi/src/proto/device_path/mod.rs b/uefi/src/proto/device_path/mod.rs index e60cd916e..4fc863356 100644 --- a/uefi/src/proto/device_path/mod.rs +++ b/uefi/src/proto/device_path/mod.rs @@ -69,6 +69,7 @@ //! //! [`END_ENTIRE`]: DeviceSubType::END_ENTIRE //! [`END_INSTANCE`]: DeviceSubType::END_INSTANCE +//! [`Protocol`]: crate::proto::Protocol //! [`device_type`]: DevicePathNode::device_type //! [`sub_type`]: DevicePathNode::sub_type @@ -80,8 +81,7 @@ pub use device_path_gen::{ acpi, bios_boot_spec, end, hardware, media, messaging, DevicePathNodeEnum, }; -use crate::proto::{Protocol, ProtocolPointer}; -use crate::unsafe_guid; +use crate::proto::{unsafe_protocol, ProtocolPointer}; use core::ffi::c_void; use core::marker::{PhantomData, PhantomPinned}; use core::{mem, ptr}; @@ -225,8 +225,8 @@ impl DevicePathInstance { /// [module-level documentation]: crate::proto::device_path /// [`END_ENTIRE`]: DeviceSubType::END_ENTIRE #[repr(C, packed)] -#[unsafe_guid("09576e91-6d3f-11d2-8e39-00a0c969723b")] -#[derive(Debug, Eq, PartialEq, Protocol)] +#[unsafe_protocol("09576e91-6d3f-11d2-8e39-00a0c969723b")] +#[derive(Debug, Eq, PartialEq)] pub struct DevicePath { data: [u8], } diff --git a/uefi/src/proto/device_path/text.rs b/uefi/src/proto/device_path/text.rs index 42c8408ca..5cfdc8e36 100644 --- a/uefi/src/proto/device_path/text.rs +++ b/uefi/src/proto/device_path/text.rs @@ -10,9 +10,9 @@ use crate::{ proto::device_path::{DevicePath, DevicePathNode, FfiDevicePath}, - proto::Protocol, + proto::unsafe_protocol, table::boot::BootServices, - unsafe_guid, CStr16, Char16, Result, Status, + CStr16, Char16, Result, Status, }; use core::ops::Deref; @@ -82,8 +82,7 @@ impl Drop for PoolString<'_> { /// This protocol provides common utility functions for converting device /// nodes and device paths to a text representation. #[repr(C)] -#[unsafe_guid("8b843e20-8132-4852-90cc-551a4e4a7f1c")] -#[derive(Protocol)] +#[unsafe_protocol("8b843e20-8132-4852-90cc-551a4e4a7f1c")] pub struct DevicePathToText { convert_device_node_to_text: unsafe extern "efiapi" fn( device_node: *const FfiDevicePath, @@ -150,8 +149,7 @@ impl DevicePathToText { /// This protocol provides common utilities for converting text to /// device paths and device nodes. #[repr(C)] -#[unsafe_guid("05c99a21-c70f-4ad2-8a5f-35df3343f51e")] -#[derive(Protocol)] +#[unsafe_protocol("05c99a21-c70f-4ad2-8a5f-35df3343f51e")] pub struct DevicePathFromText { convert_text_to_device_node: unsafe extern "efiapi" fn(text_device_node: *const Char16) -> *const FfiDevicePath, diff --git a/uefi/src/proto/loaded_image.rs b/uefi/src/proto/loaded_image.rs index b659c04c1..ff820a184 100644 --- a/uefi/src/proto/loaded_image.rs +++ b/uefi/src/proto/loaded_image.rs @@ -3,16 +3,15 @@ use crate::{ data_types::FromSliceWithNulError, proto::device_path::{DevicePath, FfiDevicePath}, - proto::Protocol, + proto::unsafe_protocol, table::boot::MemoryType, - unsafe_guid, CStr16, Handle, Status, + CStr16, Handle, Status, }; use core::{ffi::c_void, mem, slice}; /// The LoadedImage protocol. This can be opened on any image handle using the `HandleProtocol` boot service. #[repr(C)] -#[unsafe_guid("5b1b31a1-9562-11d2-8e3f-00a0c969723b")] -#[derive(Protocol)] +#[unsafe_protocol("5b1b31a1-9562-11d2-8e3f-00a0c969723b")] pub struct LoadedImage { revision: u32, parent_handle: Handle, diff --git a/uefi/src/proto/media/block.rs b/uefi/src/proto/media/block.rs index 6861699fe..4d90deaa3 100644 --- a/uefi/src/proto/media/block.rs +++ b/uefi/src/proto/media/block.rs @@ -1,12 +1,11 @@ //! Block I/O protocols. -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; /// The Block I/O protocol. #[repr(C)] -#[unsafe_guid("964e5b21-6459-11d2-8e39-00a0c969723b")] -#[derive(Protocol)] +#[unsafe_protocol("964e5b21-6459-11d2-8e39-00a0c969723b")] pub struct BlockIO { revision: u64, media: *const BlockIOMedia, diff --git a/uefi/src/proto/media/disk.rs b/uefi/src/proto/media/disk.rs index 56e54b6ef..8d0562f33 100644 --- a/uefi/src/proto/media/disk.rs +++ b/uefi/src/proto/media/disk.rs @@ -1,7 +1,7 @@ //! Disk I/O protocols. -use crate::proto::Protocol; -use crate::{unsafe_guid, Event, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Event, Result, Status}; use core::ptr::NonNull; /// The disk I/O protocol. @@ -11,8 +11,7 @@ use core::ptr::NonNull; /// reponsible for adding this protocol to any block I/O interface that /// appears in the system that does not already have a disk I/O protocol. #[repr(C)] -#[unsafe_guid("ce345171-ba0b-11d2-8e4f-00a0c969723b")] -#[derive(Protocol)] +#[unsafe_protocol("ce345171-ba0b-11d2-8e4f-00a0c969723b")] pub struct DiskIo { revision: u64, read_disk: extern "efiapi" fn( @@ -84,8 +83,7 @@ pub struct DiskIo2Token { /// This protocol provides an extension to the disk I/O protocol to enable /// non-blocking / asynchronous byte-oriented disk operation. #[repr(C)] -#[unsafe_guid("151c8eae-7f2c-472c-9e54-9828194f6a88")] -#[derive(Protocol)] +#[unsafe_protocol("151c8eae-7f2c-472c-9e54-9828194f6a88")] pub struct DiskIo2 { revision: u64, cancel: extern "efiapi" fn(this: &mut DiskIo2) -> Status, diff --git a/uefi/src/proto/media/file/info.rs b/uefi/src/proto/media/file/info.rs index afe021273..b49bc2942 100644 --- a/uefi/src/proto/media/file/info.rs +++ b/uefi/src/proto/media/file/info.rs @@ -1,7 +1,7 @@ use super::FileAttribute; use crate::data_types::Align; use crate::table::runtime::Time; -use crate::{unsafe_guid, CStr16, Char16, Identify}; +use crate::{guid, CStr16, Char16, Guid, Identify}; use core::ffi::c_void; use core::{mem, ptr}; @@ -142,7 +142,6 @@ pub enum FileInfoCreationError { /// attribute. Other changes must be carried out in a separate transaction. #[derive(Debug, Eq, PartialEq)] #[repr(C)] -#[unsafe_guid("09576e92-6d3f-11d2-8e39-00a0c969723b")] pub struct FileInfo { size: u64, file_size: u64, @@ -237,6 +236,10 @@ impl Align for FileInfo { } } +unsafe impl Identify for FileInfo { + const GUID: Guid = guid!("09576e92-6d3f-11d2-8e39-00a0c969723b"); +} + impl InfoInternal for FileInfo { fn name_offset() -> usize { 80 @@ -253,7 +256,6 @@ impl FileProtocolInfo for FileInfo {} /// this information structure. Consider using `FileSystemVolumeLabel` instead. #[derive(Debug, Eq, PartialEq)] #[repr(C)] -#[unsafe_guid("09576e93-6d3f-11d2-8e39-00a0c969723b")] pub struct FileSystemInfo { size: u64, read_only: bool, @@ -329,6 +331,10 @@ impl Align for FileSystemInfo { } } +unsafe impl Identify for FileSystemInfo { + const GUID: Guid = guid!("09576e93-6d3f-11d2-8e39-00a0c969723b"); +} + impl InfoInternal for FileSystemInfo { fn name_offset() -> usize { 36 @@ -342,7 +348,6 @@ impl FileProtocolInfo for FileSystemInfo {} /// May only be obtained on the root directory's file handle. #[derive(Debug, Eq, PartialEq)] #[repr(C)] -#[unsafe_guid("db47d7d3-fe81-11d3-9a35-0090273fc14d")] pub struct FileSystemVolumeLabel { volume_label: [Char16], } @@ -377,6 +382,10 @@ impl Align for FileSystemVolumeLabel { } } +unsafe impl Identify for FileSystemVolumeLabel { + const GUID: Guid = guid!("db47d7d3-fe81-11d3-9a35-0090273fc14d"); +} + impl InfoInternal for FileSystemVolumeLabel { fn name_offset() -> usize { 0 diff --git a/uefi/src/proto/media/fs.rs b/uefi/src/proto/media/fs.rs index 32df63da3..c016388c7 100644 --- a/uefi/src/proto/media/fs.rs +++ b/uefi/src/proto/media/fs.rs @@ -1,8 +1,8 @@ //! File system support protocols. use super::file::{Directory, FileHandle, FileImpl}; -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; use core::ptr; /// Allows access to a FAT-12/16/32 file system. @@ -20,8 +20,7 @@ use core::ptr; /// [`BootServices::get_image_file_system`]: crate::table::boot::BootServices::get_image_file_system /// [`BootServices`]: crate::table::boot::BootServices#accessing-protocols #[repr(C)] -#[unsafe_guid("964e5b22-6459-11d2-8e39-00a0c969723b")] -#[derive(Protocol)] +#[unsafe_protocol("964e5b22-6459-11d2-8e39-00a0c969723b")] pub struct SimpleFileSystem { revision: u64, open_volume: diff --git a/uefi/src/proto/media/partition.rs b/uefi/src/proto/media/partition.rs index 7243decd7..b2e353ee7 100644 --- a/uefi/src/proto/media/partition.rs +++ b/uefi/src/proto/media/partition.rs @@ -1,7 +1,7 @@ //! Partition information protocol. -use crate::proto::Protocol; -use crate::{guid, unsafe_guid, Char16, Guid}; +use crate::proto::unsafe_protocol; +use crate::{guid, Char16, Guid}; use bitflags::bitflags; newtype_enum! { @@ -175,8 +175,7 @@ newtype_enum! { /// Protocol for accessing partition information. #[repr(C)] #[repr(packed)] -#[unsafe_guid("8cf2f62c-bc9b-4821-808d-ec9ec421a1a0")] -#[derive(Clone, Copy, Protocol)] +#[unsafe_protocol("8cf2f62c-bc9b-4821-808d-ec9ec421a1a0")] pub struct PartitionInfo { /// Revision of the partition info protocol. pub revision: PartitionInfoRevision, diff --git a/uefi/src/proto/mod.rs b/uefi/src/proto/mod.rs index 6984150ff..51f69b783 100644 --- a/uefi/src/proto/mod.rs +++ b/uefi/src/proto/mod.rs @@ -12,19 +12,23 @@ use crate::Identify; use core::ffi::c_void; -/// Common trait implemented by all standard UEFI protocols +/// Common trait implemented by all standard UEFI protocols. /// /// According to the UEFI's specification, protocols are `!Send` (they expect to /// be run on the bootstrap processor) and `!Sync` (they are not thread-safe). -/// You can derive the `Protocol` trait, add these bounds and specify the -/// protocol's GUID using the following syntax: +/// You can derive the `Protocol` trait, add these bounds, and specify the +/// protocol's GUID using the [`unsafe_protocol`] macro. +/// +/// # Example /// /// ``` -/// #![feature(negative_impls)] -/// use uefi::{proto::Protocol, unsafe_guid}; -/// #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")] -/// #[derive(Protocol)] -/// struct DummyProtocol {} +/// use uefi::{Identify, guid}; +/// use uefi::proto::unsafe_protocol; +/// +/// #[unsafe_protocol("12345678-9abc-def0-1234-56789abcdef0")] +/// struct ExampleProtocol {} +/// +/// assert_eq!(ExampleProtocol::GUID, guid!("12345678-9abc-def0-1234-56789abcdef0")); /// ``` pub trait Protocol: Identify {} @@ -62,7 +66,7 @@ where } } -pub use uefi_macros::Protocol; +pub use uefi_macros::unsafe_protocol; pub mod console; pub mod debug; diff --git a/uefi/src/proto/network/pxe.rs b/uefi/src/proto/network/pxe.rs index 7acd5a2e8..b13757439 100644 --- a/uefi/src/proto/network/pxe.rs +++ b/uefi/src/proto/network/pxe.rs @@ -6,8 +6,8 @@ use core::{ ptr::{null, null_mut}, }; +use crate::proto::unsafe_protocol; use bitflags::bitflags; -use uefi_macros::{unsafe_guid, Protocol}; use crate::{CStr8, Char8, Result, Status}; @@ -15,8 +15,7 @@ use super::{IpAddress, MacAddress}; /// PXE Base Code protocol #[repr(C)] -#[unsafe_guid("03c4e603-ac28-11d3-9a2d-0090273fc14d")] -#[derive(Protocol)] +#[unsafe_protocol("03c4e603-ac28-11d3-9a2d-0090273fc14d")] #[allow(clippy::type_complexity)] pub struct BaseCode { revision: u64, diff --git a/uefi/src/proto/network/snp.rs b/uefi/src/proto/network/snp.rs index 6554455c3..8f55c0cb4 100644 --- a/uefi/src/proto/network/snp.rs +++ b/uefi/src/proto/network/snp.rs @@ -14,12 +14,11 @@ use bitflags::bitflags; use core::ffi::c_void; use core::ptr; use core::ptr::NonNull; -use uefi_macros::{unsafe_guid, Protocol}; +use uefi_macros::unsafe_protocol; /// The Simple Network Protocol #[repr(C)] -#[unsafe_guid("a19832b9-ac25-11d3-9a2d-0090273fc14d")] -#[derive(Protocol)] +#[unsafe_protocol("a19832b9-ac25-11d3-9a2d-0090273fc14d")] pub struct SimpleNetwork { revision: u64, start: extern "efiapi" fn(this: &Self) -> Status, diff --git a/uefi/src/proto/pi/mp.rs b/uefi/src/proto/pi/mp.rs index 52b5b5fb6..b450d2c22 100644 --- a/uefi/src/proto/pi/mp.rs +++ b/uefi/src/proto/pi/mp.rs @@ -11,8 +11,8 @@ //! * dispatching user-provided function to APs //! * maintaining MP-related processor status -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; use bitflags::bitflags; use core::ffi::c_void; use core::ptr; @@ -93,8 +93,7 @@ pub struct CpuPhysicalLocation { /// Protocol that provides services needed for multi-processor management. #[repr(C)] -#[unsafe_guid("3fdda605-a76e-4f46-ad29-12f4531b3d08")] -#[derive(Protocol)] +#[unsafe_protocol("3fdda605-a76e-4f46-ad29-12f4531b3d08")] pub struct MpServices { get_number_of_processors: extern "efiapi" fn( this: *const MpServices, diff --git a/uefi/src/proto/rng.rs b/uefi/src/proto/rng.rs index cc3363cf0..6ab53f9c4 100644 --- a/uefi/src/proto/rng.rs +++ b/uefi/src/proto/rng.rs @@ -1,6 +1,6 @@ //! `Rng` protocol. -use crate::{data_types::Guid, guid, proto::Protocol, unsafe_guid, Result, Status}; +use crate::{data_types::Guid, guid, proto::unsafe_protocol, Result, Status}; use core::{mem, ptr}; newtype_enum! { @@ -35,8 +35,7 @@ newtype_enum! { /// Rng protocol #[repr(C)] -#[unsafe_guid("3152bca5-eade-433d-862e-c01cdc291f44")] -#[derive(Protocol)] +#[unsafe_protocol("3152bca5-eade-433d-862e-c01cdc291f44")] pub struct Rng { get_info: unsafe extern "efiapi" fn( this: &Rng, diff --git a/uefi/src/proto/security/memory_protection.rs b/uefi/src/proto/security/memory_protection.rs index 0f548fc6c..38c229547 100644 --- a/uefi/src/proto/security/memory_protection.rs +++ b/uefi/src/proto/security/memory_protection.rs @@ -1,7 +1,7 @@ use crate::data_types::PhysicalAddress; -use crate::proto::Protocol; +use crate::proto::unsafe_protocol; use crate::table::boot::MemoryAttribute; -use crate::{unsafe_guid, Result, Status}; +use crate::{Result, Status}; use core::ops::Range; /// Protocol for getting and setting memory protection attributes. @@ -10,8 +10,7 @@ use core::ops::Range; /// /// [proposal]: https://bugzilla.tianocore.org/show_bug.cgi?id=3519 #[repr(C)] -#[unsafe_guid("f4560cf6-40ec-4b4a-a192-bf1d57d0b189")] -#[derive(Protocol)] +#[unsafe_protocol("f4560cf6-40ec-4b4a-a192-bf1d57d0b189")] pub struct MemoryProtection { get_memory_attributes: unsafe extern "efiapi" fn( this: *const Self, diff --git a/uefi/src/proto/shim/mod.rs b/uefi/src/proto/shim/mod.rs index c2a52b604..7dac6853a 100644 --- a/uefi/src/proto/shim/mod.rs +++ b/uefi/src/proto/shim/mod.rs @@ -7,9 +7,9 @@ target_arch = "aarch64" ))] -use crate::proto::Protocol; +use crate::proto::unsafe_protocol; use crate::result::Error; -use crate::{unsafe_guid, Result, Status}; +use crate::{Result, Status}; use core::ffi::c_void; use core::mem::MaybeUninit; @@ -65,8 +65,7 @@ macro_rules! shim_function { /// another EFI application before running it, and the shim lock /// protocol exists to support that. #[repr(C)] -#[unsafe_guid("605dab50-e046-4300-abb6-3dd810dd8b23")] -#[derive(Protocol)] +#[unsafe_protocol("605dab50-e046-4300-abb6-3dd810dd8b23")] pub struct ShimLock { verify: shim_function! { fn(buffer: *const u8, size: u32) -> Status }, hash: shim_function! { diff --git a/uefi/src/proto/string/unicode_collation.rs b/uefi/src/proto/string/unicode_collation.rs index 0bce35750..78866cdc8 100644 --- a/uefi/src/proto/string/unicode_collation.rs +++ b/uefi/src/proto/string/unicode_collation.rs @@ -3,16 +3,15 @@ //! This protocol is used in the boot services environment to perform //! lexical comparison functions on Unicode strings for given languages. +use crate::proto::unsafe_protocol; use core::cmp::Ordering; use uefi::data_types::{CStr16, CStr8, Char16, Char8}; -use uefi_macros::{unsafe_guid, Protocol}; /// The Unicode Collation Protocol. /// /// Used to perform case-insensitive comaprisons of strings. #[repr(C)] -#[unsafe_guid("a4c751fc-23ae-4c3e-92e9-4964cf63f349")] -#[derive(Protocol)] +#[unsafe_protocol("a4c751fc-23ae-4c3e-92e9-4964cf63f349")] pub struct UnicodeCollation { stri_coll: extern "efiapi" fn(this: &Self, s1: *const Char16, s2: *const Char16) -> isize, metai_match: diff --git a/uefi/src/proto/tcg/v1.rs b/uefi/src/proto/tcg/v1.rs index 055b7efd9..0ab59ac14 100644 --- a/uefi/src/proto/tcg/v1.rs +++ b/uefi/src/proto/tcg/v1.rs @@ -10,8 +10,8 @@ use super::{usize_from_u32, EventType, HashAlgorithm, PcrIndex}; use crate::data_types::PhysicalAddress; -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; use core::fmt::{self, Debug, Formatter}; use core::marker::PhantomData; use core::{mem, ptr}; @@ -249,8 +249,7 @@ impl<'a> Iterator for EventLogIter<'a> { /// /// The corresponding C type is `EFI_TCG_PROTOCOL`. #[repr(C)] -#[unsafe_guid("f541796d-a62e-4954-a775-9584f61b9cdd")] -#[derive(Protocol)] +#[unsafe_protocol("f541796d-a62e-4954-a775-9584f61b9cdd")] pub struct Tcg { status_check: unsafe extern "efiapi" fn( this: *mut Tcg, diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index cc199818e..f44c65a33 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -11,8 +11,8 @@ //! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module use super::HashAlgorithm; -use crate::proto::Protocol; -use crate::{unsafe_guid, Result, Status}; +use crate::proto::unsafe_protocol; +use crate::{Result, Status}; use bitflags::bitflags; use core::mem; @@ -124,8 +124,7 @@ impl BootServiceCapability { /// /// The corresponding C type is `EFI_TCG2_PROTOCOL`. #[repr(C)] -#[unsafe_guid("607f766c-7455-42be-930b-e4d76db2720f")] -#[derive(Protocol)] +#[unsafe_protocol("607f766c-7455-42be-930b-e4d76db2720f")] pub struct Tcg { get_capability: unsafe extern "efiapi" fn( this: *mut Tcg,