Skip to content

Commit aa29589

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 aa29589

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

uefi/CHANGELOG.md

+1
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

+55
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,23 @@ 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: &DevicePathNode;
262+
unsafe {
263+
dp = DevicePathNode::from_ffi_ptr(bytes.as_ptr().cast());
264+
}
265+
if dp.length() as usize <= bytes.len() {
266+
return Ok(dp);
267+
}
268+
}
269+
Err(ByteConversionError::InvalidLength)
270+
}
271+
}
272+
256273
/// A single device path instance that ends with either an [`END_INSTANCE`]
257274
/// or [`END_ENTIRE`] node. Use [`DevicePath::instance_iter`] to get the
258275
/// path instances in a [`DevicePath`].
@@ -729,6 +746,15 @@ impl DeviceSubType {
729746
pub const END_ENTIRE: DeviceSubType = DeviceSubType(0xff);
730747
}
731748

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

0 commit comments

Comments
 (0)