mirror of https://github.com/acidanthera/audk.git
593 lines
14 KiB
C
593 lines
14 KiB
C
/** @file
|
|
Common functions used by PCD PEIM and PCD DXE.
|
|
|
|
Copyright (c) 2006, Intel Corporation
|
|
All rights reserved. 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: PcdCommon.c
|
|
|
|
**/
|
|
#include "PcdCommon.h"
|
|
|
|
|
|
|
|
/**
|
|
The function retrieves the PCD data value according to
|
|
the PCD_DATA_TYPE specified.
|
|
|
|
@param[in] Type The PCD_DATA_TYPE used to interpret the data.
|
|
@param[in] InData The input data.
|
|
@param[in] OutData The output data.
|
|
@param[in] Len The length of the data; it is mainly used for PcdPointer type.
|
|
|
|
@retval VOID
|
|
--*/
|
|
VOID
|
|
GetDataBasedOnType (
|
|
IN PCD_DATA_TYPE Type,
|
|
IN VOID *InData,
|
|
OUT VOID *OutData,
|
|
IN UINTN Len
|
|
)
|
|
{
|
|
if (Type == PcdPointer) {
|
|
//
|
|
// When the Type is PcdPointer, we are returning
|
|
// the address of the internal buffer kpet by
|
|
// PCD database. Therefore, we treat OutData as
|
|
// a pointer to a "VOID *". Thus, the ugly type cast
|
|
// (VOID **) is used.
|
|
//
|
|
|
|
*((VOID **) OutData) = InData;
|
|
} else {
|
|
CopyMem (OutData, InData, Len);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UINTN
|
|
GetExtendedDataOffset (
|
|
IN CONST PCD_INDEX *PcdIndex,
|
|
IN UINTN SkuIdx,
|
|
IN CONST PCD_DATABASE_HEADER *Info
|
|
)
|
|
{
|
|
UINT8 *OffsetAddress;
|
|
UINTN Offset;
|
|
|
|
OffsetAddress = GetAbsoluteAddress (PcdIndex->ExtendedDataOffset,
|
|
Info->ImageIndexOffset,
|
|
Info
|
|
);
|
|
|
|
OffsetAddress += (SkuIdx * Info->ExtendedOffsetLength);
|
|
|
|
|
|
CopyMem (&Offset, OffsetAddress, Info->ExtendedOffsetLength);
|
|
|
|
return Offset;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
GetHiiDataProperty (
|
|
IN CONST PCD_INDEX *PcdIndex,
|
|
IN UINTN SkuIdx,
|
|
IN CONST PCD_DATABASE_HEADER *Info,
|
|
OUT EFI_GUID **VariableGuid,
|
|
OUT UINT16 **VariableName
|
|
)
|
|
{
|
|
UINT16 NameOffset;
|
|
UINT16 GuidOffset;
|
|
UINT8 *HiiDataOffset;
|
|
|
|
HiiDataOffset = GetAbsoluteAddress (PcdIndex->HiiData, Info->ImageIndexOffset, Info);
|
|
HiiDataOffset += (SkuIdx * (Info->HiiGuidOffsetLength + Info->HiiVariableOffsetLength));
|
|
|
|
CopyMem (&GuidOffset, HiiDataOffset, Info->HiiGuidOffsetLength);
|
|
CopyMem (&NameOffset, HiiDataOffset + Info->HiiGuidOffsetLength, Info->HiiVariableOffsetLength);
|
|
|
|
*VariableGuid = (EFI_GUID *) GetAbsoluteAddress (GuidOffset * sizeof (EFI_GUID), Info->GuidTableOffset, Info);
|
|
*VariableName = (UINT16 *) GetAbsoluteAddress (NameOffset * sizeof (UINT16) , Info->StringTableOffset, Info);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
UINTN
|
|
GetSkuIdIdx (
|
|
IN CONST PCD_INDEX *PcdIndex,
|
|
IN CONST PCD_DATABASE_HEADER *Info
|
|
)
|
|
{
|
|
UINT8 *SkuIdArray;
|
|
UINTN SkuIdx;
|
|
|
|
SkuIdArray = GetAbsoluteAddress (PcdIndex->SkuIdArray, Info->ImageIndexOffset, Info);
|
|
|
|
SkuIdx = 0;
|
|
|
|
if (PcdIndex->StateByte.SkuEnable) {
|
|
|
|
for (; SkuIdx < PcdIndex->SkuCount; SkuIdx++) {
|
|
if (SkuIdArray[SkuIdx] == Info->SkuId) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SkuIdx > PcdIndex->SkuCount) {
|
|
if (Info->SkuId == 0) {
|
|
//
|
|
// If no SKU_ID is set previously
|
|
// Just retrieve the first value
|
|
//
|
|
SkuIdx = 0;
|
|
} else {
|
|
//
|
|
// Just can't find the SKU_ID, ASSERT according to Spec.
|
|
//
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return SkuIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function is the worker function to get the data of a PCD entry.
|
|
|
|
@param[in] PcdIndex The PCD Index.
|
|
@param[in] Info The attributes of the PCD database.
|
|
@param[out] Data The output data.
|
|
|
|
@retval VOID
|
|
--*/
|
|
UINT8*
|
|
GetPcdDataPtr (
|
|
IN CONST PCD_INDEX *PcdIndex,
|
|
IN CONST PCD_DATABASE_HEADER *Info
|
|
)
|
|
{
|
|
UINTN VariableDataSize;
|
|
VOID *VariableData;
|
|
UINT16 *VariableName;
|
|
UINT8 *PcdData;
|
|
EFI_GUID *VariableGuid;
|
|
EFI_STATUS Status;
|
|
UINTN SkuIdx;
|
|
UINTN ExtendedOffset;
|
|
|
|
//
|
|
// If Sku is not enalbed for this PCD Entry.
|
|
// SkuIdx 0 will be used to compute PcdData
|
|
//
|
|
SkuIdx = GetSkuIdIdx (PcdIndex, Info);
|
|
|
|
if (PcdIndex->StateByte.HiiEnable) {
|
|
|
|
GetHiiDataProperty (PcdIndex, SkuIdx, Info, &VariableGuid, &VariableName);
|
|
|
|
Status = GetHiiVariable (VariableGuid, VariableName, &VariableData, &VariableDataSize);
|
|
ASSERT_EFI_ERROR (Status);
|
|
ASSERT (VariableDataSize >= (PcdIndex->DatumSize + PcdIndex->ExtendedDataOffset));
|
|
|
|
PcdData = (UINT8 *) VariableData + PcdIndex->ExtendedDataOffset;
|
|
|
|
return PcdData;
|
|
}
|
|
|
|
//
|
|
// For VPD and Data type, we need the ExtendedOffset.
|
|
// So get it here.
|
|
//
|
|
ExtendedOffset = GetExtendedDataOffset (PcdIndex, SkuIdx, Info);
|
|
|
|
if (PcdIndex->StateByte.VpdEnable) {
|
|
|
|
PcdData = (VOID *) (Info->VpdStart + ExtendedOffset);
|
|
|
|
return PcdData;
|
|
}
|
|
|
|
//
|
|
// For data type, we just need the pointer
|
|
//
|
|
PcdData = GetAbsoluteAddress (
|
|
ExtendedOffset,
|
|
Info->DataBufferOffset,
|
|
Info
|
|
);
|
|
|
|
return PcdData;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function locates the PCD_INDEX according to TokeNumber and GUID space given.
|
|
|
|
@param[in] TokenNumber The token number.
|
|
@param[in] Guid The GUID token space.
|
|
@param[out] Info The attributes of the PCD database.
|
|
|
|
@retval PCD_INDEX* The PCD_INDEX found.
|
|
--*/
|
|
PCD_INDEX *
|
|
FindPcdIndex (
|
|
IN UINTN TokenNumber,
|
|
IN CONST EFI_GUID *Guid,
|
|
IN CONST PCD_DATABASE_HEADER *Info,
|
|
OUT UINTN *Index
|
|
)
|
|
{
|
|
PCD_INDEX *PcdIndex;
|
|
UINTN Idx;
|
|
EFI_GUID *GuidSpace;
|
|
|
|
PcdIndex = (PCD_INDEX *) GetAbsoluteAddress (0, Info->PcdIndexOffset, Info);
|
|
|
|
for (Idx = 0; Idx < Info->EntryCount; Idx++, PcdIndex++) {
|
|
if (Index != NULL) {
|
|
*Index = Idx;
|
|
}
|
|
|
|
if (PcdIndex->TokenNumber == TokenNumber) {
|
|
if (Guid == NULL) {
|
|
if (!PcdIndex->StateByte.ExtendedGuidPresent) {
|
|
return PcdIndex;
|
|
}
|
|
} else {
|
|
if (PcdIndex->StateByte.ExtendedGuidPresent) {
|
|
GuidSpace = (EFI_GUID *) GetAbsoluteAddress (PcdIndex->DynamicExGuid, Info->GuidTableOffset, Info);
|
|
if (CompareGuid (GuidSpace, Guid)) {
|
|
return PcdIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (Index != NULL) {
|
|
*Index = 0;
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function set the PCD Entry data value according to the
|
|
PCD_DATA_TYPE given.
|
|
|
|
@param[out] OutData The output data.
|
|
@param[in] InData The input data.
|
|
@param[in] Len The length of the data.
|
|
|
|
|
|
@retval EFI_SUCESS If data value is found according to SKU_ID.
|
|
@retval EFI_NOT_FOUND If not such a value is found.
|
|
|
|
--*/
|
|
VOID
|
|
SetDataBasedOnType (
|
|
OUT VOID * OutData,
|
|
IN CONST VOID * InData,
|
|
IN UINTN Len
|
|
)
|
|
{
|
|
CopyMem (OutData, InData, Len);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function returns the actual address of item in the PCD
|
|
database according to its Segment and Offset.
|
|
|
|
@param[out] Offset The offset within the segment.
|
|
@param[in] SegmentStart The starting address of the segment.
|
|
@param[in] DatabaseStart The base address of the PCD DataBase.
|
|
|
|
|
|
@retval UINT8* The absolute address.
|
|
|
|
--*/
|
|
UINT8 *
|
|
GetAbsoluteAddress (
|
|
IN UINTN Offset,
|
|
IN UINTN SegmentStart,
|
|
IN CONST PCD_DATABASE_HEADER *DatabaseStart
|
|
)
|
|
{
|
|
UINT8 *Address;
|
|
|
|
Address = (UINT8 *) DatabaseStart + SegmentStart + Offset;
|
|
|
|
return Address;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function retrieves the PCD data value according to
|
|
TokenNumber and Guid space given.
|
|
|
|
@param[in] Database The PCD Database Instance.
|
|
@param[in] TokenNumber The token number.
|
|
@param[in] Guid The Guid space.
|
|
@param[in] Type The storage type.
|
|
@param[out] Data The output data.
|
|
|
|
@retval VOID
|
|
|
|
--*/
|
|
VOID
|
|
GetPcdEntryWorker (
|
|
IN CONST PCD_DATABASE_HEADER *Info,
|
|
IN UINTN TokenNumber,
|
|
IN CONST EFI_GUID *Guid, OPTIONAL
|
|
IN PCD_DATA_TYPE Type,
|
|
OUT VOID *Data
|
|
)
|
|
{
|
|
PCD_INDEX *PcdIndex;
|
|
UINT8 *PcdData;
|
|
|
|
ASSERT (Data != NULL);
|
|
|
|
//
|
|
// Find the PCD entry in list in memory first
|
|
//
|
|
PcdIndex = FindPcdIndex (TokenNumber, Guid, Info, NULL);
|
|
|
|
ASSERT (PcdIndex != NULL);
|
|
|
|
ASSERT (PcdIndex->StateByte.DataType == Type);
|
|
|
|
PcdData = GetPcdDataPtr (PcdIndex, Info);
|
|
|
|
GetDataBasedOnType (PcdIndex->StateByte.DataType, PcdData, Data, PcdIndex->DatumSize);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function retrieves the PCD data value according to
|
|
TokenNumber and Guid space given.
|
|
|
|
@param[in] Database The PCD Database Instance.
|
|
@param[in] TokenNumber The token number.
|
|
@param[in] Guid The Guid space.
|
|
|
|
@retval UINTN The size of the PCD Entry.
|
|
|
|
--*/
|
|
UINTN
|
|
GetPcdEntrySizeWorker (
|
|
IN CONST PCD_DATABASE_HEADER *Info,
|
|
IN UINTN TokenNumber,
|
|
IN CONST EFI_GUID *Guid OPTIONAL
|
|
)
|
|
{
|
|
PCD_INDEX *PcdIndex;
|
|
|
|
//
|
|
// Find the PCD entry in list in memory first
|
|
//
|
|
PcdIndex = FindPcdIndex (TokenNumber, Guid, Info, NULL);
|
|
|
|
ASSERT (PcdIndex != NULL);
|
|
|
|
return PcdIndex->DatumSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The function checks if given GUID space match the record
|
|
in the PCD_INDEX.
|
|
|
|
@param[in] Guid The GUID space.
|
|
@param[in] PcdIndex The PCD_INDEX.
|
|
@param[in] Info The attribute of the PCD DATABASE.
|
|
|
|
@retval TRUE The GUID space match the record.
|
|
@retval FALSE Othewise.
|
|
|
|
--*/
|
|
BOOLEAN
|
|
PeiImageIndexMatchGuidSpace (
|
|
IN CONST EFI_GUID *Guid,
|
|
IN CONST PCD_INDEX *PcdIndex,
|
|
IN CONST PCD_DATABASE_HEADER *Info
|
|
)
|
|
{
|
|
EFI_GUID *GuidSpace;
|
|
|
|
if (PcdIndex->StateByte.ExtendedGuidPresent) {
|
|
GuidSpace = (EFI_GUID *) GetAbsoluteAddress (PcdIndex->DynamicExGuid, Info->GuidTableOffset, Info);
|
|
return CompareGuid (GuidSpace, Guid);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
The function looks for the next PCD ENTRY.
|
|
If *TokenNumber is 0, the first TokenNumber in
|
|
the GUID token space is return.
|
|
If there is no next TokenNumber found,
|
|
*TokenNumber will be 0.
|
|
|
|
@param[in] Database The PCD Database Instance.
|
|
@param[in,out] TokenNumber The token number.
|
|
@param[in] Guid The Guid space.
|
|
|
|
@retval EFI_NOT_FOUND Can't find the PCD_ENTRY.
|
|
@retval EFI_SUCCESS Operation succesful.
|
|
|
|
--*/
|
|
EFI_STATUS
|
|
GetNextTokenWorker (
|
|
IN CONST PCD_DATABASE_HEADER *Info,
|
|
IN OUT UINTN *TokenNumber,
|
|
IN CONST EFI_GUID *Guid OPTIONAL
|
|
)
|
|
{
|
|
PCD_INDEX *PcdIndex;
|
|
UINTN Idx;
|
|
BOOLEAN Found;
|
|
|
|
Idx = 0;
|
|
Found = FALSE;
|
|
PcdIndex = (PCD_INDEX *) GetAbsoluteAddress (0, Info->PcdIndexOffset, Info);
|
|
|
|
while ((Idx < Info->EntryCount) && !Found) {
|
|
if (*TokenNumber == 0) {
|
|
if (Guid == NULL || PeiImageIndexMatchGuidSpace (Guid, PcdIndex, Info)) {
|
|
*TokenNumber = PcdIndex->TokenNumber;
|
|
return EFI_SUCCESS;
|
|
}
|
|
} else {
|
|
if (PcdIndex->TokenNumber == *TokenNumber) {
|
|
if (Guid == NULL || PeiImageIndexMatchGuidSpace (Guid, PcdIndex, Info)) {
|
|
Found = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
PcdIndex++;
|
|
Idx++;
|
|
}
|
|
|
|
//
|
|
// No PCD Entry in the database match the GUID space given.
|
|
//
|
|
if (*TokenNumber == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Can't find the PCD Entry
|
|
//
|
|
if (!Found) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Move to the Next Entry
|
|
//
|
|
Idx++;
|
|
PcdIndex++;
|
|
|
|
//
|
|
// Now look for the Next TokenNumber
|
|
//
|
|
while (Idx < Info->EntryCount) {
|
|
if (Guid == NULL || PeiImageIndexMatchGuidSpace (Guid, PcdIndex, Info)) {
|
|
*TokenNumber = PcdIndex->TokenNumber;
|
|
return EFI_SUCCESS;
|
|
}
|
|
PcdIndex++;
|
|
Idx++;
|
|
}
|
|
|
|
//
|
|
// Reache the last TokeNumber.
|
|
//
|
|
*TokenNumber = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
The function is the worker function to set the data of a PCD entry.
|
|
|
|
@param[in] PcdIndex The PCD Index.
|
|
@param[in] Info The attributes of the PCD database.
|
|
@param[in] Data The input data.
|
|
|
|
@retval VOID
|
|
--*/
|
|
EFI_STATUS
|
|
SetPcdData (
|
|
IN CONST PCD_INDEX *PcdIndex,
|
|
IN CONST PCD_DATABASE_HEADER *Info,
|
|
IN CONST VOID *Data
|
|
)
|
|
{
|
|
UINT16 *VariableName;
|
|
UINT8 *PcdData;
|
|
EFI_GUID *VariableGuid;
|
|
EFI_STATUS Status;
|
|
UINTN SkuIdx;
|
|
UINTN ExtendedOffset;
|
|
|
|
if (PcdIndex->StateByte.VpdEnable) {
|
|
ASSERT (FALSE);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
SkuIdx = GetSkuIdIdx (PcdIndex, Info);
|
|
|
|
//
|
|
// For Hii and Data type, we need the ExtendedOffset.
|
|
// So get it here.
|
|
//
|
|
ExtendedOffset = GetExtendedDataOffset (PcdIndex, SkuIdx, Info);
|
|
|
|
if (PcdIndex->StateByte.HiiEnable) {
|
|
GetHiiDataProperty (PcdIndex, SkuIdx, Info, &VariableGuid, &VariableName);
|
|
|
|
Status = SetHiiVariable (VariableGuid,
|
|
VariableName,
|
|
Data,
|
|
PcdIndex->DatumSize,
|
|
ExtendedOffset
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
PcdData = GetAbsoluteAddress (
|
|
ExtendedOffset,
|
|
Info->DataBufferOffset,
|
|
Info
|
|
);
|
|
|
|
CopyMem (PcdData, Data, PcdIndex->DatumSize);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|