1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. 24 * Copyright 2019 Joyent, Inc. 25 * Copyright 2025 Oxide Computer Company 26 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 /* 31 * SMBIOS Information Routines 32 * 33 * The routines in this file are used to convert from the SMBIOS data format to 34 * a more reasonable and stable set of structures offered as part of our ABI. 35 * These functions take the general form: 36 * 37 * stp = smb_lookup_type(shp, foo); 38 * smb_foo_t foo; 39 * 40 * smb_info_bcopy(stp->smbst_hdr, &foo, sizeof (foo)); 41 * bzero(caller's struct); 42 * 43 * copy/convert foo members into caller's struct 44 * 45 * We copy the internal structure on to an automatic variable so as to avoid 46 * checks everywhere for structures that the BIOS has improperly truncated, and 47 * also to automatically handle the case of a structure that has been extended. 48 * When necessary, this code can use smb_gteq() to determine whether the SMBIOS 49 * data is of a particular revision that is supposed to contain a new field. 50 * 51 * Note, when trying to bzero the caller's struct you have to be careful about 52 * versions. One can only bzero the initial version that existed in illumos. In 53 * other words, if someone passes an older library handle that doesn't support a 54 * version you cannot assume that their structures have those additional members 55 * in them. Instead, a 'base' version is introduced for such types that have 56 * differences and instead we only bzero out the base version and then handle 57 * the additional members. In general, because all additional members will be 58 * assigned, there's no reason to zero them out unless they are arrays that 59 * won't be entirely filled in. 60 * 61 * Due to history, anything added after the update from version 2.4, in other 62 * words additions from or after '5094 Update libsmbios with recent items' 63 * (4e901881) is currently being used for this. While we don't allow software 64 * compiling against this to get an older form, this was the first major update 65 * and a good starting point for us to enforce this behavior which is useful for 66 * moving forward to making this more public. 67 */ 68 69 #include <sys/smbios_impl.h> 70 #include <sys/byteorder.h> 71 #include <sys/debug.h> 72 73 #ifdef _KERNEL 74 #include <sys/sunddi.h> 75 #else 76 #include <fcntl.h> 77 #include <unistd.h> 78 #include <string.h> 79 #endif 80 81 #define SMB_CONT_WORD 2 /* contained elements are word size */ 82 83 /* 84 * A large number of SMBIOS structures contain a set of common strings used to 85 * describe a h/w component's serial number, manufacturer, etc. These fields 86 * helpfully have different names and offsets and sometimes aren't consistent. 87 * To simplify life for our clients, we factor these common things out into 88 * smbios_info_t, which can be retrieved for any structure. The following 89 * table describes the mapping from a given structure to the smbios_info_t. 90 * Multiple SMBIOS stuctures' contained objects are also handled here. 91 */ 92 static const struct smb_infospec { 93 uint8_t is_type; /* structure type */ 94 uint8_t is_manu; /* manufacturer offset */ 95 uint8_t is_product; /* product name offset */ 96 uint8_t is_version; /* version offset */ 97 uint8_t is_serial; /* serial number offset */ 98 uint8_t is_asset; /* asset tag offset */ 99 uint8_t is_location; /* location string offset */ 100 uint8_t is_part; /* part number offset */ 101 uint8_t is_contc; /* contained count */ 102 uint8_t is_contsz; /* contained size */ 103 uint8_t is_contv; /* contained objects */ 104 } _smb_infospecs[] = { 105 { SMB_TYPE_SYSTEM, 106 offsetof(smb_system_t, smbsi_manufacturer), 107 offsetof(smb_system_t, smbsi_product), 108 offsetof(smb_system_t, smbsi_version), 109 offsetof(smb_system_t, smbsi_serial), 110 0, 111 0, 112 0, 113 0, 114 0, 115 0 }, 116 { SMB_TYPE_BASEBOARD, 117 offsetof(smb_bboard_t, smbbb_manufacturer), 118 offsetof(smb_bboard_t, smbbb_product), 119 offsetof(smb_bboard_t, smbbb_version), 120 offsetof(smb_bboard_t, smbbb_serial), 121 offsetof(smb_bboard_t, smbbb_asset), 122 offsetof(smb_bboard_t, smbbb_location), 123 0, 124 offsetof(smb_bboard_t, smbbb_cn), 125 SMB_CONT_WORD, 126 offsetof(smb_bboard_t, smbbb_cv) }, 127 { SMB_TYPE_CHASSIS, 128 offsetof(smb_chassis_t, smbch_manufacturer), 129 0, 130 offsetof(smb_chassis_t, smbch_version), 131 offsetof(smb_chassis_t, smbch_serial), 132 offsetof(smb_chassis_t, smbch_asset), 133 0, 134 0, 135 0, 136 0, 137 0 }, 138 { SMB_TYPE_PROCESSOR, 139 offsetof(smb_processor_t, smbpr_manufacturer), 140 0, 141 offsetof(smb_processor_t, smbpr_version), 142 offsetof(smb_processor_t, smbpr_serial), 143 offsetof(smb_processor_t, smbpr_asset), 144 offsetof(smb_processor_t, smbpr_socket), 145 offsetof(smb_processor_t, smbpr_part), 146 0, 147 0, 148 0 }, 149 { SMB_TYPE_CACHE, 150 0, 151 0, 152 0, 153 0, 154 0, 155 offsetof(smb_cache_t, smbca_socket), 156 0, 157 0, 158 0, 159 0 }, 160 { SMB_TYPE_PORT, 161 0, 162 0, 163 0, 164 0, 165 0, 166 offsetof(smb_port_t, smbpo_iref), 167 0, 168 0, 169 0, 170 0 }, 171 { SMB_TYPE_SLOT, 172 0, 173 0, 174 0, 175 0, 176 0, 177 offsetof(smb_slot_t, smbsl_name), 178 0, 179 0, 180 0, 181 0 }, 182 { SMB_TYPE_MEMDEVICE, 183 offsetof(smb_memdevice_t, smbmdev_manufacturer), 184 0, 185 0, 186 offsetof(smb_memdevice_t, smbmdev_serial), 187 offsetof(smb_memdevice_t, smbmdev_asset), 188 offsetof(smb_memdevice_t, smbmdev_dloc), 189 offsetof(smb_memdevice_t, smbmdev_part), 190 0, 191 0, 192 0 }, 193 { SMB_TYPE_POWERSUP, 194 offsetof(smb_powersup_t, smbpsup_manufacturer), 195 offsetof(smb_powersup_t, smbpsup_devname), 196 offsetof(smb_powersup_t, smbpsup_rev), 197 offsetof(smb_powersup_t, smbpsup_serial), 198 offsetof(smb_powersup_t, smbpsup_asset), 199 offsetof(smb_powersup_t, smbpsup_loc), 200 offsetof(smb_powersup_t, smbpsup_part), 201 0, 202 0, 203 0 }, 204 { SMB_TYPE_BATTERY, 205 offsetof(smb_battery_t, smbbat_manufacturer), 206 offsetof(smb_battery_t, smbbat_devname), 207 0, 208 /* 209 * While the serial number is a part of the device, because of 210 * the fact that the battery has two different serial numbers, 211 * we don't include it here. 212 */ 213 0, 214 0, 215 offsetof(smb_battery_t, smbbat_loc), 216 0, 217 0, 218 0, 219 0 220 }, 221 { SMB_TYPE_FWINFO, 222 offsetof(smb_fwinfo_t, smbfwii_mfg), 223 0, 224 offsetof(smb_fwinfo_t, smbfwii_vers), 225 0, 226 0, 227 0, 228 0, 229 0, 230 0, 231 0 232 }, 233 { SMB_TYPE_EOT } 234 }; 235 236 static const char * 237 smb_info_strptr(const smb_struct_t *stp, uint8_t off, int *n) 238 { 239 const uint8_t *sp = (const uint8_t *)(uintptr_t)stp->smbst_hdr; 240 241 if (off != 0 && sp + off < stp->smbst_end) { 242 (*n)++; /* indicate success for caller */ 243 return (smb_strptr(stp, sp[off])); 244 } 245 246 return (smb_strptr(stp, 0)); 247 } 248 249 static void 250 smb_info_bcopy_offset(const smb_header_t *hp, void *dst, size_t dstlen, 251 size_t offset) 252 { 253 if (offset >= hp->smbh_len) { 254 bzero(dst, dstlen); 255 } else if (offset + dstlen > hp->smbh_len) { 256 size_t nvalid = MIN(hp->smbh_len - offset, dstlen); 257 bcopy((char *)hp + offset, dst, nvalid); 258 bzero((char *)dst + nvalid, dstlen - nvalid); 259 } else { 260 bcopy((char *)hp + offset, dst, dstlen); 261 } 262 } 263 264 static void 265 smb_info_bcopy(const smb_header_t *hp, void *dst, size_t dstlen) 266 { 267 return (smb_info_bcopy_offset(hp, dst, dstlen, 0)); 268 } 269 270 smbios_entry_point_t 271 smbios_info_smbios(smbios_hdl_t *shp, smbios_entry_t *ep) 272 { 273 bcopy(&shp->sh_ent, ep, sizeof (smbios_entry_t)); 274 return (shp->sh_ent_type); 275 } 276 277 void 278 smbios_info_smbios_version(smbios_hdl_t *shp, smbios_version_t *v) 279 { 280 v->smbv_major = SMB_MAJOR(shp->sh_smbvers); 281 v->smbv_minor = SMB_MINOR(shp->sh_smbvers); 282 } 283 284 #ifndef _KERNEL 285 static char smbios_product_override[256]; 286 static boolean_t smbios_product_checked; 287 #endif 288 289 int 290 smbios_info_common(smbios_hdl_t *shp, id_t id, smbios_info_t *ip) 291 { 292 const smb_struct_t *stp = smb_lookup_id(shp, id); 293 const struct smb_infospec *isp; 294 int n = 0; 295 296 if (stp == NULL) 297 return (-1); /* errno is set for us */ 298 299 for (isp = _smb_infospecs; isp->is_type != SMB_TYPE_EOT; isp++) { 300 if (isp->is_type == stp->smbst_hdr->smbh_type) 301 break; 302 } 303 304 ip->smbi_manufacturer = smb_info_strptr(stp, isp->is_manu, &n); 305 ip->smbi_product = smb_info_strptr(stp, isp->is_product, &n); 306 ip->smbi_version = smb_info_strptr(stp, isp->is_version, &n); 307 ip->smbi_serial = smb_info_strptr(stp, isp->is_serial, &n); 308 ip->smbi_asset = smb_info_strptr(stp, isp->is_asset, &n); 309 ip->smbi_location = smb_info_strptr(stp, isp->is_location, &n); 310 ip->smbi_part = smb_info_strptr(stp, isp->is_part, &n); 311 312 /* 313 * This private file allows developers to experiment with reporting 314 * different platform strings from SMBIOS. It is not a supported 315 * mechanism in the long term, and does not work in the kernel. 316 */ 317 #ifndef _KERNEL 318 if (isp->is_type == SMB_TYPE_SYSTEM) { 319 if (!smbios_product_checked) { 320 int fd = open("/etc/smbios_product", O_RDONLY); 321 if (fd >= 0) { 322 (void) read(fd, smbios_product_override, 323 sizeof (smbios_product_override) - 1); 324 (void) close(fd); 325 } 326 smbios_product_checked = B_TRUE; 327 } 328 329 if (smbios_product_override[0] != '\0') 330 ip->smbi_product = smbios_product_override; 331 } 332 #endif 333 334 /* 335 * If we have a port with an empty internal reference designator string 336 * try using the external reference designator string instead. 337 */ 338 if (isp->is_type == SMB_TYPE_PORT && ip->smbi_location[0] == '\0') { 339 ip->smbi_location = smb_info_strptr(stp, 340 offsetof(smb_port_t, smbpo_eref), &n); 341 } 342 343 return (n ? 0 : smb_set_errno(shp, ESMB_NOINFO)); 344 } 345 346 /* 347 * Returns the actual number of contained objects. 348 * 349 * idc - number of contained objects 350 * idv - returned array of contained objects 351 */ 352 int 353 smbios_info_contains(smbios_hdl_t *shp, id_t id, uint_t idc, id_t *idv) 354 { 355 const smb_struct_t *stp = smb_lookup_id(shp, id); 356 const struct smb_infospec *isp; 357 id_t *cp; 358 uint_t size; 359 uint8_t cnt; 360 int i, n; 361 362 if (stp == NULL) { 363 return (-1); /* errno is set for us */ 364 } 365 366 for (isp = _smb_infospecs; isp->is_type != SMB_TYPE_EOT; isp++) { 367 if (isp->is_type == stp->smbst_hdr->smbh_type) 368 break; 369 } 370 if (isp->is_type == SMB_TYPE_EOT) 371 return (smb_set_errno(shp, ESMB_TYPE)); 372 373 size = isp->is_contsz; 374 cnt = *((uint8_t *)(uintptr_t)stp->smbst_hdr + isp->is_contc); 375 cp = (id_t *)((uintptr_t)stp->smbst_hdr + isp->is_contv); 376 377 n = MIN(cnt, idc); 378 for (i = 0; i < n; i++) { 379 if (size == SMB_CONT_WORD) 380 idv[i] = *((uint16_t *)(uintptr_t)cp + (i * 2)); 381 else 382 return (smb_set_errno(shp, ESMB_INVAL)); 383 } 384 385 return (cnt); 386 } 387 388 id_t 389 smbios_info_bios(smbios_hdl_t *shp, smbios_bios_t *bp) 390 { 391 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BIOS); 392 const smb_bios_t *bip; 393 394 if (stp == NULL) 395 return (-1); /* errno is set for us */ 396 397 if (stp->smbst_hdr->smbh_len < sizeof (smb_bios_t) - sizeof (uint8_t)) 398 return (smb_set_errno(shp, ESMB_CORRUPT)); 399 400 bip = (smb_bios_t *)(uintptr_t)stp->smbst_hdr; 401 bzero(bp, sizeof (smb_base_bios_t)); 402 if (smb_libgteq(shp, SMB_VERSION_31)) { 403 bp->smbb_extromsize = 0; 404 } 405 406 bp->smbb_vendor = smb_strptr(stp, bip->smbbi_vendor); 407 bp->smbb_version = smb_strptr(stp, bip->smbbi_version); 408 bp->smbb_segment = bip->smbbi_segment; 409 bp->smbb_reldate = smb_strptr(stp, bip->smbbi_reldate); 410 bp->smbb_romsize = 64 * 1024 * ((uint32_t)bip->smbbi_romsize + 1); 411 bp->smbb_runsize = 16 * (0x10000 - (uint32_t)bip->smbbi_segment); 412 bp->smbb_cflags = bip->smbbi_cflags; 413 414 /* 415 * If one or more extension bytes are present, reset smbb_xcflags to 416 * point to them. Otherwise leave this member set to NULL. 417 */ 418 if (stp->smbst_hdr->smbh_len >= sizeof (smb_bios_t)) { 419 bp->smbb_xcflags = bip->smbbi_xcflags; 420 bp->smbb_nxcflags = stp->smbst_hdr->smbh_len - 421 sizeof (smb_bios_t) + 1; 422 423 if (bp->smbb_nxcflags > SMB_BIOSXB_ECFW_MIN && 424 smb_gteq(shp, SMB_VERSION_24)) { 425 bp->smbb_biosv.smbv_major = 426 bip->smbbi_xcflags[SMB_BIOSXB_BIOS_MAJ]; 427 bp->smbb_biosv.smbv_minor = 428 bip->smbbi_xcflags[SMB_BIOSXB_BIOS_MIN]; 429 bp->smbb_ecfwv.smbv_major = 430 bip->smbbi_xcflags[SMB_BIOSXB_ECFW_MAJ]; 431 bp->smbb_ecfwv.smbv_minor = 432 bip->smbbi_xcflags[SMB_BIOSXB_ECFW_MIN]; 433 } 434 435 if (bp->smbb_nxcflags > SMB_BIOSXB_EXTROM + 1 && 436 smb_gteq(shp, SMB_VERSION_31)) { 437 uint16_t val; 438 uint64_t rs; 439 440 /* 441 * Because of the fact that the extended size is a 442 * uint16_t and we'd need to define an explicit 443 * endian-aware way to access it, we don't include it in 444 * the number of extended flags below and thus subtract 445 * its size. 446 */ 447 bp->smbb_nxcflags -= sizeof (uint16_t); 448 bcopy(&bip->smbbi_xcflags[SMB_BIOSXB_EXTROM], &val, 449 sizeof (val)); 450 val = LE_16(val); 451 452 /* 453 * The upper two bits of the extended rom size are used 454 * to indicate whether the other 14 bits are in MB or 455 * GB. 456 */ 457 rs = SMB_BIOS_EXTROM_VALUE_MASK(val); 458 switch (SMB_BIOS_EXTROM_SHIFT_MASK(val)) { 459 case 0: 460 rs *= 1024ULL * 1024ULL; 461 break; 462 case 1: 463 rs *= 1024ULL * 1024ULL * 1024ULL; 464 break; 465 default: 466 rs = 0; 467 break; 468 } 469 470 if (smb_libgteq(shp, SMB_VERSION_31)) { 471 bp->smbb_extromsize = rs; 472 } 473 } 474 } 475 476 if (smb_libgteq(shp, SMB_VERSION_31) && bp->smbb_extromsize == 0) { 477 bp->smbb_extromsize = bp->smbb_romsize; 478 } 479 480 return (stp->smbst_hdr->smbh_hdl); 481 } 482 483 id_t 484 smbios_info_system(smbios_hdl_t *shp, smbios_system_t *sip) 485 { 486 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_SYSTEM); 487 smb_system_t si; 488 489 if (stp == NULL) 490 return (-1); /* errno is set for us */ 491 492 smb_info_bcopy(stp->smbst_hdr, &si, sizeof (si)); 493 bzero(sip, sizeof (smbios_system_t)); 494 495 sip->smbs_uuid = ((smb_system_t *)stp->smbst_hdr)->smbsi_uuid; 496 sip->smbs_uuidlen = sizeof (si.smbsi_uuid); 497 sip->smbs_wakeup = si.smbsi_wakeup; 498 sip->smbs_sku = smb_strptr(stp, si.smbsi_sku); 499 sip->smbs_family = smb_strptr(stp, si.smbsi_family); 500 501 return (stp->smbst_hdr->smbh_hdl); 502 } 503 504 int 505 smbios_info_bboard(smbios_hdl_t *shp, id_t id, smbios_bboard_t *bbp) 506 { 507 const smb_struct_t *stp = smb_lookup_id(shp, id); 508 smb_bboard_t bb; 509 510 if (stp == NULL) 511 return (-1); /* errno is set for us */ 512 513 if (stp->smbst_hdr->smbh_type != SMB_TYPE_BASEBOARD) 514 return (smb_set_errno(shp, ESMB_TYPE)); 515 516 smb_info_bcopy(stp->smbst_hdr, &bb, sizeof (bb)); 517 bzero(bbp, sizeof (smbios_bboard_t)); 518 519 bbp->smbb_chassis = bb.smbbb_chassis; 520 bbp->smbb_flags = bb.smbbb_flags; 521 bbp->smbb_type = bb.smbbb_type; 522 bbp->smbb_contn = bb.smbbb_cn; 523 524 return (0); 525 } 526 527 int 528 smbios_info_chassis(smbios_hdl_t *shp, id_t id, smbios_chassis_t *chp) 529 { 530 const smb_struct_t *stp = smb_lookup_id(shp, id); 531 off_t skuoff; 532 smb_chassis_t ch; 533 smb_chassis_bonus_t b; 534 535 if (stp == NULL) { 536 return (-1); /* errno is set for us */ 537 } 538 539 if (stp->smbst_hdr->smbh_type != SMB_TYPE_CHASSIS) { 540 return (smb_set_errno(shp, ESMB_TYPE)); 541 } 542 543 /* 544 * The minimum table length for the chassis is 0xd, which is the 545 * starting point of the OEM data. This was set in SMBIOS 2.1. We don't 546 * consider SMBIOS 2.0 tables right now. 547 */ 548 if (stp->smbst_hdr->smbh_len < offsetof(smb_chassis_t, smbch_oemdata)) { 549 return (smb_set_errno(shp, ESMB_SHORT)); 550 } 551 552 smb_info_bcopy(stp->smbst_hdr, &ch, sizeof (ch)); 553 bzero(chp, sizeof (smb_base_chassis_t)); 554 555 /* 556 * See the comments for the smb_chassis_pre35_t in <sys/smbios_impl.h> 557 * for an explanation as to why this is here. The use of smb_strptr with 558 * index 0 below ensures that we initialize this to an empty string. 559 */ 560 if (smb_libgteq(shp, SMB_VERSION_35)) { 561 chp->smbc_sku = smb_strptr(stp, 0); 562 } else if (smb_libgteq(shp, SMB_VERSION_27)) { 563 smb_chassis_pre35_t *p35 = (smb_chassis_pre35_t *)chp; 564 bzero(p35->smbc_sku, sizeof (p35->smbc_sku)); 565 } 566 567 /* 568 * SMBIOS 3.9 added the rack type and height. Make sure to initialize 569 * this if the library is new enough. 570 */ 571 if (smb_libgteq(shp, SMB_VERSION_39)) { 572 chp->smbc_rtype = 0; 573 chp->smbc_rheight = 0; 574 } 575 chp->smbc_oemdata = ch.smbch_oemdata; 576 chp->smbc_lock = (ch.smbch_type & SMB_CHT_LOCK) != 0; 577 chp->smbc_type = ch.smbch_type & ~SMB_CHT_LOCK; 578 chp->smbc_bustate = ch.smbch_bustate; 579 chp->smbc_psstate = ch.smbch_psstate; 580 chp->smbc_thstate = ch.smbch_thstate; 581 chp->smbc_security = ch.smbch_security; 582 chp->smbc_uheight = ch.smbch_uheight; 583 chp->smbc_cords = ch.smbch_cords; 584 chp->smbc_elems = ch.smbch_cn; 585 chp->smbc_elemlen = ch.smbch_cm; 586 587 /* 588 * If the table is older than version 2.7 which added support for the 589 * chassis SKU, there's no reason to proceed. A 2.7 table is not 590 * required to have support for a chassis SKU so we don't proceed either 591 * if there isn't space for the SKU byte. This is very common of 592 * hypervisors. 593 */ 594 if (!smb_gteq(shp, SMB_VERSION_27)) { 595 return (0); 596 } 597 598 skuoff = sizeof (ch) + ch.smbch_cn * ch.smbch_cm; 599 smb_info_bcopy_offset(stp->smbst_hdr, &b, sizeof (b), skuoff); 600 601 /* 602 * In the library versions between 2.7 and 3.4, we opted to embed the 603 * SKU in the chassis structure itself, rather than include a pointer. 604 * See the comments around the smb_chassis_pre35_t in 605 * <sys/smbios_impl.h>. 606 */ 607 if (smb_libgteq(shp, SMB_VERSION_27) && 608 !smb_libgteq(shp, SMB_VERSION_34)) { 609 smb_chassis_pre35_t *p35 = (smb_chassis_pre35_t *)chp; 610 const char *str; 611 612 str = smb_strptr(stp, b.smbcb_sku); 613 (void) strlcpy(p35->smbc_sku, str, sizeof (p35->smbc_sku)); 614 } 615 616 if (smb_libgteq(shp, SMB_VERSION_35)) { 617 chp->smbc_sku = smb_strptr(stp, b.smbcb_sku); 618 } 619 620 if (smb_libgteq(shp, SMB_VERSION_39)) { 621 chp->smbc_rtype = b.smbcb_rtype; 622 chp->smbc_rheight = b.smbcb_rheight; 623 } 624 625 return (0); 626 } 627 628 int 629 smbios_info_chassis_elts(smbios_hdl_t *shp, id_t id, uint_t *nentsp, 630 smbios_chassis_entry_t **entsp) 631 { 632 const smb_struct_t *stp = smb_lookup_id(shp, id); 633 smbios_chassis_entry_t *entry; 634 smb_chassis_t ch; 635 size_t entlen; 636 uint_t i; 637 638 if (stp == NULL) { 639 return (-1); /* errno is set for us */ 640 } 641 642 if (stp->smbst_hdr->smbh_type != SMB_TYPE_CHASSIS) { 643 return (smb_set_errno(shp, ESMB_TYPE)); 644 } 645 646 /* 647 * We don't explicitly check the length of the table as it is legal for 648 * the chassis table to be shorter than something that contains the 649 * number of elements. 650 */ 651 smb_info_bcopy(stp->smbst_hdr, &ch, sizeof (ch)); 652 if (ch.smbch_cn == 0) { 653 *nentsp = 0; 654 *entsp = NULL; 655 return (0); 656 } 657 658 if (ch.smbch_cm != sizeof (smb_chassis_entry_t)) { 659 return (smb_set_errno(shp, ESMB_CORRUPT)); 660 } 661 662 entlen = ch.smbch_cm * ch.smbch_cn; 663 if (stp->smbst_hdr->smbh_len < sizeof (ch) + entlen) { 664 return (smb_set_errno(shp, ESMB_SHORT)); 665 } 666 667 if ((entry = smb_alloc(entlen)) == NULL) { 668 return (smb_set_errno(shp, ESMB_NOMEM)); 669 } 670 671 for (i = 0; i < ch.smbch_cn; i++) { 672 smb_chassis_entry_t e; 673 size_t off = sizeof (ch) + i * sizeof (e); 674 675 smb_info_bcopy_offset(stp->smbst_hdr, &e, sizeof (e), off); 676 /* 677 * The top bit is used to indicate what type of record this is, 678 * while the lower 7-bits indicate the actual type. 679 */ 680 entry[i].smbce_type = e.smbce_type & 0x80 ? 681 SMB_CELT_SMBIOS : SMB_CELT_BBOARD; 682 entry[i].smbce_elt = e.smbce_type & 0x7f; 683 entry[i].smbce_min = e.smbce_min; 684 entry[i].smbce_max = e.smbce_max; 685 } 686 687 *entsp = entry; 688 *nentsp = ch.smbch_cn; 689 690 return (0); 691 } 692 693 void 694 smbios_info_chassis_elts_free(smbios_hdl_t *shp, uint_t nents, 695 smbios_chassis_entry_t *ent) 696 { 697 size_t sz = nents * sizeof (smbios_chassis_entry_t); 698 699 if (nents == 0) { 700 ASSERT3P(ent, ==, NULL); 701 return; 702 } 703 704 smb_free(ent, sz); 705 } 706 707 int 708 smbios_info_processor(smbios_hdl_t *shp, id_t id, smbios_processor_t *pp) 709 { 710 const smb_struct_t *stp = smb_lookup_id(shp, id); 711 smb_processor_t p; 712 713 if (stp == NULL) 714 return (-1); /* errno is set for us */ 715 716 if (stp->smbst_hdr->smbh_type != SMB_TYPE_PROCESSOR) 717 return (smb_set_errno(shp, ESMB_TYPE)); 718 719 smb_info_bcopy(stp->smbst_hdr, &p, sizeof (p)); 720 bzero(pp, sizeof (smb_base_processor_t)); 721 722 pp->smbp_cpuid = p.smbpr_cpuid; 723 pp->smbp_type = p.smbpr_type; 724 pp->smbp_family = p.smbpr_family; 725 pp->smbp_voltage = p.smbpr_voltage; 726 pp->smbp_clkspeed = p.smbpr_clkspeed; 727 pp->smbp_maxspeed = p.smbpr_maxspeed; 728 pp->smbp_curspeed = p.smbpr_curspeed; 729 pp->smbp_status = p.smbpr_status; 730 pp->smbp_upgrade = p.smbpr_upgrade; 731 pp->smbp_l1cache = p.smbpr_l1cache; 732 pp->smbp_l2cache = p.smbpr_l2cache; 733 pp->smbp_l3cache = p.smbpr_l3cache; 734 735 if (smb_libgteq(shp, SMB_VERSION_25)) { 736 pp->smbp_corecount = p.smbpr_corecount; 737 pp->smbp_coresenabled = p.smbpr_coresenabled; 738 pp->smbp_threadcount = p.smbpr_threadcount; 739 pp->smbp_cflags = p.smbpr_cflags; 740 } 741 742 if (smb_libgteq(shp, SMB_VERSION_26)) { 743 if (pp->smbp_family == 0xfe) { 744 pp->smbp_family = p.smbpr_family2; 745 } 746 } 747 748 if (smb_libgteq(shp, SMB_VERSION_30)) { 749 if (pp->smbp_corecount == 0xff) { 750 pp->smbp_corecount = p.smbpr_corecount2; 751 } 752 if (pp->smbp_coresenabled == 0xff) { 753 pp->smbp_coresenabled = p.smbpr_coresenabled2; 754 } 755 if (pp->smbp_threadcount == 0xff) { 756 pp->smbp_threadcount = p.smbpr_threadcount2; 757 } 758 } 759 760 if (smb_libgteq(shp, SMB_VERSION_36)) { 761 pp->smbp_threadsenabled = p.smbpr_threaden; 762 } 763 764 /* 765 * SMBIOS 3.8 added a socket string which is only required if the 766 * processor upgrade constant is not present. We don't try to munge 767 * these two together here and leave it to clients to figure out 768 * (especially as what'll happen in practice is unknown). 769 */ 770 if (smb_libgteq(shp, SMB_VERSION_38)) { 771 pp->smbp_socktype = smb_strptr(stp, p.smbpr_socktype); 772 } 773 774 return (0); 775 } 776 777 int 778 smbios_info_cache(smbios_hdl_t *shp, id_t id, smbios_cache_t *cap) 779 { 780 const smb_struct_t *stp = smb_lookup_id(shp, id); 781 smb_cache_t c; 782 783 if (stp == NULL) 784 return (-1); /* errno is set for us */ 785 786 if (stp->smbst_hdr->smbh_type != SMB_TYPE_CACHE) 787 return (smb_set_errno(shp, ESMB_TYPE)); 788 789 smb_info_bcopy(stp->smbst_hdr, &c, sizeof (c)); 790 bzero(cap, sizeof (smb_base_cache_t)); 791 792 cap->smba_maxsize = SMB_CACHE_SIZE(c.smbca_maxsize); 793 cap->smba_size = SMB_CACHE_SIZE(c.smbca_size); 794 cap->smba_stype = c.smbca_stype; 795 cap->smba_ctype = c.smbca_ctype; 796 cap->smba_speed = c.smbca_speed; 797 cap->smba_etype = c.smbca_etype; 798 cap->smba_ltype = c.smbca_ltype; 799 cap->smba_assoc = c.smbca_assoc; 800 cap->smba_level = SMB_CACHE_CFG_LEVEL(c.smbca_config); 801 cap->smba_mode = SMB_CACHE_CFG_MODE(c.smbca_config); 802 cap->smba_location = SMB_CACHE_CFG_LOCATION(c.smbca_config); 803 804 if (SMB_CACHE_CFG_ENABLED(c.smbca_config)) 805 cap->smba_flags |= SMB_CAF_ENABLED; 806 807 if (SMB_CACHE_CFG_SOCKETED(c.smbca_config)) 808 cap->smba_flags |= SMB_CAF_SOCKETED; 809 810 if (smb_libgteq(shp, SMB_VERSION_31)) { 811 cap->smba_maxsize2 = SMB_CACHE_EXT_SIZE(c.smbca_maxsize2); 812 cap->smba_size2 = SMB_CACHE_EXT_SIZE(c.smbca_size2); 813 814 if (cap->smba_maxsize2 == 0) { 815 cap->smba_maxsize2 = cap->smba_maxsize; 816 } 817 818 if (cap->smba_size2 == 0) { 819 cap->smba_size2 = cap->smba_size; 820 } 821 } 822 823 return (0); 824 } 825 826 int 827 smbios_info_port(smbios_hdl_t *shp, id_t id, smbios_port_t *pop) 828 { 829 const smb_struct_t *stp = smb_lookup_id(shp, id); 830 smb_port_t p; 831 832 if (stp == NULL) 833 return (-1); /* errno is set for us */ 834 835 if (stp->smbst_hdr->smbh_type != SMB_TYPE_PORT) 836 return (smb_set_errno(shp, ESMB_TYPE)); 837 838 smb_info_bcopy(stp->smbst_hdr, &p, sizeof (p)); 839 bzero(pop, sizeof (smbios_port_t)); 840 841 pop->smbo_iref = smb_strptr(stp, p.smbpo_iref); 842 pop->smbo_eref = smb_strptr(stp, p.smbpo_eref); 843 844 pop->smbo_itype = p.smbpo_itype; 845 pop->smbo_etype = p.smbpo_etype; 846 pop->smbo_ptype = p.smbpo_ptype; 847 848 return (0); 849 } 850 851 int 852 smbios_info_slot(smbios_hdl_t *shp, id_t id, smbios_slot_t *sp) 853 { 854 const smb_struct_t *stp = smb_lookup_id(shp, id); 855 smb_slot_t s; 856 smb_slot_cont_t cont; 857 size_t off; 858 859 if (stp == NULL) 860 return (-1); /* errno is set for us */ 861 862 if (stp->smbst_hdr->smbh_type != SMB_TYPE_SLOT) 863 return (smb_set_errno(shp, ESMB_TYPE)); 864 865 smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s)); 866 bzero(sp, sizeof (smb_base_slot_t)); 867 868 sp->smbl_name = smb_strptr(stp, s.smbsl_name); 869 sp->smbl_type = s.smbsl_type; 870 sp->smbl_width = s.smbsl_width; 871 sp->smbl_usage = s.smbsl_usage; 872 sp->smbl_length = s.smbsl_length; 873 sp->smbl_id = s.smbsl_id; 874 sp->smbl_ch1 = s.smbsl_ch1; 875 sp->smbl_ch2 = s.smbsl_ch2; 876 sp->smbl_sg = s.smbsl_sg; 877 sp->smbl_bus = s.smbsl_bus; 878 sp->smbl_df = s.smbsl_df; 879 880 if (smb_libgteq(shp, SMB_VERSION_32)) { 881 sp->smbl_dbw = s.smbsl_dbw; 882 sp->smbl_npeers = s.smbsl_npeers; 883 } 884 885 if (!smb_libgteq(shp, SMB_VERSION_34)) { 886 return (0); 887 } 888 889 /* 890 * In SMBIOS 3.4, several members were added to follow the variable 891 * number of peers. These are defined to start at byte 0x14 + 5 * 892 * npeers. If the table is from before 3.4, we simple zero things out. 893 * Otherwise we check if the length covers the peers and this addendum 894 * to include it as the table length is allowed to be less than this and 895 * not include it. 896 */ 897 off = SMB_SLOT_CONT_START + 5 * s.smbsl_npeers; 898 smb_info_bcopy_offset(stp->smbst_hdr, &cont, sizeof (cont), off); 899 sp->smbl_info = cont.smbsl_info; 900 sp->smbl_pwidth = cont.smbsl_pwidth; 901 sp->smbl_pitch = cont.smbsl_pitch; 902 903 if (smb_libgteq(shp, SMB_VERSION_35)) { 904 sp->smbl_height = cont.smbsl_height; 905 } 906 907 return (0); 908 } 909 910 void 911 smbios_info_slot_peers_free(smbios_hdl_t *shp, uint_t npeers, 912 smbios_slot_peer_t *peer) 913 { 914 size_t sz = npeers * sizeof (smbios_slot_peer_t); 915 916 if (npeers == 0) { 917 ASSERT3P(peer, ==, NULL); 918 return; 919 } 920 921 smb_free(peer, sz); 922 } 923 924 int 925 smbios_info_slot_peers(smbios_hdl_t *shp, id_t id, uint_t *npeers, 926 smbios_slot_peer_t **peerp) 927 { 928 const smb_struct_t *stp = smb_lookup_id(shp, id); 929 const smb_slot_t *slotp; 930 smbios_slot_peer_t *peer; 931 size_t minlen; 932 uint_t i; 933 934 if (stp == NULL) 935 return (-1); /* errno is set for us */ 936 937 slotp = (const smb_slot_t *)stp->smbst_hdr; 938 939 if (stp->smbst_hdr->smbh_type != SMB_TYPE_SLOT) 940 return (smb_set_errno(shp, ESMB_TYPE)); 941 942 if (stp->smbst_hdr->smbh_len <= offsetof(smb_slot_t, smbsl_npeers) || 943 slotp->smbsl_npeers == 0) { 944 *npeers = 0; 945 *peerp = NULL; 946 return (0); 947 } 948 949 /* 950 * Make sure that the size of the structure makes sense for the number 951 * of peers reported. 952 */ 953 minlen = slotp->smbsl_npeers * sizeof (smb_slot_peer_t) + 954 offsetof(smb_slot_t, smbsl_npeers); 955 if (stp->smbst_hdr->smbh_len < minlen) { 956 return (smb_set_errno(shp, ESMB_SHORT)); 957 } 958 959 if ((peer = smb_alloc(slotp->smbsl_npeers * 960 sizeof (smbios_slot_peer_t))) == NULL) { 961 return (smb_set_errno(shp, ESMB_NOMEM)); 962 } 963 964 for (i = 0; i < slotp->smbsl_npeers; i++) { 965 peer[i].smblp_group = slotp->smbsl_peers[i].smbspb_group_no; 966 peer[i].smblp_bus = slotp->smbsl_peers[i].smbspb_bus; 967 peer[i].smblp_device = slotp->smbsl_peers[i].smbspb_df >> 3; 968 peer[i].smblp_function = slotp->smbsl_peers[i].smbspb_df & 0x7; 969 peer[i].smblp_data_width = slotp->smbsl_peers[i].smbspb_width; 970 } 971 972 *npeers = slotp->smbsl_npeers; 973 *peerp = peer; 974 975 return (0); 976 } 977 978 int 979 smbios_info_obdevs_ext(smbios_hdl_t *shp, id_t id, smbios_obdev_ext_t *oep) 980 { 981 const smb_struct_t *stp = smb_lookup_id(shp, id); 982 smb_obdev_ext_t obe; 983 984 if (stp == NULL) 985 return (-1); /* errno is set for us */ 986 987 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OBDEVEXT) 988 return (smb_set_errno(shp, ESMB_TYPE)); 989 990 smb_info_bcopy(stp->smbst_hdr, &obe, sizeof (obe)); 991 bzero(oep, sizeof (smbios_obdev_ext_t)); 992 993 oep->smboe_name = smb_strptr(stp, obe.smbobe_name); 994 oep->smboe_dtype = obe.smbobe_dtype; 995 oep->smboe_dti = obe.smbobe_dti; 996 oep->smboe_sg = obe.smbobe_sg; 997 oep->smboe_bus = obe.smbobe_bus; 998 oep->smboe_df = obe.smbobe_df; 999 1000 return (0); 1001 } 1002 1003 int 1004 smbios_info_obdevs(smbios_hdl_t *shp, id_t id, int obc, smbios_obdev_t *obp) 1005 { 1006 const smb_struct_t *stp = smb_lookup_id(shp, id); 1007 const smb_obdev_t *op; 1008 int i, m, n; 1009 1010 if (stp == NULL) 1011 return (-1); /* errno is set for us */ 1012 1013 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OBDEVS) 1014 return (smb_set_errno(shp, ESMB_TYPE)); 1015 1016 op = (smb_obdev_t *)((uintptr_t)stp->smbst_hdr + sizeof (smb_header_t)); 1017 m = (stp->smbst_hdr->smbh_len - sizeof (smb_header_t)) / sizeof (*op); 1018 n = MIN(m, obc); 1019 1020 for (i = 0; i < n; i++, op++, obp++) { 1021 obp->smbd_name = smb_strptr(stp, op->smbob_name); 1022 obp->smbd_type = op->smbob_type & ~SMB_OBT_ENABLED; 1023 obp->smbd_enabled = (op->smbob_type & SMB_OBT_ENABLED) != 0; 1024 } 1025 1026 return (m); 1027 } 1028 1029 /* 1030 * The implementation structures for OEMSTR, SYSCONFSTR, and LANG all use the 1031 * first byte to indicate the size of a string table at the end of the record. 1032 * Therefore, smbios_info_strtab() can be used to retrieve the table size and 1033 * strings for any of these underlying record types. 1034 */ 1035 int 1036 smbios_info_strtab(smbios_hdl_t *shp, id_t id, int argc, const char *argv[]) 1037 { 1038 const smb_struct_t *stp = smb_lookup_id(shp, id); 1039 smb_strtab_t s; 1040 int i, n; 1041 1042 if (stp == NULL) 1043 return (-1); /* errno is set for us */ 1044 1045 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OEMSTR && 1046 stp->smbst_hdr->smbh_type != SMB_TYPE_SYSCONFSTR && 1047 stp->smbst_hdr->smbh_type != SMB_TYPE_LANG) 1048 return (smb_set_errno(shp, ESMB_TYPE)); 1049 1050 smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s)); 1051 n = MIN(s.smbtb_count, argc); 1052 1053 for (i = 0; i < n; i++) 1054 argv[i] = smb_strptr(stp, i + 1); 1055 1056 return (s.smbtb_count); 1057 } 1058 1059 id_t 1060 smbios_info_lang(smbios_hdl_t *shp, smbios_lang_t *lp) 1061 { 1062 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_LANG); 1063 smb_lang_t l; 1064 1065 if (stp == NULL) 1066 return (-1); /* errno is set for us */ 1067 1068 smb_info_bcopy(stp->smbst_hdr, &l, sizeof (l)); 1069 bzero(lp, sizeof (smbios_lang_t)); 1070 1071 lp->smbla_cur = smb_strptr(stp, l.smblang_cur); 1072 lp->smbla_fmt = l.smblang_flags & 1; 1073 lp->smbla_num = l.smblang_num; 1074 1075 return (stp->smbst_hdr->smbh_hdl); 1076 } 1077 1078 id_t 1079 smbios_info_eventlog(smbios_hdl_t *shp, smbios_evlog_t *evp) 1080 { 1081 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_EVENTLOG); 1082 const smb_sel_t *sel; 1083 size_t len; 1084 1085 if (stp == NULL) 1086 return (-1); /* errno is set for us */ 1087 1088 if (stp->smbst_hdr->smbh_len < sizeof (smb_sel_t) - sizeof (uint8_t)) 1089 return (smb_set_errno(shp, ESMB_CORRUPT)); 1090 1091 sel = (smb_sel_t *)(uintptr_t)stp->smbst_hdr; 1092 len = stp->smbst_hdr->smbh_len - sizeof (smb_sel_t) + sizeof (uint8_t); 1093 bzero(evp, sizeof (smbios_evlog_t)); 1094 1095 if (len < sel->smbsel_typec * sel->smbsel_typesz) 1096 return (smb_set_errno(shp, ESMB_CORRUPT)); 1097 1098 evp->smbev_size = sel->smbsel_len; 1099 evp->smbev_hdr = sel->smbsel_hdroff; 1100 evp->smbev_data = sel->smbsel_dataoff; 1101 evp->smbev_method = sel->smbsel_method; 1102 evp->smbev_flags = sel->smbsel_status; 1103 evp->smbev_format = sel->smbsel_format; 1104 evp->smbev_token = sel->smbsel_token; 1105 evp->smbev_addr.eva_addr = sel->smbsel_addr; 1106 1107 if (sel->smbsel_typesz == sizeof (smbios_evtype_t)) { 1108 evp->smbev_typec = sel->smbsel_typec; 1109 evp->smbev_typev = (void *)(uintptr_t)sel->smbsel_typev; 1110 } 1111 1112 return (stp->smbst_hdr->smbh_hdl); 1113 } 1114 1115 int 1116 smbios_info_memarray(smbios_hdl_t *shp, id_t id, smbios_memarray_t *map) 1117 { 1118 const smb_struct_t *stp = smb_lookup_id(shp, id); 1119 smb_memarray_t m; 1120 1121 if (stp == NULL) 1122 return (-1); /* errno is set for us */ 1123 1124 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMARRAY) 1125 return (smb_set_errno(shp, ESMB_TYPE)); 1126 1127 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 1128 bzero(map, sizeof (smbios_memarray_t)); 1129 1130 map->smbma_location = m.smbmarr_loc; 1131 map->smbma_use = m.smbmarr_use; 1132 map->smbma_ecc = m.smbmarr_ecc; 1133 map->smbma_ndevs = m.smbmarr_ndevs; 1134 map->smbma_err = m.smbmarr_err; 1135 1136 if (m.smbmarr_cap != 0x80000000) 1137 map->smbma_size = (uint64_t)m.smbmarr_cap * 1024; 1138 else if (m.smbmarr_extcap != 0) 1139 map->smbma_size = m.smbmarr_extcap; 1140 else 1141 map->smbma_size = 0; /* unknown */ 1142 1143 return (0); 1144 } 1145 1146 int 1147 smbios_info_memarrmap(smbios_hdl_t *shp, id_t id, smbios_memarrmap_t *map) 1148 { 1149 const smb_struct_t *stp = smb_lookup_id(shp, id); 1150 smb_memarrmap_t m; 1151 1152 if (stp == NULL) 1153 return (-1); /* errno is set for us */ 1154 1155 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMARRAYMAP) 1156 return (smb_set_errno(shp, ESMB_TYPE)); 1157 1158 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 1159 bzero(map, sizeof (smbios_memarrmap_t)); 1160 1161 map->smbmam_array = m.smbamap_array; 1162 map->smbmam_width = m.smbamap_width; 1163 1164 if (m.smbamap_start != 0xFFFFFFFF && m.smbamap_end != 0xFFFFFFFF) { 1165 map->smbmam_addr = (uint64_t)m.smbamap_start * 1024; 1166 map->smbmam_size = (uint64_t) 1167 (m.smbamap_end - m.smbamap_start + 1) * 1024; 1168 } else if (m.smbamap_extstart != 0 && m.smbamap_extend != 0) { 1169 map->smbmam_addr = m.smbamap_extstart; 1170 map->smbmam_size = m.smbamap_extend - m.smbamap_extstart + 1; 1171 } 1172 1173 return (0); 1174 } 1175 1176 int 1177 smbios_info_memdevice(smbios_hdl_t *shp, id_t id, smbios_memdevice_t *mdp) 1178 { 1179 const smb_struct_t *stp = smb_lookup_id(shp, id); 1180 smb_memdevice_t m; 1181 1182 if (stp == NULL) 1183 return (-1); /* errno is set for us */ 1184 1185 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMDEVICE) 1186 return (smb_set_errno(shp, ESMB_TYPE)); 1187 1188 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 1189 bzero(mdp, sizeof (smb_base_memdevice_t)); 1190 1191 mdp->smbmd_array = m.smbmdev_array; 1192 mdp->smbmd_error = m.smbmdev_error; 1193 mdp->smbmd_twidth = m.smbmdev_twidth == 0xFFFF ? -1U : m.smbmdev_twidth; 1194 mdp->smbmd_dwidth = m.smbmdev_dwidth == 0xFFFF ? -1U : m.smbmdev_dwidth; 1195 1196 if (m.smbmdev_size == 0x7FFF) { 1197 mdp->smbmd_size = (uint64_t)m.smbmdev_extsize; 1198 mdp->smbmd_size *= 1024 * 1024; /* convert MB to bytes */ 1199 } else if (m.smbmdev_size != 0xFFFF) { 1200 mdp->smbmd_size = (uint64_t)(m.smbmdev_size & ~SMB_MDS_KBYTES); 1201 if (m.smbmdev_size & SMB_MDS_KBYTES) 1202 mdp->smbmd_size *= 1024; 1203 else 1204 mdp->smbmd_size *= 1024 * 1024; 1205 } else 1206 mdp->smbmd_size = -1ULL; /* size unknown */ 1207 1208 mdp->smbmd_form = m.smbmdev_form; 1209 mdp->smbmd_set = m.smbmdev_set; 1210 mdp->smbmd_type = m.smbmdev_type; 1211 mdp->smbmd_speed = m.smbmdev_speed; 1212 mdp->smbmd_flags = m.smbmdev_flags; 1213 mdp->smbmd_dloc = smb_strptr(stp, m.smbmdev_dloc); 1214 mdp->smbmd_bloc = smb_strptr(stp, m.smbmdev_bloc); 1215 1216 if (smb_libgteq(shp, SMB_VERSION_26)) { 1217 mdp->smbmd_rank = m.smbmdev_attrs & 0x0F; 1218 } 1219 1220 if (smb_libgteq(shp, SMB_VERSION_27)) { 1221 mdp->smbmd_clkspeed = m.smbmdev_clkspeed; 1222 } 1223 1224 if (smb_libgteq(shp, SMB_VERSION_28)) { 1225 mdp->smbmd_minvolt = m.smbmdev_minvolt; 1226 mdp->smbmd_maxvolt = m.smbmdev_maxvolt; 1227 mdp->smbmd_confvolt = m.smbmdev_confvolt; 1228 } 1229 1230 if (smb_libgteq(shp, SMB_VERSION_32)) { 1231 mdp->smbmd_memtech = m.smbmdev_memtech; 1232 mdp->smbmd_opcap_flags = m.smbmdev_opmode; 1233 mdp->smbmd_firmware_rev = smb_strptr(stp, 1234 m.smbmdev_fwver); 1235 mdp->smbmd_modmfg_id = m.smbmdev_modulemfgid; 1236 mdp->smbmd_modprod_id = m.smbmdev_moduleprodid; 1237 mdp->smbmd_cntrlmfg_id = m.smbmdev_memsysmfgid; 1238 mdp->smbmd_cntrlprod_id = m.smbmdev_memsysprodid; 1239 mdp->smbmd_nvsize = m.smbmdev_nvsize; 1240 mdp->smbmd_volatile_size = m.smbmdev_volsize; 1241 mdp->smbmd_cache_size = m.smbmdev_cachesize; 1242 mdp->smbmd_logical_size = m.smbmdev_logicalsize; 1243 } 1244 1245 if (smb_libgteq(shp, SMB_VERSION_33)) { 1246 if (m.smbmdev_speed == 0xffff) { 1247 mdp->smbmd_extspeed = m.smbmdev_extspeed; 1248 } else { 1249 mdp->smbmd_extspeed = m.smbmdev_speed; 1250 } 1251 1252 if (m.smbmdev_clkspeed == 0xffff) { 1253 mdp->smbmd_extclkspeed = m.smbmdev_extclkspeed; 1254 } else { 1255 mdp->smbmd_extclkspeed = m.smbmdev_clkspeed; 1256 } 1257 } 1258 1259 /* 1260 * The unknown key for missing revision information for the RCD and 1261 * PMIC0 is not all zeros. As such, we need to look if the device SMBIOS 1262 * table is not 3.7 then we need to fix up the bits that we copied. 1263 * After that we need to go back and check the consumer's version to 1264 * actually place this data there. 1265 */ 1266 if (!smb_gteq(shp, SMB_VERSION_37)) { 1267 m.smbmdev_pmic0mfgid = SMB_MD_MFG_UNKNOWN; 1268 m.smbmdev_pmic0rev = SMB_MD_REV_UNKNOWN; 1269 m.smbmdev_rcdmfgid = SMB_MD_MFG_UNKNOWN; 1270 m.smbmdev_rcdrev = SMB_MD_REV_UNKNOWN; 1271 } 1272 1273 if (smb_libgteq(shp, SMB_VERSION_37)) { 1274 mdp->smbmd_pmic0_mfgid = m.smbmdev_pmic0mfgid; 1275 mdp->smbmd_pmic0_rev = m.smbmdev_pmic0rev; 1276 mdp->smbmd_rcd_mfgid = m.smbmdev_rcdmfgid; 1277 mdp->smbmd_rcd_rev = m.smbmdev_rcdrev; 1278 } 1279 1280 return (0); 1281 } 1282 1283 int 1284 smbios_info_memdevmap(smbios_hdl_t *shp, id_t id, smbios_memdevmap_t *mdp) 1285 { 1286 const smb_struct_t *stp = smb_lookup_id(shp, id); 1287 smb_memdevmap_t m; 1288 1289 if (stp == NULL) 1290 return (-1); /* errno is set for us */ 1291 1292 if (stp->smbst_hdr->smbh_type != SMB_TYPE_MEMDEVICEMAP) 1293 return (smb_set_errno(shp, ESMB_TYPE)); 1294 1295 smb_info_bcopy(stp->smbst_hdr, &m, sizeof (m)); 1296 bzero(mdp, sizeof (smbios_memdevmap_t)); 1297 1298 mdp->smbmdm_device = m.smbdmap_device; 1299 mdp->smbmdm_arrmap = m.smbdmap_array; 1300 mdp->smbmdm_rpos = m.smbdmap_rpos; 1301 mdp->smbmdm_ipos = m.smbdmap_ipos; 1302 mdp->smbmdm_idepth = m.smbdmap_idepth; 1303 1304 if (m.smbdmap_start != 0xFFFFFFFF && m.smbdmap_end != 0xFFFFFFFF) { 1305 mdp->smbmdm_addr = (uint64_t)m.smbdmap_start * 1024; 1306 mdp->smbmdm_size = (uint64_t) 1307 (m.smbdmap_end - m.smbdmap_start + 1) * 1024; 1308 } else if (m.smbdmap_extstart != 0 && m.smbdmap_extend != 0) { 1309 mdp->smbmdm_addr = m.smbdmap_extstart; 1310 mdp->smbmdm_size = m.smbdmap_extend - m.smbdmap_extstart + 1; 1311 } 1312 1313 return (0); 1314 } 1315 1316 id_t 1317 smbios_info_hwsec(smbios_hdl_t *shp, smbios_hwsec_t *hsp) 1318 { 1319 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_SECURITY); 1320 smb_hwsec_t hs; 1321 1322 if (stp == NULL) 1323 return (-1); /* errno is set for us */ 1324 1325 smb_info_bcopy(stp->smbst_hdr, &hs, sizeof (hs)); 1326 bzero(hsp, sizeof (smbios_hwsec_t)); 1327 1328 hsp->smbh_pwr_ps = SMB_HWS_PWR_PS(hs.smbhs_settings); 1329 hsp->smbh_kbd_ps = SMB_HWS_KBD_PS(hs.smbhs_settings); 1330 hsp->smbh_adm_ps = SMB_HWS_ADM_PS(hs.smbhs_settings); 1331 hsp->smbh_pan_ps = SMB_HWS_PAN_PS(hs.smbhs_settings); 1332 1333 return (stp->smbst_hdr->smbh_hdl); 1334 } 1335 1336 id_t 1337 smbios_info_boot(smbios_hdl_t *shp, smbios_boot_t *bp) 1338 { 1339 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_BOOT); 1340 const smb_boot_t *b; 1341 1342 if (stp == NULL) 1343 return (-1); /* errno is set for us */ 1344 1345 bzero(bp, sizeof (smbios_boot_t)); 1346 1347 b = (smb_boot_t *)(uintptr_t)stp->smbst_hdr; 1348 1349 bp->smbt_status = b->smbbo_status[0]; 1350 bp->smbt_size = stp->smbst_hdr->smbh_len - sizeof (smb_boot_t); 1351 bp->smbt_data = bp->smbt_size ? &b->smbbo_status[1] : NULL; 1352 1353 return (stp->smbst_hdr->smbh_hdl); 1354 } 1355 1356 id_t 1357 smbios_info_ipmi(smbios_hdl_t *shp, smbios_ipmi_t *ip) 1358 { 1359 const smb_struct_t *stp = smb_lookup_type(shp, SMB_TYPE_IPMIDEV); 1360 smb_ipmi_t i; 1361 1362 if (stp == NULL) 1363 return (-1); /* errno is set for us */ 1364 1365 smb_info_bcopy(stp->smbst_hdr, &i, sizeof (i)); 1366 bzero(ip, sizeof (smbios_ipmi_t)); 1367 1368 ip->smbip_type = i.smbipm_type; 1369 ip->smbip_vers.smbv_major = SMB_IPM_SPEC_MAJOR(i.smbipm_spec); 1370 ip->smbip_vers.smbv_minor = SMB_IPM_SPEC_MINOR(i.smbipm_spec); 1371 ip->smbip_i2c = i.smbipm_i2c; 1372 ip->smbip_addr = i.smbipm_addr & ~SMB_IPM_ADDR_IO; 1373 ip->smbip_intr = i.smbipm_intr; 1374 1375 if (i.smbipm_bus != (uint8_t)-1) 1376 ip->smbip_bus = i.smbipm_bus; 1377 else 1378 ip->smbip_bus = -1u; 1379 1380 if (SMB_IPM_INFO_LSB(i.smbipm_info)) 1381 ip->smbip_addr |= 1; /* turn on least-significant bit of addr */ 1382 1383 if (i.smbipm_addr & SMB_IPM_ADDR_IO) { 1384 switch (SMB_IPM_INFO_REGS(i.smbipm_info)) { 1385 case SMB_IPM_REGS_1B: 1386 ip->smbip_regspacing = 1; 1387 break; 1388 case SMB_IPM_REGS_4B: 1389 ip->smbip_regspacing = 4; 1390 break; 1391 case SMB_IPM_REGS_16B: 1392 ip->smbip_regspacing = 16; 1393 break; 1394 default: 1395 ip->smbip_regspacing = 1; 1396 } 1397 ip->smbip_flags |= SMB_IPMI_F_IOADDR; 1398 } 1399 1400 if (SMB_IPM_INFO_ISPEC(i.smbipm_info)) 1401 ip->smbip_flags |= SMB_IPMI_F_INTRSPEC; 1402 1403 if (SMB_IPM_INFO_IPOL(i.smbipm_info) == SMB_IPM_IPOL_HI) 1404 ip->smbip_flags |= SMB_IPMI_F_INTRHIGH; 1405 1406 if (SMB_IPM_INFO_IMODE(i.smbipm_info) == SMB_IPM_IMODE_EDGE) 1407 ip->smbip_flags |= SMB_IPMI_F_INTREDGE; 1408 1409 return (stp->smbst_hdr->smbh_hdl); 1410 } 1411 1412 static boolean_t 1413 smbios_has_oemstr(smbios_hdl_t *shp, const char *oemstr) 1414 { 1415 const smb_struct_t *stp = shp->sh_structs; 1416 smb_strtab_t s; 1417 int i, j; 1418 1419 for (i = 0; i < shp->sh_nstructs; i++, stp++) { 1420 if (stp->smbst_hdr->smbh_type != SMB_TYPE_OEMSTR) 1421 continue; 1422 1423 smb_info_bcopy(stp->smbst_hdr, &s, sizeof (s)); 1424 for (j = 0; j < s.smbtb_count; j++) 1425 if (strcmp(smb_strptr(stp, j + 1), oemstr) == 0) 1426 return (B_TRUE); 1427 } 1428 1429 return (B_FALSE); 1430 } 1431 1432 static const char * 1433 smb_serial_valid(const char *serial) 1434 { 1435 char buf[MAXNAMELEN]; 1436 int i = 0; 1437 1438 if (serial == NULL) 1439 return (NULL); 1440 1441 (void) strlcpy(buf, serial, sizeof (buf)); 1442 1443 while (buf[i] != '\0' && buf[i] == ' ') 1444 i++; 1445 1446 if (buf[i] == '\0' || strstr(buf, SMB_DEFAULT1) != NULL || 1447 strstr(buf, SMB_DEFAULT2) != NULL) 1448 return (NULL); 1449 1450 return (serial); 1451 } 1452 1453 /* 1454 * Get chassis SN or product SN 1455 */ 1456 static int 1457 smb_get_sn(smbios_hdl_t *shp, const char **psnp, const char **csnp) 1458 { 1459 const smb_struct_t *stp; 1460 smbios_info_t s1, s3; 1461 1462 if (psnp == NULL || csnp == NULL) 1463 return (smb_set_errno(shp, ESMB_INVAL)); 1464 1465 *psnp = *csnp = NULL; 1466 1467 /* 1468 * If SMBIOS meets Sun's PRMS requirements, retrieve product SN 1469 * from type 1 structure, and chassis SN from type 3 structure. 1470 * Otherwise return SN in type 1 structure as chassis SN. 1471 */ 1472 1473 /* Get type 1 SN */ 1474 if ((stp = smb_lookup_type(shp, SMB_TYPE_SYSTEM)) == NULL || 1475 smbios_info_common(shp, stp->smbst_hdr->smbh_hdl, &s1) == SMB_ERR) 1476 s1.smbi_serial = NULL; 1477 1478 /* Get type 3 SN */ 1479 if ((stp = smb_lookup_type(shp, SMB_TYPE_CHASSIS)) == NULL || 1480 smbios_info_common(shp, stp->smbst_hdr->smbh_hdl, &s3) == SMB_ERR) 1481 s3.smbi_serial = NULL; 1482 1483 if (smbios_has_oemstr(shp, SMB_PRMS1)) { 1484 *psnp = smb_serial_valid(s1.smbi_serial); 1485 *csnp = smb_serial_valid(s3.smbi_serial); 1486 } else { 1487 *csnp = smb_serial_valid(s1.smbi_serial); 1488 } 1489 1490 return (0); 1491 } 1492 1493 const char * 1494 smbios_psn(smbios_hdl_t *shp) 1495 { 1496 const char *psn, *csn; 1497 1498 return (smb_get_sn(shp, &psn, &csn) == SMB_ERR ? NULL : psn); 1499 } 1500 1501 const char * 1502 smbios_csn(smbios_hdl_t *shp) 1503 { 1504 const char *psn, *csn; 1505 1506 return (smb_get_sn(shp, &psn, &csn) == SMB_ERR ? NULL : csn); 1507 } 1508 1509 int 1510 smbios_info_extprocessor(smbios_hdl_t *shp, id_t id, 1511 smbios_processor_ext_t *epp) 1512 { 1513 const smb_struct_t *stp = smb_lookup_id(shp, id); 1514 smb_processor_ext_t *exp; 1515 1516 if (stp == NULL) 1517 return (-1); /* errno is set for us */ 1518 1519 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_PROCESSOR) 1520 return (smb_set_errno(shp, ESMB_TYPE)); 1521 1522 exp = (smb_processor_ext_t *)(uintptr_t)stp->smbst_hdr; 1523 bzero(epp, sizeof (smbios_processor_ext_t)); 1524 1525 epp->smbpe_processor = exp->smbpre_processor; 1526 epp->smbpe_fru = exp->smbpre_fru; 1527 epp->smbpe_n = exp->smbpre_n; 1528 epp->smbpe_apicid = exp->smbpre_apicid; 1529 1530 return (0); 1531 } 1532 1533 int 1534 smbios_info_extport(smbios_hdl_t *shp, id_t id, smbios_port_ext_t *eportp) 1535 { 1536 const smb_struct_t *stp = smb_lookup_id(shp, id); 1537 smb_port_ext_t *ep; 1538 1539 if (stp == NULL) 1540 return (-1); /* errno is set for us */ 1541 1542 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_PORT) 1543 return (smb_set_errno(shp, ESMB_TYPE)); 1544 1545 ep = (smb_port_ext_t *)(uintptr_t)stp->smbst_hdr; 1546 bzero(eportp, sizeof (smbios_port_ext_t)); 1547 1548 eportp->smbporte_chassis = ep->smbpoe_chassis; 1549 eportp->smbporte_port = ep->smbpoe_port; 1550 eportp->smbporte_dtype = ep->smbpoe_dtype; 1551 eportp->smbporte_devhdl = ep->smbpoe_devhdl; 1552 eportp->smbporte_phy = ep->smbpoe_phy; 1553 1554 return (0); 1555 } 1556 1557 int 1558 smbios_info_pciexrc(smbios_hdl_t *shp, id_t id, 1559 smbios_pciexrc_t *rcp) 1560 { 1561 const smb_struct_t *stp = smb_lookup_id(shp, id); 1562 smb_pciexrc_t rc; 1563 1564 if (stp == NULL) 1565 return (-1); /* errno is set for us */ 1566 1567 if (stp->smbst_hdr->smbh_type != SUN_OEM_PCIEXRC) 1568 return (smb_set_errno(shp, ESMB_TYPE)); 1569 1570 smb_info_bcopy(stp->smbst_hdr, &rc, sizeof (rc)); 1571 bzero(rcp, sizeof (smbios_pciexrc_t)); 1572 1573 rcp->smbpcie_bb = rc.smbpciexrc_bboard; 1574 rcp->smbpcie_bdf = rc.smbpciexrc_bdf; 1575 1576 return (0); 1577 } 1578 1579 int 1580 smbios_info_extmemarray(smbios_hdl_t *shp, id_t id, smbios_memarray_ext_t *emap) 1581 { 1582 const smb_struct_t *stp = smb_lookup_id(shp, id); 1583 smb_memarray_ext_t exma; 1584 1585 if (stp == NULL) 1586 return (-1); /* errno is set for us */ 1587 1588 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_MEMARRAY) 1589 return (smb_set_errno(shp, ESMB_TYPE)); 1590 1591 smb_info_bcopy(stp->smbst_hdr, &exma, sizeof (exma)); 1592 bzero(emap, sizeof (smbios_memarray_ext_t)); 1593 1594 emap->smbmae_ma = exma.smbmarre_ma; 1595 emap->smbmae_comp = exma.smbmarre_component; 1596 emap->smbmae_bdf = exma.smbmarre_bdf; 1597 1598 return (0); 1599 } 1600 1601 int 1602 smbios_info_extmemdevice(smbios_hdl_t *shp, id_t id, 1603 smbios_memdevice_ext_t *emdp) 1604 { 1605 const smb_struct_t *stp = smb_lookup_id(shp, id); 1606 smb_memdevice_ext_t exmd; 1607 1608 if (stp == NULL) 1609 return (-1); /* errno is set for us */ 1610 1611 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_MEMDEVICE) 1612 return (smb_set_errno(shp, ESMB_TYPE)); 1613 1614 smb_info_bcopy(stp->smbst_hdr, &exmd, sizeof (exmd)); 1615 bzero(emdp, sizeof (smbios_memdevice_ext_t)); 1616 1617 emdp->smbmdeve_md = exmd.smbmdeve_mdev; 1618 emdp->smbmdeve_drch = exmd.smbmdeve_dchan; 1619 emdp->smbmdeve_ncs = exmd.smbmdeve_ncs; 1620 1621 return (0); 1622 } 1623 1624 int 1625 smbios_info_extmemdevice_cs(smbios_hdl_t *shp, id_t id, uint_t *ncsp, 1626 uint8_t **csp) 1627 { 1628 const smb_struct_t *stp = smb_lookup_id(shp, id); 1629 smb_memdevice_ext_t exmd; 1630 size_t size; 1631 void *buf; 1632 1633 if (stp == NULL) 1634 return (-1); /* errno is set for us */ 1635 1636 if (stp->smbst_hdr->smbh_type != SUN_OEM_EXT_MEMDEVICE) 1637 return (smb_set_errno(shp, ESMB_TYPE)); 1638 1639 smb_info_bcopy(stp->smbst_hdr, &exmd, sizeof (exmd)); 1640 if (exmd.smbmdeve_ncs == 0) { 1641 *ncsp = 0; 1642 *csp = NULL; 1643 return (0); 1644 } 1645 1646 size = exmd.smbmdeve_ncs * sizeof (*exmd.smbmdeve_cs); 1647 1648 if (stp->smbst_hdr->smbh_len < sizeof (exmd) + size) 1649 return (smb_set_errno(shp, ESMB_SHORT)); 1650 1651 buf = smb_alloc(size); 1652 if (buf == NULL) 1653 return (smb_set_errno(shp, ESMB_NOMEM)); 1654 smb_info_bcopy_offset(stp->smbst_hdr, buf, size, sizeof (exmd)); 1655 1656 *ncsp = exmd.smbmdeve_ncs; 1657 *csp = buf; 1658 return (0); 1659 } 1660 1661 void 1662 smbios_info_extmemdevice_cs_free(smbios_hdl_t *shp __unused, uint_t ncs, 1663 uint8_t *csp) 1664 { 1665 size_t size = ncs * sizeof (uint8_t); 1666 1667 if (size == 0) { 1668 ASSERT3P(csp, ==, NULL); 1669 return; 1670 } 1671 smb_free(csp, size); 1672 } 1673 1674 int 1675 smbios_info_powersup(smbios_hdl_t *shp, id_t id, smbios_powersup_t *psup) 1676 { 1677 const smb_struct_t *stp = smb_lookup_id(shp, id); 1678 smb_powersup_t psu; 1679 1680 if (stp == NULL) 1681 return (-1); /* errno is set for us */ 1682 1683 if (stp->smbst_hdr->smbh_type != SMB_TYPE_POWERSUP) 1684 return (smb_set_errno(shp, ESMB_TYPE)); 1685 1686 /* The minimum length required by the spec is 0x10. */ 1687 if (stp->smbst_hdr->smbh_len < 0x10) 1688 return (smb_set_errno(shp, ESMB_SHORT)); 1689 1690 bzero(psup, sizeof (*psup)); 1691 smb_info_bcopy(stp->smbst_hdr, &psu, sizeof (psu)); 1692 psup->smbps_group = psu.smbpsup_group; 1693 psup->smbps_maxout = psu.smbpsup_max; 1694 1695 if (SMB_PSU_CHARS_ISHOT(psu.smbpsup_char)) 1696 psup->smbps_flags |= SMB_POWERSUP_F_HOT; 1697 if (SMB_PSU_CHARS_ISPRES(psu.smbpsup_char)) 1698 psup->smbps_flags |= SMB_POWERSUP_F_PRESENT; 1699 if (SMB_PSU_CHARS_ISUNPLUG(psu.smbpsup_char)) 1700 psup->smbps_flags |= SMB_POWERSUP_F_UNPLUG; 1701 1702 psup->smbps_ivrs = SMB_PSU_CHARS_IVRS(psu.smbpsup_char); 1703 psup->smbps_status = SMB_PSU_CHARS_STATUS(psu.smbpsup_char); 1704 psup->smbps_pstype = SMB_PSU_CHARS_TYPE(psu.smbpsup_char); 1705 1706 if (stp->smbst_hdr->smbh_len >= 0x12) { 1707 psup->smbps_vprobe = psu.smbpsup_vprobe; 1708 } else { 1709 psup->smbps_vprobe = 0xffff; 1710 } 1711 1712 if (stp->smbst_hdr->smbh_len >= 0x14) { 1713 psup->smbps_cooldev = psu.smbpsup_cooldev; 1714 } else { 1715 psup->smbps_cooldev = 0xffff; 1716 } 1717 1718 if (stp->smbst_hdr->smbh_len >= 0x16) { 1719 psup->smbps_iprobe = psu.smbpsup_iprobe; 1720 } else { 1721 psup->smbps_iprobe = 0xffff; 1722 } 1723 1724 return (0); 1725 } 1726 1727 int 1728 smbios_info_vprobe(smbios_hdl_t *shp, id_t id, smbios_vprobe_t *vprobe) 1729 { 1730 const smb_struct_t *stp = smb_lookup_id(shp, id); 1731 smb_vprobe_t vp; 1732 1733 if (stp == NULL) 1734 return (-1); /* errno is set for us */ 1735 1736 if (stp->smbst_hdr->smbh_type != SMB_TYPE_VPROBE) 1737 return (smb_set_errno(shp, ESMB_TYPE)); 1738 1739 if (stp->smbst_hdr->smbh_len < SMB_VPROBE_MINLEN) 1740 return (smb_set_errno(shp, ESMB_SHORT)); 1741 1742 bzero(vprobe, sizeof (*vprobe)); 1743 smb_info_bcopy(stp->smbst_hdr, &vp, sizeof (vp)); 1744 vprobe->smbvp_description = smb_strptr(stp, vp.smbvpr_descr); 1745 vprobe->smbvp_location = SMB_VPROBE_LOCATION(vp.smbvpr_locstat); 1746 vprobe->smbvp_status = SMB_VPROBE_STATUS(vp.smbvpr_locstat); 1747 vprobe->smbvp_maxval = vp.smbvpr_maxval; 1748 vprobe->smbvp_minval = vp.smbvpr_minval; 1749 vprobe->smbvp_resolution = vp.smbvpr_resolution; 1750 vprobe->smbvp_tolerance = vp.smbvpr_tolerance; 1751 vprobe->smbvp_accuracy = vp.smbvpr_accuracy; 1752 1753 if (stp->smbst_hdr->smbh_len >= SMB_VPROBE_NOMINAL_MINLEN) { 1754 vprobe->smbvp_nominal = vp.smbvpr_nominal; 1755 } else { 1756 vprobe->smbvp_nominal = SMB_PROBE_UNKNOWN_VALUE; 1757 } 1758 1759 return (0); 1760 } 1761 1762 int 1763 smbios_info_cooldev(smbios_hdl_t *shp, id_t id, smbios_cooldev_t *cooldev) 1764 { 1765 const smb_struct_t *stp = smb_lookup_id(shp, id); 1766 smb_cooldev_t cd; 1767 1768 if (stp == NULL) 1769 return (-1); /* errno is set for us */ 1770 1771 if (stp->smbst_hdr->smbh_type != SMB_TYPE_COOLDEV) 1772 return (smb_set_errno(shp, ESMB_TYPE)); 1773 1774 if (stp->smbst_hdr->smbh_len < SMB_COOLDEV_MINLEN) 1775 return (smb_set_errno(shp, ESMB_SHORT)); 1776 1777 bzero(cooldev, sizeof (*cooldev)); 1778 smb_info_bcopy(stp->smbst_hdr, &cd, sizeof (cd)); 1779 cooldev->smbcd_tprobe = cd.smbcdev_tprobe; 1780 cooldev->smbcd_type = SMB_COOLDEV_TYPE(cd.smbcdev_typstat); 1781 cooldev->smbcd_status = SMB_COOLDEV_STATUS(cd.smbcdev_typstat); 1782 cooldev->smbcd_group = cd.smbcdev_group; 1783 cooldev->smbcd_oem = cd.smbcdev_oem; 1784 1785 if (stp->smbst_hdr->smbh_len >= SMB_COOLDEV_NOMINAL_MINLEN) { 1786 cooldev->smbcd_nominal = cd.smbcdev_nominal; 1787 } else { 1788 cooldev->smbcd_nominal = SMB_PROBE_UNKNOWN_VALUE; 1789 } 1790 1791 /* 1792 * The description field was added in SMBIOS version 2.7. The 1793 * SMB_TYPE_COOLDEV support was only added after all of the 2.7+ fields 1794 * were added in the spec. So while a user may request an older version, 1795 * we don't have to worry about old structures and just simply skip it 1796 * if they're not asking for it. 1797 */ 1798 if (smb_libgteq(shp, SMB_VERSION_27) && 1799 smb_gteq(shp, SMB_VERSION_27) && 1800 stp->smbst_hdr->smbh_len >= SMB_COOLDEV_DESCR_MINLEN) { 1801 cooldev->smbcd_descr = smb_strptr(stp, cd.smbcdev_descr); 1802 } else { 1803 cooldev->smbcd_descr = NULL; 1804 } 1805 1806 return (0); 1807 } 1808 1809 int 1810 smbios_info_tprobe(smbios_hdl_t *shp, id_t id, smbios_tprobe_t *tprobe) 1811 { 1812 const smb_struct_t *stp = smb_lookup_id(shp, id); 1813 smb_tprobe_t tp; 1814 1815 if (stp == NULL) 1816 return (-1); /* errno is set for us */ 1817 1818 if (stp->smbst_hdr->smbh_type != SMB_TYPE_TPROBE) 1819 return (smb_set_errno(shp, ESMB_TYPE)); 1820 1821 if (stp->smbst_hdr->smbh_len < SMB_TPROBE_MINLEN) 1822 return (smb_set_errno(shp, ESMB_SHORT)); 1823 1824 bzero(tprobe, sizeof (*tprobe)); 1825 smb_info_bcopy(stp->smbst_hdr, &tp, sizeof (tp)); 1826 tprobe->smbtp_description = smb_strptr(stp, tp.smbtpr_descr); 1827 tprobe->smbtp_location = SMB_TPROBE_LOCATION(tp.smbtpr_locstat); 1828 tprobe->smbtp_status = SMB_TPROBE_STATUS(tp.smbtpr_locstat); 1829 tprobe->smbtp_maxval = tp.smbtpr_maxval; 1830 tprobe->smbtp_minval = tp.smbtpr_minval; 1831 tprobe->smbtp_resolution = tp.smbtpr_resolution; 1832 tprobe->smbtp_tolerance = tp.smbtpr_tolerance; 1833 tprobe->smbtp_accuracy = tp.smbtpr_accuracy; 1834 1835 if (stp->smbst_hdr->smbh_len >= SMB_TPROBE_NOMINAL_MINLEN) { 1836 tprobe->smbtp_nominal = tp.smbtpr_nominal; 1837 } else { 1838 tprobe->smbtp_nominal = SMB_PROBE_UNKNOWN_VALUE; 1839 } 1840 1841 return (0); 1842 } 1843 1844 int 1845 smbios_info_iprobe(smbios_hdl_t *shp, id_t id, smbios_iprobe_t *iprobe) 1846 { 1847 const smb_struct_t *sip = smb_lookup_id(shp, id); 1848 smb_iprobe_t ip; 1849 1850 if (sip == NULL) 1851 return (-1); /* errno is set for us */ 1852 1853 if (sip->smbst_hdr->smbh_type != SMB_TYPE_IPROBE) 1854 return (smb_set_errno(shp, ESMB_TYPE)); 1855 1856 if (sip->smbst_hdr->smbh_len < SMB_IPROBE_MINLEN) 1857 return (smb_set_errno(shp, ESMB_SHORT)); 1858 1859 bzero(iprobe, sizeof (*iprobe)); 1860 smb_info_bcopy(sip->smbst_hdr, &ip, sizeof (ip)); 1861 iprobe->smbip_description = smb_strptr(sip, ip.smbipr_descr); 1862 iprobe->smbip_location = SMB_IPROBE_LOCATION(ip.smbipr_locstat); 1863 iprobe->smbip_status = SMB_IPROBE_STATUS(ip.smbipr_locstat); 1864 iprobe->smbip_maxval = ip.smbipr_maxval; 1865 iprobe->smbip_minval = ip.smbipr_minval; 1866 iprobe->smbip_resolution = ip.smbipr_resolution; 1867 iprobe->smbip_tolerance = ip.smbipr_tolerance; 1868 iprobe->smbip_accuracy = ip.smbipr_accuracy; 1869 1870 if (sip->smbst_hdr->smbh_len >= SMB_IPROBE_NOMINAL_MINLEN) { 1871 iprobe->smbip_nominal = ip.smbipr_nominal; 1872 } else { 1873 iprobe->smbip_nominal = SMB_PROBE_UNKNOWN_VALUE; 1874 } 1875 1876 return (0); 1877 } 1878 1879 int 1880 smbios_info_processor_info(smbios_hdl_t *shp, id_t id, 1881 smbios_processor_info_t *proc) 1882 { 1883 const smb_struct_t *stp = smb_lookup_id(shp, id); 1884 smb_processor_info_t pi; 1885 1886 if (stp == NULL) 1887 return (-1); /* errno is set for us */ 1888 1889 if (stp->smbst_hdr->smbh_type != SMB_TYPE_PROCESSOR_INFO) 1890 return (smb_set_errno(shp, ESMB_TYPE)); 1891 1892 if (stp->smbst_hdr->smbh_len < sizeof (pi)) 1893 return (smb_set_errno(shp, ESMB_SHORT)); 1894 1895 bzero(proc, sizeof (*proc)); 1896 smb_info_bcopy(stp->smbst_hdr, &pi, sizeof (pi)); 1897 1898 if (sizeof (pi) + pi.smbpai_len > stp->smbst_hdr->smbh_len) 1899 return (smb_set_errno(shp, ESMB_CORRUPT)); 1900 1901 proc->smbpi_processor = pi.smbpai_proc; 1902 proc->smbpi_ptype = pi.smbpai_type; 1903 1904 return (0); 1905 } 1906 1907 int 1908 smbios_info_processor_riscv(smbios_hdl_t *shp, id_t id, 1909 smbios_processor_info_riscv_t *riscv) 1910 { 1911 const smb_struct_t *stp = smb_lookup_id(shp, id); 1912 const smb_processor_info_t *proc; 1913 const smb_processor_info_riscv_t *rv; 1914 1915 if (stp == NULL) { 1916 return (-1); /* errno is set for us */ 1917 } 1918 1919 if (stp->smbst_hdr->smbh_type != SMB_TYPE_PROCESSOR_INFO) { 1920 return (smb_set_errno(shp, ESMB_TYPE)); 1921 } 1922 1923 if (stp->smbst_hdr->smbh_len < sizeof (*proc)) { 1924 return (smb_set_errno(shp, ESMB_SHORT)); 1925 } 1926 1927 proc = (const smb_processor_info_t *)stp->smbst_hdr; 1928 if (sizeof (*proc) + proc->smbpai_len > stp->smbst_hdr->smbh_len) { 1929 return (smb_set_errno(shp, ESMB_CORRUPT)); 1930 } 1931 1932 switch (proc->smbpai_type) { 1933 case SMB_PROCINFO_T_RV32: 1934 case SMB_PROCINFO_T_RV64: 1935 case SMB_PROCINFO_T_RV128: 1936 break; 1937 default: 1938 return (smb_set_errno(shp, ESMB_TYPE)); 1939 } 1940 1941 if (stp->smbst_hdr->smbh_len < sizeof (*proc) + sizeof (*rv)) { 1942 return (smb_set_errno(shp, ESMB_SHORT)); 1943 } 1944 rv = (const smb_processor_info_riscv_t *)&proc->smbpai_data[0]; 1945 if (rv->smbpairv_len != sizeof (*rv)) { 1946 return (smb_set_errno(shp, ESMB_CORRUPT)); 1947 } 1948 1949 bcopy(rv->smbpairv_hartid, riscv->smbpirv_hartid, 1950 sizeof (riscv->smbpirv_hartid)); 1951 bcopy(rv->smbpairv_vendid, riscv->smbpirv_vendid, 1952 sizeof (riscv->smbpirv_vendid)); 1953 bcopy(rv->smbpairv_archid, riscv->smbpirv_archid, 1954 sizeof (riscv->smbpirv_archid)); 1955 bcopy(rv->smbpairv_machid, riscv->smbpirv_machid, 1956 sizeof (riscv->smbpirv_machid)); 1957 bcopy(rv->smbpairv_metdi, riscv->smbpirv_metdi, 1958 sizeof (riscv->smbpirv_metdi)); 1959 bcopy(rv->smbpairv_mitdi, riscv->smbpirv_mitdi, 1960 sizeof (riscv->smbpirv_mitdi)); 1961 riscv->smbpirv_isa = rv->smbpairv_isa; 1962 riscv->smbpirv_privlvl = rv->smbpairv_privlvl; 1963 riscv->smbpirv_boothart = rv->smbpairv_boot; 1964 riscv->smbpirv_xlen = rv->smbpairv_xlen; 1965 riscv->smbpirv_mxlen = rv->smbpairv_mxlen; 1966 riscv->smbpirv_sxlen = rv->smbpairv_sxlen; 1967 riscv->smbpirv_uxlen = rv->smbpairv_uxlen; 1968 1969 return (0); 1970 } 1971 1972 int 1973 smbios_info_pointdev(smbios_hdl_t *shp, id_t id, smbios_pointdev_t *pd) 1974 { 1975 const smb_struct_t *stp = smb_lookup_id(shp, id); 1976 smb_pointdev_t point; 1977 1978 if (stp == NULL) { 1979 return (-1); /* errno is set for us */ 1980 } 1981 1982 if (stp->smbst_hdr->smbh_type != SMB_TYPE_POINTDEV) { 1983 return (smb_set_errno(shp, ESMB_TYPE)); 1984 } 1985 1986 if (stp->smbst_hdr->smbh_len < sizeof (point)) { 1987 return (smb_set_errno(shp, ESMB_SHORT)); 1988 } 1989 1990 bzero(pd, sizeof (*pd)); 1991 smb_info_bcopy(stp->smbst_hdr, &point, sizeof (point)); 1992 1993 pd->smbpd_type = point.smbpdev_type; 1994 pd->smbpd_iface = point.smbpdev_iface; 1995 pd->smbpd_nbuttons = point.smbpdev_nbuttons; 1996 1997 return (0); 1998 } 1999 2000 int 2001 smbios_info_battery(smbios_hdl_t *shp, id_t id, smbios_battery_t *bp) 2002 { 2003 const smb_struct_t *stp = smb_lookup_id(shp, id); 2004 smb_battery_t bat; 2005 2006 if (stp == NULL) { 2007 return (-1); /* errno is set for us */ 2008 } 2009 2010 if (stp->smbst_hdr->smbh_type != SMB_TYPE_BATTERY) { 2011 return (smb_set_errno(shp, ESMB_TYPE)); 2012 } 2013 2014 if (stp->smbst_hdr->smbh_len < sizeof (bat)) { 2015 return (smb_set_errno(shp, ESMB_SHORT)); 2016 } 2017 2018 bzero(bp, sizeof (*bp)); 2019 smb_info_bcopy(stp->smbst_hdr, &bat, sizeof (bat)); 2020 2021 /* 2022 * This may be superseded by the SBDS data. 2023 */ 2024 if (bat.smbbat_date != 0) { 2025 bp->smbb_date = smb_strptr(stp, bat.smbbat_date); 2026 } else { 2027 bp->smbb_date = NULL; 2028 } 2029 2030 /* 2031 * This may be superseded by the SBDS data. 2032 */ 2033 if (bat.smbbat_serial != 0) { 2034 bp->smbb_serial = smb_strptr(stp, bat.smbbat_serial); 2035 } else { 2036 bp->smbb_serial = NULL; 2037 } 2038 2039 bp->smbb_chem = bat.smbbat_chem; 2040 bp->smbb_cap = bat.smbbat_cap; 2041 if (bat.smbbat_mult > 0) { 2042 bp->smbb_cap *= bat.smbbat_mult; 2043 } 2044 bp->smbb_volt = bat.smbbat_volt; 2045 bp->smbb_version = smb_strptr(stp, bat.smbbat_version); 2046 bp->smbb_err = bat.smbbat_err; 2047 bp->smbb_ssn = bat.smbbat_ssn; 2048 bp->smbb_syear = 1980 + (bat.smbbat_sdate >> 9); 2049 bp->smbb_smonth = (bat.smbbat_sdate >> 5) & 0xf; 2050 bp->smbb_sday = bat.smbbat_sdate & 0x1f; 2051 bp->smbb_schem = smb_strptr(stp, bat.smbbat_schem); 2052 bp->smbb_oemdata = bat.smbbat_oemdata; 2053 2054 return (0); 2055 } 2056 2057 int 2058 smbios_info_strprop(smbios_hdl_t *shp, id_t id, smbios_strprop_t *str) 2059 { 2060 const smb_struct_t *stp = smb_lookup_id(shp, id); 2061 smb_strprop_t prop; 2062 2063 if (stp == NULL) { 2064 return (-1); /* errno is set for us */ 2065 } 2066 2067 if (stp->smbst_hdr->smbh_type != SMB_TYPE_STRPROP) { 2068 return (smb_set_errno(shp, ESMB_TYPE)); 2069 } 2070 2071 if (stp->smbst_hdr->smbh_len < sizeof (prop)) { 2072 return (smb_set_errno(shp, ESMB_SHORT)); 2073 } 2074 2075 if (stp->smbst_hdr->smbh_len > sizeof (prop)) { 2076 return (smb_set_errno(shp, ESMB_CORRUPT)); 2077 } 2078 2079 bzero(str, sizeof (*str)); 2080 smb_info_bcopy(stp->smbst_hdr, &prop, sizeof (prop)); 2081 2082 str->smbsp_parent = prop.smbstrp_phdl; 2083 str->smbsp_prop_id = prop.smbstrp_prop_id; 2084 str->smbsp_prop_val = smb_strptr(stp, prop.smbstrp_prop_val); 2085 2086 return (0); 2087 } 2088 2089 int 2090 smbios_info_fwinfo(smbios_hdl_t *shp, id_t id, smbios_fwinfo_t *fwinfo) 2091 { 2092 const smb_struct_t *stp = smb_lookup_id(shp, id); 2093 smb_fwinfo_t fw; 2094 2095 if (stp == NULL) { 2096 return (-1); /* errno is set for us */ 2097 } 2098 2099 if (stp->smbst_hdr->smbh_type != SMB_TYPE_FWINFO) { 2100 return (smb_set_errno(shp, ESMB_TYPE)); 2101 } 2102 2103 if (stp->smbst_hdr->smbh_len < sizeof (fw)) { 2104 return (smb_set_errno(shp, ESMB_SHORT)); 2105 } 2106 2107 /* 2108 * The verion and manufacturer are part of smbios_info_common(). 2109 */ 2110 bzero(fwinfo, sizeof (*fwinfo)); 2111 smb_info_bcopy(stp->smbst_hdr, &fw, sizeof (fw)); 2112 fwinfo->smbfw_name = smb_strptr(stp, fw.smbfwii_name); 2113 fwinfo->smbfw_id = smb_strptr(stp, fw.smbfwii_id); 2114 fwinfo->smbfw_reldate = smb_strptr(stp, fw.smbfwii_reldate); 2115 fwinfo->smbfw_lsv = smb_strptr(stp, fw.smbfwii_lsv); 2116 fwinfo->smbfw_imgsz = fw.smbfwii_imgsz; 2117 fwinfo->smbfw_chars = fw.smbfwii_chars; 2118 fwinfo->smbfw_state = fw.smbfwii_state; 2119 fwinfo->smbfw_ncomps = fw.smbfwii_ncomps; 2120 fwinfo->smbfw_vers_fmt = fw.smbfwii_vers_fmt; 2121 fwinfo->smbfw_id_fmt = fw.smbfwii_id_fmt; 2122 2123 return (0); 2124 } 2125 2126 int 2127 smbios_info_fwinfo_comps(smbios_hdl_t *shp, id_t id, uint_t *ncompsp, 2128 smbios_fwinfo_comp_t **compsp) 2129 { 2130 const smb_struct_t *stp = smb_lookup_id(shp, id); 2131 smbios_fwinfo_comp_t *comps; 2132 smb_fwinfo_t fw; 2133 size_t need; 2134 uint_t i; 2135 2136 if (stp == NULL) { 2137 return (-1); /* errno is set for us */ 2138 } 2139 2140 if (stp->smbst_hdr->smbh_type != SMB_TYPE_FWINFO) { 2141 return (smb_set_errno(shp, ESMB_TYPE)); 2142 } 2143 2144 if (stp->smbst_hdr->smbh_len < sizeof (fw)) { 2145 return (smb_set_errno(shp, ESMB_SHORT)); 2146 } 2147 2148 smb_info_bcopy(stp->smbst_hdr, &fw, sizeof (fw)); 2149 if (fw.smbfwii_ncomps == 0) { 2150 *ncompsp = 0; 2151 *compsp = NULL; 2152 return (0); 2153 } 2154 2155 need = fw.smbfwii_ncomps * sizeof (uint16_t) + sizeof (smb_fwinfo_t); 2156 if (stp->smbst_hdr->smbh_len < need) { 2157 return (smb_set_errno(shp, ESMB_SHORT)); 2158 } 2159 2160 comps = smb_alloc(fw.smbfwii_ncomps * sizeof (smbios_fwinfo_comp_t)); 2161 if (comps == NULL) { 2162 return (smb_set_errno(shp, ESMB_NOMEM)); 2163 } 2164 2165 for (i = 0; i < fw.smbfwii_ncomps; i++) { 2166 uint16_t id; 2167 size_t off = sizeof (smb_fwinfo_t) + sizeof (uint16_t) * i; 2168 smb_info_bcopy_offset(stp->smbst_hdr, &id, sizeof (id), off); 2169 comps[i].smbfwe_id = id; 2170 } 2171 2172 *ncompsp = fw.smbfwii_ncomps; 2173 *compsp = comps; 2174 2175 return (0); 2176 } 2177 2178 void 2179 smbios_info_fwinfo_comps_free(smbios_hdl_t *shp, uint_t ncomps, 2180 smbios_fwinfo_comp_t *comps) 2181 { 2182 size_t sz = ncomps * sizeof (smbios_fwinfo_comp_t); 2183 2184 if (ncomps == 0) { 2185 ASSERT3P(comps, ==, NULL); 2186 return; 2187 } 2188 2189 smb_free(comps, sz); 2190 } 2191 2192 int 2193 smbios_info_addinfo_nents(smbios_hdl_t *shp, id_t id, uint_t *nentsp) 2194 { 2195 const smb_struct_t *stp = smb_lookup_id(shp, id); 2196 smb_addinfo_t add; 2197 2198 if (stp == NULL) { 2199 return (-1); /* errno is set for us */ 2200 } 2201 2202 if (stp->smbst_hdr->smbh_type != SMB_TYPE_ADDINFO) { 2203 return (smb_set_errno(shp, ESMB_TYPE)); 2204 } 2205 2206 if (stp->smbst_hdr->smbh_len < sizeof (add)) { 2207 return (smb_set_errno(shp, ESMB_SHORT)); 2208 } 2209 2210 smb_info_bcopy(stp->smbst_hdr, &add, sizeof (add)); 2211 *nentsp = add.smbai_nents; 2212 2213 return (0); 2214 } 2215 2216 void 2217 smbios_info_addinfo_ent_free(smbios_hdl_t *hdl, smbios_addinfo_ent_t *ent) 2218 { 2219 if (ent->smbai_dlen > 0) { 2220 ASSERT3P(ent->smbai_data, !=, NULL); 2221 smb_free(ent->smbai_data, ent->smbai_dlen); 2222 } 2223 2224 smb_free(ent, sizeof (smbios_addinfo_ent_t)); 2225 } 2226 2227 int 2228 smbios_info_addinfo_ent(smbios_hdl_t *shp, id_t id, uint_t entno, 2229 smbios_addinfo_ent_t **entp) 2230 { 2231 const smb_struct_t *stp = smb_lookup_id(shp, id); 2232 size_t off; 2233 smb_addinfo_t add; 2234 smb_addinfo_ent_t ent; 2235 smbios_addinfo_ent_t *entry; 2236 uint_t i; 2237 2238 if (stp == NULL) { 2239 return (-1); /* errno is set for us */ 2240 } 2241 2242 if (stp->smbst_hdr->smbh_type != SMB_TYPE_ADDINFO) { 2243 return (smb_set_errno(shp, ESMB_TYPE)); 2244 } 2245 2246 if (stp->smbst_hdr->smbh_len < sizeof (add)) { 2247 return (smb_set_errno(shp, ESMB_SHORT)); 2248 } 2249 2250 smb_info_bcopy(stp->smbst_hdr, &add, sizeof (add)); 2251 if (entno >= add.smbai_nents) { 2252 return (smb_set_errno(shp, ESMB_REQVAL)); 2253 } 2254 2255 off = sizeof (add); 2256 for (i = 0; i <= entno; i++) { 2257 if (off + sizeof (ent) > stp->smbst_hdr->smbh_len) { 2258 return (smb_set_errno(shp, ESMB_SHORT)); 2259 } 2260 2261 smb_info_bcopy_offset(stp->smbst_hdr, &ent, sizeof (ent), off); 2262 if (ent.smbaie_len < sizeof (ent)) { 2263 return (smb_set_errno(shp, ESMB_SHORT)); 2264 } 2265 2266 if (ent.smbaie_len + off > stp->smbst_hdr->smbh_len) { 2267 return (smb_set_errno(shp, ESMB_CORRUPT)); 2268 } 2269 2270 if (i != entno) { 2271 off += ent.smbaie_len; 2272 } 2273 } 2274 2275 entry = smb_alloc(sizeof (smbios_addinfo_ent_t)); 2276 if (entry == NULL) { 2277 return (smb_set_errno(shp, ESMB_NOMEM)); 2278 } 2279 2280 entry->smbai_ref = ent.smbaie_rhdl; 2281 entry->smbai_ref_off = ent.smbaie_off; 2282 if (ent.smbaie_str != 0) { 2283 entry->smbai_str = smb_strptr(stp, ent.smbaie_str); 2284 } else { 2285 entry->smbai_str = NULL; 2286 } 2287 entry->smbai_dlen = ent.smbaie_len - sizeof (ent); 2288 if (entry->smbai_dlen > 0) { 2289 entry->smbai_data = smb_alloc(entry->smbai_dlen); 2290 if (entry->smbai_data == NULL) { 2291 smb_free(entry, sizeof (smbios_addinfo_ent_t)); 2292 return (smb_set_errno(shp, ESMB_NOMEM)); 2293 } 2294 smb_info_bcopy_offset(stp->smbst_hdr, entry->smbai_data, 2295 entry->smbai_dlen, off + offsetof(smb_addinfo_ent_t, 2296 smbaie_val)); 2297 } else { 2298 entry->smbai_data = NULL; 2299 } 2300 2301 *entp = entry; 2302 return (0); 2303 } 2304