swupdate-yaffs根文件系统使用mtd-uitls nandwrite工具升级注意事项

最近调试嵌入式升级swupdate开源工具。

添加了在swupdate/handlers中添加了yaffs_handle.c

原工程文件在flash_erase和flash_write_image函数中没有详细关于nand flash oob区域的管理操作。需要加上这一部分的处理。

yaffs_handle.c代码如下:

/*
 * (C) Copyright 2014-2016
 * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
 *
 * Hamming code from
 * https://github.com/martinezjavier/writeloader
 * Copyright (C) 2011 ISEE 2007, SL
 * Author: Javier Martinez Canillas <martinez.javier@gmail.com>
 * Author: Agusti Fontquerni Gorchs <afontquerni@iseebcn.com>
 * Overview:
 *   Writes a loader binary to a NAND flash memory device and calculates
 *   1-bit Hamming ECC codes to fill the MTD's out-of-band (oob) area
 *   independently of the ECC technique implemented on the NAND driver.
 *   This is a workaround required for TI ARM OMAP DM3730 ROM boot to load.
 *
 * SPDX-License-Identifier:     GPL-2.0-or-later
 */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <linux/version.h>
#include <sys/ioctl.h>

#include <mtd/mtd-user.h>
#include <mtd/jffs2-user.h>

#include "swupdate.h"
#include "handler.h"
#include "util.h"
#include "flash.h"
#include "progress.h"

#define PROCMTD	"/proc/mtd"
#define LINESIZE	80
#define YAFFS_FS_TYPE	1

#define FILESYSTEM_OOB	YAFFS_FS_TYPE
#define MAX_PAGE_SIZE	8192
#define MAX_OOB_SIZE	512

#define DEBUG_BSTAR(a,x...) do{fprintf(stderr, "%s %s %d:"a, __FILE__, __FUNCTION__, __LINE__, ##x);}while(0)

static int jffs2 = 0;		// format for jffs2 usage
static bool	pad = false;
static int quiet = 0;

static struct jffs2_unknown_node cleanmarker;
static unsigned char writebuf[MAX_PAGE_SIZE];
static unsigned char oobbuf[MAX_OOB_SIZE];



void yaffs_handler(void);

/* Check whether buffer is filled with character 'pattern' */
static inline int buffer_check_pattern(unsigned char *buffer, size_t size,
                                       unsigned char pattern)
{
        /* Invalid input */
        if (!buffer || (size == 0))
                return 0;

        /* No match on first byte */
        if (*buffer != pattern)
                return 0;

        /* First byte matched and buffer is 1 byte long, OK. */
        if (size == 1)
                return 1;

        /*
         * Check buffer longer than 1 byte. We already know that buffer[0]
         * matches the pattern, so the test below only checks whether the
         * buffer[0...size-2] == buffer[1...size-1] , which is a test for
         * whether the buffer is filled with constant value.
         */
        return !memcmp(buffer, buffer + 1, size - 1);
}


/*
 * Writing to the NAND must take into account ECC errors
 * and BAD sectors.
 * This is not required for NOR flashes
 * The function reassembles nandwrite from mtd-utils
 * dropping all options that are not required here.
 */

static void erase_buffer(void *buffer, size_t size)
{
	const uint8_t kEraseByte = 0xff;

	if (buffer != NULL && size > 0)
		memset(buffer, kEraseByte, size);
}

#define DEBUG_FLAGS		1

