4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
6 Copyright (C) 2012-2014, 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 "QemuLoader.h"
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/QemuFwCfgLib.h>
23 #include <Library/DxeServicesTableLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/OrderedCollectionLib.h>
26 #include <IndustryStandard/Acpi.h>
33 if (!QemuFwCfgIsAvailable ()) {
48 // For all N >= 1, N bits are enough to represent the number of bits set
49 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
50 // the maximum number of possibly set bits increases by one, while the
51 // representable maximum doubles.
53 Mask
= ((Mask
& 0xAAAA) >> 1) + (Mask
& 0x5555);
54 Mask
= ((Mask
& 0xCCCC) >> 2) + (Mask
& 0x3333);
55 Mask
= ((Mask
& 0xF0F0) >> 4) + (Mask
& 0x0F0F);
56 Mask
= ((Mask
& 0xFF00) >> 8) + (Mask
& 0x00FF);
65 QemuInstallAcpiMadtTable (
66 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
67 IN VOID
*AcpiTableBuffer
,
68 IN UINTN AcpiTableBufferSize
,
73 UINTN PciLinkIsoCount
;
75 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*Madt
;
76 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE
*LocalApic
;
77 EFI_ACPI_1_0_IO_APIC_STRUCTURE
*IoApic
;
78 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*Iso
;
79 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE
*LocalApicNmi
;
84 ASSERT (AcpiTableBufferSize
>= sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
86 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount
);
87 CpuCount
= QemuFwCfgRead16 ();
88 ASSERT (CpuCount
>= 1);
91 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
92 // corresponds to the union of all possible interrupt assignments for the LNKA,
93 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
95 PciLinkIsoCount
= CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel
));
97 NewBufferSize
= 1 * sizeof (*Madt
) +
98 CpuCount
* sizeof (*LocalApic
) +
99 1 * sizeof (*IoApic
) +
100 (1 + PciLinkIsoCount
) * sizeof (*Iso
) +
101 1 * sizeof (*LocalApicNmi
);
103 Madt
= AllocatePool (NewBufferSize
);
105 return EFI_OUT_OF_RESOURCES
;
108 CopyMem (&(Madt
->Header
), AcpiTableBuffer
, sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
109 Madt
->Header
.Length
= (UINT32
) NewBufferSize
;
110 Madt
->LocalApicAddress
= PcdGet32 (PcdCpuLocalApicBaseAddress
);
111 Madt
->Flags
= EFI_ACPI_1_0_PCAT_COMPAT
;
115 for (Loop
= 0; Loop
< CpuCount
; ++Loop
) {
116 LocalApic
->Type
= EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC
;
117 LocalApic
->Length
= sizeof (*LocalApic
);
118 LocalApic
->AcpiProcessorId
= (UINT8
) Loop
;
119 LocalApic
->ApicId
= (UINT8
) Loop
;
120 LocalApic
->Flags
= 1; // enabled
126 IoApic
->Type
= EFI_ACPI_1_0_IO_APIC
;
127 IoApic
->Length
= sizeof (*IoApic
);
128 IoApic
->IoApicId
= (UINT8
) CpuCount
;
129 IoApic
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
130 IoApic
->IoApicAddress
= 0xFEC00000;
131 IoApic
->SystemVectorBase
= 0x00000000;
135 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
138 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
139 Iso
->Length
= sizeof (*Iso
);
140 Iso
->Bus
= 0x00; // ISA
141 Iso
->Source
= 0x00; // IRQ0
142 Iso
->GlobalSystemInterruptVector
= 0x00000002;
143 Iso
->Flags
= 0x0000; // Conforms to specs of the bus
147 // Set Level-tiggered, Active High for all possible PCI link targets.
149 for (Loop
= 0; Loop
< 16; ++Loop
) {
150 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel
) & (1 << Loop
)) == 0) {
153 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
154 Iso
->Length
= sizeof (*Iso
);
155 Iso
->Bus
= 0x00; // ISA
156 Iso
->Source
= (UINT8
) Loop
;
157 Iso
->GlobalSystemInterruptVector
= (UINT32
) Loop
;
158 Iso
->Flags
= 0x000D; // Level-tiggered, Active High
162 (UINTN
) (Iso
- (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*)Ptr
) ==
168 LocalApicNmi
->Type
= EFI_ACPI_1_0_LOCAL_APIC_NMI
;
169 LocalApicNmi
->Length
= sizeof (*LocalApicNmi
);
170 LocalApicNmi
->AcpiProcessorId
= 0xFF; // applies to all processors
172 // polarity and trigger mode of the APIC I/O input signals conform to the
173 // specifications of the bus
175 LocalApicNmi
->Flags
= 0x0000;
177 // Local APIC interrupt input LINTn to which NMI is connected.
179 LocalApicNmi
->LocalApicInti
= 0x01;
180 Ptr
= LocalApicNmi
+ 1;
182 ASSERT ((UINTN
) ((UINT8
*)Ptr
- (UINT8
*)Madt
) == NewBufferSize
);
183 Status
= InstallAcpiTable (AcpiProtocol
, Madt
, NewBufferSize
, TableKey
);
200 PCI_WINDOW PciWindow32
;
201 PCI_WINDOW PciWindow64
;
216 AML_BYTE Pm1aCntSlpTyp
;
217 AML_BYTE Pm1bCntSlpTyp
;
218 AML_BYTE Reserved
[2];
219 } SYSTEM_STATE_PACKAGE
;
228 OUT FIRMWARE_DATA
*FwData
233 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*AllDesc
;
235 Status
= gDS
->GetMemorySpaceMap (&NumDesc
, &AllDesc
);
236 if (Status
== EFI_SUCCESS
) {
237 UINT64 NonMmio32MaxExclTop
;
238 UINT64 Mmio32MinBase
;
239 UINT64 Mmio32MaxExclTop
;
242 Status
= EFI_UNSUPPORTED
;
244 NonMmio32MaxExclTop
= 0;
245 Mmio32MinBase
= BASE_4GB
;
246 Mmio32MaxExclTop
= 0;
248 for (CurDesc
= 0; CurDesc
< NumDesc
; ++CurDesc
) {
249 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Desc
;
252 Desc
= &AllDesc
[CurDesc
];
253 ExclTop
= Desc
->BaseAddress
+ Desc
->Length
;
255 if (ExclTop
<= (UINT64
) PcdGet32 (PcdOvmfFdBaseAddress
)) {
256 switch (Desc
->GcdMemoryType
) {
257 case EfiGcdMemoryTypeNonExistent
:
260 case EfiGcdMemoryTypeReserved
:
261 case EfiGcdMemoryTypeSystemMemory
:
262 if (NonMmio32MaxExclTop
< ExclTop
) {
263 NonMmio32MaxExclTop
= ExclTop
;
267 case EfiGcdMemoryTypeMemoryMappedIo
:
268 if (Mmio32MinBase
> Desc
->BaseAddress
) {
269 Mmio32MinBase
= Desc
->BaseAddress
;
271 if (Mmio32MaxExclTop
< ExclTop
) {
272 Mmio32MaxExclTop
= ExclTop
;
282 if (Mmio32MinBase
< NonMmio32MaxExclTop
) {
283 Mmio32MinBase
= NonMmio32MaxExclTop
;
286 if (Mmio32MinBase
< Mmio32MaxExclTop
) {
287 FwData
->PciWindow32
.Base
= Mmio32MinBase
;
288 FwData
->PciWindow32
.End
= Mmio32MaxExclTop
- 1;
289 FwData
->PciWindow32
.Length
= Mmio32MaxExclTop
- Mmio32MinBase
;
291 FwData
->PciWindow64
.Base
= 0;
292 FwData
->PciWindow64
.End
= 0;
293 FwData
->PciWindow64
.Length
= 0;
295 Status
= EFI_SUCCESS
;
303 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
304 FwData
->PciWindow32
.Base
,
305 FwData
->PciWindow32
.End
,
306 FwData
->PciWindow32
.Length
310 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
311 FwData
->PciWindow64
.Base
,
312 FwData
->PciWindow64
.End
,
313 FwData
->PciWindow64
.Length
324 UINTN
*SuspendToRamSize
,
325 SYSTEM_STATE_PACKAGE
*SuspendToRam
,
326 UINTN
*SuspendToDiskSize
,
327 SYSTEM_STATE_PACKAGE
*SuspendToDisk
330 STATIC CONST SYSTEM_STATE_PACKAGE Template
= {
333 { '_', 'S', 'x', '_' }, // NameChar[4]
337 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
338 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
344 RETURN_STATUS Status
;
345 FIRMWARE_CONFIG_ITEM FwCfgItem
;
347 UINT8 SystemStates
[6];
350 // configure defaults
352 *SuspendToRamSize
= sizeof Template
;
353 CopyMem (SuspendToRam
, &Template
, sizeof Template
);
354 SuspendToRam
->NameChar
[2] = '3'; // S3
355 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
= 1; // PIIX4: STR
357 *SuspendToDiskSize
= sizeof Template
;
358 CopyMem (SuspendToDisk
, &Template
, sizeof Template
);
359 SuspendToDisk
->NameChar
[2] = '4'; // S4
360 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
= 2; // PIIX4: POSCL
363 // check for overrides
365 Status
= QemuFwCfgFindFile ("etc/system-states", &FwCfgItem
, &FwCfgSize
);
366 if (Status
!= RETURN_SUCCESS
|| FwCfgSize
!= sizeof SystemStates
) {
367 DEBUG ((DEBUG_INFO
, "ACPI using S3/S4 defaults\n"));
370 QemuFwCfgSelectItem (FwCfgItem
);
371 QemuFwCfgReadBytes (sizeof SystemStates
, SystemStates
);
374 // Each byte corresponds to a system state. In each byte, the MSB tells us
375 // whether the given state is enabled. If so, the three LSBs specify the
376 // value to be written to the PM control register's SUS_TYP bits.
378 if (SystemStates
[3] & BIT7
) {
379 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
=
380 SystemStates
[3] & (BIT2
| BIT1
| BIT0
);
381 DEBUG ((DEBUG_INFO
, "ACPI S3 value: %d\n",
382 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
));
384 *SuspendToRamSize
= 0;
385 DEBUG ((DEBUG_INFO
, "ACPI S3 disabled\n"));
388 if (SystemStates
[4] & BIT7
) {
389 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
=
390 SystemStates
[4] & (BIT2
| BIT1
| BIT0
);
391 DEBUG ((DEBUG_INFO
, "ACPI S4 value: %d\n",
392 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
));
394 *SuspendToDiskSize
= 0;
395 DEBUG ((DEBUG_INFO
, "ACPI S4 disabled\n"));
403 QemuInstallAcpiSsdtTable (
404 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
405 IN VOID
*AcpiTableBuffer
,
406 IN UINTN AcpiTableBufferSize
,
411 FIRMWARE_DATA
*FwData
;
413 Status
= EFI_OUT_OF_RESOURCES
;
415 FwData
= AllocateReservedPool (sizeof (*FwData
));
416 if (FwData
!= NULL
) {
417 UINTN SuspendToRamSize
;
418 SYSTEM_STATE_PACKAGE SuspendToRam
;
419 UINTN SuspendToDiskSize
;
420 SYSTEM_STATE_PACKAGE SuspendToDisk
;
424 GetSuspendStates (&SuspendToRamSize
, &SuspendToRam
,
425 &SuspendToDiskSize
, &SuspendToDisk
);
426 SsdtSize
= AcpiTableBufferSize
+ 17 + SuspendToRamSize
+ SuspendToDiskSize
;
427 Ssdt
= AllocatePool (SsdtSize
);
430 Status
= PopulateFwData (FwData
);
432 if (Status
== EFI_SUCCESS
) {
437 CopyMem (SsdtPtr
, AcpiTableBuffer
, AcpiTableBufferSize
);
438 SsdtPtr
+= AcpiTableBufferSize
;
441 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
443 *(SsdtPtr
++) = 0x5B; // ExtOpPrefix
444 *(SsdtPtr
++) = 0x80; // OpRegionOp
449 *(SsdtPtr
++) = 0x00; // SystemMemory
450 *(SsdtPtr
++) = 0x0C; // DWordPrefix
453 // no virtual addressing yet, take the four least significant bytes
455 CopyMem(SsdtPtr
, &FwData
, 4);
458 *(SsdtPtr
++) = 0x0C; // DWordPrefix
460 *(UINT32
*) SsdtPtr
= sizeof (*FwData
);
464 // add suspend system states
466 CopyMem (SsdtPtr
, &SuspendToRam
, SuspendToRamSize
);
467 SsdtPtr
+= SuspendToRamSize
;
468 CopyMem (SsdtPtr
, &SuspendToDisk
, SuspendToDiskSize
);
469 SsdtPtr
+= SuspendToDiskSize
;
471 ASSERT((UINTN
) (SsdtPtr
- Ssdt
) == SsdtSize
);
472 ((EFI_ACPI_DESCRIPTION_HEADER
*) Ssdt
)->Length
= (UINT32
) SsdtSize
;
473 Status
= InstallAcpiTable (AcpiProtocol
, Ssdt
, SsdtSize
, TableKey
);
479 if (Status
!= EFI_SUCCESS
) {
490 QemuInstallAcpiTable (
491 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
492 IN VOID
*AcpiTableBuffer
,
493 IN UINTN AcpiTableBufferSize
,
497 EFI_ACPI_DESCRIPTION_HEADER
*Hdr
;
498 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction
;
500 Hdr
= (EFI_ACPI_DESCRIPTION_HEADER
*) AcpiTableBuffer
;
501 switch (Hdr
->Signature
) {
502 case EFI_ACPI_1_0_APIC_SIGNATURE
:
503 TableInstallFunction
= QemuInstallAcpiMadtTable
;
505 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
506 TableInstallFunction
= QemuInstallAcpiSsdtTable
;
509 TableInstallFunction
= InstallAcpiTable
;
512 return TableInstallFunction (