4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
6 Copyright (C) 2012, Red Hat, Inc.
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "AcpiPlatform.h"
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/QemuFwCfgLib.h>
22 #include <Library/DxeServicesTableLib.h>
23 #include <Library/PcdLib.h>
24 #include <IndustryStandard/Acpi.h>
31 if (!QemuFwCfgIsAvailable ()) {
46 // For all N >= 1, N bits are enough to represent the number of bits set
47 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
48 // the maximum number of possibly set bits increases by one, while the
49 // representable maximum doubles.
51 Mask
= ((Mask
& 0xAAAA) >> 1) + (Mask
& 0x5555);
52 Mask
= ((Mask
& 0xCCCC) >> 2) + (Mask
& 0x3333);
53 Mask
= ((Mask
& 0xF0F0) >> 4) + (Mask
& 0x0F0F);
54 Mask
= ((Mask
& 0xFF00) >> 8) + (Mask
& 0x00FF);
63 QemuInstallAcpiMadtTable (
64 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
65 IN VOID
*AcpiTableBuffer
,
66 IN UINTN AcpiTableBufferSize
,
71 UINTN PciLinkIsoCount
;
73 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*Madt
;
74 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE
*LocalApic
;
75 EFI_ACPI_1_0_IO_APIC_STRUCTURE
*IoApic
;
76 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*Iso
;
77 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE
*LocalApicNmi
;
82 ASSERT (AcpiTableBufferSize
>= sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
84 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount
);
85 CpuCount
= QemuFwCfgRead16 ();
86 ASSERT (CpuCount
>= 1);
89 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
90 // corresponds to the union of all possible interrupt assignments for the LNKA,
91 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
93 PciLinkIsoCount
= CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel
));
95 NewBufferSize
= 1 * sizeof (*Madt
) +
96 CpuCount
* sizeof (*LocalApic
) +
97 1 * sizeof (*IoApic
) +
98 (1 + PciLinkIsoCount
) * sizeof (*Iso
) +
99 1 * sizeof (*LocalApicNmi
);
101 Madt
= AllocatePool (NewBufferSize
);
103 return EFI_OUT_OF_RESOURCES
;
106 CopyMem (&(Madt
->Header
), AcpiTableBuffer
, sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
107 Madt
->Header
.Length
= (UINT32
) NewBufferSize
;
108 Madt
->LocalApicAddress
= PcdGet32 (PcdCpuLocalApicBaseAddress
);
109 Madt
->Flags
= EFI_ACPI_1_0_PCAT_COMPAT
;
113 for (Loop
= 0; Loop
< CpuCount
; ++Loop
) {
114 LocalApic
->Type
= EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC
;
115 LocalApic
->Length
= sizeof (*LocalApic
);
116 LocalApic
->AcpiProcessorId
= (UINT8
) Loop
;
117 LocalApic
->ApicId
= (UINT8
) Loop
;
118 LocalApic
->Flags
= 1; // enabled
124 IoApic
->Type
= EFI_ACPI_1_0_IO_APIC
;
125 IoApic
->Length
= sizeof (*IoApic
);
126 IoApic
->IoApicId
= (UINT8
) CpuCount
;
127 IoApic
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
128 IoApic
->IoApicAddress
= 0xFEC00000;
129 IoApic
->SystemVectorBase
= 0x00000000;
133 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
136 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
137 Iso
->Length
= sizeof (*Iso
);
138 Iso
->Bus
= 0x00; // ISA
139 Iso
->Source
= 0x00; // IRQ0
140 Iso
->GlobalSystemInterruptVector
= 0x00000002;
141 Iso
->Flags
= 0x0000; // Conforms to specs of the bus
145 // Set Level-tiggered, Active High for all possible PCI link targets.
147 for (Loop
= 0; Loop
< 16; ++Loop
) {
148 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel
) & (1 << Loop
)) == 0) {
151 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
152 Iso
->Length
= sizeof (*Iso
);
153 Iso
->Bus
= 0x00; // ISA
154 Iso
->Source
= (UINT8
) Loop
;
155 Iso
->GlobalSystemInterruptVector
= (UINT32
) Loop
;
156 Iso
->Flags
= 0x000D; // Level-tiggered, Active High
160 (UINTN
) (Iso
- (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*)Ptr
) ==
166 LocalApicNmi
->Type
= EFI_ACPI_1_0_LOCAL_APIC_NMI
;
167 LocalApicNmi
->Length
= sizeof (*LocalApicNmi
);
168 LocalApicNmi
->AcpiProcessorId
= 0xFF; // applies to all processors
170 // polarity and trigger mode of the APIC I/O input signals conform to the
171 // specifications of the bus
173 LocalApicNmi
->Flags
= 0x0000;
175 // Local APIC interrupt input LINTn to which NMI is connected.
177 LocalApicNmi
->LocalApicInti
= 0x01;
178 Ptr
= LocalApicNmi
+ 1;
180 ASSERT ((UINTN
) ((UINT8
*)Ptr
- (UINT8
*)Madt
) == NewBufferSize
);
181 Status
= InstallAcpiTable (AcpiProtocol
, Madt
, NewBufferSize
, TableKey
);
198 PCI_WINDOW PciWindow32
;
199 PCI_WINDOW PciWindow64
;
214 AML_BYTE Pm1aCntSlpTyp
;
215 AML_BYTE Pm1bCntSlpTyp
;
216 AML_BYTE Reserved
[2];
217 } SYSTEM_STATE_PACKAGE
;
226 OUT FIRMWARE_DATA
*FwData
231 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*AllDesc
;
233 Status
= gDS
->GetMemorySpaceMap (&NumDesc
, &AllDesc
);
234 if (Status
== EFI_SUCCESS
) {
235 UINT64 NonMmio32MaxExclTop
;
236 UINT64 Mmio32MinBase
;
237 UINT64 Mmio32MaxExclTop
;
240 Status
= EFI_UNSUPPORTED
;
242 NonMmio32MaxExclTop
= 0;
243 Mmio32MinBase
= BASE_4GB
;
244 Mmio32MaxExclTop
= 0;
246 for (CurDesc
= 0; CurDesc
< NumDesc
; ++CurDesc
) {
247 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Desc
;
250 Desc
= &AllDesc
[CurDesc
];
251 ExclTop
= Desc
->BaseAddress
+ Desc
->Length
;
253 if (ExclTop
<= (UINT64
) PcdGet32 (PcdOvmfFdBaseAddress
)) {
254 switch (Desc
->GcdMemoryType
) {
255 case EfiGcdMemoryTypeNonExistent
:
258 case EfiGcdMemoryTypeReserved
:
259 case EfiGcdMemoryTypeSystemMemory
:
260 if (NonMmio32MaxExclTop
< ExclTop
) {
261 NonMmio32MaxExclTop
= ExclTop
;
265 case EfiGcdMemoryTypeMemoryMappedIo
:
266 if (Mmio32MinBase
> Desc
->BaseAddress
) {
267 Mmio32MinBase
= Desc
->BaseAddress
;
269 if (Mmio32MaxExclTop
< ExclTop
) {
270 Mmio32MaxExclTop
= ExclTop
;
280 if (Mmio32MinBase
< NonMmio32MaxExclTop
) {
281 Mmio32MinBase
= NonMmio32MaxExclTop
;
284 if (Mmio32MinBase
< Mmio32MaxExclTop
) {
285 FwData
->PciWindow32
.Base
= Mmio32MinBase
;
286 FwData
->PciWindow32
.End
= Mmio32MaxExclTop
- 1;
287 FwData
->PciWindow32
.Length
= Mmio32MaxExclTop
- Mmio32MinBase
;
289 FwData
->PciWindow64
.Base
= 0;
290 FwData
->PciWindow64
.End
= 0;
291 FwData
->PciWindow64
.Length
= 0;
293 Status
= EFI_SUCCESS
;
301 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
302 FwData
->PciWindow32
.Base
,
303 FwData
->PciWindow32
.End
,
304 FwData
->PciWindow32
.Length
308 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
309 FwData
->PciWindow64
.Base
,
310 FwData
->PciWindow64
.End
,
311 FwData
->PciWindow64
.Length
322 UINTN
*SuspendToRamSize
,
323 SYSTEM_STATE_PACKAGE
*SuspendToRam
,
324 UINTN
*SuspendToDiskSize
,
325 SYSTEM_STATE_PACKAGE
*SuspendToDisk
328 STATIC CONST SYSTEM_STATE_PACKAGE Template
= {
331 { '_', 'S', 'x', '_' }, // NameChar[4]
335 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
336 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
342 RETURN_STATUS Status
;
343 FIRMWARE_CONFIG_ITEM FwCfgItem
;
345 UINT8 SystemStates
[6];
348 // configure defaults
350 *SuspendToRamSize
= sizeof Template
;
351 CopyMem (SuspendToRam
, &Template
, sizeof Template
);
352 SuspendToRam
->NameChar
[2] = '3'; // S3
353 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
= 1; // PIIX4: STR
355 *SuspendToDiskSize
= sizeof Template
;
356 CopyMem (SuspendToDisk
, &Template
, sizeof Template
);
357 SuspendToDisk
->NameChar
[2] = '4'; // S4
358 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
= 2; // PIIX4: POSCL
361 // check for overrides
363 Status
= QemuFwCfgFindFile ("etc/system-states", &FwCfgItem
, &FwCfgSize
);
364 if (Status
!= RETURN_SUCCESS
|| FwCfgSize
!= sizeof SystemStates
) {
365 DEBUG ((DEBUG_INFO
, "ACPI using S3/S4 defaults\n"));
368 QemuFwCfgSelectItem (FwCfgItem
);
369 QemuFwCfgReadBytes (sizeof SystemStates
, SystemStates
);
372 // Each byte corresponds to a system state. In each byte, the MSB tells us
373 // whether the given state is enabled. If so, the three LSBs specify the
374 // value to be written to the PM control register's SUS_TYP bits.
376 if (SystemStates
[3] & BIT7
) {
377 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
=
378 SystemStates
[3] & (BIT2
| BIT1
| BIT0
);
379 DEBUG ((DEBUG_INFO
, "ACPI S3 value: %d\n",
380 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
));
382 *SuspendToRamSize
= 0;
383 DEBUG ((DEBUG_INFO
, "ACPI S3 disabled\n"));
386 if (SystemStates
[4] & BIT7
) {
387 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
=
388 SystemStates
[4] & (BIT2
| BIT1
| BIT0
);
389 DEBUG ((DEBUG_INFO
, "ACPI S4 value: %d\n",
390 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
));
392 *SuspendToDiskSize
= 0;
393 DEBUG ((DEBUG_INFO
, "ACPI S4 disabled\n"));
401 QemuInstallAcpiSsdtTable (
402 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
403 IN VOID
*AcpiTableBuffer
,
404 IN UINTN AcpiTableBufferSize
,
409 FIRMWARE_DATA
*FwData
;
411 Status
= EFI_OUT_OF_RESOURCES
;
413 FwData
= AllocateReservedPool (sizeof (*FwData
));
414 if (FwData
!= NULL
) {
415 UINTN SuspendToRamSize
;
416 SYSTEM_STATE_PACKAGE SuspendToRam
;
417 UINTN SuspendToDiskSize
;
418 SYSTEM_STATE_PACKAGE SuspendToDisk
;
422 GetSuspendStates (&SuspendToRamSize
, &SuspendToRam
,
423 &SuspendToDiskSize
, &SuspendToDisk
);
424 SsdtSize
= AcpiTableBufferSize
+ 17 + SuspendToRamSize
+ SuspendToDiskSize
;
425 Ssdt
= AllocatePool (SsdtSize
);
428 Status
= PopulateFwData (FwData
);
430 if (Status
== EFI_SUCCESS
) {
435 CopyMem (SsdtPtr
, AcpiTableBuffer
, AcpiTableBufferSize
);
436 SsdtPtr
+= AcpiTableBufferSize
;
439 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
441 *(SsdtPtr
++) = 0x5B; // ExtOpPrefix
442 *(SsdtPtr
++) = 0x80; // OpRegionOp
447 *(SsdtPtr
++) = 0x00; // SystemMemory
448 *(SsdtPtr
++) = 0x0C; // DWordPrefix
451 // no virtual addressing yet, take the four least significant bytes
453 CopyMem(SsdtPtr
, &FwData
, 4);
456 *(SsdtPtr
++) = 0x0C; // DWordPrefix
458 *(UINT32
*) SsdtPtr
= sizeof (*FwData
);
462 // add suspend system states
464 CopyMem (SsdtPtr
, &SuspendToRam
, SuspendToRamSize
);
465 SsdtPtr
+= SuspendToRamSize
;
466 CopyMem (SsdtPtr
, &SuspendToDisk
, SuspendToDiskSize
);
467 SsdtPtr
+= SuspendToDiskSize
;
469 ASSERT((UINTN
) (SsdtPtr
- Ssdt
) == SsdtSize
);
470 ((EFI_ACPI_DESCRIPTION_HEADER
*) Ssdt
)->Length
= (UINT32
) SsdtSize
;
471 Status
= InstallAcpiTable (AcpiProtocol
, Ssdt
, SsdtSize
, TableKey
);
477 if (Status
!= EFI_SUCCESS
) {
488 QemuInstallAcpiTable (
489 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
490 IN VOID
*AcpiTableBuffer
,
491 IN UINTN AcpiTableBufferSize
,
495 EFI_ACPI_DESCRIPTION_HEADER
*Hdr
;
496 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction
;
498 Hdr
= (EFI_ACPI_DESCRIPTION_HEADER
*) AcpiTableBuffer
;
499 switch (Hdr
->Signature
) {
500 case EFI_ACPI_1_0_APIC_SIGNATURE
:
501 TableInstallFunction
= QemuInstallAcpiMadtTable
;
503 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
504 TableInstallFunction
= QemuInstallAcpiSsdtTable
;
507 TableInstallFunction
= InstallAcpiTable
;
510 return TableInstallFunction (
520 Download the ACPI table data file from QEMU and interpret it.
522 @param[in] AcpiProtocol The ACPI table protocol used to install tables.
524 @retval EFI_UNSUPPORTED Firmware configuration is unavailable.
526 @retval EFI_NOT_FOUND The host doesn't export the required fw_cfg
529 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
531 @retval EFI_PROTOCOL_ERROR Found truncated or invalid ACPI table header
532 in the fw_cfg contents.
534 @return Status codes returned by
535 AcpiProtocol->InstallAcpiTable().
540 // We'll be saving the keys of installed tables so that we can roll them back
541 // in case of failure. 128 tables should be enough for anyone (TM).
543 #define INSTALLED_TABLES_MAX 128
547 InstallQemuLinkedTables (
548 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
552 FIRMWARE_CONFIG_ITEM TablesFile
;
553 UINTN TablesFileSize
;
559 Status
= QemuFwCfgFindFile ("etc/acpi/tables", &TablesFile
, &TablesFileSize
);
560 if (EFI_ERROR (Status
)) {
561 DEBUG ((EFI_D_INFO
, "%a: \"etc/acpi/tables\" interface unavailable: %r\n",
562 __FUNCTION__
, Status
));
566 Tables
= AllocatePool (TablesFileSize
);
567 if (Tables
== NULL
) {
568 return EFI_OUT_OF_RESOURCES
;
571 QemuFwCfgSelectItem (TablesFile
);
572 QemuFwCfgReadBytes (TablesFileSize
, Tables
);
574 InstalledKey
= AllocatePool (INSTALLED_TABLES_MAX
* sizeof *InstalledKey
);
575 if (InstalledKey
== NULL
) {
576 Status
= EFI_OUT_OF_RESOURCES
;
582 while (Processed
< TablesFileSize
) {
584 EFI_ACPI_DESCRIPTION_HEADER
*Probe
;
586 Remaining
= TablesFileSize
- Processed
;
587 if (Remaining
< sizeof *Probe
) {
588 Status
= EFI_PROTOCOL_ERROR
;
592 Probe
= (EFI_ACPI_DESCRIPTION_HEADER
*) (Tables
+ Processed
);
593 if (Remaining
< Probe
->Length
|| Probe
->Length
< sizeof *Probe
) {
594 Status
= EFI_PROTOCOL_ERROR
;
598 DEBUG ((EFI_D_VERBOSE
, "%a: offset 0x%016Lx:"
599 " Signature=\"%-4.4a\" Length=0x%08x\n",
600 __FUNCTION__
, (UINT64
) Processed
,
601 (CONST CHAR8
*) &Probe
->Signature
, Probe
->Length
));
604 // skip automatically handled "root" tables: RSDT, XSDT
606 if (Probe
->Signature
!=
607 EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
&&
609 EFI_ACPI_2_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
) {
610 if (Installed
== INSTALLED_TABLES_MAX
) {
611 DEBUG ((EFI_D_ERROR
, "%a: can't install more than %d tables\n",
612 __FUNCTION__
, INSTALLED_TABLES_MAX
));
613 Status
= EFI_OUT_OF_RESOURCES
;
617 Status
= AcpiProtocol
->InstallAcpiTable (AcpiProtocol
, Probe
,
618 Probe
->Length
, &InstalledKey
[Installed
]);
619 if (EFI_ERROR (Status
)) {
621 "%a: failed to install table \"%-4.4a\" at offset 0x%Lx: %r\n",
622 __FUNCTION__
, (CONST CHAR8
*) &Probe
->Signature
, (UINT64
) Processed
,
630 Processed
+= Probe
->Length
;
634 // NUL-padding at the end is accepted
636 if (Status
== EFI_PROTOCOL_ERROR
) {
639 ErrorLocation
= Processed
;
640 while (Processed
< TablesFileSize
&& Tables
[Processed
] == '\0') {
643 if (Processed
< TablesFileSize
) {
644 DEBUG ((EFI_D_ERROR
, "%a: truncated or invalid ACPI table header at "
645 "offset 0x%Lx\n", __FUNCTION__
, (UINT64
) ErrorLocation
));
649 if (Processed
== TablesFileSize
) {
650 DEBUG ((EFI_D_INFO
, "%a: installed %d tables\n", __FUNCTION__
, Installed
));
651 Status
= EFI_SUCCESS
;
653 ASSERT (EFI_ERROR (Status
));
656 // Roll back partial installation.
658 while (Installed
> 0) {
660 AcpiProtocol
->UninstallAcpiTable (AcpiProtocol
, InstalledKey
[Installed
]);
664 FreePool (InstalledKey
);