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 /* legacy structures and constants for <= 2.0 machines */
26 struct smbios_header
{
32 struct smbios_header header
;
39 struct smbios_header header
;
43 #define SMBIOS_FIELD_ENTRY 0
44 #define SMBIOS_TABLE_ENTRY 1
46 static uint8_t *smbios_entries
;
47 static size_t smbios_entries_len
;
48 /* end: legacy structures & constants for <= 2.0 machines */
51 static int smbios_type4_count
= 0;
52 static bool smbios_immutable
;
61 const char *vendor
, *version
, *date
;
62 bool have_major_minor
;
67 const char *manufacturer
, *product
, *version
, *serial
, *sku
, *family
;
68 /* uuid is in qemu_uuid[] */
71 static QemuOptsList qemu_smbios_opts
= {
73 .head
= QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts
.head
),
76 * no elements => accept any params
77 * validation will happen later
83 static const QemuOptDesc qemu_smbios_file_opts
[] = {
86 .type
= QEMU_OPT_STRING
,
87 .help
= "binary file containing an SMBIOS element",
92 static const QemuOptDesc qemu_smbios_type0_opts
[] = {
95 .type
= QEMU_OPT_NUMBER
,
96 .help
= "SMBIOS element type",
99 .type
= QEMU_OPT_STRING
,
100 .help
= "vendor name",
103 .type
= QEMU_OPT_STRING
,
104 .help
= "version number",
107 .type
= QEMU_OPT_STRING
,
108 .help
= "release date",
111 .type
= QEMU_OPT_STRING
,
112 .help
= "revision number",
114 { /* end of list */ }
117 static const QemuOptDesc qemu_smbios_type1_opts
[] = {
120 .type
= QEMU_OPT_NUMBER
,
121 .help
= "SMBIOS element type",
123 .name
= "manufacturer",
124 .type
= QEMU_OPT_STRING
,
125 .help
= "manufacturer name",
128 .type
= QEMU_OPT_STRING
,
129 .help
= "product name",
132 .type
= QEMU_OPT_STRING
,
133 .help
= "version number",
136 .type
= QEMU_OPT_STRING
,
137 .help
= "serial number",
140 .type
= QEMU_OPT_STRING
,
144 .type
= QEMU_OPT_STRING
,
145 .help
= "SKU number",
148 .type
= QEMU_OPT_STRING
,
149 .help
= "family name",
151 { /* end of list */ }
154 static void smbios_register_config(void)
156 qemu_add_opts(&qemu_smbios_opts
);
159 machine_init(smbios_register_config
);
161 static void smbios_validate_table(void)
163 if (smbios_type4_count
&& smbios_type4_count
!= smp_cpus
) {
164 error_report("Number of SMBIOS Type 4 tables must match cpu count");
170 * To avoid unresolvable overlaps in data, don't allow both
171 * tables and fields for the same smbios type.
173 static void smbios_check_collision(int type
, int entry
)
175 if (type
< ARRAY_SIZE(first_opt
)) {
176 if (first_opt
[type
].seen
) {
177 if (first_opt
[type
].headertype
!= entry
) {
178 error_report("Can't mix file= and type= for same type");
179 loc_push_restore(&first_opt
[type
].loc
);
180 error_report("This is the conflicting setting");
181 loc_pop(&first_opt
[type
].loc
);
185 first_opt
[type
].seen
= true;
186 first_opt
[type
].headertype
= entry
;
187 loc_save(&first_opt
[type
].loc
);
193 /* legacy setup functions for <= 2.0 machines */
194 static void smbios_add_field(int type
, int offset
, const void *data
, size_t len
)
196 struct smbios_field
*field
;
198 if (!smbios_entries
) {
199 smbios_entries_len
= sizeof(uint16_t);
200 smbios_entries
= g_malloc0(smbios_entries_len
);
202 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
203 sizeof(*field
) + len
);
204 field
= (struct smbios_field
*)(smbios_entries
+ smbios_entries_len
);
205 field
->header
.type
= SMBIOS_FIELD_ENTRY
;
206 field
->header
.length
= cpu_to_le16(sizeof(*field
) + len
);
209 field
->offset
= cpu_to_le16(offset
);
210 memcpy(field
->data
, data
, len
);
212 smbios_entries_len
+= sizeof(*field
) + len
;
213 (*(uint16_t *)smbios_entries
) =
214 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
217 static void smbios_maybe_add_str(int type
, int offset
, const char *data
)
220 smbios_add_field(type
, offset
, data
, strlen(data
) + 1);
224 static void smbios_build_type_0_fields(void)
226 smbios_maybe_add_str(0, offsetof(struct smbios_type_0
, vendor_str
),
228 smbios_maybe_add_str(0, offsetof(struct smbios_type_0
, bios_version_str
),
230 smbios_maybe_add_str(0, offsetof(struct smbios_type_0
,
231 bios_release_date_str
),
233 if (type0
.have_major_minor
) {
234 smbios_add_field(0, offsetof(struct smbios_type_0
,
235 system_bios_major_release
),
237 smbios_add_field(0, offsetof(struct smbios_type_0
,
238 system_bios_minor_release
),
243 static void smbios_build_type_1_fields(void)
245 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, manufacturer_str
),
247 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, product_name_str
),
249 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, version_str
),
251 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, serial_number_str
),
253 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, sku_number_str
),
255 smbios_maybe_add_str(1, offsetof(struct smbios_type_1
, family_str
),
258 smbios_add_field(1, offsetof(struct smbios_type_1
, uuid
),
263 uint8_t *smbios_get_table_legacy(size_t *length
)
265 if (!smbios_immutable
) {
266 smbios_build_type_0_fields();
267 smbios_build_type_1_fields();
268 smbios_validate_table();
269 smbios_immutable
= true;
271 *length
= smbios_entries_len
;
272 return smbios_entries
;
274 /* end: legacy setup functions for <= 2.0 machines */
277 #define SMBIOS_SET_DEFAULT(field, value) \
282 void smbios_set_defaults(const char *manufacturer
, const char *product
,
285 SMBIOS_SET_DEFAULT(type1
.manufacturer
, manufacturer
);
286 SMBIOS_SET_DEFAULT(type1
.product
, product
);
287 SMBIOS_SET_DEFAULT(type1
.version
, version
);
290 static void save_opt(const char **dest
, QemuOpts
*opts
, const char *name
)
292 const char *val
= qemu_opt_get(opts
, name
);
299 void smbios_entry_add(QemuOpts
*opts
)
301 Error
*local_err
= NULL
;
304 assert(!smbios_immutable
);
305 val
= qemu_opt_get(opts
, "file");
307 struct smbios_structure_header
*header
;
308 struct smbios_table
*table
;
311 qemu_opts_validate(opts
, qemu_smbios_file_opts
, &local_err
);
313 error_report("%s", error_get_pretty(local_err
));
317 size
= get_image_size(val
);
318 if (size
== -1 || size
< sizeof(struct smbios_structure_header
)) {
319 error_report("Cannot read SMBIOS file %s", val
);
323 if (!smbios_entries
) {
324 smbios_entries_len
= sizeof(uint16_t);
325 smbios_entries
= g_malloc0(smbios_entries_len
);
328 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
329 sizeof(*table
) + size
);
330 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
331 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
332 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
334 if (load_image(val
, table
->data
) != size
) {
335 error_report("Failed to load SMBIOS file %s", val
);
339 header
= (struct smbios_structure_header
*)(table
->data
);
340 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
341 if (header
->type
== 4) {
342 smbios_type4_count
++;
345 smbios_entries_len
+= sizeof(*table
) + size
;
346 (*(uint16_t *)smbios_entries
) =
347 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
351 val
= qemu_opt_get(opts
, "type");
353 unsigned long type
= strtoul(val
, NULL
, 0);
355 smbios_check_collision(type
, SMBIOS_FIELD_ENTRY
);
359 qemu_opts_validate(opts
, qemu_smbios_type0_opts
, &local_err
);
361 error_report("%s", error_get_pretty(local_err
));
364 save_opt(&type0
.vendor
, opts
, "vendor");
365 save_opt(&type0
.version
, opts
, "version");
366 save_opt(&type0
.date
, opts
, "date");
368 val
= qemu_opt_get(opts
, "release");
370 if (sscanf(val
, "%hhu.%hhu", &type0
.major
, &type0
.minor
) != 2) {
371 error_report("Invalid release");
374 type0
.have_major_minor
= true;
378 qemu_opts_validate(opts
, qemu_smbios_type1_opts
, &local_err
);
380 error_report("%s", error_get_pretty(local_err
));
383 save_opt(&type1
.manufacturer
, opts
, "manufacturer");
384 save_opt(&type1
.product
, opts
, "product");
385 save_opt(&type1
.version
, opts
, "version");
386 save_opt(&type1
.serial
, opts
, "serial");
387 save_opt(&type1
.sku
, opts
, "sku");
388 save_opt(&type1
.family
, opts
, "family");
390 val
= qemu_opt_get(opts
, "uuid");
392 if (qemu_uuid_parse(val
, qemu_uuid
) != 0) {
393 error_report("Invalid UUID");
396 qemu_uuid_set
= true;
400 error_report("Don't know how to build fields for SMBIOS type %ld",
406 error_report("Must specify type= or file=");