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

conf_space_header.c (10104B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * PCI Backend - Handles the virtual fields in the configuration space headers.
      4 *
      5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9#define dev_fmt pr_fmt
     10
     11#include <linux/kernel.h>
     12#include <linux/pci.h>
     13#include "pciback.h"
     14#include "conf_space.h"
     15
     16struct pci_cmd_info {
     17	u16 val;
     18};
     19
     20struct pci_bar_info {
     21	u32 val;
     22	u32 len_val;
     23	int which;
     24};
     25
     26#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
     27#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
     28
     29/* Bits guests are allowed to control in permissive mode. */
     30#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
     31			   PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
     32			   PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
     33
     34static void *command_init(struct pci_dev *dev, int offset)
     35{
     36	struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
     37	int err;
     38
     39	if (!cmd)
     40		return ERR_PTR(-ENOMEM);
     41
     42	err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
     43	if (err) {
     44		kfree(cmd);
     45		return ERR_PTR(err);
     46	}
     47
     48	return cmd;
     49}
     50
     51static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
     52{
     53	int ret = pci_read_config_word(dev, offset, value);
     54	const struct pci_cmd_info *cmd = data;
     55
     56	*value &= PCI_COMMAND_GUEST;
     57	*value |= cmd->val & ~PCI_COMMAND_GUEST;
     58
     59	return ret;
     60}
     61
     62static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
     63{
     64	struct xen_pcibk_dev_data *dev_data;
     65	int err;
     66	u16 val;
     67	struct pci_cmd_info *cmd = data;
     68
     69	dev_data = pci_get_drvdata(dev);
     70	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
     71		dev_dbg(&dev->dev, "enable\n");
     72		err = pci_enable_device(dev);
     73		if (err)
     74			return err;
     75		if (dev_data)
     76			dev_data->enable_intx = 1;
     77	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
     78		dev_dbg(&dev->dev, "disable\n");
     79		pci_disable_device(dev);
     80		if (dev_data)
     81			dev_data->enable_intx = 0;
     82	}
     83
     84	if (!dev->is_busmaster && is_master_cmd(value)) {
     85		dev_dbg(&dev->dev, "set bus master\n");
     86		pci_set_master(dev);
     87	} else if (dev->is_busmaster && !is_master_cmd(value)) {
     88		dev_dbg(&dev->dev, "clear bus master\n");
     89		pci_clear_master(dev);
     90	}
     91
     92	if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
     93	    (value & PCI_COMMAND_INVALIDATE)) {
     94		dev_dbg(&dev->dev, "enable memory-write-invalidate\n");
     95		err = pci_set_mwi(dev);
     96		if (err) {
     97			dev_warn(&dev->dev, "cannot enable memory-write-invalidate (%d)\n",
     98				err);
     99			value &= ~PCI_COMMAND_INVALIDATE;
    100		}
    101	} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
    102		   !(value & PCI_COMMAND_INVALIDATE)) {
    103		dev_dbg(&dev->dev, "disable memory-write-invalidate\n");
    104		pci_clear_mwi(dev);
    105	}
    106
    107	if (dev_data && dev_data->allow_interrupt_control) {
    108		if ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE) {
    109			if (value & PCI_COMMAND_INTX_DISABLE) {
    110				pci_intx(dev, 0);
    111			} else {
    112				/* Do not allow enabling INTx together with MSI or MSI-X. */
    113				switch (xen_pcibk_get_interrupt_type(dev)) {
    114				case INTERRUPT_TYPE_NONE:
    115					pci_intx(dev, 1);
    116					break;
    117				case INTERRUPT_TYPE_INTX:
    118					break;
    119				default:
    120					return PCIBIOS_SET_FAILED;
    121				}
    122			}
    123		}
    124	}
    125
    126	cmd->val = value;
    127
    128	if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
    129		return 0;
    130
    131	/* Only allow the guest to control certain bits. */
    132	err = pci_read_config_word(dev, offset, &val);
    133	if (err || val == value)
    134		return err;
    135
    136	value &= PCI_COMMAND_GUEST;
    137	value |= val & ~PCI_COMMAND_GUEST;
    138
    139	return pci_write_config_word(dev, offset, value);
    140}
    141
    142static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
    143{
    144	struct pci_bar_info *bar = data;
    145
    146	if (unlikely(!bar)) {
    147		dev_warn(&dev->dev, "driver data not found\n");
    148		return XEN_PCI_ERR_op_failed;
    149	}
    150
    151	/* A write to obtain the length must happen as a 32-bit write.
    152	 * This does not (yet) support writing individual bytes
    153	 */
    154	if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
    155		bar->which = 1;
    156	else {
    157		u32 tmpval;
    158		pci_read_config_dword(dev, offset, &tmpval);
    159		if (tmpval != bar->val && value == bar->val) {
    160			/* Allow restoration of bar value. */
    161			pci_write_config_dword(dev, offset, bar->val);
    162		}
    163		bar->which = 0;
    164	}
    165
    166	/* Do we need to support enabling/disabling the rom address here? */
    167
    168	return 0;
    169}
    170
    171/* For the BARs, only allow writes which write ~0 or
    172 * the correct resource information
    173 * (Needed for when the driver probes the resource usage)
    174 */
    175static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
    176{
    177	struct pci_bar_info *bar = data;
    178	unsigned int pos = (offset - PCI_BASE_ADDRESS_0) / 4;
    179	const struct resource *res = dev->resource;
    180	u32 mask;
    181
    182	if (unlikely(!bar)) {
    183		dev_warn(&dev->dev, "driver data not found\n");
    184		return XEN_PCI_ERR_op_failed;
    185	}
    186
    187	/* A write to obtain the length must happen as a 32-bit write.
    188	 * This does not (yet) support writing individual bytes
    189	 */
    190	if (res[pos].flags & IORESOURCE_IO)
    191		mask = ~PCI_BASE_ADDRESS_IO_MASK;
    192	else if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64))
    193		mask = 0;
    194	else
    195		mask = ~PCI_BASE_ADDRESS_MEM_MASK;
    196	if ((value | mask) == ~0U)
    197		bar->which = 1;
    198	else {
    199		u32 tmpval;
    200		pci_read_config_dword(dev, offset, &tmpval);
    201		if (tmpval != bar->val && value == bar->val) {
    202			/* Allow restoration of bar value. */
    203			pci_write_config_dword(dev, offset, bar->val);
    204		}
    205		bar->which = 0;
    206	}
    207
    208	return 0;
    209}
    210
    211static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
    212{
    213	struct pci_bar_info *bar = data;
    214
    215	if (unlikely(!bar)) {
    216		dev_warn(&dev->dev, "driver data not found\n");
    217		return XEN_PCI_ERR_op_failed;
    218	}
    219
    220	*value = bar->which ? bar->len_val : bar->val;
    221
    222	return 0;
    223}
    224
    225static void *bar_init(struct pci_dev *dev, int offset)
    226{
    227	unsigned int pos;
    228	const struct resource *res = dev->resource;
    229	struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
    230
    231	if (!bar)
    232		return ERR_PTR(-ENOMEM);
    233
    234	if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
    235		pos = PCI_ROM_RESOURCE;
    236	else {
    237		pos = (offset - PCI_BASE_ADDRESS_0) / 4;
    238		if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
    239			/*
    240			 * Use ">> 16 >> 16" instead of direct ">> 32" shift
    241			 * to avoid warnings on 32-bit architectures.
    242			 */
    243			bar->val = res[pos - 1].start >> 16 >> 16;
    244			bar->len_val = -resource_size(&res[pos - 1]) >> 16 >> 16;
    245			return bar;
    246		}
    247	}
    248
    249	if (!res[pos].flags ||
    250	    (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
    251			       IORESOURCE_BUSY)))
    252		return bar;
    253
    254	bar->val = res[pos].start |
    255		   (res[pos].flags & PCI_REGION_FLAG_MASK);
    256	bar->len_val = -resource_size(&res[pos]) |
    257		       (res[pos].flags & PCI_REGION_FLAG_MASK);
    258
    259	return bar;
    260}
    261
    262static void bar_reset(struct pci_dev *dev, int offset, void *data)
    263{
    264	struct pci_bar_info *bar = data;
    265
    266	bar->which = 0;
    267}
    268
    269static void bar_release(struct pci_dev *dev, int offset, void *data)
    270{
    271	kfree(data);
    272}
    273
    274static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
    275			       u16 *value, void *data)
    276{
    277	*value = dev->vendor;
    278
    279	return 0;
    280}
    281
    282static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
    283			       u16 *value, void *data)
    284{
    285	*value = dev->device;
    286
    287	return 0;
    288}
    289
    290static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
    291			  void *data)
    292{
    293	*value = (u8) dev->irq;
    294
    295	return 0;
    296}
    297
    298static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
    299{
    300	u8 cur_value;
    301	int err;
    302
    303	err = pci_read_config_byte(dev, offset, &cur_value);
    304	if (err)
    305		goto out;
    306
    307	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
    308	    || value == PCI_BIST_START)
    309		err = pci_write_config_byte(dev, offset, value);
    310
    311out:
    312	return err;
    313}
    314
    315static const struct config_field header_common[] = {
    316	{
    317	 .offset    = PCI_VENDOR_ID,
    318	 .size      = 2,
    319	 .u.w.read  = xen_pcibk_read_vendor,
    320	},
    321	{
    322	 .offset    = PCI_DEVICE_ID,
    323	 .size      = 2,
    324	 .u.w.read  = xen_pcibk_read_device,
    325	},
    326	{
    327	 .offset    = PCI_COMMAND,
    328	 .size      = 2,
    329	 .init      = command_init,
    330	 .release   = bar_release,
    331	 .u.w.read  = command_read,
    332	 .u.w.write = command_write,
    333	},
    334	{
    335	 .offset    = PCI_INTERRUPT_LINE,
    336	 .size      = 1,
    337	 .u.b.read  = interrupt_read,
    338	},
    339	{
    340	 .offset    = PCI_INTERRUPT_PIN,
    341	 .size      = 1,
    342	 .u.b.read  = xen_pcibk_read_config_byte,
    343	},
    344	{
    345	 /* Any side effects of letting driver domain control cache line? */
    346	 .offset    = PCI_CACHE_LINE_SIZE,
    347	 .size      = 1,
    348	 .u.b.read  = xen_pcibk_read_config_byte,
    349	 .u.b.write = xen_pcibk_write_config_byte,
    350	},
    351	{
    352	 .offset    = PCI_LATENCY_TIMER,
    353	 .size      = 1,
    354	 .u.b.read  = xen_pcibk_read_config_byte,
    355	},
    356	{
    357	 .offset    = PCI_BIST,
    358	 .size      = 1,
    359	 .u.b.read  = xen_pcibk_read_config_byte,
    360	 .u.b.write = bist_write,
    361	},
    362	{}
    363};
    364
    365#define CFG_FIELD_BAR(reg_offset)			\
    366	{						\
    367	.offset     = reg_offset,			\
    368	.size       = 4,				\
    369	.init       = bar_init,				\
    370	.reset      = bar_reset,			\
    371	.release    = bar_release,			\
    372	.u.dw.read  = bar_read,				\
    373	.u.dw.write = bar_write,			\
    374	}
    375
    376#define CFG_FIELD_ROM(reg_offset)			\
    377	{						\
    378	.offset     = reg_offset,			\
    379	.size       = 4,				\
    380	.init       = bar_init,				\
    381	.reset      = bar_reset,			\
    382	.release    = bar_release,			\
    383	.u.dw.read  = bar_read,				\
    384	.u.dw.write = rom_write,			\
    385	}
    386
    387static const struct config_field header_0[] = {
    388	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
    389	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
    390	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
    391	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
    392	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
    393	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
    394	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
    395	{}
    396};
    397
    398static const struct config_field header_1[] = {
    399	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
    400	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
    401	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
    402	{}
    403};
    404
    405int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
    406{
    407	int err;
    408
    409	err = xen_pcibk_config_add_fields(dev, header_common);
    410	if (err)
    411		goto out;
    412
    413	switch (dev->hdr_type) {
    414	case PCI_HEADER_TYPE_NORMAL:
    415		err = xen_pcibk_config_add_fields(dev, header_0);
    416		break;
    417
    418	case PCI_HEADER_TYPE_BRIDGE:
    419		err = xen_pcibk_config_add_fields(dev, header_1);
    420		break;
    421
    422	default:
    423		err = -EINVAL;
    424		dev_err(&dev->dev, "Unsupported header type %d!\n",
    425			dev->hdr_type);
    426		break;
    427	}
    428
    429out:
    430	return err;
    431}