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]) {
156 pthread_cond_signal(&ctx->dfu_sync_done);
158 fprintf(stdout, "finished\n");
161 static char *get_partition_devname(const char *label)
163 blkid_dev_iterate dev_iter;
164 blkid_tag_iterate tag_iter;
166 blkid_cache cache = NULL;
167 const char *type, *value;
170 ret = blkid_get_cache(&cache, NULL);
174 blkid_probe_all(cache);
176 dev_iter = blkid_dev_iterate_begin(cache);
177 blkid_dev_set_search(dev_iter, NULL, NULL);
178 while (blkid_dev_next(dev_iter, &dev) == 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, "LABEL", 5) && !strncmp(value, label, strlen(label))) {
186 char *devname = strdup(blkid_dev_devname(dev));
189 * To distinguish physical partition and ram mounted partition,
190 * continue to search the next entry if the devname includes
191 * 'ram'(eg. /dev/ram0).
193 if (strstr(devname, "ram")) {
198 blkid_tag_iterate_end(tag_iter);
199 blkid_dev_iterate_end(dev_iter);
200 blkid_put_cache(cache);
204 blkid_tag_iterate_end(tag_iter);
206 blkid_dev_iterate_end(dev_iter);
207 blkid_put_cache(cache);
212 static char *get_partition_fstype(const char *devname)
214 blkid_tag_iterate tag_iter;
216 blkid_cache cache = NULL;
217 const char *type, *value;
220 ret = blkid_get_cache(&cache, NULL);
224 blkid_probe_all(cache);
226 dev = blkid_get_dev(cache, devname, 0);
230 dev = blkid_verify(cache, dev);
234 tag_iter = blkid_tag_iterate_begin(dev);
235 while (blkid_tag_next(tag_iter, &type, &value) == 0) {
236 if (!strncmp(type, "TYPE", 4)) {
237 char *fstype = strdup(value);
239 blkid_tag_iterate_end(tag_iter);
240 blkid_put_cache(cache);
244 blkid_tag_iterate_end(tag_iter);
245 blkid_put_cache(cache);
250 static int dfu_start_entity(struct tfm_context *ctx, int idx, unsigned long size)
252 char **info = dfu_info[idx];
256 switch (*info[DFU_INFO_MODE]) {
258 file = get_partition_devname(info[DFU_INFO_LABEL]);
260 fprintf(stderr, "failed to get partition devname: %s", info[DFU_INFO_LABEL]);
266 int path_prefix = strlen(DFU_MOUNT_PATH);
267 int path_suffix = strlen(info[DFU_INFO_PATH]);
268 int path_name = strlen(info[DFU_INFO_NAME]);
269 char *devname, *fstype;
271 devname = get_partition_devname(info[DFU_INFO_LABEL]);
273 fprintf(stderr, "failed to get partition devname: %s", info[DFU_INFO_LABEL]);
277 fstype = get_partition_fstype(devname);
279 fprintf(stderr, "failed to get partition filesystem type: %s", devname);
283 mount_dev(devname, fstype);
287 file = malloc(path_prefix + path_suffix + path_name + 1);
291 strncpy(file, DFU_MOUNT_PATH, path_prefix + 1);
292 strncat(file, info[DFU_INFO_PATH], path_suffix);
293 strncat(file, info[DFU_INFO_NAME], path_name);
297 fprintf(stderr, "flash entry '%s' has wrong mode\n", info[DFU_INFO_NAME]);
301 fd = open(file, O_WRONLY);
303 fprintf(stderr, "cannot open target: %s\n", info[DFU_INFO_NAME]);
310 ctx->dfu_info = info;
311 ctx->transfer_done = 0;
319 int dfu_start(struct tfm_context *ctx, const char *entity)
321 unsigned long size = ctx->thor_file_size;
324 idx = find_match(entity);
326 fprintf(stderr, "Cannot find dfu info for %s\n", entity);
330 ret = dfu_start_entity(ctx, idx, size);
332 fprintf(stderr, "Cannot start download: %s\n", entity);
336 fprintf(stdout, "Start download: %s...", entity);
341 static void dfu_thread_cleanup(void *ptr)
343 struct tfm_context *ctx = ptr;
344 struct dfu_frame *frame;
346 while (!TAILQ_EMPTY(&ctx->dfu_ioq_head)) {
347 frame = TAILQ_FIRST(&ctx->dfu_ioq_head);
349 TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry);
351 dfu_put_buffer(frame->buf);
356 static void *dfu_thread_main(void *ptr)
358 struct tfm_context *ctx = ptr;
359 struct dfu_frame *frame;
360 int state = DFU_THREAD_STATE_IDLE;
361 uint64_t progress = 0;
364 pthread_cleanup_push(dfu_thread_cleanup, ptr);
366 while (state != DFU_THREAD_STATE_ERROR) {
367 pthread_mutex_lock(&ctx->dfu_mutex);
369 while (TAILQ_EMPTY(&ctx->dfu_ioq_head)) {
370 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
371 pthread_cond_wait(&ctx->dfu_data_arrive, &ctx->dfu_mutex);
374 if (state == DFU_THREAD_STATE_IDLE) {
375 pthread_mutex_unlock(&ctx->dfu_mutex);
376 state = DFU_THREAD_STATE_FLASHING;
377 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
378 pthread_mutex_lock(&ctx->dfu_mutex);
381 frame = TAILQ_FIRST(&ctx->dfu_ioq_head);
383 TAILQ_REMOVE(&ctx->dfu_ioq_head, frame, entry);
385 pthread_mutex_unlock(&ctx->dfu_mutex);
387 ret = write(ctx->dfu_fd, frame->buf, frame->len);
389 if (ret < frame->len) {
390 fprintf(stdout, "Error occurs while flashing\n");
391 state = DFU_THREAD_STATE_ERROR;
394 progress += frame->len;
396 dfu_put_buffer(frame->buf);
399 /* transfer finished */
400 if (state != DFU_THREAD_STATE_ERROR && progress >= ctx->thor_file_size) {
402 ctx->transfer_done = 1;
404 state = DFU_THREAD_STATE_IDLE;
405 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
407 pthread_cond_signal(&ctx->dfu_write_done);
409 pthread_mutex_lock(&ctx->dfu_sync_mutex);
410 pthread_cond_wait(&ctx->dfu_sync_done,
411 &ctx->dfu_sync_mutex);
412 pthread_mutex_unlock(&ctx->dfu_sync_mutex);
416 pthread_cleanup_pop(1);
421 static int parse_dfu_info(char *buf, char **info)
426 for (i = 0; i < DFU_INFO_MAX; i++) {
427 ptr = strsep(&buf, DFU_DELIMITER);
431 info[i] = strdup(ptr);
439 static void destroy_dfu_info(void)
443 for (i = 0; i < DFU_INFO_NUM; i++) {
444 for (j = 0; j < DFU_INFO_MAX; j++)
445 if (dfu_info[i][j]) {
446 free(dfu_info[i][j]);
447 dfu_info[i][j] = NULL;
453 static int init_dfu_info(const char *dfu_info_file)
460 fp = fopen(dfu_info_file, "r");
464 while (i < DFU_INFO_NUM && !feof(fp)) {
465 if (fgets(buf, 1024, fp) == NULL)
468 ret = parse_dfu_info(buf, dfu_info[i++]);
470 fprintf(stderr, "cannot parse dfu info");
486 int dfu_init(struct tfm_context *ctx, const char *dfu_info_file)
490 ret = init_dfu_info(dfu_info_file);
492 fprintf(stderr, "failed to get flash entries\n");
496 TAILQ_INIT(&ctx->dfu_ioq_head);
498 pthread_mutex_init(&ctx->dfu_mutex, NULL);
499 pthread_mutex_init(&ctx->dfu_sync_mutex, NULL);
500 pthread_cond_init(&ctx->dfu_data_arrive, NULL);
501 pthread_cond_init(&ctx->dfu_write_done, NULL);
502 pthread_cond_init(&ctx->dfu_sync_done, NULL);
504 ret = pthread_create(&ctx->dfu_thread, NULL, dfu_thread_main, ctx);
506 fprintf(stderr, "failed to create thread for dfu\n");
513 void dfu_exit(struct tfm_context *ctx)
515 pthread_cancel(ctx->dfu_thread);
516 pthread_join(ctx->dfu_thread, NULL);