• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
QemuDetected(VOID)29 QemuDetected (
30   VOID
31   )
32 {
33   if (!QemuFwCfgIsAvailable ()) {
34     return FALSE;
35   }
36 
37   return TRUE;
38 }
39 
40 
41 STATIC
42 UINTN
CountBits16(UINT16 Mask)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
QemuInstallAcpiMadtTable(IN EFI_ACPI_TABLE_PROTOCOL * AcpiProtocol,IN VOID * AcpiTableBuffer,IN UINTN AcpiTableBufferSize,OUT UINTN * TableKey)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
PopulateFwData(OUT FIRMWARE_DATA * FwData)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
GetSuspendStates(UINTN * SuspendToRamSize,SYSTEM_STATE_PACKAGE * SuspendToRam,UINTN * SuspendToDiskSize,SYSTEM_STATE_PACKAGE * SuspendToDisk)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
QemuInstallAcpiSsdtTable(IN EFI_ACPI_TABLE_PROTOCOL * AcpiProtocol,IN VOID * AcpiTableBuffer,IN UINTN AcpiTableBufferSize,OUT UINTN * TableKey)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
QemuInstallAcpiTable(IN EFI_ACPI_TABLE_PROTOCOL * AcpiProtocol,IN VOID * AcpiTableBuffer,IN UINTN AcpiTableBufferSize,OUT UINTN * TableKey)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 }
519