Home | History | Annotate | Download | only in fastbootd
      1 /*
      2  * Copyright (c) 2009-2013, Google Inc.
      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
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *  * Neither the name of Google, Inc. nor the names of its contributors
     15  *    may be used to endorse or promote products derived from this
     16  *    software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     22  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     25  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <inttypes.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include <sys/types.h>
     36 #include <sys/mman.h>
     37 #include <sys/stat.h>
     38 #include <unistd.h>
     39 #include <sys/reboot.h>
     40 #include <fcntl.h>
     41 
     42 #include "bootimg.h"
     43 #include "commands/boot.h"
     44 #include "commands/flash.h"
     45 #include "commands/partitions.h"
     46 #include "commands/virtual_partitions.h"
     47 #include "debug.h"
     48 #include "protocol.h"
     49 #include "trigger.h"
     50 #include "utils.h"
     51 
     52 #define ATAGS_LOCATION "/proc/atags"
     53 
     54 static void cmd_boot(struct protocol_handle *phandle, const char *arg)
     55 {
     56     int sz, atags_sz, new_atags_sz;
     57     int rv;
     58     unsigned kernel_actual;
     59     unsigned ramdisk_actual;
     60     unsigned second_actual;
     61     void *kernel_ptr;
     62     void *ramdisk_ptr;
     63     void *second_ptr;
     64     struct boot_img_hdr *hdr;
     65     char *ptr = NULL;
     66     char *atags_ptr = NULL;
     67     char *new_atags = NULL;
     68     int data_fd = 0;
     69 
     70     D(DEBUG, "cmd_boot %s\n", arg);
     71 
     72     if (phandle->download_fd < 0) {
     73         fastboot_fail(phandle, "no kernel file");
     74         return;
     75     }
     76 
     77     atags_ptr = read_atags(ATAGS_LOCATION, &atags_sz);
     78     if (atags_ptr == NULL) {
     79         fastboot_fail(phandle, "atags read error");
     80         goto error;
     81     }
     82 
     83     // TODO: With cms we can also verify partition name included as
     84     // cms signed attribute
     85     if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
     86         fastboot_fail(phandle, "Access forbiden you need the certificate");
     87         return;
     88     }
     89 
     90     sz = get_file_size(data_fd);
     91 
     92     ptr = (char *) mmap(NULL, sz, PROT_READ,
     93                         MAP_POPULATE | MAP_PRIVATE, data_fd, 0);
     94 
     95     hdr = (struct boot_img_hdr *) ptr;
     96 
     97     if (ptr == MAP_FAILED) {
     98         fastboot_fail(phandle, "internal fastbootd error");
     99         goto error;
    100     }
    101 
    102     if ((size_t) sz < sizeof(*hdr)) {
    103         fastboot_fail(phandle, "invalid bootimage header");
    104         goto error;
    105     }
    106 
    107     kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, hdr->page_size);
    108     ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, hdr->page_size);
    109     second_actual = ROUND_TO_PAGE(hdr->second_size, hdr->page_size);
    110 
    111     new_atags = (char *) create_atags((unsigned *) atags_ptr, atags_sz, hdr, &new_atags_sz);
    112 
    113     if (new_atags == NULL) {
    114         fastboot_fail(phandle, "atags generate error");
    115         goto error;
    116     }
    117     if (new_atags_sz > 0x4000) {
    118         fastboot_fail(phandle, "atags file to large");
    119         goto error;
    120     }
    121 
    122     if ((int) (hdr->page_size + kernel_actual + ramdisk_actual) < sz) {
    123         fastboot_fail(phandle, "incomplete bootimage");
    124         goto error;
    125     }
    126 
    127     kernel_ptr = (void *)((uintptr_t) ptr + hdr->page_size);
    128     ramdisk_ptr = (void *)((uintptr_t) kernel_ptr + kernel_actual);
    129     second_ptr = (void *)((uintptr_t) ramdisk_ptr + ramdisk_actual);
    130 
    131     D(INFO, "preparing to boot");
    132     // Prepares boot physical address. Addresses from header are ignored
    133     rv = prepare_boot_linux(hdr->kernel_addr, kernel_ptr, kernel_actual,
    134                             hdr->ramdisk_addr, ramdisk_ptr, ramdisk_actual,
    135                             hdr->second_addr, second_ptr, second_actual,
    136                             hdr->tags_addr, new_atags, ROUND_TO_PAGE(new_atags_sz, hdr->page_size));
    137     if (rv < 0) {
    138         fastboot_fail(phandle, "kexec prepare failed");
    139         goto error;
    140     }
    141 
    142     fastboot_okay(phandle, "");
    143 
    144     free(atags_ptr);
    145     munmap(ptr, sz);
    146     free(new_atags);
    147     close(data_fd);
    148 
    149     D(INFO, "Kexec going to reboot");
    150     reboot(LINUX_REBOOT_CMD_KEXEC);
    151 
    152     fastboot_fail(phandle, "reboot error");
    153 
    154     return;
    155 
    156 error:
    157 
    158     if (atags_ptr != NULL)
    159         free(atags_ptr);
    160     if (ptr != NULL)
    161         munmap(ptr, sz);
    162 
    163 }
    164 
    165 static void cmd_erase(struct protocol_handle *phandle, const char *arg)
    166 {
    167     int partition_fd;
    168     char path[PATH_MAX];
    169     D(DEBUG, "cmd_erase %s\n", arg);
    170 
    171     if (flash_find_entry(arg, path, PATH_MAX)) {
    172         fastboot_fail(phandle, "partition table doesn't exist");
    173         return;
    174     }
    175 
    176     if (path == NULL) {
    177         fastboot_fail(phandle, "Couldn't find partition");
    178         return;
    179     }
    180 
    181     partition_fd = flash_get_partiton(path);
    182     if (partition_fd < 0) {
    183         fastboot_fail(phandle, "partiton file does not exists");
    184     }
    185 
    186     if (flash_erase(partition_fd)) {
    187         fastboot_fail(phandle, "failed to erase partition");
    188         flash_close(partition_fd);
    189         return;
    190     }
    191 
    192     if (flash_close(partition_fd) < 0) {
    193         D(ERR, "could not close device %s", strerror(errno));
    194         fastboot_fail(phandle, "failed to erase partition");
    195         return;
    196     }
    197     fastboot_okay(phandle, "");
    198 }
    199 
    200 static int GPT_header_location() {
    201     const char *location_str = fastboot_getvar("gpt_sector");
    202     char *str;
    203     int location;
    204 
    205     if (!strcmp("", location_str)) {
    206         D(INFO, "GPT location not specified using second sector");
    207         return 1;
    208     }
    209     else {
    210         location = strtoul(location_str, &str, 10);
    211         D(INFO, "GPT location specified as %d", location);
    212 
    213         if (*str != '\0')
    214             return -1;
    215 
    216         return location - 1;
    217     }
    218 }
    219 
    220 static void cmd_gpt_layout(struct protocol_handle *phandle, const char *arg) {
    221     struct GPT_entry_table *oldtable;
    222     int location;
    223     struct GPT_content content;
    224     const char *device;
    225     device = fastboot_getvar("blockdev");
    226 
    227     if (!strcmp(device, "")) {
    228         fastboot_fail(phandle, "blockdev not defined in config file");
    229         return;
    230     }
    231 
    232     //TODO: add same verification as in cmd_flash
    233     if (phandle->download_fd < 0) {
    234         fastboot_fail(phandle, "no layout file");
    235         return;
    236     }
    237 
    238     location = GPT_header_location();
    239     oldtable = GPT_get_device(device, location);
    240 
    241     GPT_default_content(&content, oldtable);
    242     if (oldtable == NULL)
    243         D(WARN, "Could not get old gpt table");
    244     else
    245         GPT_release_device(oldtable);
    246 
    247     if (!GPT_parse_file(phandle->download_fd, &content)) {
    248         fastboot_fail(phandle, "Could not parse partition config file");
    249         return;
    250     }
    251 
    252     if (trigger_gpt_layout(&content)) {
    253         fastboot_fail(phandle, "Vendor forbids this opperation");
    254         GPT_release_content(&content);
    255         return;
    256     }
    257 
    258     if (!GPT_write_content(device, &content)) {
    259         fastboot_fail(phandle, "Unable to write gpt file");
    260         GPT_release_content(&content);
    261         return;
    262     }
    263 
    264     GPT_release_content(&content);
    265     fastboot_okay(phandle, "");
    266 }
    267 
    268 static void cmd_flash(struct protocol_handle *phandle, const char *arg)
    269 {
    270     int partition;
    271     uint64_t sz;
    272     char data[BOOT_MAGIC_SIZE];
    273     char path[PATH_MAX];
    274     ssize_t header_sz = 0;
    275     int data_fd = 0;
    276 
    277     D(DEBUG, "cmd_flash %s\n", arg);
    278 
    279     if (try_handle_virtual_partition(phandle, arg)) {
    280         return;
    281     }
    282 
    283     if (phandle->download_fd < 0) {
    284         fastboot_fail(phandle, "no kernel file");
    285         return;
    286     }
    287 
    288     if (flash_find_entry(arg, path, PATH_MAX)) {
    289         fastboot_fail(phandle, "partition table doesn't exist");
    290         return;
    291     }
    292 
    293     if (flash_validate_certificate(phandle->download_fd, &data_fd) != 1) {
    294         fastboot_fail(phandle, "Access forbiden you need certificate");
    295         return;
    296     }
    297 
    298     // TODO: Maybe its goot idea to check whether the partition is bootable
    299     if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
    300         if (read_data_once(data_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
    301             fastboot_fail(phandle, "incoming data read error, cannot read boot header");
    302             return;
    303         }
    304         if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
    305             fastboot_fail(phandle, "image is not a boot image");
    306             return;
    307         }
    308     }
    309 
    310     partition = flash_get_partiton(path);
    311 
    312     sz = get_file_size64(data_fd);
    313 
    314     sz -= header_sz;
    315 
    316     if (sz > get_file_size64(partition)) {
    317         flash_close(partition);
    318         D(WARN, "size of file too large");
    319         fastboot_fail(phandle, "size of file too large");
    320         return;
    321     }
    322 
    323     D(INFO, "writing %"PRId64" bytes to '%s'\n", sz, arg);
    324 
    325     if (flash_write(partition, phandle->download_fd, sz, header_sz)) {
    326         fastboot_fail(phandle, "flash write failure");
    327         return;
    328     }
    329     D(INFO, "partition '%s' updated\n", arg);
    330 
    331     flash_close(partition);
    332     close(data_fd);
    333 
    334     fastboot_okay(phandle, "");
    335 }
    336 
    337 static void cmd_continue(struct protocol_handle *phandle, const char *arg)
    338 {
    339     fastboot_okay(phandle, "");
    340 #if 0
    341     udc_stop();
    342 
    343     boot_linux_from_flash();
    344 #endif
    345 }
    346 
    347 static void cmd_getvar(struct protocol_handle *phandle, const char *arg)
    348 {
    349     const char *value;
    350     D(DEBUG, "cmd_getvar %s\n", arg);
    351 
    352     value = fastboot_getvar(arg);
    353 
    354     fastboot_okay(phandle, value);
    355 }
    356 
    357 static void cmd_download(struct protocol_handle *phandle, const char *arg)
    358 {
    359     unsigned len = strtoul(arg, NULL, 16);
    360     int old_fd;
    361 
    362     if (len > 256 * 1024 * 1024) {
    363         fastboot_fail(phandle, "data too large");
    364         return;
    365     }
    366 
    367     fastboot_data(phandle, len);
    368 
    369     old_fd = protocol_get_download(phandle);
    370     if (old_fd >= 0) {
    371         off_t len = lseek(old_fd, 0, SEEK_END);
    372         D(INFO, "disposing of unused fd %d, size %ld", old_fd, len);
    373         close(old_fd);
    374     }
    375 
    376     phandle->download_fd = protocol_handle_download(phandle, len);
    377     if (phandle->download_fd < 0) {
    378         fastboot_fail(phandle, "download failed");
    379         return;
    380     }
    381 
    382     fastboot_okay(phandle, "");
    383 }
    384 
    385 static void cmd_oem(struct protocol_handle *phandle, const char *arg) {
    386     const char *response = "";
    387 
    388     //TODO: Maybe it should get download descriptor also
    389     if (trigger_oem_cmd(arg, &response))
    390         fastboot_fail(phandle, response);
    391     else
    392         fastboot_okay(phandle, response);
    393 }
    394 
    395 void commands_init()
    396 {
    397     virtual_partition_register("partition-table", cmd_gpt_layout);
    398 
    399     fastboot_register("boot", cmd_boot);
    400     fastboot_register("erase:", cmd_erase);
    401     fastboot_register("flash:", cmd_flash);
    402     fastboot_register("continue", cmd_continue);
    403     fastboot_register("getvar:", cmd_getvar);
    404     fastboot_register("download:", cmd_download);
    405     fastboot_register("oem", cmd_oem);
    406     //fastboot_publish("version", "0.5");
    407     //fastboot_publish("product", "swordfish");
    408     //fastboot_publish("kernel", "lk");
    409 }
    410