xref: /qemu/hw/smbios/smbios.c (revision 5ed79482)
160d8f328SWei Huang /*
260d8f328SWei Huang  * SMBIOS Support
360d8f328SWei Huang  *
460d8f328SWei Huang  * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
560d8f328SWei Huang  * Copyright (C) 2013 Red Hat, Inc.
660d8f328SWei Huang  *
760d8f328SWei Huang  * Authors:
860d8f328SWei Huang  *  Alex Williamson <alex.williamson@hp.com>
960d8f328SWei Huang  *  Markus Armbruster <armbru@redhat.com>
1060d8f328SWei Huang  *
1160d8f328SWei Huang  * This work is licensed under the terms of the GNU GPL, version 2.  See
1260d8f328SWei Huang  * the COPYING file in the top-level directory.
1360d8f328SWei Huang  *
1460d8f328SWei Huang  * Contributions after 2012-01-13 are licensed under the terms of the
1560d8f328SWei Huang  * GNU GPL, version 2 or (at your option) any later version.
1660d8f328SWei Huang  */
1760d8f328SWei Huang 
180430891cSPeter Maydell #include "qemu/osdep.h"
19968dfd05SPhilippe Mathieu-Daudé #include "qemu/units.h"
20da34e65cSMarkus Armbruster #include "qapi/error.h"
2160d8f328SWei Huang #include "qemu/config-file.h"
220b8fa32fSMarkus Armbruster #include "qemu/module.h"
23922a01a0SMarkus Armbruster #include "qemu/option.h"
2460d8f328SWei Huang #include "sysemu/sysemu.h"
25cea25275SFam Zheng #include "qemu/uuid.h"
26a2eb5c0cSPhilippe Mathieu-Daudé #include "hw/firmware/smbios.h"
2760d8f328SWei Huang #include "hw/loader.h"
28a0628599SLike Xu #include "hw/boards.h"
2905dfb447SVincent Bernat #include "hw/pci/pci_bus.h"
30edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
310517cc98SCorey Minyard #include "smbios_build.h"
3260d8f328SWei Huang 
3360d8f328SWei Huang static bool smbios_uuid_encoded = true;
34cba59fe3SIgor Mammedov /*
35cba59fe3SIgor Mammedov  * SMBIOS tables provided by user with '-smbios file=<foo>' option
36cba59fe3SIgor Mammedov  */
37cba59fe3SIgor Mammedov uint8_t *usr_blobs;
38cba59fe3SIgor Mammedov size_t usr_blobs_len;
39cba59fe3SIgor Mammedov static unsigned usr_table_max;
40cba59fe3SIgor Mammedov static unsigned usr_table_cnt;
4160d8f328SWei Huang 
420517cc98SCorey Minyard uint8_t *smbios_tables;
430517cc98SCorey Minyard size_t smbios_tables_len;
440517cc98SCorey Minyard unsigned smbios_table_max;
450517cc98SCorey Minyard unsigned smbios_table_cnt;
4686299120SWei Huang 
4786299120SWei Huang static SmbiosEntryPoint ep;
4860d8f328SWei Huang 
4960d8f328SWei Huang static int smbios_type4_count = 0;
5060d8f328SWei Huang static bool smbios_have_defaults;
51e94e0a83SIgor Mammedov static uint32_t smbios_cpuid_version, smbios_cpuid_features;
5260d8f328SWei Huang 
53d638a865SIgor Mammedov DECLARE_BITMAP(smbios_have_binfile_bitmap, SMBIOS_MAX_TYPE + 1);
54d638a865SIgor Mammedov DECLARE_BITMAP(smbios_have_fields_bitmap, SMBIOS_MAX_TYPE + 1);
5560d8f328SWei Huang 
56d638a865SIgor Mammedov smbios_type0_t smbios_type0;
57d638a865SIgor Mammedov smbios_type1_t smbios_type1;
5860d8f328SWei Huang 
5960d8f328SWei Huang static struct {
6060d8f328SWei Huang     const char *manufacturer, *product, *version, *serial, *asset, *location;
6160d8f328SWei Huang } type2;
6260d8f328SWei Huang 
6360d8f328SWei Huang static struct {
6460d8f328SWei Huang     const char *manufacturer, *version, *serial, *asset, *sku;
6560d8f328SWei Huang } type3;
6660d8f328SWei Huang 
67c906e039SYing Fang /*
68c906e039SYing Fang  * SVVP requires max_speed and current_speed to be set and not being
69c906e039SYing Fang  * 0 which counts as unknown (SMBIOS 3.1.0/Table 21). Set the
70c906e039SYing Fang  * default value to 2000MHz as we did before.
71c906e039SYing Fang  */
72c906e039SYing Fang #define DEFAULT_CPU_SPEED 2000
73c906e039SYing Fang 
7460d8f328SWei Huang static struct {
75b5831d79SHeinrich Schuchardt     uint16_t processor_family;
7660d8f328SWei Huang     const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
77c906e039SYing Fang     uint64_t max_speed;
78c906e039SYing Fang     uint64_t current_speed;
79cb5fb04fSPatrick Venture     uint64_t processor_id;
80c906e039SYing Fang } type4 = {
81c906e039SYing Fang     .max_speed = DEFAULT_CPU_SPEED,
82cb5fb04fSPatrick Venture     .current_speed = DEFAULT_CPU_SPEED,
83cb5fb04fSPatrick Venture     .processor_id = 0,
84b5831d79SHeinrich Schuchardt     .processor_family = 0x01, /* Other */
85c906e039SYing Fang };
8660d8f328SWei Huang 
87fd8caa25SHal Martin struct type8_instance {
88fd8caa25SHal Martin     const char *internal_reference, *external_reference;
89fd8caa25SHal Martin     uint8_t connector_type, port_type;
90fd8caa25SHal Martin     QTAILQ_ENTRY(type8_instance) next;
91fd8caa25SHal Martin };
92fd8caa25SHal Martin static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8);
93fd8caa25SHal Martin 
94735eee07SFelix Wu /* type 9 instance for parsing */
95735eee07SFelix Wu struct type9_instance {
9604f143d8SFelix Wu     const char *slot_designation, *pcidev;
97735eee07SFelix Wu     uint8_t slot_type, slot_data_bus_width, current_usage, slot_length,
98735eee07SFelix Wu             slot_characteristics1, slot_characteristics2;
99735eee07SFelix Wu     uint16_t slot_id;
100735eee07SFelix Wu     QTAILQ_ENTRY(type9_instance) next;
101735eee07SFelix Wu };
102735eee07SFelix Wu static QTAILQ_HEAD(, type9_instance) type9 = QTAILQ_HEAD_INITIALIZER(type9);
103735eee07SFelix Wu 
10460d8f328SWei Huang static struct {
1052d6dcbf9SDaniel P. Berrange     size_t nvalues;
106bb99f477SDaniel P. Berrangé     char **values;
1072d6dcbf9SDaniel P. Berrange } type11;
1082d6dcbf9SDaniel P. Berrange 
1092d6dcbf9SDaniel P. Berrange static struct {
11060d8f328SWei Huang     const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
11160d8f328SWei Huang     uint16_t speed;
11260d8f328SWei Huang } type17;
11360d8f328SWei Huang 
11405dfb447SVincent Bernat static QEnumLookup type41_kind_lookup = {
11505dfb447SVincent Bernat     .array = (const char *const[]) {
11605dfb447SVincent Bernat         "other",
11705dfb447SVincent Bernat         "unknown",
11805dfb447SVincent Bernat         "video",
11905dfb447SVincent Bernat         "scsi",
12005dfb447SVincent Bernat         "ethernet",
12105dfb447SVincent Bernat         "tokenring",
12205dfb447SVincent Bernat         "sound",
12305dfb447SVincent Bernat         "pata",
12405dfb447SVincent Bernat         "sata",
12505dfb447SVincent Bernat         "sas",
12605dfb447SVincent Bernat     },
12705dfb447SVincent Bernat     .size = 10
12805dfb447SVincent Bernat };
12905dfb447SVincent Bernat struct type41_instance {
13005dfb447SVincent Bernat     const char *designation, *pcidev;
13105dfb447SVincent Bernat     uint8_t instance, kind;
13205dfb447SVincent Bernat     QTAILQ_ENTRY(type41_instance) next;
13305dfb447SVincent Bernat };
13405dfb447SVincent Bernat static QTAILQ_HEAD(, type41_instance) type41 = QTAILQ_HEAD_INITIALIZER(type41);
13505dfb447SVincent Bernat 
13660d8f328SWei Huang static QemuOptsList qemu_smbios_opts = {
13760d8f328SWei Huang     .name = "smbios",
13860d8f328SWei Huang     .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
13960d8f328SWei Huang     .desc = {
14060d8f328SWei Huang         /*
14160d8f328SWei Huang          * no elements => accept any params
14260d8f328SWei Huang          * validation will happen later
14360d8f328SWei Huang          */
14460d8f328SWei Huang         { /* end of list */ }
14560d8f328SWei Huang     }
14660d8f328SWei Huang };
14760d8f328SWei Huang 
14860d8f328SWei Huang static const QemuOptDesc qemu_smbios_file_opts[] = {
14960d8f328SWei Huang     {
15060d8f328SWei Huang         .name = "file",
15160d8f328SWei Huang         .type = QEMU_OPT_STRING,
15260d8f328SWei Huang         .help = "binary file containing an SMBIOS element",
15360d8f328SWei Huang     },
15460d8f328SWei Huang     { /* end of list */ }
15560d8f328SWei Huang };
15660d8f328SWei Huang 
15760d8f328SWei Huang static const QemuOptDesc qemu_smbios_type0_opts[] = {
15860d8f328SWei Huang     {
15960d8f328SWei Huang         .name = "type",
16060d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
16160d8f328SWei Huang         .help = "SMBIOS element type",
16260d8f328SWei Huang     },{
16360d8f328SWei Huang         .name = "vendor",
16460d8f328SWei Huang         .type = QEMU_OPT_STRING,
16560d8f328SWei Huang         .help = "vendor name",
16660d8f328SWei Huang     },{
16760d8f328SWei Huang         .name = "version",
16860d8f328SWei Huang         .type = QEMU_OPT_STRING,
16960d8f328SWei Huang         .help = "version number",
17060d8f328SWei Huang     },{
17160d8f328SWei Huang         .name = "date",
17260d8f328SWei Huang         .type = QEMU_OPT_STRING,
17360d8f328SWei Huang         .help = "release date",
17460d8f328SWei Huang     },{
17560d8f328SWei Huang         .name = "release",
17660d8f328SWei Huang         .type = QEMU_OPT_STRING,
17760d8f328SWei Huang         .help = "revision number",
17860d8f328SWei Huang     },{
17960d8f328SWei Huang         .name = "uefi",
18060d8f328SWei Huang         .type = QEMU_OPT_BOOL,
18160d8f328SWei Huang         .help = "uefi support",
18260d8f328SWei Huang     },
18360d8f328SWei Huang     { /* end of list */ }
18460d8f328SWei Huang };
18560d8f328SWei Huang 
18660d8f328SWei Huang static const QemuOptDesc qemu_smbios_type1_opts[] = {
18760d8f328SWei Huang     {
18860d8f328SWei Huang         .name = "type",
18960d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
19060d8f328SWei Huang         .help = "SMBIOS element type",
19160d8f328SWei Huang     },{
19260d8f328SWei Huang         .name = "manufacturer",
19360d8f328SWei Huang         .type = QEMU_OPT_STRING,
19460d8f328SWei Huang         .help = "manufacturer name",
19560d8f328SWei Huang     },{
19660d8f328SWei Huang         .name = "product",
19760d8f328SWei Huang         .type = QEMU_OPT_STRING,
19860d8f328SWei Huang         .help = "product name",
19960d8f328SWei Huang     },{
20060d8f328SWei Huang         .name = "version",
20160d8f328SWei Huang         .type = QEMU_OPT_STRING,
20260d8f328SWei Huang         .help = "version number",
20360d8f328SWei Huang     },{
20460d8f328SWei Huang         .name = "serial",
20560d8f328SWei Huang         .type = QEMU_OPT_STRING,
20660d8f328SWei Huang         .help = "serial number",
20760d8f328SWei Huang     },{
20860d8f328SWei Huang         .name = "uuid",
20960d8f328SWei Huang         .type = QEMU_OPT_STRING,
21060d8f328SWei Huang         .help = "UUID",
21160d8f328SWei Huang     },{
21260d8f328SWei Huang         .name = "sku",
21360d8f328SWei Huang         .type = QEMU_OPT_STRING,
21460d8f328SWei Huang         .help = "SKU number",
21560d8f328SWei Huang     },{
21660d8f328SWei Huang         .name = "family",
21760d8f328SWei Huang         .type = QEMU_OPT_STRING,
21860d8f328SWei Huang         .help = "family name",
21960d8f328SWei Huang     },
22060d8f328SWei Huang     { /* end of list */ }
22160d8f328SWei Huang };
22260d8f328SWei Huang 
22360d8f328SWei Huang static const QemuOptDesc qemu_smbios_type2_opts[] = {
22460d8f328SWei Huang     {
22560d8f328SWei Huang         .name = "type",
22660d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
22760d8f328SWei Huang         .help = "SMBIOS element type",
22860d8f328SWei Huang     },{
22960d8f328SWei Huang         .name = "manufacturer",
23060d8f328SWei Huang         .type = QEMU_OPT_STRING,
23160d8f328SWei Huang         .help = "manufacturer name",
23260d8f328SWei Huang     },{
23360d8f328SWei Huang         .name = "product",
23460d8f328SWei Huang         .type = QEMU_OPT_STRING,
23560d8f328SWei Huang         .help = "product name",
23660d8f328SWei Huang     },{
23760d8f328SWei Huang         .name = "version",
23860d8f328SWei Huang         .type = QEMU_OPT_STRING,
23960d8f328SWei Huang         .help = "version number",
24060d8f328SWei Huang     },{
24160d8f328SWei Huang         .name = "serial",
24260d8f328SWei Huang         .type = QEMU_OPT_STRING,
24360d8f328SWei Huang         .help = "serial number",
24460d8f328SWei Huang     },{
24560d8f328SWei Huang         .name = "asset",
24660d8f328SWei Huang         .type = QEMU_OPT_STRING,
24760d8f328SWei Huang         .help = "asset tag number",
24860d8f328SWei Huang     },{
24960d8f328SWei Huang         .name = "location",
25060d8f328SWei Huang         .type = QEMU_OPT_STRING,
25160d8f328SWei Huang         .help = "location in chassis",
25260d8f328SWei Huang     },
25360d8f328SWei Huang     { /* end of list */ }
25460d8f328SWei Huang };
25560d8f328SWei Huang 
25660d8f328SWei Huang static const QemuOptDesc qemu_smbios_type3_opts[] = {
25760d8f328SWei Huang     {
25860d8f328SWei Huang         .name = "type",
25960d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
26060d8f328SWei Huang         .help = "SMBIOS element type",
26160d8f328SWei Huang     },{
26260d8f328SWei Huang         .name = "manufacturer",
26360d8f328SWei Huang         .type = QEMU_OPT_STRING,
26460d8f328SWei Huang         .help = "manufacturer name",
26560d8f328SWei Huang     },{
26660d8f328SWei Huang         .name = "version",
26760d8f328SWei Huang         .type = QEMU_OPT_STRING,
26860d8f328SWei Huang         .help = "version number",
26960d8f328SWei Huang     },{
27060d8f328SWei Huang         .name = "serial",
27160d8f328SWei Huang         .type = QEMU_OPT_STRING,
27260d8f328SWei Huang         .help = "serial number",
27360d8f328SWei Huang     },{
27460d8f328SWei Huang         .name = "asset",
27560d8f328SWei Huang         .type = QEMU_OPT_STRING,
27660d8f328SWei Huang         .help = "asset tag number",
27760d8f328SWei Huang     },{
27860d8f328SWei Huang         .name = "sku",
27960d8f328SWei Huang         .type = QEMU_OPT_STRING,
28060d8f328SWei Huang         .help = "SKU number",
28160d8f328SWei Huang     },
28260d8f328SWei Huang     { /* end of list */ }
28360d8f328SWei Huang };
28460d8f328SWei Huang 
28560d8f328SWei Huang static const QemuOptDesc qemu_smbios_type4_opts[] = {
28660d8f328SWei Huang     {
28760d8f328SWei Huang         .name = "type",
28860d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
28960d8f328SWei Huang         .help = "SMBIOS element type",
29060d8f328SWei Huang     },{
29160d8f328SWei Huang         .name = "sock_pfx",
29260d8f328SWei Huang         .type = QEMU_OPT_STRING,
29360d8f328SWei Huang         .help = "socket designation string prefix",
29460d8f328SWei Huang     },{
29560d8f328SWei Huang         .name = "manufacturer",
29660d8f328SWei Huang         .type = QEMU_OPT_STRING,
29760d8f328SWei Huang         .help = "manufacturer name",
29860d8f328SWei Huang     },{
29960d8f328SWei Huang         .name = "version",
30060d8f328SWei Huang         .type = QEMU_OPT_STRING,
30160d8f328SWei Huang         .help = "version number",
30260d8f328SWei Huang     },{
303c906e039SYing Fang         .name = "max-speed",
304c906e039SYing Fang         .type = QEMU_OPT_NUMBER,
305c906e039SYing Fang         .help = "max speed in MHz",
306c906e039SYing Fang     },{
307c906e039SYing Fang         .name = "current-speed",
308c906e039SYing Fang         .type = QEMU_OPT_NUMBER,
309c906e039SYing Fang         .help = "speed at system boot in MHz",
310c906e039SYing Fang     },{
31160d8f328SWei Huang         .name = "serial",
31260d8f328SWei Huang         .type = QEMU_OPT_STRING,
31360d8f328SWei Huang         .help = "serial number",
31460d8f328SWei Huang     },{
31560d8f328SWei Huang         .name = "asset",
31660d8f328SWei Huang         .type = QEMU_OPT_STRING,
31760d8f328SWei Huang         .help = "asset tag number",
31860d8f328SWei Huang     },{
31960d8f328SWei Huang         .name = "part",
32060d8f328SWei Huang         .type = QEMU_OPT_STRING,
32160d8f328SWei Huang         .help = "part number",
322cb5fb04fSPatrick Venture     }, {
323b5831d79SHeinrich Schuchardt         .name = "processor-family",
324b5831d79SHeinrich Schuchardt         .type = QEMU_OPT_NUMBER,
325b5831d79SHeinrich Schuchardt         .help = "processor family",
326b5831d79SHeinrich Schuchardt     }, {
327cb5fb04fSPatrick Venture         .name = "processor-id",
328cb5fb04fSPatrick Venture         .type = QEMU_OPT_NUMBER,
329cb5fb04fSPatrick Venture         .help = "processor id",
33060d8f328SWei Huang     },
33160d8f328SWei Huang     { /* end of list */ }
33260d8f328SWei Huang };
33360d8f328SWei Huang 
334fd8caa25SHal Martin static const QemuOptDesc qemu_smbios_type8_opts[] = {
335fd8caa25SHal Martin     {
336196578c9SAkihiko Odaki         .name = "type",
337196578c9SAkihiko Odaki         .type = QEMU_OPT_NUMBER,
338196578c9SAkihiko Odaki         .help = "SMBIOS element type",
339196578c9SAkihiko Odaki     },
340196578c9SAkihiko Odaki     {
341fd8caa25SHal Martin         .name = "internal_reference",
342fd8caa25SHal Martin         .type = QEMU_OPT_STRING,
343fd8caa25SHal Martin         .help = "internal reference designator",
344fd8caa25SHal Martin     },
345fd8caa25SHal Martin     {
346fd8caa25SHal Martin         .name = "external_reference",
347fd8caa25SHal Martin         .type = QEMU_OPT_STRING,
348fd8caa25SHal Martin         .help = "external reference designator",
349fd8caa25SHal Martin     },
350fd8caa25SHal Martin     {
351fd8caa25SHal Martin         .name = "connector_type",
352fd8caa25SHal Martin         .type = QEMU_OPT_NUMBER,
353fd8caa25SHal Martin         .help = "connector type",
354fd8caa25SHal Martin     },
355fd8caa25SHal Martin     {
356fd8caa25SHal Martin         .name = "port_type",
357fd8caa25SHal Martin         .type = QEMU_OPT_NUMBER,
358fd8caa25SHal Martin         .help = "port type",
359fd8caa25SHal Martin     },
360196578c9SAkihiko Odaki     { /* end of list */ }
361fd8caa25SHal Martin };
362fd8caa25SHal Martin 
363735eee07SFelix Wu static const QemuOptDesc qemu_smbios_type9_opts[] = {
364735eee07SFelix Wu     {
365735eee07SFelix Wu         .name = "type",
366735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
367735eee07SFelix Wu         .help = "SMBIOS element type",
368735eee07SFelix Wu     },
369735eee07SFelix Wu     {
370735eee07SFelix Wu         .name = "slot_designation",
371735eee07SFelix Wu         .type = QEMU_OPT_STRING,
372735eee07SFelix Wu         .help = "string number for reference designation",
373735eee07SFelix Wu     },
374735eee07SFelix Wu     {
375735eee07SFelix Wu         .name = "slot_type",
376735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
377735eee07SFelix Wu         .help = "connector type",
378735eee07SFelix Wu     },
379735eee07SFelix Wu     {
380735eee07SFelix Wu         .name = "slot_data_bus_width",
381735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
382735eee07SFelix Wu         .help = "port type",
383735eee07SFelix Wu     },
384735eee07SFelix Wu     {
385735eee07SFelix Wu         .name = "current_usage",
386735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
387735eee07SFelix Wu         .help = "current usage",
388735eee07SFelix Wu     },
389735eee07SFelix Wu     {
390735eee07SFelix Wu         .name = "slot_length",
391735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
392735eee07SFelix Wu         .help = "system slot length",
393735eee07SFelix Wu     },
394735eee07SFelix Wu     {
395735eee07SFelix Wu         .name = "slot_id",
396735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
397735eee07SFelix Wu         .help = "system slot id",
398735eee07SFelix Wu     },
399735eee07SFelix Wu     {
400735eee07SFelix Wu         .name = "slot_characteristics1",
401735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
402735eee07SFelix Wu         .help = "slot characteristics1, see the spec",
403735eee07SFelix Wu     },
404735eee07SFelix Wu     {
405735eee07SFelix Wu         .name = "slot_characteristics2",
406735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
407735eee07SFelix Wu         .help = "slot characteristics2, see the spec",
408735eee07SFelix Wu     },
40904f143d8SFelix Wu     {
41004f143d8SFelix Wu         .name = "pci_device",
41104f143d8SFelix Wu         .type = QEMU_OPT_STRING,
41204f143d8SFelix Wu         .help = "PCI device, if provided."
41304f143d8SFelix Wu     }
414735eee07SFelix Wu };
415735eee07SFelix Wu 
4162d6dcbf9SDaniel P. Berrange static const QemuOptDesc qemu_smbios_type11_opts[] = {
4172d6dcbf9SDaniel P. Berrange     {
418cd8a35b9SAkihiko Odaki         .name = "type",
419cd8a35b9SAkihiko Odaki         .type = QEMU_OPT_NUMBER,
420cd8a35b9SAkihiko Odaki         .help = "SMBIOS element type",
421cd8a35b9SAkihiko Odaki     },
422cd8a35b9SAkihiko Odaki     {
4232d6dcbf9SDaniel P. Berrange         .name = "value",
4242d6dcbf9SDaniel P. Berrange         .type = QEMU_OPT_STRING,
4252d6dcbf9SDaniel P. Berrange         .help = "OEM string data",
4262d6dcbf9SDaniel P. Berrange     },
427bb99f477SDaniel P. Berrangé     {
428bb99f477SDaniel P. Berrangé         .name = "path",
429bb99f477SDaniel P. Berrangé         .type = QEMU_OPT_STRING,
430bb99f477SDaniel P. Berrangé         .help = "OEM string data from file",
431bb99f477SDaniel P. Berrangé     },
432cd8a35b9SAkihiko Odaki     { /* end of list */ }
4332d6dcbf9SDaniel P. Berrange };
4342d6dcbf9SDaniel P. Berrange 
43560d8f328SWei Huang static const QemuOptDesc qemu_smbios_type17_opts[] = {
43660d8f328SWei Huang     {
43760d8f328SWei Huang         .name = "type",
43860d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
43960d8f328SWei Huang         .help = "SMBIOS element type",
44060d8f328SWei Huang     },{
44160d8f328SWei Huang         .name = "loc_pfx",
44260d8f328SWei Huang         .type = QEMU_OPT_STRING,
44360d8f328SWei Huang         .help = "device locator string prefix",
44460d8f328SWei Huang     },{
44560d8f328SWei Huang         .name = "bank",
44660d8f328SWei Huang         .type = QEMU_OPT_STRING,
44760d8f328SWei Huang         .help = "bank locator string",
44860d8f328SWei Huang     },{
44960d8f328SWei Huang         .name = "manufacturer",
45060d8f328SWei Huang         .type = QEMU_OPT_STRING,
45160d8f328SWei Huang         .help = "manufacturer name",
45260d8f328SWei Huang     },{
45360d8f328SWei Huang         .name = "serial",
45460d8f328SWei Huang         .type = QEMU_OPT_STRING,
45560d8f328SWei Huang         .help = "serial number",
45660d8f328SWei Huang     },{
45760d8f328SWei Huang         .name = "asset",
45860d8f328SWei Huang         .type = QEMU_OPT_STRING,
45960d8f328SWei Huang         .help = "asset tag number",
46060d8f328SWei Huang     },{
46160d8f328SWei Huang         .name = "part",
46260d8f328SWei Huang         .type = QEMU_OPT_STRING,
46360d8f328SWei Huang         .help = "part number",
46460d8f328SWei Huang     },{
46560d8f328SWei Huang         .name = "speed",
46660d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
46760d8f328SWei Huang         .help = "maximum capable speed",
46860d8f328SWei Huang     },
46960d8f328SWei Huang     { /* end of list */ }
47060d8f328SWei Huang };
47160d8f328SWei Huang 
47205dfb447SVincent Bernat static const QemuOptDesc qemu_smbios_type41_opts[] = {
47305dfb447SVincent Bernat     {
47405dfb447SVincent Bernat         .name = "type",
47505dfb447SVincent Bernat         .type = QEMU_OPT_NUMBER,
47605dfb447SVincent Bernat         .help = "SMBIOS element type",
47705dfb447SVincent Bernat     },{
47805dfb447SVincent Bernat         .name = "designation",
47905dfb447SVincent Bernat         .type = QEMU_OPT_STRING,
48005dfb447SVincent Bernat         .help = "reference designation string",
48105dfb447SVincent Bernat     },{
48205dfb447SVincent Bernat         .name = "kind",
48305dfb447SVincent Bernat         .type = QEMU_OPT_STRING,
48405dfb447SVincent Bernat         .help = "device type",
48505dfb447SVincent Bernat         .def_value_str = "other",
48605dfb447SVincent Bernat     },{
48705dfb447SVincent Bernat         .name = "instance",
48805dfb447SVincent Bernat         .type = QEMU_OPT_NUMBER,
48905dfb447SVincent Bernat         .help = "device type instance",
49005dfb447SVincent Bernat     },{
49105dfb447SVincent Bernat         .name = "pcidev",
49205dfb447SVincent Bernat         .type = QEMU_OPT_STRING,
49305dfb447SVincent Bernat         .help = "PCI device",
49405dfb447SVincent Bernat     },
49505dfb447SVincent Bernat     { /* end of list */ }
49605dfb447SVincent Bernat };
49705dfb447SVincent Bernat 
smbios_register_config(void)49860d8f328SWei Huang static void smbios_register_config(void)
49960d8f328SWei Huang {
50060d8f328SWei Huang     qemu_add_opts(&qemu_smbios_opts);
50160d8f328SWei Huang }
50260d8f328SWei Huang 
50334294e2fSEduardo Habkost opts_init(smbios_register_config);
50460d8f328SWei Huang 
50510c36666SDaniel P. Berrangé /*
50610c36666SDaniel P. Berrangé  * The SMBIOS 2.1 "structure table length" field in the
50710c36666SDaniel P. Berrangé  * entry point uses a 16-bit integer, so we're limited
50810c36666SDaniel P. Berrangé  * in total table size
50910c36666SDaniel P. Berrangé  */
51010c36666SDaniel P. Berrangé #define SMBIOS_21_MAX_TABLES_LEN 0xffff
51110c36666SDaniel P. Berrangé 
smbios_check_type4_count(uint32_t expected_t4_count,Error ** errp)512643e1c9eSIgor Mammedov static bool smbios_check_type4_count(uint32_t expected_t4_count, Error **errp)
51360d8f328SWei Huang {
514e94e0a83SIgor Mammedov     if (smbios_type4_count && smbios_type4_count != expected_t4_count) {
515643e1c9eSIgor Mammedov         error_setg(errp, "Expected %d SMBIOS Type 4 tables, got %d instead",
516e94e0a83SIgor Mammedov                    expected_t4_count, smbios_type4_count);
517643e1c9eSIgor Mammedov         return false;
51860d8f328SWei Huang     }
519643e1c9eSIgor Mammedov     return true;
5209cd7fd69SIgor Mammedov }
52110c36666SDaniel P. Berrangé 
smbios_validate_table(SmbiosEntryPointType ep_type,Error ** errp)52269ea07a5SIgor Mammedov bool smbios_validate_table(SmbiosEntryPointType ep_type, Error **errp)
5239cd7fd69SIgor Mammedov {
52469ea07a5SIgor Mammedov     if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
52510c36666SDaniel P. Berrangé         smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
526643e1c9eSIgor Mammedov         error_setg(errp, "SMBIOS 2.1 table length %zu exceeds %d",
52710c36666SDaniel P. Berrangé                    smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
528643e1c9eSIgor Mammedov         return false;
52910c36666SDaniel P. Berrangé     }
530643e1c9eSIgor Mammedov     return true;
53160d8f328SWei Huang }
53260d8f328SWei Huang 
smbios_skip_table(uint8_t type,bool required_table)5330517cc98SCorey Minyard bool smbios_skip_table(uint8_t type, bool required_table)
53460d8f328SWei Huang {
535d638a865SIgor Mammedov     if (test_bit(type, smbios_have_binfile_bitmap)) {
53660d8f328SWei Huang         return true; /* user provided their own binary blob(s) */
53760d8f328SWei Huang     }
538d638a865SIgor Mammedov     if (test_bit(type, smbios_have_fields_bitmap)) {
53960d8f328SWei Huang         return false; /* user provided fields via command line */
54060d8f328SWei Huang     }
54160d8f328SWei Huang     if (smbios_have_defaults && required_table) {
54260d8f328SWei Huang         return false; /* we're building tables, and this one's required */
54360d8f328SWei Huang     }
54460d8f328SWei Huang     return true;
54560d8f328SWei Huang }
54660d8f328SWei Huang 
5473818acf5SAni Sinha #define T0_BASE 0x000
5483818acf5SAni Sinha #define T1_BASE 0x100
5493818acf5SAni Sinha #define T2_BASE 0x200
5503818acf5SAni Sinha #define T3_BASE 0x300
5513818acf5SAni Sinha #define T4_BASE 0x400
552735eee07SFelix Wu #define T9_BASE 0x900
5533818acf5SAni Sinha #define T11_BASE 0xe00
5543818acf5SAni Sinha 
5553818acf5SAni Sinha #define T16_BASE 0x1000
5563818acf5SAni Sinha #define T17_BASE 0x1100
5573818acf5SAni Sinha #define T19_BASE 0x1300
5583818acf5SAni Sinha #define T32_BASE 0x2000
5593818acf5SAni Sinha #define T41_BASE 0x2900
5603818acf5SAni Sinha #define T127_BASE 0x7F00
5613818acf5SAni Sinha 
smbios_build_type_0_table(void)56260d8f328SWei Huang static void smbios_build_type_0_table(void)
56360d8f328SWei Huang {
5643818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(0, T0_BASE, false); /* optional, leave up to BIOS */
56560d8f328SWei Huang 
566d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(0, vendor_str, smbios_type0.vendor);
567d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(0, bios_version_str, smbios_type0.version);
56860d8f328SWei Huang 
56960d8f328SWei Huang     t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
57060d8f328SWei Huang 
571d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(0, bios_release_date_str, smbios_type0.date);
57260d8f328SWei Huang 
57360d8f328SWei Huang     t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
57460d8f328SWei Huang 
57560d8f328SWei Huang     t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
57660d8f328SWei Huang     t->bios_characteristics_extension_bytes[0] = 0;
57760d8f328SWei Huang     t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
578d638a865SIgor Mammedov     if (smbios_type0.uefi) {
57960d8f328SWei Huang         t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
58060d8f328SWei Huang     }
58160d8f328SWei Huang 
582d638a865SIgor Mammedov     if (smbios_type0.have_major_minor) {
583d638a865SIgor Mammedov         t->system_bios_major_release = smbios_type0.major;
584d638a865SIgor Mammedov         t->system_bios_minor_release = smbios_type0.minor;
58560d8f328SWei Huang     } else {
58660d8f328SWei Huang         t->system_bios_major_release = 0;
58760d8f328SWei Huang         t->system_bios_minor_release = 0;
58860d8f328SWei Huang     }
58960d8f328SWei Huang 
59060d8f328SWei Huang     /* hardcoded in SeaBIOS */
59160d8f328SWei Huang     t->embedded_controller_major_release = 0xFF;
59260d8f328SWei Huang     t->embedded_controller_minor_release = 0xFF;
59360d8f328SWei Huang 
59460d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
59560d8f328SWei Huang }
59660d8f328SWei Huang 
59760d8f328SWei Huang /* Encode UUID from the big endian encoding described on RFC4122 to the wire
59860d8f328SWei Huang  * format specified by SMBIOS version 2.6.
59960d8f328SWei Huang  */
smbios_encode_uuid(struct smbios_uuid * uuid,QemuUUID * in)6009c5ce8dbSFam Zheng static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in)
60160d8f328SWei Huang {
602664ee768SMarc-André Lureau     memcpy(uuid, in, 16);
60360d8f328SWei Huang     if (smbios_uuid_encoded) {
60460d8f328SWei Huang         uuid->time_low = bswap32(uuid->time_low);
60560d8f328SWei Huang         uuid->time_mid = bswap16(uuid->time_mid);
60660d8f328SWei Huang         uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
60760d8f328SWei Huang     }
60860d8f328SWei Huang }
60960d8f328SWei Huang 
smbios_build_type_1_table(void)61060d8f328SWei Huang static void smbios_build_type_1_table(void)
61160d8f328SWei Huang {
6123818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(1, T1_BASE, true); /* required */
61360d8f328SWei Huang 
614d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, manufacturer_str, smbios_type1.manufacturer);
615d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, product_name_str, smbios_type1.product);
616d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, version_str, smbios_type1.version);
617d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, serial_number_str, smbios_type1.serial);
61860d8f328SWei Huang     if (qemu_uuid_set) {
6199c5ce8dbSFam Zheng         smbios_encode_uuid(&t->uuid, &qemu_uuid);
62060d8f328SWei Huang     } else {
62160d8f328SWei Huang         memset(&t->uuid, 0, 16);
62260d8f328SWei Huang     }
62360d8f328SWei Huang     t->wake_up_type = 0x06; /* power switch */
624d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, sku_number_str, smbios_type1.sku);
625d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, family_str, smbios_type1.family);
62660d8f328SWei Huang 
62760d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
62860d8f328SWei Huang }
62960d8f328SWei Huang 
smbios_build_type_2_table(void)63060d8f328SWei Huang static void smbios_build_type_2_table(void)
63160d8f328SWei Huang {
6323818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(2, T2_BASE, false); /* optional */
63360d8f328SWei Huang 
63460d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
63560d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
63660d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
63760d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
63860d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
63960d8f328SWei Huang     t->feature_flags = 0x01; /* Motherboard */
64060d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
64160d8f328SWei Huang     t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
64260d8f328SWei Huang     t->board_type = 0x0A; /* Motherboard */
64360d8f328SWei Huang     t->contained_element_count = 0;
64460d8f328SWei Huang 
64560d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
64660d8f328SWei Huang }
64760d8f328SWei Huang 
smbios_build_type_3_table(void)64860d8f328SWei Huang static void smbios_build_type_3_table(void)
64960d8f328SWei Huang {
6503818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(3, T3_BASE, true); /* required */
65160d8f328SWei Huang 
65260d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
65360d8f328SWei Huang     t->type = 0x01; /* Other */
65460d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
65560d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
65660d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
65760d8f328SWei Huang     t->boot_up_state = 0x03; /* Safe */
65860d8f328SWei Huang     t->power_supply_state = 0x03; /* Safe */
65960d8f328SWei Huang     t->thermal_state = 0x03; /* Safe */
66060d8f328SWei Huang     t->security_status = 0x02; /* Unknown */
66160d8f328SWei Huang     t->oem_defined = cpu_to_le32(0);
66260d8f328SWei Huang     t->height = 0;
66360d8f328SWei Huang     t->number_of_power_cords = 0;
66460d8f328SWei Huang     t->contained_element_count = 0;
665b81a5f94SDaniel P. Berrangé     t->contained_element_record_length = 0;
66660d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
66760d8f328SWei Huang 
66860d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
66960d8f328SWei Huang }
67060d8f328SWei Huang 
smbios_build_type_4_table(MachineState * ms,unsigned instance,SmbiosEntryPointType ep_type,Error ** errp)67169ea07a5SIgor Mammedov static void smbios_build_type_4_table(MachineState *ms, unsigned instance,
672*5ed79482SIgor Mammedov                                       SmbiosEntryPointType ep_type,
673*5ed79482SIgor Mammedov                                       Error **errp)
67460d8f328SWei Huang {
67560d8f328SWei Huang     char sock_str[128];
67605e27d74SJulia Suvorova     size_t tbl_len = SMBIOS_TYPE_4_LEN_V28;
6777298fd7dSZhao Liu     unsigned threads_per_socket;
678196ea60aSZhao Liu     unsigned cores_per_socket;
67960d8f328SWei Huang 
68069ea07a5SIgor Mammedov     if (ep_type == SMBIOS_ENTRY_POINT_TYPE_64) {
68105e27d74SJulia Suvorova         tbl_len = SMBIOS_TYPE_4_LEN_V30;
68205e27d74SJulia Suvorova     }
68305e27d74SJulia Suvorova 
68405e27d74SJulia Suvorova     SMBIOS_BUILD_TABLE_PRE_SIZE(4, T4_BASE + instance,
68505e27d74SJulia Suvorova                                 true, tbl_len); /* required */
68660d8f328SWei Huang 
68760d8f328SWei Huang     snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
68860d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
68960d8f328SWei Huang     t->processor_type = 0x03; /* CPU */
690b5831d79SHeinrich Schuchardt     t->processor_family = 0xfe; /* use Processor Family 2 field */
69160d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
692cb5fb04fSPatrick Venture     if (type4.processor_id == 0) {
69360d8f328SWei Huang         t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
69460d8f328SWei Huang         t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
695cb5fb04fSPatrick Venture     } else {
696cb5fb04fSPatrick Venture         t->processor_id[0] = cpu_to_le32((uint32_t)type4.processor_id);
697cb5fb04fSPatrick Venture         t->processor_id[1] = cpu_to_le32(type4.processor_id >> 32);
698cb5fb04fSPatrick Venture     }
69960d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
70060d8f328SWei Huang     t->voltage = 0;
70160d8f328SWei Huang     t->external_clock = cpu_to_le16(0); /* Unknown */
702c906e039SYing Fang     t->max_speed = cpu_to_le16(type4.max_speed);
703c906e039SYing Fang     t->current_speed = cpu_to_le16(type4.current_speed);
70460d8f328SWei Huang     t->status = 0x41; /* Socket populated, CPU enabled */
70560d8f328SWei Huang     t->processor_upgrade = 0x01; /* Other */
70660d8f328SWei Huang     t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
70760d8f328SWei Huang     t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
70860d8f328SWei Huang     t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
70960d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
71060d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
71160d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
71205e27d74SJulia Suvorova 
7137298fd7dSZhao Liu     threads_per_socket = machine_topo_get_threads_per_socket(ms);
714196ea60aSZhao Liu     cores_per_socket = machine_topo_get_cores_per_socket(ms);
7157298fd7dSZhao Liu 
716196ea60aSZhao Liu     t->core_count = (cores_per_socket > 255) ? 0xFF : cores_per_socket;
71705e27d74SJulia Suvorova     t->core_enabled = t->core_count;
71805e27d74SJulia Suvorova 
7197298fd7dSZhao Liu     t->thread_count = (threads_per_socket > 255) ? 0xFF : threads_per_socket;
72005e27d74SJulia Suvorova 
72160d8f328SWei Huang     t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
722b5831d79SHeinrich Schuchardt     t->processor_family2 = cpu_to_le16(type4.processor_family);
72360d8f328SWei Huang 
72460d09b8dSJulia Suvorova     if (tbl_len == SMBIOS_TYPE_4_LEN_V30) {
725196ea60aSZhao Liu         t->core_count2 = t->core_enabled2 = cpu_to_le16(cores_per_socket);
7267298fd7dSZhao Liu         t->thread_count2 = cpu_to_le16(threads_per_socket);
727*5ed79482SIgor Mammedov     } else if (t->core_count == 0xFF || t->thread_count == 0xFF) {
728*5ed79482SIgor Mammedov         error_setg(errp, "SMBIOS 2.0 doesn't support number of processor "
729*5ed79482SIgor Mammedov                          "cores/threads more than 255, use "
730*5ed79482SIgor Mammedov                          "-machine smbios-entry-point-type=64 option to enable "
731*5ed79482SIgor Mammedov                          "SMBIOS 3.0 support");
732*5ed79482SIgor Mammedov         return;
73360d09b8dSJulia Suvorova     }
73460d09b8dSJulia Suvorova 
73560d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
73660d8f328SWei Huang     smbios_type4_count++;
73760d8f328SWei Huang }
73860d8f328SWei Huang 
smbios_build_type_8_table(void)739fd8caa25SHal Martin static void smbios_build_type_8_table(void)
740fd8caa25SHal Martin {
741fd8caa25SHal Martin     unsigned instance = 0;
742fd8caa25SHal Martin     struct type8_instance *t8;
743fd8caa25SHal Martin 
744fd8caa25SHal Martin     QTAILQ_FOREACH(t8, &type8, next) {
745fd8caa25SHal Martin         SMBIOS_BUILD_TABLE_PRE(8, T0_BASE + instance, true);
746fd8caa25SHal Martin 
747fd8caa25SHal Martin         SMBIOS_TABLE_SET_STR(8, internal_reference_str, t8->internal_reference);
748fd8caa25SHal Martin         SMBIOS_TABLE_SET_STR(8, external_reference_str, t8->external_reference);
749fd8caa25SHal Martin         /* most vendors seem to set this to None */
750fd8caa25SHal Martin         t->internal_connector_type = 0x0;
751fd8caa25SHal Martin         t->external_connector_type = t8->connector_type;
752fd8caa25SHal Martin         t->port_type = t8->port_type;
753fd8caa25SHal Martin 
754fd8caa25SHal Martin         SMBIOS_BUILD_TABLE_POST;
755fd8caa25SHal Martin         instance++;
756fd8caa25SHal Martin     }
757fd8caa25SHal Martin }
758fd8caa25SHal Martin 
smbios_build_type_9_table(Error ** errp)75904f143d8SFelix Wu static void smbios_build_type_9_table(Error **errp)
760735eee07SFelix Wu {
761735eee07SFelix Wu     unsigned instance = 0;
762735eee07SFelix Wu     struct type9_instance *t9;
763735eee07SFelix Wu 
764735eee07SFelix Wu     QTAILQ_FOREACH(t9, &type9, next) {
765735eee07SFelix Wu         SMBIOS_BUILD_TABLE_PRE(9, T9_BASE + instance, true);
766735eee07SFelix Wu 
767735eee07SFelix Wu         SMBIOS_TABLE_SET_STR(9, slot_designation, t9->slot_designation);
768735eee07SFelix Wu         t->slot_type = t9->slot_type;
769735eee07SFelix Wu         t->slot_data_bus_width = t9->slot_data_bus_width;
770735eee07SFelix Wu         t->current_usage = t9->current_usage;
771735eee07SFelix Wu         t->slot_length = t9->slot_length;
772735eee07SFelix Wu         t->slot_id = t9->slot_id;
773735eee07SFelix Wu         t->slot_characteristics1 = t9->slot_characteristics1;
774735eee07SFelix Wu         t->slot_characteristics2 = t9->slot_characteristics2;
775735eee07SFelix Wu 
77604f143d8SFelix Wu         if (t9->pcidev) {
77704f143d8SFelix Wu             PCIDevice *pdev = NULL;
77804f143d8SFelix Wu             int rc = pci_qdev_find_device(t9->pcidev, &pdev);
77904f143d8SFelix Wu             if (rc != 0) {
78004f143d8SFelix Wu                 error_setg(errp,
78104f143d8SFelix Wu                            "No PCI device %s for SMBIOS type 9 entry %s",
78204f143d8SFelix Wu                            t9->pcidev, t9->slot_designation);
78304f143d8SFelix Wu                 return;
78404f143d8SFelix Wu             }
78504f143d8SFelix Wu             /*
78604f143d8SFelix Wu              * We only handle the case were the device is attached to
78704f143d8SFelix Wu              * the PCI root bus. The general case is more complex as
78804f143d8SFelix Wu              * bridges are enumerated later and the table would need
78904f143d8SFelix Wu              * to be updated at this moment.
79004f143d8SFelix Wu              */
79104f143d8SFelix Wu             if (!pci_bus_is_root(pci_get_bus(pdev))) {
79204f143d8SFelix Wu                 error_setg(errp,
79304f143d8SFelix Wu                            "Cannot create type 9 entry for PCI device %s: "
79404f143d8SFelix Wu                            "not attached to the root bus",
79504f143d8SFelix Wu                            t9->pcidev);
79604f143d8SFelix Wu                 return;
79704f143d8SFelix Wu             }
79804f143d8SFelix Wu             t->segment_group_number = cpu_to_le16(0);
79904f143d8SFelix Wu             t->bus_number = pci_dev_bus_num(pdev);
80004f143d8SFelix Wu             t->device_number = pdev->devfn;
80104f143d8SFelix Wu         } else {
80204f143d8SFelix Wu             /*
80304f143d8SFelix Wu              * Per SMBIOS spec, For slots that are not of the PCI, AGP, PCI-X,
80404f143d8SFelix Wu              * or PCI-Express type that do not have bus/device/function
80504f143d8SFelix Wu              * information, 0FFh should be populated in the fields of Segment
80604f143d8SFelix Wu              * Group Number, Bus Number, Device/Function Number.
80704f143d8SFelix Wu              */
80804f143d8SFelix Wu             t->segment_group_number = 0xff;
80904f143d8SFelix Wu             t->bus_number = 0xff;
81004f143d8SFelix Wu             t->device_number = 0xff;
81104f143d8SFelix Wu         }
81204f143d8SFelix Wu 
813735eee07SFelix Wu         SMBIOS_BUILD_TABLE_POST;
814735eee07SFelix Wu         instance++;
815735eee07SFelix Wu     }
816735eee07SFelix Wu }
817735eee07SFelix Wu 
smbios_build_type_11_table(void)8182d6dcbf9SDaniel P. Berrange static void smbios_build_type_11_table(void)
8192d6dcbf9SDaniel P. Berrange {
8202d6dcbf9SDaniel P. Berrange     char count_str[128];
8212d6dcbf9SDaniel P. Berrange     size_t i;
8222d6dcbf9SDaniel P. Berrange 
8232d6dcbf9SDaniel P. Berrange     if (type11.nvalues == 0) {
8242d6dcbf9SDaniel P. Berrange         return;
8252d6dcbf9SDaniel P. Berrange     }
8262d6dcbf9SDaniel P. Berrange 
8273818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(11, T11_BASE, true); /* required */
8282d6dcbf9SDaniel P. Berrange 
8292d6dcbf9SDaniel P. Berrange     snprintf(count_str, sizeof(count_str), "%zu", type11.nvalues);
8302d6dcbf9SDaniel P. Berrange     t->count = type11.nvalues;
8312d6dcbf9SDaniel P. Berrange 
8322d6dcbf9SDaniel P. Berrange     for (i = 0; i < type11.nvalues; i++) {
8332d6dcbf9SDaniel P. Berrange         SMBIOS_TABLE_SET_STR_LIST(11, type11.values[i]);
834bb99f477SDaniel P. Berrangé         g_free(type11.values[i]);
835bb99f477SDaniel P. Berrangé         type11.values[i] = NULL;
8362d6dcbf9SDaniel P. Berrange     }
8372d6dcbf9SDaniel P. Berrange 
8382d6dcbf9SDaniel P. Berrange     SMBIOS_BUILD_TABLE_POST;
8392d6dcbf9SDaniel P. Berrange }
8402d6dcbf9SDaniel P. Berrange 
84160d8f328SWei Huang #define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
84260d8f328SWei Huang 
smbios_build_type_16_table(unsigned dimm_cnt)84360d8f328SWei Huang static void smbios_build_type_16_table(unsigned dimm_cnt)
84460d8f328SWei Huang {
84560d8f328SWei Huang     uint64_t size_kb;
84660d8f328SWei Huang 
8473818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(16, T16_BASE, true); /* required */
84860d8f328SWei Huang 
84960d8f328SWei Huang     t->location = 0x01; /* Other */
85060d8f328SWei Huang     t->use = 0x03; /* System memory */
85160d8f328SWei Huang     t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
85286378b29SPaolo Bonzini     size_kb = QEMU_ALIGN_UP(current_machine->ram_size, KiB) / KiB;
85360d8f328SWei Huang     if (size_kb < MAX_T16_STD_SZ) {
85460d8f328SWei Huang         t->maximum_capacity = cpu_to_le32(size_kb);
85560d8f328SWei Huang         t->extended_maximum_capacity = cpu_to_le64(0);
85660d8f328SWei Huang     } else {
85760d8f328SWei Huang         t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
85886378b29SPaolo Bonzini         t->extended_maximum_capacity = cpu_to_le64(current_machine->ram_size);
85960d8f328SWei Huang     }
86060d8f328SWei Huang     t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
86160d8f328SWei Huang     t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
86260d8f328SWei Huang 
86360d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
86460d8f328SWei Huang }
86560d8f328SWei Huang 
86660d8f328SWei Huang #define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
86760d8f328SWei Huang #define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
86860d8f328SWei Huang 
smbios_build_type_17_table(unsigned instance,uint64_t size)86960d8f328SWei Huang static void smbios_build_type_17_table(unsigned instance, uint64_t size)
87060d8f328SWei Huang {
87160d8f328SWei Huang     char loc_str[128];
87260d8f328SWei Huang     uint64_t size_mb;
87360d8f328SWei Huang 
8743818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(17, T17_BASE + instance, true); /* required */
87560d8f328SWei Huang 
87660d8f328SWei Huang     t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
87760d8f328SWei Huang     t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
87860d8f328SWei Huang     t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
87960d8f328SWei Huang     t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
880968dfd05SPhilippe Mathieu-Daudé     size_mb = QEMU_ALIGN_UP(size, MiB) / MiB;
88160d8f328SWei Huang     if (size_mb < MAX_T17_STD_SZ) {
88260d8f328SWei Huang         t->size = cpu_to_le16(size_mb);
88360d8f328SWei Huang         t->extended_size = cpu_to_le32(0);
88460d8f328SWei Huang     } else {
88560d8f328SWei Huang         assert(size_mb < MAX_T17_EXT_SZ);
88660d8f328SWei Huang         t->size = cpu_to_le16(MAX_T17_STD_SZ);
88760d8f328SWei Huang         t->extended_size = cpu_to_le32(size_mb);
88860d8f328SWei Huang     }
88960d8f328SWei Huang     t->form_factor = 0x09; /* DIMM */
89060d8f328SWei Huang     t->device_set = 0; /* Not in a set */
89160d8f328SWei Huang     snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
89260d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
89360d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
89460d8f328SWei Huang     t->memory_type = 0x07; /* RAM */
89560d8f328SWei Huang     t->type_detail = cpu_to_le16(0x02); /* Other */
89660d8f328SWei Huang     t->speed = cpu_to_le16(type17.speed);
89760d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
89860d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
89960d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
90060d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
90160d8f328SWei Huang     t->attributes = 0; /* Unknown */
90260d8f328SWei Huang     t->configured_clock_speed = t->speed; /* reuse value for max speed */
90360d8f328SWei Huang     t->minimum_voltage = cpu_to_le16(0); /* Unknown */
90460d8f328SWei Huang     t->maximum_voltage = cpu_to_le16(0); /* Unknown */
90560d8f328SWei Huang     t->configured_voltage = cpu_to_le16(0); /* Unknown */
90660d8f328SWei Huang 
90760d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
90860d8f328SWei Huang }
90960d8f328SWei Huang 
smbios_build_type_19_table(unsigned instance,unsigned offset,uint64_t start,uint64_t size)910a379d455SAni Sinha static void smbios_build_type_19_table(unsigned instance, unsigned offset,
91160d8f328SWei Huang                                        uint64_t start, uint64_t size)
91260d8f328SWei Huang {
91360d8f328SWei Huang     uint64_t end, start_kb, end_kb;
91460d8f328SWei Huang 
915a379d455SAni Sinha     SMBIOS_BUILD_TABLE_PRE(19, T19_BASE + offset + instance,
916a379d455SAni Sinha                            true); /* required */
91760d8f328SWei Huang 
91860d8f328SWei Huang     end = start + size - 1;
91960d8f328SWei Huang     assert(end > start);
920968dfd05SPhilippe Mathieu-Daudé     start_kb = start / KiB;
921968dfd05SPhilippe Mathieu-Daudé     end_kb = end / KiB;
92260d8f328SWei Huang     if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
92360d8f328SWei Huang         t->starting_address = cpu_to_le32(start_kb);
92460d8f328SWei Huang         t->ending_address = cpu_to_le32(end_kb);
92560d8f328SWei Huang         t->extended_starting_address =
92660d8f328SWei Huang             t->extended_ending_address = cpu_to_le64(0);
92760d8f328SWei Huang     } else {
92860d8f328SWei Huang         t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
92960d8f328SWei Huang         t->extended_starting_address = cpu_to_le64(start);
93060d8f328SWei Huang         t->extended_ending_address = cpu_to_le64(end);
93160d8f328SWei Huang     }
93260d8f328SWei Huang     t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
93360d8f328SWei Huang     t->partition_width = 1; /* One device per row */
93460d8f328SWei Huang 
93560d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
93660d8f328SWei Huang }
93760d8f328SWei Huang 
smbios_build_type_32_table(void)93860d8f328SWei Huang static void smbios_build_type_32_table(void)
93960d8f328SWei Huang {
9403818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(32, T32_BASE, true); /* required */
94160d8f328SWei Huang 
94260d8f328SWei Huang     memset(t->reserved, 0, 6);
94360d8f328SWei Huang     t->boot_status = 0; /* No errors detected */
94460d8f328SWei Huang 
94560d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
94660d8f328SWei Huang }
94760d8f328SWei Huang 
smbios_build_type_41_table(Error ** errp)94805dfb447SVincent Bernat static void smbios_build_type_41_table(Error **errp)
94905dfb447SVincent Bernat {
95005dfb447SVincent Bernat     unsigned instance = 0;
95105dfb447SVincent Bernat     struct type41_instance *t41;
95205dfb447SVincent Bernat 
95305dfb447SVincent Bernat     QTAILQ_FOREACH(t41, &type41, next) {
9543818acf5SAni Sinha         SMBIOS_BUILD_TABLE_PRE(41, T41_BASE + instance, true);
95505dfb447SVincent Bernat 
95605dfb447SVincent Bernat         SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation);
95705dfb447SVincent Bernat         t->device_type = t41->kind;
95805dfb447SVincent Bernat         t->device_type_instance = t41->instance;
95905dfb447SVincent Bernat         t->segment_group_number = cpu_to_le16(0);
96005dfb447SVincent Bernat         t->bus_number = 0;
96105dfb447SVincent Bernat         t->device_number = 0;
96205dfb447SVincent Bernat 
96305dfb447SVincent Bernat         if (t41->pcidev) {
96405dfb447SVincent Bernat             PCIDevice *pdev = NULL;
96505dfb447SVincent Bernat             int rc = pci_qdev_find_device(t41->pcidev, &pdev);
96605dfb447SVincent Bernat             if (rc != 0) {
96705dfb447SVincent Bernat                 error_setg(errp,
96805dfb447SVincent Bernat                            "No PCI device %s for SMBIOS type 41 entry %s",
96905dfb447SVincent Bernat                            t41->pcidev, t41->designation);
97005dfb447SVincent Bernat                 return;
97105dfb447SVincent Bernat             }
97205dfb447SVincent Bernat             /*
97305dfb447SVincent Bernat              * We only handle the case were the device is attached to
97405dfb447SVincent Bernat              * the PCI root bus. The general case is more complex as
97505dfb447SVincent Bernat              * bridges are enumerated later and the table would need
97605dfb447SVincent Bernat              * to be updated at this moment.
97705dfb447SVincent Bernat              */
97805dfb447SVincent Bernat             if (!pci_bus_is_root(pci_get_bus(pdev))) {
97905dfb447SVincent Bernat                 error_setg(errp,
98005dfb447SVincent Bernat                            "Cannot create type 41 entry for PCI device %s: "
98105dfb447SVincent Bernat                            "not attached to the root bus",
98205dfb447SVincent Bernat                            t41->pcidev);
98305dfb447SVincent Bernat                 return;
98405dfb447SVincent Bernat             }
98505dfb447SVincent Bernat             t->segment_group_number = cpu_to_le16(0);
98605dfb447SVincent Bernat             t->bus_number = pci_dev_bus_num(pdev);
98705dfb447SVincent Bernat             t->device_number = pdev->devfn;
98805dfb447SVincent Bernat         }
98905dfb447SVincent Bernat 
99005dfb447SVincent Bernat         SMBIOS_BUILD_TABLE_POST;
99105dfb447SVincent Bernat         instance++;
99205dfb447SVincent Bernat     }
99305dfb447SVincent Bernat }
99405dfb447SVincent Bernat 
smbios_build_type_127_table(void)99560d8f328SWei Huang static void smbios_build_type_127_table(void)
99660d8f328SWei Huang {
9973818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(127, T127_BASE, true); /* required */
99860d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
99960d8f328SWei Huang }
100060d8f328SWei Huang 
smbios_set_cpuid(uint32_t version,uint32_t features)100160d8f328SWei Huang void smbios_set_cpuid(uint32_t version, uint32_t features)
100260d8f328SWei Huang {
100360d8f328SWei Huang     smbios_cpuid_version = version;
100460d8f328SWei Huang     smbios_cpuid_features = features;
100560d8f328SWei Huang }
100660d8f328SWei Huang 
100760d8f328SWei Huang #define SMBIOS_SET_DEFAULT(field, value)                                  \
100860d8f328SWei Huang     if (!field) {                                                         \
100960d8f328SWei Huang         field = value;                                                    \
101060d8f328SWei Huang     }
101160d8f328SWei Huang 
smbios_set_default_processor_family(uint16_t processor_family)10126f3b727bSHeinrich Schuchardt void smbios_set_default_processor_family(uint16_t processor_family)
10136f3b727bSHeinrich Schuchardt {
10146f3b727bSHeinrich Schuchardt     if (type4.processor_family <= 0x01) {
10156f3b727bSHeinrich Schuchardt         type4.processor_family = processor_family;
10166f3b727bSHeinrich Schuchardt     }
10176f3b727bSHeinrich Schuchardt }
10186f3b727bSHeinrich Schuchardt 
smbios_set_defaults(const char * manufacturer,const char * product,const char * version,bool uuid_encoded)101960d8f328SWei Huang void smbios_set_defaults(const char *manufacturer, const char *product,
1020b3854ce8SIgor Mammedov                          const char *version,
102169ea07a5SIgor Mammedov                          bool uuid_encoded)
102260d8f328SWei Huang {
102360d8f328SWei Huang     smbios_have_defaults = true;
102460d8f328SWei Huang     smbios_uuid_encoded = uuid_encoded;
102560d8f328SWei Huang 
1026d638a865SIgor Mammedov     SMBIOS_SET_DEFAULT(smbios_type1.manufacturer, manufacturer);
1027d638a865SIgor Mammedov     SMBIOS_SET_DEFAULT(smbios_type1.product, product);
1028d638a865SIgor Mammedov     SMBIOS_SET_DEFAULT(smbios_type1.version, version);
102960d8f328SWei Huang     SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
103060d8f328SWei Huang     SMBIOS_SET_DEFAULT(type2.product, product);
103160d8f328SWei Huang     SMBIOS_SET_DEFAULT(type2.version, version);
103260d8f328SWei Huang     SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
103360d8f328SWei Huang     SMBIOS_SET_DEFAULT(type3.version, version);
103460d8f328SWei Huang     SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
103560d8f328SWei Huang     SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
103660d8f328SWei Huang     SMBIOS_SET_DEFAULT(type4.version, version);
103760d8f328SWei Huang     SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
103860d8f328SWei Huang     SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
103960d8f328SWei Huang }
104060d8f328SWei Huang 
smbios_entry_point_setup(SmbiosEntryPointType ep_type)104169ea07a5SIgor Mammedov static void smbios_entry_point_setup(SmbiosEntryPointType ep_type)
104260d8f328SWei Huang {
104369ea07a5SIgor Mammedov     switch (ep_type) {
104410be11d0SEduardo Habkost     case SMBIOS_ENTRY_POINT_TYPE_32:
104586299120SWei Huang         memcpy(ep.ep21.anchor_string, "_SM_", 4);
104686299120SWei Huang         memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
104786299120SWei Huang         ep.ep21.length = sizeof(struct smbios_21_entry_point);
104886299120SWei Huang         ep.ep21.entry_point_revision = 0; /* formatted_area reserved */
104986299120SWei Huang         memset(ep.ep21.formatted_area, 0, 5);
105060d8f328SWei Huang 
105160d8f328SWei Huang         /* compliant with smbios spec v2.8 */
105286299120SWei Huang         ep.ep21.smbios_major_version = 2;
105386299120SWei Huang         ep.ep21.smbios_minor_version = 8;
105486299120SWei Huang         ep.ep21.smbios_bcd_revision = 0x28;
105560d8f328SWei Huang 
105660d8f328SWei Huang         /* set during table construction, but BIOS may override: */
105786299120SWei Huang         ep.ep21.structure_table_length = cpu_to_le16(smbios_tables_len);
105886299120SWei Huang         ep.ep21.max_structure_size = cpu_to_le16(smbios_table_max);
105986299120SWei Huang         ep.ep21.number_of_structures = cpu_to_le16(smbios_table_cnt);
106060d8f328SWei Huang 
106186299120SWei Huang         /* BIOS must recalculate */
106286299120SWei Huang         ep.ep21.checksum = 0;
106386299120SWei Huang         ep.ep21.intermediate_checksum = 0;
106486299120SWei Huang         ep.ep21.structure_table_address = cpu_to_le32(0);
106586299120SWei Huang 
106686299120SWei Huang         break;
106710be11d0SEduardo Habkost     case SMBIOS_ENTRY_POINT_TYPE_64:
106886299120SWei Huang         memcpy(ep.ep30.anchor_string, "_SM3_", 5);
106986299120SWei Huang         ep.ep30.length = sizeof(struct smbios_30_entry_point);
107086299120SWei Huang         ep.ep30.entry_point_revision = 1;
107186299120SWei Huang         ep.ep30.reserved = 0;
107286299120SWei Huang 
107386299120SWei Huang         /* compliant with smbios spec 3.0 */
107486299120SWei Huang         ep.ep30.smbios_major_version = 3;
107586299120SWei Huang         ep.ep30.smbios_minor_version = 0;
107686299120SWei Huang         ep.ep30.smbios_doc_rev = 0;
107786299120SWei Huang 
107886299120SWei Huang         /* set during table construct, but BIOS might override */
107986299120SWei Huang         ep.ep30.structure_table_max_size = cpu_to_le32(smbios_tables_len);
108086299120SWei Huang 
108186299120SWei Huang         /* BIOS must recalculate */
108286299120SWei Huang         ep.ep30.checksum = 0;
108386299120SWei Huang         ep.ep30.structure_table_address = cpu_to_le64(0);
108486299120SWei Huang 
108586299120SWei Huang         break;
108686299120SWei Huang     default:
108786299120SWei Huang         abort();
108886299120SWei Huang         break;
108986299120SWei Huang     }
109060d8f328SWei Huang }
109160d8f328SWei Huang 
smbios_get_tables_ep(MachineState * ms,SmbiosEntryPointType ep_type,const struct smbios_phys_mem_area * mem_array,const unsigned int mem_array_size,uint8_t ** tables,size_t * tables_len,uint8_t ** anchor,size_t * anchor_len,Error ** errp)10924840c8a2SIgor Mammedov static bool smbios_get_tables_ep(MachineState *ms,
109369ea07a5SIgor Mammedov                        SmbiosEntryPointType ep_type,
1094a0628599SLike Xu                        const struct smbios_phys_mem_area *mem_array,
109560d8f328SWei Huang                        const unsigned int mem_array_size,
109660d8f328SWei Huang                        uint8_t **tables, size_t *tables_len,
109705dfb447SVincent Bernat                        uint8_t **anchor, size_t *anchor_len,
109805dfb447SVincent Bernat                        Error **errp)
109960d8f328SWei Huang {
1100a379d455SAni Sinha     unsigned i, dimm_cnt, offset;
11014840c8a2SIgor Mammedov     ERRP_GUARD();
110260d8f328SWei Huang 
110369ea07a5SIgor Mammedov     assert(ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ||
110469ea07a5SIgor Mammedov            ep_type == SMBIOS_ENTRY_POINT_TYPE_64);
110569ea07a5SIgor Mammedov 
1106cba59fe3SIgor Mammedov     g_free(smbios_tables);
11076735a494SIgor Mammedov     smbios_type4_count = 0;
1108cba59fe3SIgor Mammedov     smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);
1109cba59fe3SIgor Mammedov     smbios_tables_len = usr_blobs_len;
1110cba59fe3SIgor Mammedov     smbios_table_max = usr_table_max;
1111cba59fe3SIgor Mammedov     smbios_table_cnt = usr_table_cnt;
1112b3854ce8SIgor Mammedov 
111360d8f328SWei Huang     smbios_build_type_0_table();
111460d8f328SWei Huang     smbios_build_type_1_table();
111560d8f328SWei Huang     smbios_build_type_2_table();
111660d8f328SWei Huang     smbios_build_type_3_table();
111760d8f328SWei Huang 
1118e94e0a83SIgor Mammedov     assert(ms->smp.sockets >= 1);
111960d8f328SWei Huang 
1120e94e0a83SIgor Mammedov     for (i = 0; i < ms->smp.sockets; i++) {
1121*5ed79482SIgor Mammedov         smbios_build_type_4_table(ms, i, ep_type, errp);
1122*5ed79482SIgor Mammedov         if (*errp) {
1123*5ed79482SIgor Mammedov             goto err_exit;
1124*5ed79482SIgor Mammedov         }
112560d8f328SWei Huang     }
112660d8f328SWei Huang 
1127fd8caa25SHal Martin     smbios_build_type_8_table();
112804f143d8SFelix Wu     smbios_build_type_9_table(errp);
11292d6dcbf9SDaniel P. Berrange     smbios_build_type_11_table();
11302d6dcbf9SDaniel P. Berrange 
1131968dfd05SPhilippe Mathieu-Daudé #define MAX_DIMM_SZ (16 * GiB)
113260d8f328SWei Huang #define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
113386378b29SPaolo Bonzini                                         : ((current_machine->ram_size - 1) % MAX_DIMM_SZ) + 1)
113460d8f328SWei Huang 
1135cba59fe3SIgor Mammedov     dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) /
1136cba59fe3SIgor Mammedov                MAX_DIMM_SZ;
113760d8f328SWei Huang 
1138a379d455SAni Sinha     /*
11399b4b4e51SMichael Tokarev      * The offset determines if we need to keep additional space between
1140a379d455SAni Sinha      * table 17 and table 19 header handle numbers so that they do
1141a379d455SAni Sinha      * not overlap. For example, for a VM with larger than 8 TB guest
1142a379d455SAni Sinha      * memory and DIMM like chunks of 16 GiB, the default space between
1143a379d455SAni Sinha      * the two tables (T19_BASE - T17_BASE = 512) is not enough.
1144a379d455SAni Sinha      */
1145a379d455SAni Sinha     offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
1146a379d455SAni Sinha              dimm_cnt - (T19_BASE - T17_BASE) : 0;
1147a379d455SAni Sinha 
114860d8f328SWei Huang     smbios_build_type_16_table(dimm_cnt);
114960d8f328SWei Huang 
115060d8f328SWei Huang     for (i = 0; i < dimm_cnt; i++) {
115160d8f328SWei Huang         smbios_build_type_17_table(i, GET_DIMM_SZ);
115260d8f328SWei Huang     }
115360d8f328SWei Huang 
115460d8f328SWei Huang     for (i = 0; i < mem_array_size; i++) {
1155a379d455SAni Sinha         smbios_build_type_19_table(i, offset, mem_array[i].address,
115660d8f328SWei Huang                                    mem_array[i].length);
115760d8f328SWei Huang     }
115860d8f328SWei Huang 
115963670bd3SAni Sinha     /*
116063670bd3SAni Sinha      * make sure 16 bit handle numbers in the headers of tables 19
116163670bd3SAni Sinha      * and 32 do not overlap.
116263670bd3SAni Sinha      */
116363670bd3SAni Sinha     assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
116463670bd3SAni Sinha 
116560d8f328SWei Huang     smbios_build_type_32_table();
116635658f6eSCorey Minyard     smbios_build_type_38_table();
116705dfb447SVincent Bernat     smbios_build_type_41_table(errp);
116860d8f328SWei Huang     smbios_build_type_127_table();
116960d8f328SWei Huang 
1170643e1c9eSIgor Mammedov     if (!smbios_check_type4_count(ms->smp.sockets, errp)) {
1171643e1c9eSIgor Mammedov         goto err_exit;
1172643e1c9eSIgor Mammedov     }
117369ea07a5SIgor Mammedov     if (!smbios_validate_table(ep_type, errp)) {
1174643e1c9eSIgor Mammedov         goto err_exit;
1175643e1c9eSIgor Mammedov     }
117669ea07a5SIgor Mammedov     smbios_entry_point_setup(ep_type);
117760d8f328SWei Huang 
117860d8f328SWei Huang     /* return tables blob and entry point (anchor), and their sizes */
117960d8f328SWei Huang     *tables = smbios_tables;
118060d8f328SWei Huang     *tables_len = smbios_tables_len;
118160d8f328SWei Huang     *anchor = (uint8_t *)&ep;
118286299120SWei Huang     /* calculate length based on anchor string */
118386299120SWei Huang     if (!strncmp((char *)&ep, "_SM_", 4)) {
118486299120SWei Huang         *anchor_len = sizeof(struct smbios_21_entry_point);
118586299120SWei Huang     } else if (!strncmp((char *)&ep, "_SM3_", 5)) {
118686299120SWei Huang         *anchor_len = sizeof(struct smbios_30_entry_point);
118786299120SWei Huang     } else {
118886299120SWei Huang         abort();
118986299120SWei Huang     }
1190643e1c9eSIgor Mammedov 
11914840c8a2SIgor Mammedov     return true;
1192643e1c9eSIgor Mammedov err_exit:
1193643e1c9eSIgor Mammedov     g_free(smbios_tables);
1194643e1c9eSIgor Mammedov     smbios_tables = NULL;
11954840c8a2SIgor Mammedov     return false;
11964840c8a2SIgor Mammedov }
11974840c8a2SIgor Mammedov 
smbios_get_tables(MachineState * ms,SmbiosEntryPointType ep_type,const struct smbios_phys_mem_area * mem_array,const unsigned int mem_array_size,uint8_t ** tables,size_t * tables_len,uint8_t ** anchor,size_t * anchor_len,Error ** errp)11984840c8a2SIgor Mammedov void smbios_get_tables(MachineState *ms,
11994840c8a2SIgor Mammedov                        SmbiosEntryPointType ep_type,
12004840c8a2SIgor Mammedov                        const struct smbios_phys_mem_area *mem_array,
12014840c8a2SIgor Mammedov                        const unsigned int mem_array_size,
12024840c8a2SIgor Mammedov                        uint8_t **tables, size_t *tables_len,
12034840c8a2SIgor Mammedov                        uint8_t **anchor, size_t *anchor_len,
12044840c8a2SIgor Mammedov                        Error **errp)
12054840c8a2SIgor Mammedov {
12064840c8a2SIgor Mammedov     Error *local_err = NULL;
12074840c8a2SIgor Mammedov     bool is_valid;
12084840c8a2SIgor Mammedov     ERRP_GUARD();
12094840c8a2SIgor Mammedov 
12104840c8a2SIgor Mammedov     switch (ep_type) {
12114840c8a2SIgor Mammedov     case SMBIOS_ENTRY_POINT_TYPE_AUTO:
12124840c8a2SIgor Mammedov     case SMBIOS_ENTRY_POINT_TYPE_32:
12134840c8a2SIgor Mammedov         is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_32,
12144840c8a2SIgor Mammedov                                         mem_array, mem_array_size,
12154840c8a2SIgor Mammedov                                         tables, tables_len,
12164840c8a2SIgor Mammedov                                         anchor, anchor_len,
12174840c8a2SIgor Mammedov                                         &local_err);
12184840c8a2SIgor Mammedov         if (is_valid || ep_type != SMBIOS_ENTRY_POINT_TYPE_AUTO) {
12194840c8a2SIgor Mammedov             break;
12204840c8a2SIgor Mammedov         }
12214840c8a2SIgor Mammedov         /*
12224840c8a2SIgor Mammedov          * fall through in case AUTO endpoint is selected and
12234840c8a2SIgor Mammedov          * SMBIOS 2.x tables can't be generated, to try if SMBIOS 3.x
12244840c8a2SIgor Mammedov          * tables would work
12254840c8a2SIgor Mammedov          */
12264840c8a2SIgor Mammedov     case SMBIOS_ENTRY_POINT_TYPE_64:
12274840c8a2SIgor Mammedov         error_free(local_err);
12284840c8a2SIgor Mammedov         local_err = NULL;
12294840c8a2SIgor Mammedov         is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_64,
12304840c8a2SIgor Mammedov                                         mem_array, mem_array_size,
12314840c8a2SIgor Mammedov                                         tables, tables_len,
12324840c8a2SIgor Mammedov                                         anchor, anchor_len,
12334840c8a2SIgor Mammedov                                         &local_err);
12344840c8a2SIgor Mammedov         break;
12354840c8a2SIgor Mammedov     default:
12364840c8a2SIgor Mammedov         abort();
12374840c8a2SIgor Mammedov     }
12384840c8a2SIgor Mammedov     if (!is_valid) {
12394840c8a2SIgor Mammedov         error_propagate(errp, local_err);
12404840c8a2SIgor Mammedov     }
124160d8f328SWei Huang }
124260d8f328SWei Huang 
save_opt(const char ** dest,QemuOpts * opts,const char * name)124360d8f328SWei Huang static void save_opt(const char **dest, QemuOpts *opts, const char *name)
124460d8f328SWei Huang {
124560d8f328SWei Huang     const char *val = qemu_opt_get(opts, name);
124660d8f328SWei Huang 
124760d8f328SWei Huang     if (val) {
124860d8f328SWei Huang         *dest = val;
124960d8f328SWei Huang     }
125060d8f328SWei Huang }
125160d8f328SWei Huang 
12522d6dcbf9SDaniel P. Berrange 
12532d6dcbf9SDaniel P. Berrange struct opt_list {
12542d6dcbf9SDaniel P. Berrange     size_t *ndest;
1255bb99f477SDaniel P. Berrangé     char ***dest;
12562d6dcbf9SDaniel P. Berrange };
12572d6dcbf9SDaniel P. Berrange 
save_opt_one(void * opaque,const char * name,const char * value,Error ** errp)12582d6dcbf9SDaniel P. Berrange static int save_opt_one(void *opaque,
12592d6dcbf9SDaniel P. Berrange                         const char *name, const char *value,
12602d6dcbf9SDaniel P. Berrange                         Error **errp)
12612d6dcbf9SDaniel P. Berrange {
12622d6dcbf9SDaniel P. Berrange     struct opt_list *opt = opaque;
12632d6dcbf9SDaniel P. Berrange 
1264bb99f477SDaniel P. Berrangé     if (g_str_equal(name, "path")) {
1265bb99f477SDaniel P. Berrangé         g_autoptr(GByteArray) data = g_byte_array_new();
1266bb99f477SDaniel P. Berrangé         g_autofree char *buf = g_new(char, 4096);
1267bb99f477SDaniel P. Berrangé         ssize_t ret;
1268bb99f477SDaniel P. Berrangé         int fd = qemu_open(value, O_RDONLY, errp);
1269bb99f477SDaniel P. Berrangé         if (fd < 0) {
1270bb99f477SDaniel P. Berrangé             return -1;
12712d6dcbf9SDaniel P. Berrange         }
12722d6dcbf9SDaniel P. Berrange 
1273bb99f477SDaniel P. Berrangé         while (1) {
1274bb99f477SDaniel P. Berrangé             ret = read(fd, buf, 4096);
1275bb99f477SDaniel P. Berrangé             if (ret == 0) {
1276bb99f477SDaniel P. Berrangé                 break;
1277bb99f477SDaniel P. Berrangé             }
1278bb99f477SDaniel P. Berrangé             if (ret < 0) {
1279bb99f477SDaniel P. Berrangé                 error_setg(errp, "Unable to read from %s: %s",
1280bb99f477SDaniel P. Berrangé                            value, strerror(errno));
12818055d2fbSPhilippe Mathieu-Daudé                 qemu_close(fd);
1282bb99f477SDaniel P. Berrangé                 return -1;
1283bb99f477SDaniel P. Berrangé             }
1284bb99f477SDaniel P. Berrangé             if (memchr(buf, '\0', ret)) {
1285bb99f477SDaniel P. Berrangé                 error_setg(errp, "NUL in OEM strings value in %s", value);
12868055d2fbSPhilippe Mathieu-Daudé                 qemu_close(fd);
1287bb99f477SDaniel P. Berrangé                 return -1;
1288bb99f477SDaniel P. Berrangé             }
1289bb99f477SDaniel P. Berrangé             g_byte_array_append(data, (guint8 *)buf, ret);
1290bb99f477SDaniel P. Berrangé         }
1291bb99f477SDaniel P. Berrangé 
12928055d2fbSPhilippe Mathieu-Daudé         qemu_close(fd);
1293bb99f477SDaniel P. Berrangé 
1294bb99f477SDaniel P. Berrangé         *opt->dest = g_renew(char *, *opt->dest, (*opt->ndest) + 1);
1295bb99f477SDaniel P. Berrangé         (*opt->dest)[*opt->ndest] = (char *)g_byte_array_free(data,  FALSE);
12962d6dcbf9SDaniel P. Berrange         (*opt->ndest)++;
1297bb99f477SDaniel P. Berrangé         data = NULL;
1298bb99f477SDaniel P. Berrangé    } else if (g_str_equal(name, "value")) {
1299bb99f477SDaniel P. Berrangé         *opt->dest = g_renew(char *, *opt->dest, (*opt->ndest) + 1);
1300bb99f477SDaniel P. Berrangé         (*opt->dest)[*opt->ndest] = g_strdup(value);
1301bb99f477SDaniel P. Berrangé         (*opt->ndest)++;
1302bb99f477SDaniel P. Berrangé     } else if (!g_str_equal(name, "type")) {
1303bb99f477SDaniel P. Berrangé         error_setg(errp, "Unexpected option %s", name);
1304bb99f477SDaniel P. Berrangé         return -1;
1305bb99f477SDaniel P. Berrangé     }
1306bb99f477SDaniel P. Berrangé 
13072d6dcbf9SDaniel P. Berrange     return 0;
13082d6dcbf9SDaniel P. Berrange }
13092d6dcbf9SDaniel P. Berrange 
save_opt_list(size_t * ndest,char *** dest,QemuOpts * opts,Error ** errp)1310bb99f477SDaniel P. Berrangé static bool save_opt_list(size_t *ndest, char ***dest, QemuOpts *opts,
1311bb99f477SDaniel P. Berrangé                           Error **errp)
13122d6dcbf9SDaniel P. Berrange {
13132d6dcbf9SDaniel P. Berrange     struct opt_list opt = {
1314bb99f477SDaniel P. Berrangé         ndest, dest,
13152d6dcbf9SDaniel P. Berrange     };
1316bb99f477SDaniel P. Berrangé     if (!qemu_opt_foreach(opts, save_opt_one, &opt, errp)) {
1317bb99f477SDaniel P. Berrangé         return false;
1318bb99f477SDaniel P. Berrangé     }
1319bb99f477SDaniel P. Berrangé     return true;
13202d6dcbf9SDaniel P. Berrange }
13212d6dcbf9SDaniel P. Berrange 
smbios_entry_add(QemuOpts * opts,Error ** errp)13221007a37eSLeif Lindholm void smbios_entry_add(QemuOpts *opts, Error **errp)
132360d8f328SWei Huang {
132460d8f328SWei Huang     const char *val;
132560d8f328SWei Huang 
132660d8f328SWei Huang     val = qemu_opt_get(opts, "file");
132760d8f328SWei Huang     if (val) {
132860d8f328SWei Huang         struct smbios_structure_header *header;
1329cba59fe3SIgor Mammedov         size_t size;
133060d8f328SWei Huang 
1331668f62ecSMarkus Armbruster         if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) {
13321028283cSMarkus Armbruster             return;
13331028283cSMarkus Armbruster         }
133460d8f328SWei Huang 
133560d8f328SWei Huang         size = get_image_size(val);
133660d8f328SWei Huang         if (size == -1 || size < sizeof(struct smbios_structure_header)) {
13371028283cSMarkus Armbruster             error_setg(errp, "Cannot read SMBIOS file %s", val);
13381028283cSMarkus Armbruster             return;
133960d8f328SWei Huang         }
134060d8f328SWei Huang 
134160d8f328SWei Huang         /*
134260d8f328SWei Huang          * NOTE: standard double '\0' terminator expected, per smbios spec.
134360d8f328SWei Huang          * (except in legacy mode, where the second '\0' is implicit and
134460d8f328SWei Huang          *  will be inserted by the BIOS).
134560d8f328SWei Huang          */
1346cba59fe3SIgor Mammedov         usr_blobs = g_realloc(usr_blobs, usr_blobs_len + size);
1347cba59fe3SIgor Mammedov         header = (struct smbios_structure_header *)(usr_blobs +
1348cba59fe3SIgor Mammedov                                                     usr_blobs_len);
134960d8f328SWei Huang 
1350b7abb791SPeter Maydell         if (load_image_size(val, (uint8_t *)header, size) != size) {
13511028283cSMarkus Armbruster             error_setg(errp, "Failed to load SMBIOS file %s", val);
13521028283cSMarkus Armbruster             return;
135360d8f328SWei Huang         }
135460d8f328SWei Huang 
135557e30696SPaolo Bonzini         if (header->type <= SMBIOS_MAX_TYPE) {
1356d638a865SIgor Mammedov             if (test_bit(header->type, smbios_have_fields_bitmap)) {
13571028283cSMarkus Armbruster                 error_setg(errp,
13581028283cSMarkus Armbruster                            "can't load type %d struct, fields already specified!",
135960d8f328SWei Huang                            header->type);
13601028283cSMarkus Armbruster                 return;
136160d8f328SWei Huang             }
1362d638a865SIgor Mammedov             set_bit(header->type, smbios_have_binfile_bitmap);
136357e30696SPaolo Bonzini         }
136460d8f328SWei Huang 
136560d8f328SWei Huang         if (header->type == 4) {
136660d8f328SWei Huang             smbios_type4_count++;
136760d8f328SWei Huang         }
136860d8f328SWei Huang 
1369684b49fdSIgor Mammedov         /*
1370684b49fdSIgor Mammedov          * preserve blob size for legacy mode so it could build its
1371684b49fdSIgor Mammedov          * blobs flavor from 'usr_blobs'
1372684b49fdSIgor Mammedov          */
1373684b49fdSIgor Mammedov         smbios_add_usr_blob_size(size);
1374684b49fdSIgor Mammedov 
1375cba59fe3SIgor Mammedov         usr_blobs_len += size;
1376cba59fe3SIgor Mammedov         if (size > usr_table_max) {
1377cba59fe3SIgor Mammedov             usr_table_max = size;
137860d8f328SWei Huang         }
1379cba59fe3SIgor Mammedov         usr_table_cnt++;
138060d8f328SWei Huang 
138160d8f328SWei Huang         return;
138260d8f328SWei Huang     }
138360d8f328SWei Huang 
138460d8f328SWei Huang     val = qemu_opt_get(opts, "type");
138560d8f328SWei Huang     if (val) {
138660d8f328SWei Huang         unsigned long type = strtoul(val, NULL, 0);
138760d8f328SWei Huang 
138860d8f328SWei Huang         if (type > SMBIOS_MAX_TYPE) {
13891028283cSMarkus Armbruster             error_setg(errp, "out of range!");
13901028283cSMarkus Armbruster             return;
139160d8f328SWei Huang         }
139260d8f328SWei Huang 
1393d638a865SIgor Mammedov         if (test_bit(type, smbios_have_binfile_bitmap)) {
13941028283cSMarkus Armbruster             error_setg(errp, "can't add fields, binary file already loaded!");
13951028283cSMarkus Armbruster             return;
139660d8f328SWei Huang         }
1397d638a865SIgor Mammedov         set_bit(type, smbios_have_fields_bitmap);
139860d8f328SWei Huang 
139960d8f328SWei Huang         switch (type) {
140060d8f328SWei Huang         case 0:
1401668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, errp)) {
14021028283cSMarkus Armbruster                 return;
14031028283cSMarkus Armbruster             }
1404d638a865SIgor Mammedov             save_opt(&smbios_type0.vendor, opts, "vendor");
1405d638a865SIgor Mammedov             save_opt(&smbios_type0.version, opts, "version");
1406d638a865SIgor Mammedov             save_opt(&smbios_type0.date, opts, "date");
1407d638a865SIgor Mammedov             smbios_type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
140860d8f328SWei Huang 
140960d8f328SWei Huang             val = qemu_opt_get(opts, "release");
141060d8f328SWei Huang             if (val) {
1411d638a865SIgor Mammedov                 if (sscanf(val, "%hhu.%hhu", &smbios_type0.major,
1412d638a865SIgor Mammedov                            &smbios_type0.minor) != 2) {
14131028283cSMarkus Armbruster                     error_setg(errp, "Invalid release");
14141028283cSMarkus Armbruster                     return;
141560d8f328SWei Huang                 }
1416d638a865SIgor Mammedov                 smbios_type0.have_major_minor = true;
141760d8f328SWei Huang             }
141860d8f328SWei Huang             return;
141960d8f328SWei Huang         case 1:
1420668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, errp)) {
14211028283cSMarkus Armbruster                 return;
14221028283cSMarkus Armbruster             }
1423d638a865SIgor Mammedov             save_opt(&smbios_type1.manufacturer, opts, "manufacturer");
1424d638a865SIgor Mammedov             save_opt(&smbios_type1.product, opts, "product");
1425d638a865SIgor Mammedov             save_opt(&smbios_type1.version, opts, "version");
1426d638a865SIgor Mammedov             save_opt(&smbios_type1.serial, opts, "serial");
1427d638a865SIgor Mammedov             save_opt(&smbios_type1.sku, opts, "sku");
1428d638a865SIgor Mammedov             save_opt(&smbios_type1.family, opts, "family");
142960d8f328SWei Huang 
143060d8f328SWei Huang             val = qemu_opt_get(opts, "uuid");
143160d8f328SWei Huang             if (val) {
14329c5ce8dbSFam Zheng                 if (qemu_uuid_parse(val, &qemu_uuid) != 0) {
14331028283cSMarkus Armbruster                     error_setg(errp, "Invalid UUID");
14341028283cSMarkus Armbruster                     return;
143560d8f328SWei Huang                 }
143660d8f328SWei Huang                 qemu_uuid_set = true;
143760d8f328SWei Huang             }
143860d8f328SWei Huang             return;
143960d8f328SWei Huang         case 2:
1440668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type2_opts, errp)) {
14411028283cSMarkus Armbruster                 return;
14421028283cSMarkus Armbruster             }
144360d8f328SWei Huang             save_opt(&type2.manufacturer, opts, "manufacturer");
144460d8f328SWei Huang             save_opt(&type2.product, opts, "product");
144560d8f328SWei Huang             save_opt(&type2.version, opts, "version");
144660d8f328SWei Huang             save_opt(&type2.serial, opts, "serial");
144760d8f328SWei Huang             save_opt(&type2.asset, opts, "asset");
144860d8f328SWei Huang             save_opt(&type2.location, opts, "location");
144960d8f328SWei Huang             return;
145060d8f328SWei Huang         case 3:
1451668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type3_opts, errp)) {
14521028283cSMarkus Armbruster                 return;
14531028283cSMarkus Armbruster             }
145460d8f328SWei Huang             save_opt(&type3.manufacturer, opts, "manufacturer");
145560d8f328SWei Huang             save_opt(&type3.version, opts, "version");
145660d8f328SWei Huang             save_opt(&type3.serial, opts, "serial");
145760d8f328SWei Huang             save_opt(&type3.asset, opts, "asset");
145860d8f328SWei Huang             save_opt(&type3.sku, opts, "sku");
145960d8f328SWei Huang             return;
146060d8f328SWei Huang         case 4:
1461668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type4_opts, errp)) {
14621028283cSMarkus Armbruster                 return;
14631028283cSMarkus Armbruster             }
146460d8f328SWei Huang             save_opt(&type4.sock_pfx, opts, "sock_pfx");
1465b5831d79SHeinrich Schuchardt             type4.processor_family = qemu_opt_get_number(opts,
1466b5831d79SHeinrich Schuchardt                                                          "processor-family",
1467b5831d79SHeinrich Schuchardt                                                          0x01 /* Other */);
146860d8f328SWei Huang             save_opt(&type4.manufacturer, opts, "manufacturer");
146960d8f328SWei Huang             save_opt(&type4.version, opts, "version");
147060d8f328SWei Huang             save_opt(&type4.serial, opts, "serial");
147160d8f328SWei Huang             save_opt(&type4.asset, opts, "asset");
147260d8f328SWei Huang             save_opt(&type4.part, opts, "part");
1473cb5fb04fSPatrick Venture             /* If the value is 0, it will take the value from the CPU model. */
1474cb5fb04fSPatrick Venture             type4.processor_id = qemu_opt_get_number(opts, "processor-id", 0);
1475c906e039SYing Fang             type4.max_speed = qemu_opt_get_number(opts, "max-speed",
1476c906e039SYing Fang                                                   DEFAULT_CPU_SPEED);
1477c906e039SYing Fang             type4.current_speed = qemu_opt_get_number(opts, "current-speed",
1478c906e039SYing Fang                                                       DEFAULT_CPU_SPEED);
1479c906e039SYing Fang             if (type4.max_speed > UINT16_MAX ||
1480c906e039SYing Fang                 type4.current_speed > UINT16_MAX) {
1481c906e039SYing Fang                 error_setg(errp, "SMBIOS CPU speed is too large (> %d)",
1482c906e039SYing Fang                            UINT16_MAX);
1483c906e039SYing Fang             }
148460d8f328SWei Huang             return;
1485fd8caa25SHal Martin         case 8:
1486fd8caa25SHal Martin             if (!qemu_opts_validate(opts, qemu_smbios_type8_opts, errp)) {
1487fd8caa25SHal Martin                 return;
1488fd8caa25SHal Martin             }
14897b393b71SAni Sinha             struct type8_instance *t8_i;
14907b393b71SAni Sinha             t8_i = g_new0(struct type8_instance, 1);
14917b393b71SAni Sinha             save_opt(&t8_i->internal_reference, opts, "internal_reference");
14927b393b71SAni Sinha             save_opt(&t8_i->external_reference, opts, "external_reference");
14937b393b71SAni Sinha             t8_i->connector_type = qemu_opt_get_number(opts,
14947b393b71SAni Sinha                                                        "connector_type", 0);
14957b393b71SAni Sinha             t8_i->port_type = qemu_opt_get_number(opts, "port_type", 0);
14967b393b71SAni Sinha             QTAILQ_INSERT_TAIL(&type8, t8_i, next);
1497fd8caa25SHal Martin             return;
1498735eee07SFelix Wu         case 9: {
1499735eee07SFelix Wu             if (!qemu_opts_validate(opts, qemu_smbios_type9_opts, errp)) {
1500735eee07SFelix Wu                 return;
1501735eee07SFelix Wu             }
1502735eee07SFelix Wu             struct type9_instance *t;
1503735eee07SFelix Wu             t = g_new0(struct type9_instance, 1);
1504735eee07SFelix Wu             save_opt(&t->slot_designation, opts, "slot_designation");
1505735eee07SFelix Wu             t->slot_type = qemu_opt_get_number(opts, "slot_type", 0);
1506fdf1c980SMichael S. Tsirkin             t->slot_data_bus_width =
1507fdf1c980SMichael S. Tsirkin                 qemu_opt_get_number(opts, "slot_data_bus_width", 0);
1508735eee07SFelix Wu             t->current_usage = qemu_opt_get_number(opts, "current_usage", 0);
1509735eee07SFelix Wu             t->slot_length = qemu_opt_get_number(opts, "slot_length", 0);
1510735eee07SFelix Wu             t->slot_id = qemu_opt_get_number(opts, "slot_id", 0);
1511fdf1c980SMichael S. Tsirkin             t->slot_characteristics1 =
1512fdf1c980SMichael S. Tsirkin                 qemu_opt_get_number(opts, "slot_characteristics1", 0);
1513fdf1c980SMichael S. Tsirkin             t->slot_characteristics2 =
1514fdf1c980SMichael S. Tsirkin                 qemu_opt_get_number(opts, "slot_characteristics2", 0);
151504f143d8SFelix Wu             save_opt(&t->pcidev, opts, "pcidev");
1516735eee07SFelix Wu             QTAILQ_INSERT_TAIL(&type9, t, next);
1517735eee07SFelix Wu             return;
1518735eee07SFelix Wu         }
15192d6dcbf9SDaniel P. Berrange         case 11:
1520668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) {
15211028283cSMarkus Armbruster                 return;
15221028283cSMarkus Armbruster             }
1523bb99f477SDaniel P. Berrangé             if (!save_opt_list(&type11.nvalues, &type11.values, opts, errp)) {
1524bb99f477SDaniel P. Berrangé                 return;
1525bb99f477SDaniel P. Berrangé             }
15262d6dcbf9SDaniel P. Berrange             return;
152760d8f328SWei Huang         case 17:
1528668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type17_opts, errp)) {
15291028283cSMarkus Armbruster                 return;
15301028283cSMarkus Armbruster             }
153160d8f328SWei Huang             save_opt(&type17.loc_pfx, opts, "loc_pfx");
153260d8f328SWei Huang             save_opt(&type17.bank, opts, "bank");
153360d8f328SWei Huang             save_opt(&type17.manufacturer, opts, "manufacturer");
153460d8f328SWei Huang             save_opt(&type17.serial, opts, "serial");
153560d8f328SWei Huang             save_opt(&type17.asset, opts, "asset");
153660d8f328SWei Huang             save_opt(&type17.part, opts, "part");
153760d8f328SWei Huang             type17.speed = qemu_opt_get_number(opts, "speed", 0);
153860d8f328SWei Huang             return;
153905dfb447SVincent Bernat         case 41: {
15407b393b71SAni Sinha             struct type41_instance *t41_i;
154105dfb447SVincent Bernat             Error *local_err = NULL;
154205dfb447SVincent Bernat 
154305dfb447SVincent Bernat             if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) {
154405dfb447SVincent Bernat                 return;
154505dfb447SVincent Bernat             }
15467b393b71SAni Sinha             t41_i = g_new0(struct type41_instance, 1);
15477b393b71SAni Sinha             save_opt(&t41_i->designation, opts, "designation");
15487b393b71SAni Sinha             t41_i->kind = qapi_enum_parse(&type41_kind_lookup,
154905dfb447SVincent Bernat                                           qemu_opt_get(opts, "kind"),
155005dfb447SVincent Bernat                                           0, &local_err) + 1;
15517b393b71SAni Sinha             t41_i->kind |= 0x80;     /* enabled */
155205dfb447SVincent Bernat             if (local_err != NULL) {
155305dfb447SVincent Bernat                 error_propagate(errp, local_err);
15547b393b71SAni Sinha                 g_free(t41_i);
155505dfb447SVincent Bernat                 return;
155605dfb447SVincent Bernat             }
15577b393b71SAni Sinha             t41_i->instance = qemu_opt_get_number(opts, "instance", 1);
15587b393b71SAni Sinha             save_opt(&t41_i->pcidev, opts, "pcidev");
155905dfb447SVincent Bernat 
15607b393b71SAni Sinha             QTAILQ_INSERT_TAIL(&type41, t41_i, next);
156105dfb447SVincent Bernat             return;
156205dfb447SVincent Bernat         }
156360d8f328SWei Huang         default:
15641028283cSMarkus Armbruster             error_setg(errp,
15651028283cSMarkus Armbruster                        "Don't know how to build fields for SMBIOS type %ld",
156660d8f328SWei Huang                        type);
15671028283cSMarkus Armbruster             return;
156860d8f328SWei Huang         }
156960d8f328SWei Huang     }
157060d8f328SWei Huang 
15711028283cSMarkus Armbruster     error_setg(errp, "Must specify type= or file=");
157260d8f328SWei Huang }
1573