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

flash.c (4820B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
      3 *
      4 * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
      5 */
      6
      7#include <linux/module.h>
      8#include <linux/types.h>
      9#include <linux/errno.h>
     10#include <linux/miscdevice.h>
     11#include <linux/fcntl.h>
     12#include <linux/poll.h>
     13#include <linux/mutex.h>
     14#include <linux/spinlock.h>
     15#include <linux/mm.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18
     19#include <linux/uaccess.h>
     20#include <asm/io.h>
     21#include <asm/upa.h>
     22
     23static DEFINE_MUTEX(flash_mutex);
     24static DEFINE_SPINLOCK(flash_lock);
     25static struct {
     26	unsigned long read_base;	/* Physical read address */
     27	unsigned long write_base;	/* Physical write address */
     28	unsigned long read_size;	/* Size of read area */
     29	unsigned long write_size;	/* Size of write area */
     30	unsigned long busy;		/* In use? */
     31} flash;
     32
     33static int
     34flash_mmap(struct file *file, struct vm_area_struct *vma)
     35{
     36	unsigned long addr;
     37	unsigned long size;
     38
     39	spin_lock(&flash_lock);
     40	if (flash.read_base == flash.write_base) {
     41		addr = flash.read_base;
     42		size = flash.read_size;
     43	} else {
     44		if ((vma->vm_flags & VM_READ) &&
     45		    (vma->vm_flags & VM_WRITE)) {
     46			spin_unlock(&flash_lock);
     47			return -EINVAL;
     48		}
     49		if (vma->vm_flags & VM_READ) {
     50			addr = flash.read_base;
     51			size = flash.read_size;
     52		} else if (vma->vm_flags & VM_WRITE) {
     53			addr = flash.write_base;
     54			size = flash.write_size;
     55		} else {
     56			spin_unlock(&flash_lock);
     57			return -ENXIO;
     58		}
     59	}
     60	spin_unlock(&flash_lock);
     61
     62	if ((vma->vm_pgoff << PAGE_SHIFT) > size)
     63		return -ENXIO;
     64	addr = vma->vm_pgoff + (addr >> PAGE_SHIFT);
     65
     66	if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size)
     67		size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT));
     68
     69	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
     70
     71	if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
     72		return -EAGAIN;
     73		
     74	return 0;
     75}
     76
     77static long long
     78flash_llseek(struct file *file, long long offset, int origin)
     79{
     80	mutex_lock(&flash_mutex);
     81	switch (origin) {
     82		case 0:
     83			file->f_pos = offset;
     84			break;
     85		case 1:
     86			file->f_pos += offset;
     87			if (file->f_pos > flash.read_size)
     88				file->f_pos = flash.read_size;
     89			break;
     90		case 2:
     91			file->f_pos = flash.read_size;
     92			break;
     93		default:
     94			mutex_unlock(&flash_mutex);
     95			return -EINVAL;
     96	}
     97	mutex_unlock(&flash_mutex);
     98	return file->f_pos;
     99}
    100
    101static ssize_t
    102flash_read(struct file * file, char __user * buf,
    103	   size_t count, loff_t *ppos)
    104{
    105	loff_t p = *ppos;
    106	int i;
    107
    108	if (count > flash.read_size - p)
    109		count = flash.read_size - p;
    110
    111	for (i = 0; i < count; i++) {
    112		u8 data = upa_readb(flash.read_base + p + i);
    113		if (put_user(data, buf))
    114			return -EFAULT;
    115		buf++;
    116	}
    117
    118	*ppos += count;
    119	return count;
    120}
    121
    122static int
    123flash_open(struct inode *inode, struct file *file)
    124{
    125	mutex_lock(&flash_mutex);
    126	if (test_and_set_bit(0, (void *)&flash.busy) != 0) {
    127		mutex_unlock(&flash_mutex);
    128		return -EBUSY;
    129	}
    130
    131	mutex_unlock(&flash_mutex);
    132	return 0;
    133}
    134
    135static int
    136flash_release(struct inode *inode, struct file *file)
    137{
    138	spin_lock(&flash_lock);
    139	flash.busy = 0;
    140	spin_unlock(&flash_lock);
    141
    142	return 0;
    143}
    144
    145static const struct file_operations flash_fops = {
    146	/* no write to the Flash, use mmap
    147	 * and play flash dependent tricks.
    148	 */
    149	.owner =	THIS_MODULE,
    150	.llseek =	flash_llseek,
    151	.read =		flash_read,
    152	.mmap =		flash_mmap,
    153	.open =		flash_open,
    154	.release =	flash_release,
    155};
    156
    157static struct miscdevice flash_dev = { SBUS_FLASH_MINOR, "flash", &flash_fops };
    158
    159static int flash_probe(struct platform_device *op)
    160{
    161	struct device_node *dp = op->dev.of_node;
    162	struct device_node *parent;
    163
    164	parent = dp->parent;
    165
    166	if (!of_node_name_eq(parent, "sbus") &&
    167	    !of_node_name_eq(parent, "sbi") &&
    168	    !of_node_name_eq(parent, "ebus"))
    169		return -ENODEV;
    170
    171	flash.read_base = op->resource[0].start;
    172	flash.read_size = resource_size(&op->resource[0]);
    173	if (op->resource[1].flags) {
    174		flash.write_base = op->resource[1].start;
    175		flash.write_size = resource_size(&op->resource[1]);
    176	} else {
    177		flash.write_base = op->resource[0].start;
    178		flash.write_size = resource_size(&op->resource[0]);
    179	}
    180	flash.busy = 0;
    181
    182	printk(KERN_INFO "%pOF: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
    183	       op->dev.of_node,
    184	       flash.read_base, flash.read_size,
    185	       flash.write_base, flash.write_size);
    186
    187	return misc_register(&flash_dev);
    188}
    189
    190static int flash_remove(struct platform_device *op)
    191{
    192	misc_deregister(&flash_dev);
    193
    194	return 0;
    195}
    196
    197static const struct of_device_id flash_match[] = {
    198	{
    199		.name = "flashprom",
    200	},
    201	{},
    202};
    203MODULE_DEVICE_TABLE(of, flash_match);
    204
    205static struct platform_driver flash_driver = {
    206	.driver = {
    207		.name = "flash",
    208		.of_match_table = flash_match,
    209	},
    210	.probe		= flash_probe,
    211	.remove		= flash_remove,
    212};
    213
    214module_platform_driver(flash_driver);
    215
    216MODULE_LICENSE("GPL");