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