xref: /openbmc/qemu/hw/smbios/smbios.c (revision 62f182c9)
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 
33cba59fe3SIgor Mammedov /*
34cba59fe3SIgor Mammedov  * SMBIOS tables provided by user with '-smbios file=<foo>' option
35cba59fe3SIgor Mammedov  */
36cba59fe3SIgor Mammedov uint8_t *usr_blobs;
37cba59fe3SIgor Mammedov size_t usr_blobs_len;
38cba59fe3SIgor Mammedov static unsigned usr_table_max;
39cba59fe3SIgor Mammedov static unsigned usr_table_cnt;
4060d8f328SWei Huang 
410517cc98SCorey Minyard uint8_t *smbios_tables;
420517cc98SCorey Minyard size_t smbios_tables_len;
430517cc98SCorey Minyard unsigned smbios_table_max;
440517cc98SCorey Minyard unsigned smbios_table_cnt;
4586299120SWei Huang 
4686299120SWei Huang static SmbiosEntryPoint ep;
4760d8f328SWei Huang 
4860d8f328SWei Huang static int smbios_type4_count = 0;
4960d8f328SWei Huang static bool smbios_have_defaults;
50e94e0a83SIgor Mammedov static uint32_t smbios_cpuid_version, smbios_cpuid_features;
5160d8f328SWei Huang 
52d638a865SIgor Mammedov DECLARE_BITMAP(smbios_have_binfile_bitmap, SMBIOS_MAX_TYPE + 1);
53d638a865SIgor Mammedov DECLARE_BITMAP(smbios_have_fields_bitmap, SMBIOS_MAX_TYPE + 1);
5460d8f328SWei Huang 
55d638a865SIgor Mammedov smbios_type0_t smbios_type0;
56d638a865SIgor Mammedov smbios_type1_t smbios_type1;
5760d8f328SWei Huang 
5860d8f328SWei Huang static struct {
5960d8f328SWei Huang     const char *manufacturer, *product, *version, *serial, *asset, *location;
6060d8f328SWei Huang } type2;
6160d8f328SWei Huang 
6260d8f328SWei Huang static struct {
6360d8f328SWei Huang     const char *manufacturer, *version, *serial, *asset, *sku;
6460d8f328SWei Huang } type3;
6560d8f328SWei Huang 
66c906e039SYing Fang /*
67c906e039SYing Fang  * SVVP requires max_speed and current_speed to be set and not being
68c906e039SYing Fang  * 0 which counts as unknown (SMBIOS 3.1.0/Table 21). Set the
69c906e039SYing Fang  * default value to 2000MHz as we did before.
70c906e039SYing Fang  */
71c906e039SYing Fang #define DEFAULT_CPU_SPEED 2000
72c906e039SYing Fang 
7360d8f328SWei Huang static struct {
74b5831d79SHeinrich Schuchardt     uint16_t processor_family;
7560d8f328SWei Huang     const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
76c906e039SYing Fang     uint64_t max_speed;
77c906e039SYing Fang     uint64_t current_speed;
78cb5fb04fSPatrick Venture     uint64_t processor_id;
79c906e039SYing Fang } type4 = {
80c906e039SYing Fang     .max_speed = DEFAULT_CPU_SPEED,
81cb5fb04fSPatrick Venture     .current_speed = DEFAULT_CPU_SPEED,
82cb5fb04fSPatrick Venture     .processor_id = 0,
83b5831d79SHeinrich Schuchardt     .processor_family = 0x01, /* Other */
84c906e039SYing Fang };
8560d8f328SWei Huang 
86fd8caa25SHal Martin struct type8_instance {
87fd8caa25SHal Martin     const char *internal_reference, *external_reference;
88fd8caa25SHal Martin     uint8_t connector_type, port_type;
89fd8caa25SHal Martin     QTAILQ_ENTRY(type8_instance) next;
90fd8caa25SHal Martin };
91fd8caa25SHal Martin static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8);
92fd8caa25SHal Martin 
93735eee07SFelix Wu /* type 9 instance for parsing */
94735eee07SFelix Wu struct type9_instance {
9504f143d8SFelix Wu     const char *slot_designation, *pcidev;
96735eee07SFelix Wu     uint8_t slot_type, slot_data_bus_width, current_usage, slot_length,
97735eee07SFelix Wu             slot_characteristics1, slot_characteristics2;
98735eee07SFelix Wu     uint16_t slot_id;
99735eee07SFelix Wu     QTAILQ_ENTRY(type9_instance) next;
100735eee07SFelix Wu };
101735eee07SFelix Wu static QTAILQ_HEAD(, type9_instance) type9 = QTAILQ_HEAD_INITIALIZER(type9);
102735eee07SFelix Wu 
10360d8f328SWei Huang static struct {
1042d6dcbf9SDaniel P. Berrange     size_t nvalues;
105bb99f477SDaniel P. Berrangé     char **values;
1062d6dcbf9SDaniel P. Berrange } type11;
1072d6dcbf9SDaniel P. Berrange 
1082d6dcbf9SDaniel P. Berrange static struct {
10960d8f328SWei Huang     const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
11060d8f328SWei Huang     uint16_t speed;
11160d8f328SWei Huang } type17;
11260d8f328SWei Huang 
11305dfb447SVincent Bernat static QEnumLookup type41_kind_lookup = {
11405dfb447SVincent Bernat     .array = (const char *const[]) {
11505dfb447SVincent Bernat         "other",
11605dfb447SVincent Bernat         "unknown",
11705dfb447SVincent Bernat         "video",
11805dfb447SVincent Bernat         "scsi",
11905dfb447SVincent Bernat         "ethernet",
12005dfb447SVincent Bernat         "tokenring",
12105dfb447SVincent Bernat         "sound",
12205dfb447SVincent Bernat         "pata",
12305dfb447SVincent Bernat         "sata",
12405dfb447SVincent Bernat         "sas",
12505dfb447SVincent Bernat     },
12605dfb447SVincent Bernat     .size = 10
12705dfb447SVincent Bernat };
12805dfb447SVincent Bernat struct type41_instance {
12905dfb447SVincent Bernat     const char *designation, *pcidev;
13005dfb447SVincent Bernat     uint8_t instance, kind;
13105dfb447SVincent Bernat     QTAILQ_ENTRY(type41_instance) next;
13205dfb447SVincent Bernat };
13305dfb447SVincent Bernat static QTAILQ_HEAD(, type41_instance) type41 = QTAILQ_HEAD_INITIALIZER(type41);
13405dfb447SVincent Bernat 
13560d8f328SWei Huang static QemuOptsList qemu_smbios_opts = {
13660d8f328SWei Huang     .name = "smbios",
13760d8f328SWei Huang     .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
13860d8f328SWei Huang     .desc = {
13960d8f328SWei Huang         /*
14060d8f328SWei Huang          * no elements => accept any params
14160d8f328SWei Huang          * validation will happen later
14260d8f328SWei Huang          */
14360d8f328SWei Huang         { /* end of list */ }
14460d8f328SWei Huang     }
14560d8f328SWei Huang };
14660d8f328SWei Huang 
14760d8f328SWei Huang static const QemuOptDesc qemu_smbios_file_opts[] = {
14860d8f328SWei Huang     {
14960d8f328SWei Huang         .name = "file",
15060d8f328SWei Huang         .type = QEMU_OPT_STRING,
15160d8f328SWei Huang         .help = "binary file containing an SMBIOS element",
15260d8f328SWei Huang     },
15360d8f328SWei Huang     { /* end of list */ }
15460d8f328SWei Huang };
15560d8f328SWei Huang 
15660d8f328SWei Huang static const QemuOptDesc qemu_smbios_type0_opts[] = {
15760d8f328SWei Huang     {
15860d8f328SWei Huang         .name = "type",
15960d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
16060d8f328SWei Huang         .help = "SMBIOS element type",
16160d8f328SWei Huang     },{
16260d8f328SWei Huang         .name = "vendor",
16360d8f328SWei Huang         .type = QEMU_OPT_STRING,
16460d8f328SWei Huang         .help = "vendor name",
16560d8f328SWei Huang     },{
16660d8f328SWei Huang         .name = "version",
16760d8f328SWei Huang         .type = QEMU_OPT_STRING,
16860d8f328SWei Huang         .help = "version number",
16960d8f328SWei Huang     },{
17060d8f328SWei Huang         .name = "date",
17160d8f328SWei Huang         .type = QEMU_OPT_STRING,
17260d8f328SWei Huang         .help = "release date",
17360d8f328SWei Huang     },{
17460d8f328SWei Huang         .name = "release",
17560d8f328SWei Huang         .type = QEMU_OPT_STRING,
17660d8f328SWei Huang         .help = "revision number",
17760d8f328SWei Huang     },{
17860d8f328SWei Huang         .name = "uefi",
17960d8f328SWei Huang         .type = QEMU_OPT_BOOL,
18060d8f328SWei Huang         .help = "uefi support",
18160d8f328SWei Huang     },
18260d8f328SWei Huang     { /* end of list */ }
18360d8f328SWei Huang };
18460d8f328SWei Huang 
18560d8f328SWei Huang static const QemuOptDesc qemu_smbios_type1_opts[] = {
18660d8f328SWei Huang     {
18760d8f328SWei Huang         .name = "type",
18860d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
18960d8f328SWei Huang         .help = "SMBIOS element type",
19060d8f328SWei Huang     },{
19160d8f328SWei Huang         .name = "manufacturer",
19260d8f328SWei Huang         .type = QEMU_OPT_STRING,
19360d8f328SWei Huang         .help = "manufacturer name",
19460d8f328SWei Huang     },{
19560d8f328SWei Huang         .name = "product",
19660d8f328SWei Huang         .type = QEMU_OPT_STRING,
19760d8f328SWei Huang         .help = "product name",
19860d8f328SWei Huang     },{
19960d8f328SWei Huang         .name = "version",
20060d8f328SWei Huang         .type = QEMU_OPT_STRING,
20160d8f328SWei Huang         .help = "version number",
20260d8f328SWei Huang     },{
20360d8f328SWei Huang         .name = "serial",
20460d8f328SWei Huang         .type = QEMU_OPT_STRING,
20560d8f328SWei Huang         .help = "serial number",
20660d8f328SWei Huang     },{
20760d8f328SWei Huang         .name = "uuid",
20860d8f328SWei Huang         .type = QEMU_OPT_STRING,
20960d8f328SWei Huang         .help = "UUID",
21060d8f328SWei Huang     },{
21160d8f328SWei Huang         .name = "sku",
21260d8f328SWei Huang         .type = QEMU_OPT_STRING,
21360d8f328SWei Huang         .help = "SKU number",
21460d8f328SWei Huang     },{
21560d8f328SWei Huang         .name = "family",
21660d8f328SWei Huang         .type = QEMU_OPT_STRING,
21760d8f328SWei Huang         .help = "family name",
21860d8f328SWei Huang     },
21960d8f328SWei Huang     { /* end of list */ }
22060d8f328SWei Huang };
22160d8f328SWei Huang 
22260d8f328SWei Huang static const QemuOptDesc qemu_smbios_type2_opts[] = {
22360d8f328SWei Huang     {
22460d8f328SWei Huang         .name = "type",
22560d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
22660d8f328SWei Huang         .help = "SMBIOS element type",
22760d8f328SWei Huang     },{
22860d8f328SWei Huang         .name = "manufacturer",
22960d8f328SWei Huang         .type = QEMU_OPT_STRING,
23060d8f328SWei Huang         .help = "manufacturer name",
23160d8f328SWei Huang     },{
23260d8f328SWei Huang         .name = "product",
23360d8f328SWei Huang         .type = QEMU_OPT_STRING,
23460d8f328SWei Huang         .help = "product name",
23560d8f328SWei Huang     },{
23660d8f328SWei Huang         .name = "version",
23760d8f328SWei Huang         .type = QEMU_OPT_STRING,
23860d8f328SWei Huang         .help = "version number",
23960d8f328SWei Huang     },{
24060d8f328SWei Huang         .name = "serial",
24160d8f328SWei Huang         .type = QEMU_OPT_STRING,
24260d8f328SWei Huang         .help = "serial number",
24360d8f328SWei Huang     },{
24460d8f328SWei Huang         .name = "asset",
24560d8f328SWei Huang         .type = QEMU_OPT_STRING,
24660d8f328SWei Huang         .help = "asset tag number",
24760d8f328SWei Huang     },{
24860d8f328SWei Huang         .name = "location",
24960d8f328SWei Huang         .type = QEMU_OPT_STRING,
25060d8f328SWei Huang         .help = "location in chassis",
25160d8f328SWei Huang     },
25260d8f328SWei Huang     { /* end of list */ }
25360d8f328SWei Huang };
25460d8f328SWei Huang 
25560d8f328SWei Huang static const QemuOptDesc qemu_smbios_type3_opts[] = {
25660d8f328SWei Huang     {
25760d8f328SWei Huang         .name = "type",
25860d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
25960d8f328SWei Huang         .help = "SMBIOS element type",
26060d8f328SWei Huang     },{
26160d8f328SWei Huang         .name = "manufacturer",
26260d8f328SWei Huang         .type = QEMU_OPT_STRING,
26360d8f328SWei Huang         .help = "manufacturer name",
26460d8f328SWei Huang     },{
26560d8f328SWei Huang         .name = "version",
26660d8f328SWei Huang         .type = QEMU_OPT_STRING,
26760d8f328SWei Huang         .help = "version number",
26860d8f328SWei Huang     },{
26960d8f328SWei Huang         .name = "serial",
27060d8f328SWei Huang         .type = QEMU_OPT_STRING,
27160d8f328SWei Huang         .help = "serial number",
27260d8f328SWei Huang     },{
27360d8f328SWei Huang         .name = "asset",
27460d8f328SWei Huang         .type = QEMU_OPT_STRING,
27560d8f328SWei Huang         .help = "asset tag number",
27660d8f328SWei Huang     },{
27760d8f328SWei Huang         .name = "sku",
27860d8f328SWei Huang         .type = QEMU_OPT_STRING,
27960d8f328SWei Huang         .help = "SKU number",
28060d8f328SWei Huang     },
28160d8f328SWei Huang     { /* end of list */ }
28260d8f328SWei Huang };
28360d8f328SWei Huang 
28460d8f328SWei Huang static const QemuOptDesc qemu_smbios_type4_opts[] = {
28560d8f328SWei Huang     {
28660d8f328SWei Huang         .name = "type",
28760d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
28860d8f328SWei Huang         .help = "SMBIOS element type",
28960d8f328SWei Huang     },{
29060d8f328SWei Huang         .name = "sock_pfx",
29160d8f328SWei Huang         .type = QEMU_OPT_STRING,
29260d8f328SWei Huang         .help = "socket designation string prefix",
29360d8f328SWei Huang     },{
29460d8f328SWei Huang         .name = "manufacturer",
29560d8f328SWei Huang         .type = QEMU_OPT_STRING,
29660d8f328SWei Huang         .help = "manufacturer name",
29760d8f328SWei Huang     },{
29860d8f328SWei Huang         .name = "version",
29960d8f328SWei Huang         .type = QEMU_OPT_STRING,
30060d8f328SWei Huang         .help = "version number",
30160d8f328SWei Huang     },{
302c906e039SYing Fang         .name = "max-speed",
303c906e039SYing Fang         .type = QEMU_OPT_NUMBER,
304c906e039SYing Fang         .help = "max speed in MHz",
305c906e039SYing Fang     },{
306c906e039SYing Fang         .name = "current-speed",
307c906e039SYing Fang         .type = QEMU_OPT_NUMBER,
308c906e039SYing Fang         .help = "speed at system boot in MHz",
309c906e039SYing Fang     },{
31060d8f328SWei Huang         .name = "serial",
31160d8f328SWei Huang         .type = QEMU_OPT_STRING,
31260d8f328SWei Huang         .help = "serial number",
31360d8f328SWei Huang     },{
31460d8f328SWei Huang         .name = "asset",
31560d8f328SWei Huang         .type = QEMU_OPT_STRING,
31660d8f328SWei Huang         .help = "asset tag number",
31760d8f328SWei Huang     },{
31860d8f328SWei Huang         .name = "part",
31960d8f328SWei Huang         .type = QEMU_OPT_STRING,
32060d8f328SWei Huang         .help = "part number",
321cb5fb04fSPatrick Venture     }, {
322b5831d79SHeinrich Schuchardt         .name = "processor-family",
323b5831d79SHeinrich Schuchardt         .type = QEMU_OPT_NUMBER,
324b5831d79SHeinrich Schuchardt         .help = "processor family",
325b5831d79SHeinrich Schuchardt     }, {
326cb5fb04fSPatrick Venture         .name = "processor-id",
327cb5fb04fSPatrick Venture         .type = QEMU_OPT_NUMBER,
328cb5fb04fSPatrick Venture         .help = "processor id",
32960d8f328SWei Huang     },
33060d8f328SWei Huang     { /* end of list */ }
33160d8f328SWei Huang };
33260d8f328SWei Huang 
333fd8caa25SHal Martin static const QemuOptDesc qemu_smbios_type8_opts[] = {
334fd8caa25SHal Martin     {
335196578c9SAkihiko Odaki         .name = "type",
336196578c9SAkihiko Odaki         .type = QEMU_OPT_NUMBER,
337196578c9SAkihiko Odaki         .help = "SMBIOS element type",
338196578c9SAkihiko Odaki     },
339196578c9SAkihiko Odaki     {
340fd8caa25SHal Martin         .name = "internal_reference",
341fd8caa25SHal Martin         .type = QEMU_OPT_STRING,
342fd8caa25SHal Martin         .help = "internal reference designator",
343fd8caa25SHal Martin     },
344fd8caa25SHal Martin     {
345fd8caa25SHal Martin         .name = "external_reference",
346fd8caa25SHal Martin         .type = QEMU_OPT_STRING,
347fd8caa25SHal Martin         .help = "external reference designator",
348fd8caa25SHal Martin     },
349fd8caa25SHal Martin     {
350fd8caa25SHal Martin         .name = "connector_type",
351fd8caa25SHal Martin         .type = QEMU_OPT_NUMBER,
352fd8caa25SHal Martin         .help = "connector type",
353fd8caa25SHal Martin     },
354fd8caa25SHal Martin     {
355fd8caa25SHal Martin         .name = "port_type",
356fd8caa25SHal Martin         .type = QEMU_OPT_NUMBER,
357fd8caa25SHal Martin         .help = "port type",
358fd8caa25SHal Martin     },
359196578c9SAkihiko Odaki     { /* end of list */ }
360fd8caa25SHal Martin };
361fd8caa25SHal Martin 
362735eee07SFelix Wu static const QemuOptDesc qemu_smbios_type9_opts[] = {
363735eee07SFelix Wu     {
364735eee07SFelix Wu         .name = "type",
365735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
366735eee07SFelix Wu         .help = "SMBIOS element type",
367735eee07SFelix Wu     },
368735eee07SFelix Wu     {
369735eee07SFelix Wu         .name = "slot_designation",
370735eee07SFelix Wu         .type = QEMU_OPT_STRING,
371735eee07SFelix Wu         .help = "string number for reference designation",
372735eee07SFelix Wu     },
373735eee07SFelix Wu     {
374735eee07SFelix Wu         .name = "slot_type",
375735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
376735eee07SFelix Wu         .help = "connector type",
377735eee07SFelix Wu     },
378735eee07SFelix Wu     {
379735eee07SFelix Wu         .name = "slot_data_bus_width",
380735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
381735eee07SFelix Wu         .help = "port type",
382735eee07SFelix Wu     },
383735eee07SFelix Wu     {
384735eee07SFelix Wu         .name = "current_usage",
385735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
386735eee07SFelix Wu         .help = "current usage",
387735eee07SFelix Wu     },
388735eee07SFelix Wu     {
389735eee07SFelix Wu         .name = "slot_length",
390735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
391735eee07SFelix Wu         .help = "system slot length",
392735eee07SFelix Wu     },
393735eee07SFelix Wu     {
394735eee07SFelix Wu         .name = "slot_id",
395735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
396735eee07SFelix Wu         .help = "system slot id",
397735eee07SFelix Wu     },
398735eee07SFelix Wu     {
399735eee07SFelix Wu         .name = "slot_characteristics1",
400735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
401735eee07SFelix Wu         .help = "slot characteristics1, see the spec",
402735eee07SFelix Wu     },
403735eee07SFelix Wu     {
404735eee07SFelix Wu         .name = "slot_characteristics2",
405735eee07SFelix Wu         .type = QEMU_OPT_NUMBER,
406735eee07SFelix Wu         .help = "slot characteristics2, see the spec",
407735eee07SFelix Wu     },
40804f143d8SFelix Wu     {
40904f143d8SFelix Wu         .name = "pci_device",
41004f143d8SFelix Wu         .type = QEMU_OPT_STRING,
41104f143d8SFelix Wu         .help = "PCI device, if provided."
41204f143d8SFelix Wu     }
413735eee07SFelix Wu };
414735eee07SFelix Wu 
4152d6dcbf9SDaniel P. Berrange static const QemuOptDesc qemu_smbios_type11_opts[] = {
4162d6dcbf9SDaniel P. Berrange     {
417cd8a35b9SAkihiko Odaki         .name = "type",
418cd8a35b9SAkihiko Odaki         .type = QEMU_OPT_NUMBER,
419cd8a35b9SAkihiko Odaki         .help = "SMBIOS element type",
420cd8a35b9SAkihiko Odaki     },
421cd8a35b9SAkihiko Odaki     {
4222d6dcbf9SDaniel P. Berrange         .name = "value",
4232d6dcbf9SDaniel P. Berrange         .type = QEMU_OPT_STRING,
4242d6dcbf9SDaniel P. Berrange         .help = "OEM string data",
4252d6dcbf9SDaniel P. Berrange     },
426bb99f477SDaniel P. Berrangé     {
427bb99f477SDaniel P. Berrangé         .name = "path",
428bb99f477SDaniel P. Berrangé         .type = QEMU_OPT_STRING,
429bb99f477SDaniel P. Berrangé         .help = "OEM string data from file",
430bb99f477SDaniel P. Berrangé     },
431cd8a35b9SAkihiko Odaki     { /* end of list */ }
4322d6dcbf9SDaniel P. Berrange };
4332d6dcbf9SDaniel P. Berrange 
43460d8f328SWei Huang static const QemuOptDesc qemu_smbios_type17_opts[] = {
43560d8f328SWei Huang     {
43660d8f328SWei Huang         .name = "type",
43760d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
43860d8f328SWei Huang         .help = "SMBIOS element type",
43960d8f328SWei Huang     },{
44060d8f328SWei Huang         .name = "loc_pfx",
44160d8f328SWei Huang         .type = QEMU_OPT_STRING,
44260d8f328SWei Huang         .help = "device locator string prefix",
44360d8f328SWei Huang     },{
44460d8f328SWei Huang         .name = "bank",
44560d8f328SWei Huang         .type = QEMU_OPT_STRING,
44660d8f328SWei Huang         .help = "bank locator string",
44760d8f328SWei Huang     },{
44860d8f328SWei Huang         .name = "manufacturer",
44960d8f328SWei Huang         .type = QEMU_OPT_STRING,
45060d8f328SWei Huang         .help = "manufacturer name",
45160d8f328SWei Huang     },{
45260d8f328SWei Huang         .name = "serial",
45360d8f328SWei Huang         .type = QEMU_OPT_STRING,
45460d8f328SWei Huang         .help = "serial number",
45560d8f328SWei Huang     },{
45660d8f328SWei Huang         .name = "asset",
45760d8f328SWei Huang         .type = QEMU_OPT_STRING,
45860d8f328SWei Huang         .help = "asset tag number",
45960d8f328SWei Huang     },{
46060d8f328SWei Huang         .name = "part",
46160d8f328SWei Huang         .type = QEMU_OPT_STRING,
46260d8f328SWei Huang         .help = "part number",
46360d8f328SWei Huang     },{
46460d8f328SWei Huang         .name = "speed",
46560d8f328SWei Huang         .type = QEMU_OPT_NUMBER,
46660d8f328SWei Huang         .help = "maximum capable speed",
46760d8f328SWei Huang     },
46860d8f328SWei Huang     { /* end of list */ }
46960d8f328SWei Huang };
47060d8f328SWei Huang 
47105dfb447SVincent Bernat static const QemuOptDesc qemu_smbios_type41_opts[] = {
47205dfb447SVincent Bernat     {
47305dfb447SVincent Bernat         .name = "type",
47405dfb447SVincent Bernat         .type = QEMU_OPT_NUMBER,
47505dfb447SVincent Bernat         .help = "SMBIOS element type",
47605dfb447SVincent Bernat     },{
47705dfb447SVincent Bernat         .name = "designation",
47805dfb447SVincent Bernat         .type = QEMU_OPT_STRING,
47905dfb447SVincent Bernat         .help = "reference designation string",
48005dfb447SVincent Bernat     },{
48105dfb447SVincent Bernat         .name = "kind",
48205dfb447SVincent Bernat         .type = QEMU_OPT_STRING,
48305dfb447SVincent Bernat         .help = "device type",
48405dfb447SVincent Bernat         .def_value_str = "other",
48505dfb447SVincent Bernat     },{
48605dfb447SVincent Bernat         .name = "instance",
48705dfb447SVincent Bernat         .type = QEMU_OPT_NUMBER,
48805dfb447SVincent Bernat         .help = "device type instance",
48905dfb447SVincent Bernat     },{
49005dfb447SVincent Bernat         .name = "pcidev",
49105dfb447SVincent Bernat         .type = QEMU_OPT_STRING,
49205dfb447SVincent Bernat         .help = "PCI device",
49305dfb447SVincent Bernat     },
49405dfb447SVincent Bernat     { /* end of list */ }
49505dfb447SVincent Bernat };
49605dfb447SVincent Bernat 
smbios_register_config(void)49760d8f328SWei Huang static void smbios_register_config(void)
49860d8f328SWei Huang {
49960d8f328SWei Huang     qemu_add_opts(&qemu_smbios_opts);
50060d8f328SWei Huang }
50160d8f328SWei Huang 
50234294e2fSEduardo Habkost opts_init(smbios_register_config);
50360d8f328SWei Huang 
50410c36666SDaniel P. Berrangé /*
50510c36666SDaniel P. Berrangé  * The SMBIOS 2.1 "structure table length" field in the
50610c36666SDaniel P. Berrangé  * entry point uses a 16-bit integer, so we're limited
50710c36666SDaniel P. Berrangé  * in total table size
50810c36666SDaniel P. Berrangé  */
50910c36666SDaniel P. Berrangé #define SMBIOS_21_MAX_TABLES_LEN 0xffff
51010c36666SDaniel P. Berrangé 
smbios_check_type4_count(uint32_t expected_t4_count,Error ** errp)511643e1c9eSIgor Mammedov static bool smbios_check_type4_count(uint32_t expected_t4_count, Error **errp)
51260d8f328SWei Huang {
513e94e0a83SIgor Mammedov     if (smbios_type4_count && smbios_type4_count != expected_t4_count) {
514643e1c9eSIgor Mammedov         error_setg(errp, "Expected %d SMBIOS Type 4 tables, got %d instead",
515e94e0a83SIgor Mammedov                    expected_t4_count, smbios_type4_count);
516643e1c9eSIgor Mammedov         return false;
51760d8f328SWei Huang     }
518643e1c9eSIgor Mammedov     return true;
5199cd7fd69SIgor Mammedov }
52010c36666SDaniel P. Berrangé 
smbios_validate_table(SmbiosEntryPointType ep_type,Error ** errp)52169ea07a5SIgor Mammedov bool smbios_validate_table(SmbiosEntryPointType ep_type, Error **errp)
5229cd7fd69SIgor Mammedov {
52369ea07a5SIgor Mammedov     if (ep_type == SMBIOS_ENTRY_POINT_TYPE_32 &&
52410c36666SDaniel P. Berrangé         smbios_tables_len > SMBIOS_21_MAX_TABLES_LEN) {
525643e1c9eSIgor Mammedov         error_setg(errp, "SMBIOS 2.1 table length %zu exceeds %d",
52610c36666SDaniel P. Berrangé                    smbios_tables_len, SMBIOS_21_MAX_TABLES_LEN);
527643e1c9eSIgor Mammedov         return false;
52810c36666SDaniel P. Berrangé     }
529643e1c9eSIgor Mammedov     return true;
53060d8f328SWei Huang }
53160d8f328SWei Huang 
smbios_skip_table(uint8_t type,bool required_table)5320517cc98SCorey Minyard bool smbios_skip_table(uint8_t type, bool required_table)
53360d8f328SWei Huang {
534d638a865SIgor Mammedov     if (test_bit(type, smbios_have_binfile_bitmap)) {
53560d8f328SWei Huang         return true; /* user provided their own binary blob(s) */
53660d8f328SWei Huang     }
537d638a865SIgor Mammedov     if (test_bit(type, smbios_have_fields_bitmap)) {
53860d8f328SWei Huang         return false; /* user provided fields via command line */
53960d8f328SWei Huang     }
54060d8f328SWei Huang     if (smbios_have_defaults && required_table) {
54160d8f328SWei Huang         return false; /* we're building tables, and this one's required */
54260d8f328SWei Huang     }
54360d8f328SWei Huang     return true;
54460d8f328SWei Huang }
54560d8f328SWei Huang 
5463818acf5SAni Sinha #define T0_BASE 0x000
5473818acf5SAni Sinha #define T1_BASE 0x100
5483818acf5SAni Sinha #define T2_BASE 0x200
5493818acf5SAni Sinha #define T3_BASE 0x300
5503818acf5SAni Sinha #define T4_BASE 0x400
551735eee07SFelix Wu #define T9_BASE 0x900
5523818acf5SAni Sinha #define T11_BASE 0xe00
5533818acf5SAni Sinha 
5543818acf5SAni Sinha #define T16_BASE 0x1000
5553818acf5SAni Sinha #define T17_BASE 0x1100
5563818acf5SAni Sinha #define T19_BASE 0x1300
5573818acf5SAni Sinha #define T32_BASE 0x2000
5583818acf5SAni Sinha #define T41_BASE 0x2900
5593818acf5SAni Sinha #define T127_BASE 0x7F00
5603818acf5SAni Sinha 
smbios_build_type_0_table(void)56160d8f328SWei Huang static void smbios_build_type_0_table(void)
56260d8f328SWei Huang {
5633818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(0, T0_BASE, false); /* optional, leave up to BIOS */
56460d8f328SWei Huang 
565d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(0, vendor_str, smbios_type0.vendor);
566d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(0, bios_version_str, smbios_type0.version);
56760d8f328SWei Huang 
56860d8f328SWei Huang     t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
56960d8f328SWei Huang 
570d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(0, bios_release_date_str, smbios_type0.date);
57160d8f328SWei Huang 
57260d8f328SWei Huang     t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
57360d8f328SWei Huang 
57460d8f328SWei Huang     t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
57560d8f328SWei Huang     t->bios_characteristics_extension_bytes[0] = 0;
57660d8f328SWei Huang     t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
577d638a865SIgor Mammedov     if (smbios_type0.uefi) {
57860d8f328SWei Huang         t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
57960d8f328SWei Huang     }
58060d8f328SWei Huang 
581d638a865SIgor Mammedov     if (smbios_type0.have_major_minor) {
582d638a865SIgor Mammedov         t->system_bios_major_release = smbios_type0.major;
583d638a865SIgor Mammedov         t->system_bios_minor_release = smbios_type0.minor;
58460d8f328SWei Huang     } else {
58560d8f328SWei Huang         t->system_bios_major_release = 0;
58660d8f328SWei Huang         t->system_bios_minor_release = 0;
58760d8f328SWei Huang     }
58860d8f328SWei Huang 
58960d8f328SWei Huang     /* hardcoded in SeaBIOS */
59060d8f328SWei Huang     t->embedded_controller_major_release = 0xFF;
59160d8f328SWei Huang     t->embedded_controller_minor_release = 0xFF;
59260d8f328SWei Huang 
59360d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
59460d8f328SWei Huang }
59560d8f328SWei Huang 
59660d8f328SWei Huang /* Encode UUID from the big endian encoding described on RFC4122 to the wire
59760d8f328SWei Huang  * format specified by SMBIOS version 2.6.
59860d8f328SWei Huang  */
smbios_encode_uuid(struct smbios_uuid * uuid,QemuUUID * in)5999c5ce8dbSFam Zheng static void smbios_encode_uuid(struct smbios_uuid *uuid, QemuUUID *in)
60060d8f328SWei Huang {
601664ee768SMarc-André Lureau     memcpy(uuid, in, 16);
60260d8f328SWei Huang     uuid->time_low = bswap32(uuid->time_low);
60360d8f328SWei Huang     uuid->time_mid = bswap16(uuid->time_mid);
60460d8f328SWei Huang     uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
60560d8f328SWei Huang }
60660d8f328SWei Huang 
smbios_build_type_1_table(void)60760d8f328SWei Huang static void smbios_build_type_1_table(void)
60860d8f328SWei Huang {
6093818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(1, T1_BASE, true); /* required */
61060d8f328SWei Huang 
611d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, manufacturer_str, smbios_type1.manufacturer);
612d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, product_name_str, smbios_type1.product);
613d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, version_str, smbios_type1.version);
614d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, serial_number_str, smbios_type1.serial);
61560d8f328SWei Huang     if (qemu_uuid_set) {
6169c5ce8dbSFam Zheng         smbios_encode_uuid(&t->uuid, &qemu_uuid);
61760d8f328SWei Huang     } else {
61860d8f328SWei Huang         memset(&t->uuid, 0, 16);
61960d8f328SWei Huang     }
62060d8f328SWei Huang     t->wake_up_type = 0x06; /* power switch */
621d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, sku_number_str, smbios_type1.sku);
622d638a865SIgor Mammedov     SMBIOS_TABLE_SET_STR(1, family_str, smbios_type1.family);
62360d8f328SWei Huang 
62460d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
62560d8f328SWei Huang }
62660d8f328SWei Huang 
smbios_build_type_2_table(void)62760d8f328SWei Huang static void smbios_build_type_2_table(void)
62860d8f328SWei Huang {
6293818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(2, T2_BASE, false); /* optional */
63060d8f328SWei Huang 
63160d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
63260d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
63360d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
63460d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
63560d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
63660d8f328SWei Huang     t->feature_flags = 0x01; /* Motherboard */
63760d8f328SWei Huang     SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
63860d8f328SWei Huang     t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
63960d8f328SWei Huang     t->board_type = 0x0A; /* Motherboard */
64060d8f328SWei Huang     t->contained_element_count = 0;
64160d8f328SWei Huang 
64260d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
64360d8f328SWei Huang }
64460d8f328SWei Huang 
smbios_build_type_3_table(void)64560d8f328SWei Huang static void smbios_build_type_3_table(void)
64660d8f328SWei Huang {
6473818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(3, T3_BASE, true); /* required */
64860d8f328SWei Huang 
64960d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
65060d8f328SWei Huang     t->type = 0x01; /* Other */
65160d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
65260d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
65360d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
65460d8f328SWei Huang     t->boot_up_state = 0x03; /* Safe */
65560d8f328SWei Huang     t->power_supply_state = 0x03; /* Safe */
65660d8f328SWei Huang     t->thermal_state = 0x03; /* Safe */
65760d8f328SWei Huang     t->security_status = 0x02; /* Unknown */
65860d8f328SWei Huang     t->oem_defined = cpu_to_le32(0);
65960d8f328SWei Huang     t->height = 0;
66060d8f328SWei Huang     t->number_of_power_cords = 0;
66160d8f328SWei Huang     t->contained_element_count = 0;
662b81a5f94SDaniel P. Berrangé     t->contained_element_record_length = 0;
66360d8f328SWei Huang     SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
66460d8f328SWei Huang 
66560d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
66660d8f328SWei Huang }
66760d8f328SWei Huang 
smbios_build_type_4_table(MachineState * ms,unsigned instance,SmbiosEntryPointType ep_type,Error ** errp)66869ea07a5SIgor Mammedov static void smbios_build_type_4_table(MachineState *ms, unsigned instance,
6695ed79482SIgor Mammedov                                       SmbiosEntryPointType ep_type,
6705ed79482SIgor Mammedov                                       Error **errp)
67160d8f328SWei Huang {
67260d8f328SWei Huang     char sock_str[128];
67305e27d74SJulia Suvorova     size_t tbl_len = SMBIOS_TYPE_4_LEN_V28;
6747298fd7dSZhao Liu     unsigned threads_per_socket;
675196ea60aSZhao Liu     unsigned cores_per_socket;
67660d8f328SWei Huang 
67769ea07a5SIgor Mammedov     if (ep_type == SMBIOS_ENTRY_POINT_TYPE_64) {
67805e27d74SJulia Suvorova         tbl_len = SMBIOS_TYPE_4_LEN_V30;
67905e27d74SJulia Suvorova     }
68005e27d74SJulia Suvorova 
68105e27d74SJulia Suvorova     SMBIOS_BUILD_TABLE_PRE_SIZE(4, T4_BASE + instance,
68205e27d74SJulia Suvorova                                 true, tbl_len); /* required */
68360d8f328SWei Huang 
68460d8f328SWei Huang     snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
68560d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
68660d8f328SWei Huang     t->processor_type = 0x03; /* CPU */
687b5831d79SHeinrich Schuchardt     t->processor_family = 0xfe; /* use Processor Family 2 field */
68860d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
689cb5fb04fSPatrick Venture     if (type4.processor_id == 0) {
69060d8f328SWei Huang         t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
69160d8f328SWei Huang         t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
692cb5fb04fSPatrick Venture     } else {
693cb5fb04fSPatrick Venture         t->processor_id[0] = cpu_to_le32((uint32_t)type4.processor_id);
694cb5fb04fSPatrick Venture         t->processor_id[1] = cpu_to_le32(type4.processor_id >> 32);
695cb5fb04fSPatrick Venture     }
69660d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
69760d8f328SWei Huang     t->voltage = 0;
69860d8f328SWei Huang     t->external_clock = cpu_to_le16(0); /* Unknown */
699c906e039SYing Fang     t->max_speed = cpu_to_le16(type4.max_speed);
700c906e039SYing Fang     t->current_speed = cpu_to_le16(type4.current_speed);
70160d8f328SWei Huang     t->status = 0x41; /* Socket populated, CPU enabled */
70260d8f328SWei Huang     t->processor_upgrade = 0x01; /* Other */
70360d8f328SWei Huang     t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
70460d8f328SWei Huang     t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
70560d8f328SWei Huang     t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
70660d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
70760d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
70860d8f328SWei Huang     SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
70905e27d74SJulia Suvorova 
7107298fd7dSZhao Liu     threads_per_socket = machine_topo_get_threads_per_socket(ms);
711196ea60aSZhao Liu     cores_per_socket = machine_topo_get_cores_per_socket(ms);
7127298fd7dSZhao Liu 
713196ea60aSZhao Liu     t->core_count = (cores_per_socket > 255) ? 0xFF : cores_per_socket;
71405e27d74SJulia Suvorova     t->core_enabled = t->core_count;
71505e27d74SJulia Suvorova 
7167298fd7dSZhao Liu     t->thread_count = (threads_per_socket > 255) ? 0xFF : threads_per_socket;
71705e27d74SJulia Suvorova 
71860d8f328SWei Huang     t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
719b5831d79SHeinrich Schuchardt     t->processor_family2 = cpu_to_le16(type4.processor_family);
72060d8f328SWei Huang 
72160d09b8dSJulia Suvorova     if (tbl_len == SMBIOS_TYPE_4_LEN_V30) {
722196ea60aSZhao Liu         t->core_count2 = t->core_enabled2 = cpu_to_le16(cores_per_socket);
7237298fd7dSZhao Liu         t->thread_count2 = cpu_to_le16(threads_per_socket);
7245ed79482SIgor Mammedov     } else if (t->core_count == 0xFF || t->thread_count == 0xFF) {
7255ed79482SIgor Mammedov         error_setg(errp, "SMBIOS 2.0 doesn't support number of processor "
7265ed79482SIgor Mammedov                          "cores/threads more than 255, use "
7275ed79482SIgor Mammedov                          "-machine smbios-entry-point-type=64 option to enable "
7285ed79482SIgor Mammedov                          "SMBIOS 3.0 support");
7295ed79482SIgor Mammedov         return;
73060d09b8dSJulia Suvorova     }
73160d09b8dSJulia Suvorova 
73260d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
73360d8f328SWei Huang     smbios_type4_count++;
73460d8f328SWei Huang }
73560d8f328SWei Huang 
smbios_build_type_8_table(void)736fd8caa25SHal Martin static void smbios_build_type_8_table(void)
737fd8caa25SHal Martin {
738fd8caa25SHal Martin     unsigned instance = 0;
739fd8caa25SHal Martin     struct type8_instance *t8;
740fd8caa25SHal Martin 
741fd8caa25SHal Martin     QTAILQ_FOREACH(t8, &type8, next) {
742fd8caa25SHal Martin         SMBIOS_BUILD_TABLE_PRE(8, T0_BASE + instance, true);
743fd8caa25SHal Martin 
744fd8caa25SHal Martin         SMBIOS_TABLE_SET_STR(8, internal_reference_str, t8->internal_reference);
745fd8caa25SHal Martin         SMBIOS_TABLE_SET_STR(8, external_reference_str, t8->external_reference);
746fd8caa25SHal Martin         /* most vendors seem to set this to None */
747fd8caa25SHal Martin         t->internal_connector_type = 0x0;
748fd8caa25SHal Martin         t->external_connector_type = t8->connector_type;
749fd8caa25SHal Martin         t->port_type = t8->port_type;
750fd8caa25SHal Martin 
751fd8caa25SHal Martin         SMBIOS_BUILD_TABLE_POST;
752fd8caa25SHal Martin         instance++;
753fd8caa25SHal Martin     }
754fd8caa25SHal Martin }
755fd8caa25SHal Martin 
smbios_build_type_9_table(Error ** errp)75604f143d8SFelix Wu static void smbios_build_type_9_table(Error **errp)
757735eee07SFelix Wu {
758735eee07SFelix Wu     unsigned instance = 0;
759735eee07SFelix Wu     struct type9_instance *t9;
760735eee07SFelix Wu 
761735eee07SFelix Wu     QTAILQ_FOREACH(t9, &type9, next) {
762735eee07SFelix Wu         SMBIOS_BUILD_TABLE_PRE(9, T9_BASE + instance, true);
763735eee07SFelix Wu 
764735eee07SFelix Wu         SMBIOS_TABLE_SET_STR(9, slot_designation, t9->slot_designation);
765735eee07SFelix Wu         t->slot_type = t9->slot_type;
766735eee07SFelix Wu         t->slot_data_bus_width = t9->slot_data_bus_width;
767735eee07SFelix Wu         t->current_usage = t9->current_usage;
768735eee07SFelix Wu         t->slot_length = t9->slot_length;
769735eee07SFelix Wu         t->slot_id = t9->slot_id;
770735eee07SFelix Wu         t->slot_characteristics1 = t9->slot_characteristics1;
771735eee07SFelix Wu         t->slot_characteristics2 = t9->slot_characteristics2;
772735eee07SFelix Wu 
77304f143d8SFelix Wu         if (t9->pcidev) {
77404f143d8SFelix Wu             PCIDevice *pdev = NULL;
77504f143d8SFelix Wu             int rc = pci_qdev_find_device(t9->pcidev, &pdev);
77604f143d8SFelix Wu             if (rc != 0) {
77704f143d8SFelix Wu                 error_setg(errp,
77804f143d8SFelix Wu                            "No PCI device %s for SMBIOS type 9 entry %s",
77904f143d8SFelix Wu                            t9->pcidev, t9->slot_designation);
78004f143d8SFelix Wu                 return;
78104f143d8SFelix Wu             }
78204f143d8SFelix Wu             /*
78304f143d8SFelix Wu              * We only handle the case were the device is attached to
78404f143d8SFelix Wu              * the PCI root bus. The general case is more complex as
78504f143d8SFelix Wu              * bridges are enumerated later and the table would need
78604f143d8SFelix Wu              * to be updated at this moment.
78704f143d8SFelix Wu              */
78804f143d8SFelix Wu             if (!pci_bus_is_root(pci_get_bus(pdev))) {
78904f143d8SFelix Wu                 error_setg(errp,
79004f143d8SFelix Wu                            "Cannot create type 9 entry for PCI device %s: "
79104f143d8SFelix Wu                            "not attached to the root bus",
79204f143d8SFelix Wu                            t9->pcidev);
79304f143d8SFelix Wu                 return;
79404f143d8SFelix Wu             }
79504f143d8SFelix Wu             t->segment_group_number = cpu_to_le16(0);
79604f143d8SFelix Wu             t->bus_number = pci_dev_bus_num(pdev);
79704f143d8SFelix Wu             t->device_number = pdev->devfn;
79804f143d8SFelix Wu         } else {
79904f143d8SFelix Wu             /*
80004f143d8SFelix Wu              * Per SMBIOS spec, For slots that are not of the PCI, AGP, PCI-X,
80104f143d8SFelix Wu              * or PCI-Express type that do not have bus/device/function
80204f143d8SFelix Wu              * information, 0FFh should be populated in the fields of Segment
80304f143d8SFelix Wu              * Group Number, Bus Number, Device/Function Number.
80404f143d8SFelix Wu              */
80504f143d8SFelix Wu             t->segment_group_number = 0xff;
80604f143d8SFelix Wu             t->bus_number = 0xff;
80704f143d8SFelix Wu             t->device_number = 0xff;
80804f143d8SFelix Wu         }
80904f143d8SFelix Wu 
810735eee07SFelix Wu         SMBIOS_BUILD_TABLE_POST;
811735eee07SFelix Wu         instance++;
812735eee07SFelix Wu     }
813735eee07SFelix Wu }
814735eee07SFelix Wu 
smbios_build_type_11_table(void)8152d6dcbf9SDaniel P. Berrange static void smbios_build_type_11_table(void)
8162d6dcbf9SDaniel P. Berrange {
8172d6dcbf9SDaniel P. Berrange     char count_str[128];
8182d6dcbf9SDaniel P. Berrange     size_t i;
8192d6dcbf9SDaniel P. Berrange 
8202d6dcbf9SDaniel P. Berrange     if (type11.nvalues == 0) {
8212d6dcbf9SDaniel P. Berrange         return;
8222d6dcbf9SDaniel P. Berrange     }
8232d6dcbf9SDaniel P. Berrange 
8243818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(11, T11_BASE, true); /* required */
8252d6dcbf9SDaniel P. Berrange 
8262d6dcbf9SDaniel P. Berrange     snprintf(count_str, sizeof(count_str), "%zu", type11.nvalues);
8272d6dcbf9SDaniel P. Berrange     t->count = type11.nvalues;
8282d6dcbf9SDaniel P. Berrange 
8292d6dcbf9SDaniel P. Berrange     for (i = 0; i < type11.nvalues; i++) {
8302d6dcbf9SDaniel P. Berrange         SMBIOS_TABLE_SET_STR_LIST(11, type11.values[i]);
831bb99f477SDaniel P. Berrangé         g_free(type11.values[i]);
832bb99f477SDaniel P. Berrangé         type11.values[i] = NULL;
8332d6dcbf9SDaniel P. Berrange     }
8342d6dcbf9SDaniel P. Berrange 
8352d6dcbf9SDaniel P. Berrange     SMBIOS_BUILD_TABLE_POST;
8362d6dcbf9SDaniel P. Berrange }
8372d6dcbf9SDaniel P. Berrange 
83860d8f328SWei Huang #define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
83960d8f328SWei Huang 
smbios_build_type_16_table(unsigned dimm_cnt)84060d8f328SWei Huang static void smbios_build_type_16_table(unsigned dimm_cnt)
84160d8f328SWei Huang {
84260d8f328SWei Huang     uint64_t size_kb;
84360d8f328SWei Huang 
8443818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(16, T16_BASE, true); /* required */
84560d8f328SWei Huang 
84660d8f328SWei Huang     t->location = 0x01; /* Other */
84760d8f328SWei Huang     t->use = 0x03; /* System memory */
84860d8f328SWei Huang     t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
84986378b29SPaolo Bonzini     size_kb = QEMU_ALIGN_UP(current_machine->ram_size, KiB) / KiB;
85060d8f328SWei Huang     if (size_kb < MAX_T16_STD_SZ) {
85160d8f328SWei Huang         t->maximum_capacity = cpu_to_le32(size_kb);
85260d8f328SWei Huang         t->extended_maximum_capacity = cpu_to_le64(0);
85360d8f328SWei Huang     } else {
85460d8f328SWei Huang         t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
85586378b29SPaolo Bonzini         t->extended_maximum_capacity = cpu_to_le64(current_machine->ram_size);
85660d8f328SWei Huang     }
85760d8f328SWei Huang     t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
85860d8f328SWei Huang     t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
85960d8f328SWei Huang 
86060d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
86160d8f328SWei Huang }
86260d8f328SWei Huang 
86360d8f328SWei Huang #define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
86460d8f328SWei Huang #define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
86560d8f328SWei Huang 
smbios_build_type_17_table(unsigned instance,uint64_t size)86660d8f328SWei Huang static void smbios_build_type_17_table(unsigned instance, uint64_t size)
86760d8f328SWei Huang {
86860d8f328SWei Huang     char loc_str[128];
86960d8f328SWei Huang     uint64_t size_mb;
87060d8f328SWei Huang 
8713818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(17, T17_BASE + instance, true); /* required */
87260d8f328SWei Huang 
87360d8f328SWei Huang     t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
87460d8f328SWei Huang     t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
87560d8f328SWei Huang     t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
87660d8f328SWei Huang     t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
877968dfd05SPhilippe Mathieu-Daudé     size_mb = QEMU_ALIGN_UP(size, MiB) / MiB;
87860d8f328SWei Huang     if (size_mb < MAX_T17_STD_SZ) {
87960d8f328SWei Huang         t->size = cpu_to_le16(size_mb);
88060d8f328SWei Huang         t->extended_size = cpu_to_le32(0);
88160d8f328SWei Huang     } else {
88260d8f328SWei Huang         assert(size_mb < MAX_T17_EXT_SZ);
88360d8f328SWei Huang         t->size = cpu_to_le16(MAX_T17_STD_SZ);
88460d8f328SWei Huang         t->extended_size = cpu_to_le32(size_mb);
88560d8f328SWei Huang     }
88660d8f328SWei Huang     t->form_factor = 0x09; /* DIMM */
88760d8f328SWei Huang     t->device_set = 0; /* Not in a set */
88860d8f328SWei Huang     snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
88960d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
89060d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
89160d8f328SWei Huang     t->memory_type = 0x07; /* RAM */
89260d8f328SWei Huang     t->type_detail = cpu_to_le16(0x02); /* Other */
89360d8f328SWei Huang     t->speed = cpu_to_le16(type17.speed);
89460d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
89560d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
89660d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
89760d8f328SWei Huang     SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
89860d8f328SWei Huang     t->attributes = 0; /* Unknown */
89960d8f328SWei Huang     t->configured_clock_speed = t->speed; /* reuse value for max speed */
90060d8f328SWei Huang     t->minimum_voltage = cpu_to_le16(0); /* Unknown */
90160d8f328SWei Huang     t->maximum_voltage = cpu_to_le16(0); /* Unknown */
90260d8f328SWei Huang     t->configured_voltage = cpu_to_le16(0); /* Unknown */
90360d8f328SWei Huang 
90460d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
90560d8f328SWei Huang }
90660d8f328SWei Huang 
smbios_build_type_19_table(unsigned instance,unsigned offset,uint64_t start,uint64_t size)907a379d455SAni Sinha static void smbios_build_type_19_table(unsigned instance, unsigned offset,
90860d8f328SWei Huang                                        uint64_t start, uint64_t size)
90960d8f328SWei Huang {
91060d8f328SWei Huang     uint64_t end, start_kb, end_kb;
91160d8f328SWei Huang 
912a379d455SAni Sinha     SMBIOS_BUILD_TABLE_PRE(19, T19_BASE + offset + instance,
913a379d455SAni Sinha                            true); /* required */
91460d8f328SWei Huang 
91560d8f328SWei Huang     end = start + size - 1;
91660d8f328SWei Huang     assert(end > start);
917968dfd05SPhilippe Mathieu-Daudé     start_kb = start / KiB;
918968dfd05SPhilippe Mathieu-Daudé     end_kb = end / KiB;
91960d8f328SWei Huang     if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
92060d8f328SWei Huang         t->starting_address = cpu_to_le32(start_kb);
92160d8f328SWei Huang         t->ending_address = cpu_to_le32(end_kb);
92260d8f328SWei Huang         t->extended_starting_address =
92360d8f328SWei Huang             t->extended_ending_address = cpu_to_le64(0);
92460d8f328SWei Huang     } else {
92560d8f328SWei Huang         t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
92660d8f328SWei Huang         t->extended_starting_address = cpu_to_le64(start);
92760d8f328SWei Huang         t->extended_ending_address = cpu_to_le64(end);
92860d8f328SWei Huang     }
92960d8f328SWei Huang     t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
93060d8f328SWei Huang     t->partition_width = 1; /* One device per row */
93160d8f328SWei Huang 
93260d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
93360d8f328SWei Huang }
93460d8f328SWei Huang 
smbios_build_type_32_table(void)93560d8f328SWei Huang static void smbios_build_type_32_table(void)
93660d8f328SWei Huang {
9373818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(32, T32_BASE, true); /* required */
93860d8f328SWei Huang 
93960d8f328SWei Huang     memset(t->reserved, 0, 6);
94060d8f328SWei Huang     t->boot_status = 0; /* No errors detected */
94160d8f328SWei Huang 
94260d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
94360d8f328SWei Huang }
94460d8f328SWei Huang 
smbios_build_type_41_table(Error ** errp)94505dfb447SVincent Bernat static void smbios_build_type_41_table(Error **errp)
94605dfb447SVincent Bernat {
94705dfb447SVincent Bernat     unsigned instance = 0;
94805dfb447SVincent Bernat     struct type41_instance *t41;
94905dfb447SVincent Bernat 
95005dfb447SVincent Bernat     QTAILQ_FOREACH(t41, &type41, next) {
9513818acf5SAni Sinha         SMBIOS_BUILD_TABLE_PRE(41, T41_BASE + instance, true);
95205dfb447SVincent Bernat 
95305dfb447SVincent Bernat         SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation);
95405dfb447SVincent Bernat         t->device_type = t41->kind;
95505dfb447SVincent Bernat         t->device_type_instance = t41->instance;
95605dfb447SVincent Bernat         t->segment_group_number = cpu_to_le16(0);
95705dfb447SVincent Bernat         t->bus_number = 0;
95805dfb447SVincent Bernat         t->device_number = 0;
95905dfb447SVincent Bernat 
96005dfb447SVincent Bernat         if (t41->pcidev) {
96105dfb447SVincent Bernat             PCIDevice *pdev = NULL;
96205dfb447SVincent Bernat             int rc = pci_qdev_find_device(t41->pcidev, &pdev);
96305dfb447SVincent Bernat             if (rc != 0) {
96405dfb447SVincent Bernat                 error_setg(errp,
96505dfb447SVincent Bernat                            "No PCI device %s for SMBIOS type 41 entry %s",
96605dfb447SVincent Bernat                            t41->pcidev, t41->designation);
96705dfb447SVincent Bernat                 return;
96805dfb447SVincent Bernat             }
96905dfb447SVincent Bernat             /*
97005dfb447SVincent Bernat              * We only handle the case were the device is attached to
97105dfb447SVincent Bernat              * the PCI root bus. The general case is more complex as
97205dfb447SVincent Bernat              * bridges are enumerated later and the table would need
97305dfb447SVincent Bernat              * to be updated at this moment.
97405dfb447SVincent Bernat              */
97505dfb447SVincent Bernat             if (!pci_bus_is_root(pci_get_bus(pdev))) {
97605dfb447SVincent Bernat                 error_setg(errp,
97705dfb447SVincent Bernat                            "Cannot create type 41 entry for PCI device %s: "
97805dfb447SVincent Bernat                            "not attached to the root bus",
97905dfb447SVincent Bernat                            t41->pcidev);
98005dfb447SVincent Bernat                 return;
98105dfb447SVincent Bernat             }
98205dfb447SVincent Bernat             t->segment_group_number = cpu_to_le16(0);
98305dfb447SVincent Bernat             t->bus_number = pci_dev_bus_num(pdev);
98405dfb447SVincent Bernat             t->device_number = pdev->devfn;
98505dfb447SVincent Bernat         }
98605dfb447SVincent Bernat 
98705dfb447SVincent Bernat         SMBIOS_BUILD_TABLE_POST;
98805dfb447SVincent Bernat         instance++;
98905dfb447SVincent Bernat     }
99005dfb447SVincent Bernat }
99105dfb447SVincent Bernat 
smbios_build_type_127_table(void)99260d8f328SWei Huang static void smbios_build_type_127_table(void)
99360d8f328SWei Huang {
9943818acf5SAni Sinha     SMBIOS_BUILD_TABLE_PRE(127, T127_BASE, true); /* required */
99560d8f328SWei Huang     SMBIOS_BUILD_TABLE_POST;
99660d8f328SWei Huang }
99760d8f328SWei Huang 
smbios_set_cpuid(uint32_t version,uint32_t features)99860d8f328SWei Huang void smbios_set_cpuid(uint32_t version, uint32_t features)
99960d8f328SWei Huang {
100060d8f328SWei Huang     smbios_cpuid_version = version;
100160d8f328SWei Huang     smbios_cpuid_features = features;
100260d8f328SWei Huang }
100360d8f328SWei Huang 
100460d8f328SWei Huang #define SMBIOS_SET_DEFAULT(field, value)                                  \
100560d8f328SWei Huang     if (!field) {                                                         \
100660d8f328SWei Huang         field = value;                                                    \
100760d8f328SWei Huang     }
100860d8f328SWei Huang 
smbios_set_default_processor_family(uint16_t processor_family)10096f3b727bSHeinrich Schuchardt void smbios_set_default_processor_family(uint16_t processor_family)
10106f3b727bSHeinrich Schuchardt {
10116f3b727bSHeinrich Schuchardt     if (type4.processor_family <= 0x01) {
10126f3b727bSHeinrich Schuchardt         type4.processor_family = processor_family;
10136f3b727bSHeinrich Schuchardt     }
10146f3b727bSHeinrich Schuchardt }
10156f3b727bSHeinrich Schuchardt 
smbios_set_defaults(const char * manufacturer,const char * product,const char * version)101660d8f328SWei Huang void smbios_set_defaults(const char *manufacturer, const char *product,
1017c338128eSPhilippe Mathieu-Daudé                          const char *version)
101860d8f328SWei Huang {
101960d8f328SWei Huang     smbios_have_defaults = true;
102060d8f328SWei Huang 
1021d638a865SIgor Mammedov     SMBIOS_SET_DEFAULT(smbios_type1.manufacturer, manufacturer);
1022d638a865SIgor Mammedov     SMBIOS_SET_DEFAULT(smbios_type1.product, product);
1023d638a865SIgor Mammedov     SMBIOS_SET_DEFAULT(smbios_type1.version, version);
102460d8f328SWei Huang     SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
102560d8f328SWei Huang     SMBIOS_SET_DEFAULT(type2.product, product);
102660d8f328SWei Huang     SMBIOS_SET_DEFAULT(type2.version, version);
102760d8f328SWei Huang     SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
102860d8f328SWei Huang     SMBIOS_SET_DEFAULT(type3.version, version);
102960d8f328SWei Huang     SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
103060d8f328SWei Huang     SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
103160d8f328SWei Huang     SMBIOS_SET_DEFAULT(type4.version, version);
103260d8f328SWei Huang     SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
103360d8f328SWei Huang     SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
103460d8f328SWei Huang }
103560d8f328SWei Huang 
smbios_entry_point_setup(SmbiosEntryPointType ep_type)103669ea07a5SIgor Mammedov static void smbios_entry_point_setup(SmbiosEntryPointType ep_type)
103760d8f328SWei Huang {
103869ea07a5SIgor Mammedov     switch (ep_type) {
103910be11d0SEduardo Habkost     case SMBIOS_ENTRY_POINT_TYPE_32:
104086299120SWei Huang         memcpy(ep.ep21.anchor_string, "_SM_", 4);
104186299120SWei Huang         memcpy(ep.ep21.intermediate_anchor_string, "_DMI_", 5);
104286299120SWei Huang         ep.ep21.length = sizeof(struct smbios_21_entry_point);
104386299120SWei Huang         ep.ep21.entry_point_revision = 0; /* formatted_area reserved */
104486299120SWei Huang         memset(ep.ep21.formatted_area, 0, 5);
104560d8f328SWei Huang 
104660d8f328SWei Huang         /* compliant with smbios spec v2.8 */
104786299120SWei Huang         ep.ep21.smbios_major_version = 2;
104886299120SWei Huang         ep.ep21.smbios_minor_version = 8;
104986299120SWei Huang         ep.ep21.smbios_bcd_revision = 0x28;
105060d8f328SWei Huang 
105160d8f328SWei Huang         /* set during table construction, but BIOS may override: */
105286299120SWei Huang         ep.ep21.structure_table_length = cpu_to_le16(smbios_tables_len);
105386299120SWei Huang         ep.ep21.max_structure_size = cpu_to_le16(smbios_table_max);
105486299120SWei Huang         ep.ep21.number_of_structures = cpu_to_le16(smbios_table_cnt);
105560d8f328SWei Huang 
105686299120SWei Huang         /* BIOS must recalculate */
105786299120SWei Huang         ep.ep21.checksum = 0;
105886299120SWei Huang         ep.ep21.intermediate_checksum = 0;
105986299120SWei Huang         ep.ep21.structure_table_address = cpu_to_le32(0);
106086299120SWei Huang 
106186299120SWei Huang         break;
106210be11d0SEduardo Habkost     case SMBIOS_ENTRY_POINT_TYPE_64:
106386299120SWei Huang         memcpy(ep.ep30.anchor_string, "_SM3_", 5);
106486299120SWei Huang         ep.ep30.length = sizeof(struct smbios_30_entry_point);
106586299120SWei Huang         ep.ep30.entry_point_revision = 1;
106686299120SWei Huang         ep.ep30.reserved = 0;
106786299120SWei Huang 
106886299120SWei Huang         /* compliant with smbios spec 3.0 */
106986299120SWei Huang         ep.ep30.smbios_major_version = 3;
107086299120SWei Huang         ep.ep30.smbios_minor_version = 0;
107186299120SWei Huang         ep.ep30.smbios_doc_rev = 0;
107286299120SWei Huang 
107386299120SWei Huang         /* set during table construct, but BIOS might override */
107486299120SWei Huang         ep.ep30.structure_table_max_size = cpu_to_le32(smbios_tables_len);
107586299120SWei Huang 
107686299120SWei Huang         /* BIOS must recalculate */
107786299120SWei Huang         ep.ep30.checksum = 0;
107886299120SWei Huang         ep.ep30.structure_table_address = cpu_to_le64(0);
107986299120SWei Huang 
108086299120SWei Huang         break;
108186299120SWei Huang     default:
108286299120SWei Huang         abort();
108386299120SWei Huang         break;
108486299120SWei Huang     }
108560d8f328SWei Huang }
108660d8f328SWei 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)10874840c8a2SIgor Mammedov static bool smbios_get_tables_ep(MachineState *ms,
108869ea07a5SIgor Mammedov                        SmbiosEntryPointType ep_type,
1089a0628599SLike Xu                        const struct smbios_phys_mem_area *mem_array,
109060d8f328SWei Huang                        const unsigned int mem_array_size,
109160d8f328SWei Huang                        uint8_t **tables, size_t *tables_len,
109205dfb447SVincent Bernat                        uint8_t **anchor, size_t *anchor_len,
109305dfb447SVincent Bernat                        Error **errp)
109460d8f328SWei Huang {
1095a379d455SAni Sinha     unsigned i, dimm_cnt, offset;
1096*62f182c9SIgor Mammedov     MachineClass *mc = MACHINE_GET_CLASS(ms);
10974840c8a2SIgor Mammedov     ERRP_GUARD();
109860d8f328SWei Huang 
109969ea07a5SIgor Mammedov     assert(ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ||
110069ea07a5SIgor Mammedov            ep_type == SMBIOS_ENTRY_POINT_TYPE_64);
110169ea07a5SIgor Mammedov 
1102cba59fe3SIgor Mammedov     g_free(smbios_tables);
11036735a494SIgor Mammedov     smbios_type4_count = 0;
1104cba59fe3SIgor Mammedov     smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);
1105cba59fe3SIgor Mammedov     smbios_tables_len = usr_blobs_len;
1106cba59fe3SIgor Mammedov     smbios_table_max = usr_table_max;
1107cba59fe3SIgor Mammedov     smbios_table_cnt = usr_table_cnt;
1108b3854ce8SIgor Mammedov 
110960d8f328SWei Huang     smbios_build_type_0_table();
111060d8f328SWei Huang     smbios_build_type_1_table();
111160d8f328SWei Huang     smbios_build_type_2_table();
111260d8f328SWei Huang     smbios_build_type_3_table();
111360d8f328SWei Huang 
1114e94e0a83SIgor Mammedov     assert(ms->smp.sockets >= 1);
111560d8f328SWei Huang 
1116e94e0a83SIgor Mammedov     for (i = 0; i < ms->smp.sockets; i++) {
11175ed79482SIgor Mammedov         smbios_build_type_4_table(ms, i, ep_type, errp);
11185ed79482SIgor Mammedov         if (*errp) {
11195ed79482SIgor Mammedov             goto err_exit;
11205ed79482SIgor Mammedov         }
112160d8f328SWei Huang     }
112260d8f328SWei Huang 
1123fd8caa25SHal Martin     smbios_build_type_8_table();
112404f143d8SFelix Wu     smbios_build_type_9_table(errp);
11252d6dcbf9SDaniel P. Berrange     smbios_build_type_11_table();
11262d6dcbf9SDaniel P. Berrange 
1127*62f182c9SIgor Mammedov #define GET_DIMM_SZ ((i < dimm_cnt - 1) ? mc->smbios_memory_device_size \
1128*62f182c9SIgor Mammedov     : ((current_machine->ram_size - 1) % mc->smbios_memory_device_size) + 1)
112960d8f328SWei Huang 
1130*62f182c9SIgor Mammedov     dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size,
1131*62f182c9SIgor Mammedov                              mc->smbios_memory_device_size) /
1132*62f182c9SIgor Mammedov                mc->smbios_memory_device_size;
113360d8f328SWei Huang 
1134a379d455SAni Sinha     /*
11359b4b4e51SMichael Tokarev      * The offset determines if we need to keep additional space between
1136a379d455SAni Sinha      * table 17 and table 19 header handle numbers so that they do
1137a379d455SAni Sinha      * not overlap. For example, for a VM with larger than 8 TB guest
1138a379d455SAni Sinha      * memory and DIMM like chunks of 16 GiB, the default space between
1139a379d455SAni Sinha      * the two tables (T19_BASE - T17_BASE = 512) is not enough.
1140a379d455SAni Sinha      */
1141a379d455SAni Sinha     offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
1142a379d455SAni Sinha              dimm_cnt - (T19_BASE - T17_BASE) : 0;
1143a379d455SAni Sinha 
114460d8f328SWei Huang     smbios_build_type_16_table(dimm_cnt);
114560d8f328SWei Huang 
114660d8f328SWei Huang     for (i = 0; i < dimm_cnt; i++) {
114760d8f328SWei Huang         smbios_build_type_17_table(i, GET_DIMM_SZ);
114860d8f328SWei Huang     }
114960d8f328SWei Huang 
115060d8f328SWei Huang     for (i = 0; i < mem_array_size; i++) {
1151a379d455SAni Sinha         smbios_build_type_19_table(i, offset, mem_array[i].address,
115260d8f328SWei Huang                                    mem_array[i].length);
115360d8f328SWei Huang     }
115460d8f328SWei Huang 
115563670bd3SAni Sinha     /*
115663670bd3SAni Sinha      * make sure 16 bit handle numbers in the headers of tables 19
115763670bd3SAni Sinha      * and 32 do not overlap.
115863670bd3SAni Sinha      */
115963670bd3SAni Sinha     assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
116063670bd3SAni Sinha 
116160d8f328SWei Huang     smbios_build_type_32_table();
116235658f6eSCorey Minyard     smbios_build_type_38_table();
116305dfb447SVincent Bernat     smbios_build_type_41_table(errp);
116460d8f328SWei Huang     smbios_build_type_127_table();
116560d8f328SWei Huang 
1166643e1c9eSIgor Mammedov     if (!smbios_check_type4_count(ms->smp.sockets, errp)) {
1167643e1c9eSIgor Mammedov         goto err_exit;
1168643e1c9eSIgor Mammedov     }
116969ea07a5SIgor Mammedov     if (!smbios_validate_table(ep_type, errp)) {
1170643e1c9eSIgor Mammedov         goto err_exit;
1171643e1c9eSIgor Mammedov     }
117269ea07a5SIgor Mammedov     smbios_entry_point_setup(ep_type);
117360d8f328SWei Huang 
117460d8f328SWei Huang     /* return tables blob and entry point (anchor), and their sizes */
117560d8f328SWei Huang     *tables = smbios_tables;
117660d8f328SWei Huang     *tables_len = smbios_tables_len;
117760d8f328SWei Huang     *anchor = (uint8_t *)&ep;
117886299120SWei Huang     /* calculate length based on anchor string */
117986299120SWei Huang     if (!strncmp((char *)&ep, "_SM_", 4)) {
118086299120SWei Huang         *anchor_len = sizeof(struct smbios_21_entry_point);
118186299120SWei Huang     } else if (!strncmp((char *)&ep, "_SM3_", 5)) {
118286299120SWei Huang         *anchor_len = sizeof(struct smbios_30_entry_point);
118386299120SWei Huang     } else {
118486299120SWei Huang         abort();
118586299120SWei Huang     }
1186643e1c9eSIgor Mammedov 
11874840c8a2SIgor Mammedov     return true;
1188643e1c9eSIgor Mammedov err_exit:
1189643e1c9eSIgor Mammedov     g_free(smbios_tables);
1190643e1c9eSIgor Mammedov     smbios_tables = NULL;
11914840c8a2SIgor Mammedov     return false;
11924840c8a2SIgor Mammedov }
11934840c8a2SIgor 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)11944840c8a2SIgor Mammedov void smbios_get_tables(MachineState *ms,
11954840c8a2SIgor Mammedov                        SmbiosEntryPointType ep_type,
11964840c8a2SIgor Mammedov                        const struct smbios_phys_mem_area *mem_array,
11974840c8a2SIgor Mammedov                        const unsigned int mem_array_size,
11984840c8a2SIgor Mammedov                        uint8_t **tables, size_t *tables_len,
11994840c8a2SIgor Mammedov                        uint8_t **anchor, size_t *anchor_len,
12004840c8a2SIgor Mammedov                        Error **errp)
12014840c8a2SIgor Mammedov {
12024840c8a2SIgor Mammedov     Error *local_err = NULL;
12034840c8a2SIgor Mammedov     bool is_valid;
12044840c8a2SIgor Mammedov     ERRP_GUARD();
12054840c8a2SIgor Mammedov 
12064840c8a2SIgor Mammedov     switch (ep_type) {
12074840c8a2SIgor Mammedov     case SMBIOS_ENTRY_POINT_TYPE_AUTO:
12084840c8a2SIgor Mammedov     case SMBIOS_ENTRY_POINT_TYPE_32:
12094840c8a2SIgor Mammedov         is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_32,
12104840c8a2SIgor Mammedov                                         mem_array, mem_array_size,
12114840c8a2SIgor Mammedov                                         tables, tables_len,
12124840c8a2SIgor Mammedov                                         anchor, anchor_len,
12134840c8a2SIgor Mammedov                                         &local_err);
12144840c8a2SIgor Mammedov         if (is_valid || ep_type != SMBIOS_ENTRY_POINT_TYPE_AUTO) {
12154840c8a2SIgor Mammedov             break;
12164840c8a2SIgor Mammedov         }
12174840c8a2SIgor Mammedov         /*
12184840c8a2SIgor Mammedov          * fall through in case AUTO endpoint is selected and
12194840c8a2SIgor Mammedov          * SMBIOS 2.x tables can't be generated, to try if SMBIOS 3.x
12204840c8a2SIgor Mammedov          * tables would work
12214840c8a2SIgor Mammedov          */
12224840c8a2SIgor Mammedov     case SMBIOS_ENTRY_POINT_TYPE_64:
12234840c8a2SIgor Mammedov         error_free(local_err);
12244840c8a2SIgor Mammedov         local_err = NULL;
12254840c8a2SIgor Mammedov         is_valid = smbios_get_tables_ep(ms, SMBIOS_ENTRY_POINT_TYPE_64,
12264840c8a2SIgor Mammedov                                         mem_array, mem_array_size,
12274840c8a2SIgor Mammedov                                         tables, tables_len,
12284840c8a2SIgor Mammedov                                         anchor, anchor_len,
12294840c8a2SIgor Mammedov                                         &local_err);
12304840c8a2SIgor Mammedov         break;
12314840c8a2SIgor Mammedov     default:
12324840c8a2SIgor Mammedov         abort();
12334840c8a2SIgor Mammedov     }
12344840c8a2SIgor Mammedov     if (!is_valid) {
12354840c8a2SIgor Mammedov         error_propagate(errp, local_err);
12364840c8a2SIgor Mammedov     }
123760d8f328SWei Huang }
123860d8f328SWei Huang 
save_opt(const char ** dest,QemuOpts * opts,const char * name)123960d8f328SWei Huang static void save_opt(const char **dest, QemuOpts *opts, const char *name)
124060d8f328SWei Huang {
124160d8f328SWei Huang     const char *val = qemu_opt_get(opts, name);
124260d8f328SWei Huang 
124360d8f328SWei Huang     if (val) {
124460d8f328SWei Huang         *dest = val;
124560d8f328SWei Huang     }
124660d8f328SWei Huang }
124760d8f328SWei Huang 
12482d6dcbf9SDaniel P. Berrange 
12492d6dcbf9SDaniel P. Berrange struct opt_list {
12502d6dcbf9SDaniel P. Berrange     size_t *ndest;
1251bb99f477SDaniel P. Berrangé     char ***dest;
12522d6dcbf9SDaniel P. Berrange };
12532d6dcbf9SDaniel P. Berrange 
save_opt_one(void * opaque,const char * name,const char * value,Error ** errp)12542d6dcbf9SDaniel P. Berrange static int save_opt_one(void *opaque,
12552d6dcbf9SDaniel P. Berrange                         const char *name, const char *value,
12562d6dcbf9SDaniel P. Berrange                         Error **errp)
12572d6dcbf9SDaniel P. Berrange {
12582d6dcbf9SDaniel P. Berrange     struct opt_list *opt = opaque;
12592d6dcbf9SDaniel P. Berrange 
1260bb99f477SDaniel P. Berrangé     if (g_str_equal(name, "path")) {
1261bb99f477SDaniel P. Berrangé         g_autoptr(GByteArray) data = g_byte_array_new();
1262bb99f477SDaniel P. Berrangé         g_autofree char *buf = g_new(char, 4096);
1263bb99f477SDaniel P. Berrangé         ssize_t ret;
1264bb99f477SDaniel P. Berrangé         int fd = qemu_open(value, O_RDONLY, errp);
1265bb99f477SDaniel P. Berrangé         if (fd < 0) {
1266bb99f477SDaniel P. Berrangé             return -1;
12672d6dcbf9SDaniel P. Berrange         }
12682d6dcbf9SDaniel P. Berrange 
1269bb99f477SDaniel P. Berrangé         while (1) {
1270bb99f477SDaniel P. Berrangé             ret = read(fd, buf, 4096);
1271bb99f477SDaniel P. Berrangé             if (ret == 0) {
1272bb99f477SDaniel P. Berrangé                 break;
1273bb99f477SDaniel P. Berrangé             }
1274bb99f477SDaniel P. Berrangé             if (ret < 0) {
1275bb99f477SDaniel P. Berrangé                 error_setg(errp, "Unable to read from %s: %s",
1276bb99f477SDaniel P. Berrangé                            value, strerror(errno));
12778055d2fbSPhilippe Mathieu-Daudé                 qemu_close(fd);
1278bb99f477SDaniel P. Berrangé                 return -1;
1279bb99f477SDaniel P. Berrangé             }
1280bb99f477SDaniel P. Berrangé             if (memchr(buf, '\0', ret)) {
1281bb99f477SDaniel P. Berrangé                 error_setg(errp, "NUL in OEM strings value in %s", value);
12828055d2fbSPhilippe Mathieu-Daudé                 qemu_close(fd);
1283bb99f477SDaniel P. Berrangé                 return -1;
1284bb99f477SDaniel P. Berrangé             }
1285bb99f477SDaniel P. Berrangé             g_byte_array_append(data, (guint8 *)buf, ret);
1286bb99f477SDaniel P. Berrangé         }
1287bb99f477SDaniel P. Berrangé 
12888055d2fbSPhilippe Mathieu-Daudé         qemu_close(fd);
1289bb99f477SDaniel P. Berrangé 
1290bb99f477SDaniel P. Berrangé         *opt->dest = g_renew(char *, *opt->dest, (*opt->ndest) + 1);
1291bb99f477SDaniel P. Berrangé         (*opt->dest)[*opt->ndest] = (char *)g_byte_array_free(data,  FALSE);
12922d6dcbf9SDaniel P. Berrange         (*opt->ndest)++;
1293bb99f477SDaniel P. Berrangé         data = NULL;
1294bb99f477SDaniel P. Berrangé    } else if (g_str_equal(name, "value")) {
1295bb99f477SDaniel P. Berrangé         *opt->dest = g_renew(char *, *opt->dest, (*opt->ndest) + 1);
1296bb99f477SDaniel P. Berrangé         (*opt->dest)[*opt->ndest] = g_strdup(value);
1297bb99f477SDaniel P. Berrangé         (*opt->ndest)++;
1298bb99f477SDaniel P. Berrangé     } else if (!g_str_equal(name, "type")) {
1299bb99f477SDaniel P. Berrangé         error_setg(errp, "Unexpected option %s", name);
1300bb99f477SDaniel P. Berrangé         return -1;
1301bb99f477SDaniel P. Berrangé     }
1302bb99f477SDaniel P. Berrangé 
13032d6dcbf9SDaniel P. Berrange     return 0;
13042d6dcbf9SDaniel P. Berrange }
13052d6dcbf9SDaniel P. Berrange 
save_opt_list(size_t * ndest,char *** dest,QemuOpts * opts,Error ** errp)1306bb99f477SDaniel P. Berrangé static bool save_opt_list(size_t *ndest, char ***dest, QemuOpts *opts,
1307bb99f477SDaniel P. Berrangé                           Error **errp)
13082d6dcbf9SDaniel P. Berrange {
13092d6dcbf9SDaniel P. Berrange     struct opt_list opt = {
1310bb99f477SDaniel P. Berrangé         ndest, dest,
13112d6dcbf9SDaniel P. Berrange     };
1312bb99f477SDaniel P. Berrangé     if (!qemu_opt_foreach(opts, save_opt_one, &opt, errp)) {
1313bb99f477SDaniel P. Berrangé         return false;
1314bb99f477SDaniel P. Berrangé     }
1315bb99f477SDaniel P. Berrangé     return true;
13162d6dcbf9SDaniel P. Berrange }
13172d6dcbf9SDaniel P. Berrange 
smbios_entry_add(QemuOpts * opts,Error ** errp)13181007a37eSLeif Lindholm void smbios_entry_add(QemuOpts *opts, Error **errp)
131960d8f328SWei Huang {
132060d8f328SWei Huang     const char *val;
132160d8f328SWei Huang 
132260d8f328SWei Huang     val = qemu_opt_get(opts, "file");
132360d8f328SWei Huang     if (val) {
132460d8f328SWei Huang         struct smbios_structure_header *header;
1325cba59fe3SIgor Mammedov         size_t size;
132660d8f328SWei Huang 
1327668f62ecSMarkus Armbruster         if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) {
13281028283cSMarkus Armbruster             return;
13291028283cSMarkus Armbruster         }
133060d8f328SWei Huang 
133160d8f328SWei Huang         size = get_image_size(val);
133260d8f328SWei Huang         if (size == -1 || size < sizeof(struct smbios_structure_header)) {
13331028283cSMarkus Armbruster             error_setg(errp, "Cannot read SMBIOS file %s", val);
13341028283cSMarkus Armbruster             return;
133560d8f328SWei Huang         }
133660d8f328SWei Huang 
133760d8f328SWei Huang         /*
133860d8f328SWei Huang          * NOTE: standard double '\0' terminator expected, per smbios spec.
133960d8f328SWei Huang          * (except in legacy mode, where the second '\0' is implicit and
134060d8f328SWei Huang          *  will be inserted by the BIOS).
134160d8f328SWei Huang          */
1342cba59fe3SIgor Mammedov         usr_blobs = g_realloc(usr_blobs, usr_blobs_len + size);
1343cba59fe3SIgor Mammedov         header = (struct smbios_structure_header *)(usr_blobs +
1344cba59fe3SIgor Mammedov                                                     usr_blobs_len);
134560d8f328SWei Huang 
1346b7abb791SPeter Maydell         if (load_image_size(val, (uint8_t *)header, size) != size) {
13471028283cSMarkus Armbruster             error_setg(errp, "Failed to load SMBIOS file %s", val);
13481028283cSMarkus Armbruster             return;
134960d8f328SWei Huang         }
135060d8f328SWei Huang 
135157e30696SPaolo Bonzini         if (header->type <= SMBIOS_MAX_TYPE) {
1352d638a865SIgor Mammedov             if (test_bit(header->type, smbios_have_fields_bitmap)) {
13531028283cSMarkus Armbruster                 error_setg(errp,
13541028283cSMarkus Armbruster                            "can't load type %d struct, fields already specified!",
135560d8f328SWei Huang                            header->type);
13561028283cSMarkus Armbruster                 return;
135760d8f328SWei Huang             }
1358d638a865SIgor Mammedov             set_bit(header->type, smbios_have_binfile_bitmap);
135957e30696SPaolo Bonzini         }
136060d8f328SWei Huang 
136160d8f328SWei Huang         if (header->type == 4) {
136260d8f328SWei Huang             smbios_type4_count++;
136360d8f328SWei Huang         }
136460d8f328SWei Huang 
1365684b49fdSIgor Mammedov         /*
1366684b49fdSIgor Mammedov          * preserve blob size for legacy mode so it could build its
1367684b49fdSIgor Mammedov          * blobs flavor from 'usr_blobs'
1368684b49fdSIgor Mammedov          */
1369684b49fdSIgor Mammedov         smbios_add_usr_blob_size(size);
1370684b49fdSIgor Mammedov 
1371cba59fe3SIgor Mammedov         usr_blobs_len += size;
1372cba59fe3SIgor Mammedov         if (size > usr_table_max) {
1373cba59fe3SIgor Mammedov             usr_table_max = size;
137460d8f328SWei Huang         }
1375cba59fe3SIgor Mammedov         usr_table_cnt++;
137660d8f328SWei Huang 
137760d8f328SWei Huang         return;
137860d8f328SWei Huang     }
137960d8f328SWei Huang 
138060d8f328SWei Huang     val = qemu_opt_get(opts, "type");
138160d8f328SWei Huang     if (val) {
138260d8f328SWei Huang         unsigned long type = strtoul(val, NULL, 0);
138360d8f328SWei Huang 
138460d8f328SWei Huang         if (type > SMBIOS_MAX_TYPE) {
13851028283cSMarkus Armbruster             error_setg(errp, "out of range!");
13861028283cSMarkus Armbruster             return;
138760d8f328SWei Huang         }
138860d8f328SWei Huang 
1389d638a865SIgor Mammedov         if (test_bit(type, smbios_have_binfile_bitmap)) {
13901028283cSMarkus Armbruster             error_setg(errp, "can't add fields, binary file already loaded!");
13911028283cSMarkus Armbruster             return;
139260d8f328SWei Huang         }
1393d638a865SIgor Mammedov         set_bit(type, smbios_have_fields_bitmap);
139460d8f328SWei Huang 
139560d8f328SWei Huang         switch (type) {
139660d8f328SWei Huang         case 0:
1397668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type0_opts, errp)) {
13981028283cSMarkus Armbruster                 return;
13991028283cSMarkus Armbruster             }
1400d638a865SIgor Mammedov             save_opt(&smbios_type0.vendor, opts, "vendor");
1401d638a865SIgor Mammedov             save_opt(&smbios_type0.version, opts, "version");
1402d638a865SIgor Mammedov             save_opt(&smbios_type0.date, opts, "date");
1403d638a865SIgor Mammedov             smbios_type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
140460d8f328SWei Huang 
140560d8f328SWei Huang             val = qemu_opt_get(opts, "release");
140660d8f328SWei Huang             if (val) {
1407d638a865SIgor Mammedov                 if (sscanf(val, "%hhu.%hhu", &smbios_type0.major,
1408d638a865SIgor Mammedov                            &smbios_type0.minor) != 2) {
14091028283cSMarkus Armbruster                     error_setg(errp, "Invalid release");
14101028283cSMarkus Armbruster                     return;
141160d8f328SWei Huang                 }
1412d638a865SIgor Mammedov                 smbios_type0.have_major_minor = true;
141360d8f328SWei Huang             }
141460d8f328SWei Huang             return;
141560d8f328SWei Huang         case 1:
1416668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type1_opts, errp)) {
14171028283cSMarkus Armbruster                 return;
14181028283cSMarkus Armbruster             }
1419d638a865SIgor Mammedov             save_opt(&smbios_type1.manufacturer, opts, "manufacturer");
1420d638a865SIgor Mammedov             save_opt(&smbios_type1.product, opts, "product");
1421d638a865SIgor Mammedov             save_opt(&smbios_type1.version, opts, "version");
1422d638a865SIgor Mammedov             save_opt(&smbios_type1.serial, opts, "serial");
1423d638a865SIgor Mammedov             save_opt(&smbios_type1.sku, opts, "sku");
1424d638a865SIgor Mammedov             save_opt(&smbios_type1.family, opts, "family");
142560d8f328SWei Huang 
142660d8f328SWei Huang             val = qemu_opt_get(opts, "uuid");
142760d8f328SWei Huang             if (val) {
14289c5ce8dbSFam Zheng                 if (qemu_uuid_parse(val, &qemu_uuid) != 0) {
14291028283cSMarkus Armbruster                     error_setg(errp, "Invalid UUID");
14301028283cSMarkus Armbruster                     return;
143160d8f328SWei Huang                 }
143260d8f328SWei Huang                 qemu_uuid_set = true;
143360d8f328SWei Huang             }
143460d8f328SWei Huang             return;
143560d8f328SWei Huang         case 2:
1436668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type2_opts, errp)) {
14371028283cSMarkus Armbruster                 return;
14381028283cSMarkus Armbruster             }
143960d8f328SWei Huang             save_opt(&type2.manufacturer, opts, "manufacturer");
144060d8f328SWei Huang             save_opt(&type2.product, opts, "product");
144160d8f328SWei Huang             save_opt(&type2.version, opts, "version");
144260d8f328SWei Huang             save_opt(&type2.serial, opts, "serial");
144360d8f328SWei Huang             save_opt(&type2.asset, opts, "asset");
144460d8f328SWei Huang             save_opt(&type2.location, opts, "location");
144560d8f328SWei Huang             return;
144660d8f328SWei Huang         case 3:
1447668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type3_opts, errp)) {
14481028283cSMarkus Armbruster                 return;
14491028283cSMarkus Armbruster             }
145060d8f328SWei Huang             save_opt(&type3.manufacturer, opts, "manufacturer");
145160d8f328SWei Huang             save_opt(&type3.version, opts, "version");
145260d8f328SWei Huang             save_opt(&type3.serial, opts, "serial");
145360d8f328SWei Huang             save_opt(&type3.asset, opts, "asset");
145460d8f328SWei Huang             save_opt(&type3.sku, opts, "sku");
145560d8f328SWei Huang             return;
145660d8f328SWei Huang         case 4:
1457668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type4_opts, errp)) {
14581028283cSMarkus Armbruster                 return;
14591028283cSMarkus Armbruster             }
146060d8f328SWei Huang             save_opt(&type4.sock_pfx, opts, "sock_pfx");
1461b5831d79SHeinrich Schuchardt             type4.processor_family = qemu_opt_get_number(opts,
1462b5831d79SHeinrich Schuchardt                                                          "processor-family",
1463b5831d79SHeinrich Schuchardt                                                          0x01 /* Other */);
146460d8f328SWei Huang             save_opt(&type4.manufacturer, opts, "manufacturer");
146560d8f328SWei Huang             save_opt(&type4.version, opts, "version");
146660d8f328SWei Huang             save_opt(&type4.serial, opts, "serial");
146760d8f328SWei Huang             save_opt(&type4.asset, opts, "asset");
146860d8f328SWei Huang             save_opt(&type4.part, opts, "part");
1469cb5fb04fSPatrick Venture             /* If the value is 0, it will take the value from the CPU model. */
1470cb5fb04fSPatrick Venture             type4.processor_id = qemu_opt_get_number(opts, "processor-id", 0);
1471c906e039SYing Fang             type4.max_speed = qemu_opt_get_number(opts, "max-speed",
1472c906e039SYing Fang                                                   DEFAULT_CPU_SPEED);
1473c906e039SYing Fang             type4.current_speed = qemu_opt_get_number(opts, "current-speed",
1474c906e039SYing Fang                                                       DEFAULT_CPU_SPEED);
1475c906e039SYing Fang             if (type4.max_speed > UINT16_MAX ||
1476c906e039SYing Fang                 type4.current_speed > UINT16_MAX) {
1477c906e039SYing Fang                 error_setg(errp, "SMBIOS CPU speed is too large (> %d)",
1478c906e039SYing Fang                            UINT16_MAX);
1479c906e039SYing Fang             }
148060d8f328SWei Huang             return;
1481fd8caa25SHal Martin         case 8:
1482fd8caa25SHal Martin             if (!qemu_opts_validate(opts, qemu_smbios_type8_opts, errp)) {
1483fd8caa25SHal Martin                 return;
1484fd8caa25SHal Martin             }
14857b393b71SAni Sinha             struct type8_instance *t8_i;
14867b393b71SAni Sinha             t8_i = g_new0(struct type8_instance, 1);
14877b393b71SAni Sinha             save_opt(&t8_i->internal_reference, opts, "internal_reference");
14887b393b71SAni Sinha             save_opt(&t8_i->external_reference, opts, "external_reference");
14897b393b71SAni Sinha             t8_i->connector_type = qemu_opt_get_number(opts,
14907b393b71SAni Sinha                                                        "connector_type", 0);
14917b393b71SAni Sinha             t8_i->port_type = qemu_opt_get_number(opts, "port_type", 0);
14927b393b71SAni Sinha             QTAILQ_INSERT_TAIL(&type8, t8_i, next);
1493fd8caa25SHal Martin             return;
1494735eee07SFelix Wu         case 9: {
1495735eee07SFelix Wu             if (!qemu_opts_validate(opts, qemu_smbios_type9_opts, errp)) {
1496735eee07SFelix Wu                 return;
1497735eee07SFelix Wu             }
1498735eee07SFelix Wu             struct type9_instance *t;
1499735eee07SFelix Wu             t = g_new0(struct type9_instance, 1);
1500735eee07SFelix Wu             save_opt(&t->slot_designation, opts, "slot_designation");
1501735eee07SFelix Wu             t->slot_type = qemu_opt_get_number(opts, "slot_type", 0);
1502fdf1c980SMichael S. Tsirkin             t->slot_data_bus_width =
1503fdf1c980SMichael S. Tsirkin                 qemu_opt_get_number(opts, "slot_data_bus_width", 0);
1504735eee07SFelix Wu             t->current_usage = qemu_opt_get_number(opts, "current_usage", 0);
1505735eee07SFelix Wu             t->slot_length = qemu_opt_get_number(opts, "slot_length", 0);
1506735eee07SFelix Wu             t->slot_id = qemu_opt_get_number(opts, "slot_id", 0);
1507fdf1c980SMichael S. Tsirkin             t->slot_characteristics1 =
1508fdf1c980SMichael S. Tsirkin                 qemu_opt_get_number(opts, "slot_characteristics1", 0);
1509fdf1c980SMichael S. Tsirkin             t->slot_characteristics2 =
1510fdf1c980SMichael S. Tsirkin                 qemu_opt_get_number(opts, "slot_characteristics2", 0);
151104f143d8SFelix Wu             save_opt(&t->pcidev, opts, "pcidev");
1512735eee07SFelix Wu             QTAILQ_INSERT_TAIL(&type9, t, next);
1513735eee07SFelix Wu             return;
1514735eee07SFelix Wu         }
15152d6dcbf9SDaniel P. Berrange         case 11:
1516668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) {
15171028283cSMarkus Armbruster                 return;
15181028283cSMarkus Armbruster             }
1519bb99f477SDaniel P. Berrangé             if (!save_opt_list(&type11.nvalues, &type11.values, opts, errp)) {
1520bb99f477SDaniel P. Berrangé                 return;
1521bb99f477SDaniel P. Berrangé             }
15222d6dcbf9SDaniel P. Berrange             return;
152360d8f328SWei Huang         case 17:
1524668f62ecSMarkus Armbruster             if (!qemu_opts_validate(opts, qemu_smbios_type17_opts, errp)) {
15251028283cSMarkus Armbruster                 return;
15261028283cSMarkus Armbruster             }
152760d8f328SWei Huang             save_opt(&type17.loc_pfx, opts, "loc_pfx");
152860d8f328SWei Huang             save_opt(&type17.bank, opts, "bank");
152960d8f328SWei Huang             save_opt(&type17.manufacturer, opts, "manufacturer");
153060d8f328SWei Huang             save_opt(&type17.serial, opts, "serial");
153160d8f328SWei Huang             save_opt(&type17.asset, opts, "asset");
153260d8f328SWei Huang             save_opt(&type17.part, opts, "part");
153360d8f328SWei Huang             type17.speed = qemu_opt_get_number(opts, "speed", 0);
153460d8f328SWei Huang             return;
153505dfb447SVincent Bernat         case 41: {
15367b393b71SAni Sinha             struct type41_instance *t41_i;
153705dfb447SVincent Bernat             Error *local_err = NULL;
153805dfb447SVincent Bernat 
153905dfb447SVincent Bernat             if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) {
154005dfb447SVincent Bernat                 return;
154105dfb447SVincent Bernat             }
15427b393b71SAni Sinha             t41_i = g_new0(struct type41_instance, 1);
15437b393b71SAni Sinha             save_opt(&t41_i->designation, opts, "designation");
15447b393b71SAni Sinha             t41_i->kind = qapi_enum_parse(&type41_kind_lookup,
154505dfb447SVincent Bernat                                           qemu_opt_get(opts, "kind"),
154605dfb447SVincent Bernat                                           0, &local_err) + 1;
15477b393b71SAni Sinha             t41_i->kind |= 0x80;     /* enabled */
154805dfb447SVincent Bernat             if (local_err != NULL) {
154905dfb447SVincent Bernat                 error_propagate(errp, local_err);
15507b393b71SAni Sinha                 g_free(t41_i);
155105dfb447SVincent Bernat                 return;
155205dfb447SVincent Bernat             }
15537b393b71SAni Sinha             t41_i->instance = qemu_opt_get_number(opts, "instance", 1);
15547b393b71SAni Sinha             save_opt(&t41_i->pcidev, opts, "pcidev");
155505dfb447SVincent Bernat 
15567b393b71SAni Sinha             QTAILQ_INSERT_TAIL(&type41, t41_i, next);
155705dfb447SVincent Bernat             return;
155805dfb447SVincent Bernat         }
155960d8f328SWei Huang         default:
15601028283cSMarkus Armbruster             error_setg(errp,
15611028283cSMarkus Armbruster                        "Don't know how to build fields for SMBIOS type %ld",
156260d8f328SWei Huang                        type);
15631028283cSMarkus Armbruster             return;
156460d8f328SWei Huang         }
156560d8f328SWei Huang     }
156660d8f328SWei Huang 
15671028283cSMarkus Armbruster     error_setg(errp, "Must specify type= or file=");
156860d8f328SWei Huang }
1569