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

policy.c (12898B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * System Trace Module (STM) master/channel allocation policy management
      4 * Copyright (c) 2014, Intel Corporation.
      5 *
      6 * A master/channel allocation policy allows mapping string identifiers to
      7 * master and channel ranges, where allocation can be done.
      8 */
      9
     10#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
     11
     12#include <linux/types.h>
     13#include <linux/module.h>
     14#include <linux/device.h>
     15#include <linux/configfs.h>
     16#include <linux/slab.h>
     17#include <linux/stm.h>
     18#include "stm.h"
     19
     20/*
     21 * STP Master/Channel allocation policy configfs layout.
     22 */
     23
     24struct stp_policy {
     25	struct config_group	group;
     26	struct stm_device	*stm;
     27};
     28
     29struct stp_policy_node {
     30	struct config_group	group;
     31	struct stp_policy	*policy;
     32	unsigned int		first_master;
     33	unsigned int		last_master;
     34	unsigned int		first_channel;
     35	unsigned int		last_channel;
     36	/* this is the one that's exposed to the attributes */
     37	unsigned char		priv[];
     38};
     39
     40void *stp_policy_node_priv(struct stp_policy_node *pn)
     41{
     42	if (!pn)
     43		return NULL;
     44
     45	return pn->priv;
     46}
     47
     48static struct configfs_subsystem stp_policy_subsys;
     49
     50void stp_policy_node_get_ranges(struct stp_policy_node *policy_node,
     51				unsigned int *mstart, unsigned int *mend,
     52				unsigned int *cstart, unsigned int *cend)
     53{
     54	*mstart	= policy_node->first_master;
     55	*mend	= policy_node->last_master;
     56	*cstart	= policy_node->first_channel;
     57	*cend	= policy_node->last_channel;
     58}
     59
     60static inline struct stp_policy *to_stp_policy(struct config_item *item)
     61{
     62	return item ?
     63		container_of(to_config_group(item), struct stp_policy, group) :
     64		NULL;
     65}
     66
     67static inline struct stp_policy_node *
     68to_stp_policy_node(struct config_item *item)
     69{
     70	return item ?
     71		container_of(to_config_group(item), struct stp_policy_node,
     72			     group) :
     73		NULL;
     74}
     75
     76void *to_pdrv_policy_node(struct config_item *item)
     77{
     78	struct stp_policy_node *node = to_stp_policy_node(item);
     79
     80	return stp_policy_node_priv(node);
     81}
     82EXPORT_SYMBOL_GPL(to_pdrv_policy_node);
     83
     84static ssize_t
     85stp_policy_node_masters_show(struct config_item *item, char *page)
     86{
     87	struct stp_policy_node *policy_node = to_stp_policy_node(item);
     88	ssize_t count;
     89
     90	count = sprintf(page, "%u %u\n", policy_node->first_master,
     91			policy_node->last_master);
     92
     93	return count;
     94}
     95
     96static ssize_t
     97stp_policy_node_masters_store(struct config_item *item, const char *page,
     98			      size_t count)
     99{
    100	struct stp_policy_node *policy_node = to_stp_policy_node(item);
    101	unsigned int first, last;
    102	struct stm_device *stm;
    103	char *p = (char *)page;
    104	ssize_t ret = -ENODEV;
    105
    106	if (sscanf(p, "%u %u", &first, &last) != 2)
    107		return -EINVAL;
    108
    109	mutex_lock(&stp_policy_subsys.su_mutex);
    110	stm = policy_node->policy->stm;
    111	if (!stm)
    112		goto unlock;
    113
    114	/* must be within [sw_start..sw_end], which is an inclusive range */
    115	if (first > last || first < stm->data->sw_start ||
    116	    last > stm->data->sw_end) {
    117		ret = -ERANGE;
    118		goto unlock;
    119	}
    120
    121	ret = count;
    122	policy_node->first_master = first;
    123	policy_node->last_master = last;
    124
    125unlock:
    126	mutex_unlock(&stp_policy_subsys.su_mutex);
    127
    128	return ret;
    129}
    130
    131static ssize_t
    132stp_policy_node_channels_show(struct config_item *item, char *page)
    133{
    134	struct stp_policy_node *policy_node = to_stp_policy_node(item);
    135	ssize_t count;
    136
    137	count = sprintf(page, "%u %u\n", policy_node->first_channel,
    138			policy_node->last_channel);
    139
    140	return count;
    141}
    142
    143static ssize_t
    144stp_policy_node_channels_store(struct config_item *item, const char *page,
    145			       size_t count)
    146{
    147	struct stp_policy_node *policy_node = to_stp_policy_node(item);
    148	unsigned int first, last;
    149	struct stm_device *stm;
    150	char *p = (char *)page;
    151	ssize_t ret = -ENODEV;
    152
    153	if (sscanf(p, "%u %u", &first, &last) != 2)
    154		return -EINVAL;
    155
    156	mutex_lock(&stp_policy_subsys.su_mutex);
    157	stm = policy_node->policy->stm;
    158	if (!stm)
    159		goto unlock;
    160
    161	if (first > INT_MAX || last > INT_MAX || first > last ||
    162	    last >= stm->data->sw_nchannels) {
    163		ret = -ERANGE;
    164		goto unlock;
    165	}
    166
    167	ret = count;
    168	policy_node->first_channel = first;
    169	policy_node->last_channel = last;
    170
    171unlock:
    172	mutex_unlock(&stp_policy_subsys.su_mutex);
    173
    174	return ret;
    175}
    176
    177static void stp_policy_node_release(struct config_item *item)
    178{
    179	struct stp_policy_node *node = to_stp_policy_node(item);
    180
    181	kfree(node);
    182}
    183
    184static struct configfs_item_operations stp_policy_node_item_ops = {
    185	.release		= stp_policy_node_release,
    186};
    187
    188CONFIGFS_ATTR(stp_policy_node_, masters);
    189CONFIGFS_ATTR(stp_policy_node_, channels);
    190
    191static struct configfs_attribute *stp_policy_node_attrs[] = {
    192	&stp_policy_node_attr_masters,
    193	&stp_policy_node_attr_channels,
    194	NULL,
    195};
    196
    197static const struct config_item_type stp_policy_type;
    198static const struct config_item_type stp_policy_node_type;
    199
    200const struct config_item_type *
    201get_policy_node_type(struct configfs_attribute **attrs)
    202{
    203	struct config_item_type *type;
    204	struct configfs_attribute **merged;
    205
    206	type = kmemdup(&stp_policy_node_type, sizeof(stp_policy_node_type),
    207		       GFP_KERNEL);
    208	if (!type)
    209		return NULL;
    210
    211	merged = memcat_p(stp_policy_node_attrs, attrs);
    212	if (!merged) {
    213		kfree(type);
    214		return NULL;
    215	}
    216
    217	type->ct_attrs = merged;
    218
    219	return type;
    220}
    221
    222static struct config_group *
    223stp_policy_node_make(struct config_group *group, const char *name)
    224{
    225	const struct config_item_type *type = &stp_policy_node_type;
    226	struct stp_policy_node *policy_node, *parent_node;
    227	const struct stm_protocol_driver *pdrv;
    228	struct stp_policy *policy;
    229
    230	if (group->cg_item.ci_type == &stp_policy_type) {
    231		policy = container_of(group, struct stp_policy, group);
    232	} else {
    233		parent_node = container_of(group, struct stp_policy_node,
    234					   group);
    235		policy = parent_node->policy;
    236	}
    237
    238	if (!policy->stm)
    239		return ERR_PTR(-ENODEV);
    240
    241	pdrv = policy->stm->pdrv;
    242	policy_node =
    243		kzalloc(offsetof(struct stp_policy_node, priv[pdrv->priv_sz]),
    244			GFP_KERNEL);
    245	if (!policy_node)
    246		return ERR_PTR(-ENOMEM);
    247
    248	if (pdrv->policy_node_init)
    249		pdrv->policy_node_init((void *)policy_node->priv);
    250
    251	if (policy->stm->pdrv_node_type)
    252		type = policy->stm->pdrv_node_type;
    253
    254	config_group_init_type_name(&policy_node->group, name, type);
    255
    256	policy_node->policy = policy;
    257
    258	/* default values for the attributes */
    259	policy_node->first_master = policy->stm->data->sw_start;
    260	policy_node->last_master = policy->stm->data->sw_end;
    261	policy_node->first_channel = 0;
    262	policy_node->last_channel = policy->stm->data->sw_nchannels - 1;
    263
    264	return &policy_node->group;
    265}
    266
    267static void
    268stp_policy_node_drop(struct config_group *group, struct config_item *item)
    269{
    270	config_item_put(item);
    271}
    272
    273static struct configfs_group_operations stp_policy_node_group_ops = {
    274	.make_group	= stp_policy_node_make,
    275	.drop_item	= stp_policy_node_drop,
    276};
    277
    278static const struct config_item_type stp_policy_node_type = {
    279	.ct_item_ops	= &stp_policy_node_item_ops,
    280	.ct_group_ops	= &stp_policy_node_group_ops,
    281	.ct_attrs	= stp_policy_node_attrs,
    282	.ct_owner	= THIS_MODULE,
    283};
    284
    285/*
    286 * Root group: policies.
    287 */
    288static ssize_t stp_policy_device_show(struct config_item *item,
    289				      char *page)
    290{
    291	struct stp_policy *policy = to_stp_policy(item);
    292	ssize_t count;
    293
    294	count = sprintf(page, "%s\n",
    295			(policy && policy->stm) ?
    296			policy->stm->data->name :
    297			"<none>");
    298
    299	return count;
    300}
    301
    302CONFIGFS_ATTR_RO(stp_policy_, device);
    303
    304static ssize_t stp_policy_protocol_show(struct config_item *item,
    305					char *page)
    306{
    307	struct stp_policy *policy = to_stp_policy(item);
    308	ssize_t count;
    309
    310	count = sprintf(page, "%s\n",
    311			(policy && policy->stm) ?
    312			policy->stm->pdrv->name :
    313			"<none>");
    314
    315	return count;
    316}
    317
    318CONFIGFS_ATTR_RO(stp_policy_, protocol);
    319
    320static struct configfs_attribute *stp_policy_attrs[] = {
    321	&stp_policy_attr_device,
    322	&stp_policy_attr_protocol,
    323	NULL,
    324};
    325
    326void stp_policy_unbind(struct stp_policy *policy)
    327{
    328	struct stm_device *stm = policy->stm;
    329
    330	/*
    331	 * stp_policy_release() will not call here if the policy is already
    332	 * unbound; other users should not either, as no link exists between
    333	 * this policy and anything else in that case
    334	 */
    335	if (WARN_ON_ONCE(!policy->stm))
    336		return;
    337
    338	lockdep_assert_held(&stm->policy_mutex);
    339
    340	stm->policy = NULL;
    341	policy->stm = NULL;
    342
    343	/*
    344	 * Drop the reference on the protocol driver and lose the link.
    345	 */
    346	stm_put_protocol(stm->pdrv);
    347	stm->pdrv = NULL;
    348	stm_put_device(stm);
    349}
    350
    351static void stp_policy_release(struct config_item *item)
    352{
    353	struct stp_policy *policy = to_stp_policy(item);
    354	struct stm_device *stm = policy->stm;
    355
    356	/* a policy *can* be unbound and still exist in configfs tree */
    357	if (!stm)
    358		return;
    359
    360	mutex_lock(&stm->policy_mutex);
    361	stp_policy_unbind(policy);
    362	mutex_unlock(&stm->policy_mutex);
    363
    364	kfree(policy);
    365}
    366
    367static struct configfs_item_operations stp_policy_item_ops = {
    368	.release		= stp_policy_release,
    369};
    370
    371static struct configfs_group_operations stp_policy_group_ops = {
    372	.make_group	= stp_policy_node_make,
    373};
    374
    375static const struct config_item_type stp_policy_type = {
    376	.ct_item_ops	= &stp_policy_item_ops,
    377	.ct_group_ops	= &stp_policy_group_ops,
    378	.ct_attrs	= stp_policy_attrs,
    379	.ct_owner	= THIS_MODULE,
    380};
    381
    382static struct config_group *
    383stp_policy_make(struct config_group *group, const char *name)
    384{
    385	const struct config_item_type *pdrv_node_type;
    386	const struct stm_protocol_driver *pdrv;
    387	char *devname, *proto, *p;
    388	struct config_group *ret;
    389	struct stm_device *stm;
    390	int err;
    391
    392	devname = kasprintf(GFP_KERNEL, "%s", name);
    393	if (!devname)
    394		return ERR_PTR(-ENOMEM);
    395
    396	/*
    397	 * node must look like <device_name>.<policy_name>, where
    398	 * <device_name> is the name of an existing stm device; may
    399	 *               contain dots;
    400	 * <policy_name> is an arbitrary string; may not contain dots
    401	 * <device_name>:<protocol_name>.<policy_name>
    402	 */
    403	p = strrchr(devname, '.');
    404	if (!p) {
    405		kfree(devname);
    406		return ERR_PTR(-EINVAL);
    407	}
    408
    409	*p = '\0';
    410
    411	/*
    412	 * look for ":<protocol_name>":
    413	 *  + no protocol suffix: fall back to whatever is available;
    414	 *  + unknown protocol: fail the whole thing
    415	 */
    416	proto = strrchr(devname, ':');
    417	if (proto)
    418		*proto++ = '\0';
    419
    420	stm = stm_find_device(devname);
    421	if (!stm) {
    422		kfree(devname);
    423		return ERR_PTR(-ENODEV);
    424	}
    425
    426	err = stm_lookup_protocol(proto, &pdrv, &pdrv_node_type);
    427	kfree(devname);
    428
    429	if (err) {
    430		stm_put_device(stm);
    431		return ERR_PTR(-ENODEV);
    432	}
    433
    434	mutex_lock(&stm->policy_mutex);
    435	if (stm->policy) {
    436		ret = ERR_PTR(-EBUSY);
    437		goto unlock_policy;
    438	}
    439
    440	stm->policy = kzalloc(sizeof(*stm->policy), GFP_KERNEL);
    441	if (!stm->policy) {
    442		ret = ERR_PTR(-ENOMEM);
    443		goto unlock_policy;
    444	}
    445
    446	config_group_init_type_name(&stm->policy->group, name,
    447				    &stp_policy_type);
    448
    449	stm->pdrv = pdrv;
    450	stm->pdrv_node_type = pdrv_node_type;
    451	stm->policy->stm = stm;
    452	ret = &stm->policy->group;
    453
    454unlock_policy:
    455	mutex_unlock(&stm->policy_mutex);
    456
    457	if (IS_ERR(ret)) {
    458		/*
    459		 * pdrv and stm->pdrv at this point can be quite different,
    460		 * and only one of them needs to be 'put'
    461		 */
    462		stm_put_protocol(pdrv);
    463		stm_put_device(stm);
    464	}
    465
    466	return ret;
    467}
    468
    469static struct configfs_group_operations stp_policy_root_group_ops = {
    470	.make_group	= stp_policy_make,
    471};
    472
    473static const struct config_item_type stp_policy_root_type = {
    474	.ct_group_ops	= &stp_policy_root_group_ops,
    475	.ct_owner	= THIS_MODULE,
    476};
    477
    478static struct configfs_subsystem stp_policy_subsys = {
    479	.su_group = {
    480		.cg_item = {
    481			.ci_namebuf	= "stp-policy",
    482			.ci_type	= &stp_policy_root_type,
    483		},
    484	},
    485};
    486
    487/*
    488 * Lock the policy mutex from the outside
    489 */
    490static struct stp_policy_node *
    491__stp_policy_node_lookup(struct stp_policy *policy, char *s)
    492{
    493	struct stp_policy_node *policy_node, *ret = NULL;
    494	struct list_head *head = &policy->group.cg_children;
    495	struct config_item *item;
    496	char *start, *end = s;
    497
    498	if (list_empty(head))
    499		return NULL;
    500
    501next:
    502	for (;;) {
    503		start = strsep(&end, "/");
    504		if (!start)
    505			break;
    506
    507		if (!*start)
    508			continue;
    509
    510		list_for_each_entry(item, head, ci_entry) {
    511			policy_node = to_stp_policy_node(item);
    512
    513			if (!strcmp(start,
    514				    policy_node->group.cg_item.ci_name)) {
    515				ret = policy_node;
    516
    517				if (!end)
    518					goto out;
    519
    520				head = &policy_node->group.cg_children;
    521				goto next;
    522			}
    523		}
    524		break;
    525	}
    526
    527out:
    528	return ret;
    529}
    530
    531
    532struct stp_policy_node *
    533stp_policy_node_lookup(struct stm_device *stm, char *s)
    534{
    535	struct stp_policy_node *policy_node = NULL;
    536
    537	mutex_lock(&stp_policy_subsys.su_mutex);
    538
    539	mutex_lock(&stm->policy_mutex);
    540	if (stm->policy)
    541		policy_node = __stp_policy_node_lookup(stm->policy, s);
    542	mutex_unlock(&stm->policy_mutex);
    543
    544	if (policy_node)
    545		config_item_get(&policy_node->group.cg_item);
    546	else
    547		mutex_unlock(&stp_policy_subsys.su_mutex);
    548
    549	return policy_node;
    550}
    551
    552void stp_policy_node_put(struct stp_policy_node *policy_node)
    553{
    554	lockdep_assert_held(&stp_policy_subsys.su_mutex);
    555
    556	mutex_unlock(&stp_policy_subsys.su_mutex);
    557	config_item_put(&policy_node->group.cg_item);
    558}
    559
    560int __init stp_configfs_init(void)
    561{
    562	config_group_init(&stp_policy_subsys.su_group);
    563	mutex_init(&stp_policy_subsys.su_mutex);
    564	return configfs_register_subsystem(&stp_policy_subsys);
    565}
    566
    567void __exit stp_configfs_exit(void)
    568{
    569	configfs_unregister_subsystem(&stp_policy_subsys);
    570}