mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: retrieve timebase-frequency from KVM instead of hardcoding
The RISC-V device tree's timebase-frequency was hardcoded to 10 MHz (0x989680). Actual hardware uses different frequencies. Read the timebase frequency from KVM_GET_ONE_REG via KVM_REG_RISCV_TIMER (offset 0, kvm_riscv_timer.frequency), thread it through the VMM to arch to FDT layers, and fall back to the 10 MHz default when KVM returns no value. Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn>
This commit is contained in:
@@ -71,6 +71,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
aia_device: &Arc<Mutex<dyn Vaia>>,
|
||||
initrd: &Option<InitramfsConfig>,
|
||||
pci_space_info: &[PciSpaceInfo],
|
||||
timebase_frequency: u32,
|
||||
) -> FdtWriterResult<Vec<u8>> {
|
||||
// Allocate stuff necessary for the holding the blob.
|
||||
let mut fdt = FdtWriter::new()?;
|
||||
@@ -86,7 +87,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
||||
// Properties
|
||||
fdt.property_u32("#address-cells", ADDRESS_CELLS)?;
|
||||
fdt.property_u32("#size-cells", SIZE_CELLS)?;
|
||||
create_cpu_nodes(&mut fdt, num_vcpu, isa_string)?;
|
||||
create_cpu_nodes(&mut fdt, num_vcpu, isa_string, timebase_frequency)?;
|
||||
create_memory_node(&mut fdt, guest_mem)?;
|
||||
create_chosen_node(&mut fdt, cmdline, initrd)?;
|
||||
create_aia_node(&mut fdt, aia_device)?;
|
||||
@@ -110,14 +111,17 @@ pub fn write_fdt_to_memory(fdt_final: &[u8], guest_mem: &GuestMemoryMmap) -> Res
|
||||
}
|
||||
|
||||
// Following are the auxiliary function for creating the different nodes that we append to our FDT.
|
||||
fn create_cpu_nodes(fdt: &mut FdtWriter, num_cpus: u32, isa_string: &str) -> FdtWriterResult<()> {
|
||||
fn create_cpu_nodes(
|
||||
fdt: &mut FdtWriter,
|
||||
num_cpus: u32,
|
||||
isa_string: &str,
|
||||
timebase_frequency: u32,
|
||||
) -> FdtWriterResult<()> {
|
||||
// See https://elixir.bootlin.com/linux/v6.10/source/Documentation/devicetree/bindings/riscv/cpus.yaml
|
||||
let cpus = fdt.begin_node("cpus")?;
|
||||
// As per documentation, on RISC-V 64-bit systems value should be set to 1.
|
||||
fdt.property_u32("#address-cells", 0x01)?;
|
||||
fdt.property_u32("#size-cells", 0x0)?;
|
||||
// TODO: Retrieve CPU frequency from cpu timer regs
|
||||
let timebase_frequency: u32 = 0x989680;
|
||||
fdt.property_u32("timebase-frequency", timebase_frequency)?;
|
||||
|
||||
for cpu_index in 0..num_cpus {
|
||||
|
||||
@@ -168,6 +168,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
||||
initrd: &Option<super::InitramfsConfig>,
|
||||
pci_space_info: &[PciSpaceInfo],
|
||||
aia_device: &Arc<Mutex<dyn Vaia>>,
|
||||
timebase_frequency: u32,
|
||||
) -> super::Result<()> {
|
||||
let isa_string = isa_string_from_host()?;
|
||||
let fdt_final = fdt::create_fdt(
|
||||
@@ -179,6 +180,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
||||
aia_device,
|
||||
initrd,
|
||||
pci_space_info,
|
||||
timebase_frequency,
|
||||
)
|
||||
.map_err(|_| Error::SetupFdt)?;
|
||||
|
||||
|
||||
@@ -516,6 +516,14 @@ pub trait Vcpu: Send + Sync {
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
fn get_non_core_reg(&self, non_core_reg: u32) -> Result<u64>;
|
||||
///
|
||||
/// Get the timebase frequency (timer frequency in Hz) on RISC-V 64-bit.
|
||||
/// This is the frequency at which the RISC-V `time` CSR increments.
|
||||
///
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
fn get_timebase_frequency(&self) -> Result<u64> {
|
||||
Ok(0)
|
||||
}
|
||||
///
|
||||
/// Configure core registers for a given CPU.
|
||||
///
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
|
||||
@@ -124,7 +124,7 @@ use kvm_bindings::{
|
||||
KVM_REG_SIZE_U32, KVM_REG_SIZE_U64, KVM_REG_SIZE_U128, kvm_regs, user_pt_regs,
|
||||
};
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
use kvm_bindings::{KVM_REG_RISCV_CORE, kvm_riscv_core};
|
||||
use kvm_bindings::{KVM_REG_RISCV_CORE, KVM_REG_RISCV_TIMER, kvm_riscv_core};
|
||||
#[cfg(feature = "tdx")]
|
||||
use kvm_bindings::{KVM_X86_SW_PROTECTED_VM, KVMIO};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -2730,6 +2730,18 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
fn get_timebase_frequency(&self) -> cpu::Result<u64> {
|
||||
use kvm_bindings::kvm_riscv_timer;
|
||||
let freq_offset = offset_of!(kvm_riscv_timer, frequency);
|
||||
let id = riscv64_reg_id!(KVM_REG_RISCV_TIMER, freq_offset);
|
||||
let mut freq_bytes = [0u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(id, &mut freq_bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetNonCoreRegister(e.into()))?;
|
||||
Ok(u64::from_le_bytes(freq_bytes))
|
||||
}
|
||||
|
||||
///
|
||||
/// Configure core registers for a given CPU.
|
||||
///
|
||||
|
||||
@@ -642,6 +642,11 @@ impl Vcpu {
|
||||
self.vcpu.run()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub fn get_timebase_frequency(&self) -> result::Result<u64, hypervisor::HypervisorCpuError> {
|
||||
self.vcpu.get_timebase_frequency()
|
||||
}
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
pub fn set_sev_control_register(&self, vmsa_pfn: u64) -> Result<()> {
|
||||
self.vcpu
|
||||
|
||||
@@ -1988,6 +1988,16 @@ impl Vm {
|
||||
|
||||
// TODO: PMU support for riscv64 is scheduled to next stage.
|
||||
|
||||
let timebase_frequency = self
|
||||
.cpu_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.vcpus()
|
||||
.first()
|
||||
.and_then(|vcpu| vcpu.lock().unwrap().get_timebase_frequency().ok())
|
||||
.map(|f| f as u32)
|
||||
.unwrap_or(0x989680);
|
||||
|
||||
arch::configure_system(
|
||||
&mem,
|
||||
cmdline.as_cstring().unwrap().to_str().unwrap(),
|
||||
@@ -1996,6 +2006,7 @@ impl Vm {
|
||||
&initramfs_config,
|
||||
&pci_space_info,
|
||||
&vaia,
|
||||
timebase_frequency,
|
||||
)
|
||||
.map_err(Error::ConfigureSystem)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user