4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "AcpiPlatform.h"
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/QemuFwCfgLib.h>
19 #include <Library/DxeServicesTableLib.h>
20 #include <Library/PcdLib.h>
21 #include <IndustryStandard/Acpi.h>
28 if (!QemuFwCfgIsAvailable ()) {
43 // For all N >= 1, N bits are enough to represent the number of bits set
44 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
45 // the maximum number of possibly set bits increases by one, while the
46 // representable maximum doubles.
48 Mask
= ((Mask
& 0xAAAA) >> 1) + (Mask
& 0x5555);
49 Mask
= ((Mask
& 0xCCCC) >> 2) + (Mask
& 0x3333);
50 Mask
= ((Mask
& 0xF0F0) >> 4) + (Mask
& 0x0F0F);
51 Mask
= ((Mask
& 0xFF00) >> 8) + (Mask
& 0x00FF);
60 QemuInstallAcpiMadtTable (
61 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
62 IN VOID
*AcpiTableBuffer
,
63 IN UINTN AcpiTableBufferSize
,
68 UINTN PciLinkIsoCount
;
70 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER
*Madt
;
71 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE
*LocalApic
;
72 EFI_ACPI_1_0_IO_APIC_STRUCTURE
*IoApic
;
73 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*Iso
;
74 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE
*LocalApicNmi
;
79 ASSERT (AcpiTableBufferSize
>= sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
81 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount
);
82 CpuCount
= QemuFwCfgRead16 ();
83 ASSERT (CpuCount
>= 1);
86 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
87 // corresponds to the union of all possible interrupt assignments for the LNKA,
88 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
90 PciLinkIsoCount
= CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel
));
92 NewBufferSize
= 1 * sizeof (*Madt
) +
93 CpuCount
* sizeof (*LocalApic
) +
94 1 * sizeof (*IoApic
) +
95 (1 + PciLinkIsoCount
) * sizeof (*Iso
) +
96 1 * sizeof (*LocalApicNmi
);
98 Madt
= AllocatePool (NewBufferSize
);
100 return EFI_OUT_OF_RESOURCES
;
103 CopyMem (&(Madt
->Header
), AcpiTableBuffer
, sizeof (EFI_ACPI_DESCRIPTION_HEADER
));
104 Madt
->Header
.Length
= (UINT32
) NewBufferSize
;
105 Madt
->LocalApicAddress
= PcdGet32 (PcdCpuLocalApicBaseAddress
);
106 Madt
->Flags
= EFI_ACPI_1_0_PCAT_COMPAT
;
110 for (Loop
= 0; Loop
< CpuCount
; ++Loop
) {
111 LocalApic
->Type
= EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC
;
112 LocalApic
->Length
= sizeof (*LocalApic
);
113 LocalApic
->AcpiProcessorId
= (UINT8
) Loop
;
114 LocalApic
->ApicId
= (UINT8
) Loop
;
115 LocalApic
->Flags
= 1; // enabled
121 IoApic
->Type
= EFI_ACPI_1_0_IO_APIC
;
122 IoApic
->Length
= sizeof (*IoApic
);
123 IoApic
->IoApicId
= (UINT8
) CpuCount
;
124 IoApic
->Reserved
= EFI_ACPI_RESERVED_BYTE
;
125 IoApic
->IoApicAddress
= 0xFEC00000;
126 IoApic
->SystemVectorBase
= 0x00000000;
130 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
133 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
134 Iso
->Length
= sizeof (*Iso
);
135 Iso
->Bus
= 0x00; // ISA
136 Iso
->Source
= 0x00; // IRQ0
137 Iso
->GlobalSystemInterruptVector
= 0x00000002;
138 Iso
->Flags
= 0x0000; // Conforms to specs of the bus
142 // Set Level-tiggered, Active High for all possible PCI link targets.
144 for (Loop
= 0; Loop
< 16; ++Loop
) {
145 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel
) & (1 << Loop
)) == 0) {
148 Iso
->Type
= EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE
;
149 Iso
->Length
= sizeof (*Iso
);
150 Iso
->Bus
= 0x00; // ISA
151 Iso
->Source
= (UINT8
) Loop
;
152 Iso
->GlobalSystemInterruptVector
= (UINT32
) Loop
;
153 Iso
->Flags
= 0x000D; // Level-tiggered, Active High
157 (UINTN
) (Iso
- (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE
*)Ptr
) ==
163 LocalApicNmi
->Type
= EFI_ACPI_1_0_LOCAL_APIC_NMI
;
164 LocalApicNmi
->Length
= sizeof (*LocalApicNmi
);
165 LocalApicNmi
->AcpiProcessorId
= 0xFF; // applies to all processors
167 // polarity and trigger mode of the APIC I/O input signals conform to the
168 // specifications of the bus
170 LocalApicNmi
->Flags
= 0x0000;
172 // Local APIC interrupt input LINTn to which NMI is connected.
174 LocalApicNmi
->LocalApicInti
= 0x01;
175 Ptr
= LocalApicNmi
+ 1;
177 ASSERT ((UINTN
) ((UINT8
*)Ptr
- (UINT8
*)Madt
) == NewBufferSize
);
178 Status
= InstallAcpiTable (AcpiProtocol
, Madt
, NewBufferSize
, TableKey
);
195 PCI_WINDOW PciWindow32
;
196 PCI_WINDOW PciWindow64
;
206 OUT FIRMWARE_DATA
*FwData
211 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*AllDesc
;
213 Status
= gDS
->GetMemorySpaceMap (&NumDesc
, &AllDesc
);
214 if (Status
== EFI_SUCCESS
) {
215 UINT64 NonMmio32MaxExclTop
;
216 UINT64 Mmio32MinBase
;
217 UINT64 Mmio32MaxExclTop
;
220 Status
= EFI_UNSUPPORTED
;
222 NonMmio32MaxExclTop
= 0;
223 Mmio32MinBase
= BASE_4GB
;
224 Mmio32MaxExclTop
= 0;
226 for (CurDesc
= 0; CurDesc
< NumDesc
; ++CurDesc
) {
227 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Desc
;
230 Desc
= &AllDesc
[CurDesc
];
231 ExclTop
= Desc
->BaseAddress
+ Desc
->Length
;
233 if (ExclTop
<= BASE_4GB
) {
234 switch (Desc
->GcdMemoryType
) {
235 case EfiGcdMemoryTypeNonExistent
:
238 case EfiGcdMemoryTypeReserved
:
239 case EfiGcdMemoryTypeSystemMemory
:
240 if (NonMmio32MaxExclTop
< ExclTop
) {
241 NonMmio32MaxExclTop
= ExclTop
;
245 case EfiGcdMemoryTypeMemoryMappedIo
:
246 if (Mmio32MinBase
> Desc
->BaseAddress
) {
247 Mmio32MinBase
= Desc
->BaseAddress
;
249 if (Mmio32MaxExclTop
< ExclTop
) {
250 Mmio32MaxExclTop
= ExclTop
;
260 if (Mmio32MinBase
< NonMmio32MaxExclTop
) {
261 Mmio32MinBase
= NonMmio32MaxExclTop
;
264 if (Mmio32MinBase
< Mmio32MaxExclTop
) {
265 FwData
->PciWindow32
.Base
= Mmio32MinBase
;
266 FwData
->PciWindow32
.End
= Mmio32MaxExclTop
- 1;
267 FwData
->PciWindow32
.Length
= Mmio32MaxExclTop
- Mmio32MinBase
;
269 FwData
->PciWindow64
.Base
= 0;
270 FwData
->PciWindow64
.End
= 0;
271 FwData
->PciWindow64
.Length
= 0;
273 Status
= EFI_SUCCESS
;
281 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
282 FwData
->PciWindow32
.Base
,
283 FwData
->PciWindow32
.End
,
284 FwData
->PciWindow32
.Length
288 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
289 FwData
->PciWindow64
.Base
,
290 FwData
->PciWindow64
.End
,
291 FwData
->PciWindow64
.Length
301 QemuInstallAcpiSsdtTable (
302 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
303 IN VOID
*AcpiTableBuffer
,
304 IN UINTN AcpiTableBufferSize
,
309 FIRMWARE_DATA
*FwData
;
311 Status
= EFI_OUT_OF_RESOURCES
;
313 FwData
= AllocateReservedPool (sizeof (*FwData
));
314 if (FwData
!= NULL
) {
318 SsdtSize
= AcpiTableBufferSize
+ 17;
319 Ssdt
= AllocatePool (SsdtSize
);
322 Status
= PopulateFwData (FwData
);
324 if (Status
== EFI_SUCCESS
) {
329 CopyMem (SsdtPtr
, AcpiTableBuffer
, AcpiTableBufferSize
);
330 SsdtPtr
+= AcpiTableBufferSize
;
333 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
335 *(SsdtPtr
++) = 0x5B; // ExtOpPrefix
336 *(SsdtPtr
++) = 0x80; // OpRegionOp
341 *(SsdtPtr
++) = 0x00; // SystemMemory
342 *(SsdtPtr
++) = 0x0C; // DWordPrefix
345 // no virtual addressing yet, take the four least significant bytes
347 CopyMem(SsdtPtr
, &FwData
, 4);
350 *(SsdtPtr
++) = 0x0C; // DWordPrefix
352 *(UINT32
*) SsdtPtr
= sizeof (*FwData
);
355 ASSERT((UINTN
) (SsdtPtr
- Ssdt
) == SsdtSize
);
356 ((EFI_ACPI_DESCRIPTION_HEADER
*) Ssdt
)->Length
= (UINT32
) SsdtSize
;
357 Status
= InstallAcpiTable (AcpiProtocol
, Ssdt
, SsdtSize
, TableKey
);
363 if (Status
!= EFI_SUCCESS
) {
374 QemuInstallAcpiTable (
375 IN EFI_ACPI_TABLE_PROTOCOL
*AcpiProtocol
,
376 IN VOID
*AcpiTableBuffer
,
377 IN UINTN AcpiTableBufferSize
,
381 EFI_ACPI_DESCRIPTION_HEADER
*Hdr
;
382 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction
;
384 Hdr
= (EFI_ACPI_DESCRIPTION_HEADER
*) AcpiTableBuffer
;
385 switch (Hdr
->Signature
) {
386 case EFI_ACPI_1_0_APIC_SIGNATURE
:
387 TableInstallFunction
= QemuInstallAcpiMadtTable
;
389 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE
:
390 TableInstallFunction
= QemuInstallAcpiSsdtTable
;
393 TableInstallFunction
= InstallAcpiTable
;
396 return TableInstallFunction (