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

simdisk.c (8184B)


      1/*
      2 * arch/xtensa/platforms/iss/simdisk.c
      3 *
      4 * This file is subject to the terms and conditions of the GNU General Public
      5 * License.  See the file "COPYING" in the main directory of this archive
      6 * for more details.
      7 *
      8 * Copyright (C) 2001-2013 Tensilica Inc.
      9 *   Authors	Victor Prupis
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/moduleparam.h>
     14#include <linux/kernel.h>
     15#include <linux/init.h>
     16#include <linux/string.h>
     17#include <linux/blkdev.h>
     18#include <linux/bio.h>
     19#include <linux/proc_fs.h>
     20#include <linux/uaccess.h>
     21#include <platform/simcall.h>
     22
     23#define SIMDISK_MAJOR 240
     24#define SIMDISK_MINORS 1
     25#define MAX_SIMDISK_COUNT 10
     26
     27struct simdisk {
     28	const char *filename;
     29	spinlock_t lock;
     30	struct gendisk *gd;
     31	struct proc_dir_entry *procfile;
     32	int users;
     33	unsigned long size;
     34	int fd;
     35};
     36
     37
     38static int simdisk_count = CONFIG_BLK_DEV_SIMDISK_COUNT;
     39module_param(simdisk_count, int, S_IRUGO);
     40MODULE_PARM_DESC(simdisk_count, "Number of simdisk units.");
     41
     42static int n_files;
     43static const char *filename[MAX_SIMDISK_COUNT] = {
     44#ifdef CONFIG_SIMDISK0_FILENAME
     45	CONFIG_SIMDISK0_FILENAME,
     46#ifdef CONFIG_SIMDISK1_FILENAME
     47	CONFIG_SIMDISK1_FILENAME,
     48#endif
     49#endif
     50};
     51
     52static int simdisk_param_set_filename(const char *val,
     53		const struct kernel_param *kp)
     54{
     55	if (n_files < ARRAY_SIZE(filename))
     56		filename[n_files++] = val;
     57	else
     58		return -EINVAL;
     59	return 0;
     60}
     61
     62static const struct kernel_param_ops simdisk_param_ops_filename = {
     63	.set = simdisk_param_set_filename,
     64};
     65module_param_cb(filename, &simdisk_param_ops_filename, &n_files, 0);
     66MODULE_PARM_DESC(filename, "Backing storage filename.");
     67
     68static int simdisk_major = SIMDISK_MAJOR;
     69
     70static void simdisk_transfer(struct simdisk *dev, unsigned long sector,
     71		unsigned long nsect, char *buffer, int write)
     72{
     73	unsigned long offset = sector << SECTOR_SHIFT;
     74	unsigned long nbytes = nsect << SECTOR_SHIFT;
     75
     76	if (offset > dev->size || dev->size - offset < nbytes) {
     77		pr_notice("Beyond-end %s (%ld %ld)\n",
     78				write ? "write" : "read", offset, nbytes);
     79		return;
     80	}
     81
     82	spin_lock(&dev->lock);
     83	while (nbytes > 0) {
     84		unsigned long io;
     85
     86		simc_lseek(dev->fd, offset, SEEK_SET);
     87		READ_ONCE(*buffer);
     88		if (write)
     89			io = simc_write(dev->fd, buffer, nbytes);
     90		else
     91			io = simc_read(dev->fd, buffer, nbytes);
     92		if (io == -1) {
     93			pr_err("SIMDISK: IO error %d\n", errno);
     94			break;
     95		}
     96		buffer += io;
     97		offset += io;
     98		nbytes -= io;
     99	}
    100	spin_unlock(&dev->lock);
    101}
    102
    103static void simdisk_submit_bio(struct bio *bio)
    104{
    105	struct simdisk *dev = bio->bi_bdev->bd_disk->private_data;
    106	struct bio_vec bvec;
    107	struct bvec_iter iter;
    108	sector_t sector = bio->bi_iter.bi_sector;
    109
    110	bio_for_each_segment(bvec, bio, iter) {
    111		char *buffer = bvec_kmap_local(&bvec);
    112		unsigned len = bvec.bv_len >> SECTOR_SHIFT;
    113
    114		simdisk_transfer(dev, sector, len, buffer,
    115				bio_data_dir(bio) == WRITE);
    116		sector += len;
    117		kunmap_local(buffer);
    118	}
    119
    120	bio_endio(bio);
    121}
    122
    123static int simdisk_open(struct block_device *bdev, fmode_t mode)
    124{
    125	struct simdisk *dev = bdev->bd_disk->private_data;
    126
    127	spin_lock(&dev->lock);
    128	++dev->users;
    129	spin_unlock(&dev->lock);
    130	return 0;
    131}
    132
    133static void simdisk_release(struct gendisk *disk, fmode_t mode)
    134{
    135	struct simdisk *dev = disk->private_data;
    136	spin_lock(&dev->lock);
    137	--dev->users;
    138	spin_unlock(&dev->lock);
    139}
    140
    141static const struct block_device_operations simdisk_ops = {
    142	.owner		= THIS_MODULE,
    143	.submit_bio	= simdisk_submit_bio,
    144	.open		= simdisk_open,
    145	.release	= simdisk_release,
    146};
    147
    148static struct simdisk *sddev;
    149static struct proc_dir_entry *simdisk_procdir;
    150
    151static int simdisk_attach(struct simdisk *dev, const char *filename)
    152{
    153	int err = 0;
    154
    155	filename = kstrdup(filename, GFP_KERNEL);
    156	if (filename == NULL)
    157		return -ENOMEM;
    158
    159	spin_lock(&dev->lock);
    160
    161	if (dev->fd != -1) {
    162		err = -EBUSY;
    163		goto out;
    164	}
    165	dev->fd = simc_open(filename, O_RDWR, 0);
    166	if (dev->fd == -1) {
    167		pr_err("SIMDISK: Can't open %s: %d\n", filename, errno);
    168		err = -ENODEV;
    169		goto out;
    170	}
    171	dev->size = simc_lseek(dev->fd, 0, SEEK_END);
    172	set_capacity(dev->gd, dev->size >> SECTOR_SHIFT);
    173	dev->filename = filename;
    174	pr_info("SIMDISK: %s=%s\n", dev->gd->disk_name, dev->filename);
    175out:
    176	if (err)
    177		kfree(filename);
    178	spin_unlock(&dev->lock);
    179
    180	return err;
    181}
    182
    183static int simdisk_detach(struct simdisk *dev)
    184{
    185	int err = 0;
    186
    187	spin_lock(&dev->lock);
    188
    189	if (dev->users != 0) {
    190		err = -EBUSY;
    191	} else if (dev->fd != -1) {
    192		if (simc_close(dev->fd)) {
    193			pr_err("SIMDISK: error closing %s: %d\n",
    194					dev->filename, errno);
    195			err = -EIO;
    196		} else {
    197			pr_info("SIMDISK: %s detached from %s\n",
    198					dev->gd->disk_name, dev->filename);
    199			dev->fd = -1;
    200			kfree(dev->filename);
    201			dev->filename = NULL;
    202		}
    203	}
    204	spin_unlock(&dev->lock);
    205	return err;
    206}
    207
    208static ssize_t proc_read_simdisk(struct file *file, char __user *buf,
    209			size_t size, loff_t *ppos)
    210{
    211	struct simdisk *dev = pde_data(file_inode(file));
    212	const char *s = dev->filename;
    213	if (s) {
    214		ssize_t len = strlen(s);
    215		char *temp = kmalloc(len + 2, GFP_KERNEL);
    216
    217		if (!temp)
    218			return -ENOMEM;
    219
    220		len = scnprintf(temp, len + 2, "%s\n", s);
    221		len = simple_read_from_buffer(buf, size, ppos,
    222					      temp, len);
    223
    224		kfree(temp);
    225		return len;
    226	}
    227	return simple_read_from_buffer(buf, size, ppos, "\n", 1);
    228}
    229
    230static ssize_t proc_write_simdisk(struct file *file, const char __user *buf,
    231			size_t count, loff_t *ppos)
    232{
    233	char *tmp = memdup_user_nul(buf, count);
    234	struct simdisk *dev = pde_data(file_inode(file));
    235	int err;
    236
    237	if (IS_ERR(tmp))
    238		return PTR_ERR(tmp);
    239
    240	err = simdisk_detach(dev);
    241	if (err != 0)
    242		goto out_free;
    243
    244	if (count > 0 && tmp[count - 1] == '\n')
    245		tmp[count - 1] = 0;
    246
    247	if (tmp[0])
    248		err = simdisk_attach(dev, tmp);
    249
    250	if (err == 0)
    251		err = count;
    252out_free:
    253	kfree(tmp);
    254	return err;
    255}
    256
    257static const struct proc_ops simdisk_proc_ops = {
    258	.proc_read	= proc_read_simdisk,
    259	.proc_write	= proc_write_simdisk,
    260	.proc_lseek	= default_llseek,
    261};
    262
    263static int __init simdisk_setup(struct simdisk *dev, int which,
    264		struct proc_dir_entry *procdir)
    265{
    266	char tmp[2] = { '0' + which, 0 };
    267	int err = -ENOMEM;
    268
    269	dev->fd = -1;
    270	dev->filename = NULL;
    271	spin_lock_init(&dev->lock);
    272	dev->users = 0;
    273
    274	dev->gd = blk_alloc_disk(NUMA_NO_NODE);
    275	if (!dev->gd)
    276		goto out;
    277	dev->gd->major = simdisk_major;
    278	dev->gd->first_minor = which;
    279	dev->gd->minors = SIMDISK_MINORS;
    280	dev->gd->fops = &simdisk_ops;
    281	dev->gd->private_data = dev;
    282	snprintf(dev->gd->disk_name, 32, "simdisk%d", which);
    283	set_capacity(dev->gd, 0);
    284	err = add_disk(dev->gd);
    285	if (err)
    286		goto out_cleanup_disk;
    287
    288	dev->procfile = proc_create_data(tmp, 0644, procdir, &simdisk_proc_ops, dev);
    289
    290	return 0;
    291
    292out_cleanup_disk:
    293	blk_cleanup_disk(dev->gd);
    294out:
    295	return err;
    296}
    297
    298static int __init simdisk_init(void)
    299{
    300	int i;
    301
    302	if (register_blkdev(simdisk_major, "simdisk") < 0) {
    303		pr_err("SIMDISK: register_blkdev: %d\n", simdisk_major);
    304		return -EIO;
    305	}
    306	pr_info("SIMDISK: major: %d\n", simdisk_major);
    307
    308	if (n_files > simdisk_count)
    309		simdisk_count = n_files;
    310	if (simdisk_count > MAX_SIMDISK_COUNT)
    311		simdisk_count = MAX_SIMDISK_COUNT;
    312
    313	sddev = kmalloc_array(simdisk_count, sizeof(*sddev), GFP_KERNEL);
    314	if (sddev == NULL)
    315		goto out_unregister;
    316
    317	simdisk_procdir = proc_mkdir("simdisk", 0);
    318	if (simdisk_procdir == NULL)
    319		goto out_free_unregister;
    320
    321	for (i = 0; i < simdisk_count; ++i) {
    322		if (simdisk_setup(sddev + i, i, simdisk_procdir) == 0) {
    323			if (filename[i] != NULL && filename[i][0] != 0 &&
    324					(n_files == 0 || i < n_files))
    325				simdisk_attach(sddev + i, filename[i]);
    326		}
    327	}
    328
    329	return 0;
    330
    331out_free_unregister:
    332	kfree(sddev);
    333out_unregister:
    334	unregister_blkdev(simdisk_major, "simdisk");
    335	return -ENOMEM;
    336}
    337module_init(simdisk_init);
    338
    339static void simdisk_teardown(struct simdisk *dev, int which,
    340		struct proc_dir_entry *procdir)
    341{
    342	char tmp[2] = { '0' + which, 0 };
    343
    344	simdisk_detach(dev);
    345	if (dev->gd) {
    346		del_gendisk(dev->gd);
    347		blk_cleanup_disk(dev->gd);
    348	}
    349	remove_proc_entry(tmp, procdir);
    350}
    351
    352static void __exit simdisk_exit(void)
    353{
    354	int i;
    355
    356	for (i = 0; i < simdisk_count; ++i)
    357		simdisk_teardown(sddev + i, i, simdisk_procdir);
    358	remove_proc_entry("simdisk", 0);
    359	kfree(sddev);
    360	unregister_blkdev(simdisk_major, "simdisk");
    361}
    362module_exit(simdisk_exit);
    363
    364MODULE_ALIAS_BLOCKDEV_MAJOR(SIMDISK_MAJOR);
    365
    366MODULE_LICENSE("GPL");