Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 27 additions & 10 deletions firehose.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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 };
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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)
Copy link
Contributor

@igoropaniuk igoropaniuk Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering that struct qdl_device already has some storage-related fields like size_t sector_size, why not include qdl_storage_type into this structure as well?

This will remove the need to pass one more param to functions like this

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does make sense, we only support flashing single-storage-type anyways, so that would keep things cleaner. Thanks.

{
unsigned int num_sectors;
unsigned int sector_size;
unsigned int zlp_timeout = 10000;
struct stat sb;
size_t chunk_size;
xmlNode *root;
Expand All @@ -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;

Expand Down Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual increase to 30s occurred in the previous commit "qdl: Be explicit about storage types". Could you rephrase the commit message to more accurately reflect the changes made in that commit, or transfer that change (s/10000/30000/g) to this commit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that, the timeout was not supposed to change in the previous commit.

if (n < 0) {
ux_err("USB write failed for data chunk\n");
ret = firehose_read(qdl, 30000, firehose_generic_parser, NULL);
Expand Down Expand Up @@ -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 };
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;

Expand Down
9 changes: 7 additions & 2 deletions program.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion program.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 24 additions & 5 deletions qdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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: <emmc|nand|ufs>\n");
fprintf(out, " -s, --storage=T\t\tSet target storage type T: <emmc|nand|nvme|spinor|ufs>\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");
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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]);

Expand All @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion qdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Loading