support openflashloader for nuttx

wiki:https://wiki.segger.com/SEGGER_Flash_Loader

Signed-off-by: anjiahao <anjiahao@xiaomi.com>
Signed-off-by: chao an <anchao@xiaomi.com>
This commit is contained in:
anjiahao 2023-04-06 15:42:57 +08:00 committed by Xiang Xiao
parent 85988dc77f
commit d0ad047f81
6 changed files with 780 additions and 0 deletions

44
system/ofloader/Kconfig Normal file
View File

@ -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

23
system/ofloader/Make.defs Normal file
View File

@ -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

30
system/ofloader/Makefile Normal file
View File

@ -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

371
system/ofloader/ofloader.c Normal file
View File

@ -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 <inttypes.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <mqueue.h>
#include <sys/ioctl.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;
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;
}

View File

@ -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 <syslog.h>
#include <stdlib.h>
/****************************************************************************
* 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 */

244
system/ofloader/segger.c Normal file
View File

@ -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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <mqueue.h>
#include <nuttx/init.h>
#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;
}