/**************************************************************************** * apps/system/ofloader/ofloader.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you 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. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include "ofloader.h" /**************************************************************************** * Private Type Definitions ****************************************************************************/ struct devinfo_s { int fd; off_t pos; off_t base; size_t size; }; /**************************************************************************** * Private Functions ****************************************************************************/ static int get_partinfo(FAR struct devinfo_s *devinfo) { struct partition_info_s info; int ret; ret = ioctl(devinfo->fd, BIOC_PARTINFO, &info); if (ret < 0) { return -errno; } devinfo->base = info.sectorsize * info.startsector; devinfo->size = info.sectorsize * info.numsectors; return 0; } static void free_devinfo(FAR struct devinfo_s *devinfo, size_t count) { if (devinfo == NULL || count == 0) { return; } while (count-- != 0) { if (devinfo[count].fd > 0) { close(devinfo[count].fd); } } free(devinfo); } static FAR struct devinfo_s *parse_devinfo(FAR size_t *index) { char table[] = CONFIG_SYSTEM_OFLOADER_TABLE; FAR struct devinfo_s *devinfo = NULL; FAR struct devinfo_s *tmp; FAR char *save_once; FAR char *save; FAR char *p; *index = 0; p = strtok_r(table, ";", &save_once); while (p != NULL) { p = strtok_r(p, ",", &save); if (p == NULL) { goto out; } tmp = realloc(devinfo, (*index + 1) * sizeof(struct devinfo_s)); if (tmp == NULL) { goto out; } devinfo = tmp; devinfo[*index].fd = open(p, O_RDWR); if (devinfo[*index].fd < 0) { goto out; } p = strtok_r(NULL, ",", &save); devinfo[*index].base = strtoul(p, NULL, 0); if (devinfo[*index].base == 0) { if (get_partinfo(&devinfo[*index]) < 0) { (*index)++; goto out; } goto again; } p = strtok_r(NULL, ",", &save); if (p == NULL) { (*index)++; goto out; } devinfo[*index].size = strtoul(p, NULL, 0); if (devinfo[*index].size == 0) { (*index)++; goto out; } again: devinfo[*index].pos = devinfo[*index].base; p = strtok_r(NULL, ";", &save_once); (*index)++; } return devinfo; out: free_devinfo(devinfo, *index); return NULL; } static ssize_t read_safe(int fd, FAR uint8_t *buff, size_t size) { ssize_t i = 0; while (i < size) { ssize_t ret = read(fd, buff + i, size - i); if (ret < 0) { return -errno; } i += ret; } return i; } static ssize_t write_safe(int fd, FAR uint8_t *buff, size_t size) { ssize_t i = 0; while (i < size) { ssize_t ret = write(fd, buff + i, size - i); if (ret < 0) { return -errno; } i += ret; } return i; } static ssize_t handle(FAR struct ofloader_msg *msg, FAR struct devinfo_s *devinfo, size_t count) { FAR uint8_t *buff = NULL; ssize_t ret = 0; size_t index; for (index = 0; index < count; index++) { if (msg->addr >= devinfo[index].base && msg->addr < devinfo[index].base + devinfo[index].size) { break; } } if (index == count) { return -ENODEV; } if (devinfo[index].pos != msg->addr) { off_t off = msg->addr - devinfo[index].pos; off = lseek(devinfo[index].fd, off, SEEK_CUR); if (off < 0) { OFLOADER_DEBUG("lseek error\n"); return -errno; } devinfo[index].pos = msg->addr; } OFLOADER_DEBUG("index %zu pos %" PRIxOFF "\n", index, devinfo[index].pos); OFLOADER_DEBUG("atcion %d addr %" PRIxOFF "size %zu\n", msg->atcion, msg->addr, msg->size); switch (msg->atcion) { case OFLOADER_SYNC: ret = fsync(devinfo[index].fd); if (ret < 0) { ret = -errno; } break; case OFLOADER_VERIFY: buff = malloc(msg->size); if (buff == NULL) { OFLOADER_DEBUG("verify no mem\n"); return -ENOMEM; } ret = read_safe(devinfo[index].fd, buff, msg->size); if (ret < 0) { OFLOADER_DEBUG("verify read error\n"); free(buff); break; } devinfo[index].pos += ret; if (memcmp(msg->buff, buff, ret) != 0) { OFLOADER_DEBUG("verify error\n"); ret = -EIO; free(buff); break; } free(buff); break; case OFLOADER_READ: ret = read_safe(devinfo[index].fd, msg->buff, msg->size); if (ret < 0) { OFLOADER_DEBUG("read error\n"); break; } devinfo[index].pos += ret; break; case OFLOADER_WRITE: ret = write_safe(devinfo[index].fd, msg->buff, msg->size); if (ret < 0) { OFLOADER_DEBUG("write error\n"); break; } devinfo[index].pos += ret; break; } return ret; } static pthread_addr_t fake_idle(pthread_addr_t arg) { for (; ; ) { } return NULL; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * ofl_main ****************************************************************************/ int main(int argc, FAR char *argv[]) { FAR struct devinfo_s *devinfo; FAR struct ofloader_msg *msg; struct mq_attr mqattr; pthread_attr_t attr; pthread_t thread; size_t count; size_t i; mqd_t mq; memset(&mqattr, 0, sizeof(struct mq_attr)); mqattr.mq_msgsize = sizeof(msg); mqattr.mq_maxmsg = 10; if (g_create_idle) { pthread_attr_init(&attr); attr.priority = 1; pthread_create(&thread, &attr, fake_idle, NULL); pthread_attr_destroy(&attr); } mq = mq_open(OFLOADER_QNAME, O_CREAT | O_RDWR, 0660, &mqattr); if (mq < 0) { OFLOADER_DEBUG("mq_open error:%d\n", errno); return -errno; } devinfo = parse_devinfo(&count); if (devinfo == NULL) { OFLOADER_DEBUG("parsdevinfo error\n"); mq_close(mq); return -EINVAL; } for (i = 0; i < count; i++) { OFLOADER_DEBUG("seq %d, base %" PRIxOFF ", size %zx\n", i, devinfo[i].base, devinfo[i].size); } while (1) { if (mq_receive(mq, (FAR char *)&msg, sizeof(msg), NULL) < 0) { OFLOADER_DEBUG(" mq_receive error %d\n", -errno); continue; } if (handle(msg, devinfo, count) < 0) { msg->atcion = OFLOADER_ERROR; } else { msg->atcion = OFLOADER_FINSH; } } /* Never run to here */ free_devinfo(devinfo, count); mq_close(mq); return 0; }