1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 pub mod geniezone_sys;
6
7 use std::cmp::Reverse;
8 use std::collections::BTreeMap;
9 use std::collections::BinaryHeap;
10 use std::convert::TryFrom;
11 use std::ffi::CString;
12 use std::os::raw::c_ulong;
13 use std::os::unix::prelude::OsStrExt;
14 use std::path::Path;
15 use std::path::PathBuf;
16 use std::sync::Arc;
17
18 use base::errno_result;
19 use base::error;
20 use base::ioctl;
21 use base::ioctl_with_ref;
22 use base::ioctl_with_val;
23 use base::pagesize;
24 use base::AsRawDescriptor;
25 use base::Error;
26 use base::Event;
27 use base::FromRawDescriptor;
28 use base::MappedRegion;
29 use base::MemoryMapping;
30 use base::MemoryMappingBuilder;
31 use base::MmapError;
32 use base::Protection;
33 use base::RawDescriptor;
34 use base::Result;
35 use base::SafeDescriptor;
36 use cros_fdt::Fdt;
37 #[cfg(feature = "gdb")]
38 use gdbstub::arch::Arch;
39 #[cfg(feature = "gdb")]
40 use gdbstub_arch::aarch64::reg::id::AArch64RegId;
41 #[cfg(feature = "gdb")]
42 use gdbstub_arch::aarch64::AArch64 as GdbArch;
43 pub use geniezone_sys::*;
44 use libc::open;
45 use libc::EFAULT;
46 use libc::EINVAL;
47 use libc::EIO;
48 use libc::ENOENT;
49 use libc::ENOMEM;
50 use libc::ENOSPC;
51 use libc::ENOTSUP;
52 use libc::EOVERFLOW;
53 use libc::O_CLOEXEC;
54 use libc::O_RDWR;
55 use sync::Mutex;
56 use vm_memory::GuestAddress;
57 use vm_memory::GuestMemory;
58 use vm_memory::MemoryRegionPurpose;
59
60 use crate::BalloonEvent;
61 use crate::ClockState;
62 use crate::Config;
63 use crate::Datamatch;
64 use crate::DeviceKind;
65 use crate::HypervHypercall;
66 use crate::Hypervisor;
67 use crate::HypervisorCap;
68 use crate::IoEventAddress;
69 use crate::IoOperation;
70 use crate::IoParams;
71 use crate::MemCacheType;
72 use crate::MemSlot;
73 use crate::PsciVersion;
74 use crate::Vcpu;
75 use crate::VcpuAArch64;
76 use crate::VcpuExit;
77 use crate::VcpuFeature;
78 use crate::VcpuRegAArch64;
79 use crate::VcpuSignalHandle;
80 use crate::VcpuSignalHandleInner;
81 use crate::Vm;
82 use crate::VmAArch64;
83 use crate::VmCap;
84 use crate::PSCI_0_2;
85
86 impl Geniezone {
87 /// Get the size of guest physical addresses (IPA) in bits.
get_guest_phys_addr_bits(&self) -> u888 pub fn get_guest_phys_addr_bits(&self) -> u8 {
89 // SAFETY:
90 // Safe because we know self is a real geniezone fd
91 match unsafe {
92 ioctl_with_val(
93 self,
94 GZVM_CHECK_EXTENSION(),
95 GZVM_CAP_ARM_VM_IPA_SIZE.into(),
96 )
97 } {
98 // Default physical address size is 40 bits if the extension is not supported.
99 ret if ret <= 0 => 40,
100 ipa => ipa as u8,
101 }
102 }
103 }
104
105 impl GeniezoneVm {
106 /// Does platform specific initialization for the GeniezoneVm.
init_arch(&self, cfg: &Config) -> Result<()>107 pub fn init_arch(&self, cfg: &Config) -> Result<()> {
108 #[cfg(target_arch = "aarch64")]
109 if cfg.mte {
110 // SAFETY:
111 // Safe because it does not take pointer arguments.
112 unsafe {
113 self.ctrl_geniezone_enable_capability(GeniezoneCap::ArmMte, &[0, 0, 0, 0, 0])
114 }?;
115 }
116 Ok(())
117 }
118
119 /// Checks if a particular `VmCap` is available, or returns None if arch-independent
120 /// Vm.check_capability() should handle the check.
check_capability_arch(&self, _c: VmCap) -> Option<bool>121 pub fn check_capability_arch(&self, _c: VmCap) -> Option<bool> {
122 None
123 }
124
125 /// Arch-specific implementation of `Vm::get_pvclock`. Always returns an error on AArch64.
get_pvclock_arch(&self) -> Result<ClockState>126 pub fn get_pvclock_arch(&self) -> Result<ClockState> {
127 // TODO: Geniezone not support pvclock currently
128 error!("Geniezone: not support get_pvclock_arch");
129 Err(Error::new(EINVAL))
130 }
131
132 /// Arch-specific implementation of `Vm::set_pvclock`. Always returns an error on AArch64.
set_pvclock_arch(&self, _state: &ClockState) -> Result<()>133 pub fn set_pvclock_arch(&self, _state: &ClockState) -> Result<()> {
134 // TODO: Geniezone not support pvclock currently
135 error!("Geniezone: not support set_pvclock_arch");
136 Err(Error::new(EINVAL))
137 }
138
get_protected_vm_info(&self) -> Result<u64>139 fn get_protected_vm_info(&self) -> Result<u64> {
140 // SAFETY:
141 // Safe because we allocated the struct and we know the kernel won't write beyond the end of
142 // the struct or keep a pointer to it.
143 let cap: gzvm_enable_cap = unsafe {
144 self.ctrl_geniezone_enable_capability(
145 GeniezoneCap::ArmProtectedVm,
146 &[GZVM_CAP_ARM_PVM_GET_PVMFW_SIZE as u64, 0, 0, 0, 0],
147 )
148 }?;
149 Ok(cap.args[1])
150 }
151
set_protected_vm_firmware_ipa(&self, fw_addr: GuestAddress) -> Result<()>152 fn set_protected_vm_firmware_ipa(&self, fw_addr: GuestAddress) -> Result<()> {
153 // SAFETY:
154 // Safe because none of the args are pointers.
155 unsafe {
156 self.ctrl_geniezone_enable_capability(
157 GeniezoneCap::ArmProtectedVm,
158 &[GZVM_CAP_ARM_PVM_SET_PVMFW_IPA as u64, fw_addr.0, 0, 0, 0],
159 )
160 }?;
161 Ok(())
162 }
163 }
164
165 impl VmAArch64 for GeniezoneVm {
get_hypervisor(&self) -> &dyn Hypervisor166 fn get_hypervisor(&self) -> &dyn Hypervisor {
167 &self.geniezone
168 }
169
load_protected_vm_firmware( &mut self, fw_addr: GuestAddress, fw_max_size: u64, ) -> Result<()>170 fn load_protected_vm_firmware(
171 &mut self,
172 fw_addr: GuestAddress,
173 fw_max_size: u64,
174 ) -> Result<()> {
175 let size: u64 = self.get_protected_vm_info()?;
176 if size == 0 {
177 Err(Error::new(EINVAL))
178 } else {
179 if size > fw_max_size {
180 return Err(Error::new(ENOMEM));
181 }
182 self.set_protected_vm_firmware_ipa(fw_addr)
183 }
184 }
185
create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>186 fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>> {
187 Ok(Box::new(GeniezoneVm::create_vcpu(self, id)?))
188 }
189
create_fdt(&self, _fdt: &mut Fdt, _phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()>190 fn create_fdt(&self, _fdt: &mut Fdt, _phandles: &BTreeMap<&str, u32>) -> cros_fdt::Result<()> {
191 Ok(())
192 }
193
init_arch( &self, _payload_entry_address: GuestAddress, fdt_address: GuestAddress, fdt_size: usize, ) -> Result<()>194 fn init_arch(
195 &self,
196 _payload_entry_address: GuestAddress,
197 fdt_address: GuestAddress,
198 fdt_size: usize,
199 ) -> Result<()> {
200 let dtb_config = gzvm_dtb_config {
201 dtb_addr: fdt_address.offset(),
202 dtb_size: fdt_size.try_into().unwrap(),
203 };
204 // SAFETY:
205 // Safe because we allocated the struct and we know the kernel will modify exactly the size
206 // of the struct.
207 let ret = unsafe { ioctl_with_ref(self, GZVM_SET_DTB_CONFIG(), &dtb_config) };
208 if ret == 0 {
209 Ok(())
210 } else {
211 errno_result()
212 }
213 }
214 }
215
216 impl GeniezoneVcpu {
set_one_geniezone_reg_u64( &self, gzvm_reg_id: GeniezoneVcpuRegister, data: u64, ) -> Result<()>217 fn set_one_geniezone_reg_u64(
218 &self,
219 gzvm_reg_id: GeniezoneVcpuRegister,
220 data: u64,
221 ) -> Result<()> {
222 self.set_one_geniezone_reg(gzvm_reg_id, data.to_ne_bytes().as_slice())
223 }
224
set_one_geniezone_reg(&self, gzvm_reg_id: GeniezoneVcpuRegister, data: &[u8]) -> Result<()>225 fn set_one_geniezone_reg(&self, gzvm_reg_id: GeniezoneVcpuRegister, data: &[u8]) -> Result<()> {
226 let onereg = gzvm_one_reg {
227 id: gzvm_reg_id.into(),
228 addr: (data.as_ptr() as usize)
229 .try_into()
230 .expect("can't represent usize as u64"),
231 };
232 // SAFETY:
233 // Safe because we allocated the struct and we know the kernel will read exactly the size of
234 // the struct.
235 let ret = unsafe { ioctl_with_ref(self, GZVM_SET_ONE_REG(), &onereg) };
236 if ret == 0 {
237 Ok(())
238 } else {
239 errno_result()
240 }
241 }
242
get_one_geniezone_reg_u64(&self, gzvm_reg_id: GeniezoneVcpuRegister) -> Result<u64>243 fn get_one_geniezone_reg_u64(&self, gzvm_reg_id: GeniezoneVcpuRegister) -> Result<u64> {
244 let mut bytes = 0u64.to_ne_bytes();
245 self.get_one_geniezone_reg(gzvm_reg_id, bytes.as_mut_slice())?;
246 Ok(u64::from_ne_bytes(bytes))
247 }
248
get_one_geniezone_reg( &self, gzvm_reg_id: GeniezoneVcpuRegister, data: &mut [u8], ) -> Result<()>249 fn get_one_geniezone_reg(
250 &self,
251 gzvm_reg_id: GeniezoneVcpuRegister,
252 data: &mut [u8],
253 ) -> Result<()> {
254 let onereg = gzvm_one_reg {
255 id: gzvm_reg_id.into(),
256 addr: (data.as_mut_ptr() as usize)
257 .try_into()
258 .expect("can't represent usize as u64"),
259 };
260
261 // SAFETY:
262 // Safe because we allocated the struct and we know the kernel will read exactly the size of
263 // the struct.
264 let ret = unsafe { ioctl_with_ref(self, GZVM_GET_ONE_REG(), &onereg) };
265 if ret == 0 {
266 Ok(())
267 } else {
268 errno_result()
269 }
270 }
271 }
272
273 #[allow(dead_code)]
274 /// GZVM registers as used by the `GET_ONE_REG`/`SET_ONE_REG` ioctl API
275 pub enum GeniezoneVcpuRegister {
276 /// General Purpose Registers X0-X30
277 X(u8),
278 /// Stack Pointer
279 Sp,
280 /// Program Counter
281 Pc,
282 /// Processor State
283 Pstate,
284 /// Stack Pointer (EL1)
285 SpEl1,
286 /// Exception Link Register (EL1)
287 ElrEl1,
288 /// Saved Program Status Register (EL1, abt, und, irq, fiq)
289 Spsr(u8),
290 /// FP & SIMD Registers V0-V31
291 V(u8),
292 /// Floating-point Status Register
293 Fpsr,
294 /// Floating-point Control Register
295 Fpcr,
296 /// Geniezone Firmware Pseudo-Registers
297 Firmware(u16),
298 /// Generic System Registers by (Op0, Op1, CRn, CRm, Op2)
299 System(u16),
300 /// CCSIDR_EL1 Demultiplexed by CSSELR_EL1
301 Ccsidr(u8),
302 }
303
304 /// Gives the `u64` register ID expected by the `GET_ONE_REG`/`SET_ONE_REG` ioctl API.
305 impl From<GeniezoneVcpuRegister> for u64 {
from(register: GeniezoneVcpuRegister) -> Self306 fn from(register: GeniezoneVcpuRegister) -> Self {
307 const fn reg(size: u64, kind: u64, fields: u64) -> u64 {
308 GZVM_REG_ARM64 | size | kind | fields
309 }
310
311 const fn gzvm_regs_reg(size: u64, offset: usize) -> u64 {
312 let offset = offset / std::mem::size_of::<u32>();
313
314 reg(size, GZVM_REG_ARM_CORE as u64, offset as u64)
315 }
316
317 const fn gzvm_reg(offset: usize) -> u64 {
318 gzvm_regs_reg(GZVM_REG_SIZE_U64, offset)
319 }
320
321 fn user_pt_reg(offset: usize) -> u64 {
322 gzvm_regs_reg(
323 GZVM_REG_SIZE_U64,
324 memoffset::offset_of!(gzvm_regs, regs) + offset,
325 )
326 }
327
328 fn user_fpsimd_state_reg(size: u64, offset: usize) -> u64 {
329 gzvm_regs_reg(size, memoffset::offset_of!(gzvm_regs, fp_regs) + offset)
330 }
331
332 const fn reg_u64(kind: u64, fields: u64) -> u64 {
333 reg(GZVM_REG_SIZE_U64, kind, fields)
334 }
335
336 const fn demux_reg(size: u64, index: u64, value: u64) -> u64 {
337 let index =
338 (index << GZVM_REG_ARM_DEMUX_ID_SHIFT) & (GZVM_REG_ARM_DEMUX_ID_MASK as u64);
339 let value =
340 (value << GZVM_REG_ARM_DEMUX_VAL_SHIFT) & (GZVM_REG_ARM_DEMUX_VAL_MASK as u64);
341
342 reg(size, GZVM_REG_ARM_DEMUX as u64, index | value)
343 }
344
345 match register {
346 GeniezoneVcpuRegister::X(n @ 0..=30) => {
347 let n = std::mem::size_of::<u64>() * (n as usize);
348
349 user_pt_reg(memoffset::offset_of!(user_pt_regs, regs) + n)
350 }
351 GeniezoneVcpuRegister::X(n) => {
352 unreachable!("invalid GeniezoneVcpuRegister Xn index: {n}")
353 }
354 GeniezoneVcpuRegister::Sp => user_pt_reg(memoffset::offset_of!(user_pt_regs, sp)),
355 GeniezoneVcpuRegister::Pc => user_pt_reg(memoffset::offset_of!(user_pt_regs, pc)),
356 GeniezoneVcpuRegister::Pstate => {
357 user_pt_reg(memoffset::offset_of!(user_pt_regs, pstate))
358 }
359 GeniezoneVcpuRegister::SpEl1 => gzvm_reg(memoffset::offset_of!(gzvm_regs, sp_el1)),
360 GeniezoneVcpuRegister::ElrEl1 => gzvm_reg(memoffset::offset_of!(gzvm_regs, elr_el1)),
361 GeniezoneVcpuRegister::Spsr(n @ 0..=4) => {
362 let n = std::mem::size_of::<u64>() * (n as usize);
363 gzvm_reg(memoffset::offset_of!(gzvm_regs, spsr) + n)
364 }
365 GeniezoneVcpuRegister::Spsr(n) => {
366 unreachable!("invalid GeniezoneVcpuRegister Spsr index: {n}")
367 }
368 GeniezoneVcpuRegister::V(n @ 0..=31) => {
369 let n = std::mem::size_of::<u128>() * (n as usize);
370 user_fpsimd_state_reg(
371 GZVM_REG_SIZE_U128,
372 memoffset::offset_of!(user_fpsimd_state, vregs) + n,
373 )
374 }
375 GeniezoneVcpuRegister::V(n) => {
376 unreachable!("invalid GeniezoneVcpuRegister Vn index: {n}")
377 }
378 GeniezoneVcpuRegister::Fpsr => user_fpsimd_state_reg(
379 GZVM_REG_SIZE_U32,
380 memoffset::offset_of!(user_fpsimd_state, fpsr),
381 ),
382 GeniezoneVcpuRegister::Fpcr => user_fpsimd_state_reg(
383 GZVM_REG_SIZE_U32,
384 memoffset::offset_of!(user_fpsimd_state, fpcr),
385 ),
386 GeniezoneVcpuRegister::Firmware(n) => reg_u64(GZVM_REG_ARM, n.into()),
387 GeniezoneVcpuRegister::System(n) => reg_u64(GZVM_REG_ARM64_SYSREG.into(), n.into()),
388 GeniezoneVcpuRegister::Ccsidr(n) => demux_reg(GZVM_REG_SIZE_U32, 0, n.into()),
389 }
390 }
391 }
392
393 #[cfg(feature = "gdb")]
394 impl TryFrom<AArch64RegId> for GeniezoneVcpuRegister {
395 type Error = Error;
396
try_from(_reg: <GdbArch as Arch>::RegId) -> std::result::Result<Self, Self::Error>397 fn try_from(_reg: <GdbArch as Arch>::RegId) -> std::result::Result<Self, Self::Error> {
398 // TODO: Geniezone not support gdb currently
399 error!("Geniezone: not support gdb");
400 Err(Error::new(EINVAL))
401 }
402 }
403
404 impl From<VcpuRegAArch64> for GeniezoneVcpuRegister {
from(reg: VcpuRegAArch64) -> Self405 fn from(reg: VcpuRegAArch64) -> Self {
406 match reg {
407 VcpuRegAArch64::X(n @ 0..=30) => Self::X(n),
408 VcpuRegAArch64::X(n) => unreachable!("invalid VcpuRegAArch64 index: {n}"),
409 VcpuRegAArch64::Sp => Self::Sp,
410 VcpuRegAArch64::Pc => Self::Pc,
411 VcpuRegAArch64::Pstate => Self::Pstate,
412 }
413 }
414 }
415
416 impl VcpuAArch64 for GeniezoneVcpu {
init(&self, _features: &[VcpuFeature]) -> Result<()>417 fn init(&self, _features: &[VcpuFeature]) -> Result<()> {
418 // Geniezone init vcpu in creation
419 // Return Ok since aarch64/src/lib.rs will use this
420 Ok(())
421 }
422
init_pmu(&self, _irq: u64) -> Result<()>423 fn init_pmu(&self, _irq: u64) -> Result<()> {
424 // TODO: Geniezone not support pmu currently
425 // temporary return ok since aarch64/src/lib.rs will use this
426 Ok(())
427 }
428
has_pvtime_support(&self) -> bool429 fn has_pvtime_support(&self) -> bool {
430 // TODO: Geniezone not support pvtime currently
431 false
432 }
433
init_pvtime(&self, _pvtime_ipa: u64) -> Result<()>434 fn init_pvtime(&self, _pvtime_ipa: u64) -> Result<()> {
435 // TODO: Geniezone not support pvtime currently
436 error!("Geniezone: not support init_pvtime");
437 Err(Error::new(EINVAL))
438 }
439
set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()>440 fn set_one_reg(&self, reg_id: VcpuRegAArch64, data: u64) -> Result<()> {
441 self.set_one_geniezone_reg_u64(GeniezoneVcpuRegister::from(reg_id), data)
442 }
443
get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64>444 fn get_one_reg(&self, reg_id: VcpuRegAArch64) -> Result<u64> {
445 self.get_one_geniezone_reg_u64(GeniezoneVcpuRegister::from(reg_id))
446 }
447
set_vector_reg(&self, _reg_num: u8, _data: u128) -> Result<()>448 fn set_vector_reg(&self, _reg_num: u8, _data: u128) -> Result<()> {
449 unimplemented!()
450 }
451
get_vector_reg(&self, _reg_num: u8) -> Result<u128>452 fn get_vector_reg(&self, _reg_num: u8) -> Result<u128> {
453 unimplemented!()
454 }
455
get_psci_version(&self) -> Result<PsciVersion>456 fn get_psci_version(&self) -> Result<PsciVersion> {
457 Ok(PSCI_0_2)
458 }
459
460 #[cfg(feature = "gdb")]
get_max_hw_bps(&self) -> Result<usize>461 fn get_max_hw_bps(&self) -> Result<usize> {
462 // TODO: Geniezone not support gdb currently
463 error!("Geniezone: not support get_max_hw_bps");
464 Err(Error::new(EINVAL))
465 }
466
467 #[cfg(feature = "gdb")]
set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()>468 fn set_guest_debug(&self, _addrs: &[GuestAddress], _enable_singlestep: bool) -> Result<()> {
469 // TODO: Geniezone not support gdb currently
470 error!("Geniezone: not support set_gdb_registers");
471 Err(Error::new(EINVAL))
472 }
473
474 #[cfg(feature = "gdb")]
set_gdb_registers(&self, _regs: &<GdbArch as Arch>::Registers) -> Result<()>475 fn set_gdb_registers(&self, _regs: &<GdbArch as Arch>::Registers) -> Result<()> {
476 // TODO: Geniezone not support gdb currently
477 error!("Geniezone: not support set_gdb_registers");
478 Err(Error::new(EINVAL))
479 }
480
481 #[cfg(feature = "gdb")]
get_gdb_registers(&self, _regs: &mut <GdbArch as Arch>::Registers) -> Result<()>482 fn get_gdb_registers(&self, _regs: &mut <GdbArch as Arch>::Registers) -> Result<()> {
483 // TODO: Geniezone not support gdb currently
484 error!("Geniezone: not support get_gdb_registers");
485 Err(Error::new(EINVAL))
486 }
487
488 #[cfg(feature = "gdb")]
set_gdb_register(&self, _reg: <GdbArch as Arch>::RegId, _data: &[u8]) -> Result<()>489 fn set_gdb_register(&self, _reg: <GdbArch as Arch>::RegId, _data: &[u8]) -> Result<()> {
490 // TODO: Geniezone not support gdb currently
491 error!("Geniezone: not support set_gdb_register");
492 Err(Error::new(EINVAL))
493 }
494
495 #[cfg(feature = "gdb")]
get_gdb_register(&self, _reg: <GdbArch as Arch>::RegId, _data: &mut [u8]) -> Result<usize>496 fn get_gdb_register(&self, _reg: <GdbArch as Arch>::RegId, _data: &mut [u8]) -> Result<usize> {
497 // TODO: Geniezone not support gdb currently
498 error!("Geniezone: not support get_gdb_register");
499 Err(Error::new(EINVAL))
500 }
501 }
502
503 // Wrapper around GZVM_SET_USER_MEMORY_REGION ioctl, which creates, modifies, or deletes a mapping
504 // from guest physical to host user pages.
505 //
506 // SAFETY:
507 // Safe when the guest regions are guaranteed not to overlap.
set_user_memory_region( descriptor: &SafeDescriptor, slot: MemSlot, _read_only: bool, _log_dirty_pages: bool, guest_addr: u64, memory_size: u64, userspace_addr: *mut u8, flags: u32, ) -> Result<()>508 unsafe fn set_user_memory_region(
509 descriptor: &SafeDescriptor,
510 slot: MemSlot,
511 _read_only: bool,
512 _log_dirty_pages: bool,
513 guest_addr: u64,
514 memory_size: u64,
515 userspace_addr: *mut u8,
516 flags: u32,
517 ) -> Result<()> {
518 let region = gzvm_userspace_memory_region {
519 slot,
520 flags,
521 guest_phys_addr: guest_addr,
522 memory_size,
523 userspace_addr: userspace_addr as u64,
524 };
525
526 let ret = ioctl_with_ref(descriptor, GZVM_SET_USER_MEMORY_REGION(), ®ion);
527 if ret == 0 {
528 Ok(())
529 } else {
530 errno_result()
531 }
532 }
533
534 /// Helper function to determine the size in bytes of a dirty log bitmap for the given memory region
535 /// size.
536 ///
537 /// # Arguments
538 ///
539 /// * `size` - Number of bytes in the memory region being queried.
dirty_log_bitmap_size(size: usize) -> usize540 pub fn dirty_log_bitmap_size(size: usize) -> usize {
541 let page_size = pagesize();
542 (((size + page_size - 1) / page_size) + 7) / 8
543 }
544
545 pub struct Geniezone {
546 geniezone: SafeDescriptor,
547 }
548
549 #[repr(u32)]
550 pub enum GeniezoneCap {
551 ArmMte,
552 ArmProtectedVm = GZVM_CAP_ARM_PROTECTED_VM,
553 }
554
555 impl Geniezone {
new_with_path(device_path: &Path) -> Result<Geniezone>556 pub fn new_with_path(device_path: &Path) -> Result<Geniezone> {
557 let c_path = CString::new(device_path.as_os_str().as_bytes()).unwrap();
558 // SAFETY:
559 // Open calls are safe because we give a nul-terminated string and verify the result.
560 let ret = unsafe { open(c_path.as_ptr(), O_RDWR | O_CLOEXEC) };
561 if ret < 0 {
562 return errno_result();
563 }
564 Ok(Geniezone {
565 // SAFETY:
566 // Safe because we verify that ret is valid and we own the fd.
567 geniezone: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
568 })
569 }
570
571 /// Opens `/dev/gzvm/` and returns a gzvm object on success.
new() -> Result<Geniezone>572 pub fn new() -> Result<Geniezone> {
573 Geniezone::new_with_path(&PathBuf::from("/dev/gzvm"))
574 }
575
576 /// Gets the size of the mmap required to use vcpu's `gzvm_vcpu_run` structure.
get_vcpu_mmap_size(&self) -> Result<usize>577 pub fn get_vcpu_mmap_size(&self) -> Result<usize> {
578 // We don't use mmap, return sizeof(gzvm_vcpu_run) directly
579 let res = std::mem::size_of::<gzvm_vcpu_run>();
580 Ok(res)
581 }
582 }
583
584 impl AsRawDescriptor for Geniezone {
as_raw_descriptor(&self) -> RawDescriptor585 fn as_raw_descriptor(&self) -> RawDescriptor {
586 self.geniezone.as_raw_descriptor()
587 }
588 }
589
590 impl Hypervisor for Geniezone {
try_clone(&self) -> Result<Self>591 fn try_clone(&self) -> Result<Self> {
592 Ok(Geniezone {
593 geniezone: self.geniezone.try_clone()?,
594 })
595 }
596
check_capability(&self, cap: HypervisorCap) -> bool597 fn check_capability(&self, cap: HypervisorCap) -> bool {
598 match cap {
599 HypervisorCap::UserMemory => true,
600 HypervisorCap::ArmPmuV3 => false,
601 HypervisorCap::ImmediateExit => true,
602 HypervisorCap::StaticSwiotlbAllocationRequired => true,
603 HypervisorCap::HypervisorInitializedBootContext => false,
604 HypervisorCap::S390UserSigp | HypervisorCap::TscDeadlineTimer => false,
605 }
606 }
607 }
608
609 /// A wrapper around creating and using a Geniezone VM.
610 pub struct GeniezoneVm {
611 geniezone: Geniezone,
612 vm: SafeDescriptor,
613 guest_mem: GuestMemory,
614 mem_regions: Arc<Mutex<BTreeMap<MemSlot, Box<dyn MappedRegion>>>>,
615 /// A min heap of MemSlot numbers that were used and then removed and can now be re-used
616 mem_slot_gaps: Arc<Mutex<BinaryHeap<Reverse<MemSlot>>>>,
617 }
618
619 impl GeniezoneVm {
620 /// Constructs a new `GeniezoneVm` using the given `Geniezone` instance.
new(geniezone: &Geniezone, guest_mem: GuestMemory, cfg: Config) -> Result<GeniezoneVm>621 pub fn new(geniezone: &Geniezone, guest_mem: GuestMemory, cfg: Config) -> Result<GeniezoneVm> {
622 // SAFETY:
623 // Safe because we know gzvm is a real gzvm fd as this module is the only one that can make
624 // gzvm objects.
625 let ret = unsafe { ioctl(geniezone, GZVM_CREATE_VM()) };
626 if ret < 0 {
627 return errno_result();
628 }
629 // SAFETY:
630 // Safe because we verify that ret is valid and we own the fd.
631 let vm_descriptor = unsafe { SafeDescriptor::from_raw_descriptor(ret) };
632 for region in guest_mem.regions() {
633 let flags = match region.options.purpose {
634 MemoryRegionPurpose::GuestMemoryRegion => GZVM_USER_MEM_REGION_GUEST_MEM,
635 MemoryRegionPurpose::ProtectedFirmwareRegion => GZVM_USER_MEM_REGION_PROTECT_FW,
636 MemoryRegionPurpose::StaticSwiotlbRegion => GZVM_USER_MEM_REGION_STATIC_SWIOTLB,
637 };
638 // SAFETY:
639 // Safe because the guest regions are guaranteed not to overlap.
640 unsafe {
641 set_user_memory_region(
642 &vm_descriptor,
643 region.index as MemSlot,
644 false,
645 false,
646 region.guest_addr.offset(),
647 region.size as u64,
648 region.host_addr as *mut u8,
649 flags,
650 )
651 }?;
652 }
653
654 let vm = GeniezoneVm {
655 geniezone: geniezone.try_clone()?,
656 vm: vm_descriptor,
657 guest_mem,
658 mem_regions: Arc::new(Mutex::new(BTreeMap::new())),
659 mem_slot_gaps: Arc::new(Mutex::new(BinaryHeap::new())),
660 };
661 vm.init_arch(&cfg)?;
662 Ok(vm)
663 }
664
create_vcpu(&self, id: usize) -> Result<GeniezoneVcpu>665 fn create_vcpu(&self, id: usize) -> Result<GeniezoneVcpu> {
666 // run is a data stucture shared with ko and geniezone
667 let run_mmap_size = self.geniezone.get_vcpu_mmap_size()?;
668
669 let fd =
670 // SAFETY:
671 // Safe because we know that our file is a VM fd and we verify the return result.
672 unsafe { ioctl_with_val(self, GZVM_CREATE_VCPU(), c_ulong::try_from(id).unwrap()) };
673
674 if fd < 0 {
675 return errno_result();
676 }
677
678 // SAFETY:
679 // Wrap the vcpu now in case the following ? returns early. This is safe because we verified
680 // the value of the fd and we own the fd.
681 let vcpu = unsafe { SafeDescriptor::from_raw_descriptor(fd) };
682
683 // Memory mapping --> Memory allocation
684 let run_mmap = MemoryMappingBuilder::new(run_mmap_size)
685 .build()
686 .map_err(|_| Error::new(ENOSPC))?;
687
688 Ok(GeniezoneVcpu {
689 vm: self.vm.try_clone()?,
690 vcpu,
691 id,
692 run_mmap: Arc::new(run_mmap),
693 })
694 }
695
696 /// Creates an in kernel interrupt controller.
697 ///
698 /// See the documentation on the GZVM_CREATE_IRQCHIP ioctl.
create_irq_chip(&self) -> Result<()>699 pub fn create_irq_chip(&self) -> Result<()> {
700 // SAFETY:
701 // Safe because we know that our file is a VM fd and we verify the return result.
702 let ret = unsafe { ioctl(self, GZVM_CREATE_IRQCHIP()) };
703 if ret == 0 {
704 Ok(())
705 } else {
706 errno_result()
707 }
708 }
709
710 /// Sets the level on the given irq to 1 if `active` is true, and 0 otherwise.
set_irq_line(&self, irq: u32, active: bool) -> Result<()>711 pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> {
712 let mut irq_level = gzvm_irq_level::default();
713 irq_level.__bindgen_anon_1.irq = irq;
714 irq_level.level = active as u32;
715
716 // SAFETY:
717 // Safe because we know that our file is a VM fd, we know the kernel will only read the
718 // correct amount of memory from our pointer, and we verify the return result.
719 let ret = unsafe { ioctl_with_ref(self, GZVM_IRQ_LINE(), &irq_level) };
720 if ret == 0 {
721 Ok(())
722 } else {
723 errno_result()
724 }
725 }
726
727 /// Registers an event that will, when signalled, trigger the `gsi` irq, and `resample_evt`
728 /// ( when not None ) will be triggered when the irqchip is resampled.
register_irqfd( &self, gsi: u32, evt: &Event, resample_evt: Option<&Event>, ) -> Result<()>729 pub fn register_irqfd(
730 &self,
731 gsi: u32,
732 evt: &Event,
733 resample_evt: Option<&Event>,
734 ) -> Result<()> {
735 let mut irqfd = gzvm_irqfd {
736 fd: evt.as_raw_descriptor() as u32,
737 gsi,
738 ..Default::default()
739 };
740
741 if let Some(r_evt) = resample_evt {
742 irqfd.flags = GZVM_IRQFD_FLAG_RESAMPLE;
743 irqfd.resamplefd = r_evt.as_raw_descriptor() as u32;
744 }
745
746 // SAFETY:
747 // Safe because we know that our file is a VM fd, we know the kernel will only read the
748 // correct amount of memory from our pointer, and we verify the return result.
749 let ret = unsafe { ioctl_with_ref(self, GZVM_IRQFD(), &irqfd) };
750 if ret == 0 {
751 Ok(())
752 } else {
753 errno_result()
754 }
755 }
756
757 /// Unregisters an event that was previously registered with
758 /// `register_irqfd`.
759 ///
760 /// The `evt` and `gsi` pair must be the same as the ones passed into
761 /// `register_irqfd`.
unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()>762 pub fn unregister_irqfd(&self, gsi: u32, evt: &Event) -> Result<()> {
763 let irqfd = gzvm_irqfd {
764 fd: evt.as_raw_descriptor() as u32,
765 gsi,
766 flags: GZVM_IRQFD_FLAG_DEASSIGN,
767 ..Default::default()
768 };
769 // SAFETY:
770 // Safe because we know that our file is a VM fd, we know the kernel will only read the
771 // correct amount of memory from our pointer, and we verify the return result.
772 let ret = unsafe { ioctl_with_ref(self, GZVM_IRQFD(), &irqfd) };
773 if ret == 0 {
774 Ok(())
775 } else {
776 errno_result()
777 }
778 }
779
ioeventfd( &self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, deassign: bool, ) -> Result<()>780 fn ioeventfd(
781 &self,
782 evt: &Event,
783 addr: IoEventAddress,
784 datamatch: Datamatch,
785 deassign: bool,
786 ) -> Result<()> {
787 let (do_datamatch, datamatch_value, datamatch_len) = match datamatch {
788 Datamatch::AnyLength => (false, 0, 0),
789 Datamatch::U8(v) => match v {
790 Some(u) => (true, u as u64, 1),
791 None => (false, 0, 1),
792 },
793 Datamatch::U16(v) => match v {
794 Some(u) => (true, u as u64, 2),
795 None => (false, 0, 2),
796 },
797 Datamatch::U32(v) => match v {
798 Some(u) => (true, u as u64, 4),
799 None => (false, 0, 4),
800 },
801 Datamatch::U64(v) => match v {
802 Some(u) => (true, u, 8),
803 None => (false, 0, 8),
804 },
805 };
806 let mut flags = 0;
807 if deassign {
808 flags |= 1 << gzvm_ioeventfd_flag_nr_deassign;
809 }
810 if do_datamatch {
811 flags |= 1 << gzvm_ioeventfd_flag_nr_datamatch
812 }
813 if let IoEventAddress::Pio(_) = addr {
814 flags |= 1 << gzvm_ioeventfd_flag_nr_pio;
815 }
816 let ioeventfd = gzvm_ioeventfd {
817 datamatch: datamatch_value,
818 len: datamatch_len,
819 addr: match addr {
820 IoEventAddress::Pio(p) => p,
821 IoEventAddress::Mmio(m) => m,
822 },
823 fd: evt.as_raw_descriptor(),
824 flags,
825 ..Default::default()
826 };
827 // SAFETY:
828 // Safe because we know that our file is a VM fd, we know the kernel will only read the
829 // correct amount of memory from our pointer, and we verify the return result.
830 let ret = unsafe { ioctl_with_ref(self, GZVM_IOEVENTFD(), &ioeventfd) };
831 if ret == 0 {
832 Ok(())
833 } else {
834 errno_result()
835 }
836 }
837
838 /// Checks whether a particular GZVM-specific capability is available for this VM.
check_raw_capability(&self, capability: GeniezoneCap) -> bool839 fn check_raw_capability(&self, capability: GeniezoneCap) -> bool {
840 let cap: u64 = capability as u64;
841 // SAFETY:
842 // Safe because we know that our file is a GZVM fd, and if the cap is invalid GZVM assumes
843 // it's an unavailable extension and returns 0.
844 unsafe {
845 ioctl_with_ref(self, GZVM_CHECK_EXTENSION(), &cap);
846 }
847 cap == 1
848 }
849
850 // Currently only used on aarch64, but works on any architecture.
851 #[allow(dead_code)]
852 /// Enables a GZVM-specific capability for this VM, with the given arguments.
853 ///
854 /// # Safety
855 /// This function is marked as unsafe because `args` may be interpreted as pointers for some
856 /// capabilities. The caller must ensure that any pointers passed in the `args` array are
857 /// allocated as the kernel expects, and that mutable pointers are owned.
ctrl_geniezone_enable_capability( &self, capability: GeniezoneCap, args: &[u64; 5], ) -> Result<gzvm_enable_cap>858 unsafe fn ctrl_geniezone_enable_capability(
859 &self,
860 capability: GeniezoneCap,
861 args: &[u64; 5],
862 ) -> Result<gzvm_enable_cap> {
863 let gzvm_cap = gzvm_enable_cap {
864 cap: capability as u64,
865 args: *args,
866 };
867 // Safe because we allocated the struct and we know the kernel will read exactly the size of
868 // the struct, and because we assume the caller has allocated the args appropriately.
869 let ret = ioctl_with_ref(self, GZVM_ENABLE_CAP(), &gzvm_cap);
870 if ret == 0 {
871 Ok(gzvm_cap)
872 } else {
873 errno_result()
874 }
875 }
876
create_geniezone_device(&self, dev: gzvm_create_device) -> Result<()>877 pub fn create_geniezone_device(&self, dev: gzvm_create_device) -> Result<()> {
878 // SAFETY:
879 // Safe because we allocated the struct and we know the kernel will modify exactly the size
880 // of the struct and the return value is checked.
881 let ret = unsafe { base::ioctl_with_ref(self, GZVM_CREATE_DEVICE(), &dev) };
882 if ret == 0 {
883 Ok(())
884 } else {
885 errno_result()
886 }
887 }
888
handle_inflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()>889 fn handle_inflate(&mut self, guest_address: GuestAddress, size: u64) -> Result<()> {
890 match self.guest_mem.remove_range(guest_address, size) {
891 Ok(_) => Ok(()),
892 Err(vm_memory::Error::MemoryAccess(_, MmapError::SystemCallFailed(e))) => Err(e),
893 Err(_) => Err(Error::new(EIO)),
894 }
895 }
896
handle_deflate(&mut self, _guest_address: GuestAddress, _size: u64) -> Result<()>897 fn handle_deflate(&mut self, _guest_address: GuestAddress, _size: u64) -> Result<()> {
898 // No-op, when the guest attempts to access the pages again, Linux/GZVM will provide them.
899 Ok(())
900 }
901 }
902
903 impl Vm for GeniezoneVm {
try_clone(&self) -> Result<Self>904 fn try_clone(&self) -> Result<Self> {
905 Ok(GeniezoneVm {
906 geniezone: self.geniezone.try_clone()?,
907 vm: self.vm.try_clone()?,
908 guest_mem: self.guest_mem.clone(),
909 mem_regions: self.mem_regions.clone(),
910 mem_slot_gaps: self.mem_slot_gaps.clone(),
911 })
912 }
913
check_capability(&self, c: VmCap) -> bool914 fn check_capability(&self, c: VmCap) -> bool {
915 if let Some(val) = self.check_capability_arch(c) {
916 return val;
917 }
918 match c {
919 VmCap::DirtyLog => true,
920 VmCap::PvClock => false,
921 VmCap::Protected => self.check_raw_capability(GeniezoneCap::ArmProtectedVm),
922 VmCap::EarlyInitCpuid => false,
923 VmCap::ReadOnlyMemoryRegion => false,
924 VmCap::MemNoncoherentDma => false,
925 }
926 }
927
get_guest_phys_addr_bits(&self) -> u8928 fn get_guest_phys_addr_bits(&self) -> u8 {
929 self.geniezone.get_guest_phys_addr_bits()
930 }
931
get_memory(&self) -> &GuestMemory932 fn get_memory(&self) -> &GuestMemory {
933 &self.guest_mem
934 }
935
add_memory_region( &mut self, guest_addr: GuestAddress, mem: Box<dyn MappedRegion>, read_only: bool, log_dirty_pages: bool, _cache: MemCacheType, ) -> Result<MemSlot>936 fn add_memory_region(
937 &mut self,
938 guest_addr: GuestAddress,
939 mem: Box<dyn MappedRegion>,
940 read_only: bool,
941 log_dirty_pages: bool,
942 _cache: MemCacheType,
943 ) -> Result<MemSlot> {
944 let pgsz = pagesize() as u64;
945 // GZVM require to set the user memory region with page size aligned size. Safe to extend
946 // the mem.size() to be page size aligned because the mmap will round up the size to be
947 // page size aligned if it is not.
948 let size = (mem.size() as u64 + pgsz - 1) / pgsz * pgsz;
949 let end_addr = guest_addr
950 .checked_add(size)
951 .ok_or_else(|| Error::new(EOVERFLOW))?;
952 if self.guest_mem.range_overlap(guest_addr, end_addr) {
953 return Err(Error::new(ENOSPC));
954 }
955 let mut regions = self.mem_regions.lock();
956 let mut gaps = self.mem_slot_gaps.lock();
957 let slot = match gaps.pop() {
958 Some(gap) => gap.0,
959 None => (regions.len() + self.guest_mem.num_regions() as usize) as MemSlot,
960 };
961 let flags = 0;
962
963 // SAFETY:
964 // Safe because we check that the given guest address is valid and has no overlaps. We also
965 // know that the pointer and size are correct because the MemoryMapping interface ensures
966 // this. We take ownership of the memory mapping so that it won't be unmapped until the slot
967 // is removed.
968 let res = unsafe {
969 set_user_memory_region(
970 &self.vm,
971 slot,
972 read_only,
973 log_dirty_pages,
974 guest_addr.offset(),
975 size,
976 mem.as_ptr(),
977 flags,
978 )
979 };
980
981 if let Err(e) = res {
982 gaps.push(Reverse(slot));
983 return Err(e);
984 }
985 regions.insert(slot, mem);
986 Ok(slot)
987 }
988
msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()>989 fn msync_memory_region(&mut self, slot: MemSlot, offset: usize, size: usize) -> Result<()> {
990 let mut regions = self.mem_regions.lock();
991 let mem = regions.get_mut(&slot).ok_or_else(|| Error::new(ENOENT))?;
992
993 mem.msync(offset, size).map_err(|err| match err {
994 MmapError::InvalidAddress => Error::new(EFAULT),
995 MmapError::NotPageAligned => Error::new(EINVAL),
996 MmapError::SystemCallFailed(e) => e,
997 _ => Error::new(EIO),
998 })
999 }
1000
remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>>1001 fn remove_memory_region(&mut self, slot: MemSlot) -> Result<Box<dyn MappedRegion>> {
1002 let mut regions = self.mem_regions.lock();
1003 if !regions.contains_key(&slot) {
1004 return Err(Error::new(ENOENT));
1005 }
1006 // SAFETY:
1007 // Safe because the slot is checked against the list of memory slots.
1008 unsafe {
1009 set_user_memory_region(&self.vm, slot, false, false, 0, 0, std::ptr::null_mut(), 0)?;
1010 }
1011 self.mem_slot_gaps.lock().push(Reverse(slot));
1012 // This remove will always succeed because of the contains_key check above.
1013 Ok(regions.remove(&slot).unwrap())
1014 }
1015
create_device(&self, _kind: DeviceKind) -> Result<SafeDescriptor>1016 fn create_device(&self, _kind: DeviceKind) -> Result<SafeDescriptor> {
1017 // This function should not be invoked because the vgic device is created in irqchip.
1018 errno_result()
1019 }
1020
get_dirty_log(&self, _slot: MemSlot, _dirty_log: &mut [u8]) -> Result<()>1021 fn get_dirty_log(&self, _slot: MemSlot, _dirty_log: &mut [u8]) -> Result<()> {
1022 Err(Error::new(ENOTSUP))
1023 }
1024
register_ioevent( &mut self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, ) -> Result<()>1025 fn register_ioevent(
1026 &mut self,
1027 evt: &Event,
1028 addr: IoEventAddress,
1029 datamatch: Datamatch,
1030 ) -> Result<()> {
1031 self.ioeventfd(evt, addr, datamatch, false)
1032 }
1033
unregister_ioevent( &mut self, evt: &Event, addr: IoEventAddress, datamatch: Datamatch, ) -> Result<()>1034 fn unregister_ioevent(
1035 &mut self,
1036 evt: &Event,
1037 addr: IoEventAddress,
1038 datamatch: Datamatch,
1039 ) -> Result<()> {
1040 self.ioeventfd(evt, addr, datamatch, true)
1041 }
1042
handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()>1043 fn handle_io_events(&self, _addr: IoEventAddress, _data: &[u8]) -> Result<()> {
1044 // GZVM delivers IO events in-kernel with ioeventfds, so this is a no-op
1045 Ok(())
1046 }
1047
get_pvclock(&self) -> Result<ClockState>1048 fn get_pvclock(&self) -> Result<ClockState> {
1049 self.get_pvclock_arch()
1050 }
1051
set_pvclock(&self, state: &ClockState) -> Result<()>1052 fn set_pvclock(&self, state: &ClockState) -> Result<()> {
1053 self.set_pvclock_arch(state)
1054 }
1055
add_fd_mapping( &mut self, slot: u32, offset: usize, size: usize, fd: &dyn AsRawDescriptor, fd_offset: u64, prot: Protection, ) -> Result<()>1056 fn add_fd_mapping(
1057 &mut self,
1058 slot: u32,
1059 offset: usize,
1060 size: usize,
1061 fd: &dyn AsRawDescriptor,
1062 fd_offset: u64,
1063 prot: Protection,
1064 ) -> Result<()> {
1065 let mut regions = self.mem_regions.lock();
1066 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
1067
1068 match region.add_fd_mapping(offset, size, fd, fd_offset, prot) {
1069 Ok(()) => Ok(()),
1070 Err(MmapError::SystemCallFailed(e)) => Err(e),
1071 Err(_) => Err(Error::new(EIO)),
1072 }
1073 }
1074
remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()>1075 fn remove_mapping(&mut self, slot: u32, offset: usize, size: usize) -> Result<()> {
1076 let mut regions = self.mem_regions.lock();
1077 let region = regions.get_mut(&slot).ok_or_else(|| Error::new(EINVAL))?;
1078
1079 match region.remove_mapping(offset, size) {
1080 Ok(()) => Ok(()),
1081 Err(MmapError::SystemCallFailed(e)) => Err(e),
1082 Err(_) => Err(Error::new(EIO)),
1083 }
1084 }
1085
handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()>1086 fn handle_balloon_event(&mut self, event: BalloonEvent) -> Result<()> {
1087 match event {
1088 BalloonEvent::Inflate(m) => self.handle_inflate(m.guest_address, m.size),
1089 BalloonEvent::Deflate(m) => self.handle_deflate(m.guest_address, m.size),
1090 BalloonEvent::BalloonTargetReached(_) => Ok(()),
1091 }
1092 }
1093 }
1094
1095 impl AsRawDescriptor for GeniezoneVm {
as_raw_descriptor(&self) -> RawDescriptor1096 fn as_raw_descriptor(&self) -> RawDescriptor {
1097 self.vm.as_raw_descriptor()
1098 }
1099 }
1100
1101 struct GeniezoneVcpuSignalHandle {
1102 run_mmap: Arc<MemoryMapping>,
1103 }
1104
1105 impl VcpuSignalHandleInner for GeniezoneVcpuSignalHandle {
signal_immediate_exit(&self)1106 fn signal_immediate_exit(&self) {
1107 // SAFETY: we ensure `run_mmap` is a valid mapping of `kvm_run` at creation time, and the
1108 // `Arc` ensures the mapping still exists while we hold a reference to it.
1109 unsafe {
1110 let run = self.run_mmap.as_ptr() as *mut gzvm_vcpu_run;
1111 (*run).immediate_exit = 1;
1112 }
1113 }
1114 }
1115
1116 /// A wrapper around using a Geniezone Vcpu.
1117 pub struct GeniezoneVcpu {
1118 vm: SafeDescriptor,
1119 vcpu: SafeDescriptor,
1120 id: usize,
1121 run_mmap: Arc<MemoryMapping>,
1122 }
1123
1124 impl Vcpu for GeniezoneVcpu {
try_clone(&self) -> Result<Self>1125 fn try_clone(&self) -> Result<Self> {
1126 let vm = self.vm.try_clone()?;
1127 let vcpu = self.vcpu.try_clone()?;
1128
1129 Ok(GeniezoneVcpu {
1130 vm,
1131 vcpu,
1132 id: self.id,
1133 run_mmap: self.run_mmap.clone(),
1134 })
1135 }
1136
as_vcpu(&self) -> &dyn Vcpu1137 fn as_vcpu(&self) -> &dyn Vcpu {
1138 self
1139 }
1140
id(&self) -> usize1141 fn id(&self) -> usize {
1142 self.id
1143 }
1144
1145 #[allow(clippy::cast_ptr_alignment)]
set_immediate_exit(&self, exit: bool)1146 fn set_immediate_exit(&self, exit: bool) {
1147 // TODO(b/315998194): Add safety comment
1148 #[allow(clippy::undocumented_unsafe_blocks)]
1149 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut gzvm_vcpu_run) };
1150 run.immediate_exit = exit as u8;
1151 }
1152
signal_handle(&self) -> VcpuSignalHandle1153 fn signal_handle(&self) -> VcpuSignalHandle {
1154 VcpuSignalHandle {
1155 inner: Box::new(GeniezoneVcpuSignalHandle {
1156 run_mmap: self.run_mmap.clone(),
1157 }),
1158 }
1159 }
1160
on_suspend(&self) -> Result<()>1161 fn on_suspend(&self) -> Result<()> {
1162 Ok(())
1163 }
1164
enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()>1165 unsafe fn enable_raw_capability(&self, _cap: u32, _args: &[u64; 4]) -> Result<()> {
1166 Err(Error::new(libc::ENXIO))
1167 }
1168
1169 #[allow(clippy::cast_ptr_alignment)]
1170 // The pointer is page aligned so casting to a different type is well defined, hence the clippy
1171 // allow attribute.
run(&mut self) -> Result<VcpuExit>1172 fn run(&mut self) -> Result<VcpuExit> {
1173 // SAFETY:
1174 // Safe because we know that our file is a VCPU fd and we verify the return result.
1175 let ret = unsafe { ioctl_with_val(self, GZVM_RUN(), self.run_mmap.as_ptr() as u64) };
1176 if ret != 0 {
1177 return errno_result();
1178 }
1179
1180 // SAFETY:
1181 // Safe because we know we mapped enough memory to hold the gzvm_vcpu_run struct because the
1182 // kernel told us how large it was.
1183 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut gzvm_vcpu_run) };
1184
1185 match run.exit_reason {
1186 GZVM_EXIT_MMIO => Ok(VcpuExit::Mmio),
1187 GZVM_EXIT_IRQ => Ok(VcpuExit::IrqWindowOpen),
1188 GZVM_EXIT_HVC => Ok(VcpuExit::Hypercall),
1189 GZVM_EXIT_EXCEPTION => Err(Error::new(EINVAL)),
1190 GZVM_EXIT_DEBUG => Ok(VcpuExit::Debug),
1191 GZVM_EXIT_FAIL_ENTRY => {
1192 // SAFETY:
1193 // Safe because the exit_reason (which comes from the kernel) told us which
1194 // union field to use.
1195 let hardware_entry_failure_reason = unsafe {
1196 run.__bindgen_anon_1
1197 .fail_entry
1198 .hardware_entry_failure_reason
1199 };
1200 Ok(VcpuExit::FailEntry {
1201 hardware_entry_failure_reason,
1202 })
1203 }
1204 GZVM_EXIT_SYSTEM_EVENT => {
1205 // SAFETY:
1206 // Safe because the exit_reason (which comes from the kernel) told us which
1207 // union field to use.
1208 let event_type = unsafe { run.__bindgen_anon_1.system_event.type_ };
1209 match event_type {
1210 GZVM_SYSTEM_EVENT_SHUTDOWN => Ok(VcpuExit::SystemEventShutdown),
1211 GZVM_SYSTEM_EVENT_RESET => Ok(VcpuExit::SystemEventReset),
1212 GZVM_SYSTEM_EVENT_CRASH => Ok(VcpuExit::SystemEventCrash),
1213 _ => {
1214 error!("Unknown GZVM system event {}", event_type);
1215 Err(Error::new(EINVAL))
1216 }
1217 }
1218 }
1219 GZVM_EXIT_INTERNAL_ERROR => Ok(VcpuExit::InternalError),
1220 GZVM_EXIT_SHUTDOWN => Ok(VcpuExit::Shutdown),
1221 GZVM_EXIT_UNKNOWN => panic!("unknown gzvm exit reason\n"),
1222 r => panic!("unknown gzvm exit reason: {}", r),
1223 }
1224 }
1225
handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Option<[u8; 8]>) -> Result<()>1226 fn handle_mmio(&self, handle_fn: &mut dyn FnMut(IoParams) -> Option<[u8; 8]>) -> Result<()> {
1227 // SAFETY:
1228 // Safe because we know we mapped enough memory to hold the gzvm_vcpu_run struct because the
1229 // kernel told us how large it was. The pointer is page aligned so casting to a different
1230 // type is well defined, hence the clippy allow attribute.
1231 let run = unsafe { &mut *(self.run_mmap.as_ptr() as *mut gzvm_vcpu_run) };
1232
1233 // Verify that the handler is called in the right context.
1234 assert!(run.exit_reason == GZVM_EXIT_MMIO);
1235 // SAFETY:
1236 // Safe because the exit_reason (which comes from the kernel) told us which
1237 // union field to use.
1238 let mmio = unsafe { &mut run.__bindgen_anon_1.mmio };
1239 let address = mmio.phys_addr;
1240
1241 let size = mmio.size as usize;
1242
1243 if mmio.is_write != 0 {
1244 handle_fn(IoParams {
1245 address,
1246 size,
1247 operation: IoOperation::Write { data: mmio.data },
1248 });
1249 Ok(())
1250 } else if let Some(data) = handle_fn(IoParams {
1251 address,
1252 size,
1253 operation: IoOperation::Read,
1254 }) {
1255 mmio.data[..size].copy_from_slice(&data[..size]);
1256 Ok(())
1257 } else {
1258 Err(Error::new(EINVAL))
1259 }
1260 }
1261
handle_io(&self, _handle_fn: &mut dyn FnMut(IoParams) -> Option<[u8; 8]>) -> Result<()>1262 fn handle_io(&self, _handle_fn: &mut dyn FnMut(IoParams) -> Option<[u8; 8]>) -> Result<()> {
1263 Err(Error::new(EINVAL))
1264 }
1265
handle_hyperv_hypercall( &self, _handle_fn: &mut dyn FnMut(HypervHypercall) -> u64, ) -> Result<()>1266 fn handle_hyperv_hypercall(
1267 &self,
1268 _handle_fn: &mut dyn FnMut(HypervHypercall) -> u64,
1269 ) -> Result<()> {
1270 Err(Error::new(EINVAL))
1271 }
1272
handle_rdmsr(&self, _data: u64) -> Result<()>1273 fn handle_rdmsr(&self, _data: u64) -> Result<()> {
1274 Err(Error::new(EINVAL))
1275 }
1276
handle_wrmsr(&self)1277 fn handle_wrmsr(&self) {}
1278 }
1279
1280 impl AsRawDescriptor for GeniezoneVcpu {
as_raw_descriptor(&self) -> RawDescriptor1281 fn as_raw_descriptor(&self) -> RawDescriptor {
1282 self.vcpu.as_raw_descriptor()
1283 }
1284 }
1285