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