xref: /illumos-gate/usr/src/test/util-tests/tests/smbios/smbios.c (revision 12fb9219923f41528f673d4f31667db2c3f103ff)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (c) 2018, Joyent, Inc.
14  * Copyright 2023 Oxide Computer Company
15  */
16 
17 /*
18  * Primordial SMBIOS test suite. At the moment, the purpose of this is just to
19  * test the recent SMBIOS 3.2 additions specific to the variable length slots.
20  * This should be evolved into a much fuller test suite.
21  */
22 
23 #include <umem.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <unistd.h>
29 #include "smbios_test.h"
30 
31 static int test_dirfd = -1;
32 
33 const char *
34 _umem_debug_init(void)
35 {
36 	return ("default,verbose");
37 }
38 
39 const char *
40 _umem_logging_init(void)
41 {
42 	return ("fail,contents");
43 }
44 
45 smbios_test_table_t *
46 smbios_test_table_init(smbios_entry_point_t type, uint_t version)
47 {
48 	smbios_test_table_t *table;
49 
50 	if (type != SMBIOS_ENTRY_POINT_30) {
51 		abort();
52 	}
53 
54 	table = umem_zalloc(sizeof (smbios_test_table_t), UMEM_DEFAULT);
55 	if (table == NULL) {
56 		return (NULL);
57 	}
58 
59 	table->stt_data = umem_zalloc(SMBIOS_TEST_ALLOC_SIZE, UMEM_DEFAULT);
60 	if (table->stt_data == NULL) {
61 		umem_free(table, sizeof (smbios_test_table_t));
62 		return (NULL);
63 	}
64 	table->stt_buflen = SMBIOS_TEST_ALLOC_SIZE;
65 	table->stt_type = type;
66 	table->stt_version = version;
67 	table->stt_nextid = 1;
68 
69 	return (table);
70 }
71 
72 static void *
73 smbios_test_table_append_common(smbios_test_table_t *table, const void *buf,
74     size_t len)
75 {
76 	void *start;
77 
78 	if (SIZE_MAX - table->stt_offset < len)
79 		abort();
80 
81 	if (len + table->stt_offset >= table->stt_buflen) {
82 		void *newbuf;
83 		size_t newlen = table->stt_buflen + SMBIOS_TEST_ALLOC_SIZE;
84 
85 		while (len + table->stt_offset >= newlen) {
86 			newlen += SMBIOS_TEST_ALLOC_SIZE;
87 		}
88 
89 		newbuf = umem_zalloc(newlen, UMEM_DEFAULT);
90 		if (newbuf == NULL) {
91 			err(EXIT_FAILURE, "failed to umem_zalloc for %zu bytes",
92 			    newlen);
93 		}
94 
95 		(void) memcpy(newbuf, table->stt_data, table->stt_buflen);
96 		umem_free(table->stt_data, table->stt_buflen);
97 		table->stt_data = newbuf;
98 		table->stt_buflen = newlen;
99 	}
100 
101 	start = (void *)((uintptr_t)table->stt_data + table->stt_offset);
102 	(void) memcpy(start, buf, len);
103 	table->stt_offset += len;
104 
105 	return (start);
106 }
107 
108 void
109 smbios_test_table_append_raw(smbios_test_table_t *table, const void *buf,
110     size_t len)
111 {
112 	(void) smbios_test_table_append_common(table, buf, len);
113 }
114 
115 void
116 smbios_test_table_append_string(smbios_test_table_t *table, const char *str)
117 {
118 	size_t len = strlen(str) + 1;
119 	(void) smbios_test_table_append_common(table, str, len);
120 }
121 
122 void
123 smbios_test_table_str_fini(smbios_test_table_t *table)
124 {
125 	const uint8_t endstring = 0;
126 
127 	smbios_test_table_append_raw(table, &endstring, sizeof (endstring));
128 }
129 
130 uint16_t
131 smbios_test_table_append(smbios_test_table_t *table, const void *buf,
132     size_t len)
133 {
134 	smb_header_t *hdr;
135 	uint16_t id;
136 
137 	hdr = smbios_test_table_append_common(table, buf, len);
138 	table->stt_nents++;
139 
140 	id = table->stt_nextid;
141 	hdr->smbh_hdl = htole16(table->stt_nextid);
142 	table->stt_nextid++;
143 
144 	return (id);
145 }
146 
147 void
148 smbios_test_table_append_eot(smbios_test_table_t *table)
149 {
150 	smb_header_t eot;
151 	uint8_t endstring = 0;
152 
153 	bzero(&eot, sizeof (eot));
154 	eot.smbh_type = SMB_TYPE_EOT;
155 	eot.smbh_len = 4;
156 	(void) smbios_test_table_append(table, &eot, sizeof (eot));
157 	(void) smbios_test_table_append_raw(table, &endstring,
158 	    sizeof (endstring));
159 	smbios_test_table_append_raw(table, &endstring,
160 	    sizeof (endstring));
161 	smbios_test_table_append_raw(table, &endstring,
162 	    sizeof (endstring));
163 
164 }
165 
166 static uint8_t
167 smbios_test_table_checksum(const uint8_t *buf, size_t len)
168 {
169 	uint8_t sum;
170 	size_t i;
171 
172 	for (i = 0, sum = 0; i < len; i++) {
173 		sum += buf[i];
174 	}
175 
176 	if (sum == 0)
177 		return (0);
178 
179 	return ((uint8_t)(0x100 - sum));
180 }
181 
182 static void
183 smbios_test_table_snapshot(smbios_test_table_t *table, smbios_entry_t **entryp,
184     void **bufp, size_t *lenp)
185 {
186 	smbios_30_entry_t *ent30;
187 
188 	switch (table->stt_type) {
189 	case SMBIOS_ENTRY_POINT_30:
190 		ent30 = &table->stt_entry.ep30;
191 
192 		(void) memcpy(ent30->smbe_eanchor, SMB3_ENTRY_EANCHOR,
193 		    sizeof (ent30->smbe_eanchor));
194 		ent30->smbe_ecksum = 0;
195 		ent30->smbe_elen = sizeof (*ent30);
196 		ent30->smbe_major = (table->stt_version >> 8) & 0xff;
197 		ent30->smbe_minor = table->stt_version & 0xff;
198 		ent30->smbe_docrev = 0;
199 		ent30->smbe_revision = 1;
200 		ent30->smbe_reserved = 0;
201 		ent30->smbe_stlen = htole32(table->stt_offset);
202 		ent30->smbe_staddr = htole64(P2ROUNDUP(sizeof (*ent30), 16));
203 
204 		ent30->smbe_ecksum = smbios_test_table_checksum((void *)ent30,
205 		    sizeof (*ent30));
206 		break;
207 	default:
208 		abort();
209 	}
210 
211 	*entryp = &table->stt_entry;
212 	*bufp = table->stt_data;
213 	*lenp = table->stt_offset;
214 }
215 
216 static void
217 smbios_test_table_fini(smbios_test_table_t *table)
218 {
219 	if (table == NULL) {
220 		return;
221 	}
222 
223 	if (table->stt_data != NULL) {
224 		umem_free(table->stt_data, table->stt_buflen);
225 	}
226 
227 	umem_free(table, sizeof (smbios_test_table_t));
228 }
229 
230 static const smbios_test_t smbios_tests[] = {
231 	{
232 	    .st_entry = SMBIOS_ENTRY_POINT_30,
233 	    .st_tvers = SMB_VERSION,
234 	    .st_libvers = 0xffff,
235 	    .st_mktable = smbios_test_badvers_mktable,
236 	    .st_desc = "bad library version"
237 	}, {
238 	    .st_entry = SMBIOS_ENTRY_POINT_30,
239 	    .st_tvers = SMB_VERSION,
240 	    .st_libvers = 0,
241 	    .st_mktable = smbios_test_badvers_mktable,
242 	    .st_desc = "bad library version (zeros)"
243 	}, {
244 	    .st_entry = SMBIOS_ENTRY_POINT_30,
245 	    .st_tvers = SMB_VERSION,
246 	    .st_libvers = SMB_VERSION,
247 	    .st_mktable = smbios_test_slot_mktable,
248 	    .st_canopen = B_TRUE,
249 	    .st_verify = smbios_test_verify_badids,
250 	    .st_desc = "smbios_info_* with bad id"
251 	}, {
252 	    .st_entry = SMBIOS_ENTRY_POINT_30,
253 	    .st_tvers = SMB_VERSION,
254 	    .st_libvers = SMB_VERSION,
255 	    .st_mktable = smbios_test_slot_mktable,
256 	    .st_canopen = B_TRUE,
257 	    .st_verify = smbios_test_verify_strings,
258 	    .st_desc = "smbios string functions"
259 	}, {
260 	    .st_entry = SMBIOS_ENTRY_POINT_30,
261 	    .st_tvers = SMB_VERSION_32,
262 	    .st_libvers = SMB_VERSION,
263 	    .st_mktable = smbios_test_slot_mktable,
264 	    .st_canopen = B_TRUE,
265 	    .st_verify = smbios_test_slot_verify,
266 	    .st_desc = "slot 3.2"
267 	}, {
268 	    .st_entry = SMBIOS_ENTRY_POINT_30,
269 	    .st_tvers = SMB_VERSION_34,
270 	    .st_libvers = SMB_VERSION,
271 	    .st_mktable = smbios_test_slot_mktable_34_nopeers,
272 	    .st_canopen = B_TRUE,
273 	    .st_verify = smbios_test_slot_verify_34_nopeers,
274 	    .st_desc = "slot 3.4 without peers"
275 	}, {
276 	    .st_entry = SMBIOS_ENTRY_POINT_30,
277 	    .st_tvers = SMB_VERSION_34,
278 	    .st_libvers = SMB_VERSION,
279 	    .st_mktable = smbios_test_slot_mktable_34_peers,
280 	    .st_canopen = B_TRUE,
281 	    .st_verify = smbios_test_slot_verify_34_peers,
282 	    .st_desc = "slot 3.4 with peers"
283 	}, {
284 	    .st_entry = SMBIOS_ENTRY_POINT_30,
285 	    .st_tvers = SMB_VERSION_35,
286 	    .st_libvers = SMB_VERSION_34,
287 	    .st_mktable = smbios_test_slot_mktable_35,
288 	    .st_canopen = B_TRUE,
289 	    .st_verify = smbios_test_slot_verify_34_overrun,
290 	    .st_desc = "slot 3.5 against 3.4 lib"
291 	}, {
292 	    .st_entry = SMBIOS_ENTRY_POINT_30,
293 	    .st_tvers = SMB_VERSION_35,
294 	    .st_libvers = SMB_VERSION,
295 	    .st_mktable = smbios_test_slot_mktable_35,
296 	    .st_canopen = B_TRUE,
297 	    .st_verify = smbios_test_slot_verify_35,
298 	    .st_desc = "slot 3.5"
299 	}, {
300 	    .st_entry = SMBIOS_ENTRY_POINT_30,
301 	    .st_tvers = SMB_VERSION_32,
302 	    .st_libvers = SMB_VERSION_32,
303 	    .st_mktable = smbios_test_memdevice_mktable_32,
304 	    .st_canopen = B_TRUE,
305 	    .st_verify = smbios_test_memdevice_verify_32,
306 	    .st_desc = "memory device 3.2 % 3.2"
307 	}, {
308 	    .st_entry = SMBIOS_ENTRY_POINT_30,
309 	    .st_tvers = SMB_VERSION_32,
310 	    .st_libvers = SMB_VERSION_33,
311 	    .st_mktable = smbios_test_memdevice_mktable_32,
312 	    .st_canopen = B_TRUE,
313 	    .st_verify = smbios_test_memdevice_verify_32_33,
314 	    .st_desc = "memory device 3.2 % 3.3"
315 	}, {
316 	    .st_entry = SMBIOS_ENTRY_POINT_30,
317 	    .st_tvers = SMB_VERSION_32,
318 	    .st_libvers = SMB_VERSION_37,
319 	    .st_mktable = smbios_test_memdevice_mktable_32,
320 	    .st_canopen = B_TRUE,
321 	    .st_verify = smbios_test_memdevice_verify_32_37,
322 	    .st_desc = "memory device 3.2 % 3.7"
323 	}, {
324 	    .st_entry = SMBIOS_ENTRY_POINT_30,
325 	    .st_tvers = SMB_VERSION_33,
326 	    .st_libvers = SMB_VERSION_33,
327 	    .st_mktable = smbios_test_memdevice_mktable_33,
328 	    .st_canopen = B_TRUE,
329 	    .st_verify = smbios_test_memdevice_verify_33,
330 	    .st_desc = "memory device 3.3"
331 	}, {
332 	    .st_entry = SMBIOS_ENTRY_POINT_30,
333 	    .st_tvers = SMB_VERSION_33,
334 	    .st_libvers = SMB_VERSION_33,
335 	    .st_mktable = smbios_test_memdevice_mktable_33ext,
336 	    .st_canopen = B_TRUE,
337 	    .st_verify = smbios_test_memdevice_verify_33ext,
338 	    .st_desc = "memory device 3.3 with extended data"
339 	}, {
340 	    .st_entry = SMBIOS_ENTRY_POINT_30,
341 	    .st_tvers = SMB_VERSION_37,
342 	    .st_libvers = SMB_VERSION_37,
343 	    .st_mktable = smbios_test_memdevice_mktable_37,
344 	    .st_canopen = B_TRUE,
345 	    .st_verify = smbios_test_memdevice_verify_37,
346 	    .st_desc = "memory device 3.7"
347 	}, {
348 	    .st_entry = SMBIOS_ENTRY_POINT_30,
349 	    .st_tvers = SMB_VERSION,
350 	    .st_libvers = SMB_VERSION,
351 	    .st_mktable = smbios_test_pinfo_mktable_amd64,
352 	    .st_canopen = B_TRUE,
353 	    .st_verify = smbios_test_pinfo_verify_amd64,
354 	    .st_desc = "processor additional information - amd64"
355 	}, {
356 	    .st_entry = SMBIOS_ENTRY_POINT_30,
357 	    .st_tvers = SMB_VERSION,
358 	    .st_libvers = SMB_VERSION,
359 	    .st_mktable = smbios_test_pinfo_mktable_riscv,
360 	    .st_canopen = B_TRUE,
361 	    .st_verify = smbios_test_pinfo_verify_riscv,
362 	    .st_desc = "processor additional information - riscv"
363 	}, {
364 	    .st_entry = SMBIOS_ENTRY_POINT_30,
365 	    .st_tvers = SMB_VERSION,
366 	    .st_libvers = SMB_VERSION,
367 	    .st_mktable = smbios_test_pinfo_mktable_invlen1,
368 	    .st_canopen = B_TRUE,
369 	    .st_verify = smbios_test_pinfo_verify_invlen1,
370 	    .st_desc = "processor additional information - bad table length 1"
371 	}, {
372 	    .st_entry = SMBIOS_ENTRY_POINT_30,
373 	    .st_tvers = SMB_VERSION,
374 	    .st_libvers = SMB_VERSION,
375 	    .st_mktable = smbios_test_pinfo_mktable_invlen2,
376 	    .st_canopen = B_TRUE,
377 	    .st_verify = smbios_test_pinfo_verify_invlen2,
378 	    .st_desc = "processor additional information - bad table length 2"
379 	}, {
380 	    .st_entry = SMBIOS_ENTRY_POINT_30,
381 	    .st_tvers = SMB_VERSION,
382 	    .st_libvers = SMB_VERSION,
383 	    .st_mktable = smbios_test_pinfo_mktable_invlen3,
384 	    .st_canopen = B_TRUE,
385 	    .st_verify = smbios_test_pinfo_verify_invlen3,
386 	    .st_desc = "processor additional information - bad table length 3"
387 	}, {
388 	    .st_entry = SMBIOS_ENTRY_POINT_30,
389 	    .st_tvers = SMB_VERSION,
390 	    .st_libvers = SMB_VERSION,
391 	    .st_mktable = smbios_test_pinfo_mktable_invlen4,
392 	    .st_canopen = B_TRUE,
393 	    .st_verify = smbios_test_pinfo_verify_invlen4,
394 	    .st_desc = "processor additional information - bad table length 4"
395 	}, {
396 	    .st_entry = SMBIOS_ENTRY_POINT_30,
397 	    .st_tvers = SMB_VERSION,
398 	    .st_libvers = SMB_VERSION,
399 	    .st_mktable = smbios_test_memdevice_mktable_32,
400 	    .st_canopen = B_TRUE,
401 	    .st_verify = smbios_test_pinfo_verify_badtype,
402 	    .st_desc = "processor additional information - bad type"
403 	}, {
404 	    .st_entry = SMBIOS_ENTRY_POINT_30,
405 	    .st_tvers = SMB_VERSION,
406 	    .st_libvers = SMB_VERSION,
407 	    .st_mktable = smbios_test_strprop_mktable_invlen1,
408 	    .st_canopen = B_TRUE,
409 	    .st_verify = smbios_test_strprop_verify_invlen1,
410 	    .st_desc = "string property - bad table length 1"
411 	}, {
412 	    .st_entry = SMBIOS_ENTRY_POINT_30,
413 	    .st_tvers = SMB_VERSION,
414 	    .st_libvers = SMB_VERSION,
415 	    .st_mktable = smbios_test_strprop_mktable_invlen2,
416 	    .st_canopen = B_TRUE,
417 	    .st_verify = smbios_test_strprop_verify_invlen2,
418 	    .st_desc = "string property - bad table length 2"
419 	}, {
420 	    .st_entry = SMBIOS_ENTRY_POINT_30,
421 	    .st_tvers = SMB_VERSION,
422 	    .st_libvers = SMB_VERSION,
423 	    .st_mktable = smbios_test_memdevice_mktable_32,
424 	    .st_canopen = B_TRUE,
425 	    .st_verify = smbios_test_strprop_verify_badtype,
426 	    .st_desc = "string property - bad type"
427 	}, {
428 	    .st_entry = SMBIOS_ENTRY_POINT_30,
429 	    .st_tvers = SMB_VERSION,
430 	    .st_libvers = SMB_VERSION,
431 	    .st_mktable = smbios_test_strprop_mktable_basic,
432 	    .st_canopen = B_TRUE,
433 	    .st_verify = smbios_test_strprop_verify_basic,
434 	    .st_desc = "string property - basic"
435 	}, {
436 	    .st_entry = SMBIOS_ENTRY_POINT_30,
437 	    .st_tvers = SMB_VERSION,
438 	    .st_libvers = SMB_VERSION,
439 	    .st_mktable = smbios_test_strprop_mktable_badstr,
440 	    .st_canopen = B_TRUE,
441 	    .st_verify = smbios_test_strprop_verify_badstr,
442 	    .st_desc = "string property - bad string"
443 	}, {
444 	    .st_entry = SMBIOS_ENTRY_POINT_30,
445 	    .st_tvers = SMB_VERSION,
446 	    .st_libvers = SMB_VERSION,
447 	    .st_mktable = smbios_test_fwinfo_mktable_invlen_base,
448 	    .st_canopen = B_TRUE,
449 	    .st_verify = smbios_test_fwinfo_verify_invlen_base,
450 	    .st_desc = "firmware inventory - bad base length"
451 	}, {
452 	    .st_entry = SMBIOS_ENTRY_POINT_30,
453 	    .st_tvers = SMB_VERSION,
454 	    .st_libvers = SMB_VERSION,
455 	    .st_mktable = smbios_test_fwinfo_mktable_invlen_comps,
456 	    .st_canopen = B_TRUE,
457 	    .st_verify = smbios_test_fwinfo_verify_invlen_comps,
458 	    .st_desc = "firmware inventory - bad comp length"
459 	}, {
460 	    .st_entry = SMBIOS_ENTRY_POINT_30,
461 	    .st_tvers = SMB_VERSION,
462 	    .st_libvers = SMB_VERSION,
463 	    .st_mktable = smbios_test_memdevice_mktable_32,
464 	    .st_canopen = B_TRUE,
465 	    .st_verify = smbios_test_fwinfo_verify_badtype,
466 	    .st_desc = "firmware inventory - bad type"
467 	}, {
468 	    .st_entry = SMBIOS_ENTRY_POINT_30,
469 	    .st_tvers = SMB_VERSION,
470 	    .st_libvers = SMB_VERSION,
471 	    .st_mktable = smbios_test_fwinfo_mktable_nocomps,
472 	    .st_canopen = B_TRUE,
473 	    .st_verify = smbios_test_fwinfo_verify_nocomps,
474 	    .st_desc = "firmware inventory - no components"
475 	}, {
476 	    .st_entry = SMBIOS_ENTRY_POINT_30,
477 	    .st_tvers = SMB_VERSION,
478 	    .st_libvers = SMB_VERSION,
479 	    .st_mktable = smbios_test_fwinfo_mktable_comps,
480 	    .st_canopen = B_TRUE,
481 	    .st_verify = smbios_test_fwinfo_verify_comps,
482 	    .st_desc = "firmware inventory - components"
483 	}, {
484 	    .st_entry = SMBIOS_ENTRY_POINT_30,
485 	    .st_tvers = SMB_VERSION_24,
486 	    .st_libvers = SMB_VERSION,
487 	    .st_mktable = smbios_test_chassis_mktable_invlen_base,
488 	    .st_canopen = B_TRUE,
489 	    .st_verify = smbios_test_chassis_verify_invlen,
490 	    .st_desc = "chassis - bad length (2.4 table)"
491 	}, {
492 	    .st_entry = SMBIOS_ENTRY_POINT_30,
493 	    .st_tvers = SMB_VERSION,
494 	    .st_libvers = SMB_VERSION,
495 	    .st_mktable = smbios_test_chassis_mktable_invlen_base,
496 	    .st_canopen = B_TRUE,
497 	    .st_verify = smbios_test_chassis_verify_invlen,
498 	    .st_desc = "chassis - bad length (latest version)"
499 	}, {
500 	    .st_entry = SMBIOS_ENTRY_POINT_30,
501 	    .st_tvers = SMB_VERSION,
502 	    .st_libvers = SMB_VERSION,
503 	    .st_mktable = smbios_test_chassis_mktable_base,
504 	    .st_canopen = B_TRUE,
505 	    .st_verify = smbios_test_chassis_verify_invlen,
506 	    .st_desc = "chassis - bad length, expect sku"
507 	}, {
508 	    .st_entry = SMBIOS_ENTRY_POINT_30,
509 	    .st_tvers = SMB_VERSION_24,
510 	    .st_libvers = SMB_VERSION,
511 	    .st_mktable = smbios_test_chassis_mktable_base,
512 	    .st_canopen = B_TRUE,
513 	    .st_verify = smbios_test_chassis_verify_base,
514 	    .st_desc = "chassis - basic 2.4 version"
515 	}, {
516 	    .st_entry = SMBIOS_ENTRY_POINT_30,
517 	    .st_tvers = SMB_VERSION,
518 	    .st_libvers = SMB_VERSION,
519 	    .st_mktable = smbios_test_chassis_mktable_sku_nocomps,
520 	    .st_canopen = B_TRUE,
521 	    .st_verify = smbios_test_chassis_verify_sku_nocomps,
522 	    .st_desc = "chassis - sku, but no components"
523 	}, {
524 	    .st_entry = SMBIOS_ENTRY_POINT_30,
525 	    .st_tvers = SMB_VERSION_24,
526 	    .st_libvers = SMB_VERSION,
527 	    .st_mktable = smbios_test_chassis_mktable_comps,
528 	    .st_canopen = B_TRUE,
529 	    .st_verify = smbios_test_chassis_verify_comps,
530 	    .st_desc = "chassis - 2.4 version with comps"
531 	}, {
532 	    .st_entry = SMBIOS_ENTRY_POINT_30,
533 	    .st_tvers = SMB_VERSION,
534 	    .st_libvers = SMB_VERSION,
535 	    .st_mktable = smbios_test_chassis_mktable_sku_nocomps,
536 	    .st_canopen = B_TRUE,
537 	    .st_verify = smbios_test_chassis_verify_sku_nocomps,
538 	    .st_desc = "chassis - sku + comps"
539 	}, {
540 	    .st_entry = SMBIOS_ENTRY_POINT_30,
541 	    .st_tvers = SMB_VERSION_25,
542 	    .st_libvers = SMB_VERSION,
543 	    .st_mktable = smbios_test_proc_mktable_25,
544 	    .st_canopen = B_TRUE,
545 	    .st_verify = smbios_test_proc_verify_25,
546 	    .st_desc = "SMBIOS 2.5 processor"
547 	}, {
548 	    .st_entry = SMBIOS_ENTRY_POINT_30,
549 	    .st_tvers = SMB_VERSION_36,
550 	    .st_libvers = SMB_VERSION,
551 	    .st_mktable = smbios_test_proc_mktable_36,
552 	    .st_canopen = B_TRUE,
553 	    .st_verify = smbios_test_proc_verify_36,
554 	    .st_desc = "SMBIOS 3.6 processor"
555 	}, {
556 	    .st_entry = SMBIOS_ENTRY_POINT_30,
557 	    .st_tvers = SMB_VERSION_36,
558 	    .st_libvers = SMB_VERSION_25,
559 	    .st_mktable = smbios_test_proc_mktable_36,
560 	    .st_canopen = B_TRUE,
561 	    .st_verify = smbios_test_proc_verify_36_25,
562 	    .st_desc = "SMBIOS 3.6 processor, 2.5 client"
563 	}, {
564 	    .st_entry = SMBIOS_ENTRY_POINT_30,
565 	    .st_tvers = SMB_VERSION,
566 	    .st_libvers = SMB_VERSION,
567 	    .st_mktable = smbios_test_extmem_mktable_cs,
568 	    .st_canopen = B_TRUE,
569 	    .st_verify = smbios_test_extmem_verify_cs,
570 	    .st_desc = "SMBIOS Sun extended memory device with cs"
571 	}, {
572 	    .st_entry = SMBIOS_ENTRY_POINT_30,
573 	    .st_tvers = SMB_VERSION,
574 	    .st_libvers = SMB_VERSION,
575 	    .st_mktable = smbios_test_extmem_mktable_nocs,
576 	    .st_canopen = B_TRUE,
577 	    .st_verify = smbios_test_extmem_verify_nocs,
578 	    .st_desc = "SMBIOS Sun extended memory device with no cs"
579 	}, {
580 	    .st_entry = SMBIOS_ENTRY_POINT_30,
581 	    .st_tvers = SMB_VERSION,
582 	    .st_libvers = SMB_VERSION,
583 	    .st_mktable = smbios_test_extmem_mktable_invlen_cs,
584 	    .st_canopen = B_TRUE,
585 	    .st_verify = smbios_test_extmem_verify_invlen_cs,
586 	    .st_desc = "SMBIOS Sun extended memory device invalid cs length"
587 	}
588 };
589 
590 static boolean_t
591 smbios_test_run_one(const smbios_test_t *test)
592 {
593 	smbios_test_table_t *table = NULL;
594 	smbios_hdl_t *hdl = NULL;
595 	void *buf;
596 	size_t len;
597 	smbios_entry_t *entry;
598 	int err = 0;
599 	boolean_t ret = B_FALSE;
600 
601 	table = smbios_test_table_init(test->st_entry, test->st_tvers);
602 	if (!test->st_mktable(table)) {
603 		goto out;
604 	}
605 
606 	smbios_test_table_snapshot(table, &entry, &buf, &len);
607 	hdl = smbios_bufopen(entry, buf, len, test->st_libvers, SMB_FL_DEBUG,
608 	    &err);
609 	if (test->st_canopen) {
610 		if (hdl == NULL) {
611 			warnx("failed to create table for test %s: %s",
612 			    test->st_desc, smbios_errmsg(err));
613 			goto out;
614 		}
615 	} else {
616 		if (hdl != NULL) {
617 			warnx("accidentally created table for test %s, "
618 			    "expected failure", test->st_desc);
619 		} else {
620 			ret = B_TRUE;
621 		}
622 		goto out;
623 	}
624 
625 	if (test->st_verify(hdl)) {
626 		ret = B_TRUE;
627 	}
628 
629 	if (hdl != NULL && test_dirfd > -1) {
630 		int fd;
631 		char fname[PATH_MAX];
632 
633 		(void) snprintf(fname, sizeof (fname), "%s.smbios",
634 		    test->st_desc);
635 		fd = openat(test_dirfd, fname, O_RDWR | O_CREAT, 0644);
636 		if (fd < 0) {
637 			warn("failed to dump test %s, failed to open output "
638 			    "file", test->st_desc);
639 		} else {
640 			if (smbios_write(hdl, fd) != 0) {
641 				warnx("failed to dump test %s: %s",
642 				    test->st_desc,
643 				    smbios_errmsg(smbios_errno(hdl)));
644 			} else {
645 				(void) close(fd);
646 			}
647 		}
648 	}
649 out:
650 	if (hdl != NULL) {
651 		smbios_close(hdl);
652 	}
653 
654 	if (table != NULL) {
655 		smbios_test_table_fini(table);
656 	}
657 
658 	if (ret) {
659 		(void) printf("TEST PASSED: %s\n", test->st_desc);
660 	} else {
661 		(void) printf("TEST FAILED: %s\n", test->st_desc);
662 	}
663 
664 	return (ret);
665 }
666 
667 int
668 main(int argc, char *argv[])
669 {
670 	int ret = 0, c;
671 	size_t i;
672 	const char *outdir = NULL;
673 
674 	while ((c = getopt(argc, argv, ":d:")) != -1) {
675 		switch (c) {
676 		case 'd':
677 			outdir = optarg;
678 			break;
679 		case '?':
680 			errx(EXIT_FAILURE, "unknown option: -%c", optopt);
681 		case ':':
682 			errx(EXIT_FAILURE, "-%c requires an operand", optopt);
683 		}
684 	}
685 
686 	if (outdir != NULL) {
687 		if ((test_dirfd = open(outdir, O_RDONLY)) < 0) {
688 			err(EXIT_FAILURE, "failed to open %s", outdir);
689 		}
690 	}
691 
692 	for (i = 0; i < ARRAY_SIZE(smbios_tests); i++) {
693 		if (!smbios_test_run_one(&smbios_tests[i])) {
694 			ret = 1;
695 		}
696 	}
697 
698 	if (ret == 0) {
699 		(void) printf("All tests passed successfully\n");
700 	}
701 
702 	return (ret);
703 }
704