26 Commits

Author SHA1 Message Date
Bjorn Andersson
8589513f65 qdl: Wait for missing EDL device
Add support back for waiting for an EDL device to appear. This is useful
when paired with some automation scripts that introduces "arbitrary"
delays in the process of entering EDL mode.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-01-07 21:20:25 -08:00
Bjorn Andersson
ba86b03391 qdl: Remove debug print for claim return code
The USB claim return code was printed to the console for debug purposes,
remove this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-01-07 21:05:47 -08:00
Bjorn Andersson
59717efcd4 firehose: Remove unnecessary nop request
The nop was added to mitigate the fact that there's a rather long delay
in the response when sending out the first command. Increasing the write
timeout removes this problem and it's possible to just send the
configure as the first command without issues.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-01-07 21:00:42 -08:00
Bjorn Andersson
5ea1e20c01 program: Match xbl in a/b scenarios
On devices implementing a/b updates the xbl partiiton will be named
xbl_a and xbl_b, extend the match for finding the bootable partition to
support this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-01-07 16:41:39 -08:00
Bjorn Andersson
826a5cd4fd firehose: Send ZLP after each chunk
It was assumed that we should send all the data following a "program"
request to the device, before sending a ZLP. But on SDM845 it's seen
that not sending a ZLP after each chunk sometimes causes the
communication to stall.

Given that the "program" request already carries the information about
how much data will be transferred there should be no issues with sending
additional ZLPs, so do this.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-01-07 16:36:54 -08:00
Bjorn Andersson
8f7987f756 qdl: Communicate using USBFS instead of qcserial
On some newer platforms the device ignore the configure request to
disable ZLP, causing the Firehose program request to stall, when the
device is waiting for a ZLP to end a transfer.

Mitigate this by circumventing the qcserial driver and drive the USB
traffic directly using USBFS. The tool will attempt to detach qcserial
from the device, in case it's already attached, so no changes are needed
in the kernel or system configuration.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2019-01-07 16:36:50 -08:00
Laxman
b338928519 firehose: support for emmc storage
Added qdl support for emmc storage on platforms with UFS support.  Use
option --s emmc or ufs as a argument to qdl command, if not specified
any option the default storage would be ufs

Tested-by: Nicolas Dechesne <nicolas.dechesne@linaro.org>
Signed-off-by: Laxman <itsmelaxman91@gmail.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-11-07 21:33:44 -08:00
Daniel Kutik
dc61f8f79e Moved attr_as_unsigned and attr_as_string to util
Moved the two functions to util.c to remove duplicate code.
The previous error handling in some of the implemenations was
incomplete as it caused qdl to crash.
While the variable errors was incremented we still tried to
return the regular result. Now returning 0/NULL in case of error.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-11-05 09:10:00 -08:00
Daniel Kutik
cfce0beeab program: dropped unused attributes
The attributes size_in_KB, sparse and start_byte_hex
are not used and seem to be optional. Some program
xml files do not always contain them which then causes
qdl to crash. Simply removing the unused attributes
fixes this problem.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-11-05 09:09:36 -08:00
Niklas Cassel
a50ec8047c qdl: fix qdl when building for 32-bit
The sahara protocol specification defines the image field
for a read64 request as 8 bytes.
Use the correct type to represent this.

This will not change the behavior when building for 64-bit,
where the compiler already aligned the offset field correctly,
in order to satisfy natural alignment requirements.

However, when building for 32-bit, this change results in a
qdl that can flash a device successfully.

Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-06-12 12:08:01 -07:00
Niklas Cassel
5fc4cdbba4 qdl: fix error message referring to ttyUSB1
Since it is by no means certain that the current tty is ttyUSB1,
do not assume it to be so.

Unfortunately we do not know the current tty in main().
It would be possible to refactor the code so that we could print
the current tty, but since the only consumer of that information
would be this error message, that refactoring seems unjustified.

Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-06-12 12:07:35 -07:00
Niklas Cassel
37edf318b2 qdl: remove superfluous assignment
This assignment is superfluous, since the same assignment is performed
in the for loop's initializer.

Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-06-12 12:07:28 -07:00
Niklas Cassel
d9935e1f54 qdl: use correct printf modifier for uint64_t
printf uses PRIx64 modifier to print uint64_t.

This modifier has to be used outside of double-quotes.

Fixes build warnings on 32-bit systems, e.g. ARMv7.

Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-05-28 22:45:17 -07:00
Niklas Cassel
d77b106a57 qdl: use correct printf modifier for size_t
printf uses z modifier to print size_t.

