• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(), &region);
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