2 * flash-manager - Tizen kernel-level image flashing solution
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <sys/types.h>
24 #include <sys/queue.h>
26 #include <sys/fcntl.h>
27 #include <sys/mount.h>
29 #include <blkid/blkid.h>
32 #include "thor-proto.h"
34 static char *dfu_info[DFU_INFO_NUM][DFU_INFO_MAX] = {NULL,};
36 void *dfu_get_buffer(unsigned long size)
38 int wait = 100000; /* 100ms */
41 while (!(buf = malloc(size))) {
43 * In the case of not enough memory, instead of returning error,
44 * transfer thread waits until dfu writes and frees buffers.
53 void dfu_put_buffer(void *ptr)
58 static int find_match(const char *name)
62 for (i = 0; i < DFU_INFO_NUM; i++) {
63 char *entry = dfu_info[i][DFU_INFO_NAME];
65 if (entry && !strncmp(entry, name, strlen(entry)))
72 int dfu_request_io(struct tfm_context *ctx, unsigned long len)
75 struct dfu_frame *frame;
77 frame = malloc(sizeof(*frame));
81 frame->buf = ctx->transfer_buffer;
84 pthread_mutex_lock(&ctx->dfu_mutex);
86 if (TAILQ_EMPTY(&ctx->dfu_ioq_head))
89 /* dfu_thread_main() de-queues i/o request and processes it */
90 TAILQ_INSERT_TAIL(&ctx->dfu_ioq_head, frame, entry);
92 pthread_mutex_unlock(&ctx->dfu_mutex);
95 pthread_cond_signal(&ctx->dfu_data_arrive);
100 static void mount_dev(const char *dev, const char *fstype)
104 ret = mkdir(DFU_MOUNT_PATH, 0600);
106 fprintf(stderr, "Failed to create target directory\n");
110 ret = mount(dev, DFU_MOUNT_PATH, fstype, 0, NULL);
112 fprintf(stderr, "Failed to mount target partition\n");
113 rmdir(DFU_MOUNT_PATH);
118 static void umount_dev(void)
122 ret = umount(DFU_MOUNT_PATH);
124 fprintf(stderr, "Failed to mount target partition\n");
126 /* umount is failed, but anyway try to delete mount point */
127 rmdir(DFU_MOUNT_PATH);
131 rmdir(DFU_MOUNT_PATH);
134 void dfu_sync(struct tfm_context *ctx)
136 char **info = ctx->dfu_info;
138 pthread_mutex_lock(&ctx->dfu_sync_mutex);
139 if (!ctx->transfer_done)
140 pthread_cond_wait(&ctx->dfu_write_done, &ctx->dfu_sync_mutex);
141 pthread_mutex_unlock(&ctx->dfu_sync_mutex);
143 switch (*info[DFU_INFO_MODE]) {
144 case DFU_INFO_MODE_FILE:
149 case DFU_INFO_MODE_PARTITION:
156 pthread_cond_signal(&ctx->dfu_sync_done);
158 fprintf(stdout, "finished\n");
161 static char *get_partition_fstype(const char *devname)
163 blkid_tag_iterate tag_iter;
165 blkid_cache cache = NULL;
166 const char *type, *value;
169 ret = blkid_get_cache(&cache, NULL);
173 blkid_probe_all(cache);
175 dev = blkid_get_dev(cache, devname, 0);
179 dev = blkid_verify(cache, dev);
183 tag_iter = blkid_tag_iterate_begin(dev);
184 while (blkid_tag_next(tag_iter, &type, &value) == 0) {
185 if (!strncmp(type, "TYPE", 4)) {
186 char *fstype = strdup(value);
188 blkid_tag_iterate_end(tag_iter);
189 blkid_put_cache(cache);
193 blkid_tag_iterate_end(tag_iter);
194 blkid_put_cache(cache);
199 static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size)
201 char **info = dfu_info[idx];
205 switch (*info[DFU_INFO_MODE]) {
206 case DFU_INFO_MODE_PARTITION:
207 file = strdup(info[DFU_INFO_PARTITION]);
211 case DFU_INFO_MODE_FILE:
213 int path_prefix = strlen(DFU_MOUNT_PATH);
214 int path_suffix = strlen(info[DFU_INFO_PATH]);
215 int path_name = strlen(info[DFU_INFO_NAME]);
218 fstype = get_partition_fstype(info[DFU_INFO_PARTITION]);
220 fprintf(stderr, "failed to get partition filesystem type: %s", info[DFU_INFO_PARTITION]);
224 mount_dev(info[DFU_INFO_PARTITION], fstype);
227 file = malloc(path_prefix + path_suffix + path_name + 1);
231 strncpy(file, DFU_MOUNT_PATH, path_prefix + 1);
232 strncat(file, info[DFU_INFO_PATH], path_suffix);
233 strncat(file, info[DFU_INFO_NAME], path_name);
237 fprintf(stderr, "flash entry '%s' has wrong mode\n", info[DFU_INFO_NAME]);
241 fd = open(file, O_WRONLY);
243 fprintf(stderr, "cannot open target: %s\n", info[DFU_INFO_NAME]);
250 ctx->dfu_info = info;
251 ctx->transfer_done = 0;
258 int dfu_start(struct tfm_context *ctx, const char *entity)
260 unsigned long size = ctx->thor_file_size;
263 idx = find_match(entity);
265 fprintf(stderr, "Cannot find dfu info for %s\n", entity);
269 ret = dfu_start_entity(ctx, idx, size);
271 fprintf(stderr, "Cannot start download: %s\n", entity);
275 fprintf(stdout, "Start download: %s...", entity);
280 static void dfu_thread_cleanup(void *ptr)
282 struct tfm_context *ctx = ptr;
283 struct dfu_frame *frame;
285 while (!TAILQ_EMPTY(&ctx->dfu_ioq_head)) {
286 frame = TAILQ_FIRST(&ctx->dfu_ioq_head);
288 TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry);
290 dfu_put_buffer(frame->buf);
295 static void *dfu_thread_main(void *ptr)
297 struct tfm_context *ctx = ptr;
298 struct dfu_frame *frame;
299 int state = DFU_THREAD_STATE_IDLE;
300 uint64_t progress = 0;
303 pthread_cleanup_push(dfu_thread_cleanup, ptr);
305 while (state != DFU_THREAD_STATE_ERROR) {
306 pthread_mutex_lock(&ctx->dfu_mutex);
308 while (TAILQ_EMPTY(&ctx->dfu_ioq_head)) {
309 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
310 pthread_cond_wait(&ctx->dfu_data_arrive, &ctx->dfu_mutex);
313 if (state == DFU_THREAD_STATE_IDLE) {
314 pthread_mutex_unlock(&ctx->dfu_mutex);
315 state = DFU_THREAD_STATE_FLASHING;
316 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
317 pthread_mutex_lock(&ctx->dfu_mutex);
320 frame = TAILQ_FIRST(&ctx->dfu_ioq_head);
322 TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry);
324 pthread_mutex_unlock(&ctx->dfu_mutex);
326 ret = write(ctx->dfu_fd, frame->buf, frame->len);
328 if (ret < frame->len) {
329 fprintf(stdout, "Error occurs while flashing\n");
330 state = DFU_THREAD_STATE_ERROR;
333 progress += frame->len;
335 dfu_put_buffer(frame->buf);
338 /* transfer finished */
339 if (state != DFU_THREAD_STATE_ERROR && progress >= ctx->thor_file_size) {
341 ctx->transfer_done = 1;
343 state = DFU_THREAD_STATE_IDLE;
344 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
346 pthread_cond_signal(&ctx->dfu_write_done);
348 pthread_mutex_lock(&ctx->dfu_sync_mutex);
349 pthread_cond_wait(&ctx->dfu_sync_done,
350 &ctx->dfu_sync_mutex);
351 pthread_mutex_unlock(&ctx->dfu_sync_mutex);
355 pthread_cleanup_pop(1);
360 static int parse_dfu_info(char *buf, char **info)
365 for (i = 0; i < DFU_INFO_MAX; i++) {
366 ptr = strsep(&buf, DFU_DELIMITER);
370 info[i] = strdup(ptr);
378 static void destroy_dfu_info(void)
382 for (i = 0; i < DFU_INFO_NUM; i++) {
383 for (j = 0; j < DFU_INFO_MAX; j++)
384 if (dfu_info[i][j]) {
385 free(dfu_info[i][j]);
386 dfu_info[i][j] = NULL;
392 static int init_dfu_info(const char *dfu_info_file)
399 fp = fopen(dfu_info_file, "r");
403 while (i < DFU_INFO_NUM && !feof(fp)) {
404 if (fgets(buf, 1024, fp) == NULL)
407 ret = parse_dfu_info(buf, dfu_info[i++]);
409 fprintf(stderr, "cannot parse dfu info");
425 int dfu_init(struct tfm_context *ctx, const char *dfu_info_file)
429 ret = init_dfu_info(dfu_info_file);
431 fprintf(stderr, "failed to get flash entries\n");
435 TAILQ_INIT(&ctx->dfu_ioq_head);
437 pthread_mutex_init(&ctx->dfu_mutex, NULL);
438 pthread_mutex_init(&ctx->dfu_sync_mutex, NULL);
439 pthread_cond_init(&ctx->dfu_data_arrive, NULL);
440 pthread_cond_init(&ctx->dfu_write_done, NULL);
441 pthread_cond_init(&ctx->dfu_sync_done, NULL);
443 ret = pthread_create(&ctx->dfu_thread, NULL, dfu_thread_main, ctx);
445 fprintf(stderr, "failed to create thread for dfu\n");
452 void dfu_exit(struct tfm_context *ctx)
454 pthread_cancel(ctx->dfu_thread);
455 pthread_join(ctx->dfu_thread, NULL);