Also change d modifier to u, since size_t is unsigned.
(ssize_t is the signed version.)

Fixes build warning on 32-bit systems, e.g. ARMv7.

Signed-off-by: Niklas Cassel <niklas.cassel@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-05-28 22:45:15 -07:00
Nicolas Dechesne
45cc3521d8 qdl: add --include to specific optional folder to look for files
Let the programmer search for files beyond the current folder. When --include is
used , the programmmer will first look for files in the specified folder, and it
will then fallback to looking at the current folder.

Signed-off-by: Nicolas Dechesne <nicolas.dechesne@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-04-18 22:07:36 -07:00
Nicolas Dechesne
5d51472f1c Merge ".gitreview: add new file" 2018-04-06 07:50:40 +00:00
Tanya Finkel
df842101b1 QDL: Fix UFS provision issue
Fix the return value verification and add printf status message

Signed-off-by: Tanya Finkel <tfinkel@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-28 14:13:59 -08:00
Bjorn Andersson
44a80b1266 qdl: Remove possibility for uninitialized variable
In the case that we find a "data" tag, but not a "program" or "ufs"
child node type might have been left unitialized. Fix this by
initializing type.

Also fix up the styling of the multiline blocks.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-21 22:36:03 -08:00
Kirill Kapranov
d2e791a950 QDL/firehose: Add UFS provisioning functionality
Add UFS provisioning functionality using Firehose.

Signed-off-by: Kirill Kapranov <kkapra@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-21 22:29:15 -08:00
Kirill Kapranov
b4c2e8f267 qdl: fix 'usage' message, add missing key 'debug'
Add a mention of command line parameter '--debug' in 'usage' printout

Signed-off-by: Kirill Kapranov <kkapra@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-05 09:52:22 -08:00
Nicolas Dechesne
7be48f4fc9 qdl: implement args processing with getopt_long
we preserve the same args as before, however it should now be simpler to
add new options.

Signed-off-by: Nicolas Dechesne <nicolas.dechesne@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-02 10:02:56 -08:00
Kirill Kapranov
19e8a2d4ba firehose: Add missing xmlFreeDoc
Each xmlNewDoc should have a matching xmlFreeDoc call in order to avoid
memory leaks.

Signed-off-by: Kirill Kapranov <kkapra@codeaurora.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2018-02-01 22:07:43 -08:00
Nicolas Dechesne
1fc3c04d17 firehose: Don't truncate partitions to 0 sectors
Some program entries has num_partition_sectors=0 but still specifies a
file, don't truncate the size of the file in this case.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2017-11-30 21:38:36 -08:00
Bjorn Andersson
0251833b4d program: Skip entries without a valid filename
Follow the behavior of the other flash tools and skip partitions with no
filename, instead of filling them with zeros. This reduces the flash
time considerably for some set of xml files.

Also clean up firehose_program() as we no longer need to support calling
this function with an invalid fd.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2017-11-29 21:13:10 -08:00
Bjorn Andersson
febbbcc32e firehose: Negotiate max payload size
When the host propose a larger payload size than the device accepts the
device will respond with a NACK, containing the maximum payload size.
Similarily the ACK will contain the supported max if the host requests a
lower value than the device supports.

In both cases we pick the largest possible value and send a second
configure message to select this payload size.

Reported-by: Kirill Kapranov <c_kkapra@qti.qualcomm.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
2017-11-29 13:24:29 -08:00
Nicolas Dechesne
922699c4db .gitreview: add new file
Convenient file to be used with git-review to make it simpler to contribute
patches into Linaro Gerrit review.

Change-Id: Ia96d2fea0de031e67f03c4384fb20dc9d5696c28
Signed-off-by: Nicolas Dechesne <nicolas.dechesne@linaro.org>
2017-08-29 13:56:05 +02:00
13 changed files with 1061 additions and 340 deletions

4
.gitreview Normal file
View File

@@ -0,0 +1,4 @@
[gerrit]
host=review.linaro.org
port=29418
project=landing-teams/working/qualcomm/qdl

View File

@@ -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)

View File

@@ -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
View File

@@ -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;
}

View File

@@ -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

View File

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

View File

@@ -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

488
qdl.c

File diff suppressed because it is too large Load Diff

12
qdl.h
View File

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

View File

@@ -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
View 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
View 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
View File

@@ -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);
}