xref: /cloud-hypervisor/hypervisor/src/vm.rs (revision 7d7bfb2034001d4cb15df2ddc56d2d350c8da30f)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5 // Copyright © 2020, Microsoft Corporation
6 //
7 // Copyright 2018-2019 CrowdStrike, Inc.
8 //
9 //
10 
11 #[cfg(target_arch = "aarch64")]
12 use crate::aarch64::VcpuInit;
13 use crate::cpu::Vcpu;
14 use crate::device::Device;
15 #[cfg(feature = "tdx")]
16 use crate::x86_64::CpuId;
17 #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
18 use crate::ClockData;
19 use crate::CreateDevice;
20 #[cfg(feature = "mshv")]
21 use crate::HvState as VmState;
22 #[cfg(feature = "kvm")]
23 use crate::KvmVmState as VmState;
24 use crate::{IoEventAddress, IrqRoutingEntry, MemoryRegion};
25 #[cfg(feature = "kvm")]
26 use kvm_ioctls::Cap;
27 #[cfg(target_arch = "x86_64")]
28 use std::fs::File;
29 use std::sync::Arc;
30 use thiserror::Error;
31 use vmm_sys_util::eventfd::EventFd;
32 
33 ///
34 /// I/O events data matches (32 or 64 bits).
35 ///
36 #[derive(Debug)]
37 pub enum DataMatch {
38     DataMatch32(u32),
39     DataMatch64(u64),
40 }
41 
42 impl From<DataMatch> for u64 {
43     fn from(dm: DataMatch) -> u64 {
44         match dm {
45             DataMatch::DataMatch32(dm) => dm.into(),
46             DataMatch::DataMatch64(dm) => dm,
47         }
48     }
49 }
50 
51 #[derive(Error, Debug)]
52 ///
53 /// Enum for VM error
54 pub enum HypervisorVmError {
55     ///
56     /// Create Vcpu error
57     ///
58     #[error("Failed to create Vcpu: {0}")]
59     CreateVcpu(#[source] anyhow::Error),
60     ///
61     /// Identity map address error
62     ///
63     #[error("Failed to set identity map address: {0}")]
64     SetIdentityMapAddress(#[source] anyhow::Error),
65     ///
66     /// TSS address error
67     ///
68     #[error("Failed to set TSS address: {0}")]
69     SetTssAddress(#[source] anyhow::Error),
70     ///
71     /// Create interrupt controller error
72     ///
73     #[error("Failed to create interrupt controller: {0}")]
74     CreateIrq(#[source] anyhow::Error),
75     ///
76     /// Register interrupt event error
77     ///
78     #[error("Failed to register interrupt event: {0}")]
79     RegisterIrqFd(#[source] anyhow::Error),
80     ///
81     /// Un register interrupt event error
82     ///
83     #[error("Failed to unregister interrupt event: {0}")]
84     UnregisterIrqFd(#[source] anyhow::Error),
85     ///
86     /// Register IO event error
87     ///
88     #[error("Failed to register IO event: {0}")]
89     RegisterIoEvent(#[source] anyhow::Error),
90     ///
91     /// Unregister IO event error
92     ///
93     #[error("Failed to unregister IO event: {0}")]
94     UnregisterIoEvent(#[source] anyhow::Error),
95     ///
96     /// Set GSI routing error
97     ///
98     #[error("Failed to set GSI routing: {0}")]
99     SetGsiRouting(#[source] anyhow::Error),
100     ///
101     /// Create user memory error
102     ///
103     #[error("Failed to create user memory: {0}")]
104     CreateUserMemory(#[source] anyhow::Error),
105     ///
106     /// Remove user memory region error
107     ///
108     #[error("Failed to remove user memory: {0}")]
109     RemoveUserMemory(#[source] anyhow::Error),
110     ///
111     /// Create device error
112     ///
113     #[error("Failed to set GSI routing: {0}")]
114     CreateDevice(#[source] anyhow::Error),
115     ///
116     /// Get preferred target error
117     ///
118     #[error("Failed to get preferred target: {0}")]
119     GetPreferredTarget(#[source] anyhow::Error),
120     ///
121     /// Enable split Irq error
122     ///
123     #[error("Failed to enable split Irq: {0}")]
124     EnableSplitIrq(#[source] anyhow::Error),
125     ///
126     /// Enable SGX attribute error
127     ///
128     #[error("Failed to enable SGX attribute: {0}")]
129     EnableSgxAttribute(#[source] anyhow::Error),
130     ///
131     /// Get clock error
132     ///
133     #[error("Failed to get clock: {0}")]
134     GetClock(#[source] anyhow::Error),
135     ///
136     /// Set clock error
137     ///
138     #[error("Failed to set clock: {0}")]
139     SetClock(#[source] anyhow::Error),
140     ///
141     /// Create passthrough device
142     ///
143     #[error("Failed to create passthrough device: {0}")]
144     CreatePassthroughDevice(#[source] anyhow::Error),
145     /// Write to Guest memory
146     ///
147     #[error("Failed to write to guest memory: {0}")]
148     GuestMemWrite(#[source] anyhow::Error),
149     ///
150     /// Read Guest memory
151     ///
152     #[error("Failed to read guest memory: {0}")]
153     GuestMemRead(#[source] anyhow::Error),
154     ///
155     /// Read from MMIO Bus
156     ///
157     #[error("Failed to read from MMIO Bus: {0}")]
158     MmioBusRead(#[source] anyhow::Error),
159     ///
160     /// Write to MMIO Bus
161     ///
162     #[error("Failed to write to MMIO Bus: {0}")]
163     MmioBusWrite(#[source] anyhow::Error),
164     ///
165     /// Read from IO Bus
166     ///
167     #[error("Failed to read from IO Bus: {0}")]
168     IoBusRead(#[source] anyhow::Error),
169     ///
170     /// Write to IO Bus
171     ///
172     #[error("Failed to write to IO Bus: {0}")]
173     IoBusWrite(#[source] anyhow::Error),
174     ///
175     /// Start dirty log error
176     ///
177     #[error("Failed to get dirty log: {0}")]
178     StartDirtyLog(#[source] anyhow::Error),
179     ///
180     /// Stop dirty log error
181     ///
182     #[error("Failed to get dirty log: {0}")]
183     StopDirtyLog(#[source] anyhow::Error),
184     ///
185     /// Get dirty log error
186     ///
187     #[error("Failed to get dirty log: {0}")]
188     GetDirtyLog(#[source] anyhow::Error),
189     ///
190     /// Assert virtual interrupt error
191     ///
192     #[error("Failed to assert virtual Interrupt: {0}")]
193     AsserttVirtualInterrupt(#[source] anyhow::Error),
194 
195     #[cfg(feature = "tdx")]
196     ///
197     /// Error initializing TDX on the VM
198     ///
199     #[error("Failed to initialize TDX: {0}")]
200     InitializeTdx(#[source] std::io::Error),
201     #[cfg(feature = "tdx")]
202     ///
203     /// Error finalizing the TDX configuration on the VM
204     ///
205     #[error("Failed to finalize TDX: {0}")]
206     FinalizeTdx(#[source] std::io::Error),
207     #[cfg(feature = "tdx")]
208     ///
209     /// Error initializing the TDX memory region
210     ///
211     #[error("Failed to initialize memory region TDX: {0}")]
212     InitMemRegionTdx(#[source] std::io::Error),
213 }
214 ///
215 /// Result type for returning from a function
216 ///
217 pub type Result<T> = std::result::Result<T, HypervisorVmError>;
218 
219 ///
220 /// Trait to represent a Vm
221 ///
222 /// This crate provides a hypervisor-agnostic interfaces for Vm
223 ///
224 pub trait Vm: Send + Sync {
225     #[cfg(target_arch = "x86_64")]
226     /// Sets the address of the one-page region in the VM's address space.
227     fn set_identity_map_address(&self, address: u64) -> Result<()>;
228     #[cfg(target_arch = "x86_64")]
229     /// Sets the address of the three-page region in the VM's address space.
230     fn set_tss_address(&self, offset: usize) -> Result<()>;
231     /// Creates an in-kernel interrupt controller.
232     fn create_irq_chip(&self) -> Result<()>;
233     /// Registers an event that will, when signaled, trigger the `gsi` IRQ.
234     fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
235     /// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
236     fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
237     /// Creates a new KVM vCPU file descriptor and maps the memory corresponding
238     fn create_vcpu(&self, id: u8, vmmops: Option<Arc<dyn VmmOps>>) -> Result<Arc<dyn Vcpu>>;
239     /// Registers an event to be signaled whenever a certain address is written to.
240     fn register_ioevent(
241         &self,
242         fd: &EventFd,
243         addr: &IoEventAddress,
244         datamatch: Option<DataMatch>,
245     ) -> Result<()>;
246     /// Unregister an event from a certain address it has been previously registered to.
247     fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
248     /// Sets the GSI routing table entries, overwriting any previously set
249     fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
250     /// Creates a memory region structure that can be used with {create/remove}_user_memory_region
251     fn make_user_memory_region(
252         &self,
253         slot: u32,
254         guest_phys_addr: u64,
255         memory_size: u64,
256         userspace_addr: u64,
257         readonly: bool,
258         log_dirty_pages: bool,
259     ) -> MemoryRegion;
260     /// Creates a guest physical memory slot.
261     fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
262     /// Removes a guest physical memory slot.
263     fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> Result<()>;
264     /// Creates an emulated device in the kernel.
265     fn create_device(&self, device: &mut CreateDevice) -> Result<Arc<dyn Device>>;
266     /// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
267     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
268     fn get_preferred_target(&self, kvi: &mut VcpuInit) -> Result<()>;
269     /// Enable split Irq capability
270     #[cfg(target_arch = "x86_64")]
271     fn enable_split_irq(&self) -> Result<()>;
272     #[cfg(target_arch = "x86_64")]
273     fn enable_sgx_attribute(&self, file: File) -> Result<()>;
274     /// Retrieve guest clock.
275     #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
276     fn get_clock(&self) -> Result<ClockData>;
277     /// Set guest clock.
278     #[cfg(all(feature = "kvm", target_arch = "x86_64"))]
279     fn set_clock(&self, data: &ClockData) -> Result<()>;
280     #[cfg(feature = "kvm")]
281     /// Checks if a particular `Cap` is available.
282     fn check_extension(&self, c: Cap) -> bool;
283     /// Create a device that is used for passthrough
284     fn create_passthrough_device(&self) -> Result<Arc<dyn Device>>;
285     /// Get the Vm state. Return VM specific data
286     fn state(&self) -> Result<VmState>;
287     /// Set the VM state
288     fn set_state(&self, state: VmState) -> Result<()>;
289     /// Start logging dirty pages
290     fn start_dirty_log(&self) -> Result<()>;
291     /// Stop logging dirty pages
292     fn stop_dirty_log(&self) -> Result<()>;
293     /// Get dirty pages bitmap
294     fn get_dirty_log(&self, slot: u32, base_gpa: u64, memory_size: u64) -> Result<Vec<u64>>;
295     #[cfg(feature = "tdx")]
296     /// Initalize TDX on this VM
297     fn tdx_init(&self, cpuid: &CpuId, max_vcpus: u32) -> Result<()>;
298     #[cfg(feature = "tdx")]
299     /// Finalize the configuration of TDX on this VM
300     fn tdx_finalize(&self) -> Result<()>;
301     #[cfg(feature = "tdx")]
302     /// Initalize a TDX memory region for this VM
303     fn tdx_init_memory_region(
304         &self,
305         host_address: u64,
306         guest_address: u64,
307         size: u64,
308         measure: bool,
309     ) -> Result<()>;
310 }
311 
312 pub trait VmmOps: Send + Sync {
313     fn guest_mem_write(&self, gpa: u64, buf: &[u8]) -> Result<usize>;
314     fn guest_mem_read(&self, gpa: u64, buf: &mut [u8]) -> Result<usize>;
315     fn mmio_read(&self, gpa: u64, data: &mut [u8]) -> Result<()>;
316     fn mmio_write(&self, gpa: u64, data: &[u8]) -> Result<()>;
317     #[cfg(target_arch = "x86_64")]
318     fn pio_read(&self, port: u64, data: &mut [u8]) -> Result<()>;
319     #[cfg(target_arch = "x86_64")]
320     fn pio_write(&self, port: u64, data: &[u8]) -> Result<()>;
321 }
322