1946
- 收藏
- 点赞
- 分享
- 举报
auto_update.c
海思的例子是使用spi nor flash ,怎么样改成spi nand flash啊,板子是3531d做U盘升级。谢谢大佬们了,比较需要思路,从哪离开始改。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_AUTO_UPDATE /* cover the whole file 覆盖整个文件*/
#ifdef CONFIG_AUTO_SD_UPDATE
#ifndef CONFIG_MMC
#error "should have defined CONFIG_MMC"
#endif
#include
#include "mmc_init.c"
#endif
#if defined CONFIG_AUTO_USB_UPDATE
#if !defined CONFIG_USB_OHCI && !defined CONFIG_USB_XHCI
#error "should have defined CONFIG_USB_OHCI or CONFIG_USB_XHCI"
#endif
#ifndef CONFIG_USB_STORAGE
#error "should have defined CONFIG_USB_STORAGE"
#endif
#include
#include "usb_init.c"
#endif
#undef AU_DEBUG
#undef debug
#ifdef AU_DEBUG
#define debug(fmt, args...) printf(fmt, ##args)
#else
#define debug(fmt, args...)
#endif /* AU_DEBUG */
/* possible names of files on the medium.介质上文件的可能名称 */
#define AU_FIRMWARE "u-boot"
#define AU_KERNEL "kernel"
#define AU_ROOTFS "rootfs"
struct flash_layout {
long start;
long end;
};
static struct spi_flash *flash;
struct medium_interface {
char name[20];
int (*init) (void);
void (*exit) (void);
};
#define MAX_UPDATE_INTF 3
static struct medium_interface s_intf[MAX_UPDATE_INTF] = {
#ifdef CONFIG_AUTO_SD_UPDATE
{.name = "mmc", .init = mmc_stor_init, .exit = mmc_stor_exit,},
#endif
#ifdef CONFIG_AUTO_USB_UPDATE
{.name = "usb", .init = usb_stor_init, .exit = usb_stor_exit,},
#endif
};
/* layout of the FLASH. ST = start address, ND = end address. FLASH的布局。ST =开始地址,ND =结束地址。*/
#define AU_FL_FIRMWARE_ST 0x0
#define AU_FL_FIRMWARE_ND 0x7FFFF
#define AU_FL_KERNEL_ST 0x100000
#define AU_FL_KERNEL_ND 0x5FFFFF
#define AU_FL_ROOTFS_ST 0x600000
#define AU_FL_ROOTFS_ND 0xbFFFFF
static int au_stor_curr_dev; /* current device目前的设备*/
/* index of each file in the following arrays 以下数组中每个文件的索引 */
#define IDX_FIRMWARE 0
#define IDX_KERNEL 1
#define IDX_ROOTFS 2
/* max. number of files which could interest us 我们感兴趣的文件数量 */
#define AU_MAXFILES 3
/* pointers to file names 指向文件名的指针 */
char *aufile[AU_MAXFILES] = {
AU_FIRMWARE,
AU_KERNEL,
AU_ROOTFS
};
/* sizes of flash areas for each file 每个文件的flash区域大小*/
long ausize[AU_MAXFILES] = {
(AU_FL_FIRMWARE_ND + 1) - AU_FL_FIRMWARE_ST,
(AU_FL_KERNEL_ND + 1) - AU_FL_KERNEL_ST,
(AU_FL_ROOTFS_ND + 1) - AU_FL_ROOTFS_ST,
};
/* array of flash areas start and end addresses flash区域开始和结束地址的数组*/
struct flash_layout aufl_layout[AU_MAXFILES] = {
{ AU_FL_FIRMWARE_ST, AU_FL_FIRMWARE_ND, },
{ AU_FL_KERNEL_ST, AU_FL_KERNEL_ND, },
{ AU_FL_ROOTFS_ST, AU_FL_ROOTFS_ND, },
};
/* where to load files into memory 哪里加载文件到内存*/
#if defined(CONFIG_HI3536) || defined(CONFIG_HI3531A) || defined(CONFIG_HI3531D)
#define LOAD_ADDR ((unsigned char *)0x42000000)
#else
#define LOAD_ADDR ((unsigned char *)0x82000000)
#endif
/* the app is the largest image应用程序是最大的图像 */
#define MAX_LOADSZ ausize[IDX_ROOTFS]
/*获取当前文件的总大小,把它与 image_header 中记录的总大小比较,如果不匹配
则返回错误,并中止升级*/
static int au_check_cksum_valid(int idx, long nbytes)
{
image_header_t *hdr;
unsigned long checksum;
hdr = (image_header_t *)LOAD_ADDR;
if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
printf("Image %s bad total SIZE\n", aufile[idx]);
return -1;
}
/* check the data CRC 检查数据CRC*/
checksum = ntohl(hdr->ih_dcrc);
if (crc32(0, (unsigned char const *)(LOAD_ADDR + sizeof(*hdr)),
ntohl(hdr->ih_size)) != checksum) {
printf("Image %s bad data checksum\n", aufile[idx]);
return -1;
}
return 0;
}
/*这个函数的主要功能就是校验镜像文件的 image_header 信息,如果校验不通过
则不会进行升级。
− 如果校验通过,这个函数还有一个重要的功能就是对比 ih_time 这个时间戳信
息,用它来判断镜像文件的版本。如果镜像文件的生成时间小于已记录的时间
之前,那么该镜像就不会被 down 到 flash 上。当满足信息的镜像更新到 flash
上之后就会在 boot 的环境变量中保存当前镜像的时间戳信息用于下一次比较。*/
static int au_check_header_valid(int idx, long nbytes)
{
image_header_t *hdr;
unsigned long checksum;
char env[20] = {0};
char auversion[20] = {0};
hdr = (image_header_t *)LOAD_ADDR;
/* check the easy ones first 先检查一下*/
#if 0
#define CHECK_VALID_DEBUG
#else
#undef CHECK_VALID_DEBUG
#endif
#ifdef CHECK_VALID_DEBUG
printf("\nmagic %#x %#x\n", ntohl(hdr->ih_magic), IH_MAGIC);
printf("arch %#x %#x\n", hdr->ih_arch, IH_ARCH_ARM);
printf("size %#x %#lx\n", ntohl(hdr->ih_size), nbytes);
printf("type %#x %#x\n", hdr->ih_type, IH_TYPE_KERNEL);
#endif
if (nbytes < sizeof(*hdr)) {
printf("Image %s bad header SIZE\n", aufile[idx]);
return -1;
}
if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_ARCH_ARM) {
printf("Image %s bad MAGIC or ARCH\n", aufile[idx]);
return -1;
}
/* check the hdr CRC 检查hdr CRC*/
checksum = ntohl(hdr->ih_hcrc);
hdr->ih_hcrc = 0;
if (crc32(0, (unsigned char const *)hdr, sizeof(*hdr)) != checksum) {
printf("Image %s bad header checksum\n", aufile[idx]);
return -1;
}
hdr->ih_hcrc = htonl(checksum);
/* check the type - could do this all in one gigantic if() 检查类型-可以在一个巨大的if()中完成所有这些*/
if ((idx == IDX_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
printf("Image %s wrong type\n", aufile[idx]);
return -1;
}
if ((idx == IDX_KERNEL) && (hdr->ih_type != IH_TYPE_KERNEL)) {
printf("Image %s wrong type\n", aufile[idx]);
return -1;
}
if ((idx == IDX_ROOTFS) &&
(hdr->ih_type != IH_TYPE_RAMDISK) &&
(hdr->ih_type != IH_TYPE_FILESYSTEM)) {
printf("Image %s wrong type\n", aufile[idx]);
ausize[idx] = 0;
return -1;
}
/* recycle checksum 循环校验和*/
checksum = ntohl(hdr->ih_size);
/* for kernel and app the image header must also fit into flash 对于内核和应用程序,图像头部也必须适应flash*/
if ((idx == IDX_KERNEL) || (hdr->ih_type == IH_TYPE_RAMDISK))
checksum += sizeof(*hdr);
/* check the size does not exceed space in flash. HUSH scripts 检查大小不超过flash中的空间。嘘的脚本*/
/* all have ausize[] set to 0 都将ausize[]设置为0*/
if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
printf("Image %s is bigger than FLASH\n", aufile[idx]);
return -1;
}
sprintf(env, "%lx", (unsigned long)ntohl(hdr->ih_time));
setenv(auversion, env);
return 0;
}
//时间进度通知
static void schedule_notify(unsigned long offset, unsigned long len,
unsigned long off_start)
{
int percent_complete = -1;
do {
unsigned long long n = (unsigned long long)
(offset - off_start) * 100;
int percent;
do_div(n, len);
percent = (int)n;
/* output progress message only at whole percent
* steps to reduce the number of messages
* printed on (slow) serial consoles
仅以整个百分比的步骤输出进度消息,以减少(缓慢的)串行控制台上打印的消息数量*/
if (percent != percent_complete) {
percent_complete = percent;
printf("\rOperation at 0x%lx -- %3d%% complete.",
offset, percent);
}
} while (0);
}
//spi_flash擦除函数
static int spi_flash_erase_op(struct spi_flash *flash, unsigned long offset,
unsigned long len)
{
int ret;
struct mtd_info_ex *spiflash_info = get_spiflash_info();
unsigned long erase_start, erase_len, erase_step;
erase_start = offset;
erase_len = len;
erase_step = spiflash_info->erasesize;
while (len > 0) {
if (len < erase_step)
erase_step = len;
ret = flash->erase(flash, (u32)offset, erase_step);
if (ret)
return 1;
len -= erase_step;
offset += erase_step;
/* notify real time schedule 实时通知时间表*/
schedule_notify(offset, erase_len, erase_start);
}
return ret;
}
//spi_flash写入函数
static int spi_flash_write_op(struct spi_flash *flash, unsigned long offset,
unsigned long len, void *buf)
{
int ret = 0;
unsigned long write_start, write_len, write_step;
char *pbuf = buf;
struct mtd_info_ex *spiflash_info = get_spiflash_info();
write_start = offset;
write_len = len;
write_step = spiflash_info->erasesize;
while (len > 0) {
if (len < write_step)
write_step = len;
ret = flash->write(flash, offset, write_step, pbuf);
if (ret)
break;
offset += write_step;
pbuf += write_step;
len -= write_step;
/* notify real time schedule 实时通知时间表*/
schedule_notify(offset, write_len, write_start);
}
return ret;
}
/*这个函数的主要功能就是写 flash,当所有的校验通过之后,就会通过这个函数
把镜像写到 flash 上。 */
static int au_do_update(int idx, long sz)
{
image_header_t *hdr;
unsigned long start, len;
unsigned long write_len;
int rc;
void *buf;
char *pbuf;
hdr = (image_header_t *)LOAD_ADDR;
start = aufl_layout[idx].start;
len = aufl_layout[idx].end - aufl_layout[idx].start + 1;
/*
* erase the address range.
删除地址范围*/
printf("flash erase...\n");
rc = spi_flash_erase_op(flash, start, len);
if (rc) {
printf("SPI flash sector erase failed\n");
return 1;
}
buf = map_physmem((unsigned long)LOAD_ADDR, len, MAP_WRBACK);
if (!buf) {
puts("Failed to map physical memory\n");
return 1;
}
/* strip the header - except for the kernel and ramdisk 除去内核和ramdisk之外的头 */
if (hdr->ih_type == IH_TYPE_KERNEL || hdr->ih_type == IH_TYPE_RAMDISK) {
pbuf = buf;
write_len = sizeof(*hdr) + ntohl(hdr->ih_size);
} else {
pbuf = (buf + sizeof(*hdr));
write_len = ntohl(hdr->ih_size);
}
/* copy the data from RAM to FLASH 将数据从RAM复制到FLASH*/
printf("\nflash write...\n");
rc = spi_flash_write_op(flash, start, write_len, pbuf);
if (rc) {
printf("SPI flash write failed, return %d\n", rc);
return 1;
}
/* check the dcrc of the copy 检查副本的dcrc*/
if (crc32(0, (unsigned char const *)(buf + sizeof(*hdr)),
ntohl(hdr->ih_size)) != ntohl(hdr->ih_dcrc)) {
printf("Image %s Bad Data Checksum After COPY\n", aufile[idx]);
return -1;
}
unmap_physmem(buf, len);
return 0;
}
//得到更新的环境变量
static void get_update_env(char *img_start, char *img_end)
{
long start = -1, end = 0;
char *env;
/*
* check whether start and end are defined in environment
* variables.
检查start和end是否在环境变量中定义。 */
env = getenv(img_start);
if (env != NULL)
start = simple_strtoul(env, NULL, 16);
env = getenv(img_end);
if (env != NULL)
end = simple_strtoul(env, NULL, 16);
if (start >= 0 && end && end > start) {
ausize[IDX_FIRMWARE] = (end + 1) - start;
aufl_layout[0].start = start;
aufl_layout[0].end = end;
}
}
/*
* If none of the update file(u-boot, kernel or rootfs) was found
* in the medium, return -1;
* If u-boot has been updated, return 1;
* Others, return 0;
如果没有找到任何更新文件(u-boot、内核或rootfs)
*在介质中,返回-1;
*如果u-boot已更新,返回1;
*其他,返回0;
*/
static int update_to_flash(void)
{
int i = 0;
long sz;
int res, cnt;
int uboot_updated = 0;
int image_found = 0;
/* just loop thru all the possible files 循环遍历所有可能的文件*/
for (i = 0; i < AU_MAXFILES; i++) {
/* just read the header 读一下标题*/
sz = file_fat_read(aufile, LOAD_ADDR,
sizeof(image_header_t));
debug("read %s sz %ld hdr %d\n",
aufile, sz, sizeof(image_header_t));
if (sz <= 0 || sz < sizeof(image_header_t)) {
debug("%s not found\n", aufile);
continue;
}
image_found = 1;
//au_check_header_valid()返回值小于0效验头不通过不升级
if (au_check_header_valid(i, sz) < 0) {
debug("%s header not valid\n", aufile);
continue;
}
sz = file_fat_read(aufile, LOAD_ADDR, MAX_LOADSZ);
debug("read %s sz %ld hdr %d\n",
aufile, sz, sizeof(image_header_t));
if (sz <= 0 || sz <= sizeof(image_header_t)) {
debug("%s not found\n", aufile);
continue;
}
//au_check_cksum_valid返回值小于0效验和不通过不升级
if (au_check_cksum_valid(i, sz) < 0) {
debug("%s checksum not valid\n", aufile);
continue;
}
/* If u-boot had been updated, we need to
* save current env to flash 如果u-boot已经更新,我们需要将当前环境保存为flash*/
if (0 == strcmp((char *)AU_FIRMWARE, aufile))
uboot_updated = 1;
/* this is really not a good idea, but it's what the */
/* customer wants. 这确实不是一个好主意,但这是客户想要的。*/
cnt = 0;
do {
res = au_do_update(i, sz);//写 flash
/* let the user break out of the loop让用户跳出循环 */
if (ctrlc() || had_ctrlc()) {
clear_ctrlc();
break;
}
cnt++;
#ifdef AU_TEST_ONLY
} while (res < 0 && cnt < 3);
if (cnt < 3)
#else
} while (res < 0);
#endif
}
if (1 == uboot_updated)
return 1;
if (1 == image_found)
return 0;
return -1;
}
/*
* This is called by board_init() after the hardware has been set up
* and is usable. Only if SPI flash initialization failed will this function
* return -1, otherwise it will return 0;
*在硬件设置好并可用之后,board_init()调用这个函数。只有SPI flash初始化失败时,该函数才返回-1,否则返回0;
*提供给外部的函数接口,是 auto update 的主函数。*/
int do_auto_update(void)
{
block_dev_desc_t *stor_dev;
int old_ctrlc;
int j;
int state = -1;
int dev;
au_stor_curr_dev = -1;
for (j = 0; j < MAX_UPDATE_INTF; j++) {
if (0 != (unsigned int)s_intf[j].name[0]) {
au_stor_curr_dev = s_intf[j].init();
if (-1 == au_stor_curr_dev) {
debug("No %s storage device found!\n",
s_intf[j].name);
continue;
}
dev = 0;
#if (defined CONFIG_HI3516CV300 || defined CONFIG_ARCH_HI3519 || \
defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3516AV200)
if (strncmp("mmc", s_intf[j].name, sizeof("mmc")) == 0)
dev = 2;
#endif
debug("device name %s!\n", s_intf[j].name);
stor_dev = get_dev(s_intf[j].name, dev);
if (NULL == stor_dev) {
debug("Unknow device type!\n");
continue;
}
if (fat_register_device(stor_dev, 1) != 0) {
debug("Unable to use %s %d:%d for fatls\n",
s_intf[j].name,
au_stor_curr_dev,
1);
continue;
}
if (file_fat_detectfs() != 0) {
debug("file_fat_detectfs failed\n");
continue;
}
/*
* Get image layout from environment.
* If the start address and the end address
* were not definedin environment virables,
* use the default value
从环境中获取图像布局。如果环境virables中没有定义开始地址和结束地址,请使用默认值
*/
get_update_env("firmware_st", "firmware_nd");
get_update_env("kernel_st", "kernel_nd");
get_update_env("rootfs_st", "rootfs_nd");
/*
* make sure that we see CTRL-C
* and save the old state
确保我们看到CTRL-C并保存旧状态
*/
old_ctrlc = disable_ctrlc(0);
/*
* CONFIG_SF_DEFAULT_SPEED=1000000,
* CONFIG_SF_DEFAULT_MODE=0x3
*/
flash = spi_flash_probe(0, 0, 1000000, 0x3);
if (!flash) {
printf("Failed to initialize SPI flash\n");
return -1;
}
state = update_to_flash();//功能更新flash;函数里面调用au_do_update();功能写flash
//调用au_check_header_valid()校验函数
/* restore the old state 恢复旧状态*/
disable_ctrlc(old_ctrlc);
s_intf[j].exit();
/*
* no update file found没有找到更新文件
*/
if (-1 == state)
continue;
/*
* update files have been found on current medium,
* so just break here
更新文件已在当前媒体上找到,因此请在此中断
*/
break;
}
}
/*
* If u-boot has been updated, it's better to save environment to flash
如果u-boot已经更新,最好将环境保存到flash中
*/
if (1 == state) {
env_crc_update();
saveenv();
}
return 0;
}
#endif /* CONFIG_AUTO_UPDATE */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_AUTO_UPDATE /* cover the whole file 覆盖整个文件*/
#ifdef CONFIG_AUTO_SD_UPDATE
#ifndef CONFIG_MMC
#error "should have defined CONFIG_MMC"
#endif
#include
#include "mmc_init.c"
#endif
#if defined CONFIG_AUTO_USB_UPDATE
#if !defined CONFIG_USB_OHCI && !defined CONFIG_USB_XHCI
#error "should have defined CONFIG_USB_OHCI or CONFIG_USB_XHCI"
#endif
#ifndef CONFIG_USB_STORAGE
#error "should have defined CONFIG_USB_STORAGE"
#endif
#include
#include "usb_init.c"
#endif
#undef AU_DEBUG
#undef debug
#ifdef AU_DEBUG
#define debug(fmt, args...) printf(fmt, ##args)
#else
#define debug(fmt, args...)
#endif /* AU_DEBUG */
/* possible names of files on the medium.介质上文件的可能名称 */
#define AU_FIRMWARE "u-boot"
#define AU_KERNEL "kernel"
#define AU_ROOTFS "rootfs"
struct flash_layout {
long start;
long end;
};
static struct spi_flash *flash;
struct medium_interface {
char name[20];
int (*init) (void);
void (*exit) (void);
};
#define MAX_UPDATE_INTF 3
static struct medium_interface s_intf[MAX_UPDATE_INTF] = {
#ifdef CONFIG_AUTO_SD_UPDATE
{.name = "mmc", .init = mmc_stor_init, .exit = mmc_stor_exit,},
#endif
#ifdef CONFIG_AUTO_USB_UPDATE
{.name = "usb", .init = usb_stor_init, .exit = usb_stor_exit,},
#endif
};
/* layout of the FLASH. ST = start address, ND = end address. FLASH的布局。ST =开始地址,ND =结束地址。*/
#define AU_FL_FIRMWARE_ST 0x0
#define AU_FL_FIRMWARE_ND 0x7FFFF
#define AU_FL_KERNEL_ST 0x100000
#define AU_FL_KERNEL_ND 0x5FFFFF
#define AU_FL_ROOTFS_ST 0x600000
#define AU_FL_ROOTFS_ND 0xbFFFFF
static int au_stor_curr_dev; /* current device目前的设备*/
/* index of each file in the following arrays 以下数组中每个文件的索引 */
#define IDX_FIRMWARE 0
#define IDX_KERNEL 1
#define IDX_ROOTFS 2
/* max. number of files which could interest us 我们感兴趣的文件数量 */
#define AU_MAXFILES 3
/* pointers to file names 指向文件名的指针 */
char *aufile[AU_MAXFILES] = {
AU_FIRMWARE,
AU_KERNEL,
AU_ROOTFS
};
/* sizes of flash areas for each file 每个文件的flash区域大小*/
long ausize[AU_MAXFILES] = {
(AU_FL_FIRMWARE_ND + 1) - AU_FL_FIRMWARE_ST,
(AU_FL_KERNEL_ND + 1) - AU_FL_KERNEL_ST,
(AU_FL_ROOTFS_ND + 1) - AU_FL_ROOTFS_ST,
};
/* array of flash areas start and end addresses flash区域开始和结束地址的数组*/
struct flash_layout aufl_layout[AU_MAXFILES] = {
{ AU_FL_FIRMWARE_ST, AU_FL_FIRMWARE_ND, },
{ AU_FL_KERNEL_ST, AU_FL_KERNEL_ND, },
{ AU_FL_ROOTFS_ST, AU_FL_ROOTFS_ND, },
};
/* where to load files into memory 哪里加载文件到内存*/
#if defined(CONFIG_HI3536) || defined(CONFIG_HI3531A) || defined(CONFIG_HI3531D)
#define LOAD_ADDR ((unsigned char *)0x42000000)
#else
#define LOAD_ADDR ((unsigned char *)0x82000000)
#endif
/* the app is the largest image应用程序是最大的图像 */
#define MAX_LOADSZ ausize[IDX_ROOTFS]
/*获取当前文件的总大小,把它与 image_header 中记录的总大小比较,如果不匹配
则返回错误,并中止升级*/
static int au_check_cksum_valid(int idx, long nbytes)
{
image_header_t *hdr;
unsigned long checksum;
hdr = (image_header_t *)LOAD_ADDR;
if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size))) {
printf("Image %s bad total SIZE\n", aufile[idx]);
return -1;
}
/* check the data CRC 检查数据CRC*/
checksum = ntohl(hdr->ih_dcrc);
if (crc32(0, (unsigned char const *)(LOAD_ADDR + sizeof(*hdr)),
ntohl(hdr->ih_size)) != checksum) {
printf("Image %s bad data checksum\n", aufile[idx]);
return -1;
}
return 0;
}
/*这个函数的主要功能就是校验镜像文件的 image_header 信息,如果校验不通过
则不会进行升级。
− 如果校验通过,这个函数还有一个重要的功能就是对比 ih_time 这个时间戳信
息,用它来判断镜像文件的版本。如果镜像文件的生成时间小于已记录的时间
之前,那么该镜像就不会被 down 到 flash 上。当满足信息的镜像更新到 flash
上之后就会在 boot 的环境变量中保存当前镜像的时间戳信息用于下一次比较。*/
static int au_check_header_valid(int idx, long nbytes)
{
image_header_t *hdr;
unsigned long checksum;
char env[20] = {0};
char auversion[20] = {0};
hdr = (image_header_t *)LOAD_ADDR;
/* check the easy ones first 先检查一下*/
#if 0
#define CHECK_VALID_DEBUG
#else
#undef CHECK_VALID_DEBUG
#endif
#ifdef CHECK_VALID_DEBUG
printf("\nmagic %#x %#x\n", ntohl(hdr->ih_magic), IH_MAGIC);
printf("arch %#x %#x\n", hdr->ih_arch, IH_ARCH_ARM);
printf("size %#x %#lx\n", ntohl(hdr->ih_size), nbytes);
printf("type %#x %#x\n", hdr->ih_type, IH_TYPE_KERNEL);
#endif
if (nbytes < sizeof(*hdr)) {
printf("Image %s bad header SIZE\n", aufile[idx]);
return -1;
}
if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_ARCH_ARM) {
printf("Image %s bad MAGIC or ARCH\n", aufile[idx]);
return -1;
}
/* check the hdr CRC 检查hdr CRC*/
checksum = ntohl(hdr->ih_hcrc);
hdr->ih_hcrc = 0;
if (crc32(0, (unsigned char const *)hdr, sizeof(*hdr)) != checksum) {
printf("Image %s bad header checksum\n", aufile[idx]);
return -1;
}
hdr->ih_hcrc = htonl(checksum);
/* check the type - could do this all in one gigantic if() 检查类型-可以在一个巨大的if()中完成所有这些*/
if ((idx == IDX_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
printf("Image %s wrong type\n", aufile[idx]);
return -1;
}
if ((idx == IDX_KERNEL) && (hdr->ih_type != IH_TYPE_KERNEL)) {
printf("Image %s wrong type\n", aufile[idx]);
return -1;
}
if ((idx == IDX_ROOTFS) &&
(hdr->ih_type != IH_TYPE_RAMDISK) &&
(hdr->ih_type != IH_TYPE_FILESYSTEM)) {
printf("Image %s wrong type\n", aufile[idx]);
ausize[idx] = 0;
return -1;
}
/* recycle checksum 循环校验和*/
checksum = ntohl(hdr->ih_size);
/* for kernel and app the image header must also fit into flash 对于内核和应用程序,图像头部也必须适应flash*/
if ((idx == IDX_KERNEL) || (hdr->ih_type == IH_TYPE_RAMDISK))
checksum += sizeof(*hdr);
/* check the size does not exceed space in flash. HUSH scripts 检查大小不超过flash中的空间。嘘的脚本*/
/* all have ausize[] set to 0 都将ausize[]设置为0*/
if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
printf("Image %s is bigger than FLASH\n", aufile[idx]);
return -1;
}
sprintf(env, "%lx", (unsigned long)ntohl(hdr->ih_time));
setenv(auversion, env);
return 0;
}
//时间进度通知
static void schedule_notify(unsigned long offset, unsigned long len,
unsigned long off_start)
{
int percent_complete = -1;
do {
unsigned long long n = (unsigned long long)
(offset - off_start) * 100;
int percent;
do_div(n, len);
percent = (int)n;
/* output progress message only at whole percent
* steps to reduce the number of messages
* printed on (slow) serial consoles
仅以整个百分比的步骤输出进度消息,以减少(缓慢的)串行控制台上打印的消息数量*/
if (percent != percent_complete) {
percent_complete = percent;
printf("\rOperation at 0x%lx -- %3d%% complete.",
offset, percent);
}
} while (0);
}
//spi_flash擦除函数
static int spi_flash_erase_op(struct spi_flash *flash, unsigned long offset,
unsigned long len)
{
int ret;
struct mtd_info_ex *spiflash_info = get_spiflash_info();
unsigned long erase_start, erase_len, erase_step;
erase_start = offset;
erase_len = len;
erase_step = spiflash_info->erasesize;
while (len > 0) {
if (len < erase_step)
erase_step = len;
ret = flash->erase(flash, (u32)offset, erase_step);
if (ret)
return 1;
len -= erase_step;
offset += erase_step;
/* notify real time schedule 实时通知时间表*/
schedule_notify(offset, erase_len, erase_start);
}
return ret;
}
//spi_flash写入函数
static int spi_flash_write_op(struct spi_flash *flash, unsigned long offset,
unsigned long len, void *buf)
{
int ret = 0;
unsigned long write_start, write_len, write_step;
char *pbuf = buf;
struct mtd_info_ex *spiflash_info = get_spiflash_info();
write_start = offset;
write_len = len;
write_step = spiflash_info->erasesize;
while (len > 0) {
if (len < write_step)
write_step = len;
ret = flash->write(flash, offset, write_step, pbuf);
if (ret)
break;
offset += write_step;
pbuf += write_step;
len -= write_step;
/* notify real time schedule 实时通知时间表*/
schedule_notify(offset, write_len, write_start);
}
return ret;
}
/*这个函数的主要功能就是写 flash,当所有的校验通过之后,就会通过这个函数
把镜像写到 flash 上。 */
static int au_do_update(int idx, long sz)
{
image_header_t *hdr;
unsigned long start, len;
unsigned long write_len;
int rc;
void *buf;
char *pbuf;
hdr = (image_header_t *)LOAD_ADDR;
start = aufl_layout[idx].start;
len = aufl_layout[idx].end - aufl_layout[idx].start + 1;
/*
* erase the address range.
删除地址范围*/
printf("flash erase...\n");
rc = spi_flash_erase_op(flash, start, len);
if (rc) {
printf("SPI flash sector erase failed\n");
return 1;
}
buf = map_physmem((unsigned long)LOAD_ADDR, len, MAP_WRBACK);
if (!buf) {
puts("Failed to map physical memory\n");
return 1;
}
/* strip the header - except for the kernel and ramdisk 除去内核和ramdisk之外的头 */
if (hdr->ih_type == IH_TYPE_KERNEL || hdr->ih_type == IH_TYPE_RAMDISK) {
pbuf = buf;
write_len = sizeof(*hdr) + ntohl(hdr->ih_size);
} else {
pbuf = (buf + sizeof(*hdr));
write_len = ntohl(hdr->ih_size);
}
/* copy the data from RAM to FLASH 将数据从RAM复制到FLASH*/
printf("\nflash write...\n");
rc = spi_flash_write_op(flash, start, write_len, pbuf);
if (rc) {
printf("SPI flash write failed, return %d\n", rc);
return 1;
}
/* check the dcrc of the copy 检查副本的dcrc*/
if (crc32(0, (unsigned char const *)(buf + sizeof(*hdr)),
ntohl(hdr->ih_size)) != ntohl(hdr->ih_dcrc)) {
printf("Image %s Bad Data Checksum After COPY\n", aufile[idx]);
return -1;
}
unmap_physmem(buf, len);
return 0;
}
//得到更新的环境变量
static void get_update_env(char *img_start, char *img_end)
{
long start = -1, end = 0;
char *env;
/*
* check whether start and end are defined in environment
* variables.
检查start和end是否在环境变量中定义。 */
env = getenv(img_start);
if (env != NULL)
start = simple_strtoul(env, NULL, 16);
env = getenv(img_end);
if (env != NULL)
end = simple_strtoul(env, NULL, 16);
if (start >= 0 && end && end > start) {
ausize[IDX_FIRMWARE] = (end + 1) - start;
aufl_layout[0].start = start;
aufl_layout[0].end = end;
}
}
/*
* If none of the update file(u-boot, kernel or rootfs) was found
* in the medium, return -1;
* If u-boot has been updated, return 1;
* Others, return 0;
如果没有找到任何更新文件(u-boot、内核或rootfs)
*在介质中,返回-1;
*如果u-boot已更新,返回1;
*其他,返回0;
*/
static int update_to_flash(void)
{
int i = 0;
long sz;
int res, cnt;
int uboot_updated = 0;
int image_found = 0;
/* just loop thru all the possible files 循环遍历所有可能的文件*/
for (i = 0; i < AU_MAXFILES; i++) {
/* just read the header 读一下标题*/
sz = file_fat_read(aufile, LOAD_ADDR,
sizeof(image_header_t));
debug("read %s sz %ld hdr %d\n",
aufile, sz, sizeof(image_header_t));
if (sz <= 0 || sz < sizeof(image_header_t)) {
debug("%s not found\n", aufile);
continue;
}
image_found = 1;
//au_check_header_valid()返回值小于0效验头不通过不升级
if (au_check_header_valid(i, sz) < 0) {
debug("%s header not valid\n", aufile);
continue;
}
sz = file_fat_read(aufile, LOAD_ADDR, MAX_LOADSZ);
debug("read %s sz %ld hdr %d\n",
aufile, sz, sizeof(image_header_t));
if (sz <= 0 || sz <= sizeof(image_header_t)) {
debug("%s not found\n", aufile);
continue;
}
//au_check_cksum_valid返回值小于0效验和不通过不升级
if (au_check_cksum_valid(i, sz) < 0) {
debug("%s checksum not valid\n", aufile);
continue;
}
/* If u-boot had been updated, we need to
* save current env to flash 如果u-boot已经更新,我们需要将当前环境保存为flash*/
if (0 == strcmp((char *)AU_FIRMWARE, aufile))
uboot_updated = 1;
/* this is really not a good idea, but it's what the */
/* customer wants. 这确实不是一个好主意,但这是客户想要的。*/
cnt = 0;
do {
res = au_do_update(i, sz);//写 flash
/* let the user break out of the loop让用户跳出循环 */
if (ctrlc() || had_ctrlc()) {
clear_ctrlc();
break;
}
cnt++;
#ifdef AU_TEST_ONLY
} while (res < 0 && cnt < 3);
if (cnt < 3)
#else
} while (res < 0);
#endif
}
if (1 == uboot_updated)
return 1;
if (1 == image_found)
return 0;
return -1;
}
/*
* This is called by board_init() after the hardware has been set up
* and is usable. Only if SPI flash initialization failed will this function
* return -1, otherwise it will return 0;
*在硬件设置好并可用之后,board_init()调用这个函数。只有SPI flash初始化失败时,该函数才返回-1,否则返回0;
*提供给外部的函数接口,是 auto update 的主函数。*/
int do_auto_update(void)
{
block_dev_desc_t *stor_dev;
int old_ctrlc;
int j;
int state = -1;
int dev;
au_stor_curr_dev = -1;
for (j = 0; j < MAX_UPDATE_INTF; j++) {
if (0 != (unsigned int)s_intf[j].name[0]) {
au_stor_curr_dev = s_intf[j].init();
if (-1 == au_stor_curr_dev) {
debug("No %s storage device found!\n",
s_intf[j].name);
continue;
}
dev = 0;
#if (defined CONFIG_HI3516CV300 || defined CONFIG_ARCH_HI3519 || \
defined CONFIG_ARCH_HI3519V101 || defined CONFIG_ARCH_HI3516AV200)
if (strncmp("mmc", s_intf[j].name, sizeof("mmc")) == 0)
dev = 2;
#endif
debug("device name %s!\n", s_intf[j].name);
stor_dev = get_dev(s_intf[j].name, dev);
if (NULL == stor_dev) {
debug("Unknow device type!\n");
continue;
}
if (fat_register_device(stor_dev, 1) != 0) {
debug("Unable to use %s %d:%d for fatls\n",
s_intf[j].name,
au_stor_curr_dev,
1);
continue;
}
if (file_fat_detectfs() != 0) {
debug("file_fat_detectfs failed\n");
continue;
}
/*
* Get image layout from environment.
* If the start address and the end address
* were not definedin environment virables,
* use the default value
从环境中获取图像布局。如果环境virables中没有定义开始地址和结束地址,请使用默认值
*/
get_update_env("firmware_st", "firmware_nd");
get_update_env("kernel_st", "kernel_nd");
get_update_env("rootfs_st", "rootfs_nd");
/*
* make sure that we see CTRL-C
* and save the old state
确保我们看到CTRL-C并保存旧状态
*/
old_ctrlc = disable_ctrlc(0);
/*
* CONFIG_SF_DEFAULT_SPEED=1000000,
* CONFIG_SF_DEFAULT_MODE=0x3
*/
flash = spi_flash_probe(0, 0, 1000000, 0x3);
if (!flash) {
printf("Failed to initialize SPI flash\n");
return -1;
}
state = update_to_flash();//功能更新flash;函数里面调用au_do_update();功能写flash
//调用au_check_header_valid()校验函数
/* restore the old state 恢复旧状态*/
disable_ctrlc(old_ctrlc);
s_intf[j].exit();
/*
* no update file found没有找到更新文件
*/
if (-1 == state)
continue;
/*
* update files have been found on current medium,
* so just break here
更新文件已在当前媒体上找到,因此请在此中断
*/
break;
}
}
/*
* If u-boot has been updated, it's better to save environment to flash
如果u-boot已经更新,最好将环境保存到flash中
*/
if (1 == state) {
env_crc_update();
saveenv();
}
return 0;
}
#endif /* CONFIG_AUTO_UPDATE */
我来回答
回答2个
时间排序
认可量排序
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片![alt](url)
相关问答
-
2015-03-07 08:01:38
-
2020-08-22 15:04:56
-
2020-09-17 10:40:09
-
2013-09-09 10:11:31
-
2017-10-13 15:27:20
-
2022-05-18 16:34:15
-
2019-09-03 14:45:40
-
2016-07-23 18:08:57
-
2016-07-09 10:55:07
-
2023-07-18 09:27:38
-
2023-07-14 14:40:23
-
2017-08-30 17:56:44
-
2018-12-05 10:16:45
-
2018-12-14 13:32:29
-
2019-08-13 09:54:38
-
2022-04-26 15:55:26
-
2017-05-11 15:04:03
-
2016-09-18 11:07:57
-
2024-01-18 18:28:31
无更多相似问答 去提问
点击登录
-- 积分
-- E币
提问
—
收益
—
被采纳
—
我要提问
切换马甲
上一页
下一页
悬赏问答
-
5SS928的emmc有32GB,bootargs设置使用16GB,但是为啥能用的只有rootfs的大小
-
33SS928怎样烧写ubuntu系统
-
10ToolPlatform下载rootfs提示网络失败
-
10谁有GK7205V500的SDK
-
5Hi3516CV610 烧录不进去
-
10Hi3559AV100 芯片硬解码h265编码格式的视频时出现视频播放错误,解码错误信息 s32PackErr:码流有错
-
5海思SS928 / SD3403的sample_venc.c摄像头编码Demo中,采集到的摄像头的YUV数据在哪个相关的函数中?
-
5海鸥派openEuler无法启动网卡,连接WIFI存在问题
-
66有没有ISP相关的巨佬帮忙看看SS928对接IMX347的图像问题
-
50求助hi3559与FPGA通过SLVS-EC接口对接问题
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
提醒
你的问题还没有最佳答案,是否结题,结题后将扣除20%的悬赏金
取消
确认
提醒
你的问题还没有最佳答案,是否结题,结题后将根据回答情况扣除相应悬赏金(1回答=1E币)
取消
确认