]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiPlatformDxe/Qemu.c
OvmfPkg: generate full MADT dynamically, synchronize contents with qemu
[mirror_edk2.git] / OvmfPkg / AcpiPlatformDxe / Qemu.c
1 /** @file
2 OVMF ACPI QEMU support
3
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
9
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.
12
13 **/
14
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>
22
23 BOOLEAN
24 QemuDetected (
25 VOID
26 )
27 {
28 if (!QemuFwCfgIsAvailable ()) {
29 return FALSE;
30 }
31
32 return TRUE;
33 }
34
35
36 STATIC
37 UINTN
38 CountBits16 (
39 UINT16 Mask
40 )
41 {
42 //
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.
47 //
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);
52
53 return Mask;
54 }
55
56
57 STATIC
58 EFI_STATUS
59 EFIAPI
60 QemuInstallAcpiMadtTable (
61 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
62 IN VOID *AcpiTableBuffer,
63 IN UINTN AcpiTableBufferSize,
64 OUT UINTN *TableKey
65 )
66 {
67 UINTN CpuCount;
68 UINTN PciLinkIsoCount;
69 UINTN NewBufferSize;
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;
75 VOID *Ptr;
76 UINTN Loop;
77 EFI_STATUS Status;
78
79 ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
80
81 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
82 CpuCount = QemuFwCfgRead16 ();
83 ASSERT (CpuCount >= 1);
84
85 //
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.
89 //
90 PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
91
92 NewBufferSize = 1 * sizeof (*Madt) +
93 CpuCount * sizeof (*LocalApic) +
94 1 * sizeof (*IoApic) +
95 (1 + PciLinkIsoCount) * sizeof (*Iso) +
96 1 * sizeof (*LocalApicNmi);
97
98 Madt = AllocatePool (NewBufferSize);
99 if (Madt == NULL) {
100 return EFI_OUT_OF_RESOURCES;
101 }
102
103 Madt->Header = *(EFI_ACPI_DESCRIPTION_HEADER *) AcpiTableBuffer;
104 Madt->Header.Length = NewBufferSize;
105 Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
106 Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT;
107 Ptr = Madt + 1;
108
109 LocalApic = Ptr;
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 = Loop;
114 LocalApic->ApicId = Loop;
115 LocalApic->Flags = 1; // enabled
116 ++LocalApic;
117 }
118 Ptr = LocalApic;
119
120 IoApic = Ptr;
121 IoApic->Type = EFI_ACPI_1_0_IO_APIC;
122 IoApic->Length = sizeof (*IoApic);
123 IoApic->IoApicId = CpuCount;
124 IoApic->Reserved = EFI_ACPI_RESERVED_BYTE;
125 IoApic->IoApicAddress = 0xFEC00000;
126 IoApic->SystemVectorBase = 0x00000000;
127 Ptr = IoApic + 1;
128
129 //
130 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
131 //
132 Iso = Ptr;
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
139 ++Iso;
140
141 //
142 // Set Level-tiggered, Active High for all possible PCI link targets.
143 //
144 for (Loop = 0; Loop < 16; ++Loop) {
145 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
146 continue;
147 }
148 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
149 Iso->Length = sizeof (*Iso);
150 Iso->Bus = 0x00; // ISA
151 Iso->Source = Loop;
152 Iso->GlobalSystemInterruptVector = Loop;
153 Iso->Flags = 0x000D; // Level-tiggered, Active High
154 ++Iso;
155 }
156 ASSERT (
157 Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr ==
158 1 + PciLinkIsoCount
159 );
160 Ptr = Iso;
161
162 LocalApicNmi = Ptr;
163 LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI;
164 LocalApicNmi->Length = sizeof (*LocalApicNmi);
165 LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
166 //
167 // polarity and trigger mode of the APIC I/O input signals conform to the
168 // specifications of the bus
169 //
170 LocalApicNmi->Flags = 0x0000;
171 //
172 // Local APIC interrupt input LINTn to which NMI is connected.
173 //
174 LocalApicNmi->LocalApicInti = 0x01;
175 Ptr = LocalApicNmi + 1;
176
177 ASSERT ((UINT8 *)Ptr - (UINT8 *)Madt == NewBufferSize);
178 Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
179
180 FreePool (Madt);
181
182 return Status;
183 }
184
185
186 #pragma pack(1)
187
188 typedef struct {
189 UINT64 Base;
190 UINT64 End;
191 UINT64 Length;
192 } PCI_WINDOW;
193
194 typedef struct {
195 PCI_WINDOW PciWindow32;
196 PCI_WINDOW PciWindow64;
197 } FIRMWARE_DATA;
198
199 #pragma pack()
200
201
202 STATIC
203 EFI_STATUS
204 EFIAPI
205 PopulateFwData(
206 OUT FIRMWARE_DATA *FwData
207 )
208 {
209 EFI_STATUS Status;
210 UINTN NumDesc;
211 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
212
213 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
214 if (Status == EFI_SUCCESS) {
215 UINT64 NonMmio32MaxExclTop;
216 UINT64 Mmio32MinBase;
217 UINT64 Mmio32MaxExclTop;
218 UINTN CurDesc;
219
220 Status = EFI_UNSUPPORTED;
221
222 NonMmio32MaxExclTop = 0;
223 Mmio32MinBase = BASE_4GB;
224 Mmio32MaxExclTop = 0;
225
226 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
227 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
228 UINT64 ExclTop;
229
230 Desc = &AllDesc[CurDesc];
231 ExclTop = Desc->BaseAddress + Desc->Length;
232
233 if (ExclTop <= BASE_4GB) {
234 switch (Desc->GcdMemoryType) {
235 case EfiGcdMemoryTypeNonExistent:
236 break;
237
238 case EfiGcdMemoryTypeReserved:
239 case EfiGcdMemoryTypeSystemMemory:
240 if (NonMmio32MaxExclTop < ExclTop) {
241 NonMmio32MaxExclTop = ExclTop;
242 }
243 break;
244
245 case EfiGcdMemoryTypeMemoryMappedIo:
246 if (Mmio32MinBase > Desc->BaseAddress) {
247 Mmio32MinBase = Desc->BaseAddress;
248 }
249 if (Mmio32MaxExclTop < ExclTop) {
250 Mmio32MaxExclTop = ExclTop;
251 }
252 break;
253
254 default:
255 ASSERT(0);
256 }
257 }
258 }
259
260 if (Mmio32MinBase < NonMmio32MaxExclTop) {
261 Mmio32MinBase = NonMmio32MaxExclTop;
262 }
263
264 if (Mmio32MinBase < Mmio32MaxExclTop) {
265 FwData->PciWindow32.Base = Mmio32MinBase;
266 FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
267 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
268
269 FwData->PciWindow64.Base = 0;
270 FwData->PciWindow64.End = 0;
271 FwData->PciWindow64.Length = 0;
272
273 Status = EFI_SUCCESS;
274 }
275
276 FreePool (AllDesc);
277 }
278
279 DEBUG ((
280 DEBUG_INFO,
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
285 ));
286 DEBUG ((
287 DEBUG_INFO,
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
292 ));
293
294 return Status;
295 }
296
297
298 STATIC
299 EFI_STATUS
300 EFIAPI
301 QemuInstallAcpiSsdtTable (
302 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
303 IN VOID *AcpiTableBuffer,
304 IN UINTN AcpiTableBufferSize,
305 OUT UINTN *TableKey
306 )
307 {
308 EFI_STATUS Status;
309 FIRMWARE_DATA *FwData;
310
311 Status = EFI_OUT_OF_RESOURCES;
312
313 FwData = AllocateReservedPool (sizeof (*FwData));
314 if (FwData != NULL) {
315 UINTN SsdtSize;
316 UINT8 *Ssdt;
317
318 SsdtSize = AcpiTableBufferSize + 17;
319 Ssdt = AllocatePool (SsdtSize);
320
321 if (Ssdt != NULL) {
322 Status = PopulateFwData (FwData);
323
324 if (Status == EFI_SUCCESS) {
325 UINT8 *SsdtPtr;
326
327 SsdtPtr = Ssdt;
328
329 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
330 SsdtPtr += AcpiTableBufferSize;
331
332 //
333 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
334 //
335 *(SsdtPtr++) = 0x5B; // ExtOpPrefix
336 *(SsdtPtr++) = 0x80; // OpRegionOp
337 *(SsdtPtr++) = 'F';
338 *(SsdtPtr++) = 'W';
339 *(SsdtPtr++) = 'D';
340 *(SsdtPtr++) = 'T';
341 *(SsdtPtr++) = 0x00; // SystemMemory
342 *(SsdtPtr++) = 0x0C; // DWordPrefix
343
344 //
345 // no virtual addressing yet, take the four least significant bytes
346 //
347 CopyMem(SsdtPtr, &FwData, 4);
348 SsdtPtr += 4;
349
350 *(SsdtPtr++) = 0x0C; // DWordPrefix
351
352 *(UINT32*) SsdtPtr = sizeof (*FwData);
353 SsdtPtr += 4;
354
355 ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
356 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
357 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
358 }
359
360 FreePool(Ssdt);
361 }
362
363 if (Status != EFI_SUCCESS) {
364 FreePool(FwData);
365 }
366 }
367
368 return Status;
369 }
370
371
372 EFI_STATUS
373 EFIAPI
374 QemuInstallAcpiTable (
375 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
376 IN VOID *AcpiTableBuffer,
377 IN UINTN AcpiTableBufferSize,
378 OUT UINTN *TableKey
379 )
380 {
381 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
382 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
383
384 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
385 switch (Hdr->Signature) {
386 case EFI_ACPI_1_0_APIC_SIGNATURE:
387 TableInstallFunction = QemuInstallAcpiMadtTable;
388 break;
389 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
390 TableInstallFunction = QemuInstallAcpiSsdtTable;
391 break;
392 default:
393 TableInstallFunction = InstallAcpiTable;
394 }
395
396 return TableInstallFunction (
397 AcpiProtocol,
398 AcpiTableBuffer,
399 AcpiTableBufferSize,
400 TableKey
401 );
402 }
403