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 */ 15 16 /* 17 * Primordial SMBIOS test suite. At the moment, the purpose of this is just to 18 * test the recent SMBIOS 3.2 additions specific to the variable length slots. 19 * This should be evolved into a much fuller test suite. 20 */ 21 22 #include <smbios.h> 23 #include <umem.h> 24 #include <stdint.h> 25 #include <endian.h> 26 #include <stdio.h> 27 #include <err.h> 28 29 #include <sys/smbios.h> 30 #include <sys/smbios_impl.h> 31 32 static const char *smbios_test_name = "The One Slot"; 33 34 /* 35 * Number of bytes we allocate at a given time for an SMBIOS table. 36 */ 37 #define SMBIOS_TEST_ALLOC_SIZE 1024 38 39 typedef struct smbios_test_table { 40 smbios_entry_point_t stt_type; 41 void *stt_data; 42 size_t stt_buflen; 43 size_t stt_offset; 44 uint_t stt_nents; 45 uint_t stt_version; 46 uint_t stt_nextid; 47 smbios_entry_t stt_entry; 48 } smbios_test_table_t; 49 50 const char * 51 _umem_debug_init(void) 52 { 53 return ("default,verbose"); 54 } 55 56 const char * 57 _umem_logging_init(void) 58 { 59 return ("fail,contents"); 60 } 61 62 static smbios_test_table_t * 63 smbios_test_table_init(smbios_entry_point_t type, uint_t version) 64 { 65 smbios_test_table_t *table; 66 67 if (type != SMBIOS_ENTRY_POINT_30) { 68 abort(); 69 } 70 71 table = umem_zalloc(sizeof (smbios_test_table_t), UMEM_DEFAULT); 72 if (table == NULL) { 73 return (NULL); 74 } 75 76 table->stt_data = umem_zalloc(SMBIOS_TEST_ALLOC_SIZE, UMEM_DEFAULT); 77 if (table->stt_data == NULL) { 78 umem_free(table, sizeof (smbios_test_table_t)); 79 return (NULL); 80 } 81 table->stt_buflen = SMBIOS_TEST_ALLOC_SIZE; 82 table->stt_type = type; 83 table->stt_version = version; 84 table->stt_nextid = 1; 85 86 return (table); 87 } 88 89 static void * 90 smbios_test_table_append_common(smbios_test_table_t *table, const void *buf, 91 size_t len) 92 { 93 void *start; 94 95 if (SIZE_MAX - table->stt_offset < len) 96 abort(); 97 98 if (len + table->stt_offset >= table->stt_buflen) { 99 void *newbuf; 100 size_t newlen = table->stt_buflen + SMBIOS_TEST_ALLOC_SIZE; 101 102 while (len + table->stt_offset >= newlen) { 103 newlen += SMBIOS_TEST_ALLOC_SIZE; 104 } 105 106 newbuf = umem_zalloc(newlen, UMEM_DEFAULT); 107 if (newbuf == NULL) { 108 err(EXIT_FAILURE, "failed to umem_zalloc for %lu bytes", 109 newlen); 110 } 111 112 (void) memcpy(newbuf, table->stt_data, table->stt_buflen); 113 umem_free(table->stt_data, table->stt_buflen); 114 table->stt_data = newbuf; 115 table->stt_buflen = newlen; 116 } 117 118 start = (void *)((uintptr_t)table->stt_data + table->stt_offset); 119 (void) memcpy(start, buf, len); 120 table->stt_offset += len; 121 122 return (start); 123 } 124 125 static void 126 smbios_test_table_append_raw(smbios_test_table_t *table, const void *buf, 127 size_t len) 128 { 129 (void) smbios_test_table_append_common(table, buf, len); 130 } 131 132 static void 133 smbios_test_table_append_string(smbios_test_table_t *table, const char *str) 134 { 135 size_t len = strlen(str) + 1; 136 (void) smbios_test_table_append_common(table, str, len); 137 } 138 139 static uint16_t 140 smbios_test_table_append(smbios_test_table_t *table, const void *buf, 141 size_t len) 142 { 143 smb_header_t *hdr; 144 uint16_t id; 145 146 hdr = smbios_test_table_append_common(table, buf, len); 147 table->stt_nents++; 148 149 id = table->stt_nextid; 150 hdr->smbh_hdl = htole16(table->stt_nextid); 151 table->stt_nextid++; 152 153 return (id); 154 } 155 156 static uint8_t 157 smbios_test_table_checksum(const uint8_t *buf, size_t len) 158 { 159 uint8_t sum; 160 size_t i; 161 162 for (i = 0, sum = 0; i < len; i++) { 163 sum += buf[i]; 164 } 165 166 if (sum == 0) 167 return (0); 168 169 return ((uint8_t)(0x100 - sum)); 170 } 171 172 static void 173 smbios_test_table_snapshot(smbios_test_table_t *table, smbios_entry_t **entryp, 174 void **bufp, size_t *lenp) 175 { 176 smbios_30_entry_t *ent30; 177 178 switch (table->stt_type) { 179 case SMBIOS_ENTRY_POINT_30: 180 ent30 = &table->stt_entry.ep30; 181 182 (void) memcpy(ent30->smbe_eanchor, SMB3_ENTRY_EANCHOR, 183 sizeof (ent30->smbe_eanchor)); 184 ent30->smbe_ecksum = 0; 185 ent30->smbe_elen = sizeof (*ent30); 186 ent30->smbe_major = (table->stt_version >> 8) & 0xff; 187 ent30->smbe_minor = table->stt_version & 0xff; 188 ent30->smbe_docrev = 0; 189 ent30->smbe_revision = 1; 190 ent30->smbe_reserved = 0; 191 ent30->smbe_stlen = htole32(table->stt_offset); 192 ent30->smbe_staddr = htole64(P2ROUNDUP(sizeof (*ent30), 16)); 193 194 ent30->smbe_ecksum = smbios_test_table_checksum((void *)ent30, 195 sizeof (*ent30)); 196 break; 197 default: 198 abort(); 199 } 200 201 *entryp = &table->stt_entry; 202 *bufp = table->stt_data; 203 *lenp = table->stt_offset; 204 } 205 206 static void 207 smbios_test_table_fini(smbios_test_table_t *table) 208 { 209 if (table == NULL) { 210 return; 211 } 212 213 if (table->stt_data != NULL) { 214 umem_free(table->stt_data, table->stt_buflen); 215 } 216 217 umem_free(table, sizeof (smbios_test_table_t)); 218 } 219 220 static void 221 smbios_test_mktable(smbios_test_table_t *table) 222 { 223 smb_slot_t slot; 224 smb_slot_peer_t peers[2]; 225 smb_header_t eot; 226 uint8_t endstring = 0; 227 228 slot.smbsl_hdr.smbh_type = SMB_TYPE_SLOT; 229 slot.smbsl_hdr.smbh_len = sizeof (smb_slot_t) + sizeof (peers); 230 231 slot.smbsl_name = 1; 232 slot.smbsl_type = SMB_SLT_PCIE3G16; 233 slot.smbsl_width = SMB_SLW_16X; 234 slot.smbsl_length = SMB_SLL_SHORT; 235 slot.smbsl_id = htole16(1); 236 slot.smbsl_ch1 = SMB_SLCH1_33V; 237 slot.smbsl_ch2 = SMB_SLCH2_PME; 238 slot.smbsl_sg = htole16(1); 239 slot.smbsl_bus = 0x42; 240 slot.smbsl_df = 0x23; 241 slot.smbsl_dbw = SMB_SLW_16X; 242 slot.smbsl_npeers = 2; 243 peers[0].smbspb_group_no = htole16(1); 244 peers[0].smbspb_bus = 0x42; 245 peers[0].smbspb_df = 0x42; 246 peers[0].smbspb_width = SMB_SLW_8X; 247 248 peers[1].smbspb_group_no = htole16(1); 249 peers[1].smbspb_bus = 0x23; 250 peers[1].smbspb_df = 0x31; 251 peers[1].smbspb_width = SMB_SLW_8X; 252 253 (void) smbios_test_table_append(table, &slot, sizeof (slot)); 254 (void) smbios_test_table_append_raw(table, peers, sizeof (peers)); 255 (void) smbios_test_table_append_string(table, smbios_test_name); 256 (void) smbios_test_table_append_raw(table, &endstring, 257 sizeof (endstring)); 258 259 bzero(&eot, sizeof (eot)); 260 eot.smbh_type = SMB_TYPE_EOT; 261 eot.smbh_len = 4; 262 (void) smbios_test_table_append(table, &eot, sizeof (eot)); 263 (void) smbios_test_table_append_raw(table, &endstring, 264 sizeof (endstring)); 265 (void) smbios_test_table_append_raw(table, &endstring, 266 sizeof (endstring)); 267 } 268 269 static void 270 smbios_test_verify_table(smbios_hdl_t *hdl) 271 { 272 smbios_struct_t sp; 273 smbios_slot_t slot; 274 uint_t npeers; 275 smbios_slot_peer_t *peers; 276 uint_t errs = 0; 277 278 if (smbios_lookup_type(hdl, SMB_TYPE_SLOT, &sp) == -1) { 279 errx(EXIT_FAILURE, "failed to lookup SMBIOS slot: %s", 280 smbios_errmsg(smbios_errno(hdl))); 281 } 282 283 if (smbios_info_slot(hdl, sp.smbstr_id, &slot) != 0) { 284 errx(EXIT_FAILURE, "failed to get SMBIOS slot info: %s", 285 smbios_errmsg(smbios_errno(hdl))); 286 } 287 288 /* 289 * Verify everything we'd expect about the slot. 290 */ 291 if (strcmp(slot.smbl_name, smbios_test_name) != 0) { 292 warnx("slot name mismatch, expected %s, found %s", 293 smbios_test_name, slot.smbl_name); 294 errs++; 295 } 296 297 if (slot.smbl_type != SMB_SLT_PCIE3G16) { 298 warnx("incorrect slot type, found %u", slot.smbl_type); 299 errs++; 300 } 301 302 if (slot.smbl_width != SMB_SLW_16X) { 303 warnx("incorrect slot width, found %u", slot.smbl_width); 304 errs++; 305 } 306 307 if (slot.smbl_length != SMB_SLL_SHORT) { 308 warnx("incorrect slot length, found %u", slot.smbl_length); 309 errs++; 310 } 311 312 if (slot.smbl_dbw != SMB_SLW_16X) { 313 warnx("incorrect slot data bus width, found %u", slot.smbl_dbw); 314 errs++; 315 } 316 317 if (slot.smbl_npeers != 2) { 318 warnx("incorrect number of slot peers, found %u", 319 slot.smbl_npeers); 320 errs++; 321 } 322 323 if (smbios_info_slot_peers(hdl, sp.smbstr_id, &npeers, &peers) != 0) { 324 errx(EXIT_FAILURE, "failed to get SMBIOS peer info: %s", 325 smbios_errmsg(smbios_errno(hdl))); 326 } 327 328 if (npeers != 2) { 329 errx(EXIT_FAILURE, "got wrong number of slot peers: %u\n", 330 npeers); 331 } 332 333 if (peers[0].smblp_group != 1) { 334 warnx("incorrect group for peer 0: %u", peers[0].smblp_group); 335 errs++; 336 } 337 338 if (peers[0].smblp_data_width != SMB_SLW_8X) { 339 warnx("incorrect data width for peer 0: %u", 340 peers[0].smblp_data_width); 341 errs++; 342 } 343 344 if (peers[0].smblp_device != (0x42 >> 3)) { 345 warnx("incorrect PCI device for peer 0: %u", 346 peers[0].smblp_device); 347 errs++; 348 } 349 350 if (peers[0].smblp_function != (0x42 & 0x7)) { 351 warnx("incorrect PCI function for peer 0: %u", 352 peers[0].smblp_function); 353 errs++; 354 } 355 356 if (peers[1].smblp_group != 1) { 357 warnx("incorrect group for peer 1: %u", peers[1].smblp_group); 358 errs++; 359 } 360 361 if (peers[1].smblp_device != (0x31 >> 3)) { 362 warnx("incorrect PCI device for peer 1: %u", 363 peers[1].smblp_device); 364 errs++; 365 } 366 367 if (peers[1].smblp_function != (0x31 & 0x7)) { 368 warnx("incorrect PCI function for peer 1: %u", 369 peers[1].smblp_function); 370 errs++; 371 } 372 373 if (peers[1].smblp_data_width != SMB_SLW_8X) { 374 warnx("incorrect data width for peer 1: %u", 375 peers[1].smblp_data_width); 376 errs++; 377 } 378 379 smbios_info_slot_peers_free(hdl, npeers, peers); 380 381 if (errs > 0) { 382 errx(EXIT_FAILURE, "encountered fatal errors"); 383 } 384 } 385 386 int 387 main(void) 388 { 389 void *buf; 390 size_t len; 391 smbios_test_table_t *table; 392 smbios_entry_t *entry; 393 smbios_hdl_t *hdl; 394 int err = 0; 395 396 table = smbios_test_table_init(SMBIOS_ENTRY_POINT_30, SMB_VERSION_32); 397 smbios_test_mktable(table); 398 smbios_test_table_snapshot(table, &entry, &buf, &len); 399 400 hdl = smbios_bufopen(entry, buf, len, SMB_VERSION_32, SMB_FL_DEBUG, 401 &err); 402 if (hdl == NULL) { 403 errx(EXIT_FAILURE, "failed to create fake smbios table: %s", 404 smbios_errmsg(err)); 405 } 406 smbios_test_verify_table(hdl); 407 smbios_close(hdl); 408 smbios_test_table_fini(table); 409 410 return (0); 411 } 412