1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2006 Erwan Velu - All Rights Reserved 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation 7 * files (the "Software"), to deal in the Software without 8 * restriction, including without limitation the rights to use, 9 * copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom 11 * the Software is furnished to do so, subject to the following 12 * conditions: 13 * 14 * The above copyright notice and this permission notice shall 15 * be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 * OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * ----------------------------------------------------------------------- 27 */ 28 29 #include <stdio.h> 30 #include <string.h> 31 #include "vpd/vpd.h" 32 33 int vpd_checksum(char *buf, int len) 34 { 35 uint8_t sum = 0; 36 int a; 37 38 for (a = 0; a < len; a++) 39 sum += buf[a]; 40 return (sum == 0); 41 } 42 43 int vpd_decode(s_vpd * vpd) 44 { 45 uint8_t buf[16]; 46 char *p, *q; 47 48 /* Cleaning structures */ 49 memset(&vpd->base_address, 0, sizeof(vpd->base_address)); 50 memset(&vpd->bios_build_id, 0, sizeof(vpd->bios_build_id)); 51 memset(&vpd->box_serial_number, 0, sizeof(vpd->box_serial_number)); 52 memset(&vpd->motherboard_serial_number, 0, 53 sizeof(vpd->motherboard_serial_number)); 54 memset(&vpd->machine_type_model, 0, sizeof(vpd->machine_type_model)); 55 memset(&vpd->bios_release_date, 0, sizeof(vpd->bios_release_date)); 56 memset(&vpd->default_flash_filename, 0, 57 sizeof(vpd->default_flash_filename)); 58 memset(&vpd->bios_version, 0, sizeof(vpd->bios_version)); 59 60 /* Until we found elements in the vpdtable, we consider them as not filled */ 61 vpd->filled = false; 62 63 p = (char *)0xF0000; /* The start address to look at the dmi table */ 64 for (q = p; q < p + 0x10000; q += 4) { 65 memcpy(buf, q, 5); 66 if (memcmp(buf, "\252\125VPD", 5) == 0) { 67 snprintf(vpd->base_address, sizeof(vpd->base_address), "%p", q); 68 if (q[5] < 0x30) 69 return -ENOVPDTABLE; 70 71 vpd->filled = true; 72 /* XSeries have longer records, exact length seems to vary. */ 73 if (!(q[5] >= 0x45 && vpd_checksum(q, q[5])) 74 /* Some Netvista seem to work with this. */ 75 && !(vpd_checksum(q, 0x30)) 76 /* The Thinkpad/Thinkcentre checksum does *not* include the first 13 bytes. */ 77 && !(vpd_checksum(q + 0x0D, 0x30 - 0x0D))) { 78 /* A few systems have a bad checksum (xSeries 325, 330, 335 79 and 345 with early BIOS) but the record is otherwise 80 valid. */ 81 printf("VPD: Bad checksum!\n"); 82 } 83 84 strlcpy(vpd->bios_build_id, q + 0x0D, 9); 85 strlcpy(vpd->box_serial_number, q + 0x16, 7); 86 strlcpy(vpd->motherboard_serial_number, q + 0x1D, 11); 87 strlcpy(vpd->machine_type_model, q + 0x28, 7); 88 89 if (q[5] < 0x44) 90 return VPD_TABLE_PRESENT; 91 92 strlcpy(vpd->bios_release_date, q + 0x30, 8); 93 strlcpy(vpd->default_flash_filename, q + 0x38, 12); 94 95 if (q[5] >= 0x46 && q[0x44] != 0x00) { 96 strlcpy(vpd->bios_version, q + 0x44, 255); 97 } 98 99 return VPD_TABLE_PRESENT; 100 } 101 } 102 return -ENOVPDTABLE; 103 } 104