1pub mod arch;
2mod data;
3mod flags;
4mod reason;
5mod regs;
6mod selector;
7
8use xen_sys::{
9 VM_EVENT_INTERFACE_VERSION, VM_EVENT_REASON_CPUID, VM_EVENT_REASON_DEBUG_EXCEPTION,
10 VM_EVENT_REASON_DESCRIPTOR_ACCESS, VM_EVENT_REASON_EMUL_UNIMPLEMENTED,
11 VM_EVENT_REASON_GUEST_REQUEST, VM_EVENT_REASON_INTERRUPT, VM_EVENT_REASON_IO_INSTRUCTION,
12 VM_EVENT_REASON_MEM_ACCESS, VM_EVENT_REASON_MEM_PAGING, VM_EVENT_REASON_MEM_SHARING,
13 VM_EVENT_REASON_MOV_TO_MSR, VM_EVENT_REASON_PRIVILEGED_CALL, VM_EVENT_REASON_SINGLESTEP,
14 VM_EVENT_REASON_SOFTWARE_BREAKPOINT, VM_EVENT_REASON_UNKNOWN, VM_EVENT_REASON_VMEXIT,
15 VM_EVENT_REASON_WRITE_CTRLREG, vm_event_st,
16};
17
18pub use self::{
19 arch::x86::VmEventRegsX86,
20 data::{VmEventData, VmEventEmulInsnData, VmEventEmulReadData},
21 flags::VmEventFlag,
22 reason::{
23 VmEventCpuid, VmEventCtrlReg, VmEventDebug, VmEventDescriptorAccess, VmEventFastSinglestep,
24 VmEventInterrupt, VmEventIo, VmEventMemAccess, VmEventMovToMsr, VmEventPaging,
25 VmEventReason, VmEventSharing, VmEventSinglestep, VmEventVmExit, VmEventWriteCtrlReg,
26 },
27 regs::VmEventRegs,
28 selector::VmEventSelectorReg,
29};
30use crate::VcpuId;
31
32#[derive(Debug, Default)]
33pub struct VmEventFlagOptions {
34 pub fast_singlestep: Option<VmEventFastSinglestep>,
35}
36
37#[derive(Debug)]
38pub struct VmEvent {
39 pub flags: VmEventFlag,
40 pub reason: VmEventReason,
41 pub vcpu_id: VcpuId,
42 pub altp2m_idx: u16, pub options: Option<VmEventFlagOptions>,
44 pub data: Option<VmEventData>,
45}
46
47impl From<vm_event_st> for VmEvent {
48 fn from(value: vm_event_st) -> Self {
49 let flags = VmEventFlag::from_bits_truncate(value.flags);
50
51 let reason = unsafe {
52 match value.reason {
53 VM_EVENT_REASON_MEM_ACCESS => {
54 VmEventReason::MemoryAccess(value.u.mem_access.into())
55 }
56 VM_EVENT_REASON_MEM_SHARING => {
57 VmEventReason::MemorySharing(value.u.mem_sharing.into())
58 }
59 VM_EVENT_REASON_MEM_PAGING => {
60 VmEventReason::MemoryPaging(value.u.mem_paging.into())
61 }
62 VM_EVENT_REASON_WRITE_CTRLREG => {
63 VmEventReason::WriteCtrlReg(value.u.write_ctrlreg.into())
64 }
65 VM_EVENT_REASON_MOV_TO_MSR => VmEventReason::MovToMsr(value.u.mov_to_msr.into()),
66 VM_EVENT_REASON_SOFTWARE_BREAKPOINT => {
67 VmEventReason::SoftwareBreakpoint(value.u.software_breakpoint.into())
68 }
69 VM_EVENT_REASON_SINGLESTEP => VmEventReason::Singlestep(value.u.singlestep.into()),
70 VM_EVENT_REASON_GUEST_REQUEST => VmEventReason::GuestRequest,
71 VM_EVENT_REASON_DEBUG_EXCEPTION => {
72 VmEventReason::DebugException(value.u.debug_exception.into())
73 }
74 VM_EVENT_REASON_CPUID => VmEventReason::Cpuid(value.u.cpuid.into()),
75 VM_EVENT_REASON_PRIVILEGED_CALL => VmEventReason::PrivilegedCall,
76 VM_EVENT_REASON_INTERRUPT => VmEventReason::Interrupt(value.u.interrupt.x86.into()),
77 VM_EVENT_REASON_DESCRIPTOR_ACCESS => {
78 VmEventReason::DescriptorAccess(value.u.desc_access.into())
79 }
80 VM_EVENT_REASON_EMUL_UNIMPLEMENTED => VmEventReason::EmulUnimplemented,
81 VM_EVENT_REASON_VMEXIT => VmEventReason::VmExit(value.u.vmexit.into()),
82 VM_EVENT_REASON_IO_INSTRUCTION => VmEventReason::IoInstruction(value.u.io.into()),
83 _ => VmEventReason::Unknown,
84 }
85 };
86
87 let data = unsafe {
88 if flags.contains(VmEventFlag::SET_EMUL_READ_DATA) {
89 Some(VmEventData::EmulReadData(value.data.emul.read.into()))
90 }
91 else if flags.contains(VmEventFlag::SET_EMUL_INSN_DATA) {
92 Some(VmEventData::EmulInstructionData(
93 value.data.emul.insn.into(),
94 ))
95 }
96 else
97 {
99 Some(VmEventData::Registers(value.data.regs.x86.into()))
100 }
101 };
102
103 Self {
104 flags,
105 reason,
106 vcpu_id: VcpuId(value.vcpu_id as u16),
107 altp2m_idx: value.altp2m_idx,
108 options: None,
109 data,
110 }
111 }
112}
113
114impl From<VmEvent> for vm_event_st {
115 fn from(value: VmEvent) -> Self {
116 let mut result = Self {
117 version: VM_EVENT_INTERFACE_VERSION,
118 flags: value.flags.bits(),
119 vcpu_id: value.vcpu_id.0.into(),
120 altp2m_idx: value.altp2m_idx,
121 ..Default::default()
122 };
123
124 match value.reason {
125 VmEventReason::Unknown => {
126 result.reason = VM_EVENT_REASON_UNKNOWN;
127 }
128 VmEventReason::MemoryAccess(data) => {
129 result.reason = VM_EVENT_REASON_MEM_ACCESS;
130 result.u.mem_access = data.into();
131 }
132 VmEventReason::MemorySharing(data) => {
133 result.reason = VM_EVENT_REASON_MEM_SHARING;
134 result.u.mem_sharing = data.into();
135 }
136 VmEventReason::MemoryPaging(data) => {
137 result.reason = VM_EVENT_REASON_MEM_PAGING;
138 result.u.mem_paging = data.into();
139 }
140 VmEventReason::WriteCtrlReg(data) => {
141 result.reason = VM_EVENT_REASON_WRITE_CTRLREG;
142 result.u.write_ctrlreg = data.into();
143 }
144 VmEventReason::MovToMsr(data) => {
145 result.reason = VM_EVENT_REASON_MOV_TO_MSR;
146 result.u.mov_to_msr = data.into();
147 }
148 VmEventReason::SoftwareBreakpoint(data) => {
149 result.reason = VM_EVENT_REASON_SOFTWARE_BREAKPOINT;
150 result.u.software_breakpoint = data.into();
151 }
152 VmEventReason::Singlestep(data) => {
153 result.reason = VM_EVENT_REASON_SINGLESTEP;
154 result.u.singlestep = data.into();
155 }
156 VmEventReason::GuestRequest => {
157 result.reason = VM_EVENT_REASON_GUEST_REQUEST;
158 }
159 VmEventReason::DebugException(data) => {
160 result.reason = VM_EVENT_REASON_DEBUG_EXCEPTION;
161 result.u.debug_exception = data.into();
162 }
163 VmEventReason::Cpuid(data) => {
164 result.reason = VM_EVENT_REASON_CPUID;
165 result.u.cpuid = data.into();
166 }
167 VmEventReason::PrivilegedCall => {
168 result.reason = VM_EVENT_REASON_PRIVILEGED_CALL;
169 }
170 VmEventReason::Interrupt(data) => {
171 result.reason = VM_EVENT_REASON_INTERRUPT;
172 result.u.interrupt.x86 = data.into();
173 }
174 VmEventReason::DescriptorAccess(data) => {
175 result.reason = VM_EVENT_REASON_DESCRIPTOR_ACCESS;
176 result.u.desc_access = data.into();
177 }
178 VmEventReason::EmulUnimplemented => {
179 result.reason = VM_EVENT_REASON_EMUL_UNIMPLEMENTED;
180 }
181 VmEventReason::VmExit(data) => {
182 result.reason = VM_EVENT_REASON_VMEXIT;
183 result.u.vmexit = data.into();
184 }
185 VmEventReason::IoInstruction(data) => {
186 result.reason = VM_EVENT_REASON_IO_INSTRUCTION;
187 result.u.io = data.into();
188 }
189 }
190
191 #[expect(clippy::single_match)]
192 match value.options {
193 Some(VmEventFlagOptions {
194 fast_singlestep: Some(fast_singlestep),
195 }) => {
196 if value.flags.contains(VmEventFlag::FAST_SINGLESTEP) {
197 result.u.fast_singlestep = fast_singlestep.into();
198 }
199 else {
200 result.flags &= !VmEventFlag::FAST_SINGLESTEP.bits();
201 }
202 }
203 _ => {}
204 }
205
206 match value.data {
207 Some(VmEventData::EmulReadData(data)) => {
208 result.data.emul.read = data.into();
209 }
210 Some(VmEventData::EmulInstructionData(data)) => {
211 result.data.emul.insn = data.into();
212 }
213 Some(VmEventData::Registers(data)) => {
214 result.data.regs.x86 = data.into();
215 }
216 _ => {}
217 }
218
219 result
220 }
221}