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