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

interface.c (11259B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * interface.c - contains everything related to the user interface
      4 *
      5 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
      6 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
      7 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
      8 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
      9 */
     10
     11#include <linux/pnp.h>
     12#include <linux/string.h>
     13#include <linux/errno.h>
     14#include <linux/list.h>
     15#include <linux/types.h>
     16#include <linux/stat.h>
     17#include <linux/ctype.h>
     18#include <linux/slab.h>
     19#include <linux/mutex.h>
     20
     21#include <linux/uaccess.h>
     22
     23#include "base.h"
     24
     25struct pnp_info_buffer {
     26	char *buffer;		/* pointer to begin of buffer */
     27	char *curr;		/* current position in buffer */
     28	unsigned long size;	/* current size */
     29	unsigned long len;	/* total length of buffer */
     30	int stop;		/* stop flag */
     31	int error;		/* error code */
     32};
     33
     34typedef struct pnp_info_buffer pnp_info_buffer_t;
     35
     36__printf(2, 3)
     37static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
     38{
     39	va_list args;
     40	int res;
     41
     42	if (buffer->stop || buffer->error)
     43		return 0;
     44	va_start(args, fmt);
     45	res = vsnprintf(buffer->curr, buffer->len - buffer->size, fmt, args);
     46	va_end(args);
     47	if (buffer->size + res >= buffer->len) {
     48		buffer->stop = 1;
     49		return 0;
     50	}
     51	buffer->curr += res;
     52	buffer->size += res;
     53	return res;
     54}
     55
     56static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
     57			   struct pnp_port *port)
     58{
     59	pnp_printf(buffer, "%sport %#llx-%#llx, align %#llx, size %#llx, "
     60		   "%i-bit address decoding\n", space,
     61		   (unsigned long long) port->min,
     62		   (unsigned long long) port->max,
     63		   port->align ? ((unsigned long long) port->align - 1) : 0,
     64		   (unsigned long long) port->size,
     65		   port->flags & IORESOURCE_IO_16BIT_ADDR ? 16 : 10);
     66}
     67
     68static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
     69			  struct pnp_irq *irq)
     70{
     71	int first = 1, i;
     72
     73	pnp_printf(buffer, "%sirq ", space);
     74	for (i = 0; i < PNP_IRQ_NR; i++)
     75		if (test_bit(i, irq->map.bits)) {
     76			if (!first) {
     77				pnp_printf(buffer, ",");
     78			} else {
     79				first = 0;
     80			}
     81			if (i == 2 || i == 9)
     82				pnp_printf(buffer, "2/9");
     83			else
     84				pnp_printf(buffer, "%i", i);
     85		}
     86	if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))
     87		pnp_printf(buffer, "<none>");
     88	if (irq->flags & IORESOURCE_IRQ_HIGHEDGE)
     89		pnp_printf(buffer, " High-Edge");
     90	if (irq->flags & IORESOURCE_IRQ_LOWEDGE)
     91		pnp_printf(buffer, " Low-Edge");
     92	if (irq->flags & IORESOURCE_IRQ_HIGHLEVEL)
     93		pnp_printf(buffer, " High-Level");
     94	if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
     95		pnp_printf(buffer, " Low-Level");
     96	if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
     97		pnp_printf(buffer, " (optional)");
     98	pnp_printf(buffer, "\n");
     99}
    100
    101static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
    102			  struct pnp_dma *dma)
    103{
    104	int first = 1, i;
    105	char *s;
    106
    107	pnp_printf(buffer, "%sdma ", space);
    108	for (i = 0; i < 8; i++)
    109		if (dma->map & (1 << i)) {
    110			if (!first) {
    111				pnp_printf(buffer, ",");
    112			} else {
    113				first = 0;
    114			}
    115			pnp_printf(buffer, "%i", i);
    116		}
    117	if (!dma->map)
    118		pnp_printf(buffer, "<none>");
    119	switch (dma->flags & IORESOURCE_DMA_TYPE_MASK) {
    120	case IORESOURCE_DMA_8BIT:
    121		s = "8-bit";
    122		break;
    123	case IORESOURCE_DMA_8AND16BIT:
    124		s = "8-bit&16-bit";
    125		break;
    126	default:
    127		s = "16-bit";
    128	}
    129	pnp_printf(buffer, " %s", s);
    130	if (dma->flags & IORESOURCE_DMA_MASTER)
    131		pnp_printf(buffer, " master");
    132	if (dma->flags & IORESOURCE_DMA_BYTE)
    133		pnp_printf(buffer, " byte-count");
    134	if (dma->flags & IORESOURCE_DMA_WORD)
    135		pnp_printf(buffer, " word-count");
    136	switch (dma->flags & IORESOURCE_DMA_SPEED_MASK) {
    137	case IORESOURCE_DMA_TYPEA:
    138		s = "type-A";
    139		break;
    140	case IORESOURCE_DMA_TYPEB:
    141		s = "type-B";
    142		break;
    143	case IORESOURCE_DMA_TYPEF:
    144		s = "type-F";
    145		break;
    146	default:
    147		s = "compatible";
    148		break;
    149	}
    150	pnp_printf(buffer, " %s\n", s);
    151}
    152
    153static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
    154			  struct pnp_mem *mem)
    155{
    156	char *s;
    157
    158	pnp_printf(buffer, "%sMemory %#llx-%#llx, align %#llx, size %#llx",
    159		   space, (unsigned long long) mem->min,
    160		   (unsigned long long) mem->max,
    161		   (unsigned long long) mem->align,
    162		   (unsigned long long) mem->size);
    163	if (mem->flags & IORESOURCE_MEM_WRITEABLE)
    164		pnp_printf(buffer, ", writeable");
    165	if (mem->flags & IORESOURCE_MEM_CACHEABLE)
    166		pnp_printf(buffer, ", cacheable");
    167	if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
    168		pnp_printf(buffer, ", range-length");
    169	if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
    170		pnp_printf(buffer, ", shadowable");
    171	if (mem->flags & IORESOURCE_MEM_EXPANSIONROM)
    172		pnp_printf(buffer, ", expansion ROM");
    173	switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
    174	case IORESOURCE_MEM_8BIT:
    175		s = "8-bit";
    176		break;
    177	case IORESOURCE_MEM_8AND16BIT:
    178		s = "8-bit&16-bit";
    179		break;
    180	case IORESOURCE_MEM_32BIT:
    181		s = "32-bit";
    182		break;
    183	default:
    184		s = "16-bit";
    185	}
    186	pnp_printf(buffer, ", %s\n", s);
    187}
    188
    189static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
    190			     struct pnp_option *option)
    191{
    192	switch (option->type) {
    193	case IORESOURCE_IO:
    194		pnp_print_port(buffer, space, &option->u.port);
    195		break;
    196	case IORESOURCE_MEM:
    197		pnp_print_mem(buffer, space, &option->u.mem);
    198		break;
    199	case IORESOURCE_IRQ:
    200		pnp_print_irq(buffer, space, &option->u.irq);
    201		break;
    202	case IORESOURCE_DMA:
    203		pnp_print_dma(buffer, space, &option->u.dma);
    204		break;
    205	}
    206}
    207
    208static ssize_t options_show(struct device *dmdev, struct device_attribute *attr,
    209			    char *buf)
    210{
    211	struct pnp_dev *dev = to_pnp_dev(dmdev);
    212	pnp_info_buffer_t *buffer;
    213	struct pnp_option *option;
    214	int ret, dep = 0, set = 0;
    215	char *indent;
    216
    217	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
    218	if (!buffer)
    219		return -ENOMEM;
    220
    221	buffer->len = PAGE_SIZE;
    222	buffer->buffer = buf;
    223	buffer->curr = buffer->buffer;
    224
    225	list_for_each_entry(option, &dev->options, list) {
    226		if (pnp_option_is_dependent(option)) {
    227			indent = "  ";
    228			if (!dep || pnp_option_set(option) != set) {
    229				set = pnp_option_set(option);
    230				dep = 1;
    231				pnp_printf(buffer, "Dependent: %02i - "
    232					   "Priority %s\n", set,
    233					   pnp_option_priority_name(option));
    234			}
    235		} else {
    236			dep = 0;
    237			indent = "";
    238		}
    239		pnp_print_option(buffer, indent, option);
    240	}
    241
    242	ret = (buffer->curr - buf);
    243	kfree(buffer);
    244	return ret;
    245}
    246static DEVICE_ATTR_RO(options);
    247
    248static ssize_t resources_show(struct device *dmdev,
    249			      struct device_attribute *attr, char *buf)
    250{
    251	struct pnp_dev *dev = to_pnp_dev(dmdev);
    252	pnp_info_buffer_t *buffer;
    253	struct pnp_resource *pnp_res;
    254	struct resource *res;
    255	int ret;
    256
    257	if (!dev)
    258		return -EINVAL;
    259
    260	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
    261	if (!buffer)
    262		return -ENOMEM;
    263
    264	buffer->len = PAGE_SIZE;
    265	buffer->buffer = buf;
    266	buffer->curr = buffer->buffer;
    267
    268	pnp_printf(buffer, "state = %s\n", dev->active ? "active" : "disabled");
    269
    270	list_for_each_entry(pnp_res, &dev->resources, list) {
    271		res = &pnp_res->res;
    272
    273		pnp_printf(buffer, pnp_resource_type_name(res));
    274
    275		if (res->flags & IORESOURCE_DISABLED) {
    276			pnp_printf(buffer, " disabled\n");
    277			continue;
    278		}
    279
    280		switch (pnp_resource_type(res)) {
    281		case IORESOURCE_IO:
    282		case IORESOURCE_MEM:
    283		case IORESOURCE_BUS:
    284			pnp_printf(buffer, " %#llx-%#llx%s\n",
    285				   (unsigned long long) res->start,
    286				   (unsigned long long) res->end,
    287				   res->flags & IORESOURCE_WINDOW ?
    288					" window" : "");
    289			break;
    290		case IORESOURCE_IRQ:
    291		case IORESOURCE_DMA:
    292			pnp_printf(buffer, " %lld\n",
    293				   (unsigned long long) res->start);
    294			break;
    295		}
    296	}
    297
    298	ret = (buffer->curr - buf);
    299	kfree(buffer);
    300	return ret;
    301}
    302
    303static char *pnp_get_resource_value(char *buf,
    304				    unsigned long type,
    305				    resource_size_t *start,
    306				    resource_size_t *end,
    307				    unsigned long *flags)
    308{
    309	if (start)
    310		*start = 0;
    311	if (end)
    312		*end = 0;
    313	if (flags)
    314		*flags = 0;
    315
    316	/* TBD: allow for disabled resources */
    317
    318	buf = skip_spaces(buf);
    319	if (start) {
    320		*start = simple_strtoull(buf, &buf, 0);
    321		if (end) {
    322			buf = skip_spaces(buf);
    323			if (*buf == '-') {
    324				buf = skip_spaces(buf + 1);
    325				*end = simple_strtoull(buf, &buf, 0);
    326			} else
    327				*end = *start;
    328		}
    329	}
    330
    331	/* TBD: allow for additional flags, e.g., IORESOURCE_WINDOW */
    332
    333	return buf;
    334}
    335
    336static ssize_t resources_store(struct device *dmdev,
    337			       struct device_attribute *attr, const char *ubuf,
    338			       size_t count)
    339{
    340	struct pnp_dev *dev = to_pnp_dev(dmdev);
    341	char *buf = (void *)ubuf;
    342	int retval = 0;
    343
    344	if (dev->status & PNP_ATTACHED) {
    345		retval = -EBUSY;
    346		dev_info(&dev->dev, "in use; can't configure\n");
    347		goto done;
    348	}
    349
    350	buf = skip_spaces(buf);
    351	if (!strncasecmp(buf, "disable", 7)) {
    352		retval = pnp_disable_dev(dev);
    353		goto done;
    354	}
    355	if (!strncasecmp(buf, "activate", 8)) {
    356		retval = pnp_activate_dev(dev);
    357		goto done;
    358	}
    359	if (!strncasecmp(buf, "fill", 4)) {
    360		if (dev->active)
    361			goto done;
    362		retval = pnp_auto_config_dev(dev);
    363		goto done;
    364	}
    365	if (!strncasecmp(buf, "auto", 4)) {
    366		if (dev->active)
    367			goto done;
    368		pnp_init_resources(dev);
    369		retval = pnp_auto_config_dev(dev);
    370		goto done;
    371	}
    372	if (!strncasecmp(buf, "clear", 5)) {
    373		if (dev->active)
    374			goto done;
    375		pnp_init_resources(dev);
    376		goto done;
    377	}
    378	if (!strncasecmp(buf, "get", 3)) {
    379		mutex_lock(&pnp_res_mutex);
    380		if (pnp_can_read(dev))
    381			dev->protocol->get(dev);
    382		mutex_unlock(&pnp_res_mutex);
    383		goto done;
    384	}
    385	if (!strncasecmp(buf, "set", 3)) {
    386		resource_size_t start;
    387		resource_size_t end;
    388		unsigned long flags;
    389
    390		if (dev->active)
    391			goto done;
    392		buf += 3;
    393		pnp_init_resources(dev);
    394		mutex_lock(&pnp_res_mutex);
    395		while (1) {
    396			buf = skip_spaces(buf);
    397			if (!strncasecmp(buf, "io", 2)) {
    398				buf = pnp_get_resource_value(buf + 2,
    399							     IORESOURCE_IO,
    400							     &start, &end,
    401							     &flags);
    402				pnp_add_io_resource(dev, start, end, flags);
    403			} else if (!strncasecmp(buf, "mem", 3)) {
    404				buf = pnp_get_resource_value(buf + 3,
    405							     IORESOURCE_MEM,
    406							     &start, &end,
    407							     &flags);
    408				pnp_add_mem_resource(dev, start, end, flags);
    409			} else if (!strncasecmp(buf, "irq", 3)) {
    410				buf = pnp_get_resource_value(buf + 3,
    411							     IORESOURCE_IRQ,
    412							     &start, NULL,
    413							     &flags);
    414				pnp_add_irq_resource(dev, start, flags);
    415			} else if (!strncasecmp(buf, "dma", 3)) {
    416				buf = pnp_get_resource_value(buf + 3,
    417							     IORESOURCE_DMA,
    418							     &start, NULL,
    419							     &flags);
    420				pnp_add_dma_resource(dev, start, flags);
    421			} else if (!strncasecmp(buf, "bus", 3)) {
    422				buf = pnp_get_resource_value(buf + 3,
    423							     IORESOURCE_BUS,
    424							     &start, &end,
    425							     NULL);
    426				pnp_add_bus_resource(dev, start, end);
    427			} else
    428				break;
    429		}
    430		mutex_unlock(&pnp_res_mutex);
    431		goto done;
    432	}
    433
    434done:
    435	if (retval < 0)
    436		return retval;
    437	return count;
    438}
    439static DEVICE_ATTR_RW(resources);
    440
    441static ssize_t id_show(struct device *dmdev, struct device_attribute *attr,
    442		       char *buf)
    443{
    444	char *str = buf;
    445	struct pnp_dev *dev = to_pnp_dev(dmdev);
    446	struct pnp_id *pos = dev->id;
    447
    448	while (pos) {
    449		str += sprintf(str, "%s\n", pos->id);
    450		pos = pos->next;
    451	}
    452	return (str - buf);
    453}
    454static DEVICE_ATTR_RO(id);
    455
    456static struct attribute *pnp_dev_attrs[] = {
    457	&dev_attr_resources.attr,
    458	&dev_attr_options.attr,
    459	&dev_attr_id.attr,
    460	NULL,
    461};
    462
    463static const struct attribute_group pnp_dev_group = {
    464	.attrs = pnp_dev_attrs,
    465};
    466
    467const struct attribute_group *pnp_dev_groups[] = {
    468	&pnp_dev_group,
    469	NULL,
    470};