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,
217 base_board_serial_number: json.v1.base_board_serial_number,
218 chassis_serial_number: json.v1.chassis_serial_number,
219 chassis_asset_tag: json.v1.chassis_asset_tag,
220
221 system_manufacturer: json.v2.r#static.smbios.system_manufacturer,
222 system_product_name: json.v2.r#static.smbios.system_product_name,
223 system_version: json.v2.r#static.smbios.system_version,
224 system_sku_number: json.v2.r#static.smbios.system_sku_number,
225 system_family: json.v2.r#static.smbios.system_family,
226 bios_lock_string: json.v2.r#static.smbios.bios_lock_string,
227 memory_device_serial_number: json.v2.r#static.smbios.memory_device_serial_number,
228 processor_manufacturer: json.v2.dynamic.smbios.processor_manufacturer,
229 processor_version: json.v2.dynamic.smbios.processor_version,
230 processor_id: json.v2.dynamic.smbios.processor_id,
231 external_clock: json.v2.dynamic.smbios.external_clock,
232 max_speed: json.v2.dynamic.smbios.max_speed,
233 current_speed: json.v2.dynamic.smbios.current_speed,
234 processor_characteristics: json.v2.dynamic.smbios.processor_characteristics,
235 processor_family2: json.v2.dynamic.smbios.processor_family2,
236 processor_type: json.v2.dynamic.smbios.processor_type,
237 voltage: json.v2.dynamic.smbios.voltage,
238 status: json.v2.dynamic.smbios.status,
239 processor_upgrade: json.v2.dynamic.smbios.processor_upgrade,
240 },
241 general: platform_settings::General {
242 secure_boot_enabled: json.v1.secure_boot_enabled,
243 secure_boot_template: {
244 use crate::api::platform_settings::SecureBootTemplateType;
245 use get_protocol::dps_json::HclSecureBootTemplateId;
246
247 match json.v1.secure_boot_template_id {
248 HclSecureBootTemplateId::None => SecureBootTemplateType::None,
249 HclSecureBootTemplateId::MicrosoftWindows => {
250 SecureBootTemplateType::MicrosoftWindows
251 }
252 HclSecureBootTemplateId::MicrosoftUEFICertificateAuthority => {
253 SecureBootTemplateType::MicrosoftUefiCertificateAuthority
254 }
255 }
256 },
257 bios_guid: json.v1.bios_guid,
258 console_mode: {
259 use crate::api::platform_settings::UefiConsoleMode;
260
261 match get_protocol::UefiConsoleMode(json.v1.console_mode) {
262 get_protocol::UefiConsoleMode::DEFAULT => UefiConsoleMode::Default,
263 get_protocol::UefiConsoleMode::COM1 => UefiConsoleMode::COM1,
264 get_protocol::UefiConsoleMode::COM2 => UefiConsoleMode::COM2,
265 get_protocol::UefiConsoleMode::NONE => UefiConsoleMode::None,
266 o => {
267 return Err(
268 crate::error::DevicePlatformSettingsError::InvalidConsoleMode(o),
269 );
270 }
271 }
272 },
273 battery_enabled: json.v1.enable_battery,
274 processor_idle_enabled: json.v1.enable_processor_idle,
275 tpm_enabled: json.v1.enable_tpm,
276 tpm_version: json.v2.r#static.tpm_version,
277 com1_enabled: json.v1.com1.enable_port,
278 com1_debugger_mode: json.v1.com1.debugger_mode,
279 com1_vmbus_redirector: json.v1.com1.enable_vmbus_redirector,
280 com2_enabled: json.v1.com2.enable_port,
281 com2_debugger_mode: json.v1.com2.debugger_mode,
282 com2_vmbus_redirector: json.v1.com2.enable_vmbus_redirector,
283 firmware_debugging_enabled: json.v1.enable_firmware_debugging,
284 hibernation_enabled: json.v1.enable_hibernation,
285
286 suppress_attestation: Some(json.v2.r#static.no_persistent_secrets),
287 generation_id: {
288 let mut gen_id = [0; 16];
289 gen_id[..8].copy_from_slice(&json.v2.dynamic.generation_id_low.to_ne_bytes());
290 gen_id[8..].copy_from_slice(&json.v2.dynamic.generation_id_high.to_ne_bytes());
291 Some(gen_id)
292 },
293
294 legacy_memory_map: json.v2.r#static.legacy_memory_map,
295 pause_after_boot_failure: json.v2.r#static.pause_after_boot_failure,
296 pxe_ip_v6: json.v2.r#static.pxe_ip_v6,
297 measure_additional_pcrs: json.v2.r#static.measure_additional_pcrs,
298 disable_frontpage: json.v2.r#static.disable_frontpage,
299 disable_sha384_pcr: json.v2.r#static.disable_sha384_pcr,
300 media_present_enabled_by_default: json.v2.r#static.media_present_enabled_by_default,
301 vpci_boot_enabled: json.v2.r#static.vpci_boot_enabled,
302 vpci_instance_filter: json.v2.r#static.vpci_instance_filter,
303 memory_protection_mode: {
304 use crate::api::platform_settings::MemoryProtectionMode;
305
306 match json.v2.r#static.memory_protection_mode {
307 0b00 => MemoryProtectionMode::Disabled,
308 0b01 => MemoryProtectionMode::Default,
309 0b10 => MemoryProtectionMode::Strict,
310 0b11 => MemoryProtectionMode::Relaxed,
311 o => return Err(
312 crate::error::DevicePlatformSettingsError::InvalidMemoryProtectionMode(
313 o,
314 ),
315 ),
316 }
317 },
318 default_boot_always_attempt: json.v2.r#static.default_boot_always_attempt,
319 nvdimm_count: json.v2.dynamic.nvdimm_count,
320 psp_enabled: json.v2.dynamic.enable_psp,
321 vmbus_redirection_enabled: json.v2.r#static.vmbus_redirection_enabled,
322 always_relay_host_mmio: json.v2.r#static.always_relay_host_mmio,
323 vtl2_settings,
324 watchdog_enabled: json.v2.r#static.watchdog_enabled,
325 num_lock_enabled: json.v2.r#static.num_lock_enabled,
326 pcat_boot_device_order: json.v2.r#static.pcat_boot_device_order.unwrap_or({
327 use crate::api::platform_settings::PcatBootDevice;
328 [
329 PcatBootDevice::Floppy,
330 PcatBootDevice::Optical,
331 PcatBootDevice::HardDrive,
332 PcatBootDevice::Network,
333 ]
334 }),
335 is_servicing_scenario: json.v2.dynamic.is_servicing_scenario,
336 firmware_mode_is_pcat: json.v2.r#static.firmware_mode_is_pcat,
337 imc_enabled: json.v2.r#static.imc_enabled,
338 cxl_memory_enabled: json.v2.r#static.cxl_memory_enabled,
339 efi_diagnostics_log_level: json.v2.r#static.efi_diagnostics_log_level,
340 guest_state_lifetime: json.v2.r#static.guest_state_lifetime,
341 guest_state_encryption_policy: json.v2.r#static.guest_state_encryption_policy,
342 management_vtl_features: json.v2.r#static.management_vtl_features,
343 force_dma_bounce_enabled: json.v2.r#static.force_dma_bounce_enabled,
344 hardware_sealing_policy: json.v2.r#static.hardware_sealing_policy_id,
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.into()))
375 .await
376 .0;
377
378 tracing::info!(
379 CVM_ALLOWED,
380 op_type = ?LogOpType::GspCallback,
381 latency = std::time::SystemTime::now()
382 .duration_since(start_time)
383 .map_or(0, |d| d.as_millis()),
384 "Got guest state protection data"
385 );
386
387 crate::api::GuestStateProtection {
388 encrypted_gsp: response.encrypted_gsp,
389 decrypted_gsp: response.decrypted_gsp,
390 extended_status_flags: response.extended_status_flags,
391 new_gsp: gsp_request.new_gsp,
392 }
393 }
394
395 pub fn set_gpa_allocator(&mut self, gpa_allocator: Arc<dyn DmaClient>) {
401 self.control
402 .notify(msg::Msg::SetGpaAllocator(gpa_allocator.into()));
403 }
404
405 pub fn set_debug_interrupt_callback(&mut self, callback: Box<dyn Fn(u8) + Send + Sync>) {
407 self.control
408 .notify(msg::Msg::SetDebugInterruptCallback(callback.into()));
409 }
410
411 pub fn set_post_live_migration_callback(&mut self, callback: Box<dyn Fn() + Send + Sync>) {
413 self.control
414 .notify(msg::Msg::SetPostLiveMigrationCallback(callback.into()));
415 }
416
417 pub async fn igvm_attest(
419 &self,
420 agent_data: Vec<u8>,
421 report: Vec<u8>,
422 response_buffer_len: usize,
423 ) -> Result<crate::api::IgvmAttest, crate::error::IgvmAttestError> {
424 let request = IgvmAttestRequestData {
425 agent_data,
426 report,
427 response_buffer_len,
428 };
429
430 let response = self
431 .control
432 .call(msg::Msg::IgvmAttest, Box::new(request))
433 .await?;
434
435 Ok(crate::api::IgvmAttest { response })
436 }
437
438 pub fn send_power_off(&self) {
443 tracing::info!("powering off...");
444 self.control
445 .notify(msg::Msg::PowerState(msg::PowerState::PowerOff));
446 }
447
448 pub fn send_hibernate(&self) {
453 tracing::info!("hibernating...");
454 self.control
455 .notify(msg::Msg::PowerState(msg::PowerState::Hibernate));
456 }
457
458 pub fn send_reset(&self) {
463 tracing::info!("resetting...");
464 self.control
465 .notify(msg::Msg::PowerState(msg::PowerState::Reset));
466 }
467
468 pub fn event_log(&self, event_log_id: crate::api::EventLogId) {
481 self.control.notify(msg::Msg::EventLog(event_log_id.into()));
482 }
483
484 pub async fn event_log_flush(&self) {
487 self.control.call(msg::Msg::FlushWrites, ()).await
488 }
489
490 pub async fn event_log_fatal(&self, event_log_id: crate::api::EventLogId) {
499 self.control.notify(msg::Msg::EventLog(event_log_id.into()));
500 self.control.call(msg::Msg::FlushWrites, ()).await
501 }
502
503 pub async fn host_time(&self) -> crate::api::Time {
505 let response = self.control.call(msg::Msg::HostTime, ()).await;
506 crate::api::Time {
507 utc: response.0.utc,
508 time_zone: response.0.time_zone,
509 }
510 }
511
512 pub async fn guest_state_protection_data_by_id(
514 &self,
515 ) -> Result<crate::api::GuestStateProtectionById, crate::error::GuestStateProtectionByIdError>
516 {
517 let response = self
518 .control
519 .call(msg::Msg::GuestStateProtectionById, ())
520 .await
521 .0;
522
523 if response.seed.length > response.seed.buffer.len() as u32 {
524 return Err(crate::error::GuestStateProtectionByIdError(
525 response.seed.length,
526 response.seed.buffer.len() as u32,
527 ));
528 }
529
530 Ok(crate::api::GuestStateProtectionById {
531 seed: response.seed,
532 extended_status_flags: response.extended_status_flags,
533 })
534 }
535
536 pub async fn complete_start_vtl0(&self, error_msg: Option<String>) {
538 if self.version >= get_protocol::ProtocolVersion::NICKEL_REV2 {
539 self.control
540 .call(msg::Msg::CompleteStartVtl0, error_msg.clone())
541 .await;
542
543 if let Some(error_msg) = error_msg {
544 mesh::CancelContext::new()
551 .with_timeout(std::time::Duration::from_mins(2))
552 .until_cancelled(std::future::pending::<()>())
553 .await
554 .unwrap_or_else(|_| {
555 panic!(
556 "should have been terminated after reporting start failure: {error_msg}"
557 )
558 });
559 }
560 }
561 }
562
563 pub async fn map_framebuffer(&self, gpa: u64) -> Result<(), crate::error::MapFramebufferError> {
565 let response = self.control.call(msg::Msg::MapFramebuffer, gpa).await.0;
566 match response.status {
567 get_protocol::MapFramebufferStatus::SUCCESS => Ok(()),
568 _ => Err(crate::error::MapFramebufferError(response.status)),
569 }
570 }
571
572 pub async fn unmap_framebuffer(&self) -> Result<(), crate::error::UnmapFramebufferError> {
574 let response = self.control.call(msg::Msg::UnmapFramebuffer, ()).await.0;
575 match response.status {
576 get_protocol::UnmapFramebufferStatus::SUCCESS => Ok(()),
577 _ => Err(crate::error::UnmapFramebufferError(response.status)),
578 }
579 }
580
581 pub async fn offer_vpci_device(
583 &self,
584 bus_instance_id: Guid,
585 ) -> Result<(), crate::error::VpciControlError> {
586 let response = self
587 .control
588 .call(
589 msg::Msg::VpciDeviceControl,
590 msg::VpciDeviceControlInput {
591 code: get_protocol::VpciDeviceControlCode::OFFER.into(),
592 bus_instance_id,
593 },
594 )
595 .await
596 .0;
597 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
598 Err(crate::error::VpciControlError(response.status))
599 } else {
600 Ok(())
601 }
602 }
603
604 pub async fn revoke_vpci_device(
606 &self,
607 bus_instance_id: Guid,
608 ) -> Result<(), crate::error::VpciControlError> {
609 let response = self
610 .control
611 .call(
612 msg::Msg::VpciDeviceControl,
613 msg::VpciDeviceControlInput {
614 code: get_protocol::VpciDeviceControlCode::REVOKE.into(),
615 bus_instance_id,
616 },
617 )
618 .await
619 .0;
620 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
621 Err(crate::error::VpciControlError(response.status))
622 } else {
623 Ok(())
624 }
625 }
626
627 pub async fn report_vpci_device_binding_state(
629 &self,
630 bus_instance_id: Guid,
631 binding_state: bool,
632 ) -> Result<(), crate::error::VpciControlError> {
633 let response = self
634 .control
635 .call(
636 msg::Msg::VpciDeviceBindingChange,
637 msg::VpciDeviceBindingChangeInput {
638 bus_instance_id,
639 binding_state,
640 },
641 )
642 .await
643 .0;
644 if response.status != get_protocol::VpciDeviceControlStatus::SUCCESS {
645 Err(crate::error::VpciControlError(response.status))
646 } else {
647 Ok(())
648 }
649 }
650
651 pub async fn connect_to_vpci_event_source(
654 &self,
655 bus_instance_id: Guid,
656 ) -> mesh::Receiver<VpciBusEvent> {
657 let (sender, receiver) = mesh::channel();
658 self.control
659 .call(
660 msg::Msg::VpciListenerRegistration,
661 msg::VpciListenerRegistrationInput {
662 bus_instance_id,
663 sender,
664 },
665 )
666 .await;
667 receiver
668 }
669
670 pub fn disconnect_from_vpci_event_source(&self, bus_instance_id: Guid) {
672 self.control
673 .notify(msg::Msg::VpciListenerDeregistration(bus_instance_id));
674 }
675
676 pub async fn take_vtl2_settings_recv(
678 &self,
679 ) -> Option<mesh::Receiver<ModifyVtl2SettingsRequest>> {
680 self.control
681 .call(msg::Msg::TakeVtl2SettingsReceiver, ())
682 .await
683 .0
684 }
685
686 pub async fn take_generation_id_recv(&self) -> Option<mesh::Receiver<[u8; 16]>> {
688 self.control.call(msg::Msg::TakeGenIdReceiver, ()).await
689 }
690
691 pub async fn take_battery_status_recv(&self) -> Option<mesh::Receiver<HostBatteryUpdate>> {
693 self.control
694 .call(msg::Msg::TakeBatteryStatusReceiver, ())
695 .await
696 }
697
698 pub async fn vga_proxy_pci_read(&self, offset: u16) -> u32 {
700 let response = self.control.call(msg::Msg::VgaProxyPciRead, offset).await.0;
701 response.value
702 }
703
704 pub async fn vga_proxy_pci_write(&self, offset: u16, value: u32) {
706 self.control
707 .call(
708 msg::Msg::VgaProxyPciWrite,
709 msg::VgaProxyPciWriteInput { offset, value },
710 )
711 .await;
712 }
713
714 pub async fn create_ram_gpa_range(
716 &self,
717 slot: u32,
718 gpa_start: u64,
719 gpa_count: u64,
720 gpa_offset: u64,
721 flags: crate::api::CreateRamGpaRangeFlags,
722 ) -> Result<crate::api::RemoteRamGpaRangeHandle, crate::error::CreateRamGpaRangeError> {
723 let response = self
724 .control
725 .call(
726 msg::Msg::CreateRamGpaRange,
727 msg::CreateRamGpaRangeInput {
728 slot,
729 gpa_start,
730 gpa_count,
731 gpa_offset,
732 flags: flags.into(),
733 },
734 )
735 .await
736 .0;
737 if response.status != get_protocol::CreateRamGpaRangeStatus::SUCCESS {
738 Err(crate::error::CreateRamGpaRangeError(response.status))
739 } else {
740 Ok(crate::api::RemoteRamGpaRangeHandle::from_raw(slot))
741 }
742 }
743
744 pub async fn reset_ram_gpa_range(&self, handle: crate::api::RemoteRamGpaRangeHandle) {
747 self.control
748 .call(msg::Msg::ResetRamGpaRange, handle.as_raw())
749 .await;
750 }
751
752 pub async fn load_firmware(
763 &self,
764 firmware_token: u64,
765 ) -> Result<u64, crate::error::LoadFirmwareError> {
766 let response = self
767 .control
768 .call(msg::Msg::LoadFirmware, firmware_token)
769 .await
770 .0;
771 if response.status != get_protocol::LoadFirmwareStatus::SUCCESS {
772 Err(crate::error::LoadFirmwareError(response.status))
773 } else {
774 Ok(response.entry_point_image_offset)
775 }
776 }
777
778 pub async fn get_saved_state_from_host(
781 &self,
782 ) -> Result<Vec<u8>, crate::error::SaveRestoreOperationFailure> {
783 self.control
784 .call(msg::Msg::GetVtl2SavedStateFromHost, ())
785 .await
786 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
787 }
788
789 pub async fn report_restore_result_to_host(&self, success: bool) {
794 self.control
795 .notify(msg::Msg::ReportRestoreResultToHost(success));
796 }
797
798 pub async fn take_save_request_recv(&self) -> Option<mesh::Receiver<GuestSaveRequest>> {
802 self.control
803 .call(msg::Msg::TakeSaveRequestReceiver, ())
804 .await
805 }
806
807 pub async fn send_servicing_state(
812 &self,
813 data: Vec<u8>,
814 ) -> Result<(), crate::error::SaveRestoreOperationFailure> {
815 self.control
816 .call(msg::Msg::SendServicingState, Ok(data))
817 .await
818 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
819 }
820
821 pub async fn send_servicing_failure(
826 &self,
827 err: impl ToString,
828 ) -> Result<(), crate::error::SaveRestoreOperationFailure> {
829 self.control
830 .call(msg::Msg::SendServicingState, Err(err.to_string()))
831 .await
832 .map_err(|()| crate::error::SaveRestoreOperationFailure {})
833 }
834
835 pub fn notify_of_vtl_crash(
837 &self,
838 vp_index: u32,
839 last_vtl: u8,
840 control: u64,
841 parameters: [u64; get_protocol::VTL_CRASH_PARAMETERS],
842 ) {
843 self.control.notify(msg::Msg::VtlCrashNotification(
844 get_protocol::VtlCrashNotification::new(vp_index, last_vtl, control, parameters).into(),
845 ));
846 }
847
848 pub fn triple_fault(
850 &self,
851 vp_index: u32,
852 fault_type: TripleFaultType,
853 reg_state: Vec<RegisterState>,
854 ) {
855 let mut payload = vec![];
856
857 let notification = get_protocol::TripleFaultNotification::new(
858 vp_index,
859 fault_type,
860 reg_state.len() as u32,
861 );
862 payload.extend_from_slice(notification.as_bytes());
863 payload.extend_from_slice(reg_state.as_bytes());
864
865 self.control
866 .notify(msg::Msg::TripleFaultNotification(payload));
867 }
868}