Skip to main content

xen/ctrl/event/
mod.rs

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, // may be used during request and response
43    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            /* if flags.contains(VmEventFlag::SET_REGISTERS) */
98            {
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}