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
;
213 } SYSTEM_STATE_PACKAGE
;
222 OUT FIRMWARE_DATA
*FwData
227 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*AllDesc
;
229 Status
= gDS
->GetMemorySpaceMap (&NumDesc
, &AllDesc
);
230 if (Status
== EFI_SUCCESS
) {
231 UINT64 NonMmio32MaxExclTop
;
232 UINT64 Mmio32MinBase
;
233 UINT64 Mmio32MaxExclTop
;
236 Status
= EFI_UNSUPPORTED
;
238 NonMmio32MaxExclTop
= 0;
239 Mmio32MinBase
= BASE_4GB
;
240 Mmio32MaxExclTop
= 0;
242 for (CurDesc
= 0; CurDesc
< NumDesc
; ++CurDesc
) {
243 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Desc
;
246 Desc
= &AllDesc
[CurDesc
];
247 ExclTop
= Desc
->BaseAddress
+ Desc
->Length
;
249 if (ExclTop
<= BASE_4GB
) {
250 switch (Desc
->GcdMemoryType
) {
251 case EfiGcdMemoryTypeNonExistent
:
254 case EfiGcdMemoryTypeReserved
:
255 case EfiGcdMemoryTypeSystemMemory
:
256 if (NonMmio32MaxExclTop
< ExclTop
) {
257 NonMmio32MaxExclTop
= ExclTop
;
261 case EfiGcdMemoryTypeMemoryMappedIo
:
262 if (Mmio32MinBase
> Desc
->BaseAddress
) {
263 Mmio32MinBase
= Desc
->BaseAddress
;
265 if (Mmio32MaxExclTop
< ExclTop
) {
266 Mmio32MaxExclTop
= ExclTop
;
276 if (Mmio32MinBase
< NonMmio32MaxExclTop
) {
277 Mmio32MinBase
= NonMmio32MaxExclTop
;
280 if (Mmio32MinBase
< Mmio32MaxExclTop
) {
281 FwData
->PciWindow32
.Base
= Mmio32MinBase
;
282 FwData
->PciWindow32
.End
= Mmio32MaxExclTop
- 1;
283 FwData
->PciWindow32
.Length
= Mmio32MaxExclTop
- Mmio32MinBase
;
285 FwData
->PciWindow64
.Base
= 0;
286 FwData
->PciWindow64
.End
= 0;
287 FwData
->PciWindow64
.Length
= 0;
289 Status
= EFI_SUCCESS
;
297 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
298 FwData
->PciWindow32
.Base
,
299 FwData
->PciWindow32
.End
,
300 FwData
->PciWindow32
.Length
304 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
305 FwData
->PciWindow64
.Base
,
306 FwData
->PciWindow64
.End
,
307 FwData
->PciWindow64
.Length
318 UINTN
*SuspendToRamSize
,
319 SYSTEM_STATE_PACKAGE
*SuspendToRam
,
320 UINTN
*SuspendToDiskSize
,
321 SYSTEM_STATE_PACKAGE
*SuspendToDisk
324 STATIC CONST SYSTEM_STATE_PACKAGE Template
= {
327 { '_', 'S', 'x', '_' }, // NameChar[4]
332 0x00, // Pm1aCntSlpTyp
333 0x00, // Pm1bCntSlpTyp -- we don't support it
334 { 0x00, 0x00 } // Reserved
336 RETURN_STATUS Status
;
337 FIRMWARE_CONFIG_ITEM FwCfgItem
;
339 UINT8 SystemStates
[6];
342 // configure defaults
344 *SuspendToRamSize
= sizeof Template
;
345 CopyMem (SuspendToRam
, &Template
, sizeof Template
);
346 SuspendToRam
->NameChar
[2] = '3'; // S3
347 SuspendToRam
->Pm1aCntSlpTyp
= 1; // PIIX4: STR
349 *SuspendToDiskSize
= sizeof Template
;
350 CopyMem (SuspendToDisk
, &Template
, sizeof Template
);
351 SuspendToDisk
->NameChar
[2] = '4'; // S4
352 SuspendToDisk
->Pm1aCntSlpTyp
= 2; // PIIX4: POSCL
355 // check for overrides
357 Status
= QemuFwCfgFindFile ("etc/system-states", &FwCfgItem
, &FwCfgSize
);
358 if (Status
!= RETURN_SUCCESS
|| FwCfgSize
!= sizeof SystemStates
) {
359 DEBUG ((DEBUG_INFO
, "ACPI using S3/S4 defaults\n"));
362 QemuFwCfgSelectItem (FwCfgItem
);
363 QemuFwCfgReadBytes (sizeof SystemStates
, SystemStates
);
366 // Each byte corresponds to a system state. In each byte, the MSB tells us
367 // whether the given state is enabled. If so, the three LSBs specify the
368 // value to be written to the PM control register's SUS_TYP bits.
370 if (SystemStates
[3] & BIT7
) {
371 SuspendToRam
->Pm1aCntSlpTyp
= SystemStates
[3] & (BIT2
| BIT1
| BIT0
);
372 DEBUG ((DEBUG_INFO
, "ACPI S3 value: %d\n", SuspendToRam
->Pm1aCntSlpTyp
));
374 *SuspendToRamSize
= 0;
375 DEBUG ((DEBUG_INFO
, "ACPI S3 disabled\n"));
378 if (SystemStates
[4] & BIT7
) {
379 SuspendToDisk
->Pm1aCntSlpTyp
= SystemStates
[4] & (BIT2
| BIT1
| BIT0
);
380 DEBUG ((DEBUG_INFO
, "ACPI S4 value: %d\n", SuspendToDisk
->Pm1aCntSlpTyp
));
382 *SuspendToDiskSize
= 0;
383 DEBUG ((DEBUG_INFO
, "ACPI S4 disabled\n"));
391 QemuInstallAcpiSsdtTable (
392 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
393 IN VOID
*AcpiTableBuffer
,
394 IN UINTN AcpiTableBufferSize
,
399 FIRMWARE_DATA
*FwData
;
401 Status
= EFI_OUT_OF_RESOURCES
;
403 FwData
= AllocateReservedPool (sizeof (*FwData
));
404 if (FwData
!= NULL
) {
405 UINTN SuspendToRamSize
;
406 SYSTEM_STATE_PACKAGE SuspendToRam
;
407 UINTN SuspendToDiskSize
;
408 SYSTEM_STATE_PACKAGE SuspendToDisk
;
412 GetSuspendStates (&SuspendToRamSize
, &SuspendToRam
,
413 &SuspendToDiskSize
, &SuspendToDisk
);
414 SsdtSize
= AcpiTableBufferSize
+ 17 + SuspendToRamSize
+ SuspendToDiskSize
;
415 Ssdt
= AllocatePool (SsdtSize
);
418 Status
= PopulateFwData (FwData
);
420 if (Status
== EFI_SUCCESS
) {
425 CopyMem (SsdtPtr
, AcpiTableBuffer
, AcpiTableBufferSize
);
426 SsdtPtr
+= AcpiTableBufferSize
;
429 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
431 *(SsdtPtr
++) = 0x5B; // ExtOpPrefix
432 *(SsdtPtr
++) = 0x80; // OpRegionOp
437 *(SsdtPtr
++) = 0x00; // SystemMemory
438 *(SsdtPtr
++) = 0x0C; // DWordPrefix
441 // no virtual addressing yet, take the four least significant bytes
443 CopyMem(SsdtPtr
, &FwData
, 4);
446 *(SsdtPtr
++) = 0x0C; // DWordPrefix
448 *(UINT32
*) SsdtPtr
= sizeof (*FwData
);
452 // add suspend system states
454 CopyMem (SsdtPtr
, &SuspendToRam
, SuspendToRamSize
);
455 SsdtPtr
+= SuspendToRamSize
;
456 CopyMem (SsdtPtr
, &SuspendToDisk
, SuspendToDiskSize
);
457 SsdtPtr
+= SuspendToDiskSize
;
459 ASSERT((UINTN
) (SsdtPtr
- Ssdt
) == SsdtSize
);
460 ((EFI_ACPI_DESCRIPTION_HEADER
*) Ssdt
)->Length
= (UINT32
) SsdtSize
;
461 Status
= InstallAcpiTable (AcpiProtocol
, Ssdt
, SsdtSize
, TableKey
);
467 if (Status
!= EFI_SUCCESS
) {
478 QemuInstallAcpiTable (
479 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
480 IN VOID
*AcpiTableBuffer
,
481 IN UINTN AcpiTableBufferSize
,
485 EFI_ACPI_DESCRIPTION_HEADER
*Hdr
;
486 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction
;
488 Hdr
= (EFI_ACPI_DESCRIPTION_HEADER
*) AcpiTableBuffer
;
489 switch (Hdr
->Signature
) {
490 case EFI_ACPI_1_0_APIC_SIGNATURE
:
491 TableInstallFunction
= QemuInstallAcpiMadtTable
;
493 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
494 TableInstallFunction
= QemuInstallAcpiSsdtTable
;
497 TableInstallFunction
= InstallAcpiTable
;
500 return TableInstallFunction (