x86_64/
acpi.rs

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