nuttx-apps/system/ofloader/ofloader.c

390 lines
8.7 KiB
C
Raw Normal View History

/****************************************************************************
* 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 <inttypes.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <mqueue.h>
#include <sys/ioctl.h>
#include <sys/boardctl.h>
#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;
#if defined(CONFIG_BOARDCTL) && !defined(CONFIG_NSH_ARCHINIT)
/* Perform architecture-specific initialization (if configured) */
boardctl(BOARDIOC_INIT, 0);
# ifdef CONFIG_BOARDCTL_FINALINIT
/* Perform architecture-specific final-initialization (if configured) */
boardctl(BOARDIOC_FINALINIT, 0);
# endif
#endif
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;
}