1use std::{io::ErrorKind, time::Duration};
2
3use super::{VmiState, context::VmiContext};
4use crate::{
5 Architecture, VmiCore, VmiDriver, VmiError, VmiHandler,
6 os::{NoOS, VmiOs},
7};
8
9pub struct VmiSession<'a, Driver, Os = NoOS>
15where
16 Driver: VmiDriver,
17 Os: VmiOs<Driver>,
18{
19 core: &'a VmiCore<Driver>,
21
22 os: &'a Os,
24}
25
26impl<Driver, Os> Clone for VmiSession<'_, Driver, Os>
27where
28 Driver: VmiDriver,
29 Os: VmiOs<Driver>,
30{
31 fn clone(&self) -> Self {
32 *self
33 }
34}
35
36impl<Driver, Os> Copy for VmiSession<'_, Driver, Os>
37where
38 Driver: VmiDriver,
39 Os: VmiOs<Driver>,
40{
41}
42
43impl<Driver, Os> std::ops::Deref for VmiSession<'_, Driver, Os>
44where
45 Driver: VmiDriver,
46 Os: VmiOs<Driver>,
47{
48 type Target = VmiCore<Driver>;
49
50 fn deref(&self) -> &Self::Target {
51 self.core
52 }
53}
54
55impl<'a, Driver, Os> VmiSession<'a, Driver, Os>
56where
57 Driver: VmiDriver,
58 Os: VmiOs<Driver>,
59{
60 pub fn new(core: &'a VmiCore<Driver>, os: &'a Os) -> Self {
62 Self { core, os }
63 }
64
65 pub fn with_registers(
67 &'a self,
68 registers: &'a <Driver::Architecture as Architecture>::Registers,
69 ) -> VmiState<'a, Driver, Os> {
70 VmiState::new(self, registers)
71 }
72
73 pub fn without_os(&self) -> VmiSession<'a, Driver, NoOS> {
75 VmiSession {
76 core: self.core,
77 os: &NoOS,
78 }
79 }
80
81 pub fn core(&self) -> &'a VmiCore<Driver> {
83 self.core
84 }
85
86 pub fn underlying_os(&self) -> &'a Os {
88 self.os
89 }
90
91 pub fn wait_for_event(
97 &self,
98 timeout: Duration,
99 handler: &mut impl VmiHandler<Driver, Os>,
100 ) -> Result<(), VmiError> {
101 self.core.wait_for_event(timeout, |event| {
102 let state = VmiState::new(self, event.registers());
103 handler.handle_event(VmiContext::new(&state, event))
104 })
105 }
106
107 pub fn handle<Handler>(
110 &self,
111 handler_factory: impl FnOnce(&VmiSession<Driver, Os>) -> Result<Handler, VmiError>,
112 ) -> Result<Option<Handler::Output>, VmiError>
113 where
114 Handler: VmiHandler<Driver, Os>,
115 {
116 self.handle_with_timeout(Duration::from_millis(5000), handler_factory)
117 }
118
119 pub fn handle_with_timeout<Handler>(
122 &self,
123 timeout: Duration,
124 handler_factory: impl FnOnce(&VmiSession<Driver, Os>) -> Result<Handler, VmiError>,
125 ) -> Result<Option<Handler::Output>, VmiError>
126 where
127 Handler: VmiHandler<Driver, Os>,
128 {
129 let mut result;
130 let mut handler = handler_factory(self)?;
131
132 loop {
133 result = handler.check_completion();
134
135 if result.is_some() {
136 break;
137 }
138
139 match self.wait_for_event(timeout, &mut handler) {
140 Err(VmiError::Timeout) => {
141 tracing::trace!("timeout");
142 handler.handle_timeout(self);
143 }
144 Err(VmiError::Io(err)) if err.kind() == ErrorKind::Interrupted => {
145 tracing::trace!("interrupted");
146 handler.handle_interrupted(self);
147 break;
148 }
149 Err(err) => return Err(err),
150 Ok(_) => {}
151 }
152 }
153
154 tracing::trace!("disabling monitor");
155 self.core.reset_state()?;
156 tracing::trace!(pending_events = self.events_pending());
157
158 let _pause_guard = self.pause_guard()?;
159 if self.events_pending() > 0 {
160 match self.wait_for_event(Duration::from_millis(0), &mut handler) {
161 Err(VmiError::Timeout) => {
162 tracing::trace!("timeout");
163 }
164 Err(err) => return Err(err),
165 Ok(_) => {}
166 }
167 }
168
169 Ok(result)
170 }
171}