/** @file
SMBIOS String Table Helper
Copyright (c) 2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- DSP0134 - SMBIOS Specification Version 3.6.0, 2022-06-17
**/
#include
#include
#include
#include
#include
/** Add a string to the string table.
@param[in] StrTable Pointer to the string table
@param[in] Str Pointer to the string
@param[out] StrRef Optional pointer to retrieve the string field
reference of the string in the string table
@return EFI_SUCCESS Success
@return EFI_INVALID_PARAMETER Invalid string table pointer
@return EFI_BUFFER_TOO_SMALL Insufficient space to add string
**/
EFI_STATUS
EFIAPI
StringTableAddString (
IN STRING_TABLE *CONST StrTable,
IN CONST CHAR8 *Str,
OUT UINT8 *StrRef OPTIONAL
)
{
UINTN StrLength;
STRING_ELEMENT *StrElement;
if ((StrTable == NULL) || (Str == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (StrTable->StrCount >= StrTable->MaxStringElements) {
return EFI_BUFFER_TOO_SMALL;
}
StrLength = AsciiStrLen (Str);
if (StrLength == 0) {
return EFI_INVALID_PARAMETER;
}
// Update the string element
StrElement = &StrTable->Elements[StrTable->StrCount];
StrElement->StringLen = StrLength;
StrElement->String = Str;
// Update String table information
StrTable->TotalStrLen += StrLength;
StrTable->StrCount++;
// Return the index of the string in the string table if requested
if (StrRef != NULL) {
// Note: SMBIOS string field references start at 1. So, return the
// StrCount as the string reference after it is updated.
*StrRef = StrTable->StrCount;
}
return EFI_SUCCESS;
}
/** Returns the total size required to publish the strings to the SMBIOS
string area.
@param[in] StrTable Pointer to the string table
@return Total size required to publish the strings in the SMBIOS string area.
**/
UINTN
EFIAPI
StringTableGetStringSetSize (
IN STRING_TABLE *CONST StrTable
)
{
if (StrTable == NULL) {
ASSERT (0);
return 0;
}
// See Section 6.1.3 Text strings, SMBIOS Specification Version 3.6.0
// - If the formatted portion of the structure contains string-reference
// fields and all the string fields are set to 0 (no string references),
// the formatted section of the structure is followed by two null (00h)
// BYTES.
// - Each string is terminated with a null (00h) BYTE
// - and the set of strings is terminated with an additional null (00h) BYTE.
// Therefore, if string count = 0, return 2
// if string count > 0, the string set size =
// StrTable->TotalStrLen (total length of the strings in the string table)
// + StrTable->StrCount (add string count to include '\0' for each string)
// +1 (an additional '\0' is required at the end of the string set).
return (StrTable->StrCount == 0) ? 2 :
(StrTable->TotalStrLen + StrTable->StrCount + 1);
}
/** Iterate through the string table and publish the strings in the SMBIOS
string area.
@param[in] StrTable Pointer to the string table
@param[in] SmbiosStringAreaStart Start address of the SMBIOS string area.
@param[in] SmbiosStringAreaSize Size of the SMBIOS string area.
@return EFI_SUCCESS Success
@return EFI_INVALID_PARAMETER Invalid string table pointer
@return EFI_BUFFER_TOO_SMALL Insufficient space to publish strings
**/
EFI_STATUS
EFIAPI
StringTablePublishStringSet (
IN STRING_TABLE *CONST StrTable,
IN CHAR8 *CONST SmbiosStringAreaStart,
IN CONST UINTN SmbiosStringAreaSize
)
{
UINT8 Index;
STRING_ELEMENT *StrElement;
CHAR8 *SmbiosString;
UINTN BytesRemaining;
UINTN BytesCopied;
if ((StrTable == NULL) || (SmbiosStringAreaStart == NULL)) {
return EFI_INVALID_PARAMETER;
}
if (SmbiosStringAreaSize < StringTableGetStringSetSize (StrTable)) {
return EFI_BUFFER_TOO_SMALL;
}
SmbiosString = SmbiosStringAreaStart;
BytesRemaining = SmbiosStringAreaSize;
if (StrTable->StrCount == 0) {
// See Section 6.1.3 Text strings, SMBIOS Specification Version 3.6.0
// If the formatted portion of the structure contains string-reference
// fields and all the string fields are set to 0 (no string references),
// the formatted section of the structure is followed by two null (00h)
// BYTES.
*SmbiosString++ = '\0';
} else {
for (Index = 0; Index < StrTable->StrCount; Index++) {
StrElement = &StrTable->Elements[Index];
AsciiStrCpyS (SmbiosString, BytesRemaining, StrElement->String);
// See Section 6.1.3 Text strings, SMBIOS Specification Version 3.6.0
// - Each string is terminated with a null (00h) BYTE
// Bytes Copied = String length + 1 for the string NULL terminator.
BytesCopied = StrElement->StringLen + 1;
BytesRemaining -= BytesCopied;
SmbiosString += BytesCopied;
}
}
// See Section 6.1.3 Text strings, SMBIOS Specification Version 3.6.0
// - the set of strings is terminated with an additional null (00h) BYTE.
*SmbiosString = '\0';
return EFI_SUCCESS;
}
/** Initialise the string table and allocate memory for the string elements.
@param[in] StrTable Pointer to the string table
@param[in] MaxStringElements Maximum number of strings that the string
table can hold.
@return EFI_SUCCESS Success
@return EFI_INVALID_PARAMETER Invalid string table pointer
@return EFI_OUT_OF_RESOURCES Failed to allocate memory for string elements
**/
EFI_STATUS
EFIAPI
StringTableInitialize (
IN STRING_TABLE *CONST StrTable,
IN UINTN MaxStringElements
)
{
STRING_ELEMENT *Elements;
if ((StrTable == NULL) || (MaxStringElements > MAX_UINT8)) {
return EFI_INVALID_PARAMETER;
}
ZeroMem (StrTable, sizeof (STRING_TABLE));
Elements = (STRING_ELEMENT *)AllocateZeroPool (
sizeof (STRING_ELEMENT) * MaxStringElements
);
if (Elements == NULL) {
return EFI_OUT_OF_RESOURCES;
}
StrTable->Elements = Elements;
StrTable->MaxStringElements = (UINT8)MaxStringElements;
return EFI_SUCCESS;
}
/** Free memory allocated for the string elements in the string table.
@param[in] StrTable Pointer to the string table
@return EFI_SUCCESS Success
@return EFI_INVALID_PARAMETER Invalid string table pointer or string elements
**/
EFI_STATUS
EFIAPI
StringTableFree (
IN STRING_TABLE *CONST StrTable
)
{
if ((StrTable == NULL) || (StrTable->Elements == NULL)) {
return EFI_INVALID_PARAMETER;
}
FreePool (StrTable->Elements);
ZeroMem (StrTable, sizeof (STRING_TABLE));
return EFI_SUCCESS;
}