4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
6 Copyright (C) 2012-2014, Red Hat, Inc.
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "AcpiPlatform.h"
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/QemuFwCfgLib.h>
16 #include <Library/DxeServicesTableLib.h>
17 #include <Library/PcdLib.h>
18 #include <Library/OrderedCollectionLib.h>
19 #include <IndustryStandard/Acpi.h>
26 if (!QemuFwCfgIsAvailable ()) {
41 // For all N >= 1, N bits are enough to represent the number of bits set
42 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
43 // the maximum number of possibly set bits increases by one, while the
44 // representable maximum doubles.
46 Mask
= ((Mask
& 0xAAAA) >> 1) + (Mask
& 0x5555);
47 Mask
= ((Mask
& 0xCCCC) >> 2) + (Mask
& 0x3333);
48 Mask
= ((Mask
& 0xF0F0) >> 4) + (Mask
& 0x0F0F);
49 Mask
= ((Mask
& 0xFF00) >> 8) + (Mask
& 0x00FF);
58 QemuInstallAcpiMadtTable (
59 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
60 IN VOID
*AcpiTableBuffer
,
61 IN UINTN AcpiTableBufferSize
,
66 UINTN PciLinkIsoCount
;
68 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*Madt
;
69 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE
*LocalApic
;
70 EFI_ACPI_1_0_IO_APIC_STRUCTURE
*IoApic
;
71 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*Iso
;
72 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE
*LocalApicNmi
;
77 ASSERT (AcpiTableBufferSize
>= sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
79 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount
);
80 CpuCount
= QemuFwCfgRead16 ();
81 ASSERT (CpuCount
>= 1);
84 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
85 // corresponds to the union of all possible interrupt assignments for the LNKA,
86 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
88 PciLinkIsoCount
= CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel
));
90 NewBufferSize
= 1 * sizeof (*Madt
) +
91 CpuCount
* sizeof (*LocalApic
) +
92 1 * sizeof (*IoApic
) +
93 (1 + PciLinkIsoCount
) * sizeof (*Iso
) +
94 1 * sizeof (*LocalApicNmi
);
96 Madt
= AllocatePool (NewBufferSize
);
98 return EFI_OUT_OF_RESOURCES
;
101 CopyMem (&(Madt
->Header
), AcpiTableBuffer
, sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
102 Madt
->Header
.Length
= (UINT32
) NewBufferSize
;
103 Madt
->LocalApicAddress
= PcdGet32 (PcdCpuLocalApicBaseAddress
);
104 Madt
->Flags
= EFI_ACPI_1_0_PCAT_COMPAT
;
108 for (Loop
= 0; Loop
< CpuCount
; ++Loop
) {
109 LocalApic
->Type
= EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC
;
110 LocalApic
->Length
= sizeof (*LocalApic
);
111 LocalApic
->AcpiProcessorId
= (UINT8
) Loop
;
112 LocalApic
->ApicId
= (UINT8
) Loop
;
113 LocalApic
->Flags
= 1; // enabled
119 IoApic
->Type
= EFI_ACPI_1_0_IO_APIC
;
120 IoApic
->Length
= sizeof (*IoApic
);
121 IoApic
->IoApicId
= (UINT8
) CpuCount
;
122 IoApic
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
123 IoApic
->IoApicAddress
= 0xFEC00000;
124 IoApic
->SystemVectorBase
= 0x00000000;
128 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
131 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
132 Iso
->Length
= sizeof (*Iso
);
133 Iso
->Bus
= 0x00; // ISA
134 Iso
->Source
= 0x00; // IRQ0
135 Iso
->GlobalSystemInterruptVector
= 0x00000002;
136 Iso
->Flags
= 0x0000; // Conforms to specs of the bus
140 // Set Level-tiggered, Active High for all possible PCI link targets.
142 for (Loop
= 0; Loop
< 16; ++Loop
) {
143 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel
) & (1 << Loop
)) == 0) {
146 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
147 Iso
->Length
= sizeof (*Iso
);
148 Iso
->Bus
= 0x00; // ISA
149 Iso
->Source
= (UINT8
) Loop
;
150 Iso
->GlobalSystemInterruptVector
= (UINT32
) Loop
;
151 Iso
->Flags
= 0x000D; // Level-tiggered, Active High
155 (UINTN
) (Iso
- (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*)Ptr
) ==
161 LocalApicNmi
->Type
= EFI_ACPI_1_0_LOCAL_APIC_NMI
;
162 LocalApicNmi
->Length
= sizeof (*LocalApicNmi
);
163 LocalApicNmi
->AcpiProcessorId
= 0xFF; // applies to all processors
165 // polarity and trigger mode of the APIC I/O input signals conform to the
166 // specifications of the bus
168 LocalApicNmi
->Flags
= 0x0000;
170 // Local APIC interrupt input LINTn to which NMI is connected.
172 LocalApicNmi
->LocalApicInti
= 0x01;
173 Ptr
= LocalApicNmi
+ 1;
175 ASSERT ((UINTN
) ((UINT8
*)Ptr
- (UINT8
*)Madt
) == NewBufferSize
);
176 Status
= InstallAcpiTable (AcpiProtocol
, Madt
, NewBufferSize
, TableKey
);
193 PCI_WINDOW PciWindow32
;
194 PCI_WINDOW PciWindow64
;
209 AML_BYTE Pm1aCntSlpTyp
;
210 AML_BYTE Pm1bCntSlpTyp
;
211 AML_BYTE Reserved
[2];
212 } SYSTEM_STATE_PACKAGE
;
221 OUT FIRMWARE_DATA
*FwData
226 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*AllDesc
;
228 Status
= gDS
->GetMemorySpaceMap (&NumDesc
, &AllDesc
);
229 if (Status
== EFI_SUCCESS
) {
230 UINT64 NonMmio32MaxExclTop
;
231 UINT64 Mmio32MinBase
;
232 UINT64 Mmio32MaxExclTop
;
235 Status
= EFI_UNSUPPORTED
;
237 NonMmio32MaxExclTop
= 0;
238 Mmio32MinBase
= BASE_4GB
;
239 Mmio32MaxExclTop
= 0;
241 for (CurDesc
= 0; CurDesc
< NumDesc
; ++CurDesc
) {
242 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Desc
;
245 Desc
= &AllDesc
[CurDesc
];
246 ExclTop
= Desc
->BaseAddress
+ Desc
->Length
;
248 if (ExclTop
<= (UINT64
) PcdGet32 (PcdOvmfFdBaseAddress
)) {
249 switch (Desc
->GcdMemoryType
) {
250 case EfiGcdMemoryTypeNonExistent
:
253 case EfiGcdMemoryTypeReserved
:
254 case EfiGcdMemoryTypeSystemMemory
:
255 if (NonMmio32MaxExclTop
< ExclTop
) {
256 NonMmio32MaxExclTop
= ExclTop
;
260 case EfiGcdMemoryTypeMemoryMappedIo
:
261 if (Mmio32MinBase
> Desc
->BaseAddress
) {
262 Mmio32MinBase
= Desc
->BaseAddress
;
264 if (Mmio32MaxExclTop
< ExclTop
) {
265 Mmio32MaxExclTop
= ExclTop
;
275 if (Mmio32MinBase
< NonMmio32MaxExclTop
) {
276 Mmio32MinBase
= NonMmio32MaxExclTop
;
279 if (Mmio32MinBase
< Mmio32MaxExclTop
) {
280 FwData
->PciWindow32
.Base
= Mmio32MinBase
;
281 FwData
->PciWindow32
.End
= Mmio32MaxExclTop
- 1;
282 FwData
->PciWindow32
.Length
= Mmio32MaxExclTop
- Mmio32MinBase
;
284 FwData
->PciWindow64
.Base
= 0;
285 FwData
->PciWindow64
.End
= 0;
286 FwData
->PciWindow64
.Length
= 0;
288 Status
= EFI_SUCCESS
;
296 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
297 FwData
->PciWindow32
.Base
,
298 FwData
->PciWindow32
.End
,
299 FwData
->PciWindow32
.Length
303 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
304 FwData
->PciWindow64
.Base
,
305 FwData
->PciWindow64
.End
,
306 FwData
->PciWindow64
.Length
317 UINTN
*SuspendToRamSize
,
318 SYSTEM_STATE_PACKAGE
*SuspendToRam
,
319 UINTN
*SuspendToDiskSize
,
320 SYSTEM_STATE_PACKAGE
*SuspendToDisk
323 STATIC CONST SYSTEM_STATE_PACKAGE Template
= {
326 { '_', 'S', 'x', '_' }, // NameChar[4]
330 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
331 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
337 RETURN_STATUS Status
;
338 FIRMWARE_CONFIG_ITEM FwCfgItem
;
340 UINT8 SystemStates
[6];
343 // configure defaults
345 *SuspendToRamSize
= sizeof Template
;
346 CopyMem (SuspendToRam
, &Template
, sizeof Template
);
347 SuspendToRam
->NameChar
[2] = '3'; // S3
348 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
= 1; // PIIX4: STR
350 *SuspendToDiskSize
= sizeof Template
;
351 CopyMem (SuspendToDisk
, &Template
, sizeof Template
);
352 SuspendToDisk
->NameChar
[2] = '4'; // S4
353 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
= 2; // PIIX4: POSCL
356 // check for overrides
358 Status
= QemuFwCfgFindFile ("etc/system-states", &FwCfgItem
, &FwCfgSize
);
359 if (Status
!= RETURN_SUCCESS
|| FwCfgSize
!= sizeof SystemStates
) {
360 DEBUG ((DEBUG_INFO
, "ACPI using S3/S4 defaults\n"));
363 QemuFwCfgSelectItem (FwCfgItem
);
364 QemuFwCfgReadBytes (sizeof SystemStates
, SystemStates
);
367 // Each byte corresponds to a system state. In each byte, the MSB tells us
368 // whether the given state is enabled. If so, the three LSBs specify the
369 // value to be written to the PM control register's SUS_TYP bits.
371 if (SystemStates
[3] & BIT7
) {
372 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
=
373 SystemStates
[3] & (BIT2
| BIT1
| BIT0
);
374 DEBUG ((DEBUG_INFO
, "ACPI S3 value: %d\n",
375 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
));
377 *SuspendToRamSize
= 0;
378 DEBUG ((DEBUG_INFO
, "ACPI S3 disabled\n"));
381 if (SystemStates
[4] & BIT7
) {
382 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
=
383 SystemStates
[4] & (BIT2
| BIT1
| BIT0
);
384 DEBUG ((DEBUG_INFO
, "ACPI S4 value: %d\n",
385 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
));
387 *SuspendToDiskSize
= 0;
388 DEBUG ((DEBUG_INFO
, "ACPI S4 disabled\n"));
396 QemuInstallAcpiSsdtTable (
397 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
398 IN VOID
*AcpiTableBuffer
,
399 IN UINTN AcpiTableBufferSize
,
404 FIRMWARE_DATA
*FwData
;
406 Status
= EFI_OUT_OF_RESOURCES
;
408 FwData
= AllocateReservedPool (sizeof (*FwData
));
409 if (FwData
!= NULL
) {
410 UINTN SuspendToRamSize
;
411 SYSTEM_STATE_PACKAGE SuspendToRam
;
412 UINTN SuspendToDiskSize
;
413 SYSTEM_STATE_PACKAGE SuspendToDisk
;
417 GetSuspendStates (&SuspendToRamSize
, &SuspendToRam
,
418 &SuspendToDiskSize
, &SuspendToDisk
);
419 SsdtSize
= AcpiTableBufferSize
+ 17 + SuspendToRamSize
+ SuspendToDiskSize
;
420 Ssdt
= AllocatePool (SsdtSize
);
423 Status
= PopulateFwData (FwData
);
425 if (Status
== EFI_SUCCESS
) {
430 CopyMem (SsdtPtr
, AcpiTableBuffer
, AcpiTableBufferSize
);
431 SsdtPtr
+= AcpiTableBufferSize
;
434 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
436 *(SsdtPtr
++) = 0x5B; // ExtOpPrefix
437 *(SsdtPtr
++) = 0x80; // OpRegionOp
442 *(SsdtPtr
++) = 0x00; // SystemMemory
443 *(SsdtPtr
++) = 0x0C; // DWordPrefix
446 // no virtual addressing yet, take the four least significant bytes
448 CopyMem(SsdtPtr
, &FwData
, 4);
451 *(SsdtPtr
++) = 0x0C; // DWordPrefix
453 *(UINT32
*) SsdtPtr
= sizeof (*FwData
);
457 // add suspend system states
459 CopyMem (SsdtPtr
, &SuspendToRam
, SuspendToRamSize
);
460 SsdtPtr
+= SuspendToRamSize
;
461 CopyMem (SsdtPtr
, &SuspendToDisk
, SuspendToDiskSize
);
462 SsdtPtr
+= SuspendToDiskSize
;
464 ASSERT((UINTN
) (SsdtPtr
- Ssdt
) == SsdtSize
);
465 ((EFI_ACPI_DESCRIPTION_HEADER
*) Ssdt
)->Length
= (UINT32
) SsdtSize
;
466 Status
= InstallAcpiTable (AcpiProtocol
, Ssdt
, SsdtSize
, TableKey
);
472 if (Status
!= EFI_SUCCESS
) {
483 QemuInstallAcpiTable (
484 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
485 IN VOID
*AcpiTableBuffer
,
486 IN UINTN AcpiTableBufferSize
,
490 EFI_ACPI_DESCRIPTION_HEADER
*Hdr
;
491 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction
;
493 Hdr
= (EFI_ACPI_DESCRIPTION_HEADER
*) AcpiTableBuffer
;
494 switch (Hdr
->Signature
) {
495 case EFI_ACPI_1_0_APIC_SIGNATURE
:
496 TableInstallFunction
= QemuInstallAcpiMadtTable
;
498 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
499 TableInstallFunction
= QemuInstallAcpiSsdtTable
;
502 TableInstallFunction
= InstallAcpiTable
;
505 return TableInstallFunction (