vmm: Set a default maximum physical address size

When using PVH for booting (which we use for all firmwares and direct
kernel boot) the Linux kernel does not configure LA57 correctly. As such
we need to limit the address space to the maximum 4-level paging address
space.

If the user knows that their guest image can take advantage of the
5-level addressing and they need it for their workload then they can
increase the physical address space appropriately.

This PR removes the TDX specific handling as the new address space limit
is below the one that that code specified.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-10-01 10:54:27 +01:00 committed by Bo Chen
parent 495e444ca6
commit 83066cf58e
5 changed files with 27 additions and 57 deletions

View File

@ -117,7 +117,8 @@ impl log::Log for Logger {
}
fn prepare_default_values() -> (String, String, String) {
let default_vcpus = format! {"boot={}", config::DEFAULT_VCPUS};
let default_vcpus =
format! {"boot={},max_phys_bits={}", config::DEFAULT_VCPUS,config::DEFAULT_MAX_PHYS_BITS};
let default_memory = format! {"size={}M", config::DEFAULT_MEMORY_MB};
let default_rng = format! {"src={}", config::DEFAULT_RNG_SOURCE};
@ -636,7 +637,7 @@ mod unit_tests {
max_vcpus: 1,
topology: None,
kvm_hyperv: false,
max_phys_bits: None,
max_phys_bits: 46,
},
memory: MemoryConfig {
size: 536_870_912,

View File

@ -20,6 +20,12 @@ use virtio_devices::{RateLimiterConfig, TokenBucketConfig};
pub const DEFAULT_VCPUS: u8 = 1;
pub const DEFAULT_MEMORY_MB: u64 = 512;
// When booting with PVH boot the maximum physical addressable size
// is a 46 bit address space even when the host supports with 5-level
// paging.
pub const DEFAULT_MAX_PHYS_BITS: u8 = 46;
pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom";
pub const DEFAULT_NUM_QUEUES_VUNET: usize = 2;
pub const DEFAULT_QUEUE_SIZE_VUNET: u16 = 256;
@ -410,6 +416,10 @@ impl FromStr for CpuTopology {
}
}
fn default_cpuconfig_max_phys_bits() -> u8 {
DEFAULT_MAX_PHYS_BITS
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct CpusConfig {
pub boot_vcpus: u8,
@ -418,8 +428,8 @@ pub struct CpusConfig {
pub topology: Option<CpuTopology>,
#[serde(default)]
pub kvm_hyperv: bool,
#[serde(default)]
pub max_phys_bits: Option<u8>,
#[serde(default = "default_cpuconfig_max_phys_bits")]
pub max_phys_bits: u8,
}
impl CpusConfig {
@ -449,7 +459,8 @@ impl CpusConfig {
.0;
let max_phys_bits = parser
.convert::<u8>("max_phys_bits")
.map_err(Error::ParseCpus)?;
.map_err(Error::ParseCpus)?
.unwrap_or(DEFAULT_MAX_PHYS_BITS);
Ok(CpusConfig {
boot_vcpus,
@ -468,7 +479,7 @@ impl Default for CpusConfig {
max_vcpus: DEFAULT_VCPUS,
topology: None,
kvm_hyperv: false,
max_phys_bits: None,
max_phys_bits: DEFAULT_MAX_PHYS_BITS,
}
}
}

View File

@ -553,11 +553,7 @@ impl CpuManager {
.map(|sgx_epc_region| sgx_epc_region.epc_sections().values().cloned().collect());
#[cfg(target_arch = "x86_64")]
let cpuid = {
let phys_bits = physical_bits(
config.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = physical_bits(config.max_phys_bits);
arch::generate_common_cpuid(
hypervisor,
config

View File

@ -1038,11 +1038,7 @@ impl Vmm {
let common_cpuid = {
#[cfg(feature = "tdx")]
let tdx_enabled = vm_config.lock().unwrap().tdx.is_some();
let phys_bits = vm::physical_bits(
vm_config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = vm::physical_bits(vm_config.lock().unwrap().cpus.max_phys_bits);
arch::generate_common_cpuid(
hypervisor,
None,
@ -1210,11 +1206,7 @@ impl Vmm {
#[cfg(feature = "tdx")]
let tdx_enabled = vm_config.tdx.is_some();
let phys_bits = vm::physical_bits(
vm_config.cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = vm::physical_bits(vm_config.cpus.max_phys_bits);
arch::generate_common_cpuid(
self.hypervisor.clone(),
None,

View File

@ -469,24 +469,10 @@ impl VmmOps for VmOps {
}
}
pub fn physical_bits(max_phys_bits: Option<u8>, #[cfg(feature = "tdx")] tdx_enabled: bool) -> u8 {
#[cfg(not(feature = "tdx"))]
pub fn physical_bits(max_phys_bits: u8) -> u8 {
let host_phys_bits = get_host_cpu_phys_bits();
#[cfg(feature = "tdx")]
let mut host_phys_bits = get_host_cpu_phys_bits();
#[cfg(feature = "tdx")]
if tdx_enabled {
// When running TDX guest, the Guest Physical Address space is limited
// by a shared bit that is located on bit 47 for 4 level paging, and on
// bit 51 for 5 level paging (when GPAW bit is 1). In order to keep
// things simple, and since a 47 bits address space is 128TiB large, we
// ensure to limit the physical addressable space to 47 bits when
// runnning TDX.
host_phys_bits = std::cmp::min(host_phys_bits, 47)
}
cmp::min(host_phys_bits, max_phys_bits.unwrap_or(host_phys_bits))
cmp::min(host_phys_bits, max_phys_bits)
}
pub const HANDLED_SIGNALS: [i32; 3] = [SIGWINCH, SIGTERM, SIGINT];
@ -756,11 +742,7 @@ impl Vm {
#[cfg(target_arch = "x86_64")]
vm.enable_split_irq().unwrap();
let phys_bits = physical_bits(
config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
let memory_manager = MemoryManager::new(
vm.clone(),
&config.lock().unwrap().memory.clone(),
@ -832,11 +814,7 @@ impl Vm {
let memory_manager = if let Some(memory_manager_snapshot) =
snapshot.snapshots.get(MEMORY_MANAGER_SNAPSHOT_ID)
{
let phys_bits = physical_bits(
config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
config.lock().unwrap().tdx.is_some(),
);
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
MemoryManager::new_from_snapshot(
memory_manager_snapshot,
vm.clone(),
@ -879,11 +857,7 @@ impl Vm {
let vm = hypervisor.create_vm().unwrap();
#[cfg(target_arch = "x86_64")]
vm.enable_split_irq().unwrap();
let phys_bits = physical_bits(
config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
config.lock().unwrap().tdx.is_some(),
);
let phys_bits = physical_bits(config.lock().unwrap().cpus.max_phys_bits);
let memory_manager = MemoryManager::new(
vm.clone(),
@ -2396,11 +2370,7 @@ impl Snapshottable for Vm {
let common_cpuid = {
#[cfg(feature = "tdx")]
let tdx_enabled = self.config.lock().unwrap().tdx.is_some();
let phys_bits = physical_bits(
self.config.lock().unwrap().cpus.max_phys_bits,
#[cfg(feature = "tdx")]
tdx_enabled,
);
let phys_bits = physical_bits(self.config.lock().unwrap().cpus.max_phys_bits);
arch::generate_common_cpuid(
self.hypervisor.clone(),
None,