1b42b0e4dSIgor Mammedov /*
2b42b0e4dSIgor Mammedov * SMBIOS legacy support
3b42b0e4dSIgor Mammedov *
4b42b0e4dSIgor Mammedov * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
5b42b0e4dSIgor Mammedov * Copyright (C) 2013 Red Hat, Inc.
6b42b0e4dSIgor Mammedov *
7b42b0e4dSIgor Mammedov * Authors:
8b42b0e4dSIgor Mammedov * Alex Williamson <alex.williamson@hp.com>
9b42b0e4dSIgor Mammedov * Markus Armbruster <armbru@redhat.com>
10b42b0e4dSIgor Mammedov *
11b42b0e4dSIgor Mammedov * This work is licensed under the terms of the GNU GPL, version 2. See
12b42b0e4dSIgor Mammedov * the COPYING file in the top-level directory.
13b42b0e4dSIgor Mammedov *
14b42b0e4dSIgor Mammedov * Contributions after 2012-01-13 are licensed under the terms of the
15b42b0e4dSIgor Mammedov * GNU GPL, version 2 or (at your option) any later version.
16b42b0e4dSIgor Mammedov */
17b42b0e4dSIgor Mammedov
18b42b0e4dSIgor Mammedov #include "qemu/osdep.h"
19b42b0e4dSIgor Mammedov #include "qemu/bswap.h"
20b42b0e4dSIgor Mammedov #include "hw/firmware/smbios.h"
21b42b0e4dSIgor Mammedov #include "sysemu/sysemu.h"
22643e1c9eSIgor Mammedov #include "qapi/error.h"
23b42b0e4dSIgor Mammedov
24b42b0e4dSIgor Mammedov struct smbios_header {
25b42b0e4dSIgor Mammedov uint16_t length;
26b42b0e4dSIgor Mammedov uint8_t type;
27b42b0e4dSIgor Mammedov } QEMU_PACKED;
28b42b0e4dSIgor Mammedov
29b42b0e4dSIgor Mammedov struct smbios_field {
30b42b0e4dSIgor Mammedov struct smbios_header header;
31b42b0e4dSIgor Mammedov uint8_t type;
32b42b0e4dSIgor Mammedov uint16_t offset;
33b42b0e4dSIgor Mammedov uint8_t data[];
34b42b0e4dSIgor Mammedov } QEMU_PACKED;
35b42b0e4dSIgor Mammedov
36b42b0e4dSIgor Mammedov struct smbios_table {
37b42b0e4dSIgor Mammedov struct smbios_header header;
38b42b0e4dSIgor Mammedov uint8_t data[];
39b42b0e4dSIgor Mammedov } QEMU_PACKED;
40b42b0e4dSIgor Mammedov
41b42b0e4dSIgor Mammedov #define SMBIOS_FIELD_ENTRY 0
42b42b0e4dSIgor Mammedov #define SMBIOS_TABLE_ENTRY 1
43b42b0e4dSIgor Mammedov
44b42b0e4dSIgor Mammedov static uint8_t *smbios_entries;
45b42b0e4dSIgor Mammedov static size_t smbios_entries_len;
46b42b0e4dSIgor Mammedov GArray *usr_blobs_sizes;
47b42b0e4dSIgor Mammedov
smbios_add_usr_blob_size(size_t size)48b42b0e4dSIgor Mammedov void smbios_add_usr_blob_size(size_t size)
49b42b0e4dSIgor Mammedov {
50b42b0e4dSIgor Mammedov if (!usr_blobs_sizes) {
51b42b0e4dSIgor Mammedov usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
52b42b0e4dSIgor Mammedov }
53b42b0e4dSIgor Mammedov g_array_append_val(usr_blobs_sizes, size);
54b42b0e4dSIgor Mammedov }
55b42b0e4dSIgor Mammedov
smbios_add_field(int type,int offset,const void * data,size_t len)56b42b0e4dSIgor Mammedov static void smbios_add_field(int type, int offset, const void *data, size_t len)
57b42b0e4dSIgor Mammedov {
58b42b0e4dSIgor Mammedov struct smbios_field *field;
59b42b0e4dSIgor Mammedov
60b42b0e4dSIgor Mammedov if (!smbios_entries) {
61b42b0e4dSIgor Mammedov smbios_entries_len = sizeof(uint16_t);
62b42b0e4dSIgor Mammedov smbios_entries = g_malloc0(smbios_entries_len);
63b42b0e4dSIgor Mammedov }
64b42b0e4dSIgor Mammedov smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
65b42b0e4dSIgor Mammedov sizeof(*field) + len);
66b42b0e4dSIgor Mammedov field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
67b42b0e4dSIgor Mammedov field->header.type = SMBIOS_FIELD_ENTRY;
68b42b0e4dSIgor Mammedov field->header.length = cpu_to_le16(sizeof(*field) + len);
69b42b0e4dSIgor Mammedov
70b42b0e4dSIgor Mammedov field->type = type;
71b42b0e4dSIgor Mammedov field->offset = cpu_to_le16(offset);
72b42b0e4dSIgor Mammedov memcpy(field->data, data, len);
73b42b0e4dSIgor Mammedov
74b42b0e4dSIgor Mammedov smbios_entries_len += sizeof(*field) + len;
75b42b0e4dSIgor Mammedov (*(uint16_t *)smbios_entries) =
76b42b0e4dSIgor Mammedov cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
77b42b0e4dSIgor Mammedov }
78b42b0e4dSIgor Mammedov
smbios_maybe_add_str(int type,int offset,const char * data)79b42b0e4dSIgor Mammedov static void smbios_maybe_add_str(int type, int offset, const char *data)
80b42b0e4dSIgor Mammedov {
81b42b0e4dSIgor Mammedov if (data) {
82b42b0e4dSIgor Mammedov smbios_add_field(type, offset, data, strlen(data) + 1);
83b42b0e4dSIgor Mammedov }
84b42b0e4dSIgor Mammedov }
85b42b0e4dSIgor Mammedov
smbios_build_type_0_fields(void)86b42b0e4dSIgor Mammedov static void smbios_build_type_0_fields(void)
87b42b0e4dSIgor Mammedov {
88b42b0e4dSIgor Mammedov smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str),
89b42b0e4dSIgor Mammedov smbios_type0.vendor);
90b42b0e4dSIgor Mammedov smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str),
91b42b0e4dSIgor Mammedov smbios_type0.version);
92b42b0e4dSIgor Mammedov smbios_maybe_add_str(0, offsetof(struct smbios_type_0,
93b42b0e4dSIgor Mammedov bios_release_date_str),
94b42b0e4dSIgor Mammedov smbios_type0.date);
95b42b0e4dSIgor Mammedov if (smbios_type0.have_major_minor) {
96b42b0e4dSIgor Mammedov smbios_add_field(0, offsetof(struct smbios_type_0,
97b42b0e4dSIgor Mammedov system_bios_major_release),
98b42b0e4dSIgor Mammedov &smbios_type0.major, 1);
99b42b0e4dSIgor Mammedov smbios_add_field(0, offsetof(struct smbios_type_0,
100b42b0e4dSIgor Mammedov system_bios_minor_release),
101b42b0e4dSIgor Mammedov &smbios_type0.minor, 1);
102b42b0e4dSIgor Mammedov }
103b42b0e4dSIgor Mammedov }
104b42b0e4dSIgor Mammedov
smbios_build_type_1_fields(void)105b42b0e4dSIgor Mammedov static void smbios_build_type_1_fields(void)
106b42b0e4dSIgor Mammedov {
107b42b0e4dSIgor Mammedov smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str),
108b42b0e4dSIgor Mammedov smbios_type1.manufacturer);
109b42b0e4dSIgor Mammedov smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str),
110b42b0e4dSIgor Mammedov smbios_type1.product);
111b42b0e4dSIgor Mammedov smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str),
112b42b0e4dSIgor Mammedov smbios_type1.version);
113b42b0e4dSIgor Mammedov smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str),
114b42b0e4dSIgor Mammedov smbios_type1.serial);
115b42b0e4dSIgor Mammedov smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str),
116b42b0e4dSIgor Mammedov smbios_type1.sku);
117b42b0e4dSIgor Mammedov smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str),
118b42b0e4dSIgor Mammedov smbios_type1.family);
119b42b0e4dSIgor Mammedov if (qemu_uuid_set) {
120b42b0e4dSIgor Mammedov /*
121b42b0e4dSIgor Mammedov * We don't encode the UUID in the "wire format" here because this
122b42b0e4dSIgor Mammedov * function is for legacy mode and needs to keep the guest ABI, and
123b42b0e4dSIgor Mammedov * because we don't know what's the SMBIOS version advertised by the
124b42b0e4dSIgor Mammedov * BIOS.
125b42b0e4dSIgor Mammedov */
126b42b0e4dSIgor Mammedov smbios_add_field(1, offsetof(struct smbios_type_1, uuid),
127b42b0e4dSIgor Mammedov &qemu_uuid, 16);
128b42b0e4dSIgor Mammedov }
129b42b0e4dSIgor Mammedov }
130b42b0e4dSIgor Mammedov
smbios_get_table_legacy(size_t * length,Error ** errp)131643e1c9eSIgor Mammedov uint8_t *smbios_get_table_legacy(size_t *length, Error **errp)
132b42b0e4dSIgor Mammedov {
133b42b0e4dSIgor Mammedov int i;
134b42b0e4dSIgor Mammedov size_t usr_offset;
135b42b0e4dSIgor Mammedov
136b42b0e4dSIgor Mammedov /* complain if fields were given for types > 1 */
137b42b0e4dSIgor Mammedov if (find_next_bit(smbios_have_fields_bitmap,
138b42b0e4dSIgor Mammedov SMBIOS_MAX_TYPE + 1, 2) < SMBIOS_MAX_TYPE + 1) {
139643e1c9eSIgor Mammedov error_setg(errp, "can't process fields for smbios "
140b42b0e4dSIgor Mammedov "types > 1 on machine versions < 2.1!");
141643e1c9eSIgor Mammedov goto err_exit;
142b42b0e4dSIgor Mammedov }
143b42b0e4dSIgor Mammedov
144b42b0e4dSIgor Mammedov if (test_bit(4, smbios_have_binfile_bitmap)) {
145643e1c9eSIgor Mammedov error_setg(errp, "can't process table for smbios "
146b42b0e4dSIgor Mammedov "type 4 on machine versions < 2.1!");
147643e1c9eSIgor Mammedov goto err_exit;
148b42b0e4dSIgor Mammedov }
149b42b0e4dSIgor Mammedov
150b42b0e4dSIgor Mammedov g_free(smbios_entries);
151b42b0e4dSIgor Mammedov smbios_entries_len = sizeof(uint16_t);
152b42b0e4dSIgor Mammedov smbios_entries = g_malloc0(smbios_entries_len);
153b42b0e4dSIgor Mammedov
154*bb949df6SIgor Mammedov /*
155*bb949df6SIgor Mammedov * build a set of legacy smbios_table entries using user provided blobs
156*bb949df6SIgor Mammedov */
157b42b0e4dSIgor Mammedov for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
158b42b0e4dSIgor Mammedov i++)
159b42b0e4dSIgor Mammedov {
160b42b0e4dSIgor Mammedov struct smbios_table *table;
161b42b0e4dSIgor Mammedov struct smbios_structure_header *header;
162b42b0e4dSIgor Mammedov size_t size = g_array_index(usr_blobs_sizes, size_t, i);
163b42b0e4dSIgor Mammedov
164b42b0e4dSIgor Mammedov header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
165b42b0e4dSIgor Mammedov smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
166b42b0e4dSIgor Mammedov size + sizeof(*table));
167b42b0e4dSIgor Mammedov table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
168b42b0e4dSIgor Mammedov table->header.type = SMBIOS_TABLE_ENTRY;
169b42b0e4dSIgor Mammedov table->header.length = cpu_to_le16(sizeof(*table) + size);
170b42b0e4dSIgor Mammedov memcpy(table->data, header, size);
171b42b0e4dSIgor Mammedov smbios_entries_len += sizeof(*table) + size;
172*bb949df6SIgor Mammedov /*
173*bb949df6SIgor Mammedov * update number of entries in the blob,
174*bb949df6SIgor Mammedov * see SeaBIOS: qemu_cfg_legacy():QEMU_CFG_SMBIOS_ENTRIES
175*bb949df6SIgor Mammedov */
176b42b0e4dSIgor Mammedov (*(uint16_t *)smbios_entries) =
177b42b0e4dSIgor Mammedov cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
178b42b0e4dSIgor Mammedov usr_offset += size;
179b42b0e4dSIgor Mammedov }
180b42b0e4dSIgor Mammedov
181b42b0e4dSIgor Mammedov smbios_build_type_0_fields();
182b42b0e4dSIgor Mammedov smbios_build_type_1_fields();
18369ea07a5SIgor Mammedov if (!smbios_validate_table(SMBIOS_ENTRY_POINT_TYPE_32, errp)) {
184643e1c9eSIgor Mammedov goto err_exit;
185643e1c9eSIgor Mammedov }
186643e1c9eSIgor Mammedov
187b42b0e4dSIgor Mammedov *length = smbios_entries_len;
188b42b0e4dSIgor Mammedov return smbios_entries;
189643e1c9eSIgor Mammedov err_exit:
190643e1c9eSIgor Mammedov g_free(smbios_entries);
191643e1c9eSIgor Mammedov return NULL;
192b42b0e4dSIgor Mammedov }
193