The code left behind in Qemu.c has some PCAT dependencies, and might not be able to build on all platforms. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Laszlo Ersek <lersek@redhat.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16696 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			519 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			519 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   OVMF ACPI QEMU support
 | |
| 
 | |
|   Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   Copyright (C) 2012-2014, Red Hat, Inc.
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "AcpiPlatform.h"
 | |
| #include "QemuLoader.h"
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/QemuFwCfgLib.h>
 | |
| #include <Library/DxeServicesTableLib.h>
 | |
| #include <Library/PcdLib.h>
 | |
| #include <Library/OrderedCollectionLib.h>
 | |
| #include <IndustryStandard/Acpi.h>
 | |
| 
 | |
| BOOLEAN
 | |
| QemuDetected (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   if (!QemuFwCfgIsAvailable ()) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| UINTN
 | |
| CountBits16 (
 | |
|   UINT16 Mask
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // For all N >= 1, N bits are enough to represent the number of bits set
 | |
|   // among N bits. It's true for N == 1. When adding a new bit (N := N+1),
 | |
|   // the maximum number of possibly set bits increases by one, while the
 | |
|   // representable maximum doubles.
 | |
|   //
 | |
|   Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555);
 | |
|   Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333);
 | |
|   Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F);
 | |
|   Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF);
 | |
| 
 | |
|   return Mask;
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuInstallAcpiMadtTable (
 | |
|   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
 | |
|   IN   VOID                          *AcpiTableBuffer,
 | |
|   IN   UINTN                         AcpiTableBufferSize,
 | |
|   OUT  UINTN                         *TableKey
 | |
|   )
 | |
| {
 | |
|   UINTN                                               CpuCount;
 | |
|   UINTN                                               PciLinkIsoCount;
 | |
|   UINTN                                               NewBufferSize;
 | |
|   EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
 | |
|   EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE         *LocalApic;
 | |
|   EFI_ACPI_1_0_IO_APIC_STRUCTURE                      *IoApic;
 | |
|   EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE    *Iso;
 | |
|   EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE               *LocalApicNmi;
 | |
|   VOID                                                *Ptr;
 | |
|   UINTN                                               Loop;
 | |
|   EFI_STATUS                                          Status;
 | |
| 
 | |
|   ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER));
 | |
| 
 | |
|   QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
 | |
|   CpuCount = QemuFwCfgRead16 ();
 | |
|   ASSERT (CpuCount >= 1);
 | |
| 
 | |
|   //
 | |
|   // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset
 | |
|   // corresponds to the union of all possible interrupt assignments for the LNKA,
 | |
|   // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT.
 | |
|   //
 | |
|   PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
 | |
| 
 | |
|   NewBufferSize = 1                     * sizeof (*Madt) +
 | |
|                   CpuCount              * sizeof (*LocalApic) +
 | |
|                   1                     * sizeof (*IoApic) +
 | |
|                   (1 + PciLinkIsoCount) * sizeof (*Iso) +
 | |
|                   1                     * sizeof (*LocalApicNmi);
 | |
| 
 | |
|   Madt = AllocatePool (NewBufferSize);
 | |
|   if (Madt == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CopyMem (&(Madt->Header), AcpiTableBuffer, sizeof (EFI_ACPI_DESCRIPTION_HEADER));
 | |
|   Madt->Header.Length    = (UINT32) NewBufferSize;
 | |
|   Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress);
 | |
|   Madt->Flags            = EFI_ACPI_1_0_PCAT_COMPAT;
 | |
|   Ptr = Madt + 1;
 | |
| 
 | |
|   LocalApic = Ptr;
 | |
|   for (Loop = 0; Loop < CpuCount; ++Loop) {
 | |
|     LocalApic->Type            = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
 | |
|     LocalApic->Length          = sizeof (*LocalApic);
 | |
|     LocalApic->AcpiProcessorId = (UINT8) Loop;
 | |
|     LocalApic->ApicId          = (UINT8) Loop;
 | |
|     LocalApic->Flags           = 1; // enabled
 | |
|     ++LocalApic;
 | |
|   }
 | |
|   Ptr = LocalApic;
 | |
| 
 | |
|   IoApic = Ptr;
 | |
|   IoApic->Type             = EFI_ACPI_1_0_IO_APIC;
 | |
