1
+ use alloc:: string:: ToString ;
1
2
use uefi:: proto:: console:: text:: Output ;
2
- use uefi:: table:: boot:: { BootServices , SearchType } ;
3
- use uefi:: Identify ;
3
+ use uefi:: proto:: device_path:: { DevicePath , DeviceSubType , DeviceType , LoadedImageDevicePath } ;
4
+ use uefi:: table:: boot:: { BootServices , LoadImageSource , SearchType } ;
5
+ use uefi:: { CStr16 , CString16 , Identify } ;
6
+
7
+ mod memory;
8
+ mod misc;
4
9
5
10
pub fn test ( bt : & BootServices ) {
6
11
info ! ( "Testing boot services" ) ;
7
12
memory:: test ( bt) ;
8
13
misc:: test ( bt) ;
9
14
test_locate_handle_buffer ( bt) ;
15
+ test_load_image ( bt) ;
10
16
}
11
17
12
- mod memory;
13
- mod misc;
14
-
15
18
fn test_locate_handle_buffer ( bt : & BootServices ) {
16
19
info ! ( "Testing the `locate_handle_buffer` function" ) ;
17
20
@@ -34,3 +37,71 @@ fn test_locate_handle_buffer(bt: &BootServices) {
34
37
) ;
35
38
}
36
39
}
40
+
41
+ /// This test loads the "self image" again into memory using the `load_image`
42
+ /// boot service function. The image is not started but just loaded into memory.
43
+ ///
44
+ /// It transitively tests the protocols [`LoadedImageDevicePath`] which is
45
+ /// required as helper.
46
+ fn test_load_image ( bt : & BootServices ) {
47
+ info ! ( "Testing the `load_image` function" ) ;
48
+
49
+ let image_device_path_protocol = bt
50
+ . open_protocol_exclusive :: < LoadedImageDevicePath > ( bt. image_handle ( ) )
51
+ . expect ( "should open LoadedImage protocol" ) ;
52
+
53
+ // Note: This is the full device path. The LoadedImage protocol would only
54
+ // provide us with the file-path portion of the device path.
55
+ let image_device_path: & DevicePath = & image_device_path_protocol;
56
+
57
+ // Get the file-path portion of the device path which is typically behind
58
+ // device path node (0x4, 0x4).
59
+ // TODO we need an abstraction in the UEFI crate for this.
60
+ let image_device_path_file_path = image_device_path
61
+ . node_iter ( )
62
+ . filter ( |node| {
63
+ node. device_type ( ) == DeviceType :: MEDIA /* 0x4 */
64
+ && node. sub_type ( ) == DeviceSubType :: HARDWARE_VENDOR /* 0x4 */
65
+ } )
66
+ . next ( )
67
+ . map ( |node| unsafe { CStr16 :: from_ptr ( node. data ( ) . as_ptr ( ) . cast ( ) ) } )
68
+ // to Rust string
69
+ . map ( |cstr16| cstr16. to_string ( ) . to_uppercase ( ) )
70
+ . expect ( "should have file-path portion in device path" ) ;
71
+
72
+ // On x86_64, this will be `\EFI\BOOT\BOOTX64.EFI` for example.
73
+ assert ! ( image_device_path_file_path
74
+ . as_str( )
75
+ . starts_with( r"\EFI\BOOT\BOOT" ) ) ;
76
+ assert ! ( image_device_path_file_path. as_str( ) . ends_with( ".EFI" ) ) ;
77
+
78
+ // Variant A: FromBuffer
79
+ {
80
+ let mut fs = bt
81
+ . get_image_file_system ( bt. image_handle ( ) )
82
+ . expect ( "should open file system" ) ;
83
+ let path = CString16 :: try_from ( image_device_path_file_path. as_str ( ) ) . unwrap ( ) ;
84
+ let image_data = fs. read ( & * path) . expect ( "should read file content" ) ;
85
+ let load_source = LoadImageSource :: FromBuffer {
86
+ buffer : image_data. as_slice ( ) ,
87
+ file_path : None ,
88
+ } ;
89
+ let _ = bt
90
+ . load_image ( bt. image_handle ( ) , load_source)
91
+ . expect ( "should load image" ) ;
92
+
93
+ log:: debug!( "load_image with FromBuffer strategy works" ) ;
94
+ }
95
+ // Variant B: FromFilePath
96
+ {
97
+ let load_source = LoadImageSource :: FromFilePath {
98
+ file_path : image_device_path,
99
+ from_boot_manager : false ,
100
+ } ;
101
+ let _ = bt
102
+ . load_image ( bt. image_handle ( ) , load_source)
103
+ . expect ( "should load image" ) ;
104
+
105
+ log:: debug!( "load_image with FromFilePath strategy works" ) ;
106
+ }
107
+ }
0 commit comments