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 2020 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 "smbios_test.h" 25 26 const char * 27 _umem_debug_init(void) 28 { 29 return ("default,verbose"); 30 } 31 32 const char * 33 _umem_logging_init(void) 34 { 35 return ("fail,contents"); 36 } 37 38 smbios_test_table_t * 39 smbios_test_table_init(smbios_entry_point_t type, uint_t version) 40 { 41 smbios_test_table_t *table; 42 43 if (type != SMBIOS_ENTRY_POINT_30) { 44 abort(); 45 } 46 47 table = umem_zalloc(sizeof (smbios_test_table_t), UMEM_DEFAULT); 48 if (table == NULL) { 49 return (NULL); 50 } 51 52 table->stt_data = umem_zalloc(SMBIOS_TEST_ALLOC_SIZE, UMEM_DEFAULT); 53 if (table->stt_data == NULL) { 54 umem_free(table, sizeof (smbios_test_table_t)); 55 return (NULL); 56 } 57 table->stt_buflen = SMBIOS_TEST_ALLOC_SIZE; 58 table->stt_type = type; 59 table->stt_version = version; 60 table->stt_nextid = 1; 61 62 return (table); 63 } 64 65 static void * 66 smbios_test_table_append_common(smbios_test_table_t *table, const void *buf, 67 size_t len) 68 { 69 void *start; 70 71 if (SIZE_MAX - table->stt_offset < len) 72 abort(); 73 74 if (len + table->stt_offset >= table->stt_buflen) { 75 void *newbuf; 76 size_t newlen = table->stt_buflen + SMBIOS_TEST_ALLOC_SIZE; 77 78 while (len + table->stt_offset >= newlen) { 79 newlen += SMBIOS_TEST_ALLOC_SIZE; 80 } 81 82 newbuf = umem_zalloc(newlen, UMEM_DEFAULT); 83 if (newbuf == NULL) { 84 err(EXIT_FAILURE, "failed to umem_zalloc for %lu bytes", 85 newlen); 86 } 87 88 (void) memcpy(newbuf, table->stt_data, table->stt_buflen); 89 umem_free(table->stt_data, table->stt_buflen); 90 table->stt_data = newbuf; 91 table->stt_buflen = newlen; 92 } 93 94 start = (void *)((uintptr_t)table->stt_data + table->stt_offset); 95 (void) memcpy(start, buf, len); 96 table->stt_offset += len; 97 98 return (start); 99 } 100 101 void 102 smbios_test_table_append_raw(smbios_test_table_t *table, const void *buf, 103 size_t len) 104 { 105 (void) smbios_test_table_append_common(table, buf, len); 106 } 107 108 void 109 smbios_test_table_append_string(smbios_test_table_t *table, const char *str) 110 { 111 size_t len = strlen(str) + 1; 112 (void) smbios_test_table_append_common(table, str, len); 113 } 114 115 uint16_t 116 smbios_test_table_append(smbios_test_table_t *table, const void *buf, 117 size_t len) 118 { 119 smb_header_t *hdr; 120 uint16_t id; 121 122 hdr = smbios_test_table_append_common(table, buf, len); 123 table->stt_nents++; 124 125 id = table->stt_nextid; 126 hdr->smbh_hdl = htole16(table->stt_nextid); 127 table->stt_nextid++; 128 129 return (id); 130 } 131 132 void 133 smbios_test_table_append_eot(smbios_test_table_t *table) 134 { 135 smb_header_t eot; 136 uint8_t endstring = 0; 137 138 bzero(&eot, sizeof (eot)); 139 eot.smbh_type = SMB_TYPE_EOT; 140 eot.smbh_len = 4; 141 (void) smbios_test_table_append(table, &eot, sizeof (eot)); 142 (void) smbios_test_table_append_raw(table, &endstring, 143 sizeof (endstring)); 144 smbios_test_table_append_raw(table, &endstring, 145 sizeof (endstring)); 146 smbios_test_table_append_raw(table, &endstring, 147 sizeof (endstring)); 148 149 } 150 151 static uint8_t 152 smbios_test_table_checksum(const uint8_t *buf, size_t len) 153 { 154 uint8_t sum; 155 size_t i; 156 157 for (i = 0, sum = 0; i < len; i++) { 158 sum += buf[i]; 159 } 160 161 if (sum == 0) 162 return (0); 163 164 return ((uint8_t)(0x100 - sum)); 165 } 166 167 static void 168 smbios_test_table_snapshot(smbios_test_table_t *table, smbios_entry_t **entryp, 169 void **bufp, size_t *lenp) 170 { 171 smbios_30_entry_t *ent30; 172 173 switch (table->stt_type) { 174 case SMBIOS_ENTRY_POINT_30: 175 ent30 = &table->stt_entry.ep30; 176 177 (void) memcpy(ent30->smbe_eanchor, SMB3_ENTRY_EANCHOR, 178 sizeof (ent30->smbe_eanchor)); 179 ent30->smbe_ecksum = 0; 180 ent30->smbe_elen = sizeof (*ent30); 181 ent30->smbe_major = (table->stt_version >> 8) & 0xff; 182 ent30->smbe_minor = table->stt_version & 0xff; 183 ent30->smbe_docrev = 0; 184 ent30->smbe_revision = 1; 185 ent30->smbe_reserved = 0; 186 ent30->smbe_stlen = htole32(table->stt_offset); 187 ent30->smbe_staddr = htole64(P2ROUNDUP(sizeof (*ent30), 16)); 188 189 ent30->smbe_ecksum = smbios_test_table_checksum((void *)ent30, 190 sizeof (*ent30)); 191 break; 192 default: 193 abort(); 194 } 195 196 *entryp = &table->stt_entry; 197 *bufp = table->stt_data; 198 *lenp = table->stt_offset; 199 } 200 201 static void 202 smbios_test_table_fini(smbios_test_table_t *table) 203 { 204 if (table == NULL) { 205 return; 206 } 207 208 if (table->stt_data != NULL) { 209 umem_free(table->stt_data, table->stt_buflen); 210 } 211 212 umem_free(table, sizeof (smbios_test_table_t)); 213 } 214 215 static const smbios_test_t smbios_tests[] = { 216 { 217 .st_entry = SMBIOS_ENTRY_POINT_30, 218 .st_tvers = SMB_VERSION_32, 219 .st_libvers = SMB_VERSION, 220 .st_mktable = smbios_test_slot_mktable, 221 .st_canopen = B_TRUE, 222 .st_verify = smbios_test_slot_verify, 223 .st_desc = "slot 3.2" 224 }, { 225 .st_entry = SMBIOS_ENTRY_POINT_30, 226 .st_tvers = SMB_VERSION_34, 227 .st_libvers = SMB_VERSION, 228 .st_mktable = smbios_test_slot_mktable_34_nopeers, 229 .st_canopen = B_TRUE, 230 .st_verify = smbios_test_slot_verify_34_nopeers, 231 .st_desc = "slot 3.4 without peers" 232 }, { 233 .st_entry = SMBIOS_ENTRY_POINT_30, 234 .st_tvers = SMB_VERSION_34, 235 .st_libvers = SMB_VERSION, 236 .st_mktable = smbios_test_slot_mktable_34_peers, 237 .st_canopen = B_TRUE, 238 .st_verify = smbios_test_slot_verify_34_peers, 239 .st_desc = "slot 3.4 with peers" 240 }, { 241 .st_entry = SMBIOS_ENTRY_POINT_30, 242 .st_tvers = SMB_VERSION, 243 .st_libvers = 0xffff, 244 .st_mktable = smbios_test_badvers_mktable, 245 .st_desc = "bad library version" 246 }, { 247 .st_entry = SMBIOS_ENTRY_POINT_30, 248 .st_tvers = SMB_VERSION_32, 249 .st_libvers = SMB_VERSION_32, 250 .st_mktable = smbios_test_memdevice_mktable_32, 251 .st_canopen = B_TRUE, 252 .st_verify = smbios_test_memdevice_verify_32, 253 .st_desc = "memory device 3.2 / 3.2" 254 }, { 255 .st_entry = SMBIOS_ENTRY_POINT_30, 256 .st_tvers = SMB_VERSION_32, 257 .st_libvers = SMB_VERSION_33, 258 .st_mktable = smbios_test_memdevice_mktable_32, 259 .st_canopen = B_TRUE, 260 .st_verify = smbios_test_memdevice_verify_32_33, 261 .st_desc = "memory device 3.2 / 3.3" 262 }, { 263 .st_entry = SMBIOS_ENTRY_POINT_30, 264 .st_tvers = SMB_VERSION_33, 265 .st_libvers = SMB_VERSION_33, 266 .st_mktable = smbios_test_memdevice_mktable_33, 267 .st_canopen = B_TRUE, 268 .st_verify = smbios_test_memdevice_verify_33, 269 .st_desc = "memory device 3.3" 270 }, { 271 .st_entry = SMBIOS_ENTRY_POINT_30, 272 .st_tvers = SMB_VERSION_33, 273 .st_libvers = SMB_VERSION_33, 274 .st_mktable = smbios_test_memdevice_mktable_33ext, 275 .st_canopen = B_TRUE, 276 .st_verify = smbios_test_memdevice_verify_33ext, 277 .st_desc = "memory device 3.3" 278 }, { 279 .st_entry = SMBIOS_ENTRY_POINT_30, 280 .st_tvers = SMB_VERSION, 281 .st_libvers = SMB_VERSION, 282 .st_mktable = smbios_test_pinfo_mktable_amd64, 283 .st_canopen = B_TRUE, 284 .st_verify = smbios_test_pinfo_verify_amd64, 285 .st_desc = "processor additional information - amd64" 286 }, { 287 .st_entry = SMBIOS_ENTRY_POINT_30, 288 .st_tvers = SMB_VERSION, 289 .st_libvers = SMB_VERSION, 290 .st_mktable = smbios_test_pinfo_mktable_riscv, 291 .st_canopen = B_TRUE, 292 .st_verify = smbios_test_pinfo_verify_riscv, 293 .st_desc = "processor additional information - riscv" 294 }, { 295 .st_entry = SMBIOS_ENTRY_POINT_30, 296 .st_tvers = SMB_VERSION, 297 .st_libvers = SMB_VERSION, 298 .st_mktable = smbios_test_pinfo_mktable_invlen1, 299 .st_canopen = B_TRUE, 300 .st_verify = smbios_test_pinfo_verify_invlen1, 301 .st_desc = "processor additional information - bad table length 1" 302 }, { 303 .st_entry = SMBIOS_ENTRY_POINT_30, 304 .st_tvers = SMB_VERSION, 305 .st_libvers = SMB_VERSION, 306 .st_mktable = smbios_test_pinfo_mktable_invlen2, 307 .st_canopen = B_TRUE, 308 .st_verify = smbios_test_pinfo_verify_invlen2, 309 .st_desc = "processor additional information - bad table length 2" 310 }, { 311 .st_entry = SMBIOS_ENTRY_POINT_30, 312 .st_tvers = SMB_VERSION, 313 .st_libvers = SMB_VERSION, 314 .st_mktable = smbios_test_pinfo_mktable_invlen3, 315 .st_canopen = B_TRUE, 316 .st_verify = smbios_test_pinfo_verify_invlen3, 317 .st_desc = "processor additional information - bad table length 3" 318 }, { 319 .st_entry = SMBIOS_ENTRY_POINT_30, 320 .st_tvers = SMB_VERSION, 321 .st_libvers = SMB_VERSION, 322 .st_mktable = smbios_test_pinfo_mktable_invlen4, 323 .st_canopen = B_TRUE, 324 .st_verify = smbios_test_pinfo_verify_invlen4, 325 .st_desc = "processor additional information - bad table length 4" 326 }, { 327 .st_entry = SMBIOS_ENTRY_POINT_30, 328 .st_tvers = SMB_VERSION, 329 .st_libvers = SMB_VERSION, 330 .st_mktable = smbios_test_memdevice_mktable_32, 331 .st_canopen = B_TRUE, 332 .st_verify = smbios_test_pinfo_verify_badtype, 333 .st_desc = "processor additional information - bad type" 334 }, 335 336 }; 337 338 static boolean_t 339 smbios_test_run_one(const smbios_test_t *test) 340 { 341 smbios_test_table_t *table = NULL; 342 smbios_hdl_t *hdl = NULL; 343 void *buf; 344 size_t len; 345 smbios_entry_t *entry; 346 int err = 0; 347 boolean_t ret = B_FALSE; 348 349 table = smbios_test_table_init(test->st_entry, test->st_tvers); 350 if (!test->st_mktable(table)) { 351 goto out; 352 } 353 354 smbios_test_table_snapshot(table, &entry, &buf, &len); 355 hdl = smbios_bufopen(entry, buf, len, test->st_libvers, SMB_FL_DEBUG, 356 &err); 357 if (test->st_canopen) { 358 if (hdl == NULL) { 359 warnx("failed to create table for test %s: %s", 360 test->st_desc, smbios_errmsg(err)); 361 goto out; 362 } 363 } else { 364 if (hdl != NULL) { 365 warnx("accidentally created table for test %s, " 366 "expected failure", test->st_desc); 367 } else { 368 ret = B_TRUE; 369 } 370 goto out; 371 } 372 373 if (test->st_verify(hdl)) { 374 ret = B_TRUE; 375 } 376 377 out: 378 if (hdl != NULL) { 379 smbios_close(hdl); 380 } 381 382 if (table != NULL) { 383 smbios_test_table_fini(table); 384 } 385 386 if (ret) { 387 (void) printf("TEST PASSED: %s\n", test->st_desc); 388 } else { 389 (void) printf("TEST FAILED: %s\n", test->st_desc); 390 } 391 392 return (ret); 393 } 394 395 int 396 main(void) 397 { 398 int err = 0; 399 size_t i; 400 401 for (i = 0; i < ARRAY_SIZE(smbios_tests); i++) { 402 if (!smbios_test_run_one(&smbios_tests[i])) { 403 err = 1; 404 } 405 } 406 407 return (err); 408 } 409