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

stresstest.c (5075B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2006-2008 Nokia Corporation
      4 *
      5 * Test random reads, writes and erases 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 <linux/init.h>
     13#include <linux/module.h>
     14#include <linux/moduleparam.h>
     15#include <linux/err.h>
     16#include <linux/mtd/mtd.h>
     17#include <linux/slab.h>
     18#include <linux/sched.h>
     19#include <linux/vmalloc.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 int count = 10000;
     29module_param(count, int, S_IRUGO);
     30MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");
     31
     32static struct mtd_info *mtd;
     33static unsigned char *writebuf;
     34static unsigned char *readbuf;
     35static unsigned char *bbt;
     36static int *offsets;
     37
     38static int pgsize;
     39static int bufsize;
     40static int ebcnt;
     41static int pgcnt;
     42
     43static int rand_eb(void)
     44{
     45	unsigned int eb;
     46
     47again:
     48	eb = prandom_u32();
     49	/* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
     50	eb %= (ebcnt - 1);
     51	if (bbt[eb])
     52		goto again;
     53	return eb;
     54}
     55
     56static int rand_offs(void)
     57{
     58	unsigned int offs;
     59
     60	offs = prandom_u32();
     61	offs %= bufsize;
     62	return offs;
     63}
     64
     65static int rand_len(int offs)
     66{
     67	unsigned int len;
     68
     69	len = prandom_u32();
     70	len %= (bufsize - offs);
     71	return len;
     72}
     73
     74static int do_read(void)
     75{
     76	int eb = rand_eb();
     77	int offs = rand_offs();
     78	int len = rand_len(offs);
     79	loff_t addr;
     80
     81	if (bbt[eb + 1]) {
     82		if (offs >= mtd->erasesize)
     83			offs -= mtd->erasesize;
     84		if (offs + len > mtd->erasesize)
     85			len = mtd->erasesize - offs;
     86	}
     87	addr = (loff_t)eb * mtd->erasesize + offs;
     88	return mtdtest_read(mtd, addr, len, readbuf);
     89}
     90
     91static int do_write(void)
     92{
     93	int eb = rand_eb(), offs, err, len;
     94	loff_t addr;
     95
     96	offs = offsets[eb];
     97	if (offs >= mtd->erasesize) {
     98		err = mtdtest_erase_eraseblock(mtd, eb);
     99		if (err)
    100			return err;
    101		offs = offsets[eb] = 0;
    102	}
    103	len = rand_len(offs);
    104	len = ((len + pgsize - 1) / pgsize) * pgsize;
    105	if (offs + len > mtd->erasesize) {
    106		if (bbt[eb + 1])
    107			len = mtd->erasesize - offs;
    108		else {
    109			err = mtdtest_erase_eraseblock(mtd, eb + 1);
    110			if (err)
    111				return err;
    112			offsets[eb + 1] = 0;
    113		}
    114	}
    115	addr = (loff_t)eb * mtd->erasesize + offs;
    116	err = mtdtest_write(mtd, addr, len, writebuf);
    117	if (unlikely(err))
    118		return err;
    119	offs += len;
    120	while (offs > mtd->erasesize) {
    121		offsets[eb++] = mtd->erasesize;
    122		offs -= mtd->erasesize;
    123	}
    124	offsets[eb] = offs;
    125	return 0;
    126}
    127
    128static int do_operation(void)
    129{
    130	if (prandom_u32() & 1)
    131		return do_read();
    132	else
    133		return do_write();
    134}
    135
    136static int __init mtd_stresstest_init(void)
    137{
    138	int err;
    139	int i, op;
    140	uint64_t tmp;
    141
    142	printk(KERN_INFO "\n");
    143	printk(KERN_INFO "=================================================\n");
    144
    145	if (dev < 0) {
    146		pr_info("Please specify a valid mtd-device via module parameter\n");
    147		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
    148		return -EINVAL;
    149	}
    150
    151	pr_info("MTD device: %d\n", dev);
    152
    153	mtd = get_mtd_device(NULL, dev);
    154	if (IS_ERR(mtd)) {
    155		err = PTR_ERR(mtd);
    156		pr_err("error: cannot get MTD device\n");
    157		return err;
    158	}
    159
    160	if (mtd->writesize == 1) {
    161		pr_info("not NAND flash, assume page size is 512 "
    162		       "bytes.\n");
    163		pgsize = 512;
    164	} else
    165		pgsize = mtd->writesize;
    166
    167	tmp = mtd->size;
    168	do_div(tmp, mtd->erasesize);
    169	ebcnt = tmp;
    170	pgcnt = mtd->erasesize / pgsize;
    171
    172	pr_info("MTD device size %llu, eraseblock size %u, "
    173	       "page size %u, count of eraseblocks %u, pages per "
    174	       "eraseblock %u, OOB size %u\n",
    175	       (unsigned long long)mtd->size, mtd->erasesize,
    176	       pgsize, ebcnt, pgcnt, mtd->oobsize);
    177
    178	if (ebcnt < 2) {
    179		pr_err("error: need at least 2 eraseblocks\n");
    180		err = -ENOSPC;
    181		goto out_put_mtd;
    182	}
    183
    184	/* Read or write up 2 eraseblocks at a time */
    185	bufsize = mtd->erasesize * 2;
    186
    187	err = -ENOMEM;
    188	readbuf = vmalloc(bufsize);
    189	writebuf = vmalloc(bufsize);
    190	offsets = kmalloc_array(ebcnt, sizeof(int), GFP_KERNEL);
    191	if (!readbuf || !writebuf || !offsets)
    192		goto out;
    193	for (i = 0; i < ebcnt; i++)
    194		offsets[i] = mtd->erasesize;
    195	prandom_bytes(writebuf, bufsize);
    196
    197	bbt = kzalloc(ebcnt, GFP_KERNEL);
    198	if (!bbt)
    199		goto out;
    200	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
    201	if (err)
    202		goto out;
    203
    204	/* Do operations */
    205	pr_info("doing operations\n");
    206	for (op = 0; op < count; op++) {
    207		if ((op & 1023) == 0)
    208			pr_info("%d operations done\n", op);
    209		err = do_operation();
    210		if (err)
    211			goto out;
    212
    213		err = mtdtest_relax();
    214		if (err)
    215			goto out;
    216	}
    217	pr_info("finished, %d operations done\n", op);
    218
    219out:
    220	kfree(offsets);
    221	kfree(bbt);
    222	vfree(writebuf);
    223	vfree(readbuf);
    224out_put_mtd:
    225	put_mtd_device(mtd);
    226	if (err)
    227		pr_info("error %d occurred\n", err);
    228	printk(KERN_INFO "=================================================\n");
    229	return err;
    230}
    231module_init(mtd_stresstest_init);
    232
    233static void __exit mtd_stresstest_exit(void)
    234{
    235	return;
    236}
    237module_exit(mtd_stresstest_exit);
    238
    239MODULE_DESCRIPTION("Stress test module");
    240MODULE_AUTHOR("Adrian Hunter");
    241MODULE_LICENSE("GPL");