cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

subpagetest.c (10373B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2006-2007 Nokia Corporation
      4 *
      5 * Test sub-page read and write on MTD device.
      6 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
      7 */
      8
      9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     10
     11#include <linux/init.h>
     12#include <linux/module.h>
     13#include <linux/moduleparam.h>
     14#include <linux/err.h>
     15#include <linux/mtd/mtd.h>
     16#include <linux/slab.h>
     17#include <linux/sched.h>
     18#include <linux/random.h>
     19
     20#include "mtd_test.h"
     21
     22static int dev = -EINVAL;
     23module_param(dev, int, S_IRUGO);
     24MODULE_PARM_DESC(dev, "MTD device number to use");
     25
     26static struct mtd_info *mtd;
     27static unsigned char *writebuf;
     28static unsigned char *readbuf;
     29static unsigned char *bbt;
     30
     31static int subpgsize;
     32static int bufsize;
     33static int ebcnt;
     34static int pgcnt;
     35static int errcnt;
     36static struct rnd_state rnd_state;
     37
     38static inline void clear_data(unsigned char *buf, size_t len)
     39{
     40	memset(buf, 0, len);
     41}
     42
     43static int write_eraseblock(int ebnum)
     44{
     45	size_t written;
     46	int err = 0;
     47	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     48
     49	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
     50	err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
     51	if (unlikely(err || written != subpgsize)) {
     52		pr_err("error: write failed at %#llx\n",
     53		       (long long)addr);
     54		if (written != subpgsize) {
     55			pr_err("  write size: %#x\n", subpgsize);
     56			pr_err("  written: %#zx\n", written);
     57		}
     58		return err ? err : -1;
     59	}
     60
     61	addr += subpgsize;
     62
     63	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
     64	err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
     65	if (unlikely(err || written != subpgsize)) {
     66		pr_err("error: write failed at %#llx\n",
     67		       (long long)addr);
     68		if (written != subpgsize) {
     69			pr_err("  write size: %#x\n", subpgsize);
     70			pr_err("  written: %#zx\n", written);
     71		}
     72		return err ? err : -1;
     73	}
     74
     75	return err;
     76}
     77
     78static int write_eraseblock2(int ebnum)
     79{
     80	size_t written;
     81	int err = 0, k;
     82	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     83
     84	for (k = 1; k < 33; ++k) {
     85		if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
     86			break;
     87		prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
     88		err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
     89		if (unlikely(err || written != subpgsize * k)) {
     90			pr_err("error: write failed at %#llx\n",
     91			       (long long)addr);
     92			if (written != subpgsize * k) {
     93				pr_err("  write size: %#x\n",
     94				       subpgsize * k);
     95				pr_err("  written: %#08zx\n",
     96				       written);
     97			}
     98			return err ? err : -1;
     99		}
    100		addr += subpgsize * k;
    101	}
    102
    103	return err;
    104}
    105
    106static void print_subpage(unsigned char *p)
    107{
    108	int i, j;
    109
    110	for (i = 0; i < subpgsize; ) {
    111		for (j = 0; i < subpgsize && j < 32; ++i, ++j)
    112			printk("%02x", *p++);
    113		printk("\n");
    114	}
    115}
    116
    117static int verify_eraseblock(int ebnum)
    118{
    119	size_t read;
    120	int err = 0;
    121	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    122
    123	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
    124	clear_data(readbuf, subpgsize);
    125	err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
    126	if (unlikely(err || read != subpgsize)) {
    127		if (mtd_is_bitflip(err) && read == subpgsize) {
    128			pr_info("ECC correction at %#llx\n",
    129			       (long long)addr);
    130			err = 0;
    131		} else {
    132			pr_err("error: read failed at %#llx\n",
    133			       (long long)addr);
    134			return err ? err : -1;
    135		}
    136	}
    137	if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
    138		pr_err("error: verify failed at %#llx\n",
    139		       (long long)addr);
    140		pr_info("------------- written----------------\n");
    141		print_subpage(writebuf);
    142		pr_info("------------- read ------------------\n");
    143		print_subpage(readbuf);
    144		pr_info("-------------------------------------\n");
    145		errcnt += 1;
    146	}
    147
    148	addr += subpgsize;
    149
    150	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
    151	clear_data(readbuf, subpgsize);
    152	err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
    153	if (unlikely(err || read != subpgsize)) {
    154		if (mtd_is_bitflip(err) && read == subpgsize) {
    155			pr_info("ECC correction at %#llx\n",
    156			       (long long)addr);
    157			err = 0;
    158		} else {
    159			pr_err("error: read failed at %#llx\n",
    160			       (long long)addr);
    161			return err ? err : -1;
    162		}
    163	}
    164	if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
    165		pr_info("error: verify failed at %#llx\n",
    166		       (long long)addr);
    167		pr_info("------------- written----------------\n");
    168		print_subpage(writebuf);
    169		pr_info("------------- read ------------------\n");
    170		print_subpage(readbuf);
    171		pr_info("-------------------------------------\n");
    172		errcnt += 1;
    173	}
    174
    175	return err;
    176}
    177
    178static int verify_eraseblock2(int ebnum)
    179{
    180	size_t read;
    181	int err = 0, k;
    182	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    183
    184	for (k = 1; k < 33; ++k) {
    185		if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
    186			break;
    187		prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
    188		clear_data(readbuf, subpgsize * k);
    189		err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
    190		if (unlikely(err || read != subpgsize * k)) {
    191			if (mtd_is_bitflip(err) && read == subpgsize * k) {
    192				pr_info("ECC correction at %#llx\n",
    193				       (long long)addr);
    194				err = 0;
    195			} else {
    196				pr_err("error: read failed at "
    197				       "%#llx\n", (long long)addr);
    198				return err ? err : -1;
    199			}
    200		}
    201		if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
    202			pr_err("error: verify failed at %#llx\n",
    203			       (long long)addr);
    204			errcnt += 1;
    205		}
    206		addr += subpgsize * k;
    207	}
    208
    209	return err;
    210}
    211
    212static int verify_eraseblock_ff(int ebnum)
    213{
    214	uint32_t j;
    215	size_t read;
    216	int err = 0;
    217	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    218
    219	memset(writebuf, 0xff, subpgsize);
    220	for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
    221		clear_data(readbuf, subpgsize);
    222		err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
    223		if (unlikely(err || read != subpgsize)) {
    224			if (mtd_is_bitflip(err) && read == subpgsize) {
    225				pr_info("ECC correction at %#llx\n",
    226				       (long long)addr);
    227				err = 0;
    228			} else {
    229				pr_err("error: read failed at "
    230				       "%#llx\n", (long long)addr);
    231				return err ? err : -1;
    232			}
    233		}
    234		if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
    235			pr_err("error: verify 0xff failed at "
    236			       "%#llx\n", (long long)addr);
    237			errcnt += 1;
    238		}
    239		addr += subpgsize;
    240	}
    241
    242	return err;
    243}
    244
    245static int verify_all_eraseblocks_ff(void)
    246{
    247	int err;
    248	unsigned int i;
    249
    250	pr_info("verifying all eraseblocks for 0xff\n");
    251	for (i = 0; i < ebcnt; ++i) {
    252		if (bbt[i])
    253			continue;
    254		err = verify_eraseblock_ff(i);
    255		if (err)
    256			return err;
    257		if (i % 256 == 0)
    258			pr_info("verified up to eraseblock %u\n", i);
    259
    260		err = mtdtest_relax();
    261		if (err)
    262			return err;
    263	}
    264	pr_info("verified %u eraseblocks\n", i);
    265	return 0;
    266}
    267
    268static int __init mtd_subpagetest_init(void)
    269{
    270	int err = 0;
    271	uint32_t i;
    272	uint64_t tmp;
    273
    274	printk(KERN_INFO "\n");
    275	printk(KERN_INFO "=================================================\n");
    276
    277	if (dev < 0) {
    278		pr_info("Please specify a valid mtd-device via module parameter\n");
    279		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
    280		return -EINVAL;
    281	}
    282
    283	pr_info("MTD device: %d\n", dev);
    284
    285	mtd = get_mtd_device(NULL, dev);
    286	if (IS_ERR(mtd)) {
    287		err = PTR_ERR(mtd);
    288		pr_err("error: cannot get MTD device\n");
    289		return err;
    290	}
    291
    292	if (!mtd_type_is_nand(mtd)) {
    293		pr_info("this test requires NAND flash\n");
    294		goto out;
    295	}
    296
    297	subpgsize = mtd->writesize >> mtd->subpage_sft;
    298	tmp = mtd->size;
    299	do_div(tmp, mtd->erasesize);
    300	ebcnt = tmp;
    301	pgcnt = mtd->erasesize / mtd->writesize;
    302
    303	pr_info("MTD device size %llu, eraseblock size %u, "
    304	       "page size %u, subpage size %u, count of eraseblocks %u, "
    305	       "pages per eraseblock %u, OOB size %u\n",
    306	       (unsigned long long)mtd->size, mtd->erasesize,
    307	       mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
    308
    309	err = -ENOMEM;
    310	bufsize = subpgsize * 32;
    311	writebuf = kmalloc(bufsize, GFP_KERNEL);
    312	if (!writebuf)
    313		goto out;
    314	readbuf = kmalloc(bufsize, GFP_KERNEL);
    315	if (!readbuf)
    316		goto out;
    317	bbt = kzalloc(ebcnt, GFP_KERNEL);
    318	if (!bbt)
    319		goto out;
    320
    321	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
    322	if (err)
    323		goto out;
    324
    325	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    326	if (err)
    327		goto out;
    328
    329	pr_info("writing whole device\n");
    330	prandom_seed_state(&rnd_state, 1);
    331	for (i = 0; i < ebcnt; ++i) {
    332		if (bbt[i])
    333			continue;
    334		err = write_eraseblock(i);
    335		if (unlikely(err))
    336			goto out;
    337		if (i % 256 == 0)
    338			pr_info("written up to eraseblock %u\n", i);
    339
    340		err = mtdtest_relax();
    341		if (err)
    342			goto out;
    343	}
    344	pr_info("written %u eraseblocks\n", i);
    345
    346	prandom_seed_state(&rnd_state, 1);
    347	pr_info("verifying all eraseblocks\n");
    348	for (i = 0; i < ebcnt; ++i) {
    349		if (bbt[i])
    350			continue;
    351		err = verify_eraseblock(i);
    352		if (unlikely(err))
    353			goto out;
    354		if (i % 256 == 0)
    355			pr_info("verified up to eraseblock %u\n", i);
    356
    357		err = mtdtest_relax();
    358		if (err)
    359			goto out;
    360	}
    361	pr_info("verified %u eraseblocks\n", i);
    362
    363	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    364	if (err)
    365		goto out;
    366
    367	err = verify_all_eraseblocks_ff();
    368	if (err)
    369		goto out;
    370
    371	/* Write all eraseblocks */
    372	prandom_seed_state(&rnd_state, 3);
    373	pr_info("writing whole device\n");
    374	for (i = 0; i < ebcnt; ++i) {
    375		if (bbt[i])
    376			continue;
    377		err = write_eraseblock2(i);
    378		if (unlikely(err))
    379			goto out;
    380		if (i % 256 == 0)
    381			pr_info("written up to eraseblock %u\n", i);
    382
    383		err = mtdtest_relax();
    384		if (err)
    385			goto out;
    386	}
    387	pr_info("written %u eraseblocks\n", i);
    388
    389	/* Check all eraseblocks */
    390	prandom_seed_state(&rnd_state, 3);
    391	pr_info("verifying all eraseblocks\n");
    392	for (i = 0; i < ebcnt; ++i) {
    393		if (bbt[i])
    394			continue;
    395		err = verify_eraseblock2(i);
    396		if (unlikely(err))
    397			goto out;
    398		if (i % 256 == 0)
    399			pr_info("verified up to eraseblock %u\n", i);
    400
    401		err = mtdtest_relax();
    402		if (err)
    403			goto out;
    404	}
    405	pr_info("verified %u eraseblocks\n", i);
    406
    407	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    408	if (err)
    409		goto out;
    410
    411	err = verify_all_eraseblocks_ff();
    412	if (err)
    413		goto out;
    414
    415	pr_info("finished with %d errors\n", errcnt);
    416
    417out:
    418	kfree(bbt);
    419	kfree(readbuf);
    420	kfree(writebuf);
    421	put_mtd_device(mtd);
    422	if (err)
    423		pr_info("error %d occurred\n", err);
    424	printk(KERN_INFO "=================================================\n");
    425	return err;
    426}
    427module_init(mtd_subpagetest_init);
    428
    429static void __exit mtd_subpagetest_exit(void)
    430{
    431	return;
    432}
    433module_exit(mtd_subpagetest_exit);
    434
    435MODULE_DESCRIPTION("Subpage test module");
    436MODULE_AUTHOR("Adrian Hunter");
    437MODULE_LICENSE("GPL");