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

pvpanic.c (2473B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 *  Pvpanic Device Support
      4 *
      5 *  Copyright (C) 2013 Fujitsu.
      6 *  Copyright (C) 2018 ZTE.
      7 *  Copyright (C) 2021 Oracle.
      8 */
      9
     10#include <linux/io.h>
     11#include <linux/kernel.h>
     12#include <linux/kexec.h>
     13#include <linux/mod_devicetable.h>
     14#include <linux/module.h>
     15#include <linux/platform_device.h>
     16#include <linux/panic_notifier.h>
     17#include <linux/types.h>
     18#include <linux/cdev.h>
     19#include <linux/list.h>
     20
     21#include <uapi/misc/pvpanic.h>
     22
     23#include "pvpanic.h"
     24
     25MODULE_AUTHOR("Mihai Carabas <mihai.carabas@oracle.com>");
     26MODULE_DESCRIPTION("pvpanic device driver");
     27MODULE_LICENSE("GPL");
     28
     29static struct list_head pvpanic_list;
     30static spinlock_t pvpanic_lock;
     31
     32static void
     33pvpanic_send_event(unsigned int event)
     34{
     35	struct pvpanic_instance *pi_cur;
     36
     37	if (!spin_trylock(&pvpanic_lock))
     38		return;
     39
     40	list_for_each_entry(pi_cur, &pvpanic_list, list) {
     41		if (event & pi_cur->capability & pi_cur->events)
     42			iowrite8(event, pi_cur->base);
     43	}
     44	spin_unlock(&pvpanic_lock);
     45}
     46
     47static int
     48pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, void *unused)
     49{
     50	unsigned int event = PVPANIC_PANICKED;
     51
     52	if (kexec_crash_loaded())
     53		event = PVPANIC_CRASH_LOADED;
     54
     55	pvpanic_send_event(event);
     56
     57	return NOTIFY_DONE;
     58}
     59
     60/*
     61 * Call our notifier very early on panic, deferring the
     62 * action taken to the hypervisor.
     63 */
     64static struct notifier_block pvpanic_panic_nb = {
     65	.notifier_call = pvpanic_panic_notify,
     66	.priority = INT_MAX,
     67};
     68
     69static void pvpanic_remove(void *param)
     70{
     71	struct pvpanic_instance *pi_cur, *pi_next;
     72	struct pvpanic_instance *pi = param;
     73
     74	spin_lock(&pvpanic_lock);
     75	list_for_each_entry_safe(pi_cur, pi_next, &pvpanic_list, list) {
     76		if (pi_cur == pi) {
     77			list_del(&pi_cur->list);
     78			break;
     79		}
     80	}
     81	spin_unlock(&pvpanic_lock);
     82}
     83
     84int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi)
     85{
     86	if (!pi || !pi->base)
     87		return -EINVAL;
     88
     89	spin_lock(&pvpanic_lock);
     90	list_add(&pi->list, &pvpanic_list);
     91	spin_unlock(&pvpanic_lock);
     92
     93	dev_set_drvdata(dev, pi);
     94
     95	return devm_add_action_or_reset(dev, pvpanic_remove, pi);
     96}
     97EXPORT_SYMBOL_GPL(devm_pvpanic_probe);
     98
     99static int pvpanic_init(void)
    100{
    101	INIT_LIST_HEAD(&pvpanic_list);
    102	spin_lock_init(&pvpanic_lock);
    103
    104	atomic_notifier_chain_register(&panic_notifier_list, &pvpanic_panic_nb);
    105
    106	return 0;
    107}
    108module_init(pvpanic_init);
    109
    110static void pvpanic_exit(void)
    111{
    112	atomic_notifier_chain_unregister(&panic_notifier_list, &pvpanic_panic_nb);
    113
    114}
    115module_exit(pvpanic_exit);