33use 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} ;
1012use bitflags:: bitflags;
13+ use ptr_meta:: Pointee ;
1114
1215use 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