Skip to main content

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        DEK_HARDWARE_UNSEALING_SKIPPED = 23,
354    }
355}
356
357#[repr(C)]
358#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
359pub struct EventLogNotification {
360    pub message_header: HeaderHostNotification,
361    pub event_log_id: EventLogId,
362}
363
364const_assert_eq!(8, size_of::<EventLogNotification>());
365
366impl EventLogNotification {
367    pub fn new(event_log_id: EventLogId) -> Self {
368        Self {
369            message_header: HeaderGeneric::new(HostNotifications::EVENT_LOG),
370            event_log_id,
371        }
372    }
373}
374
375pub const TRACE_MSG_MAX_SIZE: usize = 256;
376open_enum! {
377    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
378    pub enum LogLevel: u32 {
379        INVALID = 0,
380        CRITICAL = 1,
381        ERROR = 2,
382        WARNING = 3,
383        INFORMATION = 4,
384        VERBOSE = 5,
385    }
386}
387
388impl From<LogLevel> for u8 {
389    fn from(level: LogLevel) -> Self {
390        match level {
391            LogLevel::INVALID => 0,
392            LogLevel::CRITICAL => 1,
393            LogLevel::ERROR => 2,
394            LogLevel::WARNING => 3,
395            LogLevel::INFORMATION => 4,
396            LogLevel::VERBOSE => 5,
397            _ => {
398                unreachable!();
399            }
400        }
401    }
402}
403
404open_enum! {
405    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
406    pub enum GuestVtl2SaveRestoreStatus : u16 {
407        SUCCESS = 0,
408        FAILURE = 1,
409        MORE_DATA = 2,
410        REQUEST_DATA = 3,
411    }
412}
413
414#[repr(C)]
415#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
416pub struct LogTraceNotification {
417    pub message_header: HeaderHostNotification,
418    pub level: LogLevel,
419    pub message: [u16; TRACE_MSG_MAX_SIZE],
420}
421
422const_assert_eq!(520, size_of::<LogTraceNotification>());
423
424pub const VTL_CRASH_PARAMETERS: usize = 5;
425
426/// The transport level VTL crash data to send to the host.
427#[repr(C)]
428#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
429pub struct VtlCrashNotification {
430    pub message_header: HeaderHostNotification,
431    pub vp_index: u32,
432    pub last_vtl: u8,
433    pub reserved0: u8,
434    pub reserved1: u16,
435    pub reserved2: u32,
436    pub control: u64,
437    pub parameters: [u64; VTL_CRASH_PARAMETERS],
438}
439
440const_assert_eq!(64, size_of::<VtlCrashNotification>());
441
442impl VtlCrashNotification {
443    pub fn new(
444        vp_index: u32,
445        last_vtl: u8,
446        control: u64,
447        parameters: [u64; VTL_CRASH_PARAMETERS],
448    ) -> Self {
449        Self {
450            message_header: HeaderGeneric::new(HostNotifications::VTL_CRASH),
451            vp_index,
452            last_vtl,
453            reserved0: 0,
454            reserved1: 0,
455            reserved2: 0,
456            control,
457            parameters,
458        }
459    }
460}
461
462open_enum! {
463    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
464    pub enum TripleFaultType: u32 {
465        UNRECOVERABLE_EXCEPTION = 1,
466    }
467}
468
469#[repr(C)]
470#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
471pub struct RegisterState {
472    pub name: u32,
473    pub value: [u8; 16],
474}
475const_assert_eq!(20, size_of::<RegisterState>());
476
477/// Triple fault notification to send to the host.
478#[repr(C)]
479#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
480pub struct TripleFaultNotification {
481    pub message_header: HeaderHostNotification,
482    pub vp_index: u32,
483    pub fault_type: TripleFaultType,
484    pub register_count: u32,
485}
486const_assert_eq!(16, size_of::<TripleFaultNotification>());
487
488impl TripleFaultNotification {
489    pub fn new(vp_index: u32, fault_type: TripleFaultType, register_count: u32) -> Self {
490        Self {
491            message_header: HeaderGeneric::new(HostNotifications::TRIPLE_FAULT),
492            vp_index,
493            fault_type,
494            register_count,
495        }
496    }
497}
498
499#[repr(C)]
500#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
501pub struct VersionRequest {
502    pub message_header: HeaderHostRequest,
503    pub version: ProtocolVersion,
504}
505
506impl VersionRequest {
507    /// Creates new `VersionRequest` message
508    pub fn new(version: ProtocolVersion) -> Self {
509        Self {
510            message_header: HeaderGeneric::new(HostRequests::VERSION),
511            version,
512        }
513    }
514}
515
516const_assert_eq!(8, size_of::<VersionRequest>());
517
518#[repr(C)]
519#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
520pub struct VersionResponse {
521    pub message_header: HeaderHostResponse,
522    pub version_accepted: ProtocolBool,
523    pub _pad: u8,
524}
525
526impl VersionResponse {
527    pub fn new(version_accepted: bool) -> Self {
528        Self {
529            message_header: HeaderGeneric::new(HostRequests::VERSION),
530            version_accepted: version_accepted.into(),
531            _pad: 0,
532        }
533    }
534}
535
536const_assert_eq!(6, size_of::<VersionResponse>());
537
538#[repr(C)]
539#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
540pub struct TimeRequest {
541    pub message_header: HeaderHostRequest,
542}
543
544const_assert_eq!(4, size_of::<TimeRequest>());
545
546impl TimeRequest {
547    pub fn new() -> Self {
548        Self {
549            message_header: HeaderGeneric::new(HostRequests::TIME),
550        }
551    }
552}
553
554#[repr(C)]
555#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
556pub struct TimeResponse {
557    pub message_header: HeaderHostResponse,
558    pub _pad: u32,
559
560    pub vm_reference_time: u64,
561    pub utc: i64,
562    pub time_zone: i16,
563    pub daylight_savings: ProtocolBool,
564    pub _pad1: [u8; 5],
565}
566
567impl TimeResponse {
568    pub fn new(vm_reference_time: u64, utc: i64, time_zone: i16, daylight_savings: bool) -> Self {
569        Self {
570            message_header: HeaderGeneric::new(HostRequests::TIME),
571            _pad: 0,
572
573            vm_reference_time,
574            utc,
575            time_zone,
576            daylight_savings: daylight_savings.into(),
577            _pad1: [0; 5],
578        }
579    }
580}
581
582const_assert_eq!(32, size_of::<TimeResponse>());
583
584/// Maximum agent data size
585pub const IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE: usize = 2048;
586/// Maximum attestation report size
587pub const IGVM_ATTEST_MSG_REQ_REPORT_MAX_SIZE: usize = 4096;
588
589/// Maximum return pages
590pub const IGVM_ATTEST_MSG_MAX_SHARED_GPA: usize = 16;
591
592// Error from the VM worker process in the host when sending an
593// attestation request.
594pub const IGVM_ATTEST_VMWP_GENERIC_ERROR_CODE: usize = 0xFFFFFFFF;
595
596/// The response payload could be quite large, so pass host
597/// previously shared pages to use for response.
598/// Use GET response packet to serialize and convey response length.
599#[repr(C)]
600#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
601pub struct IgvmAttestRequest {
602    pub message_header: HeaderHostRequest,
603    /// Number of GPA
604    pub number_gpa: u32,
605    /// GPA addresses
606    pub shared_gpa: [u64; IGVM_ATTEST_MSG_MAX_SHARED_GPA],
607    /// Agent data length
608    pub agent_data_length: u32,
609    /// Report length
610    pub report_length: u32,
611    /// Agent data
612    pub agent_data: [u8; IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE],
613    /// Report
614    pub report: [u8; IGVM_ATTEST_MSG_REQ_REPORT_MAX_SIZE],
615}
616
617const_assert_eq!(6288, size_of::<IgvmAttestRequest>());
618
619impl IgvmAttestRequest {
620    pub fn new(
621        shared_gpa: [u64; IGVM_ATTEST_MSG_MAX_SHARED_GPA],
622        number_gpa: u32,
623        agent_data: [u8; IGVM_ATTEST_MSG_REQ_AGENT_DATA_MAX_SIZE],
624        agent_data_length: u32,
625        report: [u8; IGVM_ATTEST_MSG_REQ_REPORT_MAX_SIZE],
626        report_length: u32,
627    ) -> Self {
628        Self {
629            message_header: HeaderGeneric::new(HostRequests::IGVM_ATTEST),
630            number_gpa,
631            shared_gpa,
632            agent_data_length,
633            report_length,
634            agent_data,
635            report,
636        }
637    }
638}
639
640#[repr(C)]
641#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
642pub struct IgvmAttestResponse {
643    pub message_header: HeaderHostResponse,
644    pub length: u32,
645}
646
647const_assert_eq!(8, size_of::<IgvmAttestResponse>());
648
649/// This can only be used in PROTOCOL_VERSION_RS5
650#[repr(C)]
651#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
652pub struct BiosBootFinalizeRequest {
653    pub message_header: HeaderHostRequest,
654    pub value: u8,
655    pub _pad: u8,
656}
657
658const_assert_eq!(6, size_of::<BiosBootFinalizeRequest>());
659
660#[repr(C)]
661#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
662pub struct BiosBootFinalizeResponse {
663    pub message_header: HeaderHostResponse,
664}
665
666impl BiosBootFinalizeResponse {
667    pub fn new() -> BiosBootFinalizeResponse {
668        BiosBootFinalizeResponse {
669            message_header: HeaderGeneric::new(HostRequests::BIOS_BOOT_FINALIZE),
670        }
671    }
672}
673
674const_assert_eq!(4, size_of::<BiosBootFinalizeResponse>());
675
676#[repr(C)]
677#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
678pub struct VmgsGetDeviceInfoRequest {
679    pub message_header: HeaderHostRequest,
680}
681
682impl VmgsGetDeviceInfoRequest {
683    pub fn new() -> Self {
684        Self {
685            message_header: HeaderGeneric::new(HostRequests::VMGS_GET_DEVICE_INFO),
686        }
687    }
688}
689
690const_assert_eq!(4, size_of::<VmgsGetDeviceInfoRequest>());
691
692open_enum! {
693    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
694    pub enum VmgsIoStatus: u32 {
695        SUCCESS         = 0,
696        INVALID_COMMAND = 1,
697        DEVICE_ERROR    = 2,
698        RETRY           = 3,
699    }
700}
701
702open_enum! {
703    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
704    pub enum VmgsWriteFlags: u32 {
705        NONE          = 0,
706        WRITE_THROUGH = 0x00000001,
707    }
708}
709
710open_enum! {
711    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
712    pub enum VmgsReadFlags: u32 {
713        NONE = 0,
714    }
715}
716
717#[repr(C)]
718#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
719pub struct VmgsGetDeviceInfoResponse {
720    pub message_header: HeaderHostResponse,
721    pub status: VmgsIoStatus,
722    pub capacity: u64, // logical sectors
723    pub bytes_per_logical_sector: u16,
724    pub bytes_per_physical_sector: u16,
725    pub maximum_transfer_size_bytes: u32,
726}
727
728impl VmgsGetDeviceInfoResponse {
729    pub fn new(
730        status: VmgsIoStatus,
731        capacity: u64,
732        bytes_per_logical_sector: u16,
733        bytes_per_physical_sector: u16,
734        maximum_transfer_size_bytes: u32,
735    ) -> VmgsGetDeviceInfoResponse {
736        VmgsGetDeviceInfoResponse {
737            message_header: HeaderGeneric::new(HostRequests::VMGS_GET_DEVICE_INFO),
738
739            status,
740            capacity,
741            bytes_per_logical_sector,
742            bytes_per_physical_sector,
743            maximum_transfer_size_bytes,
744        }
745    }
746}
747
748const_assert_eq!(24, size_of::<VmgsGetDeviceInfoResponse>());
749
750#[repr(C)]
751#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
752pub struct VmgsWriteRequest {
753    pub message_header: HeaderHostRequest,
754    pub flags: VmgsWriteFlags,
755    pub sector_offset: u64, // logical sectors
756    pub sector_count: u32,  // logical sectors
757    pub _pad: u32,
758    // Variable size payload follows
759}
760
761const_assert_eq!(24, size_of::<VmgsWriteRequest>());
762
763impl VmgsWriteRequest {
764    pub fn new(flags: VmgsWriteFlags, sector_offset: u64, sector_count: u32) -> Self {
765        Self {
766            message_header: HeaderGeneric::new(HostRequests::VMGS_WRITE),
767            flags,
768            sector_offset,
769            sector_count,
770            _pad: 0,
771        }
772    }
773}
774
775#[repr(C)]
776#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
777pub struct VmgsWriteResponse {
778    pub message_header: HeaderHostResponse,
779    pub status: VmgsIoStatus,
780}
781
782impl VmgsWriteResponse {
783    pub fn new(status: VmgsIoStatus) -> VmgsWriteResponse {
784        VmgsWriteResponse {
785            message_header: HeaderGeneric::new(HostRequests::VMGS_WRITE),
786            status,
787        }
788    }
789}
790
791const_assert_eq!(8, size_of::<VmgsWriteResponse>());
792
793#[repr(C)]
794#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
795pub struct VmgsReadRequest {
796    pub message_header: HeaderHostRequest,
797    pub flags: VmgsReadFlags,
798    pub sector_offset: u64, // logical sectors
799    pub sector_count: u32,  // logical sectors
800    pub _pad: u32,
801}
802
803const_assert_eq!(24, size_of::<VmgsReadRequest>());
804
805impl VmgsReadRequest {
806    pub fn new(flags: VmgsReadFlags, sector_offset: u64, sector_count: u32) -> Self {
807        Self {
808            message_header: HeaderGeneric::new(HostRequests::VMGS_READ),
809            flags,
810            sector_offset,
811            sector_count,
812            _pad: 0,
813        }
814    }
815}
816
817#[repr(C)]
818#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
819pub struct VmgsReadResponse {
820    pub message_header: HeaderHostResponse,
821    pub status: VmgsIoStatus,
822    // Variable size payload follows
823}
824
825impl VmgsReadResponse {
826    pub fn new(status: VmgsIoStatus) -> VmgsReadResponse {
827        VmgsReadResponse {
828            message_header: HeaderGeneric::new(HostRequests::VMGS_READ),
829            status,
830        }
831    }
832}
833
834const_assert_eq!(8, size_of::<VmgsReadResponse>());
835
836#[repr(C)]
837#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
838pub struct VmgsFlushRequest {
839    pub message_header: HeaderHostRequest,
840}
841
842impl VmgsFlushRequest {
843    pub fn new() -> Self {
844        Self {
845            message_header: HeaderGeneric::new(HostRequests::VMGS_FLUSH),
846        }
847    }
848}
849
850const_assert_eq!(4, size_of::<VmgsFlushRequest>());
851
852#[repr(C)]
853#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
854pub struct VmgsFlushResponse {
855    pub message_header: HeaderHostResponse,
856    pub status: VmgsIoStatus,
857}
858
859impl VmgsFlushResponse {
860    pub fn new(status: VmgsIoStatus) -> VmgsFlushResponse {
861        VmgsFlushResponse {
862            message_header: HeaderGeneric::new(HostRequests::VMGS_FLUSH),
863            status,
864        }
865    }
866}
867
868const_assert_eq!(8, size_of::<VmgsFlushResponse>());
869
870const VMGS_MAX_IO_MSG_HEADER_SIZE: usize = size_of::<VmgsReadRequest>();
871const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE >= size_of::<VmgsReadResponse>());
872const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE >= size_of::<VmgsWriteRequest>());
873const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE >= size_of::<VmgsWriteResponse>());
874const_assert!(VMGS_MAX_IO_MSG_HEADER_SIZE <= MAX_HEADER_SIZE);
875
876pub const MAX_TRANSFER_SIZE: usize = u32::MAX as usize - VMGS_MAX_IO_MSG_HEADER_SIZE;
877
878open_enum! {
879    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
880    pub enum ActivityClassId: u32 {
881        INVALID = 0,
882        VMGS_INITIALIZE_DEVICE = 1,
883        VMGS_INITIALIZE_STORE = 2,
884        VMGS_OPEN_STORE = 3,
885        VMGS_FORMAT = 4,
886        VMGS_SEND_RECEIVE = 5,
887        VMGS_DEVICE_READ = 6,
888        VMGS_DEVICE_WRITE = 7,
889        VMGS_DEVICE_FLUSH = 8,
890    }
891}
892
893open_enum! {
894    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
895    pub enum ActivityOpCode: u32 {
896        INFO = 0,
897        START = 1,
898        STOP = 2,
899    }
900}
901
902open_enum! {
903    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
904    pub enum EventId: u32 {
905        INVALID = 0,
906        VMGS_INFO = 1,
907        VMGS_WARNING = 2,
908        VMGS_ERROR = 3,
909        VMGS_CRITICAL = 4,
910    }
911}
912
913#[repr(C)]
914#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
915pub struct LogTraceRequest {
916    pub message_header: HeaderHostRequest,
917    pub level: LogLevel,
918    pub message: [u16; TRACE_MSG_MAX_SIZE],
919}
920
921const_assert_eq!(520, size_of::<LogTraceRequest>());
922
923#[repr(C)]
924#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
925pub struct LogTraceResponse {
926    pub message_header: HeaderHostResponse,
927}
928
929const_assert_eq!(4, size_of::<LogTraceResponse>());
930
931#[repr(C)]
932#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
933pub struct ActivityTraceStartRequest {
934    pub message_header: HeaderHostRequest,
935    pub activity_class: ActivityClassId,
936    pub related_activity_id: Guid,
937    pub size: u32, // Size of payload
938                   // Variable size payload follows, maximum TRACE_MSG_MAX_SIZE WCHAR
939}
940
941const_assert_eq!(28, size_of::<ActivityTraceStartRequest>());
942
943#[repr(C)]
944#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
945pub struct ActivityTraceStartResponse {
946    pub message_header: HeaderHostResponse,
947    pub activity_id: Guid,
948}
949
950const_assert_eq!(20, size_of::<ActivityTraceStartResponse>());
951
952#[repr(C)]
953#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
954pub struct ActivityTraceOpRequest {
955    pub message_header: HeaderHostRequest,
956    pub activity_class: ActivityClassId,
957    pub activity_id: Guid,
958    pub related_activity_id: Guid,
959    pub op_code: ActivityOpCode,
960    pub size: u32, // Size of payload
961                   // Variable size payload follows, maximum TRACE_MSG_MAX_SIZE_WCHAR
962}
963
964const_assert_eq!(48, size_of::<ActivityTraceOpRequest>());
965
966#[repr(C)]
967#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
968pub struct ActivityTraceOpResponse {
969    pub message_header: HeaderHostResponse,
970}
971
972const_assert_eq!(4, size_of::<ActivityTraceOpResponse>());
973
974#[repr(C)]
975#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
976pub struct EventTraceRequest {
977    pub message_header: HeaderHostRequest,
978    pub event: EventId,
979    pub size: u32, // Size of payload
980                   // Variable size payload follows, maximum TRACE_MSG_MAX_SIZE WCHAR
981}
982
983const_assert_eq!(12, size_of::<EventTraceRequest>());
984
985#[repr(C)]
986#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
987pub struct EventTraceResponse {
988    pub message_header: HeaderHostResponse,
989}
990
991const_assert_eq!(4, size_of::<EventTraceResponse>());
992
993open_enum! {
994    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
995    pub enum SecureBootTemplateType: u32 {
996        SECURE_BOOT_DISABLED = 0,
997        MICROSOFT_WINDOWS = 1,
998        MICROSOFT_UEFI_CERTIFICATE_AUTHORITY = 2,
999        OPEN_SOURCE_SHIELDED_VM = 3,
1000    }
1001}
1002
1003open_enum! {
1004    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1005    pub enum UefiConsoleMode: u8 {
1006        DEFAULT = 0,
1007        COM1 = 1,
1008        COM2 = 2,
1009        NONE = 3,
1010    }
1011}
1012
1013pub const HCL_DEVICE_PLATFORM_MAX_SMBIOS_LENGTH: usize = 64;
1014
1015#[repr(C)]
1016#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1017pub struct DevicePlatformSettingsRequestV2 {
1018    pub message_header: HeaderHostRequest,
1019}
1020
1021impl DevicePlatformSettingsRequestV2 {
1022    pub fn new() -> Self {
1023        Self {
1024            message_header: HeaderGeneric::new(HostRequests::DEVICE_PLATFORM_SETTINGS_V2),
1025        }
1026    }
1027}
1028
1029const_assert_eq!(4, size_of::<DevicePlatformSettingsRequestV2>());
1030
1031/// This represents a boolean value sent over the protocol as a u8. The only
1032/// valid values are 0 or 1.
1033#[repr(transparent)]
1034#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1035pub struct ProtocolBool(pub u8);
1036
1037impl From<bool> for ProtocolBool {
1038    fn from(value: bool) -> Self {
1039        ProtocolBool(if value { 1 } else { 0 })
1040    }
1041}
1042
1043#[repr(C)]
1044#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1045pub struct DevicePlatformSettingsResponseV2 {
1046    pub message_header: HeaderHostResponse,
1047
1048    pub size: u32,
1049    // variable length JSON payload
1050}
1051
1052#[repr(C)]
1053#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1054pub struct DevicePlatformSettingsResponseV2Rev1 {
1055    pub message_header: HeaderHostResponse,
1056
1057    pub size: u32,
1058
1059    pub payload_state: LargePayloadState,
1060    // variable length JSON payload
1061}
1062
1063pub const GSP_CLEARTEXT_MAX: u32 = 32;
1064pub const GSP_CIPHERTEXT_MAX: u32 = 512;
1065pub const NUMBER_GSP: u32 = 2;
1066
1067#[bitfield(u32)]
1068#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
1069pub struct GspExtendedStatusFlags {
1070    pub state_refresh_request: bool,
1071    pub no_registry_file: bool,
1072    pub no_rpc_server: bool,
1073    pub allow_ak_cert_renewal: bool,
1074    pub requires_rpc_server: bool,
1075
1076    #[bits(27)]
1077    _reserved: u32,
1078}
1079
1080#[repr(C)]
1081#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1082pub struct GspCleartextContent {
1083    pub length: u32,
1084    pub buffer: [u8; GSP_CLEARTEXT_MAX as usize * 2],
1085}
1086
1087const_assert_eq!(68, size_of::<GspCleartextContent>());
1088
1089#[repr(C)]
1090#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1091pub struct GspCiphertextContent {
1092    pub length: u32,
1093    pub buffer: [u8; GSP_CIPHERTEXT_MAX as usize],
1094}
1095
1096const_assert_eq!(516, size_of::<GspCiphertextContent>());
1097
1098/// This can only be used in PROTOCOL_VERSION_RS5
1099#[repr(C)]
1100#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1101pub struct GuestStateProtectionByIdRequest {
1102    pub message_header: HeaderHostRequest,
1103}
1104
1105const_assert_eq!(4, size_of::<GuestStateProtectionByIdRequest>());
1106
1107impl GuestStateProtectionByIdRequest {
1108    pub fn new() -> Self {
1109        Self {
1110            message_header: HeaderGeneric::new(HostRequests::GUEST_STATE_PROTECTION_BY_ID),
1111        }
1112    }
1113}
1114
1115#[repr(C)]
1116#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1117pub struct GuestStateProtectionByIdResponse {
1118    pub message_header: HeaderHostResponse,
1119    pub seed: GspCleartextContent,
1120    pub extended_status_flags: GspExtendedStatusFlags,
1121}
1122
1123const_assert_eq!(76, size_of::<GuestStateProtectionByIdResponse>());
1124
1125#[repr(C)]
1126#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1127pub struct GuestStateProtectionRequest {
1128    pub message_header: HeaderHostRequest,
1129    pub new_gsp: GspCleartextContent,
1130    pub encrypted_gsp: [GspCiphertextContent; NUMBER_GSP as usize],
1131    pub extended_status_support_flags: GspExtendedStatusFlags,
1132}
1133
1134const_assert_eq!(1108, size_of::<GuestStateProtectionRequest>());
1135
1136impl GuestStateProtectionRequest {
1137    pub fn new(
1138        buffer: [u8; GSP_CLEARTEXT_MAX as usize * 2],
1139        encrypted_gsp: [GspCiphertextContent; NUMBER_GSP as usize],
1140        extended_status_support_flags: GspExtendedStatusFlags,
1141    ) -> Self {
1142        Self {
1143            message_header: HeaderGeneric::new(HostRequests::GUEST_STATE_PROTECTION),
1144            new_gsp: GspCleartextContent {
1145                length: GSP_CLEARTEXT_MAX,
1146                buffer,
1147            },
1148            encrypted_gsp,
1149            extended_status_support_flags,
1150        }
1151    }
1152}
1153
1154#[repr(C)]
1155#[derive(Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1156pub struct GuestStateProtectionResponse {
1157    pub message_header: HeaderHostResponse,
1158    pub encrypted_gsp: GspCiphertextContent,
1159    pub decrypted_gsp: [GspCleartextContent; NUMBER_GSP as usize],
1160    pub extended_status_flags: GspExtendedStatusFlags,
1161}
1162
1163const_assert_eq!(660, size_of::<GuestStateProtectionResponse>());
1164
1165#[repr(C)]
1166#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1167pub struct UpdateGenerationId {
1168    pub message_header: HeaderGuestNotification,
1169    pub _pad: u32,
1170    pub generation_id: [u8; 16],
1171}
1172
1173const_assert_eq!(24, size_of::<UpdateGenerationId>());
1174
1175impl UpdateGenerationId {
1176    pub fn new(generation_id: [u8; 16]) -> Self {
1177        Self {
1178            message_header: HeaderGeneric::new(GuestNotifications::UPDATE_GENERATION_ID),
1179            _pad: 0,
1180            generation_id,
1181        }
1182    }
1183}
1184
1185/// Bitfield describing SaveGuestVtl2StateNotification::capabilities_flags
1186#[bitfield(u64)]
1187#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1188pub struct SaveGuestVtl2StateFlags {
1189    /// Explicitly allow nvme_keepalive feature when servicing.
1190    #[bits(1)]
1191    pub enable_nvme_keepalive: bool,
1192
1193    /// Explicitly allow mana_keepalive feature when servicing.
1194    #[bits(1)]
1195    pub enable_mana_keepalive: bool,
1196
1197    /// Reserved, must be zero.
1198    #[bits(62)]
1199    _rsvd1: u64,
1200}
1201
1202#[repr(C, packed)]
1203#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1204pub struct SaveGuestVtl2StateNotification {
1205    pub message_header: HeaderGuestNotification,
1206    pub correlation_id: Guid,
1207    pub capabilities_flags: SaveGuestVtl2StateFlags,
1208    pub timeout_hint_secs: u16,
1209}
1210
1211const_assert_eq!(30, size_of::<SaveGuestVtl2StateNotification>());
1212
1213#[repr(C)]
1214#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1215pub struct SaveGuestVtl2StateRequest {
1216    pub message_header: HeaderHostRequest,
1217    pub save_status: GuestVtl2SaveRestoreStatus,
1218    // Variable-length payload follows
1219}
1220
1221const_assert_eq!(6, size_of::<SaveGuestVtl2StateRequest>());
1222
1223impl SaveGuestVtl2StateRequest {
1224    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1225        Self {
1226            message_header: HeaderGeneric::new(HostRequests::SAVE_GUEST_VTL2_STATE),
1227            save_status: status,
1228        }
1229    }
1230}
1231
1232#[repr(C)]
1233#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1234pub struct SaveGuestVtl2StateResponse {
1235    pub message_header: HeaderHostResponse,
1236    pub save_status: GuestVtl2SaveRestoreStatus,
1237}
1238
1239const_assert_eq!(6, size_of::<SaveGuestVtl2StateResponse>());
1240
1241impl SaveGuestVtl2StateResponse {
1242    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1243        Self {
1244            message_header: HeaderGeneric::new(HostRequests::SAVE_GUEST_VTL2_STATE),
1245            save_status: status,
1246        }
1247    }
1248}
1249
1250#[repr(C)]
1251#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1252pub struct RestoreGuestVtl2StateHostNotification {
1253    pub message_header: HeaderHostNotification,
1254    pub status: GuestVtl2SaveRestoreStatus,
1255}
1256
1257const_assert_eq!(6, size_of::<RestoreGuestVtl2StateHostNotification>());
1258
1259impl RestoreGuestVtl2StateHostNotification {
1260    pub fn new(stat: GuestVtl2SaveRestoreStatus) -> Self {
1261        Self {
1262            message_header: HeaderGeneric::new(
1263                HostNotifications::RESTORE_GUEST_VTL2_STATE_COMPLETED,
1264            ),
1265            status: stat,
1266        }
1267    }
1268}
1269
1270#[repr(C)]
1271#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1272pub struct RestoreGuestVtl2StateRequest {
1273    pub message_header: HeaderHostRequest,
1274    pub restore_status: GuestVtl2SaveRestoreStatus,
1275}
1276
1277const_assert_eq!(6, size_of::<RestoreGuestVtl2StateRequest>());
1278
1279impl RestoreGuestVtl2StateRequest {
1280    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1281        Self {
1282            message_header: HeaderGeneric::new(HostRequests::RESTORE_GUEST_VTL2_STATE),
1283            restore_status: status,
1284        }
1285    }
1286}
1287
1288#[repr(C, packed)]
1289#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1290pub struct RestoreGuestVtl2StateResponse {
1291    pub message_header: HeaderHostResponse,
1292    pub data_length: u32,
1293    pub restore_status: GuestVtl2SaveRestoreStatus,
1294    // Variable-length payload follows
1295}
1296
1297const_assert_eq!(10, size_of::<RestoreGuestVtl2StateResponse>());
1298
1299impl RestoreGuestVtl2StateResponse {
1300    pub fn new(length: u32, status: GuestVtl2SaveRestoreStatus) -> Self {
1301        Self {
1302            message_header: HeaderGeneric::new(HostRequests::RESTORE_GUEST_VTL2_STATE),
1303            data_length: length,
1304            restore_status: status,
1305        }
1306    }
1307}
1308
1309open_enum! {
1310    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1311    pub enum VpciDeviceControlCode: u32 {
1312        UNDEFINED = 0,
1313        OFFER = 1,
1314        REVOKE = 2,
1315        RESET = 3,
1316    }
1317}
1318
1319open_enum! {
1320    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1321    pub enum VpciDeviceControlStatus: u32 {
1322        SUCCESS = 0,
1323        INVALID_REQUEST = 1,
1324        DEVICE_NOT_FOUND = 2,
1325        INVALID_DEVICE_STATE = 3,
1326        GENERIC_FAILURE = 4,
1327    }
1328}
1329
1330#[repr(C)]
1331#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1332pub struct VpciDeviceControlRequest {
1333    pub message_header: HeaderHostRequest,
1334    pub code: VpciDeviceControlCode,
1335    pub bus_instance_id: Guid,
1336}
1337
1338const_assert_eq!(24, size_of::<VpciDeviceControlRequest>());
1339
1340impl VpciDeviceControlRequest {
1341    pub fn new(code: VpciDeviceControlCode, bus_instance_id: Guid) -> Self {
1342        Self {
1343            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_CONTROL),
1344            code,
1345            bus_instance_id,
1346        }
1347    }
1348}
1349
1350#[repr(C)]
1351#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1352pub struct VpciDeviceControlResponse {
1353    pub message_header: HeaderHostResponse,
1354    pub status: VpciDeviceControlStatus,
1355}
1356
1357const_assert_eq!(8, size_of::<VpciDeviceControlResponse>());
1358
1359impl VpciDeviceControlResponse {
1360    pub fn new(status: VpciDeviceControlStatus) -> Self {
1361        Self {
1362            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_CONTROL),
1363            status,
1364        }
1365    }
1366}
1367
1368open_enum! {
1369    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1370    pub enum VpciDeviceNotificationCode : u32 {
1371        UNDEFINED = 0,
1372        ENUMERATED = 1,
1373        PREPARE_FOR_REMOVAL = 2,
1374    }
1375}
1376
1377#[repr(C)]
1378#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1379pub struct VpciDeviceNotification {
1380    pub message_header: HeaderGuestNotification,
1381    pub bus_instance_id: Guid,
1382    pub code: VpciDeviceNotificationCode,
1383}
1384
1385const_assert_eq!(24, size_of::<VpciDeviceNotification>());
1386
1387#[repr(C, packed)]
1388#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1389pub struct VpciDeviceBindingChangeRequest {
1390    pub message_header: HeaderHostRequest,
1391    pub bus_instance_id: [u8; 16], // Guid
1392    pub binding_state: u8,
1393}
1394
1395const_assert_eq!(21, size_of::<VpciDeviceBindingChangeRequest>());
1396
1397impl VpciDeviceBindingChangeRequest {
1398    pub fn new(bus_instance_id: Guid, binding_state: bool) -> Self {
1399        let mut guid: [u8; 16] = [0; 16];
1400        guid.copy_from_slice(bus_instance_id.as_bytes());
1401        Self {
1402            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_BINDING_CHANGE),
1403            bus_instance_id: guid,
1404            binding_state: binding_state as u8,
1405        }
1406    }
1407}
1408
1409#[repr(C)]
1410#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1411pub struct VpciDeviceBindingChangeResponse {
1412    pub message_header: HeaderHostResponse,
1413    pub bus_instance_id: Guid,
1414    pub status: VpciDeviceControlStatus,
1415}
1416
1417const_assert_eq!(24, size_of::<VpciDeviceBindingChangeResponse>());
1418
1419impl VpciDeviceBindingChangeResponse {
1420    pub fn new(bus_instance_id: Guid, status: VpciDeviceControlStatus) -> Self {
1421        Self {
1422            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_BINDING_CHANGE),
1423            bus_instance_id,
1424            status,
1425        }
1426    }
1427}
1428
1429#[repr(C, packed)]
1430#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1431pub struct VgaProxyPciReadRequest {
1432    pub message_header: HeaderHostRequest,
1433    pub offset: u16,
1434}
1435
1436const_assert_eq!(6, size_of::<VgaProxyPciReadRequest>());
1437
1438impl VgaProxyPciReadRequest {
1439    pub fn new(offset: u16) -> Self {
1440        Self {
1441            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_READ),
1442            offset,
1443        }
1444    }
1445}
1446
1447#[repr(C)]
1448#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1449pub struct VgaProxyPciReadResponse {
1450    pub message_header: HeaderHostResponse,
1451    pub value: u32,
1452}
1453
1454const_assert_eq!(8, size_of::<VgaProxyPciReadResponse>());
1455
1456impl VgaProxyPciReadResponse {
1457    pub fn new(value: u32) -> Self {
1458        Self {
1459            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_READ),
1460            value,
1461        }
1462    }
1463}
1464
1465#[repr(C, packed)]
1466#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1467pub struct VgaProxyPciWriteRequest {
1468    pub message_header: HeaderHostRequest,
1469    pub value: u32,
1470    pub offset: u16,
1471}
1472
1473const_assert_eq!(10, size_of::<VgaProxyPciWriteRequest>());
1474
1475impl VgaProxyPciWriteRequest {
1476    pub fn new(offset: u16, value: u32) -> Self {
1477        Self {
1478            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_WRITE),
1479            offset,
1480            value,
1481        }
1482    }
1483}
1484
1485#[repr(C)]
1486#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1487pub struct VgaProxyPciWriteResponse {
1488    pub message_header: HeaderHostResponse,
1489}
1490
1491const_assert_eq!(4, size_of::<VgaProxyPciWriteResponse>());
1492
1493impl VgaProxyPciWriteResponse {
1494    pub fn new() -> Self {
1495        Self {
1496            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_WRITE),
1497        }
1498    }
1499}
1500
1501open_enum! {
1502    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1503    pub enum ModifyVtl2SettingsStatus : u32 {
1504        SUCCESS = 0,
1505        FAILURE = 1,
1506    }
1507}
1508
1509#[repr(C)]
1510#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1511pub struct ModifyVtl2SettingsNotification {
1512    pub message_header: HeaderGuestNotification,
1513
1514    pub size: u32,
1515    // variable length JSON payload
1516}
1517
1518const_assert_eq!(8, size_of::<ModifyVtl2SettingsNotification>());
1519
1520#[repr(C)]
1521#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1522pub struct ModifyVtl2SettingsRev1Notification {
1523    pub message_header: HeaderGuestNotification,
1524
1525    pub size: u32,
1526
1527    pub payload_state: LargePayloadState,
1528    // variable length JSON payload
1529}
1530
1531const_assert_eq!(12, size_of::<ModifyVtl2SettingsRev1Notification>());
1532
1533#[repr(C, packed)]
1534#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1535pub struct ModifyVtl2SettingsCompleteNotification {
1536    pub message_header: HeaderHostNotification,
1537    pub modify_status: ModifyVtl2SettingsStatus,
1538    pub result_document_size: u32,
1539}
1540
1541const_assert_eq!(12, size_of::<ModifyVtl2SettingsCompleteNotification>());
1542
1543impl ModifyVtl2SettingsCompleteNotification {
1544    pub fn new(status: ModifyVtl2SettingsStatus, result_document_size: u32) -> Self {
1545        Self {
1546            message_header: HeaderGeneric::new(HostNotifications::MODIFY_VTL2_SETTINGS_COMPLETED),
1547            modify_status: status,
1548            result_document_size,
1549        }
1550    }
1551}
1552
1553pub const GET_LOG_INTERFACE_GUID: Guid = guid::guid!("AA5DE534-D149-487A-9053-05972BA20A7C");
1554
1555open_enum! {
1556    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1557    pub enum LogType: u8 {
1558        EVENT = 0,
1559        SPAN_ENTER = 1,
1560        SPAN_EXIT = 2,
1561    }
1562}
1563
1564#[bitfield(u16)]
1565#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1566pub struct LogFlags {
1567    pub kmsg: bool,
1568    #[bits(15)]
1569    pub mbz0: u16,
1570}
1571
1572pub const TRACE_LOGGING_NAME_MAX_SIZE: usize = 128;
1573pub const TRACE_LOGGING_TARGET_MAX_SIZE: usize = 128;
1574pub const TRACE_LOGGING_FIELDS_MAX_SIZE: usize = 256;
1575pub const TRACE_LOGGING_MESSAGE_MAX_SIZE: usize = 4096;
1576pub const TRACE_LOGGING_NOTIFICATION_MAX_SIZE: usize = TRACE_LOGGING_NAME_MAX_SIZE
1577    + TRACE_LOGGING_TARGET_MAX_SIZE
1578    + TRACE_LOGGING_FIELDS_MAX_SIZE
1579    + TRACE_LOGGING_MESSAGE_MAX_SIZE
1580    + size_of::<TraceLoggingNotificationHeader>();
1581
1582#[repr(C)]
1583#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1584pub struct TraceLoggingBufferOffset {
1585    pub size: u16,
1586    pub offset: u16,
1587}
1588
1589// The header is followed by a buffer which holds the string fields.
1590//
1591//  ---------------------------------------------------------
1592//  |  Header | Buffer [ name | target | fields | message ] |
1593//  ---------------------------------------------------------
1594#[repr(C)]
1595#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1596pub struct TraceLoggingNotificationHeader {
1597    pub log_type: LogType,
1598    pub level: u8,
1599    pub flags: LogFlags,
1600    pub name: TraceLoggingBufferOffset,
1601    pub target: TraceLoggingBufferOffset,
1602    pub fields: TraceLoggingBufferOffset,
1603    pub message: TraceLoggingBufferOffset,
1604    pub mbz0: u32,
1605    pub activity_id: Guid,
1606    pub related_activity_id: Guid,
1607    pub correlation_id: Guid,
1608    pub timestamp: u64,
1609}
1610const_assert_eq!(80, size_of::<TraceLoggingNotificationHeader>());
1611
1612/// MAP_FRAMEBUFFER_REQUEST
1613#[repr(C, packed)]
1614#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1615pub struct MapFramebufferRequest {
1616    pub message_header: HeaderHostRequest,
1617    pub gpa: u64,
1618}
1619
1620const_assert_eq!(12, size_of::<MapFramebufferRequest>());
1621
1622impl MapFramebufferRequest {
1623    pub fn new(gpa: u64) -> Self {
1624        Self {
1625            message_header: HeaderGeneric::new(HostRequests::MAP_FRAMEBUFFER),
1626            gpa,
1627        }
1628    }
1629}
1630
1631open_enum! {
1632    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1633    pub enum MapFramebufferStatus : u32 {
1634        SUCCESS = 0,
1635        FAILURE = 1,
1636    }
1637}
1638
1639/// MAP_FRAMEBUFFER_RESPONSE
1640#[repr(C, packed)]
1641#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1642pub struct MapFramebufferResponse {
1643    pub message_header: HeaderHostResponse,
1644    pub status: MapFramebufferStatus,
1645}
1646
1647const_assert_eq!(8, size_of::<MapFramebufferResponse>());
1648
1649impl MapFramebufferResponse {
1650    pub fn new(status: MapFramebufferStatus) -> Self {
1651        Self {
1652            message_header: HeaderGeneric::new(HostRequests::MAP_FRAMEBUFFER),
1653            status,
1654        }
1655    }
1656}
1657
1658/// UNMAP_FRAMEBUFFER
1659#[repr(C, packed)]
1660#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1661pub struct UnmapFramebufferRequest {
1662    pub message_header: HeaderHostRequest,
1663}
1664
1665const_assert_eq!(4, size_of::<UnmapFramebufferRequest>());
1666
1667impl UnmapFramebufferRequest {
1668    pub fn new() -> Self {
1669        Self {
1670            message_header: HeaderGeneric::new(HostRequests::UNMAP_FRAMEBUFFER),
1671        }
1672    }
1673}
1674
1675open_enum! {
1676    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1677    pub enum UnmapFramebufferStatus : u32 {
1678        SUCCESS = 0,
1679        FAILURE = 1,
1680    }
1681}
1682
1683/// UNMAP_FRAMEBUFFER_RESPONSE
1684#[repr(C, packed)]
1685#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1686pub struct UnmapFramebufferResponse {
1687    pub message_header: HeaderHostResponse,
1688    pub status: UnmapFramebufferStatus,
1689}
1690
1691const_assert_eq!(8, size_of::<UnmapFramebufferResponse>());
1692
1693impl UnmapFramebufferResponse {
1694    pub fn new(status: UnmapFramebufferStatus) -> Self {
1695        Self {
1696            message_header: HeaderGeneric::new(HostRequests::UNMAP_FRAMEBUFFER),
1697            status,
1698        }
1699    }
1700}
1701
1702open_enum! {
1703    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1704    pub enum StartVtl0Status : u32 {
1705        SUCCESS = 0,
1706        FAILURE = 1,
1707    }
1708}
1709
1710#[repr(C, packed)]
1711#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1712pub struct StartVtl0CompleteNotification {
1713    pub message_header: HeaderHostNotification,
1714    pub status: StartVtl0Status,
1715    pub result_document_size: u32,
1716    // result_document is a variable size raw string because the Error is anyhow::Error
1717    // TODO: use specific Errors for "start VM"
1718}
1719
1720const_assert_eq!(12, size_of::<StartVtl0CompleteNotification>());
1721
1722impl StartVtl0CompleteNotification {
1723    pub fn new(status: StartVtl0Status, result_document_size: u32) -> Self {
1724        Self {
1725            message_header: HeaderGeneric::new(HostNotifications::START_VTL0_COMPLETED),
1726            status,
1727            result_document_size,
1728        }
1729    }
1730}
1731
1732#[repr(C)]
1733#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1734pub struct BatteryStatusNotification {
1735    pub message_header: HeaderGuestNotification,
1736    pub flags: BatteryStatusFlags,
1737    pub max_capacity: u32,
1738    pub remaining_capacity: u32,
1739    pub rate: u32,
1740}
1741
1742#[bitfield(u32)]
1743#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1744pub struct BatteryStatusFlags {
1745    pub ac_online: bool,
1746    pub battery_present: bool,
1747    pub charging: bool,
1748    pub discharging: bool,
1749    #[bits(28)]
1750    pub reserved: u32,
1751}
1752
1753impl BatteryStatusNotification {
1754    pub fn new(
1755        flags: BatteryStatusFlags,
1756        max_capacity: u32,
1757        remaining_capacity: u32,
1758        rate: u32,
1759    ) -> Self {
1760        Self {
1761            message_header: HeaderGeneric::new(GuestNotifications::BATTERY_STATUS),
1762            flags,
1763            max_capacity,
1764            remaining_capacity,
1765            rate,
1766        }
1767    }
1768}
1769
1770#[repr(C)]
1771#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1772pub struct InjectDebugInterruptNotification {
1773    pub message_header: HeaderGuestNotification,
1774    pub vtl: u8,
1775    pub _pad: u8,
1776}
1777const_assert_eq!(6, size_of::<InjectDebugInterruptNotification>());
1778
1779#[repr(C)]
1780#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1781pub struct PostLiveMigrationNotification {
1782    pub message_header: HeaderGuestNotification,
1783}
1784const_assert_eq!(4, size_of::<PostLiveMigrationNotification>());
1785
1786#[bitfield(u64)]
1787#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1788pub struct CreateRamGpaRangeFlags {
1789    _reserved1: bool,
1790
1791    /// Writes are discarded
1792    pub rom_mb: bool,
1793
1794    #[bits(62)]
1795    _reserved: u64,
1796}
1797
1798#[repr(C, packed)]
1799#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1800pub struct CreateRamGpaRangeRequest {
1801    pub message_header: HeaderHostRequest,
1802    pub slot: u32,
1803    pub gpa_start: u64,
1804    pub gpa_count: u64,
1805    pub gpa_offset: u64,
1806    pub flags: CreateRamGpaRangeFlags,
1807}
1808
1809const_assert_eq!(40, size_of::<CreateRamGpaRangeRequest>());
1810
1811impl CreateRamGpaRangeRequest {
1812    pub fn new(
1813        slot: u32,
1814        gpa_start: u64,
1815        gpa_count: u64,
1816        gpa_offset: u64,
1817        flags: CreateRamGpaRangeFlags,
1818    ) -> Self {
1819        Self {
1820            message_header: HeaderGeneric::new(HostRequests::CREATE_RAM_GPA_RANGE),
1821            slot,
1822            gpa_start,
1823            gpa_count,
1824            gpa_offset,
1825            flags,
1826        }
1827    }
1828}
1829
1830open_enum! {
1831    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1832    pub enum CreateRamGpaRangeStatus : u32 {
1833        SUCCESS = 0,
1834        /// slot index out of bounds
1835        SLOT_OUT_OF_BOUNDS = 1,
1836        /// slot is already occupied. needs to be reset first
1837        SLOT_OCCUPIED = 2,
1838        /// invalid flag
1839        INVALID_FLAG = 3,
1840        /// invalid GPA
1841        INVALID_GPA = 4,
1842        /// call to CreateRamGpaRange failed
1843        FAILED = 5,
1844    }
1845}
1846
1847#[repr(C)]
1848#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1849pub struct CreateRamGpaRangeResponse {
1850    pub message_header: HeaderHostResponse,
1851    pub status: CreateRamGpaRangeStatus,
1852}
1853
1854const_assert_eq!(8, size_of::<CreateRamGpaRangeResponse>());
1855
1856impl CreateRamGpaRangeResponse {
1857    pub fn new(status: CreateRamGpaRangeStatus) -> Self {
1858        Self {
1859            message_header: HeaderGeneric::new(HostRequests::CREATE_RAM_GPA_RANGE),
1860            status,
1861        }
1862    }
1863}
1864
1865#[repr(C)]
1866#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1867pub struct ResetRamGpaRangeRequest {
1868    pub message_header: HeaderHostRequest,
1869    pub slot: u32,
1870}
1871
1872const_assert_eq!(8, size_of::<ResetRamGpaRangeRequest>());
1873
1874impl ResetRamGpaRangeRequest {
1875    pub fn new(slot: u32) -> Self {
1876        Self {
1877            message_header: HeaderGeneric::new(HostRequests::RESET_RAM_GPA_RANGE),
1878            slot,
1879        }
1880    }
1881}
1882
1883#[repr(C)]
1884#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1885pub struct ResetRamGpaRangeResponse {
1886    pub message_header: HeaderHostResponse,
1887}
1888
1889const_assert_eq!(4, size_of::<ResetRamGpaRangeResponse>());
1890
1891impl ResetRamGpaRangeResponse {
1892    pub fn new() -> Self {
1893        Self {
1894            message_header: HeaderGeneric::new(HostRequests::RESET_RAM_GPA_RANGE),
1895        }
1896    }
1897}
1898
1899pub mod test_utilities {
1900    // These constants are shared across GED and GET testing
1901    pub const TEST_VMGS_SECTOR_SIZE: u32 = 512;
1902    pub const TEST_VMGS_CAPACITY: usize = 4194816; // 4 MB
1903}