vmbus_core/
protocol.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::VersionInfo;
5use bitfield_struct::bitfield;
6use hvdef::Vtl;
7use inspect::Inspect;
8use mesh::payload::Protobuf;
9use open_enum::open_enum;
10use std::mem::size_of;
11use std::ops::BitAnd;
12use std::ops::BitAndAssign;
13use std::ops::BitOr;
14use std::ops::Deref;
15use std::ops::DerefMut;
16use thiserror::Error;
17use zerocopy::FromBytes;
18use zerocopy::FromZeros;
19use zerocopy::Immutable;
20use zerocopy::IntoBytes;
21use zerocopy::KnownLayout;
22use zerocopy::Unalign;
23
24#[macro_use]
25mod macros;
26
27type Guid = guid::Guid;
28
29pub const VMBUS_MESSAGE_REDIRECT_CONNECTION_ID: u32 = 0x800074;
30
31pub const STATUS_SUCCESS: i32 = 0;
32pub const STATUS_UNSUCCESSFUL: i32 = 0x8000ffff_u32 as i32;
33pub const STATUS_CONNECTION_REFUSED: i32 = 0xc0000236_u32 as i32;
34
35pub const HEADER_SIZE: usize = size_of::<MessageHeader>();
36pub const MAX_MESSAGE_SIZE: usize = hvdef::HV_MESSAGE_PAYLOAD_SIZE;
37
38// This macro is used to define a MessageType open enum, a Message enum, a parse method for the
39// Message enum, and VmbusMessage trait implementations for each protocol message struct.
40//
41// The syntax here is as follows:
42// number name { struct min_version [options],* },*
43//
44// If a message has different variants depending on the version or feature flags, you can express
45// this by having multiple comma-separated items inside the curly braces for that message. List the
46// variants in the order you want them to be matched (so, newer first).
47//
48// A message that can be received when disconnected should have the min_version set to 0.
49//
50// The following additional options can be set:
51// - features: specifies one or more feature flags, at least one of which must be supported for the
52//             message to be allowed.
53// - check_size: set to true to only match the message if its size is at least the size of the
54//               struct; if it's not, allow another message to match. Without this option, the size
55//               is still checked but a message that is too small is considered a parsing failure,
56//               and won't allow another match. Use this for a message whose variants can only be
57//               distinguished by size.
58vmbus_messages! {
59    pub enum Message, MessageType {
60        1 OFFER_CHANNEL { OfferChannel V1 },
61        2 RESCIND_CHANNEL_OFFER { RescindChannelOffer V1 },
62        3 REQUEST_OFFERS { RequestOffers V1 },
63        4 ALL_OFFERS_DELIVERED { AllOffersDelivered V1 },
64        5 OPEN_CHANNEL {
65            OpenChannel2 Copper features:(guest_specified_signal_parameters | channel_interrupt_redirection),
66            OpenChannel V1
67        },
68        6 OPEN_CHANNEL_RESULT { OpenResult V1 },
69        7 CLOSE_CHANNEL { CloseChannel V1 },
70        8 GPADL_HEADER { GpadlHeader V1 },
71        9 GPADL_BODY { GpadlBody V1 },
72        10 GPADL_CREATED { GpadlCreated V1 },
73        11 GPADL_TEARDOWN { GpadlTeardown V1 },
74        12 GPADL_TORNDOWN { GpadlTorndown V1 },
75        13 REL_ID_RELEASED { RelIdReleased V1 },
76        14 INITIATE_CONTACT {
77            // Although the InitiateContact2 message is only used in Copper and above, it
78            // must be set as minimum version 0 because the version is not known when the message
79            // is received. For this same reason, we can't check the feature flags here.
80            InitiateContact2 0 check_size:true,
81            InitiateContact 0
82        },
83        15 VERSION_RESPONSE {
84            VersionResponse3 0 check_size:true,
85            VersionResponse2 0 check_size:true,
86            VersionResponse 0
87        },
88        16 UNLOAD { Unload V1 },
89        17 UNLOAD_COMPLETE { UnloadComplete Win7 },
90        18 OPEN_RESERVED_CHANNEL { OpenReservedChannel Win10 },
91        19 CLOSE_RESERVED_CHANNEL { CloseReservedChannel 0 },
92        20 CLOSE_RESERVED_RESPONSE { CloseReservedChannelResponse Win10 },
93        21 TL_CONNECT_REQUEST {
94            // Some clients send the old message even for newer protocols, so check the size to allow
95            // the old version to match if it's smaller.
96            TlConnectRequest2 Win10Rs5 check_size:true,
97            TlConnectRequest Win10
98        },
99        22 MODIFY_CHANNEL { ModifyChannel Win10Rs3_0 },
100        23 TL_CONNECT_REQUEST_RESULT { TlConnectResult Win10Rs3_0 },
101        24 MODIFY_CHANNEL_RESPONSE { ModifyChannelResponse Iron },
102        25 MODIFY_CONNECTION { ModifyConnection Copper features:modify_connection },
103        26 MODIFY_CONNECTION_RESPONSE { ModifyConnectionResponse Copper features:modify_connection },
104        27 PAUSE { Pause Copper features:pause_resume },
105        28 PAUSE_RESPONSE { PauseResponse Copper features:pause_resume },
106        29 RESUME { Resume Copper features:pause_resume },
107    }
108}
109
110/// An error that occurred while parsing a vmbus protocol message.
111#[derive(Debug, Error)]
112pub enum ParseError {
113    /// The message was smaller than required for the message type.
114    #[error("message too small: {0:?}")]
115    MessageTooSmall(Option<MessageType>),
116    /// The message type is not a valid vmbus protocol message, or a message that is not supported
117    /// with the current protocol version.
118    #[error("unexpected or unsupported message type: {0:?}")]
119    InvalidMessageType(MessageType),
120}
121
122/// Trait implemented on all protocol message structs by the vmbus_message! macro.
123pub trait VmbusMessage: Sized {
124    /// The corresponding message type for the struct.
125    const MESSAGE_TYPE: MessageType;
126
127    /// The size of the message, including the vmbus message header.
128    const MESSAGE_SIZE: usize = HEADER_SIZE + size_of::<Self>();
129}
130
131/// The header of a vmbus message.
132#[repr(C)]
133#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
134pub struct MessageHeader {
135    message_type: MessageType,
136    padding: u32,
137}
138
139impl MessageHeader {
140    /// Creates a new `MessageHeader` for the specified message type.
141    pub fn new(message_type: MessageType) -> Self {
142        Self {
143            message_type,
144            padding: 0,
145        }
146    }
147
148    pub fn message_type(&self) -> MessageType {
149        self.message_type
150    }
151}
152
153#[derive(Inspect)]
154#[bitfield(u32)]
155#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
156pub struct FeatureFlags {
157    /// Feature which allows the guest to specify an event flag and connection ID when opening
158    /// a channel. If not used, the event flag defaults to the channel ID and the connection ID
159    /// is specified by the host in the offer channel message.
160    pub guest_specified_signal_parameters: bool, // 0x1
161
162    /// Indicates the `REDIRECT_INTERRUPT` flag is supported in the OpenChannel flags.
163    pub channel_interrupt_redirection: bool, // 0x2
164
165    /// Indicates the `MODIFY_CONNECTION` and `MODIFY_CONNECTION_RESPONSE` messages are supported.
166    pub modify_connection: bool, // 0x4
167
168    /// Feature which allows a client (Windows, Linux, MiniVMBus, etc)
169    /// to specify a well-known GUID to identify itself when initiating contact.
170    /// If not used, the client ID is zero.
171    pub client_id: bool, // 0x8
172
173    /// Indicates the `confidential_ring_buffer` and `confidential_external_memory` offer flags are
174    /// supported.
175    pub confidential_channels: bool, // 0x10
176
177    /// The server supports messages to pause and resume additional control messages.
178    pub pause_resume: bool, // 0x20
179
180    /// The guest supports having the server (host or paravisor) provide monitor page GPAs.
181    ///
182    /// If this flag is present in the `InitiateContact` message, the guest may still provide its
183    /// own monitor pages, which the server may ignore if it supports the flag. The server will
184    /// only set this flag in the `VersionResponse` message if it is actually providing monitor
185    /// pages, which the guest must then use instead of its own.
186    ///
187    /// If the server sets the flag in the `VersionResponse` message, it must provide a non-zero
188    /// value for the [`VersionResponse3::child_to_parent_monitor_page_gpa`]; the
189    /// [`VersionResponse3::parent_to_child_monitor_page_gpa`] is optional and may be zero, in which
190    /// case the guest cannot cancel MNF interrupts from the host.
191    pub server_specified_monitor_pages: bool, // 0x40
192
193    #[bits(25)]
194    _reserved: u32,
195}
196
197impl FeatureFlags {
198    /// Returns true if `other` contains only flags that are also set in `self`.
199    pub fn contains(&self, other: FeatureFlags) -> bool {
200        self.into_bits() & other.into_bits() == other.into_bits()
201    }
202}
203
204impl BitAnd for FeatureFlags {
205    type Output = Self;
206
207    fn bitand(self, rhs: Self) -> Self::Output {
208        (self.into_bits() & rhs.into_bits()).into()
209    }
210}
211
212impl BitAndAssign for FeatureFlags {
213    fn bitand_assign(&mut self, rhs: Self) {
214        *self = (self.into_bits() & rhs.into_bits()).into()
215    }
216}
217
218impl BitOr for FeatureFlags {
219    type Output = Self;
220
221    fn bitor(self, rhs: Self) -> Self::Output {
222        (self.into_bits() | rhs.into_bits()).into()
223    }
224}
225
226#[repr(transparent)]
227#[derive(
228    Copy,
229    Clone,
230    Debug,
231    Eq,
232    PartialEq,
233    Ord,
234    PartialOrd,
235    Hash,
236    IntoBytes,
237    FromBytes,
238    Immutable,
239    KnownLayout,
240    Protobuf,
241)]
242#[mesh(package = "vmbus")]
243pub struct GpadlId(pub u32);
244
245#[repr(transparent)]
246#[derive(
247    Copy,
248    Clone,
249    Debug,
250    Eq,
251    Inspect,
252    PartialEq,
253    Ord,
254    PartialOrd,
255    Hash,
256    IntoBytes,
257    FromBytes,
258    Immutable,
259    KnownLayout,
260    Protobuf,
261)]
262#[inspect(transparent)]
263pub struct ChannelId(pub u32);
264
265pub struct ConnectionId(pub u32);
266
267impl ConnectionId {
268    /// Format a connection ID for a given channel.
269    pub fn new(channel_id: u32, vtl: Vtl, sint: u8) -> Self {
270        Self(channel_id | (sint as u32) << 12 | (vtl as u32) << 16)
271    }
272}
273
274#[repr(C)]
275#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
276pub struct InitiateContact {
277    pub version_requested: u32,
278    pub target_message_vp: u32,
279    pub interrupt_page_or_target_info: u64, // sint, vtl, _
280    pub parent_to_child_monitor_page_gpa: u64,
281    pub child_to_parent_monitor_page_gpa: u64,
282}
283
284/// Initiate contact message used with `FeatureFlags::CLIENT_ID` when the feature is supported
285/// (Copper and above).
286#[repr(C)]
287#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
288pub struct InitiateContact2 {
289    pub initiate_contact: InitiateContact,
290    pub client_id: Guid,
291}
292
293impl From<InitiateContact> for InitiateContact2 {
294    fn from(value: InitiateContact) -> Self {
295        Self {
296            initiate_contact: value,
297            ..FromZeros::new_zeroed()
298        }
299    }
300}
301
302/// Helper struct to interpret the `InitiateContact::interrupt_page_or_target_info` field.
303#[bitfield(u64)]
304pub struct TargetInfo {
305    pub sint: u8,
306    pub vtl: u8,
307    pub _padding: u16,
308    pub feature_flags: u32,
309}
310
311pub const fn make_version(major: u16, minor: u16) -> u32 {
312    ((major as u32) << 16) | (minor as u32)
313}
314
315#[repr(u32)]
316#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Inspect)]
317pub enum Version {
318    V1 = make_version(0, 13),
319    Win7 = make_version(1, 1),
320    Win8 = make_version(2, 4),
321    Win8_1 = make_version(3, 0),
322    Win10 = make_version(4, 0),
323    Win10Rs3_0 = make_version(4, 1),
324    Win10Rs3_1 = make_version(5, 0),
325    Win10Rs4 = make_version(5, 1),
326    Win10Rs5 = make_version(5, 2),
327    Iron = make_version(5, 3),
328    Copper = make_version(6, 0),
329}
330
331open_enum! {
332    /// Possible values for the `VersionResponse::connection_state` field.
333    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
334    pub enum ConnectionState: u8 {
335        SUCCESSFUL = 0,
336        FAILED_LOW_RESOURCES = 1,
337        FAILED_UNKNOWN_FAILURE = 2,
338    }
339}
340
341#[repr(C)]
342#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
343pub struct VersionResponse {
344    pub version_supported: u8,
345    pub connection_state: ConnectionState,
346    pub padding: u16,
347    pub selected_version_or_connection_id: u32,
348}
349
350/// Version response message used by `Version::Copper` and above.
351/// N.B. The server will only send this version if the requested version is `Version::Copper` or
352///      above and the version is supported. For unsupported versions, the original `VersionResponse`
353///      is always sent.
354#[repr(C)]
355#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
356pub struct VersionResponse2 {
357    pub version_response: VersionResponse,
358    pub supported_features: u32,
359}
360
361/// Version response message used by [`Version::Copper`] and above if
362/// [`FeatureFlags::server_specified_monitor_pages`] is set.
363#[repr(C)]
364#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
365pub struct VersionResponse3 {
366    pub version_response2: VersionResponse2,
367    pub _padding: u32,
368    // Only valid with `FeatureFlags::server_specified_monitor_pages`.
369    pub parent_to_child_monitor_page_gpa: u64,
370    pub child_to_parent_monitor_page_gpa: u64,
371}
372
373impl From<VersionResponse> for VersionResponse2 {
374    fn from(value: VersionResponse) -> Self {
375        Self {
376            version_response: value,
377            ..FromZeros::new_zeroed()
378        }
379    }
380}
381
382impl From<VersionResponse2> for VersionResponse3 {
383    fn from(value: VersionResponse2) -> Self {
384        Self {
385            version_response2: value,
386            ..FromZeros::new_zeroed()
387        }
388    }
389}
390
391impl From<VersionResponse> for VersionResponse3 {
392    fn from(value: VersionResponse) -> Self {
393        let version_response: VersionResponse2 = value.into();
394        version_response.into()
395    }
396}
397
398/// User-defined data provided by a device as part of an offer or open request.
399#[derive(
400    Copy,
401    Clone,
402    Debug,
403    PartialEq,
404    Eq,
405    IntoBytes,
406    FromBytes,
407    Immutable,
408    KnownLayout,
409    Protobuf,
410    Inspect,
411)]
412#[repr(C, align(4))]
413#[mesh(transparent)]
414#[inspect(transparent)]
415pub struct UserDefinedData([u8; 120]);
416
417impl UserDefinedData {
418    pub fn as_pipe_params(&self) -> &PipeUserDefinedParameters {
419        PipeUserDefinedParameters::ref_from_bytes(
420            &self.0[0..size_of::<PipeUserDefinedParameters>()],
421        )
422        .expect("from bytes should not fail")
423    }
424
425    pub fn as_pipe_params_mut(&mut self) -> &mut PipeUserDefinedParameters {
426        PipeUserDefinedParameters::mut_from_bytes(
427            &mut self.0[0..size_of::<PipeUserDefinedParameters>()],
428        )
429        .expect("from bytes should not fail")
430    }
431
432    pub fn as_hvsock_params(&self) -> &HvsockUserDefinedParameters {
433        HvsockUserDefinedParameters::ref_from_bytes(
434            &self.0[0..size_of::<HvsockUserDefinedParameters>()],
435        )
436        .expect("from bytes should not fail")
437    }
438
439    pub fn as_hvsock_params_mut(&mut self) -> &mut HvsockUserDefinedParameters {
440        HvsockUserDefinedParameters::mut_from_bytes(
441            &mut self.0[0..size_of::<HvsockUserDefinedParameters>()],
442        )
443        .expect("from bytes should not fail")
444    }
445}
446
447impl Deref for UserDefinedData {
448    type Target = [u8; 120];
449
450    fn deref(&self) -> &Self::Target {
451        &self.0
452    }
453}
454
455impl DerefMut for UserDefinedData {
456    fn deref_mut(&mut self) -> &mut Self::Target {
457        &mut self.0
458    }
459}
460
461impl From<[u8; 120]> for UserDefinedData {
462    fn from(value: [u8; 120]) -> Self {
463        Self(value)
464    }
465}
466
467impl From<UserDefinedData> for [u8; 120] {
468    fn from(value: UserDefinedData) -> Self {
469        value.0
470    }
471}
472
473impl Default for UserDefinedData {
474    fn default() -> Self {
475        Self::new_zeroed()
476    }
477}
478
479#[repr(C)]
480#[derive(
481    Copy, Clone, Debug, Inspect, PartialEq, Eq, IntoBytes, FromBytes, Immutable, KnownLayout,
482)]
483#[inspect(extra = "Self::inspect_extra")]
484pub struct OfferChannel {
485    pub interface_id: Guid,
486    pub instance_id: Guid,
487    #[inspect(skip)]
488    pub rsvd: [u32; 4],
489    pub flags: OfferFlags,
490    pub mmio_megabytes: u16,
491    pub user_defined: UserDefinedData,
492    pub subchannel_index: u16,
493    pub mmio_megabytes_optional: u16,
494    pub channel_id: ChannelId,
495    pub monitor_id: u8,
496    pub monitor_allocated: u8,
497    pub is_dedicated: u16,
498    pub connection_id: u32,
499}
500
501impl OfferChannel {
502    fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
503        // TODO: There doesn't exist a single crate that has all these interface
504        // IDs. Today they're defined in each individual crate, but we don't
505        // want to include all those crates as dependencies here.
506        //
507        // In the future, it might make sense to have a common protocol crate
508        // that has all of these defined, but for now just redefine the most
509        // common ones here. Add more as needed.
510        const SHUTDOWN_IC: Guid = guid::guid!("0e0b6031-5213-4934-818b-38d90ced39db");
511        const KVP_IC: Guid = guid::guid!("a9a0f4e7-5a45-4d96-b827-8a841e8c03e6");
512        const VSS_IC: Guid = guid::guid!("35fa2e29-ea23-4236-96ae-3a6ebacba440");
513        const TIMESYNC_IC: Guid = guid::guid!("9527e630-d0ae-497b-adce-e80ab0175caf");
514        const HEARTBEAT_IC: Guid = guid::guid!("57164f39-9115-4e78-ab55-382f3bd5422d");
515        const RDV_IC: Guid = guid::guid!("276aacf4-ac15-426c-98dd-7521ad3f01fe");
516
517        const INHERITED_ACTIVATION: Guid = guid::guid!("3375baf4-9e15-4b30-b765-67acb10d607b");
518
519        const NET: Guid = guid::guid!("f8615163-df3e-46c5-913f-f2d2f965ed0e");
520        const SCSI: Guid = guid::guid!("ba6163d9-04a1-4d29-b605-72e2ffb1dc7f");
521        const VPCI: Guid = guid::guid!("44c4f61d-4444-4400-9d52-802e27ede19f");
522
523        resp.field_with("interface_name", || match self.interface_id {
524            SHUTDOWN_IC => "shutdown_ic",
525            KVP_IC => "kvp_ic",
526            VSS_IC => "vss_ic",
527            TIMESYNC_IC => "timesync_ic",
528            HEARTBEAT_IC => "heartbeat_ic",
529            RDV_IC => "rdv_ic",
530            INHERITED_ACTIVATION => "inherited_activation",
531            NET => "net",
532            SCSI => "scsi",
533            VPCI => "vpci",
534            _ => "unknown",
535        });
536    }
537}
538
539#[derive(Inspect)]
540#[bitfield(u16)]
541#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq, Protobuf)]
542#[mesh(transparent)]
543pub struct OfferFlags {
544    pub enumerate_device_interface: bool, // 0x1
545    /// Indicates the channel must use an encrypted ring buffer on a hardware-isolated VM.
546    pub confidential_ring_buffer: bool, // 0x2
547    /// Indicates the channel must use encrypted additional GPADLs and GPA direct ranges on a
548    /// hardware-isolated VM.
549    pub confidential_external_memory: bool, // 0x4
550    #[bits(1)]
551    _reserved1: u16,
552    pub named_pipe_mode: bool, // 0x10
553    #[bits(8)]
554    _reserved2: u16,
555    pub tlnpi_provider: bool, // 0x2000
556    #[bits(2)]
557    _reserved3: u16,
558}
559
560open_enum! {
561    /// Possible values for the `PipeUserDefinedParameters::pipe_type` field.
562    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
563    pub enum PipeType: u32 {
564        BYTE = 0,
565        MESSAGE = 4,
566    }
567}
568
569/// First 4 bytes of user_defined for named pipe offers.
570#[repr(C)]
571#[derive(Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
572pub struct PipeUserDefinedParameters {
573    pub pipe_type: PipeType,
574}
575
576#[repr(C)]
577#[derive(Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
578pub struct HvsockUserDefinedParameters {
579    pub pipe_params: PipeUserDefinedParameters,
580    pub is_for_guest_accept: u8,
581    pub is_for_guest_container: u8,
582    pub version: Unalign<HvsockParametersVersion>, // unaligned u32
583    pub silo_id: Unalign<Guid>,                    // unaligned Guid
584    pub _padding: [u8; 2],
585}
586
587impl HvsockUserDefinedParameters {
588    pub fn new(is_for_guest_accept: bool, is_for_guest_container: bool, silo_id: Guid) -> Self {
589        Self {
590            pipe_params: PipeUserDefinedParameters {
591                pipe_type: PipeType::BYTE,
592            },
593            is_for_guest_accept: is_for_guest_accept.into(),
594            is_for_guest_container: is_for_guest_container.into(),
595            version: Unalign::new(HvsockParametersVersion::RS5),
596            silo_id: Unalign::new(silo_id),
597            _padding: [0; 2],
598        }
599    }
600}
601
602open_enum! {
603    /// Possible values for the `PipeUserDefinedParameters::pipe_type` field.
604    #[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
605    pub enum HvsockParametersVersion: u32 {
606        PRE_RS5 = 0,
607        RS5 = 1,
608    }
609}
610
611#[repr(C)]
612#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoBytes, FromBytes, Immutable, KnownLayout)]
613pub struct RescindChannelOffer {
614    pub channel_id: ChannelId,
615}
616
617#[repr(C)]
618#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
619pub struct GpadlHeader {
620    pub channel_id: ChannelId,
621    pub gpadl_id: GpadlId,
622    pub len: u16,
623    pub count: u16,
624}
625
626impl GpadlHeader {
627    /// The maximum number of 64 bit values that fit after the message data.
628    pub const MAX_DATA_VALUES: usize = (MAX_MESSAGE_SIZE - Self::MESSAGE_SIZE) / size_of::<u64>();
629}
630
631#[repr(C)]
632#[derive(Copy, Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
633pub struct GpadlBody {
634    pub rsvd: u32,
635    pub gpadl_id: GpadlId,
636}
637
638impl GpadlBody {
639    /// The maximum number of 64 bit values that fit after the message data.
640    pub const MAX_DATA_VALUES: usize = (MAX_MESSAGE_SIZE - Self::MESSAGE_SIZE) / size_of::<u64>();
641}
642
643#[repr(C)]
644#[derive(Copy, Clone, Eq, PartialEq, Debug, IntoBytes, FromBytes, Immutable, KnownLayout)]
645pub struct GpadlCreated {
646    pub channel_id: ChannelId,
647    pub gpadl_id: GpadlId,
648    pub status: i32,
649}
650
651/// Target VP index value that indicates that interrupts should be disabled for the channel.
652pub const VP_INDEX_DISABLE_INTERRUPT: u32 = u32::MAX;
653
654#[repr(C)]
655#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
656pub struct OpenChannel {
657    pub channel_id: ChannelId,
658    pub open_id: u32,
659    pub ring_buffer_gpadl_id: GpadlId,
660    pub target_vp: u32,
661    pub downstream_ring_buffer_page_offset: u32,
662    pub user_data: UserDefinedData,
663}
664
665#[bitfield(u16)]
666#[derive(IntoBytes, FromBytes, Immutable, KnownLayout, PartialEq, Eq)]
667pub struct OpenChannelFlags {
668    /// Indicates the host-to-guest interrupt for this channel should be sent to the redirected
669    /// VTL and SINT. This has no effect if the server is not using redirection.
670    pub redirect_interrupt: bool,
671
672    #[bits(15)]
673    pub unused: u16,
674}
675
676/// Open channel message used if `FeatureFlags::GUEST_SPECIFIED_SIGNAL_PARAMETERS` or
677/// `FeatureFlags::CHANNEL_INTERRUPT_REDIRECTION` is supported.
678#[repr(C)]
679#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
680pub struct OpenChannel2 {
681    pub open_channel: OpenChannel,
682
683    // Only valid with FeatureFlags::GUEST_SPECIFIED_SIGNAL_PARAMETERS
684    pub connection_id: u32,
685    pub event_flag: u16,
686
687    // Only valid with FeatureFlags::CHANNEL_INTERRUPT_REDIRECTION
688    pub flags: OpenChannelFlags,
689}
690
691impl From<OpenChannel> for OpenChannel2 {
692    fn from(value: OpenChannel) -> Self {
693        Self {
694            open_channel: value,
695            ..FromZeros::new_zeroed()
696        }
697    }
698}
699
700#[repr(C)]
701#[derive(PartialEq, Eq, Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
702pub struct OpenResult {
703    pub channel_id: ChannelId,
704    pub open_id: u32,
705    pub status: u32,
706}
707
708#[repr(C)]
709#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
710pub struct CloseChannel {
711    pub channel_id: ChannelId,
712}
713
714#[repr(C)]
715#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
716pub struct RelIdReleased {
717    pub channel_id: ChannelId,
718}
719
720#[repr(C)]
721#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
722pub struct GpadlTeardown {
723    pub channel_id: ChannelId,
724    pub gpadl_id: GpadlId,
725}
726
727#[repr(C)]
728#[derive(Debug, Copy, Clone, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
729pub struct GpadlTorndown {
730    pub gpadl_id: GpadlId,
731}
732
733#[repr(C)]
734#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
735pub struct OpenReservedChannel {
736    pub channel_id: ChannelId,
737    pub target_vp: u32,
738    pub target_sint: u32,
739    pub ring_buffer_gpadl: GpadlId,
740    pub downstream_page_offset: u32,
741}
742
743#[repr(C)]
744#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
745pub struct CloseReservedChannel {
746    pub channel_id: ChannelId,
747    pub target_vp: u32,
748    pub target_sint: u32,
749}
750
751#[repr(C)]
752#[derive(PartialEq, Eq, Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
753pub struct CloseReservedChannelResponse {
754    pub channel_id: ChannelId,
755}
756
757#[repr(C)]
758#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
759pub struct TlConnectRequest {
760    pub endpoint_id: Guid,
761    pub service_id: Guid,
762}
763
764#[repr(C)]
765#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
766pub struct TlConnectRequest2 {
767    pub base: TlConnectRequest,
768    pub silo_id: Guid,
769}
770
771impl From<TlConnectRequest> for TlConnectRequest2 {
772    fn from(value: TlConnectRequest) -> Self {
773        Self {
774            base: value,
775            ..FromZeros::new_zeroed()
776        }
777    }
778}
779
780#[repr(C)]
781#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
782pub struct TlConnectResult {
783    pub endpoint_id: Guid,
784    pub service_id: Guid,
785    pub status: i32,
786}
787
788#[repr(C)]
789#[derive(Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
790pub struct ModifyChannel {
791    pub channel_id: ChannelId,
792    pub target_vp: u32,
793}
794
795#[repr(C)]
796#[derive(PartialEq, Eq, Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
797pub struct ModifyChannelResponse {
798    pub channel_id: ChannelId,
799    pub status: i32,
800}
801
802#[repr(C)]
803#[derive(PartialEq, Eq, Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
804pub struct ModifyConnection {
805    pub parent_to_child_monitor_page_gpa: u64,
806    pub child_to_parent_monitor_page_gpa: u64,
807}
808
809#[repr(C)]
810#[derive(PartialEq, Eq, Debug, Copy, Clone, IntoBytes, FromBytes, Immutable, KnownLayout)]
811pub struct ModifyConnectionResponse {
812    pub connection_state: ConnectionState,
813}
814
815// The remaining structs are for empty messages, provided to simplify the vmbus_messages! macro and
816// to allow for consistent use of the VmbusMessage trait for all messages.
817
818#[repr(C)]
819#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
820pub struct RequestOffers {}
821
822#[repr(C)]
823#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
824pub struct Unload {}
825
826#[repr(C)]
827#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
828pub struct UnloadComplete {}
829
830#[repr(C)]
831#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
832pub struct AllOffersDelivered {}
833
834#[repr(C)]
835#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
836pub struct Pause;
837
838#[repr(C)]
839#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
840pub struct PauseResponse;
841
842#[repr(C)]
843#[derive(Copy, Clone, Debug, Eq, PartialEq, IntoBytes, FromBytes, Immutable, KnownLayout)]
844pub struct Resume;