Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fd9c4ea

Browse files
Procedural macros to derive Identify and Protocol (#77)
* Order workspace members properly * Implement custom derives for Protocol and Identify * Move unsafe_guid to MetaNameValue syntax * Avoid legacy macro_use statement * Make unsafe_guid an attribute macro * Apply cargo fmt * Clean up docs * Use a more appropriate identity for this hobby project * Rename uefi-derive to uefi-macros to reflect its new content * Clean up documentation
1 parent 9ae552c commit fd9c4ea

File tree

23 files changed

+364
-263
lines changed

23 files changed

+364
-263
lines changed

‎Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ edition = "2018"
1010
bitflags = "1"
1111
log = { version = "0.4", default-features = false }
1212
ucs2 = "0.1"
13+
uefi-macros = { path = "uefi-macros" }
1314

1415
[workspace]
1516
members = [
16-
"uefi-test-runner",
17-
"uefi-logger",
1817
"uefi-alloc",
19-
"uefi-services",
2018
"uefi-exts",
19+
"uefi-logger",
20+
"uefi-macros",
21+
"uefi-services",
22+
"uefi-test-runner",
2123
]
2224

2325
[profile.dev]

‎src/data_types/guid.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use core::fmt;
22

3-
/// A globally unique identifier.
3+
/// A globally unique identifier
44
///
5-
/// GUIDs are used by to identify protocols and other objects.
5+
/// GUIDs are used by UEFI to identify protocols and other objects. They are
6+
/// mostly like variant 2 UUIDs as specified by RFC 4122, but differ from them
7+
/// in that the first 3 fields are little endian instead of big endian.
68
///
7-
/// The difference from regular UUIDs is that the first 3 fields are
8-
/// always encoded as little endian.
9-
///
10-
/// The `Display` formatter prints GUIDs in the UEFI-defined format:
11-
/// `aabbccdd-eeff-gghh-iijj-kkllmmnnoopp`
9+
/// The `Display` formatter prints GUIDs in the canonical format defined by
10+
/// RFC 4122, which is also used by UEFI.
1211
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1312
#[repr(C)]
1413
pub struct Guid {
@@ -18,17 +17,43 @@ pub struct Guid {
1817
b: u16,
1918
/// The high field of the timestamp multiplexed with the version number.
2019
c: u16,
21-
/// Contains:
20+
/// Contains, in this order:
2221
/// - The high field of the clock sequence multiplexed with the variant.
2322
/// - The low field of the clock sequence.
24-
/// - Spatially unique node identifier.
23+
/// - The spatially unique node identifier.
2524
d: [u8; 8],
2625
}
2726

2827
impl Guid {
29-
/// Creates a new GUID from its component values.
30-
pub const fn from_values(a: u32, b: u16, c: u16, d: [u8; 8]) -> Self {
31-
Guid { a, b, c, d }
28+
/// Creates a new GUID from its canonical representation
29+
//
30+
// FIXME: An unwieldy array of bytes must be used for the node ID until one
31+
// can assert that an u64 has its high 16-bits cleared in a const fn.
32+
// Once that is done, we can take an u64 to be even closer to the
33+
// canonical UUID/GUID format.
34+
//
35+
pub const fn from_values(
36+
time_low: u32,
37+
time_mid: u16,
38+
time_high_and_version: u16,
39+
clock_seq_and_variant: u16,
40+
node: [u8; 6],
41+
) -> Self {
42+
Guid {
43+
a: time_low,
44+
b: time_mid,
45+
c: time_high_and_version,
46+
d: [
47+
(clock_seq_and_variant / 0x100) as u8,
48+
(clock_seq_and_variant % 0x100) as u8,
49+
node[0],
50+
node[1],
51+
node[2],
52+
node[3],
53+
node[4],
54+
node[5],
55+
],
56+
}
3257
}
3358
}
3459

@@ -59,10 +84,25 @@ impl fmt::Display for Guid {
5984
/// Several entities in the UEFI specification can be referred to by their GUID,
6085
/// this trait is a building block to interface them in uefi-rs.
6186
///
62-
/// Implementing it is unsafe, because attaching an incorrect GUID to a type can
63-
/// lead to type unsafety on both the Rust and UEFI side.
87+
/// You should never need to use the `Identify` trait directly, but instead go
88+
/// for more specific traits such as `Protocol` or `FileProtocolInfo`, which
89+
/// indicate in which circumstances an `Identify`-tagged type should be used.
90+
///
91+
/// Implementing `Identify` is unsafe because attaching an incorrect GUID to a
92+
/// type can lead to type unsafety on both the Rust and UEFI side.
6493
///
94+
/// You can derive `Identify` for a type using the `unsafe_guid` procedural
95+
/// macro, which is exported by this module. This macro mostly works like a
96+
/// custom derive, but also supports type aliases. It takes a GUID in canonical
97+
/// textual format as an argument, and is used in the following way:
98+
///
99+
/// ```
100+
/// #[unsafe_guid("12345678-9abc-def0-1234-56789abcdef0")]
101+
/// type Emptiness = ();
102+
/// ```
65103
pub unsafe trait Identify {
66104
/// Unique protocol identifier.
67105
const GUID: Guid;
68106
}
107+
108+
pub use uefi_macros::unsafe_guid;

‎src/data_types/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ pub struct Handle(*mut c_void);
1515
pub struct Event(*mut c_void);
1616

1717
mod guid;
18-
pub use self::guid::{Guid, Identify};
18+
pub use self::guid::Guid;
19+
pub(crate) use self::guid::{unsafe_guid, Identify};
1920

2021
pub mod chars;
2122
pub use self::chars::{Char16, Char8};

‎src/data_types/strs.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ pub enum FromSliceWithNulError {
1717

1818
/// A Latin-1 null-terminated string
1919
///
20-
/// This type is largely inspired by std::ffi::CStr, see documentation of CStr
21-
/// for more details on its semantics.
22-
///
20+
/// This type is largely inspired by `std::ffi::CStr`, see the documentation of
21+
/// `CStr` for more details on its semantics.
2322
#[repr(transparent)]
2423
pub struct CStr8([Char8]);
2524

@@ -71,9 +70,8 @@ impl CStr8 {
7170

7271
/// An UCS-2 null-terminated string
7372
///
74-
/// This type is largely inspired by std::ffi::CStr, see documentation of CStr
75-
/// for more details on its semantics.
76-
///
73+
/// This type is largely inspired by `std::ffi::CStr`, see the documentation of
74+
/// `CStr` for more details on its semantics.
7775
#[repr(transparent)]
7876
pub struct CStr16([Char16]);
7977

‎src/error/completion.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ impl<T> Completion<T> {
6363
///
6464
/// Since this type only has storage for one warning, if two warnings must
6565
/// be stored, one of them will be spilled into the logs.
66-
///
6766
pub fn with_status(self, extra_status: Status) -> Self {
6867
if extra_status.is_success() {
6968
self

‎src/error/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
mod status;
33
pub use self::status::Status;
44

5-
/// Completions are used to model operations which have completed, but may have
6-
/// encountered non-fatal errors ("warnings") along the way
5+
/// `Completion`s are used to model operations which have completed, but may
6+
/// have encountered non-fatal errors ("warnings") along the way
77
mod completion;
88
pub use self::completion::Completion;
99

‎src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333

3434
#[macro_use]
3535
pub mod data_types;
36-
pub use self::data_types::{CStr16, CStr8, Char16, Char8, Event, Guid, Handle, Identify};
36+
pub(crate) use self::data_types::{unsafe_guid, Identify};
37+
pub use self::data_types::{CStr16, CStr8, Char16, Char8, Event, Guid, Handle};
3738

3839
mod error;
3940
pub use self::error::{Completion, Result, ResultExt, Status};

‎src/proto/console/gop.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Graphics output protocol.
22
//!
33
//! The UEFI GOP is meant to replace existing VGA hardware.
4-
//! It can be used in the boot environment as well at runtime,
4+
//! It can be used in the boot environment as well as at runtime,
55
//! until a high-performance driver is loaded by the OS.
66
//!
77
//! The GOP provides access to a hardware frame buffer and allows UEFI apps
@@ -23,7 +23,8 @@
2323
//! In theory, a buffer with a width of 640 should have (640 * 4) bytes per row,
2424
//! but in practice there might be some extra padding used for efficiency.
2525
26-
use crate::{Completion, Result, Status};
26+
use crate::proto::Protocol;
27+
use crate::{unsafe_guid, Completion, Result, Status};
2728
use core::marker::PhantomData;
2829
use core::mem;
2930
use core::ptr;
@@ -33,6 +34,8 @@ use core::ptr;
3334
/// The GOP can be used to set the properties of the frame buffer,
3435
/// and also allows the app to access the in-memory buffer.
3536
#[repr(C)]
37+
#[unsafe_guid("9042a9de-23dc-4a38-96fb-7aded080516a")]
38+
#[derive(Protocol)]
3639
pub struct GraphicsOutput<'boot> {
3740
query_mode: extern "win64" fn(
3841
&GraphicsOutput,
@@ -87,7 +90,7 @@ impl<'boot> GraphicsOutput<'boot> {
8790
/// Sets the video device into the specified mode, clearing visible portions
8891
/// of the output display to black.
8992
///
90-
/// This function **will** invalidate the current framebuffer and change the current mode.
93+
/// This function will invalidate the current framebuffer.
9194
pub fn set_mode(&mut self, mode: &Mode) -> Result<()> {
9295
(self.set_mode)(self, mode.index).into()
9396
}
@@ -282,12 +285,6 @@ impl<'boot> GraphicsOutput<'boot> {
282285
}
283286
}
284287

285-
impl_proto! {
286-
protocol GraphicsOutput<'boot> {
287-
GUID = 0x9042a9de, 0x23dc, 0x4a38, [0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a];
288-
}
289-
}
290-
291288
#[repr(C)]
292289
struct ModeData<'a> {
293290
// Number of modes which the GOP supports.

‎src/proto/console/pointer/mod.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
//! Pointer device access.
22
3-
use crate::{Event, Result, Status};
3+
use crate::proto::Protocol;
4+
use crate::{unsafe_guid, Event, Result, Status};
45
use core::mem;
56

67
/// Provides information about a pointer device.
78
#[repr(C)]
9+
#[unsafe_guid("31878c87-0b75-11d5-9a4f-0090273fc14d")]
10+
#[derive(Protocol)]
811
pub struct Pointer<'boot> {
912
reset: extern "win64" fn(this: &mut Pointer, ext_verif: bool) -> Status,
1013
get_state: extern "win64" fn(this: &Pointer, state: &mut PointerState) -> Status,
@@ -28,7 +31,7 @@ impl<'boot> Pointer<'boot> {
2831
/// Retrieves the pointer device's current state, if a state change occured
2932
/// since the last time this function was called.
3033
///
31-
/// Use wait_for_input_event() with the BootServices::wait_for_event()
34+
/// Use `wait_for_input_event()` with the `BootServices::wait_for_event()`
3235
/// interface in order to wait for input from the pointer device.
3336
///
3437
/// # Errors
@@ -42,8 +45,8 @@ impl<'boot> Pointer<'boot> {
4245
}
4346
}
4447

45-
/// Event to use with BootServices::wait_for_event() to wait for input from
46-
/// the pointer device
48+
/// Event to be used with `BootServices::wait_for_event()` in order to wait
49+
/// for input from the pointer device
4750
pub fn wait_for_input_event(&self) -> Event {
4851
self.wait_for_input
4952
}
@@ -54,12 +57,6 @@ impl<'boot> Pointer<'boot> {
5457
}
5558
}
5659

57-
impl_proto! {
58-
protocol Pointer<'boot> {
59-
GUID = 0x31878c87, 0xb75, 0x11d5, [0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d];
60-
}
61-
}
62-
6360
/// Information about this pointer device.
6461
#[derive(Debug, Copy, Clone)]
6562
#[repr(C)]

‎src/proto/console/serial.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Abstraction over byte stream devices, also known as serial I/O devices.
22
3-
use crate::{Completion, Result, Status};
3+
use crate::proto::Protocol;
4+
use crate::{unsafe_guid, Completion, Result, Status};
45
use bitflags::bitflags;
56

67
/// Provides access to a serial I/O device.
@@ -11,6 +12,8 @@ use bitflags::bitflags;
1112
/// Since UEFI drivers are implemented through polling, if you fail to regularly
1213
/// check for input/output, some data might be lost.
1314
#[repr(C)]
15+
#[unsafe_guid("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd")]
16+
#[derive(Protocol)]
1417
pub struct Serial<'boot> {
1518
// Revision of this protocol, only 1.0 is currently defined.
1619
// Future versions will be backwards compatible.
@@ -116,12 +119,6 @@ impl<'boot> Serial<'boot> {
116119
}
117120
}
118121

119-
impl_proto! {
120-
protocol Serial<'boot> {
121-
GUID = 0xBB25CF6F, 0xF1D4, 0x11D2, [0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD];
122-
}
123-
}
124-
125122
/// Structure representing the device's current parameters.
126123
///
127124
/// The default values for all UART-like devices is:

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /