Compare commits

...

11 Commits

Author SHA1 Message Date
Kshitij Kapoor 9981159b33
Merge ba0787af14 into 241d1d5cdb 2024-05-09 16:31:16 +08:00
Wei Liu 241d1d5cdb hypervisor: kvm: add missing capability requirements
The list is gathered from going through various code paths in the code
base.

No functional change intended.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-05-09 06:50:57 +00:00
Wei Liu c07671edb4 hypervisor: kvm: introduce a check_extension macro
That reduces code repetition.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-05-09 06:50:57 +00:00
Wei Liu 8093820965 hypervisor: kvm: sort the required capabilities
No functional change.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-05-09 06:50:57 +00:00
Wei Liu 86cf50565e hypervisor: kvm: drop the check for Cap::SignalMsi
Per the KVM API document, that capability is only valid with in-kernel
irqchip that handles MSIs.

Through out the code base, there is no call to KVM_IOCTL_SIGNAL_MSI.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
2024-05-09 06:50:57 +00:00
KshitijKapoor8 ba0787af14 misc: change vcpu variable size
Modified vcpu related information to support
more vcpu's, mostly in the vmm package

Signed-off-by: Kshitij Kapoor <kshitij@utexas.edu>
2024-05-06 15:40:36 -05:00
KshitijKapoor8 2ff5cd3d2e performance-metrics: change vcpu variable size
Modified vcpu related information to support
more vcpu's

Signed-off-by: Kshitij Kapoor <kshitij@utexas.edu>
2024-05-06 15:24:02 -05:00
KshitijKapoor8 4f284ca53e hypervisor: change vcpu variable size
Modified vcpu related information to support
more vcpu's

Signed-off-by: Kshitij Kapoor <kshitij@utexas.edu>
2024-05-06 15:22:30 -05:00
KshitijKapoor8 c98f07b753 docs: changed docs to accurately reflect vcpu size
The new vcpu size is an unsigned int of 32 bits,
modified the docs to reflect this

Signed-off-by: Kshitij Kapoor <kshitij@utexas.edu>
2024-05-06 15:17:05 -05:00
KshitijKapoor8 2bf950670a devices: change vcpu variable size
Modified vcpu related information to support
more vcpu's.

Signed-off-by: Kshitij Kapoor <kshitij@utexas.edu>
2024-05-06 15:13:22 -05:00
KshitijKapoor8 50c7c09867 arch: change vcpu variable size
Modified vcpu related information to support
more vcpu's.

Signed-off-by: Kshitij Kapoor <kshitij@utexas.edu>
2024-05-06 15:09:43 -05:00
18 changed files with 87 additions and 68 deletions

View File

