mirror of
https://github.com/linux-msm/qdl.git
synced 2026-02-25 13:12:25 -08:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8589513f65 | ||
|
|
ba86b03391 | ||
|
|
59717efcd4 | ||
|
|
5ea1e20c01 | ||
|
|
826a5cd4fd | ||
|
|
8f7987f756 | ||
|
|
b338928519 | ||
|
|
dc61f8f79e | ||
|
|
cfce0beeab | ||
|
|
a50ec8047c | ||
|
|
5fc4cdbba4 | ||
|
|
37edf318b2 | ||
|
|
d9935e1f54 | ||
|
|
d77b106a57 | ||
|
|
45cc3521d8 | ||
|
|
5d51472f1c | ||
|
|
df842101b1 | ||
|
|
44a80b1266 | ||
|
|
d2e791a950 | ||
|
|
b4c2e8f267 | ||
|
|
7be48f4fc9 | ||
|
|
19e8a2d4ba | ||
|
|
1fc3c04d17 | ||
|
|
0251833b4d | ||
|
|
febbbcc32e | ||
|
|
922699c4db |
4
.gitreview
Normal file
4
.gitreview
Normal file
@@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=review.linaro.org
|
||||
port=29418
|
||||
project=landing-teams/working/qualcomm/qdl
|
||||
4
Makefile
4
Makefile
@@ -1,10 +1,10 @@
|
||||
OUT := qdl
|
||||
|
||||
CFLAGS := -O2 -Wall -g `xml2-config --cflags`
|
||||
LDFLAGS := `xml2-config --libs`
|
||||
LDFLAGS := `xml2-config --libs` -ludev
|
||||
prefix := /usr/local
|
||||
|
||||
SRCS := firehose.c qdl.c sahara.c util.c patch.c program.c
|
||||
SRCS := firehose.c qdl.c sahara.c util.c patch.c program.c ufs.c
|
||||
OBJS := $(SRCS:.c=.o)
|
||||
|
||||
$(OUT): $(OBJS)
|
||||
|
||||
304
firehose.c
304
firehose.c
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2017, Linaro Ltd.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -48,6 +49,7 @@
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include "qdl.h"
|
||||
#include "ufs.h"
|
||||
|
||||
static void xml_setpropf(xmlNode *node, const char *attr, const char *fmt, ...)
|
||||
{
|
||||
@@ -102,21 +104,7 @@ static void firehose_response_log(xmlNode *node)
|
||||
printf("LOG: %s\n", value);
|
||||
}
|
||||
|
||||
static int firehose_wait(int fd, int timeout)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ret;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
ret = poll(&pfd, 1, timeout);
|
||||
if (ret == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return ret < 0 ? ret : 0;;
|
||||
}
|
||||
|
||||
static int firehose_read(int fd, int timeout, int (*response_parser)(xmlNode *node))
|
||||
static int firehose_read(struct qdl_device *qdl, int wait, int (*response_parser)(xmlNode *node))
|
||||
{
|
||||
char buf[4096];
|
||||
xmlNode *nodes;
|
||||
@@ -127,25 +115,22 @@ static int firehose_read(int fd, int timeout, int (*response_parser)(xmlNode *no
|
||||
bool done = false;
|
||||
int ret = -ENXIO;
|
||||
int n;
|
||||
int timeout = 1000;
|
||||
|
||||
if (wait > 0)
|
||||
timeout = 10000;
|
||||
|
||||
while (!done) {
|
||||
ret = firehose_wait(fd, timeout);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
n = read(fd, buf, sizeof(buf));
|
||||
if (n == 0) {
|
||||
continue;
|
||||
} else if (n < 0) {
|
||||
n = qdl_read(qdl, buf, sizeof(buf), timeout);
|
||||
if (n < 0) {
|
||||
warn("failed to read");
|
||||
break;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
buf[n] = '\0';
|
||||
|
||||
if (qdl_debug)
|
||||
fprintf(stderr, "FIREHOSE READ: %s\n", buf);
|
||||
|
||||
msg = buf;
|
||||
for (msg = buf; msg[0]; msg = end) {
|
||||
end = strstr(msg, "</data>");
|
||||
if (!end) {
|
||||
@@ -175,12 +160,15 @@ static int firehose_read(int fd, int timeout, int (*response_parser)(xmlNode *no
|
||||
|
||||
xmlFreeDoc(nodes->doc);
|
||||
}
|
||||
|
||||
if (wait > 0)
|
||||
timeout = 100;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int firehose_write(int fd, xmlDoc *doc)
|
||||
static int firehose_write(struct qdl_device *qdl, xmlDoc *doc)
|
||||
{
|
||||
int saved_errno;
|
||||
xmlChar *s;
|
||||
@@ -192,7 +180,7 @@ static int firehose_write(int fd, xmlDoc *doc)
|
||||
if (qdl_debug)
|
||||
fprintf(stderr, "FIREHOSE WRITE: %s\n", s);
|
||||
|
||||
ret = write(fd, s, len);
|
||||
ret = qdl_write(qdl, s, len, true);
|
||||
saved_errno = errno;
|
||||
xmlFree(s);
|
||||
return ret < 0 ? -saved_errno : 0;
|
||||
@@ -206,7 +194,7 @@ static int firehose_nop_parser(xmlNode *node)
|
||||
return !!xmlStrcmp(value, (xmlChar*)"ACK");
|
||||
}
|
||||
|
||||
static int firehose_nop(int fd)
|
||||
static int firehose_nop(struct qdl_device *qdl)
|
||||
{
|
||||
xmlNode *root;
|
||||
xmlNode *node;
|
||||
@@ -220,31 +208,51 @@ static int firehose_nop(int fd)
|
||||
node = xmlNewChild(root, NULL, (xmlChar*)"nop", NULL);
|
||||
xml_setpropf(node, "value", "ping");
|
||||
|
||||
ret = firehose_write(fd, doc);
|
||||
ret = firehose_write(qdl, doc);
|
||||
xmlFreeDoc(doc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return firehose_read(fd, -1, firehose_nop_parser);
|
||||
return firehose_read(qdl, -1, firehose_nop_parser);
|
||||
}
|
||||
|
||||
static size_t max_payload_size = 1048576;
|
||||
|
||||
/**
|
||||
* firehose_configure_response_parser() - parse a configure response
|
||||
* @node: response xmlNode
|
||||
*
|
||||
* Return: max size supported by the remote, or negative errno on failure
|
||||
*/
|
||||
static int firehose_configure_response_parser(xmlNode *node)
|
||||
{
|
||||
xmlChar *payload;
|
||||
xmlChar *value;
|
||||
size_t max_size;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)"value");
|
||||
if (xmlStrcmp(value, (xmlChar*)"ACK"))
|
||||
payload = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytes");
|
||||
if (!value || !payload)
|
||||
return -EINVAL;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytes");
|
||||
if (value)
|
||||
max_payload_size = strtoul((char*)value, NULL, 10);
|
||||
max_size = strtoul((char*)payload, NULL, 10);
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* When receiving an ACK the remote may indicate that we should attempt
|
||||
* a larger payload size
|
||||
*/
|
||||
if (!xmlStrcmp(value, (xmlChar*)"ACK")) {
|
||||
payload = xmlGetProp(node, (xmlChar*)"MaxPayloadSizeToTargetInBytesSupported");
|
||||
if (!payload)
|
||||
return -EINVAL;
|
||||
|
||||
max_size = strtoul((char*)payload, NULL, 10);
|
||||
}
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
static int firehose_configure(int fd)
|
||||
static int firehose_send_configure(struct qdl_device *qdl, size_t payload_size, bool skip_storage_init, const char *storage)
|
||||
{
|
||||
xmlNode *root;
|
||||
xmlNode *node;
|
||||
@@ -256,22 +264,49 @@ static int firehose_configure(int fd)
|
||||
xmlDocSetRootElement(doc, root);
|
||||
|
||||
node = xmlNewChild(root, NULL, (xmlChar*)"configure", NULL);
|
||||
xml_setpropf(node, "MemoryName", "ufs");
|
||||
xml_setpropf(node, "MaxPayloadSizeToTargetInBytes", "%d", max_payload_size);
|
||||
xml_setpropf(node, "MemoryName", storage);
|
||||
xml_setpropf(node, "MaxPayloadSizeToTargetInBytes", "%d", payload_size);
|
||||
xml_setpropf(node, "verbose", "%d", 0);
|
||||
xml_setpropf(node, "ZLPAwareHost", "%d", 0);
|
||||
xml_setpropf(node, "ZLPAwareHost", "%d", 1);
|
||||
xml_setpropf(node, "SkipStorageInit", "%d", skip_storage_init);
|
||||
|
||||
ret = firehose_write(fd, doc);
|
||||
ret = firehose_write(qdl, doc);
|
||||
xmlFreeDoc(doc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return firehose_read(fd, -1, firehose_configure_response_parser);
|
||||
return firehose_read(qdl, -1, firehose_configure_response_parser);
|
||||
}
|
||||
|
||||
static int firehose_configure(struct qdl_device *qdl, bool skip_storage_init, const char *storage)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = firehose_send_configure(qdl, max_payload_size, skip_storage_init, storage);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Retry if remote proposed different size */
|
||||
if (ret != max_payload_size) {
|
||||
ret = firehose_send_configure(qdl, ret, skip_storage_init, storage);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
max_payload_size = ret;
|
||||
}
|
||||
|
||||
if (qdl_debug) {
|
||||
fprintf(stderr, "[CONFIGURE] max payload size: %zu\n",
|
||||
max_payload_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
|
||||
|
||||
static int firehose_program(int usbfd, struct program *program, int fd)
|
||||
static int firehose_program(struct qdl_device *qdl, struct program *program, int fd)
|
||||
{
|
||||
unsigned num_sectors;
|
||||
struct stat sb;
|
||||
@@ -288,16 +323,17 @@ static int firehose_program(int usbfd, struct program *program, int fd)
|
||||
|
||||
num_sectors = program->num_sectors;
|
||||
|
||||
if (fd >= 0) {
|
||||
fstat(fd, &sb);
|
||||
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
|
||||
ret = fstat(fd, &sb);
|
||||
if (ret < 0)
|
||||
err(1, "failed to stat \"%s\"\n", program->filename);
|
||||
|
||||
if (num_sectors > program->num_sectors) {
|
||||
fprintf(stderr, "[PROGRAM] %s truncated to %d\n",
|
||||
program->label,
|
||||
program->num_sectors * program->sector_size);
|
||||
num_sectors = program->num_sectors;
|
||||
}
|
||||
num_sectors = (sb.st_size + program->sector_size - 1) / program->sector_size;
|
||||
|
||||
if (program->num_sectors && num_sectors > program->num_sectors) {
|
||||
fprintf(stderr, "[PROGRAM] %s truncated to %d\n",
|
||||
program->label,
|
||||
program->num_sectors * program->sector_size);
|
||||
num_sectors = program->num_sectors;
|
||||
}
|
||||
|
||||
buf = malloc(max_payload_size);
|
||||
@@ -316,13 +352,13 @@ static int firehose_program(int usbfd, struct program *program, int fd)
|
||||
if (program->filename)
|
||||
xml_setpropf(node, "filename", "%s", program->filename);
|
||||
|
||||
ret = firehose_write(usbfd, doc);
|
||||
ret = firehose_write(qdl, doc);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "[PROGRAM] failed to write program command\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = firehose_read(usbfd, -1, firehose_nop_parser);
|
||||
ret = firehose_read(qdl, -1, firehose_nop_parser);
|
||||
if (ret) {
|
||||
fprintf(stderr, "[PROGRAM] failed to setup programming\n");
|
||||
goto out;
|
||||
@@ -335,18 +371,14 @@ static int firehose_program(int usbfd, struct program *program, int fd)
|
||||
while (left > 0) {
|
||||
chunk_size = MIN(max_payload_size / program->sector_size, left);
|
||||
|
||||
if (fd >= 0) {
|
||||
n = read(fd, buf, chunk_size * program->sector_size);
|
||||
if (n < 0)
|
||||
err(1, "failed to read");
|
||||
} else {
|
||||
n = 0;
|
||||
}
|
||||
n = read(fd, buf, chunk_size * program->sector_size);
|
||||
if (n < 0)
|
||||
err(1, "failed to read");
|
||||
|
||||
if (n < max_payload_size)
|
||||
memset(buf + n, 0, max_payload_size - n);
|
||||
|
||||
n = write(usbfd, buf, chunk_size * program->sector_size);
|
||||
n = qdl_write(qdl, buf, chunk_size * program->sector_size, true);
|
||||
if (n < 0)
|
||||
err(1, "failed to write");
|
||||
|
||||
@@ -358,7 +390,7 @@ static int firehose_program(int usbfd, struct program *program, int fd)
|
||||
|
||||
t = time(NULL) - t0;
|
||||
|
||||
ret = firehose_read(usbfd, -1, firehose_nop_parser);
|
||||
ret = firehose_read(qdl, -1, firehose_nop_parser);
|
||||
if (ret) {
|
||||
fprintf(stderr, "[PROGRAM] failed\n");
|
||||
} else if (t) {
|
||||
@@ -376,7 +408,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int firehose_apply_patch(int fd, struct patch *patch)
|
||||
static int firehose_apply_patch(struct qdl_device *qdl, struct patch *patch)
|
||||
{
|
||||
xmlNode *root;
|
||||
xmlNode *node;
|
||||
@@ -398,11 +430,11 @@ static int firehose_apply_patch(int fd, struct patch *patch)
|
||||
xml_setpropf(node, "start_sector", "%s", patch->start_sector);
|
||||
xml_setpropf(node, "value", "%s", patch->value);
|
||||
|
||||
ret = firehose_write(fd, doc);
|
||||
ret = firehose_write(qdl, doc);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = firehose_read(fd, -1, firehose_nop_parser);
|
||||
ret = firehose_read(qdl, -1, firehose_nop_parser);
|
||||
if (ret)
|
||||
fprintf(stderr, "[APPLY PATCH] %d\n", ret);
|
||||
|
||||
@@ -411,7 +443,101 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int firehose_set_bootable(int fd, int part)
|
||||
static int firehose_send_single_tag(struct qdl_device *qdl, xmlNode *node){
|
||||
xmlNode *root;
|
||||
xmlDoc *doc;
|
||||
int ret;
|
||||
|
||||
doc = xmlNewDoc((xmlChar*)"1.0");
|
||||
root = xmlNewNode(NULL, (xmlChar*)"data");
|
||||
xmlDocSetRootElement(doc, root);
|
||||
xmlAddChild(root, node);
|
||||
|
||||
ret = firehose_write(qdl, doc);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = firehose_read(qdl, -1, firehose_nop_parser);
|
||||
if (ret) {
|
||||
fprintf(stderr, "[UFS] %s err %d\n", __func__, ret);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
xmlFreeDoc(doc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int firehose_apply_ufs_common(struct qdl_device *qdl, struct ufs_common *ufs)
|
||||
{
|
||||
xmlNode *node_to_send;
|
||||
int ret;
|
||||
|
||||
node_to_send = xmlNewNode (NULL, (xmlChar*)"ufs");
|
||||
|
||||
xml_setpropf(node_to_send, "bNumberLU", "%d", ufs->bNumberLU);
|
||||
xml_setpropf(node_to_send, "bBootEnable", "%d", ufs->bBootEnable);
|
||||
xml_setpropf(node_to_send, "bDescrAccessEn", "%d", ufs->bDescrAccessEn);
|
||||
xml_setpropf(node_to_send, "bInitPowerMode", "%d", ufs->bInitPowerMode);
|
||||
xml_setpropf(node_to_send, "bHighPriorityLUN", "%d", ufs->bHighPriorityLUN);
|
||||
xml_setpropf(node_to_send, "bSecureRemovalType", "%d", ufs->bSecureRemovalType);
|
||||
xml_setpropf(node_to_send, "bInitActiveICCLevel", "%d", ufs->bInitActiveICCLevel);
|
||||
xml_setpropf(node_to_send, "wPeriodicRTCUpdate", "%d", ufs->wPeriodicRTCUpdate);
|
||||
xml_setpropf(node_to_send, "bConfigDescrLock", "%d", 0/*ufs->bConfigDescrLock*/); //Safety, remove before fly
|
||||
|
||||
ret = firehose_send_single_tag(qdl, node_to_send);
|
||||
if (ret)
|
||||
fprintf(stderr, "[APPLY UFS common] %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int firehose_apply_ufs_body(struct qdl_device *qdl, struct ufs_body *ufs)
|
||||
{
|
||||
xmlNode *node_to_send;
|
||||
int ret;
|
||||
|
||||
node_to_send = xmlNewNode (NULL, (xmlChar*)"ufs");
|
||||
|
||||
xml_setpropf(node_to_send, "LUNum", "%d", ufs->LUNum);
|
||||
xml_setpropf(node_to_send, "bLUEnable", "%d", ufs->bLUEnable);
|
||||
xml_setpropf(node_to_send, "bBootLunID", "%d", ufs->bBootLunID);
|
||||
xml_setpropf(node_to_send, "size_in_kb", "%d", ufs->size_in_kb);
|
||||
xml_setpropf(node_to_send, "bDataReliability", "%d", ufs->bDataReliability);
|
||||
xml_setpropf(node_to_send, "bLUWriteProtect", "%d", ufs->bLUWriteProtect);
|
||||
xml_setpropf(node_to_send, "bMemoryType", "%d", ufs->bMemoryType);
|
||||
xml_setpropf(node_to_send, "bLogicalBlockSize", "%d", ufs->bLogicalBlockSize);
|
||||
xml_setpropf(node_to_send, "bProvisioningType", "%d", ufs->bProvisioningType);
|
||||
xml_setpropf(node_to_send, "wContextCapabilities", "%d", ufs->wContextCapabilities);
|
||||
if(ufs->desc)
|
||||
xml_setpropf(node_to_send, "desc", "%s", ufs->desc);
|
||||
|
||||
ret = firehose_send_single_tag(qdl, node_to_send);
|
||||
if (ret)
|
||||
fprintf(stderr, "[APPLY UFS body] %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int firehose_apply_ufs_epilogue(struct qdl_device *qdl, struct ufs_epilogue *ufs,
|
||||
bool commit)
|
||||
{
|
||||
xmlNode *node_to_send;
|
||||
int ret;
|
||||
|
||||
node_to_send = xmlNewNode (NULL, (xmlChar*)"ufs");
|
||||
|
||||
xml_setpropf(node_to_send, "LUNtoGrow", "%d", ufs->LUNtoGrow);
|
||||
xml_setpropf(node_to_send, "commit", "%d", commit);
|
||||
|
||||
ret = firehose_send_single_tag(qdl, node_to_send);
|
||||
if (ret)
|
||||
fprintf(stderr, "[APPLY UFS epilogue] %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int firehose_set_bootable(struct qdl_device *qdl, int part)
|
||||
{
|
||||
xmlNode *root;
|
||||
xmlNode *node;
|
||||
@@ -425,11 +551,12 @@ static int firehose_set_bootable(int fd, int part)
|
||||
node = xmlNewChild(root, NULL, (xmlChar*)"setbootablestoragedrive", NULL);
|
||||
xml_setpropf(node, "value", "%d", part);
|
||||
|
||||
ret = firehose_write(fd, doc);
|
||||
ret = firehose_write(qdl, doc);
|
||||
xmlFreeDoc(doc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = firehose_read(fd, -1, firehose_nop_parser);
|
||||
ret = firehose_read(qdl, -1, firehose_nop_parser);
|
||||
if (ret) {
|
||||
fprintf(stderr, "failed to mark partition %d as bootable\n", part);
|
||||
return -1;
|
||||
@@ -439,7 +566,7 @@ static int firehose_set_bootable(int fd, int part)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int firehose_reset(int fd)
|
||||
static int firehose_reset(struct qdl_device *qdl)
|
||||
{
|
||||
xmlNode *root;
|
||||
xmlNode *node;
|
||||
@@ -453,38 +580,43 @@ static int firehose_reset(int fd)
|
||||
node = xmlNewChild(root, NULL, (xmlChar*)"power", NULL);
|
||||
xml_setpropf(node, "value", "reset");
|
||||
|
||||
ret = firehose_write(fd, doc);
|
||||
ret = firehose_write(qdl, doc);
|
||||
xmlFreeDoc(doc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return firehose_read(fd, -1, firehose_nop_parser);
|
||||
return firehose_read(qdl, -1, firehose_nop_parser);
|
||||
}
|
||||
|
||||
int firehose_run(int fd)
|
||||
int firehose_run(struct qdl_device *qdl, const char *incdir, const char *storage)
|
||||
{
|
||||
int bootable;
|
||||
int ret;
|
||||
|
||||
ret = firehose_wait(fd, 10000);
|
||||
if (ret < 0 && ret != -ETIMEDOUT)
|
||||
firehose_read(qdl, 5000, NULL);
|
||||
|
||||
if(ufs_need_provisioning()) {
|
||||
ret = firehose_configure(qdl, true, storage);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ufs_provisioning_execute(qdl, firehose_apply_ufs_common,
|
||||
firehose_apply_ufs_body, firehose_apply_ufs_epilogue);
|
||||
if (!ret)
|
||||
printf("UFS provisioning succeeded\n");
|
||||
else
|
||||
printf("UFS provisioning failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (firehose_read(fd, 100, NULL) != -ETIMEDOUT)
|
||||
;
|
||||
|
||||
ret = firehose_nop(fd);
|
||||
ret = firehose_configure(qdl, false, storage);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = firehose_configure(fd);
|
||||
ret = program_execute(qdl, firehose_program, incdir);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = program_execute(fd, firehose_program);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = patch_execute(fd, firehose_apply_patch);
|
||||
ret = patch_execute(qdl, firehose_apply_patch);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -492,9 +624,9 @@ int firehose_run(int fd)
|
||||
if (bootable < 0)
|
||||
fprintf(stderr, "no boot partition found\n");
|
||||
else
|
||||
firehose_set_bootable(fd, bootable);
|
||||
firehose_set_bootable(qdl, bootable);
|
||||
|
||||
firehose_reset(fd);
|
||||
firehose_reset(qdl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
27
patch.c
27
patch.c
@@ -34,32 +34,11 @@
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "patch.h"
|
||||
#include "qdl.h"
|
||||
|
||||
static struct patch *patches;
|
||||
static struct patch *patches_last;
|
||||
|
||||
static unsigned attr_as_unsigned(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value)
|
||||
(*errors)++;
|
||||
|
||||
return strtoul((char*)value, NULL, 10);
|
||||
}
|
||||
|
||||
static const char *attr_as_string(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value)
|
||||
(*errors)++;
|
||||
|
||||
return strdup((char*)value);
|
||||
}
|
||||
|
||||
int patch_load(const char *patch_file)
|
||||
{
|
||||
struct patch *patch;
|
||||
@@ -117,7 +96,7 @@ int patch_load(const char *patch_file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int patch_execute(int fd, int (*apply)(int fd, struct patch *patch))
|
||||
int patch_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct patch *patch))
|
||||
{
|
||||
struct patch *patch;
|
||||
int ret;
|
||||
@@ -126,7 +105,7 @@ int patch_execute(int fd, int (*apply)(int fd, struct patch *patch))
|
||||
if (strcmp(patch->filename, "DISK"))
|
||||
continue;
|
||||
|
||||
ret = apply(fd, patch);
|
||||
ret = apply(qdl, patch);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
4
patch.h
4
patch.h
@@ -1,6 +1,8 @@
|
||||
#ifndef __PATCH_H__
|
||||
#define __PATCH_H__
|
||||
|
||||
struct qdl_device;
|
||||
|
||||
struct patch {
|
||||
unsigned sector_size;
|
||||
unsigned byte_offset;
|
||||
@@ -15,6 +17,6 @@ struct patch {
|
||||
};
|
||||
|
||||
int patch_load(const char *patch_file);
|
||||
int patch_execute(int fd, int (*apply)(int fd, struct patch *patch));
|
||||
int patch_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct patch *patch));
|
||||
|
||||
#endif
|
||||
|
||||
78
program.c
78
program.c
@@ -36,46 +36,11 @@
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#include "program.h"
|
||||
#include "qdl.h"
|
||||
|
||||
static struct program *programes;
|
||||
static struct program *programes_last;
|
||||
|
||||
static unsigned attr_as_unsigned(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value)
|
||||
(*errors)++;
|
||||
|
||||
return strtoul((char*)value, NULL, 10);
|
||||
}
|
||||
|
||||
static const char *attr_as_string(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value)
|
||||
(*errors)++;
|
||||
|
||||
if (value && value[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
return strdup((char*)value);
|
||||
}
|
||||
|
||||
static bool attr_as_bool(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value)
|
||||
(*errors)++;
|
||||
|
||||
return xmlStrcmp(value, (xmlChar*)"true") == 0;
|
||||
}
|
||||
|
||||
int program_load(const char *program_file)
|
||||
{
|
||||
struct program *program;
|
||||
@@ -110,9 +75,6 @@ int program_load(const char *program_file)
|
||||
program->label = attr_as_string(node, "label", &errors);
|
||||
program->num_sectors = attr_as_unsigned(node, "num_partition_sectors", &errors);
|
||||
program->partition = attr_as_unsigned(node, "physical_partition_number", &errors);
|
||||
program->size = attr_as_unsigned(node, "size_in_KB", &errors);
|
||||
program->sparse = attr_as_bool(node, "sparse", &errors);
|
||||
program->start_bytes = attr_as_string(node, "start_byte_hex", &errors);
|
||||
program->start_sector = attr_as_string(node, "start_sector", &errors);
|
||||
|
||||
if (errors) {
|
||||
@@ -135,22 +97,34 @@ int program_load(const char *program_file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int program_execute(int usbfd, int (*apply)(int usbfd, struct program *program, int fd))
|
||||
int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd),
|
||||
const char *incdir)
|
||||
{
|
||||
struct program *program;
|
||||
const char *filename;
|
||||
char tmp[PATH_MAX];
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
for (program = programes; program; program = program->next) {
|
||||
fd = -1;
|
||||
if (program->filename) {
|
||||
fd = open(program->filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printf("Unable to open %s...ignoring\n", program->filename);
|
||||
continue;
|
||||
}
|
||||
if (!program->filename)
|
||||
continue;
|
||||
|
||||
filename = program->filename;
|
||||
if (incdir) {
|
||||
snprintf(tmp, PATH_MAX, "%s/%s", incdir, filename);
|
||||
if (access(tmp, F_OK) != -1)
|
||||
filename = tmp;
|
||||
}
|
||||
ret = apply(usbfd, program, fd);
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
printf("Unable to open %s...ignoring\n", program->filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = apply(qdl, program, fd);
|
||||
|
||||
close(fd);
|
||||
if (ret)
|
||||
@@ -165,9 +139,9 @@ int program_execute(int usbfd, int (*apply)(int usbfd, struct program *program,
|
||||
*
|
||||
* Returns partition number, or negative errno on failure.
|
||||
*
|
||||
* Scan program tags for a partition with the label "xbl" or "sbl1" and return
|
||||
* the partition number for this. If more than one line matches we're assuming
|
||||
* our logic is flawed and return an error.
|
||||
* Scan program tags for a partition with the label "sbl1" or that starts with
|
||||
* the string "xbl" and return the partition number for this. If more than one
|
||||
* line matches we're assuming our logic is flawed and return an error.
|
||||
*/
|
||||
int program_find_bootable_partition(void)
|
||||
{
|
||||
@@ -178,7 +152,7 @@ int program_find_bootable_partition(void)
|
||||
for (program = programes; program; program = program->next) {
|
||||
label = program->label;
|
||||
|
||||
if (!strcmp(label, "xbl") || !strcmp(label, "sbl1")) {
|
||||
if (!strncmp(label, "xbl", 3) || !strcmp(label, "sbl1")) {
|
||||
if (part != -ENOENT)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __PROGRAM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "qdl.h"
|
||||
|
||||
struct program {
|
||||
unsigned sector_size;
|
||||
@@ -10,16 +11,14 @@ struct program {
|
||||
const char *label;
|
||||
unsigned num_sectors;
|
||||
unsigned partition;
|
||||
unsigned size;
|
||||
bool sparse;
|
||||
const char *start_bytes;
|
||||
const char *start_sector;
|
||||
|
||||
struct program *next;
|
||||
};
|
||||
|
||||
int program_load(const char *program_file);
|
||||
int program_execute(int usbfd, int (*apply)(int usbfd, struct program *program, int fd));
|
||||
int program_execute(struct qdl_device *qdl, int (*apply)(struct qdl_device *qdl, struct program *program, int fd),
|
||||
const char *incdir);
|
||||
int program_find_bootable_partition(void);
|
||||
|
||||
#endif
|
||||
|
||||
12
qdl.h
12
qdl.h
@@ -5,10 +5,18 @@
|
||||
|
||||
#include "patch.h"
|
||||
#include "program.h"
|
||||
#include <libxml/tree.h>
|
||||
|
||||
int firehose_run(int fd);
|
||||
int sahara_run(int fd, char *prog_mbn);
|
||||
struct qdl_device;
|
||||
|
||||
int qdl_read(struct qdl_device *qdl, void *buf, size_t len, unsigned int timeout);
|
||||
int qdl_write(struct qdl_device *qdl, const void *buf, size_t len, bool eot);
|
||||
|
||||
int firehose_run(struct qdl_device *qdl, const char *incdir, const char *storage);
|
||||
int sahara_run(struct qdl_device *qdl, char *prog_mbn);
|
||||
void print_hex_dump(const char *prefix, const void *buf, size_t len);
|
||||
unsigned attr_as_unsigned(xmlNode *node, const char *attr, int *errors);
|
||||
const char *attr_as_string(xmlNode *node, const char *attr, int *errors);
|
||||
|
||||
extern bool qdl_debug;
|
||||
|
||||
|
||||
56
sahara.c
56
sahara.c
@@ -35,6 +35,7 @@
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <poll.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -77,14 +78,14 @@ struct sahara_pkt {
|
||||
uint32_t status;
|
||||
} done_resp;
|
||||
struct {
|
||||
uint32_t image;
|
||||
uint64_t image;
|
||||
uint64_t offset;
|
||||
uint64_t length;
|
||||
} read64_req;
|
||||
};
|
||||
};
|
||||
|
||||
static void sahara_hello(int fd, struct sahara_pkt *pkt)
|
||||
static void sahara_hello(struct qdl_device *qdl, struct sahara_pkt *pkt)
|
||||
{
|
||||
struct sahara_pkt resp;
|
||||
|
||||
@@ -100,10 +101,10 @@ static void sahara_hello(int fd, struct sahara_pkt *pkt)
|
||||
resp.hello_resp.status = 0;
|
||||
resp.hello_resp.mode = pkt->hello_req.mode;
|
||||
|
||||
write(fd, &resp, resp.length);
|
||||
qdl_write(qdl, &resp, resp.length, true);
|
||||
}
|
||||
|
||||
static int sahara_read_common(int fd, const char *mbn, off_t offset, size_t len)
|
||||
static int sahara_read_common(struct qdl_device *qdl, const char *mbn, off_t offset, size_t len)
|
||||
{
|
||||
int progfd;
|
||||
ssize_t n;
|
||||
@@ -125,7 +126,7 @@ static int sahara_read_common(int fd, const char *mbn, off_t offset, size_t len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
n = write(fd, buf, n);
|
||||
n = qdl_write(qdl, buf, n, true);
|
||||
if (n != len)
|
||||
err(1, "failed to write %zu bytes to sahara", len);
|
||||
|
||||
@@ -136,7 +137,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sahara_read(int fd, struct sahara_pkt *pkt, const char *mbn)
|
||||
static void sahara_read(struct qdl_device *qdl, struct sahara_pkt *pkt, const char *mbn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -145,26 +146,26 @@ static void sahara_read(int fd, struct sahara_pkt *pkt, const char *mbn)
|
||||
printf("READ image: %d offset: 0x%x length: 0x%x\n",
|
||||
pkt->read_req.image, pkt->read_req.offset, pkt->read_req.length);
|
||||
|
||||
ret = sahara_read_common(fd, mbn, pkt->read_req.offset, pkt->read_req.length);
|
||||
ret = sahara_read_common(qdl, mbn, pkt->read_req.offset, pkt->read_req.length);
|
||||
if (ret < 0)
|
||||
errx(1, "failed to read image chunk to sahara");
|
||||
}
|
||||
|
||||
static void sahara_read64(int fd, struct sahara_pkt *pkt, const char *mbn)
|
||||
static void sahara_read64(struct qdl_device *qdl, struct sahara_pkt *pkt, const char *mbn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(pkt->length == 0x20);
|
||||
|
||||
printf("READ64 image: %d offset: 0x%lx length: 0x%lx\n",
|
||||
printf("READ64 image: %" PRId64 " offset: 0x%" PRIx64 " length: 0x%" PRIx64 "\n",
|
||||
pkt->read64_req.image, pkt->read64_req.offset, pkt->read64_req.length);
|
||||
|
||||
ret = sahara_read_common(fd, mbn, pkt->read64_req.offset, pkt->read64_req.length);
|
||||
ret = sahara_read_common(qdl, mbn, pkt->read64_req.offset, pkt->read64_req.length);
|
||||
if (ret < 0)
|
||||
errx(1, "failed to read image chunk to sahara");
|
||||
}
|
||||
|
||||
static void sahara_eoi(int fd, struct sahara_pkt *pkt)
|
||||
static void sahara_eoi(struct qdl_device *qdl, struct sahara_pkt *pkt)
|
||||
{
|
||||
struct sahara_pkt done;
|
||||
|
||||
@@ -179,10 +180,10 @@ static void sahara_eoi(int fd, struct sahara_pkt *pkt)
|
||||
|
||||
done.cmd = 5;
|
||||
done.length = 0x8;
|
||||
write(fd, &done, done.length);
|
||||
qdl_write(qdl, &done, done.length, true);
|
||||
}
|
||||
|
||||
static int sahara_done(int fd, struct sahara_pkt *pkt)
|
||||
static int sahara_done(struct qdl_device *qdl, struct sahara_pkt *pkt)
|
||||
{
|
||||
assert(pkt->length == 0xc);
|
||||
|
||||
@@ -191,31 +192,18 @@ static int sahara_done(int fd, struct sahara_pkt *pkt)
|
||||
return pkt->done_resp.status;
|
||||
}
|
||||
|
||||
int sahara_run(int fd, char *prog_mbn)
|
||||
int sahara_run(struct qdl_device *qdl, char *prog_mbn)
|
||||
{
|
||||
struct sahara_pkt *pkt;
|
||||
struct pollfd pfd;
|
||||
char buf[4096];
|
||||
char tmp[32];
|
||||
bool done = false;
|
||||
int n;
|
||||
|
||||
while (!done) {
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
n = poll(&pfd, 1, -1);
|
||||
if (n < 0) {
|
||||
warn("failed to poll");
|
||||
n = qdl_read(qdl, buf, sizeof(buf), 1000);
|
||||
if (n < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
n = read(fd, buf, sizeof(buf));
|
||||
if (n == 0) {
|
||||
continue;
|
||||
} else if (n < 0) {
|
||||
warn("failed to read");
|
||||
break;
|
||||
}
|
||||
|
||||
pkt = (struct sahara_pkt*)buf;
|
||||
if (n != pkt->length) {
|
||||
@@ -225,20 +213,20 @@ int sahara_run(int fd, char *prog_mbn)
|
||||
|
||||
switch (pkt->cmd) {
|
||||
case 1:
|
||||
sahara_hello(fd, pkt);
|
||||
sahara_hello(qdl, pkt);
|
||||
break;
|
||||
case 3:
|
||||
sahara_read(fd, pkt, prog_mbn);
|
||||
sahara_read(qdl, pkt, prog_mbn);
|
||||
break;
|
||||
case 4:
|
||||
sahara_eoi(fd, pkt);
|
||||
sahara_eoi(qdl, pkt);
|
||||
break;
|
||||
case 6:
|
||||
sahara_done(fd, pkt);
|
||||
sahara_done(qdl, pkt);
|
||||
done = true;
|
||||
break;
|
||||
case 0x12:
|
||||
sahara_read64(fd, pkt, prog_mbn);
|
||||
sahara_read64(qdl, pkt, prog_mbn);
|
||||
break;
|
||||
default:
|
||||
sprintf(tmp, "CMD%x", pkt->cmd);
|
||||
|
||||
310
ufs.c
Normal file
310
ufs.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
#include "ufs.h"
|
||||
#include "qdl.h"
|
||||
#include "patch.h"
|
||||
|
||||
struct ufs_common *ufs_common_p;
|
||||
struct ufs_epilogue *ufs_epilogue_p;
|
||||
struct ufs_body *ufs_body_p;
|
||||
struct ufs_body *ufs_body_last;
|
||||
|
||||
static const char notice_bconfigdescrlock[] = "\n"
|
||||
"Please pay attention that UFS provisioning is irreversible (OTP) operation unless parameter bConfigDescrLock = 0.\n"
|
||||
"In order to prevent unintentional device locking the tool has the following safety:\n\n"
|
||||
" if you REALLY intend to perform OTP, please ensure that your XML includes property\n"
|
||||
" bConfigDescrLock = 1 AND provide command line parameter --finalize-provisioning.\n\n"
|
||||
" Unless you intend to lock your device, please set bConfigDescrLock = 0 in your XML\n"
|
||||
" and don't use command line parameter --finalize-provisioning.\n\n"
|
||||
"In case of mismatch between CL and XML provisioning is not performed.\n\n";
|
||||
|
||||
|
||||
|
||||
bool ufs_need_provisioning(void)
|
||||
{
|
||||
return !!ufs_epilogue_p;
|
||||
}
|
||||
|
||||
struct ufs_common *ufs_parse_common_params(xmlNode *node, bool finalize_provisioning)
|
||||
{
|
||||
struct ufs_common *result;
|
||||
int errors;
|
||||
|
||||
result = calloc(1, sizeof(struct ufs_common));
|
||||
errors = 0;
|
||||
|
||||
result->bNumberLU = attr_as_unsigned(node, "bNumberLU", &errors);
|
||||
result->bBootEnable = !!attr_as_unsigned(node, "bBootEnable", &errors);
|
||||
result->bDescrAccessEn = !!attr_as_unsigned(node, "bDescrAccessEn", &errors);
|
||||
result->bInitPowerMode = attr_as_unsigned(node, "bInitPowerMode", &errors);
|
||||
result->bHighPriorityLUN = attr_as_unsigned(node, "bHighPriorityLUN", &errors);
|
||||
result->bSecureRemovalType = attr_as_unsigned(node, "bSecureRemovalType", &errors);
|
||||
result->bInitActiveICCLevel = attr_as_unsigned(node, "bInitActiveICCLevel", &errors);
|
||||
result->wPeriodicRTCUpdate = attr_as_unsigned(node, "wPeriodicRTCUpdate", &errors);
|
||||
result->bConfigDescrLock = !!attr_as_unsigned(node, "bConfigDescrLock", &errors);
|
||||
|
||||
if (errors) {
|
||||
fprintf(stderr, "[UFS] errors while parsing common\n");
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ufs_body *ufs_parse_body(xmlNode *node)
|
||||
{
|
||||
struct ufs_body *result;
|
||||
int errors;
|
||||
|
||||
result = calloc(1, sizeof(struct ufs_body));
|
||||
errors = 0;
|
||||
|
||||
result->LUNum = attr_as_unsigned(node, "LUNum", &errors);
|
||||
result->bLUEnable = !!attr_as_unsigned(node, "bLUEnable", &errors);
|
||||
result->bBootLunID = attr_as_unsigned(node, "bBootLunID", &errors);
|
||||
result->size_in_kb = attr_as_unsigned(node, "size_in_kb", &errors);
|
||||
result->bDataReliability = attr_as_unsigned(node, "bDataReliability", &errors);
|
||||
result->bLUWriteProtect = attr_as_unsigned(node, "bLUWriteProtect", &errors);
|
||||
result->bMemoryType = attr_as_unsigned(node, "bMemoryType", &errors);
|
||||
result->bLogicalBlockSize = attr_as_unsigned(node, "bLogicalBlockSize", &errors);
|
||||
result->bProvisioningType = attr_as_unsigned(node, "bProvisioningType", &errors);
|
||||
result->wContextCapabilities = attr_as_unsigned(node, "wContextCapabilities", &errors);
|
||||
result->desc = attr_as_string(node, "desc", &errors);
|
||||
|
||||
if (errors) {
|
||||
fprintf(stderr, "[UFS] errors while parsing body\n");
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ufs_epilogue *ufs_parse_epilogue(xmlNode *node)
|
||||
{
|
||||
struct ufs_epilogue *result;
|
||||
int errors = 0;
|
||||
|
||||
result = calloc(1, sizeof(struct ufs_epilogue));
|
||||
|
||||
result->LUNtoGrow = attr_as_unsigned(node, "LUNtoGrow", &errors);
|
||||
|
||||
if (errors) {
|
||||
fprintf(stderr, "[UFS] errors while parsing epilogue\n");
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ufs_load(const char *ufs_file, bool finalize_provisioning)
|
||||
{
|
||||
xmlNode *node;
|
||||
xmlNode *root;
|
||||
xmlDoc *doc;
|
||||
int retval = 0;
|
||||
struct ufs_body *ufs_body_tmp;
|
||||
|
||||
if (ufs_common_p) {
|
||||
fprintf(stderr,
|
||||
"Only one UFS provisioning XML allowed, %s ignored\n",
|
||||
ufs_file);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
doc = xmlReadFile(ufs_file, NULL, 0);
|
||||
if (!doc) {
|
||||
fprintf(stderr, "[UFS] failed to parse %s\n", ufs_file);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
root = xmlDocGetRootElement(doc);
|
||||
|
||||
for (node = root->children; node ; node = node->next) {
|
||||
if (node->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
|
||||
if (xmlStrcmp(node->name, (xmlChar*)"ufs")) {
|
||||
fprintf(stderr, "[UFS] unrecognized tag \"%s\", ignoring\n",
|
||||
node->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xmlGetProp(node, (xmlChar *)"bNumberLU")) {
|
||||
if (!ufs_common_p) {
|
||||
ufs_common_p = ufs_parse_common_params(node,
|
||||
finalize_provisioning);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "[UFS] Only one common tag is allowed\n"
|
||||
"[UFS] provisioning aborted\n");
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ufs_common_p) {
|
||||
fprintf(stderr, "[UFS] Common tag corrupted\n"
|
||||
"[UFS] provisioning aborted\n");
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else if (xmlGetProp(node, (xmlChar *)"LUNum")) {
|
||||
ufs_body_tmp = ufs_parse_body(node);
|
||||
if(ufs_body_tmp) {
|
||||
if (ufs_body_p) {
|
||||
ufs_body_last->next = ufs_body_tmp;
|
||||
ufs_body_last = ufs_body_tmp;
|
||||
}
|
||||
else {
|
||||
ufs_body_p = ufs_body_tmp;
|
||||
ufs_body_last = ufs_body_tmp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "[UFS] LU tag corrupted\n"
|
||||
"[UFS] provisioning aborted\n");
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else if (xmlGetProp(node, (xmlChar *)"commit")) {
|
||||
if (!ufs_epilogue_p) {
|
||||
ufs_epilogue_p = ufs_parse_epilogue(node);
|
||||
if (ufs_epilogue_p)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "[UFS] Only one finalizing tag is allowed\n"
|
||||
"[UFS] provisioning aborted\n");
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ufs_epilogue_p) {
|
||||
fprintf(stderr, "[UFS] Finalizing tag corrupted\n"
|
||||
"[UFS] provisioning aborted\n");
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "[UFS] Unknown tag or %s corrupted\n"
|
||||
"[UFS] provisioning aborted\n", ufs_file);
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
if (!retval && (!ufs_common_p || !ufs_body_p || !ufs_epilogue_p)) {
|
||||
fprintf(stderr, "[UFS] %s seems to be incomplete\n"
|
||||
"[UFS] provisioning aborted\n", ufs_file);
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
if (retval){
|
||||
if (ufs_common_p) {
|
||||
free(ufs_common_p);
|
||||
}
|
||||
if (ufs_body_p) {
|
||||
free(ufs_body_p);
|
||||
}
|
||||
if (ufs_epilogue_p) {
|
||||
free(ufs_epilogue_p);
|
||||
}
|
||||
fprintf(stderr, "[UFS] %s seems to be corrupted, ignore\n", ufs_file);
|
||||
return retval;
|
||||
}
|
||||
if (!finalize_provisioning != !ufs_common_p->bConfigDescrLock) {
|
||||
fprintf(stderr,
|
||||
"[UFS] Value bConfigDescrLock %d in file %s don't match command line parameter --finalize-provisioning %d\n"
|
||||
"[UFS] provisioning aborted\n",
|
||||
ufs_common_p->bConfigDescrLock, ufs_file, finalize_provisioning);
|
||||
fprintf(stderr, notice_bconfigdescrlock);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ufs_provisioning_execute(struct qdl_device *qdl,
|
||||
int (*apply_ufs_common)(struct qdl_device *, struct ufs_common*),
|
||||
int (*apply_ufs_body)(struct qdl_device *, struct ufs_body*),
|
||||
int (*apply_ufs_epilogue)(struct qdl_device *, struct ufs_epilogue*, bool))
|
||||
{
|
||||
int ret;
|
||||
struct ufs_body *body;
|
||||
|
||||
if (ufs_common_p->bConfigDescrLock) {
|
||||
int i;
|
||||
printf("Attention!\nIrreversible provisioning will start in 5 s\n");
|
||||
for(i=5; i>0; i--) {
|
||||
printf(".\a");
|
||||
sleep(1);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Just ask a target to check the XML w/o real provisioning
|
||||
ret = apply_ufs_common(qdl, ufs_common_p);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (body = ufs_body_p; body; body = body->next) {
|
||||
ret = apply_ufs_body(qdl, body);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = apply_ufs_epilogue(qdl, ufs_epilogue_p, false);
|
||||
if (ret) {
|
||||
fprintf(stderr,
|
||||
"UFS provisioning impossible, provisioning XML may be corrupted\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Real provisioning -- target didn't refuse a given XML
|
||||
ret = apply_ufs_common(qdl, ufs_common_p);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (body = ufs_body_p; body; body = body->next) {
|
||||
ret = apply_ufs_body(qdl, body);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return apply_ufs_epilogue(qdl, ufs_epilogue_p, true);
|
||||
}
|
||||
75
ufs.h
Normal file
75
ufs.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of The Linux Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __UFS_H__
|
||||
#define __UFS_H__
|
||||
#include <stdbool.h>
|
||||
|
||||
struct qdl_device;
|
||||
|
||||
struct ufs_common {
|
||||
unsigned bNumberLU;
|
||||
bool bBootEnable;
|
||||
bool bDescrAccessEn;
|
||||
unsigned bInitPowerMode;
|
||||
unsigned bHighPriorityLUN;
|
||||
unsigned bSecureRemovalType;
|
||||
unsigned bInitActiveICCLevel;
|
||||
unsigned wPeriodicRTCUpdate;
|
||||
bool bConfigDescrLock;
|
||||
};
|
||||
|
||||
struct ufs_body {
|
||||
unsigned LUNum;
|
||||
bool bLUEnable;
|
||||
unsigned bBootLunID;
|
||||
unsigned size_in_kb;
|
||||
unsigned bDataReliability;
|
||||
unsigned bLUWriteProtect;
|
||||
unsigned bMemoryType;
|
||||
unsigned bLogicalBlockSize;
|
||||
unsigned bProvisioningType;
|
||||
unsigned wContextCapabilities;
|
||||
const char *desc;
|
||||
|
||||
struct ufs_body *next;
|
||||
};
|
||||
|
||||
struct ufs_epilogue {
|
||||
unsigned LUNtoGrow;
|
||||
bool commit;
|
||||
};
|
||||
|
||||
int ufs_load(const char *ufs_file, bool finalize_provisioning);
|
||||
int ufs_provisioning_execute(struct qdl_device *qdl,
|
||||
int (*apply_ufs_common)(struct qdl_device *qdl, struct ufs_common *ufs),
|
||||
int (*apply_ufs_body)(struct qdl_device *qdl, struct ufs_body *ufs),
|
||||
int (*apply_ufs_epilogue)(struct qdl_device *qdl, struct ufs_epilogue *ufs, bool commit));
|
||||
bool ufs_need_provisioning(void);
|
||||
|
||||
#endif
|
||||
32
util.c
32
util.c
@@ -31,6 +31,9 @@
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
@@ -77,3 +80,32 @@ void print_hex_dump(const char *prefix, const void *buf, size_t len)
|
||||
printf("%s %04x: %s\n", prefix, i, line);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned attr_as_unsigned(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value) {
|
||||
(*errors)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (unsigned int) strtoul((char*)value, NULL, 10);
|
||||
}
|
||||
|
||||
const char *attr_as_string(xmlNode *node, const char *attr, int *errors)
|
||||
{
|
||||
xmlChar *value;
|
||||
|
||||
value = xmlGetProp(node, (xmlChar*)attr);
|
||||
if (!value) {
|
||||
(*errors)++;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (value[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
return strdup((char*)value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user