Skip to content

Commit f8ce0bd

Browse files
Add uefi::system module
This is similar to existing methods of `SystemTable`, but as freestanding functions that use the global system table pointer.
1 parent f3a603e commit f8ce0bd

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

uefi/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# uefi - [Unreleased]
22

3+
## Added
4+
- `uefi::system` is a new module that provides freestanding functions for
5+
accessing fields of the global system table.
6+
37
## Changed
48
- **Breaking:** `uefi::helpers::init` no longer takes an argument.
59
- The lifetime of the `SearchType` returned from

uefi/src/lib.rs

+1
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

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//! Functions for accessing fields of the system table.
2+
//!
3+
//! Some of these functions use a callback argument rather than returning a
4+
//! reference to the field directly. This pattern is used because some fields
5+
//! are allowed to change, and so a static lifetime cannot be used.
6+
//!
7+
//! Some functions can only be called while boot services are active, and will
8+
//! panic otherwise. See each function's documentation for details.
9+
10+
use crate::proto::console::text::{Input, Output};
11+
use crate::table::cfg::ConfigTableEntry;
12+
use crate::table::{self, Revision};
13+
use crate::{CStr16, Char16};
14+
use core::slice;
15+
16+
/// Get the firmware vendor string.
17+
#[must_use]
18+
pub fn firmware_vendor() -> &'static CStr16 {
19+
let st = table::system_table_raw();
20+
// SAFETY: valid per requirements of `set_system_table`.
21+
let st = unsafe { st.as_ref() };
22+
23+
let vendor: *const Char16 = st.firmware_vendor.cast();
24+
25+
// SAFETY: this assumes that the firmware vendor string is never mutated or freed.
26+
unsafe { CStr16::from_ptr(vendor) }
27+
}
28+
29+
/// Get the firmware revision.
30+
#[must_use]
31+
pub fn firmware_revision() -> u32 {
32+
let st = table::system_table_raw();
33+
// SAFETY: valid per requirements of `set_system_table`.
34+
let st = unsafe { st.as_ref() };
35+
36+
st.firmware_revision
37+
}
38+
39+
/// Get the revision of the system table, which is defined to be the revision of
40+
/// the UEFI specification implemented by the firmware.
41+
#[must_use]
42+
pub fn uefi_revision() -> Revision {
43+
let st = table::system_table_raw();
44+
// SAFETY: valid per requirements of `set_system_table`.
45+
let st = unsafe { st.as_ref() };
46+
47+
st.header.revision
48+
}
49+
50+
/// Call `f` with a slice of [`ConfigTableEntry`]. Each entry provides access to
51+
/// a vendor-specific table.
52+
pub fn with_config_table<F, R>(f: F) -> R
53+
where
54+
F: Fn(&[ConfigTableEntry]) -> R,
55+
{
56+
let st = table::system_table_raw();
57+
// SAFETY: valid per requirements of `set_system_table`.
58+
let st = unsafe { st.as_ref() };
59+
60+
let ptr: *const ConfigTableEntry = st.configuration_table.cast();
61+
let len = st.number_of_configuration_table_entries;
62+
let slice = if ptr.is_null() {
63+
&[]
64+
} else {
65+
unsafe { slice::from_raw_parts(ptr, len) }
66+
};
67+
f(slice)
68+
}
69+
70+
/// Call `f` with the [`Input`] protocol attached to stdin.
71+
///
72+
/// # Panics
73+
///
74+
/// This function will panic if called after exiting boot services, or if stdin
75+
/// is not available.
76+
pub fn with_stdin<F, R>(f: F) -> R
77+
where
78+
F: Fn(&mut Input) -> R,
79+
{
80+
let st = table::system_table_raw();
81+
// SAFETY: valid per requirements of `set_system_table`.
82+
let st = unsafe { st.as_ref() };
83+
// The I/O protocols cannot be used after exiting boot services.
84+
assert!(!st.boot_services.is_null(), "boot services are not active");
85+
assert!(!st.stdin.is_null(), "stdin is not available");
86+
87+
let stdin: *mut Input = st.stdin.cast();
88+
89+
// SAFETY: `Input` is a `repr(transparent)` wrapper around the raw input
90+
// type. The underlying pointer in the system table is assumed to be valid.
91+
let stdin = unsafe { &mut *stdin };
92+
93+
f(stdin)
94+
}
95+
96+
/// Call `f` with the [`Output`] protocol attached to stdout.
97+
///
98+
/// # Panics
99+
///
100+
/// This function will panic if called after exiting boot services, or if stdout
101+
/// is not available.
102+
pub fn with_stdout<F, R>(f: F) -> R
103+
where
104+
F: Fn(&mut Output) -> R,
105+
{
106+
let st = table::system_table_raw();
107+
// SAFETY: valid per requirements of `set_system_table`.
108+
let st = unsafe { st.as_ref() };
109+
// The I/O protocols cannot be used after exiting boot services.
110+
assert!(!st.boot_services.is_null(), "boot services are not active");
111+
assert!(!st.stdout.is_null(), "stdout is not available");
112+
113+
let stdout: *mut Output = st.stdout.cast();
114+
115+
// SAFETY: `Output` is a `repr(transparent)` wrapper around the raw output
116+
// type. The underlying pointer in the system table is assumed to be valid.
117+
let stdout = unsafe { &mut *stdout };
118+
119+
f(stdout)
120+
}
121+
122+
/// Call `f` with the [`Output`] protocol attached to stderr.
123+
///
124+
/// # Panics
125+
///
126+
/// This function will panic if called after exiting boot services, or if stderr
127+
/// is not available.
128+
pub fn with_stderr<F, R>(f: F) -> R
129+
where
130+
F: Fn(&mut Output) -> R,
131+
{
132+
let st = table::system_table_raw();
133+
// SAFETY: valid per requirements of `set_system_table`.
134+
let st = unsafe { st.as_ref() };
135+
// The I/O protocols cannot be used after exiting boot services.
136+
assert!(!st.boot_services.is_null(), "boot services are not active");
137+
assert!(!st.stderr.is_null(), "stderr is not available");
138+
139+
let stderr: *mut Output = st.stderr.cast();
140+
141+
// SAFETY: `Output` is a `repr(transparent)` wrapper around the raw output
142+
// type. The underlying pointer in the system table is assumed to be valid.
143+
let stderr = unsafe { &mut *stderr };
144+
145+
f(stderr)
146+
}

0 commit comments

Comments
 (0)