| /* |
| * 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; |
| } |