Loading fastboot/Android.mk +1 −1 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ ifeq ($(HOST_OS),windows) LOCAL_C_INCLUDES += development/host/windows/usb/api endif LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libz LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libsparse libz ifneq ($(HOST_OS),windows) ifeq ($(HAVE_SELINUX), true) Loading fastboot/engine.c +34 −7 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include "fastboot.h" #include "make_ext4fs.h" #include "ext4_utils.h" #include <stdio.h> #include <stdlib.h> Loading Loading @@ -77,6 +76,7 @@ char *mkmsg(const char *fmt, ...) #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_FORMAT 5 #define OP_DOWNLOAD_SPARSE 6 typedef struct Action Action; Loading Loading @@ -111,6 +111,20 @@ struct image_data { void generate_ext4_image(struct image_data *image); void cleanup_image(struct image_data *image); int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) { char cmd[CMD_SIZE] = "getvar:"; int getvar_len = strlen(cmd); va_list args; response[FB_RESPONSE_SZ] = '\0'; va_start(args, fmt); vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args); va_end(args); cmd[CMD_SIZE - 1] = '\0'; return fb_command_response(usb, cmd, response); } struct generator { char *fs_type; Loading Loading @@ -278,9 +292,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) unsigned i; char cmd[CMD_SIZE]; response[FB_RESPONSE_SZ] = '\0'; snprintf(cmd, sizeof(cmd), "getvar:partition-type:%s", partition); status = fb_command_response(usb, cmd, response); status = fb_getvar(usb, response, "partition-type:%s", partition); if (status) { if (skip_if_not_supported) { fprintf(stderr, Loading Loading @@ -312,9 +324,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) return -1; } response[FB_RESPONSE_SZ] = '\0'; snprintf(cmd, sizeof(cmd), "getvar:partition-size:%s", partition); status = fb_command_response(usb, cmd, response); status = fb_getvar(usb, response, "partition-size:%s", partition); if (status) { if (skip_if_not_supported) { fprintf(stderr, Loading Loading @@ -372,6 +382,19 @@ void fb_queue_flash(const char *ptn, void *data, unsigned sz) a->msg = mkmsg("writing '%s'", ptn); } void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz) { Action *a; a = queue_action(OP_DOWNLOAD_SPARSE, ""); a->data = s; a->size = 0; a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024); a = queue_action(OP_COMMAND, "flash:%s", ptn); a->msg = mkmsg("writing '%s'", ptn); } static int match(char *str, const char **value, unsigned count) { const char *val; Loading Loading @@ -572,6 +595,10 @@ int fb_execute_queue(usb_handle *usb) status = fb_format(a, usb, (int)a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else { die("bogus action"); } Loading fastboot/fastboot.c +257 −56 Original line number Diff line number Diff line Loading @@ -26,22 +26,36 @@ * SUCH DAMAGE. */ #define _LARGEFILE64_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <limits.h> #include <ctype.h> #include <getopt.h> #include <sys/time.h> #include <sys/types.h> #include <bootimg.h> #include <sparse/sparse.h> #include <zipfile/zipfile.h> #include "fastboot.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define DEFAULT_SPARSE_LIMIT (256 * 1024 * 1024) char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); Loading @@ -59,6 +73,8 @@ static const char *cmdline = 0; static int wipe_data = 0; static unsigned short vendor_id = 0; static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; static unsigned base_addr = 0x10000000; Loading Loading @@ -117,7 +133,27 @@ char *find_item(const char *item, const char *product) #ifdef _WIN32 void *load_file(const char *fn, unsigned *_sz); int64_t file_size(const char *fn); #else #if defined(__APPLE__) && defined(__MACH__) #define lseek64 lseek #define off64_t off_t #endif int64_t file_size(const char *fn) { off64_t off; int fd; fd = open(fn, O_RDONLY); if (fd < 0) return -1; off = lseek64(fd, 0, SEEK_END); close(fd); return off; } void *load_file(const char *fn, unsigned *_sz) { char *data; Loading Loading @@ -259,6 +295,8 @@ void usage(void) " -i <vendor id> specify a custom USB vendor id\n" " -b <base_addr> specify a custom kernel base address\n" " -n <page size> specify the nand page size. default: 2048\n" " -S <size>[K|M|G] automatically sparse files greater than\n" " size. default: 256M, 0 to disable\n" ); } Loading Loading @@ -444,6 +482,110 @@ void queue_info_dump(void) fb_queue_notice("--------------------------------------------"); } struct sparse_file **load_sparse_files(const char *fname, int max_size) { int fd; struct sparse_file *s; int files; struct sparse_file **out_s; fd = open(fname, O_RDONLY | O_BINARY); if (fd < 0) { die("cannot open '%s'\n", fname); } s = sparse_file_import_auto(fd, false); if (!s) { die("cannot sparse read file '%s'\n", fname); } files = sparse_file_resparse(s, max_size, NULL, 0); if (files < 0) { die("Failed to resparse '%s'\n", fname); } out_s = calloc(sizeof(struct sparse_file *), files + 1); if (!out_s) { die("Failed to allocate sparse file array\n"); } files = sparse_file_resparse(s, max_size, out_s, files); if (files < 0) { die("Failed to resparse '%s'\n", fname); } return out_s; } static int64_t get_target_sparse_limit(struct usb_handle *usb) { int64_t limit = 0; char response[FB_RESPONSE_SZ + 1]; int status = fb_getvar(usb, response, "max-download-size"); if (!status) { limit = strtoul(response, NULL, 0); if (limit > 0) { fprintf(stderr, "target reported max download size of %lld bytes\n", limit); } } return limit; } static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size) { int64_t limit; if (sparse_limit == 0) { return 0; } else if (sparse_limit > 0) { limit = sparse_limit; } else { if (target_sparse_limit == -1) { target_sparse_limit = get_target_sparse_limit(usb); } if (target_sparse_limit > 0) { limit = target_sparse_limit; } else { limit = DEFAULT_SPARSE_LIMIT; } } if (size > limit) { return limit; } return 0; } void do_flash(usb_handle *usb, const char *pname, const char *fname) { int64_t sz64; void *data; int64_t limit; sz64 = file_size(fname); limit = get_sparse_limit(usb, sz64); if (limit) { struct sparse_file **s = load_sparse_files(fname, limit); if (s == NULL) { die("cannot sparse load '%s'\n", fname); } while (*s) { sz64 = sparse_file_len(*s, true, false); fb_queue_flash_sparse(pname, *s++, sz64); } } else { unsigned int sz; data = load_file(fname, &sz); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); } } void do_update_signature(zipfile_t zip, char *fn) { void *data; Loading Loading @@ -581,73 +723,136 @@ int do_oem_command(int argc, char **argv) return 0; } static int64_t parse_num(const char *arg) { char *endptr; unsigned long long num; num = strtoull(arg, &endptr, 0); if (endptr == arg) { return -1; } if (*endptr == 'k' || *endptr == 'K') { if (num >= (-1ULL) / 1024) { return -1; } num *= 1024LL; endptr++; } else if (*endptr == 'm' || *endptr == 'M') { if (num >= (-1ULL) / (1024 * 1024)) { return -1; } num *= 1024LL * 1024LL; endptr++; } else if (*endptr == 'g' || *endptr == 'G') { if (num >= (-1ULL) / (1024 * 1024 * 1024)) { return -1; } num *= 1024LL * 1024LL * 1024LL; endptr++; } if (*endptr != '\0') { return -1; } if (num > INT64_MAX) { return -1; } return num; } int main(int argc, char **argv) { int wants_wipe = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int wants_device_list = 0; void *data; unsigned sz; unsigned page_size = 2048; int status; int c; int r; skip(1); if (argc == 0) { usage(); return 1; } if (!strcmp(*argv, "help")) { usage(); return 0; } const struct option longopts = { 0, 0, 0, 0 }; serial = getenv("ANDROID_SERIAL"); while (argc > 0) { if(!strcmp(*argv, "-w")) { while (1) { c = getopt_long(argc, argv, "wb:n:s:S:lp:c:i:m:h", &longopts, NULL); if (c < 0) { break; } switch (c) { case 'w': wants_wipe = 1; skip(1); } else if(!strcmp(*argv, "-b")) { require(2); base_addr = strtoul(argv[1], 0, 16); skip(2); } else if(!strcmp(*argv, "-n")) { require(2); page_size = (unsigned)strtoul(argv[1], NULL, 0); break; case 'b': base_addr = strtoul(optarg, 0, 16); break; case 'n': page_size = (unsigned)strtoul(optarg, NULL, 0); if (!page_size) die("invalid page size"); skip(2); } else if(!strcmp(*argv, "-s")) { require(2); serial = argv[1]; skip(2); } else if(!strcmp(*argv, "-l")) { break; case 's': serial = optarg; break; case 'S': sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'l': long_listing = 1; skip(1); } else if(!strcmp(*argv, "-p")) { require(2); product = argv[1]; skip(2); } else if(!strcmp(*argv, "-c")) { require(2); cmdline = argv[1]; skip(2); } else if(!strcmp(*argv, "-i")) { break; case 'p': product = optarg; break; case 'c': cmdline = optarg; break; case 'i': { char *endptr = NULL; unsigned long val; require(2); val = strtoul(argv[1], &endptr, 0); val = strtoul(optarg, &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", argv[1]); die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; skip(2); } else if (!strcmp(*argv, "devices")) { break; } case 'h': usage(); return 1; case '?': return 1; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (!strcmp(*argv, "devices")) { skip(1); wants_device_list = 1; } else if(!strcmp(*argv, "getvar")) { list_devices(); return 0; } usb = open_device(); while (argc > 0) { if(!strcmp(*argv, "getvar")) { require(2); fb_queue_display(argv[1], argv[1]); skip(2); Loading Loading @@ -704,9 +909,7 @@ int main(int argc, char **argv) skip(2); } if (fname == 0) die("cannot determine image filename for '%s'", pname); data = load_file(fname, &sz); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); do_flash(usb, pname, fname); } else if(!strcmp(*argv, "flash:raw")) { char *pname = argv[1]; char *kname = argv[2]; Loading Loading @@ -736,15 +939,15 @@ int main(int argc, char **argv) wants_reboot = 1; } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); } else if (!strcmp(*argv, "help")) { usage(); return 0; } else { usage(); return 1; } } if (wants_device_list) list_devices(); if (wants_wipe) { fb_queue_erase("userdata"); fb_queue_format("userdata", 1); Loading @@ -760,8 +963,6 @@ int main(int argc, char **argv) if (fb_queue_is_empty()) return 0; usb = open_device(); status = fb_execute_queue(usb); return (status) ? 1 : 0; } fastboot/fastboot.h +5 −0 Original line number Diff line number Diff line Loading @@ -31,17 +31,22 @@ #include "usb.h" struct sparse_file; /* protocol.c - fastboot protocol */ int fb_command(usb_handle *usb, const char *cmd); int fb_command_response(usb_handle *usb, const char *cmd, char *response); int fb_download_data(usb_handle *usb, const void *data, unsigned size); int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s); char *fb_get_error(void); #define FB_COMMAND_SZ 64 #define FB_RESPONSE_SZ 64 /* engine.c - high level command queue engine */ int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...); void fb_queue_flash(const char *ptn, void *data, unsigned sz);; void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz); void fb_queue_erase(const char *ptn); void fb_queue_format(const char *ptn, int skip_if_not_supported); void fb_queue_require(const char *prod, const char *var, int invert, Loading fastboot/protocol.c +160 −27 Original line number Diff line number Diff line Loading @@ -26,11 +26,18 @@ * SUCH DAMAGE. */ #define min(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) #define round_down(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sparse/sparse.h> #include "fastboot.h" static char ERROR[128]; Loading @@ -40,8 +47,7 @@ char *fb_get_error(void) return ERROR; } static int check_response(usb_handle *usb, unsigned size, unsigned data_okay, char *response) static int check_response(usb_handle *usb, unsigned int size, char *response) { unsigned char status[65]; int r; Loading Loading @@ -82,7 +88,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; } if(!memcmp(status, "DATA", 4) && data_okay){ if(!memcmp(status, "DATA", 4) && size > 0){ unsigned dsize = strtoul((char*) status + 4, 0, 16); if(dsize > size) { strcpy(ERROR, "data size too large"); Loading @@ -100,8 +106,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; } static int _command_send(usb_handle *usb, const char *cmd, const void *data, unsigned size, static int _command_start(usb_handle *usb, const char *cmd, unsigned size, char *response) { int cmdsize = strlen(cmd); Loading @@ -122,17 +127,13 @@ static int _command_send(usb_handle *usb, const char *cmd, return -1; } if(data == 0) { return check_response(usb, size, 0, response); return check_response(usb, size, response); } r = check_response(usb, size, 1, 0); if(r < 0) { return -1; } size = r; static int _command_data(usb_handle *usb, const void *data, unsigned size) { int r; if(size) { r = usb_write(usb, data, size); if(r < 0) { sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); Loading @@ -144,24 +145,63 @@ static int _command_send(usb_handle *usb, const char *cmd, usb_close(usb); return -1; } return r; } r = check_response(usb, 0, 0, 0); static int _command_end(usb_handle *usb) { int r; r = check_response(usb, 0, 0); if(r < 0) { return -1; } else { } return 0; } static int _command_send(usb_handle *usb, const char *cmd, const void *data, unsigned size, char *response) { int r; if (size == 0) { return -1; } r = _command_start(usb, cmd, size, response); if (r < 0) { return -1; } r = _command_data(usb, data, size); if (r < 0) { return -1; } r = _command_end(usb); if(r < 0) { return -1; } return size; } static int _command_send_no_data(usb_handle *usb, const char *cmd, char *response) { int r; return _command_start(usb, cmd, 0, response); } int fb_command(usb_handle *usb, const char *cmd) { return _command_send(usb, cmd, 0, 0, 0); return _command_send_no_data(usb, cmd, 0); } int fb_command_response(usb_handle *usb, const char *cmd, char *response) { return _command_send(usb, cmd, 0, 0, response); return _command_send_no_data(usb, cmd, response); } int fb_download_data(usb_handle *usb, const void *data, unsigned size) Loading @@ -179,3 +219,96 @@ int fb_download_data(usb_handle *usb, const void *data, unsigned size) } } #define USB_BUF_SIZE 512 static char usb_buf[USB_BUF_SIZE]; static int usb_buf_len; static int fb_download_data_sparse_write(void *priv, const void *data, int len) { int r; usb_handle *usb = priv; int to_write; const char *ptr = data; if (usb_buf_len) { to_write = min(USB_BUF_SIZE - usb_buf_len, len); memcpy(usb_buf + usb_buf_len, ptr, to_write); usb_buf_len += to_write; ptr += to_write; len -= to_write; } if (usb_buf_len == USB_BUF_SIZE) { r = _command_data(usb, usb_buf, USB_BUF_SIZE); if (r != USB_BUF_SIZE) { return -1; } usb_buf_len = 0; } if (len > USB_BUF_SIZE) { if (usb_buf_len > 0) { sprintf(ERROR, "internal error: usb_buf not empty\n"); return -1; } to_write = round_down(len, USB_BUF_SIZE); r = _command_data(usb, ptr, to_write); if (r != to_write) { return -1; } ptr += to_write; len -= to_write; } if (len > 0) { if (len > USB_BUF_SIZE) { sprintf(ERROR, "internal error: too much left for usb_buf\n"); return -1; } memcpy(usb_buf, ptr, len); usb_buf_len = len; } return 0; } static int fb_download_data_sparse_flush(usb_handle *usb) { int r; if (usb_buf_len > 0) { r = _command_data(usb, usb_buf, usb_buf_len); if (r != usb_buf_len) { return -1; } usb_buf_len = 0; } return 0; } int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s) { char cmd[64]; int r; int size = sparse_file_len(s, true, false); if (size <= 0) { return -1; } sprintf(cmd, "download:%08x", size); r = _command_start(usb, cmd, size, 0); if (r < 0) { return -1; } r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb); if (r < 0) { return -1; } fb_download_data_sparse_flush(usb); return _command_end(usb); } Loading
fastboot/Android.mk +1 −1 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ ifeq ($(HOST_OS),windows) LOCAL_C_INCLUDES += development/host/windows/usb/api endif LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libz LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libsparse libz ifneq ($(HOST_OS),windows) ifeq ($(HAVE_SELINUX), true) Loading
fastboot/engine.c +34 −7 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include "fastboot.h" #include "make_ext4fs.h" #include "ext4_utils.h" #include <stdio.h> #include <stdlib.h> Loading Loading @@ -77,6 +76,7 @@ char *mkmsg(const char *fmt, ...) #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_FORMAT 5 #define OP_DOWNLOAD_SPARSE 6 typedef struct Action Action; Loading Loading @@ -111,6 +111,20 @@ struct image_data { void generate_ext4_image(struct image_data *image); void cleanup_image(struct image_data *image); int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) { char cmd[CMD_SIZE] = "getvar:"; int getvar_len = strlen(cmd); va_list args; response[FB_RESPONSE_SZ] = '\0'; va_start(args, fmt); vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args); va_end(args); cmd[CMD_SIZE - 1] = '\0'; return fb_command_response(usb, cmd, response); } struct generator { char *fs_type; Loading Loading @@ -278,9 +292,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) unsigned i; char cmd[CMD_SIZE]; response[FB_RESPONSE_SZ] = '\0'; snprintf(cmd, sizeof(cmd), "getvar:partition-type:%s", partition); status = fb_command_response(usb, cmd, response); status = fb_getvar(usb, response, "partition-type:%s", partition); if (status) { if (skip_if_not_supported) { fprintf(stderr, Loading Loading @@ -312,9 +324,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) return -1; } response[FB_RESPONSE_SZ] = '\0'; snprintf(cmd, sizeof(cmd), "getvar:partition-size:%s", partition); status = fb_command_response(usb, cmd, response); status = fb_getvar(usb, response, "partition-size:%s", partition); if (status) { if (skip_if_not_supported) { fprintf(stderr, Loading Loading @@ -372,6 +382,19 @@ void fb_queue_flash(const char *ptn, void *data, unsigned sz) a->msg = mkmsg("writing '%s'", ptn); } void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz) { Action *a; a = queue_action(OP_DOWNLOAD_SPARSE, ""); a->data = s; a->size = 0; a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024); a = queue_action(OP_COMMAND, "flash:%s", ptn); a->msg = mkmsg("writing '%s'", ptn); } static int match(char *str, const char **value, unsigned count) { const char *val; Loading Loading @@ -572,6 +595,10 @@ int fb_execute_queue(usb_handle *usb) status = fb_format(a, usb, (int)a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else { die("bogus action"); } Loading
fastboot/fastboot.c +257 −56 Original line number Diff line number Diff line Loading @@ -26,22 +26,36 @@ * SUCH DAMAGE. */ #define _LARGEFILE64_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <limits.h> #include <ctype.h> #include <getopt.h> #include <sys/time.h> #include <sys/types.h> #include <bootimg.h> #include <sparse/sparse.h> #include <zipfile/zipfile.h> #include "fastboot.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define DEFAULT_SPARSE_LIMIT (256 * 1024 * 1024) char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); Loading @@ -59,6 +73,8 @@ static const char *cmdline = 0; static int wipe_data = 0; static unsigned short vendor_id = 0; static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; static unsigned base_addr = 0x10000000; Loading Loading @@ -117,7 +133,27 @@ char *find_item(const char *item, const char *product) #ifdef _WIN32 void *load_file(const char *fn, unsigned *_sz); int64_t file_size(const char *fn); #else #if defined(__APPLE__) && defined(__MACH__) #define lseek64 lseek #define off64_t off_t #endif int64_t file_size(const char *fn) { off64_t off; int fd; fd = open(fn, O_RDONLY); if (fd < 0) return -1; off = lseek64(fd, 0, SEEK_END); close(fd); return off; } void *load_file(const char *fn, unsigned *_sz) { char *data; Loading Loading @@ -259,6 +295,8 @@ void usage(void) " -i <vendor id> specify a custom USB vendor id\n" " -b <base_addr> specify a custom kernel base address\n" " -n <page size> specify the nand page size. default: 2048\n" " -S <size>[K|M|G] automatically sparse files greater than\n" " size. default: 256M, 0 to disable\n" ); } Loading Loading @@ -444,6 +482,110 @@ void queue_info_dump(void) fb_queue_notice("--------------------------------------------"); } struct sparse_file **load_sparse_files(const char *fname, int max_size) { int fd; struct sparse_file *s; int files; struct sparse_file **out_s; fd = open(fname, O_RDONLY | O_BINARY); if (fd < 0) { die("cannot open '%s'\n", fname); } s = sparse_file_import_auto(fd, false); if (!s) { die("cannot sparse read file '%s'\n", fname); } files = sparse_file_resparse(s, max_size, NULL, 0); if (files < 0) { die("Failed to resparse '%s'\n", fname); } out_s = calloc(sizeof(struct sparse_file *), files + 1); if (!out_s) { die("Failed to allocate sparse file array\n"); } files = sparse_file_resparse(s, max_size, out_s, files); if (files < 0) { die("Failed to resparse '%s'\n", fname); } return out_s; } static int64_t get_target_sparse_limit(struct usb_handle *usb) { int64_t limit = 0; char response[FB_RESPONSE_SZ + 1]; int status = fb_getvar(usb, response, "max-download-size"); if (!status) { limit = strtoul(response, NULL, 0); if (limit > 0) { fprintf(stderr, "target reported max download size of %lld bytes\n", limit); } } return limit; } static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size) { int64_t limit; if (sparse_limit == 0) { return 0; } else if (sparse_limit > 0) { limit = sparse_limit; } else { if (target_sparse_limit == -1) { target_sparse_limit = get_target_sparse_limit(usb); } if (target_sparse_limit > 0) { limit = target_sparse_limit; } else { limit = DEFAULT_SPARSE_LIMIT; } } if (size > limit) { return limit; } return 0; } void do_flash(usb_handle *usb, const char *pname, const char *fname) { int64_t sz64; void *data; int64_t limit; sz64 = file_size(fname); limit = get_sparse_limit(usb, sz64); if (limit) { struct sparse_file **s = load_sparse_files(fname, limit); if (s == NULL) { die("cannot sparse load '%s'\n", fname); } while (*s) { sz64 = sparse_file_len(*s, true, false); fb_queue_flash_sparse(pname, *s++, sz64); } } else { unsigned int sz; data = load_file(fname, &sz); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); } } void do_update_signature(zipfile_t zip, char *fn) { void *data; Loading Loading @@ -581,73 +723,136 @@ int do_oem_command(int argc, char **argv) return 0; } static int64_t parse_num(const char *arg) { char *endptr; unsigned long long num; num = strtoull(arg, &endptr, 0); if (endptr == arg) { return -1; } if (*endptr == 'k' || *endptr == 'K') { if (num >= (-1ULL) / 1024) { return -1; } num *= 1024LL; endptr++; } else if (*endptr == 'm' || *endptr == 'M') { if (num >= (-1ULL) / (1024 * 1024)) { return -1; } num *= 1024LL * 1024LL; endptr++; } else if (*endptr == 'g' || *endptr == 'G') { if (num >= (-1ULL) / (1024 * 1024 * 1024)) { return -1; } num *= 1024LL * 1024LL * 1024LL; endptr++; } if (*endptr != '\0') { return -1; } if (num > INT64_MAX) { return -1; } return num; } int main(int argc, char **argv) { int wants_wipe = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int wants_device_list = 0; void *data; unsigned sz; unsigned page_size = 2048; int status; int c; int r; skip(1); if (argc == 0) { usage(); return 1; } if (!strcmp(*argv, "help")) { usage(); return 0; } const struct option longopts = { 0, 0, 0, 0 }; serial = getenv("ANDROID_SERIAL"); while (argc > 0) { if(!strcmp(*argv, "-w")) { while (1) { c = getopt_long(argc, argv, "wb:n:s:S:lp:c:i:m:h", &longopts, NULL); if (c < 0) { break; } switch (c) { case 'w': wants_wipe = 1; skip(1); } else if(!strcmp(*argv, "-b")) { require(2); base_addr = strtoul(argv[1], 0, 16); skip(2); } else if(!strcmp(*argv, "-n")) { require(2); page_size = (unsigned)strtoul(argv[1], NULL, 0); break; case 'b': base_addr = strtoul(optarg, 0, 16); break; case 'n': page_size = (unsigned)strtoul(optarg, NULL, 0); if (!page_size) die("invalid page size"); skip(2); } else if(!strcmp(*argv, "-s")) { require(2); serial = argv[1]; skip(2); } else if(!strcmp(*argv, "-l")) { break; case 's': serial = optarg; break; case 'S': sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'l': long_listing = 1; skip(1); } else if(!strcmp(*argv, "-p")) { require(2); product = argv[1]; skip(2); } else if(!strcmp(*argv, "-c")) { require(2); cmdline = argv[1]; skip(2); } else if(!strcmp(*argv, "-i")) { break; case 'p': product = optarg; break; case 'c': cmdline = optarg; break; case 'i': { char *endptr = NULL; unsigned long val; require(2); val = strtoul(argv[1], &endptr, 0); val = strtoul(optarg, &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", argv[1]); die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; skip(2); } else if (!strcmp(*argv, "devices")) { break; } case 'h': usage(); return 1; case '?': return 1; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (!strcmp(*argv, "devices")) { skip(1); wants_device_list = 1; } else if(!strcmp(*argv, "getvar")) { list_devices(); return 0; } usb = open_device(); while (argc > 0) { if(!strcmp(*argv, "getvar")) { require(2); fb_queue_display(argv[1], argv[1]); skip(2); Loading Loading @@ -704,9 +909,7 @@ int main(int argc, char **argv) skip(2); } if (fname == 0) die("cannot determine image filename for '%s'", pname); data = load_file(fname, &sz); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); do_flash(usb, pname, fname); } else if(!strcmp(*argv, "flash:raw")) { char *pname = argv[1]; char *kname = argv[2]; Loading Loading @@ -736,15 +939,15 @@ int main(int argc, char **argv) wants_reboot = 1; } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); } else if (!strcmp(*argv, "help")) { usage(); return 0; } else { usage(); return 1; } } if (wants_device_list) list_devices(); if (wants_wipe) { fb_queue_erase("userdata"); fb_queue_format("userdata", 1); Loading @@ -760,8 +963,6 @@ int main(int argc, char **argv) if (fb_queue_is_empty()) return 0; usb = open_device(); status = fb_execute_queue(usb); return (status) ? 1 : 0; }
fastboot/fastboot.h +5 −0 Original line number Diff line number Diff line Loading @@ -31,17 +31,22 @@ #include "usb.h" struct sparse_file; /* protocol.c - fastboot protocol */ int fb_command(usb_handle *usb, const char *cmd); int fb_command_response(usb_handle *usb, const char *cmd, char *response); int fb_download_data(usb_handle *usb, const void *data, unsigned size); int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s); char *fb_get_error(void); #define FB_COMMAND_SZ 64 #define FB_RESPONSE_SZ 64 /* engine.c - high level command queue engine */ int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...); void fb_queue_flash(const char *ptn, void *data, unsigned sz);; void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz); void fb_queue_erase(const char *ptn); void fb_queue_format(const char *ptn, int skip_if_not_supported); void fb_queue_require(const char *prod, const char *var, int invert, Loading
fastboot/protocol.c +160 −27 Original line number Diff line number Diff line Loading @@ -26,11 +26,18 @@ * SUCH DAMAGE. */ #define min(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) #define round_down(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sparse/sparse.h> #include "fastboot.h" static char ERROR[128]; Loading @@ -40,8 +47,7 @@ char *fb_get_error(void) return ERROR; } static int check_response(usb_handle *usb, unsigned size, unsigned data_okay, char *response) static int check_response(usb_handle *usb, unsigned int size, char *response) { unsigned char status[65]; int r; Loading Loading @@ -82,7 +88,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; } if(!memcmp(status, "DATA", 4) && data_okay){ if(!memcmp(status, "DATA", 4) && size > 0){ unsigned dsize = strtoul((char*) status + 4, 0, 16); if(dsize > size) { strcpy(ERROR, "data size too large"); Loading @@ -100,8 +106,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; } static int _command_send(usb_handle *usb, const char *cmd, const void *data, unsigned size, static int _command_start(usb_handle *usb, const char *cmd, unsigned size, char *response) { int cmdsize = strlen(cmd); Loading @@ -122,17 +127,13 @@ static int _command_send(usb_handle *usb, const char *cmd, return -1; } if(data == 0) { return check_response(usb, size, 0, response); return check_response(usb, size, response); } r = check_response(usb, size, 1, 0); if(r < 0) { return -1; } size = r; static int _command_data(usb_handle *usb, const void *data, unsigned size) { int r; if(size) { r = usb_write(usb, data, size); if(r < 0) { sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); Loading @@ -144,24 +145,63 @@ static int _command_send(usb_handle *usb, const char *cmd, usb_close(usb); return -1; } return r; } r = check_response(usb, 0, 0, 0); static int _command_end(usb_handle *usb) { int r; r = check_response(usb, 0, 0); if(r < 0) { return -1; } else { } return 0; } static int _command_send(usb_handle *usb, const char *cmd, const void *data, unsigned size, char *response) { int r; if (size == 0) { return -1; } r = _command_start(usb, cmd, size, response); if (r < 0) { return -1; } r = _command_data(usb, data, size); if (r < 0) { return -1; } r = _command_end(usb); if(r < 0) { return -1; } return size; } static int _command_send_no_data(usb_handle *usb, const char *cmd, char *response) { int r; return _command_start(usb, cmd, 0, response); } int fb_command(usb_handle *usb, const char *cmd) { return _command_send(usb, cmd, 0, 0, 0); return _command_send_no_data(usb, cmd, 0); } int fb_command_response(usb_handle *usb, const char *cmd, char *response) { return _command_send(usb, cmd, 0, 0, response); return _command_send_no_data(usb, cmd, response); } int fb_download_data(usb_handle *usb, const void *data, unsigned size) Loading @@ -179,3 +219,96 @@ int fb_download_data(usb_handle *usb, const void *data, unsigned size) } } #define USB_BUF_SIZE 512 static char usb_buf[USB_BUF_SIZE]; static int usb_buf_len; static int fb_download_data_sparse_write(void *priv, const void *data, int len) { int r; usb_handle *usb = priv; int to_write; const char *ptr = data; if (usb_buf_len) { to_write = min(USB_BUF_SIZE - usb_buf_len, len); memcpy(usb_buf + usb_buf_len, ptr, to_write); usb_buf_len += to_write; ptr += to_write; len -= to_write; } if (usb_buf_len == USB_BUF_SIZE) { r = _command_data(usb, usb_buf, USB_BUF_SIZE); if (r != USB_BUF_SIZE) { return -1; } usb_buf_len = 0; } if (len > USB_BUF_SIZE) { if (usb_buf_len > 0) { sprintf(ERROR, "internal error: usb_buf not empty\n"); return -1; } to_write = round_down(len, USB_BUF_SIZE); r = _command_data(usb, ptr, to_write); if (r != to_write) { return -1; } ptr += to_write; len -= to_write; } if (len > 0) { if (len > USB_BUF_SIZE) { sprintf(ERROR, "internal error: too much left for usb_buf\n"); return -1; } memcpy(usb_buf, ptr, len); usb_buf_len = len; } return 0; } static int fb_download_data_sparse_flush(usb_handle *usb) { int r; if (usb_buf_len > 0) { r = _command_data(usb, usb_buf, usb_buf_len); if (r != usb_buf_len) { return -1; } usb_buf_len = 0; } return 0; } int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s) { char cmd[64]; int r; int size = sparse_file_len(s, true, false); if (size <= 0) { return -1; } sprintf(cmd, "download:%08x", size); r = _command_start(usb, cmd, size, 0); if (r < 0) { return -1; } r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb); if (r < 0) { return -1; } fb_download_data_sparse_flush(usb); return _command_end(usb); }