diff --git a/system/ofloader/Kconfig b/system/ofloader/Kconfig new file mode 100644 index 000000000..74333238c --- /dev/null +++ b/system/ofloader/Kconfig @@ -0,0 +1,44 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config SYSTEM_OFLOADER + tristate "Open flash loader" + default n + select DISABLE_IDLE_LOOP + ---help--- + Enable support for flashloader. + +if SYSTEM_OFLOADER + +config SYSTEM_OFLOADER_PROGNAME + string "Program name" + default "ofloader" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config SYSTEM_OFLOADER_PRIORITY + int "ofloader task priority" + default 100 + +config SYSTEM_OFLOADER_STACKSIZE + int "ofloader stack size" + default DEFAULT_TASK_STACKSIZE + +config SYSTEM_OFLOADER_BUFFERSIZE + int "ofloader transfer buffer size" + default 32768 + +config SYSTEM_OFLOADER_DEBUG + bool "Open flashloader debug option" + default n + +config SYSTEM_OFLOADER_TABLE + string "open flashloder table" + ---help--- + devname[,addr[,size]][;devname2[,addr[,size]]] + can enter multiple device nodes separated by semicolon + +endif diff --git a/system/ofloader/Make.defs b/system/ofloader/Make.defs new file mode 100644 index 000000000..e7b79a4fa --- /dev/null +++ b/system/ofloader/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/system/ofloader/Make.defs +# +# 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. +# +############################################################################ + +ifneq ($(CONFIG_SYSTEM_OFLOADER),) +CONFIGURED_APPS += $(APPDIR)/system/ofloader +endif diff --git a/system/ofloader/Makefile b/system/ofloader/Makefile new file mode 100644 index 000000000..8145e53c6 --- /dev/null +++ b/system/ofloader/Makefile @@ -0,0 +1,30 @@ +############################################################################ +# apps/system/ofloader/Makefile +# +# 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. +# +############################################################################ + +include $(APPDIR)/Make.defs + +PROGNAME = $(CONFIG_SYSTEM_OFLOADER_PROGNAME) +PRIORITY = $(CONFIG_SYSTEM_OFLOADER_PRIORITY) +STACKSIZE = $(CONFIG_SYSTEM_OFLOADER_STACKSIZE) + +CSRCS = segger.c +MAINSRC = ofloader.c + +include $(APPDIR)/Application.mk diff --git a/system/ofloader/ofloader.c b/system/ofloader/ofloader.c new file mode 100644 index 000000000..bbd6801d1 --- /dev/null +++ b/system/ofloader/ofloader.c @@ -0,0 +1,371 @@ +/**************************************************************************** + * 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; + pthread_attr_t attr; + pthread_t thread; + size_t count; + size_t i; + mqd_t mq; + + 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, NULL); + 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 void *)&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; +} diff --git a/system/ofloader/ofloader.h b/system/ofloader/ofloader.h new file mode 100644 index 000000000..37efff624 --- /dev/null +++ b/system/ofloader/ofloader.h @@ -0,0 +1,68 @@ +/**************************************************************************** + * apps/system/ofloader/ofloader.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __APPS_SYSTEM_OFLOADER_OFLOADER_H +#define __APPS_SYSTEM_OFLOADER_OFLOADER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define OFLOADER_QNAME "ofloader" + +#define OFLOADER_WRITE 1 +#define OFLOADER_READ 2 +#define OFLOADER_VERIFY 3 +#define OFLOADER_SYNC 4 +#define OFLOADER_ERROR 5 +#define OFLOADER_FINSH 6 + +#ifdef CONFIG_SYSTEM_OFLOADER_DEBUG +#define OFLOADER_DEBUG(...) syslog(LOG_INFO, ##__VA_ARGS__) +#else +#define OFLOADER_DEBUG(...) +#endif + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +struct ofloader_msg +{ + int atcion; + off_t addr; + size_t size; + FAR void *buff; +}; + +/**************************************************************************** + * Public data + ****************************************************************************/ + +extern FAR void *g_create_idle; + +#endif /* __APPS_SYSTEM_OFLOADER_OFLOADER_H */ diff --git a/system/ofloader/segger.c b/system/ofloader/segger.c new file mode 100644 index 000000000..0e4d6c6ae --- /dev/null +++ b/system/ofloader/segger.c @@ -0,0 +1,244 @@ +/**************************************************************************** + * apps/system/ofloader/segger.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 "ofloader.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ONCHIP 1 /* On-chip Flash Memory */ +#define ALGO_VERSION 0x101 /* Algo version, must not be modified. */ + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +struct SECTOR_INFO +{ + uint32_t SectorSize; /* Sector Size in bytes */ + uint32_t SectorStartAddr; /* Start address of the sector area + * (relative to the "BaseAddr" of the flash) + */ +}; + +struct FlashDevice +{ + uint16_t AlgoVer; + uint8_t Name[128]; + uint16_t Type; + uint32_t BaseAddr; + uint32_t TotalSize; + uint32_t PageSize; + uint32_t Reserved; + uint8_t ErasedVal; + uint32_t TimeoutProg; + uint32_t TimeoutErase; + struct SECTOR_INFO SectorInfo[2]; +}; + +const struct FlashDevice FlashDevice +locate_data("DevDscr") used_data = +{ + ALGO_VERSION, /* Algo version */ + "NuttX", /* Flash device name */ + ONCHIP, /* Flash device type */ + 0x00000000, /* Flash base address */ + 0xffffffff, /* Total flash device size in Bytes */ + CONFIG_SYSTEM_OFLOADER_BUFFERSIZE, /* Page Size (number of bytes that will + * be passed to ProgramPage(). May be + * multiple of min alignment in order + * to reduce overhead for calling + * ProgramPage multiple times + */ + 1, /* Reserved, should be 1 */ + 0xff, /* Flash erased value */ + 5000, /* Program page timeout in ms */ + 5000, /* Erase sector timeout in ms */ + + /* Flash sector layout definition + * Sector size equl with page size to skip erase + */ + + { + {CONFIG_SYSTEM_OFLOADER_BUFFERSIZE, 0x00000000}, + {0xffffffff, 0xffffffff} + } +}; + +/* This array is used to mark the stack and transfer buffer + *locations used by the ofloader + */ + +static uint8_t g_stack_buff[CONFIG_SYSTEM_OFLOADER_STACKSIZE + + CONFIG_SYSTEM_OFLOADER_BUFFERSIZE] +locate_data("DevStack") used_data; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int SEGGER_FL_Prepare(uint32_t PreparePara0, uint32_t PreparePara1, + uint32_t PreparePara2) + locate_code("PrgData") used_code; + +int SEGGER_FL_Restore(uint32_t PreparePara0, uint32_t PreparePara1, + uint32_t PreparePara2) + locate_code("PrgData") used_code; + +int SEGGER_FL_Program(uint32_t DestAddr, uint32_t NumBytes, + FAR uint8_t *pSrcBuff) + locate_code("PrgData") used_code; + +int SEGGER_FL_Erase(uint32_t SectorAddr, uint32_t SectorIndex, + uint32_t NumSectors) + locate_code("PrgData") used_code; + +int SEGGER_FL_Read(uint32_t Addr, uint32_t NumBytes, FAR uint8_t *pDestBuff) + locate_code("PrgData") used_code; + +uint32_t SEGGER_FL_Verify(uint32_t Addr, uint32_t NumBytes, + FAR uint8_t *pData) + locate_code("PrgData") used_code; + +/**************************************************************************** + * Public data + ****************************************************************************/ + +/* Reference SEGGER_FL_Prepare to prevent it from being + * optimized by the compiler + */ + +FAR void *g_create_idle = SEGGER_FL_Prepare; + +static int SEGGER_FL_SendAndWait(FAR struct ofloader_msg *msg) +{ + int atcion = msg->atcion; + mqd_t mq; + int ret; + + mq = mq_open(OFLOADER_QNAME, O_RDWR, 0666, NULL); + if (mq < 0) + { + return -errno; + } + + ret = mq_send(mq, (FAR void *)&msg, sizeof(msg), 0); + if (ret < 0) + { + ret = -errno; + goto out; + } + + /* TODO:SEGGER disables interrupts by default during operation + * so wait ofloader main thread do somthing. + */ + + while (msg->atcion == atcion); + if (msg->atcion == OFLOADER_ERROR) + { + ret = -EIO; + goto out; + } + +out: + mq_close(mq); + return ret; +} + +extern void __start(void); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int SEGGER_FL_Prepare(uint32_t PreparePara0, uint32_t PreparePara1, + uint32_t PreparePara2) +{ + g_create_idle = NULL; + __start(); + return 0; +} + +int SEGGER_FL_Restore(uint32_t PreparePara0, uint32_t PreparePara1, + uint32_t PreparePara2) +{ + struct ofloader_msg msg; + + msg.atcion = OFLOADER_SYNC; + return SEGGER_FL_SendAndWait(&msg); +} + +int SEGGER_FL_Program(uint32_t DestAddr, uint32_t NumBytes, + FAR uint8_t *pSrcBuff) +{ + struct ofloader_msg msg; + + msg.addr = DestAddr; + msg.size = NumBytes; + msg.buff = pSrcBuff; + msg.atcion = OFLOADER_WRITE; + return SEGGER_FL_SendAndWait(&msg); +} + +int SEGGER_FL_Erase(uint32_t SectorAddr, uint32_t SectorIndex, + uint32_t NumSectors) +{ + return 0; +} + +int SEGGER_FL_Read(uint32_t Addr, uint32_t NumBytes, FAR uint8_t *pDestBuff) +{ + struct ofloader_msg msg; + + msg.addr = Addr; + msg.size = NumBytes; + msg.buff = pDestBuff; + msg.atcion = OFLOADER_READ; + return SEGGER_FL_SendAndWait(&msg); +} + +uint32_t SEGGER_FL_Verify(uint32_t Addr, uint32_t NumBytes, + FAR uint8_t *pData) +{ + struct ofloader_msg msg; + + msg.addr = Addr; + msg.size = NumBytes; + msg.buff = pData; + msg.atcion = OFLOADER_VERIFY; + if (SEGGER_FL_SendAndWait(&msg) < 0) + { + return 0; + } + + return Addr + NumBytes; +}