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

crw.c (4153B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *   Channel report handling code
      4 *
      5 *    Copyright IBM Corp. 2000, 2009
      6 *    Author(s): Ingo Adlung <adlung@de.ibm.com>,
      7 *		 Martin Schwidefsky <schwidefsky@de.ibm.com>,
      8 *		 Cornelia Huck <cornelia.huck@de.ibm.com>,
      9 */
     10
     11#include <linux/mutex.h>
     12#include <linux/kthread.h>
     13#include <linux/init.h>
     14#include <linux/wait.h>
     15#include <asm/crw.h>
     16#include <asm/ctl_reg.h>
     17#include "ioasm.h"
     18
     19static DEFINE_MUTEX(crw_handler_mutex);
     20static crw_handler_t crw_handlers[NR_RSCS];
     21static atomic_t crw_nr_req = ATOMIC_INIT(0);
     22static DECLARE_WAIT_QUEUE_HEAD(crw_handler_wait_q);
     23
     24/**
     25 * crw_register_handler() - register a channel report word handler
     26 * @rsc: reporting source code to handle
     27 * @handler: handler to be registered
     28 *
     29 * Returns %0 on success and a negative error value otherwise.
     30 */
     31int crw_register_handler(int rsc, crw_handler_t handler)
     32{
     33	int rc = 0;
     34
     35	if ((rsc < 0) || (rsc >= NR_RSCS))
     36		return -EINVAL;
     37	mutex_lock(&crw_handler_mutex);
     38	if (crw_handlers[rsc])
     39		rc = -EBUSY;
     40	else
     41		crw_handlers[rsc] = handler;
     42	mutex_unlock(&crw_handler_mutex);
     43	return rc;
     44}
     45
     46/**
     47 * crw_unregister_handler() - unregister a channel report word handler
     48 * @rsc: reporting source code to handle
     49 */
     50void crw_unregister_handler(int rsc)
     51{
     52	if ((rsc < 0) || (rsc >= NR_RSCS))
     53		return;
     54	mutex_lock(&crw_handler_mutex);
     55	crw_handlers[rsc] = NULL;
     56	mutex_unlock(&crw_handler_mutex);
     57}
     58
     59/*
     60 * Retrieve CRWs and call function to handle event.
     61 */
     62static int crw_collect_info(void *unused)
     63{
     64	struct crw crw[2];
     65	int ccode, signal;
     66	unsigned int chain;
     67
     68repeat:
     69	signal = wait_event_interruptible(crw_handler_wait_q,
     70					  atomic_read(&crw_nr_req) > 0);
     71	if (unlikely(signal))
     72		atomic_inc(&crw_nr_req);
     73	chain = 0;
     74	while (1) {
     75		crw_handler_t handler;
     76
     77		if (unlikely(chain > 1)) {
     78			struct crw tmp_crw;
     79
     80			printk(KERN_WARNING"%s: Code does not support more "
     81			       "than two chained crws; please report to "
     82			       "linux390@de.ibm.com!\n", __func__);
     83			ccode = stcrw(&tmp_crw);
     84			printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
     85			       "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
     86			       __func__, tmp_crw.slct, tmp_crw.oflw,
     87			       tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
     88			       tmp_crw.erc, tmp_crw.rsid);
     89			printk(KERN_WARNING"%s: This was crw number %x in the "
     90			       "chain\n", __func__, chain);
     91			if (ccode != 0)
     92				break;
     93			chain = tmp_crw.chn ? chain + 1 : 0;
     94			continue;
     95		}
     96		ccode = stcrw(&crw[chain]);
     97		if (ccode != 0)
     98			break;
     99		printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
    100		       "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
    101		       crw[chain].slct, crw[chain].oflw, crw[chain].chn,
    102		       crw[chain].rsc, crw[chain].anc, crw[chain].erc,
    103		       crw[chain].rsid);
    104		/* Check for overflows. */
    105		if (crw[chain].oflw) {
    106			int i;
    107
    108			pr_debug("%s: crw overflow detected!\n", __func__);
    109			mutex_lock(&crw_handler_mutex);
    110			for (i = 0; i < NR_RSCS; i++) {
    111				if (crw_handlers[i])
    112					crw_handlers[i](NULL, NULL, 1);
    113			}
    114			mutex_unlock(&crw_handler_mutex);
    115			chain = 0;
    116			continue;
    117		}
    118		if (crw[0].chn && !chain) {
    119			chain++;
    120			continue;
    121		}
    122		mutex_lock(&crw_handler_mutex);
    123		handler = crw_handlers[crw[chain].rsc];
    124		if (handler)
    125			handler(&crw[0], chain ? &crw[1] : NULL, 0);
    126		mutex_unlock(&crw_handler_mutex);
    127		/* chain is always 0 or 1 here. */
    128		chain = crw[chain].chn ? chain + 1 : 0;
    129	}
    130	if (atomic_dec_and_test(&crw_nr_req))
    131		wake_up(&crw_handler_wait_q);
    132	goto repeat;
    133	return 0;
    134}
    135
    136void crw_handle_channel_report(void)
    137{
    138	atomic_inc(&crw_nr_req);
    139	wake_up(&crw_handler_wait_q);
    140}
    141
    142void crw_wait_for_channel_report(void)
    143{
    144	crw_handle_channel_report();
    145	wait_event(crw_handler_wait_q, atomic_read(&crw_nr_req) == 0);
    146}
    147
    148/*
    149 * Machine checks for the channel subsystem must be enabled
    150 * after the channel subsystem is initialized
    151 */
    152static int __init crw_machine_check_init(void)
    153{
    154	struct task_struct *task;
    155
    156	task = kthread_run(crw_collect_info, NULL, "kmcheck");
    157	if (IS_ERR(task))
    158		return PTR_ERR(task);
    159	ctl_set_bit(14, 28);	/* enable channel report MCH */
    160	return 0;
    161}
    162device_initcall(crw_machine_check_init);