Alioth Code Coverage

vmexit.rs0.00%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::hv::kvm::vcpu::KvmVcpu;
16use crate::hv::{Error, VmExit, error};
17#[cfg(target_arch = "x86_64")]
18use crate::sys::kvm::KvmExitIo;
19use crate::sys::kvm::{KvmHypercall, KvmMapGpaRangeFlag, KvmMemoryFaultFlag, KvmSystemEvent};
20
21impl KvmVcpu {
22 #[cfg(target_endian = "little")]
23 pub(super) fn handle_mmio(&mut self) -> Result<VmExit, Error> {
24 let kvm_mmio = unsafe { &self.kvm_run.exit.mmio };
25 let data = u64::from_ne_bytes(kvm_mmio.data) & u64::MAX >> (64 - (kvm_mmio.len << 3));
26 let exit = VmExit::Mmio {
27 addr: kvm_mmio.phys_addr,
28 write: if kvm_mmio.is_write > 0 {
29 Some(data)
30 } else {
31 None
32 },
33 size: kvm_mmio.len as u8,
34 };
35 Ok(exit)
36 }
37
38 #[cfg(target_arch = "x86_64")]
39 pub(super) fn handle_io(&mut self) -> VmExit {
40 let kvm_io = unsafe { self.kvm_run.exit.io };
41 let offset = kvm_io.data_offset as usize;
42 let count = kvm_io.count as usize;
43 let index = self.arch.io_index;
44 let write = if kvm_io.direction == KvmExitIo::IN {
45 None
46 } else {
47 let data = match kvm_io.size {
48 1 => unsafe { self.kvm_run.data_slice::<u8>(offset, count)[index] as u32 },
49 2 => unsafe { self.kvm_run.data_slice::<u16>(offset, count)[index] as u32 },
50 4 => unsafe { self.kvm_run.data_slice::<u32>(offset, count)[index] },
51 _ => unreachable!("kvm_io.size = {}", kvm_io.size),
52 };
53 Some(data)
54 };
55 VmExit::Io {
56 port: kvm_io.port,
57 write,
58 size: kvm_io.size,
59 }
60 }
61
62 pub(super) fn handle_hypercall(&mut self) -> Result<VmExit, Error> {
63 let hypercall = unsafe { self.kvm_run.exit.hypercall };
64 match hypercall.nr {
65 KvmHypercall::MAP_GPA_RANGE => {
66 let flag = KvmMapGpaRangeFlag::from_bits_retain(hypercall.args[2]);
67 Ok(VmExit::ConvertMemory {
68 gpa: hypercall.args[0],
69 size: hypercall.args[1] << 12,
70 private: flag.contains(KvmMapGpaRangeFlag::ENCRYPTED),
71 })
72 }
73 _ => unimplemented!(),
74 }
75 }
76
77 pub(super) fn handle_system_event(&mut self) -> Result<VmExit, Error> {
78 let kvm_system_event = unsafe { &self.kvm_run.exit.system_event };
79 match kvm_system_event.type_ {
80 KvmSystemEvent::SHUTDOWN => Ok(VmExit::Shutdown),
81 KvmSystemEvent::RESET => Ok(VmExit::Reboot),
82 _ => error::VmExit {
83 msg: format!("{kvm_system_event:#x?}"),
84 }
85 .fail(),
86 }
87 }
88
89 pub(crate) fn handle_memory_fault(&mut self) -> VmExit {
90 let memory_fault = unsafe { &self.kvm_run.exit.memory_fault };
91 let private = memory_fault.flags.contains(KvmMemoryFaultFlag::PRIVATE);
92 VmExit::ConvertMemory {
93 gpa: memory_fault.gpa,
94 size: memory_fault.size,
95 private,
96 }
97 }
98}
99