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

sbc_epx_c3.c (4939B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	SBC EPX C3 0.1	A Hardware Watchdog Device for the Winsystems EPX-C3
      4 *	single board computer
      5 *
      6 *	(c) Copyright 2006 Calin A. Culianu <calin@ajvar.org>, All Rights
      7 *	Reserved.
      8 *
      9 *	based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#include <linux/module.h>
     15#include <linux/moduleparam.h>
     16#include <linux/types.h>
     17#include <linux/kernel.h>
     18#include <linux/fs.h>
     19#include <linux/mm.h>
     20#include <linux/miscdevice.h>
     21#include <linux/watchdog.h>
     22#include <linux/notifier.h>
     23#include <linux/reboot.h>
     24#include <linux/init.h>
     25#include <linux/ioport.h>
     26#include <linux/uaccess.h>
     27#include <linux/io.h>
     28
     29static int epx_c3_alive;
     30
     31#define WATCHDOG_TIMEOUT 1		/* 1 sec default timeout */
     32
     33static bool nowayout = WATCHDOG_NOWAYOUT;
     34module_param(nowayout, bool, 0);
     35MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
     36					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
     37
     38#define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */
     39#define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */
     40
     41static void epx_c3_start(void)
     42{
     43	outb(1, EPXC3_WATCHDOG_CTL_REG);
     44}
     45
     46static void epx_c3_stop(void)
     47{
     48
     49	outb(0, EPXC3_WATCHDOG_CTL_REG);
     50
     51	pr_info("Stopped watchdog timer\n");
     52}
     53
     54static void epx_c3_pet(void)
     55{
     56	outb(1, EPXC3_WATCHDOG_PET_REG);
     57}
     58
     59/*
     60 *	Allow only one person to hold it open
     61 */
     62static int epx_c3_open(struct inode *inode, struct file *file)
     63{
     64	if (epx_c3_alive)
     65		return -EBUSY;
     66
     67	if (nowayout)
     68		__module_get(THIS_MODULE);
     69
     70	/* Activate timer */
     71	epx_c3_start();
     72	epx_c3_pet();
     73
     74	epx_c3_alive = 1;
     75	pr_info("Started watchdog timer\n");
     76
     77	return stream_open(inode, file);
     78}
     79
     80static int epx_c3_release(struct inode *inode, struct file *file)
     81{
     82	/* Shut off the timer.
     83	 * Lock it in if it's a module and we defined ...NOWAYOUT */
     84	if (!nowayout)
     85		epx_c3_stop();		/* Turn the WDT off */
     86
     87	epx_c3_alive = 0;
     88
     89	return 0;
     90}
     91
     92static ssize_t epx_c3_write(struct file *file, const char __user *data,
     93			size_t len, loff_t *ppos)
     94{
     95	/* Refresh the timer. */
     96	if (len)
     97		epx_c3_pet();
     98	return len;
     99}
    100
    101static long epx_c3_ioctl(struct file *file, unsigned int cmd,
    102						unsigned long arg)
    103{
    104	int options, retval = -EINVAL;
    105	int __user *argp = (void __user *)arg;
    106	static const struct watchdog_info ident = {
    107		.options		= WDIOF_KEEPALIVEPING,
    108		.firmware_version	= 0,
    109		.identity		= "Winsystems EPX-C3 H/W Watchdog",
    110	};
    111
    112	switch (cmd) {
    113	case WDIOC_GETSUPPORT:
    114		if (copy_to_user(argp, &ident, sizeof(ident)))
    115			return -EFAULT;
    116		return 0;
    117	case WDIOC_GETSTATUS:
    118	case WDIOC_GETBOOTSTATUS:
    119		return put_user(0, argp);
    120	case WDIOC_SETOPTIONS:
    121		if (get_user(options, argp))
    122			return -EFAULT;
    123
    124		if (options & WDIOS_DISABLECARD) {
    125			epx_c3_stop();
    126			retval = 0;
    127		}
    128
    129		if (options & WDIOS_ENABLECARD) {
    130			epx_c3_start();
    131			retval = 0;
    132		}
    133
    134		return retval;
    135	case WDIOC_KEEPALIVE:
    136		epx_c3_pet();
    137		return 0;
    138	case WDIOC_GETTIMEOUT:
    139		return put_user(WATCHDOG_TIMEOUT, argp);
    140	default:
    141		return -ENOTTY;
    142	}
    143}
    144
    145static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code,
    146				void *unused)
    147{
    148	if (code == SYS_DOWN || code == SYS_HALT)
    149		epx_c3_stop();		/* Turn the WDT off */
    150
    151	return NOTIFY_DONE;
    152}
    153
    154static const struct file_operations epx_c3_fops = {
    155	.owner		= THIS_MODULE,
    156	.llseek		= no_llseek,
    157	.write		= epx_c3_write,
    158	.unlocked_ioctl	= epx_c3_ioctl,
    159	.compat_ioctl	= compat_ptr_ioctl,
    160	.open		= epx_c3_open,
    161	.release	= epx_c3_release,
    162};
    163
    164static struct miscdevice epx_c3_miscdev = {
    165	.minor		= WATCHDOG_MINOR,
    166	.name		= "watchdog",
    167	.fops		= &epx_c3_fops,
    168};
    169
    170static struct notifier_block epx_c3_notifier = {
    171	.notifier_call = epx_c3_notify_sys,
    172};
    173
    174static int __init watchdog_init(void)
    175{
    176	int ret;
    177
    178	if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog"))
    179		return -EBUSY;
    180
    181	ret = register_reboot_notifier(&epx_c3_notifier);
    182	if (ret) {
    183		pr_err("cannot register reboot notifier (err=%d)\n", ret);
    184		goto out;
    185	}
    186
    187	ret = misc_register(&epx_c3_miscdev);
    188	if (ret) {
    189		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
    190		       WATCHDOG_MINOR, ret);
    191		unregister_reboot_notifier(&epx_c3_notifier);
    192		goto out;
    193	}
    194
    195	pr_info("Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n");
    196
    197	return 0;
    198
    199out:
    200	release_region(EPXC3_WATCHDOG_CTL_REG, 2);
    201	return ret;
    202}
    203
    204static void __exit watchdog_exit(void)
    205{
    206	misc_deregister(&epx_c3_miscdev);
    207	unregister_reboot_notifier(&epx_c3_notifier);
    208	release_region(EPXC3_WATCHDOG_CTL_REG, 2);
    209}
    210
    211module_init(watchdog_init);
    212module_exit(watchdog_exit);
    213
    214MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>");
    215MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC.  "
    216	"Note that there is no way to probe for this device -- "
    217	"so only use it if you are *sure* you are running on this specific "
    218	"SBC system from Winsystems!  It writes to IO ports 0x1ee and 0x1ef!");
    219MODULE_LICENSE("GPL");