static int write_eraseblock(int ebnum) { size_t written; int err = 0; loff_t addr = ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); err = mtd_write(mtd, addr, subpgsize, &written, writebuf); if (unlikely(err || written != subpgsize)) { pr_err("error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { pr_err(" write size: %#x\n", subpgsize); pr_err(" written: %#zx\n", written); } return err ? err : -1; } addr += subpgsize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); err = mtd_write(mtd, addr, subpgsize, &written, writebuf); if (unlikely(err || written != subpgsize)) { pr_err("error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { pr_err(" write size: %#x\n", subpgsize); pr_err(" written: %#zx\n", written); } return err ? err : -1; } return err; }
static int write_eraseblock_by_2pages(int ebnum) { size_t written, sz = pgsize * 2; int i, n = pgcnt / 2, err = 0; loff_t addr = ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < n; i++) { err = mtd_write(mtd, addr, sz, &written, buf); if (err || written != sz) { printk(PRINT_PREF "error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; return err; } addr += sz; buf += sz; } if (pgcnt % 2) { err = mtd_write(mtd, addr, pgsize, &written, buf); if (err || written != pgsize) { printk(PRINT_PREF "error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; } } return err; }
/** * nor_erase_prepare - prepare a NOR flash PEB for erasure. * @ubi: UBI device description object * @pnum: physical eraseblock number to prepare * * NOR flash, or at least some of them, have peculiar embedded PEB erasure * algorithm: the PEB is first filled with zeroes, then it is erased. And * filling with zeroes starts from the end of the PEB. This was observed with * Spansion S29GL512N NOR flash. * * This means that in case of a power cut we may end up with intact data at the * beginning of the PEB, and all zeroes at the end of PEB. In other words, the * EC and VID headers are OK, but a large chunk of data at the end of PEB is * zeroed. This makes UBI mistakenly treat this PEB as used and associate it * with an LEB, which leads to subsequent failures (e.g., UBIFS fails). * * This function is called before erasing NOR PEBs and it zeroes out EC and VID * magic numbers in order to invalidate them and prevent the failures. Returns * zero in case of success and a negative error code in case of failure. */ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) { int err; size_t written; loff_t addr; uint32_t data = 0; struct ubi_ec_hdr ec_hdr; struct ubi_vid_io_buf vidb; /* * Note, we cannot generally define VID header buffers on stack, * because of the way we deal with these buffers (see the header * comment in this file). But we know this is a NOR-specific piece of * code, so we can do this. But yes, this is error-prone and we should * (pre-)allocate VID header buffer instead. */ struct ubi_vid_hdr vid_hdr; /* * If VID or EC is valid, we have to corrupt them before erasing. * It is important to first invalidate the EC header, and then the VID * header. Otherwise a power cut may lead to valid EC header and * invalid VID header, in which case UBI will treat this PEB as * corrupted and will try to preserve it, and print scary warnings. */ addr = (loff_t)pnum * ubi->peb_size; err = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR && err != UBI_IO_FF){ err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); if(err) goto error; } ubi_init_vid_buf(ubi, &vidb, &vid_hdr); ubi_assert(&vid_hdr == ubi_get_vid_hdr(&vidb)); err = ubi_io_read_vid_hdr(ubi, pnum, &vidb, 0); if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR && err != UBI_IO_FF){ addr += ubi->vid_hdr_aloffset; err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); if (err) goto error; } return 0; error: /* * The PEB contains a valid VID or EC header, but we cannot invalidate * it. Supposedly the flash media or the driver is screwed up, so * return an error. */ ubi_err(ubi, "cannot invalidate PEB %d, write returned %d", pnum, err); ubi_dump_flash(ubi, pnum, 0, ubi->peb_size); return -EIO; }
static void test_mtd_write_nooob(void **state) { struct libmtd *lib = mock_libmtd_open(); int mock_fd = 4; int eb = 0xE0; int offs = 64; int len = 64; off_t seek; char buf[64]; memset(buf, 0xAA, len); struct mtd_dev_info mtd; memset(&mtd, 0, sizeof(mtd)); mtd.bb_allowed = 1; mtd.eb_cnt = 1024; mtd.eb_size = 128; mtd.subpage_size = 64; seek = (off_t)eb * mtd.eb_size + offs; expect_lseek(seek, SEEK_SET, seek); expect_write(buf, len, len); int r = mtd_write(lib, &mtd, mock_fd, eb, offs, buf, len, NULL, 0, 0); assert_int_equal(r, 0); libmtd_close(lib); (void)state; }
int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND, const u8 *data, const struct yaffs_spare *spare) { struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context); struct mtd_oob_ops ops; size_t dummy; int retval = 0; loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk; u8 spareAsBytes[8]; /* OOB */ if (data && !spare) retval = mtd_write(mtd, addr, dev->data_bytes_per_chunk, &dummy, data); else if (spare) { if (dev->param.use_nand_ecc) { translate_spare2oob(spare, spareAsBytes); ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = 8; /* temp hack */ } else { ops.mode = MTD_OPS_RAW; ops.ooblen = YAFFS_BYTES_PER_SPARE; } ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen; ops.datbuf = (u8 *)data; ops.ooboffs = 0; ops.oobbuf = spareAsBytes; retval = mtd_write_oob(mtd, addr, &ops); } if (retval == 0) return YAFFS_OK; else return YAFFS_FAIL; }
static void test_mtd_write_withoob(void **state) { struct libmtd *lib = mock_libmtd_open(); int mock_fd = 4; int eb = 0xE0; int offs = 64; int len = 64; int oob_len = 64; uint8_t mode = 3; off_t seek; char buf[64], oob_data[64]; struct mtd_dev_info mtd; struct mtd_write_req req; memset(buf, 0xAA, len); memset(oob_data, 0xBA, oob_len); memset(&mtd, 0, sizeof(mtd)); memset(&req, 0, sizeof(req)); mtd.bb_allowed = 1; mtd.eb_cnt = 1024; mtd.eb_size = 128; mtd.subpage_size = 64; seek = (off_t)eb * mtd.eb_size + offs; req.start = seek; req.len = len; req.ooblen = oob_len; req.usr_data = (uint64_t)(unsigned long)buf; req.usr_oob = (uint64_t)(unsigned long)oob_data; req.mode = mode; expect_ioctl(MEMWRITE, 0, &req); int r = mtd_write(lib, &mtd, mock_fd, eb, offs, buf, len, oob_data, oob_len, mode); assert_int_equal(r, 0); libmtd_close(lib); (void) state; }
static inline int write_pattern(int ebnum, void *buf) { int err; size_t written; loff_t addr = ebnum * mtd->erasesize; size_t len = mtd->erasesize; if (pgcnt) { addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; len = pgcnt * pgsize; } err = mtd_write(mtd, addr, len, &written, buf); if (err) { pr_err("error %d while writing EB %d, written %zd" " bytes\n", err, ebnum, written); return err; } if (written != len) { pr_info("written only %zd bytes of %zd, but no error" " reported\n", written, len); return -EIO; } return 0; }
static int mtd_blockdev_erase_write(struct vmm_request *r, physical_addr_t off, physical_size_t len, struct mtd_info *mtd) { struct erase_info info; unsigned int retlen = 0; info.mtd = mtd; info.addr = off; info.len = len; info.callback = mtd_blockdev_erase_callback; if (mtd_erase(mtd, &info)) { dev_err(&r->bdev->dev, "Erasing at 0x%08X failed\n", off); return VMM_EIO; } if (mtd_write(mtd, off, len, &retlen, r->data)) { dev_err(&r->bdev->dev, "Writing at 0x%08X failed\n", off); return VMM_EIO; } if (retlen < len) { dev_warn(&r->bdev->dev, "Only 0x%X/0x%X bytes have been " "written at 0x%08X\n", retlen, len, off); return VMM_EIO; } return VMM_OK; }
static int write_eraseblock2(int ebnum) { size_t written; int err = 0, k; loff_t addr = ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) break; prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); if (unlikely(err || written != subpgsize * k)) { pr_err("error: write failed at %#llx\n", (long long)addr); if (written != subpgsize) { pr_err(" write size: %#x\n", subpgsize * k); pr_err(" written: %#08zx\n", written); } return err ? err : -1; } addr += subpgsize * k; } return err; }
static int erasetest(void) { size_t read, written; int err = 0, i, ebnum, ok = 1; loff_t addr0; printk(PRINT_PREF "erasetest\n"); ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } printk(PRINT_PREF "erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); set_random_data(writebuf, pgsize); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } printk(PRINT_PREF "erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); err = mtd_read(mtd, addr0, pgsize, &read, twopages); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n", ebnum); for (i = 0; i < pgsize; ++i) if (twopages[i] != 0xff) { printk(PRINT_PREF "verifying all 0xff failed at %d\n", i); errcnt += 1; ok = 0; break; } if (ok && !err) printk(PRINT_PREF "erasetest ok\n"); return err; }
static void mtdoops_write(struct mtdoops_context *cxt, int panic) { struct mtd_info *mtd = cxt->mtd; size_t retlen; u32 *hdr; int ret; /* Add mtdoops header to the buffer */ hdr = cxt->oops_buf; hdr[0] = cxt->nextcount; hdr[1] = MTDOOPS_KERNMSG_MAGIC; if (panic) { ret = mtd_panic_write(mtd, cxt->nextpage * record_size, record_size, &retlen, cxt->oops_buf); if (ret == -EOPNOTSUPP) { printk(KERN_ERR "mtdoops: Cannot write from panic without panic_write\n"); return; } } else ret = mtd_write(mtd, cxt->nextpage * record_size, record_size, &retlen, cxt->oops_buf); if (retlen != record_size || ret < 0) printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n", cxt->nextpage * record_size, retlen, record_size, ret); mark_page_used(cxt, cxt->nextpage); memset(cxt->oops_buf, 0xff, record_size); mtdoops_inc_counter(cxt); }
int bc_ll_set_rootfs_healthy( struct bootconfig * bc, unsigned int block ) { int err; char *page; struct btblock * curr; if (! initialised) { bc_log( LOG_ERR, "Internal error: called before initialisation!\n"); exit(1); } curr = &bc->blocks[ block ]; if ( curr->rootfs.n_healthy == 1) { curr->rootfs.n_healthy = 0; page = malloc( bc->info.min_io_size ); if( NULL == page ) { bc_log( LOG_ERR, "Error #%d malloc()ing %d bytes: %s.\n",errno, bc->info.min_io_size, strerror(errno)); return -1; } memset( page, 0xFF, bc->info.min_io_size ); memcpy( page, &bc->blocks[ block ], sizeof( *bc->blocks ) ); err = mtd_write( bc->mtd, &bc->info, bc->fd, block, 0, page, bc->info.min_io_size , NULL, 0, 0 ); free( page ); if (0 > err) return 1; } return 0; }
static int _do_write_bootblock( struct bootconfig * bc, unsigned int block_idx ) { int err; char *page; err = mtd_erase( bc->mtd, &bc->info, bc->fd, block_idx ); if (0 > err) return 1; page = malloc( bc->info.min_io_size ); if( NULL == page ) { bc_log( LOG_ERR, "Error #%d malloc()ing %d bytes: %s.\n", errno, bc->info.min_io_size, strerror(errno)); return -1; } memset( page, 0xFF, bc->info.min_io_size ); memcpy( page, &bc->blocks[ block_idx ], sizeof( *bc->blocks ) ); err = mtd_write( bc->mtd, &bc->info, bc->fd, block_idx, 0, page, bc->info.min_io_size , NULL, 0, 0 ); free( page ); if (0 > err) return 1; return 0; }
int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb) { int err, i, patt_count; void *buf; normsg("run torture test for PEB %d", eb); patt_count = ARRAY_SIZE(patterns); buf = malloc(mtd->eb_size); if (!buf) { errmsg("cannot allocate %d bytes of memory", mtd->eb_size); return -1; } for (i = 0; i < patt_count; i++) { err = mtd_erase(mtd, fd, eb); if (err) goto out; /* Make sure the PEB contains only 0xFF bytes */ err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size); if (err) goto out; err = check_pattern(buf, 0xFF, mtd->eb_size); if (err == 0) { errmsg("erased PEB %d, but a non-0xFF byte found", eb); errno = EIO; goto out; } /* Write a pattern and check it */ memset(buf, patterns[i], mtd->eb_size); err = mtd_write(mtd, fd, eb, 0, buf, mtd->eb_size); if (err) goto out; memset(buf, ~patterns[i], mtd->eb_size); err = mtd_read(mtd, fd, eb, 0, buf, mtd->eb_size); if (err) goto out; err = check_pattern(buf, patterns[i], mtd->eb_size); if (err == 0) { errmsg("pattern %x checking failed for PEB %d", patterns[i], eb); errno = EIO; goto out; } } err = 0; normsg("PEB %d passed torture test, do not mark it a bad", eb); out: free(buf); return -1; }
void images_write(Image* image, void* data, unsigned int length, int encrypt) { bufferPrintf("images_write(%x, %x, %x)\r\n", image, data, length); if(image == NULL) return; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); uint32_t padded = length; if((length & 0xF) != 0) { padded = (padded & ~0xF) + 0x10; } if(image->next != NULL && (image->offset + sizeof(Img2Header) + padded) >= image->next->offset) { bufferPrintf("**ABORTED** requested length greater than available space.\r\n"); return; } uint32_t totalLen = sizeof(Img2Header) + padded; uint8_t* writeBuffer = (uint8_t*) malloc(totalLen); mtd_read(dev, writeBuffer, image->offset, sizeof(Img2Header)); memcpy(writeBuffer + sizeof(Img2Header), data, length); if(encrypt) aes_838_encrypt(writeBuffer + sizeof(Img2Header), padded, NULL); Img2Header* header = (Img2Header*) writeBuffer; header->dataLen = length; header->dataLenPadded = padded; calculateDataHash(writeBuffer + sizeof(Img2Header), padded, header->dataHash); uint32_t checksum = 0; crc32(&checksum, writeBuffer, 0x64); header->header_checksum = checksum; calculateHash(header, header->hash); bufferPrintf("mtd_write(0x%p, %x, %x, %x)\r\n", dev, writeBuffer, image->offset, totalLen); mtd_write(dev, writeBuffer, image->offset, totalLen); bufferPrintf("mtd_write(0x%p, %x, %x, %x) done\r\n", dev, writeBuffer, image->offset, totalLen); free(writeBuffer); mtd_finish(dev); images_release(); images_setup(); }
int main(void) { while(1){ mtd_erase(); mtd_write(); sleep(1); } return 0; }
static ssize_t mtd_op_write(struct cdev* cdev, const void *buf, size_t _count, loff_t _offset, ulong flags) { struct mtd_info *mtd = cdev->priv; size_t retlen; int ret; ret = mtd_write(mtd, _offset, _count, &retlen, buf); return ret ? ret : _count; }
void images_from_template(Image* image, uint32_t type, int index, void* dataBuffer, unsigned int len, int encrypt) { if(image == NULL) return; mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); uint32_t offset = MaxOffset + (SegmentSize - (MaxOffset % SegmentSize)); uint32_t padded = len; if((len & 0xF) != 0) { padded = (padded & ~0xF) + 0x10; } uint32_t totalLen = sizeof(Img2Header) + padded; uint8_t* buffer = (uint8_t*) malloc(totalLen); mtd_read(dev, buffer, image->offset, sizeof(Img2Header)); Img2Header* header = (Img2Header*) buffer; header->imageType = type; if(index >= 0) header->index = index; header->dataLen = len; header->dataLenPadded = padded; memcpy(buffer + sizeof(Img2Header), dataBuffer, len); if(encrypt) aes_838_encrypt(buffer + sizeof(Img2Header), padded, NULL); calculateDataHash(buffer + sizeof(Img2Header), image->padded, header->dataHash); uint32_t checksum = 0; crc32(&checksum, buffer, 0x64); header->header_checksum = checksum; calculateHash(header, header->hash); mtd_write(dev, buffer, offset, totalLen); free(buffer); mtd_finish(dev); images_release(); images_setup(); }
int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, const void *buf) { size_t written; int err; err = mtd_write(mtd, addr, size, &written, buf); if (!err && written != size) err = -EIO; if (err) pr_err("error: write failed at %#llx\n", addr); return err; }
static int write_eraseblock(int ebnum) { int err = 0; size_t written; loff_t addr = ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); cond_resched(); err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf); if (err || written != mtd->erasesize) pr_err("error: write failed at %#llx\n", (long long)addr); return err; }
static int write_eraseblock(int ebnum) { int err = 0; size_t written; loff_t addr = ebnum * mtd->erasesize; set_random_data(writebuf, mtd->erasesize); cond_resched(); err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf); if (err || written != mtd->erasesize) printk(PRINT_PREF "error: write failed at %#llx\n", (long long)addr); return err; }
static int write_eraseblock(int ebnum) { size_t written; int err = 0; loff_t addr = ebnum * mtd->erasesize; err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf); if (err || written != mtd->erasesize) { printk(PRINT_PREF "error: write failed at %#llx\n", addr); if (!err) err = -EINVAL; } return err; }
void images_append(void* data, int len) { mtd_t *dev = images_device(); if(!dev) return; mtd_prepare(dev); if(MaxOffset >= 0xfc000 || (MaxOffset + len) >= 0xfc000) { bufferPrintf("**ABORTED** Writing image of size %d at %x would overflow NOR!\r\n", len, MaxOffset); } else { mtd_write(dev, data, MaxOffset, len); // Destroy any following image if((MaxOffset + len) < 0xfc000) { uint8_t zero = 0; mtd_write(dev, &zero, MaxOffset + len, 1); } images_release(); images_setup(); } mtd_finish(dev); }
static int _dev_write(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { littlefs_desc_t *fs = c->context; mtd_dev_t *mtd = fs->dev; DEBUG("lfs_write: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n", (void *)c, block, off, buffer, size); int ret = mtd_write(mtd, buffer, ((fs->base_addr + block) * c->block_size) + off, size); if (ret >= 0) { return 0; } return ret; }
int saveenv(void) { env_t env_new; ssize_t len; char *res; struct mtd_info *mtd = &onenand_mtd; #ifdef CONFIG_ENV_ADDR_FLEX struct onenand_chip *this = &onenand_chip; #endif loff_t env_addr = CONFIG_ENV_ADDR; size_t retlen; struct erase_info instr = { .callback = NULL, }; res = (char *)&env_new.data; len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } env_new.crc = crc32(0, env_new.data, ENV_SIZE); instr.len = CONFIG_ENV_SIZE; #ifdef CONFIG_ENV_ADDR_FLEX if (FLEXONENAND(this)) { env_addr = CONFIG_ENV_ADDR_FLEX; instr.len = CONFIG_ENV_SIZE_FLEX; instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ? 1 : 0; } #endif instr.addr = env_addr; instr.mtd = mtd; if (mtd_erase(mtd, &instr)) { printf("OneNAND: erase failed at 0x%08llx\n", env_addr); return 1; } if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen, (u_char *)&env_new)) { printf("OneNAND: write failed at 0x%llx\n", instr.addr); return 2; } return 0; }
static int erase_write (struct mtd_info *mtd, unsigned long pos, int len, const char *buf) { struct erase_info erase; DECLARE_WAITQUEUE(wait, current); wait_queue_head_t wait_q; size_t retlen; int ret; /* * First, let's erase the flash block. */ init_waitqueue_head(&wait_q); erase.mtd = mtd; erase.callback = erase_callback; erase.addr = pos; erase.len = len; erase.priv = (u_long)&wait_q; set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&wait_q, &wait); ret = mtd_erase(mtd, &erase); if (ret) { set_current_state(TASK_RUNNING); remove_wait_queue(&wait_q, &wait); printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] " "on \"%s\" failed\n", pos, len, mtd->name); return ret; } schedule(); /* Wait for erase to finish. */ remove_wait_queue(&wait_q, &wait); /* * Next, write the data to flash. */ ret = mtd_write(mtd, pos, len, &retlen, buf); if (ret) return ret; if (retlen != len) return -EIO; return 0; }
static int concat_write(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { struct mtd_concat *concat = CONCAT(mtd); int err = -EINVAL; int i; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; *retlen = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size, retsize; if (to >= subdev->size) { size = 0; to -= subdev->size; continue; } if (to + len > subdev->size) size = subdev->size - to; else size = len; if (!(subdev->flags & MTD_WRITEABLE)) err = -EROFS; else err = mtd_write(subdev, to, size, &retsize, buf); if (err) break; *retlen += retsize; len -= size; if (len == 0) break; err = -EINVAL; buf += size; to = 0; } return err; }
static int bitfliptest_do_write(void) { int err = 0; loff_t addr = 0; size_t written = 0; int eb = bitfliptest_rand_eb(); unsigned int offs = 0, len = 0; offs = offsets[eb]; if (offs >= mtd->erasesize) { err = mtd_test_erase_eraseblock(eb, 0); if (err) return err; offs = offsets[eb] = 0; } len = bitfliptest_rand_len(offs); len = ((len + pgsize - 1) / pgsize) * pgsize; if (offs + len > mtd->erasesize) { if (bbt[eb + 1]) len = mtd->erasesize - offs; else { // pr_info("erase, block: %d\n", eb + 1); err = mtd_test_erase_eraseblock(eb + 1, 0); if (err) return err; offsets[eb + 1] = 0; } } addr = eb * mtd->erasesize + offs; // pr_info("write, addr: 0x%.8x len: %d\n", (unsigned int)addr, len); err = mtd_write(mtd, addr, len, &written, writebuf); if (unlikely(err || written != len)) { pr_err("error: write failed at 0x%llx\n", (long long)addr); if (!err) err = -EINVAL; return err; } offs += len; while (offs > mtd->erasesize) { offsets[eb++] = mtd->erasesize; offs -= mtd->erasesize; } offsets[eb] = offs; return 0; }
static int cmd_flash_write(struct vmm_chardev *cdev, int argc, char **argv) { int err = VMM_OK; int idx = 0; size_t retlen = 0; flash_op op; u_char *buf = NULL; if (VMM_OK != (err = flash_args_common(cdev, argc, argv, &op))) { return err; } vmm_cprintf(cdev, "Before writing, the %s block at 0x%08X must have " "been erased?\n", op.mtd->name, op.offset & ~op.mtd->erasesize_mask); if (!flash_question(cdev)) { vmm_cprintf(cdev, "Exiting...\n"); return VMM_OK; } if (argc - 4 <= 0) { vmm_cprintf(cdev, "Nothing to write, exiting\n"); return VMM_OK; } if (NULL == (buf = vmm_malloc(argc - 5))) { return VMM_ENOMEM; } for (idx = 0; idx < argc - 4; ++idx) { buf[idx] = strtoull(argv[idx + 4], NULL, 16); vmm_cprintf(cdev, "Writing at 0x%08X 0x%02X\n", op.offset + idx, buf[idx]); } if (0 != mtd_write(op.mtd, op.offset, argc - 4, &retlen, buf)) { vmm_cprintf(cdev, "Failed to write %s at 0x%08X\n", op.mtd->name, op.offset); } vmm_free(buf); return err; }
static int env_onenand_save(void) { env_t env_new; int ret; struct mtd_info *mtd = &onenand_mtd; #ifdef CONFIG_ENV_ADDR_FLEX struct onenand_chip *this = &onenand_chip; #endif loff_t env_addr = CONFIG_ENV_ADDR; size_t retlen; struct erase_info instr = { .callback = NULL, }; ret = env_export(&env_new); if (ret) return ret; instr.len = CONFIG_ENV_SIZE; #ifdef CONFIG_ENV_ADDR_FLEX if (FLEXONENAND(this)) { env_addr = CONFIG_ENV_ADDR_FLEX; instr.len = CONFIG_ENV_SIZE_FLEX; instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ? 1 : 0; } #endif instr.addr = env_addr; instr.mtd = mtd; if (mtd_erase(mtd, &instr)) { printf("OneNAND: erase failed at 0x%08llx\n", env_addr); return 1; } if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen, (u_char *)&env_new)) { printf("OneNAND: write failed at 0x%llx\n", instr.addr); return 2; } return 0; }