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

wdrtas.c (15006B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
      4 * RTAS calls are available
      5 */
      6
      7/*
      8 * RTAS watchdog driver
      9 *
     10 * (C) Copyright IBM Corp. 2005
     11 * device driver to exploit watchdog RTAS functions
     12 *
     13 * Authors : Utz Bacher <utz.bacher@de.ibm.com>
     14 */
     15
     16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     17
     18#include <linux/fs.h>
     19#include <linux/init.h>
     20#include <linux/kernel.h>
     21#include <linux/miscdevice.h>
     22#include <linux/module.h>
     23#include <linux/notifier.h>
     24#include <linux/reboot.h>
     25#include <linux/types.h>
     26#include <linux/watchdog.h>
     27#include <linux/uaccess.h>
     28
     29#include <asm/rtas.h>
     30
     31#define WDRTAS_MAGIC_CHAR		42
     32#define WDRTAS_SUPPORTED_MASK		(WDIOF_SETTIMEOUT | \
     33					 WDIOF_MAGICCLOSE)
     34
     35MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
     36MODULE_DESCRIPTION("RTAS watchdog driver");
     37MODULE_LICENSE("GPL");
     38
     39static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
     40static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
     41static char wdrtas_expect_close;
     42
     43static int wdrtas_interval;
     44
     45#define WDRTAS_THERMAL_SENSOR		3
     46static int wdrtas_token_get_sensor_state;
     47#define WDRTAS_SURVEILLANCE_IND		9000
     48static int wdrtas_token_set_indicator;
     49#define WDRTAS_SP_SPI			28
     50static int wdrtas_token_get_sp;
     51static int wdrtas_token_event_scan;
     52
     53#define WDRTAS_DEFAULT_INTERVAL		300
     54
     55#define WDRTAS_LOGBUFFER_LEN		128
     56static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
     57
     58
     59/*** watchdog access functions */
     60
     61/**
     62 * wdrtas_set_interval - sets the watchdog interval
     63 * @interval: new interval
     64 *
     65 * returns 0 on success, <0 on failures
     66 *
     67 * wdrtas_set_interval sets the watchdog keepalive interval by calling the
     68 * RTAS function set-indicator (surveillance). The unit of interval is
     69 * seconds.
     70 */
     71
     72static int wdrtas_set_interval(int interval)
     73{
     74	long result;
     75	static int print_msg = 10;
     76
     77	/* rtas uses minutes */
     78	interval = (interval + 59) / 60;
     79
     80	result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
     81			   WDRTAS_SURVEILLANCE_IND, 0, interval);
     82	if (result < 0 && print_msg) {
     83		pr_err("setting the watchdog to %i timeout failed: %li\n",
     84		       interval, result);
     85		print_msg--;
     86	}
     87
     88	return result;
     89}
     90
     91#define WDRTAS_SP_SPI_LEN 4
     92
     93/**
     94 * wdrtas_get_interval - returns the current watchdog interval
     95 * @fallback_value: value (in seconds) to use, if the RTAS call fails
     96 *
     97 * returns the interval
     98 *
     99 * wdrtas_get_interval returns the current watchdog keepalive interval
    100 * as reported by the RTAS function ibm,get-system-parameter. The unit
    101 * of the return value is seconds.
    102 */
    103static int wdrtas_get_interval(int fallback_value)
    104{
    105	long result;
    106	char value[WDRTAS_SP_SPI_LEN];
    107
    108	spin_lock(&rtas_data_buf_lock);
    109	memset(rtas_data_buf, 0, WDRTAS_SP_SPI_LEN);
    110	result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
    111			   WDRTAS_SP_SPI, __pa(rtas_data_buf),
    112			   WDRTAS_SP_SPI_LEN);
    113
    114	memcpy(value, rtas_data_buf, WDRTAS_SP_SPI_LEN);
    115	spin_unlock(&rtas_data_buf_lock);
    116
    117	if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
    118		pr_warn("could not get sp_spi watchdog timeout (%li). Continuing\n",
    119			result);
    120		return fallback_value;
    121	}
    122
    123	/* rtas uses minutes */
    124	return ((int)value[2]) * 60;
    125}
    126
    127/**
    128 * wdrtas_timer_start - starts watchdog
    129 *
    130 * wdrtas_timer_start starts the watchdog by calling the RTAS function
    131 * set-interval (surveillance)
    132 */
    133static void wdrtas_timer_start(void)
    134{
    135	wdrtas_set_interval(wdrtas_interval);
    136}
    137
    138/**
    139 * wdrtas_timer_stop - stops watchdog
    140 *
    141 * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
    142 * set-interval (surveillance)
    143 */
    144static void wdrtas_timer_stop(void)
    145{
    146	wdrtas_set_interval(0);
    147}
    148
    149/**
    150 * wdrtas_timer_keepalive - resets watchdog timer to keep system alive
    151 *
    152 * wdrtas_timer_keepalive restarts the watchdog timer by calling the
    153 * RTAS function event-scan and repeats these calls as long as there are
    154 * events available. All events will be dumped.
    155 */
    156static void wdrtas_timer_keepalive(void)
    157{
    158	long result;
    159
    160	do {
    161		result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
    162				   RTAS_EVENT_SCAN_ALL_EVENTS, 0,
    163				   (void *)__pa(wdrtas_logbuffer),
    164				   WDRTAS_LOGBUFFER_LEN);
    165		if (result < 0)
    166			pr_err("event-scan failed: %li\n", result);
    167		if (result == 0)
    168			print_hex_dump(KERN_INFO, "dumping event, data: ",
    169				DUMP_PREFIX_OFFSET, 16, 1,
    170				wdrtas_logbuffer, WDRTAS_LOGBUFFER_LEN, false);
    171	} while (result == 0);
    172}
    173
    174/**
    175 * wdrtas_get_temperature - returns current temperature
    176 *
    177 * returns temperature or <0 on failures
    178 *
    179 * wdrtas_get_temperature returns the current temperature in Fahrenheit. It
    180 * uses the RTAS call get-sensor-state, token 3 to do so
    181 */
    182static int wdrtas_get_temperature(void)
    183{
    184	int result;
    185	int temperature = 0;
    186
    187	result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
    188
    189	if (result < 0)
    190		pr_warn("reading the thermal sensor failed: %i\n", result);
    191	else
    192		temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
    193
    194	return temperature;
    195}
    196
    197/**
    198 * wdrtas_get_status - returns the status of the watchdog
    199 *
    200 * returns a bitmask of defines WDIOF_... as defined in
    201 * include/linux/watchdog.h
    202 */
    203static int wdrtas_get_status(void)
    204{
    205	return 0; /* TODO */
    206}
    207
    208/**
    209 * wdrtas_get_boot_status - returns the reason for the last boot
    210 *
    211 * returns a bitmask of defines WDIOF_... as defined in
    212 * include/linux/watchdog.h, indicating why the watchdog rebooted the system
    213 */
    214static int wdrtas_get_boot_status(void)
    215{
    216	return 0; /* TODO */
    217}
    218
    219/*** watchdog API and operations stuff */
    220
    221/* wdrtas_write - called when watchdog device is written to
    222 * @file: file structure
    223 * @buf: user buffer with data
    224 * @len: amount to data written
    225 * @ppos: position in file
    226 *
    227 * returns the number of successfully processed characters, which is always
    228 * the number of bytes passed to this function
    229 *
    230 * wdrtas_write processes all the data given to it and looks for the magic
    231 * character 'V'. This character allows the watchdog device to be closed
    232 * properly.
    233 */
    234static ssize_t wdrtas_write(struct file *file, const char __user *buf,
    235	     size_t len, loff_t *ppos)
    236{
    237	int i;
    238	char c;
    239
    240	if (!len)
    241		goto out;
    242
    243	if (!wdrtas_nowayout) {
    244		wdrtas_expect_close = 0;
    245		/* look for 'V' */
    246		for (i = 0; i < len; i++) {
    247			if (get_user(c, buf + i))
    248				return -EFAULT;
    249			/* allow to close device */
    250			if (c == 'V')
    251				wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
    252		}
    253	}
    254
    255	wdrtas_timer_keepalive();
    256
    257out:
    258	return len;
    259}
    260
    261/**
    262 * wdrtas_ioctl - ioctl function for the watchdog device
    263 * @file: file structure
    264 * @cmd: command for ioctl
    265 * @arg: argument pointer
    266 *
    267 * returns 0 on success, <0 on failure
    268 *
    269 * wdrtas_ioctl implements the watchdog API ioctls
    270 */
    271
    272static long wdrtas_ioctl(struct file *file, unsigned int cmd,
    273							unsigned long arg)
    274{
    275	int __user *argp = (void __user *)arg;
    276	int i;
    277	static const struct watchdog_info wdinfo = {
    278		.options = WDRTAS_SUPPORTED_MASK,
    279		.firmware_version = 0,
    280		.identity = "wdrtas",
    281	};
    282
    283	switch (cmd) {
    284	case WDIOC_GETSUPPORT:
    285		if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
    286			return -EFAULT;
    287		return 0;
    288
    289	case WDIOC_GETSTATUS:
    290		i = wdrtas_get_status();
    291		return put_user(i, argp);
    292
    293	case WDIOC_GETBOOTSTATUS:
    294		i = wdrtas_get_boot_status();
    295		return put_user(i, argp);
    296
    297	case WDIOC_GETTEMP:
    298		if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
    299			return -EOPNOTSUPP;
    300
    301		i = wdrtas_get_temperature();
    302		return put_user(i, argp);
    303
    304	case WDIOC_SETOPTIONS:
    305		if (get_user(i, argp))
    306			return -EFAULT;
    307		if (i & WDIOS_DISABLECARD)
    308			wdrtas_timer_stop();
    309		if (i & WDIOS_ENABLECARD) {
    310			wdrtas_timer_keepalive();
    311			wdrtas_timer_start();
    312		}
    313		/* not implemented. Done by H8
    314		if (i & WDIOS_TEMPPANIC) {
    315		} */
    316		return 0;
    317
    318	case WDIOC_KEEPALIVE:
    319		wdrtas_timer_keepalive();
    320		return 0;
    321
    322	case WDIOC_SETTIMEOUT:
    323		if (get_user(i, argp))
    324			return -EFAULT;
    325
    326		if (wdrtas_set_interval(i))
    327			return -EINVAL;
    328
    329		wdrtas_timer_keepalive();
    330
    331		if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
    332			wdrtas_interval = i;
    333		else
    334			wdrtas_interval = wdrtas_get_interval(i);
    335		fallthrough;
    336
    337	case WDIOC_GETTIMEOUT:
    338		return put_user(wdrtas_interval, argp);
    339
    340	default:
    341		return -ENOTTY;
    342	}
    343}
    344
    345/**
    346 * wdrtas_open - open function of watchdog device
    347 * @inode: inode structure
    348 * @file: file structure
    349 *
    350 * returns 0 on success, -EBUSY if the file has been opened already, <0 on
    351 * other failures
    352 *
    353 * function called when watchdog device is opened
    354 */
    355static int wdrtas_open(struct inode *inode, struct file *file)
    356{
    357	/* only open once */
    358	if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
    359		atomic_dec(&wdrtas_miscdev_open);
    360		return -EBUSY;
    361	}
    362
    363	wdrtas_timer_start();
    364	wdrtas_timer_keepalive();
    365
    366	return stream_open(inode, file);
    367}
    368
    369/**
    370 * wdrtas_close - close function of watchdog device
    371 * @inode: inode structure
    372 * @file: file structure
    373 *
    374 * returns 0 on success
    375 *
    376 * close function. Always succeeds
    377 */
    378static int wdrtas_close(struct inode *inode, struct file *file)
    379{
    380	/* only stop watchdog, if this was announced using 'V' before */
    381	if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
    382		wdrtas_timer_stop();
    383	else {
    384		pr_warn("got unexpected close. Watchdog not stopped.\n");
    385		wdrtas_timer_keepalive();
    386	}
    387
    388	wdrtas_expect_close = 0;
    389	atomic_dec(&wdrtas_miscdev_open);
    390	return 0;
    391}
    392
    393/**
    394 * wdrtas_temp_read - gives back the temperature in fahrenheit
    395 * @file: file structure
    396 * @buf: user buffer
    397 * @count: number of bytes to be read
    398 * @ppos: position in file
    399 *
    400 * returns always 1 or -EFAULT in case of user space copy failures, <0 on
    401 * other failures
    402 *
    403 * wdrtas_temp_read gives the temperature to the users by copying this
    404 * value as one byte into the user space buffer. The unit is Fahrenheit...
    405 */
    406static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
    407		 size_t count, loff_t *ppos)
    408{
    409	int temperature = 0;
    410
    411	temperature = wdrtas_get_temperature();
    412	if (temperature < 0)
    413		return temperature;
    414
    415	if (copy_to_user(buf, &temperature, 1))
    416		return -EFAULT;
    417
    418	return 1;
    419}
    420
    421/**
    422 * wdrtas_temp_open - open function of temperature device
    423 * @inode: inode structure
    424 * @file: file structure
    425 *
    426 * returns 0 on success, <0 on failure
    427 *
    428 * function called when temperature device is opened
    429 */
    430static int wdrtas_temp_open(struct inode *inode, struct file *file)
    431{
    432	return stream_open(inode, file);
    433}
    434
    435/**
    436 * wdrtas_temp_close - close function of temperature device
    437 * @inode: inode structure
    438 * @file: file structure
    439 *
    440 * returns 0 on success
    441 *
    442 * close function. Always succeeds
    443 */
    444static int wdrtas_temp_close(struct inode *inode, struct file *file)
    445{
    446	return 0;
    447}
    448
    449/**
    450 * wdrtas_reboot - reboot notifier function
    451 * @nb: notifier block structure
    452 * @code: reboot code
    453 * @ptr: unused
    454 *
    455 * returns NOTIFY_DONE
    456 *
    457 * wdrtas_reboot stops the watchdog in case of a reboot
    458 */
    459static int wdrtas_reboot(struct notifier_block *this,
    460					unsigned long code, void *ptr)
    461{
    462	if (code == SYS_DOWN || code == SYS_HALT)
    463		wdrtas_timer_stop();
    464
    465	return NOTIFY_DONE;
    466}
    467
    468/*** initialization stuff */
    469
    470static const struct file_operations wdrtas_fops = {
    471	.owner		= THIS_MODULE,
    472	.llseek		= no_llseek,
    473	.write		= wdrtas_write,
    474	.unlocked_ioctl	= wdrtas_ioctl,
    475	.compat_ioctl	= compat_ptr_ioctl,
    476	.open		= wdrtas_open,
    477	.release	= wdrtas_close,
    478};
    479
    480static struct miscdevice wdrtas_miscdev = {
    481	.minor =	WATCHDOG_MINOR,
    482	.name =		"watchdog",
    483	.fops =		&wdrtas_fops,
    484};
    485
    486static const struct file_operations wdrtas_temp_fops = {
    487	.owner		= THIS_MODULE,
    488	.llseek		= no_llseek,
    489	.read		= wdrtas_temp_read,
    490	.open		= wdrtas_temp_open,
    491	.release	= wdrtas_temp_close,
    492};
    493
    494static struct miscdevice wdrtas_tempdev = {
    495	.minor =	TEMP_MINOR,
    496	.name =		"temperature",
    497	.fops =		&wdrtas_temp_fops,
    498};
    499
    500static struct notifier_block wdrtas_notifier = {
    501	.notifier_call =	wdrtas_reboot,
    502};
    503
    504/**
    505 * wdrtas_get_tokens - reads in RTAS tokens
    506 *
    507 * returns 0 on success, <0 on failure
    508 *
    509 * wdrtas_get_tokens reads in the tokens for the RTAS calls used in
    510 * this watchdog driver. It tolerates, if "get-sensor-state" and
    511 * "ibm,get-system-parameter" are not available.
    512 */
    513static int wdrtas_get_tokens(void)
    514{
    515	wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
    516	if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
    517		pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
    518	}
    519
    520	wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
    521	if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
    522		pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
    523			WDRTAS_DEFAULT_INTERVAL);
    524	}
    525
    526	wdrtas_token_set_indicator = rtas_token("set-indicator");
    527	if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
    528		pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
    529		return -EIO;
    530	}
    531
    532	wdrtas_token_event_scan = rtas_token("event-scan");
    533	if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
    534		pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
    535		return -EIO;
    536	}
    537
    538	return 0;
    539}
    540
    541/**
    542 * wdrtas_unregister_devs - unregisters the misc dev handlers
    543 *
    544 * wdrtas_register_devs unregisters the watchdog and temperature watchdog
    545 * misc devs
    546 */
    547static void wdrtas_unregister_devs(void)
    548{
    549	misc_deregister(&wdrtas_miscdev);
    550	if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
    551		misc_deregister(&wdrtas_tempdev);
    552}
    553
    554/**
    555 * wdrtas_register_devs - registers the misc dev handlers
    556 *
    557 * returns 0 on success, <0 on failure
    558 *
    559 * wdrtas_register_devs registers the watchdog and temperature watchdog
    560 * misc devs
    561 */
    562static int wdrtas_register_devs(void)
    563{
    564	int result;
    565
    566	result = misc_register(&wdrtas_miscdev);
    567	if (result) {
    568		pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
    569		return result;
    570	}
    571
    572	if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
    573		result = misc_register(&wdrtas_tempdev);
    574		if (result) {
    575			pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
    576			wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
    577		}
    578	}
    579
    580	return 0;
    581}
    582
    583/**
    584 * wdrtas_init - init function of the watchdog driver
    585 *
    586 * returns 0 on success, <0 on failure
    587 *
    588 * registers the file handlers and the reboot notifier
    589 */
    590static int __init wdrtas_init(void)
    591{
    592	if (wdrtas_get_tokens())
    593		return -ENODEV;
    594
    595	if (wdrtas_register_devs())
    596		return -ENODEV;
    597
    598	if (register_reboot_notifier(&wdrtas_notifier)) {
    599		pr_err("could not register reboot notifier. Terminating watchdog code.\n");
    600		wdrtas_unregister_devs();
    601		return -ENODEV;
    602	}
    603
    604	if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
    605		wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
    606	else
    607		wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
    608
    609	return 0;
    610}
    611
    612/**
    613 * wdrtas_exit - exit function of the watchdog driver
    614 *
    615 * unregisters the file handlers and the reboot notifier
    616 */
    617static void __exit wdrtas_exit(void)
    618{
    619	if (!wdrtas_nowayout)
    620		wdrtas_timer_stop();
    621
    622	wdrtas_unregister_devs();
    623
    624	unregister_reboot_notifier(&wdrtas_notifier);
    625}
    626
    627module_init(wdrtas_init);
    628module_exit(wdrtas_exit);