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