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

preemptirq_delay_test.c (4659B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Preempt / IRQ disable delay thread to test latency tracers
      4 *
      5 * Copyright (C) 2018 Joel Fernandes (Google) <joel@joelfernandes.org>
      6 */
      7
      8#include <linux/trace_clock.h>
      9#include <linux/delay.h>
     10#include <linux/interrupt.h>
     11#include <linux/irq.h>
     12#include <linux/kernel.h>
     13#include <linux/kobject.h>
     14#include <linux/kthread.h>
     15#include <linux/module.h>
     16#include <linux/printk.h>
     17#include <linux/string.h>
     18#include <linux/sysfs.h>
     19#include <linux/completion.h>
     20
     21static ulong delay = 100;
     22static char test_mode[12] = "irq";
     23static uint burst_size = 1;
     24static int  cpu_affinity = -1;
     25
     26module_param_named(delay, delay, ulong, 0444);
     27module_param_string(test_mode, test_mode, 12, 0444);
     28module_param_named(burst_size, burst_size, uint, 0444);
     29module_param_named(cpu_affinity, cpu_affinity, int, 0444);
     30MODULE_PARM_DESC(delay, "Period in microseconds (100 us default)");
     31MODULE_PARM_DESC(test_mode, "Mode of the test such as preempt, irq, or alternate (default irq)");
     32MODULE_PARM_DESC(burst_size, "The size of a burst (default 1)");
     33MODULE_PARM_DESC(cpu_affinity, "Cpu num test is running on");
     34
     35static struct completion done;
     36
     37#define MIN(x, y) ((x) < (y) ? (x) : (y))
     38
     39static void busy_wait(ulong time)
     40{
     41	u64 start, end;
     42
     43	start = trace_clock_local();
     44
     45	do {
     46		end = trace_clock_local();
     47		if (kthread_should_stop())
     48			break;
     49	} while ((end - start) < (time * 1000));
     50}
     51
     52static __always_inline void irqoff_test(void)
     53{
     54	unsigned long flags;
     55
     56	local_irq_save(flags);
     57	busy_wait(delay);
     58	local_irq_restore(flags);
     59}
     60
     61static __always_inline void preemptoff_test(void)
     62{
     63	preempt_disable();
     64	busy_wait(delay);
     65	preempt_enable();
     66}
     67
     68static void execute_preemptirqtest(int idx)
     69{
     70	if (!strcmp(test_mode, "irq"))
     71		irqoff_test();
     72	else if (!strcmp(test_mode, "preempt"))
     73		preemptoff_test();
     74	else if (!strcmp(test_mode, "alternate")) {
     75		if (idx % 2 == 0)
     76			irqoff_test();
     77		else
     78			preemptoff_test();
     79	}
     80}
     81
     82#define DECLARE_TESTFN(POSTFIX)				\
     83	static void preemptirqtest_##POSTFIX(int idx)	\
     84	{						\
     85		execute_preemptirqtest(idx);		\
     86	}						\
     87
     88/*
     89 * We create 10 different functions, so that we can get 10 different
     90 * backtraces.
     91 */
     92DECLARE_TESTFN(0)
     93DECLARE_TESTFN(1)
     94DECLARE_TESTFN(2)
     95DECLARE_TESTFN(3)
     96DECLARE_TESTFN(4)
     97DECLARE_TESTFN(5)
     98DECLARE_TESTFN(6)
     99DECLARE_TESTFN(7)
    100DECLARE_TESTFN(8)
    101DECLARE_TESTFN(9)
    102
    103static void (*testfuncs[])(int)  = {
    104	preemptirqtest_0,
    105	preemptirqtest_1,
    106	preemptirqtest_2,
    107	preemptirqtest_3,
    108	preemptirqtest_4,
    109	preemptirqtest_5,
    110	preemptirqtest_6,
    111	preemptirqtest_7,
    112	preemptirqtest_8,
    113	preemptirqtest_9,
    114};
    115
    116#define NR_TEST_FUNCS ARRAY_SIZE(testfuncs)
    117
    118static int preemptirq_delay_run(void *data)
    119{
    120	int i;
    121	int s = MIN(burst_size, NR_TEST_FUNCS);
    122	struct cpumask cpu_mask;
    123
    124	if (cpu_affinity > -1) {
    125		cpumask_clear(&cpu_mask);
    126		cpumask_set_cpu(cpu_affinity, &cpu_mask);
    127		if (set_cpus_allowed_ptr(current, &cpu_mask))
    128			pr_err("cpu_affinity:%d, failed\n", cpu_affinity);
    129	}
    130
    131	for (i = 0; i < s; i++)
    132		(testfuncs[i])(i);
    133
    134	complete(&done);
    135
    136	set_current_state(TASK_INTERRUPTIBLE);
    137	while (!kthread_should_stop()) {
    138		schedule();
    139		set_current_state(TASK_INTERRUPTIBLE);
    140	}
    141
    142	__set_current_state(TASK_RUNNING);
    143
    144	return 0;
    145}
    146
    147static int preemptirq_run_test(void)
    148{
    149	struct task_struct *task;
    150	char task_name[50];
    151
    152	init_completion(&done);
    153
    154	snprintf(task_name, sizeof(task_name), "%s_test", test_mode);
    155	task =  kthread_run(preemptirq_delay_run, NULL, task_name);
    156	if (IS_ERR(task))
    157		return PTR_ERR(task);
    158	if (task) {
    159		wait_for_completion(&done);
    160		kthread_stop(task);
    161	}
    162	return 0;
    163}
    164
    165
    166static ssize_t trigger_store(struct kobject *kobj, struct kobj_attribute *attr,
    167			 const char *buf, size_t count)
    168{
    169	ssize_t ret;
    170
    171	ret = preemptirq_run_test();
    172	if (ret)
    173		return ret;
    174	return count;
    175}
    176
    177static struct kobj_attribute trigger_attribute =
    178	__ATTR(trigger, 0200, NULL, trigger_store);
    179
    180static struct attribute *attrs[] = {
    181	&trigger_attribute.attr,
    182	NULL,
    183};
    184
    185static struct attribute_group attr_group = {
    186	.attrs = attrs,
    187};
    188
    189static struct kobject *preemptirq_delay_kobj;
    190
    191static int __init preemptirq_delay_init(void)
    192{
    193	int retval;
    194
    195	retval = preemptirq_run_test();
    196	if (retval != 0)
    197		return retval;
    198
    199	preemptirq_delay_kobj = kobject_create_and_add("preemptirq_delay_test",
    200						       kernel_kobj);
    201	if (!preemptirq_delay_kobj)
    202		return -ENOMEM;
    203
    204	retval = sysfs_create_group(preemptirq_delay_kobj, &attr_group);
    205	if (retval)
    206		kobject_put(preemptirq_delay_kobj);
    207
    208	return retval;
    209}
    210
    211static void __exit preemptirq_delay_exit(void)
    212{
    213	kobject_put(preemptirq_delay_kobj);
    214}
    215
    216module_init(preemptirq_delay_init)
    217module_exit(preemptirq_delay_exit)
    218MODULE_LICENSE("GPL v2");