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