1use std::{io::ErrorKind, time::Duration};
2
3use super::{VmiState, context::VmiContext};
4use crate::{
5 Architecture, VcpuId, VmiCore, VmiError, VmiHandler,
6 driver::{VmiDriver, VmiEventControl, VmiQueryRegisters, VmiVmControl},
7 os::{NoOS, VmiOs},
8};
9
10pub struct VmiSession<'a, Os>
16where
17 Os: VmiOs,
18{
19 core: &'a VmiCore<Os::Driver>,
21
22 os: &'a Os,
24}
25
26impl<Os> Clone for VmiSession<'_, Os>
27where
28 Os: VmiOs,
29{
30 fn clone(&self) -> Self {
31 *self
32 }
33}
34
35impl<Os> Copy for VmiSession<'_, Os> where Os: VmiOs {}
36
37impl<Os> std::ops::Deref for VmiSession<'_, Os>
38where
39 Os: VmiOs,
40{
41 type Target = VmiCore<Os::Driver>;
42
43 fn deref(&self) -> &Self::Target {
44 self.core
45 }
46}
47
48impl<'a, Os> VmiSession<'a, Os>
49where
50 Os: VmiOs,
51{
52 pub fn new(core: &'a VmiCore<Os::Driver>, os: &'a Os) -> Self {
54 Self { core, os }
55 }
56
57 pub fn with_registers(
59 &'a self,
60 registers: &'a <Os::Architecture as Architecture>::Registers,
61 ) -> VmiState<'a, Os> {
62 VmiState::new(self, registers)
63 }
64
65 pub fn without_os(&self) -> VmiSession<'a, NoOS<Os::Driver>> {
67 VmiSession {
68 core: self.core,
69 os: const { &NoOS(std::marker::PhantomData) },
70 }
71 }
72
73 pub fn core(&self) -> &'a VmiCore<Os::Driver> {
75 self.core
76 }
77
78 pub fn underlying_os(&self) -> &'a Os {
80 self.os
81 }
82}
83
84impl<'a, Os> VmiSession<'a, Os>
89where
90 Os: VmiOs,
91 Os::Driver: VmiEventControl,
92{
93 pub fn wait_for_event(
99 &self,
100 timeout: Duration,
101 handler: &mut impl VmiHandler<Os>,
102 ) -> Result<(), VmiError> {
103 self.core.wait_for_event(timeout, |event| {
104 let state = VmiState::new(self, event.registers());
105 handler.handle_event(VmiContext::new(&state, event))
106 })
107 }
108}
109
110impl<'a, Os> VmiSession<'a, Os>
115where
116 Os: VmiOs,
117 Os::Driver: VmiEventControl + VmiVmControl,
118{
119 pub fn handle<Handler>(
122 &self,
123 handler_factory: impl FnOnce(&VmiSession<Os>) -> Result<Handler, VmiError>,
124 ) -> Result<Option<Handler::Output>, VmiError>
125 where
126 Handler: VmiHandler<Os>,
127 {
128 self.handle_with_timeout(Duration::from_millis(5000), handler_factory)
129 }
130
131 pub fn handle_with_timeout<Handler>(
134 &self,
135 timeout: Duration,
136 handler_factory: impl FnOnce(&VmiSession<Os>) -> Result<Handler, VmiError>,
137 ) -> Result<Option<Handler::Output>, VmiError>
138 where
139 Handler: VmiHandler<Os>,
140 {
141 let mut result;
142 let mut interrupted = false;
143 let mut handler = handler_factory(self)?;
144
145 loop {
146 result = handler.poll();
147
148 if result.is_some() {
149 break;
150 }
151
152 match self.wait_for_event(timeout, &mut handler) {
153 Ok(_) => {}
154 Err(VmiError::Timeout) => {
155 tracing::trace!("timeout");
156 handler.handle_timeout(self);
157 }
158 Err(VmiError::Io(err)) if err.kind() == ErrorKind::Interrupted => {
159 tracing::trace!("interrupted");
160
161 if interrupted {
164 tracing::warn!("interrupted again");
165 }
166
167 if interrupted || handler.handle_interrupted(self).is_break() {
168 result = handler.poll();
169 break;
170 }
171
172 interrupted = true;
173 }
174 Err(err) => return Err(err),
175 }
176 }
177
178 tracing::trace!("disabling monitor");
179
180 let pause_guard = self.core().pause_guard();
189 handler.cleanup(self);
190 self.core.reset_state()?;
191 let _pause_guard = pause_guard?;
192
193 tracing::trace!(pending_events = self.events_pending());
194
195 if self.events_pending() > 0 {
196 match self.wait_for_event(Duration::from_millis(0), &mut handler) {
197 Err(VmiError::Timeout) => {
198 tracing::trace!("timeout");
199 }
200 Err(err) => return Err(err),
201 Ok(_) => {}
202 }
203
204 self.core.reset_state()?;
211 }
212
213 Ok(result)
214 }
215}
216
217impl<'a, Os> VmiSession<'a, Os>
222where
223 Os: VmiOs,
224 Os::Driver: VmiQueryRegisters + VmiVmControl,
225{
226 pub fn pause_guard(&self) -> Result<VmiSessionPauseGuard<'_, Os>, VmiError> {
229 VmiSessionPauseGuard::new(self)
230 }
231}
232
233pub struct VmiSessionPauseGuard<'a, Os>
243where
244 Os: VmiOs,
245 Os::Driver: VmiQueryRegisters + VmiVmControl,
246{
247 session: &'a VmiSession<'a, Os>,
248 registers: <<Os::Driver as VmiDriver>::Architecture as Architecture>::Registers,
249}
250
251impl<'a, Os> VmiSessionPauseGuard<'a, Os>
252where
253 Os: VmiOs,
254 Os::Driver: VmiQueryRegisters + VmiVmControl,
255{
256 pub fn new(session: &'a VmiSession<'a, Os>) -> Result<Self, VmiError> {
258 session.driver().pause()?;
259
260 let registers = match session.registers(VcpuId(0)) {
261 Ok(registers) => registers,
262 Err(err) => {
263 if let Err(resume_err) = session.driver().resume() {
264 tracing::error!(
265 err = %resume_err,
266 "failed to resume after register-query failure"
267 );
268 }
269 return Err(err);
270 }
271 };
272
273 Ok(Self { session, registers })
274 }
275
276 pub fn session(&self) -> &VmiSession<'a, Os> {
278 self.session
279 }
280
281 pub fn registers(&self) -> &<Os::Architecture as Architecture>::Registers {
284 &self.registers
285 }
286
287 pub fn state(&self) -> VmiState<'_, Os> {
290 VmiState::new(self.session, &self.registers)
291 }
292}
293
294impl<Os> Drop for VmiSessionPauseGuard<'_, Os>
295where
296 Os: VmiOs,
297 Os::Driver: VmiQueryRegisters + VmiVmControl,
298{
299 fn drop(&mut self) {
300 if let Err(err) = self.session.driver().resume() {
301 tracing::error!(%err, "failed to resume the virtual machine");
302 }
303 }
304}