static int yaffs_write_nand(int mtdnum, struct img_type *img)
{
	char mtd_device[LINESIZE];
	struct flash_description *flash = get_flash_info();
	struct mtd_dev_info *mtd = &flash->mtd_info[mtdnum].mtd;
	int pagelen;
	bool baderaseblock = false;
	long long imglen = 0;
	long long blockstart = -1;
	long long offs;
	unsigned char *filebuf = NULL;
	size_t filebuf_max = 0;
	size_t filebuf_len = 0;
	size_t ooblen = 0;
	size_t pagesize_with_oob = 0;
	long long mtdoffset = 0;
	int ifd = img->fdin;
	int fd = -1;
	bool failed = true;
	int ret;
	unsigned char *writebuf = NULL;
	unsigned int perc = 0;

	/*
	 * if nothing to do, returns without errors
	 */
	if (!img->size)
		return 0;

	pagelen = mtd->min_io_size;											//pagesize
	imglen = img->size;
	ooblen = mtd->oob_size;
	pagesize_with_oob = mtd->min_io_size + mtd->oob_size;

#if DEBUG_FLAGS
	printf("\tmtdnum:%d\n \tmtdsize:%lld\n \terasesize:%d\n \tpagesize:%d\n \toobsize:%d\n",\
			mtdnum,			mtd->size,	 mtd->eb_size,	mtd->min_io_size,mtd->oob_size);
#endif
	
	snprintf(mtd_device, sizeof(mtd_device), "/dev/mtd%d", mtdnum);

	if (imglen / pagesize_with_oob * mtd->min_io_size > mtd->size) {
		ERROR("Image %s does not fit into mtd%d", img->fname, mtdnum);
		return -EIO;
	}

	/* Flashing to NAND is currently not streamable */
	if (img->install_directly) {
		ERROR("Raw NAND not streamable");
		return -EINVAL;
	}

	filebuf_max = mtd->eb_size / mtd->min_io_size * pagesize_with_oob;
	filebuf = calloc(1, filebuf_max); 										//sizeof(filebuf) = block_size			
	erase_buffer(filebuf, filebuf_max);

	if ((fd = open(mtd_device, O_SYNC | O_RDWR)) < 0) {
		ERROR( "%s: %s: %s", __func__, mtd_device, strerror(errno));
		return -ENODEV;
	}

	/*
	 * Get data from input and write to the device while there is
	 * still input to read and we are still within the device
	 * bounds. Note that in the case of standard input, the input
	 * length is simply a quasi-boolean flag whose values are page
	 * length or zero.
	 */
	while ((imglen > 0 || writebuf < filebuf + filebuf_len)
		&& mtdoffset < mtd->size) {
		/*
		 * New eraseblock, check for bad block(s)
		 * Stay in the loop to be sure that, if mtdoffset changes because
		 * of a bad block, the next block that will be written to
		 * is also checked. Thus, we avoid errors if the block(s) after the
		 * skipped block(s) is also bad
		 * 申请一个block包含oob的内存空间,然后以pagesize_with_oob为单位进行读写操作
		 */
		while (blockstart != (mtdoffset & (~mtd->eb_size + 1))) {
			blockstart = mtdoffset & (~mtd->eb_size + 1);
			offs = blockstart;

			/*
			 * if writebuf == filebuf, we are rewinding so we must
			 * not reset the buffer but just replay it
			 */
			if (writebuf != filebuf) {
				erase_buffer(filebuf, filebuf_len);
				filebuf_len = 0;
				writebuf = filebuf;
			}

			baderaseblock = false;

			do {
				ret = mtd_is_bad(mtd, fd, offs / mtd->eb_size);
				if (ret < 0) {
					ERROR("mtd%d: MTD get bad block failed", mtdnum);
					goto closeall;
				} else if (ret == 1) {
					baderaseblock = true;
				}

				if (baderaseblock) {
					mtdoffset = blockstart + mtd->eb_size;

					if (mtdoffset > mtd->size) {
						ERROR("too many bad blocks, cannot complete request");
						goto closeall;
					}
				}

				offs +=  mtd->eb_size;
			} 
			while (offs < blockstart + mtd->eb_size);
		}

		/* Read more data from the input if there isn't enough in the buffer */
		if (writebuf + pagesize_with_oob > filebuf + filebuf_len) {
			size_t readlen = pagesize_with_oob;									//sizeof(readlen)=pagesize 
			size_t alreadyread = (filebuf + filebuf_len) - writebuf;
			size_t tinycnt = alreadyread;
			ssize_t cnt = 0;

			while (tinycnt < readlen) {
				cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
				if (cnt == 0) { /* EOF */
					break;
				} else if (cnt < 0) {
					ERROR("File I/O error on input");
					goto closeall;
				}
				tinycnt += cnt;
			}

			/* No padding needed - we are done */
			if (tinycnt == 0) {
				imglen = 0;
				break;
			}

			/* Padding */
			if (tinycnt < readlen) {
				erase_buffer(writebuf + tinycnt, readlen - tinycnt);
			}

			filebuf_len += readlen - alreadyread;

			imglen -= tinycnt - alreadyread;

		}

		ret =0;
		if (!buffer_check_pattern(writebuf, pagesize_with_oob, 0xff)) {
			/* Write out data */
			ret = mtd_write(flash->libmtd, mtd, fd, mtdoffset / mtd->eb_size,
					mtdoffset % mtd->eb_size,
					writebuf,
					mtd->min_io_size,
					writebuf+mtd->min_io_size,
					mtd->oob_size,
					MTD_OPS_PLACE_OOB);
		}
		if (ret) {
			long long i;
			if (errno != EIO) {
				ERROR("mtd%d: MTD write failure", mtdnum);
				goto closeall;
			}

			/* Must rewind to blockstart if we can */
			writebuf = filebuf;

			for (i = blockstart; i < blockstart + mtd->eb_size; i += mtd->eb_size) {
				if (mtd_erase(flash->libmtd, mtd, fd, i / mtd->eb_size)) {
					int errno_tmp = errno;
					TRACE("mtd%d: MTD Erase failure", mtdnum);
					if (errno_tmp != EIO)
						goto closeall;
				}
			}

			TRACE("Marking block at %08llx bad",
					mtdoffset & (~mtd->eb_size + 1));
			if (mtd_mark_bad(mtd, fd, mtdoffset / mtd->eb_size)) {
				ERROR("mtd%d: MTD Mark bad block failure", mtdnum);
				goto closeall;
			}
			mtdoffset = blockstart + mtd->eb_size;

			continue;
		}

		/*
		 * this handler does not use copyfile()
		 * and must update itself the progress bar
		 */
		swupdate_progress_update((img->size - imglen) * 100 / img->size);
		
#if DEBUG_FLAGS
		perc = (img->size - imglen) * 100 / img->size;
		printf("imgsize:%lld,left:imglen:%lld,yaffs install %d%\n",img->size,imglen,perc);
#endif 

		mtdoffset += mtd->min_io_size;
		writebuf += pagesize_with_oob;
	}
	failed = false;

closeall:
	free(filebuf);
	close(fd);

	if (failed) {
		ERROR("Installing image %s into mtd%d failed",
			img->fname,
			mtdnum);
		return -1;
	}

	return 0;
}

