root/arch/i386/i386/bios.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. biosprobe
  2. biosattach
  3. bios_getopt
  4. bios_print
  5. bios32_service
  6. biosopen
  7. biosclose
  8. biosioctl
  9. bioscnprobe
  10. bioscninit
  11. bioscnputc
  12. bioscngetc
  13. bioscnpollc
  14. bios_sysctl
  15. bios_getdiskinfo
  16. smbios_find_table
  17. smbios_get_string
  18. fixstring
  19. smbios_info

    1 /*      $OpenBSD: bios.c,v 1.70 2007/08/06 16:12:25 gwk Exp $   */
    2 
    3 /*
    4  * Copyright (c) 1997-2001 Michael Shalayeff
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
   20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   26  * THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /* #define BIOS_DEBUG */
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/device.h>
   35 #include <sys/errno.h>
   36 #include <sys/proc.h>
   37 #include <sys/malloc.h>
   38 #include <sys/reboot.h>
   39 #include <sys/extent.h>
   40 
   41 #include <uvm/uvm_extern.h>
   42 #include <sys/sysctl.h>
   43 
   44 #include <dev/cons.h>
   45 #include <stand/boot/bootarg.h>
   46 
   47 #include <machine/cpu.h>
   48 #include <machine/pio.h>
   49 #include <machine/cpufunc.h>
   50 #include <machine/conf.h>
   51 #include <machine/gdt.h>
   52 #include <machine/pcb.h>
   53 #include <machine/biosvar.h>
   54 #include <machine/apmvar.h>
   55 #include <machine/smbiosvar.h>
   56 
   57 #include <dev/isa/isareg.h>
   58 #include <i386/isa/isa_machdep.h>
   59 
   60 #include "apm.h"
   61 #include "pcibios.h"
   62 #include "pci.h"
   63 
   64 struct bios_softc {
   65         struct  device sc_dev;
   66 };
   67 
   68 int biosprobe(struct device *, void *, void *);
   69 void biosattach(struct device *, struct device *, void *);
   70 int bios_print(void *, const char *);
   71 char *fixstring(char *);
   72 
   73 struct cfattach bios_ca = {
   74         sizeof(struct bios_softc), biosprobe, biosattach
   75 };
   76 
   77 struct cfdriver bios_cd = {
   78         NULL, "bios", DV_DULL
   79 };
   80 
   81 extern dev_t bootdev;
   82 
   83 #if NAPM > 0 || defined(DEBUG)
   84 bios_apminfo_t *apm;
   85 #endif
   86 #if NPCI > 0
   87 bios_pciinfo_t *bios_pciinfo;
   88 #endif
   89 bios_diskinfo_t *bios_diskinfo;
   90 bios_memmap_t  *bios_memmap;
   91 u_int32_t       bios_cksumlen;
   92 struct bios32_entry bios32_entry;
   93 struct smbios_entry smbios_entry;
   94 #ifdef MULTIPROCESSOR
   95 void            *bios_smpinfo;
   96 #endif
   97 #ifdef NFSCLIENT
   98 bios_bootmac_t  *bios_bootmac;
   99 #endif
  100 
  101 void            smbios_info(char*);
  102 
  103 bios_diskinfo_t *bios_getdiskinfo(dev_t);
  104 
  105 /*
  106  * used by hw_sysctl
  107  */
  108 extern char *hw_vendor, *hw_prod, *hw_uuid, *hw_serial, *hw_ver;
  109 const char *smbios_uninfo[] = {
  110         "System",
  111         "Not ",
  112         "To be",
  113         "SYS-"
  114 };
  115 
  116 
  117 int
  118 biosprobe(struct device *parent, void *match, void *aux)
  119 {
  120         struct bios_attach_args *bia = aux;
  121 
  122 #ifdef BIOS_DEBUG
  123         printf("%s%d: boot API ver %x, %x; args %p[%d]\n",
  124             bia->bios_dev, bios_cd.cd_ndevs,
  125             bootapiver, BOOTARG_APIVER, bootargp, bootargc);
  126 #endif
  127         /* there could be only one */
  128         if (bios_cd.cd_ndevs || strcmp(bia->bios_dev, bios_cd.cd_name))
  129                 return 0;
  130 
  131         if (!(bootapiver & BAPIV_VECTOR) || bootargp == NULL)
  132                 return 0;
  133 
  134         return 1;
  135 }
  136 
  137 void
  138 biosattach(struct device *parent, struct device *self, void *aux)
  139 {
  140         struct bios_softc *sc = (struct bios_softc *)self;
  141 #if (NPCI > 0 && NPCIBIOS > 0) || NAPM > 0
  142         struct bios_attach_args *bia = aux;
  143 #endif
  144         struct smbios_struct_bios *sb;
  145         struct smbtable bios;
  146         volatile u_int8_t *va;
  147         char scratch[64], *str;
  148         int flags;
  149 
  150         /* remember flags */
  151         flags = sc->sc_dev.dv_cfdata->cf_flags;
  152 
  153         va = ISA_HOLE_VADDR(0xffff0);
  154         switch (va[14]) {
  155         default:
  156         case 0xff: str = "PC";          break;
  157         case 0xfe: str = "PC/XT";       break;
  158         case 0xfd: str = "PCjr";        break;
  159         case 0xfc: str = "AT/286+";     break;
  160         case 0xfb: str = "PC/XT+";      break;
  161         case 0xfa: str = "PS/2 25/30";  break;
  162         case 0xf9: str = "PC Convertible";break;
  163         case 0xf8: str = "PS/2 386+";   break;
  164         }
  165         printf(": %s BIOS, date %c%c/%c%c/%c%c",
  166             str, va[5], va[6], va[8], va[9], va[11], va[12]);
  167 
  168         /*
  169          * Determining whether BIOS32 extensions are available is
  170          * done by searching for the BIOS32 service directory.
  171          * This 16-byte structure can be found somewhere in the
  172          * range 0E0000h - 0FFFFFh and must be 16-byte aligned.
  173          *
  174          *  _______________________________________________________
  175          * | Offset | Bytes | Description                          |
  176          * |-------------------------------------------------------|
  177          * |    0   |   4   | ASCII signature string of "_32_".    |
  178          * |    4   |   4   | 32-bit entry point.                  |
  179          * |    8   |   1   | Revision Level. Typically 00h.       |
  180          * |    9   |   1   | Header length in 16-byte units. So   |
  181          * |        |       | would have the value of 01h.         |
  182          * |    A   |   1   | Checksum. The sum of all bytes in    |
  183          * |        |       | this header must be zero.            |
  184          * |    B   |   5   | Reserved. Set to zero.               |
  185          *  -------------------------------------------------------
  186          *
  187          * To find the service directory, we first search for the
  188          * signature. If we find a match, we must also verify the
  189          * checksum. This service directory may then be used to
  190          * determine whether a PCI BIOS is present.
  191          *
  192          * For more information see the PCI BIOS Specification,
  193          * Revision 2.1 (August 26, 1994).
  194          */
  195 
  196         if (!(flags & BIOSF_BIOS32)) {
  197                 for (va = ISA_HOLE_VADDR(BIOS32_START);
  198                     va < (u_int8_t *)ISA_HOLE_VADDR(BIOS32_END); va += 16) {
  199                         bios32_header_t h = (bios32_header_t)va;
  200                         u_int8_t cksum;
  201                         int i;
  202 
  203                         if (h->signature != BIOS32_SIGNATURE)
  204                                 continue;
  205 
  206                         /* verify checksum */
  207                         for (cksum = 0, i = h->length * 16; i--; cksum += va[i])
  208                                 ;
  209                         if (cksum != 0)
  210                                 continue;
  211 
  212                         if (h->entry <= BIOS32_START || h->entry >= BIOS32_END)
  213                                 continue;
  214 
  215                         bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL);
  216                         bios32_entry.offset = (u_int32_t)ISA_HOLE_VADDR(h->entry);
  217                         printf(", BIOS32 rev. %d @ 0x%lx", h->rev, h->entry);
  218                         break;
  219                 }
  220         }
  221 
  222         /* see if we have SMBIOS extensions */
  223         if (!(flags & BIOSF_SMBIOS)) {
  224                 for (va = ISA_HOLE_VADDR(SMBIOS_START);
  225                     va < (u_int8_t *)ISA_HOLE_VADDR(SMBIOS_END); va+= 16) {
  226                         struct smbhdr * sh = (struct smbhdr *)va;
  227                         u_int8_t chksum;
  228                         vaddr_t eva;
  229                         paddr_t pa, end;
  230                         int i;
  231 
  232                         if (sh->sig != SMBIOS_SIGNATURE)
  233                                 continue;
  234                         i = sh->len;
  235                         for (chksum = 0; i--; chksum += va[i])
  236                                 ;
  237                         if (chksum != 0)
  238                                 continue;
  239                         va += 0x10;
  240                         if (va[0] != '_' && va[1] != 'D' && va[2] != 'M' &&
  241                             va[3] != 'I' && va[4] != '_')
  242                                 continue;
  243                         for (chksum = 0, i = 0xf; i--; chksum += va[i]);
  244                                 ;
  245                         if (chksum != 0)
  246                                 continue;
  247 
  248                         pa = trunc_page(sh->addr);
  249                         end = round_page(sh->addr + sh->size);
  250                         eva = uvm_km_valloc(kernel_map, end-pa);
  251                         if (eva == 0)
  252                                 break;
  253 
  254                         smbios_entry.addr = (u_int8_t *)(eva +
  255                             (sh->addr & PGOFSET));
  256                         smbios_entry.len = sh->size;
  257                         smbios_entry.mjr = sh->majrev;
  258                         smbios_entry.min = sh->minrev;
  259                         smbios_entry.count = sh->count;
  260 
  261                         for (; pa < end; pa+= NBPG, eva+= NBPG)
  262                                 pmap_kenter_pa(eva, pa, VM_PROT_READ);
  263 
  264                         printf(", SMBIOS rev. %d.%d @ 0x%lx (%d entries)",
  265                             sh->majrev, sh->minrev, sh->addr, sh->count);
  266 
  267                         bios.cookie = 0;
  268                         if (smbios_find_table(SMBIOS_TYPE_BIOS, &bios)) {
  269                                 sb = bios.tblhdr;
  270                                 printf("\n%s:", sc->sc_dev.dv_xname);
  271 
  272                                 if ((smbios_get_string(&bios, sb->vendor,
  273                                     scratch, sizeof(scratch))) != NULL)
  274                                         printf(" vendor %s", scratch);
  275                                 if ((smbios_get_string(&bios, sb->version,
  276                                     scratch, sizeof(scratch))) != NULL)
  277                                         printf(" version \"%s\"", scratch);
  278                                 if ((smbios_get_string(&bios, sb->release,
  279                                     scratch, sizeof(scratch))) != NULL)
  280                                         printf(" date %s", scratch);
  281                         }
  282                         smbios_info(sc->sc_dev.dv_xname);
  283                         break;
  284                 }
  285         }
  286 
  287         printf("\n");
  288 
  289 #if NAPM > 0
  290         if (apm) {
  291                 struct bios_attach_args ba;
  292 #if defined(DEBUG) || defined(APMDEBUG)
  293                 printf("apminfo: %x, code %x[%x]/%x[%x], data %x[%x], ept %x\n",
  294                     apm->apm_detail,
  295                     apm->apm_code32_base, apm->apm_code_len,
  296                     apm->apm_code16_base, apm->apm_code16_len,
  297                     apm->apm_data_base, apm->apm_data_len, apm->apm_entry);
  298 #endif
  299                 ba.bios_dev = "apm";
  300                 ba.bios_func = 0x15;
  301                 ba.bios_memt = bia->bios_memt;
  302                 ba.bios_iot = bia->bios_iot;
  303                 ba.bios_apmp = apm;
  304                 config_found(self, &ba, bios_print);
  305         }
  306 #endif
  307 #if NPCI > 0 && NPCIBIOS > 0
  308         if (!(flags & BIOSF_PCIBIOS)) {
  309                 struct bios_attach_args ba;
  310 
  311                 ba.bios_dev = "pcibios";
  312                 ba.bios_func = 0x1A;
  313                 ba.bios_memt = bia->bios_memt;
  314                 ba.bios_iot = bia->bios_iot;
  315                 config_found(self, &ba, bios_print);
  316         }
  317 #endif
  318 
  319         /*
  320          * now that we gave 'em a chance to attach,
  321          * scan and map all the proms we can find
  322          */
  323         if (!(flags & BIOSF_PROMSCAN)) {
  324                 volatile u_int8_t *eva;
  325 
  326                 for (str = NULL, va = ISA_HOLE_VADDR(0xc0000),
  327                     eva = ISA_HOLE_VADDR(0xf0000);
  328                     va < eva; va += 512) {
  329                         extern struct extent *iomem_ex;
  330                         bios_romheader_t romh = (bios_romheader_t)va;
  331                         u_int32_t off, len;
  332                         u_int8_t cksum;
  333                         int i;
  334 
  335                         if (romh->signature != 0xaa55)
  336                                 continue;
  337 
  338                         /*
  339                          * for this and the next check we probably want
  340                          * to reserve the page in the extent anyway
  341                          */
  342                         if (!romh->len || romh->len == 0xff)
  343                                 continue;
  344 
  345                         len = romh->len * 512;
  346                         if (va + len > eva)
  347                                 continue;
  348 
  349                         for (cksum = 0, i = len; i--; cksum += va[i])
  350                                 ;
  351 #ifdef __stinkpad_sucks__
  352                         if (cksum != 0)
  353                                 continue;
  354 #endif
  355 
  356                         off = 0xc0000 + (va - (u_int8_t *)
  357                             ISA_HOLE_VADDR(0xc0000));
  358 
  359                         if (!str)
  360                                 printf("%s: ROM list:",
  361                                     str = sc->sc_dev.dv_xname);
  362                         printf(" 0x%05x/0x%x%s", off, len,
  363                             cksum? "!" : "");
  364 
  365                         if ((i = extent_alloc_region(iomem_ex,
  366                             (paddr_t)off, len, EX_NOWAIT)))
  367                                 printf(":%d", i);
  368 
  369                         va += len - 512;
  370                 }
  371         }
  372 
  373         if (str)
  374                 printf("\n");
  375 }
  376 
  377 void
  378 bios_getopt()
  379 {
  380         bootarg_t *q;
  381 
  382 #ifdef BIOS_DEBUG
  383         printf("bootargv:");
  384 #endif
  385 
  386         for(q = bootargp; q->ba_type != BOOTARG_END; q = q->ba_next) {
  387                 q->ba_next = (bootarg_t *)((caddr_t)q + q->ba_size);
  388                 switch (q->ba_type) {
  389                 case BOOTARG_MEMMAP:
  390                         bios_memmap = (bios_memmap_t *)q->ba_arg;
  391 #ifdef BIOS_DEBUG
  392                         printf(" memmap %p", bios_memmap);
  393 #endif
  394                         break;
  395                 case BOOTARG_DISKINFO:
  396                         bios_diskinfo = (bios_diskinfo_t *)q->ba_arg;
  397 #ifdef BIOS_DEBUG
  398                         printf(" diskinfo %p", bios_diskinfo);
  399 #endif
  400                         break;
  401 #if NAPM > 0 || defined(DEBUG)
  402                 case BOOTARG_APMINFO:
  403 #ifdef BIOS_DEBUG
  404                         printf(" apminfo %p", q->ba_arg);
  405 #endif
  406                         apm = (bios_apminfo_t *)q->ba_arg;
  407                         break;
  408 #endif
  409                 case BOOTARG_CKSUMLEN:
  410                         bios_cksumlen = *(u_int32_t *)q->ba_arg;
  411 #ifdef BIOS_DEBUG
  412                         printf(" cksumlen %d", bios_cksumlen);
  413 #endif
  414                         break;
  415 #if NPCI > 0
  416                 case BOOTARG_PCIINFO:
  417                         bios_pciinfo = (bios_pciinfo_t *)q->ba_arg;
  418 #ifdef BIOS_DEBUG
  419                         printf(" pciinfo %p", bios_pciinfo);
  420 #endif
  421                         break;
  422 #endif
  423                 case BOOTARG_CONSDEV:
  424                         if (q->ba_size >= sizeof(bios_consdev_t))
  425                         {
  426                                 bios_consdev_t *cdp = (bios_consdev_t*)q->ba_arg;
  427 #include "com.h"
  428 #include "pccom.h"
  429 #if NCOM + NPCCOM > 0
  430                                 extern int comdefaultrate; /* ic/com.c */
  431                                 comdefaultrate = cdp->conspeed;
  432 #endif
  433 #ifdef BIOS_DEBUG
  434                                 printf(" console 0x%x:%d",
  435                                     cdp->consdev, cdp->conspeed);
  436 #endif
  437                                 cnset(cdp->consdev);
  438                         }
  439                         break;
  440 #ifdef MULTIPROCESSOR
  441                 case BOOTARG_SMPINFO:
  442                         bios_smpinfo = q->ba_arg;
  443                         printf(" smpinfo %p", bios_smpinfo);
  444                         break;
  445 #endif
  446 
  447 #ifdef NFSCLIENT
  448                 case BOOTARG_BOOTMAC:
  449                         bios_bootmac = (bios_bootmac_t *)q->ba_arg;
  450                         break;
  451 #endif
  452 
  453                 default:
  454 #ifdef BIOS_DEBUG
  455                         printf(" unsupported arg (%d) %p", q->ba_type,
  456                             q->ba_arg);
  457 #endif
  458                         break;
  459                 }
  460         }
  461         printf("\n");
  462 
  463 }
  464 
  465 int
  466 bios_print(void *aux, const char *pnp)
  467 {
  468         struct bios_attach_args *ba = aux;
  469 
  470         if (pnp)
  471                 printf("%s at %s function 0x%x",
  472                     ba->bios_dev, pnp, ba->bios_func);
  473         return (UNCONF);
  474 }
  475 
  476 int
  477 bios32_service(u_int32_t service, bios32_entry_t e, bios32_entry_info_t ei)
  478 {
  479         u_long pa, endpa;
  480         vaddr_t va, sva;
  481         u_int32_t base, count, off, ent;
  482         int slot;
  483 
  484         if (bios32_entry.offset == 0)
  485                 return 0;
  486 
  487         base = 0;
  488         __asm __volatile("lcall *(%4)"
  489             : "+a" (service), "+b" (base), "=c" (count), "=d" (off)
  490             : "D" (&bios32_entry)
  491             : "%esi", "cc", "memory");
  492 
  493         if (service & 0xff)
  494                 return 0;       /* not found */
  495 
  496         ent = base + off;
  497         if (ent <= BIOS32_START || ent >= BIOS32_END)
  498                 return 0;
  499 
  500 
  501         endpa = round_page(BIOS32_END);
  502 
  503         sva = va = uvm_km_valloc(kernel_map, endpa);
  504         if (va == 0)
  505                 return (0);
  506 
  507         slot = gdt_get_slot();
  508         setgdt(slot, (caddr_t)va, BIOS32_END, SDT_MEMERA, SEL_KPL, 1, 0);
  509 
  510         for (pa = trunc_page(BIOS32_START),
  511             va += trunc_page(BIOS32_START);
  512             pa < endpa; pa += NBPG, va += NBPG) {
  513                 pmap_enter(pmap_kernel(), va, pa,
  514                     VM_PROT_READ | VM_PROT_WRITE,
  515                     VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
  516 
  517                 /* for all you, broken hearted */
  518                 if (pa >= trunc_page(base)) {
  519                         pmap_enter(pmap_kernel(), sva, pa,
  520                             VM_PROT_READ | VM_PROT_WRITE,
  521                             VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
  522                         sva += NBPG;
  523                 }
  524         }
  525 
  526         e->segment = GSEL(slot, SEL_KPL);
  527         e->offset = (vaddr_t)ent;
  528 
  529         ei->bei_base = base;
  530         ei->bei_size = count;
  531         ei->bei_entry = ent;
  532 
  533         return 1;
  534 }
  535 
  536 int
  537 biosopen(dev_t dev, int flag, int mode, struct proc *p)
  538 {
  539         struct bios_softc *sc = bios_cd.cd_devs[0];
  540 
  541         if (minor(dev))
  542                 return (ENXIO);
  543 
  544         (void)sc;
  545 
  546         return 0;
  547 }
  548 
  549 int
  550 biosclose(dev_t dev, int flag, int mode, struct proc *p)
  551 {
  552         struct bios_softc *sc = bios_cd.cd_devs[0];
  553 
  554         if (minor(dev))
  555                 return (ENXIO);
  556 
  557         (void)sc;
  558 
  559         return 0;
  560 }
  561 
  562 int
  563 biosioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  564 {
  565         struct bios_softc *sc = bios_cd.cd_devs[0];
  566 
  567         if (minor(dev))
  568                 return (ENXIO);
  569 
  570         switch (cmd) {
  571         default:
  572                 return ENXIO;
  573         }
  574 
  575         (void)sc;
  576 
  577         return 0;
  578 }
  579 
  580 void
  581 bioscnprobe(struct consdev *cn)
  582 {
  583 #if 0
  584         bios_init(I386_BUS_SPACE_MEM); /* XXX */
  585         if (!bios_cd.cd_ndevs)
  586                 return;
  587 
  588         if (0 && bios_call(BOOTC_CHECK, NULL))
  589                 return;
  590 
  591         cn->cn_pri = CN_NORMAL;
  592         cn->cn_dev = makedev(48, 0);
  593 #endif
  594 }
  595 
  596 void
  597 bioscninit(struct consdev *cn)
  598 {
  599 
  600 }
  601 
  602 void
  603 bioscnputc(dev_t dev, int ch)
  604 {
  605 
  606 }
  607 
  608 int
  609 bioscngetc(dev_t dev)
  610 {
  611         return -1;
  612 }
  613 
  614 void
  615 bioscnpollc(dev_t dev, int on)
  616 {
  617 }
  618 
  619 int
  620 bios_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
  621     size_t newlen, struct proc *p)
  622 {
  623         bios_diskinfo_t *pdi;
  624         int biosdev;
  625 
  626         /* all sysctl names at this level except diskinfo are terminal */
  627         if (namelen != 1 && name[0] != BIOS_DISKINFO)
  628                 return (ENOTDIR);               /* overloaded */
  629 
  630         if (!(bootapiver & BAPIV_VECTOR))
  631                 return EOPNOTSUPP;
  632 
  633         switch (name[0]) {
  634         case BIOS_DEV:
  635                 if ((pdi = bios_getdiskinfo(bootdev)) == NULL)
  636                         return ENXIO;
  637                 biosdev = pdi->bios_number;
  638                 return sysctl_rdint(oldp, oldlenp, newp, biosdev);
  639         case BIOS_DISKINFO:
  640                 if (namelen != 2)
  641                         return ENOTDIR;
  642                 if ((pdi = bios_getdiskinfo(name[1])) == NULL)
  643                         return ENXIO;
  644                 return sysctl_rdstruct(oldp, oldlenp, newp, pdi, sizeof(*pdi));
  645         case BIOS_CKSUMLEN:
  646                 return sysctl_rdint(oldp, oldlenp, newp, bios_cksumlen);
  647         default:
  648                 return EOPNOTSUPP;
  649         }
  650         /* NOTREACHED */
  651 }
  652 
  653 bios_diskinfo_t *
  654 bios_getdiskinfo(dev_t dev)
  655 {
  656         bios_diskinfo_t *pdi;
  657 
  658         if (bios_diskinfo == NULL)
  659                 return NULL;
  660 
  661         for (pdi = bios_diskinfo; pdi->bios_number != -1; pdi++) {
  662                 if ((dev & B_MAGICMASK) == B_DEVMAGIC) { /* search by bootdev */
  663                         if (pdi->bsd_dev == dev)
  664                                 break;
  665                 } else {
  666                         if (pdi->bios_number == dev)
  667                                 break;
  668                 }
  669         }
  670 
  671         if (pdi->bios_number == -1)
  672                 return NULL;
  673         else
  674                 return pdi;
  675 }
  676 
  677 /*
  678  * smbios_find_table() takes a caller supplied smbios struct type and
  679  * a pointer to a handle (struct smbtable) returning one if the structure
  680  * is sucessfully located and zero otherwise. Callers should take care
  681  * to initialize the cookie field of the smbtable structure to zero before
  682  * the first invocation of this function.
  683  * Multiple tables of the same type can be located by repeatedly calling
  684  * smbios_find_table with the same arguments.
  685  */
  686 int
  687 smbios_find_table(u_int8_t type, struct smbtable *st)
  688 {
  689         u_int8_t *va, *end;
  690         struct smbtblhdr *hdr;
  691         int ret = 0, tcount = 1;
  692 
  693         va = smbios_entry.addr;
  694         end = va + smbios_entry.len;
  695 
  696         /*
  697          * The cookie field of the smtable structure is used to locate
  698          * multiple instances of a table of an arbitrary type. Following the
  699          * sucessful location of a table, the type is encoded as bits 0:7 of
  700          * the cookie value, the offset in terms of the number of structures
  701          * preceding that referenced by the handle is encoded in bits 15:31.
  702          */
  703         if ((st->cookie & 0xfff) == type && st->cookie >> 16) {
  704                 if ((u_int8_t *)st->hdr >= va && (u_int8_t *)st->hdr < end) {
  705                         hdr = st->hdr;
  706                         if (hdr->type == type) {
  707                                 va = (u_int8_t *)hdr + hdr->size;
  708                                 for (; va + 1 < end; va++)
  709                                         if (*va == NULL && *(va + 1) == NULL)
  710                                                 break;
  711                                 va+= 2;
  712                                 tcount = st->cookie >> 16;
  713                         }
  714                 }
  715         }
  716         for (; va + sizeof(struct smbtblhdr) < end && tcount <=
  717             smbios_entry.count; tcount++) {
  718                 hdr = (struct smbtblhdr *)va;
  719                 if (hdr->type == type) {
  720                         ret = 1;
  721                         st->hdr = hdr;
  722                         st->tblhdr = va + sizeof(struct smbtblhdr);
  723                         st->cookie = (tcount + 1) << 16 | type;
  724                         break;
  725                 }
  726                 if (hdr->type == SMBIOS_TYPE_EOT)
  727                         break;
  728                 va+= hdr->size;
  729                 for (; va + 1 < end; va++)
  730                         if (*va == NULL && *(va + 1) == NULL)
  731                                 break;
  732                 va+=2;
  733         }
  734 
  735         return ret;
  736 }
  737 
  738 char *
  739 smbios_get_string(struct smbtable *st, u_int8_t indx, char *dest, size_t len)
  740 {
  741         u_int8_t *va, *end;
  742         char *ret = NULL;
  743         int i;
  744 
  745         va = (u_int8_t *)st->hdr + st->hdr->size;
  746         end = smbios_entry.addr + smbios_entry.len;
  747         for (i = 1; va < end && i < indx && *va; i++)
  748                 while (*va++)
  749                         ;
  750         if (i == indx) {
  751                 if (va + len < end) {
  752                         ret = dest;
  753                         bcopy(va, ret, len);
  754                         ret[len - 1] = '\0';
  755                 }
  756         }
  757 
  758         return ret;
  759 }
  760 
  761 char *
  762 fixstring(char *s)
  763 {
  764         char *p, *e;
  765         int i;
  766 
  767         for (i= 0; i < sizeof(smbios_uninfo)/sizeof(smbios_uninfo[0]); i++)
  768                 if ((strncasecmp(s, smbios_uninfo[i], strlen(smbios_uninfo[i])))==0)
  769                         return NULL;
  770         /*
  771          * Remove leading and trailing whitespace
  772          */
  773         for (p = s; *p == ' '; p++)
  774                 ;
  775         /*
  776          * Special case entire string is whitespace
  777          */
  778         if (p == s + strlen(s))
  779                 return NULL;
  780         for (e = s + strlen(s) - 1; e > s && *e == ' '; e--)
  781                 ;
  782         if (p > s || e < s + strlen(s) - 1) {
  783                 bcopy(p, s, e-p + 1);
  784                 s[e - p + 1] = '\0';
  785         }
  786 
  787         return s;
  788 }
  789 
  790 void
  791 smbios_info(char * str)
  792 {
  793         char *sminfop, sminfo[64];
  794         struct smbtable stbl, btbl;
  795         struct smbios_sys *sys;
  796         struct smbios_board *board;
  797         int i, infolen, uuidf, havebb;
  798         char *p;
  799 
  800         if (smbios_entry.mjr < 2)
  801                 return;
  802         /*
  803          * According to the spec the system table among others is required,
  804          * if it is not we do not bother with this smbios implementation.
  805          */
  806         stbl.cookie = btbl.cookie = 0;
  807         if (!smbios_find_table(SMBIOS_TYPE_SYSTEM, &stbl))
  808                 return;
  809         havebb = smbios_find_table(SMBIOS_TYPE_BASEBOARD, &btbl);
  810 
  811         sys = (struct smbios_sys *)stbl.tblhdr;
  812         if (havebb)
  813                 board = (struct smbios_board *)btbl.tblhdr;
  814         /*
  815          * Some smbios implementations have no system vendor or product strings,
  816          * some have very uninformative data which is harder to work around
  817          * and we must rely upon various heuristics to detect this. In both
  818          * cases we attempt to fall back on the base board information in the
  819          * perhaps naive belief that motherboard vendors will supply this
  820          * information.
  821          */
  822         sminfop = NULL;
  823         if ((p = smbios_get_string(&stbl, sys->vendor, sminfo,
  824             sizeof(sminfo))) != NULL)
  825                 sminfop = fixstring(p);
  826         if (sminfop == NULL) {
  827                 if (havebb) {
  828                         if ((p = smbios_get_string(&btbl, board->vendor,
  829                             sminfo, sizeof(sminfo))) != NULL)
  830                                 sminfop = fixstring(p);
  831                 }
  832         }
  833         if (sminfop) {
  834                 infolen = strlen(sminfop) + 1;
  835                 hw_vendor = malloc(infolen, M_DEVBUF, M_NOWAIT);
  836                 if (hw_vendor)
  837                         strlcpy(hw_vendor, sminfop, infolen);
  838                 sminfop = NULL;
  839         }
  840         if ((p = smbios_get_string(&stbl, sys->product, sminfo,
  841             sizeof(sminfo))) != NULL)
  842                 sminfop = fixstring(p);
  843         if (sminfop == NULL) {
  844                 if (havebb) {
  845                         if ((p = smbios_get_string(&btbl, board->product,
  846                             sminfo, sizeof(sminfo))) != NULL)
  847                                 sminfop = fixstring(p);
  848                 }
  849         }
  850         if (sminfop) {
  851                 infolen = strlen(sminfop) + 1;
  852                 hw_prod = malloc(infolen, M_DEVBUF, M_NOWAIT);
  853                 if (hw_prod)
  854                         strlcpy(hw_prod, sminfop, infolen);
  855                 sminfop = NULL;
  856         }
  857         if (hw_vendor != NULL && hw_prod != NULL)
  858                 printf("\n%s: %s %s", str, hw_vendor, hw_prod);
  859         if ((p = smbios_get_string(&stbl, sys->version, sminfo,
  860             sizeof(sminfo))) != NULL)
  861                 sminfop = fixstring(p);
  862         if (sminfop) {
  863                 infolen = strlen(sminfop) + 1;
  864                 hw_ver = malloc(infolen, M_DEVBUF, M_NOWAIT);
  865                 if (hw_ver)
  866                         strlcpy(hw_ver, sminfop, infolen);
  867                 sminfop = NULL;
  868         }
  869         if ((p = smbios_get_string(&stbl, sys->serial, sminfo,
  870             sizeof(sminfo))) != NULL)
  871                 sminfop = fixstring(p);
  872         if (sminfop) {
  873                 infolen = strlen(sminfop) + 1;
  874                 hw_serial = malloc(infolen, M_DEVBUF, M_NOWAIT);
  875                 if (hw_serial)
  876                         strlcpy(hw_serial, sminfop, infolen);
  877         }
  878         if (smbios_entry.mjr > 2 || (smbios_entry.mjr == 2 &&
  879             smbios_entry.min >= 1)) {
  880                 /*
  881                  * If the uuid value is all 0xff the uuid is present but not
  882                  * set, if its all 0 then the uuid isn't present at all.
  883                  */
  884                 uuidf |= SMBIOS_UUID_NPRESENT|SMBIOS_UUID_NSET;
  885                 for (i = 0; i < sizeof(sys->uuid); i++) {
  886                         if (sys->uuid[i] != 0xff)
  887                                 uuidf &= ~SMBIOS_UUID_NSET;
  888                         if (sys->uuid[i] != 0)
  889                                 uuidf &= ~SMBIOS_UUID_NPRESENT;
  890                 }
  891 
  892                 if (uuidf & SMBIOS_UUID_NPRESENT)
  893                         hw_uuid = NULL;
  894                 else if (uuidf & SMBIOS_UUID_NSET)
  895                         hw_uuid = "Not Set";
  896                 else {
  897                         hw_uuid = malloc(SMBIOS_UUID_REPLEN, M_DEVBUF,
  898                             M_NOWAIT);
  899                         if (hw_uuid) {
  900                                 snprintf(hw_uuid, SMBIOS_UUID_REPLEN,
  901                                     SMBIOS_UUID_REP,
  902                                     sys->uuid[0], sys->uuid[1], sys->uuid[2],
  903                                     sys->uuid[3], sys->uuid[4], sys->uuid[5],
  904                                     sys->uuid[6], sys->uuid[7], sys->uuid[8],
  905                                     sys->uuid[9], sys->uuid[10], sys->uuid[11],
  906                                     sys->uuid[12], sys->uuid[13], sys->uuid[14],
  907                                     sys->uuid[15]);
  908                         }
  909                 }
  910         }
  911 }

/* [<][>][^][v][top][bottom][index][help] */