1 /** @file
2   Provides library functions for common SMBIOS operations. Only available to DXE
3   and UEFI module types.
4 
5 
6 Copyright (c) 2012, Apple Inc. All rights reserved.
7 Portitions Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 
12 #include <PiDxe.h>
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiLib.h>
19 #include <Library/SmbiosLib.h>
20 
21 
22 EFI_SMBIOS_PROTOCOL *gSmbios = NULL;
23 
24 
25 /**
26   Create an initial SMBIOS Table from an array of SMBIOS_TEMPLATE_ENTRY
27   entries. SMBIOS_TEMPLATE_ENTRY.NULL indicates the end of the table.
28 
29   @param  Template   Array of SMBIOS_TEMPLATE_ENTRY entries.
30 
31   @retval EFI_SUCCESS          New SMBIOS tables were created.
32   @retval EFI_OUT_OF_RESOURCES New SMBIOS tables were not created.
33 **/
34 EFI_STATUS
35 EFIAPI
36 SmbiosLibInitializeFromTemplate (
37   IN  SMBIOS_TEMPLATE_ENTRY   *Template
38   )
39 {
40   EFI_STATUS    Status;
41   UINTN         Index;
42 
43   if (Template == NULL) {
44     return EFI_INVALID_PARAMETER;
45   }
46 
47   Status = EFI_SUCCESS;
48 
49   for (Index = 0; Template[Index].Entry != NULL; Index++) {
50     Status = SmbiosLibCreateEntry (Template[Index].Entry, Template[Index].StringArray);
51   }
52 
53   return Status;
54 }
55 
56 
57 
58 /**
59   Create SMBIOS record.
60 
gda_vprovider_hub_class_init(GdaVproviderHubClass * klass)61   Converts a fixed SMBIOS structure and an array of pointers to strings into
62   an SMBIOS record where the strings are cat'ed on the end of the fixed record
63   and terminated via a double NULL and add to SMBIOS table.
64 
65   SMBIOS_TABLE_TYPE32 gSmbiosType12 = {
66     { EFI_SMBIOS_TYPE_SYSTEM_CONFIGURATION_OPTIONS, sizeof (SMBIOS_TABLE_TYPE12), 0 },
67     1 // StringCount
68   };
69   CHAR8 *gSmbiosType12Strings[] = {
70     "Not Found",
71     NULL
72   };
73 
74   ...
75   CreateSmbiosEntry (
76     (EFI_SMBIOS_TABLE_HEADER*)&gSmbiosType12,
77     gSmbiosType12Strings
78     );
79 
80   @param  SmbiosEntry   Fixed SMBIOS structure
81   @param  StringArray   Array of strings to convert to an SMBIOS string pack.
82                         NULL is OK.
83 
84 **/
85 EFI_STATUS
86 EFIAPI
87 SmbiosLibCreateEntry (
88   IN  SMBIOS_STRUCTURE *SmbiosEntry,
89   IN  CHAR8            **StringArray
90   )
91 {
92   EFI_STATUS                Status;
93   EFI_SMBIOS_HANDLE         SmbiosHandle;
94   EFI_SMBIOS_TABLE_HEADER   *Record;
95   UINTN                     Index;
96   UINTN                     StringSize;
97   UINTN                     Size;
98   CHAR8                     *Str;
99 
100   // Calculate the size of the fixed record and optional string pack
101   Size = SmbiosEntry->Length;
102   if (StringArray == NULL) {
103     Size += 2; // Min string section is double null
104   } else if (StringArray[0] == NULL) {
105     Size += 2; // Min string section is double null
106   } else {
107     for (Index = 0; StringArray[Index] != NULL; Index++) {
108       StringSize = AsciiStrSize (StringArray[Index]);
109       Size += StringSize;
110     }
111     // Don't forget the terminating double null
112     Size += 1;
113   }
114 
115   // Copy over Template
116   Record = (EFI_SMBIOS_TABLE_HEADER *)AllocateZeroPool (Size);
117   if (Record == NULL) {
118     return EFI_OUT_OF_RESOURCES;
119   }
120   CopyMem (Record, SmbiosEntry, SmbiosEntry->Length);
121 
122   if (StringArray != NULL) {
123     // Append string pack
124     Str = ((CHAR8 *)Record) + Record->Length;
125     for (Index = 0; StringArray[Index] != NULL; Index++) {
126       StringSize = AsciiStrSize (StringArray[Index]);
127       CopyMem (Str, StringArray[Index], StringSize);
128       Str += StringSize;
129     }
130     *Str = 0;
131   }
132 
133   SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
134   Status = gSmbios->Add (
135                      gSmbios,
136                      gImageHandle,
137                      &SmbiosHandle,
138                      Record
139                      );
140 
141   FreePool (Record);
142   return Status;
143 }
144 
145 
146 
147 /**
gda_vprovider_hub_get_property(GObject * object,guint param_id,G_GNUC_UNUSED GValue * value,GParamSpec * pspec)148   Update the string associated with an existing SMBIOS record.
149 
150   This function allows the update of specific SMBIOS strings. The number of valid strings for any
151   SMBIOS record is defined by how many strings were present when Add() was called.
152 
153   @param[in]    SmbiosHandle    SMBIOS Handle of structure that will have its string updated.
154   @param[in]    StringNumber    The non-zero string number of the string to update.
155   @param[in]    String          Update the StringNumber string with String.
156 
157   @retval EFI_SUCCESS           SmbiosHandle had its StringNumber String updated.
158   @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist. Or String is invalid.
159   @retval EFI_UNSUPPORTED       String was not added because it is longer than the SMBIOS Table supports.
160   @retval EFI_NOT_FOUND         The StringNumber.is not valid for this SMBIOS record.
161 **/
162 EFI_STATUS
163 EFIAPI
164 SmbiosLibUpdateString (
165   IN  EFI_SMBIOS_HANDLE     SmbiosHandle,
166   IN  SMBIOS_TABLE_STRING   StringNumber,
167   IN  CHAR8                 *String
168   )
169 {
170   UINTN StringIndex;
171 
172   if (String == NULL) {
173     return EFI_INVALID_PARAMETER;
174   }
175 
176   if (*String == '\0') {
177     // A string with no data is not legal in SMBIOS
178     return EFI_INVALID_PARAMETER;
179   }
180 
181   StringIndex = StringNumber;
182   return gSmbios->UpdateString (gSmbios, &SmbiosHandle, &StringIndex, String);
183 }
gda_vprovider_hub_create_connection(GdaServerProvider * provider)184 
185 
186 /**
187   Update the string associated with an existing SMBIOS record.
188 
189   This function allows the update of specific SMBIOS strings. The number of valid strings for any
190   SMBIOS record is defined by how many strings were present when Add() was called.
191 
192   @param[in]    SmbiosHandle    SMBIOS Handle of structure that will have its string updated.
193   @param[in]    StringNumber    The non-zero string number of the string to update.
194   @param[in]    String          Update the StringNumber string with String.
195 
196   @retval EFI_SUCCESS           SmbiosHandle had its StringNumber String updated.
197   @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist. Or String is invalid.
198   @retval EFI_UNSUPPORTED       String was not added because it is longer than the SMBIOS Table supports.
199   @retval EFI_NOT_FOUND         The StringNumber.is not valid for this SMBIOS record.
200 **/
201 EFI_STATUS
202 EFIAPI
203 SmbiosLibUpdateUnicodeString (
204   IN  EFI_SMBIOS_HANDLE     SmbiosHandle,
205   IN  SMBIOS_TABLE_STRING   StringNumber,
206   IN  CHAR16                *String
207   )
208 {
209   EFI_STATUS  Status;
210   UINTN       StringIndex;
211   CHAR8       *Ascii;
212 
213   if (String == NULL) {
214     return EFI_INVALID_PARAMETER;
215   }
216 
217   if (*String == '\0') {
218     // A string with no data is not legal in SMBIOS
219     return EFI_INVALID_PARAMETER;
220   }
221 
222   Ascii = AllocateZeroPool (StrSize (String));
223   if (Ascii == NULL) {
224     return EFI_OUT_OF_RESOURCES;
225   }
226   UnicodeStrToAsciiStrS (String, Ascii, StrSize (String));
227 
228   StringIndex = StringNumber;
229   Status = gSmbios->UpdateString (gSmbios, &SmbiosHandle, &StringIndex, Ascii);
230 
231   FreePool (Ascii);
232   return Status;
233 }
234 
235 
236 /**
237   Allow caller to read a specific SMBIOS string
238 
239   @param[in]    Header          SMBIOS record that contains the string.
240   @param[in[    StringNumber    Instance of SMBIOS string 1 - N.
241 
242   @retval NULL                  Instance of Type SMBIOS string was not found.
243   @retval Other                 Pointer to matching SMBIOS string.
244 **/
245 CHAR8 *
246 EFIAPI
247 SmbiosLibReadString (
248   IN SMBIOS_STRUCTURE   *Header,
249   IN EFI_SMBIOS_STRING  StringNumber
250   )
251 {
252   CHAR8       *Data;
253   UINTN       Match;
254 
255   Data = (CHAR8 *)Header + Header->Length;
256   for (Match = 1;!(*Data == 0 && *(Data+1) == 0); ) {
257     if (StringNumber == Match) {
258       return Data;
259     }
260     Data++;
261     if (*(Data - 1) == '\0') {
262       Match++;
263     }
264   }
265 
266   return NULL;
267 }
268 
269 
270 /**
271   Allow the caller to discover a specific SMBIOS entry, and patch it if necissary.
272 
273   @param[in]    Type            Type of the next SMBIOS record to return.
274   @param[in[    Instance        Instance of SMBIOS record 0 - N-1.
275   @param[out]   SmbiosHandle    Returns SMBIOS handle for the matching record.
276 
277   @retval NULL                  Instance of Type SMBIOS record was not found.
278   @retval Other                 Pointer to matching SMBIOS record.
279 **/
280 SMBIOS_STRUCTURE *
281 EFIAPI
282 SmbiosLibGetRecord (
283   IN  EFI_SMBIOS_TYPE   Type,
284   IN  UINTN             Instance,
285   OUT EFI_SMBIOS_HANDLE *SmbiosHandle
286   )
287 {
288   EFI_STATUS              Status;
289   EFI_SMBIOS_TABLE_HEADER *Record;
290   UINTN                   Match;
291 
292   Match         = 0;
293   *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
294   do {
295     Status = gSmbios->GetNext (gSmbios, SmbiosHandle, &Type, &Record, NULL);
296     if (!EFI_ERROR (Status)) {
297       if (Match == Instance) {
298         return (SMBIOS_STRUCTURE *)Record;
299       }
300       Match++;
301     }
302   } while (!EFI_ERROR (Status));
303 
304   return NULL;
305 }
306 
307 
308 /**
309   Remove an SMBIOS record.
310 
311   This function removes an SMBIOS record using the handle specified by SmbiosHandle.
312 
313   @param[in]    SmbiosHandle        The handle of the SMBIOS record to remove.
314 
315   @retval EFI_SUCCESS               SMBIOS record was removed.
316   @retval EFI_INVALID_PARAMETER     SmbiosHandle does not specify a valid SMBIOS record.
317 **/
318 EFI_STATUS
319 EFIAPI
320 SmbiosLibRemove (
321   OUT EFI_SMBIOS_HANDLE SmbiosHandle
322   )
323 {
324   return gSmbios->Remove (gSmbios, SmbiosHandle);
325 }
326 
327 
328 
329 /**
330 
331   @param  ImageHandle  ImageHandle of the loaded driver.
332   @param  SystemTable  Pointer to the EFI System Table.
333 
334   @retval  EFI_SUCCESS            Register successfully.
335   @retval  EFI_OUT_OF_RESOURCES   No enough memory to register this handler.
336 **/
337 EFI_STATUS
338 EFIAPI
339 SmbiosLibConstructor (
340   IN EFI_HANDLE        ImageHandle,
341   IN EFI_SYSTEM_TABLE  *SystemTable
342   )
343 {
344   return gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&gSmbios);
345 }
346 
347