Skip to content

Commit cf7a4bb

Browse files
authored
Merge pull request #1873 from rust-osdev/uefi-raw-serial-revision
uefi-raw & uefi: serial: add support for protocol revision 1.1
2 parents cb474db + a44c4e4 commit cf7a4bb

6 files changed

Lines changed: 114 additions & 7 deletions

File tree

uefi-raw/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@
99
- Added `HiiStringProtocol`.
1010
- Added `HiiPopupProtocol`.
1111
- Added `FormBrowser2Protocol`.
12+
- Added new type `SerialIoProtocolRevision`
13+
- Added new type `SerialIoProtocol_1_1` as companion for `SerialIoProtocol`
14+
that includes the `device_type_guid` parameter
1215

1316
## Changed
1417
- Switched `*const Self` to `*mut Self` in `SerialIoProtocol::set_attributes()`
18+
- Switched field `revision` in `SerialIoProtocol` from `u32` to new type
19+
`SerialIoProtocolRevision`
1520

1621

1722
# uefi-raw - v0.13.0 (2025-11-05)

uefi-raw/src/protocol/console/serial.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,22 @@ pub struct SerialIoMode {
7777
pub stop_bits: StopBits,
7878
}
7979

80+
newtype_enum! {
81+
/// The revision of the [`SerialIoProtocol`].
82+
#[derive(Default)]
83+
pub enum SerialIoProtocolRevision: u32 => {
84+
/// Initial version 1.0.
85+
REVISION_1_0 = 0x00010000,
86+
/// Version 1.1.
87+
REVISION_1_1 = 0x00010001,
88+
}
89+
}
90+
91+
/// Serial I/O protocol (revision 1.0).
8092
#[derive(Debug)]
8193
#[repr(C)]
8294
pub struct SerialIoProtocol {
83-
pub revision: u32,
95+
pub revision: SerialIoProtocolRevision,
8496
pub reset: unsafe extern "efiapi" fn(*mut Self) -> Status,
8597
pub set_attributes: unsafe extern "efiapi" fn(
8698
*mut Self,
@@ -100,8 +112,19 @@ pub struct SerialIoProtocol {
100112

101113
impl SerialIoProtocol {
102114
pub const GUID: Guid = guid!("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd");
103-
pub const REVISION: u32 = 0x00010000;
104-
pub const REVISION1P1: u32 = 0x00010001;
115+
}
116+
117+
/// Serial I/O protocol (revision 1.1).
118+
#[derive(Debug)]
119+
#[repr(C)]
120+
#[allow(non_camel_case_types)]
121+
pub struct SerialIoProtocol_1_1 {
122+
pub base_protocol: SerialIoProtocol,
123+
pub device_type_guid: *const Guid,
124+
}
125+
126+
impl SerialIoProtocol_1_1 {
127+
pub const GUID: Guid = SerialIoProtocol::GUID;
105128
}
106129

107130
newtype_enum! {

uefi-test-runner/src/proto/console/serial.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,16 @@ pub unsafe fn test() {
5252
info!("Running serial protocol test");
5353
let handle = boot::get_handle_for_protocol::<Serial>().expect("missing Serial protocol");
5454

55+
// Note: After this line, until we reconnected the console driver with the
56+
// serial device, we won't get logging output on the serial device.
57+
// Log messages are still printed to the debugcon device.
5558
let mut serial =
5659
boot::open_protocol_exclusive::<Serial>(handle).expect("failed to open serial protocol");
60+
debug!("Serial protocol revision: {:?}", serial.revision());
61+
debug!(
62+
"Serial protocol device_type_guid: {:?}",
63+
serial.device_type_guid()
64+
);
5765

5866
// Send the request, but don't check the result yet so that first
5967
// we can reconnect the console output for the logger.

uefi/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Added `proto::device_path::DevicePath::to_pool()`.
1111
- Added `proto::device_path::DevicePathUtilities::duplicate_path()`.
1212
- Added `proto::pci::enumeration::PciTree::device_path()`.
13+
- Added `revision()` and `device_type_guid()` to `Serial` protocol
1314

1415
## Changed
1516
- export all `text::{input, output}::*` types

uefi/src/proto/console/serial.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
//! Abstraction over byte stream devices, also known as serial I/O devices.
44
5-
#[cfg(doc)]
6-
use crate::Status;
75
use crate::proto::unsafe_protocol;
8-
use crate::{Result, StatusExt};
6+
use crate::{Error, Result, Status, StatusExt};
97
use core::fmt::Write;
10-
use uefi_raw::protocol::console::serial::SerialIoProtocol;
8+
use uefi_raw::protocol::console::serial::{
9+
SerialIoProtocol, SerialIoProtocol_1_1, SerialIoProtocolRevision,
10+
};
11+
use uguid::Guid;
1112

1213
pub use uefi_raw::protocol::console::serial::{
1314
ControlBits, Parity, SerialIoMode as IoMode, StopBits,
@@ -52,6 +53,12 @@ pub use uefi_raw::protocol::console::serial::{
5253
pub struct Serial(SerialIoProtocol);
5354

5455
impl Serial {
56+
/// Returns the revision of the protocol.
57+
#[must_use]
58+
pub const fn revision(&self) -> SerialIoProtocolRevision {
59+
self.0.revision
60+
}
61+
5562
/// Reset the device.
5663
///
5764
/// # Errors
@@ -149,6 +156,46 @@ impl Serial {
149156
|_| buffer_size,
150157
)
151158
}
159+
160+
/// Pointer to a GUID identifying the device connected to the serial port.
161+
///
162+
/// This is either `Ok` if [`Self::revision`] is at least
163+
/// [`SerialIoProtocolRevision::REVISION_1_1`] or `Err` with
164+
/// [`Status::UNSUPPORTED`].
165+
///
166+
/// This GUID is `None` when the protocol is installed by the serial port
167+
/// driver and may be populated by a platform driver for a serial port with
168+
/// a known device attached. The GUID will remain `None` if there is no
169+
/// platform serial device identification information available.
170+
///
171+
/// # Errors
172+
///
173+
/// - [`Status::UNSUPPORTED`]: If the revision is older than
174+
/// [`SerialIoProtocolRevision::REVISION_1_1`].
175+
pub fn device_type_guid(&self) -> Result<Option<&'_ Guid>> {
176+
let proto = self.as_revision_1_1()?;
177+
// SAFETY: spec guarantees the layout of the underlying type
178+
let device_type_guid = unsafe { proto.device_type_guid.as_ref() };
179+
Ok(device_type_guid)
180+
}
181+
182+
/// Casts the underlying [`SerialIoProtocol`] to an
183+
/// [`SerialIoProtocol_1_1`].
184+
fn as_revision_1_1(&self) -> Result<&'_ SerialIoProtocol_1_1> {
185+
if self.revision() < SerialIoProtocolRevision::REVISION_1_1 {
186+
return Err(Error::from(Status::UNSUPPORTED));
187+
}
188+
189+
let ptr = &raw const self.0;
190+
// SAFETY: ptr is guaranteed to be not null and by checking the revision
191+
// we know the underlying allocation has the correct size.
192+
let protocol = unsafe {
193+
ptr.cast::<SerialIoProtocol_1_1>()
194+
.as_ref()
195+
.unwrap_unchecked()
196+
};
197+
Ok(protocol)
198+
}
152199
}
153200

154201
impl Write for Serial {

xtask/src/check_raw.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl From<&Item> for ItemKind {
4343
#[derive(Debug, Eq, PartialEq)]
4444
enum ErrorKind {
4545
ForbiddenAbi,
46+
ForbiddenAllow,
4647
ForbiddenAttr,
4748
ForbiddenItemKind(ItemKind),
4849
ForbiddenRepr(Vec<Repr>),
@@ -60,6 +61,7 @@ impl Display for ErrorKind {
6061
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
6162
match self {
6263
Self::ForbiddenAbi => write!(f, "forbidden ABI"),
64+
Self::ForbiddenAllow => write!(f, "forbidden allow"),
6365
Self::ForbiddenAttr => write!(f, "forbidden attribute"),
6466
Self::ForbiddenItemKind(ItemKind::Enum) => write!(
6567
f,
@@ -140,6 +142,12 @@ fn is_pub(vis: &Visibility) -> bool {
140142
matches!(vis, Visibility::Public(_))
141143
}
142144

145+
/// Allowed `#[allow]` attributes.
146+
#[derive(Debug, Clone, Copy)]
147+
enum Allow {
148+
NonCamelCaseTypes,
149+
}
150+
143151
/// Type repr. A type may have more than one of these (e.g. both `C` and `packed`).
144152
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
145153
enum Repr {
@@ -154,6 +162,7 @@ enum Repr {
154162
/// expected in `uefi-raw`.
155163
#[derive(Debug, Clone, Copy)]
156164
enum ParsedAttr {
165+
Allow(Allow),
157166
Derive,
158167
Doc,
159168
Repr(Repr),
@@ -195,6 +204,20 @@ fn parse_attrs(attrs: &[Attribute], src: &Path) -> Result<Vec<ParsedAttr>, Error
195204
if unknown_repr_found {
196205
return Err(Error::new(ErrorKind::UnknownRepr, src, attr));
197206
}
207+
} else if path.is_ident("allow") {
208+
let mut unknown_allow_found = false;
209+
attr.parse_nested_meta(|meta| {
210+
if meta.path.is_ident("non_camel_case_types") {
211+
va.push(ParsedAttr::Allow(Allow::NonCamelCaseTypes));
212+
} else {
213+
unknown_allow_found = true;
214+
}
215+
Ok(())
216+
})
217+
.map_err(|_| Error::new(ErrorKind::MalformedAttrs, src, attr))?;
218+
if unknown_allow_found {
219+
return Err(Error::new(ErrorKind::ForbiddenAllow, src, attr));
220+
}
198221
} else {
199222
return Err(Error::new(ErrorKind::ForbiddenAttr, src, attr));
200223
}

0 commit comments

Comments
 (0)