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

monreader.c (13737B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Character device driver for reading z/VM *MONITOR service records.
      4 *
      5 * Copyright IBM Corp. 2004, 2009
      6 *
      7 * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
      8 */
      9
     10#define KMSG_COMPONENT "monreader"
     11#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     12
     13#include <linux/module.h>
     14#include <linux/moduleparam.h>
     15#include <linux/init.h>
     16#include <linux/errno.h>
     17#include <linux/types.h>
     18#include <linux/kernel.h>
     19#include <linux/miscdevice.h>
     20#include <linux/ctype.h>
     21#include <linux/spinlock.h>
     22#include <linux/interrupt.h>
     23#include <linux/poll.h>
     24#include <linux/slab.h>
     25#include <net/iucv/iucv.h>
     26#include <linux/uaccess.h>
     27#include <asm/ebcdic.h>
     28#include <asm/extmem.h>
     29
     30
     31#define MON_COLLECT_SAMPLE 0x80
     32#define MON_COLLECT_EVENT  0x40
     33#define MON_SERVICE	   "*MONITOR"
     34#define MON_IN_USE	   0x01
     35#define MON_MSGLIM	   255
     36
     37static char mon_dcss_name[9] = "MONDCSS\0";
     38
     39struct mon_msg {
     40	u32 pos;
     41	u32 mca_offset;
     42	struct iucv_message msg;
     43	char msglim_reached;
     44	char replied_msglim;
     45};
     46
     47struct mon_private {
     48	struct iucv_path *path;
     49	struct mon_msg *msg_array[MON_MSGLIM];
     50	unsigned int   write_index;
     51	unsigned int   read_index;
     52	atomic_t msglim_count;
     53	atomic_t read_ready;
     54	atomic_t iucv_connected;
     55	atomic_t iucv_severed;
     56};
     57
     58static unsigned long mon_in_use = 0;
     59
     60static unsigned long mon_dcss_start;
     61static unsigned long mon_dcss_end;
     62
     63static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
     64static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
     65
     66static u8 user_data_connect[16] = {
     67	/* Version code, must be 0x01 for shared mode */
     68	0x01,
     69	/* what to collect */
     70	MON_COLLECT_SAMPLE | MON_COLLECT_EVENT,
     71	/* DCSS name in EBCDIC, 8 bytes padded with blanks */
     72	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     73	0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     74};
     75
     76static u8 user_data_sever[16] = {
     77	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     78	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     79};
     80
     81/******************************************************************************
     82 *                             helper functions                               *
     83 *****************************************************************************/
     84/*
     85 * Create the 8 bytes EBCDIC DCSS segment name from
     86 * an ASCII name, incl. padding
     87 */
     88static void dcss_mkname(char *ascii_name, char *ebcdic_name)
     89{
     90	int i;
     91
     92	for (i = 0; i < 8; i++) {
     93		if (ascii_name[i] == '\0')
     94			break;
     95		ebcdic_name[i] = toupper(ascii_name[i]);
     96	}
     97	for (; i < 8; i++)
     98		ebcdic_name[i] = ' ';
     99	ASCEBC(ebcdic_name, 8);
    100}
    101
    102static inline unsigned long mon_mca_start(struct mon_msg *monmsg)
    103{
    104	return *(u32 *) &monmsg->msg.rmmsg;
    105}
    106
    107static inline unsigned long mon_mca_end(struct mon_msg *monmsg)
    108{
    109	return *(u32 *) &monmsg->msg.rmmsg[4];
    110}
    111
    112static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index)
    113{
    114	return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
    115}
    116
    117static inline u32 mon_mca_size(struct mon_msg *monmsg)
    118{
    119	return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
    120}
    121
    122static inline u32 mon_rec_start(struct mon_msg *monmsg)
    123{
    124	return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
    125}
    126
    127static inline u32 mon_rec_end(struct mon_msg *monmsg)
    128{
    129	return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
    130}
    131
    132static int mon_check_mca(struct mon_msg *monmsg)
    133{
    134	if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
    135	    (mon_rec_start(monmsg) < mon_dcss_start) ||
    136	    (mon_rec_end(monmsg) > mon_dcss_end) ||
    137	    (mon_mca_type(monmsg, 0) == 0) ||
    138	    (mon_mca_size(monmsg) % 12 != 0) ||
    139	    (mon_mca_end(monmsg) <= mon_mca_start(monmsg)) ||
    140	    (mon_mca_end(monmsg) > mon_dcss_end) ||
    141	    (mon_mca_start(monmsg) < mon_dcss_start) ||
    142	    ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0)))
    143		return -EINVAL;
    144	return 0;
    145}
    146
    147static int mon_send_reply(struct mon_msg *monmsg,
    148			  struct mon_private *monpriv)
    149{
    150	int rc;
    151
    152	rc = iucv_message_reply(monpriv->path, &monmsg->msg,
    153				IUCV_IPRMDATA, NULL, 0);
    154	atomic_dec(&monpriv->msglim_count);
    155	if (likely(!monmsg->msglim_reached)) {
    156		monmsg->pos = 0;
    157		monmsg->mca_offset = 0;
    158		monpriv->read_index = (monpriv->read_index + 1) %
    159				      MON_MSGLIM;
    160		atomic_dec(&monpriv->read_ready);
    161	} else
    162		monmsg->replied_msglim = 1;
    163	if (rc) {
    164		pr_err("Reading monitor data failed with rc=%i\n", rc);
    165		return -EIO;
    166	}
    167	return 0;
    168}
    169
    170static void mon_free_mem(struct mon_private *monpriv)
    171{
    172	int i;
    173
    174	for (i = 0; i < MON_MSGLIM; i++)
    175		kfree(monpriv->msg_array[i]);
    176	kfree(monpriv);
    177}
    178
    179static struct mon_private *mon_alloc_mem(void)
    180{
    181	int i;
    182	struct mon_private *monpriv;
    183
    184	monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
    185	if (!monpriv)
    186		return NULL;
    187	for (i = 0; i < MON_MSGLIM; i++) {
    188		monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg),
    189						    GFP_KERNEL);
    190		if (!monpriv->msg_array[i]) {
    191			mon_free_mem(monpriv);
    192			return NULL;
    193		}
    194	}
    195	return monpriv;
    196}
    197
    198static inline void mon_next_mca(struct mon_msg *monmsg)
    199{
    200	if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
    201		return;
    202	monmsg->mca_offset += 12;
    203	monmsg->pos = 0;
    204}
    205
    206static struct mon_msg *mon_next_message(struct mon_private *monpriv)
    207{
    208	struct mon_msg *monmsg;
    209
    210	if (!atomic_read(&monpriv->read_ready))
    211		return NULL;
    212	monmsg = monpriv->msg_array[monpriv->read_index];
    213	if (unlikely(monmsg->replied_msglim)) {
    214		monmsg->replied_msglim = 0;
    215		monmsg->msglim_reached = 0;
    216		monmsg->pos = 0;
    217		monmsg->mca_offset = 0;
    218		monpriv->read_index = (monpriv->read_index + 1) %
    219				      MON_MSGLIM;
    220		atomic_dec(&monpriv->read_ready);
    221		return ERR_PTR(-EOVERFLOW);
    222	}
    223	return monmsg;
    224}
    225
    226
    227/******************************************************************************
    228 *                               IUCV handler                                 *
    229 *****************************************************************************/
    230static void mon_iucv_path_complete(struct iucv_path *path, u8 *ipuser)
    231{
    232	struct mon_private *monpriv = path->private;
    233
    234	atomic_set(&monpriv->iucv_connected, 1);
    235	wake_up(&mon_conn_wait_queue);
    236}
    237
    238static void mon_iucv_path_severed(struct iucv_path *path, u8 *ipuser)
    239{
    240	struct mon_private *monpriv = path->private;
    241
    242	pr_err("z/VM *MONITOR system service disconnected with rc=%i\n",
    243	       ipuser[0]);
    244	iucv_path_sever(path, NULL);
    245	atomic_set(&monpriv->iucv_severed, 1);
    246	wake_up(&mon_conn_wait_queue);
    247	wake_up_interruptible(&mon_read_wait_queue);
    248}
    249
    250static void mon_iucv_message_pending(struct iucv_path *path,
    251				     struct iucv_message *msg)
    252{
    253	struct mon_private *monpriv = path->private;
    254
    255	memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
    256	       msg, sizeof(*msg));
    257	if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
    258		pr_warn("The read queue for monitor data is full\n");
    259		monpriv->msg_array[monpriv->write_index]->msglim_reached = 1;
    260	}
    261	monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM;
    262	atomic_inc(&monpriv->read_ready);
    263	wake_up_interruptible(&mon_read_wait_queue);
    264}
    265
    266static struct iucv_handler monreader_iucv_handler = {
    267	.path_complete	 = mon_iucv_path_complete,
    268	.path_severed	 = mon_iucv_path_severed,
    269	.message_pending = mon_iucv_message_pending,
    270};
    271
    272/******************************************************************************
    273 *                               file operations                              *
    274 *****************************************************************************/
    275static int mon_open(struct inode *inode, struct file *filp)
    276{
    277	struct mon_private *monpriv;
    278	int rc;
    279
    280	/*
    281	 * only one user allowed
    282	 */
    283	rc = -EBUSY;
    284	if (test_and_set_bit(MON_IN_USE, &mon_in_use))
    285		goto out;
    286
    287	rc = -ENOMEM;
    288	monpriv = mon_alloc_mem();
    289	if (!monpriv)
    290		goto out_use;
    291
    292	/*
    293	 * Connect to *MONITOR service
    294	 */
    295	monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
    296	if (!monpriv->path)
    297		goto out_priv;
    298	rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
    299			       MON_SERVICE, NULL, user_data_connect, monpriv);
    300	if (rc) {
    301		pr_err("Connecting to the z/VM *MONITOR system service "
    302		       "failed with rc=%i\n", rc);
    303		rc = -EIO;
    304		goto out_path;
    305	}
    306	/*
    307	 * Wait for connection confirmation
    308	 */
    309	wait_event(mon_conn_wait_queue,
    310		   atomic_read(&monpriv->iucv_connected) ||
    311		   atomic_read(&monpriv->iucv_severed));
    312	if (atomic_read(&monpriv->iucv_severed)) {
    313		atomic_set(&monpriv->iucv_severed, 0);
    314		atomic_set(&monpriv->iucv_connected, 0);
    315		rc = -EIO;
    316		goto out_path;
    317	}
    318	filp->private_data = monpriv;
    319	return nonseekable_open(inode, filp);
    320
    321out_path:
    322	iucv_path_free(monpriv->path);
    323out_priv:
    324	mon_free_mem(monpriv);
    325out_use:
    326	clear_bit(MON_IN_USE, &mon_in_use);
    327out:
    328	return rc;
    329}
    330
    331static int mon_close(struct inode *inode, struct file *filp)
    332{
    333	int rc, i;
    334	struct mon_private *monpriv = filp->private_data;
    335
    336	/*
    337	 * Close IUCV connection and unregister
    338	 */
    339	if (monpriv->path) {
    340		rc = iucv_path_sever(monpriv->path, user_data_sever);
    341		if (rc)
    342			pr_warn("Disconnecting the z/VM *MONITOR system service failed with rc=%i\n",
    343				rc);
    344		iucv_path_free(monpriv->path);
    345	}
    346
    347	atomic_set(&monpriv->iucv_severed, 0);
    348	atomic_set(&monpriv->iucv_connected, 0);
    349	atomic_set(&monpriv->read_ready, 0);
    350	atomic_set(&monpriv->msglim_count, 0);
    351	monpriv->write_index  = 0;
    352	monpriv->read_index   = 0;
    353
    354	for (i = 0; i < MON_MSGLIM; i++)
    355		kfree(monpriv->msg_array[i]);
    356	kfree(monpriv);
    357	clear_bit(MON_IN_USE, &mon_in_use);
    358	return 0;
    359}
    360
    361static ssize_t mon_read(struct file *filp, char __user *data,
    362			size_t count, loff_t *ppos)
    363{
    364	struct mon_private *monpriv = filp->private_data;
    365	struct mon_msg *monmsg;
    366	int ret;
    367	u32 mce_start;
    368
    369	monmsg = mon_next_message(monpriv);
    370	if (IS_ERR(monmsg))
    371		return PTR_ERR(monmsg);
    372
    373	if (!monmsg) {
    374		if (filp->f_flags & O_NONBLOCK)
    375			return -EAGAIN;
    376		ret = wait_event_interruptible(mon_read_wait_queue,
    377					atomic_read(&monpriv->read_ready) ||
    378					atomic_read(&monpriv->iucv_severed));
    379		if (ret)
    380			return ret;
    381		if (unlikely(atomic_read(&monpriv->iucv_severed)))
    382			return -EIO;
    383		monmsg = monpriv->msg_array[monpriv->read_index];
    384	}
    385
    386	if (!monmsg->pos)
    387		monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset;
    388	if (mon_check_mca(monmsg))
    389		goto reply;
    390
    391	/* read monitor control element (12 bytes) first */
    392	mce_start = mon_mca_start(monmsg) + monmsg->mca_offset;
    393	if ((monmsg->pos >= mce_start) && (monmsg->pos < mce_start + 12)) {
    394		count = min(count, (size_t) mce_start + 12 - monmsg->pos);
    395		ret = copy_to_user(data, (void *) (unsigned long) monmsg->pos,
    396				   count);
    397		if (ret)
    398			return -EFAULT;
    399		monmsg->pos += count;
    400		if (monmsg->pos == mce_start + 12)
    401			monmsg->pos = mon_rec_start(monmsg);
    402		goto out_copy;
    403	}
    404
    405	/* read records */
    406	if (monmsg->pos <= mon_rec_end(monmsg)) {
    407		count = min(count, (size_t) mon_rec_end(monmsg) - monmsg->pos
    408					    + 1);
    409		ret = copy_to_user(data, (void *) (unsigned long) monmsg->pos,
    410				   count);
    411		if (ret)
    412			return -EFAULT;
    413		monmsg->pos += count;
    414		if (monmsg->pos > mon_rec_end(monmsg))
    415			mon_next_mca(monmsg);
    416		goto out_copy;
    417	}
    418reply:
    419	ret = mon_send_reply(monmsg, monpriv);
    420	return ret;
    421
    422out_copy:
    423	*ppos += count;
    424	return count;
    425}
    426
    427static __poll_t mon_poll(struct file *filp, struct poll_table_struct *p)
    428{
    429	struct mon_private *monpriv = filp->private_data;
    430
    431	poll_wait(filp, &mon_read_wait_queue, p);
    432	if (unlikely(atomic_read(&monpriv->iucv_severed)))
    433		return EPOLLERR;
    434	if (atomic_read(&monpriv->read_ready))
    435		return EPOLLIN | EPOLLRDNORM;
    436	return 0;
    437}
    438
    439static const struct file_operations mon_fops = {
    440	.owner   = THIS_MODULE,
    441	.open    = &mon_open,
    442	.release = &mon_close,
    443	.read    = &mon_read,
    444	.poll    = &mon_poll,
    445	.llseek  = noop_llseek,
    446};
    447
    448static struct miscdevice mon_dev = {
    449	.name       = "monreader",
    450	.fops       = &mon_fops,
    451	.minor      = MISC_DYNAMIC_MINOR,
    452};
    453
    454/******************************************************************************
    455 *                              module init/exit                              *
    456 *****************************************************************************/
    457static int __init mon_init(void)
    458{
    459	int rc;
    460
    461	if (!MACHINE_IS_VM) {
    462		pr_err("The z/VM *MONITOR record device driver cannot be "
    463		       "loaded without z/VM\n");
    464		return -ENODEV;
    465	}
    466
    467	/*
    468	 * Register with IUCV and connect to *MONITOR service
    469	 */
    470	rc = iucv_register(&monreader_iucv_handler, 1);
    471	if (rc) {
    472		pr_err("The z/VM *MONITOR record device driver failed to "
    473		       "register with IUCV\n");
    474		return rc;
    475	}
    476
    477	rc = segment_type(mon_dcss_name);
    478	if (rc < 0) {
    479		segment_warning(rc, mon_dcss_name);
    480		goto out_iucv;
    481	}
    482	if (rc != SEG_TYPE_SC) {
    483		pr_err("The specified *MONITOR DCSS %s does not have the "
    484		       "required type SC\n", mon_dcss_name);
    485		rc = -EINVAL;
    486		goto out_iucv;
    487	}
    488
    489	rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
    490			  &mon_dcss_start, &mon_dcss_end);
    491	if (rc < 0) {
    492		segment_warning(rc, mon_dcss_name);
    493		rc = -EINVAL;
    494		goto out_iucv;
    495	}
    496	dcss_mkname(mon_dcss_name, &user_data_connect[8]);
    497
    498	/*
    499	 * misc_register() has to be the last action in module_init(), because
    500	 * file operations will be available right after this.
    501	 */
    502	rc = misc_register(&mon_dev);
    503	if (rc < 0 )
    504		goto out;
    505	return 0;
    506
    507out:
    508	segment_unload(mon_dcss_name);
    509out_iucv:
    510	iucv_unregister(&monreader_iucv_handler, 1);
    511	return rc;
    512}
    513
    514static void __exit mon_exit(void)
    515{
    516	segment_unload(mon_dcss_name);
    517	misc_deregister(&mon_dev);
    518	iucv_unregister(&monreader_iucv_handler, 1);
    519	return;
    520}
    521
    522
    523module_init(mon_init);
    524module_exit(mon_exit);
    525
    526module_param_string(mondcss, mon_dcss_name, 9, 0444);
    527MODULE_PARM_DESC(mondcss, "Name of DCSS segment to be used for *MONITOR "
    528		 "service, max. 8 chars. Default is MONDCSS");
    529
    530MODULE_AUTHOR("Gerald Schaefer <geraldsc@de.ibm.com>");
    531MODULE_DESCRIPTION("Character device driver for reading z/VM "
    532		   "monitor service records.");
    533MODULE_LICENSE("GPL");