"Fossies" - the Fresh Open Source Software Archive

Member "dmidecode-3.2/biosdecode.c" (14 Sep 2018, 16145 Bytes) of package /linux/privat/dmidecode-3.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "biosdecode.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.1_vs_3.2.

    1 /*
    2  * BIOS Decode
    3  *
    4  *   Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
    5  *   Copyright (C) 2002-2017 Jean Delvare <jdelvare@suse.de>
    6  *
    7  *   This program is free software; you can redistribute it and/or modify
    8  *   it under the terms of the GNU General Public License as published by
    9  *   the Free Software Foundation; either version 2 of the License, or
   10  *   (at your option) any later version.
   11  *
   12  *   This program is distributed in the hope that it will be useful,
   13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  *   GNU General Public License for more details.
   16  *
   17  *   You should have received a copy of the GNU General Public License
   18  *   along with this program; if not, write to the Free Software
   19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   20  *
   21  *   For the avoidance of doubt the "preferred form" of this code is one which
   22  *   is in an open unpatent encumbered format. Where cryptographic key signing
   23  *   forms part of the process of creating an executable the information
   24  *   including keys needed to generate an equivalently functional executable
   25  *   are deemed to be part of the source code.
   26  *
   27  * References:
   28  *  - DMTF "System Management BIOS (SMBIOS) Reference Specification"
   29  *    Version 3.0.0
   30  *    http://www.dmtf.org/standards/smbios
   31  *  - Intel "Preboot Execution Environment (PXE) Specification"
   32  *    Version 2.1
   33  *    http://www.intel.com/labs/manage/wfm/wfmspecs.htm
   34  *  - ACPI "Advanced Configuration and Power Interface Specification"
   35  *    Revision 2.0
   36  *    http://www.acpi.info/spec20.htm
   37  *  - Phoenix "BIOS32 Service Directory"
   38  *    Revision 0.4
   39  *    http://www.phoenix.com/en/support/white+papers-specs/
   40  *  - Microsoft "Plug and Play BIOS Specification"
   41  *    Version 1.0A
   42  *    http://www.microsoft.com/hwdev/tech/PnP/
   43  *  - Microsoft "PCI IRQ Routing Table Specification"
   44  *    Version 1.0
   45  *    http://www.microsoft.com/hwdev/archive/BUSBIOS/pciirq.asp
   46  *  - Compaq "Technical Reference Guide for Compaq Deskpro 4000 and 6000"
   47  *    First Edition
   48  *    http://h18000.www1.hp.com/support/techpubs/technical_reference_guides/113a1097.html
   49  *  - IBM "Using the BIOS Build ID to identify Thinkpad systems"
   50  *    Revision 2005-09-19
   51  *    http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
   52  *  - Fujitsu application panel technical details
   53  *    As of July 23rd, 2004
   54  *    http://apanel.sourceforge.net/tech.php
   55  *  - Intel Multiprocessor Specification
   56  *    Version 1.4
   57  *    http://www.intel.com/design/archives/processors/pro/docs/242016.htm
   58  */
   59 
   60 #include <stdio.h>
   61 #include <string.h>
   62 #include <stdlib.h>
   63 #include <unistd.h>
   64 #include <getopt.h>
   65 
   66 #include "version.h"
   67 #include "config.h"
   68 #include "types.h"
   69 #include "util.h"
   70 
   71 /* Options are global */
   72 struct opt
   73 {
   74     const char *devmem;
   75     unsigned int flags;
   76     unsigned char pir;
   77 };
   78 static struct opt opt;
   79 
   80 #define FLAG_VERSION            (1 << 0)
   81 #define FLAG_HELP               (1 << 1)
   82 
   83 #define PIR_SHORT               0
   84 #define PIR_FULL                1
   85 
   86 struct bios_entry {
   87     const char *anchor;
   88     size_t anchor_len; /* computed */
   89     off_t low_address;
   90     off_t high_address;
   91     size_t (*length)(const u8 *);
   92     int (*decode)(const u8*, size_t);
   93 };
   94 
   95 
   96 /*
   97  * SMBIOS
   98  */
   99 
  100 static size_t smbios3_length(const u8 *p)
  101 {
  102     return p[0x06];
  103 }
  104 
  105 static int smbios3_decode(const u8 *p, size_t len)
  106 {
  107     if (len < 0x18 || !checksum(p, p[0x06]))
  108         return 0;
  109 
  110     printf("SMBIOS %u.%u.%u present.\n",
  111         p[0x07], p[0x08], p[0x09]);
  112     printf("\tStructure Table Maximum Length: %u bytes\n",
  113         DWORD(p + 0x0C));
  114     printf("\tStructure Table 64-bit Address: 0x%08X%08X\n",
  115         QWORD(p + 0x10).h, QWORD(p + 0x10).l);
  116 
  117     return 1;
  118 }
  119 
  120 static size_t smbios_length(const u8 *p)
  121 {
  122     return p[0x05] == 0x1E ? 0x1F : p[0x05];
  123 }
  124 
  125 static int smbios_decode(const u8 *p, size_t len)
  126 {
  127     if (len < 0x1F || !checksum(p, p[0x05])
  128      || memcmp("_DMI_", p + 0x10, 5) != 0
  129      || !checksum(p + 0x10, 0x0F))
  130         return 0;
  131 
  132     printf("SMBIOS %u.%u present.\n",
  133         p[0x06], p[0x07]);
  134     printf("\tStructure Table Length: %u bytes\n",
  135         WORD(p + 0x16));
  136     printf("\tStructure Table Address: 0x%08X\n",
  137         DWORD(p + 0x18));
  138     printf("\tNumber Of Structures: %u\n",
  139         WORD(p + 0x1C));
  140     printf("\tMaximum Structure Size: %u bytes\n",
  141         WORD(p + 0x08));
  142 
  143     return 1;
  144 }
  145 
  146 static size_t dmi_length(const u8 *p)
  147 {
  148     (void) p;
  149 
  150     return 0x0F;
  151 }
  152 
  153 static int dmi_decode(const u8 *p, size_t len)
  154 {
  155     if (len < 0x0F || !checksum(p, len))
  156         return 0;
  157 
  158     printf("Legacy DMI %u.%u present.\n",
  159         p[0x0E]>>4, p[0x0E] & 0x0F);
  160     printf("\tStructure Table Length: %u bytes\n",
  161         WORD(p + 0x06));
  162     printf("\tStructure Table Address: 0x%08X\n",
  163         DWORD(p + 0x08));
  164     printf("\tNumber Of Structures: %u\n",
  165         WORD(p + 0x0C));
  166 
  167     return 1;
  168 }
  169 
  170 /*
  171  * SYSID
  172  */
  173 
  174 static size_t sysid_length(const u8 *p)
  175 {
  176     return WORD(p + 0x08);
  177 }
  178 
  179 static int sysid_decode(const u8 *p, size_t len)
  180 {
  181     if (len < 0x11 || !checksum(p, WORD(p + 0x08)))
  182         return 0;
  183 
  184     printf("SYSID present.\n");
  185     printf("\tRevision: %u\n",
  186         p[0x10]);
  187     printf("\tStructure Table Address: 0x%08X\n",
  188         DWORD(p + 0x0A));
  189     printf("\tNumber Of Structures: %u\n",
  190         WORD(p + 0x0E));
  191 
  192     return 1;
  193 }
  194 
  195 /*
  196  * PnP
  197  */
  198 
  199 static size_t pnp_length(const u8 *p)
  200 {
  201     return p[0x05];
  202 }
  203 
  204 static const char *pnp_event_notification(u8 code)
  205 {
  206     static const char *notification[] = {
  207         "Not Supported", /* 0x0 */
  208         "Polling",
  209         "Asynchronous",
  210         "Unknown" /* 0x3 */
  211     };
  212 
  213     return notification[code];
  214 }
  215 
  216 static int pnp_decode(const u8 *p, size_t len)
  217 {
  218     if (len < 0x21 || !checksum(p, p[0x05]))
  219         return 0;
  220 
  221     printf("PNP BIOS %u.%u present.\n",
  222         p[0x04] >> 4, p[0x04] & 0x0F);
  223     printf("\tEvent Notification: %s\n",
  224         pnp_event_notification(WORD(p + 0x06) & 0x03));
  225     if ((WORD(p + 0x06) & 0x03) == 0x01)
  226         printf("\tEvent Notification Flag Address: 0x%08X\n",
  227             DWORD(p + 0x09));
  228     printf("\tReal Mode 16-bit Code Address: %04X:%04X\n",
  229         WORD(p + 0x0F), WORD(p + 0x0D));
  230     printf("\tReal Mode 16-bit Data Address: %04X:0000\n",
  231         WORD(p + 0x1B));
  232     printf("\t16-bit Protected Mode Code Address: 0x%08X\n",
  233         DWORD(p + 0x13) + WORD(p + 0x11));
  234     printf("\t16-bit Protected Mode Data Address: 0x%08X\n",
  235         DWORD(p + 0x1D));
  236     if (DWORD(p + 0x17) != 0)
  237         printf("\tOEM Device Identifier: %c%c%c%02X%02X\n",
  238             0x40 + ((p[0x17] >> 2) & 0x1F),
  239             0x40 + ((p[0x17] & 0x03) << 3) + ((p[0x18] >> 5) & 0x07),
  240             0x40 + (p[0x18] & 0x1F), p[0x19], p[0x20]);
  241 
  242     return 1;
  243 }
  244 
  245 /*
  246  * ACPI
  247  */
  248 
  249 static size_t acpi_length(const u8 *p)
  250 {
  251     return p[15] == 2 ? 36 : 20;
  252 }
  253 
  254 static const char *acpi_revision(u8 code)
  255 {
  256     switch (code)
  257     {
  258         case 0:
  259             return " 1.0";
  260         case 2:
  261             return " 2.0";
  262         default:
  263             return "";
  264     }
  265 }
  266 
  267 static int acpi_decode(const u8 *p, size_t len)
  268 {
  269     if (len < 20 || !checksum(p, 20))
  270         return 0;
  271 
  272     printf("ACPI%s present.\n",
  273         acpi_revision(p[15]));
  274     printf("\tOEM Identifier: %c%c%c%c%c%c\n",
  275         p[9], p[10], p[11], p[12], p[13], p[14]);
  276     printf("\tRSD Table 32-bit Address: 0x%08X\n",
  277         DWORD(p + 16));
  278 
  279     if (len < 36)
  280         return 1;
  281 
  282     if (DWORD(p + 20) > len || !checksum(p, DWORD(p + 20)))
  283         return 0;
  284 
  285     if (DWORD(p + 20) < 32) return 1;
  286 
  287     printf("\tXSD Table 64-bit Address: 0x%08X%08X\n",
  288         QWORD(p + 24).h, QWORD(p + 24).l);
  289 
  290     return 1;
  291 }
  292 
  293 /*
  294  * Sony
  295  */
  296 
  297 static size_t sony_length(const u8 *p)
  298 {
  299     return p[0x05];
  300 }
  301 
  302 static int sony_decode(const u8 *p, size_t len)
  303 {
  304     if (!checksum(p, len))
  305         return 0;
  306 
  307     printf("Sony system detected.\n");
  308 
  309     return 1;
  310 }
  311 
  312 /*
  313  * BIOS32
  314  */
  315 
  316 static size_t bios32_length(const u8 *p)
  317 {
  318     return p[0x09] << 4;
  319 }
  320 
  321 static int bios32_decode(const u8 *p, size_t len)
  322 {
  323     if (len < 0x0A || !checksum(p, p[0x09] << 4))
  324         return 0;
  325 
  326     printf("BIOS32 Service Directory present.\n");
  327     printf("\tRevision: %u\n",
  328         p[0x08]);
  329     printf("\tCalling Interface Address: 0x%08X\n",
  330         DWORD(p + 0x04));
  331 
  332     return 1;
  333 }
  334 
  335 /*
  336  * PIR
  337  */
  338 
  339 static void pir_irqs(u16 code)
  340 {
  341     if (code == 0)
  342         printf(" None");
  343     else
  344     {
  345         u8 i;
  346 
  347         for (i = 0; i < 16; i++)
  348             if (code & (1 << i))
  349                 printf(" %u", i);
  350     }
  351 }
  352 
  353 static void pir_slot_number(u8 code)
  354 {
  355     if (code == 0)
  356         printf(" on-board");
  357     else
  358         printf(" slot %u", code);
  359 }
  360 
  361 static size_t pir_length(const u8 *p)
  362 {
  363     return WORD(p + 6);
  364 }
  365 
  366 static void pir_link_bitmap(char letter, const u8 *p)
  367 {
  368     if (p[0] == 0) /* Not connected */
  369         return;
  370 
  371     printf("\t\tINT%c#: Link 0x%02x, IRQ Bitmap", letter, p[0]);
  372     pir_irqs(WORD(p + 1));
  373     printf("\n");
  374 }
  375 
  376 static int pir_decode(const u8 *p, size_t len)
  377 {
  378     int i, n;
  379 
  380     if (len < 32 || !checksum(p, WORD(p + 6)))
  381         return 0;
  382 
  383     printf("PCI Interrupt Routing %u.%u present.\n",
  384         p[5], p[4]);
  385     printf("\tRouter Device: %02x:%02x.%1x\n",
  386         p[8], p[9]>>3, p[9] & 0x07);
  387     printf("\tExclusive IRQs:");
  388     pir_irqs(WORD(p + 10));
  389     printf("\n");
  390     if (DWORD(p + 12) != 0)
  391         printf("\tCompatible Router: %04x:%04x\n",
  392             WORD(p + 12), WORD(p + 14));
  393     if (DWORD(p + 16) != 0)
  394         printf("\tMiniport Data: 0x%08X\n",
  395             DWORD(p + 16));
  396 
  397     n = (len - 32) / 16;
  398     for (i = 1, p += 32; i <= n; i++, p += 16)
  399     {
  400         printf("\tDevice: %02x:%02x,", p[0], p[1] >> 3);
  401         pir_slot_number(p[14]);
  402         printf("\n");
  403         if (opt.pir == PIR_FULL)
  404         {
  405             pir_link_bitmap('A', p + 2);
  406             pir_link_bitmap('B', p + 5);
  407             pir_link_bitmap('C', p + 8);
  408             pir_link_bitmap('D', p + 11);
  409         }
  410     }
  411 
  412     return 1;
  413 }
  414 
  415 /*
  416  * Compaq-specific entries
  417  */
  418 
  419 static size_t compaq_length(const u8 *p)
  420 {
  421     return p[4] * 10 + 5;
  422 }
  423 
  424 static int compaq_decode(const u8 *p, size_t len)
  425 {
  426     unsigned int i;
  427     (void) len;
  428 
  429     printf("Compaq-specific entries present.\n");
  430 
  431     /* integrity checking (lack of checksum) */
  432     for (i = 0; i < p[4]; i++)
  433     {
  434         /*
  435          * We do not check for truncated entries, because the length
  436          * was computed from the number of records in compaq_length
  437          * right above, so it can't be wrong.
  438          */
  439         if (p[5 + i * 10] != '$'
  440          || !(p[6 + i * 10] >= 'A' && p[6 + i * 10] <= 'Z')
  441          || !(p[7 + i * 10] >= 'A' && p[7 + i * 10] <= 'Z')
  442          || !(p[8 + i * 10] >= 'A' && p[8 + i * 10] <= 'Z'))
  443         {
  444             printf("\t Abnormal entry! Please report. [%02X %02X "
  445                 "%02X %02X]\n", p[5 + i * 10], p[6 + i * 10],
  446                 p[7 + i * 10], p[8 + i * 10]);
  447             return 0;
  448         }
  449     }
  450 
  451     for (i = 0; i < p[4]; i++)
  452     {
  453         printf("\tEntry %u: %c%c%c%c at 0x%08X (%u bytes)\n",
  454             i + 1, p[5 + i * 10], p[6 + i * 10], p[7 + i * 10],
  455             p[8 + i * 10], DWORD(p + 9 + i * 10),
  456             WORD(p + 13 + i * 10));
  457     }
  458 
  459     return 1;
  460 }
  461 
  462 /*
  463  * VPD (vital product data, IBM-specific)
  464  */
  465 
  466 static void vpd_print_entry(const char *name, const u8 *p, size_t len)
  467 {
  468     size_t i;
  469 
  470     printf("\t%s: ", name);
  471     for (i = 0; i < len; i++)
  472         if (p[i] >= 32 && p[i] < 127)
  473             printf("%c", p[i]);
  474     printf("\n");
  475 }
  476 
  477 static size_t vpd_length(const u8 *p)
  478 {
  479     return p[5];
  480 }
  481 
  482 static int vpd_decode(const u8 *p, size_t len)
  483 {
  484     if (len < 0x30)
  485         return 0;
  486 
  487     /* XSeries have longer records. */
  488     if (!(len >= 0x45 && checksum(p, len))
  489     /* Some Netvista seem to work with this. */
  490      && !checksum(p, 0x30)
  491     /* The Thinkpad checksum does *not* include the first 13 bytes. */
  492      && !checksum(p + 0x0D, 0x30 - 0x0D))
  493         return 0;
  494 
  495     printf("VPD present.\n");
  496 
  497     vpd_print_entry("BIOS Build ID", p + 0x0D, 9);
  498     vpd_print_entry("Box Serial Number", p + 0x16, 7);
  499     vpd_print_entry("Motherboard Serial Number", p + 0x1D, 11);
  500     vpd_print_entry("Machine Type/Model", p + 0x28, 7);
  501 
  502     if (len < 0x45)
  503         return 1;
  504 
  505     vpd_print_entry("BIOS Release Date", p + 0x30, 8);
  506 
  507     return 1;
  508 }
  509 
  510 /*
  511  * Fujitsu application panel
  512  */
  513 
  514 static size_t fjkeyinf_length(const u8 *p)
  515 {
  516     (void) p;
  517     /*
  518      * We don't know at this point, it's somewhere between 12 and 32.
  519      * So we return the max, it shouldn't hurt.
  520      */
  521     return 32;
  522 }
  523 
  524 static int fjkeyinf_decode(const u8 *p, size_t len)
  525 {
  526     int i;
  527     (void) len;
  528 
  529     printf("Fujitsu application panel present.\n");
  530 
  531     for (i = 0; i < 6; i++)
  532     {
  533         if (*(p + 8 + i * 4) == 0)
  534             return 1;
  535         printf("\tDevice %d: type %u, chip %u", i + 1,
  536                *(p + 8 + i * 4), *(p + 8 + i * 4 + 2));
  537         if (*(p + 8 + i * 4 + 1)) /* Access method */
  538             printf(", SMBus address 0x%x",
  539                 *(p + 8 + i * 4 + 3) >> 1);
  540         printf("\n");
  541     }
  542 
  543     return 1;
  544 }
  545 
  546 /*
  547  * Intel Multiprocessor
  548  */
  549 
  550 static size_t mp_length(const u8 *p)
  551 {
  552     return 16 * p[8];
  553 }
  554 
  555 static int mp_decode(const u8 *p, size_t len)
  556 {
  557     if (!checksum(p, len))
  558         return 0;
  559 
  560     printf("Intel Multiprocessor present.\n");
  561     printf("\tSpecification Revision: %s\n",
  562         p[9] == 0x01 ? "1.1" : p[9] == 0x04 ? "1.4" : "Invalid");
  563     if (p[11])
  564         printf("\tDefault Configuration: #%d\n", p[11]);
  565     else
  566         printf("\tConfiguration Table Address: 0x%08X\n",
  567             DWORD(p + 4));
  568     printf("\tMode: %s\n", p[12] & (1 << 7) ?
  569         "IMCR and PIC" : "Virtual Wire");
  570 
  571     return 1;
  572 }
  573 
  574 /*
  575  * Main
  576  */
  577 
  578 static struct bios_entry bios_entries[] = {
  579     { "_SM3_", 0, 0xF0000, 0xFFFFF, smbios3_length, smbios3_decode },
  580     { "_SM_", 0, 0xF0000, 0xFFFFF, smbios_length, smbios_decode },
  581     { "_DMI_", 0, 0xF0000, 0xFFFFF, dmi_length, dmi_decode },
  582     { "_SYSID_", 0, 0xE0000, 0xFFFFF, sysid_length, sysid_decode },
  583     { "$PnP", 0, 0xF0000, 0xFFFFF, pnp_length, pnp_decode },
  584     { "RSD PTR ", 0, 0xE0000, 0xFFFFF, acpi_length, acpi_decode },
  585     { "$SNY", 0, 0xE0000, 0xFFFFF, sony_length, sony_decode },
  586     { "_32_", 0, 0xE0000, 0xFFFFF, bios32_length, bios32_decode },
  587     { "$PIR", 0, 0xF0000, 0xFFFFF, pir_length, pir_decode },
  588     { "32OS", 0, 0xE0000, 0xFFFFF, compaq_length, compaq_decode },
  589     { "\252\125VPD", 0, 0xF0000, 0xFFFFF, vpd_length, vpd_decode },
  590     { "FJKEYINF", 0, 0xF0000, 0xFFFFF, fjkeyinf_length, fjkeyinf_decode },
  591     { "_MP_", 0, 0xE0000, 0xFFFFF, mp_length, mp_decode },
  592     { NULL, 0, 0, 0, NULL, NULL }
  593 };
  594 
  595 /* Believe it or not, this is significantly faster than memcmp */
  596 static int anchor_match(const struct bios_entry *entry, const char *p)
  597 {
  598     size_t i;
  599 
  600     for (i = 0; i < entry->anchor_len; i++)
  601         if (entry->anchor[i] != p[i])
  602             return 0;
  603 
  604     return 1;
  605 }
  606 
  607 /* Return -1 on error, 0 on success */
  608 static int parse_command_line(int argc, char * const argv[])
  609 {
  610     int option;
  611     const char *optstring = "d:hV";
  612     struct option longopts[] = {
  613         { "dev-mem", required_argument, NULL, 'd' },
  614         { "pir", required_argument, NULL, 'P' },
  615         { "help", no_argument, NULL, 'h' },
  616         { "version", no_argument, NULL, 'V' },
  617         { NULL, 0, NULL, 0 }
  618     };
  619 
  620     while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
  621         switch (option)
  622         {
  623             case 'd':
  624                 opt.devmem = optarg;
  625                 break;
  626             case 'P':
  627                 if (strcmp(optarg, "full") == 0)
  628                     opt.pir = PIR_FULL;
  629                 break;
  630             case 'h':
  631                 opt.flags |= FLAG_HELP;
  632                 break;
  633             case 'V':
  634                 opt.flags |= FLAG_VERSION;
  635                 break;
  636             case '?':
  637                 return -1;
  638         }
  639 
  640     return 0;
  641 }
  642 
  643 static void print_help(void)
  644 {
  645     static const char *help =
  646         "Usage: biosdecode [OPTIONS]\n"
  647         "Options are:\n"
  648         " -d, --dev-mem FILE     Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n"
  649         "     --pir full         Decode the details of the PCI IRQ routing table\n"
  650         " -h, --help             Display this help text and exit\n"
  651         " -V, --version          Display the version and exit\n";
  652 
  653     printf("%s", help);
  654 }
  655 
  656 int main(int argc, char * const argv[])
  657 {
  658     u8 *buf;
  659     off_t fp;
  660     int i;
  661 
  662     if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4)
  663     {
  664         fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
  665         exit(255);
  666     }
  667 
  668     /* Set default option values */
  669     opt.devmem = DEFAULT_MEM_DEV;
  670     opt.flags = 0;
  671 
  672     if (parse_command_line(argc, argv) < 0)
  673         exit(2);
  674 
  675     if (opt.flags & FLAG_HELP)
  676     {
  677         print_help();
  678         return 0;
  679     }
  680 
  681     if (opt.flags & FLAG_VERSION)
  682     {
  683         printf("%s\n", VERSION);
  684         return 0;
  685     }
  686 
  687     printf("# biosdecode %s\n", VERSION);
  688 
  689     if ((buf = mem_chunk(0xE0000, 0x20000, opt.devmem)) == NULL)
  690         exit(1);
  691 
  692     /* Compute anchor lengths once and for all */
  693     for (i = 0; bios_entries[i].anchor != NULL; i++)
  694         bios_entries[i].anchor_len = strlen(bios_entries[i].anchor);
  695 
  696     for (fp = 0xE0000; fp <= 0xFFFF0; fp += 16)
  697     {
  698         u8 *p = buf + fp - 0xE0000;
  699 
  700         for (i = 0; bios_entries[i].anchor != NULL; i++)
  701         {
  702             if (anchor_match(&bios_entries[i], (char *)p)
  703              && fp >= bios_entries[i].low_address
  704              && fp < bios_entries[i].high_address)
  705             {
  706                 off_t len = bios_entries[i].length(p);
  707 
  708                 if (fp + len - 1 <= bios_entries[i].high_address)
  709                 {
  710                     if (bios_entries[i].decode(p, len))
  711                     {
  712                         fp += (((len - 1) >> 4) << 4);
  713                         break;
  714                     }
  715                 }
  716             }
  717         }
  718     }
  719 
  720     free(buf);
  721 
  722     return 0;
  723 }