Skip to content

Commit 887cd56

Browse files
authored
Merge pull request #1156 from nicholasbishop/bishop-global-tables-simple
Add basic API for a global system table
2 parents 65a215d + c04e423 commit 887cd56

File tree

6 files changed

+113
-16
lines changed

6 files changed

+113
-16
lines changed

Diff for: uefi-macros/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# uefi-macros - [Unreleased]
22

3+
## Changed
4+
- The `entry` macro now sets the global system table pointer with `uefi::set_system_table`.
5+
36
## Removed
47
- Removed the `cstr8` and `cstr16` macros. Use the declarative macros of the
58
same names exported by the `uefi` crate as a replacement.

Diff for: uefi-macros/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
204204
parse_quote! {
205205
unsafe {
206206
#system_table_ident.boot_services().set_image_handle(#image_handle_ident);
207+
::uefi::table::set_system_table(#system_table_ident.as_ptr().cast());
207208
}
208209
},
209210
);

Diff for: uefi-test-runner/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ fn shutdown(mut st: SystemTable<Boot>) -> ! {
199199
info!("Testing complete, exiting boot services...");
200200

201201
// Exit boot services as a proof that it works :)
202-
let (st, mmap) = st.exit_boot_services(MemoryType::LOADER_DATA);
202+
let (st, mmap) = unsafe { st.exit_boot_services(MemoryType::LOADER_DATA) };
203203

204204
info!("Memory Map:");
205205
for desc in mmap.entries() {

Diff for: uefi/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88
works on x86. It is activated by default (only on x86) and can be deactivated
99
by removing the `log-debugcon` cargo feature. The major benefit is that one
1010
can get log messages even after one exited the boot services.
11+
- Added `table::{set_system_table, system_table_boot, system_table_runtime}`.
12+
This provides an initial API for global tables that do not require passing
13+
around a reference.
14+
15+
## Changed
16+
- `SystemTable::exit_boot_services` is now `unsafe`. See that method's
17+
documentation for details of obligations for callers.
1118

1219
## Removed
1320
- Removed the `panic-on-logger-errors` feature of the `uefi` crate. Logger

Diff for: uefi/src/table/mod.rs

+75-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,84 @@
11
//! Standard UEFI tables.
22
3-
/// Common trait implemented by all standard UEFI tables.
4-
pub trait Table {
5-
/// A unique number assigned by the UEFI specification
6-
/// to the standard tables.
7-
const SIGNATURE: u64;
8-
}
3+
pub mod boot;
4+
pub mod cfg;
5+
pub mod runtime;
96

107
mod header;
11-
pub use header::Header;
12-
138
mod system;
9+
10+
pub use header::Header;
1411
pub use system::{Boot, Runtime, SystemTable};
12+
pub use uefi_raw::table::Revision;
1513

16-
pub mod boot;
17-
pub mod runtime;
14+
use core::ptr;
15+
use core::sync::atomic::{AtomicPtr, Ordering};
1816

19-
pub mod cfg;
17+
/// Global system table pointer. This is only modified by [`set_system_table`].
18+
static SYSTEM_TABLE: AtomicPtr<uefi_raw::table::system::SystemTable> =
19+
AtomicPtr::new(ptr::null_mut());
2020

21-
pub use uefi_raw::table::Revision;
21+
/// Update the global system table pointer.
22+
///
23+
/// This is called automatically in the `main` entry point as part of
24+
/// [`uefi::entry`]. It should not be called at any other point in time, unless
25+
/// the executable does not use [`uefi::entry`], in which case it should be
26+
/// called once before calling any other API in this crate.
27+
///
28+
/// # Safety
29+
///
30+
/// This function should only be called as described above, and the
31+
/// `ptr` must be a valid [`SystemTable`].
32+
pub unsafe fn set_system_table(ptr: *const uefi_raw::table::system::SystemTable) {
33+
SYSTEM_TABLE.store(ptr.cast_mut(), Ordering::Release);
34+
}
35+
36+
/// Get the system table while boot services are active.
37+
///
38+
/// # Panics
39+
///
40+
/// Panics if the system table has not been set with `set_system_table`, or if
41+
/// boot services are not available (e.g. if [`exit_boot_services`] has been
42+
/// called).
43+
///
44+
/// [`exit_boot_services`]: SystemTable::exit_boot_services
45+
pub fn system_table_boot() -> SystemTable<Boot> {
46+
let st = SYSTEM_TABLE.load(Ordering::Acquire);
47+
assert!(!st.is_null());
48+
49+
// SAFETY: the system table is valid per the requirements of `set_system_table`.
50+
unsafe {
51+
if (*st).boot_services.is_null() {
52+
panic!("boot services are not active");
53+
}
54+
55+
SystemTable::<Boot>::from_ptr(st.cast()).unwrap()
56+
}
57+
}
58+
59+
/// Get the system table while runtime services are active.
60+
///
61+
/// # Panics
62+
///
63+
/// Panics if the system table has not been set with `set_system_table`, or if
64+
/// runtime services are not available.
65+
pub fn system_table_runtime() -> SystemTable<Runtime> {
66+
let st = SYSTEM_TABLE.load(Ordering::Acquire);
67+
assert!(!st.is_null());
68+
69+
// SAFETY: the system table is valid per the requirements of `set_system_table`.
70+
unsafe {
71+
if (*st).runtime_services.is_null() {
72+
panic!("runtime services are not active");
73+
}
74+
75+
SystemTable::<Runtime>::from_ptr(st.cast()).unwrap()
76+
}
77+
}
78+
79+
/// Common trait implemented by all standard UEFI tables.
80+
pub trait Table {
81+
/// A unique number assigned by the UEFI specification
82+
/// to the standard tables.
83+
const SIGNATURE: u64;
84+
}

Diff for: uefi/src/table/system.rs

+26-3
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,27 @@ impl SystemTable<Boot> {
208208
///
209209
/// Note that once the boot services are exited, associated loggers and
210210
/// allocators can't use the boot services anymore. For the corresponding
211-
/// abstractions provided by this crate, invoking this function will
212-
/// automatically disable them.
211+
/// abstractions provided by this crate (see the [`helpers`] module),
212+
/// invoking this function will automatically disable them. If the
213+
/// `global_allocator` feature is enabled, attempting to use the allocator
214+
/// after exiting boot services will panic.
215+
///
216+
/// # Safety
217+
///
218+
/// The caller is responsible for ensuring that no references to
219+
/// boot-services data remain. A non-exhaustive list of resources to check:
220+
///
221+
/// * All protocols will be invalid after exiting boot services. This
222+
/// includes the [`Output`] protocols attached to stdout/stderr. The
223+
/// caller must ensure that no protocol references remain.
224+
/// * The pool allocator is not usable after exiting boot services. Types
225+
/// such as [`PoolString`] which call [`BootServices::free_pool`] on drop
226+
/// must be cleaned up before calling `exit_boot_services`, or leaked to
227+
/// avoid drop ever being called.
228+
/// * All data in the memory map marked as
229+
/// [`MemoryType::BOOT_SERVICES_CODE`] and
230+
/// [`MemoryType::BOOT_SERVICES_DATA`] will become free memory, the caller
231+
/// must ensure that no references to such memory exist.
213232
///
214233
/// # Errors
215234
///
@@ -220,8 +239,12 @@ impl SystemTable<Boot> {
220239
/// All errors are treated as unrecoverable because the system is
221240
/// now in an undefined state. Rather than returning control to the
222241
/// caller, the system will be reset.
242+
///
243+
/// [`helpers`]: crate::helpers
244+
/// [`Output`]: crate::proto::console::text::Output
245+
/// [`PoolString`]: crate::proto::device_path::text::PoolString
223246
#[must_use]
224-
pub fn exit_boot_services(
247+
pub unsafe fn exit_boot_services(
225248
self,
226249
memory_type: MemoryType,
227250
) -> (SystemTable<Runtime>, MemoryMap<'static>) {

0 commit comments

Comments
 (0)