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