arch: don't construct mptable on x86_64 if too many CPUs
MP table is a legacy device that is incompatible with x2apic CPU IDs exceeding 254. The Linux kernel is perfectly happy without MP table in these cases. Signed-off-by: Barret Rhoden <brho@google.com> Signed-off-by: Neel Natu <neelnatu@google.com> Signed-off-by: Ofir Weisse <oweisse@google.com> Signed-off-by: Peter Oskolkov <posk@google.com>
This commit is contained in:
parent
dd8687aebb
commit
2c7d6be3f4
2 changed files with 18 additions and 19 deletions
|
|
@ -33,6 +33,10 @@ use std::arch::x86_64;
|
|||
#[cfg(feature = "tdx")]
|
||||
pub mod tdx;
|
||||
|
||||
// While modern architectures support more than 255 CPUs via x2APIC,
|
||||
// legacy devices such as mptable support at most 254 CPUs.
|
||||
pub(crate) const MAX_SUPPORTED_CPUS_LEGACY: u32 = 254;
|
||||
|
||||
// CPUID feature bits
|
||||
#[cfg(feature = "kvm")]
|
||||
const TSC_DEADLINE_TIMER_ECX_BIT: u8 = 24; // tsc deadline timer ecx bit.
|
||||
|
|
@ -915,7 +919,7 @@ pub fn configure_vcpu(
|
|||
// does not recognize the last vCPU if x2apic is not enabled when
|
||||
// there are 256 vCPUs in a flat hierarchy (i.e. max x2apic ID is 255),
|
||||
// so we need to enable x2apic in this case as well.
|
||||
let enable_x2_apic_mode = get_max_x2apic_id(topology) >= 255;
|
||||
let enable_x2_apic_mode = get_max_x2apic_id(topology) > MAX_SUPPORTED_CPUS_LEGACY;
|
||||
regs::setup_sregs(&guest_memory.memory(), vcpu, enable_x2_apic_mode)
|
||||
.map_err(Error::SregsConfiguration)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use libc::c_uchar;
|
|||
use thiserror::Error;
|
||||
use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError};
|
||||
|
||||
use super::MAX_SUPPORTED_CPUS_LEGACY;
|
||||
use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
|
||||
use crate::x86_64::{get_x2apic_id, mpspec};
|
||||
use crate::GuestMemoryMmap;
|
||||
|
|
@ -61,9 +62,6 @@ pub enum Error {
|
|||
/// Failure while zeroing out the memory for the MP table.
|
||||
#[error("Failure while zeroing out the memory for the MP table")]
|
||||
Clear(#[source] GuestMemoryError),
|
||||
/// Number of CPUs exceeds the maximum supported CPUs
|
||||
#[error("Number of CPUs exceeds the maximum supported CPUs")]
|
||||
TooManyCpus,
|
||||
/// Failure to write the MP floating pointer.
|
||||
#[error("Failure to write the MP floating pointer")]
|
||||
WriteMpfIntel(#[source] GuestMemoryError),
|
||||
|
|
@ -89,11 +87,6 @@ pub enum Error {
|
|||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
// With APIC/xAPIC, there are only 255 APIC IDs available. And IOAPIC occupies
|
||||
// one APIC ID, so only 254 CPUs at maximum may be supported. Actually it's
|
||||
// a large number for FC usecases.
|
||||
pub const MAX_SUPPORTED_CPUS: u32 = 254;
|
||||
|
||||
// Most of these variables are sourced from the Intel MP Spec 1.4.
|
||||
const SMP_MAGIC_IDENT: &[c_uchar; 4] = b"_MP_";
|
||||
const MPC_SIGNATURE: &[c_uchar; 4] = b"PCMP";
|
||||
|
|
@ -141,8 +134,9 @@ pub fn setup_mptable(
|
|||
if num_cpus > 0 {
|
||||
let cpu_id_max = num_cpus - 1;
|
||||
let x2apic_id_max = get_x2apic_id(cpu_id_max, topology);
|
||||
if x2apic_id_max >= MAX_SUPPORTED_CPUS {
|
||||
return Err(Error::TooManyCpus);
|
||||
if x2apic_id_max >= MAX_SUPPORTED_CPUS_LEGACY {
|
||||
info!("Skipping mptable creation due to too many CPUs");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +151,7 @@ pub fn setup_mptable(
|
|||
}
|
||||
|
||||
let mut checksum: u8 = 0;
|
||||
let ioapicid: u8 = MAX_SUPPORTED_CPUS as u8 + 1;
|
||||
let ioapicid: u8 = MAX_SUPPORTED_CPUS_LEGACY as u8 + 1;
|
||||
|
||||
// The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
|
||||
// overflow.
|
||||
|
|
@ -392,11 +386,13 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn cpu_entry_count() {
|
||||
let mem =
|
||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(MAX_SUPPORTED_CPUS))])
|
||||
.unwrap();
|
||||
let mem = GuestMemoryMmap::from_ranges(&[(
|
||||
MPTABLE_START,
|
||||
compute_mp_size(MAX_SUPPORTED_CPUS_LEGACY),
|
||||
)])
|
||||
.unwrap();
|
||||
|
||||
for i in 0..MAX_SUPPORTED_CPUS {
|
||||
for i in 0..MAX_SUPPORTED_CPUS_LEGACY {
|
||||
setup_mptable(MPTABLE_START, &mem, i, None).unwrap();
|
||||
|
||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||
|
|
@ -426,10 +422,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn cpu_entry_count_max() {
|
||||
let cpus = MAX_SUPPORTED_CPUS + 1;
|
||||
let cpus = MAX_SUPPORTED_CPUS_LEGACY + 1;
|
||||
let mem = GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(cpus))]).unwrap();
|
||||
|
||||
let result = setup_mptable(MPTABLE_START, &mem, cpus, None);
|
||||
result.unwrap_err();
|
||||
setup_mptable(MPTABLE_START, &mem, cpus, None).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue