Home | History | Annotate | Download | only in updater
      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