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