//! 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: 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: 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: 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: 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) }