Home | History | Annotate | Download | only in recovery
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    269 int update_ifwi_file_scu_emmc(void *data, size_t size)
    270 {
    271 	return write_umip_emmc(IFWI_OFFSET, data, size);
    272 }
    273 
    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 
    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 
    342 void Register_librecovery_updater_fugu() {
    343 	RegisterFunction("fugu.flash_ifwi", FlashIfwiFuguFn);
    344 }
    345