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 <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 <Library/OrderedCollectionLib.h>
25 #include <IndustryStandard/Acpi.h>
32 if (!QemuFwCfgIsAvailable ()) {
47 // For all N >= 1, N bits are enough to represent the number of bits set
48 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
49 // the maximum number of possibly set bits increases by one, while the
50 // representable maximum doubles.
52 Mask
= ((Mask
& 0xAAAA) >> 1) + (Mask
& 0x5555);
53 Mask
= ((Mask
& 0xCCCC) >> 2) + (Mask
& 0x3333);
54 Mask
= ((Mask
& 0xF0F0) >> 4) + (Mask
& 0x0F0F);
55 Mask
= ((Mask
& 0xFF00) >> 8) + (Mask
& 0x00FF);
64 QemuInstallAcpiMadtTable (
65 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
66 IN VOID
*AcpiTableBuffer
,
67 IN UINTN AcpiTableBufferSize
,
72 UINTN PciLinkIsoCount
;
74 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*Madt
;
75 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE
*LocalApic
;
76 EFI_ACPI_1_0_IO_APIC_STRUCTURE
*IoApic
;
77 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*Iso
;
78 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE
*LocalApicNmi
;
83 ASSERT (AcpiTableBufferSize
>= sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
85 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount
);
86 CpuCount
= QemuFwCfgRead16 ();
87 ASSERT (CpuCount
>= 1);
90 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
91 // corresponds to the union of all possible interrupt assignments for the LNKA,
92 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
94 PciLinkIsoCount
= CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel
));
96 NewBufferSize
= 1 * sizeof (*Madt
) +
97 CpuCount
* sizeof (*LocalApic
) +
98 1 * sizeof (*IoApic
) +
99 (1 + PciLinkIsoCount
) * sizeof (*Iso
) +
100 1 * sizeof (*LocalApicNmi
);
102 Madt
= AllocatePool (NewBufferSize
);
104 return EFI_OUT_OF_RESOURCES
;
107 CopyMem (&(Madt
->Header
), AcpiTableBuffer
, sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
108 Madt
->Header
.Length
= (UINT32
) NewBufferSize
;
109 Madt
->LocalApicAddress
= PcdGet32 (PcdCpuLocalApicBaseAddress
);
110 Madt
->Flags
= EFI_ACPI_1_0_PCAT_COMPAT
;
114 for (Loop
= 0; Loop
< CpuCount
; ++Loop
) {
115 LocalApic
->Type
= EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC
;
116 LocalApic
->Length
= sizeof (*LocalApic
);
117 LocalApic
->AcpiProcessorId
= (UINT8
) Loop
;
118 LocalApic
->ApicId
= (UINT8
) Loop
;
119 LocalApic
->Flags
= 1; // enabled
125 IoApic
->Type
= EFI_ACPI_1_0_IO_APIC
;
126 IoApic
->Length
= sizeof (*IoApic
);
127 IoApic
->IoApicId
= (UINT8
) CpuCount
;
128 IoApic
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
129 IoApic
->IoApicAddress
= 0xFEC00000;
130 IoApic
->SystemVectorBase
= 0x00000000;
134 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
137 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
138 Iso
->Length
= sizeof (*Iso
);
139 Iso
->Bus
= 0x00; // ISA
140 Iso
->Source
= 0x00; // IRQ0
141 Iso
->GlobalSystemInterruptVector
= 0x00000002;
142 Iso
->Flags
= 0x0000; // Conforms to specs of the bus
146 // Set Level-tiggered, Active High for all possible PCI link targets.
148 for (Loop
= 0; Loop
< 16; ++Loop
) {
149 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel
) & (1 << Loop
)) == 0) {
152 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
153 Iso
->Length
= sizeof (*Iso
);
154 Iso
->Bus
= 0x00; // ISA
155 Iso
->Source
= (UINT8
) Loop
;
156 Iso
->GlobalSystemInterruptVector
= (UINT32
) Loop
;
157 Iso
->Flags
= 0x000D; // Level-tiggered, Active High
161 (UINTN
) (Iso
- (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*)Ptr
) ==
167 LocalApicNmi
->Type
= EFI_ACPI_1_0_LOCAL_APIC_NMI
;
168 LocalApicNmi
->Length
= sizeof (*LocalApicNmi
);
169 LocalApicNmi
->AcpiProcessorId
= 0xFF; // applies to all processors
171 // polarity and trigger mode of the APIC I/O input signals conform to the
172 // specifications of the bus
174 LocalApicNmi
->Flags
= 0x0000;
176 // Local APIC interrupt input LINTn to which NMI is connected.
178 LocalApicNmi
->LocalApicInti
= 0x01;
179 Ptr
= LocalApicNmi
+ 1;
181 ASSERT ((UINTN
) ((UINT8
*)Ptr
- (UINT8
*)Madt
) == NewBufferSize
);
182 Status
= InstallAcpiTable (AcpiProtocol
, Madt
, NewBufferSize
, TableKey
);
199 PCI_WINDOW PciWindow32
;
200 PCI_WINDOW PciWindow64
;
215 AML_BYTE Pm1aCntSlpTyp
;
216 AML_BYTE Pm1bCntSlpTyp
;
217 AML_BYTE Reserved
[2];
218 } SYSTEM_STATE_PACKAGE
;
227 OUT FIRMWARE_DATA
*FwData
232 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*AllDesc
;
234 Status
= gDS
->GetMemorySpaceMap (&NumDesc
, &AllDesc
);
235 if (Status
== EFI_SUCCESS
) {
236 UINT64 NonMmio32MaxExclTop
;
237 UINT64 Mmio32MinBase
;
238 UINT64 Mmio32MaxExclTop
;
241 Status
= EFI_UNSUPPORTED
;
243 NonMmio32MaxExclTop
= 0;
244 Mmio32MinBase
= BASE_4GB
;
245 Mmio32MaxExclTop
= 0;
247 for (CurDesc
= 0; CurDesc
< NumDesc
; ++CurDesc
) {
248 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Desc
;
251 Desc
= &AllDesc
[CurDesc
];
252 ExclTop
= Desc
->BaseAddress
+ Desc
->Length
;
254 if (ExclTop
<= (UINT64
) PcdGet32 (PcdOvmfFdBaseAddress
)) {
255 switch (Desc
->GcdMemoryType
) {
256 case EfiGcdMemoryTypeNonExistent
:
259 case EfiGcdMemoryTypeReserved
:
260 case EfiGcdMemoryTypeSystemMemory
:
261 if (NonMmio32MaxExclTop
< ExclTop
) {
262 NonMmio32MaxExclTop
= ExclTop
;
266 case EfiGcdMemoryTypeMemoryMappedIo
:
267 if (Mmio32MinBase
> Desc
->BaseAddress
) {
268 Mmio32MinBase
= Desc
->BaseAddress
;
270 if (Mmio32MaxExclTop
< ExclTop
) {
271 Mmio32MaxExclTop
= ExclTop
;
281 if (Mmio32MinBase
< NonMmio32MaxExclTop
) {
282 Mmio32MinBase
= NonMmio32MaxExclTop
;
285 if (Mmio32MinBase
< Mmio32MaxExclTop
) {
286 FwData
->PciWindow32
.Base
= Mmio32MinBase
;
287 FwData
->PciWindow32
.End
= Mmio32MaxExclTop
- 1;
288 FwData
->PciWindow32
.Length
= Mmio32MaxExclTop
- Mmio32MinBase
;
290 FwData
->PciWindow64
.Base
= 0;
291 FwData
->PciWindow64
.End
= 0;
292 FwData
->PciWindow64
.Length
= 0;
294 Status
= EFI_SUCCESS
;
302 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
303 FwData
->PciWindow32
.Base
,
304 FwData
->PciWindow32
.End
,
305 FwData
->PciWindow32
.Length
309 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
310 FwData
->PciWindow64
.Base
,
311 FwData
->PciWindow64
.End
,
312 FwData
->PciWindow64
.Length
323 UINTN
*SuspendToRamSize
,
324 SYSTEM_STATE_PACKAGE
*SuspendToRam
,
325 UINTN
*SuspendToDiskSize
,
326 SYSTEM_STATE_PACKAGE
*SuspendToDisk
329 STATIC CONST SYSTEM_STATE_PACKAGE Template
= {
332 { '_', 'S', 'x', '_' }, // NameChar[4]
336 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
337 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
343 RETURN_STATUS Status
;
344 FIRMWARE_CONFIG_ITEM FwCfgItem
;
346 UINT8 SystemStates
[6];
349 // configure defaults
351 *SuspendToRamSize
= sizeof Template
;
352 CopyMem (SuspendToRam
, &Template
, sizeof Template
);
353 SuspendToRam
->NameChar
[2] = '3'; // S3
354 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
= 1; // PIIX4: STR
356 *SuspendToDiskSize
= sizeof Template
;
357 CopyMem (SuspendToDisk
, &Template
, sizeof Template
);
358 SuspendToDisk
->NameChar
[2] = '4'; // S4
359 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
= 2; // PIIX4: POSCL
362 // check for overrides
364 Status
= QemuFwCfgFindFile ("etc/system-states", &FwCfgItem
, &FwCfgSize
);
365 if (Status
!= RETURN_SUCCESS
|| FwCfgSize
!= sizeof SystemStates
) {
366 DEBUG ((DEBUG_INFO
, "ACPI using S3/S4 defaults\n"));
369 QemuFwCfgSelectItem (FwCfgItem
);
370 QemuFwCfgReadBytes (sizeof SystemStates
, SystemStates
);
373 // Each byte corresponds to a system state. In each byte, the MSB tells us
374 // whether the given state is enabled. If so, the three LSBs specify the
375 // value to be written to the PM control register's SUS_TYP bits.
377 if (SystemStates
[3] & BIT7
) {
378 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
=
379 SystemStates
[3] & (BIT2
| BIT1
| BIT0
);
380 DEBUG ((DEBUG_INFO
, "ACPI S3 value: %d\n",
381 SuspendToRam
->Pm1aCntSlpTyp
.ByteValue
));
383 *SuspendToRamSize
= 0;
384 DEBUG ((DEBUG_INFO
, "ACPI S3 disabled\n"));
387 if (SystemStates
[4] & BIT7
) {
388 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
=
389 SystemStates
[4] & (BIT2
| BIT1
| BIT0
);
390 DEBUG ((DEBUG_INFO
, "ACPI S4 value: %d\n",
391 SuspendToDisk
->Pm1aCntSlpTyp
.ByteValue
));
393 *SuspendToDiskSize
= 0;
394 DEBUG ((DEBUG_INFO
, "ACPI S4 disabled\n"));
402 QemuInstallAcpiSsdtTable (
403 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
404 IN VOID
*AcpiTableBuffer
,
405 IN UINTN AcpiTableBufferSize
,
410 FIRMWARE_DATA
*FwData
;
412 Status
= EFI_OUT_OF_RESOURCES
;
414 FwData
= AllocateReservedPool (sizeof (*FwData
));
415 if (FwData
!= NULL
) {
416 UINTN SuspendToRamSize
;
417 SYSTEM_STATE_PACKAGE SuspendToRam
;
418 UINTN SuspendToDiskSize
;
419 SYSTEM_STATE_PACKAGE SuspendToDisk
;
423 GetSuspendStates (&SuspendToRamSize
, &SuspendToRam
,
424 &SuspendToDiskSize
, &SuspendToDisk
);
425 SsdtSize
= AcpiTableBufferSize
+ 17 + SuspendToRamSize
+ SuspendToDiskSize
;
426 Ssdt
= AllocatePool (SsdtSize
);
429 Status
= PopulateFwData (FwData
);
431 if (Status
== EFI_SUCCESS
) {
436 CopyMem (SsdtPtr
, AcpiTableBuffer
, AcpiTableBufferSize
);
437 SsdtPtr
+= AcpiTableBufferSize
;
440 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
442 *(SsdtPtr
++) = 0x5B; // ExtOpPrefix
443 *(SsdtPtr
++) = 0x80; // OpRegionOp
448 *(SsdtPtr
++) = 0x00; // SystemMemory
449 *(SsdtPtr
++) = 0x0C; // DWordPrefix
452 // no virtual addressing yet, take the four least significant bytes
454 CopyMem(SsdtPtr
, &FwData
, 4);
457 *(SsdtPtr
++) = 0x0C; // DWordPrefix
459 *(UINT32
*) SsdtPtr
= sizeof (*FwData
);
463 // add suspend system states
465 CopyMem (SsdtPtr
, &SuspendToRam
, SuspendToRamSize
);
466 SsdtPtr
+= SuspendToRamSize
;
467 CopyMem (SsdtPtr
, &SuspendToDisk
, SuspendToDiskSize
);
468 SsdtPtr
+= SuspendToDiskSize
;
470 ASSERT((UINTN
) (SsdtPtr
- Ssdt
) == SsdtSize
);
471 ((EFI_ACPI_DESCRIPTION_HEADER
*) Ssdt
)->Length
= (UINT32
) SsdtSize
;
472 Status
= InstallAcpiTable (AcpiProtocol
, Ssdt
, SsdtSize
, TableKey
);
478 if (Status
!= EFI_SUCCESS
) {
489 QemuInstallAcpiTable (
490 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
491 IN VOID
*AcpiTableBuffer
,
492 IN UINTN AcpiTableBufferSize
,
496 EFI_ACPI_DESCRIPTION_HEADER
*Hdr
;
497 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction
;
499 Hdr
= (EFI_ACPI_DESCRIPTION_HEADER
*) AcpiTableBuffer
;
500 switch (Hdr
->Signature
) {
501 case EFI_ACPI_1_0_APIC_SIGNATURE
:
502 TableInstallFunction
= QemuInstallAcpiMadtTable
;
504 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
505 TableInstallFunction
= QemuInstallAcpiSsdtTable
;
508 TableInstallFunction
= InstallAcpiTable
;
511 return TableInstallFunction (