Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit efacc77

Browse files
Type-safety cleanup and safe exit from boot services (#65)
- Improve type correctness in various places (no more usize as a hidden pointer or fake 'static lifetimes). - Tie protocols to the lifetime of the UEFI boot services so that the borrow checker can invalidate them once boot services are exited - Disable global services (logging, memory allocation...) on exit from boot services. - Implement a safe way to exit the UEFI boot services (and hide the unsafe one).
1 parent 5e95f52 commit efacc77

File tree

27 files changed

+597
-219
lines changed

27 files changed

+597
-219
lines changed

‎BUILDING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ The following steps allow you to build a simple UEFI app.
1919

2020
```rust
2121
#[no_mangle]
22-
pub extern "win64" fn uefi_start(handle: Handle, system_table: &'statictable::SystemTable) -> Status;
22+
pub extern "win64" fn uefi_start(handle: Handle, system_table: SystemTable<Boot>) -> Status;
2323
```
2424

2525
- Copy the `uefi-test-runner/x86_64-uefi.json` target file to your project's root.

‎src/error/completion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<T> Completion<T> {
5252
}
5353

5454
/// Transform the inner value without unwrapping the Completion
55-
pub fn map<U>(self, f: impl Fn(T) -> U) -> Completion<U> {
55+
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Completion<U> {
5656
match self {
5757
Completion::Success(res) => Completion::Success(f(res)),
5858
Completion::Warning(res, stat) => Completion::Warning(f(res), stat),

‎src/error/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub trait ResultExt<T> {
2525
fn expect_success(self, msg: &str) -> T;
2626

2727
/// Transform the inner output, if any
28-
fn map_inner<U>(self, f: impl Fn(T) -> U) -> Result<U>;
28+
fn map_inner<U>(self, f: impl FnOnce(T) -> U) -> Result<U>;
2929
}
3030

3131
impl<T> ResultExt<T> for Result<T> {
@@ -49,7 +49,7 @@ impl<T> ResultExt<T> for Result<T> {
4949
self.expect(msg).expect(msg)
5050
}
5151

52-
fn map_inner<U>(self, f: impl Fn(T) -> U) -> Result<U> {
52+
fn map_inner<U>(self, f: impl FnOnce(T) -> U) -> Result<U> {
5353
self.map(|completion| completion.map(f))
5454
}
5555
}

‎src/prelude.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@
55
pub use crate::{ResultExt, Status};
66

77
// Import the basic table types.
8-
pub use crate::table::{boot::BootServices, runtime::RuntimeServices, SystemTable};
8+
pub use crate::table::boot::BootServices;
9+
pub use crate::table::runtime::RuntimeServices;
10+
pub use crate::table::{Boot, SystemTable};

‎src/proto/console/gop.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::{Completion, Result, Status};
3333
/// The GOP can be used to set the properties of the frame buffer,
3434
/// and also allows the app to access the in-memory buffer.
3535
#[repr(C)]
36-
pub struct GraphicsOutput {
36+
pub struct GraphicsOutput<'boot> {
3737
query_mode:
3838
extern "win64" fn(&GraphicsOutput, mode: u32, info_sz: &mut usize, &mut *const ModeInfo)
3939
-> Status,
@@ -42,7 +42,7 @@ pub struct GraphicsOutput {
4242
#[allow(clippy::type_complexity)]
4343
blt: extern "win64" fn(
4444
this: &mut GraphicsOutput,
45-
buffer: usize,
45+
buffer: *mutBltPixel,
4646
op: u32,
4747
source_x: usize,
4848
source_y: usize,
@@ -52,18 +52,18 @@ pub struct GraphicsOutput {
5252
height: usize,
5353
stride: usize,
5454
) -> Status,
55-
mode: &'static ModeData,
55+
mode: &'boot ModeData<'boot>,
5656
}
5757

58-
impl GraphicsOutput {
58+
impl<'boot> GraphicsOutput<'boot> {
5959
/// Returns information for an available graphics mode that the graphics
6060
/// device and the set of active video output devices supports.
6161
fn query_mode(&self, index: u32) -> Result<Mode> {
6262
let mut info_sz = 0;
6363
let mut info = ptr::null();
6464

6565
(self.query_mode)(self, index, &mut info_sz, &mut info).into_with(|| {
66-
let info = unsafe { &*info };
66+
let info = unsafe { *info };
6767
Mode {
6868
index,
6969
info_sz,
@@ -103,7 +103,7 @@ impl GraphicsOutput {
103103
self.check_framebuffer_region((dest_x, dest_y), (width, height));
104104
(self.blt)(
105105
self,
106-
&color as *const _ as usize,
106+
&color as *const _ as *mut_,
107107
0,
108108
0,
109109
0,
@@ -126,7 +126,7 @@ impl GraphicsOutput {
126126
match dest_region {
127127
BltRegion::Full => (self.blt)(
128128
self,
129-
buffer.as_mut_ptr()asusize,
129+
buffer.as_mut_ptr(),
130130
1,
131131
src_x,
132132
src_y,
@@ -142,7 +142,7 @@ impl GraphicsOutput {
142142
px_stride,
143143
} => (self.blt)(
144144
self,
145-
buffer.as_mut_ptr()asusize,
145+
buffer.as_mut_ptr(),
146146
1,
147147
src_x,
148148
src_y,
@@ -166,7 +166,7 @@ impl GraphicsOutput {
166166
match src_region {
167167
BltRegion::Full => (self.blt)(
168168
self,
169-
buffer.as_ptr() as usize,
169+
buffer.as_ptr() as *mut_,
170170
2,
171171
0,
172172
0,
@@ -182,7 +182,7 @@ impl GraphicsOutput {
182182
px_stride,
183183
} => (self.blt)(
184184
self,
185-
buffer.as_ptr() as usize,
185+
buffer.as_ptr() as *mut_,
186186
2,
187187
src_x,
188188
src_y,
@@ -203,7 +203,16 @@ impl GraphicsOutput {
203203
self.check_framebuffer_region((src_x, src_y), (width, height));
204204
self.check_framebuffer_region((dest_x, dest_y), (width, height));
205205
(self.blt)(
206-
self, 0usize, 3, src_x, src_y, dest_x, dest_y, width, height, 0,
206+
self,
207+
ptr::null_mut(),
208+
3,
209+
src_x,
210+
src_y,
211+
dest_x,
212+
dest_y,
213+
width,
214+
height,
215+
0,
207216
)
208217
.into()
209218
}
@@ -269,19 +278,19 @@ impl GraphicsOutput {
269278
}
270279

271280
impl_proto! {
272-
protocol GraphicsOutput {
281+
protocol GraphicsOutput<'boot> {
273282
GUID = 0x9042a9de, 0x23dc, 0x4a38, [0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a];
274283
}
275284
}
276285

277286
#[repr(C)]
278-
struct ModeData {
287+
struct ModeData<'a> {
279288
// Number of modes which the GOP supports.
280289
max_mode: u32,
281290
// Current mode.
282291
mode: u32,
283292
// Information about the current mode.
284-
info: &'static ModeInfo,
293+
info: &'a ModeInfo,
285294
// Size of the above structure.
286295
info_sz: usize,
287296
// Physical address of the frame buffer.
@@ -329,7 +338,7 @@ pub struct PixelBitmask {
329338
pub struct Mode {
330339
index: u32,
331340
info_sz: usize,
332-
info: &'staticModeInfo,
341+
info: ModeInfo,
333342
}
334343

335344
impl Mode {
@@ -342,7 +351,7 @@ impl Mode {
342351

343352
/// Returns a reference to the mode info structure.
344353
pub fn info(&self) -> &ModeInfo {
345-
self.info
354+
&self.info
346355
}
347356
}
348357

@@ -391,7 +400,7 @@ impl ModeInfo {
391400

392401
/// Iterator for graphics modes.
393402
struct ModeIter<'a> {
394-
gop: &'a GraphicsOutput,
403+
gop: &'a GraphicsOutput<'a>,
395404
current: u32,
396405
max: u32,
397406
}

‎src/proto/console/pointer/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ use crate::{Event, Result, Status};
55

66
/// Provides information about a pointer device.
77
#[repr(C)]
8-
pub struct Pointer {
8+
pub struct Pointer<'boot> {
99
reset: extern "win64" fn(this: &mut Pointer, ext_verif: bool) -> Status,
1010
get_state: extern "win64" fn(this: &Pointer, state: &mut PointerState) -> Status,
1111
wait_for_input: Event,
12-
mode: &'static PointerMode,
12+
mode: &'boot PointerMode,
1313
}
1414

15-
impl Pointer {
15+
impl<'boot> Pointer<'boot> {
1616
/// Resets the pointer device hardware.
1717
///
1818
/// The `extended_verification` parameter is used to request that UEFI
@@ -55,7 +55,7 @@ impl Pointer {
5555
}
5656

5757
impl_proto! {
58-
protocol Pointer {
58+
protocol Pointer<'boot> {
5959
GUID = 0x31878c87, 0xb75, 0x11d5, [0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d];
6060
}
6161
}

‎src/proto/console/serial.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{Completion, Result, Status};
1111
/// Since UEFI drivers are implemented through polling, if you fail to regularly
1212
/// check for input/output, some data might be lost.
1313
#[repr(C)]
14-
pub struct Serial {
14+
pub struct Serial<'boot> {
1515
// Revision of this protocol, only 1.0 is currently defined.
1616
// Future versions will be backwards compatible.
1717
revision: u32,
@@ -29,10 +29,10 @@ pub struct Serial {
2929
get_control_bits: extern "win64" fn(&Serial, &mut ControlBits) -> Status,
3030
write: extern "win64" fn(&mut Serial, &mut usize, *const u8) -> Status,
3131
read: extern "win64" fn(&mut Serial, &mut usize, *mut u8) -> Status,
32-
io_mode: &'static IoMode,
32+
io_mode: &'boot IoMode,
3333
}
3434

35-
impl Serial {
35+
impl<'boot> Serial<'boot> {
3636
/// Reset the device.
3737
pub fn reset(&mut self) -> Result<()> {
3838
(self.reset)(self).into()
@@ -117,7 +117,7 @@ impl Serial {
117117
}
118118

119119
impl_proto! {
120-
protocol Serial {
120+
protocol Serial<'boot> {
121121
GUID = 0xBB25CF6F, 0xF1D4, 0x11D2, [0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0xFD];
122122
}
123123
}

‎src/proto/console/text/output.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{CStr16, Char16, Completion, Result, Status};
77
/// It implements the fmt::Write trait, so you can use it to print text with
88
/// standard Rust constructs like the write!() and writeln!() macros.
99
#[repr(C)]
10-
pub struct Output {
10+
pub struct Output<'boot> {
1111
reset: extern "win64" fn(this: &Output, extended: bool) -> Status,
1212
output_string: extern "win64" fn(this: &Output, string: *const Char16) -> Status,
1313
test_string: extern "win64" fn(this: &Output, string: *const Char16) -> Status,
@@ -18,10 +18,10 @@ pub struct Output {
1818
clear_screen: extern "win64" fn(this: &mut Output) -> Status,
1919
set_cursor_position: extern "win64" fn(this: &mut Output, column: usize, row: usize) -> Status,
2020
enable_cursor: extern "win64" fn(this: &mut Output, visible: bool) -> Status,
21-
data: &'static OutputData,
21+
data: &'boot OutputData,
2222
}
2323

24-
impl Output {
24+
impl<'boot> Output<'boot> {
2525
/// Resets and clears the text output device hardware.
2626
pub fn reset(&mut self, extended: bool) -> Result<()> {
2727
(self.reset)(self, extended).into()
@@ -53,8 +53,8 @@ impl Output {
5353
}
5454

5555
/// Returns an iterator of all supported text modes.
56-
// TODO: fix the ugly lifetime parameter.
57-
pub fn modes<'a>(&'a mut self) -> implIterator<Item = Completion<OutputMode>> + 'a {
56+
// TODO: Bring back impl Trait once the story around bounds improves
57+
pub fn modes<'a>(&'a mut self) -> OutputModeIter<'a,'boot> {
5858
let max = self.data.max_mode;
5959
OutputModeIter {
6060
output: self,
@@ -134,7 +134,7 @@ impl Output {
134134
}
135135
}
136136

137-
impl fmt::Write for Output {
137+
impl<'boot> fmt::Write for Output<'boot> {
138138
fn write_str(&mut self, s: &str) -> fmt::Result {
139139
// Allocate a small buffer on the stack.
140140
const BUF_SIZE: usize = 128;
@@ -215,13 +215,13 @@ impl OutputMode {
215215
}
216216

217217
/// An iterator of the text modes (possibly) supported by a device.
218-
struct OutputModeIter<'a> {
219-
output: &'a mut Output,
218+
pubstruct OutputModeIter<'a,'b:'a> {
219+
output: &'a mut Output<'b>,
220220
current: i32,
221221
max: i32,
222222
}
223223

224-
impl<'a> Iterator for OutputModeIter<'a> {
224+
impl<'a,'b> Iterator for OutputModeIter<'a,'b> {
225225
type Item = Completion<OutputMode>;
226226

227227
fn next(&mut self) -> Option<Self::Item> {
@@ -259,7 +259,7 @@ struct OutputData {
259259
}
260260

261261
impl_proto! {
262-
protocol Output {
262+
protocol Output<'boot> {
263263
GUID = 0x387477c2, 0x69c7, 0x11d2, [0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b];
264264
}
265265
}

‎src/proto/macros.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,21 @@ macro_rules! impl_proto {
3333
// Most UEFI functions do not support multithreaded access.
3434
impl !Sync for $p {}
3535
};
36+
(
37+
protocol $p:ident<'boot> {
38+
GUID = $a:expr, $b:expr, $c:expr, $d:expr;
39+
}
40+
) => {
41+
impl<'boot> $crate::proto::Protocol for $p<'boot> {
42+
#[doc(hidden)]
43+
// These literals aren't meant to be human-readable.
44+
#[allow(clippy::unreadable_literal)]
45+
const GUID: $crate::Guid = $crate::Guid::from_values($a, $b, $c, $d);
46+
}
47+
48+
// Most UEFI functions expect to be called on the bootstrap processor.
49+
impl<'boot> !Send for $p<'boot> {}
50+
// Most UEFI functions do not support multithreaded access.
51+
impl<'boot> !Sync for $p<'boot> {}
52+
};
3653
}

‎src/proto/media/file.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
88
use bitflags::bitflags;
99
use core::mem;
10+
use core::ptr;
1011
use crate::prelude::*;
1112
use crate::{CStr16, Char16, Result, Status};
1213
use ucs2;
@@ -22,10 +23,8 @@ pub struct File<'a> {
2223
}
2324

2425
impl<'a> File<'a> {
25-
pub(super) unsafe fn new(ptr: usize) -> Self {
26-
let ptr = ptr as *mut FileImpl;
27-
let inner = &mut *ptr;
28-
File { inner }
26+
pub(super) unsafe fn new(ptr: *mut FileImpl) -> Self {
27+
File { inner: &mut *ptr }
2928
}
3029

3130
/// Try to open a file relative to this file/directory.
@@ -58,7 +57,7 @@ impl<'a> File<'a> {
5857
Err(Status::INVALID_PARAMETER)
5958
} else {
6059
let mut buf = [0u16; BUF_SIZE + 1];
61-
let mut ptr = 0usize;
60+
let mut ptr = ptr::null_mut();
6261

6362
let len = ucs2::encode(filename, &mut buf)?;
6463
let filename = unsafe { CStr16::from_u16_with_nul_unchecked(&buf[..=len]) };
@@ -70,9 +69,7 @@ impl<'a> File<'a> {
7069
open_mode,
7170
attributes,
7271
)
73-
.into_with(|| File {
74-
inner: unsafe { &mut *(ptr as *mut FileImpl) },
75-
})
72+
.into_with(|| unsafe { File::new(ptr) })
7673
}
7774
}
7875

@@ -175,11 +172,11 @@ impl<'a> Drop for File<'a> {
175172

176173
/// The function pointer table for the File protocol.
177174
#[repr(C)]
178-
struct FileImpl {
175+
pub(super)struct FileImpl {
179176
revision: u64,
180177
open: extern "win64" fn(
181178
this: &mut FileImpl,
182-
new_handle: &mut usize,
179+
new_handle: &mut *mutFileImpl,
183180
filename: *const Char16,
184181
open_mode: FileMode,
185182
attributes: FileAttribute,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /