Exemplo n.º 1
0
static void pad(int size)
{
	if ((ofs % size == 0) && (ofs < erasesize))
		return;

	if (ofs < erasesize) {
		memset(buf + ofs, 0xff, (size - (ofs % size)));
		ofs += (size - (ofs % size));
	}
	ofs = ofs % erasesize;
	if (ofs == 0) {
		while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize)) {
			if (!quiet)
				fprintf(stderr, "\nSkipping bad block at 0x%08x   ", mtdofs);

			mtdofs += erasesize;

			/* Move the file pointer along over the bad block. */
			lseek(outfd, erasesize, SEEK_CUR);
		}
		mtd_erase_block(outfd, mtdofs);
		write(outfd, buf, erasesize);
		mtdofs += erasesize;
	}
}
Exemplo n.º 2
0
static int
mtd_erase(const char *mtd)
{
	int fd;
	struct erase_info_user mtdEraseInfo;

	if (quiet < 2)
		fprintf(stderr, "Erasing %s ...\n", mtd);

	fd = mtd_check_open(mtd);
	if(fd < 0) {
		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
		exit(1);
	}

	mtdEraseInfo.length = erasesize;

	for (mtdEraseInfo.start = 0;
		 mtdEraseInfo.start < mtdsize;
		 mtdEraseInfo.start += erasesize) {
		if (mtd_block_is_bad(fd, mtdEraseInfo.start)) {
			if (!quiet)
				fprintf(stderr, "\nSkipping bad block at 0x%x   ", mtdEraseInfo.start);
		} else {
			ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
			if(ioctl(fd, MEMERASE, &mtdEraseInfo))
				fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
		}
	}

	close(fd);
	return 0;

}
Exemplo n.º 3
0
static int
mtd_dump(const char *mtd, int part_offset, int size)
{
	int ret = 0, offset = 0;
	int fd;
	char *buf;

	if (quiet < 2)
		fprintf(stderr, "Dumping %s ...\n", mtd);

	fd = mtd_check_open(mtd);
	if(fd < 0) {
		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
		return -1;
	}

	if (!size)
		size = mtdsize;

	if (part_offset)
		lseek(fd, part_offset, SEEK_SET);

	buf = malloc(erasesize);
	if (!buf)
		return -1;

	do {
		int len = (size > erasesize) ? (erasesize) : (size);
		int rlen = read(fd, buf, len);

		if (rlen < 0) {
			if (errno == EINTR)
				continue;
			ret = -1;
			goto out;
		}
		if (!rlen || rlen != len)
			break;
		if (mtd_block_is_bad(fd, offset)) {
			fprintf(stderr, "skipping bad block at 0x%08x\n", offset);
		} else {
			size -= rlen;
			write(1, buf, rlen);
		}
		offset += rlen;
	} while (size > 0);

out:
	close(fd);
	return ret;
}
Exemplo n.º 4
0
static int
mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
{
	char *next = NULL;
	char *str = NULL;
	int fd, result;
	ssize_t r, w, e;
	ssize_t skip = 0;
	uint32_t offset = 0;
	int jffs2_replaced = 0;
	int skip_bad_blocks = 0;

#ifdef FIS_SUPPORT
	static struct fis_part new_parts[MAX_ARGS];
	static struct fis_part old_parts[MAX_ARGS];
	int n_new = 0, n_old = 0;

	if (fis_layout) {
		const char *tmp = mtd;
		char *word, *brkt;
		int ret;

		memset(&old_parts, 0, sizeof(old_parts));
		memset(&new_parts, 0, sizeof(new_parts));

		do {
			next = strchr(tmp, ':');
			if (!next)
				next = (char *) tmp + strlen(tmp);

			memcpy(old_parts[n_old].name, tmp, next - tmp);

			n_old++;
			tmp = next + 1;
		} while(*next);

		for (word = strtok_r(fis_layout, ",", &brkt);
		     word;
			 word = strtok_r(NULL, ",", &brkt)) {

			tmp = strtok(word, ":");
			strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1);

			tmp = strtok(NULL, ":");
			if (!tmp)
				goto next;

			new_parts[n_new].size = strtoul(tmp, NULL, 0);

			tmp = strtok(NULL, ":");
			if (!tmp)
				goto next;

			new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16);
next:
			n_new++;
		}
		ret = fis_validate(old_parts, n_old, new_parts, n_new);
		if (ret < 0) {
			fprintf(stderr, "Failed to validate the new FIS partition table\n");
			exit(1);
		}
		if (ret == 0)
			fis_layout = NULL;
	}
#endif

	if (strchr(mtd, ':')) {
		str = strdup(mtd);
		mtd = str;
	}

	r = 0;

