Skip to content

Commit b725f68

Browse files
committed
uefi: pxe: convert DiscoverInfo into DST.
1 parent 8979b01 commit b725f68

File tree

2 files changed

+68
-31
lines changed

2 files changed

+68
-31
lines changed

CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@
3131
which simplifies usage.
3232
- Use of the unstable `ptr_metadata` feature has been replaced with a dependency
3333
on the [`ptr_meta`](https://docs.rs/ptr_meta) crate.
34-
- `pxe::DiscoverInfo` is now generic over the number of Servers it specifies instead
35-
of `[Server]` and `[Server; N]` (of which only the later is FFI safe).
36-
- `BaseCode::discover` is now generic over the number of Servers in `DiscoverInfo`,
37-
but the source-level interface should remain compatible with existing correct code.
34+
- `pxe::DiscoverInfo` is now a DST. Create with `new_in_buffer` by supplying a
35+
`MaybeUninit<u8>` slice of appropriate length.
3836

3937
### Removed
4038

uefi/src/proto/network/pxe.rs

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
use core::{
44
ffi::c_void,
55
iter::from_fn,
6+
marker::{PhantomData, PhantomPinned},
7+
mem::MaybeUninit,
68
ptr::{null, null_mut},
79
};
810

9-
use crate::proto::unsafe_protocol;
11+
use crate::{polyfill::maybe_uninit_slice_as_mut_ptr, proto::unsafe_protocol};
1012
use bitflags::bitflags;
13+
use ptr_meta::Pointee;
1114

1215
use crate::{CStr8, Char8, Result, Status};
1316

@@ -27,7 +30,7 @@ pub struct BaseCode {
2730
ty: BootstrapType,
2831
layer: &mut u16,
2932
use_bis: bool,
30-
info: *const DiscoverInfo<0>,
33+
info: *const FfiDiscoverInfo,
3134
) -> Status,
3235
mtftp: unsafe extern "efiapi" fn(
3336
this: &Self,
@@ -122,18 +125,19 @@ impl BaseCode {
122125

123126
/// Attempts to complete the PXE Boot Server and/or boot image discovery
124127
/// sequence.
125-
///
126-
/// The const `N` is the number of server entries in the [`DiscoverInfo`].
127-
pub fn discover<const N: usize>(
128+
pub fn discover(
128129
&mut self,
129130
ty: BootstrapType,
130131
layer: &mut u16,
131132
use_bis: bool,
132-
info: Option<&DiscoverInfo<N>>,
133+
info: Option<&DiscoverInfo>,
133134
) -> Result {
134-
let info = info
135-
.map(|info| (info as *const DiscoverInfo<N>).cast())
136-
.unwrap_or(core::ptr::null());
135+
let info: *const FfiDiscoverInfo = info
136+
.map(|info| {
137+
let info_ptr: *const DiscoverInfo = info;
138+
info_ptr.cast()
139+
})
140+
.unwrap_or(null());
137141

138142
(self.discover)(self, ty, layer, use_bis, info).into()
139143
}
@@ -647,46 +651,81 @@ pub enum BootstrapType {
647651
PxeTest = 65535,
648652
}
649653

654+
/// Opaque type that should be used to represent a pointer to a [`DiscoverInfo`] in
655+
/// foreign function interfaces. This type produces a thin pointer, unlike
656+
/// [`DiscoverInfo`].
657+
#[repr(C, packed)]
658+
pub struct FfiDiscoverInfo {
659+
// This representation is recommended by the nomicon:
660+
// https://doc.rust-lang.org/stable/nomicon/ffi.html#representing-opaque-structs
661+
_data: [u8; 0],
662+
_marker: PhantomData<(*mut u8, PhantomPinned)>,
663+
}
664+
650665
/// This struct contains optional parameters for [`BaseCode::discover`].
651666
///
652667
/// Corresponds to the `EFI_PXE_BASE_CODE_DISCOVER_INFO` type in the C API.
653668
#[repr(C)]
654-
pub struct DiscoverInfo<const N: usize> {
669+
#[derive(Pointee)]
670+
pub struct DiscoverInfo {
655671
use_m_cast: bool,
656672
use_b_cast: bool,
657673
use_u_cast: bool,
658674
must_use_list: bool,
659675
server_m_cast_ip: IpAddress,
660676
ip_cnt: u16,
661-
srv_list: [Server; N],
677+
srv_list: [Server],
662678
}
663679

664-
impl<const N: usize> DiscoverInfo<N> {
680+
impl DiscoverInfo {
665681
/// Create a `DiscoverInfo`.
666-
#[must_use]
667-
pub const fn new(
682+
pub fn new_in_buffer<'buf>(
683+
buffer: &'buf mut [MaybeUninit<u8>],
668684
use_m_cast: bool,
669685
use_b_cast: bool,
670686
use_u_cast: bool,
671687
must_use_list: bool,
672688
server_m_cast_ip: IpAddress,
673-
srv_list: [Server; N],
674-
) -> Self {
675-
assert!(N <= u16::MAX as usize, "too many servers");
676-
let ip_cnt = N as u16;
677-
Self {
678-
use_m_cast,
679-
use_b_cast,
680-
use_u_cast,
681-
must_use_list,
682-
server_m_cast_ip,
683-
ip_cnt,
684-
srv_list,
689+
srv_list: &[Server],
690+
) -> Result<&'buf mut Self> {
691+
let server_count = srv_list.len();
692+
assert!(server_count <= u16::MAX as usize, "too many servers");
693+
694+
let required_size = core::mem::size_of::<bool>() * 4
695+
+ core::mem::size_of::<IpAddress>()
696+
+ core::mem::size_of::<u16>()
697+
+ core::mem::size_of::<Server>() * server_count;
698+
699+
if buffer.len() < required_size {
700+
return Err(Status::BUFFER_TOO_SMALL.into());
701+
}
702+
703+
/// Write `value` to `ptr` unaligned, then advance `ptr` by `sizeof(value)`.
704+
unsafe fn ptr_write_unaligned_and_add<T>(ptr: &mut *mut u8, val: T) {
705+
ptr.cast::<T>().write_unaligned(val);
706+
*ptr = ptr.add(core::mem::size_of::<T>());
707+
}
708+
709+
let mut ptr: *mut u8 = maybe_uninit_slice_as_mut_ptr(buffer);
710+
unsafe {
711+
ptr_write_unaligned_and_add(&mut ptr, use_m_cast);
712+
ptr_write_unaligned_and_add(&mut ptr, use_b_cast);
713+
ptr_write_unaligned_and_add(&mut ptr, use_u_cast);
714+
ptr_write_unaligned_and_add(&mut ptr, must_use_list);
715+
ptr_write_unaligned_and_add(&mut ptr, server_m_cast_ip);
716+
ptr_write_unaligned_and_add(&mut ptr, server_count as u16);
717+
718+
ptr = ptr.add(2); // Align server list (4-byte alignment).
719+
core::ptr::copy(srv_list.as_ptr(), ptr.cast(), server_count);
720+
721+
let ptr: *mut Self =
722+
ptr_meta::from_raw_parts_mut(buffer.as_mut_ptr().cast(), server_count);
723+
Ok(&mut *ptr)
685724
}
686725
}
687726
}
688727

689-
impl<const N: usize> DiscoverInfo<N> {
728+
impl DiscoverInfo {
690729
/// Returns whether discovery should use multicast.
691730
#[must_use]
692731
pub const fn use_m_cast(&self) -> bool {

0 commit comments

Comments
 (0)