void cb_set_active(struct usb_ep *ep, struct usb_request *req) { int ret; int i; unsigned int slot = 0; char *cmd = req->buf; struct boot_ctl t_bootctl; memset(&t_bootctl, 0, sizeof(t_bootctl)); strsep(&cmd, ":"); if (!cmd) { error("missing slot suffix\n"); fastboot_tx_write_str("FAILmissing slot suffix"); return; } slot = slotidx_from_suffix(cmd); if (slot >= SLOT_NUM) { fastboot_tx_write_str("FAILerr slot suffix"); return; } ret = read_bootctl(&t_bootctl); if (ret) fastboot_tx_write_str("FAILReadBootCtl failed"); t_bootctl.a_slot_meta[slot].bootsuc = 0; t_bootctl.a_slot_meta[slot].priority = 15; t_bootctl.a_slot_meta[slot].tryremain = 7; /* low other slot priority */ for (i = 0; i < SLOT_NUM; i++) { if (i == slot) continue; if (t_bootctl.a_slot_meta[i].priority >= 15) t_bootctl.a_slot_meta[i].priority = 14; } ret = write_bootctl(&t_bootctl); if (ret) fastboot_tx_write_str("write_bootctl failed"); else fastboot_tx_write_str("OKAY"); return; }
void rx_handler_command(struct usb_ep *ep, struct usb_request *req) { char response[RESPONSE_LEN]; char *cmdbuf = req->buf; void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; int i; sprintf(response, "FAIL"); for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) { func_cb = cmd_dispatch_info[i].cb; break; } } if (!func_cb) fastboot_tx_write_str("FAILunknown command"); else func_cb(ep, req); if (req->status == 0) { *cmdbuf = '\0'; req->actual = 0; usb_ep_queue(ep, req, 0); } }
static void cb_download(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; char response[RESPONSE_LEN]; strsep(&cmd, ":"); /*HACK: Zero terminate the command string*/ strlcpy(cmd, cmd, 9); download_size = simple_strtoul(cmd, NULL, 16); download_bytes = 0; printf("Starting download of %d bytes\n", download_size); if (0 == download_size) { sprintf(response, "FAILdata invalid size"); } else if (download_size > fb_cfg.transfer_buffer_size) { download_size = 0; sprintf(response, "FAILdata too large"); } else { sprintf(response, "DATA%08x", download_size); req->complete = rx_handler_dl_image; req->length = rx_bytes_expected(); if (req->length < ep->maxpacket) req->length = ep->maxpacket; } fastboot_tx_write_str(response); }
static void cb_boot(struct usb_ep *ep, struct usb_request *req) { sprintf(boot_addr_start, "0x%p", fb_cfg.transfer_buffer); req_in->complete = do_bootm_on_complete; fastboot_tx_write_str("OKAY"); return; }
static void cb_oem(struct usb_ep *ep, struct usb_request *req) { char buf[FORMAT_LEN]; #ifdef CONFIG_SPL_SPI_SUPPORT char *sf_erase[4] = {"sf", "erase", "0", "20000"}; int status; char *sf_probe[3] = {"sf", "probe", "0"}; if (strncmp(req->buf + 4, "spi", 3) == 0) { boot_from_spi = 1; status = do_spi_flash(NULL, 0, 3, sf_probe); if (status) { fastboot_tx_write_str("FAIL:Could not probe SPI"); return; } status = do_spi_flash(NULL, 0, 4, sf_erase); if (status) { fastboot_tx_write_str("FAIL:Could not erase SPI"); return; } fastboot_tx_write_str("OKAY"); return; }else if (strncmp(req->buf + 4, "mmc", 3) == 0) { boot_from_spi = 0; fastboot_tx_write_str("OKAY"); return; } #endif strlcpy(buf, req->buf + 4, FORMAT_LEN); if (fastboot_oem(buf) == 0) fastboot_tx_write_str("OKAY"); else { fastboot_tx_write_str("FAIL: Unable to create partitions"); } return; }
static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) { char response[RESPONSE_LEN]; unsigned int transfer_size = download_size - download_bytes; const unsigned char *buffer = req->buf; unsigned int buffer_size = req->actual; if (req->status != 0) { printf("Bad status: %d\n", req->status); return; } if (buffer_size < transfer_size) transfer_size = buffer_size; memcpy(fb_cfg.transfer_buffer + download_bytes, buffer, transfer_size); download_bytes += transfer_size; /* Check if transfer is done */ if (download_bytes >= download_size) { /* * Reset global transfer variable, keep download_bytes because * it will be used in the next possible flashing command */ download_size = 0; req->complete = rx_handler_command; req->length = EP_BUFFER_SIZE; sprintf(response, "OKAY"); fastboot_tx_write_str(response); printf("\ndownloading of %d bytes finished\n", download_bytes); } else { req->length = rx_bytes_expected(); if (req->length < ep->maxpacket) req->length = ep->maxpacket; } /*if (download_bytes && !(download_bytes % BYTES_PER_DOT)) { printf("."); if (!(download_bytes % (74 * BYTES_PER_DOT))) printf("\n"); }*/ req->actual = 0; usb_ep_queue(ep, req, 0); }
static int fastboot_erase(const char *partition) { struct fastboot_ptentry *ptn; int status = 0; unsigned int sectors; char start[32], length[32]; char *dev[3] = { "mmc", "dev", "1" }; char *erase[4] = { "mmc", "erase", NULL, NULL, }; char *mmc_init[2] = {"mmc", "rescan",}; /* Find the partition and erase it */ ptn = fastboot_flash_find_ptn(partition); if (ptn == 0) { printf("Partition does not exist"); fastboot_tx_write_str("FAIL: partition doesn't exist"); status = -1; } else { sectors = ptn->length / 512; /*Sectors should be aligned to 1024*/ if (sectors < 0x400) { sectors = 0x400; } sprintf(length, "0x%x", sectors); sprintf(start, "0x%x", (ptn->start & ~(0x400 - 1))); erase[2] = start; erase[3] = length; status = do_mmcops(NULL, 0, 3, dev); if (status) { printf("Unable to set MMC device\n"); fastboot_tx_write_str("FAIL: init of MMC"); goto exit; } status = do_mmcops(NULL, 0, 2, mmc_init); if (status) { fastboot_tx_write_str("FAIL: init of MMC"); goto exit; } printf("Erasing '%s'\n", ptn->name); status = do_mmcops(NULL, 0, 4, erase); if (status) { printf("Erasing '%s' FAILED! %d\n", ptn->name,status); fastboot_tx_write_str("FAIL: Eraze of partition"); } else { printf("Erasing '%s' DONE!\n", ptn->name); fastboot_tx_write_str("OKAY"); } fastboot_tx_write_str("OKAY"); } exit: return status; }
static u32 fastboot_get_boot_ptn(boot_img_hdr *hdr, char *response, struct mmc* mmc) { u32 hdr_sectors = 0; u32 sector_size; struct fastboot_ptentry *pte = NULL; int status = 0; strcpy(response, "OKAY"); pte = fastboot_flash_find_ptn("boot"); if (NULL == pte) { strcpy(response, "FAILCannot find boot partition"); goto out; } /* Read the boot image header */ sector_size = mmc->block_dev.blksz; hdr_sectors = (sizeof(struct boot_img_hdr)/sector_size) + 1; status = mmc->block_dev.block_read(1, pte->start, hdr_sectors, (void *)hdr); if (status < 0) { strcpy(response, "FAILCannot read hdr from boot partition"); goto out; } if (memcmp(hdr->magic, BOOT_MAGIC, 8) != 0) { printf("bad boot image magic\n"); strcpy(response, "FAILBoot partition not initialized"); goto out; } return hdr_sectors; out: strcpy(response, "INFO"); fastboot_tx_write_str(response); return -1; }
static int fastboot_flash(const char *partition) { int status = 0; struct fastboot_ptentry *ptn; char source[32], dest[32], length[32]; char *dev[3] = { "mmc", "dev", "1" }; char *mmc_write[5] = {"mmc", "write", NULL, NULL, NULL}; char *mmc_init[2] = {"mmc", "rescan",}; #ifdef CONFIG_SPL_SPI_SUPPORT char *sf_probe[3] = {"sf", "probe", "0"}; char *sf_write_xloader[5] = {"sf", "write", NULL, "0", "20000"}; char *sf_update_xloader[5] = {"sf", "update", NULL, "0", "20000"}; char *sf_write_bootloader[5] = {"sf", "write", NULL, "80000", "80000"}; char *sf_update_bootloader[5] = {"sf", "update", NULL, "80000", "80000"}; /*Check if this is for xloader or bootloader. Also, check if we have to flash to SPI*/ if (strcmp(partition, "xloader") == 0 && boot_from_spi) { printf("Flashing %s to SPI\n", partition); status = do_spi_flash(NULL, 0, 3, sf_probe); if (status) { fastboot_tx_write_str("FAIL:Could not probe SPI"); return status; } sf_write_xloader[2] = source; sf_update_xloader[2] = source; sprintf(source, "0x%x", (unsigned int)fb_cfg.transfer_buffer); printf("Updating X-LOADER to SPI\n"); status = do_spi_flash(NULL, 0, 5, sf_update_xloader); if(status) { fastboot_tx_write_str("FAIL:Could not update xloader to SPI"); return status; } printf("Writing X-LOADER to SPI\n"); status = do_spi_flash(NULL, 0, 5, sf_write_xloader); if (status) { fastboot_tx_write_str("FAIL:Could not write xloader to SPI"); return status; } printf("Writing xloader DONE\n"); fastboot_tx_write_str("OKAY"); return 0; } if (strcmp(partition, "bootloader") == 0 && boot_from_spi) { printf("Flashing %s to SPI\n", partition); status = do_spi_flash(NULL, 0, 3, sf_probe); if (status) { fastboot_tx_write_str("FAIL:Could not probe SPI"); return status; } sf_write_bootloader[2] = source; sf_update_bootloader[2] = source; sprintf(source, "0x%x", (unsigned int)fb_cfg.transfer_buffer); printf("Updating bootloader to SPI\n"); status = do_spi_flash(NULL, 0, 5, sf_update_bootloader); if (status) { fastboot_tx_write_str("FAIL:Could not update bootloader to SPI"); return status; } printf("Writing bootloader to SPI\n"); status = do_spi_flash(NULL, 0, 5, sf_write_bootloader); if (status) { fastboot_tx_write_str("FAIL:Could not write bootloader to SPI"); return status; } printf("Writing bootloader DONE\n"); fastboot_tx_write_str("OKAY"); return 0; } #endif if (!strcmp(partition, "zImage") || !strcmp(partition, "zimage")) { return fastboot_update_zimage(); } ptn = fastboot_flash_find_ptn(partition); if (ptn == 0) { printf("Partition:[%s] does not exist\n", partition); fastboot_tx_write_str("FAIL:Partition does not exist"); } else if ((download_bytes> ptn->length) && !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { printf("Image too large for the partition\n"); fastboot_tx_write_str("FAIL: image too large for partition"); } else { source[0] = '\0'; dest[0] = '\0'; length[0] = '\0'; mmc_write[2] = source; mmc_write[3] = dest; mmc_write[4] = length; sprintf(source, "0x%x", (unsigned int)fb_cfg.transfer_buffer); sprintf(dest, "0x%x", ptn->start); sprintf(length, "0x%x", (download_bytes/512) + 1); status = do_mmcops(NULL, 0, 3, dev); if (status) { printf("Unable to set MMC device\n"); fastboot_tx_write_str("FAIL: init of MMC"); goto exit; } status = do_mmcops(NULL, 0, 2, mmc_init); if (status) { fastboot_tx_write_str("FAIL:Init of MMC card"); goto exit; } if ( ((sparse_header_t *)fb_cfg.transfer_buffer)->magic == SPARSE_HEADER_MAGIC) { printf("fastboot: %s is in sparse format %u %llu \n", ptn->name, ptn->start, ptn->length); status = do_unsparse(fb_cfg.transfer_buffer, ptn->start, ptn->length); if (status) { printf("Writing '%s' FAILED!\n", ptn->name); fastboot_tx_write_str("FAIL: Write partition"); } else { printf("Writing sparsed: '%s' DONE!\n", ptn->name); printf("Writing '%s' DONE!\n", ptn->name); fastboot_tx_write_str("OKAY"); } } else { printf("Writing non-sparsed format '%s'\n", ptn->name); status = do_mmcops(NULL, 0, 5, mmc_write); if (status) { printf("Writing '%s' FAILED!\n", ptn->name); fastboot_tx_write_str("FAIL: Write partition"); goto exit; } else { printf("Writing '%s' DONE!\n", ptn->name); fastboot_tx_write_str("OKAY"); } } } exit: return status; }
static int fastboot_update_zimage(void) { boot_img_hdr *hdr = NULL; u8 *ramdisk_buffer; u32 ramdisk_sector_start, ramdisk_sectors; u32 kernel_sector_start, kernel_sectors; u32 hdr_sectors = 0; u32 sectors_per_page = 0; int ret = 0; struct mmc* mmc = NULL; struct fastboot_ptentry *pte = NULL; char response[128]; u32 addr = CONFIG_ADDR_DOWNLOAD; strcpy(response, "OKAY"); printf("Flashing zImage...%d bytes\n", download_bytes); mmc = find_mmc_device(1); if (mmc == NULL) { strcpy(response, "FAILCannot find mmc at slot 1"); goto out; } if (mmc_init(mmc) != 0) { strcpy(response, "FAILCannot init mmc at slot 1"); goto out; } hdr = (boot_img_hdr *) addr; hdr_sectors = fastboot_get_boot_ptn(hdr, response, mmc); if (hdr_sectors <= 0) { sprintf(response + strlen(response), "FAILINVALID number of boot sectors %d", hdr_sectors); ret = -1; goto out; } pte = fastboot_flash_find_ptn("boot"); if (pte == NULL) { sprintf(response + strlen(response), "FAILINVALID partition"); ret = -1; goto out; } /* Extract ramdisk location and read it into local buffer */ sectors_per_page = hdr->page_size / mmc->block_dev.blksz; ramdisk_sector_start = pte->start + sectors_per_page; ramdisk_sector_start += CEIL(hdr->kernel_size, hdr->page_size)* sectors_per_page; ramdisk_sectors = CEIL(hdr->ramdisk_size, hdr->page_size)* sectors_per_page; ramdisk_buffer = (u8 *)hdr; ramdisk_buffer += (hdr_sectors * mmc->block_dev.blksz); ret = mmc->block_dev.block_read(1, ramdisk_sector_start, ramdisk_sectors, ramdisk_buffer); if (ret < 0) { sprintf(response, "FAILCannot read ramdisk from boot " "partition"); ret = -1; goto out; } /* Change the boot img hdr */ hdr->kernel_size = download_bytes; ret = mmc->block_dev.block_write(1, pte->start, hdr_sectors, (void *)hdr); if (ret < 0) { sprintf(response, "FAILCannot writeback boot img hdr"); ret = -1; goto out; } /* Write the new downloaded kernel*/ kernel_sector_start = pte->start + sectors_per_page; kernel_sectors = CEIL(hdr->kernel_size, hdr->page_size)* sectors_per_page; ret = mmc->block_dev.block_write(1, kernel_sector_start, kernel_sectors, fb_cfg.transfer_buffer); if (ret < 0) { sprintf(response, "FAILCannot write new kernel"); ret = -1; goto out; } /* Write the saved Ramdisk back */ ramdisk_sector_start = pte->start + sectors_per_page; ramdisk_sector_start += CEIL(hdr->kernel_size, hdr->page_size)* sectors_per_page; ret = mmc->block_dev.block_write(1, ramdisk_sector_start, ramdisk_sectors, ramdisk_buffer); if (ret < 0) { sprintf(response, "FAILCannot write back original ramdisk"); ret = -1; goto out; } fastboot_tx_write_str(response); return 0; out: fastboot_tx_write_str(response); return ret; }
static void cb_reboot_bootloader(struct usb_ep *ep, struct usb_request *req) { fastboot_tx_write_str("OKAY"); fastboot_reboot_bootloader(); }
static void cb_getvar(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; char response[RESPONSE_LEN]; const char *s; char userdata_sz[64]; strcpy(response, "OKAY"); strsep(&cmd, ":"); if (!cmd) { fastboot_tx_write_str("FAILmissing var"); return; } if (!strcmp_l1("version", cmd)) { strncat(response, FASTBOOT_VERSION, sizeof(response)); } else if (!strcmp_l1("downloadsize", cmd)) { char str_num[12]; sprintf(str_num, "%08x", fb_cfg.transfer_buffer_size); strncat(response, str_num, sizeof(response)); } else if (!strcmp_l1("product", cmd)) { s = fb_find_usb_string(FB_STR_PRODUCT_IDX); if (s) strncat(response, s, sizeof(response)); else strcpy(response, "FAILValue not set"); } else if (!strcmp_l1("serialno", cmd)) { s = fb_find_usb_string(FB_STR_SERIAL_IDX); if (s) strncat(response, s, sizeof(response)); else strcpy(response, "FAILValue not set"); } else if (!strcmp_l1("cpurev", cmd)) { s = fb_find_usb_string(FB_STR_PROC_REV_IDX); if (s) strncat(response, s, sizeof(response)); else strcpy(response, "FAILValue not set"); } else if (!strcmp_l1("secure", cmd)) { s = get_cpu_type(); if (s) strncat(response, s, sizeof(response)); else strcpy(response, "FAILValue not set"); } else if (!strcmp_l1("userdata_size", cmd)) { strncat(response, get_ptn_size(userdata_sz, "userdata"), sizeof(response)); } else { strcpy(response, "FAILVariable not implemented"); } fastboot_tx_write_str(response); }
static void cb_reboot(struct usb_ep *ep, struct usb_request *req) { req_in->complete = compl_do_reset; fastboot_tx_write_str("OKAY"); }