/** @file
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
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.
Module Name:
LegacyTable.c
Abstract:
Revision History:
**/
#include "DxeIpl.h"
#include "HobGeneration.h"
#include "Debug.h"
#define MPS_PTR SIGNATURE_32('_','M','P','_')
#define SMBIOS_PTR SIGNATURE_32('_','S','M','_')
#define EBDA_BASE_ADDRESS 0x40E
VOID *
FindAcpiRsdPtr (
VOID
)
{
UINTN Address;
UINTN Index;
//
// First Seach 0x0e0000 - 0x0fffff for RSD Ptr
//
for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
if (*(UINT64 *)(Address) == EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
return (VOID *)Address;
}
}
//
// Search EBDA
//
Address = (*(UINT16 *)(UINTN)(EBDA_BASE_ADDRESS)) << 4;
for (Index = 0; Index < 0x400 ; Index += 16) {
if (*(UINT64 *)(Address + Index) == EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
return (VOID *)Address;
}
}
return NULL;
}
VOID *
FindSMBIOSPtr (
VOID
)
{
UINTN Address;
//
// First Seach 0x0f0000 - 0x0fffff for SMBIOS Ptr
//
for (Address = 0xf0000; Address < 0xfffff; Address += 0x10) {
if (*(UINT32 *)(Address) == SMBIOS_PTR) {
return (VOID *)Address;
}
}
return NULL;
}
VOID *
FindMPSPtr (
VOID
)
{
UINTN Address;
UINTN Index;
//
// First Seach 0x0e0000 - 0x0fffff for MPS Ptr
//
for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
if (*(UINT32 *)(Address) == MPS_PTR) {
return (VOID *)Address;
}
}
//
// Search EBDA
//
Address = (*(UINT16 *)(UINTN)(EBDA_BASE_ADDRESS)) << 4;
for (Index = 0; Index < 0x400 ; Index += 16) {
if (*(UINT32 *)(Address + Index) == MPS_PTR) {
return (VOID *)Address;
}
}
return NULL;
}
#pragma pack(1)
typedef struct {
EFI_ACPI_DESCRIPTION_HEADER Header;
UINT32 Entry;
} RSDT_TABLE;
typedef struct {
EFI_ACPI_DESCRIPTION_HEADER Header;
UINT64 Entry;
} XSDT_TABLE;
#pragma pack()
VOID
ScanTableInRSDT (
RSDT_TABLE *Rsdt,
UINT32 Signature,
EFI_ACPI_DESCRIPTION_HEADER **FoundTable
)
{
UINTN Index;
UINT32 EntryCount;
UINT32 *EntryPtr;
EFI_ACPI_DESCRIPTION_HEADER *Table;
*FoundTable = NULL;
EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
EntryPtr = &Rsdt->Entry;
for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));
if (Table->Signature == Signature) {
*FoundTable = Table;
break;
}
}
return;
}
VOID
ScanTableInXSDT (
XSDT_TABLE *Xsdt,
UINT32 Signature,
EFI_ACPI_DESCRIPTION_HEADER **FoundTable
)
{
UINTN Index;
UINT32 EntryCount;
UINT64 EntryPtr;
UINTN BasePtr;
EFI_ACPI_DESCRIPTION_HEADER *Table;
*FoundTable = NULL;
EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
BasePtr = (UINTN)(&(Xsdt->Entry));
for (Index = 0; Index < EntryCount; Index ++) {
CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));
if (Table->Signature == Signature) {
*FoundTable = Table;
break;
}
}
return;
}
VOID *
FindAcpiPtr (
IN HOB_TEMPLATE *Hob,
UINT32 Signature
)
{
EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
RSDT_TABLE *Rsdt;
XSDT_TABLE *Xsdt;
AcpiTable = NULL;
//
// Check ACPI2.0 table
//
if ((int)Hob->Acpi20.Table != -1) {
Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)Hob->Acpi20.Table;
Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;
Xsdt = NULL;
if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {
Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;
}
//
// Check Xsdt
//
if (Xsdt != NULL) {
ScanTableInXSDT (Xsdt, Signature, &AcpiTable);
}
//
// Check Rsdt
//
if ((AcpiTable == NULL) && (Rsdt != NULL)) {
ScanTableInRSDT (Rsdt, Signature, &AcpiTable);
}
}
//
// Check ACPI1.0 table
//
if ((AcpiTable == NULL) && ((int)Hob->Acpi.Table != -1)) {
Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)Hob->Acpi.Table;
Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;
//
// Check Rsdt
//
if (Rsdt != NULL) {
ScanTableInRSDT (Rsdt, Signature, &AcpiTable);
}
}
return AcpiTable;
}
#pragma pack(1)
typedef struct {
UINT64 BaseAddress;
UINT16 PciSegmentGroupNumber;
UINT8 StartBusNumber;
UINT8 EndBusNumber;
UINT32 Reserved;
} MCFG_STRUCTURE;
#pragma pack()
VOID
PrepareMcfgTable (
IN HOB_TEMPLATE *Hob
)
{
EFI_ACPI_DESCRIPTION_HEADER *McfgTable;
MCFG_STRUCTURE *Mcfg;
UINTN McfgCount;
UINTN Index;
McfgTable = FindAcpiPtr (Hob, EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE);
if (McfgTable == NULL) {
return ;
}
Mcfg = (MCFG_STRUCTURE *)((UINTN)McfgTable + sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64));
McfgCount = (McfgTable->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER) - sizeof(UINT64)) / sizeof(MCFG_STRUCTURE);
//
// Fill PciExpress info on Hob
// Note: Only for 1st segment
//
for (Index = 0; Index < McfgCount; Index++) {
if (Mcfg[Index].PciSegmentGroupNumber == 0) {
Hob->PciExpress.PciExpressBaseAddressInfo.PciExpressBaseAddress = Mcfg[Index].BaseAddress;
break;
}
}
return ;
}
VOID
PrepareFadtTable (
IN HOB_TEMPLATE *Hob
)
{
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
EFI_ACPI_DESCRIPTION *AcpiDescription;
Fadt = FindAcpiPtr (Hob, EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
if (Fadt == NULL) {
return ;
}
AcpiDescription = &Hob->AcpiInfo.AcpiDescription;
//
// Fill AcpiDescription according to FADT
// Currently, only for PM_TMR
//
AcpiDescription->PM_TMR_LEN = Fadt->PmTmrLen;
AcpiDescription->TMR_VAL_EXT = (UINT8)((Fadt->Flags & 0x100) != 0);
//
// For fields not included in ACPI 1.0 spec, we get the value based on table length
//
if (Fadt->Header.Length >= OFFSET_OF (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE, XPmTmrBlk) + sizeof (Fadt->XPmTmrBlk)) {
CopyMem (
&AcpiDescription->PM_TMR_BLK,
&Fadt->XPmTmrBlk,
sizeof(EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE)
);
}
if (Fadt->Header.Length >= OFFSET_OF (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE, ResetValue) + sizeof (Fadt->ResetValue)) {
CopyMem (
&AcpiDescription->RESET_REG,
&Fadt->ResetReg,
sizeof(EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE)
);
AcpiDescription->RESET_VALUE = Fadt->ResetValue;
}
if (AcpiDescription->PM_TMR_BLK.Address == 0) {
AcpiDescription->PM_TMR_BLK.Address = Fadt->PmTmrBlk;
AcpiDescription->PM_TMR_BLK.AddressSpaceId = EFI_ACPI_3_0_SYSTEM_IO;
}
//
// It's possible that the PM_TMR_BLK.RegisterBitWidth is always 32,
// we need to set the correct RegisterBitWidth value according to the TMR_VAL_EXT
// A zero indicates TMR_VAL is implemented as a 24-bit value.
// A one indicates TMR_VAL is implemented as a 32-bit value
//
AcpiDescription->PM_TMR_BLK.RegisterBitWidth = (UINT8) ((AcpiDescription->TMR_VAL_EXT == 0) ? 24 : 32);
return ;
}
VOID
PrepareHobLegacyTable (
IN HOB_TEMPLATE *Hob
)
{
CHAR8 PrintBuffer[256];
Hob->Acpi.Table = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiRsdPtr ();
AsciiSPrint (PrintBuffer, 256, "\nAcpiTable=0x%x ", (UINT32)(UINTN)Hob->Acpi.Table);
PrintString (PrintBuffer);
Hob->Acpi20.Table = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiRsdPtr ();
Hob->Smbios.Table = (EFI_PHYSICAL_ADDRESS)(UINTN)FindSMBIOSPtr ();
AsciiSPrint (PrintBuffer, 256, "SMBIOS Table=0x%x ", (UINT32)(UINTN)Hob->Smbios.Table);
PrintString (PrintBuffer);
Hob->Mps.Table = (EFI_PHYSICAL_ADDRESS)(UINTN)FindMPSPtr ();
AsciiSPrint (PrintBuffer, 256, "MPS Table=0x%x\n", (UINT32)(UINTN)Hob->Mps.Table);
PrintString (PrintBuffer);
PrepareMcfgTable (Hob);
PrepareFadtTable (Hob);
return ;
}