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