openhcl_boot/
boot_logger.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Logging support for the bootshim.
5//!
6//! The bootshim performs no filtering of its logging messages when running in
7//! a confidential VM. This is because it runs before any keys can be accessed
8//! or any guest code is executed, and therefore it can not leak anything
9//! sensitive.
10
11#[cfg(target_arch = "x86_64")]
12use crate::arch::tdx::TdxIoAccess;
13use crate::host_params::shim_params::IsolationType;
14use crate::single_threaded::SingleThreaded;
15use core::cell::RefCell;
16use core::fmt;
17use core::fmt::Write;
18#[cfg(target_arch = "x86_64")]
19use minimal_rt::arch::InstrIoAccess;
20use minimal_rt::arch::Serial;
21
22enum Logger {
23    #[cfg(target_arch = "x86_64")]
24    Serial(Serial<InstrIoAccess>),
25    #[cfg(target_arch = "aarch64")]
26    Serial(Serial),
27    #[cfg(target_arch = "x86_64")]
28    TdxSerial(Serial<TdxIoAccess>),
29    None,
30}
31
32impl Logger {
33    fn write_str(&mut self, s: &str) -> fmt::Result {
34        match self {
35            Logger::Serial(serial) => serial.write_str(s),
36            #[cfg(target_arch = "x86_64")]
37            Logger::TdxSerial(serial) => serial.write_str(s),
38            Logger::None => Ok(()),
39        }
40    }
41}
42
43pub struct BootLogger {
44    logger: SingleThreaded<RefCell<Logger>>,
45}
46
47pub static BOOT_LOGGER: BootLogger = BootLogger {
48    logger: SingleThreaded(RefCell::new(Logger::None)),
49};
50
51/// Initialize the boot logger. This replaces any previous init calls.
52pub fn boot_logger_init(isolation_type: IsolationType, com3_serial_available: bool) {
53    let mut logger = BOOT_LOGGER.logger.borrow_mut();
54
55    *logger = match (isolation_type, com3_serial_available) {
56        #[cfg(target_arch = "x86_64")]
57        (IsolationType::None, true) => Logger::Serial(Serial::init(InstrIoAccess)),
58        #[cfg(target_arch = "aarch64")]
59        (IsolationType::None, true) => Logger::Serial(Serial::init()),
60        #[cfg(target_arch = "x86_64")]
61        (IsolationType::Tdx, true) => Logger::TdxSerial(Serial::init(TdxIoAccess)),
62        _ => Logger::None,
63    };
64}
65
66impl Write for &BootLogger {
67    fn write_str(&mut self, s: &str) -> fmt::Result {
68        self.logger.borrow_mut().write_str(s)
69    }
70}
71
72/// Log a message. These messages are always emitted regardless of debug or
73/// release, if a corresponding logger was configured.
74///
75/// If you want to log something just for local debugging, use [`debug_log!`]
76/// instead.
77macro_rules! log {
78    () => {};
79    ($($arg:tt)*) => {
80        {
81            use core::fmt::Write;
82            let _ = writeln!(&$crate::boot_logger::BOOT_LOGGER, $($arg)*);
83        }
84    };
85}
86
87pub(crate) use log;
88
89/// This emits the same as [`log!`], but is intended for local debugging and is
90/// linted against to not pass CI. Use for local development when you just need
91/// debug prints.
92//
93// Expect unused macros for the same reason as unused_imports below, as there
94// should be no usage of this macro normally.
95#[expect(unused_macros)]
96macro_rules! debug_log {
97    ($($arg:tt)*) => {
98        $crate::boot_logger::log!($($arg)*)
99    };
100}
101
102// Expect unused imports because there should be no normal usage in code due to
103// lints against it in CI.
104#[expect(unused_imports)]
105pub(crate) use debug_log;