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