firmware_uefi/service/
event_log.rs1use crate::UefiDevice;
7use crate::platform::logger::BootInfo;
8use crate::platform::logger::UefiEvent;
9use crate::platform::logger::UefiLogger;
10use guestmem::GuestMemory;
11use guestmem::GuestMemoryError;
12use inspect::Inspect;
13use std::fmt::Debug;
14use thiserror::Error;
15use zerocopy::FromBytes;
16
17#[derive(Debug, Error)]
18pub enum EventLogError {
19 #[error("error converting bytes")]
20 ConvertBytes,
21 #[error("could not access guest memory")]
22 Memory(#[source] GuestMemoryError),
23 #[error("invalid event channel data size")]
24 EventChannelDataSize,
25 #[error("invalid boot event size")]
26 BootEventSize,
27 #[error("invalid event size")]
28 EventSize,
29 #[error("no boot events present in log")]
30 NoBootEvents,
31}
32
33#[derive(Inspect)]
34pub struct EventLogServices {
35 #[inspect(skip)]
36 logger: Box<dyn UefiLogger>,
37}
38
39impl EventLogServices {
40 pub fn new(logger: Box<dyn UefiLogger>) -> EventLogServices {
41 EventLogServices { logger }
42 }
43
44 pub fn reset(&mut self) {
45 }
47
48 fn event_log_flush_inner(&mut self, gpa: u64, gm: &GuestMemory) -> Result<(), EventLogError> {
49 use uefi_specs::hyperv::bios_event_log::BiosEventChannel;
50 use uefi_specs::hyperv::bios_event_log::EfiEventDescriptor;
51 use uefi_specs::hyperv::boot_bios_log::BootDeviceStatus;
52 use uefi_specs::hyperv::boot_bios_log::BootEventDeviceEntry;
53
54 let event_channel = gm
55 .read_plain::<BiosEventChannel>(gpa)
56 .map_err(EventLogError::Memory)?;
57
58 const EVENT_CHANNEL_MAX_DATA_SIZE: u32 = 16 * 1024;
60
61 if event_channel.data_size < size_of::<EfiEventDescriptor>() as u32
63 || event_channel.data_size > EVENT_CHANNEL_MAX_DATA_SIZE
64 {
65 return Err(EventLogError::EventChannelDataSize);
66 }
67
68 let mut event_data = vec![0; event_channel.data_size as usize];
70 gm.read_at(gpa + size_of::<BiosEventChannel>() as u64, &mut event_data)
71 .map_err(EventLogError::Memory)?;
72 let mut event_data = event_data.as_slice();
73
74 let mut boot_succeeded = false;
80 let mut no_boot_devices = false;
81 let mut secure_boot_failure = None;
82 let mut last_boot_event = None;
83
84 while !event_data.is_empty() {
85 let desc = EfiEventDescriptor::read_from_prefix(event_data)
86 .map_err(|_| EventLogError::ConvertBytes)?
87 .0; let data = event_data
90 .get(desc.header_size as usize..)
91 .ok_or(EventLogError::EventSize)?
92 .get(..desc.data_size as usize)
93 .ok_or(EventLogError::EventSize)?;
94
95 event_data = &event_data[(desc.header_size + desc.data_size) as usize..];
97
98 match desc.event_id {
99 uefi_specs::hyperv::boot_bios_log::BOOT_DEVICE_EVENT_ID => {
100 let boot_entry = BootEventDeviceEntry::read_from_prefix(data)
101 .map_err(|_| EventLogError::BootEventSize)?
102 .0; tracing::debug!(?boot_entry, "boot log entry");
105
106 match boot_entry.status {
107 BootDeviceStatus::BOOT_DEVICE_OS_LOADED => boot_succeeded = true,
108 BootDeviceStatus::BOOT_DEVICE_NO_DEVICES => no_boot_devices = true,
109 _ if boot_entry.status.get_boot_device_status_group()
110 == BootDeviceStatus::SECURE_BOOT_FAILED.0 =>
111 {
112 secure_boot_failure = Some(boot_entry.status);
113 }
114 _ => {}
115 }
116
117 last_boot_event = Some(boot_entry);
118 }
119 id => {
120 tracelimit::warn_ratelimited!(id, "unsupported uefi event log id");
121 }
122 }
123 }
124
125 let last_boot_event = last_boot_event.ok_or(EventLogError::NoBootEvents)?;
126 let boot_info = BootInfo {
127 secure_boot_succeeded: secure_boot_failure.is_none(),
128 };
129
130 let secure_boot_error = if secure_boot_failure != Some(last_boot_event.status) {
133 secure_boot_failure.map(tracing::field::debug)
134 } else {
135 None
136 };
137
138 let event = if no_boot_devices {
139 tracelimit::info_ratelimited!("uefi boot: no boot devices");
140 UefiEvent::NoBootDevice
141 } else if boot_succeeded {
142 tracelimit::info_ratelimited!(secure_boot_error, "uefi boot: success");
143 UefiEvent::BootSuccess(boot_info)
144 } else {
145 tracelimit::info_ratelimited!(
146 error = ?last_boot_event.status,
147 extended_status = ?last_boot_event.extended_status,
148 secure_boot_error,
149 "uefi boot: failure",
150 );
151 UefiEvent::BootFailure(boot_info)
152 };
153 self.logger.log_event(event);
154 Ok(())
155 }
156}
157
158impl UefiDevice {
159 pub(crate) fn event_log_flush(&mut self, data: u32) {
161 if let Err(err) = self
162 .service
163 .event_log
164 .event_log_flush_inner(data.into(), &self.gm)
165 {
166 tracelimit::error_ratelimited!(
167 error = &err as &dyn std::error::Error,
168 "event log flush error"
169 );
170 }
171 }
172}
173
174mod save_restore {
175 use super::*;
176 use vmcore::save_restore::NoSavedState;
177 use vmcore::save_restore::RestoreError;
178 use vmcore::save_restore::SaveError;
179 use vmcore::save_restore::SaveRestore;
180
181 impl SaveRestore for EventLogServices {
182 type SavedState = NoSavedState;
183
184 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
185 Ok(NoSavedState)
186 }
187
188 fn restore(&mut self, NoSavedState: Self::SavedState) -> Result<(), RestoreError> {
189 Ok(())
190 }
191 }
192}