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

stop_machine.h (5050B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#ifndef _LINUX_STOP_MACHINE
      3#define _LINUX_STOP_MACHINE
      4
      5#include <linux/cpu.h>
      6#include <linux/cpumask.h>
      7#include <linux/smp.h>
      8#include <linux/list.h>
      9
     10/*
     11 * stop_cpu[s]() is simplistic per-cpu maximum priority cpu
     12 * monopolization mechanism.  The caller can specify a non-sleeping
     13 * function to be executed on a single or multiple cpus preempting all
     14 * other processes and monopolizing those cpus until it finishes.
     15 *
     16 * Resources for this mechanism are preallocated when a cpu is brought
     17 * up and requests are guaranteed to be served as long as the target
     18 * cpus are online.
     19 */
     20typedef int (*cpu_stop_fn_t)(void *arg);
     21
     22#ifdef CONFIG_SMP
     23
     24struct cpu_stop_work {
     25	struct list_head	list;		/* cpu_stopper->works */
     26	cpu_stop_fn_t		fn;
     27	unsigned long		caller;
     28	void			*arg;
     29	struct cpu_stop_done	*done;
     30};
     31
     32int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
     33int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg);
     34bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
     35			 struct cpu_stop_work *work_buf);
     36void stop_machine_park(int cpu);
     37void stop_machine_unpark(int cpu);
     38void stop_machine_yield(const struct cpumask *cpumask);
     39
     40extern void print_stop_info(const char *log_lvl, struct task_struct *task);
     41
     42#else	/* CONFIG_SMP */
     43
     44#include <linux/workqueue.h>
     45
     46struct cpu_stop_work {
     47	struct work_struct	work;
     48	cpu_stop_fn_t		fn;
     49	void			*arg;
     50};
     51
     52static inline int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg)
     53{
     54	int ret = -ENOENT;
     55	preempt_disable();
     56	if (cpu == smp_processor_id())
     57		ret = fn(arg);
     58	preempt_enable();
     59	return ret;
     60}
     61
     62static void stop_one_cpu_nowait_workfn(struct work_struct *work)
     63{
     64	struct cpu_stop_work *stwork =
     65		container_of(work, struct cpu_stop_work, work);
     66	preempt_disable();
     67	stwork->fn(stwork->arg);
     68	preempt_enable();
     69}
     70
     71static inline bool stop_one_cpu_nowait(unsigned int cpu,
     72				       cpu_stop_fn_t fn, void *arg,
     73				       struct cpu_stop_work *work_buf)
     74{
     75	if (cpu == smp_processor_id()) {
     76		INIT_WORK(&work_buf->work, stop_one_cpu_nowait_workfn);
     77		work_buf->fn = fn;
     78		work_buf->arg = arg;
     79		schedule_work(&work_buf->work);
     80		return true;
     81	}
     82
     83	return false;
     84}
     85
     86static inline void print_stop_info(const char *log_lvl, struct task_struct *task) { }
     87
     88#endif	/* CONFIG_SMP */
     89
     90/*
     91 * stop_machine "Bogolock": stop the entire machine, disable
     92 * interrupts.  This is a very heavy lock, which is equivalent to
     93 * grabbing every spinlock (and more).  So the "read" side to such a
     94 * lock is anything which disables preemption.
     95 */
     96#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
     97
     98/**
     99 * stop_machine: freeze the machine on all CPUs and run this function
    100 * @fn: the function to run
    101 * @data: the data ptr for the @fn()
    102 * @cpus: the cpus to run the @fn() on (NULL = any online cpu)
    103 *
    104 * Description: This causes a thread to be scheduled on every cpu,
    105 * each of which disables interrupts.  The result is that no one is
    106 * holding a spinlock or inside any other preempt-disabled region when
    107 * @fn() runs.
    108 *
    109 * This can be thought of as a very heavy write lock, equivalent to
    110 * grabbing every spinlock in the kernel.
    111 *
    112 * Protects against CPU hotplug.
    113 */
    114int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);
    115
    116/**
    117 * stop_machine_cpuslocked: freeze the machine on all CPUs and run this function
    118 * @fn: the function to run
    119 * @data: the data ptr for the @fn()
    120 * @cpus: the cpus to run the @fn() on (NULL = any online cpu)
    121 *
    122 * Same as above. Must be called from with in a cpus_read_lock() protected
    123 * region. Avoids nested calls to cpus_read_lock().
    124 */
    125int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);
    126
    127/**
    128 * stop_core_cpuslocked: - stop all threads on just one core
    129 * @cpu: any cpu in the targeted core
    130 * @fn: the function to run
    131 * @data: the data ptr for @fn()
    132 *
    133 * Same as above, but instead of every CPU, only the logical CPUs of a
    134 * single core are affected.
    135 *
    136 * Context: Must be called from within a cpus_read_lock() protected region.
    137 *
    138 * Return: 0 if all executions of @fn returned 0, any non zero return
    139 * value if any returned non zero.
    140 */
    141int stop_core_cpuslocked(unsigned int cpu, cpu_stop_fn_t fn, void *data);
    142
    143int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
    144				   const struct cpumask *cpus);
    145#else	/* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
    146
    147static __always_inline int stop_machine_cpuslocked(cpu_stop_fn_t fn, void *data,
    148					  const struct cpumask *cpus)
    149{
    150	unsigned long flags;
    151	int ret;
    152	local_irq_save(flags);
    153	ret = fn(data);
    154	local_irq_restore(flags);
    155	return ret;
    156}
    157
    158static __always_inline int
    159stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
    160{
    161	return stop_machine_cpuslocked(fn, data, cpus);
    162}
    163
    164static __always_inline int
    165stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
    166			       const struct cpumask *cpus)
    167{
    168	return stop_machine(fn, data, cpus);
    169}
    170
    171#endif	/* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
    172#endif	/* _LINUX_STOP_MACHINE */