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