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: %" PRIu64, 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: %" 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 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 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 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 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