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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
|
Let's try to get information from one of the system tables that we've discovered.
You can find the most recent version of the "System Management BIOS (SMBIOS) Reference Specification" on the DMTF site https://www.dmtf.org/dsp/DSP0134
For example now 3.4.0 is the most recent version https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf
From the previous lesson we now, that SMBIOS table is declared under `gEfiSmbiosTableGuid`.
Let's create an app, that would print the address of this table.
```
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseMemoryLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiSmbiosTableGuid)) {
Print(L"SMBIOS table is placed at %p\n", SystemTable->ConfigurationTable[i].VendorTable);
}
}
return EFI_SUCCESS;
}
```
In this code we've used `CompareGuid` function from the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/BaseMemoryLib.h:
```
/**
Compares two GUIDs.
This function compares Guid1 to Guid2. If the GUIDs are identical then TRUE is returned.
If there are any bit differences in the two GUIDs, then FALSE is returned.
If Guid1 is NULL, then ASSERT().
If Guid2 is NULL, then ASSERT().
@param Guid1 A pointer to a 128 bit GUID.
@param Guid2 A pointer to a 128 bit GUID.
@retval TRUE Guid1 and Guid2 are identical.
@retval FALSE Guid1 and Guid2 are not identical.
**/
BOOLEAN
EFIAPI
CompareGuid (
IN CONST GUID *Guid1,
IN CONST GUID *Guid2
);
```
Don't forget to add:
```
[Guids]
gEfiSmbiosTableGuid
```
to app *inf file.
Let's build our app and execute it under OVMF:
```
FS0:\> SmbiosInfo.efi
SMBIOS table is placed at 7941000
```
# Get SMBIOS tables with `dmem`
UEFI shell has a command `dmem` for memory dump:
```
FS0:\> dmem -? -b
Displays the contents of system or device memory.
DMEM [-b] [address] [size] [-MMIO]
-b - Displays one screen at a time.
-MMIO - Forces address cycles to the PCI bus.
address - Specifies a starting address in hexadecimal format.
size - Specifies the number of bytes to display in hexadecimal format.
NOTES:
1. This command displays the contents of system memory or device memory.
2. Enter address and size in hexadecimal format.
3. If address is not specified, the contents of the UEFI System Table
are displayed. Otherwise, memory starting at the specified address is displayed.
4. Size specifies the number of bytes to display. If size is not specified,
512 bytes are displayed.
5. If MMIO is not specified, main system memory is displayed. Otherwise,
device memory is displayed through the use of the
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
EXAMPLES:
* To display the UEFI system table pointer entries:
fs0:\> dmem
* To display memory contents from 1af3088 with size of 16 bytes:
Shell> dmem 1af3088 16
* To display memory mapped IO contents from 1af3088 with a size of 16 bytes:
Shell> dmem 1af3088 16 -MMIO
```
Let's use it to print 0x30 bytes from the 0x7941000 address that we count as a SMBIOS table pointer.
```
FS0:\> dmem 7941000 30
Memory Address 0000000007941000 30 Bytes
07941000: 5F 53 4D 5F 26 1F 02 08-53 00 00 00 00 00 00 00 *_SM_&...S.......*
07941010: 5F 44 4D 49 5F 0A 91 01-00 00 94 07 09 00 28 AF *_DMI_.........(.*
07941020: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF *................*
```
If you look at SMBIOS specification for SMBIOS Entry Point structure you'll see, that `_SM_` and `_DMI_` are predefined values in this structure.
![SMBIOS_entry_structure](SMBIOS_entry_structure.png?raw=true "SMBIOS_entry_structure")
You can find definition for the structure itself in edk2 under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h
```
typedef struct {
UINT8 AnchorString[4];
UINT8 EntryPointStructureChecksum;
UINT8 EntryPointLength;
UINT8 MajorVersion;
UINT8 MinorVersion;
UINT16 MaxStructureSize;
UINT8 EntryPointRevision;
UINT8 FormattedArea[5];
UINT8 IntermediateAnchorString[5];
UINT8 IntermediateChecksum;
UINT16 TableLength;
UINT32 TableAddress;
UINT16 NumberOfSmbiosStructures;
UINT8 SmbiosBcdRevision;
} SMBIOS_TABLE_ENTRY_POINT;
```
If you calculate offsets for different fields you can parse memory dump:
![SMBIOS_entry_structure_dump](SMBIOS_entry_structure_dump.png?raw=true "SMBIOS_entry_structure_dump")
System has 9 SMBIOS structures placed from 0x07940000 to (0x07940000+0x191).
Now when we know address for SMBIOS structures, we can dump them as well.
```
FS0:\> dmem 07940000 191
Memory Address 0000000007940000 191 Bytes
07940000: 01 1B 00 01 01 02 03 00-00 00 00 00 00 00 00 00 *................*
07940010: 00 00 00 00 00 00 00 00-06 00 00 51 45 4D 55 00 *...........QEMU.*
07940020: 53 74 61 6E 64 61 72 64-20 50 43 20 28 69 34 34 *Standard PC (i44*
07940030: 30 46 58 20 2B 20 50 49-49 58 2C 20 31 39 39 36 *0FX + PIIX, 1996*
07940040: 29 00 70 63 2D 69 34 34-30 66 78 2D 66 6F 63 61 *).pc-i440fx-foca*
07940050: 6C 00 00 03 16 00 03 01-01 02 00 00 03 03 03 02 *l...............*
07940060: 00 00 00 00 00 00 00 00-00 51 45 4D 55 00 70 63 *.........QEMU.pc*
07940070: 2D 69 34 34 30 66 78 2D-66 6F 63 61 6C 00 00 04 *-i440fx-focal...*
07940080: 2A 00 04 01 03 01 02 63-06 00 00 FD FB 8B 07 03 **......c........*
07940090: 00 00 00 D0 07 D0 07 41-01 FF FF FF FF FF FF 00 *.......A........*
079400A0: 00 00 01 01 01 02 00 01-00 43 50 55 20 30 00 51 *.........CPU 0.Q*
079400B0: 45 4D 55 00 70 63 2D 69-34 34 30 66 78 2D 66 6F *EMU.pc-i440fx-fo*
079400C0: 63 61 6C 00 00 10 17 00-10 01 03 06 00 00 02 00 *cal.............*
079400D0: FE FF 01 00 00 00 00 00-00 00 00 00 00 00 11 28 *...............(*
079400E0: 00 11 00 10 FE FF FF FF-FF FF 80 00 09 00 01 00 *................*
079400F0: 07 02 00 00 00 02 00 00-00 00 00 00 00 00 00 00 *................*
07940100: 00 00 00 00 00 00 44 49-4D 4D 20 30 00 51 45 4D *......DIMM 0.QEM*
07940110: 55 00 00 13 1F 00 13 00-00 00 00 FF FF 01 00 00 *U...............*
07940120: 10 01 00 00 00 00 00 00-00 00 00 00 00 00 00 00 *................*
07940130: 00 00 00 00 20 0B 00 20-00 00 00 00 00 00 00 00 *.... .. ........*
07940140: 00 00 1A 00 00 01 02 00-E8 03 00 08 00 00 00 00 *................*
07940150: 00 00 00 00 1C 00 00 FF-FF 00 00 45 46 49 20 44 *...........EFI D*
07940160: 65 76 65 6C 6F 70 6D 65-6E 74 20 4B 69 74 20 49 *evelopment Kit I*
07940170: 49 20 2F 20 4F 56 4D 46-00 30 2E 30 2E 30 00 30 *I / OVMF.0.0.0.0*
07940180: 32 2F 30 36 2F 32 30 31-35 00 00 7F 04 FF FE 00 *2/06/2015.......*
07940190: 00 *.*
```
# Use EFI_SMBIOS_PROTOCOL to parse SMBIOS data
We can use direct pointer arithmetics to parse SMBIOS tables, but that would be very tedious.
Luckily UEFI PI specification defines a `EFI_SMBIOS_PROTOCOL`, that we can use to get SMBIOS data.
```
EFI_SMBIOS_PROTOCOL
Summary:
Allows consumers to log SMBIOS data records, and enables the producer to create the SMBIOS tables for a platform.
Protocol Interface Structure:
typedef struct _EFI_SMBIOS_PROTOCOL {
EFI_SMBIOS_ADD Add;
EFI_SMBIOS_UPDATE_STRINGUpdateString;
EFI_SMBIOS_REMOVE Remove;
EFI_SMBIOS_GET_NEXT GetNext;
UINT8 MajorVersion;
UINT8 MinorVersion;
} EFI_SMBIOS_PROTOCOL;
Member Description:
Add Add an SMBIOS record including the formatted area and the optional strings
that follow the formatted area.
UpdateString Update a string in the SMBIOS record.
Remove Remove an SMBIOS record.
GetNext Discover all SMBIOS records.
MajorVersion The major revision of the SMBIOS specification supported.
MinorVersion The minor revision of the SMBIOS specification supported.
Description:
This protocol provides an interface to add, remove or discover SMBIOS records. The driver which
produces this protocol is responsible for creating the SMBIOS data tables and installing the pointer
to the tables in the EFI System Configuration Table.
```
Right now we are interested in SMBIOS table parsing, so we need to utilize `GetNext` function:
```
EFI_SMBIOS_PROTOCOL.GetNext()
Summary:
Allow the caller to discover all or some of the SMBIOS records.
Prototype
typedef
EFI_STATUS
(EFIAPI *EFI_SMBIOS_GET_NEXT) (
IN CONST EFI_SMBIOS_PROTOCOL *This,
IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
IN EFI_SMBIOS_TYPE *Type, OPTIONAL
OUT EFI_SMBIOS_TABLE_HEADER **Record,
OUT EFI_HANDLE *ProducerHandle OPTIONAL
);
Parameters:
This The EFI_SMBIOS_PROTOCOL instance.
SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record
handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS
records.
Type On entry, it points to the type of the next SMBIOS record to return. If NULL, it
indicates that the next record of any type will be returned. Type is not modified by
the this function.
Record On exit, points to a pointer to the the SMBIOS Record consisting of the formatted area
followed by the unformatted area. The unformatted area optionally contains text
strings.
ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no
ProducerHandle was passed into Add() NULL is returned. If a NULL pointer is
passed in no data will be returned
Description
This function allows all of the SMBIOS records to be discovered. It's possible to find
only the SMBIOS records that match the optional Type argument.
Status Codes Returned:
EFI_SUCCESS .SMBIOS record information was successfully returned in Record.
SmbiosHandle is the handle of the current SMBIOS record
EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
```
First let's get this protocol in our app.
```
EFI_SMBIOS_PROTOCOL* SmbiosProtocol;
EFI_STATUS Status = gBS->LocateProtocol (
&gEfiSmbiosProtocolGuid,
NULL,
(VOID**)&SmbiosProtocol
);
if (EFI_ERROR (Status)) {
return Status;
}
```
To use it we need to add include to our app https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Smbios.h:
```
#include <Protocol/Smbios.h>
```
And add protocol guid to our *.inf file:
```
[Protocols]
gEfiSmbiosProtocolGuid
```
Now let's try to get SMBIOS tables. We would be using `SMBIOS_HANDLE_PI_RESERVED` as `EFI_SMBIOS_HANDLE` in protocol calls. You can find explanation in https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h:
```
///
/// Reference SMBIOS 2.7, chapter 6.1.2.
/// The UEFI Platform Initialization Specification reserves handle number FFFEh for its
/// EFI_SMBIOS_PROTOCOL.Add() function to mean "assign an unused handle number automatically."
/// This number is not used for any other purpose by the SMBIOS specification.
///
#define SMBIOS_HANDLE_PI_RESERVED 0xFFFE
```
Also before we start writing code look at the definition of `EFI_SMBIOS_TABLE_HEADER` structure, that we would receive on `GetNext` calls.
https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Smbios.h
```
typedef SMBIOS_STRUCTURE EFI_SMBIOS_TABLE_HEADER;
```
https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h
```
///
/// The Smbios structure header.
///
typedef struct {
SMBIOS_TYPE Type;
UINT8 Length;
SMBIOS_HANDLE Handle;
} SMBIOS_STRUCTURE;
```
Now we are ready to write some code. Write a code to print all types of Smbios tables that are present in the system:
```
EFI_SMBIOS_HANDLE SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
EFI_SMBIOS_TABLE_HEADER* Record;
Status = SmbiosProtocol->GetNext(SmbiosProtocol,
&SmbiosHandle,
NULL,
&Record,
NULL);
while (!EFI_ERROR(Status)) {
Print (L"SMBIOS Type %d \n", Record->Type);
Status = SmbiosProtocol->GetNext(SmbiosProtocol,
&SmbiosHandle,
NULL,
&Record,
NULL);
}
```
If you build our app and test it under OVMF you would get:
```
SMBIOS table is placed at 7941000
SMBIOS Type 1
SMBIOS Type 3
SMBIOS Type 4
SMBIOS Type 16
SMBIOS Type 17
SMBIOS Type 19
SMBIOS Type 32
SMBIOS Type 0
```
Ok, now let's write code that can parse information in these tables.
Let's start with Type 0 table. edk2 has a structure description at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h:
```
///
/// BIOS Information (Type 0).
///
typedef struct {
SMBIOS_STRUCTURE Hdr;
SMBIOS_TABLE_STRING Vendor;
SMBIOS_TABLE_STRING BiosVersion;
UINT16 BiosSegment;
SMBIOS_TABLE_STRING BiosReleaseDate;
UINT8 BiosSize;
MISC_BIOS_CHARACTERISTICS BiosCharacteristics;
UINT8 BIOSCharacteristicsExtensionBytes[2];
UINT8 SystemBiosMajorRelease;
UINT8 SystemBiosMinorRelease;
UINT8 EmbeddedControllerFirmwareMajorRelease;
UINT8 EmbeddedControllerFirmwareMinorRelease;
//
// Add for smbios 3.1.0
//
EXTENDED_BIOS_ROM_SIZE ExtendedBiosSize;
} SMBIOS_TABLE_TYPE0;
```
In this structure `SMBIOS_STRUCTURE Hdr` is a mandatory field that is the same as `EFI_SMBIOS_TABLE_HEADER` that we receive from our protocol function call.
Also `SMBIOS_TABLE_STRING` is just an UINT8 value that defines a string number in an ASCII string array that is placed directly after the structure.
```
///
/// Text strings associated with a given SMBIOS structure are returned in the dmiStrucBuffer, appended directly after
/// the formatted portion of the structure. This method of returning string information eliminates the need for
/// application software to deal with pointers embedded in the SMBIOS structure. Each string is terminated with a null
/// (00h) BYTE and the set of strings is terminated with an additional null (00h) BYTE. When the formatted portion of
/// a SMBIOS structure references a string, it does so by specifying a non-zero string number within the structure's
/// string-set. For example, if a string field contains 02h, it references the second string following the formatted portion
/// of the SMBIOS structure. If a string field references no string, a null (0) is placed in that string field. 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.
///
typedef UINT8 SMBIOS_TABLE_STRING;
```
So let's write a simple function that returns actual ASCII string from a `EFI_SMBIOS_TABLE_HEADER*` and a string number:
```
CHAR8* GetRecordString(EFI_SMBIOS_TABLE_HEADER* Record, UINTN number)
{
if (!number)
return "";
CHAR8* String = (CHAR8*)Record + Record->Length;
UINTN i=1;
while (i < number) {
String = String + AsciiStrSize(String);
i++;
}
return String;
}
```
Here we've used `AsciiStrSize` function that is defined in https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/String.c file.
```
/**
Returns the size of a Null-terminated ASCII string in bytes, including the
Null terminator.
This function returns the size, in bytes, of the Null-terminated ASCII string
specified by String.
If String is NULL, then ASSERT().
If PcdMaximumAsciiStringLength is not zero and String contains more than
PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
then ASSERT().
@param String A pointer to a Null-terminated ASCII string.
@return The size of String.
**/
UINTN
EFIAPI
AsciiStrSize (
IN CONST CHAR8 *String
)
```
Now we have everything to write actual parsing code in our `while` loop:
```
while (!EFI_ERROR(Status)) {
Print (L"SMBIOS Type %d \n", Record->Type);
switch (Record->Type) {
case EFI_SMBIOS_TYPE_BIOS_INFORMATION: {
SMBIOS_TABLE_TYPE0* Type0Record = (SMBIOS_TABLE_TYPE0*) Record;
Print(L"\tVendor=%a\n", GetRecordString(Record, Type0Record->Vendor));
Print(L"\tBiosVersion=%a\n", GetRecordString(Record, Type0Record->BiosVersion));
Print(L"\tBiosReleaseDate=%a\n", GetRecordString(Record, Type0Record->BiosReleaseDate));
Print(L"\tBiosSegment=0x%x\n", Type0Record->BiosSegment);
Print(L"\tSystemBiosMajorRelease=0x%x\n", Type0Record->SystemBiosMajorRelease);
Print(L"\tSystemBiosMinorRelease=0x%x\n", Type0Record->SystemBiosMinorRelease);
break;
}
default:
Print(L"\tTODO: Parsing for this table is not ready yet\n");
break;
}
Status = SmbiosProtocol->GetNext(SmbiosProtocol,
&SmbiosHandle,
NULL,
&Record,
NULL);
}
```
To print ASCII strings here we've used `%a` format code (https://github.com/tianocore/edk/blob/master/Foundation/Library/Pei/PeiLib/Print/Print.c).
If you build and execute our app under OVMF you would get:
```
FS0:\> SmbiosInfo.efi
SMBIOS table is placed at 7941000
SMBIOS Type 1
TODO: Parsing for this table is not ready yet
SMBIOS Type 3
TODO: Parsing for this table is not ready yet
SMBIOS Type 4
TODO: Parsing for this table is not ready yet
SMBIOS Type 16
TODO: Parsing for this table is not ready yet
SMBIOS Type 17
TODO: Parsing for this table is not ready yet
SMBIOS Type 19
TODO: Parsing for this table is not ready yet
SMBIOS Type 32
TODO: Parsing for this table is not ready yet
SMBIOS Type 0
Vendor=EFI Development Kit II / OVMF
BiosVersion=0.0.0
BiosReleaseDate=02/06/2015
BiosSegment=0xE800
SystemBiosMajorRelease=0x0
SystemBiosMinorRelease=0x0
```
If you look closely at `dmem` dump from earlier, you'll see that these are the exact strings that were actually present in memory.
We can easily to add code to parse other SMBIOS tables.
For example here is some parsing code for table type 1 structure:
```
case EFI_SMBIOS_TYPE_SYSTEM_INFORMATION: {
SMBIOS_TABLE_TYPE1* Type1Record = (SMBIOS_TABLE_TYPE1*) Record;
Print(L"\tManufacturer=%a\n", GetRecordString(Record, Type1Record->Manufacturer));
Print(L"\tProductName=%a\n", GetRecordString(Record, Type1Record->ProductName));
Print(L"\tVersion=%a\n", GetRecordString(Record, Type1Record->Version));
Print(L"\tSerialNumber=%a\n", GetRecordString(Record, Type1Record->SerialNumber));
Print(L"\tUUID=%g\n", Type1Record->Uuid);
Print(L"\tWakeUpType=%d\n", Type1Record->WakeUpType);
Print(L"\tSKUNumber=%a\n", GetRecordString(Record, Type1Record->SKUNumber));
Print(L"\tFamily=%a\n", GetRecordString(Record, Type1Record->Family));
break;
}
```
Structure itself is:
```
typedef struct {
SMBIOS_STRUCTURE Hdr;
SMBIOS_TABLE_STRING Manufacturer;
SMBIOS_TABLE_STRING ProductName;
SMBIOS_TABLE_STRING Version;
SMBIOS_TABLE_STRING SerialNumber;
GUID Uuid;
UINT8 WakeUpType; ///< The enumeration value from MISC_SYSTEM_WAKEUP_TYPE.
SMBIOS_TABLE_STRING SKUNumber;
SMBIOS_TABLE_STRING Family;
} SMBIOS_TABLE_TYPE1;
```
Build and execute:
```
FS0:\> SmbiosInfo.efi
SMBIOS table is placed at 7941000
SMBIOS Type 1
Manufacturer=QEMU
ProductName=Standard PC (i440FX + PIIX, 1996)
Version=pc-i440fx-focal
SerialNumber=
UUID=00000000-0000-0000-0000-000000000000
WakeUpType=6
SKUNumber=
Family=
SMBIOS Type 3
TODO: Parsing for this table is not ready yet
SMBIOS Type 4
TODO: Parsing for this table is not ready yet
SMBIOS Type 16
TODO: Parsing for this table is not ready yet
SMBIOS Type 17
TODO: Parsing for this table is not ready yet
SMBIOS Type 19
TODO: Parsing for this table is not ready yet
SMBIOS Type 32
TODO: Parsing for this table is not ready yet
SMBIOS Type 0
Vendor=EFI Development Kit II / OVMF
BiosVersion=0.0.0
BiosReleaseDate=02/06/2015
BiosSegment=0xE800
SystemBiosMajorRelease=0x0
SystemBiosMinorRelease=0x0
```
As you remember the same information that is present in these SMBIOS tables is present in the main BIOS menu:
![BIOS_menu](BIOS_menu.png?raw=true "BIOS_menu")
And in case you wonder where OVMF defines all these information for its SMBIOS structures, checkout https://github.com/tianocore/edk2/blob/master/OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.c and implementation of a `EFI_SMBIOS_PROTOCOL` is placed here https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
# `smbiosview` command
We can use `EFI_SMBIOS_PROTOCOL` to parse SMBIOS table information, but actually if you just want to see SMBIOS information there is a better option.
UEFI shell has a `smbiosview` command that does exactly what we need.
You can checkout sources for this command here: https://github.com/tianocore/edk2/tree/master/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView
First checkout help for this command:
```
FS0:\> smbiosview -?
Displays SMBIOS information.
SMBIOSVIEW [-t SmbiosType]|[-h SmbiosHandle]|[-s]|[-a]
-t - Displays all structures of SmbiosType.
-h - Displays structure of SmbiosHandle.
-s - Displays a statistics table.
-a - Displays all information.
SmbiosType - Specifies a SMBIOS structure type.
SmbiosHandle - Specifies a SMBIOS structure unique 16-bit handle.
NOTES:
1. The SmbiosType parameter supports the following types:
0 - BIOS Information
1 - System Information
2 - Baseboard Information
3 - System Enclosure
4 - Processor Information
5 - Memory Controller Information
6 - Memory Module Information
7 - Cache Information
8 - Port Connector Information
9 - System Slots
10 - On Board Devices Information
11 - OEM Strings
12 - System Configuration Options
13 - BIOS Language Information
14 - Group Associations
15 - System Event Log
16 - Physical Memory Array
17 - Memory Device
18 - 32-bit Memory Error Information
19 - Memory Array Mapped Address
20 - Memory Device Mapped Address
21 - Built-in Pointing Device
22 - Portable Battery
23 - System Reset
24 - Hardware Security
25 - System Power Controls
26 - Voltage Probe
27 - Cooling Device
28 - Temperature Probe
29 - Electrical Current Probe
30 - Out-Of-Band Remote Access
31 - Boot Integrity Services (BIS) Entry Point
32 - System Boot Information
33 - 64-Bit Memory Error Information
34 - Management Device
35 - Management Device Component
36 - Management Device Threshold Data
37 - Memory Channel
38 - IPMI Device Information
39 - System Power Supply
40 - Additional Information
41 - Onboard Devices Extended Information
42 - Management Controller Host Interface
43 - TPM Device
44 - Processor Additional Information
2. Enter the SmbiosHandle parameter in hexadecimal format.
Do not use the '0x' prefix format for hexadecimal values.
3. Internal commands:
:q -------- quit smbiosview
:0 -------- Change smbiosview display NONE info
:1 -------- Change smbiosview display OUTLINE info
:2 -------- Change smbiosview display NORMAL info
:3 -------- Change smbiosview display DETAIL info
/? -------- Show help
```
Try to dump one of the structures that we've tried to parse manually:
```
FS0:\> smbiosview -t 0
SMBIOS Entry Point Structure:
Anchor String: _SM_
EPS Checksum: 0x26
Entry Point Len: 31
Version: 2.8
Number of Structures: 9
Max Struct size: 83
Table Address: 0x7940000
Table Length: 401
Entry Point revision: 0x0
SMBIOS BCD Revision: 0x28
Inter Anchor: _DMI_
Inter Checksum: 0xA
Formatted Area:
00000000: 00 00 00 00 00 *.....*
=========================================================
Query Structure, conditions are:
QueryType = 0
QueryHandle = Random
ShowType = SHOW_DETAIL
=========================================================
Type=0, Handle=0x0
Dump Structure as:
Index=7,Length=0x4A,Addr=0x7940141
00000000: 00 1A 00 00 01 02 00 E8-03 00 08 00 00 00 00 00 *................*
FS0:\> 0: 00 00 00 1C 00 00 FF FF-00 00 45 46 49 20 44 65 *..........EFI De*
00000020: 76 65 6C 6F 70 6D 65 6E-74 20 4B 69 74 20 49 49 *velopment Kit II*
00000030: 20 2F 20 4F 56 4D 46 00-30 2E 30 2E 30 00 30 32 * / OVMF.0.0.0.02*
00000040: 2F 30 36 2F 32 30 31 35-00 00 */06/2015..*
Structure Type: BIOS Information
Format part Len : 26
Structure Handle: 0
Vendor: EFI Development Kit II / OVMF
BiosVersion: 0.0.0
BiosSegment: 0xE800
BiosReleaseDate: 02/06/2015
BiosSize: 64 KB
BIOS Characteristics:
BIOS Characteristics Not Supported
Bits 32:47 are reserved for BIOS Vendor
Bits 48:64 are reserved for System Vendor
BIOS Characteristics Extension Byte1:
BIOS Characteristics Extension Byte2:
Enable Targeted Content Distribution
UEFI Specification is supported
The SMBIOS table describes a virtual machine
Bits 5:7 are reserved for future assignment
SystemBiosMajorRelease: 0
SystemBiosMinorRelease: 0
EmbeddedControllerFirmwareMajorRelease: 255
EmbeddedControllerFirmwareMinorRelease: 255
```
As you can see it is all the same info that we've received using `EFI_SMBIOS_PROTOCOL`.
You can use this command to see what is inside all of the SMBIOS structures using:
```
FS0:\> smbiosview -b
...
```
The output is too big to paste here, so check it out yourself!
|