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_quirks.c (3210B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * PCI Backend - Handle special overlays for broken devices.
      4 *
      5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
      6 * Author: Chris Bookholt <hap10@epoch.ncsc.mil>
      7 */
      8
      9#define dev_fmt(fmt) DRV_NAME ": " fmt
     10
     11#include <linux/kernel.h>
     12#include <linux/pci.h>
     13#include "pciback.h"
     14#include "conf_space.h"
     15#include "conf_space_quirks.h"
     16
     17LIST_HEAD(xen_pcibk_quirks);
     18static inline const struct pci_device_id *
     19match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
     20{
     21	if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
     22	    (id->device == PCI_ANY_ID || id->device == dev->device) &&
     23	    (id->subvendor == PCI_ANY_ID ||
     24				id->subvendor == dev->subsystem_vendor) &&
     25	    (id->subdevice == PCI_ANY_ID ||
     26				id->subdevice == dev->subsystem_device) &&
     27	    !((id->class ^ dev->class) & id->class_mask))
     28		return id;
     29	return NULL;
     30}
     31
     32static struct xen_pcibk_config_quirk *xen_pcibk_find_quirk(struct pci_dev *dev)
     33{
     34	struct xen_pcibk_config_quirk *tmp_quirk;
     35
     36	list_for_each_entry(tmp_quirk, &xen_pcibk_quirks, quirks_list)
     37		if (match_one_device(&tmp_quirk->devid, dev) != NULL)
     38			goto out;
     39	tmp_quirk = NULL;
     40	dev_printk(KERN_DEBUG, &dev->dev,
     41		   "quirk didn't match any device known\n");
     42out:
     43	return tmp_quirk;
     44}
     45
     46static inline void register_quirk(struct xen_pcibk_config_quirk *quirk)
     47{
     48	list_add_tail(&quirk->quirks_list, &xen_pcibk_quirks);
     49}
     50
     51int xen_pcibk_field_is_dup(struct pci_dev *dev, unsigned int reg)
     52{
     53	int ret = 0;
     54	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
     55	struct config_field_entry *cfg_entry;
     56
     57	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
     58		if (OFFSET(cfg_entry) == reg) {
     59			ret = 1;
     60			break;
     61		}
     62	}
     63	return ret;
     64}
     65
     66int xen_pcibk_config_quirks_add_field(struct pci_dev *dev, struct config_field
     67				    *field)
     68{
     69	int err = 0;
     70
     71	switch (field->size) {
     72	case 1:
     73		field->u.b.read = xen_pcibk_read_config_byte;
     74		field->u.b.write = xen_pcibk_write_config_byte;
     75		break;
     76	case 2:
     77		field->u.w.read = xen_pcibk_read_config_word;
     78		field->u.w.write = xen_pcibk_write_config_word;
     79		break;
     80	case 4:
     81		field->u.dw.read = xen_pcibk_read_config_dword;
     82		field->u.dw.write = xen_pcibk_write_config_dword;
     83		break;
     84	default:
     85		err = -EINVAL;
     86		goto out;
     87	}
     88
     89	xen_pcibk_config_add_field(dev, field);
     90
     91out:
     92	return err;
     93}
     94
     95int xen_pcibk_config_quirks_init(struct pci_dev *dev)
     96{
     97	struct xen_pcibk_config_quirk *quirk;
     98	int ret = 0;
     99
    100	quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
    101	if (!quirk) {
    102		ret = -ENOMEM;
    103		goto out;
    104	}
    105
    106	quirk->devid.vendor = dev->vendor;
    107	quirk->devid.device = dev->device;
    108	quirk->devid.subvendor = dev->subsystem_vendor;
    109	quirk->devid.subdevice = dev->subsystem_device;
    110	quirk->devid.class = 0;
    111	quirk->devid.class_mask = 0;
    112	quirk->devid.driver_data = 0UL;
    113
    114	quirk->pdev = dev;
    115
    116	register_quirk(quirk);
    117out:
    118	return ret;
    119}
    120
    121void xen_pcibk_config_field_free(struct config_field *field)
    122{
    123	kfree(field);
    124}
    125
    126int xen_pcibk_config_quirk_release(struct pci_dev *dev)
    127{
    128	struct xen_pcibk_config_quirk *quirk;
    129	int ret = 0;
    130
    131	quirk = xen_pcibk_find_quirk(dev);
    132	if (!quirk) {
    133		ret = -ENXIO;
    134		goto out;
    135	}
    136
    137	list_del(&quirk->quirks_list);
    138	kfree(quirk);
    139
    140out:
    141	return ret;
    142}