| //! Functions for accessing fields of the system table. |
| //! |
| //! Some of these functions use a callback argument rather than returning a |
| //! reference to the field directly. This pattern is used because some fields |
| //! are allowed to change, and so a static lifetime cannot be used. |
| //! |
| //! Some functions can only be called while boot services are active, and will |
| //! panic otherwise. See each function's documentation for details. |
| |
| use crate::proto::console::text::{Input, Output}; |
| use crate::table::cfg::ConfigTableEntry; |
| use crate::table::{self, Revision}; |
| use crate::{CStr16, Char16}; |
| use core::slice; |
| |
| /// Get the firmware vendor string. |
| #[must_use] |
| pub fn firmware_vendor() -> &'static CStr16 { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| |
| let vendor: *const Char16 = st.firmware_vendor.cast(); |
| |
| // SAFETY: this assumes that the firmware vendor string is never mutated or freed. |
| unsafe { CStr16::from_ptr(vendor) } |
| } |
| |
| /// Get the firmware revision. |
| #[must_use] |
| pub fn firmware_revision() -> u32 { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| |
| st.firmware_revision |
| } |
| |
| /// Get the revision of the system table, which is defined to be the revision of |
| /// the UEFI specification implemented by the firmware. |
| #[must_use] |
| pub fn uefi_revision() -> Revision { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| |
| st.header.revision |
| } |
| |
| /// Call `f` with a slice of [`ConfigTableEntry`]. Each entry provides access to |
| /// a vendor-specific table. |
| pub fn with_config_table<F, R>(f: F) -> R |
| where |
| F: Fn(&[ConfigTableEntry]) -> R, |
| { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| |
| let ptr: *const ConfigTableEntry = st.configuration_table.cast(); |
| let len = st.number_of_configuration_table_entries; |
| let slice = if ptr.is_null() { |
| &[] |
| } else { |
| unsafe { slice::from_raw_parts(ptr, len) } |
| }; |
| f(slice) |
| } |
| |
| /// Call `f` with the [`Input`] protocol attached to stdin. |
| /// |
| /// # Panics |
| /// |
| /// This function will panic if called after exiting boot services, or if stdin |
| /// is not available. |
| pub fn with_stdin<F, R>(f: F) -> R |
| where |
| F: Fn(&mut Input) -> R, |
| { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| // The I/O protocols cannot be used after exiting boot services. |
| assert!(!st.boot_services.is_null(), "boot services are not active"); |
| assert!(!st.stdin.is_null(), "stdin is not available"); |
| |
| let stdin: *mut Input = st.stdin.cast(); |
| |
| // SAFETY: `Input` is a `repr(transparent)` wrapper around the raw input |
| // type. The underlying pointer in the system table is assumed to be valid. |
| let stdin = unsafe { &mut *stdin }; |
| |
| f(stdin) |
| } |
| |
| /// Call `f` with the [`Output`] protocol attached to stdout. |
| /// |
| /// # Panics |
| /// |
| /// This function will panic if called after exiting boot services, or if stdout |
| /// is not available. |
| pub fn with_stdout<F, R>(f: F) -> R |
| where |
| F: Fn(&mut Output) -> R, |
| { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| // The I/O protocols cannot be used after exiting boot services. |
| assert!(!st.boot_services.is_null(), "boot services are not active"); |
| assert!(!st.stdout.is_null(), "stdout is not available"); |
| |
| let stdout: *mut Output = st.stdout.cast(); |
| |
| // SAFETY: `Output` is a `repr(transparent)` wrapper around the raw output |
| // type. The underlying pointer in the system table is assumed to be valid. |
| let stdout = unsafe { &mut *stdout }; |
| |
| f(stdout) |
| } |
| |
| /// Call `f` with the [`Output`] protocol attached to stderr. |
| /// |
| /// # Panics |
| /// |
| /// This function will panic if called after exiting boot services, or if stderr |
| /// is not available. |
| pub fn with_stderr<F, R>(f: F) -> R |
| where |
| F: Fn(&mut Output) -> R, |
| { |
| let st = table::system_table_raw_panicking(); |
| // SAFETY: valid per requirements of `set_system_table`. |
| let st = unsafe { st.as_ref() }; |
| // The I/O protocols cannot be used after exiting boot services. |
| assert!(!st.boot_services.is_null(), "boot services are not active"); |
| assert!(!st.stderr.is_null(), "stderr is not available"); |
| |
| let stderr: *mut Output = st.stderr.cast(); |
| |
| // SAFETY: `Output` is a `repr(transparent)` wrapper around the raw output |
| // type. The underlying pointer in the system table is assumed to be valid. |
| let stderr = unsafe { &mut *stderr }; |
| |
| f(stderr) |
| } |