• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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