@@ -21,6 +21,12 @@ use crate::slice;
2121use crate :: sync:: atomic:: { AtomicPtr , Ordering } ;
2222use crate :: sys_common:: wstr:: WStrUnits ;
2323
24+ type BootInstallMultipleProtocolInterfaces =
25+ unsafe extern "efiapi" fn ( _: * mut r_efi:: efi:: Handle , _: ...) -> r_efi:: efi:: Status ;
26+
27+ type BootUninstallMultipleProtocolInterfaces =
28+ unsafe extern "efiapi" fn ( _: r_efi:: efi:: Handle , _: ...) -> r_efi:: efi:: Status ;
29+
2430const BOOT_SERVICES_UNAVAILABLE : io:: Error =
2531 const_io_error ! ( io:: ErrorKind :: Other , "Boot Services are no longer available" ) ;
2632
@@ -231,6 +237,13 @@ impl DevicePath {
231237 protocol : NonNull < r_efi:: protocols:: device_path_from_text:: Protocol > ,
232238 ) -> io:: Result < DevicePath > {
233239 let path_vec = p. encode_wide ( ) . chain ( Some ( 0 ) ) . collect :: < Vec < u16 > > ( ) ;
240+ if path_vec[ ..path_vec. len ( ) - 1 ] . contains ( & 0 ) {
241+ return Err ( const_io_error ! (
242+ io:: ErrorKind :: InvalidInput ,
243+ "strings passed to UEFI cannot contain NULs" ,
244+ ) ) ;
245+ }
246+
234247 let path =
235248 unsafe { ( ( * protocol. as_ptr ( ) ) . convert_text_to_device_path ) ( path_vec. as_ptr ( ) ) } ;
236249
@@ -267,17 +280,9 @@ impl DevicePath {
267280 "DevicePathFromText Protocol not found"
268281 ) )
269282 }
270- }
271-
272- impl AsRef < r_efi:: protocols:: device_path:: Protocol > for DevicePath {
273- fn as_ref ( & self ) -> & r_efi:: protocols:: device_path:: Protocol {
274- unsafe { self . 0 . as_ref ( ) }
275- }
276- }
277283
278- impl AsMut < r_efi:: protocols:: device_path:: Protocol > for DevicePath {
279- fn as_mut ( & mut self ) -> & mut r_efi:: protocols:: device_path:: Protocol {
280- unsafe { self . 0 . as_mut ( ) }
284+ pub ( crate ) fn as_ptr ( & self ) -> * mut r_efi:: protocols:: device_path:: Protocol {
285+ self . 0 . as_ptr ( )
281286 }
282287}
283288
@@ -292,74 +297,122 @@ impl Drop for DevicePath {
292297 }
293298}
294299
295- pub ( crate ) struct Protocol < T > {
300+ pub ( crate ) struct OwnedProtocol < T > {
296301 guid : r_efi:: efi:: Guid ,
297302 handle : NonNull < crate :: ffi:: c_void > ,
298- protocol : Box < T > ,
303+ protocol : * mut T ,
299304}
300305
301- impl < T > Protocol < T > {
302- const fn new (
303- guid : r_efi:: efi:: Guid ,
304- handle : NonNull < crate :: ffi:: c_void > ,
305- protocol : Box < T > ,
306- ) -> Self {
307- Self { guid, handle, protocol }
308- }
309-
310- pub ( crate ) fn create ( protocol : T , mut guid : r_efi:: efi:: Guid ) -> io:: Result < Self > {
311- let boot_services: NonNull < r_efi:: efi:: BootServices > =
306+ impl < T > OwnedProtocol < T > {
307+ // FIXME: Consider using unsafe trait for matching protocol with guid
308+ pub ( crate ) unsafe fn create ( protocol : T , mut guid : r_efi:: efi:: Guid ) -> io:: Result < Self > {
309+ let bt: NonNull < r_efi:: efi:: BootServices > =
312310 boot_services ( ) . ok_or ( BOOT_SERVICES_UNAVAILABLE ) ?. cast ( ) ;
313- let mut protocol = Box :: new ( protocol) ;
311+ let protocol : * mut T = Box :: into_raw ( Box :: new ( protocol) ) ;
314312 let mut handle: r_efi:: efi:: Handle = crate :: ptr:: null_mut ( ) ;
315313
314+ // FIXME: Move into r-efi once extended_varargs_abi_support is stablized
315+ let func: BootInstallMultipleProtocolInterfaces =
316+ unsafe { crate :: mem:: transmute ( ( * bt. as_ptr ( ) ) . install_multiple_protocol_interfaces ) } ;
317+
316318 let r = unsafe {
317- ( ( * boot_services . as_ptr ( ) ) . install_protocol_interface ) (
319+ func (
318320 & mut handle,
319- & mut guid,
320- r_efi :: efi :: NATIVE_INTERFACE ,
321- protocol . as_mut ( ) as * mut T as * mut crate :: ffi:: c_void ,
321+ & mut guid as * mut _ as * mut crate :: ffi :: c_void ,
322+ protocol as * mut crate :: ffi :: c_void ,
323+ crate :: ptr :: null_mut ( ) as * mut crate :: ffi:: c_void ,
322324 )
323325 } ;
324326
325327 if r. is_error ( ) {
328+ drop ( unsafe { Box :: from_raw ( protocol) } ) ;
326329 return Err ( crate :: io:: Error :: from_raw_os_error ( r. as_usize ( ) ) ) ;
327330 } ;
328331
329332 let handle = NonNull :: new ( handle)
330333 . ok_or ( io:: const_io_error!( io:: ErrorKind :: Uncategorized , "found null handle" ) ) ?;
331334
332- Ok ( Self :: new ( guid, handle, protocol) )
335+ Ok ( Self { guid, handle, protocol } )
333336 }
334337
335338 pub ( crate ) fn handle ( & self ) -> NonNull < crate :: ffi:: c_void > {
336339 self . handle
337340 }
338341}
339342
340- impl < T > Drop for Protocol < T > {
343+ impl < T > Drop for OwnedProtocol < T > {
341344 fn drop ( & mut self ) {
345+ // Do not deallocate a runtime protocol
342346 if let Some ( bt) = boot_services ( ) {
343347 let bt: NonNull < r_efi:: efi:: BootServices > = bt. cast ( ) ;
344- unsafe {
345- ( ( * bt. as_ptr ( ) ) . uninstall_protocol_interface ) (
348+ // FIXME: Move into r-efi once extended_varargs_abi_support is stablized
349+ let func: BootUninstallMultipleProtocolInterfaces = unsafe {
350+ crate :: mem:: transmute ( ( * bt. as_ptr ( ) ) . uninstall_multiple_protocol_interfaces )
351+ } ;
352+ let status = unsafe {
353+ func (
346354 self . handle . as_ptr ( ) ,
347- & mut self . guid ,
348- self . protocol . as_mut ( ) as * mut T as * mut crate :: ffi:: c_void ,
355+ & mut self . guid as * mut _ as * mut crate :: ffi:: c_void ,
356+ self . protocol as * mut crate :: ffi:: c_void ,
357+ crate :: ptr:: null_mut ( ) as * mut crate :: ffi:: c_void ,
349358 )
350359 } ;
360+
361+ // Leak the protocol in case uninstall fails
362+ if status == r_efi:: efi:: Status :: SUCCESS {
363+ let _ = unsafe { Box :: from_raw ( self . protocol ) } ;
364+ }
351365 }
352366 }
353367}
354368
355- impl < T > AsRef < T > for Protocol < T > {
369+ impl < T > AsRef < T > for OwnedProtocol < T > {
356370 fn as_ref ( & self ) -> & T {
357- & self . protocol
371+ unsafe { self . protocol . as_ref ( ) . unwrap ( ) }
372+ }
373+ }
374+
375+ pub ( crate ) struct OwnedTable < T > {
376+ layout : crate :: alloc:: Layout ,
377+ ptr : * mut T ,
378+ }
379+
380+ impl < T > OwnedTable < T > {
381+ pub ( crate ) fn from_table_header ( hdr : & r_efi:: efi:: TableHeader ) -> Self {
382+ let header_size = hdr. header_size as usize ;
383+ let layout = crate :: alloc:: Layout :: from_size_align ( header_size, 8 ) . unwrap ( ) ;
384+ let ptr = unsafe { crate :: alloc:: alloc ( layout) as * mut T } ;
385+ Self { layout, ptr }
386+ }
387+
388+ pub ( crate ) const fn as_ptr ( & self ) -> * const T {
389+ self . ptr
390+ }
391+
392+ pub ( crate ) const fn as_mut_ptr ( & self ) -> * mut T {
393+ self . ptr
358394 }
359395}
360396
361- impl < T > AsMut < T > for Protocol < T > {
362- fn as_mut ( & mut self ) -> & mut T {
363- & mut self . protocol
397+ impl OwnedTable < r_efi:: efi:: SystemTable > {
398+ pub ( crate ) fn from_table ( tbl : * const r_efi:: efi:: SystemTable ) -> Self {
399+ let hdr = unsafe { ( * tbl) . hdr } ;
400+
401+ let owned_tbl = Self :: from_table_header ( & hdr) ;
402+ unsafe {
403+ crate :: ptr:: copy_nonoverlapping (
404+ tbl as * const u8 ,
405+ owned_tbl. as_mut_ptr ( ) as * mut u8 ,
406+ hdr. header_size as usize ,
407+ )
408+ } ;
409+
410+ owned_tbl
411+ }
412+ }
413+
414+ impl < T > Drop for OwnedTable < T > {
415+ fn drop ( & mut self ) {
416+ unsafe { crate :: alloc:: dealloc ( self . ptr as * mut u8 , self . layout ) } ;
364417 }
365418}
0 commit comments