/* * Copyright (C) 2011 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <errno.h> #include <fcntl.h> #include <getopt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <unistd.h> #include <stdint.h> #include "fw_version_check.h" #define DEVICE_NAME "/sys/kernel/fw_update/fw_info/fw_version" #define FIP_PATTERN 0x50494624 #define SCU_IPC_VERSION_LEN_LONG 32 #define READ_SZ 256 struct fip_version_block { uint16_t minor; uint16_t major; uint8_t checksum; uint8_t reserved8; uint16_t reserved16; }; struct fip_version_block_chxx { uint16_t minor; uint16_t major; uint8_t checksum; uint8_t reserved8; uint16_t reserved16; uint16_t size; uint16_t dest; }; struct FIP_header { uint32_t FIP_SIG; struct fip_version_block umip_rev; struct fip_version_block spat_rev; struct fip_version_block spct_rev; struct fip_version_block rpch_rev; struct fip_version_block ch00_rev; struct fip_version_block mipd_rev; struct fip_version_block mipn_rev; struct fip_version_block scuc_rev; struct fip_version_block hvm_rev; struct fip_version_block mia_rev; struct fip_version_block ia32_rev; struct fip_version_block oem_rev; struct fip_version_block ved_rev; struct fip_version_block vec_rev; struct fip_version_block mos_rev; struct fip_version_block pos_rev; struct fip_version_block cos_rev; struct fip_version_block_chxx ch01_rev; struct fip_version_block_chxx ch02_rev; struct fip_version_block_chxx ch03_rev; struct fip_version_block_chxx ch04_rev; struct fip_version_block_chxx ch05_rev; struct fip_version_block_chxx ch06_rev; struct fip_version_block_chxx ch07_rev; struct fip_version_block_chxx ch08_rev; struct fip_version_block_chxx ch09_rev; struct fip_version_block_chxx ch10_rev; struct fip_version_block_chxx ch11_rev; struct fip_version_block_chxx ch12_rev; struct fip_version_block_chxx ch13_rev; struct fip_version_block_chxx ch14_rev; struct fip_version_block_chxx ch15_rev; struct fip_version_block dnx_rev; struct fip_version_block reserved0_rev; struct fip_version_block reserved1_rev; struct fip_version_block ifwi_rev; }; static int read_fw_revision(unsigned int *fw_revision, int len) { int i, fw_info, ret; const char *sep = " "; char *p, *save; char buf[READ_SZ]; fw_info = open(DEVICE_NAME, O_RDONLY); if (fw_info < 0) { fprintf(stderr, "failed to open %s ", DEVICE_NAME); return fw_info; } ret = read(fw_info, buf, READ_SZ - 1); if (ret < 0) { fprintf(stderr, "failed to read fw_revision, ret = %d\n", ret); goto err; } buf[ret] = 0; p = strtok_r(buf, sep, &save); for (i = 0; p && i < len; i++) { ret = sscanf(p, "%x", &fw_revision[i]); if (ret != 1) { fprintf(stderr, "failed to parse fw_revision, ret = %d\n", ret); goto err; } p = strtok_r(NULL, sep, &save); } ret = 0; err: close(fw_info); return ret; } /* Bytes in scu_ipc_version after the ioctl(): * 00 SCU Boot Strap Firmware Minor Revision Low * 01 SCU Boot Strap Firmware Minor Revision High * 02 SCU Boot Strap Firmware Major Revision Low * 03 SCU Boot Strap Firmware Major Revision High * 04 SCU Firmware Minor Revision Low * 05 SCU Firmware Minor Revision High * 06 SCU Firmware Major Revision Low * 07 SCU Firmware Major Revision High * 08 IA Firmware Minor Revision Low * 09 IA Firmware Minor Revision High * 10 IA Firmware Major Revision Low * 11 IA Firmware Major Revision High * 12 Validation Hooks Firmware Minor Revision Low * 13 Validation Hooks Firmware Minor Revision High * 14 Validation Hooks Firmware Major Revision Low * 15 Validation Hooks Firmware Major Revision High * 16 IFWI Firmware Minor Revision Low * 17 IFWI Firmware Minor Revision High * 18 IFWI Firmware Major Revision Low * 19 IFWI Firmware Major Revision High * 20 Chaabi Firmware Minor Revision Low * 21 Chaabi Firmware Minor Revision High * 22 Chaabi Firmware Major Revision Low * 23 Chaabi Firmware Major Revision High * 24 mIA Firmware Minor Revision Low * 25 mIA Firmware Minor Revision High * 26 mIA Firmware Major Revision Low * 27 mIA Firmware Major Revision High */ int get_current_fw_rev(struct firmware_versions *v) { int ret; unsigned int fw_revision[SCU_IPC_VERSION_LEN_LONG] = { 0 }; ret = read_fw_revision(fw_revision, SCU_IPC_VERSION_LEN_LONG); if (ret) return ret; v->scubootstrap.minor = fw_revision[1] << 8 | fw_revision[0]; v->scubootstrap.major = fw_revision[3] << 8 | fw_revision[2]; v->scu.minor = fw_revision[5] << 8 | fw_revision[4]; v->scu.major = fw_revision[7] << 8 | fw_revision[6]; v->ia32.minor = fw_revision[9] << 8 | fw_revision[8]; v->ia32.major = fw_revision[11] << 8 | fw_revision[10]; v->valhooks.minor = fw_revision[13] << 8 | fw_revision[12]; v->valhooks.major = fw_revision[15] << 8 | fw_revision[14]; v->ifwi.minor = fw_revision[17] << 8 | fw_revision[16]; v->ifwi.major = fw_revision[19] << 8 | fw_revision[18]; v->chaabi.minor = fw_revision[21] << 8 | fw_revision[20]; v->chaabi.major = fw_revision[23] << 8 | fw_revision[22]; v->mia.minor = fw_revision[25] << 8 | fw_revision[24]; v->mia.major = fw_revision[27] << 8 | fw_revision[26]; return ret; } int get_image_fw_rev(void *data, unsigned sz, struct firmware_versions *v) { struct FIP_header fip; unsigned char *databytes = (unsigned char *)data; int magic; int magic_found = 0; if (v == NULL) { fprintf(stderr, "Null pointer !\n"); return -1; } else memset((void *)v, 0, sizeof(struct firmware_versions)); while (sz >= sizeof(fip)) { /* Scan for the FIP magic */ while (sz >= sizeof(fip)) { memcpy(&magic, databytes, sizeof(magic)); if (magic == FIP_PATTERN) { magic_found = 1; break; } databytes += sizeof(magic); sz -= sizeof(magic); } if (!magic_found) { fprintf(stderr, "Couldn't find FIP magic in image!\n"); return -1; } if (sz < sizeof(fip)) { break; } memcpy(&fip, databytes, sizeof(fip)); /* not available in ifwi file */ v->scubootstrap.minor = 0; v->scubootstrap.major = 0; /* don't update if null */ if (fip.scuc_rev.minor != 0) v->scu.minor = fip.scuc_rev.minor; if (fip.scuc_rev.major != 0) v->scu.major = fip.scuc_rev.major; if (fip.ia32_rev.minor != 0) v->ia32.minor = fip.ia32_rev.minor; if (fip.ia32_rev.major != 0) v->ia32.major = fip.ia32_rev.major; if (fip.oem_rev.minor != 0) v->valhooks.minor = fip.oem_rev.minor; if (fip.oem_rev.major != 0) v->valhooks.major = fip.oem_rev.major; if (fip.ifwi_rev.minor != 0) v->ifwi.minor = fip.ifwi_rev.minor; if (fip.ifwi_rev.major != 0) v->ifwi.major = fip.ifwi_rev.major; if (fip.ch00_rev.minor != 0) v->chaabi.minor = fip.ch00_rev.minor; if (fip.ch00_rev.major != 0) v->chaabi.major = fip.ch00_rev.major; if (fip.mia_rev.minor != 0) v->mia.minor = fip.mia_rev.minor; if (fip.mia_rev.major != 0) v->mia.major = fip.mia_rev.major; databytes += sizeof(magic); sz -= sizeof(magic); } return 0; }