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