|
Packit |
a55458 |
/*
|
|
Packit |
a55458 |
* IBM Vital Product Data decoder
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* Copyright (C) 2003-2007 Jean Delvare <jdelvare@suse.de>
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
a55458 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
a55458 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
a55458 |
* (at your option) any later version.
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
a55458 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a55458 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
a55458 |
* GNU General Public License for more details.
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
a55458 |
* along with this program; if not, write to the Free Software
|
|
Packit |
a55458 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* For the avoidance of doubt the "preferred form" of this code is one which
|
|
Packit |
a55458 |
* is in an open unpatent encumbered format. Where cryptographic key signing
|
|
Packit |
a55458 |
* forms part of the process of creating an executable the information
|
|
Packit |
a55458 |
* including keys needed to generate an equivalently functional executable
|
|
Packit |
a55458 |
* are deemed to be part of the source code.
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* References:
|
|
Packit |
a55458 |
* - IBM "Using the BIOS Build ID to identify Thinkpad systems"
|
|
Packit |
a55458 |
* Revision 2006-01-31
|
|
Packit |
a55458 |
* http://www-307.ibm.com/pc/support/site.wss/MIGR-45120.html
|
|
Packit |
a55458 |
*
|
|
Packit |
a55458 |
* Notes:
|
|
Packit |
a55458 |
* - Main part of the code is taken directly from biosdecode, with an
|
|
Packit |
a55458 |
* additional command line interface and a few experimental features.
|
|
Packit |
a55458 |
*/
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
#include <stdio.h>
|
|
Packit |
a55458 |
#include <stdlib.h>
|
|
Packit |
a55458 |
#include <string.h>
|
|
Packit |
a55458 |
#include <unistd.h>
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
#include "version.h"
|
|
Packit |
a55458 |
#include "config.h"
|
|
Packit |
a55458 |
#include "types.h"
|
|
Packit |
a55458 |
#include "util.h"
|
|
Packit |
a55458 |
#include "vpdopt.h"
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
static void print_entry(const char *name, const u8 *p, size_t len)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
size_t i;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (name != NULL)
|
|
Packit |
a55458 |
printf("%s: ", name);
|
|
Packit |
a55458 |
for (i = 0; i < len; i++)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
/* ASCII filtering */
|
|
Packit |
a55458 |
if (p[i] >= 32 && p[i] < 127)
|
|
Packit |
a55458 |
printf("%c", p[i]);
|
|
Packit |
a55458 |
else if (p[i] != 0)
|
|
Packit |
a55458 |
printf(".");
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
printf("\n");
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
static void dump(const u8 *p, u8 len)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
int done, i, min;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
for (done = 0; done < len; done += 16)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
printf("%02X:", done);
|
|
Packit |
a55458 |
min = (len - done < 16) ? len - done : 16;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
/* As hexadecimal first */
|
|
Packit |
a55458 |
for (i = 0; i < min; i++)
|
|
Packit |
a55458 |
printf(" %02X", p[done + i]);
|
|
Packit |
a55458 |
for (; i < 16; i++) /* Complete line if needed */
|
|
Packit |
a55458 |
printf(" ");
|
|
Packit |
a55458 |
printf(" ");
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
/* And now as text, with ASCII filtering */
|
|
Packit |
a55458 |
for (i = 0; i < min; i++)
|
|
Packit |
a55458 |
printf("%c", (p[done + i] >= 32 && p[done + i] < 127) ?
|
|
Packit |
a55458 |
p[done + i] : '.');
|
|
Packit |
a55458 |
printf("\n");
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
static int decode(const u8 *p)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
if (p[5] < 0x30)
|
|
Packit |
a55458 |
return 0;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
/* XSeries have longer records, exact length seems to vary. */
|
|
Packit |
a55458 |
if (!(p[5] >= 0x45 && checksum(p, p[5]))
|
|
Packit |
a55458 |
/* Some Netvista seem to work with this. */
|
|
Packit |
a55458 |
&& !(checksum(p, 0x30))
|
|
Packit |
a55458 |
/* The Thinkpad/Thinkcentre checksum does *not* include the first
|
|
Packit |
a55458 |
13 bytes. */
|
|
Packit |
a55458 |
&& !(checksum(p + 0x0D, 0x30 - 0x0D)))
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
/* A few systems have a bad checksum (xSeries 325, 330, 335
|
|
Packit |
a55458 |
and 345 with early BIOS) but the record is otherwise
|
|
Packit |
a55458 |
valid. */
|
|
Packit |
a55458 |
if (!(opt.flags & FLAG_QUIET))
|
|
Packit |
a55458 |
printf("# Bad checksum!\n");
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (opt.string != NULL)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
if (opt.string->offset + opt.string->len < p[5])
|
|
Packit |
a55458 |
print_entry(NULL, p + opt.string->offset,
|
|
Packit |
a55458 |
opt.string->len);
|
|
Packit |
a55458 |
return 1;
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
print_entry("BIOS Build ID", p + 0x0D, 9);
|
|
Packit |
a55458 |
print_entry("Box Serial Number", p + 0x16, 7);
|
|
Packit |
a55458 |
print_entry("Motherboard Serial Number", p + 0x1D, 11);
|
|
Packit |
a55458 |
print_entry("Machine Type/Model", p + 0x28, 7);
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (p[5] < 0x44)
|
|
Packit |
a55458 |
return 1;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
print_entry("BIOS Release Date", p + 0x30, 8);
|
|
Packit |
a55458 |
print_entry("Default Flash Image File Name", p + 0x38, 12);
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (p[5] >= 0x46 && p[0x44] != 0x00)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
printf("%s: %u\n", "BIOS Revision", p[0x44]);
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
return 1;
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
int main(int argc, char * const argv[])
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
u8 *buf;
|
|
Packit |
a55458 |
int found = 0;
|
|
Packit |
a55458 |
unsigned int fp;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (sizeof(u8) != 1)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
fprintf(stderr, "%s: compiler incompatibility\n", argv[0]);
|
|
Packit |
a55458 |
exit(255);
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
/* Set default option values */
|
|
Packit |
a55458 |
opt.devmem = DEFAULT_MEM_DEV;
|
|
Packit |
a55458 |
opt.flags = 0;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (parse_command_line(argc, argv)<0)
|
|
Packit |
a55458 |
exit(2);
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (opt.flags & FLAG_HELP)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
print_help();
|
|
Packit |
a55458 |
return 0;
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (opt.flags & FLAG_VERSION)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
printf("%s\n", VERSION);
|
|
Packit |
a55458 |
return 0;
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (!(opt.flags & FLAG_QUIET))
|
|
Packit |
a55458 |
printf("# vpddecode %s\n", VERSION);
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL)
|
|
Packit |
a55458 |
exit(1);
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
for (fp = 0; fp <= 0xFFF0; fp += 4)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
u8 *p = buf + fp;
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (memcmp((char *)p, "\252\125VPD", 5) == 0
|
|
Packit |
a55458 |
&& fp + p[5] - 1 <= 0xFFFF)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
if (fp % 16 && !(opt.flags & FLAG_QUIET))
|
|
Packit |
a55458 |
printf("# Unaligned address (%#x)\n",
|
|
Packit |
a55458 |
0xf0000 + fp);
|
|
Packit |
a55458 |
if (opt.flags & FLAG_DUMP)
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
dump(p, p[5]);
|
|
Packit |
a55458 |
found++;
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
else
|
|
Packit |
a55458 |
{
|
|
Packit |
a55458 |
if (decode(p))
|
|
Packit |
a55458 |
found++;
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
}
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
free(buf);
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
if (!found && !(opt.flags & FLAG_QUIET))
|
|
Packit |
a55458 |
printf("# No VPD structure found, sorry.\n");
|
|
Packit |
a55458 |
|
|
Packit |
a55458 |
return 0;
|
|
Packit |
a55458 |
}
|