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 "sysemu/sysemu.h"
21 * Structures shared with the BIOS
23 struct smbios_header
{
29 struct smbios_header header
;
36 struct smbios_header header
;
40 #define SMBIOS_FIELD_ENTRY 0
41 #define SMBIOS_TABLE_ENTRY 1
44 static uint8_t *smbios_entries
;
45 static size_t smbios_entries_len
;
46 static int smbios_type4_count
= 0;
48 static void smbios_validate_table(void)
50 if (smbios_type4_count
&& smbios_type4_count
!= smp_cpus
) {
52 "Number of SMBIOS Type 4 tables must match cpu count.\n");
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 fprintf(stderr
, "SMBIOS type %d field already defined, "
86 "cannot add table\n", 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 fprintf(stderr
, "SMBIOS type %d table already defined, "
94 "cannot add field\n", type
);
98 p
+= le16_to_cpu(header
->length
);
102 void smbios_add_field(int type
, int offset
, int len
, void *data
)
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
)
131 if (get_param_value(buf
, sizeof(buf
), "vendor", t
))
132 smbios_add_field(0, offsetof(struct smbios_type_0
, vendor_str
),
133 strlen(buf
) + 1, buf
);
134 if (get_param_value(buf
, sizeof(buf
), "version", t
))
135 smbios_add_field(0, offsetof(struct smbios_type_0
, bios_version_str
),
136 strlen(buf
) + 1, buf
);
137 if (get_param_value(buf
, sizeof(buf
), "date", t
))
138 smbios_add_field(0, offsetof(struct smbios_type_0
,
139 bios_release_date_str
),
140 strlen(buf
) + 1, buf
);
141 if (get_param_value(buf
, sizeof(buf
), "release", t
)) {
143 sscanf(buf
, "%d.%d", &major
, &minor
);
144 smbios_add_field(0, offsetof(struct smbios_type_0
,
145 system_bios_major_release
), 1, &major
);
146 smbios_add_field(0, offsetof(struct smbios_type_0
,
147 system_bios_minor_release
), 1, &minor
);
151 static void smbios_build_type_1_fields(const char *t
)
155 if (get_param_value(buf
, sizeof(buf
), "manufacturer", t
))
156 smbios_add_field(1, offsetof(struct smbios_type_1
, manufacturer_str
),
157 strlen(buf
) + 1, buf
);
158 if (get_param_value(buf
, sizeof(buf
), "product", t
))
159 smbios_add_field(1, offsetof(struct smbios_type_1
, product_name_str
),
160 strlen(buf
) + 1, buf
);
161 if (get_param_value(buf
, sizeof(buf
), "version", t
))
162 smbios_add_field(1, offsetof(struct smbios_type_1
, version_str
),
163 strlen(buf
) + 1, buf
);
164 if (get_param_value(buf
, sizeof(buf
), "serial", t
))
165 smbios_add_field(1, offsetof(struct smbios_type_1
, serial_number_str
),
166 strlen(buf
) + 1, buf
);
167 if (get_param_value(buf
, sizeof(buf
), "uuid", t
)) {
168 if (qemu_uuid_parse(buf
, qemu_uuid
) != 0) {
169 fprintf(stderr
, "Invalid SMBIOS UUID string\n");
173 if (get_param_value(buf
, sizeof(buf
), "sku", t
))
174 smbios_add_field(1, offsetof(struct smbios_type_1
, sku_number_str
),
175 strlen(buf
) + 1, buf
);
176 if (get_param_value(buf
, sizeof(buf
), "family", t
))
177 smbios_add_field(1, offsetof(struct smbios_type_1
, family_str
),
178 strlen(buf
) + 1, buf
);
181 int smbios_entry_add(const char *t
)
185 if (get_param_value(buf
, sizeof(buf
), "file", t
)) {
186 struct smbios_structure_header
*header
;
187 struct smbios_table
*table
;
188 int size
= get_image_size(buf
);
190 if (size
== -1 || size
< sizeof(struct smbios_structure_header
)) {
191 fprintf(stderr
, "Cannot read smbios file %s\n", buf
);
195 if (!smbios_entries
) {
196 smbios_entries_len
= sizeof(uint16_t);
197 smbios_entries
= g_malloc0(smbios_entries_len
);
200 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
201 sizeof(*table
) + size
);
202 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
203 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
204 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
206 if (load_image(buf
, table
->data
) != size
) {
207 fprintf(stderr
, "Failed to load smbios file %s", buf
);
211 header
= (struct smbios_structure_header
*)(table
->data
);
212 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
213 if (header
->type
== 4) {
214 smbios_type4_count
++;
217 smbios_entries_len
+= sizeof(*table
) + size
;
218 (*(uint16_t *)smbios_entries
) =
219 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
223 if (get_param_value(buf
, sizeof(buf
), "type", t
)) {
224 unsigned long type
= strtoul(buf
, NULL
, 0);
227 smbios_build_type_0_fields(t
);
230 smbios_build_type_1_fields(t
);
233 fprintf(stderr
, "Don't know how to build fields for SMBIOS type "
239 fprintf(stderr
, "smbios: must specify type= or file=\n");