Commit f47e3310 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'stable/for-linus-4.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen bug fixes from David Vrabel:

 - fix a PV regression in 3.19.

 - fix a dom0 crash on hosts with large numbers of PIRQs.

 - prevent pcifront from disabling memory or I/O port access, which may
   trigger host crashes.

* tag 'stable/for-linus-4.0-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen-pciback: limit guest control of command register
  xen/events: avoid NULL pointer dereference in dom0 on large machines
  xen: Remove trailing semicolon from xenbus_register_frontend() definition
  x86/xen: correct bug in p2m list initialization
parents bbc54a00 af6fc858
...@@ -563,7 +563,7 @@ static bool alloc_p2m(unsigned long pfn) ...@@ -563,7 +563,7 @@ static bool alloc_p2m(unsigned long pfn)
if (p2m_pfn == PFN_DOWN(__pa(p2m_missing))) if (p2m_pfn == PFN_DOWN(__pa(p2m_missing)))
p2m_init(p2m); p2m_init(p2m);
else else
p2m_init_identity(p2m, pfn); p2m_init_identity(p2m, pfn & ~(P2M_PER_PAGE - 1));
spin_lock_irqsave(&p2m_update_lock, flags); spin_lock_irqsave(&p2m_update_lock, flags);
......
...@@ -526,20 +526,26 @@ static unsigned int __startup_pirq(unsigned int irq) ...@@ -526,20 +526,26 @@ static unsigned int __startup_pirq(unsigned int irq)
pirq_query_unmask(irq); pirq_query_unmask(irq);
rc = set_evtchn_to_irq(evtchn, irq); rc = set_evtchn_to_irq(evtchn, irq);
if (rc != 0) { if (rc)
pr_err("irq%d: Failed to set port to irq mapping (%d)\n", goto err;
irq, rc);
xen_evtchn_close(evtchn);
return 0;
}
bind_evtchn_to_cpu(evtchn, 0); bind_evtchn_to_cpu(evtchn, 0);
info->evtchn = evtchn; info->evtchn = evtchn;
rc = xen_evtchn_port_setup(info);
if (rc)
goto err;
out: out:
unmask_evtchn(evtchn); unmask_evtchn(evtchn);
eoi_pirq(irq_get_irq_data(irq)); eoi_pirq(irq_get_irq_data(irq));
return 0; return 0;
err:
pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc);
xen_evtchn_close(evtchn);
return 0;
} }
static unsigned int startup_pirq(struct irq_data *data) static unsigned int startup_pirq(struct irq_data *data)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "conf_space.h" #include "conf_space.h"
#include "conf_space_quirks.h" #include "conf_space_quirks.h"
static bool permissive; bool permissive;
module_param(permissive, bool, 0644); module_param(permissive, bool, 0644);
/* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
......
...@@ -64,6 +64,8 @@ struct config_field_entry { ...@@ -64,6 +64,8 @@ struct config_field_entry {
void *data; void *data;
}; };
extern bool permissive;
#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
/* Add fields to a device - the add_fields macro expects to get a pointer to /* Add fields to a device - the add_fields macro expects to get a pointer to
......
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
#include "pciback.h" #include "pciback.h"
#include "conf_space.h" #include "conf_space.h"
struct pci_cmd_info {
u16 val;
};
struct pci_bar_info { struct pci_bar_info {
u32 val; u32 val;
u32 len_val; u32 len_val;
...@@ -20,22 +24,36 @@ struct pci_bar_info { ...@@ -20,22 +24,36 @@ struct pci_bar_info {
#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) /* Bits guests are allowed to control in permissive mode. */
#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
static void *command_init(struct pci_dev *dev, int offset)
{ {
int i; struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
int ret; int err;
ret = xen_pcibk_read_config_word(dev, offset, value, data); if (!cmd)
if (!pci_is_enabled(dev)) return ERR_PTR(-ENOMEM);
return ret;
err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
for (i = 0; i < PCI_ROM_RESOURCE; i++) { if (err) {
if (dev->resource[i].flags & IORESOURCE_IO) kfree(cmd);
*value |= PCI_COMMAND_IO; return ERR_PTR(err);
if (dev->resource[i].flags & IORESOURCE_MEM)
*value |= PCI_COMMAND_MEMORY;
} }
return cmd;
}
static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
{
int ret = pci_read_config_word(dev, offset, value);
const struct pci_cmd_info *cmd = data;
*value &= PCI_COMMAND_GUEST;
*value |= cmd->val & ~PCI_COMMAND_GUEST;
return ret; return ret;
} }
...@@ -43,6 +61,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) ...@@ -43,6 +61,8 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
{ {
struct xen_pcibk_dev_data *dev_data; struct xen_pcibk_dev_data *dev_data;
int err; int err;
u16 val;
struct pci_cmd_info *cmd = data;
dev_data = pci_get_drvdata(dev); dev_data = pci_get_drvdata(dev);
if (!pci_is_enabled(dev) && is_enable_cmd(value)) { if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
...@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) ...@@ -83,6 +103,19 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
} }
} }
cmd->val = value;
if (!permissive && (!dev_data || !dev_data->permissive))
return 0;
/* Only allow the guest to control certain bits. */
err = pci_read_config_word(dev, offset, &val);
if (err || val == value)
return err;
value &= PCI_COMMAND_GUEST;
value |= val & ~PCI_COMMAND_GUEST;
return pci_write_config_word(dev, offset, value); return pci_write_config_word(dev, offset, value);
} }
...@@ -282,6 +315,8 @@ static const struct config_field header_common[] = { ...@@ -282,6 +315,8 @@ static const struct config_field header_common[] = {
{ {
.offset = PCI_COMMAND, .offset = PCI_COMMAND,
.size = 2, .size = 2,
.init = command_init,
.release = bar_release,
.u.w.read = command_read, .u.w.read = command_read,
.u.w.write = command_write, .u.w.write = command_write,
}, },
......
...@@ -114,9 +114,9 @@ int __must_check __xenbus_register_backend(struct xenbus_driver *drv, ...@@ -114,9 +114,9 @@ int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
const char *mod_name); const char *mod_name);
#define xenbus_register_frontend(drv) \ #define xenbus_register_frontend(drv) \
__xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME); __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME)
#define xenbus_register_backend(drv) \ #define xenbus_register_backend(drv) \
__xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME); __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME)
void xenbus_unregister_driver(struct xenbus_driver *drv); void xenbus_unregister_driver(struct xenbus_driver *drv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment