arch, vmm: Add new struct CpuidConfig

This struct contains all configuration fields that controls the way how
we generate CPUID for the guest on x86_64. This allows cleaner extension
when adding new configuration fields.

Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
Bo Chen 2023-10-11 11:52:24 -07:00 committed by Bo Chen
parent 30975ea102
commit 7dd260f82f
5 changed files with 50 additions and 34 deletions

View File

@ -92,7 +92,7 @@ pub mod x86_64;
pub use x86_64::{
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG,
layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry, EntryPoint, _NSIG,
};
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.

View File

@ -145,6 +145,14 @@ struct BootParamsWrapper(boot_params);
// SAFETY: BootParamsWrap is a wrapper over `boot_params` (a series of ints).
unsafe impl ByteValued for BootParamsWrapper {}
pub struct CpuidConfig {
pub sgx_epc_sections: Option<Vec<SgxEpcSection>>,
pub phys_bits: u8,
pub kvm_hyperv: bool,
#[cfg(feature = "tdx")]
pub tdx: bool,
}
#[derive(Debug)]
pub enum Error {
/// Error writing MP table to memory.
@ -552,10 +560,7 @@ impl CpuidFeatureEntry {
pub fn generate_common_cpuid(
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
sgx_epc_sections: Option<Vec<SgxEpcSection>>,
phys_bits: u8,
kvm_hyperv: bool,
#[cfg(feature = "tdx")] tdx_enabled: bool,
config: &CpuidConfig,
) -> super::Result<Vec<CpuIdEntry>> {
// SAFETY: cpuid called with valid leaves
if unsafe { x86_64::__cpuid(1) }.ecx & 1 << HYPERVISOR_ECX_BIT == 1 << HYPERVISOR_ECX_BIT {
@ -573,7 +578,10 @@ pub fn generate_common_cpuid(
);
}
info!("Generating guest CPUID for with physical address size: {phys_bits}");
info!(
"Generating guest CPUID for with physical address size: {}",
config.phys_bits
);
let cpuid_patches = vec![
// Patch tsc deadline timer bit
CpuidPatch {
@ -614,12 +622,12 @@ pub fn generate_common_cpuid(
CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches);
if let Some(sgx_epc_sections) = sgx_epc_sections {
if let Some(sgx_epc_sections) = &config.sgx_epc_sections {
update_cpuid_sgx(&mut cpuid, sgx_epc_sections)?;
}
#[cfg(feature = "tdx")]
let tdx_capabilities = if tdx_enabled {
let tdx_capabilities = if config.tdx {
let caps = hypervisor
.tdx_capabilities()
.map_err(Error::TdxCapabilities)?;
@ -667,12 +675,12 @@ pub fn generate_common_cpuid(
}
// Set CPU physical bits
0x8000_0008 => {
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
entry.eax = (entry.eax & 0xffff_ff00) | (config.phys_bits as u32 & 0xff);
}
0x4000_0001 => {
// These features are not supported by TDX
#[cfg(feature = "tdx")]
if tdx_enabled {
if config.tdx {
entry.eax &= !(1 << KVM_FEATURE_CLOCKSOURCE_BIT
| 1 << KVM_FEATURE_CLOCKSOURCE2_BIT
| 1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT
@ -700,7 +708,7 @@ pub fn generate_common_cpuid(
});
}
if kvm_hyperv {
if config.kvm_hyperv {
// Remove conflicting entries
cpuid.retain(|c| c.function != 0x4000_0000);
cpuid.retain(|c| c.function != 0x4000_0001);
@ -1293,7 +1301,7 @@ fn update_cpuid_topology(
// sections exposed to the guest.
fn update_cpuid_sgx(
cpuid: &mut Vec<CpuIdEntry>,
epc_sections: Vec<SgxEpcSection>,
epc_sections: &Vec<SgxEpcSection>,
) -> Result<(), Error> {
// Something's wrong if there's no EPC section.
if epc_sections.is_empty() {

View File

@ -726,7 +726,7 @@ impl CpuManager {
&mut self,
memory_manager: &Arc<Mutex<MemoryManager>>,
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
#[cfg(feature = "tdx")] tdx_enabled: bool,
#[cfg(feature = "tdx")] tdx: bool,
) -> Result<()> {
let sgx_epc_sections = memory_manager
.lock()
@ -739,11 +739,13 @@ impl CpuManager {
let phys_bits = physical_bits(hypervisor, self.config.max_phys_bits);
arch::generate_common_cpuid(
hypervisor,
sgx_epc_sections,
phys_bits,
self.config.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx_enabled,
&arch::CpuidConfig {
sgx_epc_sections,
phys_bits,
kvm_hyperv: self.config.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx,
},
)
.map_err(Error::CommonCpuId)?
};

View File

@ -1664,16 +1664,18 @@ impl Vmm {
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
let common_cpuid = {
#[cfg(feature = "tdx")]
let tdx_enabled = vm_config.lock().unwrap().is_tdx_enabled();
let tdx = vm_config.lock().unwrap().is_tdx_enabled();
let phys_bits =
vm::physical_bits(&hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits);
arch::generate_common_cpuid(
&hypervisor,
None,
phys_bits,
vm_config.lock().unwrap().cpus.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx_enabled,
&arch::CpuidConfig {
sgx_epc_sections: None,
phys_bits,
kvm_hyperv: vm_config.lock().unwrap().cpus.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx,
},
)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error generating common cpuid': {:?}", e))
@ -1858,11 +1860,13 @@ impl Vmm {
let phys_bits = vm::physical_bits(&self.hypervisor, vm_config.cpus.max_phys_bits);
arch::generate_common_cpuid(
&self.hypervisor.clone(),
None,
phys_bits,
vm_config.cpus.kvm_hyperv,
#[cfg(feature = "tdx")]
vm_config.is_tdx_enabled(),
&arch::CpuidConfig {
sgx_epc_sections: None,
phys_bits,
kvm_hyperv: vm_config.cpus.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx: vm_config.is_tdx_enabled(),
},
)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error generating common cpuid: {:?}", e))

View File

@ -2415,11 +2415,13 @@ impl Snapshottable for Vm {
);
arch::generate_common_cpuid(
&self.hypervisor,
None,
phys_bits,
self.config.lock().unwrap().cpus.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx_enabled,
&arch::CpuidConfig {
sgx_epc_sections: None,
phys_bits,
kvm_hyperv: self.config.lock().unwrap().cpus.kvm_hyperv,
#[cfg(feature = "tdx")]
tdx: tdx_enabled,
},
)
.map_err(|e| {
MigratableError::MigrateReceive(anyhow!("Error generating common cpuid: {:?}", e))