|   IoApic->Length           = sizeof (*IoApic);
 | |
|   IoApic->IoApicId         = (UINT8) CpuCount;
 | |
|   IoApic->Reserved         = EFI_ACPI_RESERVED_BYTE;
 | |
|   IoApic->IoApicAddress    = 0xFEC00000;
 | |
|   IoApic->SystemVectorBase = 0x00000000;
 | |
|   Ptr = IoApic + 1;
 | |
| 
 | |
|   //
 | |
|   // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
 | |
|   //
 | |
|   Iso = Ptr;
 | |
|   Iso->Type                        = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
 | |
|   Iso->Length                      = sizeof (*Iso);
 | |
|   Iso->Bus                         = 0x00; // ISA
 | |
|   Iso->Source                      = 0x00; // IRQ0
 | |
|   Iso->GlobalSystemInterruptVector = 0x00000002;
 | |
|   Iso->Flags                       = 0x0000; // Conforms to specs of the bus
 | |
|   ++Iso;
 | |
| 
 | |
|   //
 | |
|   // Set Level-tiggered, Active High for all possible PCI link targets.
 | |
|   //
 | |
|   for (Loop = 0; Loop < 16; ++Loop) {
 | |
|     if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) {
 | |
|       continue;
 | |
|     }
 | |
|     Iso->Type                        = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE;
 | |
|     Iso->Length                      = sizeof (*Iso);
 | |
|     Iso->Bus                         = 0x00; // ISA
 | |
|     Iso->Source                      = (UINT8) Loop;
 | |
|     Iso->GlobalSystemInterruptVector = (UINT32) Loop;
 | |
|     Iso->Flags                       = 0x000D; // Level-tiggered, Active High
 | |
|     ++Iso;
 | |
|   }
 | |
|   ASSERT (
 | |
|     (UINTN) (Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr) ==
 | |
|       1 + PciLinkIsoCount
 | |
|     );
 | |
|   Ptr = Iso;
 | |
| 
 | |
|   LocalApicNmi = Ptr;
 | |
|   LocalApicNmi->Type            = EFI_ACPI_1_0_LOCAL_APIC_NMI;
 | |
|   LocalApicNmi->Length          = sizeof (*LocalApicNmi);
 | |
|   LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors
 | |
|   //
 | |
|   // polarity and trigger mode of the APIC I/O input signals conform to the
 | |
|   // specifications of the bus
 | |
|   //
 | |
|   LocalApicNmi->Flags           = 0x0000;
 | |
|   //
 | |
|   // Local APIC interrupt input LINTn to which NMI is connected.
 | |
|   //
 | |
|   LocalApicNmi->LocalApicInti   = 0x01;
 | |
|   Ptr = LocalApicNmi + 1;
 | |
| 
 | |
|   ASSERT ((UINTN) ((UINT8 *)Ptr - (UINT8 *)Madt) == NewBufferSize);
 | |
|   Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
 | |
| 
 | |
|   FreePool (Madt);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| #pragma pack(1)
 | |
| 
 | |
| typedef struct {
 | |
|   UINT64 Base;
 | |
|   UINT64 End;
 | |
|   UINT64 Length;
 | |
| } PCI_WINDOW;
 | |
| 
 | |
| typedef struct {
 | |
|   PCI_WINDOW PciWindow32;
 | |
|   PCI_WINDOW PciWindow64;
 | |
| } FIRMWARE_DATA;
 | |
| 
 | |
| typedef struct {
 | |
|   UINT8 BytePrefix;
 | |
|   UINT8 ByteValue;
 | |
| } AML_BYTE;
 | |
| 
 | |
| typedef struct {
 | |
|   UINT8    NameOp;
 | |
|   UINT8    RootChar;
 | |
|   UINT8    NameChar[4];
 | |
|   UINT8    PackageOp;
 | |
|   UINT8    PkgLength;
 | |
|   UINT8    NumElements;
 | |
|   AML_BYTE Pm1aCntSlpTyp;
 | |
|   AML_BYTE Pm1bCntSlpTyp;
 | |
|   AML_BYTE Reserved[2];
 | |
| } SYSTEM_STATE_PACKAGE;
 | |
| 
 | |
