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 (