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,Value * ec_file)83 static int update_recovery_fw(struct flash_device *spi, struct flash_device *ec,
84 struct flash_device *img, 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(Value * fw_file,Value * ec_file,int force)169 int update_fw(Value *fw_file, 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