| #pragma pack()
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PopulateFwData(
 | |
|   OUT  FIRMWARE_DATA *FwData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   UINTN                           NumDesc;
 | |
|   EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
 | |
| 
 | |
|   Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
 | |
|   if (Status == EFI_SUCCESS) {
 | |
|     UINT64 NonMmio32MaxExclTop;
 | |
|     UINT64 Mmio32MinBase;
 | |
|     UINT64 Mmio32MaxExclTop;
 | |
|     UINTN CurDesc;
 | |
| 
 | |
|     Status = EFI_UNSUPPORTED;
 | |
| 
 | |
|     NonMmio32MaxExclTop = 0;
 | |
|     Mmio32MinBase = BASE_4GB;
 | |
|     Mmio32MaxExclTop = 0;
 | |
| 
 | |
|     for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
 | |
|       CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
 | |
|       UINT64 ExclTop;
 | |
| 
 | |
|       Desc = &AllDesc[CurDesc];
 | |
|       ExclTop = Desc->BaseAddress + Desc->Length;
 | |
| 
 | |
|       if (ExclTop <= (UINT64) PcdGet32 (PcdOvmfFdBaseAddress)) {
 | |
|         switch (Desc->GcdMemoryType) {
 | |
|           case EfiGcdMemoryTypeNonExistent:
 | |
|             break;
 | |
| 
 | |
|           case EfiGcdMemoryTypeReserved:
 | |
|           case EfiGcdMemoryTypeSystemMemory:
 | |
|             if (NonMmio32MaxExclTop < ExclTop) {
 | |
|               NonMmio32MaxExclTop = ExclTop;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|           case EfiGcdMemoryTypeMemoryMappedIo:
 | |
|             if (Mmio32MinBase > Desc->BaseAddress) {
 | |
|               Mmio32MinBase = Desc->BaseAddress;
 | |
|             }
 | |
|             if (Mmio32MaxExclTop < ExclTop) {
 | |
|               Mmio32MaxExclTop = ExclTop;
 | |
|             }
 | |
|             break;
 | |
| 
 | |
|           default:
 | |
|             ASSERT(0);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (Mmio32MinBase < NonMmio32MaxExclTop) {
 | |
|       Mmio32MinBase = NonMmio32MaxExclTop;
 | |
|     }
 | |
| 
 | |
|     if (Mmio32MinBase < Mmio32MaxExclTop) {
 | |
|       FwData->PciWindow32.Base   = Mmio32MinBase;
 | |
|       FwData->PciWindow32.End    = Mmio32MaxExclTop - 1;
 | |
|       FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
 | |
| 
 | |
|       FwData->PciWindow64.Base   = 0;
 | |
|       FwData->PciWindow64.End    = 0;
 | |
|       FwData->PciWindow64.Length = 0;
 | |
| 
 | |
|       Status = EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     FreePool (AllDesc);
 | |
|   }
 | |
| 
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
 | |
|     FwData->PciWindow32.Base,
 | |
|     FwData->PciWindow32.End,
 | |
|     FwData->PciWindow32.Length
 | |
|     ));
 | |
|   DEBUG ((
 | |
|     DEBUG_INFO,
 | |
|     "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
 | |
|     FwData->PciWindow64.Base,
 | |
|     FwData->PciWindow64.End,
 | |
|     FwData->PciWindow64.Length
 | |
|     ));
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| EFIAPI
 | |
| GetSuspendStates (
 | |
|   UINTN                *SuspendToRamSize,
 | |
|   SYSTEM_STATE_PACKAGE *SuspendToRam,
 | |
|   UINTN                *SuspendToDiskSize,
 | |
|   SYSTEM_STATE_PACKAGE *SuspendToDisk
 | |
|   )
 | |
| {
 | |
|   STATIC CONST SYSTEM_STATE_PACKAGE Template = {
 | |
|     0x08,                   // NameOp
 | |
|     '\\',                   // RootChar
 | |
|     { '_', 'S', 'x', '_' }, // NameChar[4]
 | |
|     0x12,                   // PackageOp
 | |
|     0x0A,                   // PkgLength
 | |
|     0x04,                   // NumElements
 | |
|     { 0x0A, 0x00 },         // Pm1aCntSlpTyp
 | |
|     { 0x0A, 0x00 },         // Pm1bCntSlpTyp -- we don't support it
 | |
|     {                       // Reserved[2]
 | |
|       { 0x0A, 0x00 },
 | |
|       { 0x0A, 0x00 }
 | |
|     }
 | |
|   };
 | |
|   RETURN_STATUS                     Status;
 | |
|   FIRMWARE_CONFIG_ITEM              FwCfgItem;
 | |
|   UINTN                             FwCfgSize;
 | |
|   UINT8                             SystemStates[6];
 | |
| 
 | |
|   //
 | |
|   // configure defaults
 | |
|   //
 | |
|   *SuspendToRamSize = sizeof Template;
 | |
|   CopyMem (SuspendToRam, &Template, sizeof Template);
 | |
|   SuspendToRam->NameChar[2]             = '3'; // S3
 | |
|   SuspendToRam->Pm1aCntSlpTyp.ByteValue = 1;   // PIIX4: STR
 | |
| 
 | |
|   *SuspendToDiskSize = sizeof Template;
 | |
|   CopyMem (SuspendToDisk, &Template, sizeof Template);
 | |
|   SuspendToDisk->NameChar[2]             = '4'; // S4
 | |
|   SuspendToDisk->Pm1aCntSlpTyp.ByteValue = 2;   // PIIX4: POSCL
 | |
| 
 | |
|   //
 | |
|   // check for overrides
 | |
|   //
 | |
|   Status = QemuFwCfgFindFile ("etc/system-states", &FwCfgItem, &FwCfgSize);
 | |
|   if (Status != RETURN_SUCCESS || FwCfgSize != sizeof SystemStates) {
 | |
|     DEBUG ((DEBUG_INFO, "ACPI using S3/S4 defaults\n"));
 | |
|     return;
 | |
|   }
 | |
|   QemuFwCfgSelectItem (FwCfgItem);
 | |
|   QemuFwCfgReadBytes (sizeof SystemStates, SystemStates);
 | |
| 
 | |
|   //
 | |
|   // Each byte corresponds to a system state. In each byte, the MSB tells us
 | |
|   // whether the given state is enabled. If so, the three LSBs specify the
 | |
|   // value to be written to the PM control register's SUS_TYP bits.
 | |
|   //
 | |
|   if (SystemStates[3] & BIT7) {
 | |
|     SuspendToRam->Pm1aCntSlpTyp.ByteValue =
 | |
|         SystemStates[3] & (BIT2 | BIT1 | BIT0);
 | |
|     DEBUG ((DEBUG_INFO, "ACPI S3 value: %d\n",
 | |
|             SuspendToRam->Pm1aCntSlpTyp.ByteValue));
 | |
|   } else {
 | |
|     *SuspendToRamSize = 0;
 | |
|     DEBUG ((DEBUG_INFO, "ACPI S3 disabled\n"));
 | |
|   }
 | |
| 
 | |
|   if (SystemStates[4] & BIT7) {
 | |
|     SuspendToDisk->Pm1aCntSlpTyp.ByteValue =
 | |
|         SystemStates[4] & (BIT2 | BIT1 | BIT0);
 | |
|     DEBUG ((DEBUG_INFO, "ACPI S4 value: %d\n",
 | |
|             SuspendToDisk->Pm1aCntSlpTyp.ByteValue));
 | |
|   } else {
 | |
|     *SuspendToDiskSize = 0;
 | |
|     DEBUG ((DEBUG_INFO, "ACPI S4 disabled\n"));
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuInstallAcpiSsdtTable (
 | |
|   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
 | |
|   IN   VOID                          *AcpiTableBuffer,
 | |
|   IN   UINTN                         AcpiTableBufferSize,
 | |
|   OUT  UINTN                         *TableKey
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   FIRMWARE_DATA *FwData;
 | |
| 
 | |
|   Status = EFI_OUT_OF_RESOURCES;
 | |
| 
 | |
|   FwData = AllocateReservedPool (sizeof (*FwData));
 | |
|   if (FwData != NULL) {
 | |
|     UINTN                SuspendToRamSize;
 | |
|     SYSTEM_STATE_PACKAGE SuspendToRam;
 | |
|     UINTN                SuspendToDiskSize;
 | |
|     SYSTEM_STATE_PACKAGE SuspendToDisk;
 | |
|     UINTN                SsdtSize;
 | |
|     UINT8                *Ssdt;
 | |
| 
 | |
|     GetSuspendStates (&SuspendToRamSize,  &SuspendToRam,
 | |
|                       &SuspendToDiskSize, &SuspendToDisk);
 | |
|     SsdtSize = AcpiTableBufferSize + 17 + SuspendToRamSize + SuspendToDiskSize;
 | |
|     Ssdt = AllocatePool (SsdtSize);
 | |
| 
 | |
|     if (Ssdt != NULL) {
 | |
|       Status = PopulateFwData (FwData);
 | |
| 
 | |
|       if (Status == EFI_SUCCESS) {
 | |
|         UINT8 *SsdtPtr;
 | |
| 
 | |
|         SsdtPtr = Ssdt;
 | |
| 
 | |
|         CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
 | |
|         SsdtPtr += AcpiTableBufferSize;
 | |
| 
 | |
|         //
 | |
|         // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
 | |
|         //
 | |
|         *(SsdtPtr++) = 0x5B; // ExtOpPrefix
 | |
|         *(SsdtPtr++) = 0x80; // OpRegionOp
 | |
|         *(SsdtPtr++) = 'F';
 | |
|         *(SsdtPtr++) = 'W';
 | |
|         *(SsdtPtr++) = 'D';
 | |
|         *(SsdtPtr++) = 'T';
 | |
|         *(SsdtPtr++) = 0x00; // SystemMemory
 | |
|         *(SsdtPtr++) = 0x0C; // DWordPrefix
 | |
| 
 | |
|         //
 | |
|         // no virtual addressing yet, take the four least significant bytes
 | |
|         //
 | |
|         CopyMem(SsdtPtr, &FwData, 4);
 | |
|         SsdtPtr += 4;
 | |
| 
 | |
|         *(SsdtPtr++) = 0x0C; // DWordPrefix
 | |
| 
 | |
|         *(UINT32*) SsdtPtr = sizeof (*FwData);
 | |
|         SsdtPtr += 4;
 | |
| 
 | |
|         //
 | |
|         // add suspend system states
 | |
|         //
 | |
|         CopyMem (SsdtPtr, &SuspendToRam, SuspendToRamSize);
 | |
|         SsdtPtr += SuspendToRamSize;
 | |
|         CopyMem (SsdtPtr, &SuspendToDisk, SuspendToDiskSize);
 | |
|         SsdtPtr += SuspendToDiskSize;
 | |
| 
 | |
|         ASSERT((UINTN) (SsdtPtr - Ssdt) == SsdtSize);
 | |
|         ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = (UINT32) SsdtSize;
 | |
|         Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
 | |
|       }
 | |
| 
 | |
|       FreePool(Ssdt);
 | |
|     }
 | |
| 
 | |
|     if (Status != EFI_SUCCESS) {
 | |
|       FreePool(FwData);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| QemuInstallAcpiTable (
 | |
|   IN   EFI_ACPI_TABLE_PROTOCOL       *AcpiProtocol,
 | |
|   IN   VOID                          *AcpiTableBuffer,
 | |
|   IN   UINTN                         AcpiTableBufferSize,
 | |
|   OUT  UINTN                         *TableKey
 | |
|   )
 | |
| {
 | |
|   EFI_ACPI_DESCRIPTION_HEADER        *Hdr;
 | |
|   EFI_ACPI_TABLE_INSTALL_ACPI_TABLE  TableInstallFunction;
 | |
| 
 | |
|   Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
 | |
|   switch (Hdr->Signature) {
 | |
|   case EFI_ACPI_1_0_APIC_SIGNATURE:
 | |
|     TableInstallFunction = QemuInstallAcpiMadtTable;
 | |
|     break;
 | |
|   case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
 | |
|     TableInstallFunction = QemuInstallAcpiSsdtTable;
 | |
|     break;
 | |
|   default:
 | |
|     TableInstallFunction = InstallAcpiTable;
 | |
|   }
 | |
| 
 | |
|   return TableInstallFunction (
 | |
|            AcpiProtocol,
 | |
|            AcpiTableBuffer,
 | |
|            AcpiTableBufferSize,
 | |
|            TableKey
 | |
|            );
 | |
| }
 |