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

platform-pci-unplug.c (5664B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3/******************************************************************************
      4 * platform-pci-unplug.c
      5 *
      6 * Xen platform PCI device driver
      7 * Copyright (c) 2010, Citrix
      8 */
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <linux/init.h>
     13#include <linux/io.h>
     14#include <linux/export.h>
     15
     16#include <xen/xen.h>
     17#include <xen/platform_pci.h>
     18#include "xen-ops.h"
     19
     20#define XEN_PLATFORM_ERR_MAGIC -1
     21#define XEN_PLATFORM_ERR_PROTOCOL -2
     22#define XEN_PLATFORM_ERR_BLACKLIST -3
     23
     24/* store the value of xen_emul_unplug after the unplug is done */
     25static int xen_platform_pci_unplug;
     26static int xen_emul_unplug;
     27
     28static int check_platform_magic(void)
     29{
     30	short magic;
     31	char protocol;
     32
     33	magic = inw(XEN_IOPORT_MAGIC);
     34	if (magic != XEN_IOPORT_MAGIC_VAL) {
     35		pr_err("Xen Platform PCI: unrecognised magic value\n");
     36		return XEN_PLATFORM_ERR_MAGIC;
     37	}
     38
     39	protocol = inb(XEN_IOPORT_PROTOVER);
     40
     41	pr_debug("Xen Platform PCI: I/O protocol version %d\n",
     42			protocol);
     43
     44	switch (protocol) {
     45	case 1:
     46		outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
     47		outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
     48		if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
     49			pr_err("Xen Platform: blacklisted by host\n");
     50			return XEN_PLATFORM_ERR_BLACKLIST;
     51		}
     52		break;
     53	default:
     54		pr_warn("Xen Platform PCI: unknown I/O protocol version\n");
     55		return XEN_PLATFORM_ERR_PROTOCOL;
     56	}
     57
     58	return 0;
     59}
     60
     61bool xen_has_pv_devices(void)
     62{
     63	if (!xen_domain())
     64		return false;
     65
     66	/* PV and PVH domains always have them. */
     67	if (xen_pv_domain() || xen_pvh_domain())
     68		return true;
     69
     70	/* And user has xen_platform_pci=0 set in guest config as
     71	 * driver did not modify the value. */
     72	if (xen_platform_pci_unplug == 0)
     73		return false;
     74
     75	if (xen_platform_pci_unplug & XEN_UNPLUG_NEVER)
     76		return false;
     77
     78	if (xen_platform_pci_unplug & XEN_UNPLUG_ALL)
     79		return true;
     80
     81	/* This is an odd one - we are going to run legacy
     82	 * and PV drivers at the same time. */
     83	if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY)
     84		return true;
     85
     86	/* And the caller has to follow with xen_pv_{disk,nic}_devices
     87	 * to be certain which driver can load. */
     88	return false;
     89}
     90EXPORT_SYMBOL_GPL(xen_has_pv_devices);
     91
     92static bool __xen_has_pv_device(int state)
     93{
     94	/* HVM domains might or might not */
     95	if (xen_hvm_domain() && (xen_platform_pci_unplug & state))
     96		return true;
     97
     98	return xen_has_pv_devices();
     99}
    100
    101bool xen_has_pv_nic_devices(void)
    102{
    103	return __xen_has_pv_device(XEN_UNPLUG_ALL_NICS | XEN_UNPLUG_ALL);
    104}
    105EXPORT_SYMBOL_GPL(xen_has_pv_nic_devices);
    106
    107bool xen_has_pv_disk_devices(void)
    108{
    109	return __xen_has_pv_device(XEN_UNPLUG_ALL_IDE_DISKS |
    110				   XEN_UNPLUG_AUX_IDE_DISKS | XEN_UNPLUG_ALL);
    111}
    112EXPORT_SYMBOL_GPL(xen_has_pv_disk_devices);
    113
    114/*
    115 * This one is odd - it determines whether you want to run PV _and_
    116 * legacy (IDE) drivers together. This combination is only possible
    117 * under HVM.
    118 */
    119bool xen_has_pv_and_legacy_disk_devices(void)
    120{
    121	if (!xen_domain())
    122		return false;
    123
    124	/* N.B. This is only ever used in HVM mode */
    125	if (xen_pv_domain())
    126		return false;
    127
    128	if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY)
    129		return true;
    130
    131	return false;
    132}
    133EXPORT_SYMBOL_GPL(xen_has_pv_and_legacy_disk_devices);
    134
    135void xen_unplug_emulated_devices(void)
    136{
    137	int r;
    138
    139	/* PVH guests don't have emulated devices. */
    140	if (xen_pvh_domain())
    141		return;
    142
    143	/* user explicitly requested no unplug */
    144	if (xen_emul_unplug & XEN_UNPLUG_NEVER)
    145		return;
    146	/* check the version of the xen platform PCI device */
    147	r = check_platform_magic();
    148	/* If the version matches enable the Xen platform PCI driver.
    149	 * Also enable the Xen platform PCI driver if the host does
    150	 * not support the unplug protocol (XEN_PLATFORM_ERR_MAGIC)
    151	 * but the user told us that unplugging is unnecessary. */
    152	if (r && !(r == XEN_PLATFORM_ERR_MAGIC &&
    153			(xen_emul_unplug & XEN_UNPLUG_UNNECESSARY)))
    154		return;
    155	/* Set the default value of xen_emul_unplug depending on whether or
    156	 * not the Xen PV frontends and the Xen platform PCI driver have
    157	 * been compiled for this kernel (modules or built-in are both OK). */
    158	if (!xen_emul_unplug) {
    159		if (xen_must_unplug_nics()) {
    160			pr_info("Netfront and the Xen platform PCI driver have "
    161					"been compiled for this kernel: unplug emulated NICs.\n");
    162			xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
    163		}
    164		if (xen_must_unplug_disks()) {
    165			pr_info("Blkfront and the Xen platform PCI driver have "
    166					"been compiled for this kernel: unplug emulated disks.\n"
    167					"You might have to change the root device\n"
    168					"from /dev/hd[a-d] to /dev/xvd[a-d]\n"
    169					"in your root= kernel command line option\n");
    170			xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
    171		}
    172	}
    173	/* Now unplug the emulated devices */
    174	if (!(xen_emul_unplug & XEN_UNPLUG_UNNECESSARY))
    175		outw(xen_emul_unplug, XEN_IOPORT_UNPLUG);
    176	xen_platform_pci_unplug = xen_emul_unplug;
    177}
    178
    179static int __init parse_xen_emul_unplug(char *arg)
    180{
    181	char *p, *q;
    182	int l;
    183
    184	for (p = arg; p; p = q) {
    185		q = strchr(p, ',');
    186		if (q) {
    187			l = q - p;
    188			q++;
    189		} else {
    190			l = strlen(p);
    191		}
    192		if (!strncmp(p, "all", l))
    193			xen_emul_unplug |= XEN_UNPLUG_ALL;
    194		else if (!strncmp(p, "ide-disks", l))
    195			xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
    196		else if (!strncmp(p, "aux-ide-disks", l))
    197			xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS;
    198		else if (!strncmp(p, "nics", l))
    199			xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
    200		else if (!strncmp(p, "unnecessary", l))
    201			xen_emul_unplug |= XEN_UNPLUG_UNNECESSARY;
    202		else if (!strncmp(p, "never", l))
    203			xen_emul_unplug |= XEN_UNPLUG_NEVER;
    204		else
    205			pr_warn("unrecognised option '%s' "
    206				 "in parameter 'xen_emul_unplug'\n", p);
    207	}
    208	return 0;
    209}
    210early_param("xen_emul_unplug", parse_xen_emul_unplug);