1#![expect(missing_docs)]
12#![forbid(unsafe_code)]
13
14pub mod resolver;
15
16#[cfg(feature = "test_utilities")]
17pub mod test_utilities;
18
19use async_trait::async_trait;
20use core::mem::size_of;
21use disk_backend::Disk;
22use futures::FutureExt;
23use futures::StreamExt;
24use get_protocol::BatteryStatusFlags;
25use get_protocol::BatteryStatusNotification;
26use get_protocol::GspCleartextContent;
27use get_protocol::GspExtendedStatusFlags;
28use get_protocol::HeaderGeneric;
29use get_protocol::HostNotifications;
30use get_protocol::HostRequests;
31use get_protocol::IgvmAttestRequest;
32use get_protocol::MAX_PAYLOAD_SIZE;
33use get_protocol::RegisterState;
34use get_protocol::SaveGuestVtl2StateFlags;
35use get_protocol::SecureBootTemplateType;
36use get_protocol::StartVtl0Status;
37use get_protocol::UefiConsoleMode;
38use get_protocol::VmgsIoStatus;
39use get_protocol::dps_json::GuestStateLifetime;
40use get_protocol::dps_json::HclSecureBootTemplateId;
41use get_protocol::dps_json::PcatBootDevice;
42use get_resources::ged::FirmwareEvent;
43use get_resources::ged::GuestEmulationRequest;
44use get_resources::ged::GuestServicingFlags;
45use get_resources::ged::IgvmAttestTestConfig;
46use get_resources::ged::ModifyVtl2SettingsError;
47use get_resources::ged::SaveRestoreError;
48use get_resources::ged::Vtl0StartError;
49use guestmem::GuestMemory;
50use guid::Guid;
51use inspect::Inspect;
52use inspect::InspectMut;
53use jiff::Zoned;
54use jiff::civil::DateTime;
55use jiff::civil::date;
56use jiff::tz::TimeZone;
57use mesh::error::RemoteError;
58use mesh::rpc::Rpc;
59use openhcl_attestation_protocol::igvm_attest::get::AK_CERT_RESPONSE_HEADER_VERSION;
60use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestAkCertResponseHeader;
61use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestRequestHeader;
62use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestRequestType;
63use power_resources::PowerRequest;
64use power_resources::PowerRequestClient;
65use scsi_buffers::OwnedRequestBuffers;
66use std::io::IoSlice;
67use task_control::StopTask;
68use thiserror::Error;
69use video_core::FramebufferControl;
70use vmbus_async::async_dgram::AsyncRecvExt;
71use vmbus_async::pipe::MessagePipe;
72use vmbus_channel::RawAsyncChannel;
73use vmbus_channel::bus::ChannelType;
74use vmbus_channel::bus::OfferParams;
75use vmbus_channel::channel::ChannelOpenError;
76use vmbus_channel::gpadl_ring::GpadlRingMem;
77use vmbus_channel::simple::SimpleVmbusDevice;
78use vmbus_ring::RingMem;
79use vmcore::save_restore::SavedStateNotSupported;
80use zerocopy::FromBytes;
81use zerocopy::FromZeros;
82use zerocopy::IntoBytes;
83
84#[derive(Debug, Error)]
86enum Error {
87 #[error("cancelled")]
90 Cancelled(task_control::Cancelled),
91 #[error("vmbus channel i/o error")]
92 Vmbus(#[source] std::io::Error),
93 #[error("accepting vmbus channel")]
94 Accept(#[from] vmbus_channel::offer::Error),
95 #[error("message too small")]
96 MessageTooSmall,
97 #[error("serializing device platform settings v2")]
98 SerializeDpsV2(#[source] serde_json::Error),
99 #[error("invalid packet sequence")]
100 InvalidSequence,
101 #[error("failed to parse host request")]
102 HostRequest,
103 #[error("invalid header version: {0:?}")]
104 HeaderVersion(get_protocol::MessageVersions),
105 #[error("data was received with an invalid field value")]
106 InvalidFieldValue,
107 #[error("large device platform settings v2 is currently unimplemented")]
108 LargeDpsV2Unimplemented,
109 #[error("invalid IGVM_ATTEST request")]
110 InvalidIgvmAttestRequest,
111 #[error("unsupported igvm attest request type: {0:?}")]
112 UnsupportedIgvmAttestRequestType(u32),
113 #[error("failed to write to shared memory")]
114 SharedMemoryWriteFailed(#[source] guestmem::GuestMemoryError),
115 #[error("invalid igvm attest state: {state:?}, test config: {test_config:?}")]
116 InvalidIgvmAttestState {
117 state: IgvmAttestState,
118 test_config: Option<IgvmAttestTestConfig>,
119 },
120}
121
122impl From<task_control::Cancelled> for Error {
123 fn from(value: task_control::Cancelled) -> Self {
124 Error::Cancelled(value)
125 }
126}
127
128#[derive(Debug, Clone, Inspect)]
130pub struct GuestConfig {
131 pub firmware: GuestFirmwareConfig,
133 pub com1: bool,
135 pub com2: bool,
137 pub vmbus_redirection: bool,
139 pub enable_tpm: bool,
141 #[inspect(with = "Option::is_some")]
143 pub vtl2_settings: Option<Vec<u8>>,
144 pub secure_boot_enabled: bool,
146 #[inspect(debug)]
148 pub secure_boot_template: SecureBootTemplateType,
149 pub enable_battery: bool,
151 pub no_persistent_secrets: bool,
153 #[inspect(debug)]
155 pub guest_state_lifetime: GuestStateLifetime,
156}
157
158#[derive(Debug, Clone, Inspect)]
159#[inspect(external_tag)]
160pub enum GuestFirmwareConfig {
161 Uefi {
162 enable_vpci_boot: bool,
164 firmware_debug: bool,
166 disable_frontpage: bool,
168 #[inspect(debug)]
170 console_mode: UefiConsoleMode,
171 default_boot_always_attempt: bool,
173 },
174 Pcat {
175 #[inspect(with = "|x| inspect::iter_by_index(x).map_value(inspect::AsDebug)")]
176 boot_order: [PcatBootDevice; 4],
177 },
178}
179
180#[derive(Debug)]
182pub enum GuestEvent {
183 BootSuccess,
184 BootSuccessSecureBootFailed,
185 BootFailure,
186 BootFailureSecureBootFailed,
187 NoBootDevice,
188 AttestationFailed,
189 VmgsFileClear,
190 VmgsInitFailed,
191 VmgsInvalidFormat,
192 VmgsCorruptFormat,
193 KeyNotReleased,
194 DekDecryptionFailed,
195 WatchdogTimeoutReset,
196 BootAttempt,
197}
198
199#[derive(Debug, Clone, Copy)]
202enum IgvmAttestState {
203 Init,
204 SendEmptyAkCert,
205 SendInvalidAkCert,
206 SendValidAkCert,
207 Done,
208}
209
210#[derive(InspectMut)]
212pub struct GuestEmulationDevice {
213 config: GuestConfig,
214
215 #[inspect(skip)]
216 power_client: PowerRequestClient,
217 #[inspect(skip)]
218 firmware_event_send: Option<mesh::Sender<FirmwareEvent>>,
219 #[inspect(skip)]
220 framebuffer_control: Option<Box<dyn FramebufferControl>>,
221 #[inspect(skip)]
222 guest_request_recv: mesh::Receiver<GuestEmulationRequest>,
223 #[inspect(skip)]
224 waiting_for_vtl0_start: Vec<Rpc<(), Result<(), Vtl0StartError>>>,
225
226 vmgs: Option<VmgsState>,
227
228 #[inspect(with = "Option::is_some")]
229 save_restore_buf: Option<Vec<u8>>,
230 last_save_restore_buf_len: usize,
231
232 #[inspect(skip)]
233 igvm_attest_test_config: Option<IgvmAttestTestConfig>,
234
235 #[inspect(skip)]
237 igvm_attest_state: IgvmAttestState,
238}
239
240#[derive(Inspect)]
241struct VmgsState {
242 disk: Disk,
244 mem: GuestMemory,
246}
247
248impl GuestEmulationDevice {
249 pub fn new(
251 config: GuestConfig,
252 power_client: PowerRequestClient,
253 firmware_event_send: Option<mesh::Sender<FirmwareEvent>>,
254 guest_request_recv: mesh::Receiver<GuestEmulationRequest>,
255 framebuffer_control: Option<Box<dyn FramebufferControl>>,
256 vmgs_disk: Option<Disk>,
257 igvm_attest_test_config: Option<IgvmAttestTestConfig>,
258 ) -> Self {
259 Self {
260 config,
261 power_client,
262 firmware_event_send,
263 framebuffer_control,
264 guest_request_recv,
265 vmgs: vmgs_disk.map(|disk| VmgsState {
266 disk,
267 mem: GuestMemory::allocate(MAX_PAYLOAD_SIZE),
268 }),
269 save_restore_buf: None,
270 waiting_for_vtl0_start: Vec::new(),
271 last_save_restore_buf_len: 0,
272 igvm_attest_state: IgvmAttestState::Init,
273 igvm_attest_test_config,
274 }
275 }
276
277 fn send_event(&self, event: FirmwareEvent) {
278 if let Some(sender) = &self.firmware_event_send {
279 sender.send(event);
280 }
281 }
282
283 fn update_igvm_attest_state(&mut self) -> Result<(), Error> {
285 match self.igvm_attest_test_config {
286 None => self.igvm_attest_state = IgvmAttestState::SendValidAkCert,
288 Some(IgvmAttestTestConfig::AkCertRequestFailureAndRetry) => {
290 match self.igvm_attest_state {
291 IgvmAttestState::Init => {
292 self.igvm_attest_state = IgvmAttestState::SendEmptyAkCert
293 }
294 IgvmAttestState::SendEmptyAkCert => {
295 self.igvm_attest_state = IgvmAttestState::SendInvalidAkCert
296 }
297 IgvmAttestState::SendInvalidAkCert => {
298 self.igvm_attest_state = IgvmAttestState::SendValidAkCert
299 }
300 IgvmAttestState::SendValidAkCert => {
301 self.igvm_attest_state = IgvmAttestState::Done
302 }
303 IgvmAttestState::Done => {}
304 }
305 }
306 Some(IgvmAttestTestConfig::AkCertPersistentAcrossBoot) => {
308 match self.igvm_attest_state {
309 IgvmAttestState::Init => {
310 self.igvm_attest_state = IgvmAttestState::SendValidAkCert
311 }
312 IgvmAttestState::SendValidAkCert => {
313 self.igvm_attest_state = IgvmAttestState::SendEmptyAkCert
314 }
315 IgvmAttestState::SendEmptyAkCert => {
316 self.igvm_attest_state = IgvmAttestState::Done
317 }
318 IgvmAttestState::Done => {}
319 _ => {
320 return Err(Error::InvalidIgvmAttestState {
321 state: self.igvm_attest_state,
322 test_config: self.igvm_attest_test_config,
323 });
324 }
325 }
326 }
327 }
328
329 Ok(())
330 }
331}
332
333#[async_trait]
334impl SimpleVmbusDevice for GuestEmulationDevice {
335 type Runner = GedChannel;
336 type SavedState = SavedStateNotSupported;
337
338 fn offer(&self) -> OfferParams {
339 OfferParams {
340 interface_name: "get".to_owned(),
341 interface_id: get_protocol::GUEST_EMULATION_INTERFACE_TYPE,
342 instance_id: get_protocol::GUEST_EMULATION_INTERFACE_INSTANCE,
343 channel_type: ChannelType::Pipe { message_mode: true },
344 ..Default::default()
345 }
346 }
347
348 fn inspect(&mut self, req: inspect::Request<'_>, mut channel: Option<&mut GedChannel>) {
349 req.respond().merge(self).field_mut("channel", &mut channel);
350 }
351
352 fn open(
353 &mut self,
354 channel: RawAsyncChannel<GpadlRingMem>,
355 guest_memory: GuestMemory,
356 ) -> Result<Self::Runner, ChannelOpenError> {
357 let pipe = MessagePipe::new(channel)?;
358 Ok(GedChannel::new(pipe, guest_memory))
359 }
360
361 async fn run(
362 &mut self,
363 stop: &mut StopTask<'_>,
364 task_state: &mut GedChannel,
365 ) -> Result<(), task_control::Cancelled> {
366 match task_state.process(stop, self).await {
367 Ok(()) => Ok(()),
368 Err(Error::Cancelled(err)) => Err(err),
369 Err(err) => {
370 tracing::error!(error = &err as &dyn std::error::Error, "ged error");
371 Ok(())
372 }
373 }
374 }
375
376 fn supports_save_restore(
377 &mut self,
378 ) -> Option<
379 &mut dyn vmbus_channel::simple::SaveRestoreSimpleVmbusDevice<
380 SavedState = Self::SavedState,
381 Runner = Self::Runner,
382 >,
383 > {
384 None
386 }
387}
388
389#[derive(InspectMut)]
391pub struct GedChannel<T: RingMem = GpadlRingMem> {
392 #[inspect(mut)]
393 channel: MessagePipe<T>,
394 #[inspect(skip)]
395 state: GedState,
396 #[inspect(with = "Option::is_some")]
397 save: Option<InProgressSave>,
398 #[inspect(with = "Option::is_some")]
399 vtl0_start_report: Option<Result<(), Vtl0StartError>>,
400 #[inspect(with = "Option::is_some")]
401 modify: Option<Rpc<(), Result<(), ModifyVtl2SettingsError>>>,
402 #[inspect(skip)]
403 gm: GuestMemory,
404}
405
406struct InProgressSave {
407 rpc: Rpc<GuestServicingFlags, Result<(), SaveRestoreError>>,
408 buffer: Vec<u8>,
409}
410
411enum GedState {
412 Init,
413 Ready,
414 SendingRestore { written: usize },
415}
416
417impl<T: RingMem + Unpin> GedChannel<T> {
418 fn new(channel: MessagePipe<T>, guest_memory: GuestMemory) -> Self {
419 Self {
420 channel,
421 save: None,
422 state: GedState::Init,
423 vtl0_start_report: None,
424 modify: None,
425 gm: guest_memory,
426 }
427 }
428
429 async fn process(
430 &mut self,
431 stop: &mut StopTask<'_>,
432 state: &mut GuestEmulationDevice,
433 ) -> Result<(), Error> {
434 tracing::trace!("Begin GetChannel process()");
435
436 loop {
437 stop.until_stopped(
439 self.channel
440 .wait_write_ready(get_protocol::MAX_MESSAGE_SIZE),
441 )
442 .await?
443 .map_err(Error::Vmbus)?;
444
445 match &mut self.state {
446 GedState::Init => {
447 let mut version_request = get_protocol::VersionRequest::new_zeroed();
449 stop.until_stopped(self.channel.recv_exact(version_request.as_mut_bytes()))
450 .await?
451 .map_err(Error::Vmbus)?;
452
453 if version_request.message_header.message_id() != HostRequests::VERSION {
454 return Err(Error::InvalidSequence);
455 }
456
457 let version_response = get_protocol::VersionResponse::new(true);
458
459 self.channel
460 .try_send(version_response.as_bytes())
461 .map_err(Error::Vmbus)?;
462
463 tracing::info!("version negotiated successfully!");
464 self.state = GedState::Ready;
465
466 let _ = self.send_hardcoded_battery_update();
474 }
475 GedState::Ready => {
476 let mut message_buf = [0; get_protocol::MAX_MESSAGE_SIZE];
477 futures::select! { pipe_input = self.channel.recv(&mut message_buf).fuse() => {
479 let bytes_read = pipe_input.map_err(Error::Vmbus)?;
480 self.handle_pipe_input(&message_buf[..bytes_read], state).await?;
481 },
482 guest_request = state.guest_request_recv.select_next_some() => {
483 self.handle_guest_request_input(state, guest_request)?;
484 }
485 _ = stop.fuse() => {
486 return Err(Error::Cancelled(task_control::Cancelled));
487 }
488 }
489 }
490 GedState::SendingRestore { written } => {
491 let buffer = state
492 .save_restore_buf
493 .as_ref()
494 .ok_or(Error::InvalidSequence)?;
495
496 let saved_state_size = buffer.len();
497 if *written >= saved_state_size {
498 self.state = GedState::Ready;
499 state.last_save_restore_buf_len = saved_state_size;
500 state.save_restore_buf = None;
501 continue;
502 }
503
504 let status_code = if *written + MAX_PAYLOAD_SIZE >= saved_state_size {
505 get_protocol::GuestVtl2SaveRestoreStatus::SUCCESS
506 } else {
507 get_protocol::GuestVtl2SaveRestoreStatus::MORE_DATA
508 };
509
510 let payload_len = (saved_state_size - *written).min(MAX_PAYLOAD_SIZE);
511
512 let host_response_header = get_protocol::RestoreGuestVtl2StateResponse::new(
513 payload_len.try_into().unwrap(),
514 status_code,
515 );
516
517 tracing::debug!(
518 ?status_code,
519 written,
520 saved_state_size,
521 payload_len,
522 "more data"
523 );
524
525 self.channel
526 .try_send_vectored(&[
527 IoSlice::new(host_response_header.as_bytes()),
528 IoSlice::new(&buffer[*written..][..payload_len]),
529 ])
530 .map_err(Error::Vmbus)?;
531
532 *written += payload_len;
533 }
534 }
535 }
536 }
537
538 async fn handle_pipe_input(
539 &mut self,
540 message_buf: &[u8],
541 state: &mut GuestEmulationDevice,
542 ) -> Result<(), Error> {
543 let header = get_protocol::HeaderRaw::read_from_prefix(message_buf)
544 .map_err(|_| Error::MessageTooSmall)?
545 .0; if header.message_version != get_protocol::MessageVersions::HEADER_VERSION_1 {
548 return Err(Error::HeaderVersion(header.message_version));
549 }
550
551 match header.message_type {
552 get_protocol::MessageTypes::HOST_NOTIFICATION => self.handle_host_notification(
553 header.try_into().expect("validated message type"),
554 message_buf,
555 state,
556 )?,
557 get_protocol::MessageTypes::HOST_REQUEST => {
558 self.handle_host_request(
559 header.try_into().expect("validated message type"),
560 message_buf,
561 state,
562 )
563 .await?
564 }
565 _ => {
566 return Err(Error::HostRequest);
567 }
568 }
569 Ok(())
570 }
571
572 fn handle_guest_request_input(
573 &mut self,
574 state: &mut GuestEmulationDevice,
575 guest_request: GuestEmulationRequest,
576 ) -> Result<(), Error> {
577 match guest_request {
578 GuestEmulationRequest::WaitForConnect(rpc) => rpc.handle_sync(|()| ()),
579 GuestEmulationRequest::WaitForVtl0Start(rpc) => {
580 if let Some(result) = self.vtl0_start_report.clone() {
581 rpc.complete(result);
582 } else {
583 state.waiting_for_vtl0_start.push(rpc);
584 }
585 }
586 GuestEmulationRequest::ModifyVtl2Settings(rpc) => {
587 let (data, response) = rpc.split();
588 if self.modify.is_some() {
589 response.complete(Err(ModifyVtl2SettingsError::OperationInProgress));
590 return Ok(());
591 }
592
593 if data.len() > MAX_PAYLOAD_SIZE {
595 response.complete(Err(ModifyVtl2SettingsError::LargeSettingsNotSupported));
596 return Ok(());
597 }
598
599 let header = get_protocol::ModifyVtl2SettingsRev1Notification {
600 message_header: HeaderGeneric::new(
601 get_protocol::GuestNotifications::MODIFY_VTL2_SETTINGS_REV1,
602 ),
603 size: data.len() as u32,
604 payload_state: get_protocol::LargePayloadState::END,
605 };
606
607 self.channel
608 .try_send_vectored(&[IoSlice::new(header.as_bytes()), IoSlice::new(&data)])
609 .map_err(Error::Vmbus)?;
610
611 self.modify = Some(response);
612 }
613 GuestEmulationRequest::SaveGuestVtl2State(rpc) => {
614 let r = (|| {
615 if self.save.is_some() {
616 return Err(SaveRestoreError::OperationInProgress);
617 }
618
619 let save_notif_packet = get_protocol::SaveGuestVtl2StateNotification {
623 message_header: HeaderGeneric::new(
624 get_protocol::GuestNotifications::SAVE_GUEST_VTL2_STATE,
625 ),
626 correlation_id: Guid::ZERO,
627 capabilities_flags: SaveGuestVtl2StateFlags::new()
628 .with_enable_nvme_keepalive(rpc.input().nvme_keepalive),
629 timeout_hint_secs: 60,
630 };
631
632 self.channel
633 .try_send(save_notif_packet.as_bytes())
634 .map_err(|err| SaveRestoreError::Io(RemoteError::new(err)))?;
635
636 Ok(())
637 })();
638 match r {
639 Ok(()) => {
640 self.save = Some(InProgressSave {
641 rpc,
642 buffer: Vec::new(),
643 })
644 }
645 Err(err) => rpc.complete(Err(err)),
646 }
647 }
648 };
649 Ok(())
650 }
651
652 async fn handle_host_request(
653 &mut self,
654 header: get_protocol::HeaderHostRequest,
655 message_buf: &[u8],
656 state: &mut GuestEmulationDevice,
657 ) -> Result<(), Error> {
658 match header.message_id() {
659 HostRequests::TIME => self.handle_time()?,
660 HostRequests::BIOS_BOOT_FINALIZE => self.handle_bios_boot_finalize(message_buf)?,
661 HostRequests::VMGS_GET_DEVICE_INFO => self.handle_vmgs_get_device_info(state)?,
662 HostRequests::VMGS_READ => self.handle_vmgs_read(state, message_buf).await?,
663 HostRequests::VMGS_WRITE => self.handle_vmgs_write(state, message_buf).await?,
664 HostRequests::VMGS_FLUSH => self.handle_vmgs_flush(state).await?,
665 HostRequests::GUEST_STATE_PROTECTION => {
666 self.handle_guest_state_protection(message_buf)?
667 }
668 HostRequests::GUEST_STATE_PROTECTION_BY_ID => {
669 self.handle_guest_state_protection_by_id()?;
670 }
671 HostRequests::IGVM_ATTEST => self.handle_igvm_attest(message_buf, state)?,
672 HostRequests::DEVICE_PLATFORM_SETTINGS_V2 => {
673 self.handle_device_platform_settings_v2(state)?
674 }
675 HostRequests::SAVE_GUEST_VTL2_STATE => {
676 self.handle_save_guest_vtl2_state(message_buf, state)?
677 }
678 HostRequests::RESTORE_GUEST_VTL2_STATE => self.handle_restore_guest_vtl2_state(),
679 HostRequests::MAP_FRAMEBUFFER => {
680 self.handle_map_framebuffer(state, message_buf).await?
681 }
682 HostRequests::UNMAP_FRAMEBUFFER => self.handle_unmap_framebuffer(state).await?,
683 HostRequests::CREATE_RAM_GPA_RANGE => self.handle_create_ram_gpa_range(message_buf)?,
684 HostRequests::RESET_RAM_GPA_RANGE => self.handle_reset_ram_gpa_range(message_buf)?,
685 _ => {
686 tracing::error!(message_id = ?header.message_id(), "unexpected message");
687 return Err(Error::InvalidSequence);
688 }
689 };
690 Ok(())
691 }
692
693 fn handle_bios_boot_finalize(&mut self, message_buf: &[u8]) -> Result<(), Error> {
694 let msg = get_protocol::BiosBootFinalizeRequest::read_from_prefix(message_buf)
695 .map_err(|_| Error::MessageTooSmall)?
696 .0; tracing::trace!(?msg, "Bios Boot Finalize request");
699
700 let response = get_protocol::BiosBootFinalizeResponse::new();
701 self.channel
702 .try_send(response.as_bytes())
703 .map_err(Error::Vmbus)?;
704 Ok(())
705 }
706
707 fn handle_time(&mut self) -> Result<(), Error> {
708 const WINDOWS_EPOCH: DateTime = date(1601, 1, 1).at(0, 0, 0, 0);
709
710 let now = Zoned::now();
711
712 let since_win_epoch = (WINDOWS_EPOCH
714 .to_zoned(TimeZone::UTC)
715 .expect("windows epoch value to be valid")
716 .timestamp()
717 .duration_until(now.timestamp())
718 .as_nanos()
719 / 100) as i64;
720
721 let tz_offset = (now.offset().seconds() / 60) as i16;
724 let response = get_protocol::TimeResponse::new(0, since_win_epoch, tz_offset, false);
725
726 self.channel
727 .try_send(response.as_bytes())
728 .map_err(Error::Vmbus)?;
729 Ok(())
730 }
731
732 fn handle_vmgs_get_device_info(
733 &mut self,
734 state: &mut GuestEmulationDevice,
735 ) -> Result<(), Error> {
736 let response = if let Some(vmgs) = &state.vmgs {
737 get_protocol::VmgsGetDeviceInfoResponse::new(
738 VmgsIoStatus::SUCCESS,
739 vmgs.disk.sector_count(),
740 vmgs.disk.sector_size().try_into().unwrap(),
741 vmgs.disk.physical_sector_size().try_into().unwrap(),
742 MAX_PAYLOAD_SIZE as u32,
743 )
744 } else {
745 get_protocol::VmgsGetDeviceInfoResponse::new(VmgsIoStatus::DEVICE_ERROR, 0, 0, 0, 0)
746 };
747 self.channel
748 .try_send(response.as_bytes())
749 .map_err(Error::Vmbus)?;
750 Ok(())
751 }
752
753 async fn handle_vmgs_read(
754 &mut self,
755 state: &mut GuestEmulationDevice,
756 message_buf: &[u8],
757 ) -> Result<(), Error> {
758 let message = get_protocol::VmgsReadRequest::read_from_prefix(message_buf)
759 .map_err(|_| Error::MessageTooSmall)?
760 .0; let (status, payload) = if let Some(vmgs) = &mut state.vmgs {
763 let len = message.sector_count as u64 * vmgs.disk.sector_size() as u64;
764 if len > MAX_PAYLOAD_SIZE as u64 {
765 return Err(Error::InvalidFieldValue);
766 }
767
768 match vmgs
772 .disk
773 .read_vectored(
774 &OwnedRequestBuffers::linear(0, len as usize, true).buffer(&vmgs.mem),
775 message.sector_offset,
776 )
777 .await
778 {
779 Ok(()) => (
780 VmgsIoStatus::SUCCESS,
781 &vmgs
782 .mem
783 .inner_buf_mut()
784 .expect("memory should not be aliased")[..len as usize],
785 ),
786 Err(err) => {
787 tracelimit::error_ratelimited!(
788 error = &err as &dyn std::error::Error,
789 "vmgs read error"
790 );
791 (VmgsIoStatus::DEVICE_ERROR, &[] as _)
792 }
793 }
794 } else {
795 (VmgsIoStatus::DEVICE_ERROR, &[] as _)
796 };
797
798 let response = get_protocol::VmgsReadResponse::new(status);
799 self.channel
800 .try_send_vectored(&[IoSlice::new(response.as_bytes()), IoSlice::new(payload)])
801 .map_err(Error::Vmbus)?;
802 Ok(())
803 }
804
805 async fn handle_vmgs_write(
806 &mut self,
807 state: &mut GuestEmulationDevice,
808 message_buf: &[u8],
809 ) -> Result<(), Error> {
810 let (message, rest) = get_protocol::VmgsWriteRequest::read_from_prefix(message_buf)
811 .map_err(|_| Error::MessageTooSmall)?; let status = if let Some(vmgs) = &mut state.vmgs {
814 let len = message.sector_count as u64 * vmgs.disk.sector_size() as u64;
815 if len > MAX_PAYLOAD_SIZE as u64 {
816 return Err(Error::InvalidFieldValue);
817 }
818
819 vmgs.mem
820 .write_at(0, rest.get(..len as usize).ok_or(Error::MessageTooSmall)?)
821 .unwrap();
822
823 match vmgs
827 .disk
828 .write_vectored(
829 &OwnedRequestBuffers::linear(0, len as usize, false).buffer(&vmgs.mem),
830 message.sector_offset,
831 false,
832 )
833 .await
834 {
835 Ok(()) => VmgsIoStatus::SUCCESS,
836 Err(err) => {
837 tracelimit::error_ratelimited!(
838 error = &err as &dyn std::error::Error,
839 "vmgs write error"
840 );
841 VmgsIoStatus::DEVICE_ERROR
842 }
843 }
844 } else {
845 VmgsIoStatus::DEVICE_ERROR
846 };
847
848 let response = get_protocol::VmgsWriteResponse::new(status);
849 self.channel
850 .try_send(response.as_bytes())
851 .map_err(Error::Vmbus)?;
852 Ok(())
853 }
854
855 async fn handle_vmgs_flush(&mut self, state: &mut GuestEmulationDevice) -> Result<(), Error> {
856 let status = if let Some(vmgs) = &mut state.vmgs {
857 match vmgs.disk.sync_cache().await {
861 Ok(()) => VmgsIoStatus::SUCCESS,
862 Err(err) => {
863 tracelimit::error_ratelimited!(
864 error = &err as &dyn std::error::Error,
865 "vmgs flush error"
866 );
867 VmgsIoStatus::DEVICE_ERROR
868 }
869 }
870 } else {
871 VmgsIoStatus::DEVICE_ERROR
872 };
873
874 let response = get_protocol::VmgsFlushResponse::new(status);
875 self.channel
876 .try_send(response.as_bytes())
877 .map_err(Error::Vmbus)?;
878 Ok(())
879 }
880
881 fn handle_guest_state_protection(&mut self, message_buf: &[u8]) -> Result<(), Error> {
882 let _message = get_protocol::GuestStateProtectionRequest::read_from_prefix(
883 &message_buf.as_bytes()[..size_of::<get_protocol::GuestStateProtectionRequest>()],
884 )
885 .map_err(|_| Error::MessageTooSmall)?
886 .0; let mut response = get_protocol::GuestStateProtectionResponse::new_zeroed();
889 response.message_header = HeaderGeneric::new(HostRequests::GUEST_STATE_PROTECTION);
890
891 self.channel
892 .try_send(response.as_bytes())
893 .map_err(Error::Vmbus)?;
894 Ok(())
895 }
896
897 fn handle_guest_state_protection_by_id(&mut self) -> Result<(), Error> {
898 let response = get_protocol::GuestStateProtectionByIdResponse {
899 message_header: HeaderGeneric::new(HostRequests::GUEST_STATE_PROTECTION_BY_ID),
900 seed: GspCleartextContent::new_zeroed(),
901 extended_status_flags: GspExtendedStatusFlags::new().with_no_registry_file(true),
902 };
903 self.channel
904 .try_send(response.as_bytes())
905 .map_err(Error::Vmbus)?;
906 Ok(())
907 }
908
909 fn handle_igvm_attest(
912 &mut self,
913 message_buf: &[u8],
914 state: &mut GuestEmulationDevice,
915 ) -> Result<(), Error> {
916 tracing::info!(state = ?state.igvm_attest_state, test_config = ?state.igvm_attest_test_config, "Handle IGVM Attest request");
917
918 let request = IgvmAttestRequest::read_from_prefix(message_buf)
919 .map_err(|_| Error::MessageTooSmall)?
920 .0; if request.agent_data_length as usize > request.agent_data.len()
924 || request.report_length as usize > request.report.len()
925 || request.number_gpa as usize > get_protocol::IGVM_ATTEST_MSG_MAX_SHARED_GPA
926 {
927 Err(Error::InvalidIgvmAttestRequest)?
928 }
929
930 let request_payload = IgvmAttestRequestHeader::read_from_prefix(&request.report)
931 .map_err(|_| Error::MessageTooSmall)?
932 .0; if matches!(state.igvm_attest_state, IgvmAttestState::Init) {
936 state.update_igvm_attest_state()?;
937 tracing::info!(state = ?state.igvm_attest_state, test_config = ?state.igvm_attest_test_config, "Update init state");
938 }
939
940 let response = match request_payload.request_type {
941 IgvmAttestRequestType::AK_CERT_REQUEST => match state.igvm_attest_state {
942 IgvmAttestState::SendEmptyAkCert => {
943 tracing::info!("Send an empty response for AK_CERT_REQEUST");
944 get_protocol::IgvmAttestResponse {
945 message_header: HeaderGeneric::new(HostRequests::IGVM_ATTEST),
946 length: 0,
947 }
948 }
949 IgvmAttestState::SendInvalidAkCert => {
950 tracing::info!("Return an invalid response for AK_CERT_REQUEST");
951 get_protocol::IgvmAttestResponse {
952 message_header: HeaderGeneric::new(HostRequests::IGVM_ATTEST),
953 length: get_protocol::IGVM_ATTEST_VMWP_GENERIC_ERROR_CODE as u32,
954 }
955 }
956 IgvmAttestState::SendValidAkCert => {
957 let data = vec![0xab; 2500];
958 let header = IgvmAttestAkCertResponseHeader {
959 data_size: (data.len() + size_of::<IgvmAttestAkCertResponseHeader>())
960 as u32,
961 version: AK_CERT_RESPONSE_HEADER_VERSION,
962 };
963 let payload = [header.as_bytes(), &data].concat();
964
965 self.gm
966 .write_at(request.shared_gpa[0], &payload)
967 .map_err(Error::SharedMemoryWriteFailed)?;
968
969 tracing::info!("Send a response for AK_CERT_REQEUST");
970
971 get_protocol::IgvmAttestResponse {
972 message_header: HeaderGeneric::new(HostRequests::IGVM_ATTEST),
973 length: payload.len() as u32,
974 }
975 }
976 IgvmAttestState::Done => {
977 tracing::info!("Bypass AK_CERT_REQEUST");
978
979 return Ok(());
980 }
981 _ => {
982 return Err(Error::InvalidIgvmAttestState {
983 state: state.igvm_attest_state,
984 test_config: state.igvm_attest_test_config,
985 });
986 }
987 },
988 ty => return Err(Error::UnsupportedIgvmAttestRequestType(ty.0)),
989 };
990
991 state.update_igvm_attest_state()?;
993
994 tracing::info!(state = ?state.igvm_attest_state, test_config = ?state.igvm_attest_test_config, "Update init state");
995
996 self.channel
997 .try_send(response.as_bytes())
998 .map_err(Error::Vmbus)?;
999
1000 Ok(())
1001 }
1002
1003 fn handle_save_guest_vtl2_state(
1004 &mut self,
1005 message_buf: &[u8],
1006 state: &mut GuestEmulationDevice,
1007 ) -> Result<(), Error> {
1008 let save = self.save.as_mut().ok_or(Error::InvalidSequence)?;
1014 let (request_header, remaining) =
1015 get_protocol::SaveGuestVtl2StateRequest::read_from_prefix(message_buf)
1016 .map_err(|_| Error::MessageTooSmall)?; let r = match request_header.save_status {
1018 get_protocol::GuestVtl2SaveRestoreStatus::MORE_DATA => {
1019 save.buffer.extend_from_slice(remaining);
1020 None
1021 }
1022 get_protocol::GuestVtl2SaveRestoreStatus::SUCCESS => {
1023 save.buffer.extend_from_slice(remaining);
1024
1025 tracing::debug!("Received all guest VTL2 save state");
1026
1027 let response = get_protocol::SaveGuestVtl2StateResponse::new(
1029 get_protocol::GuestVtl2SaveRestoreStatus::SUCCESS,
1030 );
1031 self.channel
1032 .try_send(response.as_bytes())
1033 .map_err(Error::Vmbus)?;
1034
1035 tracing::debug!("Notifying completion channel that save guest VTL2 op is complete");
1036
1037 Some(Ok(()))
1038 }
1039 get_protocol::GuestVtl2SaveRestoreStatus::FAILURE => {
1040 Some(Err(SaveRestoreError::GuestError))
1041 }
1042 _ => {
1043 return Err(Error::InvalidFieldValue);
1044 }
1045 };
1046 if let Some(r) = r {
1047 let save = self.save.take().unwrap();
1048 if r.is_ok() {
1049 state.save_restore_buf = Some(save.buffer);
1050 }
1051 save.rpc.complete(r);
1052 }
1053 Ok(())
1054 }
1055
1056 fn handle_restore_guest_vtl2_state(&mut self) {
1057 self.state = GedState::SendingRestore { written: 0 };
1058 }
1059
1060 async fn handle_map_framebuffer(
1061 &mut self,
1062 state: &mut GuestEmulationDevice,
1063 message_buf: &[u8],
1064 ) -> Result<(), Error> {
1065 let response = get_protocol::MapFramebufferResponse::new(
1066 if let Some(framebuffer_control) = state.framebuffer_control.as_mut() {
1067 let message = get_protocol::MapFramebufferRequest::read_from_prefix(message_buf)
1068 .map_err(|_| Error::MessageTooSmall)?
1069 .0; let gpa = message.gpa;
1071 tracing::debug!("Received map framebuffer request from guest {:#x}", gpa);
1072 framebuffer_control.map(gpa).await;
1073 get_protocol::MapFramebufferStatus::SUCCESS
1074 } else {
1075 tracing::warn!(
1076 "Guest requested framebuffer mapping but no framebuffer control was provided to the GET"
1077 );
1078 get_protocol::MapFramebufferStatus::FAILURE
1079 },
1080 );
1081 self.channel
1082 .try_send(response.as_bytes())
1083 .map_err(Error::Vmbus)?;
1084 Ok(())
1085 }
1086
1087 async fn handle_unmap_framebuffer(
1088 &mut self,
1089 state: &mut GuestEmulationDevice,
1090 ) -> Result<(), Error> {
1091 let response = get_protocol::UnmapFramebufferResponse::new(
1092 if let Some(framebuffer_control) = state.framebuffer_control.as_mut() {
1093 tracing::debug!("Received unmap framebuffer request from guest");
1094 framebuffer_control.unmap().await;
1095 get_protocol::UnmapFramebufferStatus::SUCCESS
1096 } else {
1097 tracing::warn!(
1098 "Guest requested framebuffer mapping but no framebuffer control was provided to the GET"
1099 );
1100 get_protocol::UnmapFramebufferStatus::FAILURE
1101 },
1102 );
1103 self.channel
1104 .try_send(response.as_bytes())
1105 .map_err(Error::Vmbus)?;
1106 Ok(())
1107 }
1108
1109 fn handle_create_ram_gpa_range(&mut self, message_buf: &[u8]) -> Result<(), Error> {
1110 let request = get_protocol::CreateRamGpaRangeRequest::read_from_prefix(message_buf)
1111 .map_err(|_| Error::MessageTooSmall)?
1112 .0; tracing::info!(?request, "create ram gpa range request");
1115
1116 let response = get_protocol::CreateRamGpaRangeResponse::new(
1117 get_protocol::CreateRamGpaRangeStatus::FAILED,
1118 );
1119 self.channel
1120 .try_send(response.as_bytes())
1121 .map_err(Error::Vmbus)?;
1122 Ok(())
1123 }
1124
1125 fn handle_reset_ram_gpa_range(&mut self, message_buf: &[u8]) -> Result<(), Error> {
1126 let _request = get_protocol::ResetRamGpaRangeRequest::read_from_prefix(message_buf)
1127 .map_err(|_| Error::MessageTooSmall)?
1128 .0; let response = get_protocol::ResetRamGpaRangeResponse::new();
1130 self.channel
1131 .try_send(response.as_bytes())
1132 .map_err(Error::Vmbus)?;
1133 Ok(())
1134 }
1135
1136 fn handle_host_notification(
1137 &mut self,
1138 header: get_protocol::HeaderHostNotification,
1139 message_buf: &[u8],
1140 state: &mut GuestEmulationDevice,
1141 ) -> Result<(), Error> {
1142 match header.message_id() {
1143 HostNotifications::POWER_OFF => {
1144 self.handle_power_off(state);
1145 }
1146 HostNotifications::RESET => {
1147 self.handle_reset(state);
1148 }
1149 HostNotifications::EVENT_LOG => {
1150 self.handle_event_log(state, message_buf)?;
1151 }
1152 HostNotifications::RESTORE_GUEST_VTL2_STATE_COMPLETED => {
1153 self.handle_restore_guest_vtl2_state_completed(message_buf)?;
1154 }
1155 HostNotifications::START_VTL0_COMPLETED => {
1156 self.handle_start_vtl0_completed(state, message_buf)?;
1157 }
1158 HostNotifications::VTL_CRASH => {
1159 self.handle_vtl_crash(message_buf)?;
1160 }
1161 HostNotifications::TRIPLE_FAULT => {
1162 self.handle_triple_fault(state, message_buf)?;
1163 }
1164 HostNotifications::MODIFY_VTL2_SETTINGS_COMPLETED => {
1165 self.handle_modify_vtl2_settings_completed(message_buf)?;
1166 }
1167 _ => {
1168 return Err(Error::InvalidFieldValue);
1169 }
1170 }
1171 Ok(())
1172 }
1173
1174 fn handle_power_off(&mut self, state: &mut GuestEmulationDevice) {
1175 state.power_client.power_request(PowerRequest::PowerOff);
1176 }
1177
1178 fn handle_reset(&mut self, state: &mut GuestEmulationDevice) {
1179 state.power_client.power_request(PowerRequest::Reset);
1180 }
1181
1182 fn handle_event_log(
1183 &mut self,
1184 state: &mut GuestEmulationDevice,
1185 message_buf: &[u8],
1186 ) -> Result<(), Error> {
1187 let msg = get_protocol::EventLogNotification::read_from_prefix(message_buf)
1188 .map_err(|_| Error::MessageTooSmall)?
1189 .0; tracing::trace!("[Event Log] {:?}", msg);
1191 let event = match msg.event_log_id {
1192 get_protocol::EventLogId::BOOT_SUCCESS => GuestEvent::BootSuccess,
1193 get_protocol::EventLogId::BOOT_SUCCESS_SECURE_BOOT_FAILED => {
1194 GuestEvent::BootSuccessSecureBootFailed
1195 }
1196 get_protocol::EventLogId::BOOT_FAILURE => GuestEvent::BootFailure,
1197 get_protocol::EventLogId::BOOT_FAILURE_SECURE_BOOT_FAILED => {
1198 GuestEvent::BootFailureSecureBootFailed
1199 }
1200 get_protocol::EventLogId::NO_BOOT_DEVICE => GuestEvent::NoBootDevice,
1201 get_protocol::EventLogId::ATTESTATION_FAILED => GuestEvent::AttestationFailed,
1202 get_protocol::EventLogId::VMGS_FILE_CLEAR => GuestEvent::VmgsFileClear,
1203 get_protocol::EventLogId::VMGS_INIT_FAILED => GuestEvent::VmgsInitFailed,
1204 get_protocol::EventLogId::VMGS_INVALID_FORMAT => GuestEvent::VmgsInvalidFormat,
1205 get_protocol::EventLogId::VMGS_CORRUPT_FORMAT => GuestEvent::VmgsCorruptFormat,
1206 get_protocol::EventLogId::KEY_NOT_RELEASED => GuestEvent::KeyNotReleased,
1207 get_protocol::EventLogId::DEK_DECRYPTION_FAILED => GuestEvent::DekDecryptionFailed,
1208 get_protocol::EventLogId::BOOT_ATTEMPT => GuestEvent::BootAttempt,
1209 get_protocol::EventLogId::WATCHDOG_TIMEOUT_RESET => GuestEvent::WatchdogTimeoutReset,
1210 _ => {
1211 tracing::error!(event_log_id = msg.event_log_id.0, "unknown event log id");
1213 return Ok(());
1214 }
1215 };
1216 tracing::info!(?event, "GET event");
1217 match event {
1218 GuestEvent::BootAttempt => state.send_event(FirmwareEvent::BootAttempt),
1219 GuestEvent::BootSuccess | GuestEvent::BootSuccessSecureBootFailed => {
1220 state.send_event(FirmwareEvent::BootSuccess);
1221 }
1222 GuestEvent::BootFailure | GuestEvent::BootFailureSecureBootFailed => {
1223 state.send_event(FirmwareEvent::BootFailed);
1224 }
1225 GuestEvent::NoBootDevice => state.send_event(FirmwareEvent::NoBootDevice),
1226 _ => {}
1228 }
1229 Ok(())
1230 }
1231
1232 fn handle_restore_guest_vtl2_state_completed(
1233 &mut self,
1234 message_buf: &[u8],
1235 ) -> Result<(), Error> {
1236 let message =
1237 get_protocol::RestoreGuestVtl2StateHostNotification::read_from_prefix(message_buf)
1238 .map_err(|_| Error::MessageTooSmall)?
1239 .0; let success = match message.status {
1241 get_protocol::GuestVtl2SaveRestoreStatus::SUCCESS => true,
1242 get_protocol::GuestVtl2SaveRestoreStatus::FAILURE => false,
1243 _ => return Err(Error::InvalidFieldValue),
1244 };
1245 tracing::info!(success, "restore vtl2 complete");
1246 Ok(())
1247 }
1248
1249 fn handle_start_vtl0_completed(
1250 &mut self,
1251 state: &mut GuestEmulationDevice,
1252 message_buf: &[u8],
1253 ) -> Result<(), Error> {
1254 let (message, remaining) =
1255 get_protocol::StartVtl0CompleteNotification::read_from_prefix(message_buf)
1256 .map_err(|_| Error::MessageTooSmall)?; let expected_len = message.result_document_size as usize;
1258 if remaining.len() != expected_len {
1259 return Err(Error::InvalidFieldValue);
1260 }
1261 let result = match message.status {
1262 StartVtl0Status::SUCCESS => {
1263 tracing::info!("guest reported vtl0 started successfully");
1264 Ok(())
1265 }
1266 StartVtl0Status::FAILURE => {
1267 let err = Vtl0StartError(String::from_utf8_lossy(remaining).into_owned());
1268 tracing::error!(
1269 error = &err as &dyn std::error::Error,
1270 "guest reported vtl0 failed to start"
1271 );
1272 state.power_client.power_request(PowerRequest::PowerOff);
1273 Err(err)
1274 }
1275 _ => return Err(Error::InvalidFieldValue),
1276 };
1277 for response in state.waiting_for_vtl0_start.drain(..) {
1278 response.complete(result.clone());
1279 }
1280 self.vtl0_start_report = Some(result);
1281 Ok(())
1282 }
1283
1284 fn handle_vtl_crash(&mut self, message_buf: &[u8]) -> Result<(), Error> {
1285 let msg = get_protocol::VtlCrashNotification::read_from_prefix(message_buf)
1286 .map_err(|_| Error::MessageTooSmall)?
1287 .0; tracing::info!("Guest has reported a system crash {msg:x?}");
1289 Ok(())
1290 }
1291
1292 fn handle_triple_fault(
1293 &mut self,
1294 state: &mut GuestEmulationDevice,
1295 message_buf: &[u8],
1296 ) -> Result<(), Error> {
1297 let (msg, remaining) = get_protocol::TripleFaultNotification::read_from_prefix(message_buf)
1298 .map_err(|_| Error::MessageTooSmall)?; let expected_len = msg.register_count as usize * size_of::<RegisterState>();
1300 if remaining.len() != expected_len {
1301 return Err(Error::InvalidFieldValue);
1302 }
1303 let registers = <[RegisterState]>::ref_from_bytes(remaining).unwrap();
1304 tracing::info!("Guest has reported a triple fault {msg:x?} {registers:?}");
1305 state
1307 .power_client
1308 .power_request(PowerRequest::TripleFault { vp: msg.vp_index });
1309 Ok(())
1310 }
1311
1312 fn handle_modify_vtl2_settings_completed(&mut self, message_buf: &[u8]) -> Result<(), Error> {
1313 let (msg, remaining) =
1314 get_protocol::ModifyVtl2SettingsCompleteNotification::read_from_prefix(message_buf)
1315 .map_err(|_| Error::MessageTooSmall)?; let modify = self.modify.take().ok_or(Error::InvalidSequence)?;
1318 let r = match msg.modify_status {
1319 get_protocol::ModifyVtl2SettingsStatus::SUCCESS => Ok(()),
1320 get_protocol::ModifyVtl2SettingsStatus::FAILURE => {
1321 let errors = std::str::from_utf8(
1322 remaining
1323 .get(..msg.result_document_size as usize)
1324 .ok_or(Error::MessageTooSmall)?,
1325 )
1326 .map_err(|_| Error::InvalidFieldValue)?;
1327
1328 Err(ModifyVtl2SettingsError::Guest(errors.to_owned()))
1329 }
1330 _ => return Err(Error::InvalidFieldValue),
1331 };
1332 modify.complete(r);
1333 Ok(())
1334 }
1335
1336 fn handle_device_platform_settings_v2(
1337 &mut self,
1338 state: &mut GuestEmulationDevice,
1339 ) -> Result<(), Error> {
1340 let vpci_boot_enabled;
1341 let enable_firmware_debugging;
1342 let disable_frontpage;
1343 let firmware_mode_is_pcat;
1344 let pcat_boot_device_order;
1345 let uefi_console_mode;
1346 let default_boot_always_attempt;
1347 match state.config.firmware {
1348 GuestFirmwareConfig::Uefi {
1349 enable_vpci_boot,
1350 firmware_debug,
1351 disable_frontpage: v_disable_frontpage,
1352 console_mode,
1353 default_boot_always_attempt: v_default_boot_always_attempt,
1354 } => {
1355 vpci_boot_enabled = enable_vpci_boot;
1356 enable_firmware_debugging = firmware_debug;
1357 disable_frontpage = v_disable_frontpage;
1358 firmware_mode_is_pcat = false;
1359 pcat_boot_device_order = None;
1360 uefi_console_mode = Some(console_mode);
1361 default_boot_always_attempt = v_default_boot_always_attempt;
1362 }
1363 GuestFirmwareConfig::Pcat { boot_order } => {
1364 vpci_boot_enabled = false;
1365 enable_firmware_debugging = false;
1366 disable_frontpage = false;
1367 firmware_mode_is_pcat = true;
1368 pcat_boot_device_order = Some(boot_order);
1369 uefi_console_mode = None;
1370 default_boot_always_attempt = false;
1371 }
1372 }
1373
1374 let json = get_protocol::dps_json::DevicePlatformSettingsV2Json {
1375 v1: get_protocol::dps_json::HclDevicePlatformSettings {
1376 com1: get_protocol::dps_json::HclUartSettings {
1377 enable_port: state.config.com1,
1378 debugger_mode: false,
1379 enable_vmbus_redirector: state.config.com1,
1380 },
1381 com2: get_protocol::dps_json::HclUartSettings {
1382 enable_port: state.config.com2,
1383 debugger_mode: false,
1384 enable_vmbus_redirector: state.config.com2,
1385 },
1386 enable_firmware_debugging,
1387 enable_tpm: state.config.enable_tpm,
1388 secure_boot_enabled: state.config.secure_boot_enabled,
1389 secure_boot_template_id: match state.config.secure_boot_template {
1390 SecureBootTemplateType::SECURE_BOOT_DISABLED => HclSecureBootTemplateId::None,
1391 SecureBootTemplateType::MICROSOFT_WINDOWS => {
1392 HclSecureBootTemplateId::MicrosoftWindows
1393 }
1394 SecureBootTemplateType::MICROSOFT_UEFI_CERTIFICATE_AUTHORITY => {
1395 HclSecureBootTemplateId::MicrosoftUEFICertificateAuthority
1396 }
1397 _ => panic!("Invalid secure boot template"),
1398 },
1399 enable_battery: state.config.enable_battery,
1400 console_mode: uefi_console_mode.unwrap_or(UefiConsoleMode::DEFAULT).0,
1401 ..Default::default()
1402 },
1403 v2: get_protocol::dps_json::HclDevicePlatformSettingsV2 {
1404 r#static: get_protocol::dps_json::HclDevicePlatformSettingsV2Static {
1405 disable_frontpage,
1406 vmbus_redirection_enabled: state.config.vmbus_redirection,
1407 vtl2_settings: state.config.vtl2_settings.clone(),
1408 firmware_mode_is_pcat,
1409 no_persistent_secrets: state.config.no_persistent_secrets,
1410 legacy_memory_map: false,
1411 pause_after_boot_failure: false,
1412 pxe_ip_v6: false,
1413 measure_additional_pcrs: true,
1414 disable_sha384_pcr: false,
1415 media_present_enabled_by_default: false,
1416 memory_protection_mode: 0,
1417 default_boot_always_attempt,
1418 vpci_boot_enabled,
1419 vpci_instance_filter: None,
1420 num_lock_enabled: false,
1421 pcat_boot_device_order,
1422 smbios: Default::default(),
1423 watchdog_enabled: false,
1424 always_relay_host_mmio: false,
1425 imc_enabled: false,
1426 cxl_memory_enabled: false,
1427 guest_state_lifetime: state.config.guest_state_lifetime,
1428 },
1429 dynamic: get_protocol::dps_json::HclDevicePlatformSettingsV2Dynamic {
1430 is_servicing_scenario: state.save_restore_buf.is_some(),
1431 ..Default::default()
1432 },
1433 },
1434 };
1435
1436 let json_data = serde_json::to_vec(&json).map_err(Error::SerializeDpsV2)?;
1437
1438 if json_data.len() > MAX_PAYLOAD_SIZE {
1443 return Err(Error::LargeDpsV2Unimplemented);
1444 }
1445
1446 let response = get_protocol::DevicePlatformSettingsResponseV2Rev1 {
1450 message_header: HeaderGeneric::new(HostRequests::DEVICE_PLATFORM_SETTINGS_V2_REV1),
1451 size: json_data.len() as u32,
1452 payload_state: get_protocol::LargePayloadState::END,
1453 };
1454
1455 self.channel
1456 .try_send_vectored(&[IoSlice::new(response.as_bytes()), IoSlice::new(&json_data)])
1457 .map_err(Error::Vmbus)?;
1458 Ok(())
1459 }
1460
1461 fn send_hardcoded_battery_update(&mut self) -> Result<(), Error> {
1462 let mut flags = BatteryStatusFlags::new();
1463 flags.set_ac_online(true);
1464 flags.set_battery_present(true);
1465 flags.set_charging(true);
1466 flags.set_discharging(false);
1467 flags.set_reserved(0);
1468
1469 let response = BatteryStatusNotification::new(flags, 1000, 950, 1);
1470 self.channel
1471 .try_send(response.as_bytes())
1472 .map_err(Error::Vmbus)?;
1473 Ok(())
1474 }
1475}