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

opal-sysparam.c (6850B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * PowerNV system parameter code
      4 *
      5 * Copyright (C) 2013 IBM
      6 */
      7
      8#include <linux/kobject.h>
      9#include <linux/mutex.h>
     10#include <linux/slab.h>
     11#include <linux/of.h>
     12#include <linux/gfp.h>
     13#include <linux/stat.h>
     14#include <asm/opal.h>
     15
     16#define MAX_PARAM_DATA_LEN	64
     17
     18static DEFINE_MUTEX(opal_sysparam_mutex);
     19static struct kobject *sysparam_kobj;
     20static void *param_data_buf;
     21
     22struct param_attr {
     23	struct list_head list;
     24	u32 param_id;
     25	u32 param_size;
     26	struct kobj_attribute kobj_attr;
     27};
     28
     29static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
     30{
     31	struct opal_msg msg;
     32	ssize_t ret;
     33	int token;
     34
     35	token = opal_async_get_token_interruptible();
     36	if (token < 0) {
     37		if (token != -ERESTARTSYS)
     38			pr_err("%s: Couldn't get the token, returning\n",
     39					__func__);
     40		ret = token;
     41		goto out;
     42	}
     43
     44	ret = opal_get_param(token, param_id, (u64)buffer, length);
     45	if (ret != OPAL_ASYNC_COMPLETION) {
     46		ret = opal_error_code(ret);
     47		goto out_token;
     48	}
     49
     50	ret = opal_async_wait_response(token, &msg);
     51	if (ret) {
     52		pr_err("%s: Failed to wait for the async response, %zd\n",
     53				__func__, ret);
     54		goto out_token;
     55	}
     56
     57	ret = opal_error_code(opal_get_async_rc(msg));
     58
     59out_token:
     60	opal_async_release_token(token);
     61out:
     62	return ret;
     63}
     64
     65static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
     66{
     67	struct opal_msg msg;
     68	int ret, token;
     69
     70	token = opal_async_get_token_interruptible();
     71	if (token < 0) {
     72		if (token != -ERESTARTSYS)
     73			pr_err("%s: Couldn't get the token, returning\n",
     74					__func__);
     75		ret = token;
     76		goto out;
     77	}
     78
     79	ret = opal_set_param(token, param_id, (u64)buffer, length);
     80
     81	if (ret != OPAL_ASYNC_COMPLETION) {
     82		ret = opal_error_code(ret);
     83		goto out_token;
     84	}
     85
     86	ret = opal_async_wait_response(token, &msg);
     87	if (ret) {
     88		pr_err("%s: Failed to wait for the async response, %d\n",
     89				__func__, ret);
     90		goto out_token;
     91	}
     92
     93	ret = opal_error_code(opal_get_async_rc(msg));
     94
     95out_token:
     96	opal_async_release_token(token);
     97out:
     98	return ret;
     99}
    100
    101static ssize_t sys_param_show(struct kobject *kobj,
    102		struct kobj_attribute *kobj_attr, char *buf)
    103{
    104	struct param_attr *attr = container_of(kobj_attr, struct param_attr,
    105			kobj_attr);
    106	ssize_t ret;
    107
    108	mutex_lock(&opal_sysparam_mutex);
    109	ret = opal_get_sys_param(attr->param_id, attr->param_size,
    110			param_data_buf);
    111	if (ret)
    112		goto out;
    113
    114	memcpy(buf, param_data_buf, attr->param_size);
    115
    116	ret = attr->param_size;
    117out:
    118	mutex_unlock(&opal_sysparam_mutex);
    119	return ret;
    120}
    121
    122static ssize_t sys_param_store(struct kobject *kobj,
    123		struct kobj_attribute *kobj_attr, const char *buf, size_t count)
    124{
    125	struct param_attr *attr = container_of(kobj_attr, struct param_attr,
    126			kobj_attr);
    127	ssize_t ret;
    128
    129        /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
    130        if (count > MAX_PARAM_DATA_LEN)
    131                count = MAX_PARAM_DATA_LEN;
    132
    133	mutex_lock(&opal_sysparam_mutex);
    134	memcpy(param_data_buf, buf, count);
    135	ret = opal_set_sys_param(attr->param_id, attr->param_size,
    136			param_data_buf);
    137	mutex_unlock(&opal_sysparam_mutex);
    138	if (!ret)
    139		ret = count;
    140	return ret;
    141}
    142
    143void __init opal_sys_param_init(void)
    144{
    145	struct device_node *sysparam;
    146	struct param_attr *attr;
    147	u32 *id, *size;
    148	int count, i;
    149	u8 *perm;
    150
    151	if (!opal_kobj) {
    152		pr_warn("SYSPARAM: opal kobject is not available\n");
    153		goto out;
    154	}
    155
    156	/* Some systems do not use sysparams; this is not an error */
    157	sysparam = of_find_node_by_path("/ibm,opal/sysparams");
    158	if (!sysparam)
    159		goto out;
    160
    161	if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
    162		pr_err("SYSPARAM: Opal sysparam node not compatible\n");
    163		goto out_node_put;
    164	}
    165
    166	sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
    167	if (!sysparam_kobj) {
    168		pr_err("SYSPARAM: Failed to create sysparam kobject\n");
    169		goto out_node_put;
    170	}
    171
    172	/* Allocate big enough buffer for any get/set transactions */
    173	param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
    174	if (!param_data_buf) {
    175		pr_err("SYSPARAM: Failed to allocate memory for param data "
    176				"buf\n");
    177		goto out_kobj_put;
    178	}
    179
    180	/* Number of parameters exposed through DT */
    181	count = of_property_count_strings(sysparam, "param-name");
    182	if (count < 0) {
    183		pr_err("SYSPARAM: No string found of property param-name in "
    184				"the node %pOFn\n", sysparam);
    185		goto out_param_buf;
    186	}
    187
    188	id = kcalloc(count, sizeof(*id), GFP_KERNEL);
    189	if (!id) {
    190		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
    191				"id\n");
    192		goto out_param_buf;
    193	}
    194
    195	size = kcalloc(count, sizeof(*size), GFP_KERNEL);
    196	if (!size) {
    197		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
    198				"size\n");
    199		goto out_free_id;
    200	}
    201
    202	perm = kcalloc(count, sizeof(*perm), GFP_KERNEL);
    203	if (!perm) {
    204		pr_err("SYSPARAM: Failed to allocate memory to read supported "
    205				"action on the parameter");
    206		goto out_free_size;
    207	}
    208
    209	if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
    210		pr_err("SYSPARAM: Missing property param-id in the DT\n");
    211		goto out_free_perm;
    212	}
    213
    214	if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
    215		pr_err("SYSPARAM: Missing property param-len in the DT\n");
    216		goto out_free_perm;
    217	}
    218
    219
    220	if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
    221		pr_err("SYSPARAM: Missing property param-perm in the DT\n");
    222		goto out_free_perm;
    223	}
    224
    225	attr = kcalloc(count, sizeof(*attr), GFP_KERNEL);
    226	if (!attr) {
    227		pr_err("SYSPARAM: Failed to allocate memory for parameter "
    228				"attributes\n");
    229		goto out_free_perm;
    230	}
    231
    232	/* For each of the parameters, populate the parameter attributes */
    233	for (i = 0; i < count; i++) {
    234		if (size[i] > MAX_PARAM_DATA_LEN) {
    235			pr_warn("SYSPARAM: Not creating parameter %d as size "
    236				"exceeds buffer length\n", i);
    237			continue;
    238		}
    239
    240		sysfs_attr_init(&attr[i].kobj_attr.attr);
    241		attr[i].param_id = id[i];
    242		attr[i].param_size = size[i];
    243		if (of_property_read_string_index(sysparam, "param-name", i,
    244				&attr[i].kobj_attr.attr.name))
    245			continue;
    246
    247		/* If the parameter is read-only or read-write */
    248		switch (perm[i] & 3) {
    249		case OPAL_SYSPARAM_READ:
    250			attr[i].kobj_attr.attr.mode = 0444;
    251			break;
    252		case OPAL_SYSPARAM_WRITE:
    253			attr[i].kobj_attr.attr.mode = 0200;
    254			break;
    255		case OPAL_SYSPARAM_RW:
    256			attr[i].kobj_attr.attr.mode = 0644;
    257			break;
    258		default:
    259			break;
    260		}
    261
    262		attr[i].kobj_attr.show = sys_param_show;
    263		attr[i].kobj_attr.store = sys_param_store;
    264
    265		if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
    266			pr_err("SYSPARAM: Failed to create sysfs file %s\n",
    267					attr[i].kobj_attr.attr.name);
    268			goto out_free_attr;
    269		}
    270	}
    271
    272	kfree(perm);
    273	kfree(size);
    274	kfree(id);
    275	of_node_put(sysparam);
    276	return;
    277
    278out_free_attr:
    279	kfree(attr);
    280out_free_perm:
    281	kfree(perm);
    282out_free_size:
    283	kfree(size);
    284out_free_id:
    285	kfree(id);
    286out_param_buf:
    287	kfree(param_data_buf);
    288out_kobj_put:
    289	kobject_put(sysparam_kobj);
    290out_node_put:
    291	of_node_put(sysparam);
    292out:
    293	return;
    294}