1 /*
2  * Copyright 2014 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 <stdio.h>
19 #include <unistd.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <cutils/properties.h>
27 #include <sys/mman.h>
28 #include "fw_version_check.h"
29 #include "edify/expr.h"
30 
31 #define FORCE_RW_OPT            "0"
32 #define BOOT_IFWI_SIZE          0x400000
33 #define BOOT_UMIP_SIZE          0x10000
34 #define BOOT_UMIP_SECTOR_SIZE   0x200
35 #define BOOT_UMIP_XOR_OFFSET    0x7
36 #define BOOT_UMIP_3GPP_OFFSET   0x76F
37 #define BOOT_IFWI_XOR_OFFSET    0x0112d8
38 #define BOOT_DNX_TIMEOUT_OFFSET 0x400
39 #define IFWI_OFFSET             0
40 #define TOKEN_UMIP_AREA_OFFSET  0x4000
41 #define TOKEN_UMIP_AREA_SIZE    0x2C00
42 #define FILE_PATH_SIZE          64
43 #define IFWI_TYPE_LSH           12
44 
dump_fw_versions(struct firmware_versions * v)45 static void dump_fw_versions(struct firmware_versions *v)
46 {
47 	fprintf(stderr, "Image FW versions:\n");
48 	fprintf(stderr, "	   ifwi: %04X.%04X\n", v->ifwi.major, v->ifwi.minor);
49 	fprintf(stderr, "---- components ----\n");
50 	fprintf(stderr, "	    scu: %04X.%04X\n", v->scu.major, v->scu.minor);
51 	fprintf(stderr, "    hooks/oem: %04X.%04X\n", v->valhooks.major, v->valhooks.minor);
52 	fprintf(stderr, "	   ia32: %04X.%04X\n", v->ia32.major, v->ia32.minor);
53 	fprintf(stderr, "	 chaabi: %04X.%04X\n", v->chaabi.major, v->chaabi.minor);
54 	fprintf(stderr, "	    mIA: %04X.%04X\n", v->mia.major, v->mia.minor);
55 }
56 
force_rw(char * name)57 static int force_rw(char *name) {
58 	int ret, fd;
59 
60 	fd = open(name, O_WRONLY);
61 	if (fd < 0) {
62 		fprintf(stderr, "force_ro(): failed to open %s\n", name);
63 		return fd;
64 	}
65 
66 	ret = write(fd, FORCE_RW_OPT, sizeof(FORCE_RW_OPT));
67 	if (ret <= 0) {
68 		fprintf(stderr, "force_ro(): failed to write %s\n", name);
69 		close(fd);
70 		return ret;
71 	}
72 
73 	close(fd);
74 	return 0;
75 }
76 
check_ifwi_file_scu_emmc(void * data,size_t size)77 int check_ifwi_file_scu_emmc(void *data, size_t size)
78 {
79 	struct firmware_versions dev_fw_rev, img_fw_rev;
80 
81 	if (get_image_fw_rev(data, size, &img_fw_rev)) {
82 		fprintf(stderr, "Coudn't extract FW version data from image\n");
83 		return -1;
84 	}
85 
86 	dump_fw_versions(&img_fw_rev);
87 	if (get_current_fw_rev(&dev_fw_rev)) {
88 		fprintf(stderr, "Couldn't query existing IFWI version\n");
89 		return -1;
90 	}
91 	fprintf(stderr,
92 		"Attempting to flash ifwi image version %04X.%04X over ifwi current version %04X.%04X\n",
93 		img_fw_rev.ifwi.major, img_fw_rev.ifwi.minor, dev_fw_rev.ifwi.major, dev_fw_rev.ifwi.minor);
94 
95 	if (img_fw_rev.ifwi.major != dev_fw_rev.ifwi.major) {
96 		fprintf(stderr,
97 			"IFWI FW Major version numbers (file=%04X current=%04X) don't match, Update abort.\n",
98 			img_fw_rev.ifwi.major, dev_fw_rev.ifwi.major);
99 		return -1;
100 	}
101 
102 	return 1;
103 }
104 
xor_compute(char * ptr,uint32_t size)105 static uint32_t xor_compute(char *ptr, uint32_t size)
106 {
107 	uint32_t xor = 0;
108 	uint32_t i;
109 
110 	for (i = 0; i < size; i+=4)
111 		xor = xor ^ *(uint32_t *)(ptr + i);
112 
113 	return xor;
114 }
115 
xor_factorize(uint32_t xor)116 static uint8_t xor_factorize(uint32_t xor)
117 {
118 	return (uint8_t)((xor & 0xff) ^ ((xor >> 8) & 0xff) ^ ((xor >> 16) & 0xff) ^ ((xor >> 24) & 0xff));
119 }
120 
xor_update(char * ptr)121 static void xor_update(char *ptr)
122 {
123 	uint16_t i;
124 	uint32_t xor;
125 
126 	/* update UMIP xor of sector 2 to 127 */
127 	for (i = 2; i < 128; i++) {
128 		xor = xor_compute(ptr + i * BOOT_UMIP_SECTOR_SIZE, BOOT_UMIP_SECTOR_SIZE);
129 		*(uint32_t *)(ptr + 4 * i) = xor;
130 	}
131 
132 	/* update UMIP xor */
133 	*(ptr + BOOT_UMIP_XOR_OFFSET) = 0;
134 	xor = xor_compute(ptr, BOOT_UMIP_SIZE);
135 	*(ptr + BOOT_UMIP_XOR_OFFSET) = xor_factorize(xor);
136 
137 	/* update IFWI xor */
138 	*(uint32_t *)(ptr + BOOT_IFWI_XOR_OFFSET) = 0x0;
139 	xor = xor_compute(ptr, BOOT_IFWI_SIZE);
140 	*(uint32_t *)(ptr + BOOT_IFWI_XOR_OFFSET) = xor;
141 }
142 
write_umip_emmc(uint32_t addr_offset,void * data,size_t size)143 static int write_umip_emmc(uint32_t addr_offset, void *data, size_t size)
144 {
145 	int boot_fd = 0;
146 	int boot_index;
147 	char boot_partition[FILE_PATH_SIZE];
148 	char boot_partition_force_ro[FILE_PATH_SIZE];
149 	char *ptr;
150 	char *token_data;
151 
152 	if (addr_offset == IFWI_OFFSET) {
153 		token_data = malloc(TOKEN_UMIP_AREA_SIZE);
154 		if (!token_data) {
155 			fprintf(stderr, "write_umip_emmc: Malloc error\n");
156 			return -1;
157 		}
158 
159 		if (size > BOOT_IFWI_SIZE) {
160 			fprintf(stderr, "write_umip_emmc: Truncating last %d bytes from the IFWI\n",
161 			(size - BOOT_IFWI_SIZE));
162 			/* Since the last 144 bytes are the FUP header which are not required,*/
163 			/* we truncate it to fit into the boot partition. */
164 			size = BOOT_IFWI_SIZE;
165 		}
166 	}
167 
168 	for (boot_index = 0; boot_index < 2; boot_index++) {
169 		snprintf(boot_partition, FILE_PATH_SIZE, "/dev/block/mmcblk0boot%d", boot_index);
170 		snprintf(boot_partition_force_ro, FILE_PATH_SIZE, "/sys/block/mmcblk0boot%d/force_ro", boot_index);
171 
172 		if (force_rw(boot_partition_force_ro)) {
173 			fprintf(stderr, "write_umip_emmc: unable to force_ro %s\n", boot_partition);
174 			goto err_boot1;
175 		}
176 		boot_fd = open(boot_partition, O_RDWR);
177 		if (boot_fd < 0) {
178 			fprintf(stderr, "write_umip_emmc: failed to open %s\n", boot_partition);
179 			goto err_boot1;
180 		}
181 
182 		ptr = (char *)mmap(NULL, BOOT_IFWI_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, boot_fd, 0);
183 		if (ptr == MAP_FAILED) {
184 			fprintf(stderr, "write_umip_emmc: mmap failed on boot%d with error : %s\n", boot_index, strerror(errno));
185 			goto err_boot1;
186 		}
187 
188 		if (addr_offset == IFWI_OFFSET)
189 			memcpy(token_data, ptr + TOKEN_UMIP_AREA_OFFSET, TOKEN_UMIP_AREA_SIZE);
190 
191 		/* Write the data */
192 		if (addr_offset + size <= BOOT_IFWI_SIZE)
193 			if (data == NULL)
194 				memset(ptr + addr_offset, 0, size);
195 			else
196 				memcpy(ptr + addr_offset, data, size);
197 		else {
198 			fprintf(stderr, "write_umip_emmc: write failed\n");
199 			goto err_boot2;
200 		}
201 
202 		if (addr_offset == IFWI_OFFSET)
203 			memcpy(ptr + TOKEN_UMIP_AREA_OFFSET, token_data, TOKEN_UMIP_AREA_SIZE);
204 
205 		/* Compute and write xor */
206 		xor_update(ptr);
207 
208 		munmap(ptr, BOOT_IFWI_SIZE);
209 		close(boot_fd);
210 	}
211 
212 	if (addr_offset == IFWI_OFFSET)
213 		free(token_data);
214 	return 0;
215 
216 err_boot2:
217 	munmap(ptr, BOOT_IFWI_SIZE);
218 
219 err_boot1:
220 	if (addr_offset == IFWI_OFFSET)
221 		free(token_data);
222 	close(boot_fd);
223 	return -1;
224 }
225 
readbyte_umip_emmc(uint32_t addr_offset)226 static int readbyte_umip_emmc(uint32_t addr_offset)
227 {
228 	int boot_fd = 0;
229 	char *ptr;
230 	int value = 0;
231 
232 	if (force_rw("/sys/block/mmcblk0boot0/force_ro")) {
233 		fprintf(stderr, "read_umip_emmc: unable to force_ro\n");
234 		goto err_boot1;
235 	}
236 	boot_fd = open("/dev/block/mmcblk0boot0", O_RDWR);
237 	if (boot_fd < 0) {
238 		fprintf(stderr, "read_umip_emmc: failed to open /dev/block/mmcblk0boot0\n");
239 		goto err_boot1;
240 	}
241 
242 	ptr = (char *)mmap(NULL, BOOT_UMIP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, boot_fd, 0);
243 	if (ptr == MAP_FAILED) {
244 		fprintf(stderr, "read_umip_emmc: mmap failed on boot0 with error : %s\n", strerror(errno));
245 		goto err_boot1;
246 	}
247 
248 	/* Read the data */
249 	if (addr_offset < BOOT_UMIP_SIZE)
250 		value = (int)*(ptr + addr_offset);
251 	else {
252 		fprintf(stderr, "read_umip_emmc: read failed\n");
253 		goto err_boot2;
254 	}
255 
256 	munmap(ptr, BOOT_UMIP_SIZE);
257 	close(boot_fd);
258 
259 	return value;
260 
261 err_boot2:
262 	munmap(ptr, BOOT_UMIP_SIZE);
263 
264 err_boot1:
265 	close(boot_fd);
266 	return -1;
267 }
268 
update_ifwi_file_scu_emmc(void * data,size_t size)269 int update_ifwi_file_scu_emmc(void *data, size_t size)
270 {
271 	return write_umip_emmc(IFWI_OFFSET, data, size);
272 }
273 
flash_ifwi_scu_emmc(void * data,unsigned size)274 int flash_ifwi_scu_emmc(void *data, unsigned size)
275 {
276 	int ret;
277 
278 	ret = check_ifwi_file_scu_emmc(data, size);
279 	if (ret > 0)
280 		return update_ifwi_file_scu_emmc(data, size);
281 
282 	return ret;
283 }
284 
FlashIfwiFuguFn(const char * name,State * state,int argc,Expr * argv[])285 Value* FlashIfwiFuguFn(const char *name, State * state, int argc, Expr * argv[]) {
286 	Value *ret = NULL;
287 	char *filename = NULL;
288 	unsigned char *buffer = NULL;
289 	int ifwi_size;
290 	FILE *f = NULL;
291 
292 	if (argc != 1) {
293 		ErrorAbort(state, "%s() expected 1 arg, got %d", name, argc);
294 		return NULL;
295 	}
296 	if (ReadArgs(state, argv, 1, &filename) < 0) {
297 		ErrorAbort(state, "%s() invalid args ", name);
298 		return NULL;
299 	}
300 
301 	if (filename == NULL || strlen(filename) == 0) {
302 		ErrorAbort(state, "filename argument to %s can't be empty", name);
303 		goto done;
304 	}
305 
306 	if ((f = fopen(filename,"rb")) == NULL) {
307 		ErrorAbort(state, "Unable to open file %s: %s ", filename, strerror(errno));
308 		goto done;
309 	}
310 
311 	fseek(f, 0, SEEK_END);
312 	ifwi_size = ftell(f);
313 	if (ifwi_size < 0) {
314 		ErrorAbort(state, "Unable to get ifwi_size ");
315 		goto done;
316 	};
317 	fseek(f, 0, SEEK_SET);
318 
319 	if ((buffer = malloc(ifwi_size)) == NULL) {
320 		ErrorAbort(state, "Unable to alloc ifwi flash buffer of size %d", ifwi_size);
321 		goto done;
322 	}
323 	fread(buffer, ifwi_size, 1, f);
324 	fclose(f);
325 
326 	if(flash_ifwi_scu_emmc(buffer, ifwi_size) !=0) {
327 		ErrorAbort(state, "Unable to flash ifwi in emmc");
328 		free(buffer);
329 		goto done;
330 	};
331 
332 	free(buffer);
333 	ret = StringValue(strdup(""));
334 
335 done:
336 	if (filename)
337 		free(filename);
338 
339 	return ret;
340 }
341 
Register_librecovery_updater_fugu()342 void Register_librecovery_updater_fugu() {
343 	RegisterFunction("fugu.flash_ifwi", FlashIfwiFuguFn);
344 }
345