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]
firmware_vendor() -> &'static CStr1618 pub fn firmware_vendor() -> &'static CStr16 {
19     let st = table::system_table_raw_panicking();
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]
firmware_revision() -> u3231 pub fn firmware_revision() -> u32 {
32     let st = table::system_table_raw_panicking();
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]
uefi_revision() -> Revision42 pub fn uefi_revision() -> Revision {
43     let st = table::system_table_raw_panicking();
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.
with_config_table<F, R>(f: F) -> R where F: Fn(&[ConfigTableEntry]) -> R,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_panicking();
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.
with_stdin<F, R>(f: F) -> R where F: Fn(&mut Input) -> R,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_panicking();
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.
with_stdout<F, R>(f: F) -> R where F: Fn(&mut Output) -> R,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_panicking();
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.
with_stderr<F, R>(f: F) -> R where F: Fn(&mut Output) -> R,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_panicking();
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 }
147