Skip to main content

get_protocol/
lib.rs

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