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

hv_debugfs.c (4487B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Authors:
      4 *   Branden Bonaby <brandonbonaby94@gmail.com>
      5 */
      6
      7#include <linux/hyperv.h>
      8#include <linux/debugfs.h>
      9#include <linux/delay.h>
     10#include <linux/err.h>
     11
     12#include "hyperv_vmbus.h"
     13
     14static struct dentry *hv_debug_root;
     15
     16static int hv_debugfs_delay_get(void *data, u64 *val)
     17{
     18	*val = *(u32 *)data;
     19	return 0;
     20}
     21
     22static int hv_debugfs_delay_set(void *data, u64 val)
     23{
     24	if (val > 1000)
     25		return -EINVAL;
     26	*(u32 *)data = val;
     27	return 0;
     28}
     29
     30DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_delay_fops, hv_debugfs_delay_get,
     31			 hv_debugfs_delay_set, "%llu\n");
     32
     33static int hv_debugfs_state_get(void *data, u64 *val)
     34{
     35	*val = *(bool *)data;
     36	return 0;
     37}
     38
     39static int hv_debugfs_state_set(void *data, u64 val)
     40{
     41	if (val == 1)
     42		*(bool *)data = true;
     43	else if (val == 0)
     44		*(bool *)data = false;
     45	else
     46		return -EINVAL;
     47	return 0;
     48}
     49
     50DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_state_fops, hv_debugfs_state_get,
     51			 hv_debugfs_state_set, "%llu\n");
     52
     53/* Setup delay files to store test values */
     54static int hv_debug_delay_files(struct hv_device *dev, struct dentry *root)
     55{
     56	struct vmbus_channel *channel = dev->channel;
     57	char *buffer = "fuzz_test_buffer_interrupt_delay";
     58	char *message = "fuzz_test_message_delay";
     59	int *buffer_val = &channel->fuzz_testing_interrupt_delay;
     60	int *message_val = &channel->fuzz_testing_message_delay;
     61	struct dentry *buffer_file, *message_file;
     62
     63	buffer_file = debugfs_create_file(buffer, 0644, root,
     64					  buffer_val,
     65					  &hv_debugfs_delay_fops);
     66	if (IS_ERR(buffer_file)) {
     67		pr_debug("debugfs_hyperv: file %s not created\n", buffer);
     68		return PTR_ERR(buffer_file);
     69	}
     70
     71	message_file = debugfs_create_file(message, 0644, root,
     72					   message_val,
     73					   &hv_debugfs_delay_fops);
     74	if (IS_ERR(message_file)) {
     75		pr_debug("debugfs_hyperv: file %s not created\n", message);
     76		return PTR_ERR(message_file);
     77	}
     78
     79	return 0;
     80}
     81
     82/* Setup test state value for vmbus device */
     83static int hv_debug_set_test_state(struct hv_device *dev, struct dentry *root)
     84{
     85	struct vmbus_channel *channel = dev->channel;
     86	bool *state = &channel->fuzz_testing_state;
     87	char *status = "fuzz_test_state";
     88	struct dentry *test_state;
     89
     90	test_state = debugfs_create_file(status, 0644, root,
     91					 state,
     92					 &hv_debugfs_state_fops);
     93	if (IS_ERR(test_state)) {
     94		pr_debug("debugfs_hyperv: file %s not created\n", status);
     95		return PTR_ERR(test_state);
     96	}
     97
     98	return 0;
     99}
    100
    101/* Bind hv device to a dentry for debugfs */
    102static void hv_debug_set_dir_dentry(struct hv_device *dev, struct dentry *root)
    103{
    104	if (hv_debug_root)
    105		dev->debug_dir = root;
    106}
    107
    108/* Create all test dentry's and names for fuzz testing */
    109int hv_debug_add_dev_dir(struct hv_device *dev)
    110{
    111	const char *device = dev_name(&dev->device);
    112	char *delay_name = "delay";
    113	struct dentry *delay, *dev_root;
    114	int ret;
    115
    116	if (!IS_ERR(hv_debug_root)) {
    117		dev_root = debugfs_create_dir(device, hv_debug_root);
    118		if (IS_ERR(dev_root)) {
    119			pr_debug("debugfs_hyperv: hyperv/%s/ not created\n",
    120				 device);
    121			return PTR_ERR(dev_root);
    122		}
    123		hv_debug_set_test_state(dev, dev_root);
    124		hv_debug_set_dir_dentry(dev, dev_root);
    125		delay = debugfs_create_dir(delay_name, dev_root);
    126
    127		if (IS_ERR(delay)) {
    128			pr_debug("debugfs_hyperv: hyperv/%s/%s/ not created\n",
    129				 device, delay_name);
    130			return PTR_ERR(delay);
    131		}
    132		ret = hv_debug_delay_files(dev, delay);
    133
    134		return ret;
    135	}
    136	pr_debug("debugfs_hyperv: hyperv/ not in root debugfs path\n");
    137	return PTR_ERR(hv_debug_root);
    138}
    139
    140/* Remove dentry associated with released hv device */
    141void hv_debug_rm_dev_dir(struct hv_device *dev)
    142{
    143	if (!IS_ERR(hv_debug_root))
    144		debugfs_remove_recursive(dev->debug_dir);
    145}
    146
    147/* Remove all dentrys associated with vmbus testing */
    148void hv_debug_rm_all_dir(void)
    149{
    150	debugfs_remove_recursive(hv_debug_root);
    151}
    152
    153/* Delay buffer/message reads on a vmbus channel */
    154void hv_debug_delay_test(struct vmbus_channel *channel, enum delay delay_type)
    155{
    156	struct vmbus_channel *test_channel =    channel->primary_channel ?
    157						channel->primary_channel :
    158						channel;
    159	bool state = test_channel->fuzz_testing_state;
    160
    161	if (state) {
    162		if (delay_type == 0)
    163			udelay(test_channel->fuzz_testing_interrupt_delay);
    164		else
    165			udelay(test_channel->fuzz_testing_message_delay);
    166	}
    167}
    168
    169/* Initialize top dentry for vmbus testing */
    170int hv_debug_init(void)
    171{
    172	hv_debug_root = debugfs_create_dir("hyperv", NULL);
    173	if (IS_ERR(hv_debug_root)) {
    174		pr_debug("debugfs_hyperv: hyperv/ not created\n");
    175		return PTR_ERR(hv_debug_root);
    176	}
    177	return 0;
    178}