blob: 4850b4a0dea06d96be21b61a88de7f106bb527aa [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
Colin Crossf8387882012-05-24 17:18:41 -070039#include <sparse/sparse.h>
40
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080041#include "fastboot.h"
David Pursell0b156632015-10-30 11:22:01 -070042#include "transport.h"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043
44static char ERROR[128];
45
46char *fb_get_error(void)
47{
48 return ERROR;
49}
50
David Pursell0b156632015-10-30 11:22:01 -070051static int check_response(Transport* transport, uint32_t size, char* response) {
Elliott Hughesfc797672015-04-07 20:12:50 -070052 char status[65];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080053
Elliott Hughesfc797672015-04-07 20:12:50 -070054 while (true) {
David Pursell0b156632015-10-30 11:22:01 -070055 int r = transport->Read(status, 64);
Elliott Hughesfc797672015-04-07 20:12:50 -070056 if (r < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080057 sprintf(ERROR, "status read failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -070058 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080059 return -1;
60 }
61 status[r] = 0;
62
Elliott Hughesfc797672015-04-07 20:12:50 -070063 if (r < 4) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080064 sprintf(ERROR, "status malformed (%d bytes)", r);
David Pursell0b156632015-10-30 11:22:01 -070065 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080066 return -1;
67 }
68
Elliott Hughesfc797672015-04-07 20:12:50 -070069 if (!memcmp(status, "INFO", 4)) {
Brian Swetland63e52052010-06-28 11:14:26 -070070 fprintf(stderr,"(bootloader) %s\n", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080071 continue;
72 }
73
Elliott Hughesfc797672015-04-07 20:12:50 -070074 if (!memcmp(status, "OKAY", 4)) {
75 if (response) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080076 strcpy(response, (char*) status + 4);
77 }
78 return 0;
79 }
80
Elliott Hughesfc797672015-04-07 20:12:50 -070081 if (!memcmp(status, "FAIL", 4)) {
82 if (r > 4) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080083 sprintf(ERROR, "remote: %s", status + 4);
84 } else {
85 strcpy(ERROR, "remote failure");
86 }
87 return -1;
88 }
89
Elliott Hughesfc797672015-04-07 20:12:50 -070090 if (!memcmp(status, "DATA", 4) && size > 0){
91 uint32_t dsize = strtol(status + 4, 0, 16);
92 if (dsize > size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080093 strcpy(ERROR, "data size too large");
David Pursell0b156632015-10-30 11:22:01 -070094 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080095 return -1;
96 }
97 return dsize;
98 }
99
100 strcpy(ERROR,"unknown status code");
David Pursell0b156632015-10-30 11:22:01 -0700101 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800102 break;
103 }
104
105 return -1;
106}
107
David Pursell0b156632015-10-30 11:22:01 -0700108static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
Elliott Hughesfc797672015-04-07 20:12:50 -0700109 size_t cmdsize = strlen(cmd);
110 if (cmdsize > 64) {
111 sprintf(ERROR, "command too large");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800112 return -1;
113 }
114
Elliott Hughesfc797672015-04-07 20:12:50 -0700115 if (response) {
116 response[0] = 0;
117 }
118
David Pursell0b156632015-10-30 11:22:01 -0700119 if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
Elliott Hughesfc797672015-04-07 20:12:50 -0700120 sprintf(ERROR, "command write failed (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700121 transport->Close();
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800122 return -1;
123 }
124
David Pursell0b156632015-10-30 11:22:01 -0700125 return check_response(transport, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700126}
127
David Pursell0b156632015-10-30 11:22:01 -0700128static int _command_data(Transport* transport, const void* data, uint32_t size) {
129 int r = transport->Write(data, size);
Elliott Hughesfc797672015-04-07 20:12:50 -0700130 if (r < 0) {
Colin Crossf8387882012-05-24 17:18:41 -0700131 sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
David Pursell0b156632015-10-30 11:22:01 -0700132 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700133 return -1;
134 }
Elliott Hughesfc797672015-04-07 20:12:50 -0700135 if (r != ((int) size)) {
Colin Crossf8387882012-05-24 17:18:41 -0700136 sprintf(ERROR, "data transfer failure (short transfer)");
David Pursell0b156632015-10-30 11:22:01 -0700137 transport->Close();
Colin Crossf8387882012-05-24 17:18:41 -0700138 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800139 }
Colin Crossf8387882012-05-24 17:18:41 -0700140 return r;
141}
142
David Pursell0b156632015-10-30 11:22:01 -0700143static int _command_end(Transport* transport) {
144 return check_response(transport, 0, 0) < 0 ? -1 : 0;
Colin Crossf8387882012-05-24 17:18:41 -0700145}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800146
David Pursell0b156632015-10-30 11:22:01 -0700147static int _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
Elliott Hughesfc797672015-04-07 20:12:50 -0700148 char* response) {
Colin Crossf8387882012-05-24 17:18:41 -0700149 if (size == 0) {
150 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800151 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800152
David Pursell0b156632015-10-30 11:22:01 -0700153 int r = _command_start(transport, cmd, size, response);
Colin Crossf8387882012-05-24 17:18:41 -0700154 if (r < 0) {
155 return -1;
156 }
157
David Pursell0b156632015-10-30 11:22:01 -0700158 r = _command_data(transport, data, size);
Colin Crossf8387882012-05-24 17:18:41 -0700159 if (r < 0) {
160 return -1;
161 }
162
David Pursell0b156632015-10-30 11:22:01 -0700163 r = _command_end(transport);
Elliott Hughesfc797672015-04-07 20:12:50 -0700164 if (r < 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800166 }
Colin Crossf8387882012-05-24 17:18:41 -0700167
168 return size;
169}
170
David Pursell0b156632015-10-30 11:22:01 -0700171static int _command_send_no_data(Transport* transport, const char* cmd, char* response) {
172 return _command_start(transport, cmd, 0, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800173}
174
David Pursell0b156632015-10-30 11:22:01 -0700175int fb_command(Transport* transport, const char* cmd) {
176 return _command_send_no_data(transport, cmd, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800177}
178
David Pursell0b156632015-10-30 11:22:01 -0700179int fb_command_response(Transport* transport, const char* cmd, char* response) {
180 return _command_send_no_data(transport, cmd, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800181}
182
David Pursell0b156632015-10-30 11:22:01 -0700183int fb_download_data(Transport* transport, const void* data, uint32_t size) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800184 char cmd[64];
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800185 sprintf(cmd, "download:%08x", size);
David Pursell0b156632015-10-30 11:22:01 -0700186 return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800187}
188
David Pursell0b156632015-10-30 11:22:01 -0700189#define TRANSPORT_BUF_SIZE 1024
190static char transport_buf[TRANSPORT_BUF_SIZE];
191static int transport_buf_len;
Colin Crossf8387882012-05-24 17:18:41 -0700192
193static int fb_download_data_sparse_write(void *priv, const void *data, int len)
194{
195 int r;
David Pursell0b156632015-10-30 11:22:01 -0700196 Transport* transport = reinterpret_cast<Transport*>(priv);
Colin Crossf8387882012-05-24 17:18:41 -0700197 int to_write;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700198 const char* ptr = reinterpret_cast<const char*>(data);
Colin Crossf8387882012-05-24 17:18:41 -0700199
David Pursell0b156632015-10-30 11:22:01 -0700200 if (transport_buf_len) {
201 to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len);
Colin Crossf8387882012-05-24 17:18:41 -0700202
David Pursell0b156632015-10-30 11:22:01 -0700203 memcpy(transport_buf + transport_buf_len, ptr, to_write);
204 transport_buf_len += to_write;
Colin Crossf8387882012-05-24 17:18:41 -0700205 ptr += to_write;
206 len -= to_write;
207 }
208
David Pursell0b156632015-10-30 11:22:01 -0700209 if (transport_buf_len == TRANSPORT_BUF_SIZE) {
210 r = _command_data(transport, transport_buf, TRANSPORT_BUF_SIZE);
211 if (r != TRANSPORT_BUF_SIZE) {
Colin Crossf8387882012-05-24 17:18:41 -0700212 return -1;
213 }
David Pursell0b156632015-10-30 11:22:01 -0700214 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700215 }
216
David Pursell0b156632015-10-30 11:22:01 -0700217 if (len > TRANSPORT_BUF_SIZE) {
218 if (transport_buf_len > 0) {
219 sprintf(ERROR, "internal error: transport_buf not empty\n");
Colin Crossf8387882012-05-24 17:18:41 -0700220 return -1;
221 }
David Pursell0b156632015-10-30 11:22:01 -0700222 to_write = round_down(len, TRANSPORT_BUF_SIZE);
223 r = _command_data(transport, ptr, to_write);
Colin Crossf8387882012-05-24 17:18:41 -0700224 if (r != to_write) {
225 return -1;
226 }
227 ptr += to_write;
228 len -= to_write;
229 }
230
231 if (len > 0) {
David Pursell0b156632015-10-30 11:22:01 -0700232 if (len > TRANSPORT_BUF_SIZE) {
233 sprintf(ERROR, "internal error: too much left for transport_buf\n");
Colin Crossf8387882012-05-24 17:18:41 -0700234 return -1;
235 }
David Pursell0b156632015-10-30 11:22:01 -0700236 memcpy(transport_buf, ptr, len);
237 transport_buf_len = len;
Colin Crossf8387882012-05-24 17:18:41 -0700238 }
239
240 return 0;
241}
242
David Pursell0b156632015-10-30 11:22:01 -0700243static int fb_download_data_sparse_flush(Transport* transport) {
244 if (transport_buf_len > 0) {
245 if (_command_data(transport, transport_buf, transport_buf_len) != transport_buf_len) {
Colin Crossf8387882012-05-24 17:18:41 -0700246 return -1;
247 }
David Pursell0b156632015-10-30 11:22:01 -0700248 transport_buf_len = 0;
Colin Crossf8387882012-05-24 17:18:41 -0700249 }
Colin Crossf8387882012-05-24 17:18:41 -0700250 return 0;
251}
252
David Pursell0b156632015-10-30 11:22:01 -0700253int fb_download_data_sparse(Transport* transport, struct sparse_file* s) {
Colin Crossf8387882012-05-24 17:18:41 -0700254 int size = sparse_file_len(s, true, false);
255 if (size <= 0) {
256 return -1;
257 }
258
Elliott Hughesfc797672015-04-07 20:12:50 -0700259 char cmd[64];
Colin Crossf8387882012-05-24 17:18:41 -0700260 sprintf(cmd, "download:%08x", size);
David Pursell0b156632015-10-30 11:22:01 -0700261 int r = _command_start(transport, cmd, size, 0);
Colin Crossf8387882012-05-24 17:18:41 -0700262 if (r < 0) {
263 return -1;
264 }
265
David Pursell0b156632015-10-30 11:22:01 -0700266 r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport);
Colin Crossf8387882012-05-24 17:18:41 -0700267 if (r < 0) {
268 return -1;
269 }
270
David Pursell0b156632015-10-30 11:22:01 -0700271 r = fb_download_data_sparse_flush(transport);
Jeremy Compostella9f0d6bd2015-02-22 10:47:16 +0100272 if (r < 0) {
273 return -1;
274 }
Colin Crossf8387882012-05-24 17:18:41 -0700275
David Pursell0b156632015-10-30 11:22:01 -0700276 return _command_end(transport);
Colin Crossf8387882012-05-24 17:18:41 -0700277}