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
This commit is contained in:
@@ -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)
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
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 @@
|
|||||||
#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,21 +24,35 @@ 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)
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!cmd)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
|
||||||
|
if (err) {
|
||||||
|
kfree(cmd);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
|
static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
|
||||||
{
|
{
|
||||||
int i;
|
int ret = pci_read_config_word(dev, offset, value);
|
||||||
int ret;
|
const struct pci_cmd_info *cmd = data;
|
||||||
|
|
||||||
ret = xen_pcibk_read_config_word(dev, offset, value, data);
|
*value &= PCI_COMMAND_GUEST;
|
||||||
if (!pci_is_enabled(dev))
|
*value |= cmd->val & ~PCI_COMMAND_GUEST;
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
|
|
||||||
if (dev->resource[i].flags & IORESOURCE_IO)
|
|
||||||
*value |= PCI_COMMAND_IO;
|
|
||||||
if (dev->resource[i].flags & IORESOURCE_MEM)
|
|
||||||
*value |= PCI_COMMAND_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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[] = {
|
|||||||
{
|
{
|
||||||
.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,
|
|||||||
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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user