Bug-fixes:
- Regression fixes for C-and-P states not being parsed properly. - Fix possible security issue with guests triggering DoS via non-assigned MSI-Xs. - Fix regression (introduced in v3.7) with raising an event (v2). - Fix hastily introduced band-aid during c0 for the CR3 blowup. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) iQEcBAABAgAGBQJRUxlVAAoJEFjIrFwIi8fJiUsH/2a3A8EVqS7OYDNgT0ZFb1VI rMLNiA50sRJNDsq0NbGl1Y+Lubus1czc0c7HXFQ557OakN6WqcmPPjCKp4JT6NnV Jz/IZ0iimdoHiPru1Qe4ah3fSgzUtht2LB48Z/a0Is4k3LsRP2W3/niVC3ypnyuJ 52HjjuxeFAfXIkNeqsrO2a6cUXZeXzUyR4g9GNxDozi4jHpoPQ4j9okZbo218xH+ /pRnFeMD7t7dFkgNeyeGXUiJn2AkNPHi3Hx+RH5nN9KXQ1eem9R4p7Qpez1dUEWF YEc/bs7MyOYezzTVHPYk77Yt8baOHJt7UbHjM6jfi1aGYYINTRr3m5mORd3rCmc= =61IX -----END PGP SIGNATURE----- Merge tag 'stable/for-linus-3.9-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen Pull Xen bug-fixes from Konrad Rzeszutek Wilk: "This is mostly just the last stragglers of the regression bugs that this merge window had. There are also two bug-fixes: one that adds an extra layer of security, and a regression fix for a change that was added in v3.7 (the v1 was faulty, the v2 works). - Regression fixes for C-and-P states not being parsed properly. - Fix possible security issue with guests triggering DoS via non-assigned MSI-Xs. - Fix regression (introduced in v3.7) with raising an event (v2). - Fix hastily introduced band-aid during c0 for the CR3 blowup." * tag 'stable/for-linus-3.9-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: xen/events: avoid race with raising an event in unmask_evtchn() xen/mmu: Move the setting of pvops.write_cr3 to later phase in bootup. xen/acpi-stub: Disable it b/c the acpi_processor_add is no longer called. xen-pciback: notify hypervisor about devices intended to be assigned to guests xen/acpi-processor: Don't dereference struct acpi_processor on all CPUs.
This commit is contained in:
commit
33b65f1e9c
8 changed files with 74 additions and 26 deletions
|
@ -382,14 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str)
|
||||||
return _hypercall3(int, console_io, cmd, count, str);
|
return _hypercall3(int, console_io, cmd, count, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int __must_check HYPERVISOR_physdev_op_compat(int, void *);
|
extern int __must_check xen_physdev_op_compat(int, void *);
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
HYPERVISOR_physdev_op(int cmd, void *arg)
|
HYPERVISOR_physdev_op(int cmd, void *arg)
|
||||||
{
|
{
|
||||||
int rc = _hypercall2(int, physdev_op, cmd, arg);
|
int rc = _hypercall2(int, physdev_op, cmd, arg);
|
||||||
if (unlikely(rc == -ENOSYS))
|
if (unlikely(rc == -ENOSYS))
|
||||||
rc = HYPERVISOR_physdev_op_compat(cmd, arg);
|
rc = xen_physdev_op_compat(cmd, arg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1467,8 +1467,6 @@ static void __init xen_write_cr3_init(unsigned long cr3)
|
||||||
__xen_write_cr3(true, cr3);
|
__xen_write_cr3(true, cr3);
|
||||||
|
|
||||||
xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */
|
xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */
|
||||||
|
|
||||||
pv_mmu_ops.write_cr3 = &xen_write_cr3;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2122,6 +2120,7 @@ static void __init xen_post_allocator_init(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
|
pv_mmu_ops.write_cr3 = &xen_write_cr3;
|
||||||
SetPagePinned(virt_to_page(level3_user_vsyscall));
|
SetPagePinned(virt_to_page(level3_user_vsyscall));
|
||||||
#endif
|
#endif
|
||||||
xen_mark_init_mm_pinned();
|
xen_mark_init_mm_pinned();
|
||||||
|
|
|
@ -182,7 +182,7 @@ config XEN_PRIVCMD
|
||||||
|
|
||||||
config XEN_STUB
|
config XEN_STUB
|
||||||
bool "Xen stub drivers"
|
bool "Xen stub drivers"
|
||||||
depends on XEN && X86_64
|
depends on XEN && X86_64 && BROKEN
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Allow kernel to install stub drivers, to reserve space for Xen drivers,
|
Allow kernel to install stub drivers, to reserve space for Xen drivers,
|
||||||
|
|
|
@ -403,11 +403,23 @@ static void unmask_evtchn(int port)
|
||||||
|
|
||||||
if (unlikely((cpu != cpu_from_evtchn(port))))
|
if (unlikely((cpu != cpu_from_evtchn(port))))
|
||||||
do_hypercall = 1;
|
do_hypercall = 1;
|
||||||
else
|
else {
|
||||||
|
/*
|
||||||
|
* Need to clear the mask before checking pending to
|
||||||
|
* avoid a race with an event becoming pending.
|
||||||
|
*
|
||||||
|
* EVTCHNOP_unmask will only trigger an upcall if the
|
||||||
|
* mask bit was set, so if a hypercall is needed
|
||||||
|
* remask the event.
|
||||||
|
*/
|
||||||
|
sync_clear_bit(port, BM(&s->evtchn_mask[0]));
|
||||||
evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
|
evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
|
||||||
|
|
||||||
if (unlikely(evtchn_pending && xen_hvm_domain()))
|
if (unlikely(evtchn_pending && xen_hvm_domain())) {
|
||||||
do_hypercall = 1;
|
sync_set_bit(port, BM(&s->evtchn_mask[0]));
|
||||||
|
do_hypercall = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Slow path (hypercall) if this is a non-local port or if this is
|
/* Slow path (hypercall) if this is a non-local port or if this is
|
||||||
* an hvm domain and an event is pending (hvm domains don't have
|
* an hvm domain and an event is pending (hvm domains don't have
|
||||||
|
@ -418,8 +430,6 @@ static void unmask_evtchn(int port)
|
||||||
} else {
|
} else {
|
||||||
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
|
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
|
||||||
|
|
||||||
sync_clear_bit(port, BM(&s->evtchn_mask[0]));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following is basically the equivalent of
|
* The following is basically the equivalent of
|
||||||
* 'hw_resend_irq'. Just like a real IO-APIC we 'lose
|
* 'hw_resend_irq'. Just like a real IO-APIC we 'lose
|
||||||
|
|
|
@ -44,7 +44,7 @@ int xen_event_channel_op_compat(int cmd, void *arg)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xen_event_channel_op_compat);
|
EXPORT_SYMBOL_GPL(xen_event_channel_op_compat);
|
||||||
|
|
||||||
int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
|
int xen_physdev_op_compat(int cmd, void *arg)
|
||||||
{
|
{
|
||||||
struct physdev_op op;
|
struct physdev_op op;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -78,3 +78,4 @@ int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xen_physdev_op_compat);
|
||||||
|
|
|
@ -505,6 +505,9 @@ static int __init xen_acpi_processor_init(void)
|
||||||
|
|
||||||
pr = per_cpu(processors, i);
|
pr = per_cpu(processors, i);
|
||||||
perf = per_cpu_ptr(acpi_perf_data, i);
|
perf = per_cpu_ptr(acpi_perf_data, i);
|
||||||
|
if (!pr)
|
||||||
|
continue;
|
||||||
|
|
||||||
pr->performance = perf;
|
pr->performance = perf;
|
||||||
rc = acpi_processor_get_performance_info(pr);
|
rc = acpi_processor_get_performance_info(pr);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <xen/events.h>
|
#include <xen/events.h>
|
||||||
#include <asm/xen/pci.h>
|
#include <asm/xen/pci.h>
|
||||||
#include <asm/xen/hypervisor.h>
|
#include <asm/xen/hypervisor.h>
|
||||||
|
#include <xen/interface/physdev.h>
|
||||||
#include "pciback.h"
|
#include "pciback.h"
|
||||||
#include "conf_space.h"
|
#include "conf_space.h"
|
||||||
#include "conf_space_quirks.h"
|
#include "conf_space_quirks.h"
|
||||||
|
@ -85,37 +86,52 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
|
||||||
static void pcistub_device_release(struct kref *kref)
|
static void pcistub_device_release(struct kref *kref)
|
||||||
{
|
{
|
||||||
struct pcistub_device *psdev;
|
struct pcistub_device *psdev;
|
||||||
|
struct pci_dev *dev;
|
||||||
struct xen_pcibk_dev_data *dev_data;
|
struct xen_pcibk_dev_data *dev_data;
|
||||||
|
|
||||||
psdev = container_of(kref, struct pcistub_device, kref);
|
psdev = container_of(kref, struct pcistub_device, kref);
|
||||||
dev_data = pci_get_drvdata(psdev->dev);
|
dev = psdev->dev;
|
||||||
|
dev_data = pci_get_drvdata(dev);
|
||||||
|
|
||||||
dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
|
dev_dbg(&dev->dev, "pcistub_device_release\n");
|
||||||
|
|
||||||
xen_unregister_device_domain_owner(psdev->dev);
|
xen_unregister_device_domain_owner(dev);
|
||||||
|
|
||||||
/* Call the reset function which does not take lock as this
|
/* Call the reset function which does not take lock as this
|
||||||
* is called from "unbind" which takes a device_lock mutex.
|
* is called from "unbind" which takes a device_lock mutex.
|
||||||
*/
|
*/
|
||||||
__pci_reset_function_locked(psdev->dev);
|
__pci_reset_function_locked(dev);
|
||||||
if (pci_load_and_free_saved_state(psdev->dev,
|
if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
|
||||||
&dev_data->pci_saved_state)) {
|
dev_dbg(&dev->dev, "Could not reload PCI state\n");
|
||||||
dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n");
|
else
|
||||||
} else
|
pci_restore_state(dev);
|
||||||
pci_restore_state(psdev->dev);
|
|
||||||
|
if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
|
||||||
|
struct physdev_pci_device ppdev = {
|
||||||
|
.seg = pci_domain_nr(dev->bus),
|
||||||
|
.bus = dev->bus->number,
|
||||||
|
.devfn = dev->devfn
|
||||||
|
};
|
||||||
|
int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix,
|
||||||
|
&ppdev);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
dev_warn(&dev->dev, "MSI-X release failed (%d)\n",
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
/* Disable the device */
|
/* Disable the device */
|
||||||
xen_pcibk_reset_device(psdev->dev);
|
xen_pcibk_reset_device(dev);
|
||||||
|
|
||||||
kfree(dev_data);
|
kfree(dev_data);
|
||||||
pci_set_drvdata(psdev->dev, NULL);
|
pci_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
/* Clean-up the device */
|
/* Clean-up the device */
|
||||||
xen_pcibk_config_free_dyn_fields(psdev->dev);
|
xen_pcibk_config_free_dyn_fields(dev);
|
||||||
xen_pcibk_config_free_dev(psdev->dev);
|
xen_pcibk_config_free_dev(dev);
|
||||||
|
|
||||||
psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
|
dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
|
||||||
pci_dev_put(psdev->dev);
|
pci_dev_put(dev);
|
||||||
|
|
||||||
kfree(psdev);
|
kfree(psdev);
|
||||||
}
|
}
|
||||||
|
@ -355,6 +371,19 @@ static int pcistub_init_device(struct pci_dev *dev)
|
||||||
if (err)
|
if (err)
|
||||||
goto config_release;
|
goto config_release;
|
||||||
|
|
||||||
|
if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
|
||||||
|
struct physdev_pci_device ppdev = {
|
||||||
|
.seg = pci_domain_nr(dev->bus),
|
||||||
|
.bus = dev->bus->number,
|
||||||
|
.devfn = dev->devfn
|
||||||
|
};
|
||||||
|
|
||||||
|
err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev);
|
||||||
|
if (err)
|
||||||
|
dev_err(&dev->dev, "MSI-X preparation failed (%d)\n",
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
/* We need the device active to save the state. */
|
/* We need the device active to save the state. */
|
||||||
dev_dbg(&dev->dev, "save state of device\n");
|
dev_dbg(&dev->dev, "save state of device\n");
|
||||||
pci_save_state(dev);
|
pci_save_state(dev);
|
||||||
|
|
|
@ -251,6 +251,12 @@ struct physdev_pci_device_add {
|
||||||
|
|
||||||
#define PHYSDEVOP_pci_device_remove 26
|
#define PHYSDEVOP_pci_device_remove 26
|
||||||
#define PHYSDEVOP_restore_msi_ext 27
|
#define PHYSDEVOP_restore_msi_ext 27
|
||||||
|
/*
|
||||||
|
* Dom0 should use these two to announce MMIO resources assigned to
|
||||||
|
* MSI-X capable devices won't (prepare) or may (release) change.
|
||||||
|
*/
|
||||||
|
#define PHYSDEVOP_prepare_msix 30
|
||||||
|
#define PHYSDEVOP_release_msix 31
|
||||||
struct physdev_pci_device {
|
struct physdev_pci_device {
|
||||||
/* IN */
|
/* IN */
|
||||||
uint16_t seg;
|
uint16_t seg;
|
||||||
|
|
Loading…
Reference in a new issue