/* ******************************************************************************* * __boot * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void __boot(void) { char response[68]; if(all_download_bytes > CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE) { char start[32]; char *bootm[3] = { "bootm", NULL, NULL, }; char *go[3] = { "go", NULL, NULL, }; struct fastboot_boot_img_hdr *fb_hdr = (struct fastboot_boot_img_hdr *) trans_data.base_recv_buffer; /* Skip the mkbootimage header */ image_header_t *hdr = (image_header_t *) &trans_data.base_recv_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; bootm[1] = go[1] = start; sprintf(start, "0x%x", (uint)hdr); printf("start addr %s\n", start); /* Execution should jump to kernel so send the response now and wait a bit. */ sprintf(response, "OKAY"); // fastboot_tx_status(response, strlen(response)); __msdelay (1000); /* 1 sec */ if (ntohl(hdr->ih_magic) == IH_MAGIC) { /* Looks like a kernel.. */ printf ("Booting kernel..\n"); /* * Check if the user sent a bootargs down. * If not, do not override what is already there */ if (strlen ((char *) &fb_hdr->cmdline[0])) { printf("Image has cmdline:"); printf("%s\n", &fb_hdr->cmdline[0]); setenv ("bootargs", (char *) &fb_hdr->cmdline[0]); } do_bootm (NULL, 0, 2, bootm); } else { /* Raw image, maybe another uboot */ printf ("Booting raw image..\n"); do_go (NULL, 0, 2, go); } printf ("ERROR : bootting failed\n"); printf ("You should reset the board\n"); } else { sprintf(response, "FAILinvalid boot image"); } }
/* * The function "mon()" is the dialog user interface, called * from the simulation just after program start. */ void mon(void) { register int eoj = 1; static char cmd[LENCMD]; tcgetattr(0, &old_term); if (x_flag) { if (do_getfile(xfn) == 0) do_go(); } while (eoj) { next: printf(">>> "); fflush(stdout); if (fgets(cmd, LENCMD, stdin) == NULL) { putchar('\n'); goto next; } switch (*cmd) { case '\n': do_step(); break; case 't': do_trace(cmd + 1); break; case 'g': do_go(); break; case 'd': do_dump(cmd + 1); break; case 'l': do_list(cmd + 1); break; case 'm': do_modify(cmd + 1); break; case 'f': do_fill(cmd + 1); break; case 'v': do_move(cmd + 1); break; case 'x': do_reg(cmd + 1); break; case 'p': do_port(cmd + 1); break; case 'b': do_break(cmd + 1); break; case 'h': do_hist(cmd + 1); break; case 'z': do_count(cmd + 1); break; case 'c': do_clock(); break; case 's': do_show(); break; case '?': do_help(); break; case 'r': do_getfile(cmd + 1); break; case '!': do_unix(cmd + 1); break; case 'q': eoj = 0; break; default: puts("what??"); break; } } }
static int rx_handler (const unsigned char *buffer, unsigned int buffer_size) { int ret = 1; /* Use 65 instead of 64 null gets dropped strcpy's need the extra byte */ char response[65]; if (download_size) { /* Something to download */ if (buffer_size) { /* Handle possible overflow */ unsigned int transfer_size = download_size - download_bytes; if (buffer_size < transfer_size) transfer_size = buffer_size; /* Save the data to the transfer buffer */ memcpy (interface.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; if (download_error) { /* There was an earlier error */ sprintf(response, "ERROR"); } else { /* Everything has transferred, send the OK response */ sprintf(response, "OKAY"); } fastboot_tx_status(response, strlen(response)); printf ("\ndownloading of %d bytes finished\n", download_bytes); #if defined(CONFIG_STORAGE_NAND) /* Pad to block length In most cases, padding the download to be block aligned is correct. The exception is when the following flash writes to the oob area. This happens when the image is a YAFFS image. Since we do not know what the download is until it is flashed, go ahead and pad it, but save the true size in case if should have been unpadded */ download_bytes_unpadded = download_bytes; if (interface.nand_block_size) { if (download_bytes % interface.nand_block_size) { unsigned int pad = interface.nand_block_size - (download_bytes % interface.nand_block_size); unsigned int i; for (i = 0; i < pad; i++) { if (download_bytes >= interface.transfer_buffer_size) break; interface.transfer_buffer[download_bytes] = 0; download_bytes++; } } } #endif } /* Provide some feedback */ if (download_bytes && 0 == (download_bytes % (16 * interface.nand_block_size))) { /* Some feeback that the download is happening */ if (download_error) printf("X"); else printf("."); if (0 == (download_bytes % (80 * 16 * interface.nand_block_size))) printf("\n"); } } else { /* Ignore empty buffers */ printf ("Warning empty download buffer\n"); printf ("Ignoring\n"); } ret = 0; } else { /* A command */ /* Cast to make compiler happy with string functions */ const char *cmdbuf = (char *) buffer; /* Generic failed response */ sprintf(response, "FAIL"); /* reboot Reboot the board. */ if(memcmp(cmdbuf, "reboot", 6) == 0) { sprintf(response,"OKAY"); fastboot_tx_status(response, strlen(response)); udelay (1000000); /* 1 sec */ do_reset (NULL, 0, 0, NULL); /* This code is unreachable, leave it to make the compiler happy */ return 0; } /* getvar Get common fastboot variables Board has a chance to handle other variables */ if(memcmp(cmdbuf, "getvar:", 7) == 0) { strcpy(response,"OKAY"); if(!strcmp(cmdbuf + strlen("version"), "version")) { strcpy(response + 4, FASTBOOT_VERSION); } else if(!strcmp(cmdbuf + strlen("product"), "product")) { if (interface.product_name) strcpy(response + 4, interface.product_name); } else if(!strcmp(cmdbuf + strlen("serialno"), "serialno")) { if (interface.serial_no) strcpy(response + 4, interface.serial_no); } else if(!strcmp(cmdbuf + strlen("downloadsize"), "downloadsize")) { if (interface.transfer_buffer_size) sprintf(response + 4, "08x", interface.transfer_buffer_size); } else { fastboot_getvar(cmdbuf + 7, response + 4); } ret = 0; } /* erase Erase a register flash partition Board has to set up flash partitions */ if(memcmp(cmdbuf, "erase:", 6) == 0){ #if defined(CONFIG_STORAGE_NAND) struct fastboot_ptentry *ptn; ptn = fastboot_flash_find_ptn(cmdbuf + 6); if(ptn == 0) { sprintf(response, "FAILpartition does not exist"); } else { char start[32], length[32]; int status, repeat, repeat_max; printf("erasing '%s'\n", ptn->name); char *lock[5] = { "nand", "lock", NULL, NULL, NULL, }; char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL, }; char *erase[5] = { "nand", "erase", NULL, NULL, NULL, }; lock[2] = unlock[2] = erase[2] = start; lock[3] = unlock[3] = erase[3] = length; repeat_max = 1; if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK; sprintf (length, "0x%x", ptn->length); for (repeat = 0; repeat < repeat_max; repeat++) { sprintf (start, "0x%x", ptn->start + (repeat * ptn->length)); do_nand (NULL, 0, 4, unlock); status = do_nand (NULL, 0, 4, erase); do_nand (NULL, 0, 4, lock); if (status) break; } if (status) { sprintf(response,"FAILfailed to erase partition"); } else { printf("partition '%s' erased\n", ptn->name); sprintf(response, "OKAY"); } } #elif defined(CONFIG_STORAGE_EMMC) struct fastboot_ptentry *ptn; /* Save the MMC controller number */ mmc_controller_no = CFG_FASTBOOT_MMC_NO; /* Find the partition and erase it */ ptn = fastboot_flash_find_ptn(cmdbuf + 6); if (ptn == 0) { sprintf(response, "FAIL: partition doesn't exist"); } else { /* Call MMC erase function here */ char start[32], length[32]; char slot_no[32]; char *erase[5] = { "mmc", NULL, "erase", NULL, NULL, }; char *mmc_init[2] = {"mmcinit", NULL,}; mmc_init[1] = slot_no; erase[1] = slot_no; erase[3] = start; erase[4] = length; sprintf(slot_no, "%d", mmc_controller_no); sprintf(length, "0x%x", ptn->length); sprintf(start, "0x%x", ptn->start); printf("Initializing '%s'\n", ptn->name); if (do_mmc(NULL, 0, 2, mmc_init)) sprintf(response, "FAIL: Init of MMC card"); else sprintf(response, "OKAY"); printf("Erasing '%s'\n", ptn->name); if (do_mmc(NULL, 0, 5, erase)) { printf("Erasing '%s' FAILED!\n", ptn->name); sprintf(response, "FAIL: Erase partition"); } else { printf("Erasing '%s' DONE!\n", ptn->name); sprintf(response, "OKAY"); } } #endif ret = 0; } /* download download something .. What happens to it depends on the next command after data */ if(memcmp(cmdbuf, "download:", 9) == 0) { /* save the size */ download_size = simple_strtoul (cmdbuf + 9, NULL, 16); /* Reset the bytes count, now it is safe */ download_bytes = 0; /* Reset error */ download_error = 0; printf ("Starting download of %d bytes\n", download_size); if (0 == download_size) { /* bad user input */ sprintf(response, "FAILdata invalid size"); } else if (download_size > interface.transfer_buffer_size) { /* set download_size to 0 because this is an error */ download_size = 0; sprintf(response, "FAILdata too large"); } else { /* The default case, the transfer fits completely in the interface buffer */ sprintf(response, "DATA%08x", download_size); } ret = 0; } /* boot boot what was downloaded WARNING WARNING WARNING This is not what you expect. The fastboot client does its own packaging of the kernel. The layout is defined in the android header file bootimage.h. This layeout is copiedlooks like this, ** ** +-----------------+ ** | boot header | 1 page ** +-----------------+ ** | kernel | n pages ** +-----------------+ ** | ramdisk | m pages ** +-----------------+ ** | second stage | o pages ** +-----------------+ ** We only care about the kernel. So we have to jump past a page. What is a page size ? The fastboot client uses 2048 The is the default value of CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE */ if(memcmp(cmdbuf, "boot", 4) == 0) { if ((download_bytes) && (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < download_bytes)) { char start[32]; char *bootm[3] = { "bootm", NULL, NULL, }; char *go[3] = { "go", NULL, NULL, }; /* * Use this later to determine if a command line was passed * for the kernel. */ struct fastboot_boot_img_hdr *fb_hdr = (struct fastboot_boot_img_hdr *) interface.transfer_buffer; /* Skip the mkbootimage header */ image_header_t *hdr = (image_header_t *) &interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE]; bootm[1] = go[1] = start; sprintf (start, "0x%x", hdr); /* Execution should jump to kernel so send the response now and wait a bit. */ sprintf(response, "OKAY"); fastboot_tx_status(response, strlen(response)); udelay (1000000); /* 1 sec */ if (ntohl(hdr->ih_magic) == IH_MAGIC) { /* Looks like a kernel.. */ printf ("Booting kernel..\n"); /* * Check if the user sent a bootargs down. * If not, do not override what is already there */ if (strlen ((char *) &fb_hdr->cmdline[0])) set_env ("bootargs", (char *) &fb_hdr->cmdline[0]); do_bootm (NULL, 0, 2, bootm); } else { /* Raw image, maybe another uboot */ printf ("Booting raw image..\n"); do_go (NULL, 0, 2, go); } printf ("ERROR : bootting failed\n"); printf ("You should reset the board\n"); } sprintf(response, "FAILinvalid boot image"); ret = 0; } /* flash Flash what was downloaded */ if(memcmp(cmdbuf, "flash:", 6) == 0) { #if defined(CONFIG_STORAGE_NAND) if (download_bytes) { struct fastboot_ptentry *ptn; ptn = fastboot_flash_find_ptn(cmdbuf + 6); if (ptn == 0) { sprintf(response, "FAILpartition does not exist"); } else if ((download_bytes > ptn->length) && !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { sprintf(response, "FAILimage too large for partition"); /* TODO : Improve check for yaffs write */ } else { /* Check if this is not really a flash write but rather a saveenv */ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { /* Since the response can only be 64 bytes, there is no point in having a large error message. */ char err_string[32]; if (saveenv_to_ptn(ptn, &err_string[0])) { printf("savenv '%s' failed : %s\n", ptn->name, err_string); sprintf(response, "FAIL%s", err_string); } else { printf("partition '%s' saveenv-ed\n", ptn->name); sprintf(response, "OKAY"); } } else { /* Normal case */ if (write_to_ptn(ptn)) { printf("flashing '%s' failed\n", ptn->name); sprintf(response, "FAILfailed to flash partition"); } else { printf("partition '%s' flashed\n", ptn->name); sprintf(response, "OKAY"); } } } } else { sprintf(response, "FAILno image downloaded"); } #elif defined(CONFIG_STORAGE_EMMC) if (download_bytes) { struct fastboot_ptentry *ptn; /* Save the MMC controller number */ mmc_controller_no = CFG_FASTBOOT_MMC_NO; /* Next is the partition name */ ptn = fastboot_flash_find_ptn(cmdbuf + 6); if (ptn == 0) { printf("Partition:'%s' does not exist\n", ptn->name); sprintf(response, "FAILpartition does not exist"); } else if ((download_bytes > ptn->length) && !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { printf("Image too large for the partition\n"); sprintf(response, "FAILimage too large for partition"); } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) { /* Check if this is not really a flash write, * but instead a saveenv */ unsigned int i = 0; /* Env file is expected with a NULL delimeter between * env variables So replace New line Feeds (0x0a) with * NULL (0x00) */ for (i = 0; i < download_bytes; i++) { if (interface.transfer_buffer[i] == 0x0a) interface.transfer_buffer[i] = 0x00; } memset(env_ptr->data, 0, ENV_SIZE); memcpy(env_ptr->data, interface.transfer_buffer, download_bytes); do_saveenv(NULL, 0, 1, NULL); printf("saveenv to '%s' DONE!\n", ptn->name); sprintf(response, "OKAY"); } else { /* Normal case */ char source[32], dest[32], length[32]; char slot_no[32]; printf("writing to partition '%s'\n", ptn->name); char *mmc_write[6] = {"mmc", NULL, "write", NULL, NULL, NULL}; char *mmc_init[2] = {"mmcinit", NULL,}; mmc_init[1] = slot_no; mmc_write[1] = slot_no; mmc_write[3] = source; mmc_write[4] = dest; mmc_write[5] = length; sprintf(slot_no, "%d", mmc_controller_no); sprintf(source, "0x%x", interface.transfer_buffer); sprintf(dest, "0x%x", ptn->start); sprintf(length, "0x%x", download_bytes); printf("Initializing '%s'\n", ptn->name); if (do_mmc(NULL, 0, 2, mmc_init)) sprintf(response, "FAIL:Init of MMC card"); else sprintf(response, "OKAY"); printf("Writing '%s'\n", ptn->name); if (do_mmc(NULL, 0, 6, mmc_write)) { printf("Writing '%s' FAILED!\n", ptn->name); sprintf(response, "FAIL: Write partition"); } else { printf("Writing '%s' DONE!\n", ptn->name); sprintf(response, "OKAY"); } } } else { sprintf(response, "FAILno image downloaded"); } #endif ret = 0; } /* continue Stop doing fastboot */ if (memcmp(cmdbuf, "continue", 8) == 0) { sprintf(response, "OKAY"); continue_booting = 1; ret = 0; } /* upload Upload just the data in a partition */ if ((memcmp(cmdbuf, "upload:", 7) == 0) || (memcmp(cmdbuf, "uploadraw:", 10) == 0)) { #if defined(CONFIG_STORAGE_NAND) unsigned int adv, delim_index, len; struct fastboot_ptentry *ptn; unsigned int is_raw = 0; /* Is this a raw read ? */ if (memcmp(cmdbuf, "uploadraw:", 10) == 0) { is_raw = 1; adv = 10; } else { adv = 7; } /* Scan to the next ':' to find when the size starts */ len = strlen(cmdbuf); for (delim_index = adv; delim_index < len; delim_index++) { if (cmdbuf[delim_index] == ':') { /* WARNING, cmdbuf is being modified. */ *((char *) &cmdbuf[delim_index]) = 0; break; } } ptn = fastboot_flash_find_ptn(cmdbuf + adv); if (ptn == 0) { sprintf(response, "FAILpartition does not exist"); } else { /* This is how much the user is expecting */ unsigned int user_size; /* * This is the maximum size needed for * this partition */ unsigned int size; /* This is the length of the data */ unsigned int length; /* * Used to check previous write of * the parition */ char env_ptn_length_var[128]; char *env_ptn_length_val; user_size = 0; if (delim_index < len) user_size = simple_strtoul(cmdbuf + delim_index + 1, NULL, 16); /* Make sure output is padded to block size */ length = ptn->length; sprintf(env_ptn_length_var, "%s_nand_size", ptn->name); env_ptn_length_val = getenv(env_ptn_length_var); if (env_ptn_length_val) { length = simple_strtoul(env_ptn_length_val, NULL, 16); /* Catch possible problems */ if (!length) length = ptn->length; } size = length / interface.nand_block_size; size *= interface.nand_block_size; if (length % interface.nand_block_size) size += interface.nand_block_size; if (is_raw) size += (size / interface.nand_block_size) * interface.nand_oob_size; if (size > interface.transfer_buffer_size) { sprintf(response, "FAILdata too large"); } else if (user_size == 0) { /* Send the data response */ sprintf(response, "DATA%08x", size); } else if (user_size != size) { /* This is the wrong size */ sprintf(response, "FAIL"); } else { /* * This is where the transfer * buffer is populated */ unsigned char *buf = interface.transfer_buffer; char start[32], length[32], type[32], addr[32]; char *read[6] = { "nand", NULL, NULL, NULL, NULL, NULL, }; /* * Setting upload_size causes * transfer to happen in main loop */ upload_size = size; upload_bytes = 0; upload_error = 0; /* * Poison the transfer buffer, 0xff * is erase value of nand */ memset(buf, 0xff, upload_size); /* Which flavor of read to use */ if (is_raw) sprintf(type, "read.raw"); else sprintf(type, "read.i"); sprintf(addr, "0x%x", interface.transfer_buffer); sprintf(start, "0x%x", ptn->start); sprintf(length, "0x%x", upload_size); read[1] = type; read[2] = addr; read[3] = start; read[4] = length; set_ptn_ecc(ptn); do_nand(NULL, 0, 5, read); /* Send the data response */ sprintf(response, "DATA%08x", size); } } #endif ret = 0; } fastboot_tx_status(response, strlen(response)); } /* End of command */ return ret; }