use std::os::fd::{FromRawFd, OwnedFd};
use snafu::ResultExt;
use crate::arch::reg::{Reg, SReg};
use crate::hv::kvm::vcpu::KvmVcpu;
use crate::hv::kvm::vm::KvmVm;
use crate::hv::{Result, Vcpu, error};
use crate::sys::kvm::{
KvmArmVcpuFeature, KvmCap, KvmOneReg, kvm_arm_preferred_target, kvm_arm_vcpu_init,
kvm_create_vcpu, kvm_get_one_reg, kvm_set_one_reg,
};
#[derive(Debug)]
pub struct VcpuArch {
mpidr: u64,
}
impl VcpuArch {
pub fn new(id: u64) -> Self {
VcpuArch { mpidr: id }
}
}
const fn encode_reg(reg: Reg) -> u64 {
0x6030_0000_0010_0000 | ((reg as u64) << 1)
}
const fn encode_system_reg(reg: SReg) -> u64 {
0x6030_0000_0013_0000 | reg.raw() as u64
}
impl KvmVcpu {
pub fn create_vcpu(vm: &KvmVm, index: u16, _: u64) -> Result<OwnedFd> {
let fd = unsafe { kvm_create_vcpu(&vm.vm.fd, index as u32) }.context(error::CreateVcpu)?;
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}
pub fn kvm_vcpu_init(&mut self, is_bsp: bool) -> Result<()> {
let mut arm_cpu_init =
unsafe { kvm_arm_preferred_target(&self.vm.fd) }.context(error::CreateVcpu)?;
self.vm.check_extension(KvmCap::ARM_PSCI_0_2)?;
arm_cpu_init.features[0] |= KvmArmVcpuFeature::PSCI_0_2.bits();
if !is_bsp {
arm_cpu_init.features[0] |= KvmArmVcpuFeature::POWER_OFF.bits();
}
unsafe { kvm_arm_vcpu_init(&self.fd, &arm_cpu_init) }.context(error::CreateVcpu)?;
self.set_sregs(&[(SReg::MPIDR_EL1, self.arch.mpidr)])
}
fn get_one_reg(&self, reg: u64) -> Result<u64> {
let mut val = 0;
let one_reg = KvmOneReg {
id: reg,
addr: &mut val as *mut _ as _,
};
unsafe { kvm_get_one_reg(&self.fd, &one_reg) }.context(error::VcpuReg)?;
Ok(val)
}
fn set_one_reg(&self, reg: u64, val: u64) -> Result<()> {
let one_reg = KvmOneReg {
id: reg,
addr: &val as *const _ as _,
};
unsafe { kvm_set_one_reg(&self.fd, &one_reg) }.context(error::VcpuReg)?;
Ok(())
}
pub fn kvm_set_regs(&self, vals: &[(Reg, u64)]) -> Result<()> {
for (reg, val) in vals {
self.set_one_reg(encode_reg(*reg), *val)?;
}
Ok(())
}
pub fn kvm_get_reg(&self, reg: Reg) -> Result<u64> {
self.get_one_reg(encode_reg(reg))
}
pub fn kvm_set_sregs(&self, vals: &[(SReg, u64)]) -> Result<()> {
for (reg, val) in vals {
self.set_one_reg(encode_system_reg(*reg), *val)?;
}
Ok(())
}
pub fn kvm_get_sreg(&self, reg: SReg) -> Result<u64> {
self.get_one_reg(encode_system_reg(reg))
}
}