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

sclp_ocf.c (3894B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *    SCLP OCF communication parameters sysfs interface
      4 *
      5 *    Copyright IBM Corp. 2011
      6 *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
      7 */
      8
      9#define KMSG_COMPONENT "sclp_ocf"
     10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     11
     12#include <linux/kernel.h>
     13#include <linux/init.h>
     14#include <linux/stat.h>
     15#include <linux/device.h>
     16#include <linux/string.h>
     17#include <linux/ctype.h>
     18#include <linux/kmod.h>
     19#include <linux/timer.h>
     20#include <linux/err.h>
     21#include <asm/ebcdic.h>
     22#include <asm/sclp.h>
     23
     24#include "sclp.h"
     25
     26#define OCF_LENGTH_HMC_NETWORK 8UL
     27#define OCF_LENGTH_CPC_NAME 8UL
     28
     29static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
     30static char cpc_name[OCF_LENGTH_CPC_NAME]; /* in EBCDIC */
     31
     32static DEFINE_SPINLOCK(sclp_ocf_lock);
     33static struct work_struct sclp_ocf_change_work;
     34
     35static struct kset *ocf_kset;
     36
     37static void sclp_ocf_change_notify(struct work_struct *work)
     38{
     39	kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE);
     40}
     41
     42/* Handler for OCF event. Look for the CPC image name. */
     43static void sclp_ocf_handler(struct evbuf_header *evbuf)
     44{
     45	struct gds_vector *v;
     46	struct gds_subvector *sv, *netid, *cpc;
     47	size_t size;
     48
     49	/* Find the 0x9f00 block. */
     50	v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
     51				 0x9f00);
     52	if (!v)
     53		return;
     54	/* Find the 0x9f22 block inside the 0x9f00 block. */
     55	v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22);
     56	if (!v)
     57		return;
     58	/* Find the 0x81 block inside the 0x9f22 block. */
     59	sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81);
     60	if (!sv)
     61		return;
     62	/* Find the 0x01 block inside the 0x81 block. */
     63	netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1);
     64	/* Find the 0x02 block inside the 0x81 block. */
     65	cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2);
     66	/* Copy network name and cpc name. */
     67	spin_lock(&sclp_ocf_lock);
     68	if (netid) {
     69		size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length);
     70		memcpy(hmc_network, netid + 1, size);
     71		EBCASC(hmc_network, size);
     72		hmc_network[size] = 0;
     73	}
     74	if (cpc) {
     75		size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
     76		memset(cpc_name, 0, OCF_LENGTH_CPC_NAME);
     77		memcpy(cpc_name, cpc + 1, size);
     78	}
     79	spin_unlock(&sclp_ocf_lock);
     80	schedule_work(&sclp_ocf_change_work);
     81}
     82
     83static struct sclp_register sclp_ocf_event = {
     84	.receive_mask = EVTYP_OCF_MASK,
     85	.receiver_fn = sclp_ocf_handler,
     86};
     87
     88void sclp_ocf_cpc_name_copy(char *dst)
     89{
     90	spin_lock_irq(&sclp_ocf_lock);
     91	memcpy(dst, cpc_name, OCF_LENGTH_CPC_NAME);
     92	spin_unlock_irq(&sclp_ocf_lock);
     93}
     94EXPORT_SYMBOL(sclp_ocf_cpc_name_copy);
     95
     96static ssize_t cpc_name_show(struct kobject *kobj,
     97			     struct kobj_attribute *attr, char *page)
     98{
     99	char name[OCF_LENGTH_CPC_NAME + 1];
    100
    101	sclp_ocf_cpc_name_copy(name);
    102	name[OCF_LENGTH_CPC_NAME] = 0;
    103	EBCASC(name, OCF_LENGTH_CPC_NAME);
    104	return snprintf(page, PAGE_SIZE, "%s\n", name);
    105}
    106
    107static struct kobj_attribute cpc_name_attr =
    108	__ATTR(cpc_name, 0444, cpc_name_show, NULL);
    109
    110static ssize_t hmc_network_show(struct kobject *kobj,
    111				struct kobj_attribute *attr, char *page)
    112{
    113	int rc;
    114
    115	spin_lock_irq(&sclp_ocf_lock);
    116	rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);
    117	spin_unlock_irq(&sclp_ocf_lock);
    118	return rc;
    119}
    120
    121static struct kobj_attribute hmc_network_attr =
    122	__ATTR(hmc_network, 0444, hmc_network_show, NULL);
    123
    124static struct attribute *ocf_attrs[] = {
    125	&cpc_name_attr.attr,
    126	&hmc_network_attr.attr,
    127	NULL,
    128};
    129
    130static const struct attribute_group ocf_attr_group = {
    131	.attrs = ocf_attrs,
    132};
    133
    134static int __init ocf_init(void)
    135{
    136	int rc;
    137
    138	INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);
    139	ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);
    140	if (!ocf_kset)
    141		return -ENOMEM;
    142
    143	rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);
    144	if (rc) {
    145		kset_unregister(ocf_kset);
    146		return rc;
    147	}
    148
    149	return sclp_register(&sclp_ocf_event);
    150}
    151
    152device_initcall(ocf_init);