Commit d2e791a9 authored by Kirill Kapranov's avatar Kirill Kapranov Committed by Bjorn Andersson
Browse files

QDL/firehose: Add UFS provisioning functionality



Add UFS provisioning functionality using Firehose.
Signed-off-by: default avatarKirill Kapranov <kkapra@codeaurora.org>
Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
parent b4c2e8f2
......@@ -4,7 +4,7 @@ CFLAGS := -O2 -Wall -g `xml2-config --cflags`
LDFLAGS := `xml2-config --libs`
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)
......
/*
* 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, ...)
{
......@@ -264,7 +266,7 @@ static int firehose_configure_response_parser(xmlNode *node)
return max_size;
}
static int firehose_send_configure(int fd, size_t payload_size)
static int firehose_send_configure(int fd, size_t payload_size, bool skip_storage_init)
{
xmlNode *root;
xmlNode *node;
......@@ -280,6 +282,7 @@ static int firehose_send_configure(int fd, size_t payload_size)
xml_setpropf(node, "MaxPayloadSizeToTargetInBytes", "%d", payload_size);
xml_setpropf(node, "verbose", "%d", 0);
xml_setpropf(node, "ZLPAwareHost", "%d", 0);
xml_setpropf(node, "SkipStorageInit", "%d", skip_storage_init);
ret = firehose_write(fd, doc);
xmlFreeDoc(doc);
......@@ -289,17 +292,17 @@ static int firehose_send_configure(int fd, size_t payload_size)
return firehose_read(fd, -1, firehose_configure_response_parser);
}
static int firehose_configure(int fd)
static int firehose_configure(int fd, bool skip_storage_init)
{
int ret;
ret = firehose_send_configure(fd, max_payload_size);
ret = firehose_send_configure(fd, max_payload_size, skip_storage_init);
if (ret < 0)
return ret;
/* Retry if remote proposed different size */
if (ret != max_payload_size) {
ret = firehose_send_configure(fd, ret);
ret = firehose_send_configure(fd, ret, skip_storage_init);
if (ret < 0)
return ret;
......@@ -454,6 +457,100 @@ out:
return ret;
}
static int firehose_send_single_tag(int usbfd, 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(usbfd, doc);
if (ret < 0)
goto out;
ret = firehose_read(usbfd, -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(int fd, 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(fd, node_to_send);
if (ret)
fprintf(stderr, "[APPLY UFS common] %d\n", ret);
return ret;
}
int firehose_apply_ufs_body(int fd, 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(fd, node_to_send);
if (ret)
fprintf(stderr, "[APPLY UFS body] %d\n", ret);
return ret;
}
int firehose_apply_ufs_epilogue(int fd, 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(fd, node_to_send);
if (ret)
fprintf(stderr, "[APPLY UFS epilogue] %d\n", ret);
return ret;
}
static int firehose_set_bootable(int fd, int part)
{
xmlNode *root;
......@@ -521,7 +618,17 @@ int firehose_run(int fd)
if (ret)
return ret;
ret = firehose_configure(fd);
if(ufs_need_provisioning()) {
ret = firehose_configure(fd, true);
if (ret)
return ret;
ret = ufs_provisioning_execute(fd, firehose_apply_ufs_common,
firehose_apply_ufs_body, firehose_apply_ufs_epilogue);
if (ret)
return ret;
}
ret = firehose_configure(fd, false);
if (ret)
return ret;
......
/*
* 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
......@@ -49,11 +50,13 @@
#include "qdl.h"
#include "patch.h"
#include "ufs.h"
enum {
QDL_FILE_UNKNOWN,
QDL_FILE_PATCH,
QDL_FILE_PROGRAM,
QDL_FILE_UFS,
QDL_FILE_CONTENTS,
};
......@@ -63,6 +66,7 @@ static int detect_type(const char *xml_file)
{
xmlNode *root;
xmlDoc *doc;
xmlNode *node;
int type;
doc = xmlReadFile(xml_file, NULL, 0);
......@@ -74,8 +78,20 @@ static int detect_type(const char *xml_file)
root = xmlDocGetRootElement(doc);
if (!xmlStrcmp(root->name, (xmlChar*)"patches"))
type = QDL_FILE_PATCH;
else if (!xmlStrcmp(root->name, (xmlChar*)"data"))
type = QDL_FILE_PROGRAM;
else if (!xmlStrcmp(root->name, (xmlChar*)"data")) {
for (node = root->children; node ; node = node->next) {
if (node->type != XML_ELEMENT_NODE)
continue;
if (!xmlStrcmp(node->name, (xmlChar*)"program")) {
type = QDL_FILE_PROGRAM;
break;
}
if (!xmlStrcmp(node->name, (xmlChar*)"ufs")) {
type = QDL_FILE_UFS;
break;
}
}
}
else if (!xmlStrcmp(root->name, (xmlChar*)"contents"))
type = QDL_FILE_CONTENTS;
else
......@@ -205,7 +221,8 @@ retry:
static void print_usage(void)
{
extern const char *__progname;
fprintf(stderr, "%s [--debug] <prog.mbn> [<program> <patch> ...]\n",
fprintf(stderr,
"%s [--debug] [--finalize-provisioning] <prog.mbn> [<program> <patch> ...]\n",
__progname);
}
......@@ -217,9 +234,12 @@ int main(int argc, char **argv)
int ret;
int fd;
int opt;
bool qdl_finalize_provisioning = false;
static struct option options[] = {
{"debug", no_argument, 0, 'd'},
{"finalize-provisioning", no_argument, 0, 'l'},
{0, 0, 0, 0}
};
......@@ -228,6 +248,9 @@ int main(int argc, char **argv)
case 'd':
qdl_debug = true;
break;
case 'l':
qdl_finalize_provisioning = true;
break;
default:
print_usage();
return 1;
......@@ -258,6 +281,11 @@ int main(int argc, char **argv)
if (ret < 0)
errx(1, "program_load %s failed", argv[optind]);
break;
case QDL_FILE_UFS:
ret = ufs_load(argv[optind],qdl_finalize_provisioning);
if (ret < 0)
errx(1, "ufs_load %s failed", argv[optind]);
break;
default:
errx(1, "%s type not yet supported", argv[optind]);
break;
......
/*
* 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";
// ToDo: These 2 functions must be moved to a common module (refactoring required)
static unsigned attr_as_unsigned(xmlNode *node, const char *attr, int *errors)
{
xmlChar *value;
value = xmlGetProp(node, (xmlChar*)attr);
if (!value) {
(*errors)++;
return 0;
}
return strtoul((char*)value, NULL, 0);
}
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);
}
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(int usbfd,
int (*apply_ufs_common)(int, struct ufs_common*),
int (*apply_ufs_body)(int, struct ufs_body*),
int (*apply_ufs_epilogue)(int, 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(usbfd, ufs_common_p);
if (!ret)
return ret;
for (body = ufs_body_p; body; body = body->next) {
ret = apply_ufs_body(usbfd, body);
if (!ret)
return ret;
}
ret = apply_ufs_epilogue(usbfd, 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(usbfd, ufs_common_p);
if (!ret)
return ret;
for (body = ufs_body_p; body; body = body->next) {
ret = apply_ufs_body(usbfd, body);
if (!ret)
return ret;
}
return apply_ufs_epilogue(usbfd, ufs_epilogue_p, true);
}
/*
* 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,