summaryrefslogtreecommitdiff
path: root/DynamicTablesPkg/Library/Common/SmbiosStringTableLib/SmbiosStringTableLib.c
blob: 9eb4a7b22dd2fb5cf8dcec257461127b033d2020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/** @file
  SMBIOS String Table Helper

  Copyright (c) 2022, Arm Limited. All rights reserved.<BR>

  SPDX-License-Identifier: BSD-2-Clause-Patent

  @par Reference(s):
  - DSP0134 - SMBIOS Specification Version 3.6.0, 2022-06-17
**/

#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/SmbiosStringTableLib.h>

/** 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;
}