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

ps3flash.c (10261B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * PS3 FLASH ROM Storage Driver
      4 *
      5 * Copyright (C) 2007 Sony Computer Entertainment Inc.
      6 * Copyright 2007 Sony Corp.
      7 */
      8
      9#include <linux/fs.h>
     10#include <linux/miscdevice.h>
     11#include <linux/slab.h>
     12#include <linux/uaccess.h>
     13#include <linux/module.h>
     14
     15#include <asm/lv1call.h>
     16#include <asm/ps3stor.h>
     17
     18
     19#define DEVICE_NAME		"ps3flash"
     20
     21#define FLASH_BLOCK_SIZE	(256*1024)
     22
     23
     24struct ps3flash_private {
     25	struct mutex mutex;	/* Bounce buffer mutex */
     26	u64 chunk_sectors;
     27	int tag;		/* Start sector of buffer, -1 if invalid */
     28	bool dirty;
     29};
     30
     31static struct ps3_storage_device *ps3flash_dev;
     32
     33static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
     34				       u64 start_sector, int write)
     35{
     36	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
     37	u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
     38					     start_sector, priv->chunk_sectors,
     39					     write);
     40	if (res) {
     41		dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
     42			__LINE__, write ? "write" : "read", res);
     43		return -EIO;
     44	}
     45	return 0;
     46}
     47
     48static int ps3flash_writeback(struct ps3_storage_device *dev)
     49{
     50	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
     51	int res;
     52
     53	if (!priv->dirty || priv->tag < 0)
     54		return 0;
     55
     56	res = ps3flash_read_write_sectors(dev, priv->tag, 1);
     57	if (res)
     58		return res;
     59
     60	priv->dirty = false;
     61	return 0;
     62}
     63
     64static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
     65{
     66	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
     67	int res;
     68
     69	if (start_sector == priv->tag)
     70		return 0;
     71
     72	res = ps3flash_writeback(dev);
     73	if (res)
     74		return res;
     75
     76	priv->tag = -1;
     77
     78	res = ps3flash_read_write_sectors(dev, start_sector, 0);
     79	if (res)
     80		return res;
     81
     82	priv->tag = start_sector;
     83	return 0;
     84}
     85
     86static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
     87{
     88	struct ps3_storage_device *dev = ps3flash_dev;
     89	return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
     90			dev->regions[dev->region_idx].size*dev->blk_size);
     91}
     92
     93static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
     94			     size_t count, loff_t *pos)
     95{
     96	struct ps3_storage_device *dev = ps3flash_dev;
     97	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
     98	u64 size, sector, offset;
     99	int res;
    100	size_t remaining, n;
    101	const void *src;
    102
    103	dev_dbg(&dev->sbd.core,
    104		"%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
    105		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
    106
    107	size = dev->regions[dev->region_idx].size*dev->blk_size;
    108	if (*pos >= size || !count)
    109		return 0;
    110
    111	if (*pos + count > size) {
    112		dev_dbg(&dev->sbd.core,
    113			"%s:%u Truncating count from %zu to %llu\n", __func__,
    114			__LINE__, count, size - *pos);
    115		count = size - *pos;
    116	}
    117
    118	sector = *pos / dev->bounce_size * priv->chunk_sectors;
    119	offset = *pos % dev->bounce_size;
    120
    121	remaining = count;
    122	do {
    123		n = min_t(u64, remaining, dev->bounce_size - offset);
    124		src = dev->bounce_buf + offset;
    125
    126		mutex_lock(&priv->mutex);
    127
    128		res = ps3flash_fetch(dev, sector);
    129		if (res)
    130			goto fail;
    131
    132		dev_dbg(&dev->sbd.core,
    133			"%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
    134			__func__, __LINE__, n, src, userbuf, kernelbuf);
    135		if (userbuf) {
    136			if (copy_to_user(userbuf, src, n)) {
    137				res = -EFAULT;
    138				goto fail;
    139			}
    140			userbuf += n;
    141		}
    142		if (kernelbuf) {
    143			memcpy(kernelbuf, src, n);
    144			kernelbuf += n;
    145		}
    146
    147		mutex_unlock(&priv->mutex);
    148
    149		*pos += n;
    150		remaining -= n;
    151		sector += priv->chunk_sectors;
    152		offset = 0;
    153	} while (remaining > 0);
    154
    155	return count;
    156
    157fail:
    158	mutex_unlock(&priv->mutex);
    159	return res;
    160}
    161
    162static ssize_t ps3flash_write(const char __user *userbuf,
    163			      const void *kernelbuf, size_t count, loff_t *pos)
    164{
    165	struct ps3_storage_device *dev = ps3flash_dev;
    166	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
    167	u64 size, sector, offset;
    168	int res = 0;
    169	size_t remaining, n;
    170	void *dst;
    171
    172	dev_dbg(&dev->sbd.core,
    173		"%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
    174		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
    175
    176	size = dev->regions[dev->region_idx].size*dev->blk_size;
    177	if (*pos >= size || !count)
    178		return 0;
    179
    180	if (*pos + count > size) {
    181		dev_dbg(&dev->sbd.core,
    182			"%s:%u Truncating count from %zu to %llu\n", __func__,
    183			__LINE__, count, size - *pos);
    184		count = size - *pos;
    185	}
    186
    187	sector = *pos / dev->bounce_size * priv->chunk_sectors;
    188	offset = *pos % dev->bounce_size;
    189
    190	remaining = count;
    191	do {
    192		n = min_t(u64, remaining, dev->bounce_size - offset);
    193		dst = dev->bounce_buf + offset;
    194
    195		mutex_lock(&priv->mutex);
    196
    197		if (n != dev->bounce_size)
    198			res = ps3flash_fetch(dev, sector);
    199		else if (sector != priv->tag)
    200			res = ps3flash_writeback(dev);
    201		if (res)
    202			goto fail;
    203
    204		dev_dbg(&dev->sbd.core,
    205			"%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
    206			__func__, __LINE__, n, userbuf, kernelbuf, dst);
    207		if (userbuf) {
    208			if (copy_from_user(dst, userbuf, n)) {
    209				res = -EFAULT;
    210				goto fail;
    211			}
    212			userbuf += n;
    213		}
    214		if (kernelbuf) {
    215			memcpy(dst, kernelbuf, n);
    216			kernelbuf += n;
    217		}
    218
    219		priv->tag = sector;
    220		priv->dirty = true;
    221
    222		mutex_unlock(&priv->mutex);
    223
    224		*pos += n;
    225		remaining -= n;
    226		sector += priv->chunk_sectors;
    227		offset = 0;
    228	} while (remaining > 0);
    229
    230	return count;
    231
    232fail:
    233	mutex_unlock(&priv->mutex);
    234	return res;
    235}
    236
    237static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
    238				  size_t count, loff_t *pos)
    239{
    240	return ps3flash_read(buf, NULL, count, pos);
    241}
    242
    243static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
    244				   size_t count, loff_t *pos)
    245{
    246	return ps3flash_write(buf, NULL, count, pos);
    247}
    248
    249static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
    250{
    251	return ps3flash_read(NULL, buf, count, &pos);
    252}
    253
    254static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
    255				     loff_t pos)
    256{
    257	ssize_t res;
    258	int wb;
    259
    260	res = ps3flash_write(NULL, buf, count, &pos);
    261	if (res < 0)
    262		return res;
    263
    264	/* Make kernel writes synchronous */
    265	wb = ps3flash_writeback(ps3flash_dev);
    266	if (wb)
    267		return wb;
    268
    269	return res;
    270}
    271
    272static int ps3flash_flush(struct file *file, fl_owner_t id)
    273{
    274	return ps3flash_writeback(ps3flash_dev);
    275}
    276
    277static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync)
    278{
    279	struct inode *inode = file_inode(file);
    280	int err;
    281	inode_lock(inode);
    282	err = ps3flash_writeback(ps3flash_dev);
    283	inode_unlock(inode);
    284	return err;
    285}
    286
    287static irqreturn_t ps3flash_interrupt(int irq, void *data)
    288{
    289	struct ps3_storage_device *dev = data;
    290	int res;
    291	u64 tag, status;
    292
    293	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
    294
    295	if (tag != dev->tag)
    296		dev_err(&dev->sbd.core,
    297			"%s:%u: tag mismatch, got %llx, expected %llx\n",
    298			__func__, __LINE__, tag, dev->tag);
    299
    300	if (res) {
    301		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
    302			__func__, __LINE__, res, status);
    303	} else {
    304		dev->lv1_status = status;
    305		complete(&dev->done);
    306	}
    307	return IRQ_HANDLED;
    308}
    309
    310static const struct file_operations ps3flash_fops = {
    311	.owner	= THIS_MODULE,
    312	.llseek	= ps3flash_llseek,
    313	.read	= ps3flash_user_read,
    314	.write	= ps3flash_user_write,
    315	.flush	= ps3flash_flush,
    316	.fsync	= ps3flash_fsync,
    317};
    318
    319static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
    320	.read	= ps3flash_kernel_read,
    321	.write	= ps3flash_kernel_write,
    322};
    323
    324static struct miscdevice ps3flash_misc = {
    325	.minor	= MISC_DYNAMIC_MINOR,
    326	.name	= DEVICE_NAME,
    327	.fops	= &ps3flash_fops,
    328};
    329
    330static int ps3flash_probe(struct ps3_system_bus_device *_dev)
    331{
    332	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
    333	struct ps3flash_private *priv;
    334	int error;
    335	unsigned long tmp;
    336
    337	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
    338	if (tmp % FLASH_BLOCK_SIZE) {
    339		dev_err(&dev->sbd.core,
    340			"%s:%u region start %lu is not aligned\n", __func__,
    341			__LINE__, tmp);
    342		return -EINVAL;
    343	}
    344	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
    345	if (tmp % FLASH_BLOCK_SIZE) {
    346		dev_err(&dev->sbd.core,
    347			"%s:%u region size %lu is not aligned\n", __func__,
    348			__LINE__, tmp);
    349		return -EINVAL;
    350	}
    351
    352	/* use static buffer, kmalloc cannot allocate 256 KiB */
    353	if (!ps3flash_bounce_buffer.address)
    354		return -ENODEV;
    355
    356	if (ps3flash_dev) {
    357		dev_err(&dev->sbd.core,
    358			"Only one FLASH device is supported\n");
    359		return -EBUSY;
    360	}
    361
    362	ps3flash_dev = dev;
    363
    364	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
    365	if (!priv) {
    366		error = -ENOMEM;
    367		goto fail;
    368	}
    369
    370	ps3_system_bus_set_drvdata(&dev->sbd, priv);
    371	mutex_init(&priv->mutex);
    372	priv->tag = -1;
    373
    374	dev->bounce_size = ps3flash_bounce_buffer.size;
    375	dev->bounce_buf = ps3flash_bounce_buffer.address;
    376	priv->chunk_sectors = dev->bounce_size / dev->blk_size;
    377
    378	error = ps3stor_setup(dev, ps3flash_interrupt);
    379	if (error)
    380		goto fail_free_priv;
    381
    382	ps3flash_misc.parent = &dev->sbd.core;
    383	error = misc_register(&ps3flash_misc);
    384	if (error) {
    385		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
    386			__func__, __LINE__, error);
    387		goto fail_teardown;
    388	}
    389
    390	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
    391		 __func__, __LINE__, ps3flash_misc.minor);
    392
    393	ps3_os_area_flash_register(&ps3flash_kernel_ops);
    394	return 0;
    395
    396fail_teardown:
    397	ps3stor_teardown(dev);
    398fail_free_priv:
    399	kfree(priv);
    400	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
    401fail:
    402	ps3flash_dev = NULL;
    403	return error;
    404}
    405
    406static void ps3flash_remove(struct ps3_system_bus_device *_dev)
    407{
    408	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
    409
    410	ps3_os_area_flash_register(NULL);
    411	misc_deregister(&ps3flash_misc);
    412	ps3stor_teardown(dev);
    413	kfree(ps3_system_bus_get_drvdata(&dev->sbd));
    414	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
    415	ps3flash_dev = NULL;
    416}
    417
    418
    419static struct ps3_system_bus_driver ps3flash = {
    420	.match_id	= PS3_MATCH_ID_STOR_FLASH,
    421	.core.name	= DEVICE_NAME,
    422	.core.owner	= THIS_MODULE,
    423	.probe		= ps3flash_probe,
    424	.remove		= ps3flash_remove,
    425	.shutdown	= ps3flash_remove,
    426};
    427
    428
    429static int __init ps3flash_init(void)
    430{
    431	return ps3_system_bus_driver_register(&ps3flash);
    432}
    433
    434static void __exit ps3flash_exit(void)
    435{
    436	ps3_system_bus_driver_unregister(&ps3flash);
    437}
    438
    439module_init(ps3flash_init);
    440module_exit(ps3flash_exit);
    441
    442MODULE_LICENSE("GPL");
    443MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
    444MODULE_AUTHOR("Sony Corporation");
    445MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);