@@ -14,8 +14,8 @@ pub struct BootServices {
14
14
header : Header ,
15
15
16
16
// Task Priority services
17
- raise_tpl : extern "win64" fn ( new_tpl : Tpl ) -> Tpl ,
18
- restore_tpl : extern "win64" fn ( old_tpl : Tpl ) ,
17
+ raise_tpl : unsafe extern "win64" fn ( new_tpl : Tpl ) -> Tpl ,
18
+ restore_tpl : unsafe extern "win64" fn ( old_tpl : Tpl ) ,
19
19
20
20
// Memory allocation functions
21
21
allocate_pages : extern "win64" fn (
@@ -25,7 +25,7 @@ pub struct BootServices {
25
25
addr : & mut u64 ,
26
26
) -> Status ,
27
27
free_pages : extern "win64" fn ( addr : u64 , pages : usize ) -> Status ,
28
- memory_map : extern "win64" fn (
28
+ get_memory_map : unsafe extern "win64" fn (
29
29
size : & mut usize ,
30
30
map : * mut MemoryDescriptor ,
31
31
key : & mut MemoryMapKey ,
@@ -37,15 +37,15 @@ pub struct BootServices {
37
37
free_pool : extern "win64" fn ( buffer : * mut u8 ) -> Status ,
38
38
39
39
// Event & timer functions
40
- create_event : extern "win64" fn (
40
+ create_event : unsafe extern "win64" fn (
41
41
ty : EventType ,
42
42
notify_tpl : Tpl ,
43
43
notify_func : Option < EventNotifyFn > ,
44
44
notify_ctx : * mut c_void ,
45
- event : * mut Event ,
45
+ event : & mut Event ,
46
46
) -> Status ,
47
47
set_timer : usize ,
48
- wait_for_event : extern "win64" fn (
48
+ wait_for_event : unsafe extern "win64" fn (
49
49
number_of_events : usize ,
50
50
events : * mut Event ,
51
51
out_index : & mut usize ,
@@ -58,14 +58,11 @@ pub struct BootServices {
58
58
install_protocol_interface : usize ,
59
59
reinstall_protocol_interface : usize ,
60
60
uninstall_protocol_interface : usize ,
61
- handle_protocol : extern "win64" fn (
62
- handle : Handle ,
63
- proto : * const Guid ,
64
- out_proto : & mut * mut c_void ,
65
- ) -> Status ,
61
+ handle_protocol :
62
+ extern "win64" fn ( handle : Handle , proto : & Guid , out_proto : & mut * mut c_void ) -> Status ,
66
63
_reserved : usize ,
67
64
register_protocol_notify : usize ,
68
- locate_handle : extern "win64" fn (
65
+ locate_handle : unsafe extern "win64" fn (
69
66
search_ty : i32 ,
70
67
proto : * const Guid ,
71
68
key : * mut c_void ,
@@ -80,12 +77,13 @@ pub struct BootServices {
80
77
start_image : usize ,
81
78
exit : usize ,
82
79
unload_image : usize ,
83
- exit_boot_services : extern "win64" fn ( image_handle : Handle , map_key : MemoryMapKey ) -> Status ,
80
+ exit_boot_services :
81
+ unsafe extern "win64" fn ( image_handle : Handle , map_key : MemoryMapKey ) -> Status ,
84
82
85
83
// Misc services
86
84
get_next_monotonic_count : usize ,
87
85
stall : extern "win64" fn ( microseconds : usize ) -> Status ,
88
- set_watchdog_timer : extern "win64" fn (
86
+ set_watchdog_timer : unsafe extern "win64" fn (
89
87
timeout : usize ,
90
88
watchdog_code : u64 ,
91
89
data_size : usize ,
@@ -112,22 +110,27 @@ pub struct BootServices {
112
110
calculate_crc32 : usize ,
113
111
114
112
// Misc services
115
- copy_mem : extern "win64" fn ( dest : * mut u8 , src : * const u8 , len : usize ) ,
116
- set_mem : extern "win64" fn ( buffer : * mut u8 , len : usize , value : u8 ) ,
113
+ copy_mem : unsafe extern "win64" fn ( dest : * mut u8 , src : * const u8 , len : usize ) ,
114
+ set_mem : unsafe extern "win64" fn ( buffer : * mut u8 , len : usize , value : u8 ) ,
117
115
118
116
// New event functions (UEFI 2.0 or newer)
119
117
create_event_ex : usize ,
120
118
}
121
119
122
120
impl BootServices {
123
121
/// Raises a task's priority level and returns its previous level.
124
- pub fn raise_tpl ( & self , tpl : Tpl ) -> Tpl {
125
- ( self . raise_tpl ) ( tpl)
126
- }
127
-
128
- /// Restores a task’s priority level to its previous value.
129
- pub fn restore_tpl ( & self , old_tpl : Tpl ) {
130
- ( self . restore_tpl ) ( old_tpl)
122
+ ///
123
+ /// The effect of calling raise_tpl with a Tpl that is below the current one
124
+ /// (which, sadly, cannot be queried) is undefined by the UEFI spec, which
125
+ /// also warns against remaining at high Tpls for extended periods of time.
126
+ ///
127
+ /// This function outputs an RAII guard that will automatically restore the
128
+ /// original Tpl when dropped.
129
+ pub unsafe fn raise_tpl ( & self , tpl : Tpl ) -> TplGuard < ' _ > {
130
+ TplGuard {
131
+ boot_services : self ,
132
+ old_tpl : ( self . raise_tpl ) ( tpl) ,
133
+ }
131
134
}
132
135
133
136
/// Allocates memory pages from the system.
@@ -165,13 +168,15 @@ impl BootServices {
165
168
let mut entry_size = 0 ;
166
169
let mut entry_version = 0 ;
167
170
168
- let status = ( self . memory_map ) (
169
- & mut map_size,
170
- ptr:: null_mut ( ) ,
171
- & mut map_key,
172
- & mut entry_size,
173
- & mut entry_version,
174
- ) ;
171
+ let status = unsafe {
172
+ ( self . get_memory_map ) (
173
+ & mut map_size,
174
+ ptr:: null_mut ( ) ,
175
+ & mut map_key,
176
+ & mut entry_size,
177
+ & mut entry_version,
178
+ )
179
+ } ;
175
180
assert_eq ! ( status, Status :: BUFFER_TOO_SMALL ) ;
176
181
177
182
map_size * entry_size
@@ -184,6 +189,8 @@ impl BootServices {
184
189
///
185
190
/// The returned key is a unique identifier of the current configuration of memory.
186
191
/// Any allocations or such will change the memory map's key.
192
+ ///
193
+ /// FIXME: The input buffer must be properly aligned or UB will occur.
187
194
pub fn memory_map < ' a > (
188
195
& self ,
189
196
buffer : & ' a mut [ u8 ] ,
@@ -194,13 +201,15 @@ impl BootServices {
194
201
let mut entry_size = 0 ;
195
202
let mut entry_version = 0 ;
196
203
197
- ( self . memory_map ) (
198
- & mut map_size,
199
- map_buffer,
200
- & mut map_key,
201
- & mut entry_size,
202
- & mut entry_version,
203
- )
204
+ unsafe {
205
+ ( self . get_memory_map ) (
206
+ & mut map_size,
207
+ map_buffer,
208
+ & mut map_key,
209
+ & mut entry_size,
210
+ & mut entry_version,
211
+ )
212
+ }
204
213
. into_with ( move || {
205
214
let len = map_size / entry_size;
206
215
let iter = MemoryMapIter {
@@ -245,7 +254,7 @@ impl BootServices {
245
254
246
255
// Use a trampoline to handle the impedance mismatch between Rust & C
247
256
unsafe extern "win64" fn notify_trampoline ( e : Event , ctx : * mut c_void ) {
248
- let notify_fn: fn ( Event ) = core :: mem:: transmute ( ctx) ;
257
+ let notify_fn: fn ( Event ) = mem:: transmute ( ctx) ;
249
258
notify_fn ( e) ; // SAFETY: Aborting panics are assumed here
250
259
}
251
260
let ( notify_func, notify_ctx) = notify_fn
@@ -258,7 +267,7 @@ impl BootServices {
258
267
. unwrap_or ( ( None , ptr:: null_mut ( ) ) ) ;
259
268
260
269
// Now we're ready to call UEFI
261
- ( self . create_event ) ( event_ty, notify_tpl, notify_func, notify_ctx, & mut event)
270
+ unsafe { ( self . create_event ) ( event_ty, notify_tpl, notify_func, notify_ctx, & mut event) }
262
271
. into_with ( || event)
263
272
}
264
273
@@ -292,7 +301,7 @@ impl BootServices {
292
301
pub fn wait_for_event ( & self , events : & mut [ Event ] ) -> result:: Result < usize , ( Status , usize ) > {
293
302
let ( number_of_events, events) = ( events. len ( ) , events. as_mut_ptr ( ) ) ;
294
303
let mut index = unsafe { mem:: uninitialized ( ) } ;
295
- match ( self . wait_for_event ) ( number_of_events, events, & mut index) {
304
+ match unsafe { ( self . wait_for_event ) ( number_of_events, events, & mut index) } {
296
305
Status :: SUCCESS => Ok ( index) ,
297
306
s @ Status :: INVALID_PARAMETER => Err ( ( s, index) ) ,
298
307
error => Err ( ( error, 0 ) ) ,
@@ -344,7 +353,7 @@ impl BootServices {
344
353
SearchType :: ByProtocol ( guid) => ( 2 , guid as * const _ , ptr:: null_mut ( ) ) ,
345
354
} ;
346
355
347
- let status = ( self . locate_handle ) ( ty, guid, key, & mut buffer_size, buffer) ;
356
+ let status = unsafe { ( self . locate_handle ) ( ty, guid, key, & mut buffer_size, buffer) } ;
348
357
349
358
// Must convert the returned size (in bytes) to length (number of elements).
350
359
let buffer_len = buffer_size / handle_size;
@@ -394,8 +403,7 @@ impl BootServices {
394
403
/// allows you to change what will be logged when the timer expires.
395
404
///
396
405
/// The watchdog codes from 0 to 0xffff (65535) are reserved for internal
397
- /// firmware use. You should therefore only use them if instructed to do so
398
- /// by firmware-specific documentation. Higher values can be used freely.
406
+ /// firmware use. Higher values can be used freely by applications.
399
407
///
400
408
/// If provided, the watchdog data must be a null-terminated string
401
409
/// optionally followed by other binary data.
@@ -405,24 +413,28 @@ impl BootServices {
405
413
watchdog_code : u64 ,
406
414
data : Option < & mut [ u16 ] > ,
407
415
) -> Result < ( ) > {
416
+ assert ! (
417
+ watchdog_code > 0xffff ,
418
+ "Invalid use of a reserved firmware watchdog code"
419
+ ) ;
420
+
408
421
let ( data_len, data) = data
409
422
. map ( |d| {
410
423
assert ! (
411
424
d. contains( & 0 ) ,
412
- "Watchdog data must contain a null-terminated string"
425
+ "Watchdog data must start with a null-terminated string"
413
426
) ;
414
427
( d. len ( ) , d. as_mut_ptr ( ) )
415
428
} )
416
429
. unwrap_or ( ( 0 , ptr:: null_mut ( ) ) ) ;
417
430
418
- ( self . set_watchdog_timer ) ( timeout, watchdog_code, data_len, data) . into ( )
431
+ unsafe { ( self . set_watchdog_timer ) ( timeout, watchdog_code, data_len, data) } . into ( )
419
432
}
420
433
421
434
/// Copies memory from source to destination. The buffers can overlap.
422
435
///
423
436
/// This function is unsafe as it can be used to violate most safety
424
437
/// invariants of the Rust type system.
425
- ///
426
438
pub unsafe fn memmove ( & self , dest : * mut u8 , src : * const u8 , size : usize ) {
427
439
( self . copy_mem ) ( dest, src, size) ;
428
440
}
@@ -431,7 +443,6 @@ impl BootServices {
431
443
///
432
444
/// This function is unsafe as it can be used to violate most safety
433
445
/// invariants of the Rust type system.
434
- ///
435
446
pub unsafe fn memset ( & self , buffer : * mut u8 , size : usize , value : u8 ) {
436
447
( self . set_mem ) ( buffer, size, value) ;
437
448
}
@@ -466,6 +477,22 @@ pub enum Tpl: usize => {
466
477
HIGH_LEVEL = 31 ,
467
478
} }
468
479
480
+ /// RAII guard for task priority level changes
481
+ ///
482
+ /// Will automatically restore the former task priority level when dropped.
483
+ pub struct TplGuard < ' a > {
484
+ boot_services : & ' a BootServices ,
485
+ old_tpl : Tpl ,
486
+ }
487
+
488
+ impl Drop for TplGuard < ' _ > {
489
+ fn drop ( & mut self ) {
490
+ unsafe {
491
+ ( self . boot_services . restore_tpl ) ( self . old_tpl ) ;
492
+ }
493
+ }
494
+ }
495
+
469
496
/// Type of allocation to perform.
470
497
#[ derive( Debug , Copy , Clone ) ]
471
498
pub enum AllocateType {
@@ -620,7 +647,7 @@ impl<'a> Iterator for MemoryMapIter<'a> {
620
647
621
648
self . index += 1 ;
622
649
623
- let descriptor: & MemoryDescriptor = unsafe { mem :: transmute ( ptr) } ;
650
+ let descriptor= unsafe { & * ( ptras * const MemoryDescriptor ) } ;
624
651
625
652
Some ( descriptor)
626
653
} else {
0 commit comments