#if 0	//另外一种操作方式 也是ok的
static int yaffs_write_nand_bstar(int mtdnum, struct img_type *img)
{
	char mtd_device[LINESIZE];
	struct flash_description *flash = get_flash_info();
	struct mtd_dev_info *mtd = &flash->mtd_info[mtdnum].mtd;
	struct mtd_write_req eccbuf;
	erase_info_t erase;
	int pagelen;
	bool baderaseblock = false;
	long long imglen = 0;
	long long blockstart = -1;
	long long offs;
	unsigned char *filebuf = NULL;
	size_t filebuf_max = 0;
	size_t filebuf_len = 0;
	size_t ooblen = 0;
	size_t pagesize_with_oob = 0;
	long long mtdoffset = 0;
	int ifd = img->fdin;
	int fd = -1;
	bool failed = true;
	int ret;
	unsigned char *writebuf = NULL;
	unsigned int perc = 0;

	/*
	 * if nothing to do, returns without errors
	 */
	if (!img->size)
		return 0;

	pagelen = mtd->min_io_size;											//pagesize
	imglen = img->size;
	ooblen = mtd->oob_size;
	pagesize_with_oob = mtd->min_io_size + ((FILESYSTEM_OOB) ? mtd->oob_size : 0);

#if DEBUG_FLAGS
	printf("\tmtdnum:%d\n \tmtdsize:%lld\n \terasesize:%d\n \tpagesize:%d\n \toobsize:%d\n",\
			mtdnum,			mtd->size,	 mtd->eb_size,	mtd->min_io_size,mtd->oob_size);
#endif
	
	snprintf(mtd_device, sizeof(mtd_device), "/dev/mtd%d", mtdnum);

	if (imglen / pagesize_with_oob * mtd->min_io_size > mtd->size) {
		ERROR("Image %s does not fit into mtd%d", img->fname, mtdnum);
		return -EIO;
	}

	/* Flashing to NAND is currently not streamable */
	if (img->install_directly) {
		ERROR("Raw NAND not streamable");
		return -EINVAL;
	}

	filebuf_max = mtd->eb_size / mtd->min_io_size * pagesize_with_oob;
	filebuf = calloc(1, filebuf_max); 										//sizeof(filebuf) = block_size			
	erase_buffer(filebuf, filebuf_max);

	if ((fd = open(mtd_device, O_SYNC |O_RDWR)) < 0) {
		ERROR( "%s: %s: %s", __func__, mtd_device, strerror(errno));
		return -ENODEV;
	}

	/*
	 * Get data from input and write to the device while there is
	 * still input to read and we are still within the device
	 * bounds. Note that in the case of standard input, the input
	 * length is simply a quasi-boolean flag whose values are page
	 * length or zero.
	 */
	while ((imglen > 0 || writebuf < filebuf + filebuf_len)
		&& mtdoffset < mtd->size) {
		/*
		 * New eraseblock, check for bad block(s)
		 * Stay in the loop to be sure that, if mtdoffset changes because
		 * of a bad block, the next block that will be written to
		 * is also checked. Thus, we avoid errors if the block(s) after the
		 * skipped block(s) is also bad
		 * 申请一个block包含oob的内存空间,然后以pagesize_with_oob为单位进行读写操作
		 */
		while (blockstart != (mtdoffset & (~mtd->eb_size + 1))) {
			blockstart = mtdoffset & (~mtd->eb_size + 1);
			offs = blockstart;

			/*
			 * if writebuf == filebuf, we are rewinding so we must
			 * not reset the buffer but just replay it
			 */
			if (writebuf != filebuf) {
				erase_buffer(filebuf, filebuf_len);
				filebuf_len = 0;
				writebuf = filebuf;
			}

			baderaseblock = false;

			do {
				//ret = mtd_is_bad(mtd, fd, offs / mtd->eb_size);
				ret = ioctl(fd, MEMGETBADBLOCK, &offs);
				if (ret < 0) {
					ERROR("mtd%d: MTD get bad block failed", mtdnum);
					goto closeall;
				} else if (ret == 1) {
					baderaseblock = true;
				}

				if (baderaseblock) {
					mtdoffset = blockstart + mtd->eb_size;

					if (mtdoffset > mtd->size) {
						ERROR("too many bad blocks, cannot complete request");
						goto closeall;
					}
				}

				offs +=  mtd->eb_size;
			} 
			while (offs < blockstart + mtd->eb_size);
		}

		/* Read more data from the input if there isn't enough in the buffer */
		if (writebuf + pagesize_with_oob > filebuf + filebuf_len) {
			size_t readlen = pagesize_with_oob;									//sizeof(readlen)=pagesize 
			size_t alreadyread = (filebuf + filebuf_len) - writebuf;
			size_t tinycnt = alreadyread;
			ssize_t cnt = 0;

			while (tinycnt < readlen) {
				cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
				if (cnt == 0) { /* EOF */
					break;
				} else if (cnt < 0) {
					ERROR("File I/O error on input");
					goto closeall;
				}
				tinycnt += cnt;
			}

			/* No padding needed - we are done */
			if (tinycnt == 0) {
				imglen = 0;
				break;
			}

			/* Padding */
			if (tinycnt < readlen) {
				erase_buffer(writebuf + tinycnt, readlen - tinycnt);
			}

			filebuf_len += readlen - alreadyread;

			imglen -= tinycnt - alreadyread;

		}

		ret =0;
		if (!buffer_check_pattern(writebuf, pagesize_with_oob, 0xff)) {

			eccbuf.usr_data = writebuf;
        	eccbuf.len = mtd->min_io_size;
        	eccbuf.start    = mtdoffset;
		
			if(FILESYSTEM_OOB)
	        {
	            eccbuf.mode = MTD_OPS_PLACE_OOB;
	            eccbuf.usr_oob  = writebuf+mtd->min_io_size;
	            eccbuf.ooblen  = mtd->oob_size;
	        }    
	        else
	        {
	            eccbuf.mode = MTD_OPS_RAW;
	            eccbuf.usr_oob  = NULL;
	            eccbuf.ooblen  = 0;
	        }
			/* Write out data */
#if 0
			ret = mtd_write(flash->libmtd, mtd, fd, mtdoffset / mtd->eb_size,
					mtdoffset % mtd->eb_size,
					writebuf,
					mtd->min_io_size,
					writebuf+mtd->min_io_size,
					mtd->oob_size,
					MTD_OPS_PLACE_OOB);
#endif
			ret = ioctl(fd, MEMWRITE, &eccbuf);
	
		}
		if (ret) {
			long long i;
			if (errno != EIO) {
				ERROR("mtd%d: MTD write failure", mtdnum);
				goto closeall;
			}

			/* Must rewind to blockstart if we can */
			writebuf = filebuf;

			for (i = blockstart; i < blockstart + mtd->eb_size; i += mtd->eb_size) {
#if 0
				if (mtd_erase(flash->libmtd, mtd, fd, i / mtd->eb_size)) {
					int errno_tmp = errno;
					TRACE("mtd%d: MTD Erase failure", mtdnum);
					if (errno_tmp != EIO)
						goto closeall;
				}
#endif
				erase.start = blockstart;
	            erase.length = mtd->eb_size;
	            fprintf(stderr, "Erasing failed write from %08lx-%08lx\n",
	                    (long)erase.start, (long)erase.start+erase.length-1);
	            if (ioctl(fd, MEMERASE, &erase) != 0) {
	                perror("MEMERASE");
	                goto closeall;
	            }
			}

			TRACE("Marking block at %08llx bad",
					mtdoffset & (~mtd->eb_size + 1));
#if 0
			if (mtd_mark_bad(mtd, fd, mtdoffset / mtd->eb_size)) {
				ERROR("mtd%d: MTD Mark bad block failure", mtdnum);
				goto closeall;
			}
#endif
			mtdoffset = blockstart + mtd->eb_size;

			continue;
		}

		/*
		 * this handler does not use copyfile()
		 * and must update itself the progress bar
		 */
		swupdate_progress_update((img->size - imglen) * 100 / img->size);
		
#if DEBUG_FLAGS
		perc = (img->size - imglen) * 100 / img->size;
		printf("imgsize:%lld,left:imglen:%lld,yaffs install %d%\n",img->size,imglen,perc);
#endif 

		mtdoffset += mtd->min_io_size;
		writebuf += pagesize_with_oob;
	}
	failed = false;

closeall:
	free(filebuf);
	close(fd);

	if (failed) {
		ERROR("Installing image %s into mtd%d failed",
			img->fname,
			mtdnum);
		return -1;
	}

	return 0;
}
#endif

