1 /* 2 * Copyright (C) 2015 The Android Open Source Project 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 /* Firmware update flow */ 17 18 #define LOG_TAG "fwtool" 19 20 #include "errno.h" 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #include "flash_device.h" 27 #include "update_log.h" 28 #include "vboot_interface.h" 29 #include "update_fw.h" 30 31 int check_compatible_keys(struct flash_device *img, struct flash_device *spi) 32 { 33 size_t img_size = 0, spi_size = 0; 34 uint8_t *img_rootkey = gbb_get_rootkey(img, &img_size); 35 uint8_t *spi_rootkey = gbb_get_rootkey(spi, &spi_size); 36 37 if (!img_rootkey || !spi_rootkey || img_size != spi_size) { 38 ALOGD("Invalid root key SPI %zd IMG %zd\n", spi_size, img_size); 39 return 0; 40 } 41 42 if (memcmp(img_rootkey, spi_rootkey, img_size)) { 43 ALOGD("Incompatible root keys\n"); 44 return 0; 45 } 46 47 /* TODO: check RW signature and TPM compatibility */ 48 49 return 1; 50 } 51 52 static int update_partition(struct flash_device *src, struct flash_device *dst, 53 const char *name) 54 { 55 int res; 56 void *content; 57 size_t size; 58 off_t offset; 59 const char *display_name = name ? name : "<flash>"; 60 61 content = fmap_read_section(src, name, &size, &offset); 62 if (!content) { 63 ALOGW("Cannot read firmware image partition %s\n", 64 display_name); 65 return -EIO; 66 } 67 ALOGD("Erasing partition '%s' ...\n", display_name); 68 res = flash_erase(dst, offset, size); 69 if (res) { 70 ALOGW("Cannot erase flash\n"); 71 goto out_free; 72 } 73 ALOGD("Writing partition '%s' ...\n", display_name); 74 res = flash_write(dst, offset, content, size); 75 if (res) 76 ALOGW("Cannot write flash\n"); 77 78 out_free: 79 free(content); 80 return 0; 81 } 82 83 static int update_recovery_fw(struct flash_device *spi, struct flash_device *ec, 84 struct flash_device *img, const Value *ec_file) 85 { 86 int res, ra, rb, rs; 87 int wp = 1; /* TODO: read SPI read-write */ 88 89 if (wp) { /* Update only RW */ 90 ALOGD("RW Recovery\n"); 91 92 if (!check_compatible_keys(img, spi)) 93 return -EINVAL; 94 95 ra = update_partition(img, spi, "RW_SECTION_A"); 96 rb = update_partition(img, spi, "RW_SECTION_B"); 97 rs = update_partition(img, spi, "RW_SHARED"); 98 res = ra || rb || rs ? -EIO : 0; 99 } else { /* Update both RO & RW on SPI + EC */ 100 ALOGD("RO+RW Recovery\n"); 101 // TODO Preserve VPD + GBB 102 // TODO write full SPI flash with "img" 103 // TODO Update EC with ec_file 104 (void)ec; 105 (void)ec_file; 106 res = -ENOENT; 107 } 108 109 /* Go back to a sane state for the firmware update */ 110 //VBNV: fwupdate_tries = 0; 111 112 return res; 113 } 114 115 static int update_rw_fw(struct flash_device *spi, struct flash_device *img, 116 char cur_part) 117 { 118 int res; 119 /* Update part A if we are running on B, write B in all other cases */ 120 const char *rw_name = cur_part == 'B' ? "RW_SECTION_A" : "RW_SECTION_B"; 121 int try_next = cur_part == 'B' ? 0 : 1; 122 123 ALOGD("RW Update of firmware '%s'\n", rw_name); 124 125 if (!check_compatible_keys(img, spi)) 126 return -EINVAL; 127 128 res = update_partition(img, spi, rw_name); 129 if (!res) { 130 /* We have updated the SPI flash */ 131 vbnv_set_flag(spi, "fw_try_next", try_next); 132 vbnv_set_flag(spi, "try_count", 6); 133 } 134 135 return res; 136 } 137 138 /* 139 * Provide RO and RW updates until RO FW is changing in dogfood. 140 * TODO (Change this to only RW update and call update_rw_fw instead.) 141 */ 142 static int update_ap_fw(struct flash_device *spi, struct flash_device *img) 143 { 144 int res = -EINVAL; 145 146 /* 147 * Save serial number. VPD changed in fmap. Dogfooders need serial 148 * number for future OTAs. 149 */ 150 size_t rovpd_sz, new_rovpd_sz; 151 off_t rovpd_off, new_rovpd_off; 152 void *rovpd = fmap_read_section(spi, "RO_VPD", &rovpd_sz, &rovpd_off); 153 void *newvpd = fmap_read_section(img, "RO_VPD", &new_rovpd_sz, 154 &new_rovpd_off); 155 156 res = update_partition(img, spi, NULL); 157 158 res = flash_erase(spi, new_rovpd_off, new_rovpd_sz); 159 if (res) 160 return res; 161 162 res = flash_write(spi, new_rovpd_off, rovpd, new_rovpd_sz); 163 if (res) 164 return res; 165 166 return res; 167 } 168 169 int update_fw(const Value *fw_file, const Value *ec_file, int force) 170 { 171 int res = -EINVAL; 172 struct flash_device *img, *spi, *ec; 173 size_t size; 174 char *fwid; 175 char cur_part = vboot_get_mainfw_act(); 176 char *version = fdt_read_string("firmware-version"); 177 if (!version) { 178 ALOGW("Cannot read firmware version from FDT\n"); 179 return -EIO; 180 } 181 ALOGD("Running firmware: %s / partition %c\n", version, cur_part); 182 183 img = flash_open("file", fw_file); 184 if (!img) 185 goto out_free; 186 fwid = reinterpret_cast<char*>(fmap_read_section(img, "RW_FWID_A", &size, NULL)); 187 188 if (!fwid) { 189 ALOGD("Cannot find firmware image version\n"); 190 goto out_close_img; 191 } 192 193 /* TODO: force update if keyblock does not match */ 194 if (!strncmp(version, fwid, size) && !force) { 195 ALOGI("Firmware already up-to-date: %s\n", version); 196 free(fwid); 197 res = 0; 198 goto out_close_img; 199 } 200 free(fwid); 201 202 ec = flash_open("ec", NULL); 203 if (!ec) 204 goto out_close_img; 205 spi = flash_open("spi", NULL); 206 if (!spi) 207 goto out_close_ec; 208 209 if (0) 210 res = update_ap_fw(spi, img); 211 212 if (cur_part == 'R') /* Recovery mode */ 213 res = update_recovery_fw(spi, ec, img, ec_file); 214 else /* Normal mode */ 215 res = update_rw_fw(spi, img, cur_part); 216 217 if (!res) /* successful update : record it */ 218 res = 1; 219 220 flash_close(spi); 221 out_close_ec: 222 flash_close(ec); 223 out_close_img: 224 flash_close(img); 225 226 out_free: 227 free(version); 228 return res; 229 } 230 231