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_cpi_sys.c (8793B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *    SCLP control program identification sysfs interface
      4 *
      5 *    Copyright IBM Corp. 2001, 2007
      6 *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
      7 *		 Michael Ernst <mernst@de.ibm.com>
      8 */
      9
     10#define KMSG_COMPONENT "sclp_cpi"
     11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     12
     13#include <linux/kernel.h>
     14#include <linux/init.h>
     15#include <linux/stat.h>
     16#include <linux/device.h>
     17#include <linux/string.h>
     18#include <linux/ctype.h>
     19#include <linux/kmod.h>
     20#include <linux/timer.h>
     21#include <linux/err.h>
     22#include <linux/slab.h>
     23#include <linux/completion.h>
     24#include <linux/export.h>
     25#include <asm/ebcdic.h>
     26#include <asm/sclp.h>
     27
     28#include "sclp.h"
     29#include "sclp_rw.h"
     30#include "sclp_cpi_sys.h"
     31
     32#define CPI_LENGTH_NAME 8
     33#define CPI_LENGTH_LEVEL 16
     34
     35static DEFINE_MUTEX(sclp_cpi_mutex);
     36
     37struct cpi_evbuf {
     38	struct evbuf_header header;
     39	u8	id_format;
     40	u8	reserved0;
     41	u8	system_type[CPI_LENGTH_NAME];
     42	u64	reserved1;
     43	u8	system_name[CPI_LENGTH_NAME];
     44	u64	reserved2;
     45	u64	system_level;
     46	u64	reserved3;
     47	u8	sysplex_name[CPI_LENGTH_NAME];
     48	u8	reserved4[16];
     49} __attribute__((packed));
     50
     51struct cpi_sccb {
     52	struct sccb_header header;
     53	struct cpi_evbuf cpi_evbuf;
     54} __attribute__((packed));
     55
     56static struct sclp_register sclp_cpi_event = {
     57	.send_mask = EVTYP_CTLPROGIDENT_MASK,
     58};
     59
     60static char system_name[CPI_LENGTH_NAME + 1];
     61static char sysplex_name[CPI_LENGTH_NAME + 1];
     62static char system_type[CPI_LENGTH_NAME + 1];
     63static u64 system_level;
     64
     65static void set_data(char *field, char *data)
     66{
     67	memset(field, ' ', CPI_LENGTH_NAME);
     68	memcpy(field, data, strlen(data));
     69	sclp_ascebc_str(field, CPI_LENGTH_NAME);
     70}
     71
     72static void cpi_callback(struct sclp_req *req, void *data)
     73{
     74	struct completion *completion = data;
     75
     76	complete(completion);
     77}
     78
     79static struct sclp_req *cpi_prepare_req(void)
     80{
     81	struct sclp_req *req;
     82	struct cpi_sccb *sccb;
     83	struct cpi_evbuf *evb;
     84
     85	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
     86	if (!req)
     87		return ERR_PTR(-ENOMEM);
     88	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
     89	if (!sccb) {
     90		kfree(req);
     91		return ERR_PTR(-ENOMEM);
     92	}
     93
     94	/* setup SCCB for Control-Program Identification */
     95	sccb->header.length = sizeof(struct cpi_sccb);
     96	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
     97	sccb->cpi_evbuf.header.type = EVTYP_CTLPROGIDENT;
     98	evb = &sccb->cpi_evbuf;
     99
    100	/* set system type */
    101	set_data(evb->system_type, system_type);
    102
    103	/* set system name */
    104	set_data(evb->system_name, system_name);
    105
    106	/* set system level */
    107	evb->system_level = system_level;
    108
    109	/* set sysplex name */
    110	set_data(evb->sysplex_name, sysplex_name);
    111
    112	/* prepare request data structure presented to SCLP driver */
    113	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
    114	req->sccb = sccb;
    115	req->status = SCLP_REQ_FILLED;
    116	req->callback = cpi_callback;
    117	return req;
    118}
    119
    120static void cpi_free_req(struct sclp_req *req)
    121{
    122	free_page((unsigned long) req->sccb);
    123	kfree(req);
    124}
    125
    126static int cpi_req(void)
    127{
    128	struct completion completion;
    129	struct sclp_req *req;
    130	int rc;
    131	int response;
    132
    133	rc = sclp_register(&sclp_cpi_event);
    134	if (rc)
    135		goto out;
    136	if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) {
    137		rc = -EOPNOTSUPP;
    138		goto out_unregister;
    139	}
    140
    141	req = cpi_prepare_req();
    142	if (IS_ERR(req)) {
    143		rc = PTR_ERR(req);
    144		goto out_unregister;
    145	}
    146
    147	init_completion(&completion);
    148	req->callback_data = &completion;
    149
    150	/* Add request to sclp queue */
    151	rc = sclp_add_request(req);
    152	if (rc)
    153		goto out_free_req;
    154
    155	wait_for_completion(&completion);
    156
    157	if (req->status != SCLP_REQ_DONE) {
    158		pr_warn("request failed (status=0x%02x)\n", req->status);
    159		rc = -EIO;
    160		goto out_free_req;
    161	}
    162
    163	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
    164	if (response != 0x0020) {
    165		pr_warn("request failed with response code 0x%x\n", response);
    166		rc = -EIO;
    167	}
    168
    169out_free_req:
    170	cpi_free_req(req);
    171
    172out_unregister:
    173	sclp_unregister(&sclp_cpi_event);
    174
    175out:
    176	return rc;
    177}
    178
    179static int check_string(const char *attr, const char *str)
    180{
    181	size_t len;
    182	size_t i;
    183
    184	len = strlen(str);
    185
    186	if ((len > 0) && (str[len - 1] == '\n'))
    187		len--;
    188
    189	if (len > CPI_LENGTH_NAME)
    190		return -EINVAL;
    191
    192	for (i = 0; i < len ; i++) {
    193		if (isalpha(str[i]) || isdigit(str[i]) ||
    194		    strchr("$@# ", str[i]))
    195			continue;
    196		return -EINVAL;
    197	}
    198
    199	return 0;
    200}
    201
    202static void set_string(char *attr, const char *value)
    203{
    204	size_t len;
    205	size_t i;
    206
    207	len = strlen(value);
    208
    209	if ((len > 0) && (value[len - 1] == '\n'))
    210		len--;
    211
    212	for (i = 0; i < CPI_LENGTH_NAME; i++) {
    213		if (i < len)
    214			attr[i] = toupper(value[i]);
    215		else
    216			attr[i] = ' ';
    217	}
    218}
    219
    220static ssize_t system_name_show(struct kobject *kobj,
    221				struct kobj_attribute *attr, char *page)
    222{
    223	int rc;
    224
    225	mutex_lock(&sclp_cpi_mutex);
    226	rc = snprintf(page, PAGE_SIZE, "%s\n", system_name);
    227	mutex_unlock(&sclp_cpi_mutex);
    228	return rc;
    229}
    230
    231static ssize_t system_name_store(struct kobject *kobj,
    232				 struct kobj_attribute *attr,
    233				 const char *buf,
    234	size_t len)
    235{
    236	int rc;
    237
    238	rc = check_string("system_name", buf);
    239	if (rc)
    240		return rc;
    241
    242	mutex_lock(&sclp_cpi_mutex);
    243	set_string(system_name, buf);
    244	mutex_unlock(&sclp_cpi_mutex);
    245
    246	return len;
    247}
    248
    249static struct kobj_attribute system_name_attr =
    250	__ATTR(system_name, 0644, system_name_show, system_name_store);
    251
    252static ssize_t sysplex_name_show(struct kobject *kobj,
    253				 struct kobj_attribute *attr, char *page)
    254{
    255	int rc;
    256
    257	mutex_lock(&sclp_cpi_mutex);
    258	rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
    259	mutex_unlock(&sclp_cpi_mutex);
    260	return rc;
    261}
    262
    263static ssize_t sysplex_name_store(struct kobject *kobj,
    264				  struct kobj_attribute *attr,
    265				  const char *buf,
    266	size_t len)
    267{
    268	int rc;
    269
    270	rc = check_string("sysplex_name", buf);
    271	if (rc)
    272		return rc;
    273
    274	mutex_lock(&sclp_cpi_mutex);
    275	set_string(sysplex_name, buf);
    276	mutex_unlock(&sclp_cpi_mutex);
    277
    278	return len;
    279}
    280
    281static struct kobj_attribute sysplex_name_attr =
    282	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
    283
    284static ssize_t system_type_show(struct kobject *kobj,
    285				struct kobj_attribute *attr, char *page)
    286{
    287	int rc;
    288
    289	mutex_lock(&sclp_cpi_mutex);
    290	rc = snprintf(page, PAGE_SIZE, "%s\n", system_type);
    291	mutex_unlock(&sclp_cpi_mutex);
    292	return rc;
    293}
    294
    295static ssize_t system_type_store(struct kobject *kobj,
    296				 struct kobj_attribute *attr,
    297				 const char *buf,
    298	size_t len)
    299{
    300	int rc;
    301
    302	rc = check_string("system_type", buf);
    303	if (rc)
    304		return rc;
    305
    306	mutex_lock(&sclp_cpi_mutex);
    307	set_string(system_type, buf);
    308	mutex_unlock(&sclp_cpi_mutex);
    309
    310	return len;
    311}
    312
    313static struct kobj_attribute system_type_attr =
    314	__ATTR(system_type, 0644, system_type_show, system_type_store);
    315
    316static ssize_t system_level_show(struct kobject *kobj,
    317				 struct kobj_attribute *attr, char *page)
    318{
    319	unsigned long long level;
    320
    321	mutex_lock(&sclp_cpi_mutex);
    322	level = system_level;
    323	mutex_unlock(&sclp_cpi_mutex);
    324	return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
    325}
    326
    327static ssize_t system_level_store(struct kobject *kobj,
    328				  struct kobj_attribute *attr,
    329				  const char *buf,
    330	size_t len)
    331{
    332	unsigned long long level;
    333	char *endp;
    334
    335	level = simple_strtoull(buf, &endp, 16);
    336
    337	if (endp == buf)
    338		return -EINVAL;
    339	if (*endp == '\n')
    340		endp++;
    341	if (*endp)
    342		return -EINVAL;
    343
    344	mutex_lock(&sclp_cpi_mutex);
    345	system_level = level;
    346	mutex_unlock(&sclp_cpi_mutex);
    347	return len;
    348}
    349
    350static struct kobj_attribute system_level_attr =
    351	__ATTR(system_level, 0644, system_level_show, system_level_store);
    352
    353static ssize_t set_store(struct kobject *kobj,
    354			 struct kobj_attribute *attr,
    355			 const char *buf, size_t len)
    356{
    357	int rc;
    358
    359	mutex_lock(&sclp_cpi_mutex);
    360	rc = cpi_req();
    361	mutex_unlock(&sclp_cpi_mutex);
    362	if (rc)
    363		return rc;
    364
    365	return len;
    366}
    367
    368static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
    369
    370static struct attribute *cpi_attrs[] = {
    371	&system_name_attr.attr,
    372	&sysplex_name_attr.attr,
    373	&system_type_attr.attr,
    374	&system_level_attr.attr,
    375	&set_attr.attr,
    376	NULL,
    377};
    378
    379static struct attribute_group cpi_attr_group = {
    380	.attrs = cpi_attrs,
    381};
    382
    383static struct kset *cpi_kset;
    384
    385int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
    386		      const u64 level)
    387{
    388	int rc;
    389
    390	rc = check_string("system_name", system);
    391	if (rc)
    392		return rc;
    393	rc = check_string("sysplex_name", sysplex);
    394	if (rc)
    395		return rc;
    396	rc = check_string("system_type", type);
    397	if (rc)
    398		return rc;
    399
    400	mutex_lock(&sclp_cpi_mutex);
    401	set_string(system_name, system);
    402	set_string(sysplex_name, sysplex);
    403	set_string(system_type, type);
    404	system_level = level;
    405
    406	rc = cpi_req();
    407	mutex_unlock(&sclp_cpi_mutex);
    408
    409	return rc;
    410}
    411EXPORT_SYMBOL(sclp_cpi_set_data);
    412
    413static int __init cpi_init(void)
    414{
    415	int rc;
    416
    417	cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
    418	if (!cpi_kset)
    419		return -ENOMEM;
    420
    421	rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
    422	if (rc)
    423		kset_unregister(cpi_kset);
    424
    425	return rc;
    426}
    427
    428__initcall(cpi_init);