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 verify_eraseblock(int ebnum) { uint32_t j; int err = 0, i; loff_t addr0, addrn; loff_t addr = (loff_t)ebnum * mtd->erasesize; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) addr0 += mtd->erasesize; addrn = mtd->size; for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i) addrn -= mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { /* Do a read to set the internal dataRAMs to different data */ err = mtdtest_read(mtd, addr0, bufsize, twopages); if (err) return err; err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages); if (err) return err; memset(twopages, 0, bufsize); err = mtdtest_read(mtd, addr, bufsize, twopages); if (err) break; if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } } /* Check boundary between eraseblocks */ if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { struct rnd_state old_state = rnd_state; /* Do a read to set the internal dataRAMs to different data */ err = mtdtest_read(mtd, addr0, bufsize, twopages); if (err) return err; err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages); if (err) return err; memset(twopages, 0, bufsize); err = mtdtest_read(mtd, addr, bufsize, twopages); if (err) return err; memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize); if (memcmp(twopages, boundary, bufsize)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } rnd_state = old_state; } return err; }
static int verify_eraseblock(int ebnum) { size_t read; int err = 0; loff_t addr = ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); clear_data(readbuf, subpgsize); err = mtd_read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (mtd_is_bitflip(err) && read == subpgsize) { pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { pr_err("error: read failed at %#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { pr_err("error: verify failed at %#llx\n", (long long)addr); pr_info("------------- written----------------\n"); print_subpage(writebuf); pr_info("------------- read ------------------\n"); print_subpage(readbuf); pr_info("-------------------------------------\n"); errcnt += 1; } addr += subpgsize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); clear_data(readbuf, subpgsize); err = mtd_read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { if (mtd_is_bitflip(err) && read == subpgsize) { pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { pr_err("error: read failed at %#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { pr_info("error: verify failed at %#llx\n", (long long)addr); pr_info("------------- written----------------\n"); print_subpage(writebuf); pr_info("------------- read ------------------\n"); print_subpage(readbuf); pr_info("-------------------------------------\n"); errcnt += 1; } return err; }
static int verify_eraseblock_in_one_go(int ebnum) { struct mtd_oob_ops ops; int err = 0; loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t len = mtd->ecclayout->oobavail * pgcnt; prandom_bytes_state(&rnd_state, writebuf, len); ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = len; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf, writebuf, len)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); return -1; } } return err; }
static int verify_eraseblock2(int ebnum) { size_t read; 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); clear_data(readbuf, subpgsize * k); err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf); if (unlikely(err || read != subpgsize * k)) { if (mtd_is_bitflip(err) && read == subpgsize * k) { pr_info("ECC correction at %#llx\n", (long long)addr); err = 0; } else { pr_err("error: read failed at " "%#llx\n", (long long)addr); return err ? err : -1; } } if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; } addr += subpgsize * k; } return err; }
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 write_eraseblock(int ebnum) { int i; struct mtd_oob_ops ops; int err = 0; loff_t addr = ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; ops.oobretlen = 0; ops.ooboffs = use_offset; ops.datbuf = NULL; ops.oobbuf = writebuf + (use_len_max * i) + use_offset; err = mtd_write_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { pr_err("error: writeoob failed at %#llx\n", (long long)addr); pr_err("error: use_len %d, use_offset %d\n", use_len, use_offset); errcnt += 1; return err ? err : -1; } if (vary_offset) do_vary_offset(); } return err; }
static int erasetest(void) { size_t read, written; int err = 0, i, ebnum, ok = 1; loff_t addr0; pr_info("erasetest\n"); ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; pr_info("writing 1st page of block %d\n", ebnum); prandom_bytes_state(&rnd_state, writebuf, pgsize); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { pr_err("error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; pr_info("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) { pr_err("error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } pr_info("verifying 1st page of block %d is all 0xff\n", ebnum); for (i = 0; i < pgsize; ++i) if (twopages[i] != 0xff) { pr_err("verifying all 0xff failed at %d\n", i); errcnt += 1; ok = 0; break; } if (ok && !err) pr_info("erasetest ok\n"); return err; }
static int write_eraseblock(int ebnum) { loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); cond_resched(); return mtdtest_write(mtd, addr, mtd->erasesize, writebuf); }
static int erasetest(void) { int err = 0, i, ebnum, ok = 1; loff_t addr0; pr_info("erasetest\n"); ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } pr_info("erasing block %d\n", ebnum); err = mtdtest_erase_eraseblock(mtd, ebnum); if (err) return err; pr_info("writing 1st page of block %d\n", ebnum); prandom_bytes_state(&rnd_state, writebuf, pgsize); err = mtdtest_write(mtd, addr0, pgsize, writebuf); if (err) return err; pr_info("erasing block %d\n", ebnum); err = mtdtest_erase_eraseblock(mtd, ebnum); if (err) return err; pr_info("reading 1st page of block %d\n", ebnum); err = mtdtest_read(mtd, addr0, pgsize, twopages); if (err) return err; pr_info("verifying 1st page of block %d is all 0xff\n", ebnum); for (i = 0; i < pgsize; ++i) if (twopages[i] != 0xff) { pr_err("verifying all 0xff failed at %d\n", i); errcnt += 1; ok = 0; break; } if (ok && !err) pr_info("erasetest ok\n"); 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 verify_eraseblock_in_one_go(int ebnum) { struct mtd_oob_ops ops; int err = 0; loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t len = mtd->ecclayout->oobavail * pgcnt; size_t oobavail = mtd->ecclayout->oobavail; size_t bitflips; int i; prandom_bytes_state(&rnd_state, writebuf, len); ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = len; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; /* read entire block's OOB at one go */ err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } /* verify one page OOB at a time for bitflip per page limit check */ for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { bitflips = memcmpshow(addr, readbuf + (i * oobavail), writebuf + (i * oobavail), oobavail); if (bitflips > bitflip_limit) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); return -1; } } else if (bitflips) { pr_info("ignoring error as within bitflip_limit\n"); } } return err; }
static int __init nandflash_ecctest_init(void) { unsigned int read_len = 0; int err = 0; loff_t offset = 0; unsigned int j = 0; struct rnd_state rnd_state; unsigned int corrected_num = 0; unsigned char *oobbuf_w = NULL; unsigned char *oobbuf_r = NULL; unsigned char *pagebuf_r = NULL; unsigned char *pagebuf_w = NULL; unsigned char *pagebuf_v = NULL; struct mtd_ecc_stats stats = {0}; struct mtd_part *mtd_part = NULL; printk("\n"); pr_info("--------------------------------------------------------------------------\n"); /*prepare work*/ mtd = get_mtd_device(NULL, 4); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("Cannot get MTD device\n"); return err; } mtd_part = (struct mtd_part *)mtd; if(!mtd->_block_isbad || !mtd->_block_markbad || !mtd->_read_oob || !mtd->_write_oob || !mtd->_read || !mtd->_write) { pr_err("Some mtd's method may be NULL!"); goto out; } pagebuf_r = vmalloc(mtd->writesize); oobbuf_r = vmalloc(mtd->oobsize); pagebuf_w = vmalloc(mtd->writesize); pagebuf_v = vmalloc(mtd->writesize); oobbuf_w = vmalloc(mtd->oobsize); if(!pagebuf_r || !oobbuf_r || !pagebuf_w || !pagebuf_v || !oobbuf_w) { pr_err("Alloc buf failed!"); goto out; } //find a vailid block while(offset < mtd->size) { if(mtd->_block_isbad(mtd, offset)) { offset += mtd->erasesize; } else { break; } } if(offset >= mtd->size) { pr_err("The whole mtd_partion are bad!\n"); goto out; } err = erase_eraseblock(((long)offset)/mtd->erasesize); if(err) { pr_err("Erase failed at EB: %d\n", ((unsigned int)offset)/mtd->erasesize); goto out; } pr_info("Erase block %d successfully!\n", ((unsigned int)offset)/mtd->erasesize); //prepare value prandom_seed_state(&rnd_state, 1); prandom_bytes_state(&rnd_state, oobbuf_w, mtd->oobsize); prandom_bytes_state(&rnd_state, pagebuf_w, mtd->writesize); memcpy(pagebuf_v, pagebuf_w, mtd->writesize); err = write_oob(offset, pagebuf_w, mtd->writesize, oobbuf_w, mtd->oobsize, MTD_OPS_PLACE_OOB); if(err != 0) { pr_err("1.1 write failed!\n"); goto erase; } err = read_oob(offset, pagebuf_r, mtd->writesize, oobbuf_r, mtd->oobsize, MTD_OPS_PLACE_OOB); if(err != 0) { pr_err("1.1 read failed!\n"); goto erase; } if(memcmp(pagebuf_v, pagebuf_r, mtd->writesize) != 0) { pr_err("1.1 compare page failed!\n"); goto erase; } memcpy(oobbuf_w, oobbuf_r, mtd->oobsize); for(j = 0; j < mtd->writesize * 8; j ++) { offset += mtd->writesize; err = insert_biterror(pagebuf_w); if(err) { pr_err("Insert biterror failed!\n"); goto erase; } pr_info("Insert %d bit-flip sucessfully!\n", j + 1); err = write_oob(offset, pagebuf_w, mtd->writesize, oobbuf_w, mtd->oobsize, MTD_OPS_RAW); if(err != 0) { pr_err("2.1 write failed!\n"); goto erase; } stats = mtd_part->master->ecc_stats; err = read_oob(offset, pagebuf_r, mtd->writesize, oobbuf_r, mtd->oobsize, MTD_OPS_PLACE_OOB); if(err != 0) { pr_err("2.1 read failed!\n"); break; } if(memcmp(pagebuf_v, pagebuf_r, mtd->writesize) != 0) { pr_err("2.2 compare page failed!\n"); goto erase; } corrected_num = mtd_part->master->ecc_stats.corrected - stats.corrected; if(corrected_num != (j + 1)) { pr_err("Bit-flip num is not match, expected:%d, really:%d\n", j + 1, corrected_num); goto erase; } } pr_info("Test successfully, this system can corrected %d bit-flip at most!\n", j); erase: err = erase_eraseblock(((unsigned int)offset)/mtd->erasesize); if(err) { pr_err("1.3 erase failed at EB: %d\n", ((unsigned int)offset)/mtd->erasesize); goto out; } out: vfree(pagebuf_r); vfree(oobbuf_r); vfree(pagebuf_w); vfree(oobbuf_w); pr_info("--------------------------------------------------------------------------\n"); return -1; }
/* Initialize base and padding for each memory region randomized with KASLR */ void __init kernel_randomize_memory(void) { size_t i; unsigned long vaddr_start, vaddr; unsigned long rand, memory_tb; struct rnd_state rand_state; unsigned long remain_entropy; vaddr_start = pgtable_l5_enabled() ? __PAGE_OFFSET_BASE_L5 : __PAGE_OFFSET_BASE_L4; vaddr = vaddr_start; /* * These BUILD_BUG_ON checks ensure the memory layout is consistent * with the vaddr_start/vaddr_end variables. These checks are very * limited.... */ BUILD_BUG_ON(vaddr_start >= vaddr_end); BUILD_BUG_ON(vaddr_end != CPU_ENTRY_AREA_BASE); BUILD_BUG_ON(vaddr_end > __START_KERNEL_map); if (!kaslr_memory_enabled()) return; kaslr_regions[0].size_tb = 1 << (MAX_PHYSMEM_BITS - TB_SHIFT); kaslr_regions[1].size_tb = VMALLOC_SIZE_TB; /* * Update Physical memory mapping to available and * add padding if needed (especially for memory hotplug support). */ BUG_ON(kaslr_regions[0].base != &page_offset_base); memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) + CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING; /* Adapt phyiscal memory region size based on available memory */ if (memory_tb < kaslr_regions[0].size_tb) kaslr_regions[0].size_tb = memory_tb; /* Calculate entropy available between regions */ remain_entropy = vaddr_end - vaddr_start; for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) remain_entropy -= get_padding(&kaslr_regions[i]); prandom_seed_state(&rand_state, kaslr_get_random_long("Memory")); for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) { unsigned long entropy; /* * Select a random virtual address using the extra entropy * available. */ entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i); prandom_bytes_state(&rand_state, &rand, sizeof(rand)); entropy = (rand % (entropy + 1)) & PUD_MASK; vaddr += entropy; *kaslr_regions[i].base = vaddr; /* * Jump the region and add a minimum padding based on * randomization alignment. */ vaddr += get_padding(&kaslr_regions[i]); vaddr = round_up(vaddr + 1, PUD_SIZE); remain_entropy -= entropy; } }
static int erasecrosstest(void) { size_t read, written; int err = 0, i, ebnum, ebnum2; loff_t addr0; char *readbuf = twopages; pr_info("erasecrosstest\n"); ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } ebnum2 = ebcnt - 1; while (ebnum2 && bbt[ebnum2]) ebnum2 -= 1; pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; pr_info("writing 1st page of block %d\n", ebnum); prandom_bytes_state(&rnd_state, writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { pr_info("error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } pr_info("reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd_read(mtd, addr0, pgsize, &read, readbuf); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { pr_err("error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } pr_info("verifying 1st page of block %d\n", ebnum); if (memcmp(writebuf, readbuf, pgsize)) { pr_err("verify failed!\n"); errcnt += 1; return -1; } pr_info("erasing block %d\n", ebnum); err = erase_eraseblock(ebnum); if (err) return err; pr_info("writing 1st page of block %d\n", ebnum); prandom_bytes_state(&rnd_state, writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtd_write(mtd, addr0, pgsize, &written, writebuf); if (err || written != pgsize) { pr_err("error: write failed at %#llx\n", (long long)addr0); return err ? err : -1; } pr_info("erasing block %d\n", ebnum2); err = erase_eraseblock(ebnum2); if (err) return err; pr_info("reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd_read(mtd, addr0, pgsize, &read, readbuf); if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { pr_err("error: read failed at %#llx\n", (long long)addr0); return err ? err : -1; } pr_info("verifying 1st page of block %d\n", ebnum); if (memcmp(writebuf, readbuf, pgsize)) { pr_err("verify failed!\n"); errcnt += 1; return -1; } if (!err) pr_info("erasecrosstest ok\n"); return err; }
static int erasecrosstest(void) { int err = 0, i, ebnum, ebnum2; loff_t addr0; char *readbuf = twopages; pr_info("erasecrosstest\n"); ebnum = 0; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) { addr0 += mtd->erasesize; ebnum += 1; } ebnum2 = ebcnt - 1; while (ebnum2 && bbt[ebnum2]) ebnum2 -= 1; pr_info("erasing block %d\n", ebnum); err = mtdtest_erase_eraseblock(mtd, ebnum); if (err) return err; pr_info("writing 1st page of block %d\n", ebnum); prandom_bytes_state(&rnd_state, writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtdtest_write(mtd, addr0, pgsize, writebuf); if (err) return err; pr_info("reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtdtest_read(mtd, addr0, pgsize, readbuf); if (err) return err; pr_info("verifying 1st page of block %d\n", ebnum); if (memcmp(writebuf, readbuf, pgsize)) { pr_err("verify failed!\n"); errcnt += 1; return -1; } pr_info("erasing block %d\n", ebnum); err = mtdtest_erase_eraseblock(mtd, ebnum); if (err) return err; pr_info("writing 1st page of block %d\n", ebnum); prandom_bytes_state(&rnd_state, writebuf, pgsize); strcpy(writebuf, "There is no data like this!"); err = mtdtest_write(mtd, addr0, pgsize, writebuf); if (err) return err; pr_info("erasing block %d\n", ebnum2); err = mtdtest_erase_eraseblock(mtd, ebnum2); if (err) return err; pr_info("reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtdtest_read(mtd, addr0, pgsize, readbuf); if (err) return err; pr_info("verifying 1st page of block %d\n", ebnum); if (memcmp(writebuf, readbuf, pgsize)) { pr_err("verify failed!\n"); errcnt += 1; return -1; } if (!err) pr_info("erasecrosstest ok\n"); return err; }
static int verify_eraseblock(int ebnum) { int i; struct mtd_oob_ops ops; int err = 0; loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; ops.oobretlen = 0; ops.ooboffs = use_offset; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf, writebuf + (use_len_max * i) + use_offset, use_len)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); return -1; } } if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { int k; ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != mtd->ecclayout->oobavail) { pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } if (memcmp(readbuf + use_offset, writebuf + (use_len_max * i) + use_offset, use_len)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); return -1; } } for (k = 0; k < use_offset; ++k) if (readbuf[k] != 0xff) { pr_err("error: verify 0xff " "failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too " "many errors\n"); return -1; } } for (k = use_offset + use_len; k < mtd->ecclayout->oobavail; ++k) if (readbuf[k] != 0xff) { pr_err("error: verify 0xff " "failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too " "many errors\n"); return -1; } } } if (vary_offset) do_vary_offset(); } return err; }
static int verify_eraseblock(int ebnum) { int i; struct mtd_oob_ops ops; int err = 0; loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t bitflips; prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; ops.oobretlen = 0; ops.ooboffs = use_offset; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != use_len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } bitflips = memcmpshow(addr, readbuf, writebuf + (use_len_max * i) + use_offset, use_len); if (bitflips > bitflip_limit) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); return -1; } } else if (bitflips) { pr_info("ignoring error as within bitflip_limit\n"); } if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { int k; ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err || ops.oobretlen != mtd->ecclayout->oobavail) { pr_err("error: readoob failed at %#llx\n", (long long)addr); errcnt += 1; return err ? err : -1; } bitflips = memcmpshow(addr, readbuf + use_offset, writebuf + (use_len_max * i) + use_offset, use_len); /* verify pre-offset area for 0xff */ bitflips += memffshow(addr, 0, readbuf, use_offset); /* verify post-(use_offset + use_len) area for 0xff */ k = use_offset + use_len; bitflips += memffshow(addr, k, readbuf + k, mtd->ecclayout->oobavail - k); if (bitflips > bitflip_limit) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); return -1; } } else if (bitflips) { pr_info("ignoring errors as within bitflip limit\n"); } } if (vary_offset) do_vary_offset(); } return err; }
/* Initialize base and padding for each memory region randomized with KASLR */ void __init kernel_randomize_memory(void) { size_t i; unsigned long vaddr = vaddr_start; unsigned long rand, memory_tb; struct rnd_state rand_state; unsigned long remain_entropy; /* * All these BUILD_BUG_ON checks ensures the memory layout is * consistent with the vaddr_start/vaddr_end variables. */ BUILD_BUG_ON(vaddr_start >= vaddr_end); BUILD_BUG_ON(IS_ENABLED(CONFIG_X86_ESPFIX64) && vaddr_end >= EFI_VA_END); BUILD_BUG_ON((IS_ENABLED(CONFIG_X86_ESPFIX64) || IS_ENABLED(CONFIG_EFI)) && vaddr_end >= __START_KERNEL_map); BUILD_BUG_ON(vaddr_end > __START_KERNEL_map); if (!kaslr_memory_enabled()) return; /* * Update Physical memory mapping to available and * add padding if needed (especially for memory hotplug support). */ BUG_ON(kaslr_regions[0].base != &page_offset_base); memory_tb = DIV_ROUND_UP(max_pfn << PAGE_SHIFT, 1UL << TB_SHIFT) + CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING; /* Adapt phyiscal memory region size based on available memory */ if (memory_tb < kaslr_regions[0].size_tb) kaslr_regions[0].size_tb = memory_tb; /* Calculate entropy available between regions */ remain_entropy = vaddr_end - vaddr_start; for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) remain_entropy -= get_padding(&kaslr_regions[i]); prandom_seed_state(&rand_state, kaslr_get_random_long("Memory")); for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++) { unsigned long entropy; /* * Select a random virtual address using the extra entropy * available. */ entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i); prandom_bytes_state(&rand_state, &rand, sizeof(rand)); entropy = (rand % (entropy + 1)) & PUD_MASK; vaddr += entropy; *kaslr_regions[i].base = vaddr; /* * Jump the region and add a minimum padding based on * randomization alignment. */ vaddr += get_padding(&kaslr_regions[i]); vaddr = round_up(vaddr + 1, PUD_SIZE); remain_entropy -= entropy; } }
static int __init mtd_oobtest_init(void) { int err = 0; unsigned int i; uint64_t tmp; struct mtd_oob_ops ops; loff_t addr = 0, addr0; printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); if (dev < 0) { pr_info("Please specify a valid mtd-device via module parameter\n"); pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL; } pr_info("MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); pr_err("error: cannot get MTD device\n"); return err; } if (!mtd_type_is_nand(mtd)) { pr_info("this test requires NAND flash\n"); goto out; } tmp = mtd->size; do_div(tmp, mtd->erasesize); ebcnt = tmp; pgcnt = mtd->erasesize / mtd->writesize; pr_info("MTD device size %llu, eraseblock size %u, " "page size %u, count of eraseblocks %u, pages per " "eraseblock %u, OOB size %u\n", (unsigned long long)mtd->size, mtd->erasesize, mtd->writesize, ebcnt, pgcnt, mtd->oobsize); err = -ENOMEM; readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!readbuf) goto out; writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!writebuf) goto out; bbt = kzalloc(ebcnt, GFP_KERNEL); if (!bbt) goto out; err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 0; /* First test: write all OOB, read it back and verify */ pr_info("test 1 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; prandom_seed_state(&rnd_state, 1); err = write_whole_device(); if (err) goto out; prandom_seed_state(&rnd_state, 1); err = verify_all_eraseblocks(); if (err) goto out; /* * Second test: write all OOB, a block at a time, read it back and * verify. */ pr_info("test 2 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; prandom_seed_state(&rnd_state, 3); err = write_whole_device(); if (err) goto out; /* Check all eraseblocks */ prandom_seed_state(&rnd_state, 3); pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = verify_eraseblock_in_one_go(i); if (err) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); cond_resched(); } pr_info("verified %u eraseblocks\n", i); /* * Third test: write OOB at varying offsets and lengths, read it back * and verify. */ pr_info("test 3 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; /* Write all eraseblocks */ use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 1; prandom_seed_state(&rnd_state, 5); err = write_whole_device(); if (err) goto out; /* Check all eraseblocks */ use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 1; prandom_seed_state(&rnd_state, 5); err = verify_all_eraseblocks(); if (err) goto out; use_offset = 0; use_len = mtd->ecclayout->oobavail; use_len_max = mtd->ecclayout->oobavail; vary_offset = 0; /* Fourth test: try to write off end of device */ pr_info("test 4 of 5\n"); err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) addr0 += mtd->erasesize; /* Attempt to write off end of OOB */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; ops.oobretlen = 0; ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = writebuf; pr_info("attempting to start write past end of OOB\n"); pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, addr0, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: can write past end of OOB\n"); errcnt += 1; } /* Attempt to read off end of OOB */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; ops.oobretlen = 0; ops.ooboffs = mtd->ecclayout->oobavail; ops.datbuf = NULL; ops.oobbuf = readbuf; pr_info("attempting to start read past end of OOB\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, addr0, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: can read past end of OOB\n"); errcnt += 1; } if (bbt[ebcnt - 1]) pr_info("skipping end of device tests because last " "block is bad\n"); else { /* Attempt to write off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf; pr_info("attempting to write past end of device\n"); pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: wrote past end of device\n"); errcnt += 1; } /* Attempt to read off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: read past end of device\n"); errcnt += 1; } err = mtdtest_erase_eraseblock(mtd, ebcnt - 1); if (err) goto out; /* Attempt to write off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = writebuf; pr_info("attempting to write past end of device\n"); pr_info("an error is expected...\n"); err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: wrote past end of device\n"); errcnt += 1; } /* Attempt to read off end of device */ ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; ops.oobretlen = 0; ops.ooboffs = 1; ops.datbuf = NULL; ops.oobbuf = readbuf; pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) { pr_info("error occurred as expected\n"); err = 0; } else { pr_err("error: read past end of device\n"); errcnt += 1; } } /* Fifth test: write / read across block boundaries */ pr_info("test 5 of 5\n"); /* Erase all eraseblocks */ err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out; /* Write all eraseblocks */ prandom_seed_state(&rnd_state, 11); pr_info("writing OOBs of whole device\n"); for (i = 0; i < ebcnt - 1; ++i) { int cnt = 2; int pg; size_t sz = mtd->ecclayout->oobavail; if (bbt[i] || bbt[i + 1]) continue; addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; prandom_bytes_state(&rnd_state, writebuf, sz * cnt); for (pg = 0; pg < cnt; ++pg) { ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = sz; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = writebuf + pg * sz; err = mtd_write_oob(mtd, addr, &ops); if (err) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); cond_resched(); addr += mtd->writesize; } } pr_info("written %u eraseblocks\n", i); /* Check all eraseblocks */ prandom_seed_state(&rnd_state, 11); pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt - 1; ++i) { if (bbt[i] || bbt[i + 1]) continue; prandom_bytes_state(&rnd_state, writebuf, mtd->ecclayout->oobavail * 2); addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail * 2; ops.oobretlen = 0; ops.ooboffs = 0; ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); if (err) goto out; if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { pr_err("error: verify failed at %#llx\n", (long long)addr); errcnt += 1; if (errcnt > 1000) { pr_err("error: too many errors\n"); goto out; } } if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); cond_resched(); } pr_info("verified %u eraseblocks\n", i); pr_info("finished with %d errors\n", errcnt); out: kfree(bbt); kfree(writebuf); kfree(readbuf); put_mtd_device(mtd); if (err) pr_info("error %d occurred\n", err); printk(KERN_INFO "=================================================\n"); return err; }
static int nandflash_agetest(void) { int err = 0; loff_t addr = 0; unsigned int test_blk = 10; unsigned int op = 0; unsigned char *readbuf = NULL; unsigned char *writebuf = NULL; unsigned int written = 0, read = 0; unsigned int continue_err = 0; unsigned int erase_time = 0; readbuf = vmalloc(mtd->writesize); if(!readbuf) { pr_err("%s, alloc readbuf failed!\n", __func__); err = -ENOMEM; goto out; } writebuf = vmalloc(mtd->writesize); if(!writebuf) { pr_err("%s, alloc writebuf failed!\n", __func__); err = -ENOMEM; goto out; } while((test_blk < ebcnt) && bbt[test_blk]) { test_blk ++; } if(test_blk >= ebcnt) { pr_err("The whole mtd_partion are bad!\n"); err = -EINVAL; goto out; } pr_info("Begin to make block %d as bad!\n", test_blk); addr = test_blk * mtd->erasesize; prandom_seed_state(&rnd_state, 1); prandom_bytes_state(&rnd_state, writebuf, mtd->writesize); err = agetest_erase_eraseblock(test_blk); if(err) { pr_err("the first erase failed at addr: 0x%.8x, err: %d\n", (unsigned int)addr, err); goto out; } while(1) { if(signal_pending(current)) goto out; err = mtd_write(mtd, addr, mtd->writesize, &written, writebuf); if(err || written != mtd->writesize) { pr_err("write failed at addr: 0x%.8x, err: %d, written: %d, time: %d\n", (unsigned int)addr, err, written, op); goto erase; } err = mtd_read(mtd, addr, mtd->writesize, &read, readbuf); if(err || read != mtd->writesize) { pr_err("read failed at addr: 0x%.8x, err: %d, read: %d, time: %d\n", (unsigned int)addr, err, read, op); goto erase; } if(memcmp(readbuf, writebuf, mtd->writesize) != 0) { pr_err("verify failed at addr: 0x%.8x!", (unsigned int)addr); goto erase; } erase: err = agetest_erase_eraseblock(test_blk); if(err) { pr_err("erase failed at addr: 0x%.8x, err: %d, time: %d\n", (unsigned int)addr, err, op); break; } op += 1; if(op % 1024 == 0) pr_info("we have erased %d times!\n", op); } /*make sure the block has been erased as bad block*/ while(1) { if(signal_pending(current)) break; err = mtd_write(mtd, addr, mtd->writesize, &written, writebuf); err = agetest_erase_eraseblock(test_blk); if(err) { continue_err ++; if(continue_err >= 0x1000) { pr_info("after %d times continue erase, the block has been erased as bad block!", erase_time); break; } if( continue_err % 100 == 0) pr_info("the continue_err is %d!", continue_err); } else { if(continue_err) pr_info("the continue_err may be clean, old value is %d\n", continue_err); continue_err = 0; } erase_time ++; if( erase_time % 1024 == 0) pr_info("the erase_time is %d!", erase_time); } pr_info("mark block %d as bad!\n", test_blk); mtd->_block_markbad(mtd, addr); err = 0; out: vfree(readbuf); vfree(writebuf); pr_info("agetest finished, %d(%d) operations done!\n", op, erase_time); return err; }