1 // Copyright 2020 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::arch::x86_64::{CpuidResult, __cpuid, __cpuid_count};
6 use std::collections::BTreeMap;
7
8 use acpi_tables::{facs::FACS, rsdp::RSDP, sdt::SDT};
9 use arch::VcpuAffinity;
10 use base::{error, warn};
11 use data_model::DataInit;
12 use devices::{ACPIPMResource, PciAddress, PciInterruptPin};
13 use std::sync::Arc;
14 use sync::Mutex;
15 use vm_memory::{GuestAddress, GuestMemory};
16
17 pub struct AcpiDevResource {
18 pub amls: Vec<u8>,
19 pub pm_iobase: u64,
20 pub pm: Arc<Mutex<ACPIPMResource>>,
21 /// Additional system descriptor tables.
22 pub sdts: Vec<SDT>,
23 }
24
25 #[repr(C, packed)]
26 #[derive(Clone, Copy, Default)]
27 struct GenericAddress {
28 _space_id: u8,
29 _bit_width: u8,
30 _bit_offset: u8,
31 _access_width: u8,
32 _address: u64,
33 }
34
35 // Safe as GenericAddress structure only contains raw data
36 unsafe impl DataInit for GenericAddress {}
37
38 #[repr(C)]
39 #[derive(Clone, Copy, Default)]
40 struct LocalApic {
41 _type: u8,
42 _length: u8,
43 _processor_id: u8,
44 _apic_id: u8,
45 _flags: u32,
46 }
47
48 // Safe as LocalAPIC structure only contains raw data
49 unsafe impl DataInit for LocalApic {}
50
51 #[repr(C)]
52 #[derive(Clone, Copy, Default)]
53 struct Ioapic {
54 _type: u8,
55 _length: u8,
56 _ioapic_id: u8,
57 _reserved: u8,
58 _apic_address: u32,
59 _gsi_base: u32,
60 }
61
62 // Safe as IOAPIC structure only contains raw data
63 unsafe impl DataInit for Ioapic {}
64
65 #[repr(C)]
66 #[derive(Clone, Copy, Default)]
67 struct IoapicInterruptSourceOverride {
68 _type: u8,
69 _length: u8,
70 _bus: u8,
71 _source: u8,
72 _gsi: u32,
73 _flags: u16,
74 }
75
76 // Safe as IoapicInterruptSourceOverride structure only contains raw data
77 unsafe impl DataInit for IoapicInterruptSourceOverride {}
78
79 #[repr(C)]
80 #[derive(Clone, Copy, Default)]
81 struct Localx2Apic {
82 _type: u8,
83 _length: u8,
84 _reserved: u16,
85 _x2apic_id: u32,
86 _flags: u32,
87 _processor_id: u32,
88 }
89
90 // Safe as LocalAPIC structure only contains raw data
91 unsafe impl DataInit for Localx2Apic {}
92
93 // Space ID for GenericAddress
94 const ADR_SPACE_SYSTEM_IO: u8 = 1;
95
96 const OEM_REVISION: u32 = 1;
97 //DSDT
98 const DSDT_REVISION: u8 = 6;
99 // FADT
100 const FADT_LEN: u32 = 276;
101 const FADT_REVISION: u8 = 6;
102 const FADT_MINOR_REVISION: u8 = 3;
103 // FADT flags
104 const FADT_POWER_BUTTON: u32 = 1 << 4;
105 const FADT_SLEEP_BUTTON: u32 = 1 << 5;
106 const FADT_RESET_REGISTER: u32 = 1 << 10;
107 const FADT_LOW_POWER_S2IDLE: u32 = 1 << 21;
108 // FADT fields offset
109 const FADT_FIELD_FACS_ADDR32: usize = 36;
110 const FADT_FIELD_DSDT_ADDR32: usize = 40;
111 pub const FADT_FIELD_SCI_INTERRUPT: usize = 46;
112 const FADT_FIELD_SMI_COMMAND: usize = 48;
113 const FADT_FIELD_PM1A_EVENT_BLK_ADDR: usize = 56;
114 const FADT_FIELD_PM1B_EVENT_BLK_ADDR: usize = 60;
115 const FADT_FIELD_PM1A_CONTROL_BLK_ADDR: usize = 64;
116 const FADT_FIELD_PM1B_CONTROL_BLK_ADDR: usize = 68;
117 const FADT_FIELD_PM2_CONTROL_BLK_ADDR: usize = 72;
118 const FADT_FIELD_PM_TMR_BLK_ADDR: usize = 76;
119 const FADT_FIELD_GPE0_BLK_ADDR: usize = 80;
120 const FADT_FIELD_GPE1_BLK_ADDR: usize = 84;
121 const FADT_FIELD_PM1A_EVENT_BLK_LEN: usize = 88;
122 const FADT_FIELD_PM1A_CONTROL_BLK_LEN: usize = 89;
123 const FADT_FIELD_PM2_CONTROL_BLK_LEN: usize = 90;
124 const FADT_FIELD_PM_TMR_LEN: usize = 91;
125 const FADT_FIELD_GPE0_BLK_LEN: usize = 92;
126 const FADT_FIELD_GPE1_BLK_LEN: usize = 93;
127 const FADT_FIELD_GPE1_BASE: usize = 94;
128 const FADT_FIELD_FLAGS: usize = 112;
129 const FADT_FIELD_RESET_REGISTER: usize = 116;
130 const FADT_FIELD_RESET_VALUE: usize = 128;
131 const FADT_FIELD_MINOR_REVISION: usize = 131;
132 const FADT_FIELD_FACS_ADDR: usize = 132;
133 const FADT_FIELD_DSDT_ADDR: usize = 140;
134 const FADT_FIELD_X_PM1A_EVENT_BLK_ADDR: usize = 148;
135 const FADT_FIELD_X_PM1B_EVENT_BLK_ADDR: usize = 160;
136 const FADT_FIELD_X_PM1A_CONTROL_BLK_ADDR: usize = 172;
137 const FADT_FIELD_X_PM1B_CONTROL_BLK_ADDR: usize = 184;
138 const FADT_FIELD_X_PM2_CONTROL_BLK_ADDR: usize = 196;
139 const FADT_FIELD_X_PM_TMR_BLK_ADDR: usize = 208;
140 const FADT_FIELD_X_GPE0_BLK_ADDR: usize = 220;
141 const FADT_FIELD_X_GPE1_BLK_ADDR: usize = 232;
142 const FADT_FIELD_HYPERVISOR_ID: usize = 268;
143 // MADT
144 const MADT_LEN: u32 = 44;
145 const MADT_REVISION: u8 = 5;
146 // MADT fields offset
147 const MADT_FIELD_LAPIC_ADDR: usize = 36;
148 const MADT_FIELD_FLAGS: usize = 40;
149 // MADT flags
150 const MADT_FLAG_PCAT_COMPAT: u32 = 1 << 0;
151 // MADT structure offsets
152 const MADT_STRUCTURE_TYPE: usize = 0;
153 const MADT_STRUCTURE_LEN: usize = 1;
154 // MADT types
155 const MADT_TYPE_LOCAL_APIC: u8 = 0;
156 const MADT_TYPE_IO_APIC: u8 = 1;
157 const MADT_TYPE_INTERRUPT_SOURCE_OVERRIDE: u8 = 2;
158 const MADT_TYPE_LOCAL_X2APIC: u8 = 9;
159 // MADT flags
160 const MADT_ENABLED: u32 = 1;
161 const MADT_INT_POLARITY_ACTIVE_LOW: u16 = 0b11;
162 const MADT_INT_TRIGGER_LEVEL: u16 = 0b11 << 2;
163 // MADT compatibility
164 const MADT_MIN_LOCAL_APIC_ID: u32 = 255;
165 // XSDT
166 const XSDT_REVISION: u8 = 1;
167
168 const CPUID_LEAF0_EBX_CPUID_SHIFT: u32 = 24; // Offset of initial apic id.
169
170 // MCFG
171 const MCFG_LEN: u32 = 60;
172 const MCFG_REVISION: u8 = 1;
173 const MCFG_FIELD_BASE_ADDRESS: usize = 44;
174 const MCFG_FIELD_START_BUS_NUMBER: usize = 54;
175 const MCFG_FIELD_END_BUS_NUMBER: usize = 55;
176
create_dsdt_table(amls: &[u8]) -> SDT177 fn create_dsdt_table(amls: &[u8]) -> SDT {
178 let mut dsdt = SDT::new(
179 *b"DSDT",
180 acpi_tables::HEADER_LEN,
181 DSDT_REVISION,
182 *b"CROSVM",
183 *b"CROSVMDT",
184 OEM_REVISION,
185 );
186
187 if !amls.is_empty() {
188 dsdt.append_slice(amls);
189 }
190
191 dsdt
192 }
193
create_facp_table(sci_irq: u16, force_s2idle: bool) -> SDT194 fn create_facp_table(sci_irq: u16, force_s2idle: bool) -> SDT {
195 let mut facp = SDT::new(
196 *b"FACP",
197 FADT_LEN,
198 FADT_REVISION,
199 *b"CROSVM",
200 *b"CROSVMDT",
201 OEM_REVISION,
202 );
203
204 let mut fadt_flags: u32 = FADT_SLEEP_BUTTON; // mask SLEEP BUTTON
205
206 if force_s2idle {
207 fadt_flags |= FADT_LOW_POWER_S2IDLE;
208 }
209
210 facp.write(FADT_FIELD_FLAGS, fadt_flags);
211
212 // SCI Interrupt
213 facp.write(FADT_FIELD_SCI_INTERRUPT, sci_irq);
214
215 facp.write(FADT_FIELD_MINOR_REVISION, FADT_MINOR_REVISION); // FADT minor version
216 facp.write(FADT_FIELD_HYPERVISOR_ID, *b"CROSVM"); // Hypervisor Vendor Identity
217
218 facp
219 }
220
221 // Write virtualized FADT fields
write_facp_overrides( facp: &mut SDT, facs_offset: GuestAddress, dsdt_offset: GuestAddress, pm_iobase: u32, reset_port: u32, reset_value: u8, )222 fn write_facp_overrides(
223 facp: &mut SDT,
224 facs_offset: GuestAddress,
225 dsdt_offset: GuestAddress,
226 pm_iobase: u32,
227 reset_port: u32,
228 reset_value: u8,
229 ) {
230 let fadt_flags: u32 = facp.read(FADT_FIELD_FLAGS);
231 // indicate we support FADT RESET_REG
232 facp.write(FADT_FIELD_FLAGS, fadt_flags | FADT_RESET_REGISTER);
233
234 facp.write(FADT_FIELD_SMI_COMMAND, 0u32);
235 facp.write(FADT_FIELD_FACS_ADDR32, 0u32);
236 facp.write(FADT_FIELD_DSDT_ADDR32, 0u32);
237 facp.write(FADT_FIELD_FACS_ADDR, facs_offset.0 as u64);
238 facp.write(FADT_FIELD_DSDT_ADDR, dsdt_offset.0 as u64);
239
240 // PM1A Event Block Address
241 facp.write(FADT_FIELD_PM1A_EVENT_BLK_ADDR, pm_iobase);
242
243 // PM1B Event Block Address (not supported)
244 facp.write(FADT_FIELD_PM1B_EVENT_BLK_ADDR, 0u32);
245
246 // PM1A Control Block Address
247 facp.write(
248 FADT_FIELD_PM1A_CONTROL_BLK_ADDR,
249 pm_iobase + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32,
250 );
251
252 // PM1B Control Block Address (not supported)
253 facp.write(FADT_FIELD_PM1B_CONTROL_BLK_ADDR, 0u32);
254
255 // PM2 Control Block Address (not supported)
256 facp.write(FADT_FIELD_PM2_CONTROL_BLK_ADDR, 0u32);
257
258 // PM Timer Control Block Address (not supported)
259 facp.write(FADT_FIELD_PM_TMR_BLK_ADDR, 0u32);
260
261 // GPE0 Block Address
262 facp.write(
263 FADT_FIELD_GPE0_BLK_ADDR,
264 pm_iobase + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32 + 4,
265 );
266
267 // GPE1 Block Address (not supported)
268 facp.write(FADT_FIELD_GPE1_BLK_ADDR, 0u32);
269
270 // PM1 Event Block Length
271 facp.write(
272 FADT_FIELD_PM1A_EVENT_BLK_LEN,
273 devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN,
274 );
275
276 // PM1 Control Block Length
277 facp.write(
278 FADT_FIELD_PM1A_CONTROL_BLK_LEN,
279 devices::acpi::ACPIPM_RESOURCE_CONTROLBLK_LEN,
280 );
281
282 // PM2 Control Block Length (not supported)
283 facp.write(FADT_FIELD_PM2_CONTROL_BLK_LEN, 0u8);
284
285 // PM Timer Control Block Length (not supported)
286 facp.write(FADT_FIELD_PM_TMR_LEN, 0u8);
287
288 // GPE0 Block Length
289 facp.write(
290 FADT_FIELD_GPE0_BLK_LEN,
291 devices::acpi::ACPIPM_RESOURCE_GPE0_BLK_LEN,
292 );
293
294 // GPE1 Block Length (not supported)
295 facp.write(FADT_FIELD_GPE1_BLK_LEN, 0u8);
296
297 // GPE1 Base (not supported)
298 facp.write(FADT_FIELD_GPE1_BASE, 0u8);
299
300 // PM1A Extended Event Block Address (not supported)
301 facp.write(
302 FADT_FIELD_X_PM1A_EVENT_BLK_ADDR,
303 GenericAddress {
304 ..Default::default()
305 },
306 );
307
308 // PM1B Extended Event Block Address (not supported)
309 facp.write(
310 FADT_FIELD_X_PM1B_EVENT_BLK_ADDR,
311 GenericAddress {
312 ..Default::default()
313 },
314 );
315
316 // PM1A Extended Control Block Address (not supported)
317 facp.write(
318 FADT_FIELD_X_PM1A_CONTROL_BLK_ADDR,
319 GenericAddress {
320 ..Default::default()
321 },
322 );
323
324 // PM1B Extended Control Block Address (not supported)
325 facp.write(
326 FADT_FIELD_X_PM1B_CONTROL_BLK_ADDR,
327 GenericAddress {
328 ..Default::default()
329 },
330 );
331
332 // PM2 Extended Control Block Address (not supported)
333 facp.write(
334 FADT_FIELD_X_PM2_CONTROL_BLK_ADDR,
335 GenericAddress {
336 ..Default::default()
337 },
338 );
339
340 // PM Timer Extended Control Block Address (not supported)
341 facp.write(
342 FADT_FIELD_X_PM_TMR_BLK_ADDR,
343 GenericAddress {
344 ..Default::default()
345 },
346 );
347
348 // GPE0 Extended Address (not supported)
349 facp.write(
350 FADT_FIELD_X_GPE0_BLK_ADDR,
351 GenericAddress {
352 ..Default::default()
353 },
354 );
355
356 // GPE1 Extended Address (not supported)
357 facp.write(
358 FADT_FIELD_X_GPE1_BLK_ADDR,
359 GenericAddress {
360 ..Default::default()
361 },
362 );
363
364 // Reset register
365 facp.write(
366 FADT_FIELD_RESET_REGISTER,
367 GenericAddress {
368 _space_id: ADR_SPACE_SYSTEM_IO,
369 _bit_width: 8,
370 _bit_offset: 0,
371 _access_width: 8,
372 _address: reset_port.into(),
373 },
374 );
375 facp.write(FADT_FIELD_RESET_VALUE, reset_value);
376 }
377
next_offset(offset: GuestAddress, len: u64) -> Option<GuestAddress>378 fn next_offset(offset: GuestAddress, len: u64) -> Option<GuestAddress> {
379 // Enforce 64-byte allocation alignment.
380 match len % 64 {
381 0 => offset.checked_add(len),
382 x => offset.checked_add(len.checked_add(64 - x)?),
383 }
384 }
385
sync_acpi_id_from_cpuid( madt: &mut SDT, cpus: BTreeMap<usize, Vec<usize>>, apic_ids: &mut Vec<usize>, ) -> base::Result<()>386 fn sync_acpi_id_from_cpuid(
387 madt: &mut SDT,
388 cpus: BTreeMap<usize, Vec<usize>>,
389 apic_ids: &mut Vec<usize>,
390 ) -> base::Result<()> {
391 let cpu_set = match base::get_cpu_affinity() {
392 Err(e) => {
393 error!("Failed to get CPU affinity: {} when create MADT", e);
394 return Err(e);
395 }
396 Ok(c) => c,
397 };
398
399 for (vcpu, pcpu) in cpus {
400 let mut has_leafb = false;
401 let mut get_apic_id = false;
402 let mut apic_id: u8 = 0;
403
404 if let Err(e) = base::set_cpu_affinity(pcpu) {
405 error!("Failed to set CPU affinity: {} when create MADT", e);
406 return Err(e);
407 }
408
409 // Safe because we pass 0 and 0 for this call and the host supports the
410 // `cpuid` instruction
411 let mut cpuid_entry: CpuidResult = unsafe { __cpuid_count(0, 0) };
412
413 if cpuid_entry.eax >= 0xB {
414 // Safe because we pass 0xB and 0 for this call and the host supports the
415 // `cpuid` instruction
416 cpuid_entry = unsafe { __cpuid_count(0xB, 0) };
417
418 if cpuid_entry.ebx != 0 {
419 // MADT compatibility: (ACPI Spec v6.4) On some legacy OSes,
420 // Logical processors with APIC ID values less than 255 (whether in
421 // XAPIC or X2APIC mode) must use the Processor Local APIC structure.
422 if cpuid_entry.edx < MADT_MIN_LOCAL_APIC_ID {
423 apic_id = cpuid_entry.edx as u8;
424 get_apic_id = true;
425 } else {
426 // (ACPI Spec v6.4) When using the X2APIC, logical processors are
427 // required to have a processor device object in the DSDT and must
428 // convey the processor’s APIC information to OSPM using the Processor
429 // Local X2APIC structure.
430 // Now vCPUs use the DSDT passthrougt from host and the same APIC ID as
431 // the physical CPUs. Both of them should meet ACPI specifications on
432 // the host.
433 has_leafb = true;
434
435 let x2apic = Localx2Apic {
436 _type: MADT_TYPE_LOCAL_X2APIC,
437 _length: std::mem::size_of::<Localx2Apic>() as u8,
438 _x2apic_id: cpuid_entry.edx,
439 _flags: MADT_ENABLED,
440 _processor_id: (vcpu + 1) as u32,
441 ..Default::default()
442 };
443 madt.append(x2apic);
444 apic_ids.push(cpuid_entry.edx as usize);
445 }
446 }
447 }
448
449 if !has_leafb {
450 if !get_apic_id {
451 // Safe because we pass 1 for this call and the host supports the
452 // `cpuid` instruction
453 cpuid_entry = unsafe { __cpuid(1) };
454 apic_id = (cpuid_entry.ebx >> CPUID_LEAF0_EBX_CPUID_SHIFT & 0xff) as u8;
455 }
456
457 let apic = LocalApic {
458 _type: MADT_TYPE_LOCAL_APIC,
459 _length: std::mem::size_of::<LocalApic>() as u8,
460 _processor_id: vcpu as u8,
461 _apic_id: apic_id,
462 _flags: MADT_ENABLED,
463 };
464 madt.append(apic);
465 apic_ids.push(apic_id as usize);
466 }
467 }
468
469 if let Err(e) = base::set_cpu_affinity(cpu_set) {
470 error!("Failed to reset CPU affinity: {} when create MADT", e);
471 return Err(e);
472 }
473
474 Ok(())
475 }
476
477 /// Create ACPI tables and return the RSDP.
478 /// The basic tables DSDT/FACP/MADT/XSDT are constructed in this function.
479 /// # Arguments
480 ///
481 /// * `guest_mem` - The guest memory where the tables will be stored.
482 /// * `num_cpus` - Used to construct the MADT.
483 /// * `sci_irq` - Used to fill the FACP SCI_INTERRUPT field, which
484 /// is going to be used by the ACPI drivers to register
485 /// sci handler.
486 /// * `acpi_dev_resource` - resouces needed by the ACPI devices for creating tables.
487 /// * `host_cpus` - The CPU affinity per CPU used to get corresponding CPUs' apic
488 /// id and set these apic id in MADT if `--host-cpu-topology`
489 /// option is set.
490 /// * `apic_ids` - The apic id for vCPU will be sent to KVM by KVM_CREATE_VCPU ioctl.
491 /// * `pci_rqs` - PCI device to IRQ number assignments as returned by
492 /// `arch::generate_pci_root()` (device address, IRQ number, and PCI
493 /// interrupt pin assignment).
494 /// * `pcie_cfg_mmio` - Base address for the pcie enhanced configuration access mechanism
495 /// * `max_bus` - Max bus number in MCFG table
496 ///
497
create_acpi_tables( guest_mem: &GuestMemory, num_cpus: u8, sci_irq: u32, reset_port: u32, reset_value: u8, acpi_dev_resource: &AcpiDevResource, host_cpus: Option<VcpuAffinity>, apic_ids: &mut Vec<usize>, pci_irqs: &[(PciAddress, u32, PciInterruptPin)], pcie_cfg_mmio: u64, max_bus: u8, force_s2idle: bool, ) -> Option<GuestAddress>498 pub fn create_acpi_tables(
499 guest_mem: &GuestMemory,
500 num_cpus: u8,
501 sci_irq: u32,
502 reset_port: u32,
503 reset_value: u8,
504 acpi_dev_resource: &AcpiDevResource,
505 host_cpus: Option<VcpuAffinity>,
506 apic_ids: &mut Vec<usize>,
507 pci_irqs: &[(PciAddress, u32, PciInterruptPin)],
508 pcie_cfg_mmio: u64,
509 max_bus: u8,
510 force_s2idle: bool,
511 ) -> Option<GuestAddress> {
512 // RSDP is at the HI RSDP WINDOW
513 let rsdp_offset = GuestAddress(super::ACPI_HI_RSDP_WINDOW_BASE);
514 let facs_offset = next_offset(rsdp_offset, RSDP::len() as u64)?;
515 let mut offset = next_offset(facs_offset, FACS::len() as u64)?;
516 let mut dsdt_offset: Option<GuestAddress> = None;
517 let mut tables: Vec<u64> = Vec::new();
518 let mut facp: Option<SDT> = None;
519 let mut host_madt: Option<SDT> = None;
520
521 // User supplied System Description Tables, e.g. SSDT.
522 for sdt in acpi_dev_resource.sdts.iter() {
523 if sdt.is_signature(b"FACP") {
524 facp = Some(sdt.clone());
525 continue;
526 }
527 if sdt.is_signature(b"APIC") {
528 host_madt = Some(sdt.clone());
529 continue;
530 }
531 guest_mem.write_at_addr(sdt.as_slice(), offset).ok()?;
532 if sdt.is_signature(b"DSDT") {
533 dsdt_offset = Some(offset);
534 } else {
535 tables.push(offset.0);
536 }
537 offset = next_offset(offset, sdt.len() as u64)?;
538 }
539
540 // FACS
541 let facs = FACS::new();
542 guest_mem.write_at_addr(facs.as_slice(), facs_offset).ok()?;
543
544 // DSDT
545 let dsdt_offset = match dsdt_offset {
546 Some(dsdt_offset) => dsdt_offset,
547 None => {
548 let dsdt_offset = offset;
549 let dsdt = create_dsdt_table(&acpi_dev_resource.amls);
550 guest_mem.write_at_addr(dsdt.as_slice(), offset).ok()?;
551 offset = next_offset(offset, dsdt.len() as u64)?;
552 dsdt_offset
553 }
554 };
555
556 // FACP aka FADT
557 let mut facp = facp.map_or_else(
558 || create_facp_table(sci_irq as u16, force_s2idle),
559 |facp| {
560 let fadt_flags: u32 = facp.read(FADT_FIELD_FLAGS);
561 if fadt_flags & FADT_POWER_BUTTON != 0 {
562 warn!(
563 "Control Method Power Button is not supported. FADT flags = 0x{:x}",
564 fadt_flags
565 );
566 }
567 facp
568 },
569 );
570
571 write_facp_overrides(
572 &mut facp,
573 facs_offset,
574 dsdt_offset,
575 acpi_dev_resource.pm_iobase as u32,
576 reset_port,
577 reset_value,
578 );
579
580 guest_mem.write_at_addr(facp.as_slice(), offset).ok()?;
581 tables.push(offset.0);
582 offset = next_offset(offset, facp.len() as u64)?;
583
584 // MADT
585 let mut madt = SDT::new(
586 *b"APIC",
587 MADT_LEN,
588 MADT_REVISION,
589 *b"CROSVM",
590 *b"CROSVMDT",
591 OEM_REVISION,
592 );
593 madt.write(
594 MADT_FIELD_LAPIC_ADDR,
595 super::mptable::APIC_DEFAULT_PHYS_BASE as u32,
596 );
597 // Our IrqChip implementations (the KVM in-kernel irqchip and the split irqchip) expose a pair
598 // of PC-compatible 8259 PICs.
599 madt.write(MADT_FIELD_FLAGS, MADT_FLAG_PCAT_COMPAT);
600
601 match host_cpus {
602 Some(VcpuAffinity::PerVcpu(cpus)) => {
603 sync_acpi_id_from_cpuid(&mut madt, cpus, apic_ids).ok()?;
604 }
605 _ => {
606 for cpu in 0..num_cpus {
607 let apic = LocalApic {
608 _type: MADT_TYPE_LOCAL_APIC,
609 _length: std::mem::size_of::<LocalApic>() as u8,
610 _processor_id: cpu,
611 _apic_id: cpu,
612 _flags: MADT_ENABLED,
613 };
614 madt.append(apic);
615 apic_ids.push(cpu as usize);
616 }
617 }
618 }
619
620 madt.append(Ioapic {
621 _type: MADT_TYPE_IO_APIC,
622 _length: std::mem::size_of::<Ioapic>() as u8,
623 _apic_address: super::mptable::IO_APIC_DEFAULT_PHYS_BASE,
624 ..Default::default()
625 });
626
627 // Add interrupt overrides for the PCI IRQs so that they are reported as level triggered, as
628 // required by the PCI bus. The source and system GSI are identical, so this does not actually
629 // override the mapping; we just use it to set the level-triggered flag.
630 let mut unique_pci_irqs: Vec<u32> = pci_irqs.iter().map(|(_, irq_num, _)| *irq_num).collect();
631 unique_pci_irqs.sort_unstable();
632 unique_pci_irqs.dedup();
633 for irq_num in unique_pci_irqs {
634 madt.append(IoapicInterruptSourceOverride {
635 _type: MADT_TYPE_INTERRUPT_SOURCE_OVERRIDE,
636 _length: std::mem::size_of::<IoapicInterruptSourceOverride>() as u8,
637 _bus: 0, // ISA
638 _source: irq_num as u8,
639 _gsi: irq_num,
640 _flags: MADT_INT_POLARITY_ACTIVE_LOW | MADT_INT_TRIGGER_LEVEL,
641 });
642 }
643
644 if let Some(host_madt) = host_madt {
645 let mut idx = MADT_LEN as usize;
646 while idx + MADT_STRUCTURE_LEN < host_madt.len() {
647 let struct_type = host_madt.as_slice()[idx + MADT_STRUCTURE_TYPE];
648 let struct_len = host_madt.as_slice()[idx + MADT_STRUCTURE_LEN] as usize;
649 if struct_type == MADT_TYPE_INTERRUPT_SOURCE_OVERRIDE {
650 if idx + struct_len <= host_madt.len() {
651 madt.append_slice(&host_madt.as_slice()[idx..(idx + struct_len)]);
652 } else {
653 error!("Malformed host MADT");
654 }
655 }
656 idx += struct_len;
657 }
658 }
659
660 guest_mem.write_at_addr(madt.as_slice(), offset).ok()?;
661 tables.push(offset.0);
662 offset = next_offset(offset, madt.len() as u64)?;
663
664 // MCFG
665 let mut mcfg = SDT::new(
666 *b"MCFG",
667 MCFG_LEN,
668 MCFG_REVISION,
669 *b"CROSVM",
670 *b"CROSVMDT",
671 OEM_REVISION,
672 );
673 mcfg.write(MCFG_FIELD_BASE_ADDRESS, pcie_cfg_mmio);
674 mcfg.write(MCFG_FIELD_START_BUS_NUMBER, 0_u8);
675 mcfg.write(MCFG_FIELD_END_BUS_NUMBER, max_bus);
676
677 guest_mem.write_at_addr(mcfg.as_slice(), offset).ok()?;
678 tables.push(offset.0);
679 offset = next_offset(offset, madt.len() as u64)?;
680
681 // XSDT
682 let mut xsdt = SDT::new(
683 *b"XSDT",
684 acpi_tables::HEADER_LEN,
685 XSDT_REVISION,
686 *b"CROSVM",
687 *b"CROSVMDT",
688 OEM_REVISION,
689 );
690 for table in tables {
691 xsdt.append(table);
692 }
693
694 guest_mem.write_at_addr(xsdt.as_slice(), offset).ok()?;
695
696 // RSDP
697 let rsdp = RSDP::new(*b"CROSVM", offset.0);
698 guest_mem.write_at_addr(rsdp.as_slice(), rsdp_offset).ok()?;
699
700 Some(rsdp_offset)
701 }
702