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 exit = VmExit::Mmio {
26 addr: kvm_mmio.phys_addr,
27 write: if kvm_mmio.is_write > 0 {
28 Some(u64::from_ne_bytes(kvm_mmio.data))
29 } else {
30 None
31 },
32 size: kvm_mmio.len as u8,
33 };
34 Ok(exit)
35 }
36
37 #[cfg(target_arch = "x86_64")]
38 pub(super) fn handle_io(&mut self) -> VmExit {
39 let kvm_io = unsafe { self.kvm_run.exit.io };
40 let offset = kvm_io.data_offset as usize;
41 let count = kvm_io.count as usize;
42 let index = self.arch.io_index;
43 let write = if kvm_io.direction == KvmExitIo::IN {
44 None
45 } else {
46 let data = match kvm_io.size {
47 1 => unsafe { self.kvm_run.data_slice::<u8>(offset, count)[index] as u32 },
48 2 => unsafe { self.kvm_run.data_slice::<u16>(offset, count)[index] as u32 },
49 4 => unsafe { self.kvm_run.data_slice::<u32>(offset, count)[index] },
50 _ => unreachable!("kvm_io.size = {}", kvm_io.size),
51 };
52 Some(data)
53 };
54 VmExit::Io {
55 port: kvm_io.port,
56 write,
57 size: kvm_io.size,
58 }
59 }
60
61 pub(super) fn handle_hypercall(&mut self) -> Result<VmExit, Error> {
62 let hypercall = unsafe { self.kvm_run.exit.hypercall };
63 match hypercall.nr {
64 KvmHypercall::MAP_GPA_RANGE => {
65 let flag = KvmMapGpaRangeFlag::from_bits_retain(hypercall.args[2]);
66 Ok(VmExit::ConvertMemory {
67 gpa: hypercall.args[0],
68 size: hypercall.args[1] << 12,
69 private: flag.contains(KvmMapGpaRangeFlag::ENCRYPTED),
70 })
71 }
72 _ => unimplemented!(),
73 }
74 }
75
76 pub(super) fn handle_system_event(&mut self) -> Result<VmExit, Error> {
77 let kvm_system_event = unsafe { &self.kvm_run.exit.system_event };
78 match kvm_system_event.type_ {
79 KvmSystemEvent::SHUTDOWN => Ok(VmExit::Shutdown),
80 KvmSystemEvent::RESET => Ok(VmExit::Reboot),
81 _ => error::VmExit {
82 msg: format!("{kvm_system_event:#x?}"),
83 }
84 .fail(),
85 }
86 }
87
88 pub(crate) fn handle_memory_fault(&mut self) -> VmExit {
89 let memory_fault = unsafe { &self.kvm_run.exit.memory_fault };
90 let private = memory_fault.flags.contains(KvmMemoryFaultFlag::PRIVATE);
91 VmExit::ConvertMemory {
92 gpa: memory_fault.gpa,
93 size: memory_fault.size,
94 private,
95 }
96 }
97}
98