diff --git a/README.md b/README.md index cc4de22..eaf91aa 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,14 @@ make ### MacOS For Homebrew users, + ```bash brew install libxml2 pkg-config libusb make ``` For MacPorts users + ```bash sudo port install libxml2 pkgconfig libusb make diff --git a/firehose.c b/firehose.c index c43eb4a..9816a9d 100644 --- a/firehose.c +++ b/firehose.c @@ -299,9 +299,17 @@ static int firehose_configure_response_parser(xmlNode *node, void *data, bool *r } static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size, - bool skip_storage_init, const char *storage, + bool skip_storage_init, + enum qdl_storage_type storage, size_t *max_payload_size) { + static const char * const memory_names[] = { + [QDL_STORAGE_EMMC] = "emmc", + [QDL_STORAGE_NAND] = "nand", + [QDL_STORAGE_UFS] = "ufs", + [QDL_STORAGE_NVME] = "nvme", + [QDL_STORAGE_SPINOR] = "spinor", + }; xmlNode *root; xmlNode *node; xmlDoc *doc; @@ -311,7 +319,7 @@ static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size, xmlDocSetRootElement(doc, root); node = xmlNewChild(root, NULL, (xmlChar *)"configure", NULL); - xml_setpropf(node, "MemoryName", storage); + xml_setpropf(node, "MemoryName", memory_names[storage]); xml_setpropf(node, "MaxPayloadSizeToTargetInBytes", "%lu", payload_size); xml_setpropf(node, "verbose", "%d", 0); xml_setpropf(node, "ZLPAwareHost", "%d", 1); @@ -324,7 +332,7 @@ static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size, } static int firehose_try_configure(struct qdl_device *qdl, bool skip_storage_init, - const char *storage) + enum qdl_storage_type storage) { size_t max_sector_size; size_t sector_sizes[] = { 512, 4096 }; @@ -359,7 +367,7 @@ static int firehose_try_configure(struct qdl_device *qdl, bool skip_storage_init ux_debug("accepted max payload size: %zu\n", qdl->max_payload_size); - if (strcmp(storage, "nand")) { + if (storage != QDL_STORAGE_NAND) { max_sector_size = sector_sizes[ARRAY_SIZE(sector_sizes) - 1]; buf = malloc(max_sector_size); memset(&op, 0, sizeof(op)); @@ -429,10 +437,12 @@ static int firehose_erase(struct qdl_device *qdl, struct program *program) return ret == FIREHOSE_ACK ? 0 : -1; } -static int firehose_program(struct qdl_device *qdl, struct program *program, int fd) +static int firehose_program(struct qdl_device *qdl, struct program *program, + int fd, enum qdl_storage_type storage) { unsigned int num_sectors; unsigned int sector_size; + unsigned int zlp_timeout = 10000; struct stat sb; size_t chunk_size; xmlNode *root; @@ -446,6 +456,13 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int int n; uint32_t fill_value; + /* + * ZLP has been measured to take up to 15 seconds on SPINOR devices, + * let's double it to be on the safe side... + */ + if (storage == QDL_STORAGE_SPINOR) + zlp_timeout = 30000; + num_sectors = program->num_sectors; sector_size = program->sector_size ? : qdl->sector_size; @@ -560,7 +577,7 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int vip_transfer_clear_status(qdl); } - n = qdl_write(qdl, buf, chunk_size * sector_size, 10000); + n = qdl_write(qdl, buf, chunk_size * sector_size, zlp_timeout); if (n < 0) { ux_err("USB write failed for data chunk\n"); ret = firehose_read(qdl, 30000, firehose_generic_parser, NULL); @@ -929,7 +946,7 @@ static int firehose_reset(struct qdl_device *qdl) static int firehose_detect_and_configure(struct qdl_device *qdl, bool skip_storage_init, - const char *storage, + enum qdl_storage_type storage, unsigned int timeout_s) { struct timeval timeout = { .tv_sec = timeout_s }; @@ -962,7 +979,7 @@ int firehose_provision(struct qdl_device *qdl) { int ret; - ret = firehose_detect_and_configure(qdl, true, "ufs", 5); + ret = firehose_detect_and_configure(qdl, true, QDL_STORAGE_UFS, 5); if (ret) return ret; @@ -980,7 +997,7 @@ int firehose_provision(struct qdl_device *qdl) } -int firehose_run(struct qdl_device *qdl, const char *storage) +int firehose_run(struct qdl_device *qdl, enum qdl_storage_type storage) { bool multiple; int bootable; @@ -1004,7 +1021,7 @@ int firehose_run(struct qdl_device *qdl, const char *storage) if (ret) return ret; - ret = program_execute(qdl, firehose_program); + ret = program_execute(qdl, firehose_program, storage); if (ret) return ret; diff --git a/program.c b/program.c index e11f5ab..fbb5eac 100644 --- a/program.c +++ b/program.c @@ -264,7 +264,12 @@ int program_load(const char *program_file, bool is_nand, bool allow_missing, con return errors; } -int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd)) +int program_execute(struct qdl_device *qdl, + int (*apply)(struct qdl_device *qdl, + struct program *program, + int fd, + enum qdl_storage_type storage), + enum qdl_storage_type storage) { struct program *program; int ret; @@ -281,7 +286,7 @@ int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, return -1; } - ret = apply(qdl, program, fd); + ret = apply(qdl, program, fd, storage); close(fd); if (ret) return ret; diff --git a/program.h b/program.h index c86d12e..0a2fd11 100644 --- a/program.h +++ b/program.h @@ -32,9 +32,15 @@ struct program { }; struct qdl_device; +enum qdl_storage_type; int program_load(const char *program_file, bool is_nand, bool allow_missing, const char *incdir); -int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd)); +int program_execute(struct qdl_device *qdl, + int (*apply)(struct qdl_device *qdl, + struct program *program, + int fd, + enum qdl_storage_type storage), + enum qdl_storage_type storage); int erase_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program)); int program_find_bootable_partition(bool *multiple_found); int program_is_sec_partition_flashed(void); diff --git a/qdl.c b/qdl.c index 41d2057..e21a11f 100644 --- a/qdl.c +++ b/qdl.c @@ -92,6 +92,24 @@ static int detect_type(const char *verb) return type; } +static enum qdl_storage_type decode_storage(const char *storage) +{ + + if (!strcmp(storage, "emmc")) + return QDL_STORAGE_EMMC; + if (!strcmp(storage, "nand")) + return QDL_STORAGE_NAND; + if (!strcmp(storage, "nvme")) + return QDL_STORAGE_NVME; + if (!strcmp(storage, "spinor")) + return QDL_STORAGE_SPINOR; + if (!strcmp(storage, "ufs")) + return QDL_STORAGE_UFS; + + fprintf(stderr, "Unknown storage type \"%s\"\n", storage); + exit(1); +} + static void print_usage(FILE *out) { extern const char *__progname; @@ -102,7 +120,7 @@ static void print_usage(FILE *out) fprintf(out, " -v, --version\t\t\tPrint the current version and exit\n"); fprintf(out, " -n, --dry-run\t\t\tDry run execution, no device reading or flashing\n"); fprintf(out, " -f, --allow-missing\t\tAllow skipping of missing files during flashing\n"); - fprintf(out, " -s, --storage=T\t\tSet target storage type T: \n"); + fprintf(out, " -s, --storage=T\t\tSet target storage type T: \n"); fprintf(out, " -l, --finalize-provisioning\tProvision the target storage\n"); fprintf(out, " -i, --include=T\t\tSet an optional folder T to search for files\n"); fprintf(out, " -S, --serial=T\t\t\tSelect target by serial number T (e.g. <0AA94EFD>)\n"); @@ -122,7 +140,8 @@ static void print_usage(FILE *out) int main(int argc, char **argv) { - char *prog_mbn, *storage = "ufs"; + enum qdl_storage_type storage = QDL_STORAGE_UFS; + char *prog_mbn; char *incdir = NULL; char *serial = NULL; const char *vip_generate_dir = NULL; @@ -186,7 +205,7 @@ int main(int argc, char **argv) out_chunk_size = strtol(optarg, NULL, 10); break; case 's': - storage = optarg; + storage = decode_storage(optarg); break; case 'S': serial = optarg; @@ -253,7 +272,7 @@ int main(int argc, char **argv) errx(1, "patch_load %s failed", argv[optind]); break; case QDL_FILE_PROGRAM: - ret = program_load(argv[optind], !strcmp(storage, "nand"), allow_missing, incdir); + ret = program_load(argv[optind], storage == QDL_STORAGE_NAND, allow_missing, incdir); if (ret < 0) errx(1, "program_load %s failed", argv[optind]); @@ -267,7 +286,7 @@ int main(int argc, char **argv) errx(1, "read_op_load %s failed", argv[optind]); break; case QDL_FILE_UFS: - if (strcmp(storage, "ufs")) + if (storage != QDL_STORAGE_UFS) errx(1, "attempting to load provisioning config when storage isn't \"ufs\""); ret = ufs_load(argv[optind], qdl_finalize_provisioning); diff --git a/qdl.h b/qdl.h index d1858bd..f5f34f1 100644 --- a/qdl.h +++ b/qdl.h @@ -35,6 +35,15 @@ enum QDL_DEVICE_TYPE { QDL_DEVICE_SIM, }; +enum qdl_storage_type { + QDL_STORAGE_UNKNOWN, + QDL_STORAGE_EMMC, + QDL_STORAGE_NAND, + QDL_STORAGE_UFS, + QDL_STORAGE_NVME, + QDL_STORAGE_SPINOR, +}; + struct qdl_device { enum QDL_DEVICE_TYPE dev_type; int fd; @@ -68,7 +77,7 @@ int qdl_vip_transfer_enable(struct qdl_device *qdl, const char *vip_table_path); struct qdl_device *usb_init(void); struct qdl_device *sim_init(void); -int firehose_run(struct qdl_device *qdl, const char *storage); +int firehose_run(struct qdl_device *qdl, enum qdl_storage_type storage); int firehose_provision(struct qdl_device *qdl); int firehose_read_buf(struct qdl_device *qdl, struct read_op *read_op, void *out_buf, size_t out_size); int sahara_run(struct qdl_device *qdl, char *img_arr[], bool single_image,