get_protocol/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Protocol used to interact between the Guest and Host via the
5//! GET (Guest Emulation Transport)
6
7#![expect(missing_docs)]
8#![forbid(unsafe_code)]
9
10use bitfield_struct::bitfield;
11use guid::Guid;
12use open_enum::open_enum;
13use static_assertions::const_assert;
14use static_assertions::const_assert_eq;
15use std::fmt::Debug;
16use zerocopy::FromBytes;
17use zerocopy::Immutable;
18use zerocopy::IntoBytes;
19use zerocopy::KnownLayout;
20
21pub mod crash;
22pub mod dps_json; // TODO: split into separate crate, so get_protocol can be no_std
23
24/// The vmbus max response size is INCOMING_PACKET_BUFFER_PAGES (currently 12K)
25pub const MAX_MESSAGE_SIZE: usize = 12288;
26
27pub const MAX_HEADER_SIZE: usize = 256;
28
29// Maximum payload size for fragmenting VMGS read/writes and saved state.
30// (required due to underlying vmbus pipe message size constraints)
31pub const MAX_PAYLOAD_SIZE: usize = 8192;
32
33const_assert!(MAX_MESSAGE_SIZE >= MAX_HEADER_SIZE + MAX_PAYLOAD_SIZE);
34
35/// {455C0F1B-D51B-40B1-BEAC-87377FE6E041}
36pub const GUEST_EMULATION_DEVICE_ID: Guid = guid::guid!("455c0f1b-d51b-40b1-beac-87377fe6e041");
37
38/// {8DEDD1AA-9056-49E4-BFD6-1BF90DC38EF0}
39pub const GUEST_EMULATION_INTERFACE_TYPE: Guid =
40    guid::guid!("8dedd1aa-9056-49e4-bfd6-1bf90dc38ef0");
41
42/// {D3E4454D-62AF-44EC-B851-3170915E5F56}
43pub const GUEST_EMULATION_INTERFACE_INSTANCE: Guid =
44    guid::guid!("d3e4454d-62af-44ec-b851-3170915e5f56");
45
46/// Make protocol version
47const fn make_version(major: u16, minor: u16) -> u32 {
48    (minor as u32) | ((major as u32) << 16)
49}
50
51open_enum! {
52    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
53    pub enum ProtocolVersion: u32 {
54        INVALID = 0,
55        RS5 = make_version(1, 0),
56        IRON = make_version(3, 0),
57        NICKEL_REV2 = make_version(4, 2),
58    }
59}
60
61open_enum! {
62    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
63    pub enum MessageVersions: u8 {
64        INVALID          = 0,
65        HEADER_VERSION_1 = 1,
66    }
67}
68
69open_enum! {
70    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
71    pub enum MessageTypes: u8 {
72        INVALID            = 0,
73        HOST_NOTIFICATION  = 1,
74        HOST_REQUEST       = 2,
75        HOST_RESPONSE      = 3,
76        GUEST_NOTIFICATION = 4,
77    }
78}
79
80open_enum! {
81    /// Guest notification messages.
82    ///
83    /// These are intended to be "fire-and-forget" messages sent from the Host
84    /// to the Guest, without requiring a response.
85    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
86    pub enum GuestNotifications: u16 {
87        INVALID              = 0,
88        UPDATE_GENERATION_ID = 1,
89        // --- NI ---
90        SAVE_GUEST_VTL2_STATE = 2,
91        _RESERVED_DO_NOT_USE_3 = 3,
92        VPCI_DEVICE_NOTIFICATION = 4,
93        MODIFY_VTL2_SETTINGS = 5,
94        MODIFY_VTL2_SETTINGS_REV1 = 6,
95        // --- GE ---
96        BATTERY_STATUS = 7,
97        INJECT_DEBUG_INTERRUPT = 8,
98        NOTIFY_POST_LIVE_MIGRATION = 9,
99    }
100}
101
102open_enum! {
103    /// Host notification messages.
104    ///
105    /// These are intended to be "fire-and-forget" messages sent from the Guest
106    /// to the Host, without requiring a response.
107    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
108    pub enum HostNotifications: u16 {
109        INVALID   = 0,
110        POWER_OFF = 1,
111        RESET     = 2,
112        EVENT_LOG = 3,
113        LOG_TRACE = 4,
114        // --- NI ---
115        RESTORE_GUEST_VTL2_STATE_COMPLETED = 5,
116        MODIFY_VTL2_SETTINGS_COMPLETED     = 6,
117        START_VTL0_COMPLETED               = 7,
118        VTL_CRASH                          = 8,
119        TRIPLE_FAULT                       = 9,
120    }
121}
122
123open_enum! {
124    /// Header ids (Each request has a response of the same ID).
125    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
126    pub enum HostRequests: u16 {
127        INVALID                      = 0,
128        VERSION                      = 1,
129        TIME                         = 2,
130        BIOS_BOOT_FINALIZE           = 3,
131        VMGS_GET_DEVICE_INFO         = 4,
132        VMGS_READ                    = 5,
133        VMGS_WRITE                   = 6,
134        VMGS_FLUSH                   = 7,
135        IGVM_ATTEST                  = 8,
136        // --- RS ---
137        GUEST_STATE_PROTECTION_BY_ID = 9,
138        VMGS_KEYS_READ               = 10,
139        LOG_TRACE                    = 11, // deprecated
140        ACTIVITY_TRACE_START         = 12,
141        ACTIVITY_TRACE_OP            = 13,
142        EVENT_TRACE                  = 14,
143        // --- MN ---
144        DEVICE_PLATFORM_SETTINGS     = 15, // deprecated in favor of DEVICE_PLATFORM_SETTINGS_V2
145        // --- FE ---
146        ADVISORY_PLATFORM_SETTINGS   = 16, // deprecated in favor of DEVICE_PLATFORM_SETTINGS_V2
147        GUEST_STATE_PROTECTION       = 17,
148        // --- NI ---
149        DEVICE_PLATFORM_SETTINGS_V2      = 18, // wart: sent in request, but responses comes back as DEVICE_PLATFORM_SETTINGS_V2_REV1
150        VPCI_DEVICE_CONTROL              = 19,
151        SAVE_GUEST_VTL2_STATE            = 20,
152        RESTORE_GUEST_VTL2_STATE         = 21,
153        VPCI_DEVICE_BINDING_CHANGE       = 22,
154        VGA_PROXY_PCI_READ               = 23,
155        VGA_PROXY_PCI_WRITE              = 24,
156        _RESERVED_DO_NOT_USE_25          = 25,
157        _RESERVED_DO_NOT_USE_26          = 26,
158        DEVICE_PLATFORM_SETTINGS_V2_REV1 = 27, // wart: only sent back in *response* to DEVICE_PLATFORM_SETTINGS
159        CREATE_RAM_GPA_RANGE             = 28,
160        RESET_RAM_GPA_RANGE              = 29,
161
162        // --- Experimental (not yet in Hyper-V) ---
163        MAP_FRAMEBUFFER              = 0xFFFF,
164        UNMAP_FRAMEBUFFER            = 0xFFFE,
165    }
166}
167
168pub use header::*;
169pub mod header {
170    use super::MessageTypes;
171    use super::MessageVersions;
172    use static_assertions::const_assert_eq;
173    use zerocopy::FromBytes;
174    use zerocopy::Immutable;
175    use zerocopy::IntoBytes;
176    use zerocopy::KnownLayout;
177
178    use super::GuestNotifications;
179    use super::HostNotifications;
180    use super::HostRequests;
181
182    /// The raw header pulled off the wire.
183    #[repr(C)]
184    #[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
185    pub struct HeaderRaw {
186        pub message_version: MessageVersions,
187        pub message_type: MessageTypes,
188        pub message_id: u16,
189    }
190
191    // this trait cannot be implemented outside `mod get_protocol::header`, as
192    // there are several safety guarantees that must be upheld when specifying
193    // the `MessageId` associated type.
194    pub trait HeaderMeta: private::Sealed {
195        const MESSAGE_TYPE: MessageTypes;
196        type MessageId: Copy + IntoBytes + FromBytes + Immutable + KnownLayout + Sized;
197    }
198
199    macro_rules! defn_header_meta {
200        (
201            $(($header_alias:ident => $name:ident, $message_type:ident, $message_id:ident)$(,)*)*
202        ) => {
203            mod private {
204                pub trait Sealed {}
205                $(
206                    impl Sealed for super::$name {}
207                )*
208            }
209
210            $(
211                #[derive(Copy, Clone, Debug)]
212                pub enum $name {}
213
214                impl HeaderMeta for $name {
215                    const MESSAGE_TYPE: MessageTypes = MessageTypes::$message_type;
216                    type MessageId = $message_id;
217                }
218
219                // ensure that all message_ids are u16 sized
220                const_assert_eq!(size_of::<u16>(), size_of::<$message_id>());
221                // ensure that the resulting header is sized correctly
222                const_assert_eq!(4, size_of::<HeaderGeneric<$name>>());
223
224                impl TryFrom<HeaderRaw> for HeaderGeneric<$name> {
225                    type Error = ();
226
227                    fn try_from(raw: HeaderRaw) -> Result<HeaderGeneric<$name>, ()> {
228                        if raw.message_type != MessageTypes::$message_type {
229                            return Err(());
230                        }
231
232                        Ok(HeaderGeneric {
233                            message_version: raw.message_version,
234                            message_type: raw.message_type,
235                            message_id: $message_id(raw.message_id),
236                        })
237                    }
238                }
239
240                pub type $header_alias = HeaderGeneric<$name>;
241            )*
242
243        };
244    }
245
246    defn_header_meta! {
247        (HeaderGuestNotification => GuestNotification, GUEST_NOTIFICATION, GuestNotifications),
248        (HeaderHostNotification => HostNotification, HOST_NOTIFICATION, HostNotifications),
249        (HeaderHostResponse => HostResponse, HOST_RESPONSE, HostRequests),
250        (HeaderHostRequest => HostRequest, HOST_REQUEST, HostRequests),
251    }
252
253    // TODO: repr(packed) is only needed here to make zerocopy's IntoBytes
254    // derive happy. Ideally it wouldn't be needed. We know this type has no
255    // padding bytes because of the asserts inside `defn_header_meta!`, and
256    // HeaderMeta is sealed, but zerocopy can't see all of that yet.
257    #[repr(C, packed)]
258    #[derive(Copy, Clone, Debug, FromBytes, Immutable, KnownLayout, PartialEq, IntoBytes)]
259    pub struct HeaderGeneric<Meta: HeaderMeta> {
260        pub message_version: MessageVersions,
261        pub message_type: MessageTypes,
262        message_id: Meta::MessageId,
263    }
264
265    impl<Meta: HeaderMeta> HeaderGeneric<Meta> {
266        pub fn new(message_id: Meta::MessageId) -> Self {
267            Self {
268                message_version: MessageVersions::HEADER_VERSION_1,
269                message_type: Meta::MESSAGE_TYPE,
270                message_id,
271            }
272        }
273
274        // This method is only needed to force a copy of the message_id field to
275        // avoid references to potentially unaligned packed fields. message_id
276        // will never actually be unaligned in practice, but the compiler can't
277        // prove that. This can go away and message_id can be made `pub` when
278        // repr(packed) goes away.
279        pub fn message_id(&self) -> Meta::MessageId {
280            self.message_id
281        }
282    }
283}
284
285open_enum! {
286    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
287    pub enum LargePayloadState : u32 {
288        END = 0,
289        MORE = 1,
290    }
291}
292
293#[repr(C)]
294#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
295pub struct PowerOffNotification {
296    pub message_header: HeaderHostNotification,
297    pub hibernate: ProtocolBool,
298    pub _pad: u8,
299}
300
301const_assert_eq!(6, size_of::<PowerOffNotification>());
302
303impl PowerOffNotification {
304    pub fn new(hibernate: bool) -> Self {
305        Self {
306            message_header: HeaderGeneric::new(HostNotifications::POWER_OFF),
307
308            hibernate: hibernate.into(),
309            _pad: 0,
310        }
311    }
312}
313
314#[repr(C)]
315#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
316pub struct ResetNotification {
317    pub message_header: HeaderHostNotification,
318}
319
320const_assert_eq!(4, size_of::<ResetNotification>());
321
322impl ResetNotification {
323    pub fn new() -> Self {
324        Self {
325            message_header: HeaderGeneric::new(HostNotifications::RESET),
326        }
327    }
328}
329
330open_enum! {
331    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
332    pub enum EventLogId: u32 {
333        INVALID_ID = 0,
334        BOOT_SUCCESS = 1,
335        BOOT_SUCCESS_SECURE_BOOT_FAILED = 2,
336        BOOT_FAILURE = 3,
337        BOOT_FAILURE_SECURE_BOOT_FAILED = 4,
338        NO_BOOT_DEVICE = 5,
339        ATTESTATION_FAILED = 6,
340        VMGS_FILE_CLEAR = 7,
341        VMGS_INIT_FAILED = 8,
342        VMGS_INVALID_FORMAT = 9,
343        VMGS_CORRUPT_FORMAT = 10,
344        KEY_NOT_RELEASED = 11,
345        DEK_DECRYPTION_FAILED = 12,
346        WATCHDOG_TIMEOUT_RESET = 13,
347        BOOT_ATTEMPT = 14,
348        VMGS_ACCESS_FAILED = 15,
349        CERTIFICATE_RENEWAL_FAILED = 16,
350        TPM_INVALID_STATE = 17,
351        TPM_IDENTITY_CHANGE_FAILED = 18,
352        WRAPPED_KEY_REQUIRED_BUT_INVALID = 19,
353    }
354}
355
356#[repr(C)]
357#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
358pub struct EventLogNotification {
359    pub message_header: HeaderHostNotification,
360    pub event_log_id: EventLogId,
361}
362
363const_assert_eq!(8, size_of::<EventLogNotification>());
364
365impl EventLogNotification {
366    pub fn new(event_log_id: EventLogId) -> Self {
367        Self {
368            message_header: HeaderGeneric::new(HostNotifications::EVENT_LOG),
369            event_log_id,
370        }
371    }
372}
373
374pub const TRACE_MSG_MAX_SIZE: usize = 256;
375open_enum! {
376    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
377    pub enum LogLevel: u32 {
378        INVALID = 0,
379        CRITICAL = 1,
380        ERROR = 2,
381        WARNING = 3,
382        INFORMATION = 4,
383        VERBOSE = 5,
384    }
385}
386
387impl From<LogLevel> for u8 {
388    fn from(level: LogLevel) -> Self {
389        match level {
390            LogLevel::INVALID => 0,
391            LogLevel::CRITICAL => 1,
392            LogLevel::ERROR => 2,
393            LogLevel::WARNING => 3,
394            LogLevel::INFORMATION => 4,
395            LogLevel::VERBOSE => 5,
396            _ => {
397                unreachable!();
398            }
399        }
400    }
401}
402
403open_enum! {
404    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
405    pub enum GuestVtl2SaveRestoreStatus : u16 {
406        SUCCESS = 0,
407        FAILURE = 1,
408        MORE_DATA = 2,
409        REQUEST_DATA = 3,
410    }
411}
412
413#[repr(C)]
414#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
415pub struct LogTraceNotification {
416    pub message_header: HeaderHostNotification,
417    pub level: LogLevel,
418    pub message: [u16; TRACE_MSG_MAX_SIZE],
419}
420
421const_assert_eq!(520, size_of::<LogTraceNotification>());
422
423pub const VTL_CRASH_PARAMETERS: usize = 5;
424
425/// The transport level VTL crash data to send to the host.
426#[repr(C)]
427#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
428pub struct VtlCrashNotification {
429    pub message_header: HeaderHostNotification,
430    pub vp_index: u32,
431    pub last_vtl: u8,
432    pub reserved0: u8,
433    pub reserved1: u16,
434    pub reserved2: u32,
435    pub control: u64,
436    pub parameters: [u64; VTL_CRASH_PARAMETERS],
437}
438
439const_assert_eq!(64, size_of::<VtlCrashNotification>());
440
441impl VtlCrashNotification {
442    pub fn new(
443        vp_index: u32,
444        last_vtl: u8,
445        control: u64,
446        parameters: [u64; VTL_CRASH_PARAMETERS],
447    ) -> Self {
448        Self {
449            message_header: HeaderGeneric::new(HostNotifications::VTL_CRASH),
450            vp_index,
451            last_vtl,
452            reserved0: 0,
453            reserved1: 0,
454            reserved2: 0,
455            control,
456            parameters,
457        }
458    }
459}
460
461open_enum! {
462    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
463    pub enum TripleFaultType: u32 {
464        UNRECOVERABLE_EXCEPTION = 1,
465    }
466}
467
468#[repr(C)]
469#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
470pub struct RegisterState {
471    pub name: u32,
472    pub value: [u8; 16],
473}
474const_assert_eq!(20, size_of::<RegisterState>());
475
476/// Triple fault notification to send to the host.
477#[repr(C)]
478#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
479pub struct TripleFaultNotification {
480    pub message_header: HeaderHostNotification,
481    pub vp_index: u32,
482    pub fault_type: TripleFaultType,
483    pub register_count: u32,
484}
485const_assert_eq!(16, size_of::<TripleFaultNotification>());
486
487impl TripleFaultNotification {
488    pub fn new(vp_index: u32, fault_type: TripleFaultType, register_count: u32) -> Self {
489        Self {
490            message_header: HeaderGeneric::new(HostNotifications::TRIPLE_FAULT),
491            vp_index,
492            fault_type,
493            register_count,
494        }
495    }
496}
497
498#[repr(C)]
499#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
500pub struct VersionRequest {
501    pub message_header: HeaderHostRequest,
502    pub version: ProtocolVersion,
503}
504
505impl VersionRequest {
506    /// Creates new `VersionRequest` message
507    pub fn new(version: ProtocolVersion) -> Self {
508        Self {
509            message_header: HeaderGeneric::new(HostRequests::VERSION),
510            version,
511        }
512    }
513}
514
515const_assert_eq!(8, size_of::<VersionRequest>());
516
517#[repr(C)]
518#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
519pub struct VersionResponse {
520    pub message_header: HeaderHostResponse,
521    pub version_accepted: ProtocolBool,
522    pub _pad: u8,
523}
524
525impl VersionResponse {
526    pub fn new(version_accepted: bool) -> Self {
527        Self {
528            message_header: HeaderGeneric::new(HostRequests::VERSION),
529            version_accepted: version_accepted.into(),
530            _pad: 0,
531        }
532    }
533}
534
535const_assert_eq!(6, size_of::<VersionResponse>());
536
537#[repr(C)]
538#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
539pub struct TimeRequest {
540    pub message_header: HeaderHostRequest,
541}
542
543const_assert_eq!(4, size_of::<TimeRequest>());
544
545impl TimeRequest {
546    pub fn new() -> Self {
547        Self {
548            message_header: HeaderGeneric::new(HostRequests::TIME),
549        }
550    }
551}
552
553#[repr(C)]
554#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
555pub struct TimeResponse {
556    pub message_header: HeaderHostResponse,
557    pub _pad: u32,
558
559    pub vm_reference_time: u64,
560    pub utc: i64,
561    pub time_zone: i16,
562    pub daylight_savings: ProtocolBool,
563    pub _pad1: [u8; 5],
564}
565
566impl TimeResponse {
567    pub fn new(vm_reference_time: u64, utc: i64, time_zone: i16, daylight_savings: bool) -> Self {
568        Self {
569            message_header: HeaderGeneric::new(HostRequests::TIME),
570            _pad: 0,
571
572            vm_reference_time,
573            utc,
574            time_zone,
575            daylight_savings: daylight_savings.into(),
576            _pad1: [0; 5],
577        }
578    }
579}
580
581const_assert_eq!(32, size_of::<TimeResponse>());
582
583/// Maximum agent data size
584pub const IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE: usize = 2048;
585/// Maximum attestation report size
586pub const IGVM_ATTEST_MSG_REQ_REPORT_MAX_SIZE: usize = 4096;
587
588/// Maximum return pages
589pub const IGVM_ATTEST_MSG_MAX_SHARED_GPA: usize = 16;
590
591// Error from the VM worker process in the host when sending an
592// attestation request.
593pub const IGVM_ATTEST_VMWP_GENERIC_ERROR_CODE: usize = 0xFFFFFFFF;
594
595/// The response payload could be quite large, so pass host
596/// previously shared pages to use for response.
597/// Use GET response packet to serialize and convey response length.
598#[repr(C)]
599#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
600pub struct IgvmAttestRequest {
601    pub message_header: HeaderHostRequest,
602    /// Number of GPA
603    pub number_gpa: u32,
604    /// GPA addresses
605    pub shared_gpa: [u64; IGVM_ATTEST_MSG_MAX_SHARED_GPA],
606    /// Agent data length
607    pub agent_data_length: u32,
608    /// Report length
609    pub report_length: u32,
610    /// Agent data
611    pub agent_data: [u8; IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE],
612    /// Report
613    pub report: [u8; IGVM_ATTEST_MSG_REQ_REPORT_MAX_SIZE],
614}
615
616const_assert_eq!(6288, size_of::<IgvmAttestRequest>());
617
618impl IgvmAttestRequest {
619    pub fn new(
620        shared_gpa: [u64; IGVM_ATTEST_MSG_MAX_SHARED_GPA],
621        number_gpa: u32,
622        agent_data: [u8; IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE],
623        agent_data_length: u32,
624        report: [u8; IGVM_ATTEST_MSG_REQ_REPORT_MAX_SIZE],
625        report_length: u32,
626    ) -> Self {
627        Self {
628            message_header: HeaderGeneric::new(HostRequests::IGVM_ATTEST),
629            number_gpa,
630            shared_gpa,
631            agent_data_length,
632            report_length,
633            agent_data,
634            report,
635        }
636    }
637}
638
639#[repr(C)]
640#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
641pub struct IgvmAttestResponse {
642    pub message_header: HeaderHostResponse,
643    pub length: u32,
644}
645
646const_assert_eq!(8, size_of::<IgvmAttestResponse>());
647
648/// This can only be used in PROTOCOL_VERSION_RS5
649#[repr(C)]
650#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
651pub struct BiosBootFinalizeRequest {
652    pub message_header: HeaderHostRequest,
653    pub value: u8,
654    pub _pad: u8,
655}
656
657const_assert_eq!(6, size_of::<BiosBootFinalizeRequest>());
658
659#[repr(C)]
660#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
661pub struct BiosBootFinalizeResponse {
662    pub message_header: HeaderHostResponse,
663}
664
665impl BiosBootFinalizeResponse {
666    pub fn new() -> BiosBootFinalizeResponse {
667        BiosBootFinalizeResponse {
668            message_header: HeaderGeneric::new(HostRequests::BIOS_BOOT_FINALIZE),
669        }
670    }
671}
672
673const_assert_eq!(4, size_of::<BiosBootFinalizeResponse>());
674
675#[repr(C)]
676#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
677pub struct VmgsGetDeviceInfoRequest {
678    pub message_header: HeaderHostRequest,
679}
680
681impl VmgsGetDeviceInfoRequest {
682    pub fn new() -> Self {
683        Self {
684            message_header: HeaderGeneric::new(HostRequests::VMGS_GET_DEVICE_INFO),
685        }
686    }
687}
688
689const_assert_eq!(4, size_of::<VmgsGetDeviceInfoRequest>());
690
691open_enum! {
692    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
693    pub enum VmgsIoStatus: u32 {
694        SUCCESS         = 0,
695        INVALID_COMMAND = 1,
696        DEVICE_ERROR    = 2,
697        RETRY           = 3,
698    }
699}
700
701open_enum! {
702    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
703    pub enum VmgsWriteFlags: u32 {
704        NONE          = 0,
705        WRITE_THROUGH = 0x00000001,
706    }
707}
708
709open_enum! {
710    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
711    pub enum VmgsReadFlags: u32 {
712        NONE = 0,
713    }
714}
715
716#[repr(C)]
717#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
718pub struct VmgsGetDeviceInfoResponse {
719    pub message_header: HeaderHostResponse,
720    pub status: VmgsIoStatus,
721    pub capacity: u64, // logical sectors
722    pub bytes_per_logical_sector: u16,
723    pub bytes_per_physical_sector: u16,
724    pub maximum_transfer_size_bytes: u32,
725}
726
727impl VmgsGetDeviceInfoResponse {
728    pub fn new(
729        status: VmgsIoStatus,
730        capacity: u64,
731        bytes_per_logical_sector: u16,
732        bytes_per_physical_sector: u16,
733        maximum_transfer_size_bytes: u32,
734    ) -> VmgsGetDeviceInfoResponse {
735        VmgsGetDeviceInfoResponse {
736            message_header: HeaderGeneric::new(HostRequests::VMGS_GET_DEVICE_INFO),
737
738            status,
739            capacity,
740            bytes_per_logical_sector,
741            bytes_per_physical_sector,
742            maximum_transfer_size_bytes,
743        }
744    }
745}
746
747const_assert_eq!(24, size_of::<VmgsGetDeviceInfoResponse>());
748
749#[repr(C)]
750#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
751pub struct VmgsWriteRequest {
752    pub message_header: HeaderHostRequest,
753    pub flags: VmgsWriteFlags,
754    pub sector_offset: u64, // logical sectors
755    pub sector_count: u32,  // logical sectors
756    pub _pad: u32,
757    // Variable size payload follows
758}
759
760const_assert_eq!(24, size_of::<VmgsWriteRequest>());
761
762impl VmgsWriteRequest {
763    pub fn new(flags: VmgsWriteFlags, sector_offset: u64, sector_count: u32) -> Self {
764        Self {
765            message_header: HeaderGeneric::new(HostRequests::VMGS_WRITE),
766            flags,
767            sector_offset,
768            sector_count,
769            _pad: 0,
770        }
771    }
772}
773
774#[repr(C)]
775#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
776pub struct VmgsWriteResponse {
777    pub message_header: HeaderHostResponse,
778    pub status: VmgsIoStatus,
779}
780
781impl VmgsWriteResponse {
782    pub fn new(status: VmgsIoStatus) -> VmgsWriteResponse {
783        VmgsWriteResponse {
784            message_header: HeaderGeneric::new(HostRequests::VMGS_WRITE),
785            status,
786        }
787    }
788}
789
790const_assert_eq!(8, size_of::<VmgsWriteResponse>());
791
792#[repr(C)]
793#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
794pub struct VmgsReadRequest {
795    pub message_header: HeaderHostRequest,
796    pub flags: VmgsReadFlags,
797    pub sector_offset: u64, // logical sectors
798    pub sector_count: u32,  // logical sectors
799    pub _pad: u32,
800}
801
802const_assert_eq!(24, size_of::<VmgsReadRequest>());
803
804impl VmgsReadRequest {
805    pub fn new(flags: VmgsReadFlags, sector_offset: u64, sector_count: u32) -> Self {
806        Self {
807            message_header: HeaderGeneric::new(HostRequests::VMGS_READ),
808            flags,
809            sector_offset,
810            sector_count,
811            _pad: 0,
812        }
813    }
814}
815
816#[repr(C)]
817#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
818pub struct VmgsReadResponse {
819    pub message_header: HeaderHostResponse,
820    pub status: VmgsIoStatus,
821    // Variable size payload follows
822}
823
824impl VmgsReadResponse {
825    pub fn new(status: VmgsIoStatus) -> VmgsReadResponse {
826        VmgsReadResponse {
827            message_header: HeaderGeneric::new(HostRequests::VMGS_READ),
828            status,
829        }
830    }
831}
832
833const_assert_eq!(8, size_of::<VmgsReadResponse>());
834
835#[repr(C)]
836#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
837pub struct VmgsFlushRequest {
838    pub message_header: HeaderHostRequest,
839}
840
841impl VmgsFlushRequest {
842    pub fn new() -> Self {
843        Self {
844            message_header: HeaderGeneric::new(HostRequests::VMGS_FLUSH),
845        }
846    }
847}
848
849const_assert_eq!(4, size_of::<VmgsFlushRequest>());
850
851#[repr(C)]
852#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
853pub struct VmgsFlushResponse {
854    pub message_header: HeaderHostResponse,
855    pub status: VmgsIoStatus,
856}
857
858impl VmgsFlushResponse {
859    pub fn new(status: VmgsIoStatus) -> VmgsFlushResponse {
860        VmgsFlushResponse {
861            message_header: HeaderGeneric::new(HostRequests::VMGS_FLUSH),
862            status,
863        }
864    }
865}
866
867const_assert_eq!(8, size_of::<VmgsFlushResponse>());
868
869const VMGS_MAX_IO_MSG_HEADER_SIZE: usize = size_of::<VmgsReadRequest>();
870const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE >= size_of::<VmgsReadResponse>());
871const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE >= size_of::<VmgsWriteRequest>());
872const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE >= size_of::<VmgsWriteResponse>());
873const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE <= MAX_HEADER_SIZE);
874
875pub const MAX_TRANSFER_SIZE: usize = u32::MAX as usize - VMGS_MAX_IO_MSG_HEADER_SIZE;
876
877open_enum! {
878    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
879    pub enum ActivityClassId: u32 {
880        INVALID = 0,
881        VMGS_INITIALIZE_DEVICE = 1,
882        VMGS_INITIALIZE_STORE = 2,
883        VMGS_OPEN_STORE = 3,
884        VMGS_FORMAT = 4,
885        VMGS_SEND_RECEIVE = 5,
886        VMGS_DEVICE_READ = 6,
887        VMGS_DEVICE_WRITE = 7,
888        VMGS_DEVICE_FLUSH = 8,
889    }
890}
891
892open_enum! {
893    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
894    pub enum ActivityOpCode: u32 {
895        INFO = 0,
896        START = 1,
897        STOP = 2,
898    }
899}
900
901open_enum! {
902    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
903    pub enum EventId: u32 {
904        INVALID = 0,
905        VMGS_INFO = 1,
906        VMGS_WARNING = 2,
907        VMGS_ERROR = 3,
908        VMGS_CRITICAL = 4,
909    }
910}
911
912#[repr(C)]
913#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
914pub struct LogTraceRequest {
915    pub message_header: HeaderHostRequest,
916    pub level: LogLevel,
917    pub message: [u16; TRACE_MSG_MAX_SIZE],
918}
919
920const_assert_eq!(520, size_of::<LogTraceRequest>());
921
922#[repr(C)]
923#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
924pub struct LogTraceResponse {
925    pub message_header: HeaderHostResponse,
926}
927
928const_assert_eq!(4, size_of::<LogTraceResponse>());
929
930#[repr(C)]
931#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
932pub struct ActivityTraceStartRequest {
933    pub message_header: HeaderHostRequest,
934    pub activity_class: ActivityClassId,
935    pub related_activity_id: Guid,
936    pub size: u32, // Size of payload
937                   // Variable size payload follows, maximum TRACE_MSG_MAX_SIZE WCHAR
938}
939
940const_assert_eq!(28, size_of::<ActivityTraceStartRequest>());
941
942#[repr(C)]
943#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
944pub struct ActivityTraceStartResponse {
945    pub message_header: HeaderHostResponse,
946    pub activity_id: Guid,
947}
948
949const_assert_eq!(20, size_of::<ActivityTraceStartResponse>());
950
951#[repr(C)]
952#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
953pub struct ActivityTraceOpRequest {
954    pub message_header: HeaderHostRequest,
955    pub activity_class: ActivityClassId,
956    pub activity_id: Guid,
957    pub related_activity_id: Guid,
958    pub op_code: ActivityOpCode,
959    pub size: u32, // Size of payload
960                   // Variable size payload follows, maximum TRACE_MSG_MAX_SIZE_WCHAR
961}
962
963const_assert_eq!(48, size_of::<ActivityTraceOpRequest>());
964
965#[repr(C)]
966#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
967pub struct ActivityTraceOpResponse {
968    pub message_header: HeaderHostResponse,
969}
970
971const_assert_eq!(4, size_of::<ActivityTraceOpResponse>());
972
973#[repr(C)]
974#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
975pub struct EventTraceRequest {
976    pub message_header: HeaderHostRequest,
977    pub event: EventId,
978    pub size: u32, // Size of payload
979                   // Variable size payload follows, maximum TRACE_MSG_MAX_SIZE WCHAR
980}
981
982const_assert_eq!(12, size_of::<EventTraceRequest>());
983
984#[repr(C)]
985#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
986pub struct EventTraceResponse {
987    pub message_header: HeaderHostResponse,
988}
989
990const_assert_eq!(4, size_of::<EventTraceResponse>());
991
992open_enum! {
993    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
994    pub enum SecureBootTemplateType: u32 {
995        SECURE_BOOT_DISABLED = 0,
996        MICROSOFT_WINDOWS = 1,
997        MICROSOFT_UEFI_CERTIFICATE_AUTHORITY = 2,
998        OPEN_SOURCE_SHIELDED_VM = 3,
999    }
1000}
1001
1002open_enum! {
1003    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1004    pub enum UefiConsoleMode: u8 {
1005        DEFAULT = 0,
1006        COM1 = 1,
1007        COM2 = 2,
1008        NONE = 3,
1009    }
1010}
1011
1012pub const HCL_DEVICE_PLATFORM_MAX_SMBIOS_LENGTH: usize = 64;
1013
1014#[repr(C)]
1015#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1016pub struct DevicePlatformSettingsRequestV2 {
1017    pub message_header: HeaderHostRequest,
1018}
1019
1020impl DevicePlatformSettingsRequestV2 {
1021    pub fn new() -> Self {
1022        Self {
1023            message_header: HeaderGeneric::new(HostRequests::DEVICE_PLATFORM_SETTINGS_V2),
1024        }
1025    }
1026}
1027
1028const_assert_eq!(4, size_of::<DevicePlatformSettingsRequestV2>());
1029
1030/// This represents a boolean value sent over the protocol as a u8. The only
1031/// valid values are 0 or 1.
1032#[repr(transparent)]
1033#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1034pub struct ProtocolBool(pub u8);
1035
1036impl From<bool> for ProtocolBool {
1037    fn from(value: bool) -> Self {
1038        ProtocolBool(if value { 1 } else { 0 })
1039    }
1040}
1041
1042#[repr(C)]
1043#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1044pub struct DevicePlatformSettingsResponseV2 {
1045    pub message_header: HeaderHostResponse,
1046
1047    pub size: u32,
1048    // variable length JSON payload
1049}
1050
1051#[repr(C)]
1052#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1053pub struct DevicePlatformSettingsResponseV2Rev1 {
1054    pub message_header: HeaderHostResponse,
1055
1056    pub size: u32,
1057
1058    pub payload_state: LargePayloadState,
1059    // variable length JSON payload
1060}
1061
1062pub const GSP_CLEARTEXT_MAX: u32 = 32;
1063pub const GSP_CIPHERTEXT_MAX: u32 = 512;
1064pub const NUMBER_GSP: u32 = 2;
1065
1066#[bitfield(u32)]
1067#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
1068pub struct GspExtendedStatusFlags {
1069    pub state_refresh_request: bool,
1070    pub no_registry_file: bool,
1071    pub no_rpc_server: bool,
1072    pub allow_ak_cert_renewal: bool,
1073    pub requires_rpc_server: bool,
1074
1075    #[bits(27)]
1076    _reserved: u32,
1077}
1078
1079#[repr(C)]
1080#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1081pub struct GspCleartextContent {
1082    pub length: u32,
1083    pub buffer: [u8; GSP_CLEARTEXT_MAX as usize * 2],
1084}
1085
1086const_assert_eq!(68, size_of::<GspCleartextContent>());
1087
1088#[repr(C)]
1089#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1090pub struct GspCiphertextContent {
1091    pub length: u32,
1092    pub buffer: [u8; GSP_CIPHERTEXT_MAX as usize],
1093}
1094
1095const_assert_eq!(516, size_of::<GspCiphertextContent>());
1096
1097/// This can only be used in PROTOCOL_VERSION_RS5
1098#[repr(C)]
1099#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1100pub struct GuestStateProtectionByIdRequest {
1101    pub message_header: HeaderHostRequest,
1102}
1103
1104const_assert_eq!(4, size_of::<GuestStateProtectionByIdRequest>());
1105
1106impl GuestStateProtectionByIdRequest {
1107    pub fn new() -> Self {
1108        Self {
1109            message_header: HeaderGeneric::new(HostRequests::GUEST_STATE_PROTECTION_BY_ID),
1110        }
1111    }
1112}
1113
1114#[repr(C)]
1115#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1116pub struct GuestStateProtectionByIdResponse {
1117    pub message_header: HeaderHostResponse,
1118    pub seed: GspCleartextContent,
1119    pub extended_status_flags: GspExtendedStatusFlags,
1120}
1121
1122const_assert_eq!(76, size_of::<GuestStateProtectionByIdResponse>());
1123
1124#[repr(C)]
1125#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1126pub struct GuestStateProtectionRequest {
1127    pub message_header: HeaderHostRequest,
1128    pub new_gsp: GspCleartextContent,
1129    pub encrypted_gsp: [GspCiphertextContent; NUMBER_GSP as usize],
1130    pub extended_status_support_flags: GspExtendedStatusFlags,
1131}
1132
1133const_assert_eq!(1108, size_of::<GuestStateProtectionRequest>());
1134
1135impl GuestStateProtectionRequest {
1136    pub fn new(
1137        buffer: [u8; GSP_CLEARTEXT_MAX as usize * 2],
1138        encrypted_gsp: [GspCiphertextContent; NUMBER_GSP as usize],
1139        extended_status_support_flags: GspExtendedStatusFlags,
1140    ) -> Self {
1141        Self {
1142            message_header: HeaderGeneric::new(HostRequests::GUEST_STATE_PROTECTION),
1143            new_gsp: GspCleartextContent {
1144                length: GSP_CLEARTEXT_MAX,
1145                buffer,
1146            },
1147            encrypted_gsp,
1148            extended_status_support_flags,
1149        }
1150    }
1151}
1152
1153#[repr(C)]
1154#[derive(Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1155pub struct GuestStateProtectionResponse {
1156    pub message_header: HeaderHostResponse,
1157    pub encrypted_gsp: GspCiphertextContent,
1158    pub decrypted_gsp: [GspCleartextContent; NUMBER_GSP as usize],
1159    pub extended_status_flags: GspExtendedStatusFlags,
1160}
1161
1162const_assert_eq!(660, size_of::<GuestStateProtectionResponse>());
1163
1164#[repr(C)]
1165#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1166pub struct UpdateGenerationId {
1167    pub message_header: HeaderGuestNotification,
1168    pub _pad: u32,
1169    pub generation_id: [u8; 16],
1170}
1171
1172const_assert_eq!(24, size_of::<UpdateGenerationId>());
1173
1174impl UpdateGenerationId {
1175    pub fn new(generation_id: [u8; 16]) -> Self {
1176        Self {
1177            message_header: HeaderGeneric::new(GuestNotifications::UPDATE_GENERATION_ID),
1178            _pad: 0,
1179            generation_id,
1180        }
1181    }
1182}
1183
1184/// Bitfield describing SaveGuestVtl2StateNotification::capabilities_flags
1185#[bitfield(u64)]
1186#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1187pub struct SaveGuestVtl2StateFlags {
1188    /// Explicitly allow nvme_keepalive feature when servicing.
1189    #[bits(1)]
1190    pub enable_nvme_keepalive: bool,
1191
1192    /// Explicitly allow mana_keepalive feature when servicing.
1193    #[bits(1)]
1194    pub enable_mana_keepalive: bool,
1195
1196    /// Reserved, must be zero.
1197    #[bits(62)]
1198    _rsvd1: u64,
1199}
1200
1201#[repr(C, packed)]
1202#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1203pub struct SaveGuestVtl2StateNotification {
1204    pub message_header: HeaderGuestNotification,
1205    pub correlation_id: Guid,
1206    pub capabilities_flags: SaveGuestVtl2StateFlags,
1207    pub timeout_hint_secs: u16,
1208}
1209
1210const_assert_eq!(30, size_of::<SaveGuestVtl2StateNotification>());
1211
1212#[repr(C)]
1213#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1214pub struct SaveGuestVtl2StateRequest {
1215    pub message_header: HeaderHostRequest,
1216    pub save_status: GuestVtl2SaveRestoreStatus,
1217    // Variable-length payload follows
1218}
1219
1220const_assert_eq!(6, size_of::<SaveGuestVtl2StateRequest>());
1221
1222impl SaveGuestVtl2StateRequest {
1223    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1224        Self {
1225            message_header: HeaderGeneric::new(HostRequests::SAVE_GUEST_VTL2_STATE),
1226            save_status: status,
1227        }
1228    }
1229}
1230
1231#[repr(C)]
1232#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1233pub struct SaveGuestVtl2StateResponse {
1234    pub message_header: HeaderHostResponse,
1235    pub save_status: GuestVtl2SaveRestoreStatus,
1236}
1237
1238const_assert_eq!(6, size_of::<SaveGuestVtl2StateResponse>());
1239
1240impl SaveGuestVtl2StateResponse {
1241    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1242        Self {
1243            message_header: HeaderGeneric::new(HostRequests::SAVE_GUEST_VTL2_STATE),
1244            save_status: status,
1245        }
1246    }
1247}
1248
1249#[repr(C)]
1250#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1251pub struct RestoreGuestVtl2StateHostNotification {
1252    pub message_header: HeaderHostNotification,
1253    pub status: GuestVtl2SaveRestoreStatus,
1254}
1255
1256const_assert_eq!(6, size_of::<RestoreGuestVtl2StateHostNotification>());
1257
1258impl RestoreGuestVtl2StateHostNotification {
1259    pub fn new(stat: GuestVtl2SaveRestoreStatus) -> Self {
1260        Self {
1261            message_header: HeaderGeneric::new(
1262                HostNotifications::RESTORE_GUEST_VTL2_STATE_COMPLETED,
1263            ),
1264            status: stat,
1265        }
1266    }
1267}
1268
1269#[repr(C)]
1270#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1271pub struct RestoreGuestVtl2StateRequest {
1272    pub message_header: HeaderHostRequest,
1273    pub restore_status: GuestVtl2SaveRestoreStatus,
1274}
1275
1276const_assert_eq!(6, size_of::<RestoreGuestVtl2StateRequest>());
1277
1278impl RestoreGuestVtl2StateRequest {
1279    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1280        Self {
1281            message_header: HeaderGeneric::new(HostRequests::RESTORE_GUEST_VTL2_STATE),
1282            restore_status: status,
1283        }
1284    }
1285}
1286
1287#[repr(C, packed)]
1288#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1289pub struct RestoreGuestVtl2StateResponse {
1290    pub message_header: HeaderHostResponse,
1291    pub data_length: u32,
1292    pub restore_status: GuestVtl2SaveRestoreStatus,
1293    // Variable-length payload follows
1294}
1295
1296const_assert_eq!(10, size_of::<RestoreGuestVtl2StateResponse>());
1297
1298impl RestoreGuestVtl2StateResponse {
1299    pub fn new(length: u32, status: GuestVtl2SaveRestoreStatus) -> Self {
1300        Self {
1301            message_header: HeaderGeneric::new(HostRequests::RESTORE_GUEST_VTL2_STATE),
1302            data_length: length,
1303            restore_status: status,
1304        }
1305    }
1306}
1307
1308open_enum! {
1309    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1310    pub enum VpciDeviceControlCode: u32 {
1311        UNDEFINED = 0,
1312        OFFER = 1,
1313        REVOKE = 2,
1314        RESET = 3,
1315    }
1316}
1317
1318open_enum! {
1319    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1320    pub enum VpciDeviceControlStatus: u32 {
1321        SUCCESS = 0,
1322        INVALID_REQUEST = 1,
1323        DEVICE_NOT_FOUND = 2,
1324        INVALID_DEVICE_STATE = 3,
1325        GENERIC_FAILURE = 4,
1326    }
1327}
1328
1329#[repr(C)]
1330#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1331pub struct VpciDeviceControlRequest {
1332    pub message_header: HeaderHostRequest,
1333    pub code: VpciDeviceControlCode,
1334    pub bus_instance_id: Guid,
1335}
1336
1337const_assert_eq!(24, size_of::<VpciDeviceControlRequest>());
1338
1339impl VpciDeviceControlRequest {
1340    pub fn new(code: VpciDeviceControlCode, bus_instance_id: Guid) -> Self {
1341        Self {
1342            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_CONTROL),
1343            code,
1344            bus_instance_id,
1345        }
1346    }
1347}
1348
1349#[repr(C)]
1350#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1351pub struct VpciDeviceControlResponse {
1352    pub message_header: HeaderHostResponse,
1353    pub status: VpciDeviceControlStatus,
1354}
1355
1356const_assert_eq!(8, size_of::<VpciDeviceControlResponse>());
1357
1358impl VpciDeviceControlResponse {
1359    pub fn new(status: VpciDeviceControlStatus) -> Self {
1360        Self {
1361            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_CONTROL),
1362            status,
1363        }
1364    }
1365}
1366
1367open_enum! {
1368    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1369    pub enum VpciDeviceNotificationCode : u32 {
1370        UNDEFINED = 0,
1371        ENUMERATED = 1,
1372        PREPARE_FOR_REMOVAL = 2,
1373    }
1374}
1375
1376#[repr(C)]
1377#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1378pub struct VpciDeviceNotification {
1379    pub message_header: HeaderGuestNotification,
1380    pub bus_instance_id: Guid,
1381    pub code: VpciDeviceNotificationCode,
1382}
1383
1384const_assert_eq!(24, size_of::<VpciDeviceNotification>());
1385
1386#[repr(C, packed)]
1387#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1388pub struct VpciDeviceBindingChangeRequest {
1389    pub message_header: HeaderHostRequest,
1390    pub bus_instance_id: [u8; 16], // Guid
1391    pub binding_state: u8,
1392}
1393
1394const_assert_eq!(21, size_of::<VpciDeviceBindingChangeRequest>());
1395
1396impl VpciDeviceBindingChangeRequest {
1397    pub fn new(bus_instance_id: Guid, binding_state: bool) -> Self {
1398        let mut guid: [u8; 16] = [0; 16];
1399        guid.copy_from_slice(bus_instance_id.as_bytes());
1400        Self {
1401            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_BINDING_CHANGE),
1402            bus_instance_id: guid,
1403            binding_state: binding_state as u8,
1404        }
1405    }
1406}
1407
1408#[repr(C)]
1409#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1410pub struct VpciDeviceBindingChangeResponse {
1411    pub message_header: HeaderHostResponse,
1412    pub bus_instance_id: Guid,
1413    pub status: VpciDeviceControlStatus,
1414}
1415
1416const_assert_eq!(24, size_of::<VpciDeviceBindingChangeResponse>());
1417
1418impl VpciDeviceBindingChangeResponse {
1419    pub fn new(bus_instance_id: Guid, status: VpciDeviceControlStatus) -> Self {
1420        Self {
1421            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_BINDING_CHANGE),
1422            bus_instance_id,
1423            status,
1424        }
1425    }
1426}
1427
1428#[repr(C, packed)]
1429#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1430pub struct VgaProxyPciReadRequest {
1431    pub message_header: HeaderHostRequest,
1432    pub offset: u16,
1433}
1434
1435const_assert_eq!(6, size_of::<VgaProxyPciReadRequest>());
1436
1437impl VgaProxyPciReadRequest {
1438    pub fn new(offset: u16) -> Self {
1439        Self {
1440            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_READ),
1441            offset,
1442        }
1443    }
1444}
1445
1446#[repr(C)]
1447#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1448pub struct VgaProxyPciReadResponse {
1449    pub message_header: HeaderHostResponse,
1450    pub value: u32,
1451}
1452
1453const_assert_eq!(8, size_of::<VgaProxyPciReadResponse>());
1454
1455impl VgaProxyPciReadResponse {
1456    pub fn new(value: u32) -> Self {
1457        Self {
1458            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_READ),
1459            value,
1460        }
1461    }
1462}
1463
1464#[repr(C, packed)]
1465#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1466pub struct VgaProxyPciWriteRequest {
1467    pub message_header: HeaderHostRequest,
1468    pub value: u32,
1469    pub offset: u16,
1470}
1471
1472const_assert_eq!(10, size_of::<VgaProxyPciWriteRequest>());
1473
1474impl VgaProxyPciWriteRequest {
1475    pub fn new(offset: u16, value: u32) -> Self {
1476        Self {
1477            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_WRITE),
1478            offset,
1479            value,
1480        }
1481    }
1482}
1483
1484#[repr(C)]
1485#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1486pub struct VgaProxyPciWriteResponse {
1487    pub message_header: HeaderHostResponse,
1488}
1489
1490const_assert_eq!(4, size_of::<VgaProxyPciWriteResponse>());
1491
1492impl VgaProxyPciWriteResponse {
1493    pub fn new() -> Self {
1494        Self {
1495            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_WRITE),
1496        }
1497    }
1498}
1499
1500open_enum! {
1501    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1502    pub enum ModifyVtl2SettingsStatus : u32 {
1503        SUCCESS = 0,
1504        FAILURE = 1,
1505    }
1506}
1507
1508#[repr(C)]
1509#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1510pub struct ModifyVtl2SettingsNotification {
1511    pub message_header: HeaderGuestNotification,
1512
1513    pub size: u32,
1514    // variable length JSON payload
1515}
1516
1517const_assert_eq!(8, size_of::<ModifyVtl2SettingsNotification>());
1518
1519#[repr(C)]
1520#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1521pub struct ModifyVtl2SettingsRev1Notification {
1522    pub message_header: HeaderGuestNotification,
1523
1524    pub size: u32,
1525
1526    pub payload_state: LargePayloadState,
1527    // variable length JSON payload
1528}
1529
1530const_assert_eq!(12, size_of::<ModifyVtl2SettingsRev1Notification>());
1531
1532#[repr(C, packed)]
1533#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1534pub struct ModifyVtl2SettingsCompleteNotification {
1535    pub message_header: HeaderHostNotification,
1536    pub modify_status: ModifyVtl2SettingsStatus,
1537    pub result_document_size: u32,
1538}
1539
1540const_assert_eq!(12, size_of::<ModifyVtl2SettingsCompleteNotification>());
1541
1542impl ModifyVtl2SettingsCompleteNotification {
1543    pub fn new(status: ModifyVtl2SettingsStatus, result_document_size: u32) -> Self {
1544        Self {
1545            message_header: HeaderGeneric::new(HostNotifications::MODIFY_VTL2_SETTINGS_COMPLETED),
1546            modify_status: status,
1547            result_document_size,
1548        }
1549    }
1550}
1551
1552pub const GET_LOG_INTERFACE_GUID: Guid = guid::guid!("AA5DE534-D149-487A-9053-05972BA20A7C");
1553
1554open_enum! {
1555    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1556    pub enum LogType: u8 {
1557        EVENT = 0,
1558        SPAN_ENTER = 1,
1559        SPAN_EXIT = 2,
1560    }
1561}
1562
1563#[bitfield(u16)]
1564#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1565pub struct LogFlags {
1566    pub kmsg: bool,
1567    #[bits(15)]
1568    pub mbz0: u16,
1569}
1570
1571pub const TRACE_LOGGING_NAME_MAX_SIZE: usize = 128;
1572pub const TRACE_LOGGING_TARGET_MAX_SIZE: usize = 128;
1573pub const TRACE_LOGGING_FIELDS_MAX_SIZE: usize = 256;
1574pub const TRACE_LOGGING_MESSAGE_MAX_SIZE: usize = 4096;
1575pub const TRACE_LOGGING_NOTIFICATION_MAX_SIZE: usize = TRACE_LOGGING_NAME_MAX_SIZE
1576    + TRACE_LOGGING_TARGET_MAX_SIZE
1577    + TRACE_LOGGING_FIELDS_MAX_SIZE
1578    + TRACE_LOGGING_MESSAGE_MAX_SIZE
1579    + size_of::<TraceLoggingNotificationHeader>();
1580
1581#[repr(C)]
1582#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1583pub struct TraceLoggingBufferOffset {
1584    pub size: u16,
1585    pub offset: u16,
1586}
1587
1588// The header is followed by a buffer which holds the string fields.
1589//
1590//  ---------------------------------------------------------
1591//  |  Header | Buffer [ name | target | fields | message ] |
1592//  ---------------------------------------------------------
1593#[repr(C)]
1594#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1595pub struct TraceLoggingNotificationHeader {
1596    pub log_type: LogType,
1597    pub level: u8,
1598    pub flags: LogFlags,
1599    pub name: TraceLoggingBufferOffset,
1600    pub target: TraceLoggingBufferOffset,
1601    pub fields: TraceLoggingBufferOffset,
1602    pub message: TraceLoggingBufferOffset,
1603    pub mbz0: u32,
1604    pub activity_id: Guid,
1605    pub related_activity_id: Guid,
1606    pub correlation_id: Guid,
1607    pub timestamp: u64,
1608}
1609const_assert_eq!(80, size_of::<TraceLoggingNotificationHeader>());
1610
1611/// MAP_FRAMEBUFFER_REQUEST
1612#[repr(C, packed)]
1613#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1614pub struct MapFramebufferRequest {
1615    pub message_header: HeaderHostRequest,
1616    pub gpa: u64,
1617}
1618
1619const_assert_eq!(12, size_of::<MapFramebufferRequest>());
1620
1621impl MapFramebufferRequest {
1622    pub fn new(gpa: u64) -> Self {
1623        Self {
1624            message_header: HeaderGeneric::new(HostRequests::MAP_FRAMEBUFFER),
1625            gpa,
1626        }
1627    }
1628}
1629
1630open_enum! {
1631    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1632    pub enum MapFramebufferStatus : u32 {
1633        SUCCESS = 0,
1634        FAILURE = 1,
1635    }
1636}
1637
1638/// MAP_FRAMEBUFFER_RESPONSE
1639#[repr(C, packed)]
1640#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1641pub struct MapFramebufferResponse {
1642    pub message_header: HeaderHostResponse,
1643    pub status: MapFramebufferStatus,
1644}
1645
1646const_assert_eq!(8, size_of::<MapFramebufferResponse>());
1647
1648impl MapFramebufferResponse {
1649    pub fn new(status: MapFramebufferStatus) -> Self {
1650        Self {
1651            message_header: HeaderGeneric::new(HostRequests::MAP_FRAMEBUFFER),
1652            status,
1653        }
1654    }
1655}
1656
1657/// UNMAP_FRAMEBUFFER
1658#[repr(C, packed)]
1659#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1660pub struct UnmapFramebufferRequest {
1661    pub message_header: HeaderHostRequest,
1662}
1663
1664const_assert_eq!(4, size_of::<UnmapFramebufferRequest>());
1665
1666impl UnmapFramebufferRequest {
1667    pub fn new() -> Self {
1668        Self {
1669            message_header: HeaderGeneric::new(HostRequests::UNMAP_FRAMEBUFFER),
1670        }
1671    }
1672}
1673
1674open_enum! {
1675    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1676    pub enum UnmapFramebufferStatus : u32 {
1677        SUCCESS = 0,
1678        FAILURE = 1,
1679    }
1680}
1681
1682/// UNMAP_FRAMEBUFFER_RESPONSE
1683#[repr(C, packed)]
1684#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1685pub struct UnmapFramebufferResponse {
1686    pub message_header: HeaderHostResponse,
1687    pub status: UnmapFramebufferStatus,
1688}
1689
1690const_assert_eq!(8, size_of::<UnmapFramebufferResponse>());
1691
1692impl UnmapFramebufferResponse {
1693    pub fn new(status: UnmapFramebufferStatus) -> Self {
1694        Self {
1695            message_header: HeaderGeneric::new(HostRequests::UNMAP_FRAMEBUFFER),
1696            status,
1697        }
1698    }
1699}
1700
1701open_enum! {
1702    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1703    pub enum StartVtl0Status : u32 {
1704        SUCCESS = 0,
1705        FAILURE = 1,
1706    }
1707}
1708
1709#[repr(C, packed)]
1710#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1711pub struct StartVtl0CompleteNotification {
1712    pub message_header: HeaderHostNotification,
1713    pub status: StartVtl0Status,
1714    pub result_document_size: u32,
1715    // result_document is a variable size raw string because the Error is anyhow::Error
1716    // TODO: use specific Errors for "start VM"
1717}
1718
1719const_assert_eq!(12, size_of::<StartVtl0CompleteNotification>());
1720
1721impl StartVtl0CompleteNotification {
1722    pub fn new(status: StartVtl0Status, result_document_size: u32) -> Self {
1723        Self {
1724            message_header: HeaderGeneric::new(HostNotifications::START_VTL0_COMPLETED),
1725            status,
1726            result_document_size,
1727        }
1728    }
1729}
1730
1731#[repr(C)]
1732#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1733pub struct BatteryStatusNotification {
1734    pub message_header: HeaderGuestNotification,
1735    pub flags: BatteryStatusFlags,
1736    pub max_capacity: u32,
1737    pub remaining_capacity: u32,
1738    pub rate: u32,
1739}
1740
1741#[bitfield(u32)]
1742#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1743pub struct BatteryStatusFlags {
1744    pub ac_online: bool,
1745    pub battery_present: bool,
1746    pub charging: bool,
1747    pub discharging: bool,
1748    #[bits(28)]
1749    pub reserved: u32,
1750}
1751
1752impl BatteryStatusNotification {
1753    pub fn new(
1754        flags: BatteryStatusFlags,
1755        max_capacity: u32,
1756        remaining_capacity: u32,
1757        rate: u32,
1758    ) -> Self {
1759        Self {
1760            message_header: HeaderGeneric::new(GuestNotifications::BATTERY_STATUS),
1761            flags,
1762            max_capacity,
1763            remaining_capacity,
1764            rate,
1765        }
1766    }
1767}
1768
1769#[repr(C)]
1770#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1771pub struct InjectDebugInterruptNotification {
1772    pub message_header: HeaderGuestNotification,
1773    pub vtl: u8,
1774    pub _pad: u8,
1775}
1776const_assert_eq!(6, size_of::<InjectDebugInterruptNotification>());
1777
1778#[repr(C)]
1779#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1780pub struct PostLiveMigrationNotification {
1781    pub message_header: HeaderGuestNotification,
1782}
1783const_assert_eq!(4, size_of::<PostLiveMigrationNotification>());
1784
1785#[bitfield(u64)]
1786#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1787pub struct CreateRamGpaRangeFlags {
1788    _reserved1: bool,
1789
1790    /// Writes are discarded
1791    pub rom_mb: bool,
1792
1793    #[bits(62)]
1794    _reserved: u64,
1795}
1796
1797#[repr(C, packed)]
1798#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1799pub struct CreateRamGpaRangeRequest {
1800    pub message_header: HeaderHostRequest,
1801    pub slot: u32,
1802    pub gpa_start: u64,
1803    pub gpa_count: u64,
1804    pub gpa_offset: u64,
1805    pub flags: CreateRamGpaRangeFlags,
1806}
1807
1808const_assert_eq!(40, size_of::<CreateRamGpaRangeRequest>());
1809
1810impl CreateRamGpaRangeRequest {
1811    pub fn new(
1812        slot: u32,
1813        gpa_start: u64,
1814        gpa_count: u64,
1815        gpa_offset: u64,
1816        flags: CreateRamGpaRangeFlags,
1817    ) -> Self {
1818        Self {
1819            message_header: HeaderGeneric::new(HostRequests::CREATE_RAM_GPA_RANGE),
1820            slot,
1821            gpa_start,
1822            gpa_count,
1823            gpa_offset,
1824            flags,
1825        }
1826    }
1827}
1828
1829open_enum! {
1830    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1831    pub enum CreateRamGpaRangeStatus : u32 {
1832        SUCCESS = 0,
1833        /// slot index out of bounds
1834        SLOT_OUT_OF_BOUNDS = 1,
1835        /// slot is already occupied. needs to be reset first
1836        SLOT_OCCUPIED = 2,
1837        /// invalid flag
1838        INVALID_FLAG = 3,
1839        /// invalid GPA
1840        INVALID_GPA = 4,
1841        /// call to CreateRamGpaRange failed
1842        FAILED = 5,
1843    }
1844}
1845
1846#[repr(C)]
1847#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1848pub struct CreateRamGpaRangeResponse {
1849    pub message_header: HeaderHostResponse,
1850    pub status: CreateRamGpaRangeStatus,
1851}
1852
1853const_assert_eq!(8, size_of::<CreateRamGpaRangeResponse>());
1854
1855impl CreateRamGpaRangeResponse {
1856    pub fn new(status: CreateRamGpaRangeStatus) -> Self {
1857        Self {
1858            message_header: HeaderGeneric::new(HostRequests::CREATE_RAM_GPA_RANGE),
1859            status,
1860        }
1861    }
1862}
1863
1864#[repr(C)]
1865#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1866pub struct ResetRamGpaRangeRequest {
1867    pub message_header: HeaderHostRequest,
1868    pub slot: u32,
1869}
1870
1871const_assert_eq!(8, size_of::<ResetRamGpaRangeRequest>());
1872
1873impl ResetRamGpaRangeRequest {
1874    pub fn new(slot: u32) -> Self {
1875        Self {
1876            message_header: HeaderGeneric::new(HostRequests::RESET_RAM_GPA_RANGE),
1877            slot,
1878        }
1879    }
1880}
1881
1882#[repr(C)]
1883#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1884pub struct ResetRamGpaRangeResponse {
1885    pub message_header: HeaderHostResponse,
1886}
1887
1888const_assert_eq!(4, size_of::<ResetRamGpaRangeResponse>());
1889
1890impl ResetRamGpaRangeResponse {
1891    pub fn new() -> Self {
1892        Self {
1893            message_header: HeaderGeneric::new(HostRequests::RESET_RAM_GPA_RANGE),
1894        }
1895    }
1896}
1897
1898pub mod test_utilities {
1899    // These constants are shared across GED and GET testing
1900    pub const TEST_VMGS_SECTOR_SIZE: u32 = 512;
1901    pub const TEST_VMGS_CAPACITY: usize = 4194816; // 4 MB
1902}