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 },
348 acpi_tables: json.v2.dynamic.acpi_tables,
349 })
350 }
351
352 pub async fn guest_state_protection_data(
354 &self,
355 encrypted_gsp: [crate::api::GspCiphertextContent; crate::api::NUMBER_GSP as usize],
356 gsp_extended_status: crate::api::GspExtendedStatusFlags,
357 ) -> crate::api::GuestStateProtection {
358 let mut buffer = [0; get_protocol::GSP_CLEARTEXT_MAX as usize * 2];
359 let start_time = std::time::SystemTime::now();
360 getrandom::fill(&mut buffer).expect("rng failure");
361
362 tracing::info!(
363 CVM_ALLOWED,
364 op_type = ?LogOpType::BeginGspCallback,
365 "Getting guest state protection data"
366 );
367
368 let gsp_request = get_protocol::GuestStateProtectionRequest::new(
369 buffer,
370 encrypted_gsp,
371 gsp_extended_status,
372 );
373
374 let response = self
375 .control
376 .call(msg::Msg::GuestStateProtection, Box::new(gsp_request.into()))
377 .await
378 .0;
379
380 tracing::info!(
381 CVM_ALLOWED,
382 op_type = ?LogOpType::GspCallback,
383 latency = std::time::SystemTime::now()
384 .duration_since(start_time)
385 .map_or(0, |d| d.as_millis()),
386 "Got guest state protection data"
387 );
388
389 crate::api::GuestStateProtection {
390 encrypted_gsp: response.encrypted_gsp,
391 decrypted_gsp: response.decrypted_gsp,
392 extended_status_flags: response.extended_status_flags,
393 new_gsp: gsp_request.new_gsp,
394 }
395 }
396
397 pub fn set_gpa_allocator(&mut self, gpa_allocator: Arc<dyn DmaClient>) {
403 self.control
404 .notify(msg::Msg::SetGpaAllocator(gpa_allocator.into()));
405 }
406
407 pub fn set_debug_interrupt_callback(&mut self, callback: Box<dyn Fn(u8) + Send + Sync>) {
409 self.control
410 .notify(msg::Msg::SetDebugInterruptCallback(callback.into()));
411 }
412
413 pub async fn igvm_attest(
415 &self,
416 agent_data: Vec<u8>,
417 report: Vec<u8>,
418 response_buffer_len: usize,
419 ) -> Result<crate::api::IgvmAttest, crate::error::IgvmAttestError> {
420 let request = IgvmAttestRequestData {
421 agent_data,
422 report,
423 response_buffer_len,
424 };
425
426 let response = self
427 .control
428 .call(msg::Msg::IgvmAttest, Box::new(request))
429 .await?;
430
431 Ok(crate::api::IgvmAttest { response })
432 }
433
434 pub fn send_power_off(&self) {
439 tracing::info!("powering off...");
440 self.control
441 .notify(msg::Msg::PowerState(msg::PowerState::PowerOff));
442 }
443
444 pub fn send_hibernate(&self) {
449 tracing::info!("hibernating...");
450 self.control
451 .notify(msg::Msg::PowerState(msg::PowerState::Hibernate));
452 }
453
454 pub fn send_reset(&self) {
459 tracing::info!("resetting...");
460 self.control
461 .notify(msg::Msg::PowerState(msg::PowerState::Reset));
462 }
463
464 pub fn event_log(&self, event_log_id: crate::api::EventLogId) {
477 self.control.notify(msg::Msg::EventLog(event_log_id.into()));
478 }
479
480 pub async fn event_log_flush(&self) {
483 self.control.call(msg::Msg::FlushWrites, ()).await
484 }
485
486 pub async fn event_log_fatal(&self, event_log_id: crate::api::EventLogId) {
495 self.control.notify(msg::Msg::EventLog(event_log_id.into()));
496 self.control.call(msg::Msg::FlushWrites, ()).await
497 }
498
499 pub async fn host_time(&self) -> crate::api::Time {
501 let response = self.control.call(msg::Msg::HostTime, ()).await;
502 crate::api::Time {
503 utc: response.0.utc,
504 time_zone: response.0.time_zone,
505 }
506 }
507
508 pub async fn guest_state_protection_data_by_id(
510 &self,
511 ) -> Result<crate::api::GuestStateProtectionById, crate::error::GuestStateProtectionByIdError>
512 {
513 let response = self
514 .control
515 .call(msg::Msg::GuestStateProtectionById, ())
516 .await
517 .0;
518
519 if response.seed.length > response.seed.buffer.len() as u32 {
520 return Err(crate::error::GuestStateProtectionByIdError(
521 response.seed.length,
522 response.seed.buffer.len() as u32,
523 ));
524 }
525
526 Ok(crate::api::GuestStateProtectionById {
527 seed: response.seed,
528 extended_status_flags: response.extended_status_flags,
529 })
530 }
531
532 pub async fn complete_start_vtl0(&self, error_msg: Option<String>) {
534 if self.version >= get_protocol::ProtocolVersion::NICKEL_REV2 {
535 self.control
536 .call(msg::Msg::CompleteStartVtl0, error_msg.clone())
537 .await;
538
539 if let Some(error_msg) = error_msg {
540 mesh::CancelContext::new()
544 .with_timeout(std::time::Duration::from_secs(30))
545 .until_cancelled(std::future::pending::<()>())
546 .await
547 .unwrap_or_else(|_| {
548 panic!(
549 "should have been terminated after reporting start failure: {error_msg}"
550 )
551 });
552 }
553 }
554 }
555
556 pub async fn map_framebuffer(&self, gpa: u64) -> Result<(), crate::error::MapFramebufferError> {
558 let response = self.control.call(msg::Msg::MapFramebuffer, gpa).await.0;
559 match response.status {
560 get_protocol::MapFramebufferStatus::SUCCESS => Ok(()),
561 _ => Err(crate::error::MapFramebufferError(response.status)),
562 }
563 }
564
565 pub async fn unmap_framebuffer(&self) -> Result<(), crate::error::UnmapFramebufferError> {
567 let response = self.control.call(msg::Msg::UnmapFramebuffer, ()).await.0;
568 match response.status {
569 get_protocol::UnmapFramebufferStatus::SUCCESS => Ok(()),
570 _ => Err(crate::error::UnmapFramebufferError(response.status)),
571 }
572 }
573
574 pub async fn offer_vpci_device(
576 &self,
577 bus_instance_id: Guid,
578 ) -> Result<(), crate::error::VpciControlError> {
579 let response = self
580 .control
581 .call(
582 msg::Msg::VpciDeviceControl,
583 msg::VpciDeviceControlInput {
584 code: get_protocol::VpciDeviceControlCode::OFFER.into(),
585 bus_instance_id,
586 },
587 )
588 .await
589 .0;
590 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
591 Err(crate::error::VpciControlError(response.status))
592 } else {
593 Ok(())
594 }
595 }
596
597 pub async fn revoke_vpci_device(
599 &self,
600 bus_instance_id: Guid,
601 ) -> Result<(), crate::error::VpciControlError> {
602 let response = self
603 .control
604 .call(
605 msg::Msg::VpciDeviceControl,
606 msg::VpciDeviceControlInput {
607 code: get_protocol::VpciDeviceControlCode::REVOKE.into(),
608 bus_instance_id,
609 },
610 )
611 .await
612 .0;
613 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
614 Err(crate::error::VpciControlError(response.status))
615 } else {
616 Ok(())
617 }
618 }
619
620 pub async fn report_vpci_device_binding_state(
622 &self,
623 bus_instance_id: Guid,
624 binding_state: bool,
625 ) -> Result<(), crate::error::VpciControlError> {
626 let response = self
627 .control
628 .call(
629 msg::Msg::VpciDeviceBindingChange,
630 msg::VpciDeviceBindingChangeInput {
631 bus_instance_id,
632 binding_state,
633 },
634 )
635 .await
636 .0;
637 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
638 Err(crate::error::VpciControlError(response.status))
639 } else {
640 Ok(())
641 }
642 }
643
644 pub async fn connect_to_vpci_event_source(
647 &self,
648 bus_instance_id: Guid,
649 ) -> mesh::Receiver<VpciBusEvent> {
650 let (sender, receiver) = mesh::channel();
651 self.control
652 .call(
653 msg::Msg::VpciListenerRegistration,
654 msg::VpciListenerRegistrationInput {
655 bus_instance_id,
656 sender,
657 },
658 )
659 .await;
660 receiver
661 }
662
663 pub fn disconnect_from_vpci_event_source(&self, bus_instance_id: Guid) {
665 self.control
666 .notify(msg::Msg::VpciListenerDeregistration(bus_instance_id));
667 }
668
669 pub async fn take_vtl2_settings_recv(
671 &self,
672 ) -> Option<mesh::Receiver<ModifyVtl2SettingsRequest>> {
673 self.control
674 .call(msg::Msg::TakeVtl2SettingsReceiver, ())
675 .await
676 .0
677 }
678
679 pub async fn take_generation_id_recv(&self) -> Option<mesh::Receiver<[u8; 16]>> {
681 self.control.call(msg::Msg::TakeGenIdReceiver, ()).await
682 }
683
684 pub async fn take_battery_status_recv(&self) -> Option<mesh::Receiver<HostBatteryUpdate>> {
686 self.control
687 .call(msg::Msg::TakeBatteryStatusReceiver, ())
688 .await
689 }
690
691 pub async fn vga_proxy_pci_read(&self, offset: u16) -> u32 {
693 let response = self.control.call(msg::Msg::VgaProxyPciRead, offset).await.0;
694 response.value
695 }
696
697 pub async fn vga_proxy_pci_write(&self, offset: u16, value: u32) {
699 self.control
700 .call(
701 msg::Msg::VgaProxyPciWrite,
702 msg::VgaProxyPciWriteInput { offset, value },
703 )
704 .await;
705 }
706
707 pub async fn create_ram_gpa_range(
709 &self,
710 slot: u32,
711 gpa_start: u64,
712 gpa_count: u64,
713 gpa_offset: u64,
714 flags: crate::api::CreateRamGpaRangeFlags,
715 ) -> Result<crate::api::RemoteRamGpaRangeHandle, crate::error::CreateRamGpaRangeError> {
716 let response = self
717 .control
718 .call(
719 msg::Msg::CreateRamGpaRange,
720 msg::CreateRamGpaRangeInput {
721 slot,
722 gpa_start,
723 gpa_count,
724 gpa_offset,
725 flags: flags.into(),
726 },
727 )
728 .await
729 .0;
730 if response.status != get_protocol::CreateRamGpaRangeStatus::SUCCESS {
731 Err(crate::error::CreateRamGpaRangeError(response.status))
732 } else {
733 Ok(crate::api::RemoteRamGpaRangeHandle::from_raw(slot))
734 }
735 }
736
737 pub async fn reset_ram_gpa_range(&self, handle: crate::api::RemoteRamGpaRangeHandle) {
740 self.control
741 .call(msg::Msg::ResetRamGpaRange, handle.as_raw())
742 .await;
743 }
744
745 pub async fn get_saved_state_from_host(
748 &self,
749 ) -> Result<Vec<u8>, crate::error::SaveRestoreOperationFailure> {
750 self.control
751 .call(msg::Msg::GetVtl2SavedStateFromHost, ())
752 .await
753 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
754 }
755
756 pub async fn report_restore_result_to_host(&self, success: bool) {
761 self.control
762 .notify(msg::Msg::ReportRestoreResultToHost(success));
763 }
764
765 pub async fn take_save_request_recv(&self) -> Option<mesh::Receiver<GuestSaveRequest>> {
769 self.control
770 .call(msg::Msg::TakeSaveRequestReceiver, ())
771 .await
772 }
773
774 pub async fn send_servicing_state(
779 &self,
780 data: Vec<u8>,
781 ) -> Result<(), crate::error::SaveRestoreOperationFailure> {
782 self.control
783 .call(msg::Msg::SendServicingState, Ok(data))
784 .await
785 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
786 }
787
788 pub async fn send_servicing_failure(
793 &self,
794 err: impl ToString,
795 ) -> Result<(), crate::error::SaveRestoreOperationFailure> {
796 self.control
797 .call(msg::Msg::SendServicingState, Err(err.to_string()))
798 .await
799 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
800 }
801
802 pub fn notify_of_vtl_crash(
804 &self,
805 vp_index: u32,
806 last_vtl: u8,
807 control: u64,
808 parameters: [u64; get_protocol::VTL_CRASH_PARAMETERS],
809 ) {
810 self.control.notify(msg::Msg::VtlCrashNotification(
811 get_protocol::VtlCrashNotification::new(vp_index, last_vtl, control, parameters).into(),
812 ));
813 }
814
815 pub fn triple_fault(
817 &self,
818 vp_index: u32,
819 fault_type: TripleFaultType,
820 reg_state: Vec<RegisterState>,
821 ) {
822 let mut payload = vec![];
823
824 let notification = get_protocol::TripleFaultNotification::new(
825 vp_index,
826 fault_type,
827 reg_state.len() as u32,
828 );
829 payload.extend_from_slice(notification.as_bytes());
830 payload.extend_from_slice(reg_state.as_bytes());
831
832 self.control
833 .notify(msg::Msg::TripleFaultNotification(payload));
834 }
835}