1use crate::ioctl::HypercallError;
7use crate::ioctl::IoctlError;
8use std::fs::File;
9use std::os::unix::prelude::*;
10
11mod ioctl {
12 #![allow(non_camel_case_types)]
13
14 use nix::ioctl_write_ptr;
15 use std::os::unix::prelude::*;
16
17 const MSHV_IOCTL: u8 = 0xb8;
18 const MSHV_SINT_SIGNAL_EVENT: u16 = 0x22;
19 const MSHV_SINT_POST_MESSAGE: u16 = 0x23;
20 const MSHV_SINT_SET_EVENTFD: u16 = 0x24;
21 const MSHV_SINT_PAUSE_MESSAGE_STREAM: u16 = 0x25;
22
23 #[repr(C)]
24 #[derive(Copy, Clone, Debug)]
25 pub struct hcl_post_message {
26 pub message_type: u64,
27 pub connection_id: u32,
28 pub payload_size: u32,
29 pub payload: *const u8,
30 }
31
32 #[repr(C)]
33 #[derive(Copy, Clone, Debug)]
34 pub struct hcl_signal_event {
35 pub connection_id: u32,
36 pub flag: u32,
37 }
38
39 #[repr(C)]
40 #[derive(Copy, Clone, Debug)]
41 pub struct hcl_set_eventfd {
42 pub fd: RawFd,
43 pub flag: u32,
44 }
45
46 #[repr(C)]
47 #[derive(Copy, Clone, Debug, Default)]
48 pub struct hcl_pause_message_stream {
49 pub pause: u8,
50 pub _reserved: [u8; 7],
51 }
52
53 ioctl_write_ptr!(
54 hcl_post_message,
55 MSHV_IOCTL,
56 MSHV_SINT_POST_MESSAGE,
57 hcl_post_message
58 );
59
60 ioctl_write_ptr!(
61 hcl_signal_event,
62 MSHV_IOCTL,
63 MSHV_SINT_SIGNAL_EVENT,
64 hcl_signal_event
65 );
66
67 ioctl_write_ptr!(
68 hcl_set_eventfd,
69 MSHV_IOCTL,
70 MSHV_SINT_SET_EVENTFD,
71 hcl_set_eventfd
72 );
73
74 ioctl_write_ptr!(
75 hcl_pause_message_stream,
76 MSHV_IOCTL,
77 MSHV_SINT_PAUSE_MESSAGE_STREAM,
78 hcl_pause_message_stream
79 );
80}
81
82pub struct HclVmbus {
84 file: File,
85}
86
87impl HclVmbus {
88 pub fn new() -> std::io::Result<Self> {
90 let file = std::fs::OpenOptions::new()
91 .read(true)
92 .write(true)
93 .open("/dev/mshv_sint")?;
94
95 Ok(Self { file })
96 }
97
98 pub fn into_inner(self) -> File {
100 self.file
101 }
102
103 pub fn post_message(
105 &self,
106 connection_id: u32,
107 message_type: u64,
108 message: &[u8],
109 ) -> Result<(), HypercallError> {
110 tracing::trace!(connection_id, "posting message");
111
112 let post_message = ioctl::hcl_post_message {
113 message_type,
114 connection_id,
115 payload_size: message.len() as u32,
116 payload: message.as_ptr(),
117 };
118
119 let result = unsafe { ioctl::hcl_post_message(self.file.as_raw_fd(), &post_message) };
121 HypercallError::check(result)
122 }
123
124 pub fn signal_event(&self, connection_id: u32, flag: u32) -> Result<(), HypercallError> {
126 tracing::trace!(connection_id, flag, "signaling event");
127
128 let signal_event = ioctl::hcl_signal_event {
129 connection_id,
130 flag,
131 };
132
133 let result = unsafe { ioctl::hcl_signal_event(self.file.as_raw_fd(), &signal_event) };
135 HypercallError::check(result)
136 }
137
138 pub fn set_eventfd(&self, flag: u32, event: Option<BorrowedFd<'_>>) -> Result<(), IoctlError> {
141 tracing::trace!(flag, ?event, "setting event fd");
142
143 let set_eventfd = ioctl::hcl_set_eventfd {
144 flag,
145 fd: event.map_or(-1, |e| e.as_raw_fd()),
146 };
147
148 unsafe { ioctl::hcl_set_eventfd(self.file.as_raw_fd(), &set_eventfd).map_err(IoctlError) }?;
150 Ok(())
151 }
152
153 pub fn pause_message_stream(&self, pause: bool) -> Result<(), IoctlError> {
164 tracing::trace!(?pause, "pausing message stream");
165
166 let pause_message_stream = ioctl::hcl_pause_message_stream {
167 pause: pause.into(),
168 _reserved: [0; 7],
169 };
170
171 unsafe {
173 ioctl::hcl_pause_message_stream(self.file.as_raw_fd(), &pause_message_stream)
174 .map_err(IoctlError)?;
175 }
176
177 Ok(())
178 }
179}