Skip to content

Commit 4cd692a

Browse files
authored
firmware_uefi: EfiDiagnostics backports for watchdog handling, tracelimit and other improvements (#1691)
This PR backports four PRs on EfiDiagnostics improvements and feature gaps. The four PRs are here: 1. #1668 2. #1677 3. #1693 4. #1706
1 parent 4f526e8 commit 4cd692a

File tree

13 files changed

+543
-235
lines changed

13 files changed

+543
-235
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3046,7 +3046,6 @@ dependencies = [
30463046
"vmswitch",
30473047
"vpci",
30483048
"watchdog_core",
3049-
"watchdog_vmgs_format",
30503049
"zerocopy 0.8.24",
30513050
]
30523051

@@ -9157,12 +9156,14 @@ version = "0.0.0"
91579156
dependencies = [
91589157
"async-trait",
91599158
"bitfield-struct 0.10.1",
9159+
"cvm_tracing",
91609160
"inspect",
91619161
"mesh",
91629162
"pal_async",
91639163
"thiserror 2.0.12",
91649164
"tracing",
91659165
"vmcore",
9166+
"watchdog_vmgs_format",
91669167
]
91679168

91689169
[[package]]
Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,60 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
use cvm_tracing::CVM_ALLOWED;
4+
//! An implementation of [`WatchdogPlatform`] for use with the Underhill
5+
//! environment.
6+
//!
7+
//! This implementation wraps over [`BaseWatchdogPlatform`] in
8+
//! [watchdog_core::platform::BaseWatchdogPlatform], providing additional
9+
//! functionality specific to the Underhill environment.
10+
511
use vmcore::non_volatile_store::NonVolatileStore;
12+
use watchdog_core::platform::BaseWatchdogPlatform;
13+
use watchdog_core::platform::WatchdogCallback;
614
use watchdog_core::platform::WatchdogPlatform;
7-
use watchdog_vmgs_format::WatchdogVmgsFormatStore;
815
use watchdog_vmgs_format::WatchdogVmgsFormatStoreError;
916

10-
/// An implementation of [`WatchdogPlatform`] for use with both the UEFI
11-
/// watchdog and the Guest Watchdog in Underhill.
12-
pub struct UnderhillWatchdog {
13-
store: WatchdogVmgsFormatStore,
17+
/// An implementation of [`WatchdogPlatform`] for the Underhill environment.
18+
pub struct UnderhillWatchdogPlatform {
19+
/// The base watchdog platform implementation
20+
base: BaseWatchdogPlatform,
21+
/// Handle to the guest emulation transport client
1422
get: guest_emulation_transport::GuestEmulationTransportClient,
15-
hook: Box<dyn WatchdogTimeout>,
16-
}
17-
18-
#[async_trait::async_trait]
19-
pub trait WatchdogTimeout: Send + Sync {
20-
async fn on_timeout(&self);
2123
}
2224

23-
impl UnderhillWatchdog {
25+
impl UnderhillWatchdogPlatform {
2426
pub async fn new(
2527
store: Box<dyn NonVolatileStore>,
2628
get: guest_emulation_transport::GuestEmulationTransportClient,
27-
hook: Box<dyn WatchdogTimeout>,
2829
) -> Result<Self, WatchdogVmgsFormatStoreError> {
29-
Ok(UnderhillWatchdog {
30-
store: WatchdogVmgsFormatStore::new(store).await?,
30+
Ok(UnderhillWatchdogPlatform {
31+
base: BaseWatchdogPlatform::new(store).await?,
3132
get,
32-
hook,
3333
})
3434
}
3535
}
3636

3737
#[async_trait::async_trait]
38-
impl WatchdogPlatform for UnderhillWatchdog {
38+
impl WatchdogPlatform for UnderhillWatchdogPlatform {
3939
async fn on_timeout(&mut self) {
40-
let res = self.store.set_boot_failure().await;
41-
if let Err(e) = res {
42-
tracing::error!(
43-
CVM_ALLOWED,
44-
error = &e as &dyn std::error::Error,
45-
"error persisting watchdog status"
46-
);
47-
}
48-
49-
// Call the hook before reporting this to the GET, as the hook may
50-
// want to do something before the host tears us down.
51-
self.hook.on_timeout().await;
40+
// Call the parent implementation first
41+
self.base.on_timeout().await;
5242

5343
// FUTURE: consider emitting different events for the UEFI watchdog vs.
5444
// the guest watchdog
45+
//
46+
// NOTE: This must be done last to ensure that all callbacks
47+
// have been executed before we log the event.
5548
self.get
5649
.event_log_fatal(get_protocol::EventLogId::WATCHDOG_TIMEOUT_RESET)
5750
.await;
5851
}
5952

6053
async fn read_and_clear_boot_status(&mut self) -> bool {
61-
let res = self.store.read_and_clear_boot_status().await;
62-
match res {
63-
Ok(status) => status,
64-
Err(e) => {
65-
tracing::error!(
66-
CVM_ALLOWED,
67-
error = &e as &dyn std::error::Error,
68-
"error reading watchdog status"
69-
);
70-
// assume no failure
71-
false
72-
}
73-
}
54+
self.base.read_and_clear_boot_status().await
55+
}
56+
57+
fn add_callback(&mut self, callback: Box<dyn WatchdogCallback>) {
58+
self.base.add_callback(callback);
7459
}
7560
}

openhcl/underhill_core/src/worker.rs

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ use crate::emuplat::non_volatile_store::VmbsBrokerNonVolatileStore;
3737
use crate::emuplat::tpm::resources::GetTpmLoggerHandle;
3838
use crate::emuplat::tpm::resources::GetTpmRequestAkCertHelperHandle;
3939
use crate::emuplat::vga_proxy::UhRegisterHostIoFastPath;
40-
use crate::emuplat::watchdog::UnderhillWatchdog;
41-
use crate::emuplat::watchdog::WatchdogTimeout;
40+
use crate::emuplat::watchdog::UnderhillWatchdogPlatform;
4241
use crate::loader::LoadKind;
4342
use crate::loader::vtl0_config::MeasuredVtl0Info;
4443
use crate::loader::vtl2_config::RuntimeParameters;
@@ -177,6 +176,8 @@ use vmotherboard::BaseChipsetBuilderOutput;
177176
use vmotherboard::ChipsetDeviceHandle;
178177
use vmotherboard::options::BaseChipsetDevices;
179178
use vmotherboard::options::BaseChipsetFoundation;
179+
use watchdog_core::platform::WatchdogCallback;
180+
use watchdog_core::platform::WatchdogPlatform;
180181
use zerocopy::FromZeros;
181182

182183
pub(crate) const PM_BASE: u16 = 0x400;
@@ -2070,6 +2071,7 @@ async fn new_underhill_vm(
20702071
},
20712072
};
20722073

2074+
let (watchdog_send, watchdog_recv) = mesh::channel();
20732075
deps_hyperv_firmware_uefi = Some(dev::HyperVFirmwareUefi {
20742076
config,
20752077
logger: Box::new(UnderhillLogger {
@@ -2093,20 +2095,30 @@ async fn new_underhill_vm(
20932095
// UEFI watchdog doesn't persist to VMGS at this time
20942096
let store = EphemeralNonVolatileStore::new_boxed();
20952097

2098+
// Create base watchdog platform
2099+
let mut underhill_watchdog_platform =
2100+
UnderhillWatchdogPlatform::new(store, get_client.clone()).await?;
2101+
2102+
// Inject NMI on watchdog timeout
20962103
#[cfg(guest_arch = "x86_64")]
2097-
let watchdog_reset = WatchdogTimeoutNmi {
2104+
let watchdog_callback = WatchdogTimeoutNmi {
20982105
partition: partition.clone(),
2106+
watchdog_send: Some(watchdog_send),
20992107
};
2108+
2109+
// ARM64 does not have NMI support yet, so halt instead
21002110
#[cfg(guest_arch = "aarch64")]
2101-
let watchdog_reset = WatchdogTimeoutHalt {
2111+
let watchdog_callback = WatchdogTimeoutReset {
21022112
halt_vps: halt_vps.clone(),
2113+
watchdog_send: Some(watchdog_send),
21032114
};
21042115

2105-
Box::new(
2106-
UnderhillWatchdog::new(store, get_client.clone(), Box::new(watchdog_reset))
2107-
.await?,
2108-
)
2116+
// Add the callback
2117+
underhill_watchdog_platform.add_callback(Box::new(watchdog_callback));
2118+
2119+
Box::new(underhill_watchdog_platform)
21092120
},
2121+
watchdog_recv,
21102122
vsm_config: Some(Box::new(UnderhillVsmConfig {
21112123
partition: Arc::downgrade(&partition),
21122124
})),
@@ -2424,14 +2436,18 @@ async fn new_underhill_vm(
24242436
let store = vmgs_client
24252437
.as_non_volatile_store(vmgs::FileId::GUEST_WATCHDOG, false)
24262438
.context("failed to instantiate guest watchdog store")?;
2427-
let trigger_reset = WatchdogTimeoutHalt {
2439+
2440+
let watchdog_callback = WatchdogTimeoutReset {
24282441
halt_vps: halt_vps.clone(),
2442+
watchdog_send: None, // This is not the UEFI watchdog, so no need to send
2443+
// watchdog notifications.
24292444
};
24302445

2431-
Box::new(
2432-
UnderhillWatchdog::new(store, get_client.clone(), Box::new(trigger_reset))
2433-
.await?,
2434-
)
2446+
let mut underhill_watchdog_platform =
2447+
UnderhillWatchdogPlatform::new(store, get_client.clone()).await?;
2448+
underhill_watchdog_platform.add_callback(Box::new(watchdog_callback));
2449+
2450+
Box::new(underhill_watchdog_platform)
24352451
},
24362452
})
24372453
} else {
@@ -3442,31 +3458,41 @@ impl ChipsetDevice for FallbackMmioDevice {
34423458
#[cfg(guest_arch = "x86_64")]
34433459
struct WatchdogTimeoutNmi {
34443460
partition: Arc<UhPartition>,
3461+
watchdog_send: Option<mesh::Sender<()>>,
34453462
}
34463463

34473464
#[cfg(guest_arch = "x86_64")]
34483465
#[async_trait::async_trait]
3449-
impl WatchdogTimeout for WatchdogTimeoutNmi {
3450-
async fn on_timeout(&self) {
3466+
impl WatchdogCallback for WatchdogTimeoutNmi {
3467+
async fn on_timeout(&mut self) {
34513468
crate::livedump::livedump().await;
34523469

34533470
// Unlike Hyper-V, we only send the NMI to the BSP.
34543471
self.partition.request_msi(
34553472
Vtl::Vtl0,
34563473
MsiRequest::new_x86(virt::irqcon::DeliveryMode::NMI, 0, false, 0, false),
34573474
);
3475+
3476+
if let Some(watchdog_send) = &self.watchdog_send {
3477+
watchdog_send.send(());
3478+
}
34583479
}
34593480
}
34603481

3461-
struct WatchdogTimeoutHalt {
3482+
struct WatchdogTimeoutReset {
34623483
halt_vps: Arc<Halt>,
3484+
watchdog_send: Option<mesh::Sender<()>>,
34633485
}
34643486

34653487
#[async_trait::async_trait]
3466-
impl WatchdogTimeout for WatchdogTimeoutHalt {
3467-
async fn on_timeout(&self) {
3488+
impl WatchdogCallback for WatchdogTimeoutReset {
3489+
async fn on_timeout(&mut self) {
34683490
crate::livedump::livedump().await;
34693491

3470-
self.halt_vps.halt(HaltReason::Reset)
3492+
self.halt_vps.halt(HaltReason::Reset);
3493+
3494+
if let Some(watchdog_send) = &self.watchdog_send {
3495+
watchdog_send.send(());
3496+
}
34713497
}
34723498
}

openvmm/hvlite_core/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ vmbus_core.workspace = true
7373
vmbus_server.workspace = true
7474
vpci.workspace = true
7575
watchdog_core.workspace = true
76-
watchdog_vmgs_format.workspace = true
7776

7877
cache_topology.workspace = true
7978
debug_ptr.workspace = true

openvmm/hvlite_core/src/emuplat/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@
33

44
pub mod firmware;
55
pub mod i440bx_host_pci_bridge;
6-
pub mod watchdog;

openvmm/hvlite_core/src/emuplat/watchdog.rs

Lines changed: 0 additions & 56 deletions
This file was deleted.

0 commit comments

Comments
 (0)