Skip to content

Commit 680b8c1

Browse files
committed
Add new online capable vCPUs sockets to MADT
Extend the MADT to contain MAX_SUPPORTED_VCPUS (32) entries. Only the number specified in the machine_config are enabled. The rest are "online capable", meaning they can be brought online. Signed-off-by: James Curtis <[email protected]>
1 parent a8819ed commit 680b8c1

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

src/acpi-tables/src/madt.rs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::{checksum, AcpiError, Result, Sdt, SdtHeader};
1313

1414
const MADT_CPU_ENABLE_FLAG: u32 = 0;
1515

16+
const MADT_CPU_ONLINE_CAPABLE_FLAG: u32 = 1;
1617
// clippy doesn't understand that we actually "use" the fields of this struct when we serialize
1718
// them as bytes in guest memory, so here we just ignore dead code to avoid having to name
1819
// everything with an underscore prefix
@@ -28,13 +29,23 @@ pub struct LocalAPIC {
2829
}
2930

3031
impl LocalAPIC {
31-
pub fn new(cpu_id: u8) -> Self {
32-
Self {
33-
r#type: 0,
34-
length: 8,
35-
processor_uid: cpu_id,
36-
apic_id: cpu_id,
37-
flags: U32::new(1u32 << MADT_CPU_ENABLE_FLAG),
32+
pub fn new(cpu_id: u8, online_capable: bool) -> Self {
33+
if online_capable {
34+
Self {
35+
r#type: 0,
36+
length: 8,
37+
processor_uid: cpu_id,
38+
apic_id: cpu_id,
39+
flags: U32::new(1u32 << MADT_CPU_ONLINE_CAPABLE_FLAG),
40+
}
41+
} else {
42+
Self {
43+
r#type: 0,
44+
length: 8,
45+
processor_uid: cpu_id,
46+
apic_id: cpu_id,
47+
flags: U32::new(1u32 << MADT_CPU_ENABLE_FLAG),
48+
}
3849
}
3950
}
4051
}
@@ -140,3 +151,30 @@ impl Sdt for Madt {
140151
Ok(())
141152
}
142153
}
154+
155+
#[cfg(test)]
156+
mod tests {
157+
use zerocopy::little_endian::U32;
158+
159+
use crate::madt::LocalAPIC;
160+
161+
#[test]
162+
fn test_online_local_apic() {
163+
let online_apic = super::LocalAPIC::new(0, false);
164+
assert_eq!(online_apic.r#type, 0);
165+
assert_eq!(online_apic.length, 8);
166+
assert_eq!(online_apic.processor_uid, 0);
167+
assert_eq!(online_apic.apic_id, 0);
168+
assert_eq!(online_apic.flags, U32::new(1));
169+
}
170+
171+
#[test]
172+
fn test_online_capable_local_apic() {
173+
let online_capable_apic = LocalAPIC::new(1, true);
174+
assert_eq!(online_capable_apic.r#type, 0);
175+
assert_eq!(online_capable_apic.length, 8);
176+
assert_eq!(online_capable_apic.processor_uid, 1);
177+
assert_eq!(online_capable_apic.apic_id, 1);
178+
assert_eq!(online_capable_apic.flags, U32::new(2));
179+
}
180+
}

src/vmm/src/acpi/x86_64.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,21 @@ use zerocopy::AsBytes;
1414

1515
use crate::arch::x86_64::layout;
1616
use crate::device_manager::legacy::PortIODeviceManager;
17+
use crate::vmm_config::machine_config::MAX_SUPPORTED_VCPUS;
1718

1819
#[inline(always)]
1920
pub(crate) fn setup_interrupt_controllers(nr_vcpus: u8) -> Vec<u8> {
20-
let mut ic =
21-
Vec::with_capacity(size_of::<IoAPIC>() + (nr_vcpus as usize) * size_of::<LocalAPIC>());
21+
let mut ic = Vec::with_capacity(
22+
size_of::<IoAPIC>() + (MAX_SUPPORTED_VCPUS as usize) * size_of::<LocalAPIC>(),
23+
);
2224

2325
ic.extend_from_slice(IoAPIC::new(0, layout::IOAPIC_ADDR).as_bytes());
24-
for i in 0..nr_vcpus {
25-
ic.extend_from_slice(LocalAPIC::new(i).as_bytes());
26+
for i in 0..MAX_SUPPORTED_VCPUS {
27+
if i < nr_vcpus {
28+
ic.extend_from_slice(LocalAPIC::new(i, false).as_bytes());
29+
} else {
30+
ic.extend_from_slice(LocalAPIC::new(i, true).as_bytes())
31+
}
2632
}
2733
ic
2834
}

0 commit comments

Comments
 (0)