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

pagetest.c (10390B)


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