From 29950f08d56bd278a198463489be60d6bbdba49c Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 18 Mar 2020 12:35:59 +0900 Subject: [PATCH 01/16] thor: Bump protocol version to 5.0 To support the images exceeds 4GB, thor protocol 5.0 is applied. This requires thor client support: Ref: https://git.tizen.org/cgit/tools/lthor/commit/?id=30fa9f0cbfc4b089bb7e733b9cb75a60e1d10369 u-boot thor downloader already supports protocol 5.0: Ref: https://gitlab.denx.de/u-boot/u-boot/-/commit/1fe9ae76b113103bcc40aa15949f9dd8aa0a06a2 Change-Id: I149361ca2f40b5775249f3672e3e19b2f6394b68 Signed-off-by: Dongwoo Lee --- src/thor-proto.h | 2 +- src/thor.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/thor-proto.h b/src/thor-proto.h index f384b46..c26aefd 100644 --- a/src/thor-proto.h +++ b/src/thor-proto.h @@ -84,7 +84,7 @@ struct data_res_pkt { int32_t cnt; /* Int. Datas. */ } __attribute__((__packed__)); -#define VER_PROTOCOL_MAJOR 4 +#define VER_PROTOCOL_MAJOR 5 #define VER_PROTOCOL_MINOR 0 #define RQT_PKT_SIZE sizeof(struct rqt_pkt) diff --git a/src/thor.c b/src/thor.c index d6dfa09..e19d33f 100644 --- a/src/thor.c +++ b/src/thor.c @@ -216,7 +216,8 @@ static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rq switch (rqt->sub_id) { case RQT_DL_INIT: - ctx->thor_file_size = (unsigned long)rqt->int_data[0]; + ctx->thor_file_size = (uint64_t)rqt->int_data[0] + + ((uint64_t)rqt->int_data[1] << 32); break; case RQT_DL_FILE_INFO: file_type = rqt->int_data[0]; @@ -226,7 +227,8 @@ static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rq break; } - ctx->thor_file_size = (unsigned long)rqt->int_data[1]; + ctx->thor_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; -- 2.7.4 From bdeb2d6876465d4d3b38b91f0f06b9a993dc5f59 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:29:24 +0900 Subject: [PATCH 02/16] tfm: Refactor code structure To cleanup code and resolve dependency on each module, this just refactors code structure without functional changes. Change-Id: I0c9e4b50d1054255c4f33f2a0218469c0647d2c7 Signed-off-by: Dongwoo Lee --- src/dfu.c | 408 ++++++++++++++++++++++++++++++++++--------------------------- src/dfu.h | 46 +++---- src/main.c | 27 ++-- src/tfm.h | 22 +--- src/thor.c | 170 ++++++++++++++++---------- 5 files changed, 370 insertions(+), 303 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 0a1b297..4ae9145 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -31,7 +31,44 @@ #include "dfu.h" #include "thor-proto.h" -static char *dfu_info[DFU_INFO_NUM][DFU_INFO_MAX] = {NULL,}; +#define DFU_DELIMITER " :,\t\n" +#define DFU_ENTRY_LIST_MAXLEN 100 +#define DFU_MOUNT_PATH "/mnt/tfm-temp" + +#define DFU_INFO_MODE_PARTITION 'p' +#define DFU_INFO_MODE_FILE 'f' + +enum dfu_entry_attr { + DFU_INFO_MODE = 0, + DFU_INFO_PARTITION, + DFU_INFO_NAME, + DFU_INFO_PATH, + DFU_INFO_MAX, +}; + +enum dfu_thread_state { + DFU_THREAD_STATE_ERROR = -1, + DFU_THREAD_STATE_IDLE, + DFU_THREAD_STATE_FLASHING, +}; + +struct dfu_frame { + void *buf; + unsigned long len; + TAILQ_ENTRY(dfu_frame) entry; +}; + +struct dfu_context { + pthread_t thread; + pthread_mutex_t mutex; + pthread_mutex_t sync_mutex; + pthread_cond_t data_arrived; + pthread_cond_t write_done; + pthread_cond_t sync_done; + TAILQ_HEAD(tailhead, dfu_frame) ioq; + + char *dfu_entry_list[DFU_ENTRY_LIST_MAXLEN][DFU_INFO_MAX]; +}; void *dfu_get_buffer(unsigned long size) { @@ -55,44 +92,45 @@ void dfu_put_buffer(void *ptr) free(ptr); } -static int find_match(const char *name) +static char **find_entry_match(struct dfu_context *ctx, const char *name) { int i; - for (i = 0; i < DFU_INFO_NUM; i++) { - char *entry = dfu_info[i][DFU_INFO_NAME]; + for (i = 0; i < DFU_ENTRY_LIST_MAXLEN; i++) { + char *entry = ctx->dfu_entry_list[i][DFU_INFO_NAME]; if (entry && !strncmp(entry, name, strlen(entry))) - return i; + return ctx->dfu_entry_list[i]; } - return -ENOENT; + return NULL; } -int dfu_request_io(struct tfm_context *ctx, unsigned long len) +int dfu_request_io(struct dfu_entry *e, void *buffer, unsigned long len) { - int notify = 0; + struct dfu_context *ctx = e->ctx; struct dfu_frame *frame; + int notify = 0; frame = malloc(sizeof(*frame)); if (!frame) return -ENOMEM; - frame->buf = ctx->transfer_buffer; + frame->buf = buffer; frame->len = len; - pthread_mutex_lock(&ctx->dfu_mutex); + pthread_mutex_lock(&ctx->mutex); - if (TAILQ_EMPTY(&ctx->dfu_ioq_head)) + if (TAILQ_EMPTY(&ctx->ioq)) notify = 1; /* dfu_thread_main() de-queues i/o request and processes it */ - TAILQ_INSERT_TAIL(&ctx->dfu_ioq_head, frame, entry); + TAILQ_INSERT_TAIL(&ctx->ioq, frame, entry); - pthread_mutex_unlock(&ctx->dfu_mutex); + pthread_mutex_unlock(&ctx->mutex); if (notify) - pthread_cond_signal(&ctx->dfu_data_arrive); + pthread_cond_signal(&ctx->data_arrived); return 0; } @@ -179,53 +217,112 @@ static void umount_dev(void) rmdir(DFU_MOUNT_PATH); } -void dfu_sync(struct tfm_context *ctx) +static void dfu_thread_cleanup(void *ptr) { - char **info = ctx->dfu_info; + struct dfu_entry *e = ptr; + struct dfu_context *ctx = e->ctx; + struct dfu_frame *frame; - 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); + while (!TAILQ_EMPTY(&ctx->ioq)) { + frame = TAILQ_FIRST(&ctx->ioq); - switch (*info[DFU_INFO_MODE]) { - case DFU_INFO_MODE_FILE: - fsync(ctx->dfu_fd); - close(ctx->dfu_fd); - umount_dev(); - break; - case DFU_INFO_MODE_PARTITION: - close(ctx->dfu_fd); - break; - default: - break; + TAILQ_REMOVE(&ctx->ioq, frame, entry); + + dfu_put_buffer(frame->buf); + free(frame); } - pthread_cond_signal(&ctx->dfu_sync_done); + free(e); +} - fprintf(stdout, "finished\n"); +static void *dfu_thread_main(void *ptr) +{ + struct dfu_entry *e = ptr; + struct dfu_context *ctx = e->ctx; + struct dfu_frame *frame; + int state = DFU_THREAD_STATE_IDLE; + uint64_t progress = 0; + int ret; + + pthread_cleanup_push(dfu_thread_cleanup, ptr); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + while (state != DFU_THREAD_STATE_ERROR) { + pthread_mutex_lock(&ctx->mutex); + + while (TAILQ_EMPTY(&ctx->ioq)) { + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + state = DFU_THREAD_STATE_IDLE; + pthread_cond_wait(&ctx->data_arrived, &ctx->mutex); + } + + if (state == DFU_THREAD_STATE_IDLE) { + state = DFU_THREAD_STATE_FLASHING; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + } + + frame = TAILQ_FIRST(&ctx->ioq); + + TAILQ_REMOVE(&ctx->ioq, frame, entry); + + pthread_mutex_unlock(&ctx->mutex); + + ret = write(e->fd, frame->buf, frame->len); + + if (ret < frame->len) { + fprintf(stderr, "Error occurs while flashing\n"); + state = DFU_THREAD_STATE_ERROR; + } + + progress += frame->len; + + fprintf(stdout, "#"); + fflush(stdout); + + dfu_put_buffer(frame->buf); + free(frame); + + /* transfer finished */ + if (state != DFU_THREAD_STATE_ERROR + && progress >= e->file_size) { + e->transfer_done = 1; + + state = DFU_THREAD_STATE_IDLE; + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + pthread_cond_signal(&ctx->write_done); + + pthread_mutex_lock(&ctx->sync_mutex); + pthread_cond_wait(&ctx->sync_done, + &ctx->sync_mutex); + pthread_mutex_unlock(&ctx->sync_mutex); + break; + } + } + + pthread_cleanup_pop(1); + + return NULL; } -static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size) +static int dfu_start_entry(struct dfu_entry *e, char **entry, uint64_t size) { - char **info = dfu_info[idx]; char *file; - int fd; + int fd, ret = 0; - switch (*info[DFU_INFO_MODE]) { + switch (*entry[DFU_INFO_MODE]) { case DFU_INFO_MODE_PARTITION: - file = strdup(info[DFU_INFO_PARTITION]); + file = strdup(entry[DFU_INFO_PARTITION]); if (!file) return -ENOMEM; break; case DFU_INFO_MODE_FILE: { - int ret; int path_prefix = strlen(DFU_MOUNT_PATH); - int path_suffix = strlen(info[DFU_INFO_PATH]); - int path_name = strlen(info[DFU_INFO_NAME]); + int path_suffix = strlen(entry[DFU_INFO_PATH]); + int path_name = strlen(entry[DFU_INFO_NAME]); - ret = mount_dev(info[DFU_INFO_PARTITION]); + ret = mount_dev(entry[DFU_INFO_PARTITION]); if (ret < 0) return -EINVAL; @@ -236,138 +333,98 @@ static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size } strncpy(file, DFU_MOUNT_PATH, path_prefix + 1); - strncat(file, info[DFU_INFO_PATH], path_suffix + 1); - strncat(file, info[DFU_INFO_NAME], path_name + 1); + strncat(file, entry[DFU_INFO_PATH], path_suffix + 1); + strncat(file, entry[DFU_INFO_NAME], path_name + 1); break; } default: - fprintf(stderr, "flash entry '%s' has wrong mode\n", info[DFU_INFO_NAME]); + fprintf(stderr, + "flash entry '%s' has wrong mode\n", + entry[DFU_INFO_NAME]); return -EINVAL; } fd = open(file, O_WRONLY); if (fd < 0) { - fprintf(stderr, "cannot open target: %s\n", info[DFU_INFO_NAME]); - free(file); - return -EIO; + fprintf(stderr, + "cannot open target: %s\n", + entry[DFU_INFO_NAME]); + ret = -EIO; + goto err; } - ctx->dfu_fd = fd; - - ctx->dfu_info = info; - ctx->transfer_done = 0; + e->entry = entry; + e->fd = fd; + e->file_size = size; + e->transfer_done = 0; +err: free(file); - return 0; + return ret; } -int dfu_start(struct tfm_context *ctx, const char *entity) +struct dfu_entry *dfu_start(struct dfu_context *ctx, + uint64_t size, const char *filename) { - 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; - } + struct dfu_entry *e; + char **entry; + int ret; - ret = dfu_start_entity(ctx, idx, size); - if (ret < 0) { - fprintf(stderr, "Cannot start download: %s\n", entity); - return -EINVAL; + entry = find_entry_match(ctx, filename); + if (!entry) { + fprintf(stderr, "Cannot find dfu info for %s\n", filename); + return NULL; } - fprintf(stdout, "Start download: %s...", entity); - fflush(stdout); + e = (struct dfu_entry *)malloc(sizeof(*e)); + if (!e) + return NULL; - return 0; -} + ret = dfu_start_entry(e, entry, size); + if (ret < 0) { + fprintf(stderr, "Cannot start download: %s\n", filename); + free(e); + return NULL; + } -static void dfu_thread_cleanup(void *ptr) -{ - struct tfm_context *ctx = ptr; - struct dfu_frame *frame; + pthread_create(&ctx->thread, NULL, dfu_thread_main, e); - while (!TAILQ_EMPTY(&ctx->dfu_ioq_head)) { - frame = TAILQ_FIRST(&ctx->dfu_ioq_head); + e->ctx = ctx; - TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry); + fprintf(stdout, "Start download: %s...", filename); + fflush(stdout); - dfu_put_buffer(frame->buf); - free(frame); - } + return e; } -static void *dfu_thread_main(void *ptr) +void dfu_sync(struct dfu_entry *e) { - struct tfm_context *ctx = ptr; - struct dfu_frame *frame; - int state = DFU_THREAD_STATE_IDLE; - uint64_t progress = 0; - int ret; - - pthread_cleanup_push(dfu_thread_cleanup, ptr); - - while (state != DFU_THREAD_STATE_ERROR) { - pthread_mutex_lock(&ctx->dfu_mutex); - - while (TAILQ_EMPTY(&ctx->dfu_ioq_head)) { - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - state = DFU_THREAD_STATE_IDLE; - pthread_cond_wait(&ctx->dfu_data_arrive, &ctx->dfu_mutex); - } - - if (state == DFU_THREAD_STATE_IDLE) { - state = DFU_THREAD_STATE_FLASHING; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - } - - frame = TAILQ_FIRST(&ctx->dfu_ioq_head); - - TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry); - - pthread_mutex_unlock(&ctx->dfu_mutex); + struct dfu_context *ctx = e->ctx; + char **info = e->entry; - ret = write(ctx->dfu_fd, frame->buf, frame->len); - - if (ret < frame->len) { - fprintf(stderr, "Error occurs while flashing\n"); - state = DFU_THREAD_STATE_ERROR; - } + pthread_mutex_lock(&ctx->sync_mutex); + if (!e->transfer_done) + pthread_cond_wait(&ctx->write_done, &ctx->sync_mutex); + pthread_mutex_unlock(&ctx->sync_mutex); - progress += frame->len; - - fprintf(stdout, "#"); - fflush(stdout); - - dfu_put_buffer(frame->buf); - free(frame); - - /* transfer finished */ - if (state != DFU_THREAD_STATE_ERROR && progress >= ctx->thor_file_size) { - progress = 0; - ctx->transfer_done = 1; - - fprintf(stdout, "\nTransfer completed. Please wait for sync..."); - fflush(stdout); - - state = DFU_THREAD_STATE_IDLE; - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - - 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); - } + switch (*info[DFU_INFO_MODE]) { + case DFU_INFO_MODE_FILE: + fsync(e->fd); + close(e->fd); + umount_dev(); + break; + case DFU_INFO_MODE_PARTITION: + close(e->fd); + break; + default: + break; } - pthread_cleanup_pop(1); + pthread_cond_signal(&ctx->sync_done); - return NULL; + fprintf(stdout, "finished\n"); } static int parse_dfu_info(char *buf, char **info) @@ -388,36 +445,35 @@ static int parse_dfu_info(char *buf, char **info) return 0; } -static void destroy_dfu_info(void) +static void destroy_dfu_info(struct dfu_context *ctx) { int i, j; - for (i = 0; i < DFU_INFO_NUM; i++) { + for (i = 0; i < DFU_ENTRY_LIST_MAXLEN; i++) { for (j = 0; j < DFU_INFO_MAX; j++) - if (dfu_info[i][j]) { - free(dfu_info[i][j]); - dfu_info[i][j] = NULL; + if (ctx->dfu_entry_list[i][j]) { + free(ctx->dfu_entry_list[i][j]); + ctx->dfu_entry_list[i][j] = NULL; } } } - -static int init_dfu_info(const char *dfu_info_file) +int dfu_init_entry(struct dfu_context *ctx, const char *entry_file) { FILE *fp; char buf[1024]; int i = 0; int ret; - fp = fopen(dfu_info_file, "r"); + fp = fopen(entry_file, "r"); if (!fp) return -ENOENT; - while (i < DFU_INFO_NUM && !feof(fp)) { + while (i < DFU_ENTRY_LIST_MAXLEN && !feof(fp)) { if (fgets(buf, 1024, fp) == NULL) break; - ret = parse_dfu_info(buf, dfu_info[i++]); + ret = parse_dfu_info(buf, ctx->dfu_entry_list[i++]); if (ret < 0) { fprintf(stderr, "cannot parse dfu info"); goto err_free_all; @@ -430,45 +486,39 @@ static int init_dfu_info(const char *dfu_info_file) err_free_all: fclose(fp); - destroy_dfu_info(); + destroy_dfu_info(ctx); return ret; } -int dfu_init(struct tfm_context *ctx, const char *dfu_info_file) +struct dfu_context *dfu_alloc_context(void) { - int ret; + struct dfu_context *ctx; - ret = init_dfu_info(dfu_info_file); - if (ret < 0) { - fprintf(stderr, "failed to get flash entries\n"); - return ret; - } + ctx = (struct dfu_context *)malloc(sizeof(*ctx)); + if (!ctx) + return NULL; - TAILQ_INIT(&ctx->dfu_ioq_head); + ctx->thread = 0; + TAILQ_INIT(&ctx->ioq); - 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); + pthread_mutex_init(&ctx->mutex, NULL); + pthread_mutex_init(&ctx->sync_mutex, NULL); + pthread_cond_init(&ctx->data_arrived, NULL); + pthread_cond_init(&ctx->write_done, NULL); + pthread_cond_init(&ctx->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; - } + memset(ctx->dfu_entry_list, 0, sizeof(ctx->dfu_entry_list)); - return 0; + return ctx; } -void dfu_exit(struct tfm_context *ctx) +void dfu_free_context(struct dfu_context *ctx) { - pthread_cancel(ctx->dfu_thread); - pthread_join(ctx->dfu_thread, NULL); - destroy_dfu_info(); - if (ctx->connect) { - free(ctx->connect); - ctx->connect = NULL; - } + if (!ctx) + return; + + pthread_cancel(ctx->thread); + destroy_dfu_info(ctx); + free(ctx); } diff --git a/src/dfu.h b/src/dfu.h index 589a9a1..0d35883 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -18,41 +18,27 @@ #define __DFU_H #include -#include "tfm.h" +#include -#define DFU_DELIMITER " :,\t\n" -#define DFU_INFO_NUM 100 -#define DFU_MOUNT_PATH "/mnt/tfm-temp" +struct dfu_context; -#define DFU_INFO_MODE_PARTITION 'p' -#define DFU_INFO_MODE_FILE 'f' - -enum dfu_info_entry { - DFU_INFO_MODE = 0, - DFU_INFO_PARTITION, - DFU_INFO_NAME, - DFU_INFO_PATH, - DFU_INFO_MAX, -}; - -enum dfu_thread_state { - DFU_THREAD_STATE_ERROR = -1, - DFU_THREAD_STATE_IDLE, - DFU_THREAD_STATE_FLASHING, -}; - -struct dfu_frame { - void *buf; - unsigned long len; - TAILQ_ENTRY(dfu_frame) entry; +struct dfu_entry { + struct dfu_context *ctx; + char **entry; + int fd; + uint64_t file_size; + int transfer_done; }; 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); +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); +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); + #endif diff --git a/src/main.c b/src/main.c index 32c2473..376d8be 100644 --- a/src/main.c +++ b/src/main.c @@ -25,12 +25,13 @@ int _main(int argc, char *argv[]) { - struct tfm_context ctx; + struct tfm_context tfm; + struct dfu_context *dfu; const char *part_table = "/usr/share/partition.info"; char *opt_table = NULL; int ret, opt; - memset(&ctx, 0, sizeof(ctx)); + memset(&tfm, 0, sizeof(tfm)); while ((opt = getopt(argc, argv, "p:i:")) != -1) { switch (opt) { @@ -65,7 +66,7 @@ int _main(int argc, char *argv[]) ret = -1; goto out_optfree; } - ctx.port = (int)val; + tfm.port = (int)val; break; } default: @@ -74,35 +75,41 @@ int _main(int argc, char *argv[]) } } - ret = dfu_init(&ctx, part_table); - if (ret < 0) { + dfu = dfu_alloc_context(); + if (!dfu) { ret = -1; goto out_optfree; } - ret = net_connect(&ctx); + ret = dfu_init_entry(dfu, part_table); + if (ret < 0) { + ret = -1; + goto out_dfuexit; + } + + ret = net_connect(&tfm); if (ret < 0) { ret = -1; goto out_dfuexit; } - ret = thor_init(&ctx); + ret = thor_setup(&tfm); if (ret < 0) { ret = -1; goto out_netdisconn; } - ret = thor_process(&ctx); + ret = thor_process(&tfm, dfu); if (ret < 0) { ret = -1; goto out_netdisconn; } out_netdisconn: - net_disconnect(&ctx); + net_disconnect(&tfm); out_dfuexit: - dfu_exit(&ctx); + dfu_free_context(dfu); out_optfree: if (opt_table) diff --git a/src/tfm.h b/src/tfm.h index 747de2d..8760e35 100644 --- a/src/tfm.h +++ b/src/tfm.h @@ -19,9 +19,10 @@ #include #include -#include #include +#include "dfu.h" + struct tfm_connect { int fd; ssize_t (*rx_data)(int fd, void *buf, ssize_t len); @@ -29,26 +30,11 @@ struct tfm_connect { }; 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); +int thor_setup(struct tfm_context *tfm); +int thor_process(struct tfm_context *tfm, struct dfu_context *dfu); #endif diff --git a/src/thor.c b/src/thor.c index e19d33f..1c255d2 100644 --- a/src/thor.c +++ b/src/thor.c @@ -26,18 +26,20 @@ #include #include +#include "tfm.h" #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); -} +struct thor_context { + struct rqt_pkt *rqt; + struct tfm_connect *intf; + struct dfu_context *dfu; + struct dfu_entry *dfu_entry; -static inline ssize_t thor_tx_data(struct tfm_connect *conn, void *buf, ssize_t len) -{ - return conn->tx_data(conn->fd, buf, len); -} + void *buffer; + uint64_t file_size; + uint64_t remain; +}; static unsigned int _checkboard(void) { @@ -48,19 +50,21 @@ static unsigned int _checkboard(void) return -1; } -static int thor_send_rsp(struct tfm_connect *conn, const struct res_pkt *rsp) +static int thor_send_rsp(struct thor_context *tctx, struct res_pkt *rsp) { + struct tfm_connect *intf = tctx->intf; ssize_t n; - n = thor_tx_data(conn, (void *)rsp, RES_PKT_SIZE); + n = intf->tx_data(intf->fd, (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) +static int thor_process_rqt_info(struct thor_context *tctx) { + struct rqt_pkt *rqt = tctx->rqt; struct res_pkt rsp; int ret; @@ -89,7 +93,7 @@ static int thor_process_rqt_info(struct tfm_context *ctx, struct rqt_pkt *rqt) return -EINVAL; } - ret = thor_send_rsp(ctx->connect, &rsp); + ret = thor_send_rsp(tctx, &rsp); if (ret < 0) { fprintf(stderr, "failed to send response of REQUEST_INFO\n"); return ret; @@ -98,9 +102,9 @@ static int thor_process_rqt_info(struct tfm_context *ctx, struct rqt_pkt *rqt) return 0; } -static int thor_process_rqt_cmd(struct tfm_context *ctx, struct rqt_pkt *rqt) +static int thor_process_rqt_cmd(struct thor_context *tctx) { - struct tfm_connect *conn = ctx->connect; + struct rqt_pkt *rqt = tctx->rqt; struct res_pkt rsp; int ret; @@ -111,7 +115,7 @@ static int thor_process_rqt_cmd(struct tfm_context *ctx, struct rqt_pkt *rqt) switch (rqt->sub_id) { case RQT_CMD_REBOOT: - thor_send_rsp(conn, &rsp); + thor_send_rsp(tctx, &rsp); ret = reboot(RB_AUTOBOOT); if (ret < 0) { @@ -120,7 +124,7 @@ static int thor_process_rqt_cmd(struct tfm_context *ctx, struct rqt_pkt *rqt) } break; case RQT_CMD_POWEROFF: - thor_send_rsp(conn, &rsp); + thor_send_rsp(tctx, &rsp); break; default: fprintf(stderr, "Not supported command request: %d", @@ -131,29 +135,32 @@ static int thor_process_rqt_cmd(struct tfm_context *ctx, struct rqt_pkt *rqt) return 0; } -static void thor_send_data_rsp(struct tfm_connect *conn, int ack, int count) +static void thor_send_data_rsp(struct thor_context *tctx, int ack, int count) { + struct tfm_connect *intf = tctx->intf; struct data_res_pkt rsp; rsp.ack = ack; rsp.cnt = count; - thor_tx_data(conn, &rsp, DATA_RES_PKT_SIZE); + intf->tx_data(intf->fd, &rsp, DATA_RES_PKT_SIZE); } -static int thor_download_head(struct tfm_context *ctx, unsigned int packet_size) +static int +thor_download_head(struct thor_context *tctx, unsigned int packet_size) { - struct tfm_connect *conn = ctx->connect; + struct tfm_connect *intf = tctx->intf; + struct dfu_entry *e = tctx->dfu_entry; uint64_t recv = 0; - uint64_t total = ctx->thor_file_size; + uint64_t total = tctx->file_size; void *buf; int usb_pkt_cnt = 0, n; int ret; - ctx->transfer_buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); + tctx->buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); while (total - recv >= packet_size) { - n = thor_rx_data(conn, buf, packet_size); + n = intf->rx_data(intf->fd, buf, packet_size); if (n < packet_size) return -EIO; @@ -162,52 +169,52 @@ static int thor_download_head(struct tfm_context *ctx, unsigned int packet_size) buf += packet_size; if ((recv % FLASH_UNIT_SIZE) == 0) { - ret = dfu_request_io(ctx, FLASH_UNIT_SIZE); + ret = dfu_request_io(e, tctx->buffer, FLASH_UNIT_SIZE); if (ret < 0) return -EIO; - ctx->transfer_buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); + tctx->buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); } - thor_send_data_rsp(conn, 0, ++usb_pkt_cnt); + thor_send_data_rsp(tctx, 0, ++usb_pkt_cnt); } - ctx->remain = (total - recv) + (uint64_t)(buf - ctx->transfer_buffer); + tctx->remain = (total - recv) + (uint64_t)(buf - tctx->buffer); if ((total - recv) > 0) { - n = thor_rx_data(conn, buf, packet_size); + n = intf->rx_data(intf->fd, buf, packet_size); if (n < packet_size) return -EIO; recv += n; - thor_send_data_rsp(conn, 0, ++usb_pkt_cnt); + thor_send_data_rsp(tctx, 0, ++usb_pkt_cnt); } return 0; } -static int thor_download_tail(struct tfm_context *ctx) +static int thor_download_tail(struct thor_context *tctx) { + struct dfu_entry *e = tctx->dfu_entry; int ret; - if (ctx->remain) { - ret = dfu_request_io(ctx, ctx->remain); + if (tctx->remain) { + ret = dfu_request_io(e, tctx->buffer, tctx->remain); if (ret < 0) return -EIO; } else { /* if there is no remain, buffer should be freed */ - dfu_put_buffer(ctx->transfer_buffer); + dfu_put_buffer(tctx->buffer); } - dfu_sync(ctx); + dfu_sync(e); return 0; } -static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rqt) +static int thor_process_rqt_download(struct thor_context *tctx) { - struct tfm_connect *conn = ctx->connect; - char f_name[FILE_NAME_MAXLEN + 1] = {0,}; + struct rqt_pkt *rqt = tctx->rqt; struct res_pkt rsp; - int ret = 0, head, file_type; + int ret = 0; memset(&rsp, 0, RES_PKT_SIZE); @@ -216,10 +223,16 @@ static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rq switch (rqt->sub_id) { case RQT_DL_INIT: - ctx->thor_file_size = (uint64_t)rqt->int_data[0] + tctx->file_size = (uint64_t)rqt->int_data[0] + ((uint64_t)rqt->int_data[1] << 32); break; case RQT_DL_FILE_INFO: + { + struct dfu_context *dfu = tctx->dfu; + struct dfu_entry *e; + char f_name[FILE_NAME_MAXLEN + 1] = {0,}; + int file_type; + file_type = rqt->int_data[0]; if (file_type != BINARY_TYPE_NORMAL) { fprintf(stderr, "Currently only NORMAL_FILE is supported\n"); @@ -227,34 +240,45 @@ static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rq break; } - ctx->thor_file_size = (uint64_t)rqt->int_data[1] + tctx->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; - ret = dfu_start(ctx, f_name); - if (ret < 0) { + e = dfu_start(dfu, tctx->file_size, f_name); + if (!e) { fprintf(stderr, "failed to start dfu\n"); ret = -EINVAL; } + + tctx->dfu_entry = e; break; + } case RQT_DL_FILE_START: - ret = thor_send_rsp(conn, &rsp); + ret = thor_send_rsp(tctx, &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; + ret = thor_download_head(tctx, DATA_PKT_SIZE); + if (ret < 0) + tctx->remain = 0; - return head; + return ret; case RQT_DL_FILE_END: - rsp.ack = thor_download_tail(ctx); + rsp.ack = thor_download_tail(tctx); ret = rsp.ack; - ctx->remain = 0; + 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; @@ -264,23 +288,24 @@ static int thor_process_rqt_download(struct tfm_context *ctx, struct rqt_pkt *rq ret = -EINVAL; } - thor_send_rsp(conn, &rsp); + thor_send_rsp(tctx, &rsp); return ret; } -static int thor_do_request(struct tfm_context *ctx, struct rqt_pkt *rqt) +static int thor_do_request(struct thor_context *tctx) { + struct rqt_pkt *rqt = tctx->rqt; int ret; switch (rqt->id) { case RQT_INFO: - ret = thor_process_rqt_info(ctx, rqt); + ret = thor_process_rqt_info(tctx); break; case RQT_CMD: - ret = thor_process_rqt_cmd(ctx, rqt); + ret = thor_process_rqt_cmd(tctx); break; case RQT_DL: - ret = thor_process_rqt_download(ctx, rqt); + ret = thor_process_rqt_download(tctx); break; case RQT_UL: fprintf(stderr, "Request \"UPLOAD\" is not supported\n"); @@ -294,17 +319,17 @@ static int thor_do_request(struct tfm_context *ctx, struct rqt_pkt *rqt) return ret; } -static int thor_handshake(struct tfm_connect *conn) +static int thor_handshake(struct tfm_connect *intf) { char buf[5]; ssize_t n; - n = thor_rx_data(conn, buf, 4/* strlen("THOR") */); + n = intf->rx_data(intf->fd, buf, 4/* strlen("THOR") */); if (n < 4) return -EIO; if (!strncmp(buf, "THOR", 4)) { - n = thor_tx_data(conn, "ROHT", 4); + n = intf->tx_data(intf->fd, "ROHT", 4); if (n < 4) return -EIO; } else { @@ -315,20 +340,21 @@ static int thor_handshake(struct tfm_connect *conn) return 0; } -int thor_init(struct tfm_context *ctx) +int thor_process(struct tfm_context *tfm, struct dfu_context *dfu) { - return thor_handshake(ctx->connect); -} - -int thor_process(struct tfm_context *ctx) -{ - struct tfm_connect *conn = ctx->connect; + struct tfm_connect *intf = tfm->connect; + struct thor_context tctx; struct rqt_pkt rqt; ssize_t n; int ret; + memset(&tctx, 0, sizeof(tctx)); + + tctx.intf = intf; + tctx.dfu = dfu; + for (;;) { - n = thor_rx_data(conn, &rqt, RQT_PKT_SIZE); + n = intf->rx_data(intf->fd, &rqt, RQT_PKT_SIZE); if (n < sizeof(rqt)) { fprintf(stderr, "Failed to receive data from the host(%zd:%zu)", @@ -336,10 +362,22 @@ int thor_process(struct tfm_context *ctx) return -EIO; } - ret = thor_do_request(ctx, &rqt); + tctx.rqt = &rqt; + + ret = thor_do_request(&tctx); if (ret < 0) return ret; } return 0; } + +int thor_setup(struct tfm_context *tfm) +{ + if (!tfm->connect) { + fprintf(stderr, "Invalid connection\n"); + return -EINVAL; + } + + return thor_handshake(tfm->connect); +} -- 2.7.4 From 5df0e1d2947d87e15492f3fe103dcd4d68992beb Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:36:02 +0900 Subject: [PATCH 03/16] interface: Add support for multiple transfer interfaces To support USB connection, multiple interface f/w should be required before. This adds only interface f/w, so network connection is still processed without f/w. Change-Id: I367f9e961daefe3b9005104084955edbe0851057 Signed-off-by: Dongwoo Lee --- CMakeLists.txt | 2 +- src/interface.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/interface.h | 70 ++++++++++++++++++ 3 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 src/interface.c create mode 100644 src/interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c722f06..9fcc572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ SET(CMAKE_EXE_LINKER_FLAGS "-pie") FIND_PACKAGE(Threads REQUIRED) -ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/net.c) +ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/interface.c src/net.c) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src) diff --git a/src/interface.c b/src/interface.c new file mode 100644 index 0000000..de6f559 --- /dev/null +++ b/src/interface.c @@ -0,0 +1,222 @@ +/* + * 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 "tfm.h" +#include "interface.h" + +struct tfm_interface_context { + struct tfm_interface *connected; + + pthread_mutex_t mutex; + pthread_cond_t signal; + + LIST_HEAD(intflist, tfm_interface) interface_list; +}; + +INTERFACE interface_avail_list = LIST_HEAD_INITIALIZER(interface_avail_list); + +ssize_t tfm_interface_send(struct tfm_interface *intf, void *buf, ssize_t len) +{ + if (!intf) + return -EINVAL; + + if (intf->ops && intf->ops->tx_data) + return intf->ops->tx_data(intf->txd, buf, len); + + return -ENOENT; +} + +ssize_t tfm_interface_recv(struct tfm_interface *intf, void *buf, ssize_t len) +{ + if (!intf) + return -EINVAL; + + if (intf->ops && intf->ops->rx_data) + return intf->ops->rx_data(intf->rxd, buf, len); + + return -ENOENT; +} + +int tfm_interface_set_private(struct tfm_interface_context *ictx, + char *name, void *data) +{ + struct tfm_interface *intf = NULL; + + LIST_FOREACH(intf, &ictx->interface_list, entry) { + if (!strncmp(intf->name, name, strlen(name))) + break; + } + + if (!intf) { + fprintf(stderr, "cannot find interface: %s\n", name); + return -ENOENT; + } + + intf->priv = data; + + return 0; +} + +static void *connect_thread_main(void *ptr) +{ + struct tfm_interface *intf = ptr; + struct tfm_interface_context *ictx = intf->ctx; + int ret; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + /* for checking which interface is connected */ + intf->tid = pthread_self(); + + if (!intf->ops || !intf->ops->connect || !intf->ops->disconnect) + return NULL; + + ret = intf->ops->connect(intf); + if (ret < 0) { + fprintf(stderr, "failed to connect: %s\n", intf->name); + return NULL; + } + + pthread_mutex_lock(&ictx->mutex); + if (ictx->connected) { + pthread_mutex_unlock(&ictx->mutex); + fprintf(stderr, + "interface %s will be ignored due to %s\n", + intf->name, ictx->connected->name); + intf->ops->disconnect(intf); + return NULL; + } + + ictx->connected = intf; + pthread_mutex_unlock(&ictx->mutex); + + fprintf(stdout, "interface %s is connected.\n", intf->name); + + pthread_cond_signal(&ictx->signal); + + return NULL; +} + +struct tfm_interface *tfm_interface_connect(struct tfm_interface_context *ictx) +{ + struct tfm_interface *intf; + + LIST_FOREACH(intf, &ictx->interface_list, entry) { + pthread_t t; + + pthread_create(&t, NULL, connect_thread_main, (void *)intf); + pthread_detach(t); + } + + pthread_mutex_lock(&ictx->mutex); + while (!ictx->connected) + pthread_cond_wait(&ictx->signal, &ictx->mutex); + pthread_mutex_unlock(&ictx->mutex); + + LIST_FOREACH(intf, &ictx->interface_list, entry) { + /* Terminate threads waiting for other connection */ + if (intf != ictx->connected) { + intf->ctx = NULL; + pthread_cancel(intf->tid); + } + } + + return ictx->connected; +} + +void tfm_interface_disconnect(struct tfm_interface *intf) +{ + if (!intf) + return; + + if (intf->ops && intf->ops->disconnect) + intf->ops->disconnect(intf); + + intf->ctx->connected = NULL; +} + +static void destroy_interface_list(struct tfm_interface_context *ictx) +{ + struct tfm_interface *intf, *temp; + + intf = LIST_FIRST(&ictx->interface_list); + while (intf != NULL) { + temp = intf; + intf = LIST_NEXT(intf, entry); + + LIST_REMOVE(temp, entry); + free(temp); + } +} + +struct tfm_interface_context *tfm_interface_init(void) +{ + struct tfm_interface_context *ictx; + struct tfm_interface_driver *driver; + + ictx = (struct tfm_interface_context *)malloc(sizeof(*ictx)); + if (!ictx) + return NULL; + + ictx->connected = NULL; + + pthread_mutex_init(&ictx->mutex, NULL); + pthread_cond_init(&ictx->signal, NULL); + + LIST_INIT(&ictx->interface_list); + + LIST_FOREACH(driver, &interface_avail_list, entry) { + struct tfm_interface *intf; + + intf = (struct tfm_interface *)malloc(sizeof(*intf)); + if (!intf) + goto err; + + intf->name = driver->name; + intf->rxd = intf->txd = -1; + intf->ops = &driver->ops; + intf->priv = NULL; + intf->tid = 0; + intf->ctx = ictx; + + LIST_INSERT_HEAD(&ictx->interface_list, intf, entry); + } + + return ictx; + +err: + destroy_interface_list(ictx); + free(ictx); + + return NULL; +} + +void tfm_interface_exit(struct tfm_interface_context *ictx) +{ + if (!ictx) + return; + + tfm_interface_disconnect(ictx->connected); + destroy_interface_list(ictx); + free(ictx); +} diff --git a/src/interface.h b/src/interface.h new file mode 100644 index 0000000..7bb9c02 --- /dev/null +++ b/src/interface.h @@ -0,0 +1,70 @@ +/* + * 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 __INTERFACE_H +#define __INTERFACE_H + +#include +#include +#include + +typedef LIST_HEAD(availlist, tfm_interface_driver) INTERFACE; + +#define INTERFACE_REGISTER(_intf) extern INTERFACE interface_avail_list; \ +static void __attribute__ ((constructor)) tfm_##_intf##_interface_init(void) \ +{ \ + LIST_INSERT_HEAD(&interface_avail_list, &_intf, entry); \ +} + +struct tfm_interface_context; +struct tfm_interface; + +struct tfm_interface_ops { + int (*connect)(struct tfm_interface *intf); + int (*disconnect)(struct tfm_interface *intf); + ssize_t (*rx_data)(int fd, void *buf, ssize_t len); + ssize_t (*tx_data)(int fd, void *buf, ssize_t len); +}; + +struct tfm_interface_driver { + char *name; + struct tfm_interface_ops ops; + + LIST_ENTRY(tfm_interface_driver) entry; +}; + +struct tfm_interface { + char *name; + int rxd; + int txd; + struct tfm_interface_ops *ops; + + void *priv; + pthread_t tid; + struct tfm_interface_context *ctx; + + LIST_ENTRY(tfm_interface) entry; +}; + +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_set_private(struct tfm_interface_context *ictx, + char *name, void *data); +struct tfm_interface *tfm_interface_connect(struct tfm_interface_context *ictx); +void tfm_interface_disconnect(struct tfm_interface *intf); +struct tfm_interface_context *tfm_interface_init(void); +void tfm_interface_exit(struct tfm_interface_context *ictx); +#endif -- 2.7.4 From bfa980fadb2273fb752ea4b45f4177cd012065e2 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:42:38 +0900 Subject: [PATCH 04/16] interface: net: Apply interface f/w into network transfer Since this, network connection is processed upon interface f/w. Change-Id: I87df71a923f010bb013e0b4166c50949bb19a153 Signed-off-by: Dongwoo Lee --- src/main.c | 37 +++++++++++++++++++------------ src/net.c | 74 +++++++++++++++++++++++++++++++++----------------------------- src/net.h | 27 ----------------------- src/tfm.h | 18 +++------------ src/thor.c | 34 ++++++++++++++--------------- 5 files changed, 83 insertions(+), 107 deletions(-) delete mode 100644 src/net.h diff --git a/src/main.c b/src/main.c index 376d8be..141f165 100644 --- a/src/main.c +++ b/src/main.c @@ -20,18 +20,24 @@ #include #include +#include "tfm.h" #include "dfu.h" -#include "net.h" +#include "interface.h" int _main(int argc, char *argv[]) { - struct tfm_context tfm; + struct tfm_interface_context *supported_interfaces; struct dfu_context *dfu; + struct tfm_interface *intf; const char *part_table = "/usr/share/partition.info"; char *opt_table = NULL; int ret, opt; - memset(&tfm, 0, sizeof(tfm)); + supported_interfaces = tfm_interface_init(); + if (!supported_interfaces) { + ret = -1; + goto out; + } while ((opt = getopt(argc, argv, "p:i:")) != -1) { switch (opt) { @@ -45,13 +51,13 @@ int _main(int argc, char *argv[]) } else { fprintf(stderr, "Out of memory\n"); ret = -1; - goto out; + goto out_intfexit; } } else { fprintf(stderr, "path should be specified with '-i'\n"); ret = -1; - goto out; + goto out_intfexit; } break; case 'p': @@ -66,7 +72,8 @@ int _main(int argc, char *argv[]) ret = -1; goto out_optfree; } - tfm.port = (int)val; + tfm_interface_set_private(supported_interfaces, + "net", (void *)val); break; } default: @@ -87,26 +94,26 @@ int _main(int argc, char *argv[]) goto out_dfuexit; } - ret = net_connect(&tfm); - if (ret < 0) { + intf = tfm_interface_connect(supported_interfaces); + if (!intf) { ret = -1; goto out_dfuexit; } - ret = thor_setup(&tfm); + ret = thor_setup(intf); if (ret < 0) { ret = -1; - goto out_netdisconn; + goto out_disconn; } - ret = thor_process(&tfm, dfu); + ret = thor_process(intf, dfu); if (ret < 0) { ret = -1; - goto out_netdisconn; + goto out_disconn; } -out_netdisconn: - net_disconnect(&tfm); +out_disconn: + tfm_interface_disconnect(intf); out_dfuexit: dfu_free_context(dfu); @@ -114,6 +121,8 @@ out_dfuexit: out_optfree: if (opt_table) free(opt_table); +out_intfexit: + tfm_interface_exit(supported_interfaces); out: exit(ret); diff --git a/src/net.c b/src/net.c index b946fa4..9de6741 100644 --- a/src/net.c +++ b/src/net.c @@ -23,80 +23,86 @@ #include #include -#include "net.h" +#include "tfm.h" +#include "interface.h" -static ssize_t net_rx_data(int sock, void *buf, ssize_t len) +#define DEFAULT_PORT 23456 + +static ssize_t net_rx_data(int fd, void *buf, ssize_t len) { - return recv(sock, buf, len, MSG_WAITALL); + return recv(fd, buf, len, MSG_WAITALL); } -static ssize_t net_tx_data(int sock, void *buf, ssize_t len) +static ssize_t net_tx_data(int fd, void *buf, ssize_t len) { - return send(sock, buf, len, 0); + return send(fd, buf, len, 0); } -int net_connect(struct tfm_context *ctx) +static int net_connect(struct tfm_interface *intf) { struct sockaddr_in servaddr; - struct tfm_connect *conn; - int listener, sock; - int ret = 0; - - conn = malloc(sizeof(*conn)); - if (!conn) - return -ENOMEM; + int listener, ret = 0; + int port; listener = socket(AF_INET, SOCK_STREAM, 0); if (listener < 0) { fprintf(stderr, "Failed to create socket\n"); - ret = -EINVAL; - goto err_free; + return -EINVAL; } + port = (unsigned long) intf->priv; + if (port <= 1024) + port = DEFAULT_PORT; + + fprintf(stdout, "%s using port: %d\n", intf->name, port); + 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)); + servaddr.sin_port = htons(port); ret = bind(listener, (struct sockaddr *) &servaddr, sizeof(servaddr)); if (ret < 0) { fprintf(stderr, "Failed to bind socket\n"); - goto err_socket; + goto err; } ret = listen(listener, 1024); if (ret < 0) { fprintf(stderr, "Failed to call listen\n"); - goto err_socket; + goto err; } - sock = accept(listener, NULL, NULL); - if (sock < 0) { + ret = accept(listener, NULL, NULL); + if (ret < 0) { fprintf(stderr, "Failed to accept connection\n"); - ret = sock; - goto err_socket; + goto err; } - conn->fd = sock; - conn->rx_data = net_rx_data; - conn->tx_data = net_tx_data; - ctx->connect = conn; + intf->rxd = intf->txd = ret; close(listener); return 0; -err_socket: +err: close(listener); -err_free: - free(conn); return ret; } -void net_disconnect(struct tfm_context *ctx) +static int net_disconnect(struct tfm_interface *intf) { - close(ctx->connect->fd); - - free(ctx->connect); - ctx->connect = NULL; + /* since rxd == txd, we close only rxd */ + return close(intf->rxd); } + +static struct tfm_interface_driver network = { + .name = "net", + .ops = { + .connect = net_connect, + .disconnect = net_disconnect, + .rx_data = net_rx_data, + .tx_data = net_tx_data, + }, +}; +INTERFACE_REGISTER(network) diff --git a/src/net.h b/src/net.h deleted file mode 100644 index dc96b4d..0000000 --- a/src/net.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 index 8760e35..7d18f4e 100644 --- a/src/tfm.h +++ b/src/tfm.h @@ -16,25 +16,13 @@ #ifndef __TFM_H #define __TFM_H - #include #include #include #include "dfu.h" +#include "interface.h" -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 { - struct tfm_connect *connect; - int port; -}; - -int thor_setup(struct tfm_context *tfm); -int thor_process(struct tfm_context *tfm, struct dfu_context *dfu); - +int thor_setup(struct tfm_interface *intf); +int thor_process(struct tfm_interface *intf, struct dfu_context *dfu); #endif diff --git a/src/thor.c b/src/thor.c index 1c255d2..426dd40 100644 --- a/src/thor.c +++ b/src/thor.c @@ -28,11 +28,12 @@ #include "tfm.h" #include "dfu.h" +#include "interface.h" #include "thor-proto.h" struct thor_context { struct rqt_pkt *rqt; - struct tfm_connect *intf; + struct tfm_interface *intf; struct dfu_context *dfu; struct dfu_entry *dfu_entry; @@ -52,10 +53,10 @@ static unsigned int _checkboard(void) static int thor_send_rsp(struct thor_context *tctx, struct res_pkt *rsp) { - struct tfm_connect *intf = tctx->intf; + struct tfm_interface *intf = tctx->intf; ssize_t n; - n = intf->tx_data(intf->fd, (void *)rsp, RES_PKT_SIZE); + n = tfm_interface_send(intf, (void *)rsp, RES_PKT_SIZE); if (n < sizeof(*rsp)) return -EIO; @@ -137,19 +138,19 @@ static int thor_process_rqt_cmd(struct thor_context *tctx) static void thor_send_data_rsp(struct thor_context *tctx, int ack, int count) { - struct tfm_connect *intf = tctx->intf; + struct tfm_interface *intf = tctx->intf; struct data_res_pkt rsp; rsp.ack = ack; rsp.cnt = count; - intf->tx_data(intf->fd, &rsp, DATA_RES_PKT_SIZE); + tfm_interface_send(intf, &rsp, DATA_RES_PKT_SIZE); } static int thor_download_head(struct thor_context *tctx, unsigned int packet_size) { - struct tfm_connect *intf = tctx->intf; + struct tfm_interface *intf = tctx->intf; struct dfu_entry *e = tctx->dfu_entry; uint64_t recv = 0; uint64_t total = tctx->file_size; @@ -160,7 +161,7 @@ thor_download_head(struct thor_context *tctx, unsigned int packet_size) tctx->buffer = buf = dfu_get_buffer(FLASH_UNIT_SIZE); while (total - recv >= packet_size) { - n = intf->rx_data(intf->fd, buf, packet_size); + n = tfm_interface_recv(intf, buf, packet_size); if (n < packet_size) return -EIO; @@ -181,7 +182,7 @@ thor_download_head(struct thor_context *tctx, unsigned int packet_size) tctx->remain = (total - recv) + (uint64_t)(buf - tctx->buffer); if ((total - recv) > 0) { - n = intf->rx_data(intf->fd, buf, packet_size); + n = tfm_interface_recv(intf, buf, packet_size); if (n < packet_size) return -EIO; recv += n; @@ -319,17 +320,17 @@ static int thor_do_request(struct thor_context *tctx) return ret; } -static int thor_handshake(struct tfm_connect *intf) +static int thor_handshake(struct tfm_interface *intf) { char buf[5]; ssize_t n; - n = intf->rx_data(intf->fd, buf, 4/* strlen("THOR") */); + n = tfm_interface_recv(intf, buf, 4/* strlen("THOR") */); if (n < 4) return -EIO; if (!strncmp(buf, "THOR", 4)) { - n = intf->tx_data(intf->fd, "ROHT", 4); + n = tfm_interface_send(intf, "ROHT", 4); if (n < 4) return -EIO; } else { @@ -340,9 +341,8 @@ static int thor_handshake(struct tfm_connect *intf) return 0; } -int thor_process(struct tfm_context *tfm, struct dfu_context *dfu) +int thor_process(struct tfm_interface *intf, struct dfu_context *dfu) { - struct tfm_connect *intf = tfm->connect; struct thor_context tctx; struct rqt_pkt rqt; ssize_t n; @@ -354,7 +354,7 @@ int thor_process(struct tfm_context *tfm, struct dfu_context *dfu) tctx.dfu = dfu; for (;;) { - n = intf->rx_data(intf->fd, &rqt, RQT_PKT_SIZE); + n = tfm_interface_recv(intf, &rqt, RQT_PKT_SIZE); if (n < sizeof(rqt)) { fprintf(stderr, "Failed to receive data from the host(%zd:%zu)", @@ -372,12 +372,12 @@ int thor_process(struct tfm_context *tfm, struct dfu_context *dfu) return 0; } -int thor_setup(struct tfm_context *tfm) +int thor_setup(struct tfm_interface *intf) { - if (!tfm->connect) { + if (!intf) { fprintf(stderr, "Invalid connection\n"); return -EINVAL; } - return thor_handshake(tfm->connect); + return thor_handshake(intf); } -- 2.7.4 From 62c1a507383c0858abf47f1f1ab8472ba42973d6 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:44:33 +0900 Subject: [PATCH 05/16] tfm: Get rid of unnecessary global header tfm.h Global tfm context is no more used, so global header tfm.h is neither required. This just removes unnecessary header, thus has no functional changes. Change-Id: I69daaaa255dea57676e04bdb0c8145cf4049ed87 Signed-off-by: Dongwoo Lee --- src/interface.c | 1 - src/main.c | 2 +- src/net.c | 2 +- src/thor.c | 1 - src/{tfm.h => thor.h} | 7 ++----- 5 files changed, 4 insertions(+), 9 deletions(-) rename src/{tfm.h => thor.h} (89%) diff --git a/src/interface.c b/src/interface.c index de6f559..69d2084 100644 --- a/src/interface.c +++ b/src/interface.c @@ -21,7 +21,6 @@ #include #include -#include "tfm.h" #include "interface.h" struct tfm_interface_context { diff --git a/src/main.c b/src/main.c index 141f165..0281c30 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ #include #include -#include "tfm.h" +#include "thor.h" #include "dfu.h" #include "interface.h" diff --git a/src/net.c b/src/net.c index 9de6741..6cd8587 100644 --- a/src/net.c +++ b/src/net.c @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include @@ -23,7 +24,6 @@ #include #include -#include "tfm.h" #include "interface.h" #define DEFAULT_PORT 23456 diff --git a/src/thor.c b/src/thor.c index 426dd40..6cb6984 100644 --- a/src/thor.c +++ b/src/thor.c @@ -26,7 +26,6 @@ #include #include -#include "tfm.h" #include "dfu.h" #include "interface.h" #include "thor-proto.h" diff --git a/src/tfm.h b/src/thor.h similarity index 89% rename from src/tfm.h rename to src/thor.h index 7d18f4e..7a88006 100644 --- a/src/tfm.h +++ b/src/thor.h @@ -14,11 +14,8 @@ * limitations under the License. */ -#ifndef __TFM_H -#define __TFM_H -#include -#include -#include +#ifndef __THOR_H +#define __THOR_H #include "dfu.h" #include "interface.h" -- 2.7.4 From a5f5989894617f51caf41550b5c760ed212ecfe4 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:53:32 +0900 Subject: [PATCH 06/16] interface: usb: Add support for USB interface USB interface is added and enabled by configuring gadget driver through configfs with support of libusbgx. Change-Id: I638bfa59e127f7896f8ed4b6fa11ba3d37d4548e Signed-off-by: Dongwoo Lee --- CMakeLists.txt | 4 +- packaging/initrd-flash.spec | 2 + scripts/flash-init.sh | 19 ++ src/usb.c | 492 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 515 insertions(+), 2 deletions(-) create mode 100644 src/usb.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fcc572..7c33f4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,10 +6,10 @@ SET(CMAKE_EXE_LINKER_FLAGS "-pie") FIND_PACKAGE(Threads REQUIRED) -ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/interface.c src/net.c) +ADD_EXECUTABLE(${PROJECT_NAME} src/main.c src/thor.c src/dfu.c src/interface.c src/net.c src/usb.c) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src) -TARGET_LINK_LIBRARIES(flash-manager "${CMAKE_THREAD_LIBS_INIT}" blkid) +TARGET_LINK_LIBRARIES(flash-manager "${CMAKE_THREAD_LIBS_INIT}" blkid usbgx) INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/packaging/initrd-flash.spec b/packaging/initrd-flash.spec index d6dc741..a2b1889 100644 --- a/packaging/initrd-flash.spec +++ b/packaging/initrd-flash.spec @@ -8,6 +8,7 @@ Source0: %{name}-%{version}.tar.gz ExclusiveArch: %{arm} BuildRequires: cmake BuildRequires: libblkid-devel +BuildRequires: pkgconfig(libusbgx) Requires: util-linux Requires: bash @@ -16,6 +17,7 @@ Requires: fm-data Requires: module-init-tools Requires: wpa_supplicant Requires: dnsmasq +Requires: libusbgx %description Provide kernel-based target image downloader. diff --git a/scripts/flash-init.sh b/scripts/flash-init.sh index 799e80a..6473dd7 100755 --- a/scripts/flash-init.sh +++ b/scripts/flash-init.sh @@ -3,6 +3,8 @@ INFORM_FILE=reboot-param.bin INFORM_MOUNT_PATH=/mnt/inform TMP_PATH=/tmp +SYSFS_PATH=/sys +CONFIGFS_PATH=/sys/kernel/config BLKID="/usr/sbin/blkid" FLASH_MANAGER="/usr/bin/flash-manager" @@ -33,6 +35,22 @@ clear_bootmode() { } #------------------------------------------------ +# setup_usb +#------------------------------------------------ +setup_usb() { + SYSFS=$($MOUNT | $GREP sysfs) + if [ -z "$SYSFS" ]; then + $MOUNT -t sysfs none $SYSFS_PATH + fi + + CONFIGFS=$($MOUNT | $GREP configfs) + if [ -z "$CONFIGFS" ]; then + $MOUNT -t configfs none $CONFIGFS_PATH + fi +} + + +#------------------------------------------------ # Copy Module and Firmware file #------------------------------------------------ setup_wireless() { @@ -126,6 +144,7 @@ do_flash() { #------------------------------------------------ setup_wired_nic setup_wireless +setup_usb clear_bootmode print_info do_flash diff --git a/src/usb.c b/src/usb.c new file mode 100644 index 0000000..f7920bb --- /dev/null +++ b/src/usb.c @@ -0,0 +1,492 @@ +/* + * 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 + +#include +#include + +#include "interface.h" + +#define TFMFFS_PATH "/dev/tfmffs" +#define TFMFFS_GADGET "g1" +#define TFMFFS_DEV "tfm" +#define TFMFFS_BIND_LINK "tfm.ffs" +#define TFMFFS_VID 0x04e8 +#define TFMFFS_PID 0x685d + +enum { + TFMFFS_EP0, + TFMFFS_EP_INT_IN, + TFMFFS_EP_BULK_IN, + TFMFFS_EP_BULK_OUT, + TFMFFS_EP_MAX, +}; + +struct usb_context { + usbg_state *usbg; + pthread_t ep0_thread; + int eps[TFMFFS_EP_MAX]; + + int enabled; + + pthread_mutex_t mutex; + pthread_cond_t ready; +}; + +struct usbg_gadget_attrs g_attrs = { + .idVendor = TFMFFS_VID, + .idProduct = TFMFFS_PID, +}; + +struct usbg_gadget_strs g_strs = { + .serial = "Unavailable", /* Serial number */ + .manufacturer = "Tizen", /* Manufacturer */ + .product = "iot-refboard" /* Product string */ +}; + +struct usbg_config_strs c_strs = { + .configuration = "Conf 1" +}; + +/******************** Descriptors and Strings *******************************/ + +static const struct { + struct usb_functionfs_descs_head header; + struct { + struct usb_interface_descriptor acm; + struct usb_endpoint_descriptor_no_audio int_in; + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio bulk_in; + struct usb_endpoint_descriptor_no_audio bulk_out; + } __attribute__ ((__packed__)) fs_descs, hs_descs; +} __attribute__ ((__packed__)) descriptors = { + .header = { + .magic = __cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), + .length = __cpu_to_le32(sizeof(descriptors)), + .fs_count = __cpu_to_le32(5), + .hs_count = __cpu_to_le32(5), + }, + .fs_descs = { + .acm = { + .bLength = sizeof(descriptors.fs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, + .iInterface = 1, + }, + .int_in = { + .bLength = sizeof(descriptors.fs_descs.bulk_in), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 3 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + }, + .intf = { + .bLength = sizeof(descriptors.fs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .iInterface = 1, + }, + .bulk_in = { + .bLength = sizeof(descriptors.fs_descs.bulk_in), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + .bulk_out = { + .bLength = sizeof(descriptors.fs_descs.bulk_out), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + }, + }, + .hs_descs = { + .acm = { + .bLength = sizeof(descriptors.fs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, + .iInterface = 1, + }, + .int_in = { + .bLength = sizeof(descriptors.fs_descs.bulk_in), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 3 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __cpu_to_le16(16), + .bInterval = 10, + }, + .intf = { + .bLength = sizeof(descriptors.hs_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .iInterface = 1, + }, + .bulk_in = { + .bLength = sizeof(descriptors.hs_descs.bulk_in), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __cpu_to_le16(512), + }, + .bulk_out = { + .bLength = sizeof(descriptors.hs_descs.bulk_out), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __cpu_to_le16(512), + }, + }, +}; + +#define STR_INTERFACE "TIZEN USB DRIVER" + +static const struct { + struct usb_functionfs_strings_head header; + struct { + __le16 code; + const char str1[sizeof(STR_INTERFACE)]; + } __attribute__ ((__packed__)) lang0; +} __attribute__ ((__packed__)) strings = { + .header = { + .magic = __cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC), + .length = __cpu_to_le32(sizeof(strings)), + .str_count = __cpu_to_le32(1), + .lang_count = __cpu_to_le32(1), + }, + .lang0 = { + __cpu_to_le16(0x0409), /* en-us */ + STR_INTERFACE, + }, +}; + +static ssize_t usb_rx_data(int fd, void *buf, ssize_t len) +{ + return read(fd, buf, len); +} + +static ssize_t usb_tx_data(int fd, void *buf, ssize_t len) +{ + return write(fd, buf, len); +} + +static void *ep0_handler(void *data) +{ + struct usb_context *ctx = data; + struct usb_functionfs_event evt; + int ret, ep0 = ctx->eps[TFMFFS_EP0]; + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + for (;;) { + ret = read(ep0, &evt, sizeof(evt)); + if (ret <= 0) + goto err; + + switch (evt.type) { + case FUNCTIONFS_SETUP: + { + struct usb_ctrlrequest *ctrl = &evt.u.setup; + + if (ctrl->bRequestType & USB_DIR_IN) { + if (write(ep0, NULL, 0) < 0) + goto err; + } else { /* ctrl->bRequestType & USB_DIR_OUT */ + switch (ctrl->bRequest) { + /* handle CDC ACM setup request */ + case USB_CDC_REQ_SET_LINE_CODING: + { + int value = __le16_to_cpu(ctrl->wLength); + char *buf; + + buf = malloc(value); + if (!buf) + goto err; + + if (read(ep0, buf, value) < 0) { + free(buf); + goto err; + } + free(buf); + break; + } + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: + { + int buf; + + if (read(ep0, &buf, sizeof(buf)) < 0) + goto err; + break; + } + default: + if (read(ep0, NULL, 0) < 0) + goto err; + } + } + break; + } + case FUNCTIONFS_ENABLE: + pthread_mutex_lock(&ctx->mutex); + ctx->enabled = 1; + pthread_mutex_unlock(&ctx->mutex); + pthread_cond_signal(&ctx->ready); + break; + case FUNCTIONFS_DISABLE: + case FUNCTIONFS_BIND: + case FUNCTIONFS_UNBIND: + default: + /* do nothing */ + break; + } + } +err: + fprintf(stderr, "Error occurs while handling ep0 event"); + return NULL; +} + +static int usb_setup_ffs_daemon(struct usb_context *ctx) +{ + char *ep_path; + int *ep = ctx->eps; + int ep_path_len = strlen(TFMFFS_PATH) + 4 /* "/ep#" */ + 1 /* '\0' */; + int i, ret; + + ep_path = malloc(ep_path_len); + if (!ep_path) + return -ENOMEM; + + snprintf(ep_path, ep_path_len, TFMFFS_PATH"/ep%d", TFMFFS_EP0); + + ep[TFMFFS_EP0] = open(ep_path, O_RDWR); + if (ep[TFMFFS_EP0] < 0) { + fprintf(stderr, "failed to open ffs ep0\n"); + ret = -ENOENT; + goto err_free; + } + + if (write(ep[TFMFFS_EP0], &descriptors, sizeof(descriptors)) < 0) { + fprintf(stderr, "failed to write descriptors\n"); + ret = -EIO; + goto err_close; + } + if (write(ep[TFMFFS_EP0], &strings, sizeof(strings)) < 0) { + fprintf(stderr, "failed to write strings\n"); + ret = -EIO; + goto err_close; + } + + for (i = 1; i < TFMFFS_EP_MAX; i++) { + snprintf(ep_path, ep_path_len, TFMFFS_PATH"/ep%d", i); + + ep[i] = open(ep_path, O_RDWR); + if (ep[i] < 0) { + fprintf(stderr, "failed to open ffs ep%d\n", i); + /* close opened endpoints */ + for (i -= 1; i >= 1; i--) + close(ep[i]); + ret = -EIO; + goto err_close; + } + } + + pthread_mutex_init(&ctx->mutex, NULL); + pthread_cond_init(&ctx->ready, NULL); + + pthread_create(&ctx->ep0_thread, NULL, ep0_handler, ctx); + pthread_detach(ctx->ep0_thread); + + free(ep_path); + + return 0; + +err_close: + close(ep[TFMFFS_EP0]); + +err_free: + free(ep_path); + + return ret; +} + +static void usb_cleanup_ffs_daemon(struct usb_context *ctx) +{ + int *ep = ctx->eps; + + pthread_cancel(ctx->ep0_thread); + close(ep[TFMFFS_EP0]); +} + +static int mount_ffs(void) +{ + int ret; + + ret = mkdir(TFMFFS_PATH, 0770); + if (ret < 0) { + fprintf(stderr, "Failed to create ffs directory\n"); + return ret; + } + + ret = mount("tfm", TFMFFS_PATH, "functionfs", 0, NULL); + if (ret < 0) { + fprintf(stderr, "Failed to mount ffs function\n"); + rmdir(TFMFFS_PATH); + } + + return ret; +} + +static void umount_ffs(void) +{ + umount(TFMFFS_PATH); + rmdir(TFMFFS_PATH); +} + +static int usb_connect(struct tfm_interface *intf) +{ + struct usb_context *ctx; + usbg_state *s; + usbg_gadget *g; + usbg_config *c; + usbg_function *f; + int ret; + + ctx = (struct usb_context *)malloc(sizeof(*ctx)); + if (!ctx) + return -ENOMEM; + + ret = usbg_init("/sys/kernel/config", &s); + if (ret < 0) { + fprintf(stderr, "Failed to init USB gadget\n"); + goto err_freectx; + } + + ret = usbg_create_gadget(s, TFMFFS_GADGET, &g_attrs, &g_strs, &g); + if (ret < 0) { + fprintf(stderr, "Failed to create USB gadget\n"); + goto err_cleanup; + } + + 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; + } + + 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; + } + + ret = usbg_add_config_function(c, TFMFFS_BIND_LINK, f); + if (ret < 0) { + fprintf(stderr, "Failed to bind USB function\n"); + goto err_cleanup; + } + + if (mount_ffs() < 0) { + fprintf(stderr, "Failed to mount functionfs\n"); + goto err_cleanup; + } + + if (usb_setup_ffs_daemon(ctx) < 0) { + fprintf(stderr, "Failed to setup ffs daemon\n"); + goto err_umount; + } + + ret = usbg_enable_gadget(g, DEFAULT_UDC); + if (ret < 0) { + fprintf(stderr, "Failed to enable USB gadget\n"); + goto err_ffs; + } + + pthread_mutex_lock(&ctx->mutex); + while (!ctx->enabled) + pthread_cond_wait(&ctx->ready, &ctx->mutex); + pthread_mutex_unlock(&ctx->mutex); + + ctx->usbg = s; + + intf->txd = ctx->eps[TFMFFS_EP_BULK_IN]; + intf->rxd = ctx->eps[TFMFFS_EP_BULK_OUT]; + intf->priv = (void *)ctx; + + return 0; + +err_ffs: + usb_cleanup_ffs_daemon(ctx); + +err_umount: + umount_ffs(); + +err_cleanup: + usbg_cleanup(s); + +err_freectx: + free(ctx); + + return -EINVAL; +} + +static int usb_disconnect(struct tfm_interface *intf) +{ + struct usb_context *ctx = intf->priv; + int *ep = ctx->eps; + int i; + + for (i = 1; i < TFMFFS_EP_MAX; i++) + close(ep[i]); + + usb_cleanup_ffs_daemon(ctx); + umount_ffs(); + if (ctx->usbg) + usbg_cleanup(ctx->usbg); + + return 0; +} + +static struct tfm_interface_driver usb = { + .name = "usb", + .ops = { + .connect = usb_connect, + .disconnect = usb_disconnect, + .rx_data = usb_rx_data, + .tx_data = usb_tx_data, + }, +}; +INTERFACE_REGISTER(usb) -- 2.7.4 From fb90bcce4ebf630e81f026a394206f2582ea622a Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:55:56 +0900 Subject: [PATCH 07/16] interface: Choose interface after thor handshake To prevent that interface blocks other connection before host actually start transferring, connected interface is selected after handshake is done. Change-Id: I6b8587898b4dae83ffeb9e4330d379fa723e98d1 Signed-off-by: Dongwoo Lee --- src/interface.c | 14 ++++++++++++++ src/main.c | 6 ------ src/thor.c | 12 +----------- src/thor.h | 2 +- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/interface.c b/src/interface.c index 69d2084..027a3fc 100644 --- a/src/interface.c +++ b/src/interface.c @@ -22,6 +22,7 @@ #include #include "interface.h" +#include "thor.h" struct tfm_interface_context { struct tfm_interface *connected; @@ -96,6 +97,19 @@ static void *connect_thread_main(void *ptr) return NULL; } + fprintf(stdout, "interface %s is ready.\n", intf->name); + + /* + * Each interface can handshake at the same time, but only one + * interface is used for flash to prevent data corruption. + */ + ret = thor_handshake(intf); + if (ret < 0) { + fprintf(stderr, "failed to handshake: %s\n", intf->name); + intf->ops->disconnect(intf); + return NULL; + } + pthread_mutex_lock(&ictx->mutex); if (ictx->connected) { pthread_mutex_unlock(&ictx->mutex); diff --git a/src/main.c b/src/main.c index 0281c30..7737e5e 100644 --- a/src/main.c +++ b/src/main.c @@ -100,12 +100,6 @@ int _main(int argc, char *argv[]) goto out_dfuexit; } - ret = thor_setup(intf); - if (ret < 0) { - ret = -1; - goto out_disconn; - } - ret = thor_process(intf, dfu); if (ret < 0) { ret = -1; diff --git a/src/thor.c b/src/thor.c index 6cb6984..ea8918e 100644 --- a/src/thor.c +++ b/src/thor.c @@ -319,7 +319,7 @@ static int thor_do_request(struct thor_context *tctx) return ret; } -static int thor_handshake(struct tfm_interface *intf) +int thor_handshake(struct tfm_interface *intf) { char buf[5]; ssize_t n; @@ -370,13 +370,3 @@ int thor_process(struct tfm_interface *intf, struct dfu_context *dfu) return 0; } - -int thor_setup(struct tfm_interface *intf) -{ - if (!intf) { - fprintf(stderr, "Invalid connection\n"); - return -EINVAL; - } - - return thor_handshake(intf); -} diff --git a/src/thor.h b/src/thor.h index 7a88006..c24fcc5 100644 --- a/src/thor.h +++ b/src/thor.h @@ -20,6 +20,6 @@ #include "dfu.h" #include "interface.h" -int thor_setup(struct tfm_interface *intf); +int thor_handshake(struct tfm_interface *intf); int thor_process(struct tfm_interface *intf, struct dfu_context *dfu); #endif -- 2.7.4 From 951986d4deb9524f2358b238d161e0b740b34bdc Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:56:36 +0900 Subject: [PATCH 08/16] thor: Use smaller flash unit size Large size of flash unit causes timeout for such interface which has request timeout by making fsync takes very long time. To prevent this, use smaller size of flash unit, and transfer unit is also adjusted. Change-Id: Ib45f20855dad4cef18e02410e9d976022cfc1597 Signed-off-by: Dongwoo Lee --- src/thor-proto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/thor-proto.h b/src/thor-proto.h index c26aefd..04cefbe 100644 --- a/src/thor-proto.h +++ b/src/thor-proto.h @@ -92,8 +92,8 @@ struct data_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 */ +#define DATA_PKT_SIZE 0x00040000 /* 256 KiB */ +#define FLASH_UNIT_SIZE 0x00100000 /* 1 MiB */ #endif /* __THOR_PROTO_H__ */ -- 2.7.4 From c7ba9c8fc76ea7a329d66ebc5da9db12d1db61da Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Tue, 17 Mar 2020 13:56:20 +0900 Subject: [PATCH 09/16] dfu: Limit maximum length of io queue To prevent timeout due to fsync, the maximum length of io queue is limited. Transfer may be blocked until the previous request is fsync'ed, but it is not harmful to overall performance since fsync is bottleneck; even transfer is faster, flashing time is not reduced because elapsed time is mostly consumed in fsync. Change-Id: I8b59c175eb8065f388487249c9e7f3ef1dbab5b6 Signed-off-by: Dongwoo Lee --- src/dfu.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 4ae9145..0d481cb 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -38,6 +38,8 @@ #define DFU_INFO_MODE_PARTITION 'p' #define DFU_INFO_MODE_FILE 'f' +#define DFU_IOQ_MAXLEN 5 + enum dfu_entry_attr { DFU_INFO_MODE = 0, DFU_INFO_PARTITION, @@ -66,6 +68,7 @@ struct dfu_context { pthread_cond_t write_done; pthread_cond_t sync_done; TAILQ_HEAD(tailhead, dfu_frame) ioq; + int ioq_len; char *dfu_entry_list[DFU_ENTRY_LIST_MAXLEN][DFU_INFO_MAX]; }; @@ -119,13 +122,19 @@ int dfu_request_io(struct dfu_entry *e, void *buffer, unsigned long len) frame->buf = buffer; frame->len = len; +retry: pthread_mutex_lock(&ctx->mutex); - - if (TAILQ_EMPTY(&ctx->ioq)) + if (TAILQ_EMPTY(&ctx->ioq)) { notify = 1; + } else if (ctx->ioq_len >= DFU_IOQ_MAXLEN) { + pthread_mutex_unlock(&ctx->mutex); + usleep(1000); + goto retry; + } /* dfu_thread_main() de-queues i/o request and processes it */ TAILQ_INSERT_TAIL(&ctx->ioq, frame, entry); + ctx->ioq_len++; pthread_mutex_unlock(&ctx->mutex); @@ -255,20 +264,15 @@ static void *dfu_thread_main(void *ptr) state = DFU_THREAD_STATE_IDLE; pthread_cond_wait(&ctx->data_arrived, &ctx->mutex); } + frame = TAILQ_FIRST(&ctx->ioq); + pthread_mutex_unlock(&ctx->mutex); if (state == DFU_THREAD_STATE_IDLE) { state = DFU_THREAD_STATE_FLASHING; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); } - frame = TAILQ_FIRST(&ctx->ioq); - - TAILQ_REMOVE(&ctx->ioq, frame, entry); - - pthread_mutex_unlock(&ctx->mutex); - ret = write(e->fd, frame->buf, frame->len); - if (ret < frame->len) { fprintf(stderr, "Error occurs while flashing\n"); state = DFU_THREAD_STATE_ERROR; @@ -276,6 +280,13 @@ static void *dfu_thread_main(void *ptr) progress += frame->len; + fsync(e->fd); + + pthread_mutex_lock(&ctx->mutex); + TAILQ_REMOVE(&ctx->ioq, frame, entry); + ctx->ioq_len--; + pthread_mutex_unlock(&ctx->mutex); + fprintf(stdout, "#"); fflush(stdout); @@ -409,18 +420,10 @@ void dfu_sync(struct dfu_entry *e) pthread_cond_wait(&ctx->write_done, &ctx->sync_mutex); pthread_mutex_unlock(&ctx->sync_mutex); - switch (*info[DFU_INFO_MODE]) { - case DFU_INFO_MODE_FILE: - fsync(e->fd); - close(e->fd); + close(e->fd); + + if (*info[DFU_INFO_MODE] == DFU_INFO_MODE_FILE) umount_dev(); - break; - case DFU_INFO_MODE_PARTITION: - close(e->fd); - break; - default: - break; - } pthread_cond_signal(&ctx->sync_done); @@ -501,6 +504,7 @@ struct dfu_context *dfu_alloc_context(void) ctx->thread = 0; TAILQ_INIT(&ctx->ioq); + ctx->ioq_len = 0; pthread_mutex_init(&ctx->mutex, NULL); pthread_mutex_init(&ctx->sync_mutex, NULL); -- 2.7.4 From cb294243117aaf821729ca2296b04de11dd1f324 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 19 Mar 2020 17:24:09 +0900 Subject: [PATCH 10/16] usb: Fix possible vulnerability Since the return value of read operation is not checked properly, it can be the target of attack by buffer overflows. To prevent this, return values will be treated. Change-Id: I702b64fb4f77b7cc507a519952c11f41813cf0a2 Signed-off-by: Dongwoo Lee --- src/usb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/usb.c b/src/usb.c index f7920bb..f927b01 100644 --- a/src/usb.c +++ b/src/usb.c @@ -210,6 +210,7 @@ static void *ep0_handler(void *data) struct usb_context *ctx = data; struct usb_functionfs_event evt; int ret, ep0 = ctx->eps[TFMFFS_EP0]; + ssize_t sz; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); @@ -238,7 +239,8 @@ static void *ep0_handler(void *data) if (!buf) goto err; - if (read(ep0, buf, value) < 0) { + sz = read(ep0, buf, value); + if (sz < 0) { free(buf); goto err; } @@ -249,12 +251,14 @@ static void *ep0_handler(void *data) { int buf; - if (read(ep0, &buf, sizeof(buf)) < 0) + sz = read(ep0, &buf, sizeof(buf)); + if (sz < 0) goto err; break; } default: - if (read(ep0, NULL, 0) < 0) + sz = read(ep0, NULL, 0); + if (sz < 0) goto err; } } -- 2.7.4 From bbb15fb2744657d4b51682655c57f8b5d6bb09fc Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 18 Mar 2020 12:31:39 +0900 Subject: [PATCH 11/16] interface: Introduce operation for checking availability Because there is no need to setup interface not supported by target, check availability of interface and ignore the target which is not available. Since this, the interface not providing available function will be also ignored. Change-Id: Ic7cf11e2d46bd6b979cc02a87cb392cfb04ed399 Signed-off-by: Dongwoo Lee --- src/interface.c | 11 +++++++++++ src/interface.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/interface.c b/src/interface.c index 027a3fc..103b749 100644 --- a/src/interface.c +++ b/src/interface.c @@ -201,6 +201,17 @@ struct tfm_interface_context *tfm_interface_init(void) LIST_FOREACH(driver, &interface_avail_list, entry) { struct tfm_interface *intf; + if (!driver->ops.available) { + fprintf(stderr, + "Cannot check availability for interface %s.\n", + driver->name); + continue; + } + + /* Ignore not supported interface */ + if (!driver->ops.available()) + continue; + intf = (struct tfm_interface *)malloc(sizeof(*intf)); if (!intf) goto err; diff --git a/src/interface.h b/src/interface.h index 7bb9c02..c908c1a 100644 --- a/src/interface.h +++ b/src/interface.h @@ -37,6 +37,7 @@ struct tfm_interface_ops { int (*disconnect)(struct tfm_interface *intf); ssize_t (*rx_data)(int fd, void *buf, ssize_t len); ssize_t (*tx_data)(int fd, void *buf, ssize_t len); + int (*available)(void); }; struct tfm_interface_driver { -- 2.7.4 From 95294064b645905641e30e9b0ea0de96a0b95bfd Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 18 Mar 2020 12:32:08 +0900 Subject: [PATCH 12/16] net: Add check availability If the target has NIC named eth0 or wlan0, then it considers that network is available. Change-Id: I6cb0bc48a9bb8154a8d02fd183db105554ea9862 Signed-off-by: Dongwoo Lee --- src/net.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/net.c b/src/net.c index 6cd8587..e4da0ca 100644 --- a/src/net.c +++ b/src/net.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "interface.h" @@ -96,6 +98,33 @@ static int net_disconnect(struct tfm_interface *intf) return close(intf->rxd); } +static int net_available(void) +{ + struct ifaddrs *ifs, *cur; + char host[NI_MAXHOST]; + int ret, s; + + ret = getifaddrs(&ifs); + if (ret < 0) + return 0; + + /* + * TODO: + * On RPI-family targets it works well checking network availabilty + * via presence of NIC 'eth0' or 'wlan0', but it looks quite hack + * anyway. So, it should be changed if there is more generic way. + */ + for (cur = ifs; cur != NULL; cur = cur->ifa_next) { + if (!strcmp(cur->ifa_name, "eth0")) + return 1; + + if (!strcmp(cur->ifa_name, "wlan0")) + return 1; + } + + return 0; +} + static struct tfm_interface_driver network = { .name = "net", .ops = { @@ -103,6 +132,7 @@ static struct tfm_interface_driver network = { .disconnect = net_disconnect, .rx_data = net_rx_data, .tx_data = net_tx_data, + .available = net_available, }, }; INTERFACE_REGISTER(network) -- 2.7.4 From b41943b05701e54fa7246bd763c9b7994529dbf8 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 18 Mar 2020 12:32:20 +0900 Subject: [PATCH 13/16] usb: Add check availability If the target can be configured by usb configfs gadget, then it considers that the target supports usb interface. Change-Id: Ief17152a655b5e0eae11db8fbb8f8ca93feec653 Signed-off-by: Dongwoo Lee --- src/usb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/usb.c b/src/usb.c index f927b01..606a2a7 100644 --- a/src/usb.c +++ b/src/usb.c @@ -484,6 +484,11 @@ static int usb_disconnect(struct tfm_interface *intf) return 0; } +static int usb_available(void) +{ + return !access("/sys/kernel/config/usb_gadget/", F_OK); +} + static struct tfm_interface_driver usb = { .name = "usb", .ops = { @@ -491,6 +496,7 @@ static struct tfm_interface_driver usb = { .disconnect = usb_disconnect, .rx_data = usb_rx_data, .tx_data = usb_tx_data, + .available = usb_available, }, }; INTERFACE_REGISTER(usb) -- 2.7.4 From d61c0dcce3948fce7354491f4d84e21ec8d15361 Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Thu, 19 Mar 2020 13:45:10 +0900 Subject: [PATCH 14/16] tfm: Add wireless connection support for RPI4 The nvram files for RPI4 and RPI3+ wifi chipset have a little difference contents but name is identical. To deal with this, the target is identified through sysfs node and the correct nvram is selected by result. In addition, now tfm shows ssid including serial number. Change-Id: I7122574b09155cbd27ccf1c35c2cdcabe528864a Signed-off-by: Dongwoo Lee --- ...mfmac43455-sdio.raspberrypi,3-model-b-plus.txt} | 0 data/brcmfmac43455-sdio.raspberrypi,4-model-b.txt | 82 ++++++++++++++++++++++ data/hostapd.conf | 2 +- scripts/41-flash.list | 1 + scripts/flash-init.sh | 39 +++++++++- 5 files changed, 122 insertions(+), 2 deletions(-) rename data/{brcmfmac43455-sdio.txt => brcmfmac43455-sdio.raspberrypi,3-model-b-plus.txt} (100%) create mode 100644 data/brcmfmac43455-sdio.raspberrypi,4-model-b.txt diff --git a/data/brcmfmac43455-sdio.txt b/data/brcmfmac43455-sdio.raspberrypi,3-model-b-plus.txt similarity index 100% rename from data/brcmfmac43455-sdio.txt rename to data/brcmfmac43455-sdio.raspberrypi,3-model-b-plus.txt diff --git a/data/brcmfmac43455-sdio.raspberrypi,4-model-b.txt b/data/brcmfmac43455-sdio.raspberrypi,4-model-b.txt new file mode 100644 index 0000000..425d293 --- /dev/null +++ b/data/brcmfmac43455-sdio.raspberrypi,4-model-b.txt @@ -0,0 +1,82 @@ +# SPDX-License-Identifier: GPL-2.0+ +# (C) Copyright 2018 Raspberry Pi (Trading) Ltd. +# NVRAM config file for the BCM43455 WiFi/BT chip as found on the +# Raspberry Pi 4 Model B +aa2g=1 +aa5g=1 +AvVmid_c0=1,165,2,100,2,100,2,100,2,100 +boardflags=0x00480201 +boardflags2=0x40800000 +boardflags3=0x44200100 +boardrev=0x1304 +boardtype=0x6e4 +btc_mode=1 +btc_params1=0x7530 +btc_params8=0x4e20 +cbfilttype=1 +cckPwrIdxCorr=3 +cckTssiDelay=150 +deadman_to=481500000 +devid=0x43ab +dot11agofdmhrbw202gpo=0x4442 +dot11b_opts=0x3aa85 +ed_thresh2g=-54 +ed_thresh5g=-54 +eu_edthresh2g=-54 +eu_edthresh5g=-54 +extpagain2g=2 +extpagain5g=2 +fdsslevel_ch11=6 +femctrl=0 +itrsw=1 +ldo1=4 +ltecxfnsel=0x22 +ltecxgcigpio=0x32 +ltecxmux=0 +ltecxpadnum=0x0504 +macaddr=b8:27:eb:74:f2:6c +manfid=0x2d0 +maxp2ga0=80 +maxp5ga0=82,82,82,82 +mcsbw202gpo=0x98444422 +mcsbw205ghpo=0xb9555000 +mcsbw205glpo=0xb9555000 +mcsbw205gmpo=0xb9555000 +mcsbw402gpo=0x98444422 +mcsbw405ghpo=0xb9555000 +mcsbw405glpo=0xb9555000 +mcsbw405gmpo=0xb9555000 +mcsbw805ghpo=0xb9555000 +mcsbw805glpo=0xb9555000 +mcsbw805gmpo=0xb9555000 +nocrc=1 +ofdmlrbw202gpo=0x0022 +ofdmTssiDelay=150 +pa2ga0=-129,6525,-718 +pa2ga1=-149,4408,-601 +pa5ga0=-185,6836,-815,-186,6838,-815,-184,6859,-815,-184,6882,-818 +pa5ga1=-202,4285,-574,-201,4312,-578,-196,4391,-586,-201,4294,-575 +pdoffset2g40ma0=16 +pdoffset2gperchan=0,-2,1,0,1,0,1,1,1,0,0,-1,-1,0 +pdoffset40ma0=0x8888 +pdoffset80ma0=0x8888 +pdoffsetcckma0=2 +phycal_tempdelta=15 +prodid=0x06e4 +rawtempsense=0x1ff +rxchain=1 +sromrev=11 +swctrlmap_2g=0x00000000,0x00000000,0x00000000,0x010000,0x3ff +swctrlmap_5g=0x00100010,0x00200020,0x00200020,0x010000,0x3fe +swctrlmapext_2g=0x00000000,0x00000000,0x00000000,0x000000,0x3 +swctrlmapext_5g=0x00000000,0x00000000,0x00000000,0x000000,0x3 +tssipos2g=1 +tssipos5g=1 +tworangetssi2g=1 +tworangetssi5g=1 +txchain=1 +txpwr2gAdcScale=1 +txpwr5gAdcScale=1 +vcodivmode=1 +vendid=0x14e4 +xtalfreq=37400 diff --git a/data/hostapd.conf b/data/hostapd.conf index 80cefcd..133fb81 100644 --- a/data/hostapd.conf +++ b/data/hostapd.conf @@ -1,6 +1,6 @@ interface=wlan0 driver=nl80211 -ssid=TIZEN_RPI3 +ssid= channel=6 ignore_broadcast_ssid=0 hw_mode=g diff --git a/scripts/41-flash.list b/scripts/41-flash.list index c9c2611..834fe76 100755 --- a/scripts/41-flash.list +++ b/scripts/41-flash.list @@ -27,6 +27,7 @@ WITHLIBS=" /bin/hostapd /bin/dnsmasq /bin/ln +/bin/sed " # LinkFileName:Target diff --git a/scripts/flash-init.sh b/scripts/flash-init.sh index 6473dd7..33c1f8e 100755 --- a/scripts/flash-init.sh +++ b/scripts/flash-init.sh @@ -21,6 +21,7 @@ INSMOD="/usr/sbin/insmod" DNSMASQ="/usr/bin/dnsmasq" HOSTAPD="/usr/bin/hostapd" LINK="/usr/bin/ln" +SED="/usr/bin/sed" NETIF="eth0" WLANIF="wlan0" @@ -49,6 +50,36 @@ setup_usb() { fi } +#------------------------------------------------ +# Identify the target and prepare firmwares +#------------------------------------------------ +prepare_wireless() { + MODEL=$(cat /sys/firmware/devicetree/base/model) + + if [[ $MODEL == *"Raspberry"* ]]; then + FIRM_DIR="/lib/firmware/brcm" + + if [ "$MODEL" = "Raspberry Pi 4 Model B" ]; then + COMPAT="raspberrypi,4-model-b" + FIRMWARE="brcmfmac43455-sdio" + BOARD_TYPE="RPI4" + elif [ "$MODEL" = "Raspberry Pi 3 Model B+" ]; then + COMPAT="raspberrypi,3-model-b-plus" + FIRMWARE="brcmfmac43455-sdio" + BOARD_TYPE="RPI3+" + elif [ "$MODEL" = "Raspberry Pi 3 Model B" ]; then + BOARD_TYPE="RPI3" + fi + + if [ -n "$COMPAT" ]; then + $LINK -s ${FIRM_DIR}/${FIRMWARE}.${COMPAT}.txt ${FIRM_DIR}/${FIRMWARE}.txt + fi + SERIAL=$(cat /sys/firmware/devicetree/base/serial-number) + else + SERIAL="" + BOARD_TYPE="BOARD" + fi +} #------------------------------------------------ # Copy Module and Firmware file @@ -68,6 +99,9 @@ setup_wireless() { $COPY $BRCMUTIL /lib/firmware/brcm/ $SYNC $UMOUNT ${TMP_PATH} + + prepare_wireless + $INSMOD /lib/firmware/brcm/brcmutil.ko sleep 1 $INSMOD /lib/firmware/brcm/brcmfmac.ko @@ -77,7 +111,10 @@ setup_wireless() { $IFCONFIG $WLANIF ${WLANIP} up $DNSMASQ -p 0 -9 -C /lib/firmware/brcm/dnsmasq.conf - SSID=`$HOSTAPD -B /lib/firmware/brcm/hostapd.conf | "$GREP" -oP '(?<=ssid\s\")(.*?)(?=\")'` + SSID="TIZEN_${BOARD_TYPE}_${SERIAL}" + + $SED -i "s/ssid=/ssid=${SSID}/g" /lib/firmware/brcm/hostapd.conf + $HOSTAPD -B /lib/firmware/brcm/hostapd.conf > /dev/null else echo "There is no module partition" WLANIP="N/A" -- 2.7.4 From 2e3ea0b7b9551379a90460f9df8deb616f23517a Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 25 Mar 2020 11:39:05 +0900 Subject: [PATCH 15/16] dfu: Use longer delay for waiting queue available By recommend of static analysis tool, sleep time for waiting queue become available will be expanded to 10000us. Change-Id: I5ace690d1f6826234fad89489c9617a046456f8c Signed-off-by: Dongwoo Lee --- src/dfu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dfu.c b/src/dfu.c index 0d481cb..acb8887 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -128,7 +128,7 @@ retry: notify = 1; } else if (ctx->ioq_len >= DFU_IOQ_MAXLEN) { pthread_mutex_unlock(&ctx->mutex); - usleep(1000); + usleep(10000); goto retry; } -- 2.7.4 From d0d02c0cde0559f71d67fbd2d0cb8316fe13a42f Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Fri, 27 Mar 2020 16:11:44 +0900 Subject: [PATCH 16/16] dfu: Fix possible wrong memory access Currently, dfu context is assigned after thread creation, tfm can be died due to wrong memory access if thread is scheduled in advance. This fixes this by assigning ctx before thread creation. Change-Id: I44f86223b90d6dac537699369a478d4cdb7829c2 Signed-off-by: Dongwoo Lee --- src/dfu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index acb8887..c33c286 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -400,13 +400,12 @@ struct dfu_entry *dfu_start(struct dfu_context *ctx, return NULL; } - pthread_create(&ctx->thread, NULL, dfu_thread_main, e); - - e->ctx = ctx; - fprintf(stdout, "Start download: %s...", filename); fflush(stdout); + e->ctx = ctx; + pthread_create(&ctx->thread, NULL, dfu_thread_main, e); + return e; } -- 2.7.4