4 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
5 * Copyright (C) 2013 Red Hat, Inc.
8 * Alex Williamson <alex.williamson@hp.com>
9 * Markus Armbruster <armbru@redhat.com>
11 * This work is licensed under the terms of the GNU GPL, version 2. See
12 * the COPYING file in the top-level directory.
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.
18 #include "qemu/config-file.h"
19 #include "qemu/error-report.h"
20 #include "sysemu/sysemu.h"
21 #include "hw/i386/smbios.h"
22 #include "hw/loader.h"
25 * Structures shared with the BIOS
27 struct smbios_header
{
33 struct smbios_header header
;
40 struct smbios_header header
;
44 #define SMBIOS_FIELD_ENTRY 0
45 #define SMBIOS_TABLE_ENTRY 1
47 static uint8_t *smbios_entries
;
48 static size_t smbios_entries_len
;
49 static int smbios_type4_count
= 0;
50 static bool smbios_immutable
;
59 const char *vendor
, *version
, *date
;
60 bool have_major_minor
;
65 const char *manufacturer
, *product
, *version
, *serial
, *sku
, *family
;
66 /* uuid is in qemu_uuid[] */
69 static QemuOptsList qemu_smbios_opts
= {
71 .head
= QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts
.head
),
74 * no elements => accept any params
75 * validation will happen later
81 static const QemuOptDesc qemu_smbios_file_opts
[] = {
84 .type
= QEMU_OPT_STRING
,
85 .help
= "binary file containing an SMBIOS element",
90 static const QemuOptDesc qemu_smbios_type0_opts
[] = {
93 .type
= QEMU_OPT_NUMBER
,
94 .help
= "SMBIOS element type",
97 .type
= QEMU_OPT_STRING
,
98 .help
= "vendor name",
101 .type
= QEMU_OPT_STRING
,
102 .help
= "version number",
105 .type
= QEMU_OPT_STRING
,
106 .help
= "release date",
109 .type
= QEMU_OPT_STRING
,
110 .help
= "revision number",
112 { /* end of list */ }
115 static const QemuOptDesc qemu_smbios_type1_opts
[] = {
118 .type
= QEMU_OPT_NUMBER
,
119 .help
= "SMBIOS element type",
121 .name
= "manufacturer",
122 .type
= QEMU_OPT_STRING
,
123 .help
= "manufacturer name",
126 .type
= QEMU_OPT_STRING
,
127 .help
= "product name",
130 .type
= QEMU_OPT_STRING
,
131 .help
= "version number",
134 .type
= QEMU_OPT_STRING
,
135 .help
= "serial number",
138 .type
= QEMU_OPT_STRING
,
142 .type
= QEMU_OPT_STRING
,
143 .help
= "SKU number",
146 .type
= QEMU_OPT_STRING
,
147 .help
= "family name",
149 { /* end of list */ }
152 static void smbios_register_config(void)
154 qemu_add_opts(&qemu_smbios_opts
);
157 machine_init(smbios_register_config
);
159 static void smbios_validate_table(void)
161 if (smbios_type4_count
&& smbios_type4_count
!= smp_cpus
) {
162 error_report("Number of SMBIOS Type 4 tables must match cpu count");
168 * To avoid unresolvable overlaps in data, don't allow both
169 * tables and fields for the same smbios type.
171 static void smbios_check_collision(int type
, int entry
)
173 if (type
< ARRAY_SIZE(first_opt
)) {
174 if (first_opt
[type
].seen
) {
175 if (first_opt
[type
].headertype
!= entry
) {
176 error_report("Can't mix file= and type= for same type");
177 loc_push_restore(&first_opt
[type
].loc
);
178 error_report("This is the conflicting setting");
179 loc_pop(&first_opt
[type
].loc
);
183 first_opt
[type
].seen
= true;
184 first_opt
[type
].headertype
= entry
;
185 loc_save(&first_opt
[type
].loc
);
190 static void smbios_add_field(int type
, int offset
, const void *data
, size_t len
)
192 struct smbios_field
*field
;
194 if (!smbios_entries
) {
195 smbios_entries_len
= sizeof(uint16_t);
196 smbios_entries
= g_malloc0(smbios_entries_len
);
198 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
199 sizeof(*field
) + len
);
200 field
= (struct smbios_field
*)(smbios_entries
+ smbios_entries_len
);
201 field
->header
.type
= SMBIOS_FIELD_ENTRY
;
202 field
->header
.length
= cpu_to_le16(sizeof(*field
) + len
);
205 field
->offset
= cpu_to_le16(offset
);
206 memcpy(field
->data
, data
, len
);
208 smbios_entries_len
+= sizeof(*field
) + len
;
209 (*(uint16_t *)smbios_entries
) =
210 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
213 static void smbios_maybe_add_str(int type
, int offset
, const char *data
)
216 smbios_add_field(type
, offset
, data
, strlen(data
) + 1);
220 static void smbios_build_type_0_fields(void)
222 smbios_maybe_add_str(0, offsetof(struct smbios_type_0
, vendor_str
),
224 smbios_maybe_add_str(0, offsetof(struct smbios_type_0
, bios_version_str
),
226 smbios_maybe_add_str(0, offsetof(struct smbios_type_0
,
227 bios_release_date_str
),
229 if (type0
.have_major_minor
) {
230 smbios_add_field(0, offsetof(struct smbios_type_0
,
231 system_bios_major_release
),
233 smbios_add_field(0, offsetof(struct smbios_type_0
,
234 system_bios_minor_release
),
239 static void smbios_build_type_1_fields(void)
241 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, manufacturer_str
),
243 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, product_name_str
),
245 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, version_str
),
247 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, serial_number_str
),
249 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, sku_number_str
),
251 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, family_str
),
254 smbios_add_field(1, offsetof(struct smbios_type_1
, uuid
),
259 void smbios_set_type1_defaults(const char *manufacturer
,
260 const char *product
, const char *version
)
262 if (!type1
.manufacturer
) {
263 type1
.manufacturer
= manufacturer
;
265 if (!type1
.product
) {
266 type1
.product
= product
;
268 if (!type1
.version
) {
269 type1
.version
= version
;
273 uint8_t *smbios_get_table(size_t *length
)
275 if (!smbios_immutable
) {
276 smbios_build_type_0_fields();
277 smbios_build_type_1_fields();
278 smbios_validate_table();
279 smbios_immutable
= true;
281 *length
= smbios_entries_len
;
282 return smbios_entries
;
285 static void save_opt(const char **dest
, QemuOpts
*opts
, const char *name
)
287 const char *val
= qemu_opt_get(opts
, name
);
294 void smbios_entry_add(QemuOpts
*opts
)
296 Error
*local_err
= NULL
;
299 assert(!smbios_immutable
);
300 val
= qemu_opt_get(opts
, "file");
302 struct smbios_structure_header
*header
;
303 struct smbios_table
*table
;
306 qemu_opts_validate(opts
, qemu_smbios_file_opts
, &local_err
);
308 error_report("%s", error_get_pretty(local_err
));
312 size
= get_image_size(val
);
313 if (size
== -1 || size
< sizeof(struct smbios_structure_header
)) {
314 error_report("Cannot read SMBIOS file %s", val
);
318 if (!smbios_entries
) {
319 smbios_entries_len
= sizeof(uint16_t);
320 smbios_entries
= g_malloc0(smbios_entries_len
);
323 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
324 sizeof(*table
) + size
);
325 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
326 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
327 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
329 if (load_image(val
, table
->data
) != size
) {
330 error_report("Failed to load SMBIOS file %s", val
);
334 header
= (struct smbios_structure_header
*)(table
->data
);
335 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
336 if (header
->type
== 4) {
337 smbios_type4_count
++;
340 smbios_entries_len
+= sizeof(*table
) + size
;
341 (*(uint16_t *)smbios_entries
) =
342 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
346 val
= qemu_opt_get(opts
, "type");
348 unsigned long type
= strtoul(val
, NULL
, 0);
350 smbios_check_collision(type
, SMBIOS_FIELD_ENTRY
);
354 qemu_opts_validate(opts
, qemu_smbios_type0_opts
, &local_err
);
356 error_report("%s", error_get_pretty(local_err
));
359 save_opt(&type0
.vendor
, opts
, "vendor");
360 save_opt(&type0
.version
, opts
, "version");
361 save_opt(&type0
.date
, opts
, "date");
363 val
= qemu_opt_get(opts
, "release");
365 if (sscanf(val
, "%hhu.%hhu", &type0
.major
, &type0
.minor
) != 2) {
366 error_report("Invalid release");
369 type0
.have_major_minor
= true;
373 qemu_opts_validate(opts
, qemu_smbios_type1_opts
, &local_err
);
375 error_report("%s", error_get_pretty(local_err
));
378 save_opt(&type1
.manufacturer
, opts
, "manufacturer");
379 save_opt(&type1
.product
, opts
, "product");
380 save_opt(&type1
.version
, opts
, "version");
381 save_opt(&type1
.serial
, opts
, "serial");
382 save_opt(&type1
.sku
, opts
, "sku");
383 save_opt(&type1
.family
, opts
, "family");
385 val
= qemu_opt_get(opts
, "uuid");
387 if (qemu_uuid_parse(val
, qemu_uuid
) != 0) {
388 error_report("Invalid UUID");
391 qemu_uuid_set
= true;
395 error_report("Don't know how to build fields for SMBIOS type %ld",
401 error_report("Must specify type= or file=");