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

cio_inject.c (3736B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *   CIO inject interface
      4 *
      5 *    Copyright IBM Corp. 2021
      6 *    Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
      7 */
      8
      9#define KMSG_COMPONENT "cio"
     10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     11
     12#include <linux/slab.h>
     13#include <linux/spinlock.h>
     14#include <linux/mm.h>
     15#include <linux/debugfs.h>
     16#include <asm/chpid.h>
     17
     18#include "cio_inject.h"
     19#include "cio_debug.h"
     20
     21static DEFINE_SPINLOCK(crw_inject_lock);
     22DEFINE_STATIC_KEY_FALSE(cio_inject_enabled);
     23static struct crw *crw_inject_data;
     24
     25/**
     26 * crw_inject : Initiate the artificial CRW inject
     27 * @crw: The data which needs to be injected as new CRW.
     28 *
     29 * The CRW handler is called, which will use the provided artificial
     30 * data instead of the CRW from the underlying hardware.
     31 *
     32 * Return: 0 on success
     33 */
     34static int crw_inject(struct crw *crw)
     35{
     36	int rc = 0;
     37	struct crw *copy;
     38	unsigned long flags;
     39
     40	copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL);
     41	if (!copy)
     42		return -ENOMEM;
     43
     44	spin_lock_irqsave(&crw_inject_lock, flags);
     45	if (crw_inject_data) {
     46		kfree(copy);
     47		rc = -EBUSY;
     48	} else {
     49		crw_inject_data = copy;
     50	}
     51	spin_unlock_irqrestore(&crw_inject_lock, flags);
     52
     53	if (!rc)
     54		crw_handle_channel_report();
     55
     56	return rc;
     57}
     58
     59/**
     60 * stcrw_get_injected: Copy the artificial CRW data to CRW struct.
     61 * @crw: The target CRW pointer.
     62 *
     63 * Retrieve an injected CRW data. Return 0 on success, 1 if no
     64 * injected-CRW is available. The function reproduces the return
     65 * code of the actual STCRW function.
     66 */
     67int stcrw_get_injected(struct crw *crw)
     68{
     69	int rc = 1;
     70	unsigned long flags;
     71
     72	spin_lock_irqsave(&crw_inject_lock, flags);
     73	if (crw_inject_data) {
     74		memcpy(crw, crw_inject_data, sizeof(*crw));
     75		kfree(crw_inject_data);
     76		crw_inject_data = NULL;
     77		rc = 0;
     78	}
     79	spin_unlock_irqrestore(&crw_inject_lock, flags);
     80
     81	return rc;
     82}
     83
     84/* The debugfs write handler for crw_inject nodes operation */
     85static ssize_t crw_inject_write(struct file *file, const char __user *buf,
     86				size_t lbuf, loff_t *ppos)
     87{
     88	u32 slct, oflw, chn, rsc, anc, erc, rsid;
     89	struct crw crw;
     90	char *buffer;
     91	int rc;
     92
     93	if (!static_branch_likely(&cio_inject_enabled)) {
     94		pr_warn("CIO inject is not enabled - ignoring CRW inject\n");
     95		return -EINVAL;
     96	}
     97
     98	buffer = vmemdup_user(buf, lbuf);
     99	if (IS_ERR(buffer))
    100		return -ENOMEM;
    101
    102	rc = sscanf(buffer, "%x %x %x %x %x %x %x", &slct, &oflw, &chn, &rsc, &anc,
    103		    &erc, &rsid);
    104
    105	kvfree(buffer);
    106	if (rc != 7) {
    107		pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n");
    108		return -EINVAL;
    109	}
    110
    111	memset(&crw, 0, sizeof(crw));
    112	crw.slct = slct;
    113	crw.oflw = oflw;
    114	crw.chn = chn;
    115	crw.rsc = rsc;
    116	crw.anc = anc;
    117	crw.erc = erc;
    118	crw.rsid = rsid;
    119
    120	rc = crw_inject(&crw);
    121	if (rc)
    122		return rc;
    123
    124	return lbuf;
    125}
    126
    127/* Debugfs write handler for inject_enable node*/
    128static ssize_t enable_inject_write(struct file *file, const char __user *buf,
    129				   size_t lbuf, loff_t *ppos)
    130{
    131	unsigned long en = 0;
    132	int rc;
    133
    134	rc = kstrtoul_from_user(buf, lbuf, 10, &en);
    135	if (rc)
    136		return rc;
    137
    138	switch (en) {
    139	case 0:
    140		static_branch_disable(&cio_inject_enabled);
    141		break;
    142	case 1:
    143		static_branch_enable(&cio_inject_enabled);
    144		break;
    145	}
    146
    147	return lbuf;
    148}
    149
    150static const struct file_operations crw_fops = {
    151	.owner = THIS_MODULE,
    152	.write = crw_inject_write,
    153};
    154
    155static const struct file_operations cio_en_fops = {
    156	.owner = THIS_MODULE,
    157	.write = enable_inject_write,
    158};
    159
    160static int __init cio_inject_init(void)
    161{
    162	/* enable_inject node enables the static branching */
    163	debugfs_create_file("enable_inject", 0200, cio_debugfs_dir,
    164			    NULL, &cio_en_fops);
    165
    166	debugfs_create_file("crw_inject", 0200, cio_debugfs_dir,
    167			    NULL, &crw_fops);
    168	return 0;
    169}
    170
    171device_initcall(cio_inject_init);