resume:
	next = strchr(mtd, ':');
	if (next) {
		*next = 0;
		next++;
	}

	fd = mtd_check_open(mtd);
	if(fd < 0) {
		fprintf(stderr, "Could not open mtd device: %s\n", mtd);
		exit(1);
	}
	if (part_offset > 0) {
		fprintf(stderr, "Seeking on mtd device '%s' to: %zu\n", mtd, part_offset);
		lseek(fd, part_offset, SEEK_SET);
	}

	indicate_writing(mtd);

	w = e = 0;
	for (;;) {
		/* buffer may contain data already (from trx check or last mtd partition write attempt) */
		while (buflen < erasesize) {
			r = read(imagefd, buf + buflen, erasesize - buflen);
			if (r < 0) {
				if ((errno == EINTR) || (errno == EAGAIN))
					continue;
				else {
					perror("read");
					break;
				}
			}

			if (r == 0)
				break;

			buflen += r;
		}

		if (buflen == 0)
			break;

		if (buflen < erasesize) {
			/* Pad block to eraseblock size */
			memset(&buf[buflen], 0xff, erasesize - buflen);
			buflen = erasesize;
		}

		if (skip > 0) {
			skip -= buflen;
			buflen = 0;
			if (skip <= 0)
				indicate_writing(mtd);

			continue;
		}

		if (jffs2file && w >= jffs2_skip_bytes) {
			if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
				if (!quiet)
					fprintf(stderr, "\b\b\b   ");
				if (quiet < 2)
					fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
				/* got an EOF marker - this is the place to add some jffs2 data */
				skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
				jffs2_replaced = 1;

				/* don't add it again */
				jffs2file = NULL;

				w += skip;
				e += skip;
				skip -= buflen;
				buflen = 0;
				offset = 0;
				continue;
			}
			/* no EOF marker, make sure we figure out the last inode number
			 * before appending some data */
			mtd_parse_jffs2data(buf, jffs2dir);
		}

		/* need to erase the next block before writing data to it */
		if(!no_erase)
		{
			while (w + buflen > e - skip_bad_blocks) {
				if (!quiet)
					fprintf(stderr, "\b\b\b[e]");

				if (mtd_block_is_bad(fd, e)) {
					if (!quiet)
						fprintf(stderr, "\nSkipping bad block at 0x%08zx   ", e);

					skip_bad_blocks += erasesize;
					e += erasesize;

					// Move the file pointer along over the bad block.
					lseek(fd, erasesize, SEEK_CUR);
					continue;
				}

				if (mtd_erase_block(fd, e) < 0) {
					if (next) {
						if (w < e) {
							write(fd, buf + offset, e - w);
							offset = e - w;
						}
						w = 0;
						e = 0;
						close(fd);
						mtd = next;
						fprintf(stderr, "\b\b\b   \n");
						goto resume;
					} else {
						fprintf(stderr, "Failed to erase block\n");
						exit(1);
					}
				}

				/* erase the chunk */
				e += erasesize;
			}
		}

		if (!quiet)
			fprintf(stderr, "\b\b\b[w]");

		if ((result = write(fd, buf + offset, buflen)) < buflen) {
			if (result < 0) {
				fprintf(stderr, "Error writing image.\n");
				exit(1);
			} else {
				fprintf(stderr, "Insufficient space.\n");
				exit(1);
			}
		}
		w += buflen;

		buflen = 0;
		offset = 0;
	}

	if (jffs2_replaced && trx_fixup) {
		trx_fixup(fd, mtd);
	}

	if (!quiet)
		fprintf(stderr, "\b\b\b\b    ");

	if (quiet < 2)
		fprintf(stderr, "\n");

#ifdef FIS_SUPPORT
	if (fis_layout) {
		if (fis_remap(old_parts, n_old, new_parts, n_new) < 0)
			fprintf(stderr, "Failed to update the FIS partition table\n");
	}
