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

ec_sys.c (3227B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ec_sys.c
      4 *
      5 * Copyright (C) 2010 SUSE Products GmbH/Novell
      6 * Author:
      7 *      Thomas Renninger <trenn@suse.de>
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/acpi.h>
     12#include <linux/debugfs.h>
     13#include <linux/module.h>
     14#include <linux/uaccess.h>
     15#include "internal.h"
     16
     17MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
     18MODULE_DESCRIPTION("ACPI EC sysfs access driver");
     19MODULE_LICENSE("GPL");
     20
     21static bool write_support;
     22module_param_hw(write_support, bool, other, 0644);
     23MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may "
     24		 "be needed.");
     25
     26#define EC_SPACE_SIZE 256
     27
     28static struct dentry *acpi_ec_debugfs_dir;
     29
     30static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
     31			       size_t count, loff_t *off)
     32{
     33	/* Use this if support reading/writing multiple ECs exists in ec.c:
     34	 * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
     35	 */
     36	unsigned int size = EC_SPACE_SIZE;
     37	loff_t init_off = *off;
     38	int err = 0;
     39
     40	if (*off >= size)
     41		return 0;
     42	if (*off + count >= size) {
     43		size -= *off;
     44		count = size;
     45	} else
     46		size = count;
     47
     48	while (size) {
     49		u8 byte_read;
     50		err = ec_read(*off, &byte_read);
     51		if (err)
     52			return err;
     53		if (put_user(byte_read, buf + *off - init_off)) {
     54			if (*off - init_off)
     55				return *off - init_off; /* partial read */
     56			return -EFAULT;
     57		}
     58		*off += 1;
     59		size--;
     60	}
     61	return count;
     62}
     63
     64static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
     65				size_t count, loff_t *off)
     66{
     67	/* Use this if support reading/writing multiple ECs exists in ec.c:
     68	 * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
     69	 */
     70
     71	unsigned int size = count;
     72	loff_t init_off = *off;
     73	int err = 0;
     74
     75	if (!write_support)
     76		return -EINVAL;
     77
     78	if (*off >= EC_SPACE_SIZE)
     79		return 0;
     80	if (*off + count >= EC_SPACE_SIZE) {
     81		size = EC_SPACE_SIZE - *off;
     82		count = size;
     83	}
     84
     85	while (size) {
     86		u8 byte_write;
     87		if (get_user(byte_write, buf + *off - init_off)) {
     88			if (*off - init_off)
     89				return *off - init_off; /* partial write */
     90			return -EFAULT;
     91		}
     92		err = ec_write(*off, byte_write);
     93		if (err)
     94			return err;
     95
     96		*off += 1;
     97		size--;
     98	}
     99	return count;
    100}
    101
    102static const struct file_operations acpi_ec_io_ops = {
    103	.owner = THIS_MODULE,
    104	.open  = simple_open,
    105	.read  = acpi_ec_read_io,
    106	.write = acpi_ec_write_io,
    107	.llseek = default_llseek,
    108};
    109
    110static void acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
    111{
    112	struct dentry *dev_dir;
    113	char name[64];
    114	umode_t mode = 0400;
    115
    116	if (ec_device_count == 0)
    117		acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL);
    118
    119	sprintf(name, "ec%u", ec_device_count);
    120	dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir);
    121
    122	debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe);
    123	debugfs_create_bool("use_global_lock", 0444, dev_dir,
    124			    &first_ec->global_lock);
    125
    126	if (write_support)
    127		mode = 0600;
    128	debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops);
    129}
    130
    131static int __init acpi_ec_sys_init(void)
    132{
    133	if (first_ec)
    134		acpi_ec_add_debugfs(first_ec, 0);
    135	return 0;
    136}
    137
    138static void __exit acpi_ec_sys_exit(void)
    139{
    140	debugfs_remove_recursive(acpi_ec_debugfs_dir);
    141}
    142
    143module_init(acpi_ec_sys_init);
    144module_exit(acpi_ec_sys_exit);