alder_lake_bios/Insyde/InsydeModulePkg/Library/PeiVerbTableCfgLib/VerbTableCfgGetVerbTable.c

471 lines
16 KiB
C

/** @file
Search and parse verbtable binary in FD.
;******************************************************************************
;* Copyright (c) 2016 - 2019, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "VerbTableCfgGetVerbTable.h"
STATIC CHAR8 mFdmSignature[] = {'H', 'F', 'D', 'M'};
/**
Check if this FDM entry supports the target board.
This method works with board-id value over 0xFF.
The board-id value less than 0xFF may compare with region id in each fdm entry.
@param[in] BoardId The qword size board id.
@param[in] RegionIndex The index of fdm entry.
@retval TRUE The entry supports this board.
@retval FALSE The entry does not support this board
or Fdm not found or Unsupported fdm version
or invalid fdm header discovered.
**/
BOOLEAN
DoesRegionSupportBoardId (
IN CONST UINT64 BoardId,
IN CONST UINT32 RegionIndex
)
{
H2O_FLASH_DEVICE_MAP_HEADER *FdmHeader;
H2O_FLASH_DEVICE_MAP_EXTS *FdmExt;
H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP *Map;
UINT32 Index;
UINT32 Index2;
UINT64 *BoardIds;
UINT32 BoardIdCount;
FdmHeader = (H2O_FLASH_DEVICE_MAP_HEADER *)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if (FdmHeader == NULL) {
return FALSE;
}
if (CompareMem(FdmHeader, mFdmSignature, sizeof(mFdmSignature))) {
return FALSE;
}
//
// In Revision 3, reserved byte in Fdm header will be ExtensionCount.See BTR 3.17.1.
// The second ext block indicates the location of the first region-to-board-id-map.
//
if (FdmHeader->Revision != 3 || FdmHeader->ExtensionCount < 2) {
return FALSE;
}
FdmExt = (H2O_FLASH_DEVICE_MAP_EXTS *)(FdmHeader + 1);
//
// Jump to second ext block.
//
FdmExt = FdmExt + 1;
Map = (H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP *)((UINT8 *)FdmHeader + FdmExt->ExtOffset);
for (Index = 0; Index < FdmExt->ExtCount; Index++) {
BoardIdCount = Map->BoardIdCount;
if (Map->RegionIndex == RegionIndex) {
BoardIds = (UINT64 *)((UINT8 *)Map + sizeof(H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP));
for (Index2 = 0; Index2 < BoardIdCount; Index2++) {
if (BoardIds[Index2] == BoardId) {
return TRUE;
}
}
}
Map = Map + 1;
Map = (H2O_FLASH_DEVICE_MAP_REGION_BOARD_ID_MAP *)((UINT64 *)Map + BoardIdCount);
}
return FALSE;
}
/**
Search and return the "entry" and the "index of the entry" in FDM.
User may specify the instance number by 1 or greater if there are multiple instances available.
@param[in] RegionType A pointer to the guid of target region.
@param[in] Instance The Nth instace of specified region type.
@param[out] RegionIndex The index of target FDM entries.
@param[out] Entry A pointer to address of target Entry.
@retval EFI_NOT_FOUND Entry not found.
@retval EFI_UNSUPPORTED Unsupported fdm version or invalid fdm header discovered.
**/
EFI_STATUS
FdmGetNIndex (
IN CONST EFI_GUID *RegionType,
IN CONST UINT32 Instance,
OUT UINT32 *RegionIndex,
OUT H2O_FLASH_DEVICE_MAP_ENTRY **Entry
)
{
H2O_FLASH_DEVICE_MAP_HEADER *FdmHeader;
H2O_FLASH_DEVICE_MAP_ENTRY *FdmEntry;
UINT32 EntryArraySize;
UINT32 EntryCount;
UINT32 Index;
UINT32 MatchCount;
FdmHeader = NULL;
FdmHeader = (H2O_FLASH_DEVICE_MAP_HEADER *)(UINTN) PcdGet64(PcdH2OFlashDeviceMapStart);
if (FdmHeader == NULL) {
return EFI_NOT_FOUND;
}
FdmEntry = (H2O_FLASH_DEVICE_MAP_ENTRY *)((UINT8 *)FdmHeader + FdmHeader->Offset);
EntryArraySize = FdmHeader->Size - FdmHeader->Offset;
EntryCount = EntryArraySize / FdmHeader->EntrySize;
MatchCount = 0;
//
// Search each fdm entry. If search hit, return entry address and its index.
//
for (Index = 0; Index < EntryCount; Index++) {
if (CompareGuid(RegionType, &FdmEntry->RegionType)) {
MatchCount++;
if (MatchCount == Instance) {
*RegionIndex = Index;
*Entry = FdmEntry;
return EFI_SUCCESS;
}
}
FdmEntry = (H2O_FLASH_DEVICE_MAP_ENTRY *)((UINT8 *)FdmEntry + FdmHeader->EntrySize);
}
return EFI_NOT_FOUND;
}
/*
Search fdm using dword board-id, if search hit,
allocate space and fill it with varbtable data.
@param[in] BoardId Qword board-id.
@param[out] VerbTable A pointer to address of verbtable.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@retval EFI_SUCCESS Get verbtable successfully.
@retval EFI_NOT_FOUND Target not found.
*/
EFI_STATUS
GetVerbTableQwordBoard (
UINT64 BoardId,
COMMON_CHIPSET_AZALIA_VERB_TABLE **VerbTable
)
{
EFI_STATUS Status;
UINT32 RegionIndex;
UINT32 Instance;
H2O_FLASH_DEVICE_MAP_ENTRY *FdmEntry;
UINT32 RegionOffset;
UINT8 *Data;
UINT8 CodecCount;
UINT8 Index;
UINT32 DwordDataCount;
COMMON_CHIPSET_AZALIA_VERB_TABLE *AzaliaVerbTable;
COMMON_VERB_TABLE_BIN_HEADER *CommonVerbTableBinHeader;
Status = EFI_SUCCESS;
Instance = 1;
while (TRUE) {
Status = FdmGetNIndex(&gH2OFlashMapRegionVerbTableGuid, Instance, &RegionIndex, &FdmEntry);
if (!EFI_ERROR(Status)) {
if (DoesRegionSupportBoardId((UINT64)BoardId, RegionIndex)) {
//
// Use this Fdm Entry.
//
RegionOffset = (UINT32)FdmEntry->RegionOffset;
Data = (UINT8 *)(UINT32)(FdmGetBaseAddr() + RegionOffset);
CodecCount = *Data;
AzaliaVerbTable = AllocateZeroPool (sizeof (COMMON_CHIPSET_AZALIA_VERB_TABLE) * (CodecCount + 1));
if (AzaliaVerbTable == NULL) {
*VerbTable = NULL;
return EFI_OUT_OF_RESOURCES;
}
//
// Binary format :
// ---------------------------------------------
// 1Byte | Number of codecs |
// ---------------------------------------------
// 14Byte | COMMON_CHIPSET_AZALIA_VERB_TABLE_HEADER | --
// --------------------------------------------- |
// 2Byte | Data size in Dword | | codec1
// --------------------------------------------- |
// non-fixed | Verb table data | --
// ---------------------------------------------
// 14Byte | COMMON_CHIPSET_AZALIA_VERB_TABLE_HEADER | --
// --------------------------------------------- |
// 2Byte | Data size in Dword | | codec2
// --------------------------------------------- |
// non-fixed | Verb table data | --
// ---------------------------------------------
// | ... | -- codec n
//
CommonVerbTableBinHeader = (COMMON_VERB_TABLE_BIN_HEADER *)(Data + 1);
for (Index = 0; Index < CodecCount; Index++) {
AzaliaVerbTable[Index].VerbTableHeader = (COMMON_CHIPSET_AZALIA_VERB_TABLE_HEADER *)&CommonVerbTableBinHeader->Header;
AzaliaVerbTable[Index].VerbTableData = (UINT32 *)(CommonVerbTableBinHeader + 1);
DwordDataCount = CommonVerbTableBinHeader->DataSizeDword;
CommonVerbTableBinHeader = CommonVerbTableBinHeader + 1;
CommonVerbTableBinHeader = (COMMON_VERB_TABLE_BIN_HEADER *)((UINT32 *)CommonVerbTableBinHeader + DwordDataCount);
}
AzaliaVerbTable[CodecCount].VerbTableHeader = NULL;
AzaliaVerbTable[CodecCount].VerbTableData = NULL;
*VerbTable = AzaliaVerbTable;
return EFI_SUCCESS;
}
} else {
break;
}
Instance++;
}
return Status;
}
/**
Find matched region by board id, and contruct a COMMON_CHIPSET_AZALIA_VERB_TABLE.
If match not found, upate VerbTableHeaderDataAddress to NULL.
@param[in] BoardId 8-bit length board-id.
@param[out] VerbTableHeaderDataAddress A pointer to address of verbtable.
@retval EFI_SUCCESS Get verbtable entry successfully.
@retval EFI_OUT_OF_RESOURCES Memory alloccation failed.
@retval EFI_NOT_FOUND Target not found.
**/
EFI_STATUS
GetVerbTableByteBoardId (
IN UINT8 BoardId,
OUT COMMON_CHIPSET_AZALIA_VERB_TABLE **VerbTableHeaderDataAddress
)
{
COMMON_CHIPSET_AZALIA_VERB_TABLE *AzaliaVerbTable;
EFI_STATUS Status;
UINT8 Instance;
VOID *VerbTableRaw;
UINT16 DwordOffset;
UINT8 RegionId[FDM_ENTRY_REGION_ID_SIZE];
UINT64 RegionOffset;
UINT64 RegionSize;
UINT32 Attribs;
UINT8 Index;
UINT8 NumberOfCodecs;
COMMON_VERB_TABLE_BIN_HEADER *CommonVerbTableBinHeader;
AzaliaVerbTable = NULL;
Status = EFI_NOT_FOUND;
Instance = 1;
VerbTableRaw = NULL;
DwordOffset = 0;
Index = 0;
NumberOfCodecs = 0;
CommonVerbTableBinHeader = NULL;
//
// Enumerate each verbtable RegionType in FDM
//
while (TRUE) {
Status = FdmGetNAt (
&gH2OFlashMapRegionVerbTableGuid,
Instance,
RegionId,
&RegionOffset,
&RegionSize,
&Attribs
);
if (EFI_ERROR (Status)) {
*VerbTableHeaderDataAddress = NULL;
return Status;
}
//
// Search within Boards [ SUPPORT_BOARD_COUNT ]
// Expected SUPPORT_BOARD_COUNT is 6.
// See BTR 3.17.3.6
// typedef struct _H2O_FLASH_MAP_VERB_TABLE_ID {
// UINT8 Reserved[10];
// UINT8 Boards[6];
// } H2O_FLASH_MAP_VERB_TABLE_ID;
//
for (Index = 0; Index < SUPPORT_BOARD_COUNT; Index++) {
if (((H2O_FLASH_MAP_VERB_TABLE_ID *)(RegionId))->Boards[Index] == 0xff) {
break;
}
//
// Compare BoardId with Boards array with platform board-id.
//
if (((H2O_FLASH_MAP_VERB_TABLE_ID *)(RegionId))->Boards[Index] == (UINT8)BoardId) {
//
// VerbTableRaw : a pointer to matched verbtable binary entry.
//
VerbTableRaw = (VOID *)(UINTN)(FdmGetBaseAddr () + RegionOffset);
//
// First byte of verbtable binary indicate total codec numbers.
// Ex. If there are two codecs exist, then two pairs of common table required to store pointers to its header and data,
// plus extra one to store NULL pointer.
//
// NOTE: This pool is allocated to store pointers to meet the requirement of chipset init code.
// (COMMON_CHIPSET_AZALIA_VERB_TABLE is a common table to store pointers point to verbtable header and data)
// If pointer lengh in pei is 32bit long, in most of cases, the pool cost about 32bit * 4 ~ 32bit * 6 (16byte ~ 24byte).
// Memorymanagement in pei phase could be different from other phases, user need to careffully control the usage of memory.
// Any Violation of this function can resualt in unexpected memory issues.
// Caller has responsibility to free this pool when COMMON_CHIPSET_AZALIA_VERB_TABLE is nolonger used
// and the verb setting process in chipset init is finished.
//
NumberOfCodecs = *((UINT8 *)VerbTableRaw);
AzaliaVerbTable = AllocateZeroPool (sizeof (COMMON_CHIPSET_AZALIA_VERB_TABLE) * (NumberOfCodecs + 1));
if (AzaliaVerbTable == NULL) {
*VerbTableHeaderDataAddress = NULL;
Status = EFI_OUT_OF_RESOURCES;
return Status;
}
//
// Binary format :
// ---------------------------------------------
// 1Byte | Number of codecs |
// ---------------------------------------------
// 14Byte | COMMON_CHIPSET_AZALIA_VERB_TABLE_HEADER | --
// --------------------------------------------- |
// 2Byte | Data size in Dword | | codec1
// --------------------------------------------- |
// non-fixed | Verb table data | --
// ---------------------------------------------
// 14Byte | COMMON_CHIPSET_AZALIA_VERB_TABLE_HEADER | --
// --------------------------------------------- |
// 2Byte | Data size in Dword | | codec2
// --------------------------------------------- |
// non-fixed | Verb table data | --
// ---------------------------------------------
// | ... | -- codec n
//
//
// Move pointer to header of first codec.
//
CommonVerbTableBinHeader = (VOID *)(((UINT8 *)VerbTableRaw) + 1);
//
// Install address of each header and data into COMMON_CHIPSET_AZALIA_VERB_TABLE.
//
for (Index = 0; Index < NumberOfCodecs; Index++) {
AzaliaVerbTable[Index].VerbTableHeader = (VOID *)CommonVerbTableBinHeader;
AzaliaVerbTable[Index].VerbTableData = (VOID *)(CommonVerbTableBinHeader + 1);
DwordOffset = CommonVerbTableBinHeader->DataSizeDword;
//
// Move pointer to header of next codec.
//
CommonVerbTableBinHeader = CommonVerbTableBinHeader + 1;
CommonVerbTableBinHeader = (VOID *)(((UINT32 *)CommonVerbTableBinHeader) + DwordOffset);
}
//
// The last pair must be NULL
//
AzaliaVerbTable[NumberOfCodecs].VerbTableHeader = NULL;
AzaliaVerbTable[NumberOfCodecs].VerbTableData = NULL;
*VerbTableHeaderDataAddress = AzaliaVerbTable;
return EFI_SUCCESS;
}
}
Instance++;
}
}
/**
Find matched region by board-id, and contruct a COMMON_CHIPSET_AZALIA_VERB_TABLE.
If match not found, upate VerbTableHeaderDataAddress to NULL
@param[out] VerbTableHeaderDataAddress A pointer to address of verbtable.
@retval EFI_SUCCESS Get verbtable entry successfully.
@retval EFI_NOT_FOUND Target not found.
**/
EFI_STATUS
EFIAPI
GetVerbTable (
OUT COMMON_CHIPSET_AZALIA_VERB_TABLE **VerbTableHeaderDataAddress
)
{
EFI_STATUS Status;
UINT64 BoardId;
Status = EFI_NOT_FOUND;
BoardId = LibPcdGetSku();
//
// Search original FDM entry array, compare each UINT8 boards[] in regionid,
// if not found, use "0" to search default item.
//
Status = GetVerbTableByteBoardId((UINT8)BoardId, VerbTableHeaderDataAddress);
if (EFI_ERROR(Status)) {
Status = GetVerbTableByteBoardId(0, VerbTableHeaderDataAddress);
}
return Status;
}
/**
This function searches fdm 3 extension area if board-id > 0xff,
or it searches fdm original area, if target not found, it searches
default item with board-id "0".
@param[out] VerbTable A pointer to the address of common verbtable entry.
@retval EFI_SUCCESS Get verbtable successfully.
@retval EFI_NOT_FOUND Target not found.
**/
EFI_STATUS
EFIAPI
GetVerbTableEx (
OUT COMMON_CHIPSET_AZALIA_VERB_TABLE **VerbTable
)
{
EFI_STATUS Status;
UINT64 BoardId;
H2O_FLASH_DEVICE_MAP_ENTRY *Entry;
Entry = NULL;
Status = EFI_NOT_FOUND;
BoardId = LibPcdGetSku();
if (BoardId > 0xFF) {
Status = GetVerbTableQwordBoard(BoardId, VerbTable);
if (EFI_ERROR(Status)) {
//
// Use board id "0" search again.
//
Status = GetVerbTableByteBoardId(0, VerbTable);
}
} else {
//
// Search using 8bit board-id.
//
Status = GetVerbTableByteBoardId((UINT8)BoardId, VerbTable);
if (EFI_ERROR(Status)) {
//
// Use board id "0" search again.
//
Status = GetVerbTableByteBoardId(0, VerbTable);
}
}
return Status;
}