xref: /illumos-gate/usr/src/test/util-tests/tests/smbios/smbios_test_memdevice.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
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 2019 Robert Mustacchi
14  * Copyright 2023 Oxide Computer Company
15  */
16 
17 /*
18  * Basic testing of the SMBIOS 3.3 memory device extensions. We test these in a
19  * few different ways:
20  *
21  * 1. Using a 3.2 table with a 3.2 library to make sure we get the old fields.
22  * We also need to verify that we don't clobber memory in this case.
23  * 2. Using a 3.2 table with a 3.3 library to make sure we get the new fields.
24  * populated with the corresponding 3.2 values.
25  * 3. Using a 3.3 table with only the old values as valid.
26  * 4. Using a 3.3 table with both the old and new values as valid.
27  * memory.
28  *
29  * We also test the 3.7 extensions in two ways:
30  *
31  * 1. Using a 3.2 table with a 3.7 library to make sure that the new fields are
32  * properly set to the right spec mandated unknown values.
33  * 2. Using a 3.7 table with a 3.7 library.
34  */
35 
36 #include <stdlib.h>
37 #include "smbios_test.h"
38 
39 static const uint16_t smbios_memdevice_speed = 0xdeed;
40 static const uint16_t smbios_memdevice_clkspeed = 0xf00f;
41 static const uint32_t smbios_memdevice_extspeed = 0xbaddeed;
42 static const uint32_t smbios_memdevice_extclkspeed = 0xbadf00f;
43 static const uint16_t smbios_memdevice_pmic0_mfg = 0x1234;
44 static const uint16_t smbios_memdevice_pmic0_rev = 0x5600;
45 static const uint16_t smbios_memdevice_rcd_mfg = 0x4321;
46 static const uint16_t smbios_memdevice_rcd_rev = 0x6500;
47 
48 /*
49  * Fixed sizes from older versions.
50  */
51 static const size_t smbios_memdevice_len_v3p2 = 0x54;
52 static const size_t smbios_memdevice_len_v3p3 = 0x5c;
53 
54 /*
55  * Fill in the basics of a single memory device. Callers need to fill in the
56  * speed, extspeed, clkspeed, and extclkspeed members.
57  */
58 static void
59 smbios_test_memdevice_fill(smb_memdevice_t *mem)
60 {
61 	mem->smbmdev_hdr.smbh_type = SMB_TYPE_MEMDEVICE;
62 	mem->smbmdev_hdr.smbh_len = sizeof (smb_memdevice_t);
63 
64 	mem->smbmdev_array = 0xffff;
65 	mem->smbmdev_error = htole16(0xfffe);
66 	mem->smbmdev_twidth = 64;
67 	mem->smbmdev_dwidth = 64;
68 	mem->smbmdev_size = 0x7fff;
69 	mem->smbmdev_form = SMB_MDFF_FBDIMM;
70 	mem->smbmdev_set = 0;
71 	mem->smbmdev_dloc = 0;
72 	mem->smbmdev_bloc = 0;
73 	mem->smbmdev_type = SMB_MDT_DDR4;
74 	mem->smbmdev_manufacturer = 0;
75 	mem->smbmdev_asset = 0;
76 	mem->smbmdev_part = 0;
77 	mem->smbmdev_attrs = 2;
78 	mem->smbmdev_extsize = htole32(0x123456);
79 	mem->smbmdev_minvolt = 0;
80 	mem->smbmdev_maxvolt = 0;
81 	mem->smbmdev_confvolt = 0;
82 	mem->smbmdev_memtech = 0;
83 	mem->smbmdev_opmode = 1 << 3;
84 	mem->smbmdev_fwver = 0;
85 	mem->smbmdev_modulemfgid = 0;
86 	mem->smbmdev_moduleprodid = 0;
87 	mem->smbmdev_memsysmfgid = 0;
88 	mem->smbmdev_memsysprodid = 0;
89 	mem->smbmdev_nvsize = htole64(UINT64_MAX);
90 	mem->smbmdev_volsize = htole64(UINT64_MAX);
91 	mem->smbmdev_cachesize = htole64(UINT64_MAX);
92 	mem->smbmdev_logicalsize = htole64(UINT64_MAX);
93 }
94 
95 boolean_t
96 smbios_test_memdevice_mktable_32(smbios_test_table_t *table)
97 {
98 	smb_memdevice_t mem;
99 
100 	smbios_test_memdevice_fill(&mem);
101 	mem.smbmdev_speed = htole16(smbios_memdevice_speed);
102 	mem.smbmdev_clkspeed = htole16(smbios_memdevice_clkspeed);
103 	mem.smbmdev_extspeed = htole32(0);
104 	mem.smbmdev_extclkspeed = htole32(0);
105 
106 	mem.smbmdev_hdr.smbh_len = smbios_memdevice_len_v3p2;
107 	(void) smbios_test_table_append(table, &mem, smbios_memdevice_len_v3p2);
108 	smbios_test_table_append_eot(table);
109 
110 	return (B_TRUE);
111 }
112 
113 boolean_t
114 smbios_test_memdevice_mktable_33(smbios_test_table_t *table)
115 {
116 	smb_memdevice_t mem;
117 
118 	smbios_test_memdevice_fill(&mem);
119 	mem.smbmdev_speed = htole16(smbios_memdevice_speed);
120 	mem.smbmdev_clkspeed = htole16(smbios_memdevice_clkspeed);
121 	mem.smbmdev_extspeed = htole32(0);
122 	mem.smbmdev_extclkspeed = htole32(0);
123 
124 	mem.smbmdev_hdr.smbh_len = smbios_memdevice_len_v3p3;
125 	(void) smbios_test_table_append(table, &mem, smbios_memdevice_len_v3p3);
126 	smbios_test_table_append_eot(table);
127 
128 	return (B_TRUE);
129 }
130 
131 boolean_t
132 smbios_test_memdevice_mktable_33ext(smbios_test_table_t *table)
133 {
134 	smb_memdevice_t mem;
135 
136 	smbios_test_memdevice_fill(&mem);
137 	mem.smbmdev_speed = htole16(0xffff);
138 	mem.smbmdev_clkspeed = htole16(0xffff);
139 	mem.smbmdev_extspeed = htole32(smbios_memdevice_extspeed);
140 	mem.smbmdev_extclkspeed = htole32(smbios_memdevice_extclkspeed);
141 
142 	mem.smbmdev_hdr.smbh_len = smbios_memdevice_len_v3p3;
143 	(void) smbios_test_table_append(table, &mem, smbios_memdevice_len_v3p3);
144 	smbios_test_table_append_eot(table);
145 
146 	return (B_TRUE);
147 }
148 
149 boolean_t
150 smbios_test_memdevice_mktable_37(smbios_test_table_t *table)
151 {
152 	smb_memdevice_t mem;
153 
154 	smbios_test_memdevice_fill(&mem);
155 	mem.smbmdev_speed = htole16(0xffff);
156 	mem.smbmdev_clkspeed = htole16(0xffff);
157 	mem.smbmdev_extspeed = htole32(smbios_memdevice_extspeed);
158 	mem.smbmdev_extclkspeed = htole32(smbios_memdevice_extclkspeed);
159 
160 	mem.smbmdev_pmic0mfgid = htole16(smbios_memdevice_pmic0_mfg);
161 	mem.smbmdev_pmic0rev = htole16(smbios_memdevice_pmic0_rev);
162 	mem.smbmdev_rcdmfgid = htole16(smbios_memdevice_rcd_mfg);
163 	mem.smbmdev_rcdrev = htole16(smbios_memdevice_rcd_rev);
164 
165 	(void) smbios_test_table_append(table, &mem, sizeof (mem));
166 	smbios_test_table_append_eot(table);
167 	return (B_TRUE);
168 }
169 
170 static boolean_t
171 smbios_test_memdevice_verify_common(smbios_memdevice_t *mem)
172 {
173 	boolean_t ret = B_TRUE;
174 
175 	if (mem->smbmd_dwidth != 64) {
176 		warnx("found wrong dwidth: %u", mem->smbmd_dwidth);
177 		ret = B_FALSE;
178 	}
179 
180 	if (mem->smbmd_twidth != 64) {
181 		warnx("found wrong twidth: %u", mem->smbmd_twidth);
182 		ret = B_FALSE;
183 	}
184 
185 	if (mem->smbmd_form != SMB_MDFF_FBDIMM) {
186 		warnx("found wrong form: %u", mem->smbmd_form);
187 		ret = B_FALSE;
188 	}
189 
190 	if (mem->smbmd_size != 0x123456ULL * 1024 * 1024) {
191 		warnx("found wrong size: %u", mem->smbmd_size);
192 		ret = B_FALSE;
193 	}
194 
195 	return (ret);
196 }
197 
198 boolean_t
199 smbios_test_memdevice_verify_32(smbios_hdl_t *hdl)
200 {
201 	smbios_struct_t sp;
202 	smbios_memdevice_t mem;
203 	boolean_t ret = B_TRUE;
204 	uint64_t rval;
205 
206 	/*
207 	 * We expect that the SMBIOS 3.2 memory device values should not be
208 	 * touched here. As such we set them to a random value to verify and
209 	 * verify that it hasn't been set.
210 	 */
211 	arc4random_buf(&rval, sizeof (rval));
212 	mem.smbmd_extspeed = rval;
213 	mem.smbmd_extclkspeed = rval;
214 
215 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
216 		warnx("failed to lookup SMBIOS memory device: %s",
217 		    smbios_errmsg(smbios_errno(hdl)));
218 		return (B_FALSE);
219 	}
220 
221 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
222 		warnx("failed to get SMBIOS memory device info: %s",
223 		    smbios_errmsg(smbios_errno(hdl)));
224 		return (B_FALSE);
225 	}
226 
227 	if (mem.smbmd_extspeed != rval || mem.smbmd_extclkspeed != rval) {
228 		warnx("smbios_memdevice_t had its memory cloberred!");
229 		return (B_FALSE);
230 	}
231 
232 	if (!smbios_test_memdevice_verify_common(&mem)) {
233 		return (B_FALSE);
234 	}
235 
236 	if (mem.smbmd_speed != smbios_memdevice_speed) {
237 		warnx("found wrong device speed: %u", mem.smbmd_speed);
238 		ret = B_FALSE;
239 	}
240 
241 	if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
242 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
243 		ret = B_FALSE;
244 	}
245 
246 	return (ret);
247 }
248 
249 /*
250  * This is a variant of smbios_test_memdevice_verify_32(), but instead of using
251  * an SMBIOS 3.2 library, we use an SMBIOS 3.3 handle. This means that we expect
252  * the extended values to be populated with the base values.
253  */
254 boolean_t
255 smbios_test_memdevice_verify_32_33(smbios_hdl_t *hdl)
256 {
257 	smbios_struct_t sp;
258 	smbios_memdevice_t mem;
259 	boolean_t ret = B_TRUE;
260 
261 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
262 		warnx("failed to lookup SMBIOS memory device: %s",
263 		    smbios_errmsg(smbios_errno(hdl)));
264 		return (B_FALSE);
265 	}
266 
267 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
268 		warnx("failed to get SMBIOS memory device info: %s",
269 		    smbios_errmsg(smbios_errno(hdl)));
270 		return (B_FALSE);
271 	}
272 
273 	if (!smbios_test_memdevice_verify_common(&mem)) {
274 		return (B_FALSE);
275 	}
276 
277 	if (mem.smbmd_speed != smbios_memdevice_speed) {
278 		warnx("found wrong device speed: %u", mem.smbmd_speed);
279 		ret = B_FALSE;
280 	}
281 
282 	if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
283 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
284 		ret = B_FALSE;
285 	}
286 
287 	if (mem.smbmd_extspeed != smbios_memdevice_speed) {
288 		warnx("found wrong device speed: %u", mem.smbmd_extspeed);
289 		ret = B_FALSE;
290 	}
291 
292 	if (mem.smbmd_extclkspeed != smbios_memdevice_clkspeed) {
293 		warnx("found wrong device clkspeed: %u", mem.smbmd_extclkspeed);
294 		ret = B_FALSE;
295 	}
296 
297 	return (ret);
298 }
299 
300 /*
301  * This is similar to the 3.2/3.3 variant above except we're checking the newer
302  * 3.7 fields related to the PMIC0 and RCD.
303  */
304 boolean_t
305 smbios_test_memdevice_verify_32_37(smbios_hdl_t *hdl)
306 {
307 	smbios_struct_t sp;
308 	smbios_memdevice_t mem;
309 	boolean_t ret = B_TRUE;
310 
311 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
312 		warnx("failed to lookup SMBIOS memory device: %s",
313 		    smbios_errmsg(smbios_errno(hdl)));
314 		return (B_FALSE);
315 	}
316 
317 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
318 		warnx("failed to get SMBIOS memory device info: %s",
319 		    smbios_errmsg(smbios_errno(hdl)));
320 		return (B_FALSE);
321 	}
322 
323 	if (!smbios_test_memdevice_verify_32_33(hdl)) {
324 		ret = B_FALSE;
325 	}
326 
327 	if (mem.smbmd_pmic0_mfgid != SMB_MD_MFG_UNKNOWN) {
328 		warnx("found wrong PMIC0 mfg id: 0x%x", mem.smbmd_pmic0_mfgid);
329 		ret = B_FALSE;
330 	}
331 
332 	if (mem.smbmd_pmic0_rev != SMB_MD_REV_UNKNOWN) {
333 		warnx("found wrong PMIC0 revision: 0x%x", mem.smbmd_pmic0_rev);
334 		ret = B_FALSE;
335 	}
336 
337 	if (mem.smbmd_rcd_mfgid != SMB_MD_MFG_UNKNOWN) {
338 		warnx("found wrong RCD mfg id: 0x%x", mem.smbmd_rcd_mfgid);
339 		ret = B_FALSE;
340 	}
341 
342 	if (mem.smbmd_rcd_rev != SMB_MD_REV_UNKNOWN) {
343 		warnx("found wrong RCD revision: 0x%x", mem.smbmd_rcd_rev);
344 		ret = B_FALSE;
345 	}
346 
347 	return (ret);
348 }
349 
350 boolean_t
351 smbios_test_memdevice_verify_33(smbios_hdl_t *hdl)
352 {
353 	smbios_struct_t sp;
354 	smbios_memdevice_t mem;
355 	boolean_t ret = B_TRUE;
356 
357 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
358 		warnx("failed to lookup SMBIOS memory device: %s",
359 		    smbios_errmsg(smbios_errno(hdl)));
360 		return (B_FALSE);
361 	}
362 
363 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
364 		warnx("failed to get SMBIOS memory device info: %s",
365 		    smbios_errmsg(smbios_errno(hdl)));
366 		return (B_FALSE);
367 	}
368 
369 	if (!smbios_test_memdevice_verify_common(&mem)) {
370 		return (B_FALSE);
371 	}
372 
373 	if (mem.smbmd_speed != smbios_memdevice_speed) {
374 		warnx("found wrong device speed: %u", mem.smbmd_speed);
375 		ret = B_FALSE;
376 	}
377 
378 	if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
379 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
380 		ret = B_FALSE;
381 	}
382 
383 	if (mem.smbmd_extspeed != smbios_memdevice_speed) {
384 		warnx("found wrong device speed: %u", mem.smbmd_extspeed);
385 		ret = B_FALSE;
386 	}
387 
388 	if (mem.smbmd_extclkspeed != smbios_memdevice_clkspeed) {
389 		warnx("found wrong device clkspeed: %u", mem.smbmd_extclkspeed);
390 		ret = B_FALSE;
391 	}
392 
393 	return (ret);
394 }
395 
396 boolean_t
397 smbios_test_memdevice_verify_33ext(smbios_hdl_t *hdl)
398 {
399 	smbios_struct_t sp;
400 	smbios_memdevice_t mem;
401 	boolean_t ret = B_TRUE;
402 
403 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
404 		warnx("failed to lookup SMBIOS memory device: %s",
405 		    smbios_errmsg(smbios_errno(hdl)));
406 		return (B_FALSE);
407 	}
408 
409 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
410 		warnx("failed to get SMBIOS memory device info: %s",
411 		    smbios_errmsg(smbios_errno(hdl)));
412 		return (B_FALSE);
413 	}
414 
415 	if (!smbios_test_memdevice_verify_common(&mem)) {
416 		return (B_FALSE);
417 	}
418 
419 	if (mem.smbmd_speed != 0xffff) {
420 		warnx("found wrong device speed: %u", mem.smbmd_speed);
421 		ret = B_FALSE;
422 	}
423 
424 	if (mem.smbmd_clkspeed != 0xffff) {
425 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
426 		ret = B_FALSE;
427 	}
428 
429 	if (mem.smbmd_extspeed != smbios_memdevice_extspeed) {
430 		warnx("found wrong device speed: %u", mem.smbmd_extspeed);
431 		ret = B_FALSE;
432 	}
433 
434 	if (mem.smbmd_extclkspeed != smbios_memdevice_extclkspeed) {
435 		warnx("found wrong device clkspeed: %u", mem.smbmd_extclkspeed);
436 		ret = B_FALSE;
437 	}
438 
439 	return (ret);
440 }
441 
442 /*
443  * Note, the 3.7 table is based upon 3.3ext so we use that for checking the
444  * first chunk of this.
445  */
446 boolean_t
447 smbios_test_memdevice_verify_37(smbios_hdl_t *hdl)
448 {
449 	smbios_struct_t sp;
450 	smbios_memdevice_t mem;
451 	boolean_t ret = B_TRUE;
452 
453 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
454 		warnx("failed to lookup SMBIOS memory device: %s",
455 		    smbios_errmsg(smbios_errno(hdl)));
456 		return (B_FALSE);
457 	}
458 
459 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
460 		warnx("failed to get SMBIOS memory device info: %s",
461 		    smbios_errmsg(smbios_errno(hdl)));
462 		return (B_FALSE);
463 	}
464 
465 	if (!smbios_test_memdevice_verify_33ext(hdl)) {
466 		ret = B_FALSE;
467 	}
468 
469 	if (mem.smbmd_pmic0_mfgid != smbios_memdevice_pmic0_mfg) {
470 		warnx("found wrong PMIC0 mfg id: 0x%x", mem.smbmd_pmic0_mfgid);
471 		ret = B_FALSE;
472 	}
473 
474 	if (mem.smbmd_pmic0_rev != smbios_memdevice_pmic0_rev) {
475 		warnx("found wrong PMIC0 revision: 0x%x", mem.smbmd_pmic0_rev);
476 		ret = B_FALSE;
477 	}
478 
479 	if (mem.smbmd_rcd_mfgid != smbios_memdevice_rcd_mfg) {
480 		warnx("found wrong RCD mfg id: 0x%x", mem.smbmd_rcd_mfgid);
481 		ret = B_FALSE;
482 	}
483 
484 	if (mem.smbmd_rcd_rev != smbios_memdevice_rcd_rev) {
485 		warnx("found wrong RCD revision: 0x%x", mem.smbmd_rcd_rev);
486 		ret = B_FALSE;
487 	}
488 
489 	return (ret);
490 }
491