xref: /cloud-hypervisor/vmm/src/acpi.rs (revision eea9bcea38e0c5649f444c829f3a4f9c22aa486c)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 use crate::cpu::CpuManager;
6 use crate::device_manager::DeviceManager;
7 use crate::memory_manager::MemoryManager;
8 use crate::pci_segment::PciSegment;
9 use crate::{GuestMemoryMmap, GuestRegionMmap};
10 #[cfg(target_arch = "aarch64")]
11 use acpi_tables::sdt::GenericAddress;
12 use acpi_tables::{aml::Aml, rsdp::Rsdp, sdt::Sdt};
13 #[cfg(target_arch = "aarch64")]
14 use arch::aarch64::DeviceInfoForFdt;
15 #[cfg(target_arch = "aarch64")]
16 use arch::DeviceType;
17 use arch::NumaNodes;
18 use bitflags::bitflags;
19 use pci::PciBdf;
20 use std::sync::{Arc, Mutex};
21 use std::time::Instant;
22 use tracer::trace_scoped;
23 use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryRegion};
24 
25 /* Values for Type in APIC sub-headers */
26 #[cfg(target_arch = "x86_64")]
27 pub const ACPI_APIC_PROCESSOR: u8 = 0;
28 #[cfg(target_arch = "x86_64")]
29 pub const ACPI_APIC_IO: u8 = 1;
30 #[cfg(target_arch = "x86_64")]
31 pub const ACPI_APIC_XRUPT_OVERRIDE: u8 = 2;
32 #[cfg(target_arch = "aarch64")]
33 pub const ACPI_APIC_GENERIC_CPU_INTERFACE: u8 = 11;
34 #[cfg(target_arch = "aarch64")]
35 pub const ACPI_APIC_GENERIC_DISTRIBUTOR: u8 = 12;
36 #[cfg(target_arch = "aarch64")]
37 pub const ACPI_APIC_GENERIC_REDISTRIBUTOR: u8 = 14;
38 #[cfg(target_arch = "aarch64")]
39 pub const ACPI_APIC_GENERIC_TRANSLATOR: u8 = 15;
40 
41 #[allow(dead_code)]
42 #[repr(packed)]
43 #[derive(Default)]
44 struct PciRangeEntry {
45     pub base_address: u64,
46     pub segment: u16,
47     pub start: u8,
48     pub end: u8,
49     _reserved: u32,
50 }
51 
52 #[allow(dead_code)]
53 #[repr(packed)]
54 #[derive(Default)]
55 struct MemoryAffinity {
56     pub type_: u8,
57     pub length: u8,
58     pub proximity_domain: u32,
59     _reserved1: u16,
60     pub base_addr_lo: u32,
61     pub base_addr_hi: u32,
62     pub length_lo: u32,
63     pub length_hi: u32,
64     _reserved2: u32,
65     pub flags: u32,
66     _reserved3: u64,
67 }
68 
69 #[allow(dead_code)]
70 #[repr(packed)]
71 #[derive(Default)]
72 struct ProcessorLocalX2ApicAffinity {
73     pub type_: u8,
74     pub length: u8,
75     _reserved1: u16,
76     pub proximity_domain: u32,
77     pub x2apic_id: u32,
78     pub flags: u32,
79     pub clock_domain: u32,
80     _reserved2: u32,
81 }
82 
83 #[allow(dead_code)]
84 #[repr(packed)]
85 #[derive(Default)]
86 struct ProcessorGiccAffinity {
87     pub type_: u8,
88     pub length: u8,
89     pub proximity_domain: u32,
90     pub acpi_processor_uid: u32,
91     pub flags: u32,
92     pub clock_domain: u32,
93 }
94 
95 bitflags! {
96     pub struct MemAffinityFlags: u32 {
97         const NOFLAGS = 0;
98         const ENABLE = 0b1;
99         const HOTPLUGGABLE = 0b10;
100         const NON_VOLATILE = 0b100;
101     }
102 }
103 
104 impl MemoryAffinity {
105     fn from_region(
106         region: &Arc<GuestRegionMmap>,
107         proximity_domain: u32,
108         flags: MemAffinityFlags,
109     ) -> Self {
110         Self::from_range(
111             region.start_addr().raw_value(),
112             region.len(),
113             proximity_domain,
114             flags,
115         )
116     }
117 
118     fn from_range(
119         base_addr: u64,
120         size: u64,
121         proximity_domain: u32,
122         flags: MemAffinityFlags,
123     ) -> Self {
124         let base_addr_lo = (base_addr & 0xffff_ffff) as u32;
125         let base_addr_hi = (base_addr >> 32) as u32;
126         let length_lo = (size & 0xffff_ffff) as u32;
127         let length_hi = (size >> 32) as u32;
128 
129         MemoryAffinity {
130             type_: 1,
131             length: 40,
132             proximity_domain,
133             base_addr_lo,
134             base_addr_hi,
135             length_lo,
136             length_hi,
137             flags: flags.bits(),
138             ..Default::default()
139         }
140     }
141 }
142 
143 #[allow(dead_code)]
144 #[repr(packed)]
145 #[derive(Default)]
146 struct ViotVirtioPciNode {
147     pub type_: u8,
148     _reserved: u8,
149     pub length: u16,
150     pub pci_segment: u16,
151     pub pci_bdf_number: u16,
152     _reserved2: [u8; 8],
153 }
154 
155 #[allow(dead_code)]
156 #[repr(packed)]
157 #[derive(Default)]
158 struct ViotPciRangeNode {
159     pub type_: u8,
160     _reserved: u8,
161     pub length: u16,
162     pub endpoint_start: u32,
163     pub pci_segment_start: u16,
164     pub pci_segment_end: u16,
165     pub pci_bdf_start: u16,
166     pub pci_bdf_end: u16,
167     pub output_node: u16,
168     _reserved2: [u8; 6],
169 }
170 
171 pub fn create_dsdt_table(
172     device_manager: &Arc<Mutex<DeviceManager>>,
173     cpu_manager: &Arc<Mutex<CpuManager>>,
174     memory_manager: &Arc<Mutex<MemoryManager>>,
175 ) -> Sdt {
176     trace_scoped!("create_dsdt_table");
177     // DSDT
178     let mut dsdt = Sdt::new(*b"DSDT", 36, 6, *b"CLOUDH", *b"CHDSDT  ", 1);
179 
180     let mut bytes = Vec::new();
181 
182     device_manager.lock().unwrap().append_aml_bytes(&mut bytes);
183     cpu_manager.lock().unwrap().append_aml_bytes(&mut bytes);
184     memory_manager.lock().unwrap().append_aml_bytes(&mut bytes);
185     dsdt.append_slice(&bytes);
186 
187     dsdt
188 }
189 
190 fn create_facp_table(dsdt_offset: GuestAddress, device_manager: &Arc<Mutex<DeviceManager>>) -> Sdt {
191     trace_scoped!("create_facp_table");
192 
193     // Revision 6 of the ACPI FADT table is 276 bytes long
194     let mut facp = Sdt::new(*b"FACP", 276, 6, *b"CLOUDH", *b"CHFACP  ", 1);
195 
196     {
197         let device_manager = device_manager.lock().unwrap();
198         if let Some(address) = device_manager.acpi_platform_addresses().reset_reg_address {
199             // RESET_REG
200             facp.write(116, address);
201             // RESET_VALUE
202             facp.write(128, 1u8);
203         }
204 
205         if let Some(address) = device_manager
206             .acpi_platform_addresses()
207             .sleep_control_reg_address
208         {
209             // SLEEP_CONTROL_REG
210             facp.write(244, address);
211         }
212 
213         if let Some(address) = device_manager
214             .acpi_platform_addresses()
215             .sleep_status_reg_address
216         {
217             // SLEEP_STATUS_REG
218             facp.write(256, address);
219         }
220 
221         if let Some(address) = device_manager.acpi_platform_addresses().pm_timer_address {
222             // X_PM_TMR_BLK
223             facp.write(208, address);
224         }
225     }
226 
227     // aarch64 specific fields
228     #[cfg(target_arch = "aarch64")]
229     // ARM_BOOT_ARCH: enable PSCI with HVC enable-method
230     facp.write(129, 3u16);
231 
232     // Architecture common fields
233     // HW_REDUCED_ACPI, RESET_REG_SUP, TMR_VAL_EXT
234     let fadt_flags: u32 = 1 << 20 | 1 << 10 | 1 << 8;
235     facp.write(112, fadt_flags);
236     // FADT minor version
237     facp.write(131, 3u8);
238     // X_DSDT
239     facp.write(140, dsdt_offset.0);
240     // Hypervisor Vendor Identity
241     facp.write(268, b"CLOUDHYP");
242 
243     facp.update_checksum();
244 
245     facp
246 }
247 
248 fn create_mcfg_table(pci_segments: &[PciSegment]) -> Sdt {
249     let mut mcfg = Sdt::new(*b"MCFG", 36, 1, *b"CLOUDH", *b"CHMCFG  ", 1);
250 
251     // MCFG reserved 8 bytes
252     mcfg.append(0u64);
253 
254     for segment in pci_segments {
255         // 32-bit PCI enhanced configuration mechanism
256         mcfg.append(PciRangeEntry {
257             base_address: segment.mmio_config_address,
258             segment: segment.id,
259             start: 0,
260             end: 0,
261             ..Default::default()
262         });
263     }
264     mcfg
265 }
266 
267 fn create_srat_table(numa_nodes: &NumaNodes) -> Sdt {
268     let mut srat = Sdt::new(*b"SRAT", 36, 3, *b"CLOUDH", *b"CHSRAT  ", 1);
269     // SRAT reserved 12 bytes
270     srat.append_slice(&[0u8; 12]);
271 
272     // Check the MemoryAffinity structure is the right size as expected by
273     // the ACPI specification.
274     assert_eq!(std::mem::size_of::<MemoryAffinity>(), 40);
275 
276     for (node_id, node) in numa_nodes.iter() {
277         let proximity_domain = *node_id as u32;
278 
279         for region in &node.memory_regions {
280             srat.append(MemoryAffinity::from_region(
281                 region,
282                 proximity_domain,
283                 MemAffinityFlags::ENABLE,
284             ))
285         }
286 
287         for region in &node.hotplug_regions {
288             srat.append(MemoryAffinity::from_region(
289                 region,
290                 proximity_domain,
291                 MemAffinityFlags::ENABLE | MemAffinityFlags::HOTPLUGGABLE,
292             ))
293         }
294 
295         #[cfg(target_arch = "x86_64")]
296         for section in &node.sgx_epc_sections {
297             srat.append(MemoryAffinity::from_range(
298                 section.start().raw_value(),
299                 section.size(),
300                 proximity_domain,
301                 MemAffinityFlags::ENABLE,
302             ))
303         }
304 
305         for cpu in &node.cpus {
306             let x2apic_id = *cpu as u32;
307 
308             // Flags
309             // - Enabled = 1 (bit 0)
310             // - Reserved bits 1-31
311             let flags = 1;
312 
313             #[cfg(target_arch = "x86_64")]
314             srat.append(ProcessorLocalX2ApicAffinity {
315                 type_: 2,
316                 length: 24,
317                 proximity_domain,
318                 x2apic_id,
319                 flags,
320                 clock_domain: 0,
321                 ..Default::default()
322             });
323             #[cfg(target_arch = "aarch64")]
324             srat.append(ProcessorGiccAffinity {
325                 type_: 3,
326                 length: 18,
327                 proximity_domain,
328                 acpi_processor_uid: x2apic_id,
329                 flags,
330                 clock_domain: 0,
331             });
332         }
333     }
334     srat
335 }
336 
337 fn create_slit_table(numa_nodes: &NumaNodes) -> Sdt {
338     let mut slit = Sdt::new(*b"SLIT", 36, 1, *b"CLOUDH", *b"CHSLIT  ", 1);
339     // Number of System Localities on 8 bytes.
340     slit.append(numa_nodes.len() as u64);
341 
342     let existing_nodes: Vec<u32> = numa_nodes.keys().cloned().collect();
343     for (node_id, node) in numa_nodes.iter() {
344         let distances = &node.distances;
345         for i in existing_nodes.iter() {
346             let dist: u8 = if *node_id == *i {
347                 10
348             } else if let Some(distance) = distances.get(i) {
349                 *distance as u8
350             } else {
351                 20
352             };
353 
354             slit.append(dist);
355         }
356     }
357     slit
358 }
359 
360 #[cfg(target_arch = "aarch64")]
361 fn create_gtdt_table() -> Sdt {
362     const ARCH_TIMER_NS_EL2_IRQ: u32 = 10;
363     const ARCH_TIMER_VIRT_IRQ: u32 = 11;
364     const ARCH_TIMER_S_EL1_IRQ: u32 = 13;
365     const ARCH_TIMER_NS_EL1_IRQ: u32 = 14;
366     const ACPI_GTDT_INTERRUPT_MODE_LEVEL: u32 = 0;
367     const ACPI_GTDT_CAP_ALWAYS_ON: u32 = 1 << 2;
368 
369     let irqflags: u32 = ACPI_GTDT_INTERRUPT_MODE_LEVEL;
370     // GTDT
371     let mut gtdt = Sdt::new(*b"GTDT", 104, 2, *b"CLOUDH", *b"CHGTDT  ", 1);
372     // Secure EL1 Timer GSIV
373     gtdt.write(48, (ARCH_TIMER_S_EL1_IRQ + 16) as u32);
374     // Secure EL1 Timer Flags
375     gtdt.write(52, irqflags);
376     // Non-Secure EL1 Timer GSIV
377     gtdt.write(56, (ARCH_TIMER_NS_EL1_IRQ + 16) as u32);
378     // Non-Secure EL1 Timer Flags
379     gtdt.write(60, (irqflags | ACPI_GTDT_CAP_ALWAYS_ON) as u32);
380     // Virtual EL1 Timer GSIV
381     gtdt.write(64, (ARCH_TIMER_VIRT_IRQ + 16) as u32);
382     // Virtual EL1 Timer Flags
383     gtdt.write(68, irqflags);
384     // EL2 Timer GSIV
385     gtdt.write(72, (ARCH_TIMER_NS_EL2_IRQ + 16) as u32);
386     // EL2 Timer Flags
387     gtdt.write(76, irqflags);
388 
389     gtdt.update_checksum();
390 
391     gtdt
392 }
393 
394 #[cfg(target_arch = "aarch64")]
395 fn create_spcr_table(base_address: u64, gsi: u32) -> Sdt {
396     // SPCR
397     let mut spcr = Sdt::new(*b"SPCR", 80, 2, *b"CLOUDH", *b"CHSPCR  ", 1);
398     // Interface Type
399     spcr.write(36, 3u8);
400     // Base Address in format ACPI Generic Address Structure
401     spcr.write(40, GenericAddress::mmio_address::<u8>(base_address));
402     // Interrupt Type: Bit[3] ARMH GIC interrupt
403     spcr.write(52, (1 << 3) as u8);
404     // Global System Interrupt used by the UART
405     spcr.write(54, (gsi as u32).to_le());
406     // Baud Rate: 3 = 9600
407     spcr.write(58, 3u8);
408     // Stop Bits: 1 Stop bit
409     spcr.write(60, 1u8);
410     // Flow Control: Bit[1] = RTS/CTS hardware flow control
411     spcr.write(61, (1 << 1) as u8);
412     // PCI Device ID: Not a PCI device
413     spcr.write(64, 0xffff_u16);
414     // PCI Vendor ID: Not a PCI device
415     spcr.write(66, 0xffff_u16);
416 
417     spcr.update_checksum();
418 
419     spcr
420 }
421 
422 #[cfg(target_arch = "aarch64")]
423 fn create_dbg2_table(base_address: u64) -> Sdt {
424     let namespace = "_SB_.COM1";
425     let debug_device_info_offset = 44usize;
426     let debug_device_info_len: u16 = 22 /* BaseAddressRegisterOffset */ +
427                        12 /* BaseAddressRegister */ +
428                        4 /* AddressSize */ +
429                        namespace.len() as u16 + 1 /* zero-terminated */;
430     let tbl_len: u32 = debug_device_info_offset as u32 + debug_device_info_len as u32;
431     let mut dbg2 = Sdt::new(*b"DBG2", tbl_len, 0, *b"CLOUDH", *b"CHDBG2  ", 1);
432 
433     /* OffsetDbgDeviceInfo */
434     dbg2.write_u32(36, 44);
435     /* NumberDbgDeviceInfo */
436     dbg2.write_u32(40, 1);
437 
438     /* Debug Device Information structure */
439     /* Offsets are calculated from the start of this structure. */
440     let namespace_offset = 38u16;
441     let base_address_register_offset = 22u16;
442     let address_size_offset = 34u16;
443     /* Revision */
444     dbg2.write_u8(debug_device_info_offset, 0);
445     /* Length */
446     dbg2.write_u16(debug_device_info_offset + 1, debug_device_info_len);
447     /* NumberofGenericAddressRegisters */
448     dbg2.write_u8(debug_device_info_offset + 3, 1);
449     /* NameSpaceStringLength */
450     dbg2.write_u16(debug_device_info_offset + 4, namespace.len() as u16 + 1);
451     /* NameSpaceStringOffset */
452     dbg2.write_u16(debug_device_info_offset + 6, namespace_offset);
453     /* OemDataLength */
454     dbg2.write_u16(debug_device_info_offset + 8, 0);
455     /* OemDataOffset */
456     dbg2.write_u16(debug_device_info_offset + 10, 0);
457     /* Port Type */
458     dbg2.write_u16(debug_device_info_offset + 12, 0x8000);
459     /* Port Subtype */
460     dbg2.write_u16(debug_device_info_offset + 14, 0x0003);
461     /* Reserved */
462     dbg2.write_u16(debug_device_info_offset + 16, 0);
463     /* BaseAddressRegisterOffset */
464     dbg2.write_u16(debug_device_info_offset + 18, base_address_register_offset);
465     /* AddressSizeOffset */
466     dbg2.write_u16(debug_device_info_offset + 20, address_size_offset);
467     /* BaseAddressRegister */
468     dbg2.write(
469         debug_device_info_offset + base_address_register_offset as usize,
470         GenericAddress::mmio_address::<u8>(base_address),
471     );
472     /* AddressSize */
473     dbg2.write_u32(
474         debug_device_info_offset + address_size_offset as usize,
475         0x1000,
476     );
477     /* NamespaceString, zero-terminated ASCII */
478     for (k, c) in namespace.chars().enumerate() {
479         dbg2.write_u8(
480             debug_device_info_offset + namespace_offset as usize + k,
481             c as u8,
482         );
483     }
484     dbg2.write_u8(
485         debug_device_info_offset + namespace_offset as usize + namespace.len(),
486         0,
487     );
488 
489     dbg2.update_checksum();
490 
491     dbg2
492 }
493 
494 #[cfg(target_arch = "aarch64")]
495 fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt {
496     const ACPI_IORT_NODE_ITS_GROUP: u8 = 0x00;
497     const ACPI_IORT_NODE_PCI_ROOT_COMPLEX: u8 = 0x02;
498     const ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET: usize = 72;
499     const ACPI_IORT_NODE_ROOT_COMPLEX_SIZE: usize = 60;
500 
501     // The IORT table containes:
502     // - Header (size = 40)
503     // - 1 x ITS Group Node (size = 24)
504     // - N x Root Complex Node (N = number of pci segments, size = 60 x N)
505     let iort_table_size: u32 = (ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET
506         + ACPI_IORT_NODE_ROOT_COMPLEX_SIZE * pci_segments.len())
507         as u32;
508     let mut iort = Sdt::new(*b"IORT", iort_table_size, 2, *b"CLOUDH", *b"CHIORT  ", 1);
509     iort.write(36, ((1 + pci_segments.len()) as u32).to_le());
510     iort.write(40, (48u32).to_le());
511 
512     // ITS group node
513     iort.write(48, ACPI_IORT_NODE_ITS_GROUP as u8);
514     // Length of the ITS group node in bytes
515     iort.write(49, (24u16).to_le());
516     // ITS counts
517     iort.write(64, (1u32).to_le());
518 
519     // Root Complex Nodes
520     for (i, segment) in pci_segments.iter().enumerate() {
521         let node_offset: usize =
522             ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET + i * ACPI_IORT_NODE_ROOT_COMPLEX_SIZE;
523         iort.write(node_offset, ACPI_IORT_NODE_PCI_ROOT_COMPLEX as u8);
524         // Length of the root complex node in bytes
525         iort.write(
526             node_offset + 1,
527             (ACPI_IORT_NODE_ROOT_COMPLEX_SIZE as u16).to_le(),
528         );
529         // Revision
530         iort.write(node_offset + 3, (3u8).to_le());
531         // Node ID
532         iort.write(node_offset + 4, (segment.id as u32).to_le());
533         // Mapping counts
534         iort.write(node_offset + 8, (1u32).to_le());
535         // Offset from the start of the RC node to the start of its Array of ID mappings
536         iort.write(node_offset + 12, (36u32).to_le());
537         // Fully coherent device
538         iort.write(node_offset + 16, (1u32).to_le());
539         // CCA = CPM = DCAS = 1
540         iort.write(node_offset + 24, 3u8);
541         // PCI segment number
542         iort.write(node_offset + 28, (segment.id as u32).to_le());
543         // Memory address size limit
544         iort.write(node_offset + 32, (64u8).to_le());
545 
546         // From offset 32 onward is the space for ID mappings Array.
547         // Now we have only one mapping.
548         let mapping_offset: usize = node_offset + 36;
549         // The lowest value in the input range
550         iort.write(mapping_offset, (0u32).to_le());
551         // The number of IDs in the range minus one:
552         // This should cover all the devices of a segment:
553         // 1 (bus) x 32 (devices) x 8 (functions) = 256
554         // Note: Currently only 1 bus is supported in a segment.
555         iort.write(mapping_offset + 4, (255_u32).to_le());
556         // The lowest value in the output range
557         iort.write(mapping_offset + 8, ((256 * segment.id) as u32).to_le());
558         // id_mapping_array_output_reference should be
559         // the ITS group node (the first node) if no SMMU
560         iort.write(mapping_offset + 12, (48u32).to_le());
561         // Flags
562         iort.write(mapping_offset + 16, (0u32).to_le());
563     }
564 
565     iort.update_checksum();
566 
567     iort
568 }
569 
570 fn create_viot_table(iommu_bdf: &PciBdf, devices_bdf: &[PciBdf]) -> Sdt {
571     // VIOT
572     let mut viot = Sdt::new(*b"VIOT", 36, 0, *b"CLOUDH", *b"CHVIOT  ", 0);
573     // Node count
574     viot.append((devices_bdf.len() + 1) as u16);
575     // Node offset
576     viot.append(48u16);
577     // VIOT reserved 8 bytes
578     viot.append_slice(&[0u8; 8]);
579 
580     // Virtio-iommu based on virtio-pci node
581     viot.append(ViotVirtioPciNode {
582         type_: 3,
583         length: 16,
584         pci_segment: iommu_bdf.segment(),
585         pci_bdf_number: iommu_bdf.into(),
586         ..Default::default()
587     });
588 
589     for device_bdf in devices_bdf {
590         viot.append(ViotPciRangeNode {
591             type_: 1,
592             length: 24,
593             endpoint_start: device_bdf.into(),
594             pci_segment_start: device_bdf.segment(),
595             pci_segment_end: device_bdf.segment(),
596             pci_bdf_start: device_bdf.into(),
597             pci_bdf_end: device_bdf.into(),
598             output_node: 48,
599             ..Default::default()
600         });
601     }
602 
603     viot
604 }
605 
606 pub fn create_acpi_tables(
607     guest_mem: &GuestMemoryMmap,
608     device_manager: &Arc<Mutex<DeviceManager>>,
609     cpu_manager: &Arc<Mutex<CpuManager>>,
610     memory_manager: &Arc<Mutex<MemoryManager>>,
611     numa_nodes: &NumaNodes,
612 ) -> GuestAddress {
613     trace_scoped!("create_acpi_tables");
614 
615     let start_time = Instant::now();
616     let rsdp_offset = arch::layout::RSDP_POINTER;
617     let mut tables: Vec<u64> = Vec::new();
618 
619     // DSDT
620     let dsdt = create_dsdt_table(device_manager, cpu_manager, memory_manager);
621     let dsdt_offset = rsdp_offset.checked_add(Rsdp::len() as u64).unwrap();
622     guest_mem
623         .write_slice(dsdt.as_slice(), dsdt_offset)
624         .expect("Error writing DSDT table");
625 
626     // FACP aka FADT
627     let facp = create_facp_table(dsdt_offset, device_manager);
628     let facp_offset = dsdt_offset.checked_add(dsdt.len() as u64).unwrap();
629     guest_mem
630         .write_slice(facp.as_slice(), facp_offset)
631         .expect("Error writing FACP table");
632     tables.push(facp_offset.0);
633 
634     // MADT
635     let madt = cpu_manager.lock().unwrap().create_madt();
636     let madt_offset = facp_offset.checked_add(facp.len() as u64).unwrap();
637     guest_mem
638         .write_slice(madt.as_slice(), madt_offset)
639         .expect("Error writing MADT table");
640     tables.push(madt_offset.0);
641     let mut prev_tbl_len = madt.len() as u64;
642     let mut prev_tbl_off = madt_offset;
643 
644     // PPTT
645     #[cfg(target_arch = "aarch64")]
646     {
647         let pptt = cpu_manager.lock().unwrap().create_pptt();
648         let pptt_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
649         guest_mem
650             .write_slice(pptt.as_slice(), pptt_offset)
651             .expect("Error writing PPTT table");
652         tables.push(pptt_offset.0);
653         prev_tbl_len = pptt.len() as u64;
654         prev_tbl_off = pptt_offset;
655     }
656 
657     // GTDT
658     #[cfg(target_arch = "aarch64")]
659     {
660         let gtdt = create_gtdt_table();
661         let gtdt_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
662         guest_mem
663             .write_slice(gtdt.as_slice(), gtdt_offset)
664             .expect("Error writing GTDT table");
665         tables.push(gtdt_offset.0);
666         prev_tbl_len = gtdt.len() as u64;
667         prev_tbl_off = gtdt_offset;
668     }
669 
670     // MCFG
671     let mcfg = create_mcfg_table(device_manager.lock().unwrap().pci_segments());
672     let mcfg_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
673     guest_mem
674         .write_slice(mcfg.as_slice(), mcfg_offset)
675         .expect("Error writing MCFG table");
676     tables.push(mcfg_offset.0);
677     prev_tbl_len = mcfg.len() as u64;
678     prev_tbl_off = mcfg_offset;
679 
680     // SPCR and DBG2
681     #[cfg(target_arch = "aarch64")]
682     {
683         let is_serial_on = device_manager
684             .lock()
685             .unwrap()
686             .get_device_info()
687             .clone()
688             .get(&(DeviceType::Serial, DeviceType::Serial.to_string()))
689             .is_some();
690         let serial_device_addr = arch::layout::LEGACY_SERIAL_MAPPED_IO_START.raw_value();
691         let serial_device_irq = if is_serial_on {
692             device_manager
693                 .lock()
694                 .unwrap()
695                 .get_device_info()
696                 .clone()
697                 .get(&(DeviceType::Serial, DeviceType::Serial.to_string()))
698                 .unwrap()
699                 .irq()
700         } else {
701             // If serial is turned off, add a fake device with invalid irq.
702             31
703         };
704 
705         // SPCR
706         let spcr = create_spcr_table(serial_device_addr, serial_device_irq);
707         let spcr_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
708         guest_mem
709             .write_slice(spcr.as_slice(), spcr_offset)
710             .expect("Error writing SPCR table");
711         tables.push(spcr_offset.0);
712         prev_tbl_len = spcr.len() as u64;
713         prev_tbl_off = spcr_offset;
714 
715         // DBG2
716         let dbg2 = create_dbg2_table(serial_device_addr);
717         let dbg2_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
718         guest_mem
719             .write_slice(dbg2.as_slice(), dbg2_offset)
720             .expect("Error writing DBG2 table");
721         tables.push(dbg2_offset.0);
722         prev_tbl_len = dbg2.len() as u64;
723         prev_tbl_off = dbg2_offset;
724     }
725 
726     // SRAT and SLIT
727     // Only created if the NUMA nodes list is not empty.
728     if !numa_nodes.is_empty() {
729         // SRAT
730         let srat = create_srat_table(numa_nodes);
731         let srat_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
732         guest_mem
733             .write_slice(srat.as_slice(), srat_offset)
734             .expect("Error writing SRAT table");
735         tables.push(srat_offset.0);
736 
737         // SLIT
738         let slit = create_slit_table(numa_nodes);
739         let slit_offset = srat_offset.checked_add(srat.len() as u64).unwrap();
740         guest_mem
741             .write_slice(slit.as_slice(), slit_offset)
742             .expect("Error writing SRAT table");
743         tables.push(slit_offset.0);
744 
745         prev_tbl_len = slit.len() as u64;
746         prev_tbl_off = slit_offset;
747     };
748 
749     #[cfg(target_arch = "aarch64")]
750     {
751         let iort = create_iort_table(device_manager.lock().unwrap().pci_segments());
752         let iort_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
753         guest_mem
754             .write_slice(iort.as_slice(), iort_offset)
755             .expect("Error writing IORT table");
756         tables.push(iort_offset.0);
757         prev_tbl_len = iort.len() as u64;
758         prev_tbl_off = iort_offset;
759     }
760 
761     // VIOT
762     if let Some((iommu_bdf, devices_bdf)) = device_manager.lock().unwrap().iommu_attached_devices()
763     {
764         let viot = create_viot_table(iommu_bdf, devices_bdf);
765 
766         let viot_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
767         guest_mem
768             .write_slice(viot.as_slice(), viot_offset)
769             .expect("Error writing VIOT table");
770         tables.push(viot_offset.0);
771         prev_tbl_len = viot.len() as u64;
772         prev_tbl_off = viot_offset;
773     }
774 
775     // XSDT
776     let mut xsdt = Sdt::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT  ", 1);
777     for table in tables {
778         xsdt.append(table);
779     }
780     xsdt.update_checksum();
781     let xsdt_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
782     guest_mem
783         .write_slice(xsdt.as_slice(), xsdt_offset)
784         .expect("Error writing XSDT table");
785 
786     // RSDP
787     let rsdp = Rsdp::new(*b"CLOUDH", xsdt_offset.0);
788     guest_mem
789         .write_slice(rsdp.as_slice(), rsdp_offset)
790         .expect("Error writing RSDP");
791 
792     info!(
793         "Generated ACPI tables: took {}µs size = {}",
794         Instant::now().duration_since(start_time).as_micros(),
795         xsdt_offset.0 + xsdt.len() as u64 - rsdp_offset.0
796     );
797     rsdp_offset
798 }
799 
800 #[cfg(feature = "tdx")]
801 pub fn create_acpi_tables_tdx(
802     device_manager: &Arc<Mutex<DeviceManager>>,
803     cpu_manager: &Arc<Mutex<CpuManager>>,
804     memory_manager: &Arc<Mutex<MemoryManager>>,
805     numa_nodes: &NumaNodes,
806 ) -> Vec<Sdt> {
807     // DSDT
808     let mut tables = vec![create_dsdt_table(
809         device_manager,
810         cpu_manager,
811         memory_manager,
812     )];
813 
814     // FACP aka FADT
815     tables.push(create_facp_table(GuestAddress(0), device_manager));
816 
817     // MADT
818     tables.push(cpu_manager.lock().unwrap().create_madt());
819 
820     // MCFG
821     tables.push(create_mcfg_table(
822         device_manager.lock().unwrap().pci_segments(),
823     ));
824 
825     // SRAT and SLIT
826     // Only created if the NUMA nodes list is not empty.
827     if !numa_nodes.is_empty() {
828         // SRAT
829         tables.push(create_srat_table(numa_nodes));
830 
831         // SLIT
832         tables.push(create_slit_table(numa_nodes));
833     };
834 
835     // VIOT
836     if let Some((iommu_bdf, devices_bdf)) = device_manager.lock().unwrap().iommu_attached_devices()
837     {
838         tables.push(create_viot_table(iommu_bdf, devices_bdf));
839     }
840 
841     tables
842 }
843