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

block2mtd.c (11615B)


      1/*
      2 * block2mtd.c - create an mtd from a block device
      3 *
      4 * Copyright (C) 2001,2002	Simon Evans <spse@secret.org.uk>
      5 * Copyright (C) 2004-2006	Joern Engel <joern@wh.fh-wedel.de>
      6 *
      7 * Licence: GPL
      8 */
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12/*
     13 * When the first attempt at device initialization fails, we may need to
     14 * wait a little bit and retry. This timeout, by default 3 seconds, gives
     15 * device time to start up. Required on BCM2708 and a few other chipsets.
     16 */
     17#define MTD_DEFAULT_TIMEOUT	3
     18
     19#include <linux/module.h>
     20#include <linux/delay.h>
     21#include <linux/fs.h>
     22#include <linux/blkdev.h>
     23#include <linux/backing-dev.h>
     24#include <linux/bio.h>
     25#include <linux/pagemap.h>
     26#include <linux/list.h>
     27#include <linux/init.h>
     28#include <linux/mtd/mtd.h>
     29#include <linux/mutex.h>
     30#include <linux/mount.h>
     31#include <linux/slab.h>
     32#include <linux/major.h>
     33
     34/* Maximum number of comma-separated items in the 'block2mtd=' parameter */
     35#define BLOCK2MTD_PARAM_MAX_COUNT 3
     36
     37/* Info for the block device */
     38struct block2mtd_dev {
     39	struct list_head list;
     40	struct block_device *blkdev;
     41	struct mtd_info mtd;
     42	struct mutex write_mutex;
     43};
     44
     45
     46/* Static info about the MTD, used in cleanup_module */
     47static LIST_HEAD(blkmtd_device_list);
     48
     49
     50static struct page *page_read(struct address_space *mapping, pgoff_t index)
     51{
     52	return read_mapping_page(mapping, index, NULL);
     53}
     54
     55/* erase a specified part of the device */
     56static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
     57{
     58	struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
     59	struct page *page;
     60	pgoff_t index = to >> PAGE_SHIFT;	// page index
     61	int pages = len >> PAGE_SHIFT;
     62	u_long *p;
     63	u_long *max;
     64
     65	while (pages) {
     66		page = page_read(mapping, index);
     67		if (IS_ERR(page))
     68			return PTR_ERR(page);
     69
     70		max = page_address(page) + PAGE_SIZE;
     71		for (p=page_address(page); p<max; p++)
     72			if (*p != -1UL) {
     73				lock_page(page);
     74				memset(page_address(page), 0xff, PAGE_SIZE);
     75				set_page_dirty(page);
     76				unlock_page(page);
     77				balance_dirty_pages_ratelimited(mapping);
     78				break;
     79			}
     80
     81		put_page(page);
     82		pages--;
     83		index++;
     84	}
     85	return 0;
     86}
     87static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
     88{
     89	struct block2mtd_dev *dev = mtd->priv;
     90	size_t from = instr->addr;
     91	size_t len = instr->len;
     92	int err;
     93
     94	mutex_lock(&dev->write_mutex);
     95	err = _block2mtd_erase(dev, from, len);
     96	mutex_unlock(&dev->write_mutex);
     97	if (err)
     98		pr_err("erase failed err = %d\n", err);
     99
    100	return err;
    101}
    102
    103
    104static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
    105		size_t *retlen, u_char *buf)
    106{
    107	struct block2mtd_dev *dev = mtd->priv;
    108	struct page *page;
    109	pgoff_t index = from >> PAGE_SHIFT;
    110	int offset = from & (PAGE_SIZE-1);
    111	int cpylen;
    112
    113	while (len) {
    114		if ((offset + len) > PAGE_SIZE)
    115			cpylen = PAGE_SIZE - offset;	// multiple pages
    116		else
    117			cpylen = len;	// this page
    118		len = len - cpylen;
    119
    120		page = page_read(dev->blkdev->bd_inode->i_mapping, index);
    121		if (IS_ERR(page))
    122			return PTR_ERR(page);
    123
    124		memcpy(buf, page_address(page) + offset, cpylen);
    125		put_page(page);
    126
    127		if (retlen)
    128			*retlen += cpylen;
    129		buf += cpylen;
    130		offset = 0;
    131		index++;
    132	}
    133	return 0;
    134}
    135
    136
    137/* write data to the underlying device */
    138static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
    139		loff_t to, size_t len, size_t *retlen)
    140{
    141	struct page *page;
    142	struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
    143	pgoff_t index = to >> PAGE_SHIFT;	// page index
    144	int offset = to & ~PAGE_MASK;	// page offset
    145	int cpylen;
    146
    147	while (len) {
    148		if ((offset+len) > PAGE_SIZE)
    149			cpylen = PAGE_SIZE - offset;	// multiple pages
    150		else
    151			cpylen = len;			// this page
    152		len = len - cpylen;
    153
    154		page = page_read(mapping, index);
    155		if (IS_ERR(page))
    156			return PTR_ERR(page);
    157
    158		if (memcmp(page_address(page)+offset, buf, cpylen)) {
    159			lock_page(page);
    160			memcpy(page_address(page) + offset, buf, cpylen);
    161			set_page_dirty(page);
    162			unlock_page(page);
    163			balance_dirty_pages_ratelimited(mapping);
    164		}
    165		put_page(page);
    166
    167		if (retlen)
    168			*retlen += cpylen;
    169
    170		buf += cpylen;
    171		offset = 0;
    172		index++;
    173	}
    174	return 0;
    175}
    176
    177
    178static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
    179		size_t *retlen, const u_char *buf)
    180{
    181	struct block2mtd_dev *dev = mtd->priv;
    182	int err;
    183
    184	mutex_lock(&dev->write_mutex);
    185	err = _block2mtd_write(dev, buf, to, len, retlen);
    186	mutex_unlock(&dev->write_mutex);
    187	if (err > 0)
    188		err = 0;
    189	return err;
    190}
    191
    192
    193/* sync the device - wait until the write queue is empty */
    194static void block2mtd_sync(struct mtd_info *mtd)
    195{
    196	struct block2mtd_dev *dev = mtd->priv;
    197	sync_blockdev(dev->blkdev);
    198	return;
    199}
    200
    201
    202static void block2mtd_free_device(struct block2mtd_dev *dev)
    203{
    204	if (!dev)
    205		return;
    206
    207	kfree(dev->mtd.name);
    208
    209	if (dev->blkdev) {
    210		invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
    211					0, -1);
    212		blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
    213	}
    214
    215	kfree(dev);
    216}
    217
    218
    219static struct block2mtd_dev *add_device(char *devname, int erase_size,
    220		char *label, int timeout)
    221{
    222#ifndef MODULE
    223	int i;
    224#endif
    225	const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
    226	struct block_device *bdev;
    227	struct block2mtd_dev *dev;
    228	char *name;
    229
    230	if (!devname)
    231		return NULL;
    232
    233	dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
    234	if (!dev)
    235		return NULL;
    236
    237	/* Get a handle on the device */
    238	bdev = blkdev_get_by_path(devname, mode, dev);
    239
    240#ifndef MODULE
    241	/*
    242	 * We might not have the root device mounted at this point.
    243	 * Try to resolve the device name by other means.
    244	 */
    245	for (i = 0; IS_ERR(bdev) && i <= timeout; i++) {
    246		dev_t devt;
    247
    248		if (i)
    249			/*
    250			 * Calling wait_for_device_probe in the first loop
    251			 * was not enough, sleep for a bit in subsequent
    252			 * go-arounds.
    253			 */
    254			msleep(1000);
    255		wait_for_device_probe();
    256
    257		devt = name_to_dev_t(devname);
    258		if (!devt)
    259			continue;
    260		bdev = blkdev_get_by_dev(devt, mode, dev);
    261	}
    262#endif
    263
    264	if (IS_ERR(bdev)) {
    265		pr_err("error: cannot open device %s\n", devname);
    266		goto err_free_block2mtd;
    267	}
    268	dev->blkdev = bdev;
    269
    270	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
    271		pr_err("attempting to use an MTD device as a block device\n");
    272		goto err_free_block2mtd;
    273	}
    274
    275	if ((long)dev->blkdev->bd_inode->i_size % erase_size) {
    276		pr_err("erasesize must be a divisor of device size\n");
    277		goto err_free_block2mtd;
    278	}
    279
    280	mutex_init(&dev->write_mutex);
    281
    282	/* Setup the MTD structure */
    283	/* make the name contain the block device in */
    284	if (!label)
    285		name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
    286	else
    287		name = kstrdup(label, GFP_KERNEL);
    288	if (!name)
    289		goto err_destroy_mutex;
    290
    291	dev->mtd.name = name;
    292
    293	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
    294	dev->mtd.erasesize = erase_size;
    295	dev->mtd.writesize = 1;
    296	dev->mtd.writebufsize = PAGE_SIZE;
    297	dev->mtd.type = MTD_RAM;
    298	dev->mtd.flags = MTD_CAP_RAM;
    299	dev->mtd._erase = block2mtd_erase;
    300	dev->mtd._write = block2mtd_write;
    301	dev->mtd._sync = block2mtd_sync;
    302	dev->mtd._read = block2mtd_read;
    303	dev->mtd.priv = dev;
    304	dev->mtd.owner = THIS_MODULE;
    305
    306	if (mtd_device_register(&dev->mtd, NULL, 0)) {
    307		/* Device didn't get added, so free the entry */
    308		goto err_destroy_mutex;
    309	}
    310
    311	list_add(&dev->list, &blkmtd_device_list);
    312	pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
    313		dev->mtd.index,
    314		label ? label : dev->mtd.name + strlen("block2mtd: "),
    315		dev->mtd.erasesize >> 10, dev->mtd.erasesize);
    316	return dev;
    317
    318err_destroy_mutex:
    319	mutex_destroy(&dev->write_mutex);
    320err_free_block2mtd:
    321	block2mtd_free_device(dev);
    322	return NULL;
    323}
    324
    325
    326/* This function works similar to reguler strtoul.  In addition, it
    327 * allows some suffixes for a more human-readable number format:
    328 * ki, Ki, kiB, KiB	- multiply result with 1024
    329 * Mi, MiB		- multiply result with 1024^2
    330 * Gi, GiB		- multiply result with 1024^3
    331 */
    332static int ustrtoul(const char *cp, char **endp, unsigned int base)
    333{
    334	unsigned long result = simple_strtoul(cp, endp, base);
    335	switch (**endp) {
    336	case 'G' :
    337		result *= 1024;
    338		fallthrough;
    339	case 'M':
    340		result *= 1024;
    341		fallthrough;
    342	case 'K':
    343	case 'k':
    344		result *= 1024;
    345	/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
    346		if ((*endp)[1] == 'i') {
    347			if ((*endp)[2] == 'B')
    348				(*endp) += 3;
    349			else
    350				(*endp) += 2;
    351		}
    352	}
    353	return result;
    354}
    355
    356
    357static int parse_num(size_t *num, const char *token)
    358{
    359	char *endp;
    360	size_t n;
    361
    362	n = (size_t) ustrtoul(token, &endp, 0);
    363	if (*endp)
    364		return -EINVAL;
    365
    366	*num = n;
    367	return 0;
    368}
    369
    370
    371static inline void kill_final_newline(char *str)
    372{
    373	char *newline = strrchr(str, '\n');
    374	if (newline && !newline[1])
    375		*newline = 0;
    376}
    377
    378
    379#ifndef MODULE
    380static int block2mtd_init_called = 0;
    381/* 80 for device, 12 for erase size */
    382static char block2mtd_paramline[80 + 12];
    383#endif
    384
    385static int block2mtd_setup2(const char *val)
    386{
    387	/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
    388	char buf[80 + 12 + 80 + 8];
    389	char *str = buf;
    390	char *token[BLOCK2MTD_PARAM_MAX_COUNT];
    391	char *name;
    392	char *label = NULL;
    393	size_t erase_size = PAGE_SIZE;
    394	unsigned long timeout = MTD_DEFAULT_TIMEOUT;
    395	int i, ret;
    396
    397	if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
    398		pr_err("parameter too long\n");
    399		return 0;
    400	}
    401
    402	strcpy(str, val);
    403	kill_final_newline(str);
    404
    405	for (i = 0; i < BLOCK2MTD_PARAM_MAX_COUNT; i++)
    406		token[i] = strsep(&str, ",");
    407
    408	if (str) {
    409		pr_err("too many arguments\n");
    410		return 0;
    411	}
    412
    413	if (!token[0]) {
    414		pr_err("no argument\n");
    415		return 0;
    416	}
    417
    418	name = token[0];
    419	if (strlen(name) + 1 > 80) {
    420		pr_err("device name too long\n");
    421		return 0;
    422	}
    423
    424	/* Optional argument when custom label is used */
    425	if (token[1] && strlen(token[1])) {
    426		ret = parse_num(&erase_size, token[1]);
    427		if (ret) {
    428			pr_err("illegal erase size\n");
    429			return 0;
    430		}
    431	}
    432
    433	if (token[2]) {
    434		label = token[2];
    435		pr_info("Using custom MTD label '%s' for dev %s\n", label, name);
    436	}
    437
    438	add_device(name, erase_size, label, timeout);
    439
    440	return 0;
    441}
    442
    443
    444static int block2mtd_setup(const char *val, const struct kernel_param *kp)
    445{
    446#ifdef MODULE
    447	return block2mtd_setup2(val);
    448#else
    449	/* If more parameters are later passed in via
    450	   /sys/module/block2mtd/parameters/block2mtd
    451	   and block2mtd_init() has already been called,
    452	   we can parse the argument now. */
    453
    454	if (block2mtd_init_called)
    455		return block2mtd_setup2(val);
    456
    457	/* During early boot stage, we only save the parameters
    458	   here. We must parse them later: if the param passed
    459	   from kernel boot command line, block2mtd_setup() is
    460	   called so early that it is not possible to resolve
    461	   the device (even kmalloc() fails). Deter that work to
    462	   block2mtd_setup2(). */
    463
    464	strlcpy(block2mtd_paramline, val, sizeof(block2mtd_paramline));
    465
    466	return 0;
    467#endif
    468}
    469
    470
    471module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
    472MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,[<erasesize>][,<label>]]\"");
    473
    474static int __init block2mtd_init(void)
    475{
    476	int ret = 0;
    477
    478#ifndef MODULE
    479	if (strlen(block2mtd_paramline))
    480		ret = block2mtd_setup2(block2mtd_paramline);
    481	block2mtd_init_called = 1;
    482#endif
    483
    484	return ret;
    485}
    486
    487
    488static void block2mtd_exit(void)
    489{
    490	struct list_head *pos, *next;
    491
    492	/* Remove the MTD devices */
    493	list_for_each_safe(pos, next, &blkmtd_device_list) {
    494		struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
    495		block2mtd_sync(&dev->mtd);
    496		mtd_device_unregister(&dev->mtd);
    497		mutex_destroy(&dev->write_mutex);
    498		pr_info("mtd%d: [%s] removed\n",
    499			dev->mtd.index,
    500			dev->mtd.name + strlen("block2mtd: "));
    501		list_del(&dev->list);
    502		block2mtd_free_device(dev);
    503	}
    504}
    505
    506late_initcall(block2mtd_init);
    507module_exit(block2mtd_exit);
    508
    509MODULE_LICENSE("GPL");
    510MODULE_AUTHOR("Joern Engel <joern@lazybastard.org>");
    511MODULE_DESCRIPTION("Emulate an MTD using a block device");