blob: 7cd203e4865cd10ee20745a9cefbf6a4a93e0ed4 [file]
/** @file
Library that implements the helper functions to parse and pack a Transfer
List as specified by the A-profile Firmware Handoff Specification.
Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- https://github.com/FirmwareHandoff/firmware_handoff
**/
#include <Base.h>
#include <Library/ArmTransferListLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
/**
Return the first Transfer Entry Node in the Transfer List.
@param [in] TransferListHeader TransferListHeader
@return Pointer to the Transfer Entry Node if successful otherwise NULL
**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TransferListGetFirstEntry (
IN TRANSFER_LIST_HEADER *TransferListHeader
)
{
return TransferListGetNextEntry (TransferListHeader, NULL);
}
/**
Return the next Transfer Entry Node in the Transfer List from
last Transfer Entry Node.
@param [in] TransferListHeader Pointer to the Transfer List Header.
@param [in] CurrentEntry Pointer to the Current Transfer Entry.
If this is NULL, the first Transfer Entry
is returned.
@return Pointer to the Transfer Entry Node if successful otherwise NULL
**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TransferListGetNextEntry (
IN TRANSFER_LIST_HEADER *TransferListHeader,
IN TRANSFER_ENTRY_HEADER *CurrentEntry
)
{
TRANSFER_ENTRY_HEADER *Entry;
UINTN CurrentAddr;
UINTN EndAddr;
if (TransferListHeader == NULL) {
return NULL;
}
EndAddr = (UINTN)TransferListHeader + TransferListHeader->UsedSize;
if (CurrentEntry != NULL) {
CurrentAddr = (UINTN)CurrentEntry + CurrentEntry->HeaderSize + CurrentEntry->DataSize;
} else {
CurrentAddr = (UINTN)TransferListHeader + TransferListHeader->HeaderSize;
}
CurrentAddr = ALIGN_VALUE (CurrentAddr, (1 << TransferListHeader->Alignment));
Entry = (TRANSFER_ENTRY_HEADER *)CurrentAddr;
if (((CurrentAddr + sizeof (TRANSFER_LIST_HEADER)) < CurrentAddr) ||
((CurrentAddr + sizeof (TRANSFER_ENTRY_HEADER)) > EndAddr) ||
((CurrentAddr + Entry->HeaderSize + Entry->DataSize) < CurrentAddr) ||
((CurrentAddr + Entry->HeaderSize + Entry->DataSize) > EndAddr))
{
return NULL;
}
return Entry;
}
/**
Return the first Transfer Entry Node in the Transfer List
matched with given tag-id.
@param [in] TransferListHeader Pointer to the Transfer List Header.
@param [in] TagId Tag id
@return Pointer to the Transfer Entry Node if successful otherwise NULL
**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TransferListFindFirstEntry (
IN TRANSFER_LIST_HEADER *TransferListHeader,
IN UINT16 TagId
)
{
TRANSFER_ENTRY_HEADER *Entry;
Entry = TransferListGetFirstEntry (TransferListHeader);
while ((Entry != NULL) && ((Entry->TagId != TagId) || Entry->Reserved0 != 0)) {
Entry = TransferListGetNextEntry (TransferListHeader, Entry);
}
return Entry;
}
/**
Return the Next Transfer Entry Node in the Transfer List
matched with given tag-id from last Transfer Entry Node.
@param [in] TransferListHeader Pointer to the Transfer List Header.
@param [in] CurrentEntry Pointer to the Current Transfer Entry.
If this is NULL, the first Transfer Entry
is returned.
@param [in] TagId Tag id
@return Pointer to the Transfer Entry Node if successful otherwise NULL
**/
TRANSFER_ENTRY_HEADER *
EFIAPI
TransferListFindNextEntry (
IN TRANSFER_LIST_HEADER *TransferListHeader,
IN TRANSFER_ENTRY_HEADER *CurrentEntry,
IN UINT16 TagId
)
{
TRANSFER_ENTRY_HEADER *Entry;
if (CurrentEntry == NULL) {
return TransferListFindFirstEntry (TransferListHeader, TagId);
} else {
Entry = TransferListGetNextEntry (TransferListHeader, CurrentEntry);
}
while ((Entry != NULL) && ((Entry->TagId != TagId) || Entry->Reserved0 != 0)) {
Entry = TransferListGetNextEntry (TransferListHeader, Entry);
}
return Entry;
}
/**
Return the data in Transfer Entry.
@param [in] TransferEntry Pointer to a Transfer Entry Header
@return Pointer to the Data of Transfer Entry Node if successful otherwise NULL
**/
VOID *
EFIAPI
TransferListGetEntryData (
IN TRANSFER_ENTRY_HEADER *TransferEntry
)
{
if ((TransferEntry == NULL) || (TransferEntry->DataSize == 0)) {
return NULL;
}
return (VOID *)((UINTN)TransferEntry + TransferEntry->HeaderSize);
}