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.
18 * Structures shared with the BIOS
20 struct smbios_header
{
23 } __attribute__((__packed__
));
26 struct smbios_header header
;
30 } __attribute__((__packed__
));
33 struct smbios_header header
;
35 } __attribute__((__packed__
));
37 #define SMBIOS_FIELD_ENTRY 0
38 #define SMBIOS_TABLE_ENTRY 1
41 static uint8_t *smbios_entries
;
42 static size_t smbios_entries_len
;
43 static int smbios_type4_count
= 0;
45 static void smbios_validate_table(void)
47 if (smbios_type4_count
&& smbios_type4_count
!= smp_cpus
) {
49 "Number of SMBIOS Type 4 tables must match cpu count.\n");
54 uint8_t *smbios_get_table(size_t *length
)
56 smbios_validate_table();
57 *length
= smbios_entries_len
;
58 return smbios_entries
;
62 * To avoid unresolvable overlaps in data, don't allow both
63 * tables and fields for the same smbios type.
65 static void smbios_check_collision(int type
, int entry
)
67 uint16_t *num_entries
= (uint16_t *)smbios_entries
;
68 struct smbios_header
*header
;
75 p
= (char *)(num_entries
+ 1);
77 for (i
= 0; i
< *num_entries
; i
++) {
78 header
= (struct smbios_header
*)p
;
79 if (entry
== SMBIOS_TABLE_ENTRY
&& header
->type
== SMBIOS_FIELD_ENTRY
) {
80 struct smbios_field
*field
= (void *)header
;
81 if (type
== field
->type
) {
82 fprintf(stderr
, "SMBIOS type %d field already defined, "
83 "cannot add table\n", type
);
86 } else if (entry
== SMBIOS_FIELD_ENTRY
&&
87 header
->type
== SMBIOS_TABLE_ENTRY
) {
88 struct smbios_structure_header
*table
= (void *)(header
+ 1);
89 if (type
== table
->type
) {
90 fprintf(stderr
, "SMBIOS type %d table already defined, "
91 "cannot add field\n", type
);
95 p
+= le16_to_cpu(header
->length
);
99 void smbios_add_field(int type
, int offset
, int len
, void *data
)
101 struct smbios_field
*field
;
103 smbios_check_collision(type
, SMBIOS_FIELD_ENTRY
);
105 if (!smbios_entries
) {
106 smbios_entries_len
= sizeof(uint16_t);
107 smbios_entries
= qemu_mallocz(smbios_entries_len
);
109 smbios_entries
= qemu_realloc(smbios_entries
, smbios_entries_len
+
110 sizeof(*field
) + len
);
111 field
= (struct smbios_field
*)(smbios_entries
+ smbios_entries_len
);
112 field
->header
.type
= SMBIOS_FIELD_ENTRY
;
113 field
->header
.length
= cpu_to_le16(sizeof(*field
) + len
);
116 field
->offset
= cpu_to_le16(offset
);
117 memcpy(field
->data
, data
, len
);
119 smbios_entries_len
+= sizeof(*field
) + len
;
120 (*(uint16_t *)smbios_entries
) =
121 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
124 static void smbios_build_type_0_fields(const char *t
)
128 if (get_param_value(buf
, sizeof(buf
), "vendor", t
))
129 smbios_add_field(0, offsetof(struct smbios_type_0
, vendor_str
),
130 strlen(buf
) + 1, buf
);
131 if (get_param_value(buf
, sizeof(buf
), "version", t
))
132 smbios_add_field(0, offsetof(struct smbios_type_0
, bios_version_str
),
133 strlen(buf
) + 1, buf
);
134 if (get_param_value(buf
, sizeof(buf
), "date", t
))
135 smbios_add_field(0, offsetof(struct smbios_type_0
,
136 bios_release_date_str
),
137 strlen(buf
) + 1, buf
);
138 if (get_param_value(buf
, sizeof(buf
), "release", t
)) {
140 sscanf(buf
, "%d.%d", &major
, &minor
);
141 smbios_add_field(0, offsetof(struct smbios_type_0
,
142 system_bios_major_release
), 1, &major
);
143 smbios_add_field(0, offsetof(struct smbios_type_0
,
144 system_bios_minor_release
), 1, &minor
);
148 static void smbios_build_type_1_fields(const char *t
)
152 if (get_param_value(buf
, sizeof(buf
), "manufacturer", t
))
153 smbios_add_field(1, offsetof(struct smbios_type_1
, manufacturer_str
),
154 strlen(buf
) + 1, buf
);
155 if (get_param_value(buf
, sizeof(buf
), "product", t
))
156 smbios_add_field(1, offsetof(struct smbios_type_1
, product_name_str
),
157 strlen(buf
) + 1, buf
);
158 if (get_param_value(buf
, sizeof(buf
), "version", t
))
159 smbios_add_field(1, offsetof(struct smbios_type_1
, version_str
),
160 strlen(buf
) + 1, buf
);
161 if (get_param_value(buf
, sizeof(buf
), "serial", t
))
162 smbios_add_field(1, offsetof(struct smbios_type_1
, serial_number_str
),
163 strlen(buf
) + 1, buf
);
164 if (get_param_value(buf
, sizeof(buf
), "uuid", t
)) {
165 if (qemu_uuid_parse(buf
, qemu_uuid
) != 0) {
166 fprintf(stderr
, "Invalid SMBIOS UUID string\n");
170 if (get_param_value(buf
, sizeof(buf
), "sku", t
))
171 smbios_add_field(1, offsetof(struct smbios_type_1
, sku_number_str
),
172 strlen(buf
) + 1, buf
);
173 if (get_param_value(buf
, sizeof(buf
), "family", t
))
174 smbios_add_field(1, offsetof(struct smbios_type_1
, family_str
),
175 strlen(buf
) + 1, buf
);
178 int smbios_entry_add(const char *t
)
182 if (get_param_value(buf
, sizeof(buf
), "file", t
)) {
183 struct smbios_structure_header
*header
;
184 struct smbios_table
*table
;
185 int size
= get_image_size(buf
);
187 if (size
== -1 || size
< sizeof(struct smbios_structure_header
)) {
188 fprintf(stderr
, "Cannot read smbios file %s\n", buf
);
192 if (!smbios_entries
) {
193 smbios_entries_len
= sizeof(uint16_t);
194 smbios_entries
= qemu_mallocz(smbios_entries_len
);
197 smbios_entries
= qemu_realloc(smbios_entries
, smbios_entries_len
+
198 sizeof(*table
) + size
);
199 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
200 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
201 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
203 if (load_image(buf
, table
->data
) != size
) {
204 fprintf(stderr
, "Failed to load smbios file %s", buf
);
208 header
= (struct smbios_structure_header
*)(table
->data
);
209 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
210 if (header
->type
== 4) {
211 smbios_type4_count
++;
214 smbios_entries_len
+= sizeof(*table
) + size
;
215 (*(uint16_t *)smbios_entries
) =
216 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
220 if (get_param_value(buf
, sizeof(buf
), "type", t
)) {
221 unsigned long type
= strtoul(buf
, NULL
, 0);
224 smbios_build_type_0_fields(t
);
227 smbios_build_type_1_fields(t
);
230 fprintf(stderr
, "Don't know how to build fields for SMBIOS type "
236 fprintf(stderr
, "smbios: must specify type= or file=\n");