xref: /cloud-hypervisor/vmm/src/acpi.rs (revision 6f8bd27cf7629733582d930519e98d19e90afb16)
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_tpm2_table() -> Sdt {
268     let mut tpm = Sdt::new(*b"TPM2", 52, 3, *b"CLOUDH", *b"CHTPM2  ", 1);
269 
270     tpm.write(36, 0_u16); //Platform Class
271     tpm.write(38, 0_u16); // Reserved Space
272     tpm.write(40, 0xfed4_0040_u64); // Address of Control Area
273     tpm.write(48, 7_u32); //Start Method
274 
275     tpm.update_checksum();
276     tpm
277 }
278 
279 fn create_srat_table(numa_nodes: &NumaNodes) -> Sdt {
280     let mut srat = Sdt::new(*b"SRAT", 36, 3, *b"CLOUDH", *b"CHSRAT  ", 1);
281     // SRAT reserved 12 bytes
282     srat.append_slice(&[0u8; 12]);
283 
284     // Check the MemoryAffinity structure is the right size as expected by
285     // the ACPI specification.
286     assert_eq!(std::mem::size_of::<MemoryAffinity>(), 40);
287 
288     for (node_id, node) in numa_nodes.iter() {
289         let proximity_domain = *node_id;
290 
291         for region in &node.memory_regions {
292             srat.append(MemoryAffinity::from_region(
293                 region,
294                 proximity_domain,
295                 MemAffinityFlags::ENABLE,
296             ))
297         }
298 
299         for region in &node.hotplug_regions {
300             srat.append(MemoryAffinity::from_region(
301                 region,
302                 proximity_domain,
303                 MemAffinityFlags::ENABLE | MemAffinityFlags::HOTPLUGGABLE,
304             ))
305         }
306 
307         #[cfg(target_arch = "x86_64")]
308         for section in &node.sgx_epc_sections {
309             srat.append(MemoryAffinity::from_range(
310                 section.start().raw_value(),
311                 section.size(),
312                 proximity_domain,
313                 MemAffinityFlags::ENABLE,
314             ))
315         }
316 
317         for cpu in &node.cpus {
318             let x2apic_id = *cpu as u32;
319 
320             // Flags
321             // - Enabled = 1 (bit 0)
322             // - Reserved bits 1-31
323             let flags = 1;
324 
325             #[cfg(target_arch = "x86_64")]
326             srat.append(ProcessorLocalX2ApicAffinity {
327                 type_: 2,
328                 length: 24,
329                 proximity_domain,
330                 x2apic_id,
331                 flags,
332                 clock_domain: 0,
333                 ..Default::default()
334             });
335             #[cfg(target_arch = "aarch64")]
336             srat.append(ProcessorGiccAffinity {
337                 type_: 3,
338                 length: 18,
339                 proximity_domain,
340                 acpi_processor_uid: x2apic_id,
341                 flags,
342                 clock_domain: 0,
343             });
344         }
345     }
346     srat
347 }
348 
349 fn create_slit_table(numa_nodes: &NumaNodes) -> Sdt {
350     let mut slit = Sdt::new(*b"SLIT", 36, 1, *b"CLOUDH", *b"CHSLIT  ", 1);
351     // Number of System Localities on 8 bytes.
352     slit.append(numa_nodes.len() as u64);
353 
354     let existing_nodes: Vec<u32> = numa_nodes.keys().cloned().collect();
355     for (node_id, node) in numa_nodes.iter() {
356         let distances = &node.distances;
357         for i in existing_nodes.iter() {
358             let dist: u8 = if *node_id == *i {
359                 10
360             } else if let Some(distance) = distances.get(i) {
361                 *distance
362             } else {
363                 20
364             };
365 
366             slit.append(dist);
367         }
368     }
369     slit
370 }
371 
372 #[cfg(target_arch = "aarch64")]
373 fn create_gtdt_table() -> Sdt {
374     const ARCH_TIMER_NS_EL2_IRQ: u32 = 10;
375     const ARCH_TIMER_VIRT_IRQ: u32 = 11;
376     const ARCH_TIMER_S_EL1_IRQ: u32 = 13;
377     const ARCH_TIMER_NS_EL1_IRQ: u32 = 14;
378     const ACPI_GTDT_INTERRUPT_MODE_LEVEL: u32 = 0;
379     const ACPI_GTDT_CAP_ALWAYS_ON: u32 = 1 << 2;
380 
381     let irqflags: u32 = ACPI_GTDT_INTERRUPT_MODE_LEVEL;
382     // GTDT
383     let mut gtdt = Sdt::new(*b"GTDT", 104, 2, *b"CLOUDH", *b"CHGTDT  ", 1);
384     // Secure EL1 Timer GSIV
385     gtdt.write(48, (ARCH_TIMER_S_EL1_IRQ + 16) as u32);
386     // Secure EL1 Timer Flags
387     gtdt.write(52, irqflags);
388     // Non-Secure EL1 Timer GSIV
389     gtdt.write(56, (ARCH_TIMER_NS_EL1_IRQ + 16) as u32);
390     // Non-Secure EL1 Timer Flags
391     gtdt.write(60, (irqflags | ACPI_GTDT_CAP_ALWAYS_ON) as u32);
392     // Virtual EL1 Timer GSIV
393     gtdt.write(64, (ARCH_TIMER_VIRT_IRQ + 16) as u32);
394     // Virtual EL1 Timer Flags
395     gtdt.write(68, irqflags);
396     // EL2 Timer GSIV
397     gtdt.write(72, (ARCH_TIMER_NS_EL2_IRQ + 16) as u32);
398     // EL2 Timer Flags
399     gtdt.write(76, irqflags);
400 
401     gtdt.update_checksum();
402 
403     gtdt
404 }
405 
406 #[cfg(target_arch = "aarch64")]
407 fn create_spcr_table(base_address: u64, gsi: u32) -> Sdt {
408     // SPCR
409     let mut spcr = Sdt::new(*b"SPCR", 80, 2, *b"CLOUDH", *b"CHSPCR  ", 1);
410     // Interface Type
411     spcr.write(36, 3u8);
412     // Base Address in format ACPI Generic Address Structure
413     spcr.write(40, GenericAddress::mmio_address::<u8>(base_address));
414     // Interrupt Type: Bit[3] ARMH GIC interrupt
415     spcr.write(52, (1 << 3) as u8);
416     // Global System Interrupt used by the UART
417     spcr.write(54, (gsi as u32).to_le());
418     // Baud Rate: 3 = 9600
419     spcr.write(58, 3u8);
420     // Stop Bits: 1 Stop bit
421     spcr.write(60, 1u8);
422     // Flow Control: Bit[1] = RTS/CTS hardware flow control
423     spcr.write(61, (1 << 1) as u8);
424     // PCI Device ID: Not a PCI device
425     spcr.write(64, 0xffff_u16);
426     // PCI Vendor ID: Not a PCI device
427     spcr.write(66, 0xffff_u16);
428 
429     spcr.update_checksum();
430 
431     spcr
432 }
433 
434 #[cfg(target_arch = "aarch64")]
435 fn create_dbg2_table(base_address: u64) -> Sdt {
436     let namespace = "_SB_.COM1";
437     let debug_device_info_offset = 44usize;
438     let debug_device_info_len: u16 = 22 /* BaseAddressRegisterOffset */ +
439                        12 /* BaseAddressRegister */ +
440                        4 /* AddressSize */ +
441                        namespace.len() as u16 + 1 /* zero-terminated */;
442     let tbl_len: u32 = debug_device_info_offset as u32 + debug_device_info_len as u32;
443     let mut dbg2 = Sdt::new(*b"DBG2", tbl_len, 0, *b"CLOUDH", *b"CHDBG2  ", 1);
444 
445     /* OffsetDbgDeviceInfo */
446     dbg2.write_u32(36, 44);
447     /* NumberDbgDeviceInfo */
448     dbg2.write_u32(40, 1);
449 
450     /* Debug Device Information structure */
451     /* Offsets are calculated from the start of this structure. */
452     let namespace_offset = 38u16;
453     let base_address_register_offset = 22u16;
454     let address_size_offset = 34u16;
455     /* Revision */
456     dbg2.write_u8(debug_device_info_offset, 0);
457     /* Length */
458     dbg2.write_u16(debug_device_info_offset + 1, debug_device_info_len);
459     /* NumberofGenericAddressRegisters */
460     dbg2.write_u8(debug_device_info_offset + 3, 1);
461     /* NameSpaceStringLength */
462     dbg2.write_u16(debug_device_info_offset + 4, namespace.len() as u16 + 1);
463     /* NameSpaceStringOffset */
464     dbg2.write_u16(debug_device_info_offset + 6, namespace_offset);
465     /* OemDataLength */
466     dbg2.write_u16(debug_device_info_offset + 8, 0);
467     /* OemDataOffset */
468     dbg2.write_u16(debug_device_info_offset + 10, 0);
469     /* Port Type */
470     dbg2.write_u16(debug_device_info_offset + 12, 0x8000);
471     /* Port Subtype */
472     dbg2.write_u16(debug_device_info_offset + 14, 0x0003);
473     /* Reserved */
474     dbg2.write_u16(debug_device_info_offset + 16, 0);
475     /* BaseAddressRegisterOffset */
476     dbg2.write_u16(debug_device_info_offset + 18, base_address_register_offset);
477     /* AddressSizeOffset */
478     dbg2.write_u16(debug_device_info_offset + 20, address_size_offset);
479     /* BaseAddressRegister */
480     dbg2.write(
481         debug_device_info_offset + base_address_register_offset as usize,
482         GenericAddress::mmio_address::<u8>(base_address),
483     );
484     /* AddressSize */
485     dbg2.write_u32(
486         debug_device_info_offset + address_size_offset as usize,
487         0x1000,
488     );
489     /* NamespaceString, zero-terminated ASCII */
490     for (k, c) in namespace.chars().enumerate() {
491         dbg2.write_u8(
492             debug_device_info_offset + namespace_offset as usize + k,
493             c as u8,
494         );
495     }
496     dbg2.write_u8(
497         debug_device_info_offset + namespace_offset as usize + namespace.len(),
498         0,
499     );
500 
501     dbg2.update_checksum();
502 
503     dbg2
504 }
505 
506 #[cfg(target_arch = "aarch64")]
507 fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt {
508     const ACPI_IORT_NODE_ITS_GROUP: u8 = 0x00;
509     const ACPI_IORT_NODE_PCI_ROOT_COMPLEX: u8 = 0x02;
510     const ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET: usize = 72;
511     const ACPI_IORT_NODE_ROOT_COMPLEX_SIZE: usize = 60;
512 
513     // The IORT table containes:
514     // - Header (size = 40)
515     // - 1 x ITS Group Node (size = 24)
516     // - N x Root Complex Node (N = number of pci segments, size = 60 x N)
517     let iort_table_size: u32 = (ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET
518         + ACPI_IORT_NODE_ROOT_COMPLEX_SIZE * pci_segments.len())
519         as u32;
520     let mut iort = Sdt::new(*b"IORT", iort_table_size, 2, *b"CLOUDH", *b"CHIORT  ", 1);
521     iort.write(36, ((1 + pci_segments.len()) as u32).to_le());
522     iort.write(40, (48u32).to_le());
523 
524     // ITS group node
525     iort.write(48, ACPI_IORT_NODE_ITS_GROUP as u8);
526     // Length of the ITS group node in bytes
527     iort.write(49, (24u16).to_le());
528     // ITS counts
529     iort.write(64, (1u32).to_le());
530 
531     // Root Complex Nodes
532     for (i, segment) in pci_segments.iter().enumerate() {
533         let node_offset: usize =
534             ACPI_IORT_NODE_ROOT_COMPLEX_OFFSET + i * ACPI_IORT_NODE_ROOT_COMPLEX_SIZE;
535         iort.write(node_offset, ACPI_IORT_NODE_PCI_ROOT_COMPLEX as u8);
536         // Length of the root complex node in bytes
537         iort.write(
538             node_offset + 1,
539             (ACPI_IORT_NODE_ROOT_COMPLEX_SIZE as u16).to_le(),
540         );
541         // Revision
542         iort.write(node_offset + 3, (3u8).to_le());
543         // Node ID
544         iort.write(node_offset + 4, (segment.id as u32).to_le());
545         // Mapping counts
546         iort.write(node_offset + 8, (1u32).to_le());
547         // Offset from the start of the RC node to the start of its Array of ID mappings
548         iort.write(node_offset + 12, (36u32).to_le());
549         // Fully coherent device
550         iort.write(node_offset + 16, (1u32).to_le());
551         // CCA = CPM = DCAS = 1
552         iort.write(node_offset + 24, 3u8);
553         // PCI segment number
554         iort.write(node_offset + 28, (segment.id as u32).to_le());
555         // Memory address size limit
556         iort.write(node_offset + 32, (64u8).to_le());
557 
558         // From offset 32 onward is the space for ID mappings Array.
559         // Now we have only one mapping.
560         let mapping_offset: usize = node_offset + 36;
561         // The lowest value in the input range
562         iort.write(mapping_offset, (0u32).to_le());
563         // The number of IDs in the range minus one:
564         // This should cover all the devices of a segment:
565         // 1 (bus) x 32 (devices) x 8 (functions) = 256
566         // Note: Currently only 1 bus is supported in a segment.
567         iort.write(mapping_offset + 4, (255_u32).to_le());
568         // The lowest value in the output range
569         iort.write(mapping_offset + 8, ((256 * segment.id) as u32).to_le());
570         // id_mapping_array_output_reference should be
571         // the ITS group node (the first node) if no SMMU
572         iort.write(mapping_offset + 12, (48u32).to_le());
573         // Flags
574         iort.write(mapping_offset + 16, (0u32).to_le());
575     }
576 
577     iort.update_checksum();
578 
579     iort
580 }
581 
582 fn create_viot_table(iommu_bdf: &PciBdf, devices_bdf: &[PciBdf]) -> Sdt {
583     // VIOT
584     let mut viot = Sdt::new(*b"VIOT", 36, 0, *b"CLOUDH", *b"CHVIOT  ", 0);
585     // Node count
586     viot.append((devices_bdf.len() + 1) as u16);
587     // Node offset
588     viot.append(48u16);
589     // VIOT reserved 8 bytes
590     viot.append_slice(&[0u8; 8]);
591 
592     // Virtio-iommu based on virtio-pci node
593     viot.append(ViotVirtioPciNode {
594         type_: 3,
595         length: 16,
596         pci_segment: iommu_bdf.segment(),
597         pci_bdf_number: iommu_bdf.into(),
598         ..Default::default()
599     });
600 
601     for device_bdf in devices_bdf {
602         viot.append(ViotPciRangeNode {
603             type_: 1,
604             length: 24,
605             endpoint_start: device_bdf.into(),
606             pci_segment_start: device_bdf.segment(),
607             pci_segment_end: device_bdf.segment(),
608             pci_bdf_start: device_bdf.into(),
609             pci_bdf_end: device_bdf.into(),
610             output_node: 48,
611             ..Default::default()
612         });
613     }
614 
615     viot
616 }
617 
618 pub fn create_acpi_tables(
619     guest_mem: &GuestMemoryMmap,
620     device_manager: &Arc<Mutex<DeviceManager>>,
621     cpu_manager: &Arc<Mutex<CpuManager>>,
622     memory_manager: &Arc<Mutex<MemoryManager>>,
623     numa_nodes: &NumaNodes,
624     tpm_enabled: bool,
625 ) -> GuestAddress {
626     trace_scoped!("create_acpi_tables");
627 
628     let start_time = Instant::now();
629     let rsdp_offset = arch::layout::RSDP_POINTER;
630     let mut tables: Vec<u64> = Vec::new();
631 
632     // DSDT
633     let dsdt = create_dsdt_table(device_manager, cpu_manager, memory_manager);
634     let dsdt_offset = rsdp_offset.checked_add(Rsdp::len() as u64).unwrap();
635     guest_mem
636         .write_slice(dsdt.as_slice(), dsdt_offset)
637         .expect("Error writing DSDT table");
638 
639     // FACP aka FADT
640     let facp = create_facp_table(dsdt_offset, device_manager);
641     let facp_offset = dsdt_offset.checked_add(dsdt.len() as u64).unwrap();
642     guest_mem
643         .write_slice(facp.as_slice(), facp_offset)
644         .expect("Error writing FACP table");
645     tables.push(facp_offset.0);
646 
647     // MADT
648     let madt = cpu_manager.lock().unwrap().create_madt();
649     let madt_offset = facp_offset.checked_add(facp.len() as u64).unwrap();
650     guest_mem
651         .write_slice(madt.as_slice(), madt_offset)
652         .expect("Error writing MADT table");
653     tables.push(madt_offset.0);
654     let mut prev_tbl_len = madt.len() as u64;
655     let mut prev_tbl_off = madt_offset;
656 
657     // PPTT
658     #[cfg(target_arch = "aarch64")]
659     {
660         let pptt = cpu_manager.lock().unwrap().create_pptt();
661         let pptt_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
662         guest_mem
663             .write_slice(pptt.as_slice(), pptt_offset)
664             .expect("Error writing PPTT table");
665         tables.push(pptt_offset.0);
666         prev_tbl_len = pptt.len() as u64;
667         prev_tbl_off = pptt_offset;
668     }
669 
670     // GTDT
671     #[cfg(target_arch = "aarch64")]
672     {
673         let gtdt = create_gtdt_table();
674         let gtdt_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
675         guest_mem
676             .write_slice(gtdt.as_slice(), gtdt_offset)
677             .expect("Error writing GTDT table");
678         tables.push(gtdt_offset.0);
679         prev_tbl_len = gtdt.len() as u64;
680         prev_tbl_off = gtdt_offset;
681     }
682 
683     // MCFG
684     let mcfg = create_mcfg_table(device_manager.lock().unwrap().pci_segments());
685     let mcfg_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
686     guest_mem
687         .write_slice(mcfg.as_slice(), mcfg_offset)
688         .expect("Error writing MCFG table");
689     tables.push(mcfg_offset.0);
690     prev_tbl_len = mcfg.len() as u64;
691     prev_tbl_off = mcfg_offset;
692 
693     // SPCR and DBG2
694     #[cfg(target_arch = "aarch64")]
695     {
696         let is_serial_on = device_manager
697             .lock()
698             .unwrap()
699             .get_device_info()
700             .clone()
701             .get(&(DeviceType::Serial, DeviceType::Serial.to_string()))
702             .is_some();
703         let serial_device_addr = arch::layout::LEGACY_SERIAL_MAPPED_IO_START.raw_value();
704         let serial_device_irq = if is_serial_on {
705             device_manager
706                 .lock()
707                 .unwrap()
708                 .get_device_info()
709                 .clone()
710                 .get(&(DeviceType::Serial, DeviceType::Serial.to_string()))
711                 .unwrap()
712                 .irq()
713         } else {
714             // If serial is turned off, add a fake device with invalid irq.
715             31
716         };
717 
718         // SPCR
719         let spcr = create_spcr_table(serial_device_addr, serial_device_irq);
720         let spcr_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
721         guest_mem
722             .write_slice(spcr.as_slice(), spcr_offset)
723             .expect("Error writing SPCR table");
724         tables.push(spcr_offset.0);
725         prev_tbl_len = spcr.len() as u64;
726         prev_tbl_off = spcr_offset;
727 
728         // DBG2
729         let dbg2 = create_dbg2_table(serial_device_addr);
730         let dbg2_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
731         guest_mem
732             .write_slice(dbg2.as_slice(), dbg2_offset)
733             .expect("Error writing DBG2 table");
734         tables.push(dbg2_offset.0);
735         prev_tbl_len = dbg2.len() as u64;
736         prev_tbl_off = dbg2_offset;
737     }
738 
739     if tpm_enabled {
740         // TPM2 Table
741         let tpm2 = create_tpm2_table();
742         let tpm2_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
743         guest_mem
744             .write_slice(tpm2.as_slice(), tpm2_offset)
745             .expect("Error writing TPM2 table");
746         tables.push(tpm2_offset.0);
747 
748         prev_tbl_len = tpm2.len() as u64;
749         prev_tbl_off = tpm2_offset;
750     }
751     // SRAT and SLIT
752     // Only created if the NUMA nodes list is not empty.
753     if !numa_nodes.is_empty() {
754         // SRAT
755         let srat = create_srat_table(numa_nodes);
756         let srat_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
757         guest_mem
758             .write_slice(srat.as_slice(), srat_offset)
759             .expect("Error writing SRAT table");
760         tables.push(srat_offset.0);
761 
762         // SLIT
763         let slit = create_slit_table(numa_nodes);
764         let slit_offset = srat_offset.checked_add(srat.len() as u64).unwrap();
765         guest_mem
766             .write_slice(slit.as_slice(), slit_offset)
767             .expect("Error writing SRAT table");
768         tables.push(slit_offset.0);
769 
770         prev_tbl_len = slit.len() as u64;
771         prev_tbl_off = slit_offset;
772     };
773 
774     #[cfg(target_arch = "aarch64")]
775     {
776         let iort = create_iort_table(device_manager.lock().unwrap().pci_segments());
777         let iort_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
778         guest_mem
779             .write_slice(iort.as_slice(), iort_offset)
780             .expect("Error writing IORT table");
781         tables.push(iort_offset.0);
782         prev_tbl_len = iort.len() as u64;
783         prev_tbl_off = iort_offset;
784     }
785 
786     // VIOT
787     if let Some((iommu_bdf, devices_bdf)) = device_manager.lock().unwrap().iommu_attached_devices()
788     {
789         let viot = create_viot_table(iommu_bdf, devices_bdf);
790 
791         let viot_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
792         guest_mem
793             .write_slice(viot.as_slice(), viot_offset)
794             .expect("Error writing VIOT table");
795         tables.push(viot_offset.0);
796         prev_tbl_len = viot.len() as u64;
797         prev_tbl_off = viot_offset;
798     }
799 
800     // XSDT
801     let mut xsdt = Sdt::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT  ", 1);
802     for table in tables {
803         xsdt.append(table);
804     }
805     xsdt.update_checksum();
806     let xsdt_offset = prev_tbl_off.checked_add(prev_tbl_len).unwrap();
807     guest_mem
808         .write_slice(xsdt.as_slice(), xsdt_offset)
809         .expect("Error writing XSDT table");
810 
811     // RSDP
812     let rsdp = Rsdp::new(*b"CLOUDH", xsdt_offset.0);
813     guest_mem
814         .write_slice(rsdp.as_slice(), rsdp_offset)
815         .expect("Error writing RSDP");
816 
817     info!(
818         "Generated ACPI tables: took {}µs size = {}",
819         Instant::now().duration_since(start_time).as_micros(),
820         xsdt_offset.0 + xsdt.len() as u64 - rsdp_offset.0
821     );
822     rsdp_offset
823 }
824 
825 #[cfg(feature = "tdx")]
826 pub fn create_acpi_tables_tdx(
827     device_manager: &Arc<Mutex<DeviceManager>>,
828     cpu_manager: &Arc<Mutex<CpuManager>>,
829     memory_manager: &Arc<Mutex<MemoryManager>>,
830     numa_nodes: &NumaNodes,
831 ) -> Vec<Sdt> {
832     // DSDT
833     let mut tables = vec![create_dsdt_table(
834         device_manager,
835         cpu_manager,
836         memory_manager,
837     )];
838 
839     // FACP aka FADT
840     tables.push(create_facp_table(GuestAddress(0), device_manager));
841 
842     // MADT
843     tables.push(cpu_manager.lock().unwrap().create_madt());
844 
845     // MCFG
846     tables.push(create_mcfg_table(
847         device_manager.lock().unwrap().pci_segments(),
848     ));
849 
850     // SRAT and SLIT
851     // Only created if the NUMA nodes list is not empty.
852     if !numa_nodes.is_empty() {
853         // SRAT
854         tables.push(create_srat_table(numa_nodes));
855 
856         // SLIT
857         tables.push(create_slit_table(numa_nodes));
858     };
859 
860     // VIOT
861     if let Some((iommu_bdf, devices_bdf)) = device_manager.lock().unwrap().iommu_attached_devices()
862     {
863         tables.push(create_viot_table(iommu_bdf, devices_bdf));
864     }
865 
866     tables
867 }
868