From af19c651ac431b90772b0810b8c9536a80a3ba69 Mon Sep 17 00:00:00 2001 From: maheeraeron Date: Wed, 20 May 2026 21:29:04 +0000 Subject: [PATCH 1/3] Force logs on reset or shutdown --- vm/devices/firmware/firmware_uefi/src/lib.rs | 28 ++++++++++++++++++- .../src/service/diagnostics/mod.rs | 9 ++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/vm/devices/firmware/firmware_uefi/src/lib.rs b/vm/devices/firmware/firmware_uefi/src/lib.rs index 78e5135487..14d39ce8fc 100644 --- a/vm/devices/firmware/firmware_uefi/src/lib.rs +++ b/vm/devices/firmware/firmware_uefi/src/lib.rs @@ -346,9 +346,35 @@ impl UefiDevice { impl ChangeDeviceState for UefiDevice { fn start(&mut self) {} - async fn stop(&mut self) {} + async fn stop(&mut self) { + // If the guest is shutting down without having gone through the normal UEFI + // diagnostics path (e.g. a custom bootloader that calls ResetSystem directly), + // process any pending diagnostics now before the buffer becomes inaccessible. + if self.service.diagnostics.has_unprocessed_diagnostics() { + let _ = self.process_diagnostics( + false, + service::diagnostics::DiagnosticsEmitter::Tracing { + limit: Some(WATCHDOG_LOGS_PER_PERIOD), + }, + Some(LogLevel::make_info()), + ); + } + } async fn reset(&mut self) { + // If the guest is resetting without having gone through the normal UEFI + // diagnostics path (e.g. a custom bootloader that calls ResetSystem directly), + // process any pending diagnostics before clearing state. + if self.service.diagnostics.has_unprocessed_diagnostics() { + let _ = self.process_diagnostics( + false, + service::diagnostics::DiagnosticsEmitter::Tracing { + limit: Some(WATCHDOG_LOGS_PER_PERIOD), + }, + Some(LogLevel::make_info()), + ); + } + self.address = 0; self.service.nvram.reset(); diff --git a/vm/devices/firmware/firmware_uefi/src/service/diagnostics/mod.rs b/vm/devices/firmware/firmware_uefi/src/service/diagnostics/mod.rs index 5e8b17bb15..2d3e91bb6b 100644 --- a/vm/devices/firmware/firmware_uefi/src/service/diagnostics/mod.rs +++ b/vm/devices/firmware/firmware_uefi/src/service/diagnostics/mod.rs @@ -178,6 +178,15 @@ impl DiagnosticsServices { self.processed = false; } + /// Returns true if a GPA has been set and diagnostics have not yet been processed. + /// + /// Used to detect cases where the guest resets or shuts down without going through + /// the normal UEFI crash path or ExitBootServices, so that the caller can trigger + /// processing before discarding the buffer. + pub fn has_unprocessed_diagnostics(&self) -> bool { + self.gpa.is_some() && !self.processed + } + /// Set the GPA of the diagnostics buffer pub fn set_gpa(&mut self, gpa: u32) { self.gpa = Gpa::new(gpa).ok(); From 267cf9d6551e71a3ee4bdcb09d4c728c18a8bfcf Mon Sep 17 00:00:00 2001 From: maheeraeron Date: Wed, 20 May 2026 22:13:37 +0000 Subject: [PATCH 2/3] feedback --- vm/devices/firmware/firmware_uefi/src/lib.rs | 51 +++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/vm/devices/firmware/firmware_uefi/src/lib.rs b/vm/devices/firmware/firmware_uefi/src/lib.rs index 14d39ce8fc..22d7050717 100644 --- a/vm/devices/firmware/firmware_uefi/src/lib.rs +++ b/vm/devices/firmware/firmware_uefi/src/lib.rs @@ -341,39 +341,44 @@ impl UefiDevice { Result::<_, std::convert::Infallible>::Ok(output.unwrap_or_else(|| USAGE.to_string())) }); } -} - -impl ChangeDeviceState for UefiDevice { - fn start(&mut self) {} - async fn stop(&mut self) { - // If the guest is shutting down without having gone through the normal UEFI - // diagnostics path (e.g. a custom bootloader that calls ResetSystem directly), - // process any pending diagnostics now before the buffer becomes inaccessible. + /// Process diagnostics if a GPA has been configured but logs have not yet + /// been processed. + fn process_pending_diagnostics(&mut self, trigger: &'static str) { if self.service.diagnostics.has_unprocessed_diagnostics() { + tracing::info!(%trigger, "processing pending UEFI diagnostics"); let _ = self.process_diagnostics( false, - service::diagnostics::DiagnosticsEmitter::Tracing { - limit: Some(WATCHDOG_LOGS_PER_PERIOD), - }, + service::diagnostics::DiagnosticsEmitter::Tracing { limit: None }, Some(LogLevel::make_info()), ); } } + /// Best-effort flush for teardown/halt paths that occur outside the normal + /// UEFI signaling flow. + pub fn flush_pending_diagnostics_for_halt(&mut self, trigger: &'static str) { + self.process_pending_diagnostics(trigger); + } +} + +impl Drop for UefiDevice { + fn drop(&mut self) { + // Best-effort fallback for teardown paths that do not invoke explicit + // ChangeDeviceState::stop/reset transitions. + self.process_pending_diagnostics("drop"); + } +} + +impl ChangeDeviceState for UefiDevice { + fn start(&mut self) {} + + async fn stop(&mut self) { + self.process_pending_diagnostics("stop"); + } + async fn reset(&mut self) { - // If the guest is resetting without having gone through the normal UEFI - // diagnostics path (e.g. a custom bootloader that calls ResetSystem directly), - // process any pending diagnostics before clearing state. - if self.service.diagnostics.has_unprocessed_diagnostics() { - let _ = self.process_diagnostics( - false, - service::diagnostics::DiagnosticsEmitter::Tracing { - limit: Some(WATCHDOG_LOGS_PER_PERIOD), - }, - Some(LogLevel::make_info()), - ); - } + self.process_pending_diagnostics("reset"); self.address = 0; From a2ccade05c267eb98597effc64035817ac86b385 Mon Sep 17 00:00:00 2001 From: maheeraeron Date: Wed, 20 May 2026 22:15:43 +0000 Subject: [PATCH 3/3] Remove unused func --- vm/devices/firmware/firmware_uefi/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/vm/devices/firmware/firmware_uefi/src/lib.rs b/vm/devices/firmware/firmware_uefi/src/lib.rs index 22d7050717..1fa60828fe 100644 --- a/vm/devices/firmware/firmware_uefi/src/lib.rs +++ b/vm/devices/firmware/firmware_uefi/src/lib.rs @@ -354,12 +354,6 @@ impl UefiDevice { ); } } - - /// Best-effort flush for teardown/halt paths that occur outside the normal - /// UEFI signaling flow. - pub fn flush_pending_diagnostics_for_halt(&mut self, trigger: &'static str) { - self.process_pending_diagnostics(trigger); - } } impl Drop for UefiDevice {