]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiPlatformDxe/Qemu.c
90f06bba6399427af9bb8028efa3a2503a982cfd
[mirror_edk2.git] / OvmfPkg / AcpiPlatformDxe / Qemu.c
1 /** @file
2 OVMF ACPI QEMU support
3
4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
5
6 Copyright (C) 2012-2014, Red Hat, Inc.
7
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
12
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.
15
16 **/
17
18 #include "AcpiPlatform.h"
19 #include "QemuLoader.h"
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/QemuFwCfgLib.h>
23 #include <Library/DxeServicesTableLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/OrderedCollectionLib.h>
26 #include <IndustryStandard/Acpi.h>
27
28 BOOLEAN
29 QemuDetected (
30 VOID
31 )
32 {
33 if (!QemuFwCfgIsAvailable ()) {
34 return FALSE;
35 }
36
37 return TRUE;
38 }
39
40
41 STATIC
42 UINTN
43 CountBits16 (
44 UINT16 Mask
45 )
46 {
47 //
48 // For all N >= 1, N bits are enough to represent the number of bits set
49 // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
50 // the maximum number of possibly set bits increases by one, while the
51 // representable maximum doubles.
52 //
53 Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555);
54 Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333);
55 Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F);
56 Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF);
57
58 return Mask;
59 }
60
61
62 STATIC
63 EFI_STATUS
64 EFIAPI
65 QemuInstallAcpiMadtTable (
66 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
67 IN VOID *AcpiTableBuffer,
68 IN UINTN AcpiTableBufferSize,
69 OUT UINTN *TableKey
70 )
71 {
72 UINTN CpuCount;
73 UINTN PciLinkIsoCount;
74 UINTN NewBufferSize;
75 EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
76 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
77 EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic;
78 EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso;
79 EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmi;
80 VOID *Ptr;
81 UINTN Loop;
82 EFI_STATUS Status;
83
84 ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
85
86 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
87 CpuCount = QemuFwCfgRead16 ();
88 ASSERT (CpuCount >= 1);
89
90 //
91 // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
92 // corresponds to the union of all possible interrupt assignments for the LNKA,
93 // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
94 //
95 PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
96
97 NewBufferSize = 1 * sizeof (*Madt) +
98 CpuCount * sizeof (*LocalApic) +
99 1 * sizeof (*IoApic) +
100 (1 + PciLinkIsoCount) * sizeof (*Iso) +
101 1 * sizeof (*LocalApicNmi);
102
103 Madt = AllocatePool (NewBufferSize);
104 if (Madt == NULL) {
105 return EFI_OUT_OF_RESOURCES;
106 }
107
108 CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
109 Madt->Header.Length = (UINT32) NewBufferSize;
110 Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
111 Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT;
112 Ptr = Madt + 1;
113
114 LocalApic = Ptr;
115 for (Loop = 0; Loop < CpuCount; ++Loop) {
116 LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
117 LocalApic->Length = sizeof (*LocalApic);
118 LocalApic->AcpiProcessorId = (UINT8) Loop;
119 LocalApic->ApicId = (UINT8) Loop;
120 LocalApic->Flags = 1; // enabled
121 ++LocalApic;
122 }
123 Ptr = LocalApic;
124
125 IoApic = Ptr;
126 IoApic->Type = EFI_ACPI_1_0_IO_APIC;
127 IoApic->Length = sizeof (*IoApic);
128 IoApic->IoApicId = (UINT8) CpuCount;
129 IoApic->Reserved = EFI_ACPI_RESERVED_BYTE;
130 IoApic->IoApicAddress = 0xFEC00000;
131 IoApic->SystemVectorBase = 0x00000000;
132 Ptr = IoApic + 1;
133
134 //
135 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
136 //
137 Iso = Ptr;
138 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
139 Iso->Length = sizeof (*Iso);
140 Iso->Bus = 0x00; // ISA
141 Iso->Source = 0x00; // IRQ0
142 Iso->GlobalSystemInterruptVector = 0x00000002;
143 Iso->Flags = 0x0000; // Conforms to specs of the bus
144 ++Iso;
145
146 //
147 // Set Level-tiggered, Active High for all possible PCI link targets.
148 //
149 for (Loop = 0; Loop < 16; ++Loop) {
150 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
151 continue;
152 }
153 Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
154 Iso->Length = sizeof (*Iso);
155 Iso->Bus = 0x00; // ISA
156 Iso->Source = (UINT8) Loop;
157 Iso->GlobalSystemInterruptVector = (UINT32) Loop;
158 Iso->Flags = 0x000D; // Level-tiggered, Active High
159 ++Iso;
160 }
161 ASSERT (
162 (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
163 1 + PciLinkIsoCount
164 );
165 Ptr = Iso;
166
167 LocalApicNmi = Ptr;
168 LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI;
169 LocalApicNmi->Length = sizeof (*LocalApicNmi);
170 LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
171 //
172 // polarity and trigger mode of the APIC I/O input signals conform to the
173 // specifications of the bus
174 //
175 LocalApicNmi->Flags = 0x0000;
176 //
177 // Local APIC interrupt input LINTn to which NMI is connected.
178 //
179 LocalApicNmi->LocalApicInti = 0x01;
180 Ptr = LocalApicNmi + 1;
181
182 ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
183 Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
184
185 FreePool (Madt);
186
187 return Status;
188 }
189
190
191 #pragma pack(1)
192
193 typedef struct {
194 UINT64 Base;
195 UINT64 End;
196 UINT64 Length;
197 } PCI_WINDOW;
198
199 typedef struct {
200 PCI_WINDOW PciWindow32;
201 PCI_WINDOW PciWindow64;
202 } FIRMWARE_DATA;
203
204 typedef struct {
205 UINT8 BytePrefix;
206 UINT8 ByteValue;
207 } AML_BYTE;
208
209 typedef struct {
210 UINT8 NameOp;
211 UINT8 RootChar;
212 UINT8 NameChar[4];
213 UINT8 PackageOp;
214 UINT8 PkgLength;
215 UINT8 NumElements;
216 AML_BYTE Pm1aCntSlpTyp;
217 AML_BYTE Pm1bCntSlpTyp;
218 AML_BYTE Reserved[2];
219 } SYSTEM_STATE_PACKAGE;
220
221 #pragma pack()
222
223
224 STATIC
225 EFI_STATUS
226 EFIAPI
227 PopulateFwData(
228 OUT FIRMWARE_DATA *FwData
229 )
230 {
231 EFI_STATUS Status;
232 UINTN NumDesc;
233 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
234
235 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
236 if (Status == EFI_SUCCESS) {
237 UINT64 NonMmio32MaxExclTop;
238 UINT64 Mmio32MinBase;
239 UINT64 Mmio32MaxExclTop;
240 UINTN CurDesc;
241
242 Status = EFI_UNSUPPORTED;
243
244 NonMmio32MaxExclTop = 0;
245 Mmio32MinBase = BASE_4GB;
246 Mmio32MaxExclTop = 0;
247
248 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
249 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
250 UINT64 ExclTop;
251
252 Desc = &AllDesc[CurDesc];
253 ExclTop = Desc->BaseAddress + Desc->Length;
254
255 if (ExclTop <= (UINT64) PcdGet32 (PcdOvmfFdBaseAddress)) {
256 switch (Desc->GcdMemoryType) {
257 case EfiGcdMemoryTypeNonExistent:
258 break;
259
260 case EfiGcdMemoryTypeReserved:
261 case EfiGcdMemoryTypeSystemMemory:
262 if (NonMmio32MaxExclTop < ExclTop) {
263 NonMmio32MaxExclTop = ExclTop;
264 }
265 break;
266
267 case EfiGcdMemoryTypeMemoryMappedIo:
268 if (Mmio32MinBase > Desc->BaseAddress) {
269 Mmio32MinBase = Desc->BaseAddress;
270 }
271 if (Mmio32MaxExclTop < ExclTop) {
272 Mmio32MaxExclTop = ExclTop;
273 }
274 break;
275
276 default:
277 ASSERT(0);
278 }
279 }
280 }
281
282 if (Mmio32MinBase < NonMmio32MaxExclTop) {
283 Mmio32MinBase = NonMmio32MaxExclTop;
284 }
285
286 if (Mmio32MinBase < Mmio32MaxExclTop) {
287 FwData->PciWindow32.Base = Mmio32MinBase;
288 FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
289 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
290
291 FwData->PciWindow64.Base = 0;
292 FwData->PciWindow64.End = 0;
293 FwData->PciWindow64.Length = 0;
294
295 Status = EFI_SUCCESS;
296 }
297
298 FreePool (AllDesc);
299 }
300
301 DEBUG ((
302 DEBUG_INFO,
303 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
304 FwData->PciWindow32.Base,
305 FwData->PciWindow32.End,
306 FwData->PciWindow32.Length
307 ));
308 DEBUG ((
309 DEBUG_INFO,
310 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
311 FwData->PciWindow64.Base,
312 FwData->PciWindow64.End,
313 FwData->PciWindow64.Length
314 ));
315
316 return Status;
317 }
318
319
320 STATIC
321 VOID
322 EFIAPI
323 GetSuspendStates (
324 UINTN *SuspendToRamSize,
325 SYSTEM_STATE_PACKAGE *SuspendToRam,
326 UINTN *SuspendToDiskSize,
327 SYSTEM_STATE_PACKAGE *SuspendToDisk
328 )
329 {
330 STATIC CONST SYSTEM_STATE_PACKAGE Template = {
331 0x08, // NameOp
332 '\\', // RootChar
333 { '_', 'S', 'x', '_' }, // NameChar[4]
334 0x12, // PackageOp
335 0x0A, // PkgLength
336 0x04, // NumElements
337 { 0x0A, 0x00 }, // Pm1aCntSlpTyp
338 { 0x0A, 0x00 }, // Pm1bCntSlpTyp -- we don't support it
339 { // Reserved[2]
340 { 0x0A, 0x00 },
341 { 0x0A, 0x00 }
342 }
343 };
344 RETURN_STATUS Status;
345 FIRMWARE_CONFIG_ITEM FwCfgItem;
346 UINTN FwCfgSize;
347 UINT8 SystemStates[6];
348
349 //
350 // configure defaults
351 //
352 *SuspendToRamSize = sizeof Template;
353 CopyMem (SuspendToRam, &Template, sizeof Template);
354 SuspendToRam->NameChar[2] = '3'; // S3
355 SuspendToRam->Pm1aCntSlpTyp.ByteValue = 1; // PIIX4: STR
356
357 *SuspendToDiskSize = sizeof Template;
358 CopyMem (SuspendToDisk, &Template, sizeof Template);
359 SuspendToDisk->NameChar[2] = '4'; // S4
360 SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 2; // PIIX4: POSCL
361
362 //
363 // check for overrides
364 //
365 Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
366 if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
367 DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
368 return;
369 }
370 QemuFwCfgSelectItem (FwCfgItem);
371 QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
372
373 //
374 // Each byte corresponds to a system state. In each byte, the MSB tells us
375 // whether the given state is enabled. If so, the three LSBs specify the
376 // value to be written to the PM control register's SUS_TYP bits.
377 //
378 if (SystemStates[3] & BIT7) {
379 SuspendToRam->Pm1aCntSlpTyp.ByteValue =
380 SystemStates[3] & (BIT2 | BIT1 | BIT0);
381 DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n",
382 SuspendToRam->Pm1aCntSlpTyp.ByteValue));
383 } else {
384 *SuspendToRamSize = 0;
385 DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n"));
386 }
387
388 if (SystemStates[4] & BIT7) {
389 SuspendToDisk->Pm1aCntSlpTyp.ByteValue =
390 SystemStates[4] & (BIT2 | BIT1 | BIT0);
391 DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n",
392 SuspendToDisk->Pm1aCntSlpTyp.ByteValue));
393 } else {
394 *SuspendToDiskSize = 0;
395 DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n"));
396 }
397 }
398
399
400 STATIC
401 EFI_STATUS
402 EFIAPI
403 QemuInstallAcpiSsdtTable (
404 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
405 IN VOID *AcpiTableBuffer,
406 IN UINTN AcpiTableBufferSize,
407 OUT UINTN *TableKey
408 )
409 {
410 EFI_STATUS Status;
411 FIRMWARE_DATA *FwData;
412
413 Status = EFI_OUT_OF_RESOURCES;
414
415 FwData = AllocateReservedPool (sizeof (*FwData));
416 if (FwData != NULL) {
417 UINTN SuspendToRamSize;
418 SYSTEM_STATE_PACKAGE SuspendToRam;
419 UINTN SuspendToDiskSize;
420 SYSTEM_STATE_PACKAGE SuspendToDisk;
421 UINTN SsdtSize;
422 UINT8 *Ssdt;
423
424 GetSuspendStates (&SuspendToRamSize, &SuspendToRam,
425 &SuspendToDiskSize, &SuspendToDisk);
426 SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize;
427 Ssdt = AllocatePool (SsdtSize);
428
429 if (Ssdt != NULL) {
430 Status = PopulateFwData (FwData);
431
432 if (Status == EFI_SUCCESS) {
433 UINT8 *SsdtPtr;
434
435 SsdtPtr = Ssdt;
436
437 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
438 SsdtPtr += AcpiTableBufferSize;
439
440 //
441 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
442 //
443 *(SsdtPtr++) = 0x5B; // ExtOpPrefix
444 *(SsdtPtr++) = 0x80; // OpRegionOp
445 *(SsdtPtr++) = 'F';
446 *(SsdtPtr++) = 'W';
447 *(SsdtPtr++) = 'D';
448 *(SsdtPtr++) = 'T';
449 *(SsdtPtr++) = 0x00; // SystemMemory
450 *(SsdtPtr++) = 0x0C; // DWordPrefix
451
452 //
453 // no virtual addressing yet, take the four least significant bytes
454 //
455 CopyMem(SsdtPtr, &FwData, 4);
456 SsdtPtr += 4;
457
458 *(SsdtPtr++) = 0x0C; // DWordPrefix
459
460 *(UINT32*) SsdtPtr = sizeof (*FwData);
461 SsdtPtr += 4;
462
463 //
464 // add suspend system states
465 //
466 CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize);
467 SsdtPtr += SuspendToRamSize;
468 CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize);
469 SsdtPtr += SuspendToDiskSize;
470
471 ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
472 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
473 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
474 }
475
476 FreePool(Ssdt);
477 }
478
479 if (Status != EFI_SUCCESS) {
480 FreePool(FwData);
481 }
482 }
483
484 return Status;
485 }
486
487
488 EFI_STATUS
489 EFIAPI
490 QemuInstallAcpiTable (
491 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
492 IN VOID *AcpiTableBuffer,
493 IN UINTN AcpiTableBufferSize,
494 OUT UINTN *TableKey
495 )
496 {
497 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
498 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
499
500 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
501 switch (Hdr->Signature) {
502 case EFI_ACPI_1_0_APIC_SIGNATURE:
503 TableInstallFunction = QemuInstallAcpiMadtTable;
504 break;
505 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
506 TableInstallFunction = QemuInstallAcpiSsdtTable;
507 break;
508 default:
509 TableInstallFunction = InstallAcpiTable;
510 }
511
512 return TableInstallFunction (
513 AcpiProtocol,
514 AcpiTableBuffer,
515 AcpiTableBufferSize,
516 TableKey
517 );
518 }