Skip to content

Commit a15b9d3

Browse files
wip: Add uefi::system module
1 parent 94c26d6 commit a15b9d3

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

uefi/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ pub use uguid::guid;
119119
mod result;
120120
pub use result::{Error, Result, ResultExt, Status, StatusExt};
121121

122+
pub mod system;
122123
pub mod table;
123124

124125
pub mod proto;

uefi/src/system.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//! TODO
2+
3+
use crate::proto::console::text;
4+
use crate::table::{cfg, Boot, Revision, SystemTable};
5+
use crate::CStr16;
6+
use core::ptr::{self, NonNull};
7+
use core::slice;
8+
use core::sync::atomic::{AtomicPtr, Ordering};
9+
10+
static SYSTEM_TABLE: AtomicPtr<uefi_raw::table::system::SystemTable> =
11+
AtomicPtr::new(ptr::null_mut());
12+
13+
/// Update the global system table pointer.
14+
///
15+
/// This is usually called automatically in the `main` entry point as part of
16+
/// [`set_main`]. It should not be called at any other point in time, unless the
17+
/// executable does not use [`set_main`], in which case it should be called once
18+
/// before calling any other functions in this crate.
19+
///
20+
/// # Safety
21+
///
22+
/// This function should only be called as described above. The pointer must
23+
/// point to a valid system table.
24+
///
25+
/// [`set_main`]: uefi::set_main
26+
pub unsafe fn set_system_table(system_table: *mut uefi_raw::table::system::SystemTable) {
27+
SYSTEM_TABLE.store(system_table, Ordering::Release);
28+
}
29+
30+
/// Get a pointer to the system table.
31+
///
32+
/// # Panics
33+
///
34+
/// Panics if [`set_system_table`] has not been called with a non-null pointer.
35+
pub(crate) fn system_table() -> NonNull<uefi_raw::table::system::SystemTable> {
36+
let st = SYSTEM_TABLE.load(Ordering::Acquire);
37+
NonNull::new(st).expect("set_system_table has not been called")
38+
}
39+
40+
/// TODO
41+
#[must_use]
42+
pub fn system_table_boot() -> SystemTable<Boot> {
43+
unsafe { SystemTable::<Boot>::from_ptr(system_table().as_ptr().cast()) }.unwrap()
44+
}
45+
46+
// TODO: is static lifetime OK for these returned references?
47+
48+
/// Get the firmware vendor string.
49+
#[must_use]
50+
pub fn firmware_vendor() -> &'static CStr16 {
51+
// SAFETY: the system table is valid as required by `set_system_table`.
52+
let st = unsafe { system_table().as_ref() };
53+
54+
// SAFETY: relies on two assumptions:
55+
// * The firmware vendor pointer is valid.
56+
// * The firmware vender string is never mutated.
57+
unsafe { CStr16::from_ptr(st.firmware_vendor.cast()) }
58+
}
59+
60+
/// Get the firmware revision.
61+
#[must_use]
62+
pub fn firmware_revision() -> u32 {
63+
// SAFETY: the system table is valid as required by `set_system_table`.
64+
let st = unsafe { system_table().as_ref() };
65+
st.firmware_revision
66+
}
67+
68+
/// Get the revision of the system table, which is defined to be the revision of
69+
/// the UEFI specification implemented by the firmware.
70+
#[must_use]
71+
pub fn uefi_revision() -> Revision {
72+
// SAFETY: the system table is valid as required by `set_system_table`.
73+
let st = unsafe { system_table().as_ref() };
74+
st.header.revision
75+
}
76+
77+
/// Get the config table entries, a linear array of structures pointing to other
78+
/// system-specific tables.
79+
pub fn with_config_table<F, R>(f: F) -> R
80+
where
81+
F: Fn(&[cfg::ConfigTableEntry]) -> R,
82+
{
83+
let st = unsafe { system_table().as_mut() };
84+
85+
let ptr: *const cfg::ConfigTableEntry = st.configuration_table.cast();
86+
let len = st.number_of_configuration_table_entries;
87+
let slice = if ptr.is_null() {
88+
&[]
89+
} else {
90+
unsafe { slice::from_raw_parts(ptr, len) }
91+
};
92+
f(slice)
93+
}
94+
95+
/// Call `f` with the [`Output`] protocol attached to stdout.
96+
///
97+
/// [`Output`]: uefi::proto::console::text::Output
98+
pub fn with_stdout<F, R>(f: F) -> R
99+
where
100+
F: Fn(&mut text::Output) -> R,
101+
{
102+
// SAFETY: the system table is valid as required by `set_system_table`.
103+
let st = unsafe { system_table().as_ref() };
104+
105+
let output_ptr: *mut text::Output = st.stdout.cast();
106+
assert!(!output_ptr.is_null());
107+
108+
// SAFETY: assume the output pointer is valid.
109+
let output = unsafe { &mut *output_ptr };
110+
f(output)
111+
}

0 commit comments

Comments
 (0)