#if 1
static int flash_eraseall(int mtdnum)
{
	mtd_info_t meminfo;
	char mtd_device[80];
	struct mtd_dev_info *mtd;
	int fd, clmpos = 0, clmlen = 8;
	erase_info_t erase;
	int isNAND, bbtest = 1;
	

	struct flash_description *flash = get_flash_info();

	if  (!mtd_dev_present(flash->libmtd, mtdnum)) {
			ERROR("MTD %d does not exist", mtdnum);
			return -ENODEV;
	}
	mtd = &flash->mtd_info[mtdnum].mtd;
	snprintf(mtd_device, sizeof(mtd_device), "/dev/mtd%d", mtdnum);
	
	if ((fd = open(mtd_device, O_SYNC | O_RDWR)) < 0) {
		ERROR( "%s: %s: %s", __func__, mtd_device, strerror(errno));
		return -ENODEV;
	}


	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
		fprintf(stderr, " %s: unable to get MTD device info\n", mtd_device);
		return 1;
	}

	erase.length = meminfo.erasesize;
	isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0;

	if (jffs2) {
		cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
		cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
		if (!isNAND)
			cleanmarker.totlen = cpu_to_je32 (sizeof (struct jffs2_unknown_node));
		else {
			struct nand_oobinfo oobinfo;

			if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) {
				fprintf(stderr, " %s: unable to get NAND oobinfo\n", mtd_device);
				return 1;
			}

			/* Check for autoplacement */
			if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
				/* Get the position of the free bytes */
				if (!oobinfo.oobfree[0][1]) {
					fprintf (stderr, " Eeep. Autoplacement selected and no empty space in oob\n");
					return 1;
				}
				clmpos = oobinfo.oobfree[0][0];
				clmlen = oobinfo.oobfree[0][1];
				if (clmlen > 8)
					clmlen = 8;
			} else {
				/* Legacy mode */
				switch (meminfo.oobsize) {
					case 8:
						clmpos = 6;
						clmlen = 2;
						break;
					case 16:
						clmpos = 8;
						clmlen = 8;
						break;
					case 64:
						clmpos = 16;
						clmlen = 8;
						break;
				}
			}
			cleanmarker.totlen = cpu_to_je32(8);
		}
		cleanmarker.hdr_crc =  cpu_to_je32 (crc32 (0, &cleanmarker,  sizeof (struct jffs2_unknown_node) - 4));
	}

	//for (erase.start = offsetMtd; erase.start < offsetMtd+SizeMtd; erase.start += meminfo.erasesize) 
	for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) 
    {
		if (bbtest) {
			loff_t offset = erase.start;
			int ret = ioctl(fd, MEMGETBADBLOCK, &offset);
			if (ret > 0) {
				if (!quiet)
					DEBUG_BSTAR ("\nSkipping bad block at 0x%08x\n", erase.start);
				continue;
			} else if (ret < 0) {
				if (errno == EOPNOTSUPP) {
					bbtest = 0;
					if (isNAND) {
						fprintf(stderr, "%s: Bad block check not available\n",  mtd_device);
						return 1;
					}
				} else {
					fprintf(stderr, "\n %s: MTD get bad block failed: %s\n",  mtd_device, strerror(errno));
					return 1;
				}
			}
		}

        DEBUG_BSTAR("file:%s, line:%d, erase.start:%p\n", __FILE__, __LINE__, erase.start);


		if (ioctl(fd, MEMERASE, &erase) != 0) {
			fprintf(stderr, "\n %s: MTD Erase failure: %s\n", mtd_device, strerror(errno));
			continue;
		}

		/* format for JFFS2 ? */
		if (!jffs2)
			continue;

		/* write cleanmarker */
		if (isNAND) {
			struct mtd_oob_buf oob;
			oob.ptr = (unsigned char *) &cleanmarker;
			oob.start = erase.start + clmpos;
			oob.length = clmlen;
			if (ioctl (fd, MEMWRITEOOB, &oob) != 0) {
				fprintf(stderr, "\n %s: MTD writeoob failure: %s\n", mtd_device, strerror(errno));
				continue;
			}
		} else {
			if (lseek (fd, erase.start, SEEK_SET) < 0) {
				fprintf(stderr, "\n %s: MTD lseek failure: %s\n",  mtd_device, strerror(errno));
				continue;
			}
			if (write (fd , &cleanmarker, sizeof (cleanmarker)) != sizeof (cleanmarker)) {
				fprintf(stderr, "\n %s: MTD write failure: %s\n",  mtd_device, strerror(errno));
				continue;
			}
		}

	}

	close(fd);
	
    DEBUG_BSTAR("file:%s, line:%d, meminfo.size:%d\n", __FILE__, __LINE__, meminfo.size);
	return 0;
}
#endif



