diff --git a/uefi-services/src/lib.rs b/uefi-services/src/lib.rs index dcc01fa8d..a352834ba 100644 --- a/uefi-services/src/lib.rs +++ b/uefi-services/src/lib.rs @@ -26,6 +26,7 @@ extern crate log; extern crate uefi; use core::ffi::c_void; +use core::fmt::Write; use core::ptr::NonNull; use cfg_if::cfg_if; @@ -93,6 +94,53 @@ pub fn init(st: &mut SystemTable) -> Result { } } +// Internal function for print macros. +#[doc(hidden)] +pub fn _print(args: core::fmt::Arguments) { + unsafe { + let st = SYSTEM_TABLE + .as_mut() + .expect("The system table handle is not available"); + + st.stdout() + .write_fmt(args) + .expect("Failed to write to stdout"); + } +} + +/// Prints to the standard output. +/// +/// # Panics +/// Will panic if `SYSTEM_TABLE` is `None` (Before [init()] and after [uefi::prelude::SystemTable::exit_boot_services()]). +/// +/// # Examples +/// ``` +/// print!(""); +/// print!("Hello World\n"); +/// print!("Hello {}", "World"); +/// ``` +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::_print(core::format_args!($($arg)*))); +} + +/// Prints to the standard output, with a newline. +/// +/// # Panics +/// Will panic if `SYSTEM_TABLE` is `None` (Before [init()] and after [uefi::prelude::SystemTable::exit_boot_services()]). +/// +/// # Examples +/// ``` +/// println!(); +/// println!("Hello World"); +/// println!("Hello {}", "World"); +/// ``` +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::_print(core::format_args!("{}{}", core::format_args!($($arg)*), "\n"))); +} + /// Set up logging /// /// This is unsafe because you must arrange for the logger to be reset with diff --git a/uefi-test-runner/src/main.rs b/uefi-test-runner/src/main.rs index 4abe960e4..2d18969b5 100644 --- a/uefi-test-runner/src/main.rs +++ b/uefi-test-runner/src/main.rs @@ -11,6 +11,7 @@ use alloc::string::String; use uefi::prelude::*; use uefi::proto::console::serial::Serial; use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams}; +use uefi_services::{print, println}; mod boot; mod proto; @@ -28,6 +29,14 @@ fn efi_main(image: Handle, mut st: SystemTable) -> Status { st.firmware_vendor().as_str_in_buf(&mut buf).unwrap(); info!("Firmware Vendor: {}", buf.as_str()); + // Test print! and println! macros. + let (print, println) = ("print!", "println!"); // necessary for clippy to ignore + print!("Testing {} macro with formatting: {:#010b} ", print, 155u8); + println!( + "Testing {} macro with formatting: {:#010b} ", + println, 155u8 + ); + // Reset the console before running all the other tests. st.stdout().reset(false).expect("Failed to reset stdout");