1mod ring;
2use xen_sys::{
3 vm_event_back_ring, xc_monitor_cpuid, xc_monitor_debug_exceptions,
4 xc_monitor_descriptor_access, xc_monitor_disable, xc_monitor_emul_unimplemented,
5 xc_monitor_emulate_each_rep, xc_monitor_enable, xc_monitor_get_capabilities,
6 xc_monitor_guest_request, xc_monitor_inguest_pagefault, xc_monitor_io, xc_monitor_mov_to_msr,
7 xc_monitor_privileged_call, xc_monitor_resume, xc_monitor_singlestep,
8 xc_monitor_software_breakpoint, xc_monitor_vmexit, xc_monitor_write_ctrlreg,
9};
10
11pub use self::ring::VmEventRing;
12use crate::{
13 BACK_RING_INIT, SHARED_RING_INIT, XenDomainId,
14 consts::PAGE_SIZE,
15 ctrl::{VmEventCtrlReg, XenInterface},
16 error::{XcError, XenError},
17 evtchn::XenEventChannelPort,
18 xc_check_error,
19};
20
21pub struct XenMonitor {
22 interface: XenInterface,
23 domain_id: XenDomainId,
24 port: u32,
25}
26
27impl XenMonitor {
28 pub(crate) fn new(
29 interface: XenInterface,
30 domain_id: XenDomainId,
31 ) -> Result<(Self, VmEventRing), XenError> {
32 let mut port: u32 = 0;
33 let ring_page = unsafe { xc_monitor_enable(interface.handle.0, domain_id.0, &mut port) };
34
35 if ring_page.is_null() {
36 return Err(XcError::new(-1, 0, "Failed to enable monitor").into());
37 }
38
39 SHARED_RING_INIT!(ring_page);
40
41 let mut back_ring = unsafe { std::mem::zeroed::<vm_event_back_ring>() };
42 BACK_RING_INIT!(back_ring, ring_page, PAGE_SIZE);
43
44 Ok((
45 Self {
46 interface,
47 domain_id,
48 port,
49 },
50 VmEventRing::new(ring_page, back_ring),
51 ))
52 }
53
54 pub fn channel(&self) -> Result<XenEventChannelPort, XenError> {
55 XenEventChannelPort::bind_interdomain(self.domain_id, self.port)
56 }
57
58 pub fn port(&self) -> u32 {
59 self.port
60 }
61
62 pub fn resume(&self) -> Result<(), XenError> {
63 let rc = unsafe { xc_monitor_resume(self.interface.handle.0, self.domain_id.0) };
64 xc_check_error!(self.interface.handle.0, rc);
65 Ok(())
66 }
67
68 pub fn get_capabilities(&self) -> Result<u32, XenError> {
69 let mut capabilities = 0;
70 let rc = unsafe {
71 xc_monitor_get_capabilities(
72 self.interface.handle.0,
73 self.domain_id.0,
74 &mut capabilities,
75 )
76 };
77 xc_check_error!(self.interface.handle.0, rc);
78 Ok(capabilities)
79 }
80
81 pub fn write_ctrlreg(
82 &self,
83 index: VmEventCtrlReg,
84 enable: bool,
85 sync: bool,
86 bitmask: u64,
87 onchangeonly: bool,
88 ) -> Result<(), XenError> {
89 let rc = unsafe {
90 xc_monitor_write_ctrlreg(
91 self.interface.handle.0,
92 self.domain_id.0,
93 index as u16,
94 enable,
95 sync,
96 bitmask,
97 onchangeonly,
98 )
99 };
100 xc_check_error!(self.interface.handle.0, rc);
101 Ok(())
102 }
103
104 pub fn mov_to_msr(&self, msr: u32, enable: bool, onchangeonly: bool) -> Result<(), XenError> {
105 let rc = unsafe {
106 xc_monitor_mov_to_msr(
107 self.interface.handle.0,
108 self.domain_id.0,
109 msr,
110 enable,
111 onchangeonly,
112 )
113 };
114 xc_check_error!(self.interface.handle.0, rc);
115 Ok(())
116 }
117
118 pub fn singlestep(&self, singlestep: bool) -> Result<(), XenError> {
119 let rc =
120 unsafe { xc_monitor_singlestep(self.interface.handle.0, self.domain_id.0, singlestep) };
121 xc_check_error!(self.interface.handle.0, rc);
122 Ok(())
123 }
124
125 pub fn software_breakpoint(&self, enable: bool) -> Result<(), XenError> {
126 let rc = unsafe {
127 xc_monitor_software_breakpoint(self.interface.handle.0, self.domain_id.0, enable)
128 };
129 xc_check_error!(self.interface.handle.0, rc);
130 Ok(())
131 }
132
133 pub fn descriptor_access(&self, enable: bool) -> Result<(), XenError> {
134 let rc = unsafe {
135 xc_monitor_descriptor_access(self.interface.handle.0, self.domain_id.0, enable)
136 };
137 xc_check_error!(self.interface.handle.0, rc);
138 Ok(())
139 }
140
141 pub fn guest_request(
142 &self,
143 enable: bool,
144 sync: bool,
145 allow_userspace: bool,
146 ) -> Result<(), XenError> {
147 let rc = unsafe {
148 xc_monitor_guest_request(
149 self.interface.handle.0,
150 self.domain_id.0,
151 enable,
152 sync,
153 allow_userspace,
154 )
155 };
156 xc_check_error!(self.interface.handle.0, rc);
157 Ok(())
158 }
159
160 pub fn inguest_pagefault(&self, disable: bool) -> Result<(), XenError> {
161 let rc = unsafe {
162 xc_monitor_inguest_pagefault(self.interface.handle.0, self.domain_id.0, disable)
163 };
164 xc_check_error!(self.interface.handle.0, rc);
165 Ok(())
166 }
167
168 pub fn debug_exceptions(&self, enable: bool, sync: bool) -> Result<(), XenError> {
169 let rc = unsafe {
170 xc_monitor_debug_exceptions(self.interface.handle.0, self.domain_id.0, enable, sync)
171 };
172 xc_check_error!(self.interface.handle.0, rc);
173 Ok(())
174 }
175
176 pub fn cpuid(&self, enable: bool) -> Result<(), XenError> {
177 let rc = unsafe { xc_monitor_cpuid(self.interface.handle.0, self.domain_id.0, enable) };
178 xc_check_error!(self.interface.handle.0, rc);
179 Ok(())
180 }
181
182 pub fn privileged_call(&self, enable: bool) -> Result<(), XenError> {
183 let rc = unsafe {
184 xc_monitor_privileged_call(self.interface.handle.0, self.domain_id.0, enable)
185 };
186 xc_check_error!(self.interface.handle.0, rc);
187 Ok(())
188 }
189
190 pub fn emul_unimplemented(&self, enable: bool) -> Result<(), XenError> {
191 let rc = unsafe {
192 xc_monitor_emul_unimplemented(self.interface.handle.0, self.domain_id.0, enable)
193 };
194 xc_check_error!(self.interface.handle.0, rc);
195 Ok(())
196 }
197
198 pub fn vmexit(&self, enable: bool, sync: bool) -> Result<(), XenError> {
199 let rc =
200 unsafe { xc_monitor_vmexit(self.interface.handle.0, self.domain_id.0, enable, sync) };
201 xc_check_error!(self.interface.handle.0, rc);
202 Ok(())
203 }
204
205 pub fn io(&self, enable: bool) -> Result<(), XenError> {
206 let rc = unsafe { xc_monitor_io(self.interface.handle.0, self.domain_id.0, enable) };
207 xc_check_error!(self.interface.handle.0, rc);
208 Ok(())
209 }
210
211 pub fn emulate_each_rep(&self, enable: bool) -> Result<(), XenError> {
212 let rc = unsafe {
213 xc_monitor_emulate_each_rep(self.interface.handle.0, self.domain_id.0, enable)
214 };
215 xc_check_error!(self.interface.handle.0, rc);
216 Ok(())
217 }
218}
219
220impl Drop for XenMonitor {
221 fn drop(&mut self) {
222 tracing::trace!(?self.domain_id, "disabling monitor");
223 unsafe {
224 xc_monitor_disable(self.interface.handle.0, self.domain_id.0);
225 }
226 }
227}