Home | History | Annotate | Download | only in recovery
      1 /*
      2  * Copyright (C) 2011 Intel Corporation
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <getopt.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <sys/stat.h>
     24 #include <sys/wait.h>
     25 #include <unistd.h>
     26 #include <stdint.h>
     27 
     28 #include "fw_version_check.h"
     29 
     30 #define DEVICE_NAME	"/sys/kernel/fw_update/fw_info/fw_version"
     31 #define FIP_PATTERN	0x50494624
     32 #define SCU_IPC_VERSION_LEN_LONG 32
     33 #define READ_SZ 256
     34 
     35 struct fip_version_block {
     36 	uint16_t minor;
     37 	uint16_t major;
     38 	uint8_t checksum;
     39 	uint8_t reserved8;
     40 	uint16_t reserved16;
     41 };
     42 
     43 struct fip_version_block_chxx {
     44 	uint16_t minor;
     45 	uint16_t major;
     46 	uint8_t checksum;
     47 	uint8_t reserved8;
     48 	uint16_t reserved16;
     49 	uint16_t size;
     50 	uint16_t dest;
     51 };
     52 
     53 struct FIP_header {
     54 	uint32_t FIP_SIG;
     55 	struct fip_version_block umip_rev;
     56 	struct fip_version_block spat_rev;
     57 	struct fip_version_block spct_rev;
     58 	struct fip_version_block rpch_rev;
     59 	struct fip_version_block ch00_rev;
     60 	struct fip_version_block mipd_rev;
     61 	struct fip_version_block mipn_rev;
     62 	struct fip_version_block scuc_rev;
     63 	struct fip_version_block hvm_rev;
     64 	struct fip_version_block mia_rev;
     65 	struct fip_version_block ia32_rev;
     66 	struct fip_version_block oem_rev;
     67 	struct fip_version_block ved_rev;
     68 	struct fip_version_block vec_rev;
     69 	struct fip_version_block mos_rev;
     70 	struct fip_version_block pos_rev;
     71 	struct fip_version_block cos_rev;
     72 	struct fip_version_block_chxx ch01_rev;
     73 	struct fip_version_block_chxx ch02_rev;
     74 	struct fip_version_block_chxx ch03_rev;
     75 	struct fip_version_block_chxx ch04_rev;
     76 	struct fip_version_block_chxx ch05_rev;
     77 	struct fip_version_block_chxx ch06_rev;
     78 	struct fip_version_block_chxx ch07_rev;
     79 	struct fip_version_block_chxx ch08_rev;
     80 	struct fip_version_block_chxx ch09_rev;
     81 	struct fip_version_block_chxx ch10_rev;
     82 	struct fip_version_block_chxx ch11_rev;
     83 	struct fip_version_block_chxx ch12_rev;
     84 	struct fip_version_block_chxx ch13_rev;
     85 	struct fip_version_block_chxx ch14_rev;
     86 	struct fip_version_block_chxx ch15_rev;
     87 	struct fip_version_block dnx_rev;
     88 	struct fip_version_block reserved0_rev;
     89 	struct fip_version_block reserved1_rev;
     90 	struct fip_version_block ifwi_rev;
     91 };
     92 
     93 static int read_fw_revision(unsigned int *fw_revision, int len)
     94 {
     95 	int i, fw_info, ret;
     96 	const char *sep = " ";
     97 	char *p, *save;
     98 	char buf[READ_SZ];
     99 
    100 	fw_info = open(DEVICE_NAME, O_RDONLY);
    101 	if (fw_info < 0) {
    102 		fprintf(stderr, "failed to open %s ", DEVICE_NAME);
    103 		return fw_info;
    104 	}
    105 
    106 	ret = read(fw_info, buf, READ_SZ - 1);
    107 	if (ret < 0) {
    108 		fprintf(stderr, "failed to read fw_revision, ret = %d\n", ret);
    109 		goto err;
    110 	}
    111 
    112 	buf[ret] = 0;
    113 	p = strtok_r(buf, sep, &save);
    114 	for (i = 0; p && i < len; i++) {
    115 		ret = sscanf(p, "%x", &fw_revision[i]);
    116 		if (ret != 1) {
    117 			fprintf(stderr, "failed to parse fw_revision, ret = %d\n", ret);
    118 			goto err;
    119 		}
    120 		p = strtok_r(NULL, sep, &save);
    121 	}
    122 	ret = 0;
    123 
    124 err:
    125 	close(fw_info);
    126 	return ret;
    127 }
    128 
    129 /* Bytes in scu_ipc_version after the ioctl():
    130 
    131  * 00 SCU Boot Strap Firmware Minor Revision Low
    132  * 01 SCU Boot Strap Firmware Minor Revision High
    133  * 02 SCU Boot Strap Firmware Major Revision Low
    134  * 03 SCU Boot Strap Firmware Major Revision High
    135 
    136  * 04 SCU Firmware Minor Revision Low
    137  * 05 SCU Firmware Minor Revision High
    138  * 06 SCU Firmware Major Revision Low
    139  * 07 SCU Firmware Major Revision High
    140 
    141  * 08 IA Firmware Minor Revision Low
    142  * 09 IA Firmware Minor Revision High
    143  * 10 IA Firmware Major Revision Low
    144  * 11 IA Firmware Major Revision High
    145 
    146  * 12 Validation Hooks Firmware Minor Revision Low
    147  * 13 Validation Hooks Firmware Minor Revision High
    148  * 14 Validation Hooks Firmware Major Revision Low
    149  * 15 Validation Hooks Firmware Major Revision High
    150 
    151  * 16 IFWI Firmware Minor Revision Low
    152  * 17 IFWI Firmware Minor Revision High
    153  * 18 IFWI Firmware Major Revision Low
    154  * 19 IFWI Firmware Major Revision High
    155 
    156  * 20 Chaabi Firmware Minor Revision Low
    157  * 21 Chaabi Firmware Minor Revision High
    158  * 22 Chaabi Firmware Major Revision Low
    159  * 23 Chaabi Firmware Major Revision High
    160 
    161  * 24 mIA Firmware Minor Revision Low
    162  * 25 mIA Firmware Minor Revision High
    163  * 26 mIA Firmware Major Revision Low
    164  * 27 mIA Firmware Major Revision High
    165 
    166  */
    167 int get_current_fw_rev(struct firmware_versions *v)
    168 {
    169 	int ret;
    170 	unsigned int fw_revision[SCU_IPC_VERSION_LEN_LONG] = { 0 };
    171 
    172 	ret = read_fw_revision(fw_revision, SCU_IPC_VERSION_LEN_LONG);
    173 	if (ret)
    174 		return ret;
    175 
    176 	v->scubootstrap.minor = fw_revision[1] << 8 | fw_revision[0];
    177 	v->scubootstrap.major = fw_revision[3] << 8 | fw_revision[2];
    178 	v->scu.minor = fw_revision[5] << 8 | fw_revision[4];
    179 	v->scu.major = fw_revision[7] << 8 | fw_revision[6];
    180 	v->ia32.minor = fw_revision[9] << 8 | fw_revision[8];
    181 	v->ia32.major = fw_revision[11] << 8 | fw_revision[10];
    182 	v->valhooks.minor = fw_revision[13] << 8 | fw_revision[12];
    183 	v->valhooks.major = fw_revision[15] << 8 | fw_revision[14];
    184 	v->ifwi.minor = fw_revision[17] << 8 | fw_revision[16];
    185 	v->ifwi.major = fw_revision[19] << 8 | fw_revision[18];
    186 	v->chaabi.minor = fw_revision[21] << 8 | fw_revision[20];
    187 	v->chaabi.major = fw_revision[23] << 8 | fw_revision[22];
    188 	v->mia.minor = fw_revision[25] << 8 | fw_revision[24];
    189 	v->mia.major = fw_revision[27] << 8 | fw_revision[26];
    190 
    191 	return ret;
    192 }
    193 
    194 int get_image_fw_rev(void *data, unsigned sz, struct firmware_versions *v)
    195 {
    196 	struct FIP_header fip;
    197 	unsigned char *databytes = (unsigned char *)data;
    198 	int magic;
    199 	int magic_found = 0;
    200 
    201 	if (v == NULL) {
    202 		fprintf(stderr, "Null pointer !\n");
    203 		return -1;
    204 	} else
    205 		memset((void *)v, 0, sizeof(struct firmware_versions));
    206 
    207 	while (sz >= sizeof(fip)) {
    208 
    209 		/* Scan for the FIP magic */
    210 		while (sz >= sizeof(fip)) {
    211 			memcpy(&magic, databytes, sizeof(magic));
    212 			if (magic == FIP_PATTERN) {
    213 				magic_found = 1;
    214 				break;
    215 			}
    216 			databytes += sizeof(magic);
    217 			sz -= sizeof(magic);
    218 		}
    219 
    220 		if (!magic_found) {
    221 			fprintf(stderr, "Couldn't find FIP magic in image!\n");
    222 			return -1;
    223 		}
    224 		if (sz < sizeof(fip)) {
    225 			break;
    226 		}
    227 
    228 		memcpy(&fip, databytes, sizeof(fip));
    229 
    230 		/* not available in ifwi file */
    231 		v->scubootstrap.minor = 0;
    232 		v->scubootstrap.major = 0;
    233 
    234 		/* don't update if null */
    235 		if (fip.scuc_rev.minor != 0)
    236 			v->scu.minor = fip.scuc_rev.minor;
    237 		if (fip.scuc_rev.major != 0)
    238 			v->scu.major = fip.scuc_rev.major;
    239 		if (fip.ia32_rev.minor != 0)
    240 			v->ia32.minor = fip.ia32_rev.minor;
    241 		if (fip.ia32_rev.major != 0)
    242 			v->ia32.major = fip.ia32_rev.major;
    243 		if (fip.oem_rev.minor != 0)
    244 			v->valhooks.minor = fip.oem_rev.minor;
    245 		if (fip.oem_rev.major != 0)
    246 			v->valhooks.major = fip.oem_rev.major;
    247 		if (fip.ifwi_rev.minor != 0)
    248 			v->ifwi.minor = fip.ifwi_rev.minor;
    249 		if (fip.ifwi_rev.major != 0)
    250 			v->ifwi.major = fip.ifwi_rev.major;
    251 		if (fip.ch00_rev.minor != 0)
    252 			v->chaabi.minor = fip.ch00_rev.minor;
    253 		if (fip.ch00_rev.major != 0)
    254 			v->chaabi.major = fip.ch00_rev.major;
    255 		if (fip.mia_rev.minor != 0)
    256 			v->mia.minor = fip.mia_rev.minor;
    257 		if (fip.mia_rev.major != 0)
    258 			v->mia.major = fip.mia_rev.major;
    259 
    260 		databytes += sizeof(magic);
    261 		sz -= sizeof(magic);
    262 	}
    263 
    264 	return 0;
    265 }
    266