]> git.proxmox.com Git - mirror_qemu.git/blame - hw/i386/smbios.c
bios-linker-loader: move source to common location
[mirror_qemu.git] / hw / i386 / smbios.c
CommitLineData
b6f6e3d3
AL
1/*
2 * SMBIOS Support
3 *
4 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
4f953d2f 5 * Copyright (C) 2013 Red Hat, Inc.
b6f6e3d3
AL
6 *
7 * Authors:
8 * Alex Williamson <alex.williamson@hp.com>
4f953d2f 9 * Markus Armbruster <armbru@redhat.com>
b6f6e3d3
AL
10 *
11 * This work is licensed under the terms of the GNU GPL, version 2. See
12 * the COPYING file in the top-level directory.
13 *
6b620ca3
PB
14 * Contributions after 2012-01-13 are licensed under the terms of the
15 * GNU GPL, version 2 or (at your option) any later version.
b6f6e3d3
AL
16 */
17
4f953d2f 18#include "qemu/config-file.h"
5bb95e41 19#include "qemu/error-report.h"
9c17d615 20#include "sysemu/sysemu.h"
c97294ec
GS
21#include "sysemu/cpus.h"
22#include "hw/i386/pc.h"
0d09e41a 23#include "hw/i386/smbios.h"
83c9f4ca 24#include "hw/loader.h"
b6f6e3d3 25
e6667f71
GS
26
27/* legacy structures and constants for <= 2.0 machines */
b6f6e3d3
AL
28struct smbios_header {
29 uint16_t length;
30 uint8_t type;
541dc0d4 31} QEMU_PACKED;
b6f6e3d3
AL
32
33struct smbios_field {
34 struct smbios_header header;
35 uint8_t type;
36 uint16_t offset;
37 uint8_t data[];
541dc0d4 38} QEMU_PACKED;
b6f6e3d3
AL
39
40struct smbios_table {
41 struct smbios_header header;
42 uint8_t data[];
541dc0d4 43} QEMU_PACKED;
b6f6e3d3
AL
44
45#define SMBIOS_FIELD_ENTRY 0
46#define SMBIOS_TABLE_ENTRY 1
47
b6f6e3d3
AL
48static uint8_t *smbios_entries;
49static size_t smbios_entries_len;
c97294ec 50static bool smbios_legacy = true;
caad057b 51static bool smbios_uuid_encoded = true;
e6667f71
GS
52/* end: legacy structures & constants for <= 2.0 machines */
53
54
c97294ec
GS
55static uint8_t *smbios_tables;
56static size_t smbios_tables_len;
57static unsigned smbios_table_max;
58static unsigned smbios_table_cnt;
59static struct smbios_entry_point ep;
60
09c0848e 61static int smbios_type4_count = 0;
fc3b3295 62static bool smbios_immutable;
c97294ec
GS
63static bool smbios_have_defaults;
64static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
09c0848e 65
2e6e8d7a
GS
66static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
67static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
ec2df8c1 68
fc3b3295
MA
69static struct {
70 const char *vendor, *version, *date;
84351843 71 bool have_major_minor, uefi;
fc3b3295
MA
72 uint8_t major, minor;
73} type0;
74
75static struct {
76 const char *manufacturer, *product, *version, *serial, *sku, *family;
77 /* uuid is in qemu_uuid[] */
78} type1;
79
c97294ec
GS
80static struct {
81 const char *manufacturer, *product, *version, *serial, *asset, *location;
82} type2;
83
84static struct {
85 const char *manufacturer, *version, *serial, *asset, *sku;
86} type3;
87
88static struct {
89 const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
90} type4;
91
92static struct {
93 const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
94} type17;
95
4f953d2f
MA
96static QemuOptsList qemu_smbios_opts = {
97 .name = "smbios",
98 .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
99 .desc = {
100 /*
101 * no elements => accept any params
102 * validation will happen later
103 */
104 { /* end of list */ }
105 }
106};
107
108static const QemuOptDesc qemu_smbios_file_opts[] = {
109 {
110 .name = "file",
111 .type = QEMU_OPT_STRING,
112 .help = "binary file containing an SMBIOS element",
113 },
114 { /* end of list */ }
115};
116
117static const QemuOptDesc qemu_smbios_type0_opts[] = {
118 {
119 .name = "type",
120 .type = QEMU_OPT_NUMBER,
121 .help = "SMBIOS element type",
122 },{
123 .name = "vendor",
124 .type = QEMU_OPT_STRING,
125 .help = "vendor name",
126 },{
127 .name = "version",
128 .type = QEMU_OPT_STRING,
129 .help = "version number",
130 },{
131 .name = "date",
132 .type = QEMU_OPT_STRING,
133 .help = "release date",
134 },{
135 .name = "release",
136 .type = QEMU_OPT_STRING,
137 .help = "revision number",
84351843
GS
138 },{
139 .name = "uefi",
140 .type = QEMU_OPT_BOOL,
141 .help = "uefi support",
4f953d2f
MA
142 },
143 { /* end of list */ }
144};
145
146static const QemuOptDesc qemu_smbios_type1_opts[] = {
147 {
148 .name = "type",
149 .type = QEMU_OPT_NUMBER,
150 .help = "SMBIOS element type",
151 },{
152 .name = "manufacturer",
153 .type = QEMU_OPT_STRING,
154 .help = "manufacturer name",
155 },{
156 .name = "product",
157 .type = QEMU_OPT_STRING,
158 .help = "product name",
159 },{
160 .name = "version",
161 .type = QEMU_OPT_STRING,
162 .help = "version number",
163 },{
164 .name = "serial",
165 .type = QEMU_OPT_STRING,
166 .help = "serial number",
167 },{
168 .name = "uuid",
169 .type = QEMU_OPT_STRING,
170 .help = "UUID",
171 },{
172 .name = "sku",
173 .type = QEMU_OPT_STRING,
174 .help = "SKU number",
175 },{
176 .name = "family",
177 .type = QEMU_OPT_STRING,
178 .help = "family name",
179 },
180 { /* end of list */ }
181};
182
c97294ec
GS
183static const QemuOptDesc qemu_smbios_type2_opts[] = {
184 {
185 .name = "type",
186 .type = QEMU_OPT_NUMBER,
187 .help = "SMBIOS element type",
188 },{
189 .name = "manufacturer",
190 .type = QEMU_OPT_STRING,
191 .help = "manufacturer name",
192 },{
193 .name = "product",
194 .type = QEMU_OPT_STRING,
195 .help = "product name",
196 },{
197 .name = "version",
198 .type = QEMU_OPT_STRING,
199 .help = "version number",
200 },{
201 .name = "serial",
202 .type = QEMU_OPT_STRING,
203 .help = "serial number",
204 },{
205 .name = "asset",
206 .type = QEMU_OPT_STRING,
207 .help = "asset tag number",
208 },{
209 .name = "location",
210 .type = QEMU_OPT_STRING,
211 .help = "location in chassis",
212 },
213 { /* end of list */ }
214};
215
216static const QemuOptDesc qemu_smbios_type3_opts[] = {
217 {
218 .name = "type",
219 .type = QEMU_OPT_NUMBER,
220 .help = "SMBIOS element type",
221 },{
222 .name = "manufacturer",
223 .type = QEMU_OPT_STRING,
224 .help = "manufacturer name",
225 },{
226 .name = "version",
227 .type = QEMU_OPT_STRING,
228 .help = "version number",
229 },{
230 .name = "serial",
231 .type = QEMU_OPT_STRING,
232 .help = "serial number",
233 },{
234 .name = "asset",
235 .type = QEMU_OPT_STRING,
236 .help = "asset tag number",
237 },{
238 .name = "sku",
239 .type = QEMU_OPT_STRING,
240 .help = "SKU number",
241 },
242 { /* end of list */ }
243};
244
245static const QemuOptDesc qemu_smbios_type4_opts[] = {
246 {
247 .name = "type",
248 .type = QEMU_OPT_NUMBER,
249 .help = "SMBIOS element type",
250 },{
251 .name = "sock_pfx",
252 .type = QEMU_OPT_STRING,
253 .help = "socket designation string prefix",
254 },{
255 .name = "manufacturer",
256 .type = QEMU_OPT_STRING,
257 .help = "manufacturer name",
258 },{
259 .name = "version",
260 .type = QEMU_OPT_STRING,
261 .help = "version number",
262 },{
263 .name = "serial",
264 .type = QEMU_OPT_STRING,
265 .help = "serial number",
266 },{
267 .name = "asset",
268 .type = QEMU_OPT_STRING,
269 .help = "asset tag number",
270 },{
271 .name = "part",
272 .type = QEMU_OPT_STRING,
273 .help = "part number",
274 },
275 { /* end of list */ }
276};
277
278static const QemuOptDesc qemu_smbios_type17_opts[] = {
279 {
280 .name = "type",
281 .type = QEMU_OPT_NUMBER,
282 .help = "SMBIOS element type",
283 },{
284 .name = "loc_pfx",
285 .type = QEMU_OPT_STRING,
286 .help = "device locator string prefix",
287 },{
288 .name = "bank",
289 .type = QEMU_OPT_STRING,
290 .help = "bank locator string",
291 },{
292 .name = "manufacturer",
293 .type = QEMU_OPT_STRING,
294 .help = "manufacturer name",
295 },{
296 .name = "serial",
297 .type = QEMU_OPT_STRING,
298 .help = "serial number",
299 },{
300 .name = "asset",
301 .type = QEMU_OPT_STRING,
302 .help = "asset tag number",
303 },{
304 .name = "part",
305 .type = QEMU_OPT_STRING,
306 .help = "part number",
307 },
308 { /* end of list */ }
309};
310
4f953d2f
MA
311static void smbios_register_config(void)
312{
313 qemu_add_opts(&qemu_smbios_opts);
314}
315
316machine_init(smbios_register_config);
317
09c0848e
BK
318static void smbios_validate_table(void)
319{
c97294ec
GS
320 uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
321
322 if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
323 error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
324 expect_t4_count, smbios_type4_count);
09c0848e
BK
325 exit(1);
326 }
327}
b6f6e3d3 328
e6667f71
GS
329
330/* legacy setup functions for <= 2.0 machines */
fc3b3295 331static void smbios_add_field(int type, int offset, const void *data, size_t len)
b6f6e3d3
AL
332{
333 struct smbios_field *field;
334
b6f6e3d3
AL
335 if (!smbios_entries) {
336 smbios_entries_len = sizeof(uint16_t);
7267c094 337 smbios_entries = g_malloc0(smbios_entries_len);
b6f6e3d3 338 }
7267c094 339 smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
b6f6e3d3
AL
340 sizeof(*field) + len);
341 field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
342 field->header.type = SMBIOS_FIELD_ENTRY;
343 field->header.length = cpu_to_le16(sizeof(*field) + len);
344
345 field->type = type;
346 field->offset = cpu_to_le16(offset);
347 memcpy(field->data, data, len);
348
349 smbios_entries_len += sizeof(*field) + len;
350 (*(uint16_t *)smbios_entries) =
351 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
352}
353
e26d3e73 354static void smbios_maybe_add_str(int type, int offset, const char *data)
b6f6e3d3 355{
e26d3e73
MA
356 if (data) {
357 smbios_add_field(type, offset, data, strlen(data) + 1);
4f953d2f 358 }
e26d3e73
MA
359}
360
361static void smbios_build_type_0_fields(void)
362{
363 smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
364 type0.vendor);
365 smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
366 type0.version);
367 smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
b6f6e3d3 368 bios_release_date_str),
e26d3e73 369 type0.date);
fc3b3295 370 if (type0.have_major_minor) {
b6f6e3d3 371 smbios_add_field(0, offsetof(struct smbios_type_0,
ebc85e3f 372 system_bios_major_release),
fc3b3295 373 &type0.major, 1);
b6f6e3d3 374 smbios_add_field(0, offsetof(struct smbios_type_0,
ebc85e3f 375 system_bios_minor_release),
fc3b3295 376 &type0.minor, 1);
b6f6e3d3
AL
377 }
378}
379
fc3b3295 380static void smbios_build_type_1_fields(void)
b6f6e3d3 381{
e26d3e73
MA
382 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
383 type1.manufacturer);
384 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
385 type1.product);
386 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
387 type1.version);
388 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
389 type1.serial);
390 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
391 type1.sku);
392 smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
393 type1.family);
fc3b3295 394 if (qemu_uuid_set) {
caad057b
EH
395 /* We don't encode the UUID in the "wire format" here because this
396 * function is for legacy mode and needs to keep the guest ABI, and
397 * because we don't know what's the SMBIOS version advertised by the
398 * BIOS.
399 */
fc3b3295
MA
400 smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
401 qemu_uuid, 16);
402 }
403}
404
e6667f71 405uint8_t *smbios_get_table_legacy(size_t *length)
fc3b3295 406{
c97294ec
GS
407 if (!smbios_legacy) {
408 *length = 0;
409 return NULL;
410 }
411
fc3b3295
MA
412 if (!smbios_immutable) {
413 smbios_build_type_0_fields();
414 smbios_build_type_1_fields();
415 smbios_validate_table();
416 smbios_immutable = true;
417 }
418 *length = smbios_entries_len;
419 return smbios_entries;
420}
e6667f71
GS
421/* end: legacy setup functions for <= 2.0 machines */
422
fc3b3295 423
c97294ec
GS
424static bool smbios_skip_table(uint8_t type, bool required_table)
425{
426 if (test_bit(type, have_binfile_bitmap)) {
427 return true; /* user provided their own binary blob(s) */
428 }
429 if (test_bit(type, have_fields_bitmap)) {
430 return false; /* user provided fields via command line */
431 }
432 if (smbios_have_defaults && required_table) {
433 return false; /* we're building tables, and this one's required */
434 }
435 return true;
436}
437
438#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \
439 struct smbios_type_##tbl_type *t; \
440 size_t t_off; /* table offset into smbios_tables */ \
441 int str_index = 0; \
442 do { \
443 /* should we skip building this table ? */ \
444 if (smbios_skip_table(tbl_type, tbl_required)) { \
445 return; \
446 } \
447 \
448 /* use offset of table t within smbios_tables */ \
449 /* (pointer must be updated after each realloc) */ \
450 t_off = smbios_tables_len; \
451 smbios_tables_len += sizeof(*t); \
452 smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \
453 t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
454 \
455 t->header.type = tbl_type; \
456 t->header.length = sizeof(*t); \
fb5be2e8 457 t->header.handle = cpu_to_le16(tbl_handle); \
c97294ec
GS
458 } while (0)
459
460#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \
461 do { \
462 int len = (value != NULL) ? strlen(value) + 1 : 0; \
463 if (len > 1) { \
464 smbios_tables = g_realloc(smbios_tables, \
465 smbios_tables_len + len); \
466 memcpy(smbios_tables + smbios_tables_len, value, len); \
467 smbios_tables_len += len; \
468 /* update pointer post-realloc */ \
469 t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
470 t->field = ++str_index; \
471 } else { \
472 t->field = 0; \
473 } \
474 } while (0)
475
476#define SMBIOS_BUILD_TABLE_POST \
477 do { \
478 size_t term_cnt, t_size; \
479 \
480 /* add '\0' terminator (add two if no strings defined) */ \
481 term_cnt = (str_index == 0) ? 2 : 1; \
482 smbios_tables = g_realloc(smbios_tables, \
483 smbios_tables_len + term_cnt); \
484 memset(smbios_tables + smbios_tables_len, 0, term_cnt); \
485 smbios_tables_len += term_cnt; \
486 \
487 /* update smbios max. element size */ \
488 t_size = smbios_tables_len - t_off; \
489 if (t_size > smbios_table_max) { \
490 smbios_table_max = t_size; \
491 } \
492 \
493 /* update smbios element count */ \
494 smbios_table_cnt++; \
495 } while (0)
496
497static void smbios_build_type_0_table(void)
498{
499 SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
500
501 SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
502 SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
503
fb5be2e8 504 t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */
c97294ec
GS
505
506 SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
507
508 t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
509
84351843 510 t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */
c97294ec 511 t->bios_characteristics_extension_bytes[0] = 0;
84351843
GS
512 t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */
513 if (type0.uefi) {
514 t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */
515 }
c97294ec
GS
516
517 if (type0.have_major_minor) {
518 t->system_bios_major_release = type0.major;
519 t->system_bios_minor_release = type0.minor;
520 } else {
521 t->system_bios_major_release = 0;
522 t->system_bios_minor_release = 0;
523 }
524
525 /* hardcoded in SeaBIOS */
526 t->embedded_controller_major_release = 0xFF;
527 t->embedded_controller_minor_release = 0xFF;
528
529 SMBIOS_BUILD_TABLE_POST;
530}
531
caad057b
EH
532/* Encode UUID from the big endian encoding described on RFC4122 to the wire
533 * format specified by SMBIOS version 2.6.
534 */
535static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf)
536{
537 memcpy(uuid, buf, 16);
538 if (smbios_uuid_encoded) {
539 uuid->time_low = bswap32(uuid->time_low);
540 uuid->time_mid = bswap16(uuid->time_mid);
541 uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version);
542 }
543}
544
c97294ec
GS
545static void smbios_build_type_1_table(void)
546{
547 SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
548
549 SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
550 SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
551 SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
552 SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
553 if (qemu_uuid_set) {
caad057b 554 smbios_encode_uuid(&t->uuid, qemu_uuid);
c97294ec 555 } else {
caad057b 556 memset(&t->uuid, 0, 16);
c97294ec
GS
557 }
558 t->wake_up_type = 0x06; /* power switch */
559 SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
560 SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
561
562 SMBIOS_BUILD_TABLE_POST;
563}
564
565static void smbios_build_type_2_table(void)
566{
567 SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
568
569 SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
570 SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
571 SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
572 SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
573 SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
574 t->feature_flags = 0x01; /* Motherboard */
575 SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
fb5be2e8 576 t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */
c97294ec
GS
577 t->board_type = 0x0A; /* Motherboard */
578 t->contained_element_count = 0;
579
580 SMBIOS_BUILD_TABLE_POST;
581}
582
583static void smbios_build_type_3_table(void)
584{
585 SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
586
587 SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
588 t->type = 0x01; /* Other */
589 SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
590 SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
591 SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
592 t->boot_up_state = 0x03; /* Safe */
593 t->power_supply_state = 0x03; /* Safe */
594 t->thermal_state = 0x03; /* Safe */
595 t->security_status = 0x02; /* Unknown */
fb5be2e8 596 t->oem_defined = cpu_to_le32(0);
c97294ec
GS
597 t->height = 0;
598 t->number_of_power_cords = 0;
599 t->contained_element_count = 0;
600 SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
601
602 SMBIOS_BUILD_TABLE_POST;
603}
604
605static void smbios_build_type_4_table(unsigned instance)
606{
607 char sock_str[128];
608
609 SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
610
611 snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
612 SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
613 t->processor_type = 0x03; /* CPU */
fb5be2e8 614 t->processor_family = 0x01; /* Other */
c97294ec 615 SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
fb5be2e8
GS
616 t->processor_id[0] = cpu_to_le32(smbios_cpuid_version);
617 t->processor_id[1] = cpu_to_le32(smbios_cpuid_features);
c97294ec
GS
618 SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
619 t->voltage = 0;
fb5be2e8
GS
620 t->external_clock = cpu_to_le16(0); /* Unknown */
621 t->max_speed = cpu_to_le16(0); /* Unknown */
622 t->current_speed = cpu_to_le16(0); /* Unknown */
c97294ec
GS
623 t->status = 0x41; /* Socket populated, CPU enabled */
624 t->processor_upgrade = 0x01; /* Other */
fb5be2e8
GS
625 t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
626 t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
627 t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */
c97294ec
GS
628 SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
629 SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
630 SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
631 t->core_count = t->core_enabled = smp_cores;
632 t->thread_count = smp_threads;
fb5be2e8
GS
633 t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */
634 t->processor_family2 = cpu_to_le16(0x01); /* Other */
c97294ec
GS
635
636 SMBIOS_BUILD_TABLE_POST;
637 smbios_type4_count++;
638}
639
640#define ONE_KB ((ram_addr_t)1 << 10)
641#define ONE_MB ((ram_addr_t)1 << 20)
642#define ONE_GB ((ram_addr_t)1 << 30)
643
644#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
645
646static void smbios_build_type_16_table(unsigned dimm_cnt)
647{
f4ec5cd2 648 uint64_t size_kb;
c97294ec
GS
649
650 SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
651
652 t->location = 0x01; /* Other */
653 t->use = 0x03; /* System memory */
654 t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
655 size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
656 if (size_kb < MAX_T16_STD_SZ) {
fb5be2e8
GS
657 t->maximum_capacity = cpu_to_le32(size_kb);
658 t->extended_maximum_capacity = cpu_to_le64(0);
c97294ec 659 } else {
fb5be2e8
GS
660 t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ);
661 t->extended_maximum_capacity = cpu_to_le64(ram_size);
c97294ec 662 }
fb5be2e8
GS
663 t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
664 t->number_of_memory_devices = cpu_to_le16(dimm_cnt);
c97294ec
GS
665
666 SMBIOS_BUILD_TABLE_POST;
667}
668
669#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
670#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
671
f4ec5cd2 672static void smbios_build_type_17_table(unsigned instance, uint64_t size)
c97294ec
GS
673{
674 char loc_str[128];
f4ec5cd2 675 uint64_t size_mb;
c97294ec
GS
676
677 SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
678
fb5be2e8
GS
679 t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
680 t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */
681 t->total_width = cpu_to_le16(0xFFFF); /* Unknown */
682 t->data_width = cpu_to_le16(0xFFFF); /* Unknown */
c97294ec
GS
683 size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
684 if (size_mb < MAX_T17_STD_SZ) {
fb5be2e8
GS
685 t->size = cpu_to_le16(size_mb);
686 t->extended_size = cpu_to_le32(0);
c97294ec
GS
687 } else {
688 assert(size_mb < MAX_T17_EXT_SZ);
fb5be2e8
GS
689 t->size = cpu_to_le16(MAX_T17_STD_SZ);
690 t->extended_size = cpu_to_le32(size_mb);
c97294ec
GS
691 }
692 t->form_factor = 0x09; /* DIMM */
693 t->device_set = 0; /* Not in a set */
694 snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
695 SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
696 SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
697 t->memory_type = 0x07; /* RAM */
fb5be2e8
GS
698 t->type_detail = cpu_to_le16(0x02); /* Other */
699 t->speed = cpu_to_le16(0); /* Unknown */
c97294ec
GS
700 SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
701 SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
702 SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
703 SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
704 t->attributes = 0; /* Unknown */
0d73394a
GS
705 t->configured_clock_speed = cpu_to_le16(0); /* Unknown */
706 t->minimum_voltage = cpu_to_le16(0); /* Unknown */
707 t->maximum_voltage = cpu_to_le16(0); /* Unknown */
708 t->configured_voltage = cpu_to_le16(0); /* Unknown */
c97294ec
GS
709
710 SMBIOS_BUILD_TABLE_POST;
711}
712
713static void smbios_build_type_19_table(unsigned instance,
f4ec5cd2 714 uint64_t start, uint64_t size)
c97294ec 715{
f4ec5cd2 716 uint64_t end, start_kb, end_kb;
c97294ec
GS
717
718 SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
719
720 end = start + size - 1;
721 assert(end > start);
722 start_kb = start / ONE_KB;
723 end_kb = end / ONE_KB;
724 if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
fb5be2e8
GS
725 t->starting_address = cpu_to_le32(start_kb);
726 t->ending_address = cpu_to_le32(end_kb);
727 t->extended_starting_address =
728 t->extended_ending_address = cpu_to_le64(0);
c97294ec 729 } else {
fb5be2e8
GS
730 t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX);
731 t->extended_starting_address = cpu_to_le64(start);
732 t->extended_ending_address = cpu_to_le64(end);
c97294ec 733 }
fb5be2e8 734 t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */
c97294ec
GS
735 t->partition_width = 1; /* One device per row */
736
737 SMBIOS_BUILD_TABLE_POST;
738}
739
740static void smbios_build_type_32_table(void)
741{
742 SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
743
744 memset(t->reserved, 0, 6);
745 t->boot_status = 0; /* No errors detected */
746
747 SMBIOS_BUILD_TABLE_POST;
748}
749
750static void smbios_build_type_127_table(void)
751{
752 SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
753 SMBIOS_BUILD_TABLE_POST;
754}
755
756void smbios_set_cpuid(uint32_t version, uint32_t features)
757{
758 smbios_cpuid_version = version;
759 smbios_cpuid_features = features;
760}
761
cb36acb6
GS
762#define SMBIOS_SET_DEFAULT(field, value) \
763 if (!field) { \
764 field = value; \
765 }
766
767void smbios_set_defaults(const char *manufacturer, const char *product,
caad057b
EH
768 const char *version, bool legacy_mode,
769 bool uuid_encoded)
cb36acb6 770{
c97294ec
GS
771 smbios_have_defaults = true;
772 smbios_legacy = legacy_mode;
caad057b 773 smbios_uuid_encoded = uuid_encoded;
c97294ec
GS
774
775 /* drop unwanted version of command-line file blob(s) */
776 if (smbios_legacy) {
a10678b0 777 g_free(smbios_tables);
c97294ec
GS
778 /* in legacy mode, also complain if fields were given for types > 1 */
779 if (find_next_bit(have_fields_bitmap,
780 SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
781 error_report("can't process fields for smbios "
782 "types > 1 on machine versions < 2.1!");
783 exit(1);
784 }
785 } else {
a10678b0 786 g_free(smbios_entries);
c97294ec
GS
787 }
788
cb36acb6
GS
789 SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
790 SMBIOS_SET_DEFAULT(type1.product, product);
791 SMBIOS_SET_DEFAULT(type1.version, version);
c97294ec
GS
792 SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
793 SMBIOS_SET_DEFAULT(type2.product, product);
794 SMBIOS_SET_DEFAULT(type2.version, version);
795 SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
796 SMBIOS_SET_DEFAULT(type3.version, version);
797 SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
798 SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
799 SMBIOS_SET_DEFAULT(type4.version, version);
800 SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
801 SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
802}
803
804static void smbios_entry_point_setup(void)
805{
806 memcpy(ep.anchor_string, "_SM_", 4);
807 memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
808 ep.length = sizeof(struct smbios_entry_point);
809 ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
810 memset(ep.formatted_area, 0, 5);
811
812 /* compliant with smbios spec v2.8 */
813 ep.smbios_major_version = 2;
814 ep.smbios_minor_version = 8;
815 ep.smbios_bcd_revision = 0x28;
816
817 /* set during table construction, but BIOS may override: */
fb5be2e8
GS
818 ep.structure_table_length = cpu_to_le16(smbios_tables_len);
819 ep.max_structure_size = cpu_to_le16(smbios_table_max);
820 ep.number_of_structures = cpu_to_le16(smbios_table_cnt);
c97294ec
GS
821
822 /* BIOS must recalculate: */
823 ep.checksum = 0;
824 ep.intermediate_checksum = 0;
fb5be2e8 825 ep.structure_table_address = cpu_to_le32(0);
c97294ec
GS
826}
827
828void smbios_get_tables(uint8_t **tables, size_t *tables_len,
829 uint8_t **anchor, size_t *anchor_len)
830{
831 unsigned i, dimm_cnt, instance;
832
833 if (smbios_legacy) {
834 *tables = *anchor = NULL;
835 *tables_len = *anchor_len = 0;
836 return;
837 }
838
839 if (!smbios_immutable) {
840 smbios_build_type_0_table();
841 smbios_build_type_1_table();
842 smbios_build_type_2_table();
843 smbios_build_type_3_table();
844
7dfddd7f 845 smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads);
c97294ec
GS
846 assert(smbios_smp_sockets >= 1);
847
848 for (i = 0; i < smbios_smp_sockets; i++) {
849 smbios_build_type_4_table(i);
850 }
851
852#define MAX_DIMM_SZ (16ll * ONE_GB)
853#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ : ram_size % MAX_DIMM_SZ)
854
855 dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
856
857 smbios_build_type_16_table(dimm_cnt);
858
859 for (i = 0; i < dimm_cnt; i++) {
860 smbios_build_type_17_table(i, GET_DIMM_SZ);
861 }
862
863 for (i = 0, instance = 0; i < e820_get_num_entries(); i++) {
864 uint64_t address, length;
865 if (e820_get_entry(i, E820_RAM, &address, &length)) {
866 smbios_build_type_19_table(instance++, address, length);
867 }
868 }
869
870 smbios_build_type_32_table();
871 smbios_build_type_127_table();
872
873 smbios_validate_table();
874 smbios_entry_point_setup();
875 smbios_immutable = true;
876 }
877
878 /* return tables blob and entry point (anchor), and their sizes */
879 *tables = smbios_tables;
880 *tables_len = smbios_tables_len;
881 *anchor = (uint8_t *)&ep;
882 *anchor_len = sizeof(struct smbios_entry_point);
cb36acb6
GS
883}
884
fc3b3295
MA
885static void save_opt(const char **dest, QemuOpts *opts, const char *name)
886{
887 const char *val = qemu_opt_get(opts, name);
888
889 if (val) {
890 *dest = val;
4f953d2f 891 }
b6f6e3d3
AL
892}
893
4f953d2f 894void smbios_entry_add(QemuOpts *opts)
b6f6e3d3 895{
4f953d2f
MA
896 Error *local_err = NULL;
897 const char *val;
b6f6e3d3 898
fc3b3295 899 assert(!smbios_immutable);
c97294ec 900
4f953d2f
MA
901 val = qemu_opt_get(opts, "file");
902 if (val) {
b6f6e3d3 903 struct smbios_structure_header *header;
4f953d2f 904 int size;
c97294ec 905 struct smbios_table *table; /* legacy mode only */
4f953d2f
MA
906
907 qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
908 if (local_err) {
909 error_report("%s", error_get_pretty(local_err));
910 exit(1);
911 }
b6f6e3d3 912
4f953d2f 913 size = get_image_size(val);
09c0848e 914 if (size == -1 || size < sizeof(struct smbios_structure_header)) {
4f953d2f 915 error_report("Cannot read SMBIOS file %s", val);
b6f6e3d3
AL
916 exit(1);
917 }
918
c97294ec
GS
919 /*
920 * NOTE: standard double '\0' terminator expected, per smbios spec.
921 * (except in legacy mode, where the second '\0' is implicit and
922 * will be inserted by the BIOS).
923 */
924 smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
925 header = (struct smbios_structure_header *)(smbios_tables +
926 smbios_tables_len);
b6f6e3d3 927
c97294ec 928 if (load_image(val, (uint8_t *)header) != size) {
4f953d2f 929 error_report("Failed to load SMBIOS file %s", val);
b6f6e3d3
AL
930 exit(1);
931 }
932
2e6e8d7a
GS
933 if (test_bit(header->type, have_fields_bitmap)) {
934 error_report("can't load type %d struct, fields already specified!",
935 header->type);
936 exit(1);
937 }
938 set_bit(header->type, have_binfile_bitmap);
939
09c0848e
BK
940 if (header->type == 4) {
941 smbios_type4_count++;
942 }
b6f6e3d3 943
c97294ec
GS
944 smbios_tables_len += size;
945 if (size > smbios_table_max) {
946 smbios_table_max = size;
947 }
948 smbios_table_cnt++;
949
950 /* add a copy of the newly loaded blob to legacy smbios_entries */
951 /* NOTE: This code runs before smbios_set_defaults(), so we don't
952 * yet know which mode (legacy vs. aggregate-table) will be
953 * required. We therefore add the binary blob to both legacy
954 * (smbios_entries) and aggregate (smbios_tables) tables, and
955 * delete the one we don't need from smbios_set_defaults(),
956 * once we know which machine version has been requested.
957 */
958 if (!smbios_entries) {
959 smbios_entries_len = sizeof(uint16_t);
960 smbios_entries = g_malloc0(smbios_entries_len);
961 }
962 smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
963 size + sizeof(*table));
964 table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
965 table->header.type = SMBIOS_TABLE_ENTRY;
966 table->header.length = cpu_to_le16(sizeof(*table) + size);
967 memcpy(table->data, header, size);
b6f6e3d3
AL
968 smbios_entries_len += sizeof(*table) + size;
969 (*(uint16_t *)smbios_entries) =
970 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
c97294ec
GS
971 /* end: add a copy of the newly loaded blob to legacy smbios_entries */
972
351a6a73 973 return;
b6f6e3d3
AL
974 }
975
4f953d2f
MA
976 val = qemu_opt_get(opts, "type");
977 if (val) {
978 unsigned long type = strtoul(val, NULL, 0);
979
2e6e8d7a
GS
980 if (type > SMBIOS_MAX_TYPE) {
981 error_report("out of range!");
982 exit(1);
983 }
984
985 if (test_bit(type, have_binfile_bitmap)) {
986 error_report("can't add fields, binary file already loaded!");
987 exit(1);
988 }
989 set_bit(type, have_fields_bitmap);
fc3b3295 990
b6f6e3d3
AL
991 switch (type) {
992 case 0:
4f953d2f
MA
993 qemu_opts_validate(opts, qemu_smbios_type0_opts, &local_err);
994 if (local_err) {
995 error_report("%s", error_get_pretty(local_err));
996 exit(1);
997 }
fc3b3295
MA
998 save_opt(&type0.vendor, opts, "vendor");
999 save_opt(&type0.version, opts, "version");
1000 save_opt(&type0.date, opts, "date");
84351843 1001 type0.uefi = qemu_opt_get_bool(opts, "uefi", false);
fc3b3295
MA
1002
1003 val = qemu_opt_get(opts, "release");
1004 if (val) {
1005 if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) {
1006 error_report("Invalid release");
1007 exit(1);
1008 }
1009 type0.have_major_minor = true;
1010 }
351a6a73 1011 return;
b6f6e3d3 1012 case 1:
4f953d2f
MA
1013 qemu_opts_validate(opts, qemu_smbios_type1_opts, &local_err);
1014 if (local_err) {
1015 error_report("%s", error_get_pretty(local_err));
1016 exit(1);
1017 }
fc3b3295
MA
1018 save_opt(&type1.manufacturer, opts, "manufacturer");
1019 save_opt(&type1.product, opts, "product");
1020 save_opt(&type1.version, opts, "version");
1021 save_opt(&type1.serial, opts, "serial");
1022 save_opt(&type1.sku, opts, "sku");
1023 save_opt(&type1.family, opts, "family");
1024
1025 val = qemu_opt_get(opts, "uuid");
1026 if (val) {
1027 if (qemu_uuid_parse(val, qemu_uuid) != 0) {
1028 error_report("Invalid UUID");
1029 exit(1);
1030 }
1031 qemu_uuid_set = true;
1032 }
351a6a73 1033 return;
c97294ec
GS
1034 case 2:
1035 qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err);
1036 if (local_err) {
1037 error_report("%s", error_get_pretty(local_err));
1038 exit(1);
1039 }
1040 save_opt(&type2.manufacturer, opts, "manufacturer");
1041 save_opt(&type2.product, opts, "product");
1042 save_opt(&type2.version, opts, "version");
1043 save_opt(&type2.serial, opts, "serial");
1044 save_opt(&type2.asset, opts, "asset");
1045 save_opt(&type2.location, opts, "location");
1046 return;
1047 case 3:
1048 qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err);
1049 if (local_err) {
1050 error_report("%s", error_get_pretty(local_err));
1051 exit(1);
1052 }
1053 save_opt(&type3.manufacturer, opts, "manufacturer");
1054 save_opt(&type3.version, opts, "version");
1055 save_opt(&type3.serial, opts, "serial");
1056 save_opt(&type3.asset, opts, "asset");
1057 save_opt(&type3.sku, opts, "sku");
1058 return;
1059 case 4:
1060 qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err);
1061 if (local_err) {
1062 error_report("%s", error_get_pretty(local_err));
1063 exit(1);
1064 }
1065 save_opt(&type4.sock_pfx, opts, "sock_pfx");
1066 save_opt(&type4.manufacturer, opts, "manufacturer");
1067 save_opt(&type4.version, opts, "version");
1068 save_opt(&type4.serial, opts, "serial");
1069 save_opt(&type4.asset, opts, "asset");
1070 save_opt(&type4.part, opts, "part");
1071 return;
1072 case 17:
1073 qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err);
1074 if (local_err) {
1075 error_report("%s", error_get_pretty(local_err));
1076 exit(1);
1077 }
1078 save_opt(&type17.loc_pfx, opts, "loc_pfx");
1079 save_opt(&type17.bank, opts, "bank");
1080 save_opt(&type17.manufacturer, opts, "manufacturer");
1081 save_opt(&type17.serial, opts, "serial");
1082 save_opt(&type17.asset, opts, "asset");
1083 save_opt(&type17.part, opts, "part");
1084 return;
b6f6e3d3 1085 default:
5bb95e41
MA
1086 error_report("Don't know how to build fields for SMBIOS type %ld",
1087 type);
b6f6e3d3
AL
1088 exit(1);
1089 }
1090 }
1091
5bb95e41 1092 error_report("Must specify type= or file=");
351a6a73 1093 exit(1);
b6f6e3d3 1094}