]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiPlatformDxe/Qemu.c
35d667fe3aca6c63edb82a882ec645dffec6f640
[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
6 Copyright (C) 2012, 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 <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>
25
26 BOOLEAN
27 QemuDetected (
28 VOID
29 )
30 {
31 if (!QemuFwCfgIsAvailable ()) {
32 return FALSE;
33 }
34
35 return TRUE;
36 }
37
38
39 STATIC
40 UINTN
41 CountBits16 (
42 UINT16 Mask
43 )
44 {
45 //
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.
50 //
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);
55
56 return Mask;
57 }
58
59
60 STATIC
61 EFI_STATUS
62 EFIAPI
63 QemuInstallAcpiMadtTable (
64 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
65 IN VOID *AcpiTableBuffer,
66 IN UINTN AcpiTableBufferSize,
67 OUT UINTN *TableKey
68 )
69 {
70 UINTN CpuCount;
71 UINTN PciLinkIsoCount;
72 UINTN NewBufferSize;
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;
78 VOID *Ptr;
79 UINTN Loop;
80 EFI_STATUS Status;
81
82 ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
83
84 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
85 CpuCount = QemuFwCfgRead16 ();
86 ASSERT (CpuCount >= 1);
87
88 //
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.
92 //
93 PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
94
95 NewBufferSize = 1 * sizeof (*Madt) +
96 CpuCount * sizeof (*LocalApic) +
97 1 * sizeof (*IoApic) +
98 (1 + PciLinkIsoCount) * sizeof (*Iso) +
99 1 * sizeof (*LocalApicNmi);
100
101 Madt = AllocatePool (NewBufferSize);
102 if (Madt == NULL) {
103 return EFI_OUT_OF_RESOURCES;
104 }
105
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;
110 Ptr = Madt + 1;
111
112 LocalApic = Ptr;
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
119 ++LocalApic;
120 }
121 Ptr = LocalApic;
122
123 IoApic = Ptr;
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;
130 Ptr = IoApic + 1;
131
132 //
133 // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
134 //
135 Iso = Ptr;
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
142 ++Iso;
143
144 //
145 // Set Level-tiggered, Active High for all possible PCI link targets.
146 //
147 for (Loop = 0; Loop < 16; ++Loop) {
148 if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
149 continue;
150 }
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
157 ++Iso;
158 }
159 ASSERT (
160 (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
161 1 + PciLinkIsoCount
162 );
163 Ptr = Iso;
164
165 LocalApicNmi = Ptr;
166 LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI;
167 LocalApicNmi->Length = sizeof (*LocalApicNmi);
168 LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
169 //
170 // polarity and trigger mode of the APIC I/O input signals conform to the
171 // specifications of the bus
172 //
173 LocalApicNmi->Flags = 0x0000;
174 //
175 // Local APIC interrupt input LINTn to which NMI is connected.
176 //
177 LocalApicNmi->LocalApicInti = 0x01;
178 Ptr = LocalApicNmi + 1;
179
180 ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
181 Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
182
183 FreePool (Madt);
184
185 return Status;
186 }
187
188
189 #pragma pack(1)
190
191 typedef struct {
192 UINT64 Base;
193 UINT64 End;
194 UINT64 Length;
195 } PCI_WINDOW;
196
197 typedef struct {
198 PCI_WINDOW PciWindow32;
199 PCI_WINDOW PciWindow64;
200 } FIRMWARE_DATA;
201
202 typedef struct {
203 UINT8 NameOp;
204 UINT8 RootChar;
205 UINT8 NameChar[4];
206 UINT8 PackageOp;
207 UINT8 PkgLength;
208 UINT8 NumElements;
209 UINT8 DWordPrefix;
210 UINT8 Pm1aCntSlpTyp;
211 UINT8 Pm1bCntSlpTyp;
212 UINT8 Reserved[2];
213 } SYSTEM_STATE_PACKAGE;
214
215 #pragma pack()
216
217
218 STATIC
219 EFI_STATUS
220 EFIAPI
221 PopulateFwData(
222 OUT FIRMWARE_DATA *FwData
223 )
224 {
225 EFI_STATUS Status;
226 UINTN NumDesc;
227 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
228
229 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
230 if (Status == EFI_SUCCESS) {
231 UINT64 NonMmio32MaxExclTop;
232 UINT64 Mmio32MinBase;
233 UINT64 Mmio32MaxExclTop;
234 UINTN CurDesc;
235
236 Status = EFI_UNSUPPORTED;
237
238 NonMmio32MaxExclTop = 0;
239 Mmio32MinBase = BASE_4GB;
240 Mmio32MaxExclTop = 0;
241
242 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
243 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
244 UINT64 ExclTop;
245
246 Desc = &AllDesc[CurDesc];
247 ExclTop = Desc->BaseAddress + Desc->Length;
248
249 if (ExclTop <= BASE_4GB) {
250 switch (Desc->GcdMemoryType) {
251 case EfiGcdMemoryTypeNonExistent:
252 break;
253
254 case EfiGcdMemoryTypeReserved:
255 case EfiGcdMemoryTypeSystemMemory:
256 if (NonMmio32MaxExclTop < ExclTop) {
257 NonMmio32MaxExclTop = ExclTop;
258 }
259 break;
260
261 case EfiGcdMemoryTypeMemoryMappedIo:
262 if (Mmio32MinBase > Desc->BaseAddress) {
263 Mmio32MinBase = Desc->BaseAddress;
264 }
265 if (Mmio32MaxExclTop < ExclTop) {
266 Mmio32MaxExclTop = ExclTop;
267 }
268 break;
269
270 default:
271 ASSERT(0);
272 }
273 }
274 }
275
276 if (Mmio32MinBase < NonMmio32MaxExclTop) {
277 Mmio32MinBase = NonMmio32MaxExclTop;
278 }
279
280 if (Mmio32MinBase < Mmio32MaxExclTop) {
281 FwData->PciWindow32.Base = Mmio32MinBase;
282 FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
283 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
284
285 FwData->PciWindow64.Base = 0;
286 FwData->PciWindow64.End = 0;
287 FwData->PciWindow64.Length = 0;
288
289 Status = EFI_SUCCESS;
290 }
291
292 FreePool (AllDesc);
293 }
294
295 DEBUG ((
296 DEBUG_INFO,
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
301 ));
302 DEBUG ((
303 DEBUG_INFO,
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
308 ));
309
310 return Status;
311 }
312
313
314 STATIC
315 VOID
316 EFIAPI
317 GetSuspendStates (
318 UINTN *SuspendToRamSize,
319 SYSTEM_STATE_PACKAGE *SuspendToRam,
320 UINTN *SuspendToDiskSize,
321 SYSTEM_STATE_PACKAGE *SuspendToDisk
322 )
323 {
324 STATIC CONST SYSTEM_STATE_PACKAGE Template = {
325 0x08, // NameOp
326 '\\', // RootChar
327 { '_', 'S', 'x', '_' }, // NameChar[4]
328 0x12, // PackageOp
329 0x07, // PkgLength
330 0x01, // NumElements
331 0x0c, // DWordPrefix
332 0x00, // Pm1aCntSlpTyp
333 0x00, // Pm1bCntSlpTyp -- we don't support it
334 { 0x00, 0x00 } // Reserved
335 };
336 RETURN_STATUS Status;
337 FIRMWARE_CONFIG_ITEM FwCfgItem;
338 UINTN FwCfgSize;
339 UINT8 SystemStates[6];
340
341 //
342 // configure defaults
343 //
344 *SuspendToRamSize = sizeof Template;
345 CopyMem (SuspendToRam, &Template, sizeof Template);
346 SuspendToRam->NameChar[2] = '3'; // S3
347 SuspendToRam->Pm1aCntSlpTyp = 1; // PIIX4: STR
348
349 *SuspendToDiskSize = sizeof Template;
350 CopyMem (SuspendToDisk, &Template, sizeof Template);
351 SuspendToDisk->NameChar[2] = '4'; // S4
352 SuspendToDisk->Pm1aCntSlpTyp = 2; // PIIX4: POSCL
353
354 //
355 // check for overrides
356 //
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"));
360 return;
361 }
362 QemuFwCfgSelectItem (FwCfgItem);
363 QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
364
365 //
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.
369 //
370 if (SystemStates[3] & BIT7) {
371 SuspendToRam->Pm1aCntSlpTyp = SystemStates[3] & (BIT2 | BIT1 | BIT0);
372 DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n", SuspendToRam->Pm1aCntSlpTyp));
373 } else {
374 *SuspendToRamSize = 0;
375 DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n"));
376 }
377
378 if (SystemStates[4] & BIT7) {
379 SuspendToDisk->Pm1aCntSlpTyp = SystemStates[4] & (BIT2 | BIT1 | BIT0);
380 DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n", SuspendToDisk->Pm1aCntSlpTyp));
381 } else {
382 *SuspendToDiskSize = 0;
383 DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n"));
384 }
385 }
386
387
388 STATIC
389 EFI_STATUS
390 EFIAPI
391 QemuInstallAcpiSsdtTable (
392 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
393 IN VOID *AcpiTableBuffer,
394 IN UINTN AcpiTableBufferSize,
395 OUT UINTN *TableKey
396 )
397 {
398 EFI_STATUS Status;
399 FIRMWARE_DATA *FwData;
400
401 Status = EFI_OUT_OF_RESOURCES;
402
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;
409 UINTN SsdtSize;
410 UINT8 *Ssdt;
411
412 GetSuspendStates (&SuspendToRamSize, &SuspendToRam,
413 &SuspendToDiskSize, &SuspendToDisk);
414 SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize;
415 Ssdt = AllocatePool (SsdtSize);
416
417 if (Ssdt != NULL) {
418 Status = PopulateFwData (FwData);
419
420 if (Status == EFI_SUCCESS) {
421 UINT8 *SsdtPtr;
422
423 SsdtPtr = Ssdt;
424
425 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
426 SsdtPtr += AcpiTableBufferSize;
427
428 //
429 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
430 //
431 *(SsdtPtr++) = 0x5B; // ExtOpPrefix
432 *(SsdtPtr++) = 0x80; // OpRegionOp
433 *(SsdtPtr++) = 'F';
434 *(SsdtPtr++) = 'W';
435 *(SsdtPtr++) = 'D';
436 *(SsdtPtr++) = 'T';
437 *(SsdtPtr++) = 0x00; // SystemMemory
438 *(SsdtPtr++) = 0x0C; // DWordPrefix
439
440 //
441 // no virtual addressing yet, take the four least significant bytes
442 //
443 CopyMem(SsdtPtr, &FwData, 4);
444 SsdtPtr += 4;
445
446 *(SsdtPtr++) = 0x0C; // DWordPrefix
447
448 *(UINT32*) SsdtPtr = sizeof (*FwData);
449 SsdtPtr += 4;
450
451 //
452 // add suspend system states
453 //
454 CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize);
455 SsdtPtr += SuspendToRamSize;
456 CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize);
457 SsdtPtr += SuspendToDiskSize;
458
459 ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
460 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
461 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
462 }
463
464 FreePool(Ssdt);
465 }
466
467 if (Status != EFI_SUCCESS) {
468 FreePool(FwData);
469 }
470 }
471
472 return Status;
473 }
474
475
476 EFI_STATUS
477 EFIAPI
478 QemuInstallAcpiTable (
479 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
480 IN VOID *AcpiTableBuffer,
481 IN UINTN AcpiTableBufferSize,
482 OUT UINTN *TableKey
483 )
484 {
485 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
486 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
487
488 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
489 switch (Hdr->Signature) {
490 case EFI_ACPI_1_0_APIC_SIGNATURE:
491 TableInstallFunction = QemuInstallAcpiMadtTable;
492 break;
493 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
494 TableInstallFunction = QemuInstallAcpiSsdtTable;
495 break;
496 default:
497 TableInstallFunction = InstallAcpiTable;
498 }
499
500 return TableInstallFunction (
501 AcpiProtocol,
502 AcpiTableBuffer,
503 AcpiTableBufferSize,
504 TableKey
505 );
506 }
507