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

fsl-mc-uapi.c (12766B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Management Complex (MC) userspace support
      4 *
      5 * Copyright 2021 NXP
      6 *
      7 */
      8
      9#include <linux/slab.h>
     10#include <linux/fs.h>
     11#include <linux/uaccess.h>
     12#include <linux/miscdevice.h>
     13
     14#include "fsl-mc-private.h"
     15
     16struct uapi_priv_data {
     17	struct fsl_mc_uapi *uapi;
     18	struct fsl_mc_io *mc_io;
     19};
     20
     21struct fsl_mc_cmd_desc {
     22	u16 cmdid_value;
     23	u16 cmdid_mask;
     24	int size;
     25	bool token;
     26	int flags;
     27};
     28
     29#define FSL_MC_CHECK_MODULE_ID		BIT(0)
     30#define FSL_MC_CAP_NET_ADMIN_NEEDED	BIT(1)
     31
     32enum fsl_mc_cmd_index {
     33	DPDBG_DUMP = 0,
     34	DPDBG_SET,
     35	DPRC_GET_CONTAINER_ID,
     36	DPRC_CREATE_CONT,
     37	DPRC_DESTROY_CONT,
     38	DPRC_ASSIGN,
     39	DPRC_UNASSIGN,
     40	DPRC_GET_OBJ_COUNT,
     41	DPRC_GET_OBJ,
     42	DPRC_GET_RES_COUNT,
     43	DPRC_GET_RES_IDS,
     44	DPRC_SET_OBJ_LABEL,
     45	DPRC_SET_LOCKED,
     46	DPRC_CONNECT,
     47	DPRC_DISCONNECT,
     48	DPRC_GET_POOL,
     49	DPRC_GET_POOL_COUNT,
     50	DPRC_GET_CONNECTION,
     51	DPCI_GET_LINK_STATE,
     52	DPCI_GET_PEER_ATTR,
     53	DPAIOP_GET_SL_VERSION,
     54	DPAIOP_GET_STATE,
     55	DPMNG_GET_VERSION,
     56	DPSECI_GET_TX_QUEUE,
     57	DPMAC_GET_COUNTER,
     58	DPMAC_GET_MAC_ADDR,
     59	DPNI_SET_PRIM_MAC,
     60	DPNI_GET_PRIM_MAC,
     61	DPNI_GET_STATISTICS,
     62	DPNI_GET_LINK_STATE,
     63	DPNI_GET_MAX_FRAME_LENGTH,
     64	DPSW_GET_TAILDROP,
     65	DPSW_SET_TAILDROP,
     66	DPSW_IF_GET_COUNTER,
     67	DPSW_IF_GET_MAX_FRAME_LENGTH,
     68	DPDMUX_GET_COUNTER,
     69	DPDMUX_IF_GET_MAX_FRAME_LENGTH,
     70	GET_ATTR,
     71	GET_IRQ_MASK,
     72	GET_IRQ_STATUS,
     73	CLOSE,
     74	OPEN,
     75	GET_API_VERSION,
     76	DESTROY,
     77	CREATE,
     78};
     79
     80static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
     81	[DPDBG_DUMP] = {
     82		.cmdid_value = 0x1300,
     83		.cmdid_mask = 0xFFF0,
     84		.token = true,
     85		.size = 28,
     86	},
     87	[DPDBG_SET] = {
     88		.cmdid_value = 0x1400,
     89		.cmdid_mask = 0xFFF0,
     90		.token = true,
     91		.size = 28,
     92	},
     93	[DPRC_GET_CONTAINER_ID] = {
     94		.cmdid_value = 0x8300,
     95		.cmdid_mask = 0xFFF0,
     96		.token = false,
     97		.size = 8,
     98	},
     99	[DPRC_CREATE_CONT] = {
    100		.cmdid_value = 0x1510,
    101		.cmdid_mask = 0xFFF0,
    102		.token = true,
    103		.size = 40,
    104		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    105	},
    106	[DPRC_DESTROY_CONT] = {
    107		.cmdid_value = 0x1520,
    108		.cmdid_mask = 0xFFF0,
    109		.token = true,
    110		.size = 12,
    111		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    112	},
    113	[DPRC_ASSIGN] = {
    114		.cmdid_value = 0x1570,
    115		.cmdid_mask = 0xFFF0,
    116		.token = true,
    117		.size = 40,
    118		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    119	},
    120	[DPRC_UNASSIGN] = {
    121		.cmdid_value = 0x1580,
    122		.cmdid_mask = 0xFFF0,
    123		.token = true,
    124		.size = 40,
    125		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    126	},
    127	[DPRC_GET_OBJ_COUNT] = {
    128		.cmdid_value = 0x1590,
    129		.cmdid_mask = 0xFFF0,
    130		.token = true,
    131		.size = 16,
    132	},
    133	[DPRC_GET_OBJ] = {
    134		.cmdid_value = 0x15A0,
    135		.cmdid_mask = 0xFFF0,
    136		.token = true,
    137		.size = 12,
    138	},
    139	[DPRC_GET_RES_COUNT] = {
    140		.cmdid_value = 0x15B0,
    141		.cmdid_mask = 0xFFF0,
    142		.token = true,
    143		.size = 32,
    144	},
    145	[DPRC_GET_RES_IDS] = {
    146		.cmdid_value = 0x15C0,
    147		.cmdid_mask = 0xFFF0,
    148		.token = true,
    149		.size = 40,
    150	},
    151	[DPRC_SET_OBJ_LABEL] = {
    152		.cmdid_value = 0x1610,
    153		.cmdid_mask = 0xFFF0,
    154		.token = true,
    155		.size = 48,
    156		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    157	},
    158	[DPRC_SET_LOCKED] = {
    159		.cmdid_value = 0x16B0,
    160		.cmdid_mask = 0xFFF0,
    161		.token = true,
    162		.size = 16,
    163		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    164	},
    165	[DPRC_CONNECT] = {
    166		.cmdid_value = 0x1670,
    167		.cmdid_mask = 0xFFF0,
    168		.token = true,
    169		.size = 56,
    170		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    171	},
    172	[DPRC_DISCONNECT] = {
    173		.cmdid_value = 0x1680,
    174		.cmdid_mask = 0xFFF0,
    175		.token = true,
    176		.size = 32,
    177		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    178	},
    179	[DPRC_GET_POOL] = {
    180		.cmdid_value = 0x1690,
    181		.cmdid_mask = 0xFFF0,
    182		.token = true,
    183		.size = 12,
    184	},
    185	[DPRC_GET_POOL_COUNT] = {
    186		.cmdid_value = 0x16A0,
    187		.cmdid_mask = 0xFFF0,
    188		.token = true,
    189		.size = 8,
    190	},
    191	[DPRC_GET_CONNECTION] = {
    192		.cmdid_value = 0x16C0,
    193		.cmdid_mask = 0xFFF0,
    194		.token = true,
    195		.size = 32,
    196	},
    197
    198	[DPCI_GET_LINK_STATE] = {
    199		.cmdid_value = 0x0E10,
    200		.cmdid_mask = 0xFFF0,
    201		.token = true,
    202		.size = 8,
    203	},
    204	[DPCI_GET_PEER_ATTR] = {
    205		.cmdid_value = 0x0E20,
    206		.cmdid_mask = 0xFFF0,
    207		.token = true,
    208		.size = 8,
    209	},
    210	[DPAIOP_GET_SL_VERSION] = {
    211		.cmdid_value = 0x2820,
    212		.cmdid_mask = 0xFFF0,
    213		.token = true,
    214		.size = 8,
    215	},
    216	[DPAIOP_GET_STATE] = {
    217		.cmdid_value = 0x2830,
    218		.cmdid_mask = 0xFFF0,
    219		.token = true,
    220		.size = 8,
    221	},
    222	[DPMNG_GET_VERSION] = {
    223		.cmdid_value = 0x8310,
    224		.cmdid_mask = 0xFFF0,
    225		.token = false,
    226		.size = 8,
    227	},
    228	[DPSECI_GET_TX_QUEUE] = {
    229		.cmdid_value = 0x1970,
    230		.cmdid_mask = 0xFFF0,
    231		.token = true,
    232		.size = 14,
    233	},
    234	[DPMAC_GET_COUNTER] = {
    235		.cmdid_value = 0x0c40,
    236		.cmdid_mask = 0xFFF0,
    237		.token = true,
    238		.size = 9,
    239	},
    240	[DPMAC_GET_MAC_ADDR] = {
    241		.cmdid_value = 0x0c50,
    242		.cmdid_mask = 0xFFF0,
    243		.token = true,
    244		.size = 8,
    245	},
    246	[DPNI_SET_PRIM_MAC] = {
    247		.cmdid_value = 0x2240,
    248		.cmdid_mask = 0xFFF0,
    249		.token = true,
    250		.size = 16,
    251		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    252	},
    253	[DPNI_GET_PRIM_MAC] = {
    254		.cmdid_value = 0x2250,
    255		.cmdid_mask = 0xFFF0,
    256		.token = true,
    257		.size = 8,
    258	},
    259	[DPNI_GET_STATISTICS] = {
    260		.cmdid_value = 0x25D0,
    261		.cmdid_mask = 0xFFF0,
    262		.token = true,
    263		.size = 10,
    264	},
    265	[DPNI_GET_LINK_STATE] = {
    266		.cmdid_value = 0x2150,
    267		.cmdid_mask = 0xFFF0,
    268		.token = true,
    269		.size = 8,
    270	},
    271	[DPNI_GET_MAX_FRAME_LENGTH] = {
    272		.cmdid_value = 0x2170,
    273		.cmdid_mask = 0xFFF0,
    274		.token = true,
    275		.size = 8,
    276	},
    277	[DPSW_GET_TAILDROP] = {
    278		.cmdid_value = 0x0A80,
    279		.cmdid_mask = 0xFFF0,
    280		.token = true,
    281		.size = 14,
    282	},
    283	[DPSW_SET_TAILDROP] = {
    284		.cmdid_value = 0x0A90,
    285		.cmdid_mask = 0xFFF0,
    286		.token = true,
    287		.size = 24,
    288		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
    289	},
    290	[DPSW_IF_GET_COUNTER] = {
    291		.cmdid_value = 0x0340,
    292		.cmdid_mask = 0xFFF0,
    293		.token = true,
    294		.size = 11,
    295	},
    296	[DPSW_IF_GET_MAX_FRAME_LENGTH] = {
    297		.cmdid_value = 0x0450,
    298		.cmdid_mask = 0xFFF0,
    299		.token = true,
    300		.size = 10,
    301	},
    302	[DPDMUX_GET_COUNTER] = {
    303		.cmdid_value = 0x0b20,
    304		.cmdid_mask = 0xFFF0,
    305		.token = true,
    306		.size = 11,
    307	},
    308	[DPDMUX_IF_GET_MAX_FRAME_LENGTH] = {
    309		.cmdid_value = 0x0a20,
    310		.cmdid_mask = 0xFFF0,
    311		.token = true,
    312		.size = 10,
    313	},
    314	[GET_ATTR] = {
    315		.cmdid_value = 0x0040,
    316		.cmdid_mask = 0xFFF0,
    317		.token = true,
    318		.size = 8,
    319	},
    320	[GET_IRQ_MASK] = {
    321		.cmdid_value = 0x0150,
    322		.cmdid_mask = 0xFFF0,
    323		.token = true,
    324		.size = 13,
    325	},
    326	[GET_IRQ_STATUS] = {
    327		.cmdid_value = 0x0160,
    328		.cmdid_mask = 0xFFF0,
    329		.token = true,
    330		.size = 13,
    331	},
    332	[CLOSE] = {
    333		.cmdid_value = 0x8000,
    334		.cmdid_mask = 0xFFF0,
    335		.token = true,
    336		.size = 8,
    337	},
    338
    339	/* Common commands amongst all types of objects. Must be checked last. */
    340	[OPEN] = {
    341		.cmdid_value = 0x8000,
    342		.cmdid_mask = 0xFC00,
    343		.token = false,
    344		.size = 12,
    345		.flags = FSL_MC_CHECK_MODULE_ID,
    346	},
    347	[GET_API_VERSION] = {
    348		.cmdid_value = 0xA000,
    349		.cmdid_mask = 0xFC00,
    350		.token = false,
    351		.size = 8,
    352		.flags = FSL_MC_CHECK_MODULE_ID,
    353	},
    354	[DESTROY] = {
    355		.cmdid_value = 0x9800,
    356		.cmdid_mask = 0xFC00,
    357		.token = true,
    358		.size = 12,
    359		.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
    360	},
    361	[CREATE] = {
    362		.cmdid_value = 0x9000,
    363		.cmdid_mask = 0xFC00,
    364		.token = true,
    365		.size = 64,
    366		.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
    367	},
    368};
    369
    370#define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds)
    371
    372#define FSL_MC_MAX_MODULE_ID 0x10
    373
    374static int fsl_mc_command_check(struct fsl_mc_device *mc_dev,
    375				struct fsl_mc_command *mc_cmd)
    376{
    377	struct fsl_mc_cmd_desc *desc = NULL;
    378	int mc_cmd_max_size, i;
    379	bool token_provided;
    380	u16 cmdid, module_id;
    381	char *mc_cmd_end;
    382	char sum = 0;
    383
    384	/* Check if this is an accepted MC command */
    385	cmdid = mc_cmd_hdr_read_cmdid(mc_cmd);
    386	for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) {
    387		desc = &fsl_mc_accepted_cmds[i];
    388		if ((cmdid & desc->cmdid_mask) == desc->cmdid_value)
    389			break;
    390	}
    391	if (i == FSL_MC_NUM_ACCEPTED_CMDS) {
    392		dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid);
    393		return -EACCES;
    394	}
    395
    396	/* Check if the size of the command is honored. Anything beyond the
    397	 * last valid byte of the command should be zeroed.
    398	 */
    399	mc_cmd_max_size = sizeof(*mc_cmd);
    400	mc_cmd_end = ((char *)mc_cmd) + desc->size;
    401	for (i = desc->size; i < mc_cmd_max_size; i++)
    402		sum |= *mc_cmd_end++;
    403	if (sum) {
    404		dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n",
    405			cmdid, desc->size);
    406		return -EACCES;
    407	}
    408
    409	/* Some MC commands request a token to be passed so that object
    410	 * identification is possible. Check if the token passed in the command
    411	 * is as expected.
    412	 */
    413	token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false;
    414	if (token_provided != desc->token) {
    415		dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n",
    416			cmdid, mc_cmd_hdr_read_token(mc_cmd));
    417		return -EACCES;
    418	}
    419
    420	/* If needed, check if the module ID passed is valid */
    421	if (desc->flags & FSL_MC_CHECK_MODULE_ID) {
    422		/* The module ID is represented by bits [4:9] from the cmdid */
    423		module_id = (cmdid & GENMASK(9, 4)) >> 4;
    424		if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) {
    425			dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n",
    426				cmdid, module_id);
    427			return -EACCES;
    428		}
    429	}
    430
    431	/* Some commands alter how hardware resources are managed. For these
    432	 * commands, check for CAP_NET_ADMIN.
    433	 */
    434	if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) {
    435		if (!capable(CAP_NET_ADMIN)) {
    436			dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n",
    437				cmdid);
    438			return -EPERM;
    439		}
    440	}
    441
    442	return 0;
    443}
    444
    445static int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg,
    446				    struct fsl_mc_io *mc_io)
    447{
    448	struct fsl_mc_command mc_cmd;
    449	int error;
    450
    451	error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
    452	if (error)
    453		return -EFAULT;
    454
    455	error = fsl_mc_command_check(mc_dev, &mc_cmd);
    456	if (error)
    457		return error;
    458
    459	error = mc_send_command(mc_io, &mc_cmd);
    460	if (error)
    461		return error;
    462
    463	error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
    464	if (error)
    465		return -EFAULT;
    466
    467	return 0;
    468}
    469
    470static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
    471{
    472	struct fsl_mc_device *root_mc_device;
    473	struct uapi_priv_data *priv_data;
    474	struct fsl_mc_io *dynamic_mc_io;
    475	struct fsl_mc_uapi *mc_uapi;
    476	struct fsl_mc_bus *mc_bus;
    477	int error;
    478
    479	priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
    480	if (!priv_data)
    481		return -ENOMEM;
    482
    483	mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
    484	mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
    485	root_mc_device = &mc_bus->mc_dev;
    486
    487	mutex_lock(&mc_uapi->mutex);
    488
    489	if (!mc_uapi->local_instance_in_use) {
    490		priv_data->mc_io = mc_uapi->static_mc_io;
    491		mc_uapi->local_instance_in_use = 1;
    492	} else {
    493		error = fsl_mc_portal_allocate(root_mc_device, 0,
    494					       &dynamic_mc_io);
    495		if (error) {
    496			dev_dbg(&root_mc_device->dev,
    497				"Could not allocate MC portal\n");
    498			goto error_portal_allocate;
    499		}
    500
    501		priv_data->mc_io = dynamic_mc_io;
    502	}
    503	priv_data->uapi = mc_uapi;
    504	filep->private_data = priv_data;
    505
    506	mutex_unlock(&mc_uapi->mutex);
    507
    508	return 0;
    509
    510error_portal_allocate:
    511	mutex_unlock(&mc_uapi->mutex);
    512	kfree(priv_data);
    513
    514	return error;
    515}
    516
    517static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
    518{
    519	struct uapi_priv_data *priv_data;
    520	struct fsl_mc_uapi *mc_uapi;
    521	struct fsl_mc_io *mc_io;
    522
    523	priv_data = filep->private_data;
    524	mc_uapi = priv_data->uapi;
    525	mc_io = priv_data->mc_io;
    526
    527	mutex_lock(&mc_uapi->mutex);
    528
    529	if (mc_io == mc_uapi->static_mc_io)
    530		mc_uapi->local_instance_in_use = 0;
    531	else
    532		fsl_mc_portal_free(mc_io);
    533
    534	kfree(filep->private_data);
    535	filep->private_data =  NULL;
    536
    537	mutex_unlock(&mc_uapi->mutex);
    538
    539	return 0;
    540}
    541
    542static long fsl_mc_uapi_dev_ioctl(struct file *file,
    543				  unsigned int cmd,
    544				  unsigned long arg)
    545{
    546	struct uapi_priv_data *priv_data = file->private_data;
    547	struct fsl_mc_device *root_mc_device;
    548	struct fsl_mc_bus *mc_bus;
    549	int error;
    550
    551	mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
    552	root_mc_device = &mc_bus->mc_dev;
    553
    554	switch (cmd) {
    555	case FSL_MC_SEND_MC_COMMAND:
    556		error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io);
    557		break;
    558	default:
    559		dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
    560		error = -EINVAL;
    561	}
    562
    563	return error;
    564}
    565
    566static const struct file_operations fsl_mc_uapi_dev_fops = {
    567	.owner = THIS_MODULE,
    568	.open = fsl_mc_uapi_dev_open,
    569	.release = fsl_mc_uapi_dev_release,
    570	.unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
    571};
    572
    573int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
    574{
    575	struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
    576	struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
    577	int error;
    578
    579	mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
    580	mc_uapi->misc.name = dev_name(&mc_dev->dev);
    581	mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
    582
    583	error = misc_register(&mc_uapi->misc);
    584	if (error)
    585		return error;
    586
    587	mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
    588
    589	mutex_init(&mc_uapi->mutex);
    590
    591	return 0;
    592}
    593
    594void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
    595{
    596	misc_deregister(&mc_bus->uapi_misc.misc);
    597}