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