Skip to content

Commit 6e95b16

Browse files
committed
uefi: Add TryFrom u8 slice to DevicePathNode
Adds the capability to convert a byte slice to a DevicePathNode. This will be used to convert a byte slice to a DevicePath in a followup PR, which allows easier interaction with the data returned from UEFI variable services.
1 parent a70ccab commit 6e95b16

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

uefi/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Added `table::{set_system_table, system_table_boot, system_table_runtime}`.
1212
This provides an initial API for global tables that do not require passing
1313
around a reference.
14+
- Added `TryFrom<&[u8]>` for `DevicePathNode`.
1415

1516
## Changed
1617
- `SystemTable::exit_boot_services` is now `unsafe`. See that method's

uefi/src/proto/device_path/mod.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,24 @@ impl PartialEq for DevicePathNode {
253253
}
254254
}
255255

256+
impl<'a> TryFrom<&[u8]> for &'a DevicePathNode {
257+
type Error = ByteConversionError;
258+
259+
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
260+
if mem::size_of::<DevicePathHeader>() <= bytes.len() {
261+
let dp: &DevicePathHeader;
262+
unsafe {
263+
dp = DevicePathHeader::from_ffi_ptr(bytes.as_ptr().cast());
264+
265+
if dp.length as usize <= bytes.len() {
266+
return Ok(DevicePathNode::from_ffi_ptr(bytes.as_ptr().cast()));
267+
}
268+
}
269+
}
270+
Err(ByteConversionError::InvalidLength)
271+
}
272+
}
273+
256274
/// A single device path instance that ends with either an [`END_INSTANCE`]
257275
/// or [`END_ENTIRE`] node. Use [`DevicePath::instance_iter`] to get the
258276
/// path instances in a [`DevicePath`].
@@ -729,6 +747,15 @@ impl DeviceSubType {
729747
pub const END_ENTIRE: DeviceSubType = DeviceSubType(0xff);
730748
}
731749

750+
/// Error returned when attempting to convert from a `&[u8]` to a
751+
/// [`DevicePath`] type using:
752+
/// - [`DevicePathNode::try_from`](struct.DevicePathNode.html#method.try_from)
753+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
754+
pub enum ByteConversionError {
755+
/// The length of the given slice is not valid for its [`DevicePath`] type.
756+
InvalidLength,
757+
}
758+
732759
/// Error returned when converting from a [`DevicePathNode`] to a more
733760
/// specific node type.
734761
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -954,4 +981,41 @@ mod tests {
954981
let owned_dp_ref = &*owned_dp;
955982
assert_eq!(owned_dp_ref, dp)
956983
}
984+
985+
#[test]
986+
fn test_device_path_from_bytes() {
987+
let mut raw_data = Vec::new();
988+
let node = [0xa0, 0xb0];
989+
let node_data = &[10, 11];
990+
let mut dp;
991+
992+
// Raw data is less than size of a [`DevicePathNode`].
993+
raw_data.push(node[0]);
994+
dp = <&DevicePathNode>::try_from(raw_data.as_slice());
995+
assert!(dp.is_err());
996+
997+
// Raw data is long enough to hold a [`DevicePathNode`].
998+
raw_data.push(node[1]);
999+
raw_data.extend(
1000+
u16::try_from(mem::size_of::<DevicePathHeader>() + node_data.len())
1001+
.unwrap()
1002+
.to_le_bytes(),
1003+
);
1004+
raw_data.extend(node_data);
1005+
dp = <&DevicePathNode>::try_from(raw_data.as_slice());
1006+
assert!(dp.is_ok());
1007+
1008+
// [`DevicePathNode`] data length exceeds the raw_data slice.
1009+
let mut raw_data = Vec::new();
1010+
raw_data.push(node[0]);
1011+
raw_data.push(node[1]);
1012+
raw_data.extend(
1013+
u16::try_from(mem::size_of::<DevicePathHeader>() + 1 + node_data.len())
1014+
.unwrap()
1015+
.to_le_bytes(),
1016+
);
1017+
raw_data.extend(node_data);
1018+
dp = <&DevicePathNode>::try_from(raw_data.as_slice());
1019+
assert!(dp.is_err());
1020+
}
9571021
}

0 commit comments

Comments
 (0)