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
;
44 uint8_t *smbios_get_table(size_t *length
)
46 *length
= smbios_entries_len
;
47 return smbios_entries
;
51 * To avoid unresolvable overlaps in data, don't allow both
52 * tables and fields for the same smbios type.
54 static void smbios_check_collision(int type
, int entry
)
56 uint16_t *num_entries
= (uint16_t *)smbios_entries
;
57 struct smbios_header
*header
;
64 p
= (char *)(num_entries
+ 1);
66 for (i
= 0; i
< *num_entries
; i
++) {
67 header
= (struct smbios_header
*)p
;
68 if (entry
== SMBIOS_TABLE_ENTRY
&& header
->type
== SMBIOS_FIELD_ENTRY
) {
69 struct smbios_field
*field
= (void *)header
;
70 if (type
== field
->type
) {
71 fprintf(stderr
, "SMBIOS type %d field already defined, "
72 "cannot add table\n", type
);
75 } else if (entry
== SMBIOS_FIELD_ENTRY
&&
76 header
->type
== SMBIOS_TABLE_ENTRY
) {
77 struct smbios_structure_header
*table
= (void *)(header
+ 1);
78 if (type
== table
->type
) {
79 fprintf(stderr
, "SMBIOS type %d table already defined, "
80 "cannot add field\n", type
);
84 p
+= le16_to_cpu(header
->length
);
88 void smbios_add_field(int type
, int offset
, int len
, void *data
)
90 struct smbios_field
*field
;
92 smbios_check_collision(type
, SMBIOS_FIELD_ENTRY
);
94 if (!smbios_entries
) {
95 smbios_entries_len
= sizeof(uint16_t);
96 smbios_entries
= qemu_mallocz(smbios_entries_len
);
98 smbios_entries
= qemu_realloc(smbios_entries
, smbios_entries_len
+
99 sizeof(*field
) + len
);
100 field
= (struct smbios_field
*)(smbios_entries
+ smbios_entries_len
);
101 field
->header
.type
= SMBIOS_FIELD_ENTRY
;
102 field
->header
.length
= cpu_to_le16(sizeof(*field
) + len
);
105 field
->offset
= cpu_to_le16(offset
);
106 memcpy(field
->data
, data
, len
);
108 smbios_entries_len
+= sizeof(*field
) + len
;
109 (*(uint16_t *)smbios_entries
) =
110 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
113 static void smbios_build_type_0_fields(const char *t
)
117 if (get_param_value(buf
, sizeof(buf
), "vendor", t
))
118 smbios_add_field(0, offsetof(struct smbios_type_0
, vendor_str
),
119 strlen(buf
) + 1, buf
);
120 if (get_param_value(buf
, sizeof(buf
), "version", t
))
121 smbios_add_field(0, offsetof(struct smbios_type_0
, bios_version_str
),
122 strlen(buf
) + 1, buf
);
123 if (get_param_value(buf
, sizeof(buf
), "date", t
))
124 smbios_add_field(0, offsetof(struct smbios_type_0
,
125 bios_release_date_str
),
126 strlen(buf
) + 1, buf
);
127 if (get_param_value(buf
, sizeof(buf
), "release", t
)) {
129 sscanf(buf
, "%d.%d", &major
, &minor
);
130 smbios_add_field(0, offsetof(struct smbios_type_0
,
131 system_bios_major_release
), 1, &major
);
132 smbios_add_field(0, offsetof(struct smbios_type_0
,
133 system_bios_minor_release
), 1, &minor
);
137 static void smbios_build_type_1_fields(const char *t
)
141 if (get_param_value(buf
, sizeof(buf
), "manufacturer", t
))
142 smbios_add_field(1, offsetof(struct smbios_type_1
, manufacturer_str
),
143 strlen(buf
) + 1, buf
);
144 if (get_param_value(buf
, sizeof(buf
), "product", t
))
145 smbios_add_field(1, offsetof(struct smbios_type_1
, product_name_str
),
146 strlen(buf
) + 1, buf
);
147 if (get_param_value(buf
, sizeof(buf
), "version", t
))
148 smbios_add_field(1, offsetof(struct smbios_type_1
, version_str
),
149 strlen(buf
) + 1, buf
);
150 if (get_param_value(buf
, sizeof(buf
), "serial", t
))
151 smbios_add_field(1, offsetof(struct smbios_type_1
, serial_number_str
),
152 strlen(buf
) + 1, buf
);
153 if (get_param_value(buf
, sizeof(buf
), "uuid", t
)) {
154 if (qemu_uuid_parse(buf
, qemu_uuid
) != 0) {
155 fprintf(stderr
, "Invalid SMBIOS UUID string\n");
159 if (get_param_value(buf
, sizeof(buf
), "sku", t
))
160 smbios_add_field(1, offsetof(struct smbios_type_1
, sku_number_str
),
161 strlen(buf
) + 1, buf
);
162 if (get_param_value(buf
, sizeof(buf
), "family", t
))
163 smbios_add_field(1, offsetof(struct smbios_type_1
, family_str
),
164 strlen(buf
) + 1, buf
);
167 int smbios_entry_add(const char *t
)
171 if (get_param_value(buf
, sizeof(buf
), "file", t
)) {
172 struct smbios_structure_header
*header
;
173 struct smbios_table
*table
;
174 int size
= get_image_size(buf
);
176 if (size
< sizeof(struct smbios_structure_header
)) {
177 fprintf(stderr
, "Cannot read smbios file %s", buf
);
181 if (!smbios_entries
) {
182 smbios_entries_len
= sizeof(uint16_t);
183 smbios_entries
= qemu_mallocz(smbios_entries_len
);
186 smbios_entries
= qemu_realloc(smbios_entries
, smbios_entries_len
+
187 sizeof(*table
) + size
);
188 table
= (struct smbios_table
*)(smbios_entries
+ smbios_entries_len
);
189 table
->header
.type
= SMBIOS_TABLE_ENTRY
;
190 table
->header
.length
= cpu_to_le16(sizeof(*table
) + size
);
192 if (load_image(buf
, table
->data
) != size
) {
193 fprintf(stderr
, "Failed to load smbios file %s", buf
);
197 header
= (struct smbios_structure_header
*)(table
->data
);
198 smbios_check_collision(header
->type
, SMBIOS_TABLE_ENTRY
);
200 smbios_entries_len
+= sizeof(*table
) + size
;
201 (*(uint16_t *)smbios_entries
) =
202 cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries
) + 1);
206 if (get_param_value(buf
, sizeof(buf
), "type", t
)) {
207 unsigned long type
= strtoul(buf
, NULL
, 0);
210 smbios_build_type_0_fields(t
);
213 smbios_build_type_1_fields(t
);
216 fprintf(stderr
, "Don't know how to build fields for SMBIOS type "
222 fprintf(stderr
, "smbios: must specify type= or file=\n");