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 
check_compatible_keys(struct flash_device * img,struct flash_device * spi)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 
update_partition(struct flash_device * src,struct flash_device * dst,const char * name)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 
update_recovery_fw(struct flash_device * spi,struct flash_device * ec,struct flash_device * img,const Value * ec_file)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 
update_rw_fw(struct flash_device * spi,struct flash_device * img,char cur_part)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  */
update_ap_fw(struct flash_device * spi,struct flash_device * img)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 
update_fw(const Value * fw_file,const Value * ec_file,int force)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