diff options
Diffstat (limited to 'vpddecode.c')
-rw-r--r-- | vpddecode.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/vpddecode.c b/vpddecode.c new file mode 100644 index 0000000..4e00263 --- /dev/null +++ b/vpddecode.c @@ -0,0 +1,202 @@ +/* + * IBM Vital Product Data decoder + * + * (C) 2003-2005 Jean Delvare <khali@linux-fr.org> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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<len; i++) + { + /* ASCII filtering */ + if(p[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<len; done+=16) + { + printf("%02X:", done); + min=(len-done<16)?len-done:16; + + /* As hexadecimal first */ + for(i=0; i<min; i++) + printf(" %02X", p[done+i]); + for(; i<16; i++) /* Complete line if needed */ + printf(" "); + printf(" "); + + /* And now as text, with ASCII filtering */ + for(i=0; i<min; i++) + printf("%c", (p[done+i]>=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->len<p[5]) + print_entry(NULL, p+opt.string->offset, + 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; +} |