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 
read_fw_revision(unsigned int * fw_revision,int len)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  */
get_current_fw_rev(struct firmware_versions * v)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 
get_image_fw_rev(void * data,unsigned sz,struct firmware_versions * v)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