1use super::process_loop::msg;
5use super::process_loop::msg::IgvmAttestRequestData;
6use crate::api::GuestSaveRequest;
7use crate::api::platform_settings;
8use chipset_resources::battery::HostBatteryUpdate;
9use cvm_tracing::CVM_ALLOWED;
10use get_protocol::RegisterState;
11use get_protocol::TripleFaultType;
12use guid::Guid;
13use inspect::Inspect;
14use mesh::MeshPayload;
15use mesh::rpc::Rpc;
16use mesh::rpc::RpcSend;
17use std::sync::Arc;
18use user_driver::DmaClient;
19use vpci::bus_control::VpciBusEvent;
20use zerocopy::IntoBytes;
21
22#[derive(Debug)]
24enum LogOpType {
25 BeginGspCallback,
26 GspCallback,
27}
28
29#[derive(Inspect, Debug, Clone, MeshPayload)]
36pub struct GuestEmulationTransportClient {
37 #[inspect(flatten)]
38 control: ProcessLoopControl,
39 #[inspect(debug)]
40 #[mesh(encoding = "mesh::payload::encoding::ZeroCopyEncoding")]
41 version: get_protocol::ProtocolVersion,
42}
43
44#[derive(Debug, Inspect, Clone, MeshPayload)]
45struct ProcessLoopControl(#[inspect(flatten, send = "msg::Msg::Inspect")] mesh::Sender<msg::Msg>);
46
47impl ProcessLoopControl {
48 async fn call<I, R: 'static + Send>(
49 &self,
50 msg: impl FnOnce(Rpc<I, R>) -> msg::Msg,
51 input: I,
52 ) -> R {
53 match self.0.call(msg, input).await {
54 Ok(val) => val,
55 Err(e) => {
60 tracing::error!(
61 error = &e as &dyn std::error::Error,
62 "fatal error: GET process loop not available. waiting to get blown away..."
63 );
64 std::future::pending::<()>().await;
65 unreachable!()
66 }
67 }
68 }
69
70 fn notify(&self, msg: msg::Msg) {
71 self.0.send(msg);
72 }
73}
74
75pub struct ModifyVtl2SettingsRequest(
76 pub Rpc<Vec<u8>, Result<(), Vec<underhill_config::Vtl2SettingsErrorInfo>>>,
77);
78
79impl GuestEmulationTransportClient {
80 pub(crate) fn new(
81 control: mesh::Sender<msg::Msg>,
82 version: get_protocol::ProtocolVersion,
83 ) -> GuestEmulationTransportClient {
84 GuestEmulationTransportClient {
85 control: ProcessLoopControl(control),
86 version,
87 }
88 }
89
90 pub fn version(&self) -> crate::api::ProtocolVersion {
93 self.version
94 }
95
96 pub async fn vmgs_read(
102 &self,
103 sector_offset: u64,
104 sector_count: u32,
105 sector_size: u32,
106 ) -> Result<Vec<u8>, crate::error::VmgsIoError> {
107 self.control
108 .call(
109 msg::Msg::VmgsRead,
110 msg::VmgsReadInput {
111 sector_offset,
112 sector_count,
113 sector_size,
114 },
115 )
116 .await
117 .map_err(|e| crate::error::VmgsIoError(e.0.status))
118 }
119
120 pub async fn vmgs_write(
129 &self,
130 sector_offset: u64,
131 buf: Vec<u8>,
132 sector_size: u32,
133 ) -> Result<(), crate::error::VmgsIoError> {
134 self.control
135 .call(
136 msg::Msg::VmgsWrite,
137 msg::VmgsWriteInput {
138 sector_offset,
139 buf,
140 sector_size,
141 },
142 )
143 .await
144 .map_err(|e| crate::error::VmgsIoError(e.0.status))
145 }
146
147 pub async fn vmgs_get_device_info(
149 &self,
150 ) -> Result<crate::api::VmgsGetDeviceInfo, crate::error::VmgsIoError> {
151 let response = self.control.call(msg::Msg::VmgsGetDeviceInfo, ()).await.0;
152
153 if response.status != get_protocol::VmgsIoStatus::SUCCESS {
154 return Err(crate::error::VmgsIoError(response.status));
155 }
156
157 let maximum_transfer_size_bytes = response
158 .maximum_transfer_size_bytes
159 .min(get_protocol::MAX_PAYLOAD_SIZE as u32);
160
161 if maximum_transfer_size_bytes != response.maximum_transfer_size_bytes {
162 tracing::warn!(
163 host_value = response.maximum_transfer_size_bytes,
164 clamped_value = maximum_transfer_size_bytes,
165 "VMGS maximum transfer size was clamped due to protocol limitations",
166 );
167 }
168
169 Ok(crate::api::VmgsGetDeviceInfo {
170 status: response.status,
171 capacity: response.capacity,
172 bytes_per_logical_sector: response.bytes_per_logical_sector,
173 bytes_per_physical_sector: response.bytes_per_physical_sector,
174 maximum_transfer_size_bytes,
175 })
176 }
177
178 pub async fn vmgs_flush(&self) -> Result<(), crate::error::VmgsIoError> {
180 let response = self.control.call(msg::Msg::VmgsFlush, ()).await.0;
181
182 if response.status != get_protocol::VmgsIoStatus::SUCCESS {
183 return Err(crate::error::VmgsIoError(response.status));
184 }
185
186 Ok(())
187 }
188
189 pub async fn device_platform_settings(
193 &self,
194 ) -> Result<platform_settings::DevicePlatformSettings, crate::error::DevicePlatformSettingsError>
195 {
196 let json = self
197 .control
198 .call(msg::Msg::DevicePlatformSettingsV2, ())
199 .await;
200
201 let json =
202 serde_json::from_slice::<get_protocol::dps_json::DevicePlatformSettingsV2Json>(&json)
203 .map_err(crate::error::DevicePlatformSettingsError::BadJson)?;
204
205 let vtl2_settings = if let Some(settings) = &json.v2.r#static.vtl2_settings {
206 Some(
207 underhill_config::Vtl2Settings::read_from(settings, Default::default())
208 .map_err(crate::error::DevicePlatformSettingsError::BadVtl2Settings)?,
209 )
210 } else {
211 None
212 };
213
214 Ok(platform_settings::DevicePlatformSettings {
215 smbios: platform_settings::Smbios {
216 serial_number: json.v1.serial_number.into(),
217 base_board_serial_number: json.v1.base_board_serial_number.into(),
218 chassis_serial_number: json.v1.chassis_serial_number.into(),
219 chassis_asset_tag: json.v1.chassis_asset_tag.into(),
220
221 system_manufacturer: json.v2.r#static.smbios.system_manufacturer.into(),
222 system_product_name: json.v2.r#static.smbios.system_product_name.into(),
223 system_version: json.v2.r#static.smbios.system_version.into(),
224 system_sku_number: json.v2.r#static.smbios.system_sku_number.into(),
225 system_family: json.v2.r#static.smbios.system_family.into(),
226 bios_lock_string: json.v2.r#static.smbios.bios_lock_string.into(),
227 memory_device_serial_number: json
228 .v2
229 .r#static
230 .smbios
231 .memory_device_serial_number
232 .into(),
233 processor_manufacturer: json.v2.dynamic.smbios.processor_manufacturer,
234 processor_version: json.v2.dynamic.smbios.processor_version,
235 processor_id: json.v2.dynamic.smbios.processor_id,
236 external_clock: json.v2.dynamic.smbios.external_clock,
237 max_speed: json.v2.dynamic.smbios.max_speed,
238 current_speed: json.v2.dynamic.smbios.current_speed,
239 processor_characteristics: json.v2.dynamic.smbios.processor_characteristics,
240 processor_family2: json.v2.dynamic.smbios.processor_family2,
241 processor_type: json.v2.dynamic.smbios.processor_type,
242 voltage: json.v2.dynamic.smbios.voltage,
243 status: json.v2.dynamic.smbios.status,
244 processor_upgrade: json.v2.dynamic.smbios.processor_upgrade,
245 },
246 general: platform_settings::General {
247 secure_boot_enabled: json.v1.secure_boot_enabled,
248 secure_boot_template: {
249 use crate::api::platform_settings::SecureBootTemplateType;
250 use get_protocol::dps_json::HclSecureBootTemplateId;
251
252 match json.v1.secure_boot_template_id {
253 HclSecureBootTemplateId::None => SecureBootTemplateType::None,
254 HclSecureBootTemplateId::MicrosoftWindows => {
255 SecureBootTemplateType::MicrosoftWindows
256 }
257 HclSecureBootTemplateId::MicrosoftUEFICertificateAuthority => {
258 SecureBootTemplateType::MicrosoftUefiCertificateAuthority
259 }
260 }
261 },
262 bios_guid: json.v1.bios_guid,
263 console_mode: {
264 use crate::api::platform_settings::UefiConsoleMode;
265
266 match get_protocol::UefiConsoleMode(json.v1.console_mode) {
267 get_protocol::UefiConsoleMode::DEFAULT => UefiConsoleMode::Default,
268 get_protocol::UefiConsoleMode::COM1 => UefiConsoleMode::COM1,
269 get_protocol::UefiConsoleMode::COM2 => UefiConsoleMode::COM2,
270 get_protocol::UefiConsoleMode::NONE => UefiConsoleMode::None,
271 o => {
272 return Err(
273 crate::error::DevicePlatformSettingsError::InvalidConsoleMode(o),
274 );
275 }
276 }
277 },
278 battery_enabled: json.v1.enable_battery,
279 processor_idle_enabled: json.v1.enable_processor_idle,
280 tpm_enabled: json.v1.enable_tpm,
281 com1_enabled: json.v1.com1.enable_port,
282 com1_debugger_mode: json.v1.com1.debugger_mode,
283 com1_vmbus_redirector: json.v1.com1.enable_vmbus_redirector,
284 com2_enabled: json.v1.com2.enable_port,
285 com2_debugger_mode: json.v1.com2.debugger_mode,
286 com2_vmbus_redirector: json.v1.com2.enable_vmbus_redirector,
287 firmware_debugging_enabled: json.v1.enable_firmware_debugging,
288 hibernation_enabled: json.v1.enable_hibernation,
289
290 suppress_attestation: Some(json.v2.r#static.no_persistent_secrets),
291 generation_id: {
292 let mut gen_id = [0; 16];
293 gen_id[..8].copy_from_slice(&json.v2.dynamic.generation_id_low.to_ne_bytes());
294 gen_id[8..].copy_from_slice(&json.v2.dynamic.generation_id_high.to_ne_bytes());
295 Some(gen_id)
296 },
297
298 legacy_memory_map: json.v2.r#static.legacy_memory_map,
299 pause_after_boot_failure: json.v2.r#static.pause_after_boot_failure,
300 pxe_ip_v6: json.v2.r#static.pxe_ip_v6,
301 measure_additional_pcrs: json.v2.r#static.measure_additional_pcrs,
302 disable_frontpage: json.v2.r#static.disable_frontpage,
303 disable_sha384_pcr: json.v2.r#static.disable_sha384_pcr,
304 media_present_enabled_by_default: json.v2.r#static.media_present_enabled_by_default,
305 vpci_boot_enabled: json.v2.r#static.vpci_boot_enabled,
306 vpci_instance_filter: json.v2.r#static.vpci_instance_filter,
307 memory_protection_mode: {
308 use crate::api::platform_settings::MemoryProtectionMode;
309
310 match json.v2.r#static.memory_protection_mode {
311 0b00 => MemoryProtectionMode::Disabled,
312 0b01 => MemoryProtectionMode::Default,
313 0b10 => MemoryProtectionMode::Strict,
314 0b11 => MemoryProtectionMode::Relaxed,
315 o => return Err(
316 crate::error::DevicePlatformSettingsError::InvalidMemoryProtectionMode(
317 o,
318 ),
319 ),
320 }
321 },
322 default_boot_always_attempt: json.v2.r#static.default_boot_always_attempt,
323 nvdimm_count: json.v2.dynamic.nvdimm_count,
324 psp_enabled: json.v2.dynamic.enable_psp,
325 vmbus_redirection_enabled: json.v2.r#static.vmbus_redirection_enabled,
326 always_relay_host_mmio: json.v2.r#static.always_relay_host_mmio,
327 vtl2_settings,
328 watchdog_enabled: json.v2.r#static.watchdog_enabled,
329 num_lock_enabled: json.v2.r#static.num_lock_enabled,
330 pcat_boot_device_order: json.v2.r#static.pcat_boot_device_order.unwrap_or({
331 use crate::api::platform_settings::PcatBootDevice;
332 [
333 PcatBootDevice::Floppy,
334 PcatBootDevice::Optical,
335 PcatBootDevice::HardDrive,
336 PcatBootDevice::Network,
337 ]
338 }),
339 is_servicing_scenario: json.v2.dynamic.is_servicing_scenario,
340 firmware_mode_is_pcat: json.v2.r#static.firmware_mode_is_pcat,
341 imc_enabled: json.v2.r#static.imc_enabled,
342 cxl_memory_enabled: json.v2.r#static.cxl_memory_enabled,
343 efi_diagnostics_log_level: json.v2.r#static.efi_diagnostics_log_level,
344 guest_state_lifetime: json.v2.r#static.guest_state_lifetime,
345 guest_state_encryption_policy: json.v2.r#static.guest_state_encryption_policy,
346 management_vtl_features: json.v2.r#static.management_vtl_features,
347 hv_sint_enabled: json.v2.r#static.hv_sint_enabled,
348 },
349 acpi_tables: json.v2.dynamic.acpi_tables,
350 })
351 }
352
353 pub async fn guest_state_protection_data(
355 &self,
356 encrypted_gsp: [crate::api::GspCiphertextContent; crate::api::NUMBER_GSP as usize],
357 gsp_extended_status: crate::api::GspExtendedStatusFlags,
358 ) -> crate::api::GuestStateProtection {
359 let mut buffer = [0; get_protocol::GSP_CLEARTEXT_MAX as usize * 2];
360 let start_time = std::time::SystemTime::now();
361 getrandom::fill(&mut buffer).expect("rng failure");
362
363 tracing::info!(
364 CVM_ALLOWED,
365 op_type = ?LogOpType::BeginGspCallback,
366 "Getting guest state protection data"
367 );
368
369 let gsp_request = get_protocol::GuestStateProtectionRequest::new(
370 buffer,
371 encrypted_gsp,
372 gsp_extended_status,
373 );
374
375 let response = self
376 .control
377 .call(msg::Msg::GuestStateProtection, Box::new(gsp_request.into()))
378 .await
379 .0;
380
381 tracing::info!(
382 CVM_ALLOWED,
383 op_type = ?LogOpType::GspCallback,
384 latency = std::time::SystemTime::now()
385 .duration_since(start_time)
386 .map_or(0, |d| d.as_millis()),
387 "Got guest state protection data"
388 );
389
390 crate::api::GuestStateProtection {
391 encrypted_gsp: response.encrypted_gsp,
392 decrypted_gsp: response.decrypted_gsp,
393 extended_status_flags: response.extended_status_flags,
394 new_gsp: gsp_request.new_gsp,
395 }
396 }
397
398 pub fn set_gpa_allocator(&mut self, gpa_allocator: Arc<dyn DmaClient>) {
404 self.control
405 .notify(msg::Msg::SetGpaAllocator(gpa_allocator.into()));
406 }
407
408 pub fn set_debug_interrupt_callback(&mut self, callback: Box<dyn Fn(u8) + Send + Sync>) {
410 self.control
411 .notify(msg::Msg::SetDebugInterruptCallback(callback.into()));
412 }
413
414 pub fn set_post_live_migration_callback(&mut self, callback: Box<dyn Fn() + Send + Sync>) {
416 self.control
417 .notify(msg::Msg::SetPostLiveMigrationCallback(callback.into()));
418 }
419
420 pub async fn igvm_attest(
422 &self,
423 agent_data: Vec<u8>,
424 report: Vec<u8>,
425 response_buffer_len: usize,
426 ) -> Result<crate::api::IgvmAttest, crate::error::IgvmAttestError> {
427 let request = IgvmAttestRequestData {
428 agent_data,
429 report,
430 response_buffer_len,
431 };
432
433 let response = self
434 .control
435 .call(msg::Msg::IgvmAttest, Box::new(request))
436 .await?;
437
438 Ok(crate::api::IgvmAttest { response })
439 }
440
441 pub fn send_power_off(&self) {
446 tracing::info!("powering off...");
447 self.control
448 .notify(msg::Msg::PowerState(msg::PowerState::PowerOff));
449 }
450
451 pub fn send_hibernate(&self) {
456 tracing::info!("hibernating...");
457 self.control
458 .notify(msg::Msg::PowerState(msg::PowerState::Hibernate));
459 }
460
461 pub fn send_reset(&self) {
466 tracing::info!("resetting...");
467 self.control
468 .notify(msg::Msg::PowerState(msg::PowerState::Reset));
469 }
470
471 pub fn event_log(&self, event_log_id: crate::api::EventLogId) {
484 self.control.notify(msg::Msg::EventLog(event_log_id.into()));
485 }
486
487 pub async fn event_log_flush(&self) {
490 self.control.call(msg::Msg::FlushWrites, ()).await
491 }
492
493 pub async fn event_log_fatal(&self, event_log_id: crate::api::EventLogId) {
502 self.control.notify(msg::Msg::EventLog(event_log_id.into()));
503 self.control.call(msg::Msg::FlushWrites, ()).await
504 }
505
506 pub async fn host_time(&self) -> crate::api::Time {
508 let response = self.control.call(msg::Msg::HostTime, ()).await;
509 crate::api::Time {
510 utc: response.0.utc,
511 time_zone: response.0.time_zone,
512 }
513 }
514
515 pub async fn guest_state_protection_data_by_id(
517 &self,
518 ) -> Result<crate::api::GuestStateProtectionById, crate::error::GuestStateProtectionByIdError>
519 {
520 let response = self
521 .control
522 .call(msg::Msg::GuestStateProtectionById, ())
523 .await
524 .0;
525
526 if response.seed.length > response.seed.buffer.len() as u32 {
527 return Err(crate::error::GuestStateProtectionByIdError(
528 response.seed.length,
529 response.seed.buffer.len() as u32,
530 ));
531 }
532
533 Ok(crate::api::GuestStateProtectionById {
534 seed: response.seed,
535 extended_status_flags: response.extended_status_flags,
536 })
537 }
538
539 pub async fn complete_start_vtl0(&self, error_msg: Option<String>) {
541 if self.version >= get_protocol::ProtocolVersion::NICKEL_REV2 {
542 self.control
543 .call(msg::Msg::CompleteStartVtl0, error_msg.clone())
544 .await;
545
546 if let Some(error_msg) = error_msg {
547 mesh::CancelContext::new()
554 .with_timeout(std::time::Duration::from_mins(2))
555 .until_cancelled(std::future::pending::<()>())
556 .await
557 .unwrap_or_else(|_| {
558 panic!(
559 "should have been terminated after reporting start failure: {error_msg}"
560 )
561 });
562 }
563 }
564 }
565
566 pub async fn map_framebuffer(&self, gpa: u64) -> Result<(), crate::error::MapFramebufferError> {
568 let response = self.control.call(msg::Msg::MapFramebuffer, gpa).await.0;
569 match response.status {
570 get_protocol::MapFramebufferStatus::SUCCESS => Ok(()),
571 _ => Err(crate::error::MapFramebufferError(response.status)),
572 }
573 }
574
575 pub async fn unmap_framebuffer(&self) -> Result<(), crate::error::UnmapFramebufferError> {
577 let response = self.control.call(msg::Msg::UnmapFramebuffer, ()).await.0;
578 match response.status {
579 get_protocol::UnmapFramebufferStatus::SUCCESS => Ok(()),
580 _ => Err(crate::error::UnmapFramebufferError(response.status)),
581 }
582 }
583
584 pub async fn offer_vpci_device(
586 &self,
587 bus_instance_id: Guid,
588 ) -> Result<(), crate::error::VpciControlError> {
589 let response = self
590 .control
591 .call(
592 msg::Msg::VpciDeviceControl,
593 msg::VpciDeviceControlInput {
594 code: get_protocol::VpciDeviceControlCode::OFFER.into(),
595 bus_instance_id,
596 },
597 )
598 .await
599 .0;
600 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
601 Err(crate::error::VpciControlError(response.status))
602 } else {
603 Ok(())
604 }
605 }
606
607 pub async fn revoke_vpci_device(
609 &self,
610 bus_instance_id: Guid,
611 ) -> Result<(), crate::error::VpciControlError> {
612 let response = self
613 .control
614 .call(
615 msg::Msg::VpciDeviceControl,
616 msg::VpciDeviceControlInput {
617 code: get_protocol::VpciDeviceControlCode::REVOKE.into(),
618 bus_instance_id,
619 },
620 )
621 .await
622 .0;
623 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
624 Err(crate::error::VpciControlError(response.status))
625 } else {
626 Ok(())
627 }
628 }
629
630 pub async fn report_vpci_device_binding_state(
632 &self,
633 bus_instance_id: Guid,
634 binding_state: bool,
635 ) -> Result<(), crate::error::VpciControlError> {
636 let response = self
637 .control
638 .call(
639 msg::Msg::VpciDeviceBindingChange,
640 msg::VpciDeviceBindingChangeInput {
641 bus_instance_id,
642 binding_state,
643 },
644 )
645 .await
646 .0;
647 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
648 Err(crate::error::VpciControlError(response.status))
649 } else {
650 Ok(())
651 }
652 }
653
654 pub async fn connect_to_vpci_event_source(
657 &self,
658 bus_instance_id: Guid,
659 ) -> mesh::Receiver<VpciBusEvent> {
660 let (sender, receiver) = mesh::channel();
661 self.control
662 .call(
663 msg::Msg::VpciListenerRegistration,
664 msg::VpciListenerRegistrationInput {
665 bus_instance_id,
666 sender,
667 },
668 )
669 .await;
670 receiver
671 }
672
673 pub fn disconnect_from_vpci_event_source(&self, bus_instance_id: Guid) {
675 self.control
676 .notify(msg::Msg::VpciListenerDeregistration(bus_instance_id));
677 }
678
679 pub async fn take_vtl2_settings_recv(
681 &self,
682 ) -> Option<mesh::Receiver<ModifyVtl2SettingsRequest>> {
683 self.control
684 .call(msg::Msg::TakeVtl2SettingsReceiver, ())
685 .await
686 .0
687 }
688
689 pub async fn take_generation_id_recv(&self) -> Option<mesh::Receiver<[u8; 16]>> {
691 self.control.call(msg::Msg::TakeGenIdReceiver, ()).await
692 }
693
694 pub async fn take_battery_status_recv(&self) -> Option<mesh::Receiver<HostBatteryUpdate>> {
696 self.control
697 .call(msg::Msg::TakeBatteryStatusReceiver, ())
698 .await
699 }
700
701 pub async fn vga_proxy_pci_read(&self, offset: u16) -> u32 {
703 let response = self.control.call(msg::Msg::VgaProxyPciRead, offset).await.0;
704 response.value
705 }
706
707 pub async fn vga_proxy_pci_write(&self, offset: u16, value: u32) {
709 self.control
710 .call(
711 msg::Msg::VgaProxyPciWrite,
712 msg::VgaProxyPciWriteInput { offset, value },
713 )
714 .await;
715 }
716
717 pub async fn create_ram_gpa_range(
719 &self,
720 slot: u32,
721 gpa_start: u64,
722 gpa_count: u64,
723 gpa_offset: u64,
724 flags: crate::api::CreateRamGpaRangeFlags,
725 ) -> Result<crate::api::RemoteRamGpaRangeHandle, crate::error::CreateRamGpaRangeError> {
726 let response = self
727 .control
728 .call(
729 msg::Msg::CreateRamGpaRange,
730 msg::CreateRamGpaRangeInput {
731 slot,
732 gpa_start,
733 gpa_count,
734 gpa_offset,
735 flags: flags.into(),
736 },
737 )
738 .await
739 .0;
740 if response.status != get_protocol::CreateRamGpaRangeStatus::SUCCESS {
741 Err(crate::error::CreateRamGpaRangeError(response.status))
742 } else {
743 Ok(crate::api::RemoteRamGpaRangeHandle::from_raw(slot))
744 }
745 }
746
747 pub async fn reset_ram_gpa_range(&self, handle: crate::api::RemoteRamGpaRangeHandle) {
750 self.control
751 .call(msg::Msg::ResetRamGpaRange, handle.as_raw())
752 .await;
753 }
754
755 pub async fn get_saved_state_from_host(
758 &self,
759 ) -> Result<Vec<u8>, crate::error::SaveRestoreOperationFailure> {
760 self.control
761 .call(msg::Msg::GetVtl2SavedStateFromHost, ())
762 .await
763 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
764 }
765
766 pub async fn report_restore_result_to_host(&self, success: bool) {
771 self.control
772 .notify(msg::Msg::ReportRestoreResultToHost(success));
773 }
774
775 pub async fn take_save_request_recv(&self) -> Option<mesh::Receiver<GuestSaveRequest>> {
779 self.control
780 .call(msg::Msg::TakeSaveRequestReceiver, ())
781 .await
782 }
783
784 pub async fn send_servicing_state(
789 &self,
790 data: Vec<u8>,
791 ) -> Result<(), crate::error::SaveRestoreOperationFailure> {
792 self.control
793 .call(msg::Msg::SendServicingState, Ok(data))
794 .await
795 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
796 }
797
798 pub async fn send_servicing_failure(
803 &self,
804 err: impl ToString,
805 ) -> Result<(), crate::error::SaveRestoreOperationFailure> {
806 self.control
807 .call(msg::Msg::SendServicingState, Err(err.to_string()))
808 .await
809 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
810 }
811
812 pub fn notify_of_vtl_crash(
814 &self,
815 vp_index: u32,
816 last_vtl: u8,
817 control: u64,
818 parameters: [u64; get_protocol::VTL_CRASH_PARAMETERS],
819 ) {
820 self.control.notify(msg::Msg::VtlCrashNotification(
821 get_protocol::VtlCrashNotification::new(vp_index, last_vtl, control, parameters).into(),
822 ));
823 }
824
825 pub fn triple_fault(
827 &self,
828 vp_index: u32,
829 fault_type: TripleFaultType,
830 reg_state: Vec<RegisterState>,
831 ) {
832 let mut payload = vec![];
833
834 let notification = get_protocol::TripleFaultNotification::new(
835 vp_index,
836 fault_type,
837 reg_state.len() as u32,
838 );
839 payload.extend_from_slice(notification.as_bytes());
840 payload.extend_from_slice(reg_state.as_bytes());
841
842 self.control
843 .notify(msg::Msg::TripleFaultNotification(payload));
844 }
845}