Logo Search packages:      
Sourcecode: virtualbox-ose version File versions  Download package

biossums.c

Go to the documentation of this file.
/* $Id: biossums.c $ */
/** @file
 * Tool for modifying a BIOS image to write the BIOS checksum.
 */

/*
 * Copyright (C) 2006-2007 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#ifndef RT_OS_WINDOWS
# include <unistd.h> /* unlink */
#endif

typedef unsigned char uint8_t;

static uint8_t abBios[64*1024];
static FILE *g_pIn = NULL;
static FILE *g_pOut = NULL;
static const char *g_pszOutFile = NULL;
static const char *g_argv0;

/**
 * Find where the filename starts in the given path.
 */
00038 static const char *name(const char *pszPath)
{
    const char *psz = strrchr(pszPath, '/');
#if defined(_MSC_VER) || defined(__OS2__)
    const char *psz2 = strrchr(pszPath, '\\');
    if (!psz2)
        psz2 = strrchr(pszPath, ':');
    if (psz2 && (!psz || psz2 > psz))
        psz = psz2;
#endif
    return psz ? psz + 1 : pszPath;
}

/**
 * Report an error.
 */
00054 static int fatal(const char *pszFormat, ...)
{
    va_list va;

    fprintf(stderr, "%s: ", name(g_argv0));

    va_start(va, pszFormat);
    vfprintf(stderr, pszFormat, va);
    va_end(va);

    /* clean up */
    if (g_pIn)
        fclose(g_pIn);
    if (g_pOut)
        fclose(g_pOut);
    if (g_pszOutFile)
        unlink(g_pszOutFile);

    return 1;
}

/**
 * Calculate the checksum.
 */
00078 static uint8_t calculateChecksum(uint8_t *pb, size_t cb, size_t iChecksum)
{
    uint8_t u8Sum = 0;
    size_t  i;

    for (i = 0; i < cb; i++)
        if (i != iChecksum)
            u8Sum += pb[i];

    return -u8Sum;
}

/**
 * Find a header in the binary.
 *
 * @param   pb        Where to search for the signature
 * @param   cb        Size of the search area
 * @param   pbHeader  Pointer to the start of the signature
 * @returns           0 if signature was not found, 1 if found or
 *                    2 if more than one signature was found */
00098 static int searchHeader(uint8_t *pb, size_t cb, const char *pszHeader, uint8_t **pbHeader)
{
    int          fFound = 0;
    unsigned int i;
    size_t       cbSignature = strlen(pszHeader);

    for (i = 0; i < cb; i += 16)
        if (!memcmp(pb + i, pszHeader, cbSignature))
        {
            if (fFound++)
                return 2;
            *pbHeader = pb + i;
        }

    return fFound;
}

int main(int argc, char **argv)
{
    FILE    *pIn, *pOut;
    size_t  cbIn, cbOut;
    int     fAdapterBios = 0;

    g_argv0 = argv[0];

    if (argc != 3)
        return fatal("Input file name and output file name required.\n");

    pIn = g_pIn = fopen(argv[1], "rb");
    if (!pIn)
        return fatal("Error opening '%s' for reading (%s).\n", argv[1], strerror(errno));

    pOut = g_pOut = fopen(argv[2], "wb");
    if (!pOut)
        return fatal("Error opening '%s' for writing (%s).\n", argv[2], strerror(errno));
    g_pszOutFile = argv[2];

    /* safety precaution (aka. complete paranoia :-) */
    memset(abBios, 0, sizeof(abBios));

    cbIn = fread(abBios, 1, sizeof(abBios), pIn);
    if (ferror(pIn))
        return fatal("Error reading from '%s' (%s).\n", argv[1], strerror(errno));
    g_pIn = NULL;
    fclose(pIn);

    fAdapterBios = abBios[0] == 0x55 && abBios[1] == 0xaa;

    /* align size to page size */
    if ((cbIn % 4096) != 0)
        cbIn = (cbIn + 4095) & ~4095;

    if (!fAdapterBios && cbIn != 64*1024)
        return fatal("Size of system BIOS is not 64KB!\n");

    if (fAdapterBios)
    {
        /* adapter BIOS */

        /* set the length indicator */
        abBios[2] = (uint8_t)(cbIn / 512);
    }
    else
    {
        /* system BIOS */
        size_t  cbChecksum;
        uint8_t u8Checksum;
        uint8_t *pbHeader;

        /* Set the BIOS32 header checksum. */
        switch (searchHeader(abBios, cbIn, "_32_", &pbHeader))
        {
            case 0:
                return fatal("No BIOS32 header not found!\n");
            case 2:
                return fatal("More than one BIOS32 header found!\n");
            case 1:
                cbChecksum = (size_t)pbHeader[9] * 16;
                u8Checksum = calculateChecksum(pbHeader, cbChecksum, 10);
                pbHeader[10] = u8Checksum;
                break;
        }

        /* Set the PIR header checksum according to PCI IRQ Routing table
         * specification version 1.0, Microsoft Corporation, 1996 */
        switch (searchHeader(abBios, cbIn, "$PIR", &pbHeader))
        {
            case 0:
                return fatal("No PCI IRQ routing table found!\n");
            case 2:
                return fatal("More than one PCI IRQ routing table found!\n");
            case 1:
                cbChecksum = (size_t)pbHeader[6] + (size_t)pbHeader[7] * 256;
                u8Checksum = calculateChecksum(pbHeader, cbChecksum, 31);
                pbHeader[31] = u8Checksum;
                break;
        }

        /* Set the SMBIOS header checksum according to System Management BIOS
         * Reference Specification Version 2.5, DSP0134. */
        switch (searchHeader(abBios, cbIn, "_SM_", &pbHeader))
        {
            case 0:
                return fatal("No SMBIOS header found!\n");
            case 2:
                return fatal("More than one SMBIOS header found!\n");
            case 1:
                /* at first fix the DMI header starting at SMBIOS header offset 16 */
                u8Checksum = calculateChecksum(pbHeader+16, 15, 5);
                pbHeader[21] = u8Checksum;

                /* now fix the checksum of the whole SMBIOS header */
                cbChecksum = (size_t)pbHeader[5];
                u8Checksum = calculateChecksum(pbHeader, cbChecksum, 4);
                pbHeader[4] = u8Checksum;
                break;
        }
    }

    /* set the BIOS checksum */
    abBios[cbIn-1] = calculateChecksum(abBios, cbIn, cbIn - 1);

    cbOut = fwrite(abBios, 1, cbIn, pOut);
    if (ferror(pOut))
        return fatal("Error writing to '%s' (%s).\n", g_pszOutFile, strerror(errno));
    g_pOut = NULL;
    if (fclose(pOut))
        return fatal("Error closing '%s' (%s).\n", g_pszOutFile, strerror(errno));

    return 0;
}


Generated by  Doxygen 1.6.0   Back to index