1 /*- 2 * Copyright (c) 2005-2009 Jung-uk Kim <jkim@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <stand.h> 28 #include <sys/endian.h> 29 30 #define PTOV(x) ptov(x) 31 32 /* Only enable 64-bit entry point if it makes sense */ 33 #if __SIZEOF_POINTER__ > 4 34 #define HAS_SMBV3 1 35 #endif 36 37 /* 38 * Detect SMBIOS and export information about the SMBIOS into the 39 * environment. 40 * 41 * System Management BIOS Reference Specification, v2.6 Final 42 * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf 43 * 44 * System Management BIOS (SMBIOS) Reference Specification, 3.6.0 45 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.6.0.pdf 46 */ 47 48 /* 49 * The first quoted paragraph below can also be found in section 2.1.1 SMBIOS 50 * Structure Table Entry Point of System Management BIOS Reference 51 * Specification, v2.6 Final 52 * 53 * (From System Management BIOS (SMBIOS) Reference Specification, 3.6.0) 54 * 5.2.1 SMBIOS 2.1 (32-bit) Entry Point 55 * 56 * "On non-UEFI systems, the 32-bit SMBIOS Entry Point structure, can be 57 * located by application software by searching for the anchor-string on 58 * paragraph (16-byte) boundaries within the physical memory address 59 * range 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate 60 * anchor string that is used by some existing DMI browsers. 61 * 62 * On UEFI-based systems, the SMBIOS Entry Point structure can be located by 63 * looking in the EFI Configuration Table for the SMBIOS GUID 64 * (SMBIOS_TABLE_GUID, {EB9D2D31-2D88-11D3-9A16-0090273FC14D}) and using the 65 * associated pointer. See section 4.6 of the UEFI Specification for details. 66 * See section 2.3 of the UEFI Specification for how to report the containing 67 * memory type. 68 * 69 * NOTE While the SMBIOS Major and Minor Versions (offsets 06h and 07h) 70 * currently duplicate the information that is present in the SMBIOS BCD 71 * Revision (offset 1Eh), they provide a path for future growth in this 72 * specification. The BCD Revision, for example, provides only a single digit 73 * for each of the major and minor version numbers." 74 * 75 * 5.2.2 SMBIOS 860 3.0 (64-bit) Entry Point 76 * 77 * "On non-UEFI systems, the 64-bit SMBIOS Entry Point structure can be located 78 * by application software by searching for the anchor-string on paragraph 79 * (16-byte) boundaries within the physical memory address range 000F0000h to 80 * 000FFFFFh. 81 * 82 * On UEFI-based systems, the SMBIOS Entry Point structure can be located by 83 * looking in the EFI Configuration Table for the SMBIOS 3.x GUID 84 * (SMBIOS3_TABLE_GUID, {F2FD1544-9794-4A2C-992E-E5BBCF20E394}) and using the 85 * associated pointer. See section 4.6 of the UEFI Specification for details. 86 * See section 2.3 of the UEFI Specification for how to report the containing 87 * memory type." 88 */ 89 #define SMBIOS_START 0xf0000 90 #define SMBIOS_LENGTH 0x10000 91 #define SMBIOS_STEP 0x10 92 #define SMBIOS_SIG "_SM_" 93 #define SMBIOS3_SIG "_SM3_" 94 #define SMBIOS_DMI_SIG "_DMI_" 95 96 /* 97 * 5.1 General 98 *... 99 * NOTE The Entry Point Structure and all SMBIOS structures assume a 100 * little-endian ordering convention... 101 * ... 102 * 103 * We use memcpy to avoid unaligned access to memory. To normal memory, this is 104 * fine, but the memory we are using might be mmap'd /dev/mem which under Linux 105 * on aarch64 doesn't allow unaligned access. leXdec and friends can't be used 106 * because those can optimize to an unaligned load (which often is fine, but not 107 * for mmap'd /dev/mem which has special memory attributes). 108 */ 109 static inline uint8_t SMBIOS_GET8(const caddr_t base, int off) { return (base[off]); } 110 111 static inline uint16_t 112 SMBIOS_GET16(const caddr_t base, int off) 113 { 114 uint16_t v; 115 116 memcpy(&v, base + off, sizeof(v)); 117 return (le16toh(v)); 118 } 119 120 static inline uint32_t 121 SMBIOS_GET32(const caddr_t base, int off) 122 { 123 uint32_t v; 124 125 memcpy(&v, base + off, sizeof(v)); 126 return (le32toh(v)); 127 } 128 129 static inline uint64_t 130 SMBIOS_GET64(const caddr_t base, int off) 131 { 132 uint64_t v; 133 134 memcpy(&v, base + off, sizeof(v)); 135 return (le64toh(v)); 136 } 137 138 #define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) 139 #define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) 140 141 struct smbios_attr { 142 int probed; 143 caddr_t addr; 144 size_t length; 145 size_t count; 146 int major; 147 int minor; 148 int ver; 149 const char* bios_vendor; 150 const char* maker; 151 const char* product; 152 uint32_t enabled_memory; 153 uint32_t old_enabled_memory; 154 uint8_t enabled_sockets; 155 uint8_t populated_sockets; 156 }; 157 158 static struct smbios_attr smbios; 159 #ifdef HAS_SMBV3 160 static int isv3; 161 #endif 162 163 static uint8_t 164 smbios_checksum(const caddr_t addr, const uint8_t len) 165 { 166 uint8_t sum; 167 int i; 168 169 for (sum = 0, i = 0; i < len; i++) 170 sum += SMBIOS_GET8(addr, i); 171 return (sum); 172 } 173 174 static caddr_t 175 smbios_sigsearch(const caddr_t addr, const uint32_t len) 176 { 177 caddr_t cp; 178 179 /* Search on 16-byte boundaries. */ 180 for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) { 181 /* v2.1, 32-bit Entry point */ 182 if (strncmp(cp, SMBIOS_SIG, sizeof(SMBIOS_SIG) - 1) == 0 && 183 smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && 184 strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 && 185 smbios_checksum(cp + 0x10, 0x0f) == 0) 186 return (cp); 187 188 #ifdef HAS_SMBV3 189 /* v3.0, 64-bit Entry point */ 190 if (strncmp(cp, SMBIOS3_SIG, sizeof(SMBIOS3_SIG) - 1) == 0 && 191 smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) { 192 isv3 = 1; 193 return (cp); 194 } 195 #endif 196 } 197 return (NULL); 198 } 199 200 static const char* 201 smbios_getstring(caddr_t addr, const int offset) 202 { 203 caddr_t cp; 204 int i, idx; 205 206 idx = SMBIOS_GET8(addr, offset); 207 if (idx != 0) { 208 cp = SMBIOS_GETSTR(addr); 209 for (i = 1; i < idx; i++) 210 cp += strlen(cp) + 1; 211 return cp; 212 } 213 return (NULL); 214 } 215 216 static void 217 smbios_setenv(const char *name, caddr_t addr, const int offset) 218 { 219 const char* val; 220 221 val = smbios_getstring(addr, offset); 222 if (val != NULL) 223 setenv(name, val, 1); 224 } 225 226 #ifdef SMBIOS_SERIAL_NUMBERS 227 228 #define UUID_SIZE 16 229 #define UUID_TYPE uint32_t 230 #define UUID_STEP sizeof(UUID_TYPE) 231 #define UUID_ALL_BITS (UUID_SIZE / UUID_STEP) 232 #define UUID_GET(base, off) SMBIOS_GET32(base, off) 233 234 static void 235 smbios_setuuid(const char *name, const caddr_t addr, const int ver __unused) 236 { 237 char uuid[37]; 238 int byteorder, i, ones, zeros; 239 UUID_TYPE n; 240 uint32_t f1; 241 uint16_t f2, f3; 242 243 for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) { 244 n = UUID_GET(addr, i) + 1; 245 if (zeros == 0 && n == 0) 246 ones++; 247 else if (ones == 0 && n == 1) 248 zeros++; 249 else 250 break; 251 } 252 253 if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) { 254 /* 255 * 3.3.2.1 System UUID 256 * 257 * "Although RFC 4122 recommends network byte order for all 258 * fields, the PC industry (including the ACPI, UEFI, and 259 * Microsoft specifications) has consistently used 260 * little-endian byte encoding for the first three fields: 261 * time_low, time_mid, time_hi_and_version. The same encoding, 262 * also known as wire format, should also be used for the 263 * SMBIOS representation of the UUID." 264 * 265 * Note: We use network byte order for backward compatibility 266 * unless SMBIOS version is 2.6+ or little-endian is forced. 267 */ 268 #if defined(SMBIOS_LITTLE_ENDIAN_UUID) 269 byteorder = LITTLE_ENDIAN; 270 #elif defined(SMBIOS_NETWORK_ENDIAN_UUID) 271 byteorder = BIG_ENDIAN; 272 #else 273 byteorder = ver < 0x0206 ? BIG_ENDIAN : LITTLE_ENDIAN; 274 #endif 275 if (byteorder != LITTLE_ENDIAN) { 276 f1 = ntohl(SMBIOS_GET32(addr, 0)); 277 f2 = ntohs(SMBIOS_GET16(addr, 4)); 278 f3 = ntohs(SMBIOS_GET16(addr, 6)); 279 } else { 280 f1 = le32toh(SMBIOS_GET32(addr, 0)); 281 f2 = le16toh(SMBIOS_GET16(addr, 4)); 282 f3 = le16toh(SMBIOS_GET16(addr, 6)); 283 } 284 sprintf(uuid, 285 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 286 f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9), 287 SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11), 288 SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13), 289 SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15)); 290 setenv(name, uuid, 1); 291 } 292 } 293 294 #undef UUID_SIZE 295 #undef UUID_TYPE 296 #undef UUID_STEP 297 #undef UUID_ALL_BITS 298 #undef UUID_GET 299 300 #endif 301 302 static const char * 303 smbios_parse_chassis_type(caddr_t addr) 304 { 305 int type; 306 307 type = SMBIOS_GET8(addr, 0x5); 308 switch (type) { 309 case 0x1: 310 return ("Other"); 311 case 0x2: 312 return ("Unknown"); 313 case 0x3: 314 return ("Desktop"); 315 case 0x4: 316 return ("Low Profile Desktop"); 317 case 0x5: 318 return ("Pizza Box"); 319 case 0x6: 320 return ("Mini Tower"); 321 case 0x7: 322 return ("Tower"); 323 case 0x8: 324 return ("Portable"); 325 case 0x9: 326 return ("Laptop"); 327 case 0xA: 328 return ("Notebook"); 329 case 0xB: 330 return ("Hand Held"); 331 case 0xC: 332 return ("Docking Station"); 333 case 0xD: 334 return ("All in One"); 335 case 0xE: 336 return ("Sub Notebook"); 337 case 0xF: 338 return ("Lunch Box"); 339 case 0x10: 340 return ("Space-saving"); 341 case 0x11: 342 return ("Main Server Chassis"); 343 case 0x12: 344 return ("Expansion Chassis"); 345 case 0x13: 346 return ("SubChassis"); 347 case 0x14: 348 return ("Bus Expansion Chassis"); 349 case 0x15: 350 return ("Peripheral Chassis"); 351 case 0x16: 352 return ("RAID Chassis"); 353 case 0x17: 354 return ("Rack Mount Chassis"); 355 case 0x18: 356 return ("Sealed-case PC"); 357 case 0x19: 358 return ("Multi-system chassis"); 359 case 0x1A: 360 return ("Compact PCI"); 361 case 0x1B: 362 return ("Advanced TCA"); 363 case 0x1C: 364 return ("Blade"); 365 case 0x1D: 366 return ("Blade Enclosure"); 367 case 0x1E: 368 return ("Tablet"); 369 case 0x1F: 370 return ("Convertible"); 371 case 0x20: 372 return ("Detachable"); 373 case 0x21: 374 return ("IoT Gateway"); 375 case 0x22: 376 return ("Embedded PC"); 377 case 0x23: 378 return ("Mini PC"); 379 case 0x24: 380 return ("Stick PC"); 381 } 382 383 return ("Undefined"); 384 } 385 386 static caddr_t 387 smbios_parse_table(const caddr_t addr) 388 { 389 caddr_t cp; 390 int proc, size, osize, type; 391 uint8_t bios_minor, bios_major; 392 char buf[16]; 393 394 type = SMBIOS_GET8(addr, 0); /* 3.1.2 Structure Header Format */ 395 switch(type) { 396 case 0: /* 3.3.1 BIOS Information (Type 0) */ 397 smbios_setenv("smbios.bios.vendor", addr, 0x04); 398 smbios_setenv("smbios.bios.version", addr, 0x05); 399 smbios_setenv("smbios.bios.reldate", addr, 0x08); 400 bios_major = SMBIOS_GET8(addr, 0x14); 401 bios_minor = SMBIOS_GET8(addr, 0x15); 402 if (bios_minor != 0xFF && bios_major != 0xFF) { 403 snprintf(buf, sizeof(buf), "%u.%u", 404 bios_major, bios_minor); 405 setenv("smbios.bios.revision", buf, 1); 406 } 407 break; 408 409 case 1: /* 3.3.2 System Information (Type 1) */ 410 smbios_setenv("smbios.system.maker", addr, 0x04); 411 smbios_setenv("smbios.system.product", addr, 0x05); 412 smbios_setenv("smbios.system.version", addr, 0x06); 413 #ifdef SMBIOS_SERIAL_NUMBERS 414 smbios_setenv("smbios.system.serial", addr, 0x07); 415 smbios_setuuid("smbios.system.uuid", addr + 0x08, smbios.ver); 416 #endif 417 if (smbios.major > 2 || 418 (smbios.major == 2 && smbios.minor >= 4)) { 419 smbios_setenv("smbios.system.sku", addr, 0x19); 420 smbios_setenv("smbios.system.family", addr, 0x1a); 421 } 422 break; 423 424 case 2: /* 3.3.3 Base Board (or Module) Information (Type 2) */ 425 smbios_setenv("smbios.planar.maker", addr, 0x04); 426 smbios_setenv("smbios.planar.product", addr, 0x05); 427 smbios_setenv("smbios.planar.version", addr, 0x06); 428 #ifdef SMBIOS_SERIAL_NUMBERS 429 smbios_setenv("smbios.planar.serial", addr, 0x07); 430 smbios_setenv("smbios.planar.tag", addr, 0x08); 431 #endif 432 smbios_setenv("smbios.planar.location", addr, 0x0a); 433 break; 434 435 case 3: /* 3.3.4 System Enclosure or Chassis (Type 3) */ 436 smbios_setenv("smbios.chassis.maker", addr, 0x04); 437 setenv("smbios.chassis.type", smbios_parse_chassis_type(addr), 1); 438 smbios_setenv("smbios.chassis.version", addr, 0x06); 439 #ifdef SMBIOS_SERIAL_NUMBERS 440 smbios_setenv("smbios.chassis.serial", addr, 0x07); 441 smbios_setenv("smbios.chassis.tag", addr, 0x08); 442 #endif 443 break; 444 445 case 4: /* 3.3.5 Processor Information (Type 4) */ 446 /* 447 * Offset 18h: Processor Status 448 * 449 * Bit 7 Reserved, must be 0 450 * Bit 6 CPU Socket Populated 451 * 1 - CPU Socket Populated 452 * 0 - CPU Socket Unpopulated 453 * Bit 5:3 Reserved, must be zero 454 * Bit 2:0 CPU Status 455 * 0h - Unknown 456 * 1h - CPU Enabled 457 * 2h - CPU Disabled by User via BIOS Setup 458 * 3h - CPU Disabled by BIOS (POST Error) 459 * 4h - CPU is Idle, waiting to be enabled 460 * 5-6h - Reserved 461 * 7h - Other 462 */ 463 proc = SMBIOS_GET8(addr, 0x18); 464 if ((proc & 0x07) == 1) 465 smbios.enabled_sockets++; 466 if ((proc & 0x40) != 0) 467 smbios.populated_sockets++; 468 break; 469 470 case 6: /* 3.3.7 Memory Module Information (Type 6, Obsolete) */ 471 /* 472 * Offset 0Ah: Enabled Size 473 * 474 * Bit 7 Bank connection 475 * 1 - Double-bank connection 476 * 0 - Single-bank connection 477 * Bit 6:0 Size (n), where 2**n is the size in MB 478 * 7Dh - Not determinable (Installed Size only) 479 * 7Eh - Module is installed, but no memory 480 * has been enabled 481 * 7Fh - Not installed 482 */ 483 osize = SMBIOS_GET8(addr, 0x0a) & 0x7f; 484 if (osize > 0 && osize < 22) 485 smbios.old_enabled_memory += 1 << (osize + 10); 486 break; 487 488 case 17: /* 3.3.18 Memory Device (Type 17) */ 489 /* 490 * Offset 0Ch: Size 491 * 492 * Bit 15 Granularity 493 * 1 - Value is in kilobytes units 494 * 0 - Value is in megabytes units 495 * Bit 14:0 Size 496 */ 497 size = SMBIOS_GET16(addr, 0x0c); 498 if (size != 0 && size != 0xffff) 499 smbios.enabled_memory += (size & 0x8000) != 0 ? 500 (size & 0x7fff) : (size << 10); 501 break; 502 503 default: /* skip other types */ 504 break; 505 } 506 507 /* Find structure terminator. */ 508 cp = SMBIOS_GETSTR(addr); 509 while (SMBIOS_GET16(cp, 0) != 0) 510 cp++; 511 512 return (cp + 2); 513 } 514 515 static caddr_t 516 smbios_find_struct(int type) 517 { 518 caddr_t dmi; 519 size_t i; 520 caddr_t ep; 521 522 if (smbios.addr == NULL) 523 return (NULL); 524 525 ep = smbios.addr + smbios.length; 526 for (dmi = smbios.addr, i = 0; 527 dmi < ep && i < smbios.count; i++) { 528 if (SMBIOS_GET8(dmi, 0) == type) { 529 return dmi; 530 } 531 /* Find structure terminator. */ 532 dmi = SMBIOS_GETSTR(dmi); 533 while (SMBIOS_GET16(dmi, 0) != 0 && dmi < ep) { 534 dmi++; 535 } 536 dmi += 2; /* For checksum */ 537 } 538 539 return (NULL); 540 } 541 542 static void 543 smbios_probe(const caddr_t addr) 544 { 545 caddr_t saddr, info; 546 uintptr_t paddr; 547 int maj_off; 548 int min_off; 549 550 if (smbios.probed) 551 return; 552 smbios.probed = 1; 553 554 /* Search signatures and validate checksums. */ 555 saddr = smbios_sigsearch(addr ? addr : PTOV(SMBIOS_START), 556 SMBIOS_LENGTH); 557 if (saddr == NULL) 558 return; 559 560 #ifdef HAS_SMBV3 561 if (isv3) { 562 smbios.length = SMBIOS_GET32(saddr, 0x0c); /* Structure Table Length */ 563 paddr = SMBIOS_GET64(saddr, 0x10); /* Structure Table Address */ 564 smbios.count = -1; /* not present in V3 */ 565 smbios.ver = 0; /* not present in V3 */ 566 maj_off = 0x07; 567 min_off = 0x08; 568 } else 569 #endif 570 { 571 smbios.length = SMBIOS_GET16(saddr, 0x16); /* Structure Table Length */ 572 paddr = SMBIOS_GET32(saddr, 0x18); /* Structure Table Address */ 573 smbios.count = SMBIOS_GET16(saddr, 0x1c); /* No of SMBIOS Structures */ 574 smbios.ver = SMBIOS_GET8(saddr, 0x1e); /* SMBIOS BCD Revision */ 575 maj_off = 0x06; 576 min_off = 0x07; 577 } 578 579 580 if (smbios.ver != 0) { 581 smbios.major = smbios.ver >> 4; 582 smbios.minor = smbios.ver & 0x0f; 583 if (smbios.major > 9 || smbios.minor > 9) 584 smbios.ver = 0; 585 } 586 if (smbios.ver == 0) { 587 smbios.major = SMBIOS_GET8(saddr, maj_off);/* SMBIOS Major Version */ 588 smbios.minor = SMBIOS_GET8(saddr, min_off);/* SMBIOS Minor Version */ 589 } 590 smbios.ver = (smbios.major << 8) | smbios.minor; 591 smbios.addr = PTOV(paddr); 592 593 /* Get system information from SMBIOS */ 594 info = smbios_find_struct(0x00); 595 if (info != NULL) { 596 smbios.bios_vendor = smbios_getstring(info, 0x04); 597 } 598 info = smbios_find_struct(0x01); 599 if (info != NULL) { 600 smbios.maker = smbios_getstring(info, 0x04); 601 smbios.product = smbios_getstring(info, 0x05); 602 } 603 } 604 605 void 606 smbios_detect(const caddr_t addr) 607 { 608 char buf[16]; 609 caddr_t dmi; 610 size_t i; 611 612 smbios_probe(addr); 613 if (smbios.addr == NULL) 614 return; 615 616 for (dmi = smbios.addr, i = 0; 617 dmi < smbios.addr + smbios.length && i < smbios.count; i++) 618 dmi = smbios_parse_table(dmi); 619 620 sprintf(buf, "%d.%d", smbios.major, smbios.minor); 621 setenv("smbios.version", buf, 1); 622 if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) { 623 sprintf(buf, "%u", smbios.enabled_memory > 0 ? 624 smbios.enabled_memory : smbios.old_enabled_memory); 625 setenv("smbios.memory.enabled", buf, 1); 626 } 627 if (smbios.enabled_sockets > 0) { 628 sprintf(buf, "%u", smbios.enabled_sockets); 629 setenv("smbios.socket.enabled", buf, 1); 630 } 631 if (smbios.populated_sockets > 0) { 632 sprintf(buf, "%u", smbios.populated_sockets); 633 setenv("smbios.socket.populated", buf, 1); 634 } 635 } 636 637 static int 638 smbios_match_str(const char* s1, const char* s2) 639 { 640 return (s1 == NULL || (s2 != NULL && !strcmp(s1, s2))); 641 } 642 643 int 644 smbios_match(const char* bios_vendor, const char* maker, 645 const char* product) 646 { 647 /* XXXRP currently, only called from non-EFI. */ 648 smbios_probe(NULL); 649 return (smbios_match_str(bios_vendor, smbios.bios_vendor) && 650 smbios_match_str(maker, smbios.maker) && 651 smbios_match_str(product, smbios.product)); 652 } 653