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

mailbox-test.c (11052B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2015 ST Microelectronics
      4 *
      5 * Author: Lee Jones <lee.jones@linaro.org>
      6 */
      7
      8#include <linux/debugfs.h>
      9#include <linux/err.h>
     10#include <linux/fs.h>
     11#include <linux/io.h>
     12#include <linux/kernel.h>
     13#include <linux/mailbox_client.h>
     14#include <linux/module.h>
     15#include <linux/of.h>
     16#include <linux/platform_device.h>
     17#include <linux/poll.h>
     18#include <linux/slab.h>
     19#include <linux/uaccess.h>
     20#include <linux/sched/signal.h>
     21
     22#define MBOX_MAX_SIG_LEN	8
     23#define MBOX_MAX_MSG_LEN	128
     24#define MBOX_BYTES_PER_LINE	16
     25#define MBOX_HEXDUMP_LINE_LEN	((MBOX_BYTES_PER_LINE * 4) + 2)
     26#define MBOX_HEXDUMP_MAX_LEN	(MBOX_HEXDUMP_LINE_LEN *		\
     27				 (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
     28
     29static bool mbox_data_ready;
     30
     31struct mbox_test_device {
     32	struct device		*dev;
     33	void __iomem		*tx_mmio;
     34	void __iomem		*rx_mmio;
     35	struct mbox_chan	*tx_channel;
     36	struct mbox_chan	*rx_channel;
     37	char			*rx_buffer;
     38	char			*signal;
     39	char			*message;
     40	spinlock_t		lock;
     41	wait_queue_head_t	waitq;
     42	struct fasync_struct	*async_queue;
     43	struct dentry		*root_debugfs_dir;
     44};
     45
     46static ssize_t mbox_test_signal_write(struct file *filp,
     47				       const char __user *userbuf,
     48				       size_t count, loff_t *ppos)
     49{
     50	struct mbox_test_device *tdev = filp->private_data;
     51
     52	if (!tdev->tx_channel) {
     53		dev_err(tdev->dev, "Channel cannot do Tx\n");
     54		return -EINVAL;
     55	}
     56
     57	if (count > MBOX_MAX_SIG_LEN) {
     58		dev_err(tdev->dev,
     59			"Signal length %zd greater than max allowed %d\n",
     60			count, MBOX_MAX_SIG_LEN);
     61		return -EINVAL;
     62	}
     63
     64	/* Only allocate memory if we need to */
     65	if (!tdev->signal) {
     66		tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
     67		if (!tdev->signal)
     68			return -ENOMEM;
     69	}
     70
     71	if (copy_from_user(tdev->signal, userbuf, count)) {
     72		kfree(tdev->signal);
     73		tdev->signal = NULL;
     74		return -EFAULT;
     75	}
     76
     77	return count;
     78}
     79
     80static const struct file_operations mbox_test_signal_ops = {
     81	.write	= mbox_test_signal_write,
     82	.open	= simple_open,
     83	.llseek	= generic_file_llseek,
     84};
     85
     86static int mbox_test_message_fasync(int fd, struct file *filp, int on)
     87{
     88	struct mbox_test_device *tdev = filp->private_data;
     89
     90	return fasync_helper(fd, filp, on, &tdev->async_queue);
     91}
     92
     93static ssize_t mbox_test_message_write(struct file *filp,
     94				       const char __user *userbuf,
     95				       size_t count, loff_t *ppos)
     96{
     97	struct mbox_test_device *tdev = filp->private_data;
     98	void *data;
     99	int ret;
    100
    101	if (!tdev->tx_channel) {
    102		dev_err(tdev->dev, "Channel cannot do Tx\n");
    103		return -EINVAL;
    104	}
    105
    106	if (count > MBOX_MAX_MSG_LEN) {
    107		dev_err(tdev->dev,
    108			"Message length %zd greater than max allowed %d\n",
    109			count, MBOX_MAX_MSG_LEN);
    110		return -EINVAL;
    111	}
    112
    113	tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
    114	if (!tdev->message)
    115		return -ENOMEM;
    116
    117	ret = copy_from_user(tdev->message, userbuf, count);
    118	if (ret) {
    119		ret = -EFAULT;
    120		goto out;
    121	}
    122
    123	/*
    124	 * A separate signal is only of use if there is
    125	 * MMIO to subsequently pass the message through
    126	 */
    127	if (tdev->tx_mmio && tdev->signal) {
    128		print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
    129				     tdev->signal, MBOX_MAX_SIG_LEN);
    130
    131		data = tdev->signal;
    132	} else
    133		data = tdev->message;
    134
    135	print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
    136			     tdev->message, MBOX_MAX_MSG_LEN);
    137
    138	ret = mbox_send_message(tdev->tx_channel, data);
    139	if (ret < 0)
    140		dev_err(tdev->dev, "Failed to send message via mailbox\n");
    141
    142out:
    143	kfree(tdev->signal);
    144	kfree(tdev->message);
    145	tdev->signal = NULL;
    146
    147	return ret < 0 ? ret : count;
    148}
    149
    150static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
    151{
    152	bool data_ready;
    153	unsigned long flags;
    154
    155	spin_lock_irqsave(&tdev->lock, flags);
    156	data_ready = mbox_data_ready;
    157	spin_unlock_irqrestore(&tdev->lock, flags);
    158
    159	return data_ready;
    160}
    161
    162static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
    163				      size_t count, loff_t *ppos)
    164{
    165	struct mbox_test_device *tdev = filp->private_data;
    166	unsigned long flags;
    167	char *touser, *ptr;
    168	int l = 0;
    169	int ret;
    170
    171	DECLARE_WAITQUEUE(wait, current);
    172
    173	touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
    174	if (!touser)
    175		return -ENOMEM;
    176
    177	if (!tdev->rx_channel) {
    178		ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
    179		ret = simple_read_from_buffer(userbuf, count, ppos,
    180					      touser, ret);
    181		goto kfree_err;
    182	}
    183
    184	add_wait_queue(&tdev->waitq, &wait);
    185
    186	do {
    187		__set_current_state(TASK_INTERRUPTIBLE);
    188
    189		if (mbox_test_message_data_ready(tdev))
    190			break;
    191
    192		if (filp->f_flags & O_NONBLOCK) {
    193			ret = -EAGAIN;
    194			goto waitq_err;
    195		}
    196
    197		if (signal_pending(current)) {
    198			ret = -ERESTARTSYS;
    199			goto waitq_err;
    200		}
    201		schedule();
    202
    203	} while (1);
    204
    205	spin_lock_irqsave(&tdev->lock, flags);
    206
    207	ptr = tdev->rx_buffer;
    208	while (l < MBOX_HEXDUMP_MAX_LEN) {
    209		hex_dump_to_buffer(ptr,
    210				   MBOX_BYTES_PER_LINE,
    211				   MBOX_BYTES_PER_LINE, 1, touser + l,
    212				   MBOX_HEXDUMP_LINE_LEN, true);
    213
    214		ptr += MBOX_BYTES_PER_LINE;
    215		l += MBOX_HEXDUMP_LINE_LEN;
    216		*(touser + (l - 1)) = '\n';
    217	}
    218	*(touser + l) = '\0';
    219
    220	memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
    221	mbox_data_ready = false;
    222
    223	spin_unlock_irqrestore(&tdev->lock, flags);
    224
    225	ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
    226waitq_err:
    227	__set_current_state(TASK_RUNNING);
    228	remove_wait_queue(&tdev->waitq, &wait);
    229kfree_err:
    230	kfree(touser);
    231	return ret;
    232}
    233
    234static __poll_t
    235mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
    236{
    237	struct mbox_test_device *tdev = filp->private_data;
    238
    239	poll_wait(filp, &tdev->waitq, wait);
    240
    241	if (mbox_test_message_data_ready(tdev))
    242		return EPOLLIN | EPOLLRDNORM;
    243	return 0;
    244}
    245
    246static const struct file_operations mbox_test_message_ops = {
    247	.write	= mbox_test_message_write,
    248	.read	= mbox_test_message_read,
    249	.fasync	= mbox_test_message_fasync,
    250	.poll	= mbox_test_message_poll,
    251	.open	= simple_open,
    252	.llseek	= generic_file_llseek,
    253};
    254
    255static int mbox_test_add_debugfs(struct platform_device *pdev,
    256				 struct mbox_test_device *tdev)
    257{
    258	if (!debugfs_initialized())
    259		return 0;
    260
    261	tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
    262	if (!tdev->root_debugfs_dir) {
    263		dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
    264		return -EINVAL;
    265	}
    266
    267	debugfs_create_file("message", 0600, tdev->root_debugfs_dir,
    268			    tdev, &mbox_test_message_ops);
    269
    270	debugfs_create_file("signal", 0200, tdev->root_debugfs_dir,
    271			    tdev, &mbox_test_signal_ops);
    272
    273	return 0;
    274}
    275
    276static void mbox_test_receive_message(struct mbox_client *client, void *message)
    277{
    278	struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
    279	unsigned long flags;
    280
    281	spin_lock_irqsave(&tdev->lock, flags);
    282	if (tdev->rx_mmio) {
    283		memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);
    284		print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS,
    285				     tdev->rx_buffer, MBOX_MAX_MSG_LEN);
    286	} else if (message) {
    287		print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS,
    288				     message, MBOX_MAX_MSG_LEN);
    289		memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
    290	}
    291	mbox_data_ready = true;
    292	spin_unlock_irqrestore(&tdev->lock, flags);
    293
    294	wake_up_interruptible(&tdev->waitq);
    295
    296	kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
    297}
    298
    299static void mbox_test_prepare_message(struct mbox_client *client, void *message)
    300{
    301	struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
    302
    303	if (tdev->tx_mmio) {
    304		if (tdev->signal)
    305			memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);
    306		else
    307			memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);
    308	}
    309}
    310
    311static void mbox_test_message_sent(struct mbox_client *client,
    312				   void *message, int r)
    313{
    314	if (r)
    315		dev_warn(client->dev,
    316			 "Client: Message could not be sent: %d\n", r);
    317	else
    318		dev_info(client->dev,
    319			 "Client: Message sent\n");
    320}
    321
    322static struct mbox_chan *
    323mbox_test_request_channel(struct platform_device *pdev, const char *name)
    324{
    325	struct mbox_client *client;
    326	struct mbox_chan *channel;
    327
    328	client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
    329	if (!client)
    330		return ERR_PTR(-ENOMEM);
    331
    332	client->dev		= &pdev->dev;
    333	client->rx_callback	= mbox_test_receive_message;
    334	client->tx_prepare	= mbox_test_prepare_message;
    335	client->tx_done		= mbox_test_message_sent;
    336	client->tx_block	= true;
    337	client->knows_txdone	= false;
    338	client->tx_tout		= 500;
    339
    340	channel = mbox_request_channel_byname(client, name);
    341	if (IS_ERR(channel)) {
    342		dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
    343		return NULL;
    344	}
    345
    346	return channel;
    347}
    348
    349static int mbox_test_probe(struct platform_device *pdev)
    350{
    351	struct mbox_test_device *tdev;
    352	struct resource *res;
    353	resource_size_t size;
    354	int ret;
    355
    356	tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
    357	if (!tdev)
    358		return -ENOMEM;
    359
    360	/* It's okay for MMIO to be NULL */
    361	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    362	tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
    363	if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
    364		/* if reserved area in SRAM, try just ioremap */
    365		size = resource_size(res);
    366		tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
    367	} else if (IS_ERR(tdev->tx_mmio)) {
    368		tdev->tx_mmio = NULL;
    369	}
    370
    371	/* If specified, second reg entry is Rx MMIO */
    372	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
    373	tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res);
    374	if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
    375		size = resource_size(res);
    376		tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
    377	} else if (IS_ERR(tdev->rx_mmio)) {
    378		tdev->rx_mmio = tdev->tx_mmio;
    379	}
    380
    381	tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
    382	tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
    383
    384	if (!tdev->tx_channel && !tdev->rx_channel)
    385		return -EPROBE_DEFER;
    386
    387	/* If Rx is not specified but has Rx MMIO, then Rx = Tx */
    388	if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
    389		tdev->rx_channel = tdev->tx_channel;
    390
    391	tdev->dev = &pdev->dev;
    392	platform_set_drvdata(pdev, tdev);
    393
    394	spin_lock_init(&tdev->lock);
    395
    396	if (tdev->rx_channel) {
    397		tdev->rx_buffer = devm_kzalloc(&pdev->dev,
    398					       MBOX_MAX_MSG_LEN, GFP_KERNEL);
    399		if (!tdev->rx_buffer)
    400			return -ENOMEM;
    401	}
    402
    403	ret = mbox_test_add_debugfs(pdev, tdev);
    404	if (ret)
    405		return ret;
    406
    407	init_waitqueue_head(&tdev->waitq);
    408	dev_info(&pdev->dev, "Successfully registered\n");
    409
    410	return 0;
    411}
    412
    413static int mbox_test_remove(struct platform_device *pdev)
    414{
    415	struct mbox_test_device *tdev = platform_get_drvdata(pdev);
    416
    417	debugfs_remove_recursive(tdev->root_debugfs_dir);
    418
    419	if (tdev->tx_channel)
    420		mbox_free_channel(tdev->tx_channel);
    421	if (tdev->rx_channel)
    422		mbox_free_channel(tdev->rx_channel);
    423
    424	return 0;
    425}
    426
    427static const struct of_device_id mbox_test_match[] = {
    428	{ .compatible = "mailbox-test" },
    429	{},
    430};
    431MODULE_DEVICE_TABLE(of, mbox_test_match);
    432
    433static struct platform_driver mbox_test_driver = {
    434	.driver = {
    435		.name = "mailbox_test",
    436		.of_match_table = mbox_test_match,
    437	},
    438	.probe  = mbox_test_probe,
    439	.remove = mbox_test_remove,
    440};
    441module_platform_driver(mbox_test_driver);
    442
    443MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
    444MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
    445MODULE_LICENSE("GPL v2");