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 use base::errno_result;
6 use base::error;
7 use base::ioctl_with_ref;
8 use base::Error;
9 use base::Result;
10 use kvm_sys::*;
11 use libc::ENXIO;
12
13 use super::Config;
14 use super::Kvm;
15 use super::KvmVcpu;
16 use super::KvmVm;
17 use crate::ClockState;
18 use crate::DeviceKind;
19 use crate::Hypervisor;
20 use crate::IrqSourceChip;
21 use crate::ProtectionType;
22 use crate::VcpuExit;
23 use crate::VcpuRegister;
24 use crate::VcpuRiscv64;
25 use crate::VmCap;
26 use crate::VmRiscv64;
27
28 impl KvmVm {
29 /// Does platform specific initialization for the KvmVm.
init_arch(&self, _cfg: &Config) -> Result<()>30 pub fn init_arch(&self, _cfg: &Config) -> Result<()> {
31 Ok(())
32 }
33
34 /// Whether running under pKVM.
is_pkvm(&self) -> bool35 pub fn is_pkvm(&self) -> bool {
36 false
37 }
38
39 /// Checks if a particular `VmCap` is available, or returns None if arch-independent
40 /// Vm.check_capability() should handle the check.
check_capability_arch(&self, _c: VmCap) -> Option<bool>41 pub fn check_capability_arch(&self, _c: VmCap) -> Option<bool> {
42 None
43 }
44
45 /// Returns the params to pass to KVM_CREATE_DEVICE for a `kind` device on this arch, or None to
46 /// let the arch-independent `KvmVm::create_device` handle it.
get_device_params_arch(&self, kind: DeviceKind) -> Option<kvm_create_device>47 pub fn get_device_params_arch(&self, kind: DeviceKind) -> Option<kvm_create_device> {
48 match kind {
49 DeviceKind::RiscvAia => Some(kvm_create_device {
50 type_: kvm_device_type_KVM_DEV_TYPE_RISCV_AIA,
51 fd: 0,
52 flags: 0,
53 }),
54 _ => None,
55 }
56 }
57
58 /// Arch-specific implementation of `Vm::get_pvclock`. Always returns an error on riscv64.
get_pvclock_arch(&self) -> Result<ClockState>59 pub fn get_pvclock_arch(&self) -> Result<ClockState> {
60 Err(Error::new(ENXIO))
61 }
62
63 /// Arch-specific implementation of `Vm::set_pvclock`. Always returns an error on riscv64.
set_pvclock_arch(&self, _state: &ClockState) -> Result<()>64 pub fn set_pvclock_arch(&self, _state: &ClockState) -> Result<()> {
65 Err(Error::new(ENXIO))
66 }
67 }
68
69 impl Kvm {
70 // The riscv machine type is always 0. Protected VMs are not supported, yet.
get_vm_type(&self, protection_type: ProtectionType) -> Result<u32>71 pub fn get_vm_type(&self, protection_type: ProtectionType) -> Result<u32> {
72 if protection_type == ProtectionType::Unprotected {
73 Ok(0)
74 } else {
75 error!("Protected mode is not supported on riscv64.");
76 Err(Error::new(libc::EINVAL))
77 }
78 }
79
80 /// Get the size of guest physical addresses in bits.
get_guest_phys_addr_bits(&self) -> u881 pub fn get_guest_phys_addr_bits(&self) -> u8 {
82 // assume sv48 addressing
83 48
84 }
85 }
86
87 impl VmRiscv64 for KvmVm {
get_hypervisor(&self) -> &dyn Hypervisor88 fn get_hypervisor(&self) -> &dyn Hypervisor {
89 &self.kvm
90 }
91
create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuRiscv64>>92 fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuRiscv64>> {
93 // create_vcpu is declared separately for each arch so it can return the arch-apropriate
94 // vcpu type. But all use the same implementation in KvmVm::create_vcpu.
95 Ok(Box::new(self.create_kvm_vcpu(id)?))
96 }
97 }
98
99 impl KvmVcpu {
100 /// Handles a `KVM_EXIT_SYSTEM_EVENT` with event type `KVM_SYSTEM_EVENT_RESET` with the given
101 /// event flags and returns the appropriate `VcpuExit` value for the run loop to handle.
102 ///
103 /// `event_flags` should be one or more of the `KVM_SYSTEM_EVENT_RESET_FLAG_*` values defined by
104 /// KVM.
system_event_reset(&self, _event_flags: u64) -> Result<VcpuExit>105 pub fn system_event_reset(&self, _event_flags: u64) -> Result<VcpuExit> {
106 Ok(VcpuExit::SystemEventReset)
107 }
108 }
109
110 impl VcpuRiscv64 for KvmVcpu {
set_one_reg(&self, reg: VcpuRegister, data: u64) -> Result<()>111 fn set_one_reg(&self, reg: VcpuRegister, data: u64) -> Result<()> {
112 let data_ref = &data as *const u64;
113 let onereg = kvm_one_reg {
114 id: vcpu_reg_id(reg),
115 addr: data_ref as u64,
116 };
117 // Safe because we allocated the struct and we know the kernel will read exactly the size of
118 // the struct.
119 let ret = unsafe { ioctl_with_ref(self, KVM_SET_ONE_REG(), &onereg) };
120 if ret == 0 {
121 Ok(())
122 } else {
123 errno_result()
124 }
125 }
126
get_one_reg(&self, reg: VcpuRegister) -> Result<u64>127 fn get_one_reg(&self, reg: VcpuRegister) -> Result<u64> {
128 let val: u64 = 0;
129 let onereg = kvm_one_reg {
130 id: vcpu_reg_id(reg),
131 addr: (&val as *const u64) as u64,
132 };
133
134 // Safe because we allocated the struct and we know the kernel will read exactly the size of
135 // the struct.
136 let ret = unsafe { ioctl_with_ref(self, KVM_GET_ONE_REG(), &onereg) };
137 if ret == 0 {
138 Ok(val)
139 } else {
140 errno_result()
141 }
142 }
143 }
144
145 // Returns the id used for call to `KVM_[GET|SET]_ONE_REG`.
vcpu_reg_id(reg: VcpuRegister) -> u64146 fn vcpu_reg_id(reg: VcpuRegister) -> u64 {
147 fn id_from_reg(reg_type: u32, index: u64) -> u64 {
148 reg_type as u64 | index | KVM_REG_RISCV as u64 | KVM_REG_SIZE_U64
149 }
150
151 match reg {
152 VcpuRegister::Config(r) => id_from_reg(KVM_REG_RISCV_CONFIG, r as u64),
153 VcpuRegister::Core(r) => id_from_reg(KVM_REG_RISCV_CORE, r as u64),
154 VcpuRegister::Timer(r) => id_from_reg(KVM_REG_RISCV_TIMER, r as u64),
155 }
156 }
157
158 // This function translates an IrqSrouceChip to the kvm u32 equivalent. It has a different
159 // implementation between the architectures because the irqchip KVM constants are not defined on all
160 // of them.
chip_to_kvm_chip(chip: IrqSourceChip) -> u32161 pub(super) fn chip_to_kvm_chip(chip: IrqSourceChip) -> u32 {
162 match chip {
163 // Riscv does not have a constant for this, but the default routing
164 // setup seems to set this to 0
165 IrqSourceChip::Aia => 0,
166 _ => {
167 error!("Invalid IrqChipSource for Riscv {:?}", chip);
168 0
169 }
170 }
171 }
172
173 #[cfg(test)]
174 mod tests {
175 use super::*;
176 use crate::CoreRegister;
177
178 #[test]
reg_id()179 fn reg_id() {
180 assert_eq!(
181 vcpu_reg_id(VcpuRegister::Core(CoreRegister::Pc)),
182 0x8030_0000_0200_0000
183 );
184 assert_eq!(
185 vcpu_reg_id(VcpuRegister::Core(CoreRegister::Ra)),
186 0x8030_0000_0200_0001
187 );
188 assert_eq!(
189 vcpu_reg_id(VcpuRegister::Core(CoreRegister::Sp)),
190 0x8030_0000_0200_0002
191 );
192 assert_eq!(
193 vcpu_reg_id(VcpuRegister::Core(CoreRegister::Gp)),
194 0x8030_0000_0200_0003
195 );
196 assert_eq!(
197 vcpu_reg_id(VcpuRegister::Core(CoreRegister::Tp)),
198 0x8030_0000_0200_0004
199 );
200 assert_eq!(
201 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T0)),
202 0x8030_0000_0200_0005
203 );
204 assert_eq!(
205 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T1)),
206 0x8030_0000_0200_0006
207 );
208 assert_eq!(
209 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T2)),
210 0x8030_0000_0200_0007
211 );
212 assert_eq!(
213 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S0)),
214 0x8030_0000_0200_0008
215 );
216 assert_eq!(
217 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S1)),
218 0x8030_0000_0200_0009
219 );
220 assert_eq!(
221 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A0)),
222 0x8030_0000_0200_000a
223 );
224 assert_eq!(
225 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A1)),
226 0x8030_0000_0200_000b
227 );
228 assert_eq!(
229 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A2)),
230 0x8030_0000_0200_000c
231 );
232 assert_eq!(
233 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A3)),
234 0x8030_0000_0200_000d
235 );
236 assert_eq!(
237 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A4)),
238 0x8030_0000_0200_000e
239 );
240 assert_eq!(
241 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A5)),
242 0x8030_0000_0200_000f
243 );
244 assert_eq!(
245 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A6)),
246 0x8030_0000_0200_0010
247 );
248 assert_eq!(
249 vcpu_reg_id(VcpuRegister::Core(CoreRegister::A7)),
250 0x8030_0000_0200_0011
251 );
252 assert_eq!(
253 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S2)),
254 0x8030_0000_0200_0012
255 );
256 assert_eq!(
257 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S3)),
258 0x8030_0000_0200_0013
259 );
260 assert_eq!(
261 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S4)),
262 0x8030_0000_0200_0014
263 );
264 assert_eq!(
265 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S5)),
266 0x8030_0000_0200_0015
267 );
268 assert_eq!(
269 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S6)),
270 0x8030_0000_0200_0016
271 );
272 assert_eq!(
273 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S7)),
274 0x8030_0000_0200_0017
275 );
276 assert_eq!(
277 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S8)),
278 0x8030_0000_0200_0018
279 );
280 assert_eq!(
281 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S9)),
282 0x8030_0000_0200_0019
283 );
284 assert_eq!(
285 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S10)),
286 0x8030_0000_0200_001a
287 );
288 assert_eq!(
289 vcpu_reg_id(VcpuRegister::Core(CoreRegister::S11)),
290 0x8030_0000_0200_001b
291 );
292 assert_eq!(
293 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T3)),
294 0x8030_0000_0200_001c
295 );
296 assert_eq!(
297 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T4)),
298 0x8030_0000_0200_001d
299 );
300 assert_eq!(
301 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T5)),
302 0x8030_0000_0200_001e
303 );
304 assert_eq!(
305 vcpu_reg_id(VcpuRegister::Core(CoreRegister::T6)),
306 0x8030_0000_0200_001f
307 );
308 assert_eq!(
309 vcpu_reg_id(VcpuRegister::Core(CoreRegister::Mode)),
310 0x8030_0000_0200_0020
311 );
312 }
313 }
314