Home | History | Annotate | Download | only in AcpiPlatformDxe
      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 }
    519