static int yaffs_write_image(int mtdnum, struct img_type *img)
{
	//return yaffs_write_nand_bstar(mtdnum, img);
	return yaffs_write_nand(mtdnum, img);
}

static int install_yaffs_image(struct img_type *img,
	void __attribute__ ((__unused__)) *data)
{
	char filename[64];
	int mtdnum;
	int n;
	const char* TMPDIR = get_tmpdir();

	n = snprintf(filename, sizeof(filename), "%s%s", TMPDIR, img->fname);
	if (n < 0 || n >= sizeof(filename)) {
		ERROR("Filename too long: %s", img->fname);
		return -1;
	}

	if (strlen(img->path))
		mtdnum = get_mtd_from_name(img->path);
	else
		mtdnum = get_mtd_from_device(img->device);
	if (mtdnum < 0) {
		ERROR("Wrong MTD device in description: %s",
			strlen(img->path) ? img->path : img->device);
		return -1;
	}

#if 1
	if(flash_eraseall(mtdnum)) {
		ERROR("I cannot erasing %s",
			img->device);
		return -1;
	}
#endif

	TRACE("Copying %s into /dev/mtd%d", img->fname, mtdnum);
	if (yaffs_write_image(mtdnum, img)) {
		ERROR("I cannot copy %s into %s partition",
			img->fname,
			img->device);
		return -1;
	}

	return 0;
}

