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