diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 50372ce64..f93dbd2e8 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -936,6 +936,7 @@ fn setup_instance( ) .with_vcpuid(vcpu.id) .with_cache_topo() + .clear_cpu_topo(cpuid::TopoKind::all()) .execute(profile.clone()) }) .unwrap_or_else(|| { diff --git a/lib/propolis/src/cpuid.rs b/lib/propolis/src/cpuid.rs index 049250e54..223d11d4d 100644 --- a/lib/propolis/src/cpuid.rs +++ b/lib/propolis/src/cpuid.rs @@ -158,7 +158,8 @@ pub struct Specializer { num_vcpu: Option, vcpuid: Option, vendor_kind: Option, - cpu_topo: BTreeSet, + cpu_topo_populate: BTreeSet, + cpu_topo_clear: BTreeSet, do_cache_topo: bool, } impl Specializer { @@ -183,13 +184,35 @@ impl Specializer { } /// Specify CPU topology types to render into the specialized [Set] - pub fn with_cpu_topo(self, topos: impl Iterator) -> Self { - let mut cpu_topo = BTreeSet::new(); - for t in topos { - cpu_topo.insert(t); + /// + /// Without basic information such as the number of vCPUs (set by + /// [`Self::with_vcpu_count()`]), population of the requested topology + /// information may be incomplete. + pub fn with_cpu_topo( + self, + populate: impl Iterator, + ) -> Self { + let mut cpu_topo_populate = BTreeSet::new(); + + for t in populate { + cpu_topo_populate.insert(t); } - Self { cpu_topo, ..self } + Self { cpu_topo_populate, ..self } + } + + /// Specify CPU topology types to clear from the specialized [Set] + /// + /// Some leafs in the provided set may not match expectations for the given + /// CPU vendor. Without populating it with generated data (via + /// [`Self::with_cpu_topo()`]), those leafs can be cleared out. + pub fn clear_cpu_topo(self, clear: impl Iterator) -> Self { + let mut cpu_topo_clear = BTreeSet::new(); + for t in clear { + cpu_topo_clear.insert(t); + } + + Self { cpu_topo_clear, ..self } } /// Update cache topology information for specified vCPU count and SMT @@ -277,11 +300,15 @@ impl Specializer { } } fn fix_cpu_topo(&self, set: &mut Set) { - for topo in enum_iterator::all::() { + for topo in self.cpu_topo_populate.union(&self.cpu_topo_clear) { // Nuke any existing info in order to potentially override it - let leaf = topo as u32; + let leaf = *topo as u32; set.remove_all(leaf); + if !self.cpu_topo_populate.contains(topo) { + continue; + } + let num_vcpu = match self.num_vcpu { Some(n) => n.get() as u32, None => { @@ -290,66 +317,64 @@ impl Specializer { } }; - if self.cpu_topo.contains(&topo) { - match topo { - TopoKind::StdB => { - // Queries with invalid ecx will get all-zeroes - set.insert(Ident(leaf, None), Entry::zero()); - if self.has_smt { - set.insert( - Ident(leaf, Some(0)), - Entry { - eax: 0x1, - ebx: 0x2, - ecx: 0x100, - // TODO: populate with x2APIC ID - edx: 0x0, - }, - ); - } else { - set.insert( - Ident(leaf, Some(0)), - Entry { - eax: 0x0, - ebx: 0x1, - ecx: 0x100, - // TODO: populate with x2APIC ID - edx: 0x0, - }, - ); - } + match topo { + TopoKind::StdB => { + // Queries with invalid ecx will get all-zeroes + set.insert(Ident(leaf, None), Entry::zero()); + if self.has_smt { set.insert( - Ident(leaf, Some(1)), + Ident(leaf, Some(0)), Entry { - eax: 0x0, - ebx: num_vcpu, - ecx: 0x201, + eax: 0x1, + ebx: 0x2, + ecx: 0x100, // TODO: populate with x2APIC ID edx: 0x0, }, ); - } - TopoKind::Std1F => { - // TODO: add 0x1f topo info - } - TopoKind::Ext1E => { - let id = self.vcpuid.unwrap_or(0) as u32; - let mut ebx = id; - if self.has_smt { - // bits 15:8 hold the zero-based threads-per-compute-unit - ebx |= 0x100; - } + } else { set.insert( - Ident(leaf, None), + Ident(leaf, Some(0)), Entry { - eax: id, - ebx, - // TODO: populate ecx info? - ecx: 0, - edx: 0, + eax: 0x0, + ebx: 0x1, + ecx: 0x100, + // TODO: populate with x2APIC ID + edx: 0x0, }, ); } + set.insert( + Ident(leaf, Some(1)), + Entry { + eax: 0x0, + ebx: num_vcpu, + ecx: 0x201, + // TODO: populate with x2APIC ID + edx: 0x0, + }, + ); + } + TopoKind::Std1F => { + // TODO: add 0x1f topo info + } + TopoKind::Ext1E => { + let id = self.vcpuid.unwrap_or(0) as u32; + let mut ebx = id; + if self.has_smt { + // bits 15:8 hold the zero-based threads-per-compute-unit + ebx |= 0x100; + } + set.insert( + Ident(leaf, None), + Entry { + eax: id, + ebx, + // TODO: populate ecx info? + ecx: 0, + edx: 0, + }, + ); } } } @@ -366,6 +391,11 @@ pub enum TopoKind { /// LEAF 0x8000001E (AMD) Ext1E = 0x8000001e, } +impl TopoKind { + pub fn all() -> enum_iterator::All { + enum_iterator::all() + } +} /// Flavors of CPU vendor for cpuid specialization #[derive(Clone, Copy)]