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