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