/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fastboot.h" #include "fs.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, void *second, unsigned second_size, unsigned second_offset, unsigned page_size, unsigned base, unsigned tags_offset, unsigned *bootimg_size); static usb_handle *usb = 0; static const char *serial = 0; static const char *product = 0; static const char *cmdline = 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; unsigned page_size = 2048; unsigned base_addr = 0x10000000; unsigned kernel_offset = 0x00008000; unsigned ramdisk_offset = 0x01000000; unsigned second_offset = 0x00f00000; unsigned tags_offset = 0x00000100; enum fb_buffer_type { FB_BUFFER, FB_BUFFER_SPARSE, }; struct fastboot_buffer { enum fb_buffer_type type; void *data; unsigned int sz; }; static struct { char img_name[13]; char sig_name[13]; char part_name[9]; bool is_optional; } images[] = { {"boot.img", "boot.sig", "boot", false}, {"recovery.img", "recovery.sig", "recovery", true}, {"system.img", "system.sig", "system", false}, {"vendor.img", "vendor.sig", "vendor", true}, }; void get_my_path(char *path); char *find_item(const char *item, const char *product) { char *dir; char *fn; char path[PATH_MAX + 128]; if(!strcmp(item,"boot")) { fn = "boot.img"; } else if(!strcmp(item,"recovery")) { fn = "recovery.img"; } else if(!strcmp(item,"system")) { fn = "system.img"; } else if(!strcmp(item,"vendor")) { fn = "vendor.img"; } else if(!strcmp(item,"userdata")) { fn = "userdata.img"; } else if(!strcmp(item,"cache")) { fn = "cache.img"; } else if(!strcmp(item,"info")) { fn = "android-info.txt"; } else { fprintf(stderr,"unknown partition '%s'\n", item); return 0; } if(product) { get_my_path(path); sprintf(path + strlen(path), "../../../target/product/%s/%s", product, fn); return strdup(path); } dir = getenv("ANDROID_PRODUCT_OUT"); if((dir == 0) || (dir[0] == 0)) { die("neither -p product specified nor ANDROID_PRODUCT_OUT set"); return 0; } sprintf(path, "%s/%s", dir, fn); return strdup(path); } static int64_t file_size(int fd) { struct stat st; int ret; ret = fstat(fd, &st); return ret ? -1 : st.st_size; } static void *load_fd(int fd, unsigned *_sz) { char *data; int sz; int errno_tmp; data = 0; sz = file_size(fd); if (sz < 0) { goto oops; } data = (char*) malloc(sz); if(data == 0) goto oops; if(read(fd, data, sz) != sz) goto oops; close(fd); if(_sz) *_sz = sz; return data; oops: errno_tmp = errno; close(fd); if(data != 0) free(data); errno = errno_tmp; return 0; } static void *load_file(const char *fn, unsigned *_sz) { int fd; fd = open(fn, O_RDONLY | O_BINARY); if(fd < 0) return 0; return load_fd(fd, _sz); } int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial) { if(!(vendor_id && (info->dev_vendor == vendor_id)) && (info->dev_vendor != 0x18d1) && // Google (info->dev_vendor != 0x8087) && // Intel (info->dev_vendor != 0x0451) && (info->dev_vendor != 0x0502) && (info->dev_vendor != 0x0fce) && // Sony Ericsson (info->dev_vendor != 0x05c6) && // Qualcomm (info->dev_vendor != 0x22b8) && // Motorola (info->dev_vendor != 0x0955) && // Nvidia (info->dev_vendor != 0x413c) && // DELL (info->dev_vendor != 0x2314) && // INQ Mobile (info->dev_vendor != 0x0b05) && // Asus (info->dev_vendor != 0x0bb4)) // HTC return -1; if(info->ifc_class != 0xff) return -1; if(info->ifc_subclass != 0x42) return -1; if(info->ifc_protocol != 0x03) return -1; // require matching serial number or device path if requested // at the command line with the -s option. if (local_serial && (strcmp(local_serial, info->serial_number) != 0 && strcmp(local_serial, info->device_path) != 0)) return -1; return 0; } int match_fastboot(usb_ifc_info *info) { return match_fastboot_with_serial(info, serial); } int list_devices_callback(usb_ifc_info *info) { if (match_fastboot_with_serial(info, NULL) == 0) { char* serial = info->serial_number; if (!info->writable) { serial = "no permissions"; // like "adb devices" } if (!serial[0]) { serial = "????????????"; } // output compatible with "adb devices" if (!long_listing) { printf("%s\tfastboot\n", serial); } else if (!strcmp("", info->device_path)) { printf("%-22s fastboot\n", serial); } else { printf("%-22s fastboot %s\n", serial, info->device_path); } } return -1; } usb_handle *open_device(void) { static usb_handle *usb = 0; int announce = 1; if(usb) return usb; for(;;) { usb = usb_open(match_fastboot); if(usb) return usb; if(announce) { announce = 0; fprintf(stderr,"< waiting for device >\n"); } usleep(1000); } } void list_devices(void) { // We don't actually open a USB device here, // just getting our callback called so we can // list all the connected devices. usb_open(list_devices_callback); } void usage(void) { fprintf(stderr, /* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */ "usage: fastboot [