use base::errno_result;
use base::error;
use base::ioctl_with_ref;
use base::Error;
use base::Result;
use kvm_sys::*;
use libc::ENXIO;
use super::Config;
use super::Kvm;
use super::KvmVcpu;
use super::KvmVm;
use crate::ClockState;
use crate::DeviceKind;
use crate::Hypervisor;
use crate::IrqSourceChip;
use crate::ProtectionType;
use crate::VcpuExit;
use crate::VcpuRegister;
use crate::VcpuRiscv64;
use crate::VmCap;
use crate::VmRiscv64;
impl KvmVm {
pub fn init_arch(&self, _cfg: &Config) -> Result<()> {
Ok(())
}
pub fn check_capability_arch(&self, _c: VmCap) -> Option<bool> {
None
}
pub fn get_device_params_arch(&self, kind: DeviceKind) -> Option<kvm_create_device> {
match kind {
DeviceKind::RiscvAia => Some(kvm_create_device {
type_: kvm_device_type_KVM_DEV_TYPE_RISCV_AIA,
fd: 0,
flags: 0,
}),
_ => None,
}
}
pub fn get_pvclock_arch(&self) -> Result<ClockState> {
Err(Error::new(ENXIO))
}
pub fn set_pvclock_arch(&self, _state: &ClockState) -> Result<()> {
Err(Error::new(ENXIO))
}
}
impl Kvm {
pub fn get_vm_type(&self, protection_type: ProtectionType) -> Result<u32> {
if protection_type == ProtectionType::Unprotected {
Ok(0)
} else {
error!("Protected mode is not supported on riscv64.");
Err(Error::new(libc::EINVAL))
}
}
pub fn get_guest_phys_addr_bits(&self) -> u8 {
48
}
}
impl VmRiscv64 for KvmVm {
fn get_hypervisor(&self) -> &dyn Hypervisor {
&self.kvm
}
fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuRiscv64>> {
Ok(Box::new(self.create_kvm_vcpu(id)?))
}
}
impl KvmVcpu {
pub fn system_event_reset(&self, _event_flags: u64) -> Result<VcpuExit> {
Ok(VcpuExit::SystemEventReset)
}
#[inline]
pub(crate) fn handle_vm_exit_arch(&self, run: &mut kvm_run) -> Option<VcpuExit> {
match run.exit_reason {
KVM_EXIT_RISCV_SBI => {
let extension_id = unsafe { run.__bindgen_anon_1.riscv_sbi.extension_id };
let function_id = unsafe { run.__bindgen_anon_1.riscv_sbi.function_id };
let args = unsafe { run.__bindgen_anon_1.riscv_sbi.args };
Some(VcpuExit::Sbi {
extension_id,
function_id,
args,
})
}
KVM_EXIT_RISCV_CSR => {
let csr_num = unsafe { run.__bindgen_anon_1.riscv_csr.csr_num };
let new_value = unsafe { run.__bindgen_anon_1.riscv_csr.new_value };
let write_mask = unsafe { run.__bindgen_anon_1.riscv_csr.write_mask };
let ret_value = unsafe { run.__bindgen_anon_1.riscv_csr.ret_value };
Some(VcpuExit::RiscvCsr {
csr_num,
new_value,
write_mask,
ret_value,
})
}
_ => None,
}
}
}
impl VcpuRiscv64 for KvmVcpu {
fn set_one_reg(&self, reg: VcpuRegister, data: u64) -> Result<()> {
let data_ref = &data as *const u64;
let onereg = kvm_one_reg {
id: vcpu_reg_id(reg),
addr: data_ref as u64,
};
let ret = unsafe { ioctl_with_ref(self, KVM_SET_ONE_REG, &onereg) };
if ret == 0 {
Ok(())
} else {
errno_result()
}
}
fn get_one_reg(&self, reg: VcpuRegister) -> Result<u64> {
let mut val: u64 = 0;
let onereg = kvm_one_reg {
id: vcpu_reg_id(reg),
addr: (&mut val as *mut u64) as u64,
};
let ret = unsafe { ioctl_with_ref(self, KVM_GET_ONE_REG, &onereg) };
if ret == 0 {
Ok(val)
} else {
errno_result()
}
}
}
fn vcpu_reg_id(reg: VcpuRegister) -> u64 {
fn id_from_reg(reg_type: u32, index: u64) -> u64 {
reg_type as u64 | index | KVM_REG_RISCV as u64 | KVM_REG_SIZE_U64
}
match reg {
VcpuRegister::Config(r) => id_from_reg(KVM_REG_RISCV_CONFIG, r as u64),
VcpuRegister::Core(r) => id_from_reg(KVM_REG_RISCV_CORE, r as u64),
VcpuRegister::Timer(r) => id_from_reg(KVM_REG_RISCV_TIMER, r as u64),
}
}
pub(super) fn chip_to_kvm_chip(chip: IrqSourceChip) -> u32 {
match chip {
IrqSourceChip::Aia => 0,
_ => {
error!("Invalid IrqChipSource for Riscv {:?}", chip);
0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::CoreRegister;
#[test]
fn reg_id() {
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::Pc)),
0x8030_0000_0200_0000
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::Ra)),
0x8030_0000_0200_0001
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::Sp)),
0x8030_0000_0200_0002
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::Gp)),
0x8030_0000_0200_0003
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::Tp)),
0x8030_0000_0200_0004
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T0)),
0x8030_0000_0200_0005
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T1)),
0x8030_0000_0200_0006
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T2)),
0x8030_0000_0200_0007
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S0)),
0x8030_0000_0200_0008
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S1)),
0x8030_0000_0200_0009
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A0)),
0x8030_0000_0200_000a
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A1)),
0x8030_0000_0200_000b
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A2)),
0x8030_0000_0200_000c
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A3)),
0x8030_0000_0200_000d
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A4)),
0x8030_0000_0200_000e
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A5)),
0x8030_0000_0200_000f
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A6)),
0x8030_0000_0200_0010
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::A7)),
0x8030_0000_0200_0011
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S2)),
0x8030_0000_0200_0012
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S3)),
0x8030_0000_0200_0013
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S4)),
0x8030_0000_0200_0014
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S5)),
0x8030_0000_0200_0015
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S6)),
0x8030_0000_0200_0016
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S7)),
0x8030_0000_0200_0017
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S8)),
0x8030_0000_0200_0018
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S9)),
0x8030_0000_0200_0019
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S10)),
0x8030_0000_0200_001a
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::S11)),
0x8030_0000_0200_001b
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T3)),
0x8030_0000_0200_001c
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T4)),
0x8030_0000_0200_001d
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T5)),
0x8030_0000_0200_001e
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::T6)),
0x8030_0000_0200_001f
);
assert_eq!(
vcpu_reg_id(VcpuRegister::Core(CoreRegister::Mode)),
0x8030_0000_0200_0020
);
}
}