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