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    /// Reserved, must be zero.
1191    #[bits(63)]
1192    _rsvd1: u64,
1193}
1194
1195#[repr(C, packed)]
1196#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1197pub struct SaveGuestVtl2StateNotification {
1198    pub message_header: HeaderGuestNotification,
1199    pub correlation_id: Guid,
1200    pub capabilities_flags: SaveGuestVtl2StateFlags,
1201    pub timeout_hint_secs: u16,
1202}
1203
1204const_assert_eq!(30, size_of::<SaveGuestVtl2StateNotification>());
1205
1206#[repr(C)]
1207#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1208pub struct SaveGuestVtl2StateRequest {
1209    pub message_header: HeaderHostRequest,
1210    pub save_status: GuestVtl2SaveRestoreStatus,
1211    // Variable-length payload follows
1212}
1213
1214const_assert_eq!(6, size_of::<SaveGuestVtl2StateRequest>());
1215
1216impl SaveGuestVtl2StateRequest {
1217    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1218        Self {
1219            message_header: HeaderGeneric::new(HostRequests::SAVE_GUEST_VTL2_STATE),
1220            save_status: status,
1221        }
1222    }
1223}
1224
1225#[repr(C)]
1226#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1227pub struct SaveGuestVtl2StateResponse {
1228    pub message_header: HeaderHostResponse,
1229    pub save_status: GuestVtl2SaveRestoreStatus,
1230}
1231
1232const_assert_eq!(6, size_of::<SaveGuestVtl2StateResponse>());
1233
1234impl SaveGuestVtl2StateResponse {
1235    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1236        Self {
1237            message_header: HeaderGeneric::new(HostRequests::SAVE_GUEST_VTL2_STATE),
1238            save_status: status,
1239        }
1240    }
1241}
1242
1243#[repr(C)]
1244#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1245pub struct RestoreGuestVtl2StateHostNotification {
1246    pub message_header: HeaderHostNotification,
1247    pub status: GuestVtl2SaveRestoreStatus,
1248}
1249
1250const_assert_eq!(6, size_of::<RestoreGuestVtl2StateHostNotification>());
1251
1252impl RestoreGuestVtl2StateHostNotification {
1253    pub fn new(stat: GuestVtl2SaveRestoreStatus) -> Self {
1254        Self {
1255            message_header: HeaderGeneric::new(
1256                HostNotifications::RESTORE_GUEST_VTL2_STATE_COMPLETED,
1257            ),
1258            status: stat,
1259        }
1260    }
1261}
1262
1263#[repr(C)]
1264#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1265pub struct RestoreGuestVtl2StateRequest {
1266    pub message_header: HeaderHostRequest,
1267    pub restore_status: GuestVtl2SaveRestoreStatus,
1268}
1269
1270const_assert_eq!(6, size_of::<RestoreGuestVtl2StateRequest>());
1271
1272impl RestoreGuestVtl2StateRequest {
1273    pub fn new(status: GuestVtl2SaveRestoreStatus) -> Self {
1274        Self {
1275            message_header: HeaderGeneric::new(HostRequests::RESTORE_GUEST_VTL2_STATE),
1276            restore_status: status,
1277        }
1278    }
1279}
1280
1281#[repr(C, packed)]
1282#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1283pub struct RestoreGuestVtl2StateResponse {
1284    pub message_header: HeaderHostResponse,
1285    pub data_length: u32,
1286    pub restore_status: GuestVtl2SaveRestoreStatus,
1287    // Variable-length payload follows
1288}
1289
1290const_assert_eq!(10, size_of::<RestoreGuestVtl2StateResponse>());
1291
1292impl RestoreGuestVtl2StateResponse {
1293    pub fn new(length: u32, status: GuestVtl2SaveRestoreStatus) -> Self {
1294        Self {
1295            message_header: HeaderGeneric::new(HostRequests::RESTORE_GUEST_VTL2_STATE),
1296            data_length: length,
1297            restore_status: status,
1298        }
1299    }
1300}
1301
1302open_enum! {
1303    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1304    pub enum VpciDeviceControlCode: u32 {
1305        UNDEFINED = 0,
1306        OFFER = 1,
1307        REVOKE = 2,
1308        RESET = 3,
1309    }
1310}
1311
1312open_enum! {
1313    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1314    pub enum VpciDeviceControlStatus: u32 {
1315        SUCCESS = 0,
1316        INVALID_REQUEST = 1,
1317        DEVICE_NOT_FOUND = 2,
1318        INVALID_DEVICE_STATE = 3,
1319        GENERIC_FAILURE = 4,
1320    }
1321}
1322
1323#[repr(C)]
1324#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1325pub struct VpciDeviceControlRequest {
1326    pub message_header: HeaderHostRequest,
1327    pub code: VpciDeviceControlCode,
1328    pub bus_instance_id: Guid,
1329}
1330
1331const_assert_eq!(24, size_of::<VpciDeviceControlRequest>());
1332
1333impl VpciDeviceControlRequest {
1334    pub fn new(code: VpciDeviceControlCode, bus_instance_id: Guid) -> Self {
1335        Self {
1336            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_CONTROL),
1337            code,
1338            bus_instance_id,
1339        }
1340    }
1341}
1342
1343#[repr(C)]
1344#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1345pub struct VpciDeviceControlResponse {
1346    pub message_header: HeaderHostResponse,
1347    pub status: VpciDeviceControlStatus,
1348}
1349
1350const_assert_eq!(8, size_of::<VpciDeviceControlResponse>());
1351
1352impl VpciDeviceControlResponse {
1353    pub fn new(status: VpciDeviceControlStatus) -> Self {
1354        Self {
1355            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_CONTROL),
1356            status,
1357        }
1358    }
1359}
1360
1361open_enum! {
1362    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1363    pub enum VpciDeviceNotificationCode : u32 {
1364        UNDEFINED = 0,
1365        ENUMERATED = 1,
1366        PREPARE_FOR_REMOVAL = 2,
1367    }
1368}
1369
1370#[repr(C)]
1371#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1372pub struct VpciDeviceNotification {
1373    pub message_header: HeaderGuestNotification,
1374    pub bus_instance_id: Guid,
1375    pub code: VpciDeviceNotificationCode,
1376}
1377
1378const_assert_eq!(24, size_of::<VpciDeviceNotification>());
1379
1380#[repr(C, packed)]
1381#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1382pub struct VpciDeviceBindingChangeRequest {
1383    pub message_header: HeaderHostRequest,
1384    pub bus_instance_id: [u8; 16], // Guid
1385    pub binding_state: u8,
1386}
1387
1388const_assert_eq!(21, size_of::<VpciDeviceBindingChangeRequest>());
1389
1390impl VpciDeviceBindingChangeRequest {
1391    pub fn new(bus_instance_id: Guid, binding_state: bool) -> Self {
1392        let mut guid: [u8; 16] = [0; 16];
1393        guid.copy_from_slice(bus_instance_id.as_bytes());
1394        Self {
1395            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_BINDING_CHANGE),
1396            bus_instance_id: guid,
1397            binding_state: binding_state as u8,
1398        }
1399    }
1400}
1401
1402#[repr(C)]
1403#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1404pub struct VpciDeviceBindingChangeResponse {
1405    pub message_header: HeaderHostResponse,
1406    pub bus_instance_id: Guid,
1407    pub status: VpciDeviceControlStatus,
1408}
1409
1410const_assert_eq!(24, size_of::<VpciDeviceBindingChangeResponse>());
1411
1412impl VpciDeviceBindingChangeResponse {
1413    pub fn new(bus_instance_id: Guid, status: VpciDeviceControlStatus) -> Self {
1414        Self {
1415            message_header: HeaderGeneric::new(HostRequests::VPCI_DEVICE_BINDING_CHANGE),
1416            bus_instance_id,
1417            status,
1418        }
1419    }
1420}
1421
1422#[repr(C, packed)]
1423#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1424pub struct VgaProxyPciReadRequest {
1425    pub message_header: HeaderHostRequest,
1426    pub offset: u16,
1427}
1428
1429const_assert_eq!(6, size_of::<VgaProxyPciReadRequest>());
1430
1431impl VgaProxyPciReadRequest {
1432    pub fn new(offset: u16) -> Self {
1433        Self {
1434            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_READ),
1435            offset,
1436        }
1437    }
1438}
1439
1440#[repr(C)]
1441#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1442pub struct VgaProxyPciReadResponse {
1443    pub message_header: HeaderHostResponse,
1444    pub value: u32,
1445}
1446
1447const_assert_eq!(8, size_of::<VgaProxyPciReadResponse>());
1448
1449impl VgaProxyPciReadResponse {
1450    pub fn new(value: u32) -> Self {
1451        Self {
1452            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_READ),
1453            value,
1454        }
1455    }
1456}
1457
1458#[repr(C, packed)]
1459#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1460pub struct VgaProxyPciWriteRequest {
1461    pub message_header: HeaderHostRequest,
1462    pub value: u32,
1463    pub offset: u16,
1464}
1465
1466const_assert_eq!(10, size_of::<VgaProxyPciWriteRequest>());
1467
1468impl VgaProxyPciWriteRequest {
1469    pub fn new(offset: u16, value: u32) -> Self {
1470        Self {
1471            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_WRITE),
1472            offset,
1473            value,
1474        }
1475    }
1476}
1477
1478#[repr(C)]
1479#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1480pub struct VgaProxyPciWriteResponse {
1481    pub message_header: HeaderHostResponse,
1482}
1483
1484const_assert_eq!(4, size_of::<VgaProxyPciWriteResponse>());
1485
1486impl VgaProxyPciWriteResponse {
1487    pub fn new() -> Self {
1488        Self {
1489            message_header: HeaderGeneric::new(HostRequests::VGA_PROXY_PCI_WRITE),
1490        }
1491    }
1492}
1493
1494open_enum! {
1495    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1496    pub enum ModifyVtl2SettingsStatus : u32 {
1497        SUCCESS = 0,
1498        FAILURE = 1,
1499    }
1500}
1501
1502#[repr(C)]
1503#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1504pub struct ModifyVtl2SettingsNotification {
1505    pub message_header: HeaderGuestNotification,
1506
1507    pub size: u32,
1508    // variable length JSON payload
1509}
1510
1511const_assert_eq!(8, size_of::<ModifyVtl2SettingsNotification>());
1512
1513#[repr(C)]
1514#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1515pub struct ModifyVtl2SettingsRev1Notification {
1516    pub message_header: HeaderGuestNotification,
1517
1518    pub size: u32,
1519
1520    pub payload_state: LargePayloadState,
1521    // variable length JSON payload
1522}
1523
1524const_assert_eq!(12, size_of::<ModifyVtl2SettingsRev1Notification>());
1525
1526#[repr(C, packed)]
1527#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1528pub struct ModifyVtl2SettingsCompleteNotification {
1529    pub message_header: HeaderHostNotification,
1530    pub modify_status: ModifyVtl2SettingsStatus,
1531    pub result_document_size: u32,
1532}
1533
1534const_assert_eq!(12, size_of::<ModifyVtl2SettingsCompleteNotification>());
1535
1536impl ModifyVtl2SettingsCompleteNotification {
1537    pub fn new(status: ModifyVtl2SettingsStatus, result_document_size: u32) -> Self {
1538        Self {
1539            message_header: HeaderGeneric::new(HostNotifications::MODIFY_VTL2_SETTINGS_COMPLETED),
1540            modify_status: status,
1541            result_document_size,
1542        }
1543    }
1544}
1545
1546pub const GET_LOG_INTERFACE_GUID: Guid = guid::guid!("AA5DE534-D149-487A-9053-05972BA20A7C");
1547
1548open_enum! {
1549    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1550    pub enum LogType: u8 {
1551        EVENT = 0,
1552        SPAN_ENTER = 1,
1553        SPAN_EXIT = 2,
1554    }
1555}
1556
1557#[bitfield(u16)]
1558#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1559pub struct LogFlags {
1560    pub kmsg: bool,
1561    #[bits(15)]
1562    pub mbz0: u16,
1563}
1564
1565pub const TRACE_LOGGING_NAME_MAX_SIZE: usize = 128;
1566pub const TRACE_LOGGING_TARGET_MAX_SIZE: usize = 128;
1567pub const TRACE_LOGGING_FIELDS_MAX_SIZE: usize = 256;
1568pub const TRACE_LOGGING_MESSAGE_MAX_SIZE: usize = 4096;
1569pub const TRACE_LOGGING_NOTIFICATION_MAX_SIZE: usize = TRACE_LOGGING_NAME_MAX_SIZE
1570    + TRACE_LOGGING_TARGET_MAX_SIZE
1571    + TRACE_LOGGING_FIELDS_MAX_SIZE
1572    + TRACE_LOGGING_MESSAGE_MAX_SIZE
1573    + size_of::<TraceLoggingNotificationHeader>();
1574
1575#[repr(C)]
1576#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1577pub struct TraceLoggingBufferOffset {
1578    pub size: u16,
1579    pub offset: u16,
1580}
1581
1582// The header is followed by a buffer which holds the string fields.
1583//
1584//  ---------------------------------------------------------
1585//  |  Header | Buffer [ name | target | fields | message ] |
1586//  ---------------------------------------------------------
1587#[repr(C)]
1588#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1589pub struct TraceLoggingNotificationHeader {
1590    pub log_type: LogType,
1591    pub level: u8,
1592    pub flags: LogFlags,
1593    pub name: TraceLoggingBufferOffset,
1594    pub target: TraceLoggingBufferOffset,
1595    pub fields: TraceLoggingBufferOffset,
1596    pub message: TraceLoggingBufferOffset,
1597    pub mbz0: u32,
1598    pub activity_id: Guid,
1599    pub related_activity_id: Guid,
1600    pub correlation_id: Guid,
1601    pub timestamp: u64,
1602}
1603const_assert_eq!(80, size_of::<TraceLoggingNotificationHeader>());
1604
1605/// MAP_FRAMEBUFFER_REQUEST
1606#[repr(C, packed)]
1607#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1608pub struct MapFramebufferRequest {
1609    pub message_header: HeaderHostRequest,
1610    pub gpa: u64,
1611}
1612
1613const_assert_eq!(12, size_of::<MapFramebufferRequest>());
1614
1615impl MapFramebufferRequest {
1616    pub fn new(gpa: u64) -> Self {
1617        Self {
1618            message_header: HeaderGeneric::new(HostRequests::MAP_FRAMEBUFFER),
1619            gpa,
1620        }
1621    }
1622}
1623
1624open_enum! {
1625    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1626    pub enum MapFramebufferStatus : u32 {
1627        SUCCESS = 0,
1628        FAILURE = 1,
1629    }
1630}
1631
1632/// MAP_FRAMEBUFFER_RESPONSE
1633#[repr(C, packed)]
1634#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1635pub struct MapFramebufferResponse {
1636    pub message_header: HeaderHostResponse,
1637    pub status: MapFramebufferStatus,
1638}
1639
1640const_assert_eq!(8, size_of::<MapFramebufferResponse>());
1641
1642impl MapFramebufferResponse {
1643    pub fn new(status: MapFramebufferStatus) -> Self {
1644        Self {
1645            message_header: HeaderGeneric::new(HostRequests::MAP_FRAMEBUFFER),
1646            status,
1647        }
1648    }
1649}
1650
1651/// UNMAP_FRAMEBUFFER
1652#[repr(C, packed)]
1653#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1654pub struct UnmapFramebufferRequest {
1655    pub message_header: HeaderHostRequest,
1656}
1657
1658const_assert_eq!(4, size_of::<UnmapFramebufferRequest>());
1659
1660impl UnmapFramebufferRequest {
1661    pub fn new() -> Self {
1662        Self {
1663            message_header: HeaderGeneric::new(HostRequests::UNMAP_FRAMEBUFFER),
1664        }
1665    }
1666}
1667
1668open_enum! {
1669    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1670    pub enum UnmapFramebufferStatus : u32 {
1671        SUCCESS = 0,
1672        FAILURE = 1,
1673    }
1674}
1675
1676/// UNMAP_FRAMEBUFFER_RESPONSE
1677#[repr(C, packed)]
1678#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1679pub struct UnmapFramebufferResponse {
1680    pub message_header: HeaderHostResponse,
1681    pub status: UnmapFramebufferStatus,
1682}
1683
1684const_assert_eq!(8, size_of::<UnmapFramebufferResponse>());
1685
1686impl UnmapFramebufferResponse {
1687    pub fn new(status: UnmapFramebufferStatus) -> Self {
1688        Self {
1689            message_header: HeaderGeneric::new(HostRequests::UNMAP_FRAMEBUFFER),
1690            status,
1691        }
1692    }
1693}
1694
1695open_enum! {
1696    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1697    pub enum StartVtl0Status : u32 {
1698        SUCCESS = 0,
1699        FAILURE = 1,
1700    }
1701}
1702
1703#[repr(C, packed)]
1704#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1705pub struct StartVtl0CompleteNotification {
1706    pub message_header: HeaderHostNotification,
1707    pub status: StartVtl0Status,
1708    pub result_document_size: u32,
1709    // result_document is a variable size raw string because the Error is anyhow::Error
1710    // TODO: use specific Errors for "start VM"
1711}
1712
1713const_assert_eq!(12, size_of::<StartVtl0CompleteNotification>());
1714
1715impl StartVtl0CompleteNotification {
1716    pub fn new(status: StartVtl0Status, result_document_size: u32) -> Self {
1717        Self {
1718            message_header: HeaderGeneric::new(HostNotifications::START_VTL0_COMPLETED),
1719            status,
1720            result_document_size,
1721        }
1722    }
1723}
1724
1725#[repr(C)]
1726#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1727pub struct BatteryStatusNotification {
1728    pub message_header: HeaderGuestNotification,
1729    pub flags: BatteryStatusFlags,
1730    pub max_capacity: u32,
1731    pub remaining_capacity: u32,
1732    pub rate: u32,
1733}
1734
1735#[bitfield(u32)]
1736#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1737pub struct BatteryStatusFlags {
1738    pub ac_online: bool,
1739    pub battery_present: bool,
1740    pub charging: bool,
1741    pub discharging: bool,
1742    #[bits(28)]
1743    pub reserved: u32,
1744}
1745
1746impl BatteryStatusNotification {
1747    pub fn new(
1748        flags: BatteryStatusFlags,
1749        max_capacity: u32,
1750        remaining_capacity: u32,
1751        rate: u32,
1752    ) -> Self {
1753        Self {
1754            message_header: HeaderGeneric::new(GuestNotifications::BATTERY_STATUS),
1755            flags,
1756            max_capacity,
1757            remaining_capacity,
1758            rate,
1759        }
1760    }
1761}
1762
1763#[repr(C)]
1764#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1765pub struct InjectDebugInterruptNotification {
1766    pub message_header: HeaderGuestNotification,
1767    pub vtl: u8,
1768    pub _pad: u8,
1769}
1770
1771const_assert_eq!(6, size_of::<InjectDebugInterruptNotification>());
1772
1773#[bitfield(u64)]
1774#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1775pub struct CreateRamGpaRangeFlags {
1776    _reserved1: bool,
1777
1778    /// Writes are discarded
1779    pub rom_mb: bool,
1780
1781    #[bits(62)]
1782    _reserved: u64,
1783}
1784
1785#[repr(C, packed)]
1786#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1787pub struct CreateRamGpaRangeRequest {
1788    pub message_header: HeaderHostRequest,
1789    pub slot: u32,
1790    pub gpa_start: u64,
1791    pub gpa_count: u64,
1792    pub gpa_offset: u64,
1793    pub flags: CreateRamGpaRangeFlags,
1794}
1795
1796const_assert_eq!(40, size_of::<CreateRamGpaRangeRequest>());
1797
1798impl CreateRamGpaRangeRequest {
1799    pub fn new(
1800        slot: u32,
1801        gpa_start: u64,
1802        gpa_count: u64,
1803        gpa_offset: u64,
1804        flags: CreateRamGpaRangeFlags,
1805    ) -> Self {
1806        Self {
1807            message_header: HeaderGeneric::new(HostRequests::CREATE_RAM_GPA_RANGE),
1808            slot,
1809            gpa_start,
1810            gpa_count,
1811            gpa_offset,
1812            flags,
1813        }
1814    }
1815}
1816
1817open_enum! {
1818    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
1819    pub enum CreateRamGpaRangeStatus : u32 {
1820        SUCCESS = 0,
1821        /// slot index out of bounds
1822        SLOT_OUT_OF_BOUNDS = 1,
1823        /// slot is already occupied. needs to be reset first
1824        SLOT_OCCUPIED = 2,
1825        /// invalid flag
1826        INVALID_FLAG = 3,
1827        /// invalid GPA
1828        INVALID_GPA = 4,
1829        /// call to CreateRamGpaRange failed
1830        FAILED = 5,
1831    }
1832}
1833
1834#[repr(C)]
1835#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1836pub struct CreateRamGpaRangeResponse {
1837    pub message_header: HeaderHostResponse,
1838    pub status: CreateRamGpaRangeStatus,
1839}
1840
1841const_assert_eq!(8, size_of::<CreateRamGpaRangeResponse>());
1842
1843impl CreateRamGpaRangeResponse {
1844    pub fn new(status: CreateRamGpaRangeStatus) -> Self {
1845        Self {
1846            message_header: HeaderGeneric::new(HostRequests::CREATE_RAM_GPA_RANGE),
1847            status,
1848        }
1849    }
1850}
1851
1852#[repr(C)]
1853#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1854pub struct ResetRamGpaRangeRequest {
1855    pub message_header: HeaderHostRequest,
1856    pub slot: u32,
1857}
1858
1859const_assert_eq!(8, size_of::<ResetRamGpaRangeRequest>());
1860
1861impl ResetRamGpaRangeRequest {
1862    pub fn new(slot: u32) -> Self {
1863        Self {
1864            message_header: HeaderGeneric::new(HostRequests::RESET_RAM_GPA_RANGE),
1865            slot,
1866        }
1867    }
1868}
1869
1870#[repr(C)]
1871#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
1872pub struct ResetRamGpaRangeResponse {
1873    pub message_header: HeaderHostResponse,
1874}
1875
1876const_assert_eq!(4, size_of::<ResetRamGpaRangeResponse>());
1877
1878impl ResetRamGpaRangeResponse {
1879    pub fn new() -> Self {
1880        Self {
1881            message_header: HeaderGeneric::new(HostRequests::RESET_RAM_GPA_RANGE),
1882        }
1883    }
1884}
1885
1886pub mod test_utilities {
1887    // These constants are shared across GED and GET testing
1888    pub const TEST_VMGS_SECTOR_SIZE: u32 = 512;
1889    pub const TEST_VMGS_CAPACITY: usize = 4194816; // 4 MB
1890}