From 83066cf58e366653fb7f434a1fa301c3419bf9bd Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 1 Oct 2021 10:54:27 +0100 Subject: [PATCH] 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 --- src/main.rs | 5 +++-- vmm/src/config.rs | 19 +++++++++++++++---- vmm/src/cpu.rs | 6 +----- vmm/src/lib.rs | 12 ++---------- vmm/src/vm.rs | 42 ++++++------------------------------------ 5 files changed, 27 insertions(+), 57 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8726eddd7..8db44d326 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 95e2e5fb5..aeb8be073 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -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, #[serde(default)] pub kvm_hyperv: bool, - #[serde(default)] - pub max_phys_bits: Option, + #[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::("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, } } } diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 21cfd3af7..e83bf8e73 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -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 diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index b4d1cb0ad..dc1ee1a44 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -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, diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 1ce4c584b..c86bb8345 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -469,24 +469,10 @@ impl VmmOps for VmOps { } } -pub fn physical_bits(max_phys_bits: Option, #[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,