mirror of https://github.com/acidanthera/audk.git
2475 lines
74 KiB
C++
2475 lines
74 KiB
C++
/** @file
|
|
|
|
The definition of CFormPkg's member function
|
|
|
|
Copyright (c) 2004 - 2017, 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.
|
|
|
|
**/
|
|
|
|
#include "stdio.h"
|
|
#include "assert.h"
|
|
#include "VfrFormPkg.h"
|
|
|
|
/*
|
|
* The definition of CFormPkg's member function
|
|
*/
|
|
|
|
SPendingAssign::SPendingAssign (
|
|
IN CHAR8 *Key,
|
|
IN VOID *Addr,
|
|
IN UINT32 Len,
|
|
IN UINT32 LineNo,
|
|
IN CONST CHAR8 *Msg
|
|
)
|
|
{
|
|
mKey = NULL;
|
|
mAddr = Addr;
|
|
mLen = Len;
|
|
mFlag = PENDING;
|
|
mLineNo = LineNo;
|
|
mMsg = NULL;
|
|
mNext = NULL;
|
|
if (Key != NULL) {
|
|
mKey = new CHAR8[strlen (Key) + 1];
|
|
if (mKey != NULL) {
|
|
strcpy (mKey, Key);
|
|
}
|
|
}
|
|
|
|
if (Msg != NULL) {
|
|
mMsg = new CHAR8[strlen (Msg) + 1];
|
|
if (mMsg != NULL) {
|
|
strcpy (mMsg, Msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
SPendingAssign::~SPendingAssign (
|
|
VOID
|
|
)
|
|
{
|
|
if (mKey != NULL) {
|
|
delete[] mKey;
|
|
}
|
|
mAddr = NULL;
|
|
mLen = 0;
|
|
mLineNo = 0;
|
|
if (mMsg != NULL) {
|
|
delete[] mMsg;
|
|
}
|
|
mNext = NULL;
|
|
}
|
|
|
|
VOID
|
|
SPendingAssign::SetAddrAndLen (
|
|
IN VOID *Addr,
|
|
IN UINT32 LineNo
|
|
)
|
|
{
|
|
mAddr = Addr;
|
|
mLineNo = LineNo;
|
|
}
|
|
|
|
VOID
|
|
SPendingAssign::AssignValue (
|
|
IN VOID *Addr,
|
|
IN UINT32 Len
|
|
)
|
|
{
|
|
memmove (mAddr, Addr, (mLen < Len ? mLen : Len));
|
|
mFlag = ASSIGNED;
|
|
}
|
|
|
|
CHAR8 *
|
|
SPendingAssign::GetKey (
|
|
VOID
|
|
)
|
|
{
|
|
return mKey;
|
|
}
|
|
|
|
CFormPkg::CFormPkg (
|
|
IN UINT32 BufferSize
|
|
)
|
|
{
|
|
CHAR8 *BufferStart;
|
|
CHAR8 *BufferEnd;
|
|
SBufferNode *Node;
|
|
|
|
mPkgLength = 0;
|
|
mBufferSize = 0;
|
|
mBufferNodeQueueHead = NULL;
|
|
mBufferNodeQueueTail = NULL;
|
|
mCurrBufferNode = NULL;
|
|
mReadBufferNode = NULL;
|
|
mReadBufferOffset = 0;
|
|
PendingAssignList = NULL;
|
|
|
|
Node = new SBufferNode;
|
|
if (Node == NULL) {
|
|
return ;
|
|
}
|
|
BufferStart = new CHAR8[BufferSize];
|
|
if (BufferStart == NULL) {
|
|
delete Node;
|
|
return;
|
|
}
|
|
BufferEnd = BufferStart + BufferSize;
|
|
|
|
memset (BufferStart, 0, BufferSize);
|
|
Node->mBufferStart = BufferStart;
|
|
Node->mBufferEnd = BufferEnd;
|
|
Node->mBufferFree = BufferStart;
|
|
Node->mNext = NULL;
|
|
|
|
mBufferSize = BufferSize;
|
|
mBufferNodeQueueHead = Node;
|
|
mBufferNodeQueueTail = Node;
|
|
mCurrBufferNode = Node;
|
|
}
|
|
|
|
CFormPkg::~CFormPkg ()
|
|
{
|
|
SBufferNode *pBNode;
|
|
SPendingAssign *pPNode;
|
|
|
|
while (mBufferNodeQueueHead != NULL) {
|
|
pBNode = mBufferNodeQueueHead;
|
|
mBufferNodeQueueHead = mBufferNodeQueueHead->mNext;
|
|
if (pBNode->mBufferStart != NULL) {
|
|
delete pBNode->mBufferStart;
|
|
delete pBNode;
|
|
}
|
|
}
|
|
mBufferNodeQueueTail = NULL;
|
|
mCurrBufferNode = NULL;
|
|
|
|
while (PendingAssignList != NULL) {
|
|
pPNode = PendingAssignList;
|
|
PendingAssignList = PendingAssignList->mNext;
|
|
delete pPNode;
|
|
}
|
|
PendingAssignList = NULL;
|
|
}
|
|
|
|
SBufferNode *
|
|
CFormPkg::CreateNewNode (
|
|
VOID
|
|
)
|
|
{
|
|
SBufferNode *Node;
|
|
|
|
Node = new SBufferNode;
|
|
if (Node == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Node->mBufferStart = new CHAR8[mBufferSize];
|
|
if (Node->mBufferStart == NULL) {
|
|
delete Node;
|
|
return NULL;
|
|
} else {
|
|
memset (Node->mBufferStart, 0, mBufferSize);
|
|
Node->mBufferEnd = Node->mBufferStart + mBufferSize;
|
|
Node->mBufferFree = Node->mBufferStart;
|
|
Node->mNext = NULL;
|
|
}
|
|
|
|
return Node;
|
|
}
|
|
|
|
CHAR8 *
|
|
CFormPkg::IfrBinBufferGet (
|
|
IN UINT32 Len
|
|
)
|
|
{
|
|
CHAR8 *BinBuffer = NULL;
|
|
SBufferNode *Node = NULL;
|
|
|
|
if ((Len == 0) || (Len > mBufferSize)) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((mCurrBufferNode->mBufferFree + Len) <= mCurrBufferNode->mBufferEnd) {
|
|
BinBuffer = mCurrBufferNode->mBufferFree;
|
|
mCurrBufferNode->mBufferFree += Len;
|
|
} else {
|
|
Node = CreateNewNode ();
|
|
if (Node == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (mBufferNodeQueueTail == NULL) {
|
|
mBufferNodeQueueHead = mBufferNodeQueueTail = Node;
|
|
} else {
|
|
mBufferNodeQueueTail->mNext = Node;
|
|
mBufferNodeQueueTail = Node;
|
|
}
|
|
mCurrBufferNode = Node;
|
|
|
|
//
|
|
// Now try again.
|
|
//
|
|
BinBuffer = mCurrBufferNode->mBufferFree;
|
|
mCurrBufferNode->mBufferFree += Len;
|
|
}
|
|
|
|
mPkgLength += Len;
|
|
|
|
return BinBuffer;
|
|
}
|
|
|
|
inline
|
|
UINT32
|
|
CFormPkg::GetPkgLength (
|
|
VOID
|
|
)
|
|
{
|
|
return mPkgLength;
|
|
}
|
|
|
|
VOID
|
|
CFormPkg::Open (
|
|
VOID
|
|
)
|
|
{
|
|
mReadBufferNode = mBufferNodeQueueHead;
|
|
mReadBufferOffset = 0;
|
|
}
|
|
|
|
VOID
|
|
CFormPkg::Close (
|
|
VOID
|
|
)
|
|
{
|
|
mReadBufferNode = NULL;
|
|
mReadBufferOffset = 0;
|
|
}
|
|
|
|
UINT32
|
|
CFormPkg::Read (
|
|
IN CHAR8 *Buffer,
|
|
IN UINT32 Size
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
if ((Size == 0) || (Buffer == NULL)) {
|
|
return 0;
|
|
}
|
|
|
|
if (mReadBufferNode == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
for (Index = 0; Index < Size; Index++) {
|
|
if ((mReadBufferNode->mBufferStart + mReadBufferOffset) < mReadBufferNode->mBufferFree) {
|
|
Buffer[Index] = mReadBufferNode->mBufferStart[mReadBufferOffset++];
|
|
} else {
|
|
if ((mReadBufferNode = mReadBufferNode->mNext) == NULL) {
|
|
return Index;
|
|
} else {
|
|
mReadBufferOffset = 0;
|
|
Index --;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Size;
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::BuildPkgHdr (
|
|
OUT EFI_HII_PACKAGE_HEADER **PkgHdr
|
|
)
|
|
{
|
|
if (PkgHdr == NULL) {
|
|
return VFR_RETURN_FATAL_ERROR;
|
|
}
|
|
|
|
if (((*PkgHdr) = new EFI_HII_PACKAGE_HEADER) == NULL) {
|
|
return VFR_RETURN_OUT_FOR_RESOURCES;
|
|
}
|
|
|
|
(*PkgHdr)->Type = EFI_HII_PACKAGE_FORM;
|
|
(*PkgHdr)->Length = mPkgLength + sizeof (EFI_HII_PACKAGE_HEADER);
|
|
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::BuildPkg (
|
|
OUT PACKAGE_DATA &TBuffer
|
|
)
|
|
{
|
|
|
|
CHAR8 *Temp;
|
|
UINT32 Size;
|
|
CHAR8 Buffer[1024];
|
|
|
|
if (TBuffer.Buffer != NULL) {
|
|
delete TBuffer.Buffer;
|
|
}
|
|
|
|
TBuffer.Size = mPkgLength;
|
|
TBuffer.Buffer = NULL;
|
|
if (TBuffer.Size != 0) {
|
|
TBuffer.Buffer = new CHAR8[TBuffer.Size];
|
|
} else {
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
Temp = TBuffer.Buffer;
|
|
Open ();
|
|
while ((Size = Read (Buffer, 1024)) != 0) {
|
|
memcpy (Temp, Buffer, Size);
|
|
Temp += Size;
|
|
}
|
|
Close ();
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::BuildPkg (
|
|
IN FILE *Output,
|
|
IN PACKAGE_DATA *PkgData
|
|
)
|
|
{
|
|
EFI_VFR_RETURN_CODE Ret;
|
|
CHAR8 Buffer[1024];
|
|
UINT32 Size;
|
|
EFI_HII_PACKAGE_HEADER *PkgHdr;
|
|
|
|
if (Output == NULL) {
|
|
return VFR_RETURN_FATAL_ERROR;
|
|
}
|
|
|
|
if ((Ret = BuildPkgHdr(&PkgHdr)) != VFR_RETURN_SUCCESS) {
|
|
return Ret;
|
|
}
|
|
fwrite (PkgHdr, sizeof (EFI_HII_PACKAGE_HEADER), 1, Output);
|
|
delete PkgHdr;
|
|
|
|
if (PkgData == NULL) {
|
|
Open ();
|
|
while ((Size = Read (Buffer, 1024)) != 0) {
|
|
fwrite (Buffer, Size, 1, Output);
|
|
}
|
|
Close ();
|
|
} else {
|
|
fwrite (PkgData->Buffer, PkgData->Size, 1, Output);
|
|
}
|
|
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
CFormPkg::_WRITE_PKG_LINE (
|
|
IN FILE *pFile,
|
|
IN UINT32 LineBytes,
|
|
IN CONST CHAR8 *LineHeader,
|
|
IN CHAR8 *BlkBuf,
|
|
IN UINT32 BlkSize
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
if ((pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {
|
|
return;
|
|
}
|
|
|
|
for (Index = 0; Index < BlkSize; Index++) {
|
|
if ((Index % LineBytes) == 0) {
|
|
fprintf (pFile, "\n%s", LineHeader);
|
|
}
|
|
fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CFormPkg::_WRITE_PKG_END (
|
|
IN FILE *pFile,
|
|
IN UINT32 LineBytes,
|
|
IN CONST CHAR8 *LineHeader,
|
|
IN CHAR8 *BlkBuf,
|
|
IN UINT32 BlkSize
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
if ((BlkSize == 0) || (pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {
|
|
return;
|
|
}
|
|
|
|
for (Index = 0; Index < BlkSize - 1; Index++) {
|
|
if ((Index % LineBytes) == 0) {
|
|
fprintf (pFile, "\n%s", LineHeader);
|
|
}
|
|
fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]);
|
|
}
|
|
|
|
if ((Index % LineBytes) == 0) {
|
|
fprintf (pFile, "\n%s", LineHeader);
|
|
}
|
|
fprintf (pFile, "0x%02X\n", (UINT8)BlkBuf[Index]);
|
|
}
|
|
|
|
#define BYTES_PRE_LINE 0x10
|
|
UINT32 gAdjustOpcodeOffset = 0;
|
|
BOOLEAN gNeedAdjustOpcode = FALSE;
|
|
UINT32 gAdjustOpcodeLen = 0;
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::GenCFile (
|
|
IN CHAR8 *BaseName,
|
|
IN FILE *pFile,
|
|
IN PACKAGE_DATA *PkgData
|
|
)
|
|
{
|
|
EFI_VFR_RETURN_CODE Ret;
|
|
CHAR8 Buffer[BYTES_PRE_LINE * 8];
|
|
EFI_HII_PACKAGE_HEADER *PkgHdr;
|
|
UINT32 PkgLength = 0;
|
|
UINT32 ReadSize = 0;
|
|
|
|
if ((BaseName == NULL) || (pFile == NULL)) {
|
|
return VFR_RETURN_FATAL_ERROR;
|
|
}
|
|
|
|
fprintf (pFile, "\nunsigned char %sBin[] = {\n", BaseName);
|
|
|
|
if ((Ret = BuildPkgHdr(&PkgHdr)) != VFR_RETURN_SUCCESS) {
|
|
return Ret;
|
|
}
|
|
|
|
//
|
|
// For framework vfr file, the extension framework header will be added.
|
|
//
|
|
if (VfrCompatibleMode) {
|
|
fprintf (pFile, " // FRAMEWORK PACKAGE HEADER Length\n");
|
|
PkgLength = PkgHdr->Length + sizeof (UINT32) + 2;
|
|
_WRITE_PKG_LINE(pFile, BYTES_PRE_LINE, " ", (CHAR8 *)&PkgLength, sizeof (UINT32));
|
|
fprintf (pFile, "\n\n // FRAMEWORK PACKAGE HEADER Type\n");
|
|
PkgLength = 3;
|
|
_WRITE_PKG_LINE(pFile, BYTES_PRE_LINE, " ", (CHAR8 *)&PkgLength, sizeof (UINT16));
|
|
} else {
|
|
fprintf (pFile, " // ARRAY LENGTH\n");
|
|
PkgLength = PkgHdr->Length + sizeof (UINT32);
|
|
_WRITE_PKG_LINE(pFile, BYTES_PRE_LINE, " ", (CHAR8 *)&PkgLength, sizeof (UINT32));
|
|
}
|
|
|
|
fprintf (pFile, "\n\n // PACKAGE HEADER\n");
|
|
_WRITE_PKG_LINE(pFile, BYTES_PRE_LINE, " ", (CHAR8 *)PkgHdr, sizeof (EFI_HII_PACKAGE_HEADER));
|
|
PkgLength = sizeof (EFI_HII_PACKAGE_HEADER);
|
|
|
|
fprintf (pFile, "\n\n // PACKAGE DATA\n");
|
|
|
|
if (PkgData == NULL) {
|
|
Open ();
|
|
while ((ReadSize = Read ((CHAR8 *)Buffer, BYTES_PRE_LINE * 8)) != 0) {
|
|
PkgLength += ReadSize;
|
|
if (PkgLength < PkgHdr->Length) {
|
|
_WRITE_PKG_LINE (pFile, BYTES_PRE_LINE, " ", Buffer, ReadSize);
|
|
} else {
|
|
_WRITE_PKG_END (pFile, BYTES_PRE_LINE, " ", Buffer, ReadSize);
|
|
}
|
|
}
|
|
Close ();
|
|
} else {
|
|
if (PkgData->Size % BYTES_PRE_LINE != 0) {
|
|
PkgLength = PkgData->Size - (PkgData->Size % BYTES_PRE_LINE);
|
|
_WRITE_PKG_LINE (pFile, BYTES_PRE_LINE, " ", PkgData->Buffer, PkgLength);
|
|
_WRITE_PKG_END (pFile, BYTES_PRE_LINE, " ", PkgData->Buffer + PkgLength, PkgData->Size % BYTES_PRE_LINE);
|
|
} else {
|
|
PkgLength = PkgData->Size - BYTES_PRE_LINE;
|
|
_WRITE_PKG_LINE (pFile, BYTES_PRE_LINE, " ", PkgData->Buffer, PkgLength);
|
|
_WRITE_PKG_END (pFile, BYTES_PRE_LINE, " ", PkgData->Buffer + PkgLength, BYTES_PRE_LINE);
|
|
}
|
|
}
|
|
|
|
delete PkgHdr;
|
|
fprintf (pFile, "\n};\n");
|
|
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::AssignPending (
|
|
IN CHAR8 *Key,
|
|
IN VOID *ValAddr,
|
|
IN UINT32 ValLen,
|
|
IN UINT32 LineNo,
|
|
IN CONST CHAR8 *Msg
|
|
)
|
|
{
|
|
SPendingAssign *pNew;
|
|
|
|
pNew = new SPendingAssign (Key, ValAddr, ValLen, LineNo, Msg);
|
|
if (pNew == NULL) {
|
|
return VFR_RETURN_OUT_FOR_RESOURCES;
|
|
}
|
|
|
|
pNew->mNext = PendingAssignList;
|
|
PendingAssignList = pNew;
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
CFormPkg::DoPendingAssign (
|
|
IN CHAR8 *Key,
|
|
IN VOID *ValAddr,
|
|
IN UINT32 ValLen
|
|
)
|
|
{
|
|
SPendingAssign *pNode;
|
|
|
|
if ((Key == NULL) || (ValAddr == NULL)) {
|
|
return;
|
|
}
|
|
|
|
for (pNode = PendingAssignList; pNode != NULL; pNode = pNode->mNext) {
|
|
if (strcmp (pNode->mKey, Key) == 0) {
|
|
pNode->AssignValue (ValAddr, ValLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
CFormPkg::HavePendingUnassigned (
|
|
VOID
|
|
)
|
|
{
|
|
SPendingAssign *pNode;
|
|
|
|
for (pNode = PendingAssignList; pNode != NULL; pNode = pNode->mNext) {
|
|
if (pNode->mFlag == PENDING) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
CFormPkg::PendingAssignPrintAll (
|
|
VOID
|
|
)
|
|
{
|
|
SPendingAssign *pNode;
|
|
|
|
for (pNode = PendingAssignList; pNode != NULL; pNode = pNode->mNext) {
|
|
if (pNode->mFlag == PENDING) {
|
|
gCVfrErrorHandle.PrintMsg (pNode->mLineNo, pNode->mKey, "Error", pNode->mMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
SBufferNode *
|
|
CFormPkg::GetBinBufferNodeForAddr (
|
|
IN CHAR8 *BinBuffAddr
|
|
)
|
|
{
|
|
SBufferNode *TmpNode;
|
|
|
|
TmpNode = mBufferNodeQueueHead;
|
|
|
|
while (TmpNode != NULL) {
|
|
if (TmpNode->mBufferStart <= BinBuffAddr && TmpNode->mBufferFree >= BinBuffAddr) {
|
|
return TmpNode;
|
|
}
|
|
|
|
TmpNode = TmpNode->mNext;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
SBufferNode *
|
|
CFormPkg::GetNodeBefore(
|
|
IN SBufferNode *CurrentNode
|
|
)
|
|
{
|
|
SBufferNode *FirstNode = mBufferNodeQueueHead;
|
|
SBufferNode *LastNode = mBufferNodeQueueHead;
|
|
|
|
while (FirstNode != NULL) {
|
|
if (FirstNode == CurrentNode) {
|
|
break;
|
|
}
|
|
|
|
LastNode = FirstNode;
|
|
FirstNode = FirstNode->mNext;
|
|
}
|
|
|
|
if (FirstNode == NULL) {
|
|
LastNode = NULL;
|
|
}
|
|
|
|
return LastNode;
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::InsertNodeBefore(
|
|
IN SBufferNode *CurrentNode,
|
|
IN SBufferNode *NewNode
|
|
)
|
|
{
|
|
SBufferNode *LastNode = GetNodeBefore (CurrentNode);
|
|
|
|
if (LastNode == NULL) {
|
|
return VFR_RETURN_MISMATCHED;
|
|
}
|
|
|
|
NewNode->mNext = LastNode->mNext;
|
|
LastNode->mNext = NewNode;
|
|
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
CHAR8 *
|
|
CFormPkg::GetBufAddrBaseOnOffset (
|
|
IN UINT32 Offset
|
|
)
|
|
{
|
|
SBufferNode *TmpNode;
|
|
UINT32 TotalBufLen;
|
|
UINT32 CurrentBufLen;
|
|
|
|
TotalBufLen = 0;
|
|
|
|
for (TmpNode = mBufferNodeQueueHead; TmpNode != NULL; TmpNode = TmpNode->mNext) {
|
|
CurrentBufLen = TmpNode->mBufferFree - TmpNode->mBufferStart;
|
|
if (Offset >= TotalBufLen && Offset < TotalBufLen + CurrentBufLen) {
|
|
return TmpNode->mBufferStart + (Offset - TotalBufLen);
|
|
}
|
|
|
|
TotalBufLen += CurrentBufLen;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::AdjustDynamicInsertOpcode (
|
|
IN CHAR8 *InserPositionAddr,
|
|
IN CHAR8 *InsertOpcodeAddr,
|
|
IN BOOLEAN CreateOpcodeAfterParsingVfr
|
|
)
|
|
{
|
|
SBufferNode *InserPositionNode;
|
|
SBufferNode *InsertOpcodeNode;
|
|
SBufferNode *NewRestoreNodeBegin;
|
|
SBufferNode *NewRestoreNodeEnd;
|
|
SBufferNode *NewLastEndNode;
|
|
SBufferNode *TmpNode;
|
|
UINT32 NeedRestoreCodeLen;
|
|
|
|
NewRestoreNodeEnd = NULL;
|
|
|
|
InserPositionNode = GetBinBufferNodeForAddr(InserPositionAddr);
|
|
InsertOpcodeNode = GetBinBufferNodeForAddr(InsertOpcodeAddr);
|
|
assert (InserPositionNode != NULL);
|
|
assert (InsertOpcodeNode != NULL);
|
|
|
|
if (InserPositionNode == InsertOpcodeNode) {
|
|
//
|
|
// Create New Node to save the restore opcode.
|
|
//
|
|
NeedRestoreCodeLen = InsertOpcodeAddr - InserPositionAddr;
|
|
gAdjustOpcodeLen = NeedRestoreCodeLen;
|
|
NewRestoreNodeBegin = CreateNewNode ();
|
|
if (NewRestoreNodeBegin == NULL) {
|
|
return VFR_RETURN_OUT_FOR_RESOURCES;
|
|
}
|
|
memcpy (NewRestoreNodeBegin->mBufferFree, InserPositionAddr, NeedRestoreCodeLen);
|
|
NewRestoreNodeBegin->mBufferFree += NeedRestoreCodeLen;
|
|
|
|
//
|
|
// Override the restore buffer data.
|
|
//
|
|
memmove (InserPositionAddr, InsertOpcodeAddr, InsertOpcodeNode->mBufferFree - InsertOpcodeAddr);
|
|
InsertOpcodeNode->mBufferFree -= NeedRestoreCodeLen;
|
|
memset (InsertOpcodeNode->mBufferFree, 0, NeedRestoreCodeLen);
|
|
} else {
|
|
//
|
|
// Create New Node to save the restore opcode.
|
|
//
|
|
NeedRestoreCodeLen = InserPositionNode->mBufferFree - InserPositionAddr;
|
|
gAdjustOpcodeLen = NeedRestoreCodeLen;
|
|
NewRestoreNodeBegin = CreateNewNode ();
|
|
if (NewRestoreNodeBegin == NULL) {
|
|
return VFR_RETURN_OUT_FOR_RESOURCES;
|
|
}
|
|
memcpy (NewRestoreNodeBegin->mBufferFree, InserPositionAddr, NeedRestoreCodeLen);
|
|
NewRestoreNodeBegin->mBufferFree += NeedRestoreCodeLen;
|
|
//
|
|
// Override the restore buffer data.
|
|
//
|
|
InserPositionNode->mBufferFree -= NeedRestoreCodeLen;
|
|
//
|
|
// Link the restore data to new node.
|
|
//
|
|
NewRestoreNodeBegin->mNext = InserPositionNode->mNext;
|
|
|
|
//
|
|
// Count the Adjust opcode len.
|
|
//
|
|
TmpNode = InserPositionNode->mNext;
|
|
while (TmpNode != InsertOpcodeNode) {
|
|
gAdjustOpcodeLen += TmpNode->mBufferFree - TmpNode->mBufferStart;
|
|
TmpNode = TmpNode->mNext;
|
|
}
|
|
|
|
//
|
|
// Create New Node to save the last node of restore opcode.
|
|
//
|
|
NeedRestoreCodeLen = InsertOpcodeAddr - InsertOpcodeNode->mBufferStart;
|
|
gAdjustOpcodeLen += NeedRestoreCodeLen;
|
|
if (NeedRestoreCodeLen > 0) {
|
|
NewRestoreNodeEnd = CreateNewNode ();
|
|
if (NewRestoreNodeEnd == NULL) {
|
|
return VFR_RETURN_OUT_FOR_RESOURCES;
|
|
}
|
|
memcpy (NewRestoreNodeEnd->mBufferFree, InsertOpcodeNode->mBufferStart, NeedRestoreCodeLen);
|
|
NewRestoreNodeEnd->mBufferFree += NeedRestoreCodeLen;
|
|
//
|
|
// Override the restore buffer data.
|
|
//
|
|
memmove (InsertOpcodeNode->mBufferStart, InsertOpcodeAddr, InsertOpcodeNode->mBufferFree - InsertOpcodeAddr);
|
|
InsertOpcodeNode->mBufferFree -= InsertOpcodeAddr - InsertOpcodeNode->mBufferStart;
|
|
|
|
//
|
|
// Insert the last restore data node.
|
|
//
|
|
TmpNode = GetNodeBefore (InsertOpcodeNode);
|
|
assert (TmpNode != NULL);
|
|
|
|
if (TmpNode == InserPositionNode) {
|
|
NewRestoreNodeBegin->mNext = NewRestoreNodeEnd;
|
|
} else {
|
|
TmpNode->mNext = NewRestoreNodeEnd;
|
|
}
|
|
//
|
|
// Connect the dynamic opcode node to the node after InserPositionNode.
|
|
//
|
|
InserPositionNode->mNext = InsertOpcodeNode;
|
|
}
|
|
}
|
|
|
|
if (CreateOpcodeAfterParsingVfr) {
|
|
//
|
|
// Th new opcodes were created after Parsing Vfr file,
|
|
// so the content in mBufferNodeQueueTail must be the new created opcodes.
|
|
// So connet the NewRestoreNodeBegin to the tail and update the tail node.
|
|
//
|
|
mBufferNodeQueueTail->mNext = NewRestoreNodeBegin;
|
|
if (NewRestoreNodeEnd != NULL) {
|
|
mBufferNodeQueueTail = NewRestoreNodeEnd;
|
|
} else {
|
|
mBufferNodeQueueTail = NewRestoreNodeBegin;
|
|
}
|
|
} else {
|
|
if (mBufferNodeQueueTail->mBufferFree - mBufferNodeQueueTail->mBufferStart > 2) {
|
|
//
|
|
// End form set opcode all in the mBufferNodeQueueTail node.
|
|
//
|
|
NewLastEndNode = CreateNewNode ();
|
|
if (NewLastEndNode == NULL) {
|
|
return VFR_RETURN_OUT_FOR_RESOURCES;
|
|
}
|
|
NewLastEndNode->mBufferStart[0] = 0x29;
|
|
NewLastEndNode->mBufferStart[1] = 0x02;
|
|
NewLastEndNode->mBufferFree += 2;
|
|
|
|
mBufferNodeQueueTail->mBufferFree -= 2;
|
|
|
|
mBufferNodeQueueTail->mNext = NewRestoreNodeBegin;
|
|
if (NewRestoreNodeEnd != NULL) {
|
|
NewRestoreNodeEnd->mNext = NewLastEndNode;
|
|
} else {
|
|
NewRestoreNodeBegin->mNext = NewLastEndNode;
|
|
}
|
|
|
|
mBufferNodeQueueTail = NewLastEndNode;
|
|
} else if (mBufferNodeQueueTail->mBufferFree - mBufferNodeQueueTail->mBufferStart == 2) {
|
|
TmpNode = GetNodeBefore(mBufferNodeQueueTail);
|
|
assert (TmpNode != NULL);
|
|
|
|
TmpNode->mNext = NewRestoreNodeBegin;
|
|
if (NewRestoreNodeEnd != NULL) {
|
|
NewRestoreNodeEnd->mNext = mBufferNodeQueueTail;
|
|
} else {
|
|
NewRestoreNodeBegin->mNext = mBufferNodeQueueTail;
|
|
}
|
|
}
|
|
}
|
|
mCurrBufferNode = mBufferNodeQueueTail;
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CFormPkg::DeclarePendingQuestion (
|
|
IN CVfrVarDataTypeDB &lCVfrVarDataTypeDB,
|
|
IN CVfrDataStorage &lCVfrDataStorage,
|
|
IN CVfrQuestionDB &lCVfrQuestionDB,
|
|
IN EFI_GUID *LocalFormSetGuid,
|
|
IN UINT32 LineNo,
|
|
OUT CHAR8 **InsertOpcodeAddr
|
|
)
|
|
{
|
|
SPendingAssign *pNode;
|
|
CHAR8 *VarStr;
|
|
UINT32 ArrayIdx;
|
|
CHAR8 FName[MAX_NAME_LEN];
|
|
CHAR8 *SName;
|
|
CHAR8 *NewStr;
|
|
UINT32 ShrinkSize = 0;
|
|
EFI_VFR_RETURN_CODE ReturnCode;
|
|
EFI_VFR_VARSTORE_TYPE VarStoreType = EFI_VFR_VARSTORE_INVALID;
|
|
UINT8 LFlags;
|
|
UINT32 MaxValue;
|
|
CIfrGuid *GuidObj = NULL;
|
|
|
|
//
|
|
// Declare all questions as Numeric in DisableIf True
|
|
//
|
|
// DisableIf
|
|
CIfrDisableIf DIObj;
|
|
DIObj.SetLineNo (LineNo);
|
|
*InsertOpcodeAddr = DIObj.GetObjBinAddr<CHAR8>();
|
|
|
|
//TrueOpcode
|
|
CIfrTrue TObj (LineNo);
|
|
|
|
// Declare Numeric qeustion for each undefined question.
|
|
for (pNode = PendingAssignList; pNode != NULL; pNode = pNode->mNext) {
|
|
if (pNode->mFlag == PENDING) {
|
|
EFI_VARSTORE_INFO Info;
|
|
EFI_QUESTION_ID QId = EFI_QUESTION_ID_INVALID;
|
|
//
|
|
// Register this question, assume it is normal question, not date or time question
|
|
//
|
|
VarStr = pNode->mKey;
|
|
ReturnCode = lCVfrQuestionDB.RegisterQuestion (NULL, VarStr, QId);
|
|
if (ReturnCode != VFR_RETURN_SUCCESS) {
|
|
gCVfrErrorHandle.HandleError (ReturnCode, pNode->mLineNo, pNode->mKey);
|
|
return ReturnCode;
|
|
}
|
|
|
|
#ifdef VFREXP_DEBUG
|
|
printf ("Undefined Question name is %s and Id is 0x%x\n", VarStr, QId);
|
|
#endif
|
|
//
|
|
// Get Question Info, framework vfr VarName == StructName
|
|
//
|
|
ReturnCode = lCVfrVarDataTypeDB.ExtractFieldNameAndArrary (VarStr, FName, ArrayIdx);
|
|
if (ReturnCode != VFR_RETURN_SUCCESS) {
|
|
gCVfrErrorHandle.PrintMsg (pNode->mLineNo, pNode->mKey, "Error", "Var string is not the valid C variable");
|
|
return ReturnCode;
|
|
}
|
|
//
|
|
// Get VarStoreType
|
|
//
|
|
ReturnCode = lCVfrDataStorage.GetVarStoreId (FName, &Info.mVarStoreId);
|
|
if (ReturnCode != VFR_RETURN_SUCCESS) {
|
|
gCVfrErrorHandle.PrintMsg (pNode->mLineNo, FName, "Error", "Var Store Type is not defined");
|
|
return ReturnCode;
|
|
}
|
|
VarStoreType = lCVfrDataStorage.GetVarStoreType (Info.mVarStoreId);
|
|
|
|
if (*VarStr == '\0' && ArrayIdx != INVALID_ARRAY_INDEX) {
|
|
ReturnCode = lCVfrDataStorage.GetNameVarStoreInfo (&Info, ArrayIdx);
|
|
} else {
|
|
if (VarStoreType == EFI_VFR_VARSTORE_EFI) {
|
|
ReturnCode = lCVfrDataStorage.GetEfiVarStoreInfo (&Info);
|
|
} else if (VarStoreType == EFI_VFR_VARSTORE_BUFFER || VarStoreType == EFI_VFR_VARSTORE_BUFFER_BITS) {
|
|
VarStr = pNode->mKey;
|
|
//convert VarStr with store name to VarStr with structure name
|
|
ReturnCode = lCVfrDataStorage.GetBufferVarStoreDataTypeName (Info.mVarStoreId, &SName);
|
|
if (ReturnCode == VFR_RETURN_SUCCESS) {
|
|
NewStr = new CHAR8[strlen (VarStr) + strlen (SName) + 1];
|
|
NewStr[0] = '\0';
|
|
strcpy (NewStr, SName);
|
|
strcat (NewStr, VarStr + strlen (FName));
|
|
ReturnCode = lCVfrVarDataTypeDB.GetDataFieldInfo (NewStr, Info.mInfo.mVarOffset, Info.mVarType, Info.mVarTotalSize, Info.mIsBitVar);
|
|
delete[] NewStr;
|
|
}
|
|
} else {
|
|
ReturnCode = VFR_RETURN_UNSUPPORTED;
|
|
}
|
|
}
|
|
if (ReturnCode != VFR_RETURN_SUCCESS) {
|
|
gCVfrErrorHandle.HandleError (ReturnCode, pNode->mLineNo, pNode->mKey);
|
|
return ReturnCode;
|
|
}
|
|
//
|
|
// If the storage is bit fields, create Guid opcode to wrap the numeric opcode.
|
|
//
|
|
if (Info.mIsBitVar) {
|
|
GuidObj = new CIfrGuid(0);
|
|
GuidObj->SetGuid (&gEdkiiIfrBitVarGuid);
|
|
GuidObj->SetLineNo(LineNo);
|
|
}
|
|
|
|
CIfrNumeric CNObj;
|
|
CNObj.SetLineNo (LineNo);
|
|
CNObj.SetPrompt (0x0);
|
|
CNObj.SetHelp (0x0);
|
|
CNObj.SetQuestionId (QId);
|
|
CNObj.SetVarStoreInfo (&Info);
|
|
|
|
//
|
|
// Set Min/Max/Step Data and flags for the question with bit fields.Min/Max/Step Data are saved as UINT32 type for bit question.
|
|
//
|
|
if (Info.mIsBitVar) {
|
|
MaxValue = (1 << Info.mVarTotalSize) -1;
|
|
CNObj.SetMinMaxStepData ((UINT32) 0, MaxValue, (UINT32) 0);
|
|
ShrinkSize = 12;
|
|
LFlags = (EDKII_IFR_NUMERIC_SIZE_BIT & Info.mVarTotalSize);
|
|
CNObj.SetFlagsForBitField (0, LFlags);
|
|
} else {
|
|
//
|
|
// Numeric doesn't support BOOLEAN data type.
|
|
// BOOLEAN type has the same data size to UINT8.
|
|
//
|
|
if (Info.mVarType == EFI_IFR_TYPE_BOOLEAN) {
|
|
Info.mVarType = EFI_IFR_TYPE_NUM_SIZE_8;
|
|
}
|
|
CNObj.SetFlags (0, Info.mVarType);
|
|
//
|
|
// Use maximum value not to limit the vaild value for the undefined question.
|
|
//
|
|
switch (Info.mVarType) {
|
|
case EFI_IFR_TYPE_NUM_SIZE_64:
|
|
CNObj.SetMinMaxStepData ((UINT64) 0, (UINT64) -1 , (UINT64) 0);
|
|
ShrinkSize = 0;
|
|
break;
|
|
case EFI_IFR_TYPE_NUM_SIZE_32:
|
|
CNObj.SetMinMaxStepData ((UINT32) 0, (UINT32) -1 , (UINT32) 0);
|
|
ShrinkSize = 12;
|
|
break;
|
|
case EFI_IFR_TYPE_NUM_SIZE_16:
|
|
CNObj.SetMinMaxStepData ((UINT16) 0, (UINT16) -1 , (UINT16) 0);
|
|
ShrinkSize = 18;
|
|
break;
|
|
case EFI_IFR_TYPE_NUM_SIZE_8:
|
|
CNObj.SetMinMaxStepData ((UINT8) 0, (UINT8) -1 , (UINT8) 0);
|
|
ShrinkSize = 21;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
CNObj.ShrinkBinSize (ShrinkSize);
|
|
|
|
//
|
|
// For undefined Efi VarStore type question
|
|
// Append the extended guided opcode to contain VarName
|
|
//
|
|
if (VarStoreType == EFI_VFR_VARSTORE_EFI || VfrCompatibleMode) {
|
|
CIfrVarEqName CVNObj (QId, Info.mInfo.mVarName);
|
|
CVNObj.SetLineNo (LineNo);
|
|
}
|
|
|
|
//
|
|
// End for Numeric
|
|
//
|
|
CIfrEnd CEObj;
|
|
CEObj.SetLineNo (LineNo);
|
|
//
|
|
// End for Guided opcode
|
|
//
|
|
if (GuidObj != NULL) {
|
|
CIfrEnd CEObjGuid;
|
|
CEObjGuid.SetLineNo (LineNo);
|
|
GuidObj->SetScope(1);
|
|
delete GuidObj;
|
|
GuidObj = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// End for DisableIf
|
|
//
|
|
CIfrEnd SEObj;
|
|
SEObj.SetLineNo (LineNo);
|
|
|
|
return VFR_RETURN_SUCCESS;
|
|
}
|
|
|
|
CFormPkg gCFormPkg;
|
|
|
|
SIfrRecord::SIfrRecord (
|
|
VOID
|
|
)
|
|
{
|
|
mIfrBinBuf = NULL;
|
|
mBinBufLen = 0;
|
|
mLineNo = 0xFFFFFFFF;
|
|
mOffset = 0xFFFFFFFF;
|
|
mNext = NULL;
|
|
}
|
|
|
|
SIfrRecord::~SIfrRecord (
|
|
VOID
|
|
)
|
|
{
|
|
if (mIfrBinBuf != NULL) {
|
|
//delete mIfrBinBuf;
|
|
mIfrBinBuf = NULL;
|
|
}
|
|
mLineNo = 0xFFFFFFFF;
|
|
mOffset = 0xFFFFFFFF;
|
|
mBinBufLen = 0;
|
|
mNext = NULL;
|
|
}
|
|
|
|
CIfrRecordInfoDB::CIfrRecordInfoDB (
|
|
VOID
|
|
)
|
|
{
|
|
mSwitch = TRUE;
|
|
mRecordCount = EFI_IFR_RECORDINFO_IDX_START;
|
|
mIfrRecordListHead = NULL;
|
|
mIfrRecordListTail = NULL;
|
|
mAllDefaultTypeCount = 0;
|
|
for (UINT8 i = 0; i < EFI_HII_MAX_SUPPORT_DEFAULT_TYPE; i++) {
|
|
mAllDefaultIdArray[i] = 0xffff;
|
|
}
|
|
}
|
|
|
|
CIfrRecordInfoDB::~CIfrRecordInfoDB (
|
|
VOID
|
|
)
|
|
{
|
|
SIfrRecord *pNode;
|
|
|
|
while (mIfrRecordListHead != NULL) {
|
|
pNode = mIfrRecordListHead;
|
|
mIfrRecordListHead = mIfrRecordListHead->mNext;
|
|
delete pNode;
|
|
}
|
|
}
|
|
|
|
SIfrRecord *
|
|
CIfrRecordInfoDB::GetRecordInfoFromIdx (
|
|
IN UINT32 RecordIdx
|
|
)
|
|
{
|
|
UINT32 Idx;
|
|
SIfrRecord *pNode = NULL;
|
|
|
|
if (RecordIdx == EFI_IFR_RECORDINFO_IDX_INVALUD) {
|
|
return NULL;
|
|
}
|
|
|
|
for (Idx = (EFI_IFR_RECORDINFO_IDX_START + 1), pNode = mIfrRecordListHead;
|
|
(Idx != RecordIdx) && (pNode != NULL);
|
|
Idx++, pNode = pNode->mNext)
|
|
;
|
|
|
|
return pNode;
|
|
}
|
|
|
|
UINT32
|
|
CIfrRecordInfoDB::IfrRecordRegister (
|
|
IN UINT32 LineNo,
|
|
IN CHAR8 *IfrBinBuf,
|
|
IN UINT8 BinBufLen,
|
|
IN UINT32 Offset
|
|
)
|
|
{
|
|
SIfrRecord *pNew;
|
|
|
|
if (mSwitch == FALSE) {
|
|
return EFI_IFR_RECORDINFO_IDX_INVALUD;
|
|
}
|
|
|
|
if ((pNew = new SIfrRecord) == NULL) {
|
|
return EFI_IFR_RECORDINFO_IDX_INVALUD;
|
|
}
|
|
|
|
if (mIfrRecordListHead == NULL) {
|
|
mIfrRecordListHead = pNew;
|
|
mIfrRecordListTail = pNew;
|
|
} else {
|
|
mIfrRecordListTail->mNext = pNew;
|
|
mIfrRecordListTail = pNew;
|
|
}
|
|
mRecordCount++;
|
|
|
|
return mRecordCount;
|
|
}
|
|
|
|
VOID
|
|
CIfrRecordInfoDB::IfrRecordInfoUpdate (
|
|
IN UINT32 RecordIdx,
|
|
IN UINT32 LineNo,
|
|
IN CHAR8 *BinBuf,
|
|
IN UINT8 BinBufLen,
|
|
IN UINT32 Offset
|
|
)
|
|
{
|
|
SIfrRecord *pNode;
|
|
SIfrRecord *Prev;
|
|
|
|
if ((pNode = GetRecordInfoFromIdx (RecordIdx)) == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (LineNo == 0) {
|
|
//
|
|
// Line number is not specified explicitly, try to use line number of previous opcode
|
|
//
|
|
Prev = GetRecordInfoFromIdx (RecordIdx - 1);
|
|
if (Prev != NULL) {
|
|
LineNo = Prev->mLineNo;
|
|
}
|
|
}
|
|
|
|
pNode->mLineNo = LineNo;
|
|
pNode->mOffset = Offset;
|
|
pNode->mBinBufLen = BinBufLen;
|
|
pNode->mIfrBinBuf = BinBuf;
|
|
|
|
}
|
|
|
|
VOID
|
|
CIfrRecordInfoDB::IfrRecordOutput (
|
|
OUT PACKAGE_DATA &TBuffer
|
|
)
|
|
{
|
|
CHAR8 *Temp;
|
|
SIfrRecord *pNode;
|
|
|
|
if (TBuffer.Buffer != NULL) {
|
|
delete TBuffer.Buffer;
|
|
}
|
|
|
|
TBuffer.Size = 0;
|
|
TBuffer.Buffer = NULL;
|
|
|
|
|
|
if (mSwitch == FALSE) {
|
|
return;
|
|
}
|
|
|
|
for (pNode = mIfrRecordListHead; pNode != NULL; pNode = pNode->mNext) {
|
|
TBuffer.Size += pNode->mBinBufLen;
|
|
}
|
|
|
|
if (TBuffer.Size != 0) {
|
|
TBuffer.Buffer = new CHAR8[TBuffer.Size];
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
Temp = TBuffer.Buffer;
|
|
|
|
for (pNode = mIfrRecordListHead; pNode != NULL; pNode = pNode->mNext) {
|
|
if (pNode->mIfrBinBuf != NULL) {
|
|
memcpy (Temp, pNode->mIfrBinBuf, pNode->mBinBufLen);
|
|
Temp += pNode->mBinBufLen;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
CIfrRecordInfoDB::IfrRecordOutput (
|
|
IN FILE *File,
|
|
IN UINT32 LineNo
|
|
)
|
|
{
|
|
SIfrRecord *pNode;
|
|
UINT8 Index;
|
|
UINT32 TotalSize;
|
|
|
|
if (mSwitch == FALSE) {
|
|
return;
|
|
}
|
|
|
|
if (File == NULL) {
|
|
return;
|
|
}
|
|
|
|
TotalSize = 0;
|
|
|
|
for (pNode = mIfrRecordListHead; pNode != NULL; pNode = pNode->mNext) {
|
|
if (pNode->mLineNo == LineNo || LineNo == 0) {
|
|
fprintf (File, ">%08X: ", pNode->mOffset);
|
|
TotalSize += pNode->mBinBufLen;
|
|
if (pNode->mIfrBinBuf != NULL) {
|
|
for (Index = 0; Index < pNode->mBinBufLen; Index++) {
|
|
fprintf (File, "%02X ", (UINT8)(pNode->mIfrBinBuf[Index]));
|
|
}
|
|
}
|
|
fprintf (File, "\n");
|
|
}
|
|
}
|
|
|
|
if (LineNo == 0) {
|
|
fprintf (File, "\nTotal Size of all record is 0x%08X\n", TotalSize);
|
|
}
|
|
}
|
|
|
|
//
|
|
// for framework vfr file
|
|
// adjust opcode sequence for uefi IFR format
|
|
// adjust inconsistent and varstore into the right position.
|
|
//
|
|
BOOLEAN
|
|
CIfrRecordInfoDB::CheckQuestionOpCode (
|
|
IN UINT8 OpCode
|
|
)
|
|
{
|
|
switch (OpCode) {
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
case EFI_IFR_NUMERIC_OP:
|
|
case EFI_IFR_PASSWORD_OP:
|
|
case EFI_IFR_ONE_OF_OP:
|
|
case EFI_IFR_ACTION_OP:
|
|
case EFI_IFR_STRING_OP:
|
|
case EFI_IFR_DATE_OP:
|
|
case EFI_IFR_TIME_OP:
|
|
case EFI_IFR_ORDERED_LIST_OP:
|
|
case EFI_IFR_REF_OP:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
CIfrRecordInfoDB::CheckIdOpCode (
|
|
IN UINT8 OpCode
|
|
)
|
|
{
|
|
switch (OpCode) {
|
|
case EFI_IFR_EQ_ID_VAL_OP:
|
|
case EFI_IFR_EQ_ID_ID_OP:
|
|
case EFI_IFR_EQ_ID_VAL_LIST_OP:
|
|
case EFI_IFR_QUESTION_REF1_OP:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
EFI_QUESTION_ID
|
|
CIfrRecordInfoDB::GetOpcodeQuestionId (
|
|
IN EFI_IFR_OP_HEADER *OpHead
|
|
)
|
|
{
|
|
EFI_IFR_QUESTION_HEADER *QuestionHead;
|
|
|
|
QuestionHead = (EFI_IFR_QUESTION_HEADER *) (OpHead + 1);
|
|
|
|
return QuestionHead->QuestionId;
|
|
}
|
|
|
|
SIfrRecord *
|
|
CIfrRecordInfoDB::GetRecordInfoFromOffset (
|
|
IN UINT32 Offset
|
|
)
|
|
{
|
|
SIfrRecord *pNode = NULL;
|
|
|
|
for (pNode = mIfrRecordListHead; pNode != NULL; pNode = pNode->mNext) {
|
|
if (pNode->mOffset == Offset) {
|
|
return pNode;
|
|
}
|
|
}
|
|
|
|
return pNode;
|
|
}
|
|
|
|
/**
|
|
Add just the op code position.
|
|
|
|
Case1 (CreateOpcodeAfterParsingVfr == FALSE): The dynamic opcodes were created before the formset opcode,
|
|
so pDynamicOpcodeNodes is before mIfrRecordListTail.
|
|
|
|
From
|
|
|
|
|mIfrRecordListHead + ...+ pAdjustNode + pDynamicOpcodeNodes + mIfrRecordListTail|
|
|
|
|
To
|
|
|
|
|mIfrRecordListHead + ...+ pDynamicOpcodeNodes + pAdjustNode + mIfrRecordListTail|
|
|
|
|
Case2 (CreateOpcodeAfterParsingVfr == TRUE): The dynamic opcodes were created after paring the vfr file,
|
|
so new records are appennded to the end of OriginalIfrRecordListTail.
|
|
|
|
From
|
|
|
|
|mIfrRecordListHead + ...+ pAdjustNode + ... + OriginalIfrRecordListTail + pDynamicOpcodeNodes|
|
|
|
|
To
|
|
|
|
|mIfrRecordListHead + ...+ pDynamicOpcodeNodes + pAdjustNode + ... + OriginalIfrRecordListTail|
|
|
|
|
|
|
@param CreateOpcodeAfterParsingVfr Whether create the dynamic opcode after parsing the VFR file.
|
|
|
|
**/
|
|
BOOLEAN
|
|
CIfrRecordInfoDB::IfrAdjustDynamicOpcodeInRecords (
|
|
IN BOOLEAN CreateOpcodeAfterParsingVfr
|
|
)
|
|
{
|
|
UINT32 OpcodeOffset;
|
|
SIfrRecord *pNode, *pPreNode;
|
|
SIfrRecord *pAdjustNode, *pNodeBeforeAdjust;
|
|
SIfrRecord *pNodeBeforeDynamic;
|
|
|
|
pPreNode = NULL;
|
|
pAdjustNode = NULL;
|
|
pNodeBeforeDynamic = NULL;
|
|
OpcodeOffset = 0;
|
|
|
|
//
|
|
// Base on the gAdjustOpcodeOffset and gAdjustOpcodeLen to find the pAdjustNod, the node before pAdjustNode,
|
|
// and the node before pDynamicOpcodeNode.
|
|
//
|
|
for (pNode = mIfrRecordListHead; pNode!= NULL; pNode = pNode->mNext) {
|
|
if (OpcodeOffset == gAdjustOpcodeOffset) {
|
|
pAdjustNode = pNode;
|
|
pNodeBeforeAdjust = pPreNode;
|
|
} else if (OpcodeOffset == gAdjustOpcodeOffset + gAdjustOpcodeLen) {
|
|
pNodeBeforeDynamic = pPreNode;
|
|
}
|
|
if (pNode->mNext != NULL) {
|
|
pPreNode = pNode;
|
|
}
|
|
OpcodeOffset += pNode->mBinBufLen;
|
|
}
|
|
|
|
//
|
|
// Check the nodes whether exist.
|
|
//
|
|
if (pNodeBeforeDynamic == NULL || pAdjustNode == NULL || pNodeBeforeAdjust == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Adjust the node. pPreNode save the Node before mIfrRecordListTail
|
|
//
|
|
pNodeBeforeAdjust->mNext = pNodeBeforeDynamic->mNext;
|
|
if (CreateOpcodeAfterParsingVfr) {
|
|
//
|
|
// mIfrRecordListTail is the end of pDynamicNode (Case2).
|
|
//
|
|
mIfrRecordListTail->mNext = pAdjustNode;
|
|
mIfrRecordListTail = pNodeBeforeDynamic;
|
|
mIfrRecordListTail->mNext = NULL;
|
|
} else {
|
|
//
|
|
//pPreNode is the end of pDynamicNode(Case1).
|
|
//
|
|
pPreNode->mNext = pAdjustNode;
|
|
pNodeBeforeDynamic->mNext = mIfrRecordListTail;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Update the record info(the position in the record list, offset and mIfrBinBuf) for new created record.
|
|
|
|
@param CreateOpcodeAfterParsingVfr Whether create the dynamic opcode after parsing the VFR file.
|
|
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrUpdateRecordInfoForDynamicOpcode (
|
|
IN BOOLEAN CreateOpcodeAfterParsingVfr
|
|
)
|
|
{
|
|
SIfrRecord *pRecord;
|
|
|
|
//
|
|
// Base on the original offset info to update the record list.
|
|
//
|
|
if (!IfrAdjustDynamicOpcodeInRecords(CreateOpcodeAfterParsingVfr)) {
|
|
gCVfrErrorHandle.PrintMsg (0, (CHAR8 *)"Error", (CHAR8 *)"Can not find the adjust offset in the record.");
|
|
}
|
|
|
|
//
|
|
// Base on the opcode binary length to recalculate the offset for each opcode.
|
|
//
|
|
IfrAdjustOffsetForRecord();
|
|
|
|
//
|
|
// Base on the offset to find the binary address.
|
|
//
|
|
pRecord = GetRecordInfoFromOffset(gAdjustOpcodeOffset);
|
|
while (pRecord != NULL) {
|
|
pRecord->mIfrBinBuf = gCFormPkg.GetBufAddrBaseOnOffset(pRecord->mOffset);
|
|
pRecord = pRecord->mNext;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CIfrRecordInfoDB::IfrAdjustOffsetForRecord (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 OpcodeOffset;
|
|
SIfrRecord *pNode;
|
|
|
|
OpcodeOffset = 0;
|
|
for (pNode = mIfrRecordListHead; pNode != NULL; pNode = pNode->mNext) {
|
|
pNode->mOffset = OpcodeOffset;
|
|
OpcodeOffset += pNode->mBinBufLen;
|
|
}
|
|
}
|
|
|
|
EFI_VFR_RETURN_CODE
|
|
CIfrRecordInfoDB::IfrRecordAdjust (
|
|
VOID
|
|
)
|
|
{
|
|
SIfrRecord *pNode, *preNode;
|
|
SIfrRecord *uNode, *tNode;
|
|
EFI_IFR_OP_HEADER *OpHead, *tOpHead;
|
|
EFI_QUESTION_ID QuestionId;
|
|
UINT32 StackCount;
|
|
UINT32 QuestionScope;
|
|
CHAR8 ErrorMsg[MAX_STRING_LEN] = {0, };
|
|
EFI_VFR_RETURN_CODE Status;
|
|
|
|
//
|
|
// Init local variable
|
|
//
|
|
Status = VFR_RETURN_SUCCESS;
|
|
pNode = mIfrRecordListHead;
|
|
preNode = pNode;
|
|
QuestionScope = 0;
|
|
while (pNode != NULL) {
|
|
OpHead = (EFI_IFR_OP_HEADER *) pNode->mIfrBinBuf;
|
|
|
|
//
|
|
// make sure the inconsistent opcode in question scope
|
|
//
|
|
if (QuestionScope > 0) {
|
|
QuestionScope += OpHead->Scope;
|
|
if (OpHead->OpCode == EFI_IFR_END_OP) {
|
|
QuestionScope --;
|
|
}
|
|
}
|
|
|
|
if (CheckQuestionOpCode (OpHead->OpCode)) {
|
|
QuestionScope = 1;
|
|
}
|
|
//
|
|
// for the inconsistent opcode not in question scope, adjust it
|
|
//
|
|
if (OpHead->OpCode == EFI_IFR_INCONSISTENT_IF_OP && QuestionScope == 0) {
|
|
//
|
|
// for inconsistent opcode not in question scope
|
|
//
|
|
|
|
//
|
|
// Count inconsistent opcode Scope
|
|
//
|
|
StackCount = OpHead->Scope;
|
|
QuestionId = EFI_QUESTION_ID_INVALID;
|
|
tNode = pNode;
|
|
while (tNode != NULL && StackCount > 0) {
|
|
tNode = tNode->mNext;
|
|
tOpHead = (EFI_IFR_OP_HEADER *) tNode->mIfrBinBuf;
|
|
//
|
|
// Calculate Scope Number
|
|
//
|
|
StackCount += tOpHead->Scope;
|
|
if (tOpHead->OpCode == EFI_IFR_END_OP) {
|
|
StackCount --;
|
|
}
|
|
//
|
|
// by IdEqual opcode to get QuestionId
|
|
//
|
|
if (QuestionId == EFI_QUESTION_ID_INVALID &&
|
|
CheckIdOpCode (tOpHead->OpCode)) {
|
|
QuestionId = *(EFI_QUESTION_ID *) (tOpHead + 1);
|
|
}
|
|
}
|
|
if (tNode == NULL || QuestionId == EFI_QUESTION_ID_INVALID) {
|
|
//
|
|
// report error; not found
|
|
//
|
|
sprintf (ErrorMsg, "Inconsistent OpCode Record list invalid QuestionId is 0x%X", QuestionId);
|
|
gCVfrErrorHandle.PrintMsg (0, NULL, "Error", ErrorMsg);
|
|
Status = VFR_RETURN_MISMATCHED;
|
|
break;
|
|
}
|
|
//
|
|
// extract inconsistent opcode list
|
|
// pNode is Incosistent opcode, tNode is End Opcode
|
|
//
|
|
|
|
//
|
|
// insert inconsistent opcode list into the right question scope by questionid
|
|
//
|
|
for (uNode = mIfrRecordListHead; uNode != NULL; uNode = uNode->mNext) {
|
|
tOpHead = (EFI_IFR_OP_HEADER *) uNode->mIfrBinBuf;
|
|
if (CheckQuestionOpCode (tOpHead->OpCode) &&
|
|
(QuestionId == GetOpcodeQuestionId (tOpHead))) {
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// insert inconsistent opcode list and check LATE_CHECK flag
|
|
//
|
|
if (uNode != NULL) {
|
|
if ((((EFI_IFR_QUESTION_HEADER *)(tOpHead + 1))->Flags & 0x20) != 0) {
|
|
//
|
|
// if LATE_CHECK flag is set, change inconsistent to nosumbit
|
|
//
|
|
OpHead->OpCode = EFI_IFR_NO_SUBMIT_IF_OP;
|
|
}
|
|
|
|
//
|
|
// skip the default storage for Date and Time
|
|
//
|
|
if ((uNode->mNext != NULL) && (*uNode->mNext->mIfrBinBuf == EFI_IFR_DEFAULT_OP)) {
|
|
uNode = uNode->mNext;
|
|
}
|
|
|
|
preNode->mNext = tNode->mNext;
|
|
tNode->mNext = uNode->mNext;
|
|
uNode->mNext = pNode;
|
|
//
|
|
// reset pNode to head list, scan the whole list again.
|
|
//
|
|
pNode = mIfrRecordListHead;
|
|
preNode = pNode;
|
|
QuestionScope = 0;
|
|
continue;
|
|
} else {
|
|
//
|
|
// not found matched question id, report error
|
|
//
|
|
sprintf (ErrorMsg, "QuestionId required by Inconsistent OpCode is not found. QuestionId is 0x%X", QuestionId);
|
|
gCVfrErrorHandle.PrintMsg (0, NULL, "Error", ErrorMsg);
|
|
Status = VFR_RETURN_MISMATCHED;
|
|
break;
|
|
}
|
|
} else if (OpHead->OpCode == EFI_IFR_VARSTORE_OP ||
|
|
OpHead->OpCode == EFI_IFR_VARSTORE_EFI_OP) {
|
|
//
|
|
// for new added group of varstore opcode
|
|
//
|
|
tNode = pNode;
|
|
while (tNode->mNext != NULL) {
|
|
tOpHead = (EFI_IFR_OP_HEADER *) tNode->mNext->mIfrBinBuf;
|
|
if (tOpHead->OpCode != EFI_IFR_VARSTORE_OP &&
|
|
tOpHead->OpCode != EFI_IFR_VARSTORE_EFI_OP) {
|
|
break;
|
|
}
|
|
tNode = tNode->mNext;
|
|
}
|
|
|
|
if (tNode->mNext == NULL) {
|
|
//
|
|
// invalid IfrCode, IfrCode end by EndOpCode
|
|
//
|
|
gCVfrErrorHandle.PrintMsg (0, NULL, "Error", "No found End Opcode in the end");
|
|
Status = VFR_RETURN_MISMATCHED;
|
|
break;
|
|
}
|
|
|
|
if (tOpHead->OpCode != EFI_IFR_END_OP) {
|
|
//
|
|
// not new added varstore, which are not needed to be adjust.
|
|
//
|
|
preNode = tNode;
|
|
pNode = tNode->mNext;
|
|
continue;
|
|
} else {
|
|
//
|
|
// move new added varstore opcode to the position befor form opcode
|
|
// varstore opcode between pNode and tNode
|
|
//
|
|
|
|
//
|
|
// search form opcode from begin
|
|
//
|
|
for (uNode = mIfrRecordListHead; uNode->mNext != NULL; uNode = uNode->mNext) {
|
|
tOpHead = (EFI_IFR_OP_HEADER *) uNode->mNext->mIfrBinBuf;
|
|
if (tOpHead->OpCode == EFI_IFR_FORM_OP) {
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Insert varstore opcode beform form opcode if form opcode is found
|
|
//
|
|
if (uNode->mNext != NULL) {
|
|
preNode->mNext = tNode->mNext;
|
|
tNode->mNext = uNode->mNext;
|
|
uNode->mNext = pNode;
|
|
//
|
|
// reset pNode to head list, scan the whole list again.
|
|
//
|
|
pNode = mIfrRecordListHead;
|
|
preNode = pNode;
|
|
QuestionScope = 0;
|
|
continue;
|
|
} else {
|
|
//
|
|
// not found form, continue scan IfrRecord list
|
|
//
|
|
preNode = tNode;
|
|
pNode = tNode->mNext;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// next node
|
|
//
|
|
preNode = pNode;
|
|
pNode = pNode->mNext;
|
|
}
|
|
|
|
//
|
|
// Update Ifr Opcode Offset
|
|
//
|
|
if (Status == VFR_RETURN_SUCCESS) {
|
|
IfrAdjustOffsetForRecord ();
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
When the Varstore of the question is EFI_VFR_VARSTORE_BUFFER and the default value is not
|
|
given by expression, should save the default info for the Buffer VarStore.
|
|
|
|
@param DefaultId The default id.
|
|
@param pQuestionNode Point to the question opcode node.
|
|
@param Value The default value.
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrAddDefaultToBufferConfig (
|
|
IN UINT16 DefaultId,
|
|
IN SIfrRecord *pQuestionNode,
|
|
IN EFI_IFR_TYPE_VALUE Value
|
|
)
|
|
{
|
|
CHAR8 *VarStoreName = NULL;
|
|
EFI_VFR_VARSTORE_TYPE VarStoreType = EFI_VFR_VARSTORE_INVALID;
|
|
EFI_GUID *VarGuid = NULL;
|
|
EFI_VARSTORE_INFO VarInfo;
|
|
EFI_IFR_QUESTION_HEADER *QuestionHead;
|
|
EFI_IFR_OP_HEADER *pQuestionOpHead;
|
|
|
|
pQuestionOpHead = (EFI_IFR_OP_HEADER *) pQuestionNode->mIfrBinBuf;
|
|
QuestionHead = (EFI_IFR_QUESTION_HEADER *) (pQuestionOpHead + 1);
|
|
|
|
//
|
|
// Get the Var Store name and type.
|
|
//
|
|
gCVfrDataStorage.GetVarStoreName (QuestionHead->VarStoreId, &VarStoreName);
|
|
VarGuid= gCVfrDataStorage.GetVarStoreGuid (QuestionHead->VarStoreId);
|
|
VarStoreType = gCVfrDataStorage.GetVarStoreType (QuestionHead->VarStoreId);
|
|
|
|
//
|
|
// Only for Buffer storage need to save the default info in the storage.
|
|
// Other type storage, just return.
|
|
//
|
|
if (VarStoreType != EFI_VFR_VARSTORE_BUFFER) {
|
|
return;
|
|
} else {
|
|
VarInfo.mInfo.mVarOffset = QuestionHead->VarStoreInfo.VarOffset;
|
|
VarInfo.mVarStoreId = QuestionHead->VarStoreId;
|
|
}
|
|
|
|
//
|
|
// Get the buffer storage info about this question.
|
|
//
|
|
gCVfrDataStorage.GetBufferVarStoreFieldInfo (&VarInfo);
|
|
|
|
//
|
|
// Add action.
|
|
//
|
|
gCVfrDefaultStore.BufferVarStoreAltConfigAdd (
|
|
DefaultId,
|
|
VarInfo,
|
|
VarStoreName,
|
|
VarGuid,
|
|
VarInfo.mVarType,
|
|
Value
|
|
);
|
|
}
|
|
|
|
/**
|
|
Record the number and default id of all defaultstore opcode.
|
|
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrGetDefaultStoreInfo (
|
|
VOID
|
|
)
|
|
{
|
|
SIfrRecord *pNode;
|
|
EFI_IFR_OP_HEADER *pOpHead;
|
|
EFI_IFR_DEFAULTSTORE *DefaultStore;
|
|
|
|
pNode = mIfrRecordListHead;
|
|
mAllDefaultTypeCount = 0;
|
|
|
|
while (pNode != NULL) {
|
|
pOpHead = (EFI_IFR_OP_HEADER *) pNode->mIfrBinBuf;
|
|
|
|
if (pOpHead->OpCode == EFI_IFR_DEFAULTSTORE_OP){
|
|
DefaultStore = (EFI_IFR_DEFAULTSTORE *) pNode->mIfrBinBuf;
|
|
mAllDefaultIdArray[mAllDefaultTypeCount++] = DefaultStore->DefaultId;
|
|
}
|
|
pNode = pNode->mNext;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Create new default opcode record.
|
|
|
|
@param Size The new default opcode size.
|
|
@param DefaultId The new default id.
|
|
@param Type The new default type.
|
|
@param LineNo The line number of the new record.
|
|
@param Value The new default value.
|
|
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrCreateDefaultRecord(
|
|
IN UINT8 Size,
|
|
IN UINT16 DefaultId,
|
|
IN UINT8 Type,
|
|
IN UINT32 LineNo,
|
|
IN EFI_IFR_TYPE_VALUE Value
|
|
)
|
|
{
|
|
CIfrDefault *DObj;
|
|
CIfrDefault2 *DObj2;
|
|
|
|
DObj = NULL;
|
|
DObj2 = NULL;
|
|
|
|
if (Type == EFI_IFR_TYPE_OTHER) {
|
|
DObj2 = new CIfrDefault2 (Size);
|
|
DObj2->SetDefaultId(DefaultId);
|
|
DObj2->SetType(Type);
|
|
DObj2->SetLineNo(LineNo);
|
|
DObj2->SetScope (1);
|
|
delete DObj2;
|
|
} else {
|
|
DObj = new CIfrDefault (Size);
|
|
DObj->SetDefaultId(DefaultId);
|
|
DObj->SetType(Type);
|
|
DObj->SetLineNo(LineNo);
|
|
DObj->SetValue (Value);
|
|
delete DObj;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Create new default opcode for question base on the QuestionDefaultInfo.
|
|
|
|
@param pQuestionNode Point to the question opcode Node.
|
|
@param QuestionDefaultInfo Point to the QuestionDefaultInfo for current question.
|
|
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrCreateDefaultForQuestion (
|
|
IN SIfrRecord *pQuestionNode,
|
|
IN QuestionDefaultRecord *QuestionDefaultInfo
|
|
)
|
|
{
|
|
EFI_IFR_OP_HEADER *pOpHead;
|
|
EFI_IFR_DEFAULT *Default;
|
|
SIfrRecord *pSNode;
|
|
SIfrRecord *pENode;
|
|
SIfrRecord *pDefaultNode;
|
|
CIfrObj *Obj;
|
|
CHAR8 *ObjBinBuf;
|
|
UINT8 ScopeCount;
|
|
UINT8 OpcodeNumber;
|
|
UINT8 OpcodeCount;
|
|
UINT8 DefaultSize;
|
|
EFI_IFR_ONE_OF_OPTION *DefaultOptionOpcode;
|
|
EFI_IFR_TYPE_VALUE CheckBoxDefaultValue;
|
|
|
|
CheckBoxDefaultValue.b = 1;
|
|
pOpHead = (EFI_IFR_OP_HEADER *) pQuestionNode->mIfrBinBuf;
|
|
ScopeCount = 0;
|
|
OpcodeCount = 0;
|
|
Obj = NULL;
|
|
|
|
//
|
|
// Record the offset of node which need to be adjust, will move the new created default opcode to this offset.
|
|
//
|
|
gAdjustOpcodeOffset = pQuestionNode->mNext->mOffset;
|
|
//
|
|
// Case 1:
|
|
// For oneof, the default with smallest default id is given by the option flag.
|
|
// So create the missing defaults base on the oneof option value(mDefaultValueRecord).
|
|
//
|
|
if (pOpHead->OpCode == EFI_IFR_ONE_OF_OP && !QuestionDefaultInfo->mIsDefaultOpcode) {
|
|
DefaultOptionOpcode = (EFI_IFR_ONE_OF_OPTION *)QuestionDefaultInfo->mDefaultValueRecord->mIfrBinBuf;
|
|
DefaultSize = QuestionDefaultInfo->mDefaultValueRecord->mBinBufLen - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value);
|
|
DefaultSize += OFFSET_OF (EFI_IFR_DEFAULT, Value);
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
IfrCreateDefaultRecord (DefaultSize, mAllDefaultIdArray[i], DefaultOptionOpcode->Type, pQuestionNode->mLineNo, DefaultOptionOpcode->Value);
|
|
//
|
|
// Save the new created default in the buffer storage.
|
|
//
|
|
IfrAddDefaultToBufferConfig (mAllDefaultIdArray[i], pQuestionNode, DefaultOptionOpcode->Value);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Case2:
|
|
// For checkbox, the default with smallest default id is given by the question flag.
|
|
// And create the missing defaults with true value.
|
|
//
|
|
if (pOpHead-> OpCode == EFI_IFR_CHECKBOX_OP && !QuestionDefaultInfo->mIsDefaultOpcode) {
|
|
DefaultSize = OFFSET_OF (EFI_IFR_DEFAULT, Value) + sizeof (BOOLEAN);
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
IfrCreateDefaultRecord (DefaultSize, mAllDefaultIdArray[i], EFI_IFR_TYPE_BOOLEAN, pQuestionNode->mLineNo, CheckBoxDefaultValue);
|
|
//
|
|
// Save the new created default.
|
|
//
|
|
IfrAddDefaultToBufferConfig (mAllDefaultIdArray[i], pQuestionNode, CheckBoxDefaultValue);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Case3:
|
|
// The default with smallest default id is given by the default opcode.
|
|
// So create the missing defaults base on the value in the default opcode.
|
|
//
|
|
|
|
//
|
|
// pDefaultNode point to the mDefaultValueRecord in QuestionDefaultInfo.
|
|
//
|
|
pDefaultNode = QuestionDefaultInfo->mDefaultValueRecord;
|
|
Default = (EFI_IFR_DEFAULT *)pDefaultNode->mIfrBinBuf;
|
|
//
|
|
// Record the offset of node which need to be adjust, will move the new created default opcode to this offset.
|
|
//
|
|
gAdjustOpcodeOffset = pDefaultNode->mNext->mOffset;
|
|
|
|
if (Default->Type == EFI_IFR_TYPE_OTHER) {
|
|
//
|
|
// EFI_IFR_DEFAULT_2 opcode.
|
|
//
|
|
// Point to the first expression opcode.
|
|
//
|
|
pSNode = pDefaultNode->mNext;
|
|
pENode = NULL;
|
|
ScopeCount++;
|
|
//
|
|
// Get opcode number behind the EFI_IFR_DEFAULT_2 until reach its END opcode (including the END opcode of EFI_IFR_DEFAULT_2)
|
|
//
|
|
while (pSNode != NULL && pSNode->mNext != NULL && ScopeCount != 0) {
|
|
pOpHead = (EFI_IFR_OP_HEADER *) pSNode->mIfrBinBuf;
|
|
if (pOpHead->Scope == 1) {
|
|
ScopeCount++;
|
|
}
|
|
if (pOpHead->OpCode == EFI_IFR_END_OP) {
|
|
ScopeCount--;
|
|
}
|
|
pENode = pSNode;
|
|
pSNode = pSNode->mNext;
|
|
OpcodeCount++;
|
|
}
|
|
|
|
assert (pSNode);
|
|
assert (pENode);
|
|
|
|
//
|
|
// Record the offset of node which need to be adjust, will move the new created default opcode to this offset.
|
|
//
|
|
gAdjustOpcodeOffset = pSNode->mOffset;
|
|
//
|
|
// Create new default opcode node for missing default.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
OpcodeNumber = OpcodeCount;
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
IfrCreateDefaultRecord (Default->Header.Length, mAllDefaultIdArray[i], Default->Type, pENode->mLineNo, Default->Value);
|
|
//
|
|
// Point to the first expression opcode node.
|
|
//
|
|
pSNode = pDefaultNode->mNext;
|
|
//
|
|
// Create the expression opcode and end opcode for the new created EFI_IFR_DEFAULT_2 opcode.
|
|
//
|
|
while (pSNode != NULL && pSNode->mNext != NULL && OpcodeNumber-- != 0) {
|
|
pOpHead = (EFI_IFR_OP_HEADER *) pSNode->mIfrBinBuf;
|
|
Obj = new CIfrObj (pOpHead->OpCode, NULL, pSNode->mBinBufLen, FALSE);
|
|
assert (Obj != NULL);
|
|
Obj->SetLineNo (pSNode->mLineNo);
|
|
ObjBinBuf = Obj->GetObjBinAddr<CHAR8>();
|
|
memcpy (ObjBinBuf, pSNode->mIfrBinBuf, (UINTN)pSNode->mBinBufLen);
|
|
delete Obj;
|
|
pSNode = pSNode->mNext;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// EFI_IFR_DEFAULT opcode.
|
|
//
|
|
// Create new default opcode node for missing default.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
IfrCreateDefaultRecord (Default->Header.Length, mAllDefaultIdArray[i], Default->Type, pDefaultNode->mLineNo, Default->Value);
|
|
//
|
|
// Save the new created default in the buffer storage..
|
|
//
|
|
IfrAddDefaultToBufferConfig (mAllDefaultIdArray[i], pQuestionNode, Default->Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Parse the default information in a question, get the QuestionDefaultInfo.
|
|
|
|
@param pQuestionNode Point to the question record Node.
|
|
@param QuestionDefaultInfo On return, point to the QuestionDefaultInfo.
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrParseDefaulInfoInQuestion(
|
|
IN SIfrRecord *pQuestionNode,
|
|
OUT QuestionDefaultRecord *QuestionDefaultInfo
|
|
)
|
|
{
|
|
SIfrRecord *pSNode;
|
|
EFI_IFR_ONE_OF_OPTION *OneofOptionOpcode;
|
|
EFI_IFR_OP_HEADER *pSOpHead;
|
|
EFI_IFR_CHECKBOX *CheckBoxOpcode;
|
|
EFI_IFR_DEFAULT *DefaultOpcode;
|
|
BOOLEAN IsOneOfOpcode;
|
|
UINT16 SmallestDefaultId;
|
|
UINT8 ScopeCount;
|
|
|
|
SmallestDefaultId = 0xffff;
|
|
IsOneOfOpcode = FALSE;
|
|
ScopeCount = 0;
|
|
pSNode = pQuestionNode;
|
|
|
|
//
|
|
// Parse all the opcodes in the Question.
|
|
//
|
|
while (pSNode != NULL) {
|
|
pSOpHead = (EFI_IFR_OP_HEADER *) pSNode->mIfrBinBuf;
|
|
//
|
|
// For a question, its scope bit must be set, the scope exists until it reaches a corresponding EFI_IFR_END_OP.
|
|
// Scopes may be nested within other scopes.
|
|
// When finishing parsing a question, the scope count must be zero.
|
|
//
|
|
if (pSOpHead->Scope == 1) {
|
|
ScopeCount++;
|
|
}
|
|
if (pSOpHead->OpCode == EFI_IFR_END_OP) {
|
|
ScopeCount--;
|
|
}
|
|
//
|
|
// Check whether finishing parsing a question.
|
|
//
|
|
if (ScopeCount == 0) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Record the default information in the question.
|
|
//
|
|
switch (pSOpHead->OpCode) {
|
|
case EFI_IFR_ONE_OF_OP:
|
|
IsOneOfOpcode = TRUE;
|
|
break;
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
//
|
|
// The default info of check box may be given by flag.
|
|
// So need to check the flag of check box.
|
|
//
|
|
CheckBoxOpcode = (EFI_IFR_CHECKBOX *)pSNode->mIfrBinBuf;
|
|
if ((CheckBoxOpcode->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0) {
|
|
//
|
|
// Check whether need to update the smallest default id.
|
|
//
|
|
if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
|
|
SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
|
|
}
|
|
//
|
|
// Update the QuestionDefaultInfo.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (mAllDefaultIdArray[i] == EFI_HII_DEFAULT_CLASS_STANDARD) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
QuestionDefaultInfo->mDefaultNumber ++;
|
|
QuestionDefaultInfo->mIsDefaultIdExist[i] = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((CheckBoxOpcode->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0) {
|
|
//
|
|
// Check whether need to update the smallest default id.
|
|
//
|
|
if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
|
|
SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
|
|
}
|
|
//
|
|
// Update the QuestionDefaultInfo.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (mAllDefaultIdArray[i] == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
QuestionDefaultInfo->mDefaultNumber ++;
|
|
QuestionDefaultInfo->mIsDefaultIdExist[i] = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EFI_IFR_ONE_OF_OPTION_OP:
|
|
if (!IsOneOfOpcode) {
|
|
//
|
|
// Only check the option in oneof.
|
|
//
|
|
break;
|
|
}
|
|
OneofOptionOpcode = (EFI_IFR_ONE_OF_OPTION *)pSNode->mIfrBinBuf;
|
|
if ((OneofOptionOpcode->Flags & EFI_IFR_OPTION_DEFAULT) != 0) {
|
|
//
|
|
// The option is used as the standard default.
|
|
// Check whether need to update the smallest default id and QuestionDefaultInfo.
|
|
//
|
|
if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
|
|
SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
|
|
QuestionDefaultInfo->mDefaultValueRecord = pSNode;
|
|
}
|
|
//
|
|
// Update the IsDefaultIdExist array in QuestionDefaultInfo.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (mAllDefaultIdArray[i] == EFI_HII_DEFAULT_CLASS_STANDARD) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
QuestionDefaultInfo->mDefaultNumber ++;
|
|
QuestionDefaultInfo->mIsDefaultIdExist[i] = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((OneofOptionOpcode->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0) {
|
|
//
|
|
// This option is used as the manufacture default.
|
|
// Check whether need to update the smallest default id and QuestionDefaultInfo.
|
|
//
|
|
if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
|
|
SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
|
|
QuestionDefaultInfo->mDefaultValueRecord = pSNode;
|
|
}
|
|
//
|
|
// Update the QuestionDefaultInfo.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++) {
|
|
if (mAllDefaultIdArray[i] == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
QuestionDefaultInfo->mDefaultNumber ++;
|
|
QuestionDefaultInfo->mIsDefaultIdExist[i] = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case EFI_IFR_DEFAULT_OP:
|
|
DefaultOpcode = (EFI_IFR_DEFAULT *) pSNode->mIfrBinBuf;
|
|
//
|
|
// Check whether need to update the smallest default id and QuestionDefaultInfo.
|
|
//
|
|
if (SmallestDefaultId >= DefaultOpcode->DefaultId ) {
|
|
SmallestDefaultId = DefaultOpcode->DefaultId;
|
|
QuestionDefaultInfo->mDefaultValueRecord= pSNode;
|
|
QuestionDefaultInfo->mIsDefaultOpcode= TRUE;
|
|
}
|
|
//
|
|
// Update the QuestionDefaultInfo.
|
|
//
|
|
for (UINT8 i = 0; i < mAllDefaultTypeCount; i++){
|
|
if (mAllDefaultIdArray[i] == ((EFI_IFR_DEFAULT *)pSNode->mIfrBinBuf)->DefaultId) {
|
|
if (!QuestionDefaultInfo->mIsDefaultIdExist[i]) {
|
|
QuestionDefaultInfo->mDefaultNumber ++;
|
|
QuestionDefaultInfo->mIsDefaultIdExist[i] = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
//
|
|
// Parse next opcode in this question.
|
|
//
|
|
pSNode = pSNode->mNext;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check or add default for question if need.
|
|
|
|
This function will check the default info for question.
|
|
If the question has default, but the default number < defaultstore opcode number.
|
|
will do following two action :
|
|
|
|
1. if (AutoDefault) will add default for question to support all kinds of defaults.
|
|
2. if (CheckDefault) will generate an error to tell user the question misses some default value.
|
|
|
|
We assume that the two options can not be TRUE at same time.
|
|
If they are TRUE at same time, only do the action corresponding to AutoDefault option.
|
|
|
|
@param AutoDefault Add default for question if needed
|
|
@param CheckDefault Check the default info, if missing default, generates an error.
|
|
|
|
**/
|
|
VOID
|
|
CIfrRecordInfoDB::IfrCheckAddDefaultRecord (
|
|
BOOLEAN AutoDefault,
|
|
BOOLEAN CheckDefault
|
|
)
|
|
{
|
|
SIfrRecord *pNode;
|
|
SIfrRecord *pTailNode;
|
|
SIfrRecord *pStartAdjustNode;
|
|
EFI_IFR_OP_HEADER *pOpHead;
|
|
QuestionDefaultRecord QuestionDefaultInfo;
|
|
UINT8 MissingDefaultCount;
|
|
CHAR8 Msg[MAX_STRING_LEN] = {0, };
|
|
|
|
pNode = mIfrRecordListHead;
|
|
|
|
//
|
|
// Record the number and default id of all defaultstore opcode.
|
|
//
|
|
IfrGetDefaultStoreInfo ();
|
|
|
|
while (pNode != NULL) {
|
|
pOpHead = (EFI_IFR_OP_HEADER *) pNode->mIfrBinBuf;
|
|
//
|
|
// Check whether is question opcode.
|
|
//
|
|
if (CheckQuestionOpCode (pOpHead->OpCode)) {
|
|
//
|
|
// Initialize some local variables here, because they vary with question.
|
|
// Record the mIfrRecordListTail for each question, because may create default node for question after mIfrRecordListTail.
|
|
//
|
|
memset (&QuestionDefaultInfo, 0, sizeof (QuestionDefaultRecord));
|
|
pTailNode = mIfrRecordListTail;
|
|
//
|
|
// Get the QuestionDefaultInfo for current question.
|
|
//
|
|
IfrParseDefaulInfoInQuestion (pNode, &QuestionDefaultInfo);
|
|
|
|
if (QuestionDefaultInfo.mDefaultNumber != mAllDefaultTypeCount && QuestionDefaultInfo.mDefaultNumber != 0) {
|
|
if (AutoDefault) {
|
|
//
|
|
// Create default for question which misses default.
|
|
//
|
|
IfrCreateDefaultForQuestion (pNode, &QuestionDefaultInfo);
|
|
|
|
//
|
|
// Adjust the buffer content.
|
|
// pStartAdjustNode->mIfrBinBuf points to the insert position.
|
|
// pTailNode->mNext->mIfrBinBuf points to the inset opcodes.
|
|
//
|
|
pStartAdjustNode =GetRecordInfoFromOffset (gAdjustOpcodeOffset);
|
|
gCFormPkg.AdjustDynamicInsertOpcode (pStartAdjustNode->mIfrBinBuf, pTailNode->mNext->mIfrBinBuf, TRUE);
|
|
|
|
//
|
|
// Update the record info.
|
|
//
|
|
IfrUpdateRecordInfoForDynamicOpcode (TRUE);
|
|
} else if (CheckDefault) {
|
|
//
|
|
// Generate an error for question which misses default.
|
|
//
|
|
MissingDefaultCount = mAllDefaultTypeCount - QuestionDefaultInfo.mDefaultNumber;
|
|
sprintf (Msg, "The question misses %d default, the question's opcode is %d", MissingDefaultCount, pOpHead->OpCode);
|
|
gCVfrErrorHandle.PrintMsg (pNode->mLineNo, NULL, "Error", Msg);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// parse next opcode.
|
|
//
|
|
pNode = pNode->mNext;
|
|
}
|
|
}
|
|
|
|
CIfrRecordInfoDB gCIfrRecordInfoDB;
|
|
|
|
VOID
|
|
CIfrObj::_EMIT_PENDING_OBJ (
|
|
VOID
|
|
)
|
|
{
|
|
CHAR8 *ObjBinBuf = NULL;
|
|
|
|
//
|
|
// do nothing
|
|
//
|
|
if (!mDelayEmit || !gCreateOp) {
|
|
return;
|
|
}
|
|
|
|
mPkgOffset = gCFormPkg.GetPkgLength ();
|
|
//
|
|
// update data buffer to package data
|
|
//
|
|
ObjBinBuf = gCFormPkg.IfrBinBufferGet (mObjBinLen);
|
|
if (ObjBinBuf != NULL) {
|
|
memmove (ObjBinBuf, mObjBinBuf, mObjBinLen);
|
|
}
|
|
|
|
//
|
|
// update bin buffer to package data buffer
|
|
//
|
|
if (mObjBinBuf != NULL) {
|
|
delete mObjBinBuf;
|
|
mObjBinBuf = ObjBinBuf;
|
|
}
|
|
|
|
mDelayEmit = FALSE;
|
|
}
|
|
|
|
/*
|
|
* The definition of CIfrObj's member function
|
|
*/
|
|
static struct {
|
|
UINT8 mSize;
|
|
UINT8 mScope;
|
|
} gOpcodeSizesScopeTable[] = {
|
|
{ 0, 0 }, // EFI_IFR_INVALID - 0x00
|
|
{ sizeof (EFI_IFR_FORM), 1 }, // EFI_IFR_FORM_OP
|
|
{ sizeof (EFI_IFR_SUBTITLE), 1 }, // EFI_IFR_SUBTITLE_OP
|
|
{ sizeof (EFI_IFR_TEXT), 0 }, // EFI_IFR_TEXT_OP
|
|
{ sizeof (EFI_IFR_IMAGE), 0 }, // EFI_IFR_IMAGE_OP
|
|
{ sizeof (EFI_IFR_ONE_OF), 1 }, // EFI_IFR_ONE_OF_OP - 0x05
|
|
{ sizeof (EFI_IFR_CHECKBOX), 1}, // EFI_IFR_CHECKBOX_OP
|
|
{ sizeof (EFI_IFR_NUMERIC), 1 }, // EFI_IFR_NUMERIC_OP
|
|
{ sizeof (EFI_IFR_PASSWORD), 1 }, // EFI_IFR_PASSWORD_OP
|
|
{ sizeof (EFI_IFR_ONE_OF_OPTION), 0 }, // EFI_IFR_ONE_OF_OPTION_OP
|
|
{ sizeof (EFI_IFR_SUPPRESS_IF), 1 }, // EFI_IFR_SUPPRESS_IF - 0x0A
|
|
{ sizeof (EFI_IFR_LOCKED), 0 }, // EFI_IFR_LOCKED_OP
|
|
{ sizeof (EFI_IFR_ACTION), 1 }, // EFI_IFR_ACTION_OP
|
|
{ sizeof (EFI_IFR_RESET_BUTTON), 1 }, // EFI_IFR_RESET_BUTTON_OP
|
|
{ sizeof (EFI_IFR_FORM_SET), 1 }, // EFI_IFR_FORM_SET_OP -0xE
|
|
{ sizeof (EFI_IFR_REF), 0 }, // EFI_IFR_REF_OP
|
|
{ sizeof (EFI_IFR_NO_SUBMIT_IF), 1}, // EFI_IFR_NO_SUBMIT_IF_OP -0x10
|
|
{ sizeof (EFI_IFR_INCONSISTENT_IF), 1 }, // EFI_IFR_INCONSISTENT_IF_OP
|
|
{ sizeof (EFI_IFR_EQ_ID_VAL), 0 }, // EFI_IFR_EQ_ID_VAL_OP
|
|
{ sizeof (EFI_IFR_EQ_ID_ID), 0 }, // EFI_IFR_EQ_ID_ID_OP
|
|
{ sizeof (EFI_IFR_EQ_ID_VAL_LIST), 0 }, // EFI_IFR_EQ_ID_LIST_OP - 0x14
|
|
{ sizeof (EFI_IFR_AND), 0 }, // EFI_IFR_AND_OP
|
|
{ sizeof (EFI_IFR_OR), 0 }, // EFI_IFR_OR_OP
|
|
{ sizeof (EFI_IFR_NOT), 0 }, // EFI_IFR_NOT_OP
|
|
{ sizeof (EFI_IFR_RULE), 1 }, // EFI_IFR_RULE_OP
|
|
{ sizeof (EFI_IFR_GRAY_OUT_IF), 1 }, // EFI_IFR_GRAYOUT_IF_OP - 0x19
|
|
{ sizeof (EFI_IFR_DATE), 1 }, // EFI_IFR_DATE_OP
|
|
{ sizeof (EFI_IFR_TIME), 1 }, // EFI_IFR_TIME_OP
|
|
{ sizeof (EFI_IFR_STRING), 1 }, // EFI_IFR_STRING_OP
|
|
{ sizeof (EFI_IFR_REFRESH), 0 }, // EFI_IFR_REFRESH_OP
|
|
{ sizeof (EFI_IFR_DISABLE_IF), 1 }, // EFI_IFR_DISABLE_IF_OP - 0x1E
|
|
{ 0, 0 }, // 0x1F
|
|
{ sizeof (EFI_IFR_TO_LOWER), 0 }, // EFI_IFR_TO_LOWER_OP - 0x20
|
|
{ sizeof (EFI_IFR_TO_UPPER), 0 }, // EFI_IFR_TO_UPPER_OP - 0x21
|
|
{ sizeof (EFI_IFR_MAP), 1 }, // EFI_IFR_MAP - 0x22
|
|
{ sizeof (EFI_IFR_ORDERED_LIST), 1 }, // EFI_IFR_ORDERED_LIST_OP - 0x23
|
|
{ sizeof (EFI_IFR_VARSTORE), 0 }, // EFI_IFR_VARSTORE_OP
|
|
{ sizeof (EFI_IFR_VARSTORE_NAME_VALUE), 0 }, // EFI_IFR_VARSTORE_NAME_VALUE_OP
|
|
{ sizeof (EFI_IFR_VARSTORE_EFI), 0 }, // EFI_IFR_VARSTORE_EFI_OP
|
|
{ sizeof (EFI_IFR_VARSTORE_DEVICE), 1 }, // EFI_IFR_VARSTORE_DEVICE_OP
|
|
{ sizeof (EFI_IFR_VERSION), 0 }, // EFI_IFR_VERSION_OP - 0x28
|
|
{ sizeof (EFI_IFR_END), 0 }, // EFI_IFR_END_OP
|
|
{ sizeof (EFI_IFR_MATCH), 0 }, // EFI_IFR_MATCH_OP - 0x2A
|
|
{ sizeof (EFI_IFR_GET), 0 }, // EFI_IFR_GET - 0x2B
|
|
{ sizeof (EFI_IFR_SET), 0 }, // EFI_IFR_SET - 0x2C
|
|
{ sizeof (EFI_IFR_READ), 0 }, // EFI_IFR_READ - 0x2D
|
|
{ sizeof (EFI_IFR_WRITE), 0 }, // EFI_IFR_WRITE - 0x2E
|
|
{ sizeof (EFI_IFR_EQUAL), 0 }, // EFI_IFR_EQUAL_OP - 0x2F
|
|
{ sizeof (EFI_IFR_NOT_EQUAL), 0 }, // EFI_IFR_NOT_EQUAL_OP
|
|
{ sizeof (EFI_IFR_GREATER_THAN), 0 }, // EFI_IFR_GREATER_THAN_OP
|
|
{ sizeof (EFI_IFR_GREATER_EQUAL), 0 }, // EFI_IFR_GREATER_EQUAL_OP
|
|
{ sizeof (EFI_IFR_LESS_THAN), 0 }, // EFI_IFR_LESS_THAN_OP
|
|
{ sizeof (EFI_IFR_LESS_EQUAL), 0 }, // EFI_IFR_LESS_EQUAL_OP - 0x34
|
|
{ sizeof (EFI_IFR_BITWISE_AND), 0 }, // EFI_IFR_BITWISE_AND_OP
|
|
{ sizeof (EFI_IFR_BITWISE_OR), 0 }, // EFI_IFR_BITWISE_OR_OP
|
|
{ sizeof (EFI_IFR_BITWISE_NOT), 0 }, // EFI_IFR_BITWISE_NOT_OP
|
|
{ sizeof (EFI_IFR_SHIFT_LEFT), 0 }, // EFI_IFR_SHIFT_LEFT_OP
|
|
{ sizeof (EFI_IFR_SHIFT_RIGHT), 0 }, // EFI_IFR_SHIFT_RIGHT_OP
|
|
{ sizeof (EFI_IFR_ADD), 0 }, // EFI_IFR_ADD_OP - 0x3A
|
|
{ sizeof (EFI_IFR_SUBTRACT), 0 }, // EFI_IFR_SUBTRACT_OP
|
|
{ sizeof (EFI_IFR_MULTIPLY), 0 }, // EFI_IFR_MULTIPLY_OP
|
|
{ sizeof (EFI_IFR_DIVIDE), 0 }, // EFI_IFR_DIVIDE_OP
|
|
{ sizeof (EFI_IFR_MODULO), 0 }, // EFI_IFR_MODULO_OP - 0x3E
|
|
{ sizeof (EFI_IFR_RULE_REF), 0 }, // EFI_IFR_RULE_REF_OP
|
|
{ sizeof (EFI_IFR_QUESTION_REF1), 0 }, // EFI_IFR_QUESTION_REF1_OP
|
|
{ sizeof (EFI_IFR_QUESTION_REF2), 0 }, // EFI_IFR_QUESTION_REF2_OP - 0x41
|
|
{ sizeof (EFI_IFR_UINT8), 0}, // EFI_IFR_UINT8
|
|
{ sizeof (EFI_IFR_UINT16), 0}, // EFI_IFR_UINT16
|
|
{ sizeof (EFI_IFR_UINT32), 0}, // EFI_IFR_UINT32
|
|
{ sizeof (EFI_IFR_UINT64), 0}, // EFI_IFR_UTNT64
|
|
{ sizeof (EFI_IFR_TRUE), 0 }, // EFI_IFR_TRUE_OP - 0x46
|
|
{ sizeof (EFI_IFR_FALSE), 0 }, // EFI_IFR_FALSE_OP
|
|
{ sizeof (EFI_IFR_TO_UINT), 0 }, // EFI_IFR_TO_UINT_OP
|
|
{ sizeof (EFI_IFR_TO_STRING), 0 }, // EFI_IFR_TO_STRING_OP
|
|
{ sizeof (EFI_IFR_TO_BOOLEAN), 0 }, // EFI_IFR_TO_BOOLEAN_OP
|
|
{ sizeof (EFI_IFR_MID), 0 }, // EFI_IFR_MID_OP
|
|
{ sizeof (EFI_IFR_FIND), 0 }, // EFI_IFR_FIND_OP
|
|
{ sizeof (EFI_IFR_TOKEN), 0 }, // EFI_IFR_TOKEN_OP
|
|
{ sizeof (EFI_IFR_STRING_REF1), 0 }, // EFI_IFR_STRING_REF1_OP - 0x4E
|
|
{ sizeof (EFI_IFR_STRING_REF2), 0 }, // EFI_IFR_STRING_REF2_OP
|
|
{ sizeof (EFI_IFR_CONDITIONAL), 0 }, // EFI_IFR_CONDITIONAL_OP
|
|
{ sizeof (EFI_IFR_QUESTION_REF3), 0 }, // EFI_IFR_QUESTION_REF3_OP
|
|
{ sizeof (EFI_IFR_ZERO), 0 }, // EFI_IFR_ZERO_OP
|
|
{ sizeof (EFI_IFR_ONE), 0 }, // EFI_IFR_ONE_OP
|
|
{ sizeof (EFI_IFR_ONES), 0 }, // EFI_IFR_ONES_OP
|
|
{ sizeof (EFI_IFR_UNDEFINED), 0 }, // EFI_IFR_UNDEFINED_OP
|
|
{ sizeof (EFI_IFR_LENGTH), 0 }, // EFI_IFR_LENGTH_OP
|
|
{ sizeof (EFI_IFR_DUP), 0 }, // EFI_IFR_DUP_OP - 0x57
|
|
{ sizeof (EFI_IFR_THIS), 0 }, // EFI_IFR_THIS_OP
|
|
{ sizeof (EFI_IFR_SPAN), 0 }, // EFI_IFR_SPAN_OP
|
|
{ sizeof (EFI_IFR_VALUE), 1 }, // EFI_IFR_VALUE_OP
|
|
{ sizeof (EFI_IFR_DEFAULT), 0 }, // EFI_IFR_DEFAULT_OP
|
|
{ sizeof (EFI_IFR_DEFAULTSTORE), 0 }, // EFI_IFR_DEFAULTSTORE_OP - 0x5C
|
|
{ sizeof (EFI_IFR_FORM_MAP), 1}, // EFI_IFR_FORM_MAP_OP - 0x5D
|
|
{ sizeof (EFI_IFR_CATENATE), 0 }, // EFI_IFR_CATENATE_OP
|
|
{ sizeof (EFI_IFR_GUID), 0 }, // EFI_IFR_GUID_OP
|
|
{ sizeof (EFI_IFR_SECURITY), 0 }, // EFI_IFR_SECURITY_OP - 0x60
|
|
{ sizeof (EFI_IFR_MODAL_TAG), 0}, // EFI_IFR_MODAL_TAG_OP - 0x61
|
|
{ sizeof (EFI_IFR_REFRESH_ID), 0}, // EFI_IFR_REFRESH_ID_OP - 0x62
|
|
{ sizeof (EFI_IFR_WARNING_IF), 1}, // EFI_IFR_WARNING_IF_OP - 0x63
|
|
{ sizeof (EFI_IFR_MATCH2), 0 }, // EFI_IFR_MATCH2_OP - 0x64
|
|
};
|
|
|
|
#ifdef CIFROBJ_DEUBG
|
|
static struct {
|
|
CHAR8 *mIfrName;
|
|
} gIfrObjPrintDebugTable[] = {
|
|
"EFI_IFR_INVALID", "EFI_IFR_FORM", "EFI_IFR_SUBTITLE", "EFI_IFR_TEXT", "EFI_IFR_IMAGE", "EFI_IFR_ONE_OF",
|
|
"EFI_IFR_CHECKBOX", "EFI_IFR_NUMERIC", "EFI_IFR_PASSWORD", "EFI_IFR_ONE_OF_OPTION", "EFI_IFR_SUPPRESS_IF", "EFI_IFR_LOCKED",
|
|
"EFI_IFR_ACTION", "EFI_IFR_RESET_BUTTON", "EFI_IFR_FORM_SET", "EFI_IFR_REF", "EFI_IFR_NO_SUBMIT_IF", "EFI_IFR_INCONSISTENT_IF",
|
|
"EFI_IFR_EQ_ID_VAL", "EFI_IFR_EQ_ID_ID", "EFI_IFR_EQ_ID_LIST", "EFI_IFR_AND", "EFI_IFR_OR", "EFI_IFR_NOT",
|
|
"EFI_IFR_RULE", "EFI_IFR_GRAY_OUT_IF", "EFI_IFR_DATE", "EFI_IFR_TIME", "EFI_IFR_STRING", "EFI_IFR_REFRESH",
|
|
"EFI_IFR_DISABLE_IF", "EFI_IFR_INVALID", "EFI_IFR_TO_LOWER", "EFI_IFR_TO_UPPER", "EFI_IFR_MAP", "EFI_IFR_ORDERED_LIST",
|
|
"EFI_IFR_VARSTORE", "EFI_IFR_VARSTORE_NAME_VALUE", "EFI_IFR_VARSTORE_EFI", "EFI_IFR_VARSTORE_DEVICE", "EFI_IFR_VERSION", "EFI_IFR_END",
|
|
"EFI_IFR_MATCH", "EFI_IFR_GET", "EFI_IFR_SET", "EFI_IFR_READ", "EFI_IFR_WRITE", "EFI_IFR_EQUAL",
|
|
"EFI_IFR_NOT_EQUAL", "EFI_IFR_GREATER_THAN", "EFI_IFR_GREATER_EQUAL", "EFI_IFR_LESS_THAN", "EFI_IFR_LESS_EQUAL", "EFI_IFR_BITWISE_AND",
|
|
"EFI_IFR_BITWISE_OR", "EFI_IFR_BITWISE_NOT", "EFI_IFR_SHIFT_LEFT", "EFI_IFR_SHIFT_RIGHT", "EFI_IFR_ADD", "EFI_IFR_SUBTRACT",
|
|
"EFI_IFR_MULTIPLY", "EFI_IFR_DIVIDE", "EFI_IFR_MODULO", "EFI_IFR_RULE_REF", "EFI_IFR_QUESTION_REF1", "EFI_IFR_QUESTION_REF2",
|
|
"EFI_IFR_UINT8", "EFI_IFR_UINT16", "EFI_IFR_UINT32", "EFI_IFR_UINT64", "EFI_IFR_TRUE", "EFI_IFR_FALSE",
|
|
"EFI_IFR_TO_UINT", "EFI_IFR_TO_STRING", "EFI_IFR_TO_BOOLEAN", "EFI_IFR_MID", "EFI_IFR_FIND", "EFI_IFR_TOKEN",
|
|
"EFI_IFR_STRING_REF1","EFI_IFR_STRING_REF2", "EFI_IFR_CONDITIONAL", "EFI_IFR_QUESTION_REF3", "EFI_IFR_ZERO", "EFI_IFR_ONE",
|
|
"EFI_IFR_ONES", "EFI_IFR_UNDEFINED", "EFI_IFR_LENGTH", "EFI_IFR_DUP", "EFI_IFR_THIS", "EFI_IFR_SPAN",
|
|
"EFI_IFR_VALUE", "EFI_IFR_DEFAULT", "EFI_IFR_DEFAULTSTORE", "EFI_IFR_FORM_MAP", "EFI_IFR_CATENATE", "EFI_IFR_GUID",
|
|
"EFI_IFR_SECURITY", "EFI_IFR_MODAL_TAG", "EFI_IFR_REFRESH_ID", "EFI_IFR_WARNING_IF", "EFI_IFR_MATCH2",
|
|
};
|
|
|
|
VOID
|
|
CIFROBJ_DEBUG_PRINT (
|
|
IN UINT8 OpCode
|
|
)
|
|
{
|
|
printf ("======Create IFR [%s]\n", gIfrObjPrintDebugTable[OpCode].mIfrName);
|
|
}
|
|
#else
|
|
|
|
#define CIFROBJ_DEBUG_PRINT(OpCode)
|
|
|
|
#endif
|
|
|
|
BOOLEAN gCreateOp = TRUE;
|
|
|
|
CIfrObj::CIfrObj (
|
|
IN UINT8 OpCode,
|
|
OUT CHAR8 **IfrObj,
|
|
IN UINT8 ObjBinLen,
|
|
IN BOOLEAN DelayEmit
|
|
)
|
|
{
|
|
mDelayEmit = DelayEmit;
|
|
mPkgOffset = gCFormPkg.GetPkgLength ();
|
|
mObjBinLen = (ObjBinLen == 0) ? gOpcodeSizesScopeTable[OpCode].mSize : ObjBinLen;
|
|
mObjBinBuf = ((DelayEmit == FALSE) && (gCreateOp == TRUE)) ? gCFormPkg.IfrBinBufferGet (mObjBinLen) : new CHAR8[EFI_IFR_MAX_LENGTH];
|
|
mRecordIdx = (gCreateOp == TRUE) ? gCIfrRecordInfoDB.IfrRecordRegister (0xFFFFFFFF, mObjBinBuf, mObjBinLen, mPkgOffset) : EFI_IFR_RECORDINFO_IDX_INVALUD;
|
|
mLineNo = 0;
|
|
|
|
assert (mObjBinBuf != NULL);
|
|
|
|
if (IfrObj != NULL) {
|
|
*IfrObj = mObjBinBuf;
|
|
}
|
|
|
|
CIFROBJ_DEBUG_PRINT (OpCode);
|
|
}
|
|
|
|
CIfrObj::~CIfrObj (
|
|
VOID
|
|
)
|
|
{
|
|
if ((mDelayEmit == TRUE) && ((gCreateOp == TRUE))) {
|
|
_EMIT_PENDING_OBJ ();
|
|
}
|
|
|
|
gCIfrRecordInfoDB.IfrRecordInfoUpdate (mRecordIdx, mLineNo, mObjBinBuf, mObjBinLen, mPkgOffset);
|
|
}
|
|
|
|
/*
|
|
* The definition of CIfrObj's member function
|
|
*/
|
|
UINT8 gScopeCount = 0;
|
|
|
|
CIfrOpHeader::CIfrOpHeader (
|
|
IN UINT8 OpCode,
|
|
IN VOID *StartAddr,
|
|
IN UINT8 Length
|
|
) : mHeader ((EFI_IFR_OP_HEADER *)StartAddr)
|
|
{
|
|
mHeader->OpCode = OpCode;
|
|
mHeader->Length = (Length == 0) ? gOpcodeSizesScopeTable[OpCode].mSize : Length;
|
|
mHeader->Scope = (gOpcodeSizesScopeTable[OpCode].mScope + gScopeCount > 0) ? 1 : 0;
|
|
}
|
|
|
|
CIfrOpHeader::CIfrOpHeader (
|
|
IN CIfrOpHeader &OpHdr
|
|
)
|
|
{
|
|
mHeader = OpHdr.mHeader;
|
|
}
|
|
|
|
UINT32 CIfrFormId::FormIdBitMap[EFI_FREE_FORM_ID_BITMAP_SIZE] = {0, };
|