blob: 334f81ffb19e8c54ef041526f0b7e19ed96ad9d9 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080012 * the documentation and/or other materials provided with the
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080013 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
Colin Crossf8387882012-05-24 17:18:41 -070029#define round_down(a, b) \
30 ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
31
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080032#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36
Elliott Hughesfc797672015-04-07 20:12:50 -070037#include <algorithm>
38
Elliott Hughes2810d002016-04-25 14:31:18 -070039#include <android-base/stringprintf.h>
Colin Crossf8387882012-05-24 17:18:41 -070040#include <sparse/sparse.h>
Chris Fries0ea946c2017-04-12 10:25:57 -050041#include <utils/FileMap.h>
Colin Crossf8387882012-05-24 17:18:41 -070042
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043#include "fastboot.h"
David Pursell0b156632015-10-30 11:22:01 -070044#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080045
Elliott Hughes2810d002016-04-25 14:31:18 -070046static std::string g_error;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047
Elliott Hughes2810d002016-04-25 14:31:18 -070048const std::string fb_get_error() {
49 return g_error;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080050}
51
Chris Fries6a999712017-04-04 09:52:47 -050052static int64_t check_response(Transport* transport, uint32_t size, char* response) {
Elliott Hughesfc797672015-04-07 20:12:50 -070053 char status[65];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080054
Elliott Hughesfc797672015-04-07 20:12:50 -070055 while (true) {
David Pursell0b156632015-10-30 11:22:01 -070056 int r = transport->Read(status, 64);
Elliott Hughesfc797672015-04-07 20:12:50 -070057 if (r < 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -070058 g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -070059 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080060 return -1;
61 }
62 status[r] = 0;
63
Elliott Hughesfc797672015-04-07 20:12:50 -070064 if (r < 4) {
Elliott Hughes2810d002016-04-25 14:31:18 -070065 g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
David Pursell0b156632015-10-30 11:22:01 -070066 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080067 return -1;
68 }
69
Elliott Hughesfc797672015-04-07 20:12:50 -070070 if (!memcmp(status, "INFO", 4)) {
Brian Swetland63e52052010-06-28 11:14:26 -070071 fprintf(stderr,"(bootloader) %s\n", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080072 continue;
73 }
74
Elliott Hughesfc797672015-04-07 20:12:50 -070075 if (!memcmp(status, "OKAY", 4)) {
76 if (response) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080077 strcpy(response, (char*) status + 4);
78 }
79 return 0;
80 }
81
Elliott Hughesfc797672015-04-07 20:12:50 -070082 if (!memcmp(status, "FAIL", 4)) {
83 if (r > 4) {
Elliott Hughes2810d002016-04-25 14:31:18 -070084 g_error = android::base::StringPrintf("remote: %s", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080085 } else {
Elliott Hughes2810d002016-04-25 14:31:18 -070086 g_error = "remote failure";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080087 }
88 return -1;
89 }
90
Elliott Hughesfc797672015-04-07 20:12:50 -070091 if (!memcmp(status, "DATA", 4) && size > 0){
92 uint32_t dsize = strtol(status + 4, 0, 16);
93 if (dsize > size) {
Elliott Hughes2810d002016-04-25 14:31:18 -070094 g_error = android::base::StringPrintf("data size too large (%d)", dsize);
David Pursell0b156632015-10-30 11:22:01 -070095 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080096 return -1;
97 }
98 return dsize;
99 }
100
Elliott Hughes2810d002016-04-25 14:31:18 -0700101 g_error = "unknown status code";
David Pursell0b156632015-10-30 11:22:01 -0700102 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800103 break;
104 }
105
106 return -1;
107}
108
Chris Fries6a999712017-04-04 09:52:47 -0500109static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
Elliott Hughesfc797672015-04-07 20:12:50 -0700110 size_t cmdsize = strlen(cmd);
111 if (cmdsize > 64) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700112 g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800113 return -1;
114 }
115
Elliott Hughesfc797672015-04-07 20:12:50 -0700116 if (response) {
117 response[0] = 0;
118 }
119
David Pursell0b156632015-10-30 11:22:01 -0700120 if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700121 g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700122 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800123 return -1;
124 }
125
David Pursell0b156632015-10-30 11:22:01 -0700126 return check_response(transport, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700127}
128
Chris Fries6a999712017-04-04 09:52:47 -0500129static int64_t _command_data(Transport* transport, const void* data, uint32_t size) {
130 int64_t r = transport->Write(data, size);
Elliott Hughesfc797672015-04-07 20:12:50 -0700131 if (r < 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700132 g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700133 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700134 return -1;
135 }
Chris Fries6a999712017-04-04 09:52:47 -0500136 if (r != static_cast<int64_t>(size)) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700137 g_error = "data transfer failure (short transfer)";
David Pursell0b156632015-10-30 11:22:01 -0700138 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700139 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800140 }
Colin Crossf8387882012-05-24 17:18:41 -0700141 return r;
142}
143
Chris Fries6a999712017-04-04 09:52:47 -0500144static int64_t _command_end(Transport* transport) {
David Pursell0b156632015-10-30 11:22:01 -0700145 return check_response(transport, 0, 0) < 0 ? -1 : 0;
Colin Crossf8387882012-05-24 17:18:41 -0700146}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800147
Chris Fries6a999712017-04-04 09:52:47 -0500148static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
Elliott Hughesfc797672015-04-07 20:12:50 -0700149 char* response) {
Colin Crossf8387882012-05-24 17:18:41 -0700150 if (size == 0) {
151 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800152 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800153
Chris Fries6a999712017-04-04 09:52:47 -0500154 int64_t r = _command_start(transport, cmd, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700155 if (r < 0) {
156 return -1;
157 }
158
David Pursell0b156632015-10-30 11:22:01 -0700159 r = _command_data(transport, data, size);
Colin Crossf8387882012-05-24 17:18:41 -0700160 if (r < 0) {
161 return -1;
162 }
163
David Pursell0b156632015-10-30 11:22:01 -0700164 r = _command_end(transport);
Elliott Hughesfc797672015-04-07 20:12:50 -0700165 if (r < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800166 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800167 }
Colin Crossf8387882012-05-24 17:18:41 -0700168
169 return size;
170}
171
Chris Fries0ea946c2017-04-12 10:25:57 -0500172static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, uint32_t size,
173 char* response) {
174 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
175 off64_t offset = 0;
176 uint32_t remaining = size;
177
178 if (_command_start(transport, cmd, size, response) < 0) {
179 return -1;
180 }
181
182 while (remaining) {
183 android::FileMap filemap;
184 size_t len = std::min(remaining, MAX_MAP_SIZE);
185
186 if (!filemap.create(NULL, fd, offset, len, true)) {
187 return -1;
188 }
189
190 if (_command_data(transport, filemap.getDataPtr(), len) < 0) {
191 return -1;
192 }
193
194 remaining -= len;
195 offset += len;
196 }
197
198 if (_command_end(transport) < 0) {
199 return -1;
200 }
201
202 return size;
203}
204
David Pursell0b156632015-10-30 11:22:01 -0700205static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
206 return _command_start(transport, cmd, 0, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800207}
208
David Pursell0b156632015-10-30 11:22:01 -0700209int fb_command(Transport* transport, const char* cmd) {
210 return _command_send_no_data(transport, cmd, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800211}
212
David Pursell0b156632015-10-30 11:22:01 -0700213int fb_command_response(Transport* transport, const char* cmd, char* response) {
214 return _command_send_no_data(transport, cmd, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800215}
216
Chris Fries6a999712017-04-04 09:52:47 -0500217int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
Chris Fries0ea946c2017-04-12 10:25:57 -0500218 std::string cmd(android::base::StringPrintf("download:%08x", size));
219 return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0;
220}
221
222int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) {
223 std::string cmd(android::base::StringPrintf("download:%08x", size));
224 return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800225}
226
David Pursell0b156632015-10-30 11:22:01 -0700227#define TRANSPORT_BUF_SIZE 1024
228static char transport_buf[TRANSPORT_BUF_SIZE];
229static int transport_buf_len;
Colin Crossf8387882012-05-24 17:18:41 -0700230
231static int fb_download_data_sparse_write(void *priv, const void *data, int len)
232{
233 int r;
David Pursell0b156632015-10-30 11:22:01 -0700234 Transport* transport = reinterpret_cast<Transport*>(priv);
Colin Crossf8387882012-05-24 17:18:41 -0700235 int to_write;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700236 const char* ptr = reinterpret_cast<const char*>(data);
Colin Crossf8387882012-05-24 17:18:41 -0700237
David Pursell0b156632015-10-30 11:22:01 -0700238 if (transport_buf_len) {
239 to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
Colin Crossf8387882012-05-24 17:18:41 -0700240
David Pursell0b156632015-10-30 11:22:01 -0700241 memcpy(transport_buf + transport_buf_len, ptr, to_write);
242 transport_buf_len += to_write;
Colin Crossf8387882012-05-24 17:18:41 -0700243 ptr += to_write;
244 len -= to_write;
245 }
246
David Pursell0b156632015-10-30 11:22:01 -0700247 if (transport_buf_len == TRANSPORT_BUF_SIZE) {
248 r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
249 if (r != TRANSPORT_BUF_SIZE) {
Colin Crossf8387882012-05-24 17:18:41 -0700250 return -1;
251 }
David Pursell0b156632015-10-30 11:22:01 -0700252 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700253 }
254
David Pursell0b156632015-10-30 11:22:01 -0700255 if (len > TRANSPORT_BUF_SIZE) {
256 if (transport_buf_len > 0) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700257 g_error = "internal error: transport_buf not empty";
Colin Crossf8387882012-05-24 17:18:41 -0700258 return -1;
259 }
David Pursell0b156632015-10-30 11:22:01 -0700260 to_write = round_down(len, TRANSPORT_BUF_SIZE);
261 r = _command_data(transport, ptr, to_write);
Colin Crossf8387882012-05-24 17:18:41 -0700262 if (r != to_write) {
263 return -1;
264 }
265 ptr += to_write;
266 len -= to_write;
267 }
268
269 if (len > 0) {
David Pursell0b156632015-10-30 11:22:01 -0700270 if (len > TRANSPORT_BUF_SIZE) {
Elliott Hughes2810d002016-04-25 14:31:18 -0700271 g_error = "internal error: too much left for transport_buf";
Colin Crossf8387882012-05-24 17:18:41 -0700272 return -1;
273 }
David Pursell0b156632015-10-30 11:22:01 -0700274 memcpy(transport_buf, ptr, len);
275 transport_buf_len = len;
Colin Crossf8387882012-05-24 17:18:41 -0700276 }
277
278 return 0;
279}
280
David Pursell0b156632015-10-30 11:22:01 -0700281static int fb_download_data_sparse_flush(Transport* transport) {
282 if (transport_buf_len > 0) {
Chris Fries6a999712017-04-04 09:52:47 -0500283 int64_t r = _command_data(transport, transport_buf, transport_buf_len);
284 if (r != static_cast<int64_t>(transport_buf_len)) {
Colin Crossf8387882012-05-24 17:18:41 -0700285 return -1;
286 }
David Pursell0b156632015-10-30 11:22:01 -0700287 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700288 }
Colin Crossf8387882012-05-24 17:18:41 -0700289 return 0;
290}
291
David Pursell0b156632015-10-30 11:22:01 -0700292int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
Colin Crossf8387882012-05-24 17:18:41 -0700293 int size = sparse_file_len(s, true, false);
294 if (size <= 0) {
295 return -1;
296 }
297
Chris Fries0ea946c2017-04-12 10:25:57 -0500298 std::string cmd(android::base::StringPrintf("download:%08x", size));
299 int r = _command_start(transport, cmd.c_str(), size, 0);
Colin Crossf8387882012-05-24 17:18:41 -0700300 if (r < 0) {
301 return -1;
302 }
303
David Pursell0b156632015-10-30 11:22:01 -0700304 r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
Colin Crossf8387882012-05-24 17:18:41 -0700305 if (r < 0) {
306 return -1;
307 }
308
David Pursell0b156632015-10-30 11:22:01 -0700309 r = fb_download_data_sparse_flush(transport);
Jeremy Compostella9f0d6bd2015-02-22 10:47:16 +0100310 if (r < 0) {
311 return -1;
312 }
Colin Crossf8387882012-05-24 17:18:41 -0700313
David Pursell0b156632015-10-30 11:22:01 -0700314 return _command_end(transport);
Colin Crossf8387882012-05-24 17:18:41 -0700315}