Skip to content

Commit 1d07062

Browse files
committed
refactor(vmm): 2-step CpuConfiguration build for x86_64
Build a custom `CpuConfiguration` with 2 steps: 1. Construct a base `CpuConfiguration`. 2. Apply CPU template to the default `CpuConfiguration`. Previously, all these processes were done in `CpuConfiguration::new()`, but this approach is a bit complex in the test perspective. In addition, we will be able to unify `CpuConfiguration` interface between x86_64 and aarch64 and simplify `configure_system_for_boot()` function in successive commits. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent dea14fc commit 1d07062

File tree

5 files changed

+90
-109
lines changed

5 files changed

+90
-109
lines changed

src/vmm/src/builder.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use crate::construct_kvm_mpidrs;
4242
use crate::device_manager::legacy::PortIODeviceManager;
4343
use crate::device_manager::mmio::MMIODeviceManager;
4444
use crate::device_manager::persist::MMIODevManagerConstructorArgs;
45-
use crate::guest_config::templates::GuestConfigError;
45+
use crate::guest_config::templates::{GetCpuTemplate, GetCpuTemplateError, GuestConfigError};
4646
use crate::persist::{MicrovmState, MicrovmStateError};
4747
use crate::resources::VmResources;
4848
use crate::vmm_config::boot_source::BootConfig;
@@ -63,8 +63,8 @@ pub enum StartMicrovmError {
6363
#[error("System configuration error: {0:?}")]
6464
ConfigureSystem(crate::arch::Error),
6565
/// Error using CPU template to configure vCPUs
66-
#[error("Unable to successfully create cpu configuration usable for guest vCPUs: {0:?}")]
67-
CreateCpuConfig(GuestConfigError),
66+
#[error("Failed to create guest config: {0:?}")]
67+
CreateGuestConfig(#[from] GuestConfigError),
6868
/// Internal errors are due to resource exhaustion.
6969
#[error("Cannot create network device. {}", format!("{:?}", .0).replace('\"', ""))]
7070
CreateNetDevice(devices::virtio::net::Error),
@@ -83,6 +83,9 @@ pub enum StartMicrovmError {
8383
/// Internal error encountered while starting a microVM.
8484
#[error("Internal error while starting microVM: {0}")]
8585
Internal(Error),
86+
/// Failed to get CPU template.
87+
#[error("Failed to get CPU template: {0}")]
88+
GetCpuTemplate(#[from] GetCpuTemplateError),
8689
/// The kernel command line is invalid.
8790
#[error("Invalid kernel command line: {0}")]
8891
KernelCmdline(String),
@@ -780,11 +783,26 @@ pub fn configure_system_for_boot(
780783
) -> std::result::Result<(), StartMicrovmError> {
781784
use self::StartMicrovmError::*;
782785

786+
let cpu_template = vm_config.cpu_template.get_cpu_template()?;
787+
783788
#[cfg(target_arch = "x86_64")]
784789
{
785-
let cpu_config =
786-
crate::guest_config::x86_64::CpuConfiguration::new(&vmm.vm, &vm_config.cpu_template)
787-
.map_err(CreateCpuConfig)?;
790+
use crate::guest_config::cpuid;
791+
// Construct the base CpuConfiguration to apply CPU template onto.
792+
let cpuid = cpuid::Cpuid::try_from(cpuid::RawCpuid::from(vmm.vm.supported_cpuid().clone()))
793+
.map_err(GuestConfigError::CpuidFromRaw)?;
794+
let msr_index_list = cpu_template.get_msr_index_list();
795+
let msrs = vcpus[0]
796+
.kvm_vcpu
797+
.get_msrs(msr_index_list)
798+
.map_err(GuestConfigError::VcpuIoctl)?;
799+
let cpu_config = crate::guest_config::x86_64::CpuConfiguration { cpuid, msrs };
800+
801+
// Apply CPU template to the base CpuConfiguration.
802+
let cpu_config = crate::guest_config::x86_64::CpuConfiguration::apply_template(
803+
cpu_config,
804+
&cpu_template,
805+
)?;
788806

789807
let vcpu_config = VcpuConfig {
790808
vcpu_count: vm_config.vcpu_count,
@@ -825,8 +843,7 @@ pub fn configure_system_for_boot(
825843
let cpu_config = crate::guest_config::aarch64::CpuConfiguration::new(
826844
&vcpus[0].kvm_vcpu.fd,
827845
&vm_config.cpu_template,
828-
)
829-
.map_err(CreateCpuConfig)?;
846+
)?;
830847

831848
let vcpu_config = VcpuConfig {
832849
vcpu_count: vm_config.vcpu_count,

src/vmm/src/guest_config/templates/x86_64.rs

+10
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,16 @@ where
327327
serializer.serialize_str(bitmap_str.as_str())
328328
}
329329

330+
impl CustomCpuTemplate {
331+
/// Get a list of MSR indices that are modified by the CPU template.
332+
pub fn get_msr_index_list(&self) -> Vec<u32> {
333+
self.msr_modifiers
334+
.iter()
335+
.map(|modifier| modifier.addr)
336+
.collect()
337+
}
338+
}
339+
330340
// TODO mark with #[cfg(test)] when we combine all crates into
331341
// one firecracker crate
332342
impl CustomCpuTemplate {

src/vmm/src/guest_config/x86_64/mod.rs

+5-61
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,10 @@ pub mod static_cpu_templates_new;
99

1010
use std::collections::HashMap;
1111

12-
use static_cpu_templates::*;
13-
14-
use super::cpuid::{CpuidKey, RawCpuid};
12+
use super::cpuid::CpuidKey;
1513
use super::templates::x86_64::CpuidRegister;
16-
use super::templates::{CpuTemplateType, CustomCpuTemplate};
14+
use super::templates::CustomCpuTemplate;
1715
use crate::guest_config::cpuid::Cpuid;
18-
use crate::vstate::vm::Vm;
1916

2017
/// Errors thrown while configuring templates.
2118
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
@@ -32,6 +29,9 @@ pub enum Error {
3229
/// Can create cpuid from raw.
3330
#[error("Can create cpuid from raw: {0}")]
3431
CpuidFromRaw(super::cpuid::CpuidTryFromRawCpuid),
32+
/// KVM vcpu ioctls failed.
33+
#[error("KVM vcpu ioctl failed: {0}")]
34+
VcpuIoctl(crate::vstate::vcpu::VcpuError),
3535
}
3636

3737
/// CPU configuration for x86_64 CPUs
@@ -46,62 +46,6 @@ pub struct CpuConfiguration {
4646
}
4747

4848
impl CpuConfiguration {
49-
/// Creates new CpuConfig with cpu template changes applied
50-
pub fn new(vm: &Vm, template: &Option<CpuTemplateType>) -> Result<Self, Error> {
51-
match template {
52-
Some(ref cpu_template) => Self::with_template(vm, cpu_template),
53-
None => Self::host(vm),
54-
}
55-
}
56-
57-
/// Creates new CpuConfig with default values
58-
pub fn host(vm: &Vm) -> Result<Self, Error> {
59-
let supported_cpuid = vm.supported_cpuid().clone();
60-
let supported_cpuid =
61-
Cpuid::try_from(RawCpuid::from(supported_cpuid)).map_err(Error::CpuidFromRaw)?;
62-
63-
Ok(Self {
64-
cpuid: supported_cpuid,
65-
msrs: Default::default(),
66-
})
67-
}
68-
69-
/// Creates new CpuConfig with cpu template changes applied
70-
pub fn with_template(vm: &Vm, template: &CpuTemplateType) -> Result<Self, Error> {
71-
match template {
72-
CpuTemplateType::Custom(template) => Self::host(vm)?.apply_template(template),
73-
CpuTemplateType::Static(template) => {
74-
let mut config = Self::host(vm)?;
75-
// If a template is specified, get the CPUID template, else use `cpuid`.
76-
let template_cpuid = match template {
77-
StaticCpuTemplate::C3 => static_cpu_templates::c3::c3(),
78-
StaticCpuTemplate::T2 => static_cpu_templates::t2::t2(),
79-
StaticCpuTemplate::T2S => static_cpu_templates::t2s::t2s(),
80-
StaticCpuTemplate::T2CL => static_cpu_templates::t2cl::t2cl(),
81-
StaticCpuTemplate::T2A => static_cpu_templates::t2a::t2a(),
82-
StaticCpuTemplate::None => unreachable!("None state is invalid"),
83-
};
84-
85-
// Include leaves from host that are not present in CPUID template.
86-
config.cpuid = template_cpuid
87-
.include_leaves_from(config.cpuid)
88-
.map_err(Error::CpuidJoin)?;
89-
90-
match template {
91-
StaticCpuTemplate::T2S => {
92-
static_cpu_templates::t2s::update_t2s_msr_entries(&mut config.msrs);
93-
}
94-
StaticCpuTemplate::T2CL => {
95-
static_cpu_templates::t2cl::update_t2cl_msr_entries(&mut config.msrs);
96-
}
97-
_ => (),
98-
}
99-
100-
Ok(config)
101-
}
102-
}
103-
}
104-
10549
/// Modifies provided config with changes from template
10650
pub fn apply_template(self, template: &CustomCpuTemplate) -> Result<Self, Error> {
10751
let Self {

src/vmm/src/vstate/vcpu/mod.rs

+18-24
Original file line numberDiff line numberDiff line change
@@ -928,30 +928,24 @@ pub mod tests {
928928
let entry_addr = load_good_kernel(&vm_mem);
929929

930930
#[cfg(target_arch = "x86_64")]
931-
vcpu.kvm_vcpu
932-
.configure(
933-
&vm_mem,
934-
entry_addr,
935-
&VcpuConfig {
936-
vcpu_count: 1,
937-
smt: false,
938-
cpu_config: crate::guest_config::x86_64::CpuConfiguration::host(&_vm).unwrap(),
939-
},
940-
)
941-
.expect("failed to configure vcpu");
942-
943-
#[cfg(target_arch = "x86_64")]
944-
vcpu.kvm_vcpu
945-
.configure(
946-
&vm_mem,
947-
entry_addr,
948-
&VcpuConfig {
949-
vcpu_count: 1,
950-
smt: false,
951-
cpu_config: crate::guest_config::x86_64::CpuConfiguration::host(&_vm).unwrap(),
952-
},
953-
)
954-
.expect("failed to configure vcpu");
931+
{
932+
use crate::guest_config::cpuid::{Cpuid, RawCpuid};
933+
vcpu.kvm_vcpu
934+
.configure(
935+
&vm_mem,
936+
entry_addr,
937+
&VcpuConfig {
938+
vcpu_count: 1,
939+
smt: false,
940+
cpu_config: CpuConfiguration {
941+
cpuid: Cpuid::try_from(RawCpuid::from(_vm.supported_cpuid().clone()))
942+
.unwrap(),
943+
msrs: std::collections::HashMap::new(),
944+
},
945+
},
946+
)
947+
.expect("failed to configure vcpu");
948+
}
955949

956950
#[cfg(target_arch = "aarch64")]
957951
vcpu.kvm_vcpu

src/vmm/src/vstate/vcpu/x86_64.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::vstate::vm::Vm;
3030
const TSC_KHZ_TOL: f64 = 250.0 / 1_000_000.0;
3131

3232
/// Errors associated with the wrappers over KVM ioctls.
33-
#[derive(Debug, thiserror::Error)]
33+
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
3434
pub enum Error {
3535
/// A FamStructWrapper operation has failed.
3636
#[error("Failed FamStructWrapper operation: {0:?}")]
@@ -618,7 +618,11 @@ mod tests {
618618

619619
use super::*;
620620
use crate::arch::x86_64::cpu_model::CpuModel;
621-
use crate::guest_config::templates::{CpuConfiguration, CpuTemplateType, StaticCpuTemplate};
621+
use crate::guest_config::cpuid::{Cpuid, RawCpuid};
622+
use crate::guest_config::templates::{
623+
CpuConfiguration, CpuTemplateType, CustomCpuTemplate, GetCpuTemplate, GuestConfigError,
624+
StaticCpuTemplate,
625+
};
622626
use crate::vstate::vm::tests::setup_vm;
623627
use crate::vstate::vm::Vm;
624628

@@ -661,36 +665,48 @@ mod tests {
661665

662666
fn create_vcpu_config(
663667
vm: &Vm,
664-
template: Option<CpuTemplateType>,
665-
) -> std::result::Result<VcpuConfig, crate::guest_config::x86_64::Error> {
666-
let custom_cpu_config = CpuConfiguration::new(vm, &template)?;
668+
vcpu: &KvmVcpu,
669+
template: &CustomCpuTemplate,
670+
) -> std::result::Result<VcpuConfig, GuestConfigError> {
671+
let cpuid = Cpuid::try_from(RawCpuid::from(vm.supported_cpuid().clone()))
672+
.map_err(GuestConfigError::CpuidFromRaw)?;
673+
let msrs = vcpu
674+
.get_msrs(template.get_msr_index_list())
675+
.map_err(GuestConfigError::VcpuIoctl)?;
676+
let base_cpu_config = CpuConfiguration { cpuid, msrs };
677+
let cpu_config = CpuConfiguration::apply_template(base_cpu_config, template)?;
667678
Ok(VcpuConfig {
668679
vcpu_count: 1,
669680
smt: false,
670-
cpu_config: custom_cpu_config,
681+
cpu_config,
671682
})
672683
}
673684

674685
#[test]
675686
fn test_configure_vcpu() {
676687
let (vm, mut vcpu, vm_mem) = setup_vcpu(0x10000);
677688

678-
let vcpu_config = create_vcpu_config(&vm, None).unwrap();
689+
let vcpu_config = create_vcpu_config(&vm, &vcpu, &CustomCpuTemplate::default()).unwrap();
679690
assert_eq!(
680691
vcpu.configure(&vm_mem, GuestAddress(0), &vcpu_config,),
681692
Ok(())
682693
);
683694

684695
let try_configure = |vm: &Vm, vcpu: &mut KvmVcpu, template| -> bool {
685-
if let Ok(config) = create_vcpu_config(vm, Some(CpuTemplateType::Static(template))) {
686-
vcpu.configure(
687-
&vm_mem,
688-
GuestAddress(crate::arch::get_kernel_start()),
689-
&config,
690-
)
691-
.is_ok()
692-
} else {
693-
false
696+
let cpu_template = Some(CpuTemplateType::Static(template));
697+
let template = cpu_template.get_cpu_template();
698+
match template {
699+
Ok(template) => match create_vcpu_config(vm, vcpu, &template) {
700+
Ok(config) => vcpu
701+
.configure(
702+
&vm_mem,
703+
GuestAddress(crate::arch::get_kernel_start()),
704+
&config,
705+
)
706+
.is_ok(),
707+
Err(_) => false,
708+
},
709+
Err(_) => false,
694710
}
695711
};
696712

0 commit comments

Comments
 (0)