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