4 * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
7 * Alex Williamson <alex.williamson@hp.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
12 * Contributions after 2012-01-13 are licensed under the terms of the
13 * GNU GPL, version 2 or (at your option) any later version.
16 #include "qemu/error-report.h"
17 #include "sysemu/sysemu.h"
18 #include "hw/i386/smbios.h"
19 #include "hw/loader.h"
22 * Structures shared with the BIOS
24 struct smbios_header
{
30 struct smbios_header header
;
37 struct smbios_header header
;
41 #define SMBIOS_FIELD_ENTRY 0
42 #define SMBIOS_TABLE_ENTRY 1
45 static uint8_t *smbios_entries
;
46 static size_t smbios_entries_len
;
47 static int smbios_type4_count
= 0;
49 static void smbios_validate_table(void)
51 if (smbios_type4_count
&& smbios_type4_count
!= smp_cpus
) {
52 error_report("Number of SMBIOS Type 4 tables must match cpu count");
57 uint8_t *smbios_get_table(size_t *length
)
59 smbios_validate_table();
60 *length
= smbios_entries_len
;
61 return smbios_entries
;
65 * To avoid unresolvable overlaps in data, don't allow both
66 * tables and fields for the same smbios type.
68 static void smbios_check_collision(int type
, int entry
)
70 uint16_t *num_entries
= (uint16_t *)smbios_entries
;
71 struct smbios_header
*header
;
78 p
= (char *)(num_entries
+ 1);
80 for (i
= 0; i
< *num_entries
; i
++) {
81 header
= (struct smbios_header
*)p
;
82 if (entry
== SMBIOS_TABLE_ENTRY
&& header
->type
== SMBIOS_FIELD_ENTRY
) {
83 struct smbios_field
*field
= (void *)header
;
84 if (type
== field
->type
) {
85 error_report("SMBIOS type %d field already defined, "
86 "cannot add table", type
);
89 } else if (entry
== SMBIOS_FIELD_ENTRY
&&
90 header
->type
== SMBIOS_TABLE_ENTRY
) {
91 struct smbios_structure_header
*table
= (void *)(header
+ 1);
92 if (type
== table
->type
) {
93 error_report("SMBIOS type %d table already defined, "
94 "cannot add field", type
);
98 p
+= le16_to_cpu(header
->length
);
102 void smbios_add_field(int type
, int offset
, const void *data
, size_t len
)
104 struct smbios_field
*field
;
106 smbios_check_collision(type
, SMBIOS_FIELD_ENTRY
);
108 if (!smbios_entries
) {
109 smbios_entries_len
= sizeof(uint16_t);
110 smbios_entries
= g_malloc0(smbios_entries_len
);
112 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
113 sizeof(*field
) + len
);
114 field
= (struct smbios_field
*)(smbios_entries
+ smbios_entries_len
);
115 field
->header
.type
= SMBIOS_FIELD_ENTRY
;
116 field
->header
.length
= cpu_to_le16(sizeof(*field
) + len
);
119 field
->offset
= cpu_to_le16(offset
);
120 memcpy(field
->data
, data
, len
);
122 smbios_entries_len
+= sizeof(*field
) + len
;
123 (*(uint16_t *)smbios_entries
) =
124 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
127 static void smbios_build_type_0_fields(const char *t
)
130 unsigned char major
, minor
;
132 if (get_param_value(buf
, sizeof(buf
), "vendor", t
))
133 smbios_add_field(0, offsetof(struct smbios_type_0
, vendor_str
),
134 buf
, strlen(buf
) + 1);
135 if (get_param_value(buf
, sizeof(buf
), "version", t
))
136 smbios_add_field(0, offsetof(struct smbios_type_0
, bios_version_str
),
137 buf
, strlen(buf
) + 1);
138 if (get_param_value(buf
, sizeof(buf
), "date", t
))
139 smbios_add_field(0, offsetof(struct smbios_type_0
,
140 bios_release_date_str
),
141 buf
, strlen(buf
) + 1);
142 if (get_param_value(buf
, sizeof(buf
), "release", t
)) {
143 if (sscanf(buf
, "%hhu.%hhu", &major
, &minor
) != 2) {
144 error_report("Invalid release");
147 smbios_add_field(0, offsetof(struct smbios_type_0
,
148 system_bios_major_release
),
150 smbios_add_field(0, offsetof(struct smbios_type_0
,
151 system_bios_minor_release
),
156 static void smbios_build_type_1_fields(const char *t
)
160 if (get_param_value(buf
, sizeof(buf
), "manufacturer", t
))
161 smbios_add_field(1, offsetof(struct smbios_type_1
, manufacturer_str
),
162 buf
, strlen(buf
) + 1);
163 if (get_param_value(buf
, sizeof(buf
), "product", t
))
164 smbios_add_field(1, offsetof(struct smbios_type_1
, product_name_str
),
165 buf
, strlen(buf
) + 1);
166 if (get_param_value(buf
, sizeof(buf
), "version", t
))
167 smbios_add_field(1, offsetof(struct smbios_type_1
, version_str
),
168 buf
, strlen(buf
) + 1);
169 if (get_param_value(buf
, sizeof(buf
), "serial", t
))
170 smbios_add_field(1, offsetof(struct smbios_type_1
, serial_number_str
),
171 buf
, strlen(buf
) + 1);
172 if (get_param_value(buf
, sizeof(buf
), "uuid", t
)) {
173 if (qemu_uuid_parse(buf
, qemu_uuid
) != 0) {
174 error_report("Invalid UUID");
178 if (get_param_value(buf
, sizeof(buf
), "sku", t
))
179 smbios_add_field(1, offsetof(struct smbios_type_1
, sku_number_str
),
180 buf
, strlen(buf
) + 1);
181 if (get_param_value(buf
, sizeof(buf
), "family", t
))
182 smbios_add_field(1, offsetof(struct smbios_type_1
, family_str
),
183 buf
, strlen(buf
) + 1);
186 int smbios_entry_add(const char *t
)
190 if (get_param_value(buf
, sizeof(buf
), "file", t
)) {
191 struct smbios_structure_header
*header
;
192 struct smbios_table
*table
;
193 int size
= get_image_size(buf
);
195 if (size
== -1 || size
< sizeof(struct smbios_structure_header
)) {
196 error_report("Cannot read SMBIOS file %s", buf
);
200 if (!smbios_entries
) {
201 smbios_entries_len
= sizeof(uint16_t);
202 smbios_entries
= g_malloc0(smbios_entries_len
);
205 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
206 sizeof(*table
) + size
);
207 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
208 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
209 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
211 if (load_image(buf
, table
->data
) != size
) {
212 error_report("Failed to load SMBIOS file %s", buf
);
216 header
= (struct smbios_structure_header
*)(table
->data
);
217 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
218 if (header
->type
== 4) {
219 smbios_type4_count
++;
222 smbios_entries_len
+= sizeof(*table
) + size
;
223 (*(uint16_t *)smbios_entries
) =
224 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
228 if (get_param_value(buf
, sizeof(buf
), "type", t
)) {
229 unsigned long type
= strtoul(buf
, NULL
, 0);
232 smbios_build_type_0_fields(t
);
235 smbios_build_type_1_fields(t
);
238 error_report("Don't know how to build fields for SMBIOS type %ld",
244 error_report("Must specify type= or file=");