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

remoteproc_cdev.c (2987B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Character device interface driver for Remoteproc framework.
      4 *
      5 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
      6 */
      7
      8#include <linux/cdev.h>
      9#include <linux/compat.h>
     10#include <linux/fs.h>
     11#include <linux/module.h>
     12#include <linux/remoteproc.h>
     13#include <linux/uaccess.h>
     14#include <uapi/linux/remoteproc_cdev.h>
     15
     16#include "remoteproc_internal.h"
     17
     18#define NUM_RPROC_DEVICES	64
     19static dev_t rproc_major;
     20
     21static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_t len, loff_t *pos)
     22{
     23	struct rproc *rproc = container_of(filp->f_inode->i_cdev, struct rproc, cdev);
     24	int ret = 0;
     25	char cmd[10];
     26
     27	if (!len || len > sizeof(cmd))
     28		return -EINVAL;
     29
     30	ret = copy_from_user(cmd, buf, len);
     31	if (ret)
     32		return -EFAULT;
     33
     34	if (!strncmp(cmd, "start", len)) {
     35		ret = rproc_boot(rproc);
     36	} else if (!strncmp(cmd, "stop", len)) {
     37		ret = rproc_shutdown(rproc);
     38	} else if (!strncmp(cmd, "detach", len)) {
     39		ret = rproc_detach(rproc);
     40	} else {
     41		dev_err(&rproc->dev, "Unrecognized option\n");
     42		ret = -EINVAL;
     43	}
     44
     45	return ret ? ret : len;
     46}
     47
     48static long rproc_device_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
     49{
     50	struct rproc *rproc = container_of(filp->f_inode->i_cdev, struct rproc, cdev);
     51	void __user *argp = (void __user *)arg;
     52	s32 param;
     53
     54	switch (ioctl) {
     55	case RPROC_SET_SHUTDOWN_ON_RELEASE:
     56		if (copy_from_user(&param, argp, sizeof(s32)))
     57			return -EFAULT;
     58
     59		rproc->cdev_put_on_release = !!param;
     60		break;
     61	case RPROC_GET_SHUTDOWN_ON_RELEASE:
     62		param = (s32)rproc->cdev_put_on_release;
     63		if (copy_to_user(argp, &param, sizeof(s32)))
     64			return -EFAULT;
     65
     66		break;
     67	default:
     68		dev_err(&rproc->dev, "Unsupported ioctl\n");
     69		return -EINVAL;
     70	}
     71
     72	return 0;
     73}
     74
     75static int rproc_cdev_release(struct inode *inode, struct file *filp)
     76{
     77	struct rproc *rproc = container_of(inode->i_cdev, struct rproc, cdev);
     78	int ret = 0;
     79
     80	if (!rproc->cdev_put_on_release)
     81		return 0;
     82
     83	if (rproc->state == RPROC_RUNNING)
     84		rproc_shutdown(rproc);
     85	else if (rproc->state == RPROC_ATTACHED)
     86		ret = rproc_detach(rproc);
     87
     88	return ret;
     89}
     90
     91static const struct file_operations rproc_fops = {
     92	.write = rproc_cdev_write,
     93	.unlocked_ioctl = rproc_device_ioctl,
     94	.compat_ioctl = compat_ptr_ioctl,
     95	.release = rproc_cdev_release,
     96};
     97
     98int rproc_char_device_add(struct rproc *rproc)
     99{
    100	int ret;
    101
    102	cdev_init(&rproc->cdev, &rproc_fops);
    103	rproc->cdev.owner = THIS_MODULE;
    104
    105	rproc->dev.devt = MKDEV(MAJOR(rproc_major), rproc->index);
    106	cdev_set_parent(&rproc->cdev, &rproc->dev.kobj);
    107	ret = cdev_add(&rproc->cdev, rproc->dev.devt, 1);
    108	if (ret < 0)
    109		dev_err(&rproc->dev, "Failed to add char dev for %s\n", rproc->name);
    110
    111	return ret;
    112}
    113
    114void rproc_char_device_remove(struct rproc *rproc)
    115{
    116	cdev_del(&rproc->cdev);
    117}
    118
    119void __init rproc_init_cdev(void)
    120{
    121	int ret;
    122
    123	ret = alloc_chrdev_region(&rproc_major, 0, NUM_RPROC_DEVICES, "remoteproc");
    124	if (ret < 0)
    125		pr_err("Failed to alloc rproc_cdev region, err %d\n", ret);
    126}