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