Skip to content

Commit 65a215d

Browse files
Merge pull request #1172 from phip1611/debugcon
uefi/helpers: logger logs to debugcon device
2 parents 3f9a5f2 + 1607f5d commit 65a215d

File tree

7 files changed

+89
-15
lines changed

7 files changed

+89
-15
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33

44
# Files generated by mdBook.
55
/book/book/
6+
7+
# Integration test output by QEMU.
8+
integration-test-debugcon.log

uefi-test-runner/src/main.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,23 @@ fn shutdown(mut st: SystemTable<Boot>) -> ! {
196196
// type of regression this prevents.
197197
info!("LOGGING_STILL_WORKING_RIGHT_BEFORE_EBS");
198198

199-
info!("Testing complete, shutting down...");
199+
info!("Testing complete, exiting boot services...");
200200

201201
// Exit boot services as a proof that it works :)
202-
let (st, _iter) = st.exit_boot_services(MemoryType::LOADER_DATA);
202+
let (st, mmap) = st.exit_boot_services(MemoryType::LOADER_DATA);
203+
204+
info!("Memory Map:");
205+
for desc in mmap.entries() {
206+
info!(
207+
"start=0x{:016x} size=0x{:016x} type={:?}, attr={:?}",
208+
desc.phys_start,
209+
desc.page_count * 4096,
210+
desc.ty,
211+
desc.att
212+
);
213+
}
214+
215+
info!("Shutting down...");
203216

204217
#[cfg(target_arch = "x86_64")]
205218
{

uefi/CHANGELOG.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
## Added
44
- Added `RuntimeServices::update_capsule`.
55
- Added `RuntimeServices::query_capsule_capabilities`.
6+
- The logger from `uefi::helpers` now also logs to the [debugcon](https://phip1611.de/blog/how-to-use-qemus-debugcon-feature/)
7+
device (QEMU) respectively the debug-console (cloud-hypervisor). This only
8+
works on x86. It is activated by default (only on x86) and can be deactivated
9+
by removing the `log-debugcon` cargo feature. The major benefit is that one
10+
can get log messages even after one exited the boot services.
611

712
## Removed
813
- Removed the `panic-on-logger-errors` feature of the `uefi` crate. Logger
@@ -13,8 +18,6 @@
1318

1419
## Added
1520
- Added `ResetNotification` protocol.
16-
17-
## Added
1821
- Added `Timestamp` protocol.
1922
- Added `UnalignedSlice::as_ptr`.
2023
- Added common derives for `Event` and `Handle`.

uefi/Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ repository.workspace = true
1313
rust-version.workspace = true
1414

1515
[features]
16+
default = [ "log-debugcon" ]
1617
alloc = []
1718

1819
# Generic gate to code that uses unstable features of Rust. You usually need a nightly toolchain.
@@ -22,7 +23,14 @@ unstable = []
2223
logger = []
2324
global_allocator = []
2425
panic_handler = []
25-
qemu = ["dep:qemu-exit", "panic_handler"] # panic_handler: logical, not technical dependency
26+
# Some convenience when running inside QEMU.
27+
# - dependency log-debugcon: logical, not technical
28+
# - dependency panic_handler: logical, not technical
29+
qemu = ["dep:qemu-exit", "panic_handler", "log-debugcon"]
30+
# Whether the internal logger from the helpers module should also log to
31+
# the debugcon device (QEMU) and debug-console (cloud-hypervisor). Only works
32+
# on x86.
33+
log-debugcon = []
2634

2735
[dependencies]
2836
bitflags.workspace = true

uefi/src/helpers/logger.rs

+47-8
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
//! The last part also means that some Unicode characters might not be
1313
//! supported by the UEFI console. Don't expect emoji output support.
1414
15-
use crate::proto::console::text::Output;
16-
1715
use crate::prelude::{Boot, SystemTable};
16+
use crate::proto::console::text::Output;
1817
use core::fmt::{self, Write};
1918
use core::ptr;
2019
use core::sync::atomic::{AtomicPtr, Ordering};
@@ -43,6 +42,31 @@ pub fn disable() {
4342
LOGGER.disable();
4443
}
4544

45+
/// Writer to the QEMU debugcon device and the debug-console of
46+
/// cloud-hypervisor.
47+
///
48+
/// More info: <https://phip1611.de/blog/how-to-use-qemus-debugcon-feature/>
49+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
50+
#[derive(Copy, Clone, Debug)]
51+
struct DebugconWriter;
52+
53+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
54+
impl DebugconWriter {
55+
const IO_PORT: u16 = 0xe9;
56+
}
57+
58+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
59+
impl core::fmt::Write for DebugconWriter {
60+
fn write_str(&mut self, s: &str) -> fmt::Result {
61+
for &byte in s.as_bytes() {
62+
unsafe {
63+
core::arch::asm!("outb %al, %dx", in("al") byte, in("dx") DebugconWriter::IO_PORT, options(att_syntax))
64+
};
65+
}
66+
Ok(())
67+
}
68+
}
69+
4670
/// Logging implementation which writes to a UEFI output stream.
4771
///
4872
/// If this logger is used as a global logger, you must disable it using the
@@ -99,15 +123,13 @@ impl Logger {
99123

100124
impl log::Log for Logger {
101125
fn enabled(&self, _metadata: &log::Metadata) -> bool {
102-
!self.output().is_null()
126+
// We decide in `log` already if something is printed. We do not
127+
// need micro optimizations here.
128+
true
103129
}
104130

105131
fn log(&self, record: &log::Record) {
106-
let output = self.output();
107-
108-
if !output.is_null() {
109-
let writer = unsafe { &mut *output };
110-
132+
if let Some(writer) = unsafe { self.output().as_mut() } {
111133
// Ignore all errors. Since we're in the logger implementation we
112134
// can't log the error. We also don't want to panic, since logging
113135
// is generally not critical functionality.
@@ -119,6 +141,23 @@ impl log::Log for Logger {
119141
record.line().unwrap_or(0),
120142
);
121143
}
144+
145+
#[cfg(all(
146+
any(target_arch = "x86", target_arch = "x86_64"),
147+
feature = "log-debugcon"
148+
))]
149+
{
150+
// Ignore all errors. Since we're in the logger implementation we
151+
// can't log the error. We also don't want to panic, since logging
152+
// is generally not critical functionality.
153+
let _ = DecoratedLog::write(
154+
&mut DebugconWriter,
155+
record.level(),
156+
record.args(),
157+
record.file().unwrap_or("<unknown file>"),
158+
record.line().unwrap_or(0),
159+
);
160+
}
122161
}
123162

124163
fn flush(&self) {

uefi/src/helpers/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
//!
55
//! For now, this includes:
66
//! - using [`uefi::allocator::Allocator`] as global allocator (feature `global_allocator`)
7-
//! - an implementation of [`log::Log`] (feature `logger`)
7+
//! - an implementation of [`log::Log`] (feature `logger`) which logs to
8+
//! the stdout text protocol of UEFI (as long as boot services were not
9+
//! excited) and to the [debugcon device](https://phip1611.de/blog/how-to-use-qemus-debugcon-feature/)
10+
//! (only on x86) (feature `log-debugcon`).
811
//! - [`print!`][print_macro] and [`println!`][println_macro] macros defaulting
912
//! to the uefi boot service stdout stream
1013
//! - default panic handler (feature `panic_handler`)
@@ -73,7 +76,8 @@ pub fn system_table() -> SystemTable<Boot> {
7376
/// memory allocation capabilities.
7477
///
7578
/// **PLEASE NOTE** that these helpers are meant for the pre exit boot service
76-
/// epoch.
79+
/// epoch. Limited functionality might work after exiting them, such as logging
80+
/// to the debugcon device.
7781
pub fn init(st: &mut SystemTable<Boot>) -> Result<()> {
7882
if system_table_opt().is_some() {
7983
// Avoid double initialization.

xtask/src/qemu.rs

+4
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,10 @@ pub fn run_qemu(arch: UefiArch, opt: &QemuOpt) -> Result<()> {
484484

485485
cmd.args(["-device", "virtio-rng-pci"]);
486486

487+
if arch == UefiArch::IA32 || arch == UefiArch::X86_64 {
488+
cmd.args(["-debugcon", "file:./integration-test-debugcon.log"]);
489+
}
490+
487491
// Set the boot menu timeout to zero. On aarch64 in particular this speeds
488492
// up the boot a lot. Note that we have to enable the menu here even though
489493
// we are skipping right past it, otherwise `splash-time` is ignored in

0 commit comments

Comments
 (0)