xref: /openbmc/qemu/hw/smbios/smbios_legacy.c (revision bb949df6)
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