#endif

	close(fd);
	return 0;
}
Exemplo n.º 5
0
int
flash_mtd_write(const char *mtd_part, int offset, unsigned char *buf, size_t count)
{
	int fd, ret, cnt, len, ofs, ofs_align, bad_shift;
	unsigned char *ptr, *tmp = NULL, *tmp_ubi = NULL;
	struct mtd_info mi;
	struct erase_info_user ei;

	if (!mtd_part || !buf || offset < 0 || count < 1)
		return -1;

	memset(&mi, 0, sizeof(mi));
	fd = mtd_dev_open(mtd_part, O_RDWR|O_SYNC, &mi);
	if (fd < 0) {
		fprintf(stderr, "%s: failed to open MTD partition %s\n",
			__func__, mtd_part);
		return -2;
	}

	ret = 0;

	if (((size_t)offset + count) > mi.size) {
		fprintf(stderr, "%s: out of MTD partition (offset: 0x%x, count: 0x%x, %s size: 0x%x)\n",
			__func__, offset, count, mi.dev, mi.size);
		ret = -3;
		goto out_err;
	}

	ptr = (unsigned char*) buf;

	/* align offset and length to write size of UBI volume backed MTD device. */
	if (mi.type == MTD_UBIVOLUME) {
		int old_offset = offset;
		size_t tmp_count, old_count = count;
		
		tmp_count = ROUNDUP((size_t)offset + count, mi.writesize);
		offset = ROUNDDOWN(offset, (int)mi.writesize);
		count = tmp_count - offset;
		
		if (offset != old_offset || count != old_count) {
			if (((size_t)offset + count) > mi.size) {
				fprintf(stderr, "%s: out of UBI partition. (aligned offset: 0x%x, count: 0x%x, %s size: 0x%x)\n",
					__func__, offset, count, mi.dev, mi.size);
				ret = -3;
				goto out_err;
			}
			
			tmp_ubi = malloc(count);
			if (!tmp_ubi) {
				fprintf(stderr, "%s: failed to alloc memory for %u bytes\n",
					__func__, count);
				ret = -1;
				goto out_err;
			}
			if (flash_mtd_read(mtd_part, offset, tmp_ubi, count) < 0) {
				ret = -4;
				goto out_err;
			}
			memcpy(tmp_ubi + (old_offset - offset), buf, old_count);
			ptr = tmp_ubi;
		}
	}

	tmp = (unsigned char *)malloc(mi.erasesize);
	if (!tmp) {
		fprintf(stderr, "%s: failed to alloc memory for %u bytes\n",
			__func__, mi.erasesize);
		ret = -1;
		goto out_err;
	}

	cnt = (int)count;
	ofs = offset;
	bad_shift = 0;

	while (cnt > 0) {
		ofs_align = ofs & ~(mi.erasesize - 1);	/* aligned to erase boundary */
		len = (int)mi.erasesize - (ofs - ofs_align);
		if (cnt < len)
			len = cnt;
		
		ei.start = ofs_align;
		ei.start += bad_shift;
		ei.length = mi.erasesize;
		
		/* check bad block */
		if (mtd_block_is_bad(fd, mi.type, ei.start)) {
			bad_shift += mi.erasesize;
			continue;
		}
		
		/* backup */
		if (lseek(fd, ei.start, SEEK_SET) < 0) {
			fprintf(stderr, "%s: failed to seek 0x%x on %s (errno: %d)\n",
				__func__, ei.start, mi.dev, errno);
			ret = -4;
			break;
		}
		if (read(fd, tmp, mi.erasesize) != mi.erasesize) {
			fprintf(stderr, "%s: failed to read %u bytes from %s (errno: %d)\n",
				__func__, mi.erasesize, mi.dev, errno);
			ret = -4;
			break;
		}
		
		/* erase */
		ioctl(fd, MEMUNLOCK, &ei);
		if (ioctl(fd, MEMERASE, &ei) < 0) {
			fprintf(stderr, "%s: failed to erase %s at start 0x%x, length 0x%x (errno: %d)\n",
				__func__, mi.dev, ei.start, ei.length, errno);
			ret = -5;
			break;
		}
		
		/* write */
		if (lseek(fd, ei.start, SEEK_SET) < 0) {
			fprintf(stderr, "%s: failed to seek 0x%x on %s (errno: %d)\n",
				__func__, ei.start, mi.dev, errno);
			ret = -6;
			break;
		}
		memcpy(tmp + (ofs - ofs_align), ptr, len);
		if (write(fd, tmp, mi.erasesize) != mi.erasesize) {
			fprintf(stderr, "%s: failed to write %u bytes to %s (errno: %d)\n",
				__func__, mi.erasesize, mi.dev, errno);
			ret = -6;
			break;
		}
		ptr += len;
		ofs += len;
		cnt -= len;
	}

	free(tmp);

	/* verify after write */
	if (cnt == 0 && mi.type != MTD_UBIVOLUME) {
		tmp = (unsigned char *)malloc(count);
		if (tmp) {
			if (flash_mtd_read(mtd_part, offset, tmp, count) == 0) {
				if (memcmp(tmp, buf, count) != 0) {
					fprintf(stderr, "%s: failed to verify after write to %s - data mismatch!\n",
						__func__, mi.dev);
					ret = -7;
				}
			}
			free(tmp);
		}
	}

out_err:

	if (tmp_ubi)
		free(tmp_ubi);

	close(fd);

	return ret;
}