text: /** @file
  
  Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #include <Uefi.h>
  #include <PiDxe.h>
  #include <Library/TestPointCheckLib.h>
  #include <Library/TestPointLib.h>
  #include <Library/DebugLib.h>
  #include <Library/UefiLib.h>
  #include <Library/BaseMemoryLib.h>
  #include <IndustryStandard/Acpi.h>
  #include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>
  #include <IndustryStandard/HighPrecisionEventTimerTable.h>
  #include <IndustryStandard/DmaRemappingReportingTable.h>
  #include <IndustryStandard/WindowsSmmSecurityMitigationTable.h>
  #include <IndustryStandard/TcpaAcpi.h>
  #include <IndustryStandard/Tpm2Acpi.h>
  #include <Guid/Acpi.h>
  
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR                     *mAcpiGcdMemoryMap;
  EFI_GCD_IO_SPACE_DESCRIPTOR                         *mAcpiGcdIoMap;
  UINTN                                               mAcpiGcdMemoryMapNumberOfDescriptors;
  UINTN                                               mAcpiGcdIoMapNumberOfDescriptors;
  
  VOID
  DumpAcpiMadt (
    IN EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER  *Madt
    );
  
  VOID
  DumpAcpiMcfg (
    IN EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER  *Mcfg
    );
  
  VOID
  DumpAcpiHpet (
    IN EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER  *Hpet
    );
  
  VOID
  DumpAcpiDmar (
    IN EFI_ACPI_DMAR_HEADER  *Dmar
    );
  
  VOID
  DumpAcpiWsmt (
    IN EFI_ACPI_WSMT_TABLE  *Wsmt
    );
  
  VOID
  DumpAcpiTpm2 (
    IN EFI_TPM2_ACPI_TABLE  *Tpm2
    );
  
  VOID
  DumpAcpiTcpa (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Tcpa
    );
  
  EFI_STATUS
  CheckAcpiMadt (
    IN EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER  *Madt
    );
  
  EFI_STATUS
  CheckAcpiMcfg (
    IN EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER  *Mcfg
    );
  
  EFI_STATUS
  CheckAcpiHpet (
    IN EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER  *Hpet
    );
  
  EFI_STATUS
  CheckAcpiDmar (
    IN EFI_ACPI_DMAR_HEADER  *Dmar
    );
  
  EFI_STATUS
  CheckAcpiTpm2 (
    IN EFI_TPM2_ACPI_TABLE  *Tpm2
    );
  
  EFI_STATUS
  CheckAcpiTcpa (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Tcpa
    );
  
  VOID
  TestPointDumpGcd (
    OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **GcdMemoryMap,  OPTIONAL
    OUT UINTN                           *GcdMemoryMapNumberOfDescriptors,  OPTIONAL
    OUT EFI_GCD_IO_SPACE_DESCRIPTOR     **GcdIoMap,  OPTIONAL
    OUT UINTN                           *GcdIoMapNumberOfDescriptors,  OPTIONAL
    IN  BOOLEAN                         DumpPrint
    );
  
  BOOLEAN
  IsMmioExit (
    IN EFI_PHYSICAL_ADDRESS  BaseAddress,
    IN UINT64                Length,
    IN BOOLEAN               CheckAllocated
    )
  {
    UINTN  Index;
    for (Index = 0; Index < mAcpiGcdMemoryMapNumberOfDescriptors; Index++) {
      if (mAcpiGcdMemoryMap[Index].GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
        continue;
      }
      if ((BaseAddress >= mAcpiGcdMemoryMap[Index].BaseAddress) &&
          (BaseAddress + Length <= mAcpiGcdMemoryMap[Index].BaseAddress + mAcpiGcdMemoryMap[Index].Length)) {
        if (CheckAllocated) {
          if (mAcpiGcdMemoryMap[Index].ImageHandle != NULL) {
            return TRUE;
          } else {
            return FALSE;
          }
        } else {
          return TRUE;
        }
      }
    }
    return FALSE;
  }
  
  BOOLEAN
  IsIoExit (
    IN EFI_PHYSICAL_ADDRESS  BaseAddress,
    IN UINT64                Length,
    IN BOOLEAN               CheckAllocated
    )
  {
    UINTN  Index;
    for (Index = 0; Index < mAcpiGcdIoMapNumberOfDescriptors; Index++) {
      if (mAcpiGcdIoMap[Index].GcdIoType != EfiGcdIoTypeIo) {
        continue;
      }
      if ((BaseAddress >= mAcpiGcdIoMap[Index].BaseAddress) &&
          (BaseAddress + Length <= mAcpiGcdIoMap[Index].BaseAddress + mAcpiGcdIoMap[Index].Length)) {
        if (CheckAllocated) {
          if (mAcpiGcdIoMap[Index].ImageHandle != NULL) {
            return TRUE;
          } else {
            return FALSE;
          }
        } else {
          return TRUE;
        }
      }
    }
    return FALSE;
  }
  
  VOID
  DumpCharArray (
    IN CHAR8  *Ch,
    IN UINTN  Size
    )
  {
    UINTN  Index;
  
    for (Index = 0; Index < Size; Index++) {
      DEBUG ((DEBUG_INFO, "%c", Ch[Index]));
    }
  }
  
  VOID
  DumpAcpiTableHeader (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Table
    )
  {
    DEBUG ((DEBUG_INFO, "  "));
    DumpCharArray ((CHAR8 *)&Table->Signature, sizeof(Table->Signature));
    DEBUG ((DEBUG_INFO, "  : (0x%016lx) 0x%02x \'", Table, Table->Revision));
    DumpCharArray ((CHAR8 *)Table->OemId, sizeof(Table->OemId));
    DEBUG ((DEBUG_INFO, "\' \'"));
    DumpCharArray ((CHAR8 *)&Table->OemTableId, sizeof(Table->OemTableId));
    DEBUG ((DEBUG_INFO, "\' 0x%08x \'", Table->OemRevision));
    DumpCharArray ((CHAR8 *)&Table->CreatorId, sizeof(Table->CreatorId));
    DEBUG ((DEBUG_INFO, "\' 0x%08x |\n", Table->CreatorRevision));
  }
  
  VOID
  DumpAcpiFadt (
    IN EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE  *Fadt
    )
  {
    DumpAcpiTableHeader (&Fadt->Header);
    DEBUG ((DEBUG_INFO, "         "));
    DEBUG ((DEBUG_INFO, " SCI=0x%04x", Fadt->SciInt));
    DEBUG ((DEBUG_INFO, " SMI=0x%08x", Fadt->SmiCmd));
    DEBUG ((DEBUG_INFO, " AcpiEnable=0x%02x", Fadt->AcpiEnable));
    DEBUG ((DEBUG_INFO, " AcpiDisable=0x%02x", Fadt->AcpiDisable));
    DEBUG ((DEBUG_INFO, "\n"));
  }
  
  EFI_STATUS
  CheckAcpiFadt (
    IN EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE  *Fadt
    )
  {
    if (Fadt->SmiCmd != 0) {
      if (!IsIoExit (Fadt->SmiCmd, 1, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.SmiCmd resource (0x%x) is not reported correctly.\n", Fadt->SmiCmd));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Pm1aEvtBlk != 0) {
      if (!IsIoExit (Fadt->Pm1aEvtBlk, Fadt->Pm1EvtLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Pm1aEvtBlk resource (0x%x) is not reported correctly.\n", Fadt->Pm1aEvtBlk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Pm1bEvtBlk != 0) {
      if (!IsIoExit (Fadt->Pm1bEvtBlk, Fadt->Pm1EvtLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Pm1bEvtBlk resource (0x%x) is not reported correctly.\n", Fadt->Pm1bEvtBlk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Pm1aCntBlk != 0) {
      if (!IsIoExit (Fadt->Pm1aCntBlk, Fadt->Pm1CntLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Pm1aCntBlk resource (0x%x) is not reported correctly.\n", Fadt->Pm1aCntBlk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Pm1bCntBlk != 0) {
      if (!IsIoExit (Fadt->Pm1bCntBlk, Fadt->Pm1CntLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Pm1bCntBlk resource (0x%x) is not reported correctly.\n", Fadt->Pm1bCntBlk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Pm2CntBlk != 0) {
      if (!IsIoExit (Fadt->Pm2CntBlk, Fadt->Pm2CntLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Pm2CntBlk resource (0x%x) is not reported correctly.\n", Fadt->Pm2CntBlk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->PmTmrBlk != 0) {
      if (!IsIoExit (Fadt->PmTmrBlk, Fadt->PmTmrLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.PmTmrBlk resource (0x%x) is not reported correctly.\n", Fadt->PmTmrBlk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Gpe0Blk != 0) {
      if (!IsIoExit (Fadt->Gpe0Blk, Fadt->Gpe0BlkLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Gpe0Blk resource (0x%x) is not reported correctly.\n", Fadt->Gpe0Blk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Gpe1Blk != 0) {
      if (!IsIoExit (Fadt->Gpe1Blk, Fadt->Gpe1BlkLen, TRUE)) {
        DEBUG ((DEBUG_ERROR, "FADT.Gpe1Blk resource (0x%x) is not reported correctly.\n", Fadt->Gpe1Blk));
        return EFI_NOT_STARTED;
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, ResetReg)) {
      if (Fadt->ResetReg.Address != 0) {
        switch (Fadt->ResetReg.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->ResetReg.Address, Fadt->ResetReg.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.ResetReg resource (0x%x) is not reported correctly.\n", Fadt->ResetReg.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->ResetReg.Address, Fadt->ResetReg.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.ResetReg resource (0x%x) is not reported correctly.\n", Fadt->ResetReg.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XPm1aEvtBlk)) {
      if (Fadt->XPm1aEvtBlk.Address != 0) {
        switch (Fadt->XPm1aEvtBlk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XPm1aEvtBlk.Address, Fadt->XPm1aEvtBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1aEvtBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1aEvtBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XPm1aEvtBlk.Address, Fadt->XPm1aEvtBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1aEvtBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1aEvtBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XPm1bEvtBlk)) {
      if (Fadt->XPm1bEvtBlk.Address != 0) {
        switch (Fadt->XPm1bEvtBlk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XPm1bEvtBlk.Address, Fadt->XPm1bEvtBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1bEvtBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1bEvtBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XPm1bEvtBlk.Address, Fadt->XPm1bEvtBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1bEvtBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1bEvtBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XPm1aCntBlk)) {
      if (Fadt->XPm1aCntBlk.Address != 0) {
        switch (Fadt->XPm1aCntBlk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XPm1aCntBlk.Address, Fadt->XPm1aCntBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1aCntBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1aCntBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XPm1aCntBlk.Address, Fadt->XPm1aCntBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1aCntBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1aCntBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XPm1bCntBlk)) {
      if (Fadt->XPm1bCntBlk.Address != 0) {
        switch (Fadt->XPm1bCntBlk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XPm1bCntBlk.Address, Fadt->XPm1bCntBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1bCntBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1bCntBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XPm1bCntBlk.Address, Fadt->XPm1bCntBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm1bCntBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm1bCntBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XPm2CntBlk)) {
      if (Fadt->XPm2CntBlk.Address != 0) {
        switch (Fadt->XPm2CntBlk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XPm2CntBlk.Address, Fadt->XPm2CntBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm2CntBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm2CntBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XPm2CntBlk.Address, Fadt->XPm2CntBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPm2CntBlk resource (0x%x) is not reported correctly.\n", Fadt->XPm2CntBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XPmTmrBlk)) {
      if (Fadt->XPmTmrBlk.Address != 0) {
        switch (Fadt->XPmTmrBlk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XPmTmrBlk.Address, Fadt->XPmTmrBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPmTmrBlk resource (0x%x) is not reported correctly.\n", Fadt->XPmTmrBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XPmTmrBlk.Address, Fadt->XPmTmrBlk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XPmTmrBlk resource (0x%x) is not reported correctly.\n", Fadt->XPmTmrBlk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XGpe0Blk)) {
      if (Fadt->XGpe0Blk.Address != 0) {
        switch (Fadt->XGpe0Blk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XGpe0Blk.Address, Fadt->XGpe0Blk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XGpe0Blk resource (0x%x) is not reported correctly.\n", Fadt->XGpe0Blk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XGpe0Blk.Address, Fadt->XGpe0Blk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XGpe0Blk resource (0x%x) is not reported correctly.\n", Fadt->XGpe0Blk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, XGpe1Blk)) {
      if (Fadt->XGpe1Blk.Address != 0) {
        switch (Fadt->XGpe1Blk.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->XGpe1Blk.Address, Fadt->XGpe1Blk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XGpe1Blk resource (0x%x) is not reported correctly.\n", Fadt->XGpe1Blk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->XGpe1Blk.Address, Fadt->XGpe1Blk.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.XGpe1Blk resource (0x%x) is not reported correctly.\n", Fadt->XGpe1Blk.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, SleepControlReg)) {
      if (Fadt->SleepControlReg.Address != 0) {
        switch (Fadt->SleepControlReg.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->SleepControlReg.Address, Fadt->SleepControlReg.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.SleepControlReg resource (0x%x) is not reported correctly.\n", Fadt->SleepControlReg.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->SleepControlReg.Address, Fadt->SleepControlReg.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.SleepControlReg resource (0x%x) is not reported correctly.\n", Fadt->SleepControlReg.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    if (Fadt->Header.Length > OFFSET_OF(EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE, SleepStatusReg)) {
      if (Fadt->SleepStatusReg.Address != 0) {
        switch (Fadt->SleepStatusReg.AddressSpaceId) {
        case EFI_ACPI_5_0_SYSTEM_MEMORY:
          if (!IsMmioExit (Fadt->SleepStatusReg.Address, Fadt->SleepStatusReg.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.SleepStatusReg resource (0x%x) is not reported correctly.\n", Fadt->SleepStatusReg.Address));
            return EFI_NOT_STARTED;
          }
          break;
        case EFI_ACPI_5_0_SYSTEM_IO:
          if (!IsIoExit (Fadt->SleepStatusReg.Address, Fadt->SleepStatusReg.RegisterBitWidth/8, TRUE)) {
            DEBUG ((DEBUG_ERROR, "FADT.SleepStatusReg resource (0x%x) is not reported correctly.\n", Fadt->SleepStatusReg.Address));
            return EFI_NOT_STARTED;
          }
          break;
        }
      }
    }
    return EFI_SUCCESS;
  }
  
  VOID
  DumpAcpiFacs (
    IN EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs
    )
  {
    DEBUG ((DEBUG_INFO, "  "));
    DumpCharArray ((CHAR8 *)&Facs->Signature, sizeof(Facs->Signature));
    DEBUG ((DEBUG_INFO, "  : (0x%016lx) 0x%02x\n", Facs, Facs->Version));
    DEBUG ((DEBUG_INFO, "    "));
    DEBUG ((DEBUG_INFO, " HardwareSignature=%08x\n", Facs->HardwareSignature));
  }
  
  VOID
  DumpAcpiTable (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Table
    )
  {
    EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE  *Fadt;
    
    if (Table == NULL) {
      return ;
    }
  
    switch (Table->Signature) {
    case EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
      Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Table;
      DumpAcpiFadt (Fadt);
      if (Fadt->Header.Revision >= EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
        if (Fadt->XFirmwareCtrl != 0) {
          DumpAcpiFacs ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->XFirmwareCtrl);
        } else {
          DumpAcpiFacs ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl);
        }
        if (Fadt->XDsdt != 0) {
          DumpAcpiTable ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Fadt->XDsdt);
        } else {
          DumpAcpiTable ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Fadt->Dsdt);
        }
      } else {
        DumpAcpiFacs ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl);
        DumpAcpiTable ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Fadt->Dsdt);
      }
      break;
    case EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
      DumpAcpiMadt ((EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)Table);
      break;
    case EFI_ACPI_2_0_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_SIGNATURE:
      DumpAcpiMcfg ((EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *)Table);
      break;
    case EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
      DumpAcpiHpet ((EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *)Table);
      break;
    case EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE:
      DumpAcpiDmar ((EFI_ACPI_DMAR_HEADER *)Table);
      break;
    case EFI_ACPI_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE:
      DumpAcpiWsmt ((EFI_ACPI_WSMT_TABLE *)Table);
      break;
    case EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE:
      DumpAcpiTpm2 ((EFI_TPM2_ACPI_TABLE *)Table);
      break;
    case EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE:
      DumpAcpiTcpa ((VOID *)Table);
      break;
    default:
      DumpAcpiTableHeader (Table);
      break;
    }
  }
  
  EFI_STATUS
  CheckAcpiTableResource (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Table
    )
  {
    EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE  *Fadt;
    
    if (Table == NULL) {
      return EFI_INVALID_PARAMETER;
    }
  
    switch (Table->Signature) {
    case EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
      Fadt = (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *)Table;
      CheckAcpiFadt (Fadt);
      if (Fadt->Header.Revision >= EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
        if (Fadt->XFirmwareCtrl != 0) {
          // CheckAcpiFacs ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->XFirmwareCtrl);
        } else {
          // CheckAcpiFacs ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl);
        }
        if (Fadt->XDsdt != 0) {
          // CheckAcpiDsdt ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Fadt->XDsdt);
        } else {
          // CheckAcpiDsdt ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Fadt->Dsdt);
        }
      } else {
        // CheckAcpiFacs ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl);
        // CheckAcpiDsdt ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Fadt->Dsdt);
      }
      break;
    case EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
      return CheckAcpiMadt ((EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)Table);
      break;
    case EFI_ACPI_2_0_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_SIGNATURE:
      return CheckAcpiMcfg ((EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *)Table);
      break;
    case EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
      return CheckAcpiHpet ((EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *)Table);
      break;
    case EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE:
      return CheckAcpiDmar ((EFI_ACPI_DMAR_HEADER *)Table);
      break;
    case EFI_ACPI_WINDOWS_SMM_SECURITY_MITIGATION_TABLE_SIGNATURE:
      // CheckAcpiWsmt ((EFI_ACPI_WSMT_TABLE *)Table);
      break;
    case EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE:
      return CheckAcpiTpm2 ((EFI_TPM2_ACPI_TABLE *)Table);
      break;
    case EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE:
      return CheckAcpiTcpa ((VOID *)Table);
      break;
    default:
      break;
    }
  
    return EFI_SUCCESS;
  }
  
  EFI_STATUS
  DumpAcpiRsdt (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Rsdt,
    IN UINT32                       *Signature, OPTIONAL
    OUT VOID                        **OutTable,
    IN BOOLEAN                      DumpPrint,
    IN BOOLEAN                      CheckResource
    )
  {
    UINTN                              Index;
    UINT32                             EntryCount;
    UINT32                             *EntryPtr;
    EFI_ACPI_DESCRIPTION_HEADER        *Table;
    EFI_STATUS                         Status;
    EFI_STATUS                         ReturnStatus;
  
    if (Rsdt == NULL) {
      return EFI_INVALID_PARAMETER;
    }
  
    if (OutTable != NULL) {
      *OutTable = NULL;
    } else {
      return EFI_INVALID_PARAMETER;
    }
  
    ReturnStatus = EFI_SUCCESS;
    EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
    EntryPtr = (UINT32 *)(Rsdt + 1);
    for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
      Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
      if (DumpPrint) {
        DumpAcpiTable (Table);
      }
      if (CheckResource) {
        Status = CheckAcpiTableResource (Table);
        if (EFI_ERROR(Status)) {
          ReturnStatus = Status;
        }
      }
      if (Signature != NULL && Table->Signature == *Signature) {
        *OutTable = Table;
      }
    }
    
    if (OutTable != NULL) {
      if (*OutTable == NULL) {
        return EFI_NOT_FOUND;
      }
    }
  
    return ReturnStatus;
  }
  
  EFI_STATUS
  DumpAcpiXsdt (
    IN EFI_ACPI_DESCRIPTION_HEADER  *Xsdt,
    IN UINT32                       *Signature, OPTIONAL
    OUT VOID                        **OutTable,
    IN BOOLEAN                      DumpPrint,
    IN BOOLEAN                      CheckResource
    )
  {
    UINTN                          Index;
    UINT32                         EntryCount;
    UINT64                         EntryPtr;
    UINTN                          BasePtr;
    EFI_ACPI_DESCRIPTION_HEADER    *Table;
    EFI_STATUS                     Status;
    EFI_STATUS                     ReturnStatus;
  
    if (Xsdt == NULL) {
      return EFI_INVALID_PARAMETER;
    }
    
    if (OutTable != NULL) {
      *OutTable = NULL;
    } else {
      return EFI_INVALID_PARAMETER;
    }
  
    ReturnStatus = EFI_SUCCESS;
    EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
    
    BasePtr = (UINTN)(Xsdt + 1);
    for (Index = 0; Index < EntryCount; Index ++) {
      CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
      Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
      if (DumpPrint) {
        DumpAcpiTable (Table);
      }
      if (CheckResource) {
        Status = CheckAcpiTableResource (Table);
        if (EFI_ERROR(Status)) {
          ReturnStatus = Status;
        }
      }
      if (Signature != NULL && Table->Signature == *Signature) {
        *OutTable = Table;
      }
    }
  
    if (OutTable != NULL) {
      if (*OutTable == NULL) {
        return EFI_NOT_FOUND;
      }
    }
  
    return ReturnStatus;
  }
  
  EFI_STATUS
  DumpAcpiRsdp (
    IN EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp,
    IN UINT32                                        *Signature, OPTIONAL
    OUT VOID                                         **Table,
    IN BOOLEAN                                       DumpPrint,
    IN BOOLEAN                                       CheckResource
    )
  {
    EFI_STATUS                                    Status;
    EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;
    EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;
  
    if (DumpPrint) {
      DumpCharArray ((CHAR8 *)&Rsdp->Signature, sizeof(Rsdp->Signature));
      DEBUG ((DEBUG_INFO, ": (0x%016lx) 0x%02x \'", Rsdp, Rsdp->Revision));
      DumpCharArray ((CHAR8 *)Rsdp->OemId, sizeof(Rsdp->OemId));
      DEBUG ((DEBUG_INFO, "\'\n"));
      DEBUG ((DEBUG_INFO, "         "));
      DEBUG ((DEBUG_INFO, " RSDT=0x%08x XSDT=0x%016lx\n", Rsdp->RsdtAddress, Rsdp->XsdtAddress));
  
      if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
        DumpAcpiTable ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress);
      }
      DumpAcpiTable ((EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress);
    }
  
    //
    // Search XSDT
    //
    if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
      Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
      Status = DumpAcpiXsdt (Xsdt, Signature, Table, DumpPrint, CheckResource);
    } else {
      //
      // Search RSDT
      //
      Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
      Status = DumpAcpiRsdt (Rsdt, Signature, Table, DumpPrint, CheckResource);
    }
  
    return Status;
  }
  
  EFI_STATUS
  DumpAcpiWithGuid (
    IN EFI_GUID  *AcpiTableGuid,
    IN UINT32    *Signature, OPTIONAL
    OUT VOID     **Table,
    IN BOOLEAN   DumpPrint,
    IN BOOLEAN   CheckResource
    )
  {
    VOID        *Rsdp;
    EFI_STATUS  Status;
  
    Status = EfiGetSystemConfigurationTable (AcpiTableGuid, &Rsdp);
    if (EFI_ERROR(Status)) {
      return EFI_NOT_FOUND;
    }
  
    Status = DumpAcpiRsdp (Rsdp, Signature, Table, DumpPrint, CheckResource);
  
    return Status;
  }
  
  EFI_STATUS
  TestPointCheckAcpi (
    VOID
    )
  {
    EFI_STATUS  Status;
  
    DEBUG ((DEBUG_INFO, "==== TestPointCheckAcpi - Enter\n"));
  
    DEBUG ((DEBUG_INFO, "AcpiTable :\n"));
    DEBUG ((DEBUG_INFO, "  Table         Address        Rev   OemId   OemTableId   OemRev   Creat  CreatorRev\n"));
    //
    // First dump
    //
    Status = DumpAcpiWithGuid (&gEfiAcpi20TableGuid, NULL, NULL, TRUE, FALSE);
    if (Status == EFI_NOT_FOUND) {
      Status = DumpAcpiWithGuid (&gEfiAcpi10TableGuid, NULL, NULL, TRUE, FALSE);
    }
    
    if (EFI_ERROR(Status)) {
      DEBUG ((DEBUG_ERROR, "No ACPI table\n"));
      TestPointLibAppendErrorString (
        PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
        NULL,
        TEST_POINT_BYTE4_READY_TO_BOOT_ACPI_TABLE_FUNCTIONAL_ERROR_CODE \
          TEST_POINT_READY_TO_BOOT \
          TEST_POINT_BYTE4_READY_TO_BOOT_ACPI_TABLE_FUNCTIONAL_ERROR_STRING
        );
    }
  
    DEBUG ((DEBUG_INFO, "==== TestPointCheckAcpi - Exit\n"));
    
    return Status;
  }
  
  EFI_STATUS
  TestPointCheckAcpiGcdResource (
    VOID
    )
  {
    EFI_STATUS  Status;
    
    DEBUG ((DEBUG_INFO, "==== TestPointCheckAcpiGcdResource - Enter\n"));
    
    //
    // Check the ACPI existence
    //
    Status = DumpAcpiWithGuid (&gEfiAcpi20TableGuid, NULL, NULL, FALSE, FALSE);
    if (Status == EFI_NOT_FOUND) {
      Status = DumpAcpiWithGuid (&gEfiAcpi10TableGuid, NULL, NULL, FALSE, FALSE);
    }
    
    if (!EFI_ERROR(Status)) {
      //
      // Then check resource in ACPI and GCD
      //
      TestPointDumpGcd (&mAcpiGcdMemoryMap, &mAcpiGcdMemoryMapNumberOfDescriptors, &mAcpiGcdIoMap, &mAcpiGcdIoMapNumberOfDescriptors, FALSE);
  
      Status = DumpAcpiWithGuid (&gEfiAcpi20TableGuid, NULL, NULL, FALSE, TRUE);
      if (Status == EFI_NOT_FOUND) {
        Status = DumpAcpiWithGuid (&gEfiAcpi10TableGuid, NULL, NULL, FALSE, TRUE);
      }
    }
    
    if (EFI_ERROR(Status)) {
      DEBUG ((DEBUG_ERROR, "ACPI table resource not in GCD\n"));
      TestPointLibAppendErrorString (
        PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV,
        NULL,
        TEST_POINT_BYTE4_READY_TO_BOOT_GCD_RESOURCE_FUNCTIONAL_ERROR_CODE \
          TEST_POINT_READY_TO_BOOT \
          TEST_POINT_BYTE4_READY_TO_BOOT_GCD_RESOURCE_FUNCTIONAL_ERROR_STRING
        );
    }
    DEBUG ((DEBUG_INFO, "==== TestPointCheckAcpiGcdResource - Exit\n"));
    
    return Status;
  }
  
  VOID *
  TestPointGetAcpi (
    IN UINT32  Signature
    )
  {
    EFI_STATUS  Status;
    VOID        *Table;
  
    Status = DumpAcpiWithGuid (&gEfiAcpi20TableGuid, &Signature, &Table, FALSE, FALSE);
    if (Status == EFI_NOT_FOUND) {
      Status = DumpAcpiWithGuid (&gEfiAcpi10TableGuid, &Signature, &Table, FALSE, FALSE);
    }
  
    if (EFI_ERROR(Status)) {
      return NULL;
    }
  
    return Table;
  }
  
  