• 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 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