From b8d89669dd4f8a29b8c6888e4334402396857afe Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 16 Apr 2018 10:45:17 +0900 Subject: [PATCH 02/11] Create spec file for RPM package This patch creates files required to build the RPM package. Althogh it is possible to build the package, only one empty RPM file would be created since source files are not implemented yet. Change-Id: Ie3ce70a8c2b00b9aaa88610bcdfdcf9384daa06d Signed-off-by: Dongwoo Lee --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++ initrd-flash.manifest | 5 ++ packaging/initrd-flash.spec | 29 +++++++ 3 files changed, 235 insertions(+) create mode 100644 LICENSE create mode 100644 initrd-flash.manifest create mode 100644 packaging/initrd-flash.spec diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/initrd-flash.manifest b/initrd-flash.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/initrd-flash.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec new file mode 100644 index 0000000..2a3486b --- /dev/null +++ b/packaging/initrd-flash.spec @@ -0,0 +1,29 @@ +Name: initrd-flash +Summary: Advanced flash-manager, package for building ramdisk-recovery.img +Version: 0.0.1 +Release: 0 +Group: System/Utilities +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +ExclusiveArch: %{arm} + +Requires: initrd-recovery + +%description +Provide kernel-based target image downloader. +This package would be included in partition image for RAMDISK2 (ramdisk-recovery.img) + +%prep +%setup -q + +%build + +%install + +%post + +%postun + +%files +%manifest initrd-flash.manifest +%license LICENSE -- 2.7.4 From caa9abb4845e7fb22cb7169ed5cbb0792de8ac50 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 3 Nov 2017 06:33:17 +0900 Subject: [PATCH 03/11] Add initial implementation of network backend This is initial version of flash-manager with network backend. The entire structure would be evolved while the new feature is added. Change-Id: I659c2795d339060afada9a9ffd5f41294c17f228 Signed-off-by: Dongwoo Lee --- CMakeLists.txt | 16 ++ packaging/initrd-flash.spec | 10 ++ src/dfu.c | 373 ++++++++++++++++++++++++++++++++++++++++++++ src/dfu.h | 49 ++++++ src/main.c | 113 ++++++++++++++ src/net.c | 102 ++++++++++++ src/net.h | 27 ++++ src/tfm.h | 54 +++++++ src/thor-proto.h | 99 ++++++++++++ src/thor.c | 343 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1186 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 src/dfu.c create mode 100644 src/dfu.h create mode 100644 src/main.c create mode 100644 src/net.c create mode 100644 src/net.h create mode 100644 src/tfm.h create mode 100644 src/thor-proto.h create mode 100644 src/thor.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8688aa1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,16 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(flash-manager C) + +FIND_PACKAGE(Threads REQUIRED) + +ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/net.c) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src) + +IF(CMAKE_THREAD_LIBS_INIT) + TARGET_LINK_LIBRARIES(flash-manager "${CMAKE_THREAD_LIBS_INIT}") +ENDIF() + +ADD_DEFINITIONS(-Wall -g -O2) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index 2a3486b..7e90fe3 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -6,7 +6,10 @@ Group: System/Utilities License: Apache-2.0 Source0: %{name}-%{version}.tar.gz ExclusiveArch: %{arm} +BuildRequires: cmake +Requires: util-linux +Requires: bash Requires: initrd-recovery %description @@ -18,8 +21,14 @@ This package would be included in partition image for RAMDISK2 (ramdisk-recovery %build +%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} + +make %{?jobs:-j%jobs} + %install +%make_install + %post %postun @@ -27,3 +36,4 @@ This package would be included in partition image for RAMDISK2 (ramdisk-recovery %files %manifest initrd-flash.manifest %license LICENSE +%attr(700,root,root) %{_bindir}/flash-manager diff --git a/src/dfu.c b/src/dfu.c new file mode 100644 index 0000000..77e47a7 --- /dev/null +++ b/src/dfu.c @@ -0,0 +1,373 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dfu.h" +#include "thor-proto.h" + +static char *dfu_info[DFU_INFO_NUM][DFU_INFO_MAX] = {NULL,}; + +void *dfu_get_buffer(unsigned long size) +{ + int wait = 100000; /* 100ms */ + void *buf; + + while (!(buf = malloc(size))) { + /* + * In the case of not enough memory, instead of returning error, + * transfer thread waits until dfu writes and frees buffers. + */ + usleep(wait); + wait *= 2; + } + + return buf; +} + +void dfu_put_buffer(void *ptr) +{ + free(ptr); +} + +static int find_match(const char *name) +{ + int i; + + for (i = 0; i < DFU_INFO_NUM; i++) { + char *entry = dfu_info[i][DFU_INFO_NAME]; + + if (entry && !strncmp(entry, name, strlen(entry))) + return i; + } + + return -ENOENT; +} + +int dfu_request_io(struct tfm_context *ctx, unsigned long len) +{ + int notify = 0; + struct dfu_frame *frame; + + frame = malloc(sizeof(*frame)); + if (!frame) + return -ENOMEM; + + frame->buf = ctx->transfer_buffer; + frame->len = len; + + pthread_mutex_lock(&ctx->dfu_mutex); + + if (TAILQ_EMPTY(&ctx->dfu_ioq_head)) + notify = 1; + + /* dfu_thread_main() de-queues i/o request and processes it */ + TAILQ_INSERT_TAIL(&ctx->dfu_ioq_head, frame, entry); + + pthread_mutex_unlock(&ctx->dfu_mutex); + + if (notify) + pthread_cond_signal(&ctx->dfu_data_arrive); + + return 0; +} + +static void mount_dev(const char *dev) +{ + int ret; + + mkdir(DFU_MOUNT_PATH, 0600); + + ret = mount(dev, DFU_MOUNT_PATH, "ext4", 0, NULL); + if (ret < 0) { + fprintf(stderr, "Failed to mount target partition\n"); + rmdir(DFU_MOUNT_PATH); + exit(-1); + } +} + +static void umount_dev(void) +{ + int ret; + + ret = umount(DFU_MOUNT_PATH); + if (ret < 0) { + fprintf(stderr, "Failed to mount target partition\n"); + + /* umount is failed, but anyway try to delete mount point */ + rmdir(DFU_MOUNT_PATH); + exit(-1); + } + + rmdir(DFU_MOUNT_PATH); +} + +void dfu_sync(struct tfm_context *ctx) +{ + char **info = ctx->dfu_info; + + pthread_mutex_lock(&ctx->dfu_sync_mutex); + if (!ctx->transfer_done) + pthread_cond_wait(&ctx->dfu_write_done, &ctx->dfu_sync_mutex); + pthread_mutex_unlock(&ctx->dfu_sync_mutex); + + switch (*info[DFU_INFO_MODE]) { + case 'f': + fsync(ctx->dfu_fd); + close(ctx->dfu_fd); + umount_dev(); + break; + case 'p': + close(ctx->dfu_fd); + break; + default: + break; + } + + pthread_cond_signal(&ctx->dfu_sync_done); + + fprintf(stdout, "finished\n"); +} + +static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size) +{ + char **info = dfu_info[idx]; + char *file; + int fd; + + switch (*info[DFU_INFO_MODE]) { + case 'p': + file = info[DFU_INFO_DEV]; + break; + case 'f': + mount_dev(info[DFU_INFO_DEV]); + file = info[DFU_INFO_PATH]; + break; + default: + fprintf(stderr, "flash entry '%s' has wrong mode\n", info[DFU_INFO_NAME]); + return -EINVAL; + } + + fd = open(file, O_WRONLY); + if (fd < 0) { + fprintf(stderr, "cannot open target: %s\n", info[DFU_INFO_NAME]); + return -EIO; + } + + ctx->dfu_fd = fd; + + ctx->dfu_info = info; + ctx->transfer_done = 0; + + return 0; +} + + +int dfu_start(struct tfm_context *ctx, const char *entity) +{ + unsigned long size = ctx->thor_file_size; + int idx, ret; + + idx = find_match(entity); + if (idx < 0) { + fprintf(stderr, "Cannot find dfu info for %s\n", entity); + return -EINVAL; + } + + ret = dfu_start_entity(ctx, idx, size); + if (ret < 0) { + fprintf(stderr, "Cannot start download: %s\n", entity); + return -EINVAL; + } + + fprintf(stdout, "Start download: %s...", entity); + + return 0; +} + +static void *dfu_thread_main(void *ptr) +{ + struct tfm_context *ctx = ptr; + struct dfu_frame *frame; + int error = 0; + uint64_t progress = 0; + int ret; + + while (!error) { + pthread_mutex_lock(&ctx->dfu_mutex); + + while (TAILQ_EMPTY(&ctx->dfu_ioq_head)) + pthread_cond_wait(&ctx->dfu_data_arrive, &ctx->dfu_mutex); + + frame = TAILQ_FIRST(&ctx->dfu_ioq_head); + + TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry); + + pthread_mutex_unlock(&ctx->dfu_mutex); + + ret = write(ctx->dfu_fd, frame->buf, frame->len); + + if (ret < frame->len) { + fprintf(stdout, "Error occurs while flashing\n"); + error = 1; + } + + progress += frame->len; + + dfu_put_buffer(frame->buf); + free(frame); + + /* transfer finished */ + if (!error && progress >= ctx->thor_file_size) { + progress = 0; + ctx->transfer_done = 1; + + pthread_cond_signal(&ctx->dfu_write_done); + + pthread_mutex_lock(&ctx->dfu_sync_mutex); + pthread_cond_wait(&ctx->dfu_sync_done, + &ctx->dfu_sync_mutex); + pthread_mutex_unlock(&ctx->dfu_sync_mutex); + } + } + + pthread_mutex_lock(&ctx->dfu_mutex); + while (TAILQ_EMPTY(&ctx->dfu_ioq_head)) { + frame = TAILQ_FIRST(&ctx->dfu_ioq_head); + + TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry); + + dfu_put_buffer(frame->buf); + free(frame); + } + pthread_mutex_unlock(&ctx->dfu_mutex); + + return NULL; +} + +static int parse_dfu_info(char *buf, char **info) +{ + char *ptr; + int i; + + for (i = 0; i < DFU_INFO_MAX; i++) { + ptr = strsep(&buf, DFU_DELIMITER); + if (!ptr) + return -EINVAL; + + info[i] = strdup(ptr); + if (!info[i]) + return -ENOMEM; + } + + return 0; +} + +static void destroy_dfu_info(void) +{ + int i, j; + + for (i = 0; i < DFU_INFO_NUM; i++) { + for (j = 0; j < DFU_INFO_MAX; j++) + if (dfu_info[i][j]) { + free(dfu_info[i][j]); + dfu_info[i][j] = NULL; + } + } +} + + +static int init_dfu_info(const char *dfu_info_file) +{ + FILE *fp; + char buf[1024]; + int i = 0; + int ret; + + fp = fopen(dfu_info_file, "r"); + if (!fp) + return -ENOENT; + + while (i < DFU_INFO_NUM && !feof(fp)) { + if (fgets(buf, 1024, fp) == NULL) + break; + + ret = parse_dfu_info(buf, dfu_info[i++]); + if (ret < 0) { + fprintf(stderr, "cannot parse dfu info"); + goto err_free_all; + } + } + + fclose(fp); + + return 0; + +err_free_all: + fclose(fp); + destroy_dfu_info(); + + return ret; +} + + +int dfu_init(struct tfm_context *ctx, const char *dfu_info_file) +{ + int ret; + + ret = init_dfu_info(dfu_info_file); + if (ret < 0) { + fprintf(stderr, "failed to get flash entries\n"); + return ret; + } + + TAILQ_INIT(&ctx->dfu_ioq_head); + + pthread_mutex_init(&ctx->dfu_mutex, NULL); + pthread_mutex_init(&ctx->dfu_sync_mutex, NULL); + pthread_cond_init(&ctx->dfu_data_arrive, NULL); + pthread_cond_init(&ctx->dfu_write_done, NULL); + pthread_cond_init(&ctx->dfu_sync_done, NULL); + + ret = pthread_create(&ctx->dfu_thread, NULL, dfu_thread_main, ctx); + if (ret < 0) { + fprintf(stderr, "failed to create thread for dfu\n"); + return ret; + } + + return 0; +} + +void dfu_exit(struct tfm_context *ctx) +{ + pthread_join(ctx->dfu_thread, NULL); + destroy_dfu_info(); + if (ctx->connect) { + free(ctx->connect); + ctx->connect = NULL; + } +} diff --git a/src/dfu.h b/src/dfu.h new file mode 100644 index 0000000..7f86a51 --- /dev/null +++ b/src/dfu.h @@ -0,0 +1,49 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DFU_H +#define __DFU_H + +#include +#include "tfm.h" + +#define DFU_DELIMITER " :,\t\n" +#define DFU_INFO_NUM 100 +#define DFU_MOUNT_PATH "/mnt/tfm-temp" + +enum dfu_info_entry { + DFU_INFO_MODE = 0, + DFU_INFO_NAME, + DFU_INFO_DEV, + DFU_INFO_PATH, + DFU_INFO_MAX, +}; + +struct dfu_frame { + void *buf; + unsigned long len; + TAILQ_ENTRY(dfu_frame) entry; +}; + +void *dfu_get_buffer(unsigned long size); +void dfu_put_buffer(void *ptr); +int dfu_init(struct tfm_context *ctx, const char *dfu_info_file); +void dfu_exit(struct tfm_context *ctx); +int dfu_start(struct tfm_context *ctx, const char *entity); +int dfu_request_io(struct tfm_context *ctx, unsigned long len); +void dfu_sync(struct tfm_context *ctx); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0b86091 --- /dev/null +++ b/src/main.c @@ -0,0 +1,113 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "dfu.h" +#include "net.h" + +int _main(int argc, char *argv[]) +{ + struct tfm_context ctx; + const char *part_table = "/usr/share/partition.info"; + int ret, opt; + + memset(&ctx, 0, sizeof(ctx)); + + while ((opt = getopt(argc, argv, "p:i:")) != -1) { + switch (opt) { + case 'i': + if (optarg) { + part_table = strdup(optarg); + } else { + fprintf(stderr, + "path should be specified with '-i'\n"); + exit(-1); + } + break; + case 'p': + { + unsigned long val; + char *endptr = NULL; + + val = strtoul(optarg, &endptr, 0); + if (*optarg == '\0' || (endptr && *endptr != '\0')) { + fprintf(stderr, + "value should be provided as a number for '-p'\n"); + exit(-1); + } + ctx.port = (int)val; + break; + } + default: + return 0; + } + } + + ret = dfu_init(&ctx, part_table); + if (ret < 0) + exit(-1); + + ret = net_connect(&ctx); + if (ret < 0) { + dfu_exit(&ctx); + exit(-1); + } + + ret = thor_init(&ctx); + if (ret < 0) { + net_disconnect(&ctx); + dfu_exit(&ctx); + exit(-1); + } + + ret = thor_process(&ctx); + if (ret < 0) { + net_disconnect(&ctx); + dfu_exit(&ctx); + exit(-1); + } + + net_disconnect(&ctx); + dfu_exit(&ctx); + exit(0); +} + +int main(int argc, char *argv[]) +{ + pid_t pid; + + for (;;) { + pid = fork(); + if (pid < 0) + exit(-1); + + if (pid == 0) + _main(argc, argv); + + wait(NULL); + + /* + * if control flow reaches here, flash might be failed. + * Thus, reset flash manager to accept other requests + */ + } + return 0; +} diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..b946fa4 --- /dev/null +++ b/src/net.c @@ -0,0 +1,102 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net.h" + +static ssize_t net_rx_data(int sock, void *buf, ssize_t len) +{ + return recv(sock, buf, len, MSG_WAITALL); +} + +static ssize_t net_tx_data(int sock, void *buf, ssize_t len) +{ + return send(sock, buf, len, 0); +} + +int net_connect(struct tfm_context *ctx) +{ + struct sockaddr_in servaddr; + struct tfm_connect *conn; + int listener, sock; + int ret = 0; + + conn = malloc(sizeof(*conn)); + if (!conn) + return -ENOMEM; + + listener = socket(AF_INET, SOCK_STREAM, 0); + if (listener < 0) { + fprintf(stderr, "Failed to create socket\n"); + ret = -EINVAL; + goto err_free; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons((ctx->port ? ctx->port : DEFAULT_PORT)); + + ret = bind(listener, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (ret < 0) { + fprintf(stderr, "Failed to bind socket\n"); + goto err_socket; + } + + ret = listen(listener, 1024); + if (ret < 0) { + fprintf(stderr, "Failed to call listen\n"); + goto err_socket; + } + + sock = accept(listener, NULL, NULL); + if (sock < 0) { + fprintf(stderr, "Failed to accept connection\n"); + ret = sock; + goto err_socket; + } + + conn->fd = sock; + conn->rx_data = net_rx_data; + conn->tx_data = net_tx_data; + ctx->connect = conn; + + close(listener); + + return 0; + +err_socket: + close(listener); +err_free: + free(conn); + return ret; +} + +void net_disconnect(struct tfm_context *ctx) +{ + close(ctx->connect->fd); + + free(ctx->connect); + ctx->connect = NULL; +} diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..dc96b4d --- /dev/null +++ b/src/net.h @@ -0,0 +1,27 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NET_H +#define __NET_H + +#include "tfm.h" + +#define DEFAULT_PORT 23456 + +int net_connect(struct tfm_context *ctx); +void net_disconnect(struct tfm_context *ctx); + +#endif diff --git a/src/tfm.h b/src/tfm.h new file mode 100644 index 0000000..747de2d --- /dev/null +++ b/src/tfm.h @@ -0,0 +1,54 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TFM_H +#define __TFM_H + +#include +#include +#include +#include + +struct tfm_connect { + int fd; + ssize_t (*rx_data)(int fd, void *buf, ssize_t len); + ssize_t (*tx_data)(int fd, void *buf, ssize_t len); +}; + +struct tfm_context { + char **dfu_info; + int dfu_fd; + pthread_t dfu_thread; + pthread_mutex_t dfu_mutex; + pthread_mutex_t dfu_sync_mutex; + pthread_cond_t dfu_data_arrive; + pthread_cond_t dfu_write_done; + pthread_cond_t dfu_sync_done; + TAILQ_HEAD(tailhead, dfu_frame) dfu_ioq_head; + + struct tfm_connect *connect; + uint64_t thor_file_size; + uint64_t remain; + void *transfer_buffer; + int transfer_done; + + int port; +}; + +int thor_init(struct tfm_context *ctx); +int thor_process(struct tfm_context *ctx); + +#endif diff --git a/src/thor-proto.h b/src/thor-proto.h new file mode 100644 index 0000000..f384b46 --- /dev/null +++ b/src/thor-proto.h @@ -0,0 +1,99 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __THOR_PROTO_H__ +#define __THOR_PROTO_H__ + +typedef enum { + RQT_INFO = 200, + RQT_CMD, + RQT_DL, + RQT_UL, +} request_type; + +/* Request Data */ +/* RQT_INFO */ +enum { + RQT_INFO_VER_PROTOCOL = 1, + RQT_INFO_VER_HW, + RQT_INFO_VER_BOOT, + RQT_INFO_VER_KERNEL, + RQT_INFO_VER_PLATFORM, + RQT_INFO_VER_CSC, +}; + +/* RQT_CMD */ +enum { + RQT_CMD_REBOOT = 1, + RQT_CMD_POWEROFF, +}; + +/* RQT_DL */ +enum { + RQT_DL_INIT = 1, + RQT_DL_FILE_INFO, + RQT_DL_FILE_START, + RQT_DL_FILE_END, + RQT_DL_EXIT, +}; + +/* RQT_UL */ +enum { + RQT_UL_INIT = 1, + RQT_UL_START, + RQT_UL_END, + RQT_UL_EXIT, +}; + +enum __binary_type { + BINARY_TYPE_NORMAL = 0, + BINARY_TYPE_PIT, +}; + +struct rqt_pkt { + int32_t id; /* Request Group ID. */ + int32_t sub_id; /* Request Data ID. */ + int32_t int_data[14]; /* Int. Datas. */ + char str_data[5][32]; /* Str. Data. */ + char md5[32]; /* MD5 Checksum. */ +} __attribute__((__packed__)); + +struct res_pkt { + int32_t id; /* Response Group ID == Request Group ID. */ + int32_t sub_id; /* Response Data ID == Request Data ID. */ + int32_t ack; /* Ack. */ + int32_t int_data[5]; /* Int. Datas. */ + char str_data[3][32]; /* Str. Data. */ +} __attribute__((__packed__)); + +struct data_res_pkt { + int32_t ack; /* Ack. */ + int32_t cnt; /* Int. Datas. */ +} __attribute__((__packed__)); + +#define VER_PROTOCOL_MAJOR 4 +#define VER_PROTOCOL_MINOR 0 + +#define RQT_PKT_SIZE sizeof(struct rqt_pkt) +#define RES_PKT_SIZE sizeof(struct res_pkt) +#define DATA_RES_PKT_SIZE sizeof(struct data_res_pkt) + +#define FILE_NAME_MAXLEN 32 +#define DATA_PKT_SIZE 0x00100000 /* 1 MiB */ +#define FLASH_UNIT_SIZE 0x02000000 /* 32 MiB */ + + +#endif /* __THOR_PROTO_H__ */ diff --git a/src/thor.c b/src/thor.c new file mode 100644 index 0000000..f12dfc3 --- /dev/null +++ b/src/thor.c @@ -0,0 +1,343 @@ +/* + * flash-manager - Tizen kernel-level image flashing solution + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dfu.h" +#include "thor-proto.h" + +static inline ssize_t thor_rx_data(struct tfm_connect *conn, void *buf, ssize_t len) +{ + return conn->rx_data(conn->fd, buf, len); +} + +static inline ssize_t thor_tx_data(struct tfm_connect *conn, void *buf, ssize_t len) +{ + return conn->tx_data(conn->fd, buf, len); +} + +static unsigned int _checkboard(void) +{ + /* + * TODO: + * Add support to get proper device name + */ + return -1; +} + +static int thor_send_rsp(struct tfm_connect *conn, const struct res_pkt *rsp) +{ + ssize_t n; + + n = thor_tx_data(conn, (void *)rsp, RES_PKT_SIZE); + if (n < sizeof(*rsp)) + return -EIO; + + return 0; +} + +static int thor_process_rqt_info(struct tfm_context *ctx, struct rqt_pkt *rqt) +{ + struct res_pkt rsp; + int ret; + + memset(&rsp, 0, RES_PKT_SIZE); + + rsp.id = rqt->id; + rsp.sub_id = rqt->sub_id; + + switch (rqt->sub_id) { + case RQT_INFO_VER_PROTOCOL: + rsp.int_data[0] = VER_PROTOCOL_MAJOR; + rsp.int_data[1] = VER_PROTOCOL_MINOR; + break; + case RQT_INFO_VER_HW: + snprintf(rsp.str_data[0], sizeof(rsp.str_data[0]), "%x", _checkboard()); + break; + case RQT_INFO_VER_BOOT: + case RQT_INFO_VER_KERNEL: + case RQT_INFO_VER_PLATFORM: + case RQT_INFO_VER_CSC: + strncpy(rsp.str_data[0], "Unknown", sizeof("Unknown")); + break; + default: + fprintf(stderr, "Not supported information request: %d\n", + rqt->sub_id); + return -EINVAL; + } + + ret = thor_send_rsp(ctx->connect, &rsp); + if (ret < 0) { + fprintf(stderr, "failed to send response of REQUEST_INFO\n"); + return ret; + } + + return 0; +} + +static int thor_process_rqt_cmd(struct tfm_context *ctx, struct rqt_pkt *rqt) +{ + struct tfm_connect *conn = ctx->connect; + struct res_pkt rsp; + int ret; + + memset(&rsp, 0, RES_PKT_SIZE); + + rsp.id = rqt->id; + rsp.sub_id = rqt->sub_id; + + switch (rqt->sub_id) { + case RQT_CMD_REBOOT: + thor_send_rsp(conn, &rsp); + + ret = reboot(RB_AUTOBOOT); + if (ret < 0) { + fprintf(stderr, "Failed to system reboot\n"); + return -EINVAL; + } + break; + case RQT_CMD_POWEROFF: + thor_send_rsp(conn, &rsp); + break; + default: + fprintf(stderr, "Not supported command request: %d", + rqt->sub_id); + return -EINVAL; + } + + return 0; +} + +static void thor_send_data_rsp(struct tfm_connect *conn, int ack, int count) +{ + struct data_res_pkt rsp; + + rsp.ack = ack; + rsp.cnt = count; + + thor_tx_data(conn, &rsp, DATA_RES_PKT_SIZE); +} + +static int thor_download_head(struct tfm_context *ctx, unsigned int packet_size) +{ + struct tfm_connect *conn = ctx->connect; + uint64_t recv = 0; + uint64_t total = ctx->thor_file_size; + void *buf; + int usb_pkt_cnt = 0, n; + int ret; + + ctx->transfer_buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); + + while (total - recv >= packet_size) { + n = thor_rx_data(conn, buf, packet_size); + + if (n < packet_size) + return -EIO; + + recv += n; + buf += packet_size; + + if ((recv % FLASH_UNIT_SIZE) == 0) { + ret = dfu_request_io(ctx, FLASH_UNIT_SIZE); + if (ret < 0) + return -EIO; + + ctx->transfer_buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); + } + thor_send_data_rsp(conn, 0, ++usb_pkt_cnt); + } + + ctx->remain = (total - recv) + buf - ctx->transfer_buffer; + + if ((total - recv) > 0) { + n = thor_rx_data(conn, buf, packet_size); + if (n < packet_size) + return -EIO; + recv += n; + thor_send_data_rsp(conn, 0, ++usb_pkt_cnt); + } + + return 0; +} + +static int thor_download_tail(struct tfm_context *ctx) +{ + int ret; + + if (ctx->remain) { + ret = dfu_request_io(ctx, ctx->remain); + if (ret < 0) + return -EIO; + } else { + /* if there is no remain, buffer should be freed */ + dfu_put_buffer(ctx->transfer_buffer); + } + + dfu_sync(ctx); + + return 0; +} + +static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rqt) +{ + struct tfm_connect *conn = ctx->connect; + char f_name[FILE_NAME_MAXLEN + 1] = {0,}; + struct res_pkt rsp; + int ret = 0, head, file_type; + + memset(&rsp, 0, RES_PKT_SIZE); + + rsp.id = rqt->id; + rsp.sub_id = rqt->sub_id; + + switch (rqt->sub_id) { + case RQT_DL_INIT: + ctx->thor_file_size = (unsigned long)rqt->int_data[0]; + break; + case RQT_DL_FILE_INFO: + file_type = rqt->int_data[0]; + if (file_type != BINARY_TYPE_NORMAL) { + fprintf(stderr, "Currently only NORMAL_FILE is supported\n"); + ret = rsp.ack = -EINVAL; + break; + } + + ctx->thor_file_size = (unsigned long)rqt->int_data[1]; + memcpy(f_name, rqt->str_data[0], FILE_NAME_MAXLEN); + + rsp.int_data[0] = DATA_PKT_SIZE; + + ret = dfu_start(ctx, f_name); + if (ret < 0) { + fprintf(stderr, "failed to start dfu\n"); + ret = -EINVAL; + } + break; + case RQT_DL_FILE_START: + ret = thor_send_rsp(conn, &rsp); + if (ret < 0) { + fprintf(stderr, "failed to send response\n"); + ret = rsp.ack = -EINVAL; + break; + } + head = thor_download_head(ctx, DATA_PKT_SIZE); + if (head < 0) + ctx->remain = 0; + + return head; + case RQT_DL_FILE_END: + rsp.ack = thor_download_tail(ctx); + ret = rsp.ack; + ctx->remain = 0; + break; + case RQT_DL_EXIT: + break; + default: + fprintf(stderr, "Invalid download request: %d\n", + rqt->sub_id); + ret = -EINVAL; + } + + thor_send_rsp(conn, &rsp); + return ret; +} + +static int thor_do_request(struct tfm_context *ctx, struct rqt_pkt *rqt) +{ + int ret; + + switch (rqt->id) { + case RQT_INFO: + ret = thor_process_rqt_info(ctx, rqt); + break; + case RQT_CMD: + ret = thor_process_rqt_cmd(ctx, rqt); + break; + case RQT_DL: + ret = thor_process_rqt_download(ctx, rqt); + break; + case RQT_UL: + fprintf(stderr, "Request \"UPLOAD\" is not supported\n"); + ret = -EINVAL; + break; + default: + fprintf(stderr, "Invalid request in rqt: %d\n", rqt->id); + ret = -EINVAL; + } + + return ret; +} + +static int thor_handshake(struct tfm_connect *conn) +{ + char buf[5]; + ssize_t n; + + n = thor_rx_data(conn, buf, 4/* strlen("THOR") */); + if (n < 4) + return -EIO; + + if (!strncmp(buf, "THOR", 4)) { + n = thor_tx_data(conn, "ROHT", 4); + if (n < 4) + return -EIO; + } else { + fprintf(stderr, "Invalid request from the host\n"); + return -EINVAL; + } + + return 0; +} + +int thor_init(struct tfm_context *ctx) +{ + return thor_handshake(ctx->connect); +} + +int thor_process(struct tfm_context *ctx) +{ + struct tfm_connect *conn = ctx->connect; + struct rqt_pkt rqt; + ssize_t n; + int ret; + + for (;;) { + n = thor_rx_data(conn, &rqt, RQT_PKT_SIZE); + if (n < sizeof(rqt)) { + fprintf(stderr, + "Failed to receive data from the host(%ld:%ld)", + n, RQT_PKT_SIZE); + return -EIO; + } + + ret = thor_do_request(ctx, &rqt); + if (ret < 0) + return ret; + } + + return 0; +} -- 2.7.4 From 7e526f7d90b1c8dd516ae188f4b2610a38d1bc59 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Mon, 16 Apr 2018 11:24:01 +0900 Subject: [PATCH 04/11] Add script for enabling flash-manager for ramdisk-recovery image This patch adds scripts for creating ramdisk partition image. The script will be executed while MIC builds ramdisk image as copying list of required files for building ramdisk-recovery image. Change-Id: I63ac7dcde55df26217de46f9bfab63dd1faebb7f Signed-off-by: Dongwoo Lee --- packaging/initrd-flash.spec | 10 ++++++++++ scripts/41-flash.list | 27 ++++++++++++++++++++++++++ scripts/flash-init.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100755 scripts/41-flash.list create mode 100755 scripts/flash-init.sh diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index 7e90fe3..8d2a24b 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -29,6 +29,14 @@ make %{?jobs:-j%jobs} %make_install +%define init_script_dir %{_libdir}/initrd-recovery/flash + +mkdir -p %{buildroot}%{init_script_dir} +cp ./scripts/flash-init.sh %{buildroot}%{init_script_dir}/flash-init.sh + +mkdir -p %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d +cp ./scripts/41-flash.list %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d + %post %postun @@ -37,3 +45,5 @@ make %{?jobs:-j%jobs} %manifest initrd-flash.manifest %license LICENSE %attr(700,root,root) %{_bindir}/flash-manager +%attr(700,root,root) %{init_script_dir}/*.sh +%attr(700,root,root) %{_datadir}/initrd-recovery/initrd.list.d/*.list diff --git a/scripts/41-flash.list b/scripts/41-flash.list new file mode 100755 index 0000000..4f91ada --- /dev/null +++ b/scripts/41-flash.list @@ -0,0 +1,27 @@ +# ---- Target contents ----------------------------------------------------- # +MVWITHLIBS=" +/usr/lib/initrd-recovery/flash/flash-init.sh +" + +WITHLIBS=" +/bin/bash +/bin/echo +/bin/mkdir +/bin/mount +/bin/sync +/bin/umount +/bin/flash-manager +/usr/sbin/ifconfig +/usr/sbin/route +/usb/sbin/blkid +" + +# LinkFileName:Target +SYMLINKS=" +/bin/sh:bash +/sbin/flash-init:/usr/lib/initrd-recovery/flash/flash-init.sh +" + +VERBATIMS=" +/usr/share/partition.info +" diff --git a/scripts/flash-init.sh b/scripts/flash-init.sh new file mode 100755 index 0000000..1b9a241 --- /dev/null +++ b/scripts/flash-init.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +INFORM_FILE=reboot-param.bin +INFORM_MOUNT_PATH=/mnt/inform + +BLKID="/usr/sbin/blkid" +FLASH_MANAGER="/usr/bin/flash-manager" +MOUNT="/usr/bin/mount" +UMOUNT="/usr/bin/umount" +IFCONFIG="/usr/sbin/ifconfig" +REBOOT="/usr/sbin/reboot" + +#------------------------------------------------ +# clear_bootmode +#------------------------------------------------ +clear_bootmode() { + echo "" > ${INFORM_MOUNT_PATH}/${INFORM_FILE} +} + +#------------------------------------------------ +# setup_network +#------------------------------------------------ +setup_network() { + "$IFCONFIG" eth0 192.168.0.1 up + echo "IP address is set to 192.168.0.1" +} + +#------------------------------------------------ +# do_flash +#------------------------------------------------ +do_flash() { + "$FLASH_MANAGER" + + #Control-flow will never reach here, because fm only terminates by rebooting + + echo "flash-manager is terminated by critical reason." + echo "Rebooting..." + "$REBOOT" +} + +#------------------------------------------------ +# Main Routine Start +#------------------------------------------------ +clear_bootmode +setup_network +do_flash -- 2.7.4 From f339cc9c3922b853b0da987fc64bf216d4dea26b Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 15 May 2018 11:14:45 +0900 Subject: [PATCH 05/11] Add pre-defined partition information for RPI3 The partition information about RPI3 will be added. This inforamation is retrieved from sd_fusing script in RPI3 kernel repository. Change-Id: Iac335daf5c285264c8d73a21c616035373028a5b Signed-off-by: Dongwoo Lee --- packaging/initrd-flash.spec | 14 ++++++++++++++ partition.info | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 partition.info diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index 8d2a24b..79f61f1 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -11,11 +11,20 @@ BuildRequires: cmake Requires: util-linux Requires: bash Requires: initrd-recovery +Requires: fm-data %description Provide kernel-based target image downloader. This package would be included in partition image for RAMDISK2 (ramdisk-recovery.img) +%package -n fm-data-rpi3 +Summary: RaspberryPi3 specific data for flash manager +Group: System/Utilities +Provides: fm-data + +%description -n fm-data-rpi3 +Provide flash-manager with partition table for flashing image and files of Raspberry Pi 3 board + %prep %setup -q @@ -37,6 +46,8 @@ cp ./scripts/flash-init.sh %{buildroot}%{init_script_dir}/flash-init.sh mkdir -p %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d cp ./scripts/41-flash.list %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d +cp ./partition.info %{buildroot}%{_datadir}/partition.info + %post %postun @@ -47,3 +58,6 @@ cp ./scripts/41-flash.list %{buildroot}%{_datadir}/initrd-recovery/initrd.list.d %attr(700,root,root) %{_bindir}/flash-manager %attr(700,root,root) %{init_script_dir}/*.sh %attr(700,root,root) %{_datadir}/initrd-recovery/initrd.list.d/*.list + +%files -n fm-data-rpi3 +%attr(700,root,root) %{_datadir}/partition.info diff --git a/partition.info b/partition.info new file mode 100644 index 0000000..e97c177 --- /dev/null +++ b/partition.info @@ -0,0 +1,8 @@ +p:boot.img:/dev/mmcblk0p1:x +p:rootfs.img:/dev/mmcblk0p2:x +p:system-data.img:/dev/mmcblk0p3:x +p:user.img:/dev/mmcblk0p5:x +p:modules.img:/dev/mmcblk0p6:x +p:ramdisk.img:/dev/mmcblk0p7:x +p:ramdisk-recovery.img:/dev/mmcblk0p8:x +f:Image:/dev/mmcblk0p1:/ -- 2.7.4 From efb1c1c3fe4348a4acfd6f568f9c49668950f143 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 25 May 2018 09:15:30 +0900 Subject: [PATCH 06/11] Recognize partition device name by blkid label In certain case, target board can have different device name for storage. So, static device name cannot be applicable for all cases. This patch gets device name from blkid information within target storage instead of static information in partition table. Change-Id: I171fa8d5da79ea815b1acdef438908849a37861b Signed-off-by: Dongwoo Lee --- CMakeLists.txt | 2 +- packaging/initrd-flash.spec | 1 + partition.info | 16 +++--- src/dfu.c | 125 ++++++++++++++++++++++++++++++++++++++++++-- src/dfu.h | 2 +- 5 files changed, 131 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8688aa1..05e7c74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/net.c) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src) IF(CMAKE_THREAD_LIBS_INIT) - TARGET_LINK_LIBRARIES(flash-manager "${CMAKE_THREAD_LIBS_INIT}") + TARGET_LINK_LIBRARIES(flash-manager "${CMAKE_THREAD_LIBS_INIT}" blkid) ENDIF() ADD_DEFINITIONS(-Wall -g -O2) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index 79f61f1..d36b5ce 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -7,6 +7,7 @@ License: Apache-2.0 Source0: %{name}-%{version}.tar.gz ExclusiveArch: %{arm} BuildRequires: cmake +BuildRequires: libblkid-devel Requires: util-linux Requires: bash diff --git a/partition.info b/partition.info index e97c177..833f9c2 100644 --- a/partition.info +++ b/partition.info @@ -1,8 +1,8 @@ -p:boot.img:/dev/mmcblk0p1:x -p:rootfs.img:/dev/mmcblk0p2:x -p:system-data.img:/dev/mmcblk0p3:x -p:user.img:/dev/mmcblk0p5:x -p:modules.img:/dev/mmcblk0p6:x -p:ramdisk.img:/dev/mmcblk0p7:x -p:ramdisk-recovery.img:/dev/mmcblk0p8:x -f:Image:/dev/mmcblk0p1:/ +p:BOOT:boot.img:x +p:rootfs:rootfs.img:x +p:system-data:system-data.img:x +p:user:user.img:x +p:modules:modules.img:x +p:ramdisk:ramdisk.img:x +p:ramdisk-recovery:ramdisk-recovery.img:x +f:BOOT:Image:/ diff --git a/src/dfu.c b/src/dfu.c index 77e47a7..9beaf95 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "dfu.h" #include "thor-proto.h" @@ -96,13 +97,13 @@ int dfu_request_io(struct tfm_context *ctx, unsigned long len) return 0; } -static void mount_dev(const char *dev) +static void mount_dev(const char *dev, const char *fstype) { int ret; mkdir(DFU_MOUNT_PATH, 0600); - ret = mount(dev, DFU_MOUNT_PATH, "ext4", 0, NULL); + ret = mount(dev, DFU_MOUNT_PATH, fstype, 0, NULL); if (ret < 0) { fprintf(stderr, "Failed to mount target partition\n"); rmdir(DFU_MOUNT_PATH); @@ -153,6 +154,85 @@ void dfu_sync(struct tfm_context *ctx) fprintf(stdout, "finished\n"); } +static char *get_partition_devname(const char *label) +{ + blkid_dev_iterate dev_iter; + blkid_tag_iterate tag_iter; + blkid_dev dev; + blkid_cache cache = NULL; + const char *type, *value; + int ret; + + ret = blkid_get_cache(&cache, NULL); + if (ret < 0) + return NULL; + + blkid_probe_all(cache); + + dev_iter = blkid_dev_iterate_begin(cache); + blkid_dev_set_search(dev_iter, NULL, NULL); + while (blkid_dev_next(dev_iter, &dev) == 0) { + dev = blkid_verify(cache, dev); + if (!dev) + continue; + + tag_iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(tag_iter, &type, &value) == 0) { + if (!strncmp(type, "LABEL", 5) && !strncmp(value, label, strlen(label))) { + char *devname = strdup(blkid_dev_devname(dev)); + + blkid_tag_iterate_end(tag_iter); + blkid_dev_iterate_end(dev_iter); + blkid_put_cache(cache); + return devname; + } + } + blkid_tag_iterate_end(tag_iter); + } + blkid_dev_iterate_end(dev_iter); + blkid_put_cache(cache); + + return NULL; +} + +static char *get_partition_fstype(const char *devname) +{ + blkid_tag_iterate tag_iter; + blkid_dev dev; + blkid_cache cache = NULL; + const char *type, *value; + int ret; + + ret = blkid_get_cache(&cache, NULL); + if (ret < 0) + return NULL; + + blkid_probe_all(cache); + + dev = blkid_get_dev(cache, devname, 0); + if (!dev) + return NULL; + + dev = blkid_verify(cache, dev); + if (!dev) + return NULL; + + tag_iter = blkid_tag_iterate_begin(dev); + while (blkid_tag_next(tag_iter, &type, &value) == 0) { + if (!strncmp(type, "TYPE", 4)) { + char *fstype = strdup(value); + + blkid_tag_iterate_end(tag_iter); + blkid_put_cache(cache); + return fstype; + } + } + blkid_tag_iterate_end(tag_iter); + blkid_put_cache(cache); + + return NULL; +} + static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size) { char **info = dfu_info[idx]; @@ -161,12 +241,44 @@ static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size switch (*info[DFU_INFO_MODE]) { case 'p': - file = info[DFU_INFO_DEV]; + file = get_partition_devname(info[DFU_INFO_LABEL]); + if (!file) { + fprintf(stderr, "failed to get partition devname: %s", info[DFU_INFO_LABEL]); + return -EINVAL; + } break; case 'f': - mount_dev(info[DFU_INFO_DEV]); - file = info[DFU_INFO_PATH]; + { + int path_prefix = strlen(DFU_MOUNT_PATH); + int path_suffix = strlen(info[DFU_INFO_PATH]); + int path_name = strlen(info[DFU_INFO_NAME]); + char *devname, *fstype; + + devname = get_partition_devname(info[DFU_INFO_LABEL]); + if (!devname) { + fprintf(stderr, "failed to get partition devname: %s", info[DFU_INFO_LABEL]); + return -EINVAL; + } + + fstype = get_partition_fstype(devname); + if (!fstype) { + fprintf(stderr, "failed to get partition filesystem type: %s", devname); + return -EINVAL; + } + + mount_dev(devname, fstype); + free(devname); + free(fstype); + + file = malloc(path_prefix + path_suffix + path_name + 1); + if (!file) + return -ENOMEM; + + strncpy(file, DFU_MOUNT_PATH, path_prefix + 1); + strncat(file, info[DFU_INFO_PATH], path_suffix); + strncat(file, info[DFU_INFO_NAME], path_name); break; + } default: fprintf(stderr, "flash entry '%s' has wrong mode\n", info[DFU_INFO_NAME]); return -EINVAL; @@ -175,6 +287,7 @@ static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size fd = open(file, O_WRONLY); if (fd < 0) { fprintf(stderr, "cannot open target: %s\n", info[DFU_INFO_NAME]); + free(file); return -EIO; } @@ -183,6 +296,8 @@ static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size ctx->dfu_info = info; ctx->transfer_done = 0; + free(file); + return 0; } diff --git a/src/dfu.h b/src/dfu.h index 7f86a51..4138acf 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -26,8 +26,8 @@ enum dfu_info_entry { DFU_INFO_MODE = 0, + DFU_INFO_LABEL, DFU_INFO_NAME, - DFU_INFO_DEV, DFU_INFO_PATH, DFU_INFO_MAX, }; -- 2.7.4 From 1b8fc257186ccecf88b0969110dca69ad75872cf Mon Sep 17 00:00:00 2001 From: Dongwoo Date: Thu, 4 Oct 2018 17:40:07 +0900 Subject: [PATCH 07/11] Fix wrong check of empty queue This patch resolves svace warnings "DEREF_OF_NULL", which means that can have only NULL value. Even it is false positive, the condition is also wrong because it should continue iteration if queue is not empty. Change-Id: I445463c9ef4522e3e58923fbcbda01d0ce606dcc Signed-off-by: Dongwoo --- src/dfu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dfu.c b/src/dfu.c index 9beaf95..f174a7e 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -371,7 +371,7 @@ static void *dfu_thread_main(void *ptr) } pthread_mutex_lock(&ctx->dfu_mutex); - while (TAILQ_EMPTY(&ctx->dfu_ioq_head)) { + while (!TAILQ_EMPTY(&ctx->dfu_ioq_head)) { frame = TAILQ_FIRST(&ctx->dfu_ioq_head); TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry); -- 2.7.4 From e6bbad7704180e548a2d61abf3b5a3d7a6907436 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 4 Oct 2018 15:22:50 +0900 Subject: [PATCH 08/11] Fix build warnings with -Wformat There are build warnings with -Wformat for printing format for size_t and ssize_t. Fix the build warnings with profer formats. Change-Id: I82f50c8541b9bc4ffba36f01b0c84eb89e04c12b Signed-off-by: Seung-Woo Kim --- src/thor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thor.c b/src/thor.c index f12dfc3..5757d56 100644 --- a/src/thor.c +++ b/src/thor.c @@ -329,7 +329,7 @@ int thor_process(struct tfm_context *ctx) n = thor_rx_data(conn, &rqt, RQT_PKT_SIZE); if (n < sizeof(rqt)) { fprintf(stderr, - "Failed to receive data from the host(%ld:%ld)", + "Failed to receive data from the host(%zd:%zu)", n, RQT_PKT_SIZE); return -EIO; } -- 2.7.4 From 3018b9a1a0f18b3f3279b4e9aeab540aca37ba39 Mon Sep 17 00:00:00 2001 From: Dongwoo Date: Thu, 4 Oct 2018 10:22:47 +0900 Subject: [PATCH 09/11] Fix to convert variable type explicitly This patch resolves svace warnings "SIGNED_TO_BIGGER_UNSIGNED", which means assignment of a signed value which has type int(void*) to a variable of a bigger integer type uint64_t. Change-Id: Icb9576641a41f695272d61fd1f0847884b865935 Signed-off-by: Dongwoo --- src/thor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thor.c b/src/thor.c index 5757d56..1d131cf 100644 --- a/src/thor.c +++ b/src/thor.c @@ -171,7 +171,7 @@ static int thor_download_head(struct tfm_context *ctx, unsigned int packet_size) thor_send_data_rsp(conn, 0, ++usb_pkt_cnt); } - ctx->remain = (total - recv) + buf - ctx->transfer_buffer; + ctx->remain = (total - recv) + (uint64_t)(buf - ctx->transfer_buffer); if ((total - recv) > 0) { n = thor_rx_data(conn, buf, packet_size); -- 2.7.4 From f7fa2aeac2c16fdb8ee294a468c4a287fb5ab7a4 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 5 Oct 2018 18:16:29 +0900 Subject: [PATCH 10/11] Check whether creating temporary directory is success or not There is no checking created temporary directory. Check whether creating is success of not. Change-Id: I499d34487659f8d3b83b706c98d8fa8d8e5f3251 Signed-off-by: Seung-Woo Kim --- src/dfu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dfu.c b/src/dfu.c index f174a7e..a0a3bed 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -101,7 +101,11 @@ static void mount_dev(const char *dev, const char *fstype) { int ret; - mkdir(DFU_MOUNT_PATH, 0600); + ret = mkdir(DFU_MOUNT_PATH, 0600); + if (ret < 0) { + fprintf(stderr, "Failed to create target directory\n"); + exit(-1); + } ret = mount(dev, DFU_MOUNT_PATH, fstype, 0, NULL); if (ret < 0) { -- 2.7.4 From eecd2ff8f76e67231723ce48b21ee8826e5868a2 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 5 Oct 2018 18:46:41 +0900 Subject: [PATCH 11/11] Fix error path of main thread with freeing allocated buffer There can be memory leak for strdup(). Fix error path of main thread with freeing allocated buffer. Change-Id: I292d66d8b9f5c857a692f35a9867d221dabb6a7d Signed-off-by: Seung-Woo Kim --- src/main.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/main.c b/src/main.c index 0b86091..194e2c8 100644 --- a/src/main.c +++ b/src/main.c @@ -27,6 +27,7 @@ int _main(int argc, char *argv[]) { struct tfm_context ctx; const char *part_table = "/usr/share/partition.info"; + char *opt_table = NULL; int ret, opt; memset(&ctx, 0, sizeof(ctx)); @@ -35,11 +36,15 @@ int _main(int argc, char *argv[]) switch (opt) { case 'i': if (optarg) { - part_table = strdup(optarg); + if (opt_table) + free(opt_table); + opt_table = strdup(optarg); + part_table = opt_table; } else { fprintf(stderr, "path should be specified with '-i'\n"); - exit(-1); + ret = -1; + goto out; } break; case 'p': @@ -51,43 +56,54 @@ int _main(int argc, char *argv[]) if (*optarg == '\0' || (endptr && *endptr != '\0')) { fprintf(stderr, "value should be provided as a number for '-p'\n"); - exit(-1); + ret = -1; + goto out_optfree; } ctx.port = (int)val; break; } default: - return 0; + ret = -1; + goto out_optfree; } } ret = dfu_init(&ctx, part_table); - if (ret < 0) - exit(-1); + if (ret < 0) { + ret = -1; + goto out_optfree; + } ret = net_connect(&ctx); if (ret < 0) { - dfu_exit(&ctx); - exit(-1); + ret = -1; + goto out_dfuexit; } ret = thor_init(&ctx); if (ret < 0) { - net_disconnect(&ctx); - dfu_exit(&ctx); - exit(-1); + ret = -1; + goto out_netdisconn; } ret = thor_process(&ctx); if (ret < 0) { - net_disconnect(&ctx); - dfu_exit(&ctx); - exit(-1); + ret = -1; + goto out_netdisconn; } +out_netdisconn: net_disconnect(&ctx); + +out_dfuexit: dfu_exit(&ctx); - exit(0); + +out_optfree: + if (opt_table) + free(opt_table); + +out: + exit(ret); } int main(int argc, char *argv[]) -- 2.7.4