__attribute__((constructor))
void yaffs_handler(void)
{
	register_handler("yaffs", install_yaffs_image,
				IMAGE_HANDLER | FILE_HANDLER, NULL);
}

代码仿照flash_handle.c撸完后,发现,文件系统升级成功这个事件呈现奇偶性。一次成功一次失败。怀疑是flash擦除根文件系统时不稳定。使用mtd-uitls工具中移植好的flash_erase工具配合swupdate升级一块调试,一样的效果。

 使用hexdump /dev/mtd3 指令(我的yaffs rootfs在mtd3),的确看到执行flash_erase的执行效果不一样。flash擦的干净时就可以升级成功。

怀疑个别进程占用了flash,导致flash擦除异常。kill掉多余进程,保证使用"mount -o remount -o ro /"重新挂载根文件系统,再次执行swupdate升级操作,百分百必成功。

 

还有一个关于写uboot env的注意事项。

如果需要支持在升级过程中修改uboot 的env变量值,在开源工具swupdate编译时需要引入libenv.a的库。此库实在uboot源码中:

使用make env ARCH=XXX CROSS_COMPILE=XXX来编译出的。

我现在用的版本是u-boot-2017.05,版本太高或太低编译可能会有问题(u-boot-2017.05\tools\env路径下可能生成不了lib.a文件)

lib.a就是swupdate所需的libenv.a。同时需要fw_printenv工具重命名后放到嵌入板"/var/lock/fw_printenv.lock",另外需要u-boot-2017.05\tools\env\fw_env.config,按照uboot中对应平台的配置头文件适当的修改其中参数即可。

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值