Skip to content

Commit b953e6b

Browse files
committed
uefi-raw: serial: add new struct for revision 1.1
Having two structs helps to prevent UB on higher levels. Otherwise, one may create a reference to a struct whose actual allocation is smaller than expected by rust.
1 parent 4bae2a3 commit b953e6b

4 files changed

Lines changed: 67 additions & 4 deletions

File tree

uefi-raw/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
- Added `HiiPopupProtocol`.
1111
- Added `FormBrowser2Protocol`.
1212
- Added new type `SerialIoProtocolRevision`
13+
- Added new type `SerialIoProtocol_1_1` as companion for `SerialIoProtocol`
14+
that includes the `device_type_guid` parameter
1315

1416
## Changed
1517
- Switched `*const Self` to `*mut Self` in `SerialIoProtocol::set_attributes()`

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,19 @@ impl SerialIoProtocol {
114114
pub const GUID: Guid = guid!("bb25cf6f-f1d4-11d2-9a0c-0090273fc1fd");
115115
}
116116

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;
128+
}
129+
117130
newtype_enum! {
118131
/// The parity of the device.
119132
pub enum Parity: u32 => {

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 {

0 commit comments

Comments
 (0)