@ -219,7 +219,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
guest_mem: &GuestMemoryMmap,
cmdline: &str,
vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>,
vcpu_topology: Option<(u32, u32, u32)>,
device_info: &HashMap<(DeviceType, String), T, S>,
gic_device: &Arc<Mutex<dyn Vgic>>,
initrd: &Option<InitramfsConfig>,
@ -281,7 +281,7 @@ pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> R
fn create_cpu_nodes(
fdt: &mut FdtWriter,
vcpu_mpidr: &[u64],
vcpu_topology: Option<(u8, u8, u8)>,
vcpu_topology: Option<(u32, u32, u32)>,
numa_nodes: &NumaNodes,
) -> FdtWriterResult<()> {
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/arm/cpus.yaml.

View File

@ -125,7 +125,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
guest_mem: &GuestMemoryMmap,
cmdline: &str,
vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>,
vcpu_topology: Option<(u32, u32, u32)>,
device_info: &HashMap<(DeviceType, String), T, S>,
initrd: &Option<super::InitramfsConfig>,
pci_space_info: &[PciSpaceInfo],

View File

@ -40,7 +40,7 @@ pub struct Gic {
impl Gic {
pub fn new(
vcpu_count: u8,
vcpu_count: u32,
interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
vm: Arc<dyn hypervisor::Vm>,
) -> Result<Gic> {

View File

@ -11,8 +11,8 @@ to set vCPUs options for Cloud Hypervisor.
```rust
struct CpusConfig {
boot_vcpus: u8,
max_vcpus: u8,
boot_vcpus: u32,
max_vcpus: u32,
topology: Option<CpuTopology>,
kvm_hyperv: bool,
max_phys_bits: u8,
@ -54,7 +54,7 @@ For instance, if booting the VM with 2 vCPUs and a maximum of 6 vCPUs, it means
up to 4 vCPUs can be added later at runtime by resizing the VM.
The value must be greater than or equal to the number of boot vCPUs.
The value is an unsigned integer of 8 bits.
The value is an unsigned integer of 32 bits.
By default this option takes the value of `boot`, meaning vCPU hotplug is not
expected and can't be performed.
@ -148,7 +148,7 @@ The affinity is described through the following structure:
```rust
struct CpuAffinity {
vcpu: u8,
vcpu: u32,
host_cpus: Vec<u8>,
}
```
@ -164,7 +164,7 @@ brackets attached to `@` define the list of host CPUs the vCPU is allowed to
run onto.
Multiple values can be provided to define each list. Each value is an unsigned
integer of 8 bits.
integer of 32 bits.
For instance, if one needs to run vCPU 0 on host CPUs from 0 to 4, the syntax
using `-` will help define a contiguous range with `affinity=0@[0-4]`. The

View File

@ -106,12 +106,23 @@ pub fn is_system_register(regid: u64) -> bool {
}
pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
if !kvm.check_extension(Cap::SignalMsi) {
return Err(KvmError::CapabilityMissing(Cap::SignalMsi));
}
if !kvm.check_extension(Cap::OneReg) {
return Err(KvmError::CapabilityMissing(Cap::OneReg));
macro_rules! check_extension {
($cap:expr) => {
if !kvm.check_extension($cap) {
return Err(KvmError::CapabilityMissing($cap));
}
};
}
// SetGuestDebug is required but some kernels have it implemented without the capability flag.
check_extension!(Cap::ImmediateExit);
check_extension!(Cap::Ioeventfd);
check_extension!(Cap::Irqchip);
check_extension!(Cap::Irqfd);
check_extension!(Cap::IrqRouting);
check_extension!(Cap::MpState);
check_extension!(Cap::OneReg);
check_extension!(Cap::UserMemory);
Ok(())
}

View File

@ -451,7 +451,7 @@ impl vm::Vm for KvmVm {
///
fn create_vcpu(
&self,
id: u8,
id: u32,
vm_ops: Option<Arc<dyn VmOps>>,
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
let fd = self

View File

@ -32,29 +32,37 @@ pub use {
/// Check KVM extension for Linux
///
pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
if !kvm.check_extension(Cap::SignalMsi) {
return Err(KvmError::CapabilityMissing(Cap::SignalMsi));
}
if !kvm.check_extension(Cap::TscDeadlineTimer) {
return Err(KvmError::CapabilityMissing(Cap::TscDeadlineTimer));
}
if !kvm.check_extension(Cap::SplitIrqchip) {
return Err(KvmError::CapabilityMissing(Cap::SplitIrqchip));
}
if !kvm.check_extension(Cap::SetIdentityMapAddr) {
return Err(KvmError::CapabilityMissing(Cap::SetIdentityMapAddr));
}
if !kvm.check_extension(Cap::SetTssAddr) {
return Err(KvmError::CapabilityMissing(Cap::SetTssAddr));
}
if !kvm.check_extension(Cap::ImmediateExit) {
return Err(KvmError::CapabilityMissing(Cap::ImmediateExit));
}
if !kvm.check_extension(Cap::GetTscKhz) {
return Err(KvmError::CapabilityMissing(Cap::GetTscKhz));
macro_rules! check_extension {
($cap:expr) => {
if !kvm.check_extension($cap) {
return Err(KvmError::CapabilityMissing($cap));
}
};
}
// DeviceCtrl, EnableCap, and SetGuestDebug are also required, but some kernels have
// the features implemented without the capability flags.
check_extension!(Cap::AdjustClock);
check_extension!(Cap::ExtCpuid);
check_extension!(Cap::GetTscKhz);
check_extension!(Cap::ImmediateExit);
check_extension!(Cap::Ioeventfd);
check_extension!(Cap::Irqchip);
check_extension!(Cap::Irqfd);
check_extension!(Cap::IrqRouting);
check_extension!(Cap::MpState);
check_extension!(Cap::SetIdentityMapAddr);
check_extension!(Cap::SetTssAddr);
check_extension!(Cap::SplitIrqchip);
check_extension!(Cap::TscDeadlineTimer);
check_extension!(Cap::UserMemory);
check_extension!(Cap::UserNmi);
check_extension!(Cap::VcpuEvents);
check_extension!(Cap::Xcrs);
check_extension!(Cap::Xsave);
Ok(())
}
#[derive(Clone, Serialize, Deserialize)]
pub struct VcpuKvmState {
pub cpuid: Vec<CpuIdEntry>,

View File

@ -1709,7 +1709,7 @@ impl vm::Vm for MshvVm {
///
fn create_vcpu(
&self,
id: u8,
id: u32,
vm_ops: Option<Arc<dyn VmOps>>,
) -> vm::Result<Arc<dyn cpu::Vcpu>> {
let vcpu_fd = self

View File

@ -289,7 +289,7 @@ pub trait Vm: Send + Sync + Any {
/// Unregister an event that will, when signaled, trigger the `gsi` IRQ.
fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>;
/// Creates a new KVM vCPU file descriptor and maps the memory corresponding
fn create_vcpu(&self, id: u8, vm_ops: Option<Arc<dyn VmOps>>) -> Result<Arc<dyn Vcpu>>;
fn create_vcpu(&self, id: u32, vm_ops: Option<Arc<dyn VmOps>>) -> Result<Arc<dyn Vcpu>>;
#[cfg(target_arch = "aarch64")]
fn create_vgic(&self, config: VgicConfig) -> Result<Arc<Mutex<dyn Vgic>>>;

View File

@ -134,7 +134,7 @@ pub struct PerformanceTestControl {
queue_size: Option<u32>,
net_control: Option<(bool, bool)>, // First bool is for RX(true)/TX(false), second bool is for bandwidth or PPS
fio_control: Option<(FioOps, bool)>, // Second parameter controls whether we want bandwidth or IOPS
num_boot_vcpus: Option<u8>,
num_boot_vcpus: Option<u32>,
}
impl fmt::Display for PerformanceTestControl {

View File

@ -723,7 +723,7 @@ fn resize_config(
memory: Option<&str>,
balloon: Option<&str>,
) -> Result<String, Error> {
let desired_vcpus: Option<u8> = if let Some(cpus) = cpus {
let desired_vcpus: Option<u32> = if let Some(cpus) = cpus {
Some(cpus.parse().map_err(Error::InvalidCpuCount)?)
} else {
None

View File

@ -653,7 +653,7 @@ fn remote_command_w_output(api_socket: &str, command: &str, arg: Option<&str>) -
fn resize_command(
api_socket: &str,
desired_vcpus: Option<u8>,
desired_vcpus: Option<u32>,
desired_ram: Option<usize>,
desired_balloon: Option<usize>,
event_file: Option<&str>,

View File

@ -226,7 +226,7 @@ pub struct VmmPingResponse {
#[derive(Clone, Deserialize, Serialize, Default, Debug)]
pub struct VmResizeData {
pub desired_vcpus: Option<u8>,
pub desired_vcpus: Option<u32>,
pub desired_ram: Option<u64>,
pub desired_balloon: Option<u64>,
}
@ -316,7 +316,7 @@ pub trait RequestHandler {
fn vm_resize(
&mut self,
desired_vcpus: Option<u8>,
desired_vcpus: Option<u32>,
desired_ram: Option<u64>,
desired_balloon: Option<u64>,
) -> Result<(), VmError>;

View File

@ -628,11 +628,11 @@ impl CpusConfig {
.add("features");
parser.parse(cpus).map_err(Error::ParseCpus)?;
let boot_vcpus: u8 = parser
let boot_vcpus: u32 = parser
.convert("boot")
.map_err(Error::ParseCpus)?
.unwrap_or(DEFAULT_VCPUS);
let max_vcpus: u8 = parser
let max_vcpus: u32 = parser
.convert("max")
.map_err(Error::ParseCpus)?
.unwrap_or(boot_vcpus);

View File

@ -322,7 +322,7 @@ macro_rules! round_up {
pub struct Vcpu {
// The hypervisor abstracted CPU.
vcpu: Arc<dyn hypervisor::Vcpu>,
id: u8,
id: u32,
#[cfg(target_arch = "aarch64")]
mpidr: u64,
saved_state: Option<CpuState>,
@ -340,7 +340,7 @@ impl Vcpu {
/// * `vm_ops` - Optional object for exit handling.
/// * `cpu_vendor` - CPU vendor as reported by __cpuid(0x0)
pub fn new(
id: u8,
id: u32,
apic_id: u8,
vm: &Arc<dyn hypervisor::Vm>,
vm_ops: Option<Arc<dyn VmOps>>,
@ -779,7 +779,7 @@ impl CpuManager {
Ok(())
}
fn create_vcpu(&mut self, cpu_id: u8, snapshot: Option<Snapshot>) -> Result<Arc<Mutex<Vcpu>>> {
fn create_vcpu(&mut self, cpu_id: u32, snapshot: Option<Snapshot>) -> Result<Arc<Mutex<Vcpu>>> {
info!("Creating vCPU: cpu_id = {}", cpu_id);
#[cfg(target_arch = "x86_64")]
@ -791,7 +791,7 @@ impl CpuManager {
let mut vcpu = Vcpu::new(
cpu_id,
x2apic_id as u8,
x2apic_id as u32,
&self.vm,
Some(self.vm_ops.clone()),
#[cfg(target_arch = "x86_64")]
@ -872,7 +872,7 @@ impl CpuManager {
/// Only create new vCPUs if there aren't any inactive ones to reuse
fn create_vcpus(
&mut self,
desired_vcpus: u8,
desired_vcpus: u32,
snapshot: Option<Snapshot>,
) -> Result<Vec<Arc<Mutex<Vcpu>>>> {
let mut vcpus: Vec<Arc<Mutex<Vcpu>>> = vec![];
@ -889,7 +889,7 @@ impl CpuManager {
}
// Only create vCPUs in excess of all the allocated vCPUs.
for cpu_id in self.vcpus.len() as u8..desired_vcpus {
for cpu_id in self.vcpus.len() as u32..desired_vcpus {
vcpus.push(self.create_vcpu(
cpu_id,
// TODO: The special format of the CPU id can be removed once
@ -927,7 +927,7 @@ impl CpuManager {
fn start_vcpu(
&mut self,
vcpu: Arc<Mutex<Vcpu>>,
vcpu_id: u8,
vcpu_id: u32,
vcpu_thread_barrier: Arc<Barrier>,
inserting: bool,
) -> Result<()> {
@ -1187,7 +1187,7 @@ impl CpuManager {
/// Start up as many vCPUs threads as needed to reach `desired_vcpus`
fn activate_vcpus(
&mut self,
desired_vcpus: u8,
desired_vcpus: u32,
inserting: bool,
paused: Option<bool>,
) -> Result<()> {
@ -1213,7 +1213,7 @@ impl CpuManager {
// This reuses any inactive vCPUs as well as any that were newly created
for vcpu_id in self.present_vcpus()..desired_vcpus {
let vcpu = Arc::clone(&self.vcpus[vcpu_id as usize]);
let vcpu = Arc::clone(&self.vcpus[vcpu_id as u32]);
self.start_vcpu(vcpu, vcpu_id, vcpu_thread_barrier.clone(), inserting)?;
}
@ -1222,7 +1222,7 @@ impl CpuManager {
Ok(())
}
fn mark_vcpus_for_removal(&mut self, desired_vcpus: u8) {
fn mark_vcpus_for_removal(&mut self, desired_vcpus: u32) {
// Mark vCPUs for removal, actual removal happens on ejection
for cpu_id in desired_vcpus..self.present_vcpus() {
self.vcpu_states[usize::from(cpu_id)].removing = true;
@ -1241,7 +1241,7 @@ impl CpuManager {
false
}
fn remove_vcpu(&mut self, cpu_id: u8) -> Result<()> {
fn remove_vcpu(&mut self, cpu_id: u32) -> Result<()> {
info!("Removing vCPU: cpu_id = {}", cpu_id);
let state = &mut self.vcpu_states[usize::from(cpu_id)];
state.kill.store(true, Ordering::SeqCst);
@ -1271,7 +1271,7 @@ impl CpuManager {
}
pub fn start_restored_vcpus(&mut self) -> Result<()> {
self.activate_vcpus(self.vcpus.len() as u8, false, Some(true))
self.activate_vcpus(self.vcpus.len() as u32, false, Some(true))
.map_err(|e| {
Error::StartRestoreVcpu(anyhow!("Failed to start restored vCPUs: {:#?}", e))
})?;
@ -1279,7 +1279,7 @@ impl CpuManager {
Ok(())
}
pub fn resize(&mut self, desired_vcpus: u8) -> Result<bool> {
pub fn resize(&mut self, desired_vcpus: u32) -> Result<bool> {
if desired_vcpus.cmp(&self.present_vcpus()) == cmp::Ordering::Equal {
return Ok(false);
}
@ -1348,11 +1348,11 @@ impl CpuManager {
Ok(())
}
pub fn boot_vcpus(&self) -> u8 {
pub fn boot_vcpus(&self) -> u32 {
self.config.boot_vcpus
}
pub fn max_vcpus(&self) -> u8 {
pub fn max_vcpus(&self) -> u32 {
self.config.max_vcpus
}
@ -1362,10 +1362,10 @@ impl CpuManager {
self.cpuid.clone()
}
fn present_vcpus(&self) -> u8 {
fn present_vcpus(&self) -> u32 {
self.vcpu_states
.iter()
.fold(0, |acc, state| acc + state.active() as u8)
.fold(0, |acc, state| acc + state.active() as u32)
}
#[cfg(target_arch = "aarch64")]
@ -1384,7 +1384,7 @@ impl CpuManager {
.collect()
}
pub fn get_vcpu_topology(&self) -> Option<(u8, u8, u8)> {
pub fn get_vcpu_topology(&self) -> Option<(u32, u32, u32)> {
self.config
.topology
.clone()
@ -2011,7 +2011,7 @@ impl Aml for CpuNotify {
}
struct CpuMethods {
max_vcpus: u8,
max_vcpus: u32,
dynamic: bool,
}

View File

@ -1536,7 +1536,7 @@ impl RequestHandler for Vmm {
fn vm_resize(
&mut self,
desired_vcpus: Option<u8>,
desired_vcpus: Option<u32>,
desired_ram: Option<u64>,
desired_balloon: Option<u64>,
) -> result::Result<(), VmError> {

View File

@ -1402,7 +1402,7 @@ impl Vm {
pub fn resize(
&mut self,
desired_vcpus: Option<u8>,
desired_vcpus: Option<u32>,
desired_memory: Option<u64>,
desired_balloon: Option<u64>,
) -> Result<()> {

View File

@ -9,7 +9,7 @@ use virtio_devices::RateLimiterConfig;
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpuAffinity {
pub vcpu: u8,
pub vcpu: u32,
pub host_cpus: Vec<usize>,
}
@ -39,8 +39,8 @@ pub fn default_cpuconfig_max_phys_bits() -> u8 {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct CpusConfig {
pub boot_vcpus: u8,
pub max_vcpus: u8,
pub boot_vcpus: u32,
pub max_vcpus: u32,
#[serde(default)]
pub topology: Option<CpuTopology>,
#[serde(default)]