openhcl_boot/
boot_logger.rs1#[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
12use crate::arch::snp::SnpSerialBackend;
13#[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
14use crate::arch::tdx::TdxSerialBackend;
15use crate::host_params::shim_params::IsolationType;
16use crate::single_threaded::SingleThreaded;
17use core::cell::RefCell;
18use core::fmt;
19use core::fmt::Write;
20use host_fdt_parser::ComInfo;
21use memory_range::MemoryRange;
22#[cfg(target_arch = "aarch64")]
23use minimal_rt::arch::Serial;
24use string_page_buf::StringBuffer;
25#[cfg(target_arch = "x86_64")]
26use uart_16550::BaudRate;
27#[cfg(target_arch = "x86_64")]
28use uart_16550::Config;
29#[cfg(target_arch = "x86_64")]
30use uart_16550::Uart16550;
31#[cfg(target_arch = "x86_64")]
32use uart_16550::Uart16550Tty;
33#[cfg(target_arch = "x86_64")]
34use uart_16550::backend::Backend;
35#[cfg(target_arch = "x86_64")]
36use uart_16550::backend::PioBackend;
37
38enum Logger {
39 #[cfg(target_arch = "x86_64")]
40 Serial(Uart16550Tty<PioBackend>),
41 #[cfg(target_arch = "aarch64")]
42 #[expect(dead_code)]
43 Serial(Serial),
44 #[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
45 TdxSerial(Uart16550Tty<TdxSerialBackend>),
46 #[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
47 SnpSerial(Uart16550Tty<SnpSerialBackend>),
48 None,
49}
50
51#[cfg(target_arch = "x86_64")]
55fn init_serial<B: Backend>(mut uart: Uart16550<B>, baud_rate: u32) -> Option<Uart16550Tty<B>> {
56 if baud_rate == 0 {
59 return None;
60 }
61 let config = Config {
62 baud_rate: BaudRate::Custom(baud_rate),
63 ..Config::DEFAULT
64 };
65 uart.init(config).ok()?;
66 Some(Uart16550Tty::from_inner(uart))
67}
68
69impl Logger {
70 fn write_str(&mut self, s: &str) -> fmt::Result {
71 match self {
72 Logger::Serial(serial) => serial.write_str(s),
73 #[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
74 Logger::TdxSerial(serial) => serial.write_str(s),
75 #[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
76 Logger::SnpSerial(serial) => serial.write_str(s),
77 Logger::None => Ok(()),
78 }
79 }
80}
81
82pub struct BootLogger {
83 logger: SingleThreaded<RefCell<Logger>>,
84 in_memory_logger: SingleThreaded<RefCell<Option<StringBuffer<'static>>>>,
85}
86
87pub static BOOT_LOGGER: BootLogger = BootLogger {
88 logger: SingleThreaded(RefCell::new(Logger::None)),
89 in_memory_logger: SingleThreaded(RefCell::new(None)),
90};
91
92pub fn boot_logger_memory_init(buffer: MemoryRange) {
95 if buffer.is_empty() {
96 return;
97 }
98
99 let log_buffer_ptr = buffer.start() as *mut u8;
100 let log_buffer_slice =
106 unsafe { core::slice::from_raw_parts_mut(log_buffer_ptr, buffer.len() as usize) };
107
108 *BOOT_LOGGER.in_memory_logger.borrow_mut() = Some(
109 StringBuffer::new(log_buffer_slice)
110 .expect("log buffer should be valid from fixed at build config"),
111 );
112}
113
114pub fn boot_logger_runtime_init(isolation_type: IsolationType, com3_serial_available: ComInfo) {
119 let mut logger = BOOT_LOGGER.logger.borrow_mut();
120
121 *logger = match (isolation_type, com3_serial_available) {
122 #[cfg(target_arch = "x86_64")]
123 (IsolationType::None | IsolationType::Vbs, ComInfo::Ns16550 { current_speed, .. }) => {
124 init_serial(minimal_rt::arch::com3(), current_speed)
125 .map_or(Logger::None, Logger::Serial)
126 }
127 #[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
132 (IsolationType::Tdx, ComInfo::Ns16550 { current_speed, .. }) => {
133 let backend = TdxSerialBackend(minimal_rt::arch::COM3);
134 let uart = unsafe { Uart16550::new_with_backend(backend) };
137 init_serial(uart, current_speed).map_or(Logger::None, Logger::TdxSerial)
138 }
139 #[cfg(all(target_arch = "x86_64", feature = "cvm_boot_log"))]
140 (IsolationType::Snp, ComInfo::Ns16550 { current_speed, .. }) => {
141 let backend = SnpSerialBackend(minimal_rt::arch::COM3);
142 let uart = unsafe { Uart16550::new_with_backend(backend) };
145 init_serial(uart, current_speed).map_or(Logger::None, Logger::SnpSerial)
146 }
147 _ => Logger::None,
148 };
149
150 if let Some(buf) = BOOT_LOGGER.in_memory_logger.borrow_mut().as_mut() {
152 let _ = logger.write_str(buf.contents());
153 }
154}
155
156impl Write for &BootLogger {
157 fn write_str(&mut self, s: &str) -> fmt::Result {
158 if let Some(buf) = self.in_memory_logger.borrow_mut().as_mut() {
159 let _ = buf.append(s);
161 }
162 self.logger.borrow_mut().write_str(s)
163 }
164}
165
166impl log::Log for BootLogger {
167 fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
168 true
170 }
171
172 fn log(&self, record: &log::Record<'_>) {
173 let _ = writeln!(&*self, "[{}] {}", record.level(), record.args());
174 }
175
176 fn flush(&self) {}
177}