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
smbios_test_memdevice_fill(smb_memdevice_t * mem)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
smbios_test_memdevice_mktable_32(smbios_test_table_t * table)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
smbios_test_memdevice_mktable_33(smbios_test_table_t * table)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
smbios_test_memdevice_mktable_33ext(smbios_test_table_t * table)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
smbios_test_memdevice_mktable_37(smbios_test_table_t * table)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
smbios_test_memdevice_verify_common(smbios_memdevice_t * mem)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: %" PRIu64, mem->smbmd_size);
192 ret = B_FALSE;
193 }
194
195 return (ret);
196 }
197
198 boolean_t
smbios_test_memdevice_verify_32(smbios_hdl_t * hdl)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
smbios_test_memdevice_verify_32_33(smbios_hdl_t * hdl)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: %" PRIu64, mem.smbmd_extspeed);
289 ret = B_FALSE;
290 }
291
292 if (mem.smbmd_extclkspeed != smbios_memdevice_clkspeed) {
293 warnx("found wrong device clkspeed: %" PRIu64,
294 mem.smbmd_extclkspeed);
295 ret = B_FALSE;
296 }
297
298 return (ret);
299 }
300
301 /*
302 * This is similar to the 3.2/3.3 variant above except we're checking the newer
303 * 3.7 fields related to the PMIC0 and RCD.
304 */
305 boolean_t
smbios_test_memdevice_verify_32_37(smbios_hdl_t * hdl)306 smbios_test_memdevice_verify_32_37(smbios_hdl_t *hdl)
307 {
308 smbios_struct_t sp;
309 smbios_memdevice_t mem;
310 boolean_t ret = B_TRUE;
311
312 if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
313 warnx("failed to lookup SMBIOS memory device: %s",
314 smbios_errmsg(smbios_errno(hdl)));
315 return (B_FALSE);
316 }
317
318 if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
319 warnx("failed to get SMBIOS memory device info: %s",
320 smbios_errmsg(smbios_errno(hdl)));
321 return (B_FALSE);
322 }
323
324 if (!smbios_test_memdevice_verify_32_33(hdl)) {
325 ret = B_FALSE;
326 }
327
328 if (mem.smbmd_pmic0_mfgid != SMB_MD_MFG_UNKNOWN) {
329 warnx("found wrong PMIC0 mfg id: 0x%x", mem.smbmd_pmic0_mfgid);
330 ret = B_FALSE;
331 }
332
333 if (mem.smbmd_pmic0_rev != SMB_MD_REV_UNKNOWN) {
334 warnx("found wrong PMIC0 revision: 0x%x", mem.smbmd_pmic0_rev);
335 ret = B_FALSE;
336 }
337
338 if (mem.smbmd_rcd_mfgid != SMB_MD_MFG_UNKNOWN) {
339 warnx("found wrong RCD mfg id: 0x%x", mem.smbmd_rcd_mfgid);
340 ret = B_FALSE;
341 }
342
343 if (mem.smbmd_rcd_rev != SMB_MD_REV_UNKNOWN) {
344 warnx("found wrong RCD revision: 0x%x", mem.smbmd_rcd_rev);
345 ret = B_FALSE;
346 }
347
348 return (ret);
349 }
350
351 boolean_t
smbios_test_memdevice_verify_33(smbios_hdl_t * hdl)352 smbios_test_memdevice_verify_33(smbios_hdl_t *hdl)
353 {
354 smbios_struct_t sp;
355 smbios_memdevice_t mem;
356 boolean_t ret = B_TRUE;
357
358 if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
359 warnx("failed to lookup SMBIOS memory device: %s",
360 smbios_errmsg(smbios_errno(hdl)));
361 return (B_FALSE);
362 }
363
364 if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
365 warnx("failed to get SMBIOS memory device info: %s",
366 smbios_errmsg(smbios_errno(hdl)));
367 return (B_FALSE);
368 }
369
370 if (!smbios_test_memdevice_verify_common(&mem)) {
371 return (B_FALSE);
372 }
373
374 if (mem.smbmd_speed != smbios_memdevice_speed) {
375 warnx("found wrong device speed: %u", mem.smbmd_speed);
376 ret = B_FALSE;
377 }
378
379 if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
380 warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
381 ret = B_FALSE;
382 }
383
384 if (mem.smbmd_extspeed != smbios_memdevice_speed) {
385 warnx("found wrong device speed: %" PRIu64, mem.smbmd_extspeed);
386 ret = B_FALSE;
387 }
388
389 if (mem.smbmd_extclkspeed != smbios_memdevice_clkspeed) {
390 warnx("found wrong device clkspeed: %" PRIu64,
391 mem.smbmd_extclkspeed);
392 ret = B_FALSE;
393 }
394
395 return (ret);
396 }
397
398 boolean_t
smbios_test_memdevice_verify_33ext(smbios_hdl_t * hdl)399 smbios_test_memdevice_verify_33ext(smbios_hdl_t *hdl)
400 {
401 smbios_struct_t sp;
402 smbios_memdevice_t mem;
403 boolean_t ret = B_TRUE;
404
405 if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
406 warnx("failed to lookup SMBIOS memory device: %s",
407 smbios_errmsg(smbios_errno(hdl)));
408 return (B_FALSE);
409 }
410
411 if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
412 warnx("failed to get SMBIOS memory device info: %s",
413 smbios_errmsg(smbios_errno(hdl)));
414 return (B_FALSE);
415 }
416
417 if (!smbios_test_memdevice_verify_common(&mem)) {
418 return (B_FALSE);
419 }
420
421 if (mem.smbmd_speed != 0xffff) {
422 warnx("found wrong device speed: %u", mem.smbmd_speed);
423 ret = B_FALSE;
424 }
425
426 if (mem.smbmd_clkspeed != 0xffff) {
427 warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
428 ret = B_FALSE;
429 }
430
431 if (mem.smbmd_extspeed != smbios_memdevice_extspeed) {
432 warnx("found wrong device speed: %" PRIu64, mem.smbmd_extspeed);
433 ret = B_FALSE;
434 }
435
436 if (mem.smbmd_extclkspeed != smbios_memdevice_extclkspeed) {
437 warnx("found wrong device clkspeed: %" PRIu64,
438 mem.smbmd_extclkspeed);
439 ret = B_FALSE;
440 }
441
442 return (ret);
443 }
444
445 /*
446 * Note, the 3.7 table is based upon 3.3ext so we use that for checking the
447 * first chunk of this.
448 */
449 boolean_t
smbios_test_memdevice_verify_37(smbios_hdl_t * hdl)450 smbios_test_memdevice_verify_37(smbios_hdl_t *hdl)
451 {
452 smbios_struct_t sp;
453 smbios_memdevice_t mem;
454 boolean_t ret = B_TRUE;
455
456 if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
457 warnx("failed to lookup SMBIOS memory device: %s",
458 smbios_errmsg(smbios_errno(hdl)));
459 return (B_FALSE);
460 }
461
462 if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
463 warnx("failed to get SMBIOS memory device info: %s",
464 smbios_errmsg(smbios_errno(hdl)));
465 return (B_FALSE);
466 }
467
468 if (!smbios_test_memdevice_verify_33ext(hdl)) {
469 ret = B_FALSE;
470 }
471
472 if (mem.smbmd_pmic0_mfgid != smbios_memdevice_pmic0_mfg) {
473 warnx("found wrong PMIC0 mfg id: 0x%x", mem.smbmd_pmic0_mfgid);
474 ret = B_FALSE;
475 }
476
477 if (mem.smbmd_pmic0_rev != smbios_memdevice_pmic0_rev) {
478 warnx("found wrong PMIC0 revision: 0x%x", mem.smbmd_pmic0_rev);
479 ret = B_FALSE;
480 }
481
482 if (mem.smbmd_rcd_mfgid != smbios_memdevice_rcd_mfg) {
483 warnx("found wrong RCD mfg id: 0x%x", mem.smbmd_rcd_mfgid);
484 ret = B_FALSE;
485 }
486
487 if (mem.smbmd_rcd_rev != smbios_memdevice_rcd_rev) {
488 warnx("found wrong RCD revision: 0x%x", mem.smbmd_rcd_rev);
489 ret = B_FALSE;
490 }
491
492 return (ret);
493 }
494