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.
19 * Structures shared with the BIOS
21 struct smbios_header
{
27 struct smbios_header header
;
34 struct smbios_header header
;
38 #define SMBIOS_FIELD_ENTRY 0
39 #define SMBIOS_TABLE_ENTRY 1
42 static uint8_t *smbios_entries
;
43 static size_t smbios_entries_len
;
44 static int smbios_type4_count
= 0;
46 static void smbios_validate_table(void)
48 if (smbios_type4_count
&& smbios_type4_count
!= smp_cpus
) {
50 "Number of SMBIOS Type 4 tables must match cpu count.\n");
55 uint8_t *smbios_get_table(size_t *length
)
57 smbios_validate_table();
58 *length
= smbios_entries_len
;
59 return smbios_entries
;
63 * To avoid unresolvable overlaps in data, don't allow both
64 * tables and fields for the same smbios type.
66 static void smbios_check_collision(int type
, int entry
)
68 uint16_t *num_entries
= (uint16_t *)smbios_entries
;
69 struct smbios_header
*header
;
76 p
= (char *)(num_entries
+ 1);
78 for (i
= 0; i
< *num_entries
; i
++) {
79 header
= (struct smbios_header
*)p
;
80 if (entry
== SMBIOS_TABLE_ENTRY
&& header
->type
== SMBIOS_FIELD_ENTRY
) {
81 struct smbios_field
*field
= (void *)header
;
82 if (type
== field
->type
) {
83 fprintf(stderr
, "SMBIOS type %d field already defined, "
84 "cannot add table\n", type
);
87 } else if (entry
== SMBIOS_FIELD_ENTRY
&&
88 header
->type
== SMBIOS_TABLE_ENTRY
) {
89 struct smbios_structure_header
*table
= (void *)(header
+ 1);
90 if (type
== table
->type
) {
91 fprintf(stderr
, "SMBIOS type %d table already defined, "
92 "cannot add field\n", type
);
96 p
+= le16_to_cpu(header
->length
);
100 void smbios_add_field(int type
, int offset
, int len
, void *data
)
102 struct smbios_field
*field
;
104 smbios_check_collision(type
, SMBIOS_FIELD_ENTRY
);
106 if (!smbios_entries
) {
107 smbios_entries_len
= sizeof(uint16_t);
108 smbios_entries
= g_malloc0(smbios_entries_len
);
110 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
111 sizeof(*field
) + len
);
112 field
= (struct smbios_field
*)(smbios_entries
+ smbios_entries_len
);
113 field
->header
.type
= SMBIOS_FIELD_ENTRY
;
114 field
->header
.length
= cpu_to_le16(sizeof(*field
) + len
);
117 field
->offset
= cpu_to_le16(offset
);
118 memcpy(field
->data
, data
, len
);
120 smbios_entries_len
+= sizeof(*field
) + len
;
121 (*(uint16_t *)smbios_entries
) =
122 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
125 static void smbios_build_type_0_fields(const char *t
)
129 if (get_param_value(buf
, sizeof(buf
), "vendor", t
))
130 smbios_add_field(0, offsetof(struct smbios_type_0
, vendor_str
),
131 strlen(buf
) + 1, buf
);
132 if (get_param_value(buf
, sizeof(buf
), "version", t
))
133 smbios_add_field(0, offsetof(struct smbios_type_0
, bios_version_str
),
134 strlen(buf
) + 1, buf
);
135 if (get_param_value(buf
, sizeof(buf
), "date", t
))
136 smbios_add_field(0, offsetof(struct smbios_type_0
,
137 bios_release_date_str
),
138 strlen(buf
) + 1, buf
);
139 if (get_param_value(buf
, sizeof(buf
), "release", t
)) {
141 sscanf(buf
, "%d.%d", &major
, &minor
);
142 smbios_add_field(0, offsetof(struct smbios_type_0
,
143 system_bios_major_release
), 1, &major
);
144 smbios_add_field(0, offsetof(struct smbios_type_0
,
145 system_bios_minor_release
), 1, &minor
);
149 static void smbios_build_type_1_fields(const char *t
)
153 if (get_param_value(buf
, sizeof(buf
), "manufacturer", t
))
154 smbios_add_field(1, offsetof(struct smbios_type_1
, manufacturer_str
),
155 strlen(buf
) + 1, buf
);
156 if (get_param_value(buf
, sizeof(buf
), "product", t
))
157 smbios_add_field(1, offsetof(struct smbios_type_1
, product_name_str
),
158 strlen(buf
) + 1, buf
);
159 if (get_param_value(buf
, sizeof(buf
), "version", t
))
160 smbios_add_field(1, offsetof(struct smbios_type_1
, version_str
),
161 strlen(buf
) + 1, buf
);
162 if (get_param_value(buf
, sizeof(buf
), "serial", t
))
163 smbios_add_field(1, offsetof(struct smbios_type_1
, serial_number_str
),
164 strlen(buf
) + 1, buf
);
165 if (get_param_value(buf
, sizeof(buf
), "uuid", t
)) {
166 if (qemu_uuid_parse(buf
, qemu_uuid
) != 0) {
167 fprintf(stderr
, "Invalid SMBIOS UUID string\n");
171 if (get_param_value(buf
, sizeof(buf
), "sku", t
))
172 smbios_add_field(1, offsetof(struct smbios_type_1
, sku_number_str
),
173 strlen(buf
) + 1, buf
);
174 if (get_param_value(buf
, sizeof(buf
), "family", t
))
175 smbios_add_field(1, offsetof(struct smbios_type_1
, family_str
),
176 strlen(buf
) + 1, buf
);
179 int smbios_entry_add(const char *t
)
183 if (get_param_value(buf
, sizeof(buf
), "file", t
)) {
184 struct smbios_structure_header
*header
;
185 struct smbios_table
*table
;
186 int size
= get_image_size(buf
);
188 if (size
== -1 || size
< sizeof(struct smbios_structure_header
)) {
189 fprintf(stderr
, "Cannot read smbios file %s\n", buf
);
193 if (!smbios_entries
) {
194 smbios_entries_len
= sizeof(uint16_t);
195 smbios_entries
= g_malloc0(smbios_entries_len
);
198 smbios_entries
= g_realloc(smbios_entries
, smbios_entries_len
+
199 sizeof(*table
) + size
);
200 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
201 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
202 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
204 if (load_image(buf
, table
->data
) != size
) {
205 fprintf(stderr
, "Failed to load smbios file %s", buf
);
209 header
= (struct smbios_structure_header
*)(table
->data
);
210 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
211 if (header
->type
== 4) {
212 smbios_type4_count
++;
215 smbios_entries_len
+= sizeof(*table
) + size
;
216 (*(uint16_t *)smbios_entries
) =
217 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
221 if (get_param_value(buf
, sizeof(buf
), "type", t
)) {
222 unsigned long type
= strtoul(buf
, NULL
, 0);
225 smbios_build_type_0_fields(t
);
228 smbios_build_type_1_fields(t
);
231 fprintf(stderr
, "Don't know how to build fields for SMBIOS type "
237 fprintf(stderr
, "smbios: must specify type= or file=\n");