From 3a3364d4c43fcf81180d239f29c0311895473771 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 26 Mar 2020 14:30:05 +0900 Subject: [PATCH 01/16] scripts: Fix to copy all firmware files Since this copying all firmware files instead of adding the individual files when making ramdisk-recovery.img. Change-Id: I7c64d861bcea5d2546b92b0ee076c266679962db Signed-off-by: Dongwoo Lee --- scripts/41-flash.list | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/41-flash.list b/scripts/41-flash.list index 834fe76..3ec0e8b 100755 --- a/scripts/41-flash.list +++ b/scripts/41-flash.list @@ -2,13 +2,7 @@ MVWITHLIBS=" /usr/lib/initrd-recovery/flash/flash-init.sh /bin/flash-manager -/usr/share/firmware/brcm/brcmfmac43430-sdio.bin -/usr/share/firmware/brcm/brcmfmac43455-sdio.bin -/usr/share/firmware/brcm/brcmfmac43430-sdio.txt -/usr/share/firmware/brcm/brcmfmac43455-sdio.txt -/usr/share/firmware/brcm/LICENCE.broadcom_bcm43xx -/usr/share/firmware/brcm/hostapd.conf -/usr/share/firmware/brcm/dnsmasq.conf +/usr/share/firmware/brcm/* " WITHLIBS=" -- 2.7.4 From 217911ef01411704b2b13995dce8a3a7cdae3be0 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 1 Apr 2020 09:22:23 +0900 Subject: [PATCH 02/16] thor: Move context members to structure dfu_entry This removes unnecessary members in thor context and move them into dfu_entry structure. The code is just cleaned up and the change has no effect on functionalites. Change-Id: I297132be52b7e5e1b75b410297e98cf63870c503 Signed-off-by: Dongwoo Lee --- src/dfu.c | 49 +++++++++++++++++++++++++++++++++-------- src/dfu.h | 11 ++++++---- src/thor.c | 74 ++++++++++++++++++++++++++++++++++---------------------------- 3 files changed, 88 insertions(+), 46 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index c33c286..166185c 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -70,10 +70,12 @@ struct dfu_context { TAILQ_HEAD(tailhead, dfu_frame) ioq; int ioq_len; + uint64_t total_size; + char *dfu_entry_list[DFU_ENTRY_LIST_MAXLEN][DFU_INFO_MAX]; }; -void *dfu_get_buffer(unsigned long size) +void *dfu_get_buffer(struct dfu_entry *e, unsigned long size) { int wait = 100000; /* 100ms */ void *buf; @@ -87,12 +89,22 @@ void *dfu_get_buffer(unsigned long size) wait *= 2; } + e->buffer = buf; + e->buf_len = size; + return buf; } -void dfu_put_buffer(void *ptr) +void dfu_put_buffer(struct dfu_entry *e) { - free(ptr); + if (!e || !e->buffer) { + fprintf(stderr, "Invalid free request\n"); + return; + } + + free(e->buffer); + e->buffer = NULL; + e->buf_len = 0; } static char **find_entry_match(struct dfu_context *ctx, const char *name) @@ -109,18 +121,22 @@ static char **find_entry_match(struct dfu_context *ctx, const char *name) return NULL; } -int dfu_request_io(struct dfu_entry *e, void *buffer, unsigned long len) +int dfu_request_io(struct dfu_entry *e) { - struct dfu_context *ctx = e->ctx; + struct dfu_context *ctx; struct dfu_frame *frame; int notify = 0; + if (!e || !e->buffer || e->buf_len == 0) + return -EINVAL; + frame = malloc(sizeof(*frame)); if (!frame) return -ENOMEM; - frame->buf = buffer; - frame->len = len; + frame->buf = e->buffer; + frame->len = e->buf_len; + ctx = e->ctx; retry: pthread_mutex_lock(&ctx->mutex); @@ -141,6 +157,10 @@ retry: if (notify) pthread_cond_signal(&ctx->data_arrived); + /* buffer will be freed by dfu_thread_main() after write is finished */ + e->buffer = NULL; + e->buf_len = 0; + return 0; } @@ -237,7 +257,7 @@ static void dfu_thread_cleanup(void *ptr) TAILQ_REMOVE(&ctx->ioq, frame, entry); - dfu_put_buffer(frame->buf); + free(frame->buf); free(frame); } @@ -290,7 +310,7 @@ static void *dfu_thread_main(void *ptr) fprintf(stdout, "#"); fflush(stdout); - dfu_put_buffer(frame->buf); + free(frame->buf); free(frame); /* transfer finished */ @@ -367,6 +387,8 @@ static int dfu_start_entry(struct dfu_entry *e, char **entry, uint64_t size) e->entry = entry; e->fd = fd; e->file_size = size; + e->buffer = NULL; + e->buf_len = 0; e->transfer_done = 0; err: @@ -375,6 +397,14 @@ err: return ret; } +void dfu_init_download(struct dfu_context *ctx, uint64_t size) +{ + ctx->total_size = size; + + fprintf(stdout, "Start Download (Total: %.2lfMB)\n", + (double)size / (1024.0f * 1024.0f)); +} + struct dfu_entry *dfu_start(struct dfu_context *ctx, uint64_t size, const char *filename) { @@ -504,6 +534,7 @@ struct dfu_context *dfu_alloc_context(void) ctx->thread = 0; TAILQ_INIT(&ctx->ioq); ctx->ioq_len = 0; + ctx->total_size = 0; pthread_mutex_init(&ctx->mutex, NULL); pthread_mutex_init(&ctx->sync_mutex, NULL); diff --git a/src/dfu.h b/src/dfu.h index 0d35883..adceb71 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -26,19 +26,22 @@ struct dfu_entry { struct dfu_context *ctx; char **entry; int fd; - uint64_t file_size; + uint64_t file_size; /* size of a flashing file */ + void *buffer; /* receive buffer for flashing */ + unsigned long buf_len; /* filled size of buffer */ int transfer_done; }; -void *dfu_get_buffer(unsigned long size); -void dfu_put_buffer(void *ptr); +void *dfu_get_buffer(struct dfu_entry *e, unsigned long size); +void dfu_put_buffer(struct dfu_entry *e); struct dfu_context *dfu_alloc_context(void); void dfu_free_context(struct dfu_context *ctx); int dfu_init_entry(struct dfu_context *ctx, const char *entry_file); +void dfu_init_download(struct dfu_context *ctx, uint64_t size); struct dfu_entry *dfu_start(struct dfu_context *ctx, uint64_t size, const char *filename); void dfu_sync(struct dfu_entry *e); -int dfu_request_io(struct dfu_entry *e, void *buffer, unsigned long len); +int dfu_request_io(struct dfu_entry *e); #endif diff --git a/src/thor.c b/src/thor.c index ea8918e..967b4dd 100644 --- a/src/thor.c +++ b/src/thor.c @@ -35,10 +35,6 @@ struct thor_context { struct tfm_interface *intf; struct dfu_context *dfu; struct dfu_entry *dfu_entry; - - void *buffer; - uint64_t file_size; - uint64_t remain; }; static unsigned int _checkboard(void) @@ -152,43 +148,54 @@ thor_download_head(struct thor_context *tctx, unsigned int packet_size) struct tfm_interface *intf = tctx->intf; struct dfu_entry *e = tctx->dfu_entry; uint64_t recv = 0; - uint64_t total = tctx->file_size; - void *buf; + uint64_t total = e->file_size; + void *buf, *curr; int usb_pkt_cnt = 0, n; int ret; - tctx->buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); + buf = curr = dfu_get_buffer(e, FLASH_UNIT_SIZE); while (total - recv >= packet_size) { - n = tfm_interface_recv(intf, buf, packet_size); + n = tfm_interface_recv(intf, curr, packet_size); - if (n < packet_size) - return -EIO; + if (n < packet_size) { + ret = -EIO; + goto err; + } recv += n; - buf += packet_size; + curr += packet_size; if ((recv % FLASH_UNIT_SIZE) == 0) { - ret = dfu_request_io(e, tctx->buffer, FLASH_UNIT_SIZE); - if (ret < 0) - return -EIO; + ret = dfu_request_io(e); + if (ret < 0) { + ret = -EIO; + goto err; + } - tctx->buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); + buf = curr = dfu_get_buffer(e, FLASH_UNIT_SIZE); } thor_send_data_rsp(tctx, 0, ++usb_pkt_cnt); } - tctx->remain = (total - recv) + (uint64_t)(buf - tctx->buffer); + e->buf_len = (total - recv) + (uint64_t)(curr - buf); if ((total - recv) > 0) { - n = tfm_interface_recv(intf, buf, packet_size); - if (n < packet_size) - return -EIO; + n = tfm_interface_recv(intf, curr, packet_size); + if (n < packet_size) { + ret = -EIO; + goto err; + } recv += n; thor_send_data_rsp(tctx, 0, ++usb_pkt_cnt); } return 0; + +err: + dfu_put_buffer(e); + + return ret; } static int thor_download_tail(struct thor_context *tctx) @@ -196,13 +203,13 @@ static int thor_download_tail(struct thor_context *tctx) struct dfu_entry *e = tctx->dfu_entry; int ret; - if (tctx->remain) { - ret = dfu_request_io(e, tctx->buffer, tctx->remain); + if (e->buf_len) { + ret = dfu_request_io(e); if (ret < 0) return -EIO; } else { /* if there is no remain, buffer should be freed */ - dfu_put_buffer(tctx->buffer); + dfu_put_buffer(e); } dfu_sync(e); @@ -223,14 +230,22 @@ static int thor_process_rqt_download(struct thor_context *tctx) switch (rqt->sub_id) { case RQT_DL_INIT: - tctx->file_size = (uint64_t)rqt->int_data[0] + { + struct dfu_context *dfu = tctx->dfu; + uint64_t total_size; + + total_size = (uint64_t)rqt->int_data[0] + ((uint64_t)rqt->int_data[1] << 32); + + dfu_init_download(dfu, total_size); break; + } case RQT_DL_FILE_INFO: { struct dfu_context *dfu = tctx->dfu; struct dfu_entry *e; char f_name[FILE_NAME_MAXLEN + 1] = {0,}; + uint64_t file_size; int file_type; file_type = rqt->int_data[0]; @@ -240,14 +255,14 @@ static int thor_process_rqt_download(struct thor_context *tctx) break; } - tctx->file_size = (uint64_t)rqt->int_data[1] + file_size = (uint64_t)rqt->int_data[1] + ((uint64_t)rqt->int_data[2] << 32); memcpy(f_name, rqt->str_data[0], FILE_NAME_MAXLEN); rsp.int_data[0] = DATA_PKT_SIZE; - e = dfu_start(dfu, tctx->file_size, f_name); + e = dfu_start(dfu, file_size, f_name); if (!e) { fprintf(stderr, "failed to start dfu\n"); ret = -EINVAL; @@ -263,22 +278,15 @@ static int thor_process_rqt_download(struct thor_context *tctx) ret = rsp.ack = -EINVAL; break; } - ret = thor_download_head(tctx, DATA_PKT_SIZE); - if (ret < 0) - tctx->remain = 0; - - return ret; + return thor_download_head(tctx, DATA_PKT_SIZE); case RQT_DL_FILE_END: rsp.ack = thor_download_tail(tctx); ret = rsp.ack; - tctx->remain = 0; - tctx->file_size = 0; /* * dfu_entry and buffer will be freed by dfu_thread_cleanup, * so just make it NULL here. */ tctx->dfu_entry = NULL; - tctx->buffer = NULL; break; case RQT_DL_EXIT: break; -- 2.7.4 From 76316d20e33346dde8812480a512091b0041e7b1 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 1 Apr 2020 10:43:52 +0900 Subject: [PATCH 03/16] dfu: Improve progress display Since commit 951986d4deb9 ("thor: Use smaller flash unit size"), the number of character '#' is extremely increased while transfer is proceeded. For removing it and providing fancy progress bar, this reworks progress display. Change-Id: Ic21ec3f1c87a469f23f6c892cfd341f956777930 Signed-off-by: Dongwoo Lee --- src/dfu.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 166185c..8a477de 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -40,6 +40,9 @@ #define DFU_IOQ_MAXLEN 5 +#define DFU_PROG_BAR_NAME_WIDTH 20 +#define DFU_PROG_BAR_WIDTH 50 + enum dfu_entry_attr { DFU_INFO_MODE = 0, DFU_INFO_PARTITION, @@ -264,6 +267,68 @@ static void dfu_thread_cleanup(void *ptr) free(e); } +static inline void print_bar_label(const char *label) +{ + fprintf(stdout, "\n[ %*s |", DFU_PROG_BAR_NAME_WIDTH, label); +} + +static void print_bar(uint64_t progress, uint64_t total, int *prev_rate) +{ + int rate = (progress * DFU_PROG_BAR_WIDTH) / total; + int bar_margin = DFU_PROG_BAR_NAME_WIDTH + 4; + int i; + + if (*prev_rate == rate) { + fprintf(stdout, "\x1b[%dC", bar_margin + DFU_PROG_BAR_WIDTH); + goto skip_bar; + } + + *prev_rate = rate; + + fprintf(stdout, "\x1b[%dC", bar_margin); + + for (i = 0; i < DFU_PROG_BAR_WIDTH; i++) { + if (i < rate) + fputc('=', stdout); + else if (i == rate) + fputc('>', stdout); + else + fputc(' ', stdout); + } + +skip_bar: + fprintf(stdout, "] (%5.1f%%)", + (double)progress / (double)total * 100.0F); +} + +static void print_progress(struct dfu_entry *e, uint64_t progress) +{ + struct dfu_context *ctx = e->ctx; + static int nth_entry = 1; + static uint64_t completed; + static int prev_total_rate; + static int prev_entry_rate; + uint64_t total_progress; + + total_progress = completed + progress; + + fprintf(stdout, "\x1b[%dA\n\x1b[1A", nth_entry); + print_bar(total_progress, ctx->total_size, &prev_total_rate); + + fprintf(stdout, "\x1b[%dB\n\x1b[1A", nth_entry); + print_bar(progress, e->file_size, &prev_entry_rate); + + /* prepare for next entry if current is finished */ + if (progress == e->file_size) { + completed += e->file_size; + nth_entry++; + } + + if (total_progress == ctx->total_size) + fprintf(stdout, "\nDownload Finished\n"); + fflush(stdout); +} + static void *dfu_thread_main(void *ptr) { struct dfu_entry *e = ptr; @@ -307,8 +372,7 @@ static void *dfu_thread_main(void *ptr) ctx->ioq_len--; pthread_mutex_unlock(&ctx->mutex); - fprintf(stdout, "#"); - fflush(stdout); + print_progress(e, progress); free(frame->buf); free(frame); @@ -401,8 +465,10 @@ void dfu_init_download(struct dfu_context *ctx, uint64_t size) { ctx->total_size = size; - fprintf(stdout, "Start Download (Total: %.2lfMB)\n", + fprintf(stdout, "Start Download (Total: %.2lfMB)", (double)size / (1024.0f * 1024.0f)); + + print_bar_label("Total"); } struct dfu_entry *dfu_start(struct dfu_context *ctx, @@ -430,8 +496,7 @@ struct dfu_entry *dfu_start(struct dfu_context *ctx, return NULL; } - fprintf(stdout, "Start download: %s...", filename); - fflush(stdout); + print_bar_label(filename); e->ctx = ctx; pthread_create(&ctx->thread, NULL, dfu_thread_main, e); @@ -455,8 +520,6 @@ void dfu_sync(struct dfu_entry *e) umount_dev(); pthread_cond_signal(&ctx->sync_done); - - fprintf(stdout, "finished\n"); } static int parse_dfu_info(char *buf, char **info) -- 2.7.4 From 00cf0e0ee0ce95e9b92285640e384000818c80f3 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 2 Apr 2020 10:47:22 +0900 Subject: [PATCH 04/16] net: Remove unused variables in net_available() There are unused variable warnings. Remove the unused variables in net_available(). Change-Id: Ic373fed340c0a65dd7c940cf407add7f0bcdb25e Signed-off-by: Seung-Woo Kim --- src/net.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/net.c b/src/net.c index e4da0ca..5b0a4f9 100644 --- a/src/net.c +++ b/src/net.c @@ -101,8 +101,7 @@ static int net_disconnect(struct tfm_interface *intf) static int net_available(void) { struct ifaddrs *ifs, *cur; - char host[NI_MAXHOST]; - int ret, s; + int ret; ret = getifaddrs(&ifs); if (ret < 0) -- 2.7.4 From ff97a1dbc3501bc3c8cbe20956a64a9697e6231c Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 2 Apr 2020 10:13:23 +0900 Subject: [PATCH 05/16] scripts: Fix file list with directory full path From file list for copying and moving, there are mixture of file path with and without prefix, "/usr". Fix the file list with prefix, "/usr", always. In Tizen, /bin and /sbin are symbolic links made from /usr/bin and /usr/sbin, so there is no functional change. Change-Id: Id7cc5ddb9d936da08fa47c05cf02b9f64f793b16 Signed-off-by: Seung-Woo Kim --- scripts/41-flash.list | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/scripts/41-flash.list b/scripts/41-flash.list index 3ec0e8b..60de1e5 100755 --- a/scripts/41-flash.list +++ b/scripts/41-flash.list @@ -1,27 +1,27 @@ # ---- Target contents ----------------------------------------------------- # MVWITHLIBS=" /usr/lib/initrd-recovery/flash/flash-init.sh -/bin/flash-manager +/usr/bin/flash-manager /usr/share/firmware/brcm/* " WITHLIBS=" -/bin/bash -/bin/echo -/bin/mkdir -/bin/mount -/bin/sync -/bin/umount -/sbin/ip +/usr/bin/bash +/usr/bin/echo +/usr/bin/mkdir +/usr/bin/mount +/usr/bin/sync +/usr/bin/umount +/usr/sbin/ip /usr/sbin/ifconfig -/bin/grep -/bin/kmod -/sbin/insmod -/bin/find -/bin/hostapd -/bin/dnsmasq -/bin/ln -/bin/sed +/usr/bin/grep +/usr/bin/kmod +/usr/sbin/insmod +/usr/bin/find +/usr/bin/hostapd +/usr/bin/dnsmasq +/usr/bin/ln +/usr/bin/sed " # LinkFileName:Target -- 2.7.4 From ea71e5d99da0966d87324dc2af87442c6738cfd2 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 2 Apr 2020 10:34:40 +0900 Subject: [PATCH 06/16] scripts: Add missing files to copying file list Add missing files to copying file list except /usr/sbin/reboot because it is symbolic link made from initrd-recovery package. This fixes below script errors when creating initrd-recovery.img without other recovery sub modules: /sbin/flash-init: line 98: /usr/bin/cp: No such file or directory /sbin/flash-init: line 99: /usr/bin/cp: No such file or directory Change-Id: I7edcc18311f07aca43f2c040f5bf1e6555e28ba0 Signed-off-by: Seung-Woo Kim --- scripts/41-flash.list | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/41-flash.list b/scripts/41-flash.list index 60de1e5..450babe 100755 --- a/scripts/41-flash.list +++ b/scripts/41-flash.list @@ -7,6 +7,8 @@ MVWITHLIBS=" WITHLIBS=" /usr/bin/bash +/usr/sbin/blkid +/usr/bin/cp /usr/bin/echo /usr/bin/mkdir /usr/bin/mount -- 2.7.4 From 6431691af7e2529a4ce447fe10905806b4c93675 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 17 Apr 2020 19:22:18 +0900 Subject: [PATCH 07/16] dfu: Don't print out progress if no terminal Since commit 76316d20e333 ("dfu: Improve progress display"), broken progress bar can flood massively if the output is redirected to non-terminal device such as a log file. To prevent this, prints out the simple result instead of progress bar if terminal doesn't exist. Change-Id: If5edb6408b7614951180fb4a73df53ad06572cc7 Signed-off-by: Dongwoo Lee --- src/dfu.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 8a477de..c7d1039 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -329,6 +329,25 @@ static void print_progress(struct dfu_entry *e, uint64_t progress) fflush(stdout); } +static void print_progress_notty(struct dfu_entry *e, uint64_t progress) +{ + struct dfu_context *ctx = e->ctx; + static uint64_t completed; + uint64_t total_progress; + + total_progress = completed + progress; + + fputc('#', stdout); + + if (progress == e->file_size) { + completed += e->file_size; + fprintf(stdout, "...Done"); + } + + if (total_progress == ctx->total_size) + fprintf(stdout, "\nDownload Finished\n"); +} + static void *dfu_thread_main(void *ptr) { struct dfu_entry *e = ptr; @@ -336,8 +355,14 @@ static void *dfu_thread_main(void *ptr) struct dfu_frame *frame; int state = DFU_THREAD_STATE_IDLE; uint64_t progress = 0; + void (*do_progress)(struct dfu_entry *e, uint64_t progress); int ret; + if (isatty(fileno(stdout))) + do_progress = print_progress; + else + do_progress = print_progress_notty; + pthread_cleanup_push(dfu_thread_cleanup, ptr); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); @@ -372,7 +397,7 @@ static void *dfu_thread_main(void *ptr) ctx->ioq_len--; pthread_mutex_unlock(&ctx->mutex); - print_progress(e, progress); + do_progress(e, progress); free(frame->buf); free(frame); @@ -468,7 +493,8 @@ void dfu_init_download(struct dfu_context *ctx, uint64_t size) fprintf(stdout, "Start Download (Total: %.2lfMB)", (double)size / (1024.0f * 1024.0f)); - print_bar_label("Total"); + if (isatty(fileno(stdout))) + print_bar_label("Total"); } struct dfu_entry *dfu_start(struct dfu_context *ctx, @@ -496,7 +522,10 @@ struct dfu_entry *dfu_start(struct dfu_context *ctx, return NULL; } - print_bar_label(filename); + if (isatty(fileno(stdout))) + print_bar_label(filename); + else + fprintf(stdout, "\n%s", filename); e->ctx = ctx; pthread_create(&ctx->thread, NULL, dfu_thread_main, e); -- 2.7.4 From 20a3844ed00655e017774266ba55edad065e20c7 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 24 Apr 2020 18:55:14 +0900 Subject: [PATCH 08/16] packaging: Enable aarch64 build The flash-manager can be used in aarch64, so no reason not to build in aarch64. Enable aarch64 build. Note: dependent package, initrd-recovery change to enable aarch64 build is required. Change-Id: Id2235971570eba474b4a5127f7587f1ccec097d3 Signed-off-by: Seung-Woo Kim --- packaging/initrd-flash.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index a2b1889..12d29d9 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -5,7 +5,7 @@ Release: 0 Group: System/Utilities License: Apache-2.0 Source0: %{name}-%{version}.tar.gz -ExclusiveArch: %{arm} +ExclusiveArch: %{arm} aarch64 BuildRequires: cmake BuildRequires: libblkid-devel BuildRequires: pkgconfig(libusbgx) -- 2.7.4 From 420fbc11e34c215900a6a0f7c5e1aa62d69bd7f6 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 4 Jun 2020 20:04:26 +0900 Subject: [PATCH 09/16] packaging: adjust file permission Only executable files are required to be set with exec permission. Adjust file permission for packaging. Change-Id: I62a11c42896bd8c96b7bb1a51fd2e867cdd5c5af Signed-off-by: Seung-Woo Kim --- packaging/initrd-flash.spec | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index 12d29d9..cb32b6b 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -70,13 +70,13 @@ mv %{_datadir}/partition_rpi3.info %{_datadir}/partition.info %files %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 +%attr(775,root,root) %{_bindir}/flash-manager +%attr(775,root,root) %{init_script_dir}/*.sh +%{_datadir}/initrd-recovery/initrd.list.d/*.list %files -n fm-data-rpi3 -%attr(700,root,root) %{_datadir}/partition_rpi3.info -%attr(700,root,root) %{_datadir}/firmware/brcm/brcmfmac* -%attr(700,root,root) %{_datadir}/firmware/brcm/LICENCE.broadcom_bcm43xx -%attr(700,root,root) %{_datadir}/firmware/brcm/hostapd.conf -%attr(700,root,root) %{_datadir}/firmware/brcm/dnsmasq.conf +%{_datadir}/partition_rpi3.info +%{_datadir}/firmware/brcm/brcmfmac* +%{_datadir}/firmware/brcm/LICENCE.broadcom_bcm43xx +%{_datadir}/firmware/brcm/hostapd.conf +%{_datadir}/firmware/brcm/dnsmasq.conf -- 2.7.4 From 65f37b21c90675e5b455589d2b14e312ddc70ec2 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 4 Jun 2020 20:01:10 +0900 Subject: [PATCH 10/16] Update install directory to support architecture difference Some install directory can be differ from each architecture. So use the install directory with packaging macro by configure file setup of cmake. Note: install init flie to libexec instead of libdir. Change-Id: I479e631a47bfff55f14209eaa60928c7a96acd8b Signed-off-by: Seung-Woo Kim --- CMakeLists.txt | 7 +++++++ packaging/initrd-flash.spec | 19 ++++++++----------- scripts/{41-flash.list => 41-flash.list.in} | 4 ++-- 3 files changed, 17 insertions(+), 13 deletions(-) rename scripts/{41-flash.list => 41-flash.list.in} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c33f4a..6b4f625 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,3 +13,10 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src) TARGET_LINK_LIBRARIES(flash-manager "${CMAKE_THREAD_LIBS_INIT}" blkid usbgx) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) + +INSTALL(FILES scripts/flash-init.sh DESTINATION ${INITRD_FLASH_LIBEXEC_DIR}) + +CONFIGURE_FILE(scripts/41-flash.list.in + scripts/41-flash.list + @ONLY) +INSTALL(FILES scripts/41-flash.list DESTINATION ${INITRD_RECOVERY_INSTALL_DROPIN_DIR}) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index cb32b6b..c991b35 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -1,6 +1,6 @@ Name: initrd-flash Summary: Advanced flash-manager, package for building ramdisk-recovery.img -Version: 0.0.1 +Version: 0.0.2 Release: 0 Group: System/Utilities License: Apache-2.0 @@ -31,12 +31,17 @@ Provides: fm-data %description -n fm-data-rpi3 Provide flash-manager with partition table for flashing image and files of Raspberry Pi 3 board +%define init_script_dir %{_libdir}/initrd-recovery/flash +%define initrd_recovery_install_dropin_dir %{_datadir}/initrd-recovery/initrd.list.d + %prep %setup -q %build -%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DINITRD_FLASH_LIBEXEC_DIR=%{init_script_dir} \ + -DINITRD_RECOVERY_INSTALL_DROPIN_DIR=%{initrd_recovery_install_dropin_dir} make %{?jobs:-j%jobs} @@ -44,14 +49,6 @@ 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 - cp ./data/partition_* %{buildroot}%{_datadir}/ mkdir -p %{buildroot}%{_datadir}/firmware/brcm @@ -72,7 +69,7 @@ mv %{_datadir}/partition_rpi3.info %{_datadir}/partition.info %license LICENSE %attr(775,root,root) %{_bindir}/flash-manager %attr(775,root,root) %{init_script_dir}/*.sh -%{_datadir}/initrd-recovery/initrd.list.d/*.list +%{initrd_recovery_install_dropin_dir}/*.list %files -n fm-data-rpi3 %{_datadir}/partition_rpi3.info diff --git a/scripts/41-flash.list b/scripts/41-flash.list.in similarity index 82% rename from scripts/41-flash.list rename to scripts/41-flash.list.in index 450babe..45c23b5 100755 --- a/scripts/41-flash.list +++ b/scripts/41-flash.list.in @@ -1,6 +1,6 @@ # ---- Target contents ----------------------------------------------------- # MVWITHLIBS=" -/usr/lib/initrd-recovery/flash/flash-init.sh +@INITRD_FLASH_LIBEXEC_DIR@/flash-init.sh /usr/bin/flash-manager /usr/share/firmware/brcm/* " @@ -29,7 +29,7 @@ WITHLIBS=" # LinkFileName:Target SYMLINKS=" /bin/sh:bash -/sbin/flash-init:/usr/lib/initrd-recovery/flash/flash-init.sh +/sbin/flash-init:@INITRD_FLASH_LIBEXEC_DIR@/flash-init.sh " VERBATIMS=" -- 2.7.4 From 0bcec92e2c6f87a7f8bfb52c406c2ce0e46df550 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 11 Jun 2020 09:55:37 +0900 Subject: [PATCH 11/16] script: flash-init: Add default PATH variable To mitigate security vulnerability, this defines default PATH variable explicitly. Change-Id: Idb828873481fe442ddf4ed3a6a89854590420e78 Signed-off-by: Dongwoo Lee --- scripts/flash-init.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/flash-init.sh b/scripts/flash-init.sh index 33c1f8e..3d0084d 100755 --- a/scripts/flash-init.sh +++ b/scripts/flash-init.sh @@ -1,5 +1,7 @@ #!/bin/bash +PATH=/bin:/usr/bin:/sbin:/usr/sbin + INFORM_FILE=reboot-param.bin INFORM_MOUNT_PATH=/mnt/inform TMP_PATH=/tmp -- 2.7.4 From 471dff4cdc0e36bced2c2bb9501efd88de76258b Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Mon, 3 Aug 2020 17:09:37 +0900 Subject: [PATCH 12/16] usb: properly clean up usb gadget If error occurs during flashing, usb gadget is not cleaned up and the second tfm session does not work for usb gadget. Properly clean up usb gadget including usbg_disable_gadget() and usbg_rm_gadget(). Change-Id: I702deaa009642e3ead45d40abb20c3bf821f1fb7 Signed-off-by: Seung-Woo Kim --- packaging/initrd-flash.spec | 2 +- src/usb.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index c991b35..05fdf38 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -1,6 +1,6 @@ Name: initrd-flash Summary: Advanced flash-manager, package for building ramdisk-recovery.img -Version: 0.0.2 +Version: 0.0.3 Release: 0 Group: System/Utilities License: Apache-2.0 diff --git a/src/usb.c b/src/usb.c index 606a2a7..9705b90 100644 --- a/src/usb.c +++ b/src/usb.c @@ -50,6 +50,7 @@ enum { struct usb_context { usbg_state *usbg; + usbg_gadget *gadget; pthread_t ep0_thread; int eps[TFMFFS_EP_MAX]; @@ -408,24 +409,24 @@ static int usb_connect(struct tfm_interface *intf) ret = usbg_create_function(g, USBG_F_FFS, TFMFFS_DEV, NULL, &f); if (ret < 0) { fprintf(stderr, "Failed to create USB function\n"); - goto err_cleanup; + goto err_rmgadget; } ret = usbg_create_config(g, 1, NULL, NULL, &c_strs, &c); if (ret < 0) { fprintf(stderr, "Failed to create USB config\n"); - goto err_cleanup; + goto err_rmgadget; } ret = usbg_add_config_function(c, TFMFFS_BIND_LINK, f); if (ret < 0) { fprintf(stderr, "Failed to bind USB function\n"); - goto err_cleanup; + goto err_rmgadget; } if (mount_ffs() < 0) { fprintf(stderr, "Failed to mount functionfs\n"); - goto err_cleanup; + goto err_rmgadget; } if (usb_setup_ffs_daemon(ctx) < 0) { @@ -444,6 +445,7 @@ static int usb_connect(struct tfm_interface *intf) pthread_cond_wait(&ctx->ready, &ctx->mutex); pthread_mutex_unlock(&ctx->mutex); + ctx->gadget = g; ctx->usbg = s; intf->txd = ctx->eps[TFMFFS_EP_BULK_IN]; @@ -458,6 +460,9 @@ err_ffs: err_umount: umount_ffs(); +err_rmgadget: + usbg_rm_gadget(g, USBG_RM_RECURSE); + err_cleanup: usbg_cleanup(s); @@ -477,9 +482,15 @@ static int usb_disconnect(struct tfm_interface *intf) close(ep[i]); usb_cleanup_ffs_daemon(ctx); + if (ctx->gadget) + usbg_disable_gadget(ctx->gadget); umount_ffs(); + if (ctx->gadget) + usbg_rm_gadget(ctx->gadget, USBG_RM_RECURSE); if (ctx->usbg) usbg_cleanup(ctx->usbg); + free(ctx); + intf->priv = NULL; return 0; } -- 2.7.4 From 4f1157dc54bf221d4e986886dbaec8ebb3a41daa Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 1 Sep 2020 19:11:28 +0900 Subject: [PATCH 13/16] usb: Read until buffer is fully filled Since a single read may not fill the buffer entirely, this makes try to fill the buffer fully with loop. Change-Id: Ic73daf50b060f37c773774108952dbdf30de07e1 Signed-off-by: Dongwoo Lee --- src/usb.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index 9705b90..0c36fa0 100644 --- a/src/usb.c +++ b/src/usb.c @@ -198,7 +198,20 @@ static const struct { static ssize_t usb_rx_data(int fd, void *buf, ssize_t len) { - return read(fd, buf, len); + ssize_t r, count = 0; + + do { + r = read(fd, buf + count, len - count); + if (r < 0) { + if (errno == EINTR) + continue; + else + return r; + } + count += r; + } while (count < len); + + return count; } static ssize_t usb_tx_data(int fd, void *buf, ssize_t len) -- 2.7.4 From 69801aee79673c883f54e8c98ef677a1b181ed83 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 3 Sep 2020 18:18:27 +0900 Subject: [PATCH 14/16] interface: Improve checking availiablity This improving checking interface availability for both situation: 1) stucked on initializing interface due to no available interfaces, and 2) options for unavailable interface is passed. Change-Id: I895d0c6e6fcf1d4539cb419c5e9c4f69ef9bf544 Signed-off-by: Dongwoo Lee --- src/interface.c | 24 ++++++++++++++++++++++-- src/interface.h | 1 + src/main.c | 7 +++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/interface.c b/src/interface.c index 103b749..778f73a 100644 --- a/src/interface.c +++ b/src/interface.c @@ -57,8 +57,8 @@ ssize_t tfm_interface_recv(struct tfm_interface *intf, void *buf, ssize_t len) return -ENOENT; } -int tfm_interface_set_private(struct tfm_interface_context *ictx, - char *name, void *data) +static struct tfm_interface * +get_interface(struct tfm_interface_context *ictx, char *name) { struct tfm_interface *intf = NULL; @@ -67,6 +67,21 @@ int tfm_interface_set_private(struct tfm_interface_context *ictx, break; } + return intf; +} + +int tfm_interface_is_available(struct tfm_interface_context *ictx, + char *name) +{ + return !!(get_interface(ictx, name)); +} + +int tfm_interface_set_private(struct tfm_interface_context *ictx, + char *name, void *data) +{ + struct tfm_interface *intf; + + intf = get_interface(ictx, name); if (!intf) { fprintf(stderr, "cannot find interface: %s\n", name); return -ENOENT; @@ -226,6 +241,11 @@ struct tfm_interface_context *tfm_interface_init(void) LIST_INSERT_HEAD(&ictx->interface_list, intf, entry); } + if (LIST_EMPTY(&ictx->interface_list)) { + fprintf(stderr, "There is no available interfaces.\n"); + goto err; + } + return ictx; err: diff --git a/src/interface.h b/src/interface.h index c908c1a..ae2ca93 100644 --- a/src/interface.h +++ b/src/interface.h @@ -62,6 +62,7 @@ struct tfm_interface { ssize_t tfm_interface_send(struct tfm_interface *intf, void *buf, ssize_t len); ssize_t tfm_interface_recv(struct tfm_interface *intf, void *buf, ssize_t len); +int tfm_interface_is_available(struct tfm_interface_context *ictx, char *name); int tfm_interface_set_private(struct tfm_interface_context *ictx, char *name, void *data); struct tfm_interface *tfm_interface_connect(struct tfm_interface_context *ictx); diff --git a/src/main.c b/src/main.c index 7737e5e..c9a3865 100644 --- a/src/main.c +++ b/src/main.c @@ -65,6 +65,13 @@ int _main(int argc, char *argv[]) unsigned long val; char *endptr = NULL; + if (!tfm_interface_is_available(supported_interfaces, + "net")) { + fprintf(stderr, + "'-p' option is ignored since net interface is not available.\n"); + continue; + } + val = strtoul(optarg, &endptr, 0); if (*optarg == '\0' || (endptr && *endptr != '\0')) { fprintf(stderr, -- 2.7.4 From 61d264453cf5c0abdd5ff013ea3a3c13f84142aa Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 3 Sep 2020 16:43:59 +0900 Subject: [PATCH 15/16] usb: Add support to set proper serial-number Now, we can provide serial-number to TFM's usb interface by using option 's'. Change-Id: Ie88350fded96999eb24b1a3f834598479c80177c Signed-off-by: Dongwoo Lee --- scripts/flash-init.sh | 6 +++++- src/main.c | 37 +++++++++++++++++++++++++++++++++---- src/usb.c | 24 +++++++++++++++++++++--- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/scripts/flash-init.sh b/scripts/flash-init.sh index 3d0084d..c316076 100755 --- a/scripts/flash-init.sh +++ b/scripts/flash-init.sh @@ -169,7 +169,11 @@ print_info() { # do_flash #------------------------------------------------ do_flash() { - "$FLASH_MANAGER" + if [ -n "$SERIAL" ]; then + FM_OPTS="-s ${SERIAL}" + fi + + bash -c "${FLASH_MANAGER} ${FM_OPTS}" #Control-flow will never reach here, because fm only terminates by rebooting diff --git a/src/main.c b/src/main.c index c9a3865..e7d276d 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,7 @@ int _main(int argc, char *argv[]) struct tfm_interface *intf; const char *part_table = "/usr/share/partition.info"; char *opt_table = NULL; + char *opt_serial = NULL; int ret, opt; supported_interfaces = tfm_interface_init(); @@ -39,7 +40,7 @@ int _main(int argc, char *argv[]) goto out; } - while ((opt = getopt(argc, argv, "p:i:")) != -1) { + while ((opt = getopt(argc, argv, "p:i:s:")) != -1) { switch (opt) { case 'i': if (optarg) { @@ -51,13 +52,13 @@ int _main(int argc, char *argv[]) } else { fprintf(stderr, "Out of memory\n"); ret = -1; - goto out_intfexit; + goto out_optfree; } } else { fprintf(stderr, "path should be specified with '-i'\n"); ret = -1; - goto out_intfexit; + goto out_optfree; } break; case 'p': @@ -83,6 +84,32 @@ int _main(int argc, char *argv[]) "net", (void *)val); break; } + case 's': + if (!tfm_interface_is_available(supported_interfaces, + "usb")) { + fprintf(stderr, + "'-s' option is ignored since usb interface is not available.\n"); + continue; + } + + if (optarg) { + if (opt_serial) + free(opt_serial); + opt_serial = strdup(optarg); + if (!opt_serial) { + fprintf(stderr, "Out of memory\n"); + ret = -1; + goto out_optfree; + } + } else { + fprintf(stderr, + "serial should be specified with '-s'\n"); + ret = -1; + goto out_optfree; + } + tfm_interface_set_private(supported_interfaces, + "usb", opt_serial); + break; default: ret = -1; goto out_optfree; @@ -122,7 +149,9 @@ out_dfuexit: out_optfree: if (opt_table) free(opt_table); -out_intfexit: + if (opt_serial) + free(opt_serial); + tfm_interface_exit(supported_interfaces); out: diff --git a/src/usb.c b/src/usb.c index 0c36fa0..791df5b 100644 --- a/src/usb.c +++ b/src/usb.c @@ -39,6 +39,9 @@ #define TFMFFS_BIND_LINK "tfm.ffs" #define TFMFFS_VID 0x04e8 #define TFMFFS_PID 0x685d +#define TFMFFS_DEFAULT_SERIAL "Unavailable" +#define TFMFFS_PRODUCT "USB download gadget" +#define TFMFFS_MANUFACTURER "Tizen" enum { TFMFFS_EP0, @@ -66,9 +69,9 @@ struct usbg_gadget_attrs g_attrs = { }; struct usbg_gadget_strs g_strs = { - .serial = "Unavailable", /* Serial number */ - .manufacturer = "Tizen", /* Manufacturer */ - .product = "iot-refboard" /* Product string */ + .serial = TFMFFS_DEFAULT_SERIAL, + .manufacturer = TFMFFS_MANUFACTURER, + .product = TFMFFS_PRODUCT }; struct usbg_config_strs c_strs = { @@ -413,7 +416,22 @@ static int usb_connect(struct tfm_interface *intf) goto err_freectx; } + /* If serial is provided as argument, set it to g_strs */ + if (intf->priv) + g_strs.serial = intf->priv; + ret = usbg_create_gadget(s, TFMFFS_GADGET, &g_attrs, &g_strs, &g); + /* + * In order to prevent that g_strs.serial has dangling pointer + * after the provided string is freed, we set g_strs.serial as + * default here. + * Since g_strs is accessed by only usbg_create_gadget() once, + * we can change it safely here. + */ + if (intf->priv) { + g_strs.serial = TFMFFS_DEFAULT_SERIAL; + intf->priv = NULL; + } if (ret < 0) { fprintf(stderr, "Failed to create USB gadget\n"); goto err_cleanup; -- 2.7.4 From b81b7d964400a40c3839c5e9c9cadd7b97a00f8c Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Tue, 22 Sep 2020 14:20:48 +0900 Subject: [PATCH 16/16] dfu: add null check for thread If dfu_start() is failed, there are cases ctx->thread is null and this causes crash during dfu_free_context(). So add null check for thread from dfu_free_context(). This fixes below crash-stack: Call Stack Count: 2 0: pthread_cancel + 0x10 (0x0000007f81d9eab0) [/mnt/initrd-recovery/usr/lib64/libpthread.so.0] + 0x10ab0 1: dfu_free_context + 0x1c (0x000000557ca2283c) [/mnt/initrd-recovery/usr/bin/flash-manager] + 0x483c End of Call Stack Change-Id: I92fb9980047a3a58de516e81d694b7507662be26 Signed-off-by: Seung-Woo Kim --- src/dfu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dfu.c b/src/dfu.c index c7d1039..362016a 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -644,7 +644,8 @@ void dfu_free_context(struct dfu_context *ctx) if (!ctx) return; - pthread_cancel(ctx->thread); + if (ctx->thread) + pthread_cancel(ctx->thread); destroy_dfu_info(ctx); free(ctx); } -- 2.7.4