Skip to content

Commit 51c71a3

Browse files
committed
xen/pvhvm: If xen_platform_pci=0 is set don't blow up (v4).
The user has the option of disabling the platform driver: 00:02.0 Unassigned class [ff80]: XenSource, Inc. Xen Platform Device (rev 01) which is used to unplug the emulated drivers (IDE, Realtek 8169, etc) and allow the PV drivers to take over. If the user wishes to disable that they can set: xen_platform_pci=0 (in the guest config file) or xen_emul_unplug=never (on the Linux command line) except it does not work properly. The PV drivers still try to load and since the Xen platform driver is not run - and it has not initialized the grant tables, most of the PV drivers stumble upon: input: Xen Virtual Keyboard as /devices/virtual/input/input5 input: Xen Virtual Pointer as /devices/virtual/input/input6M ------------[ cut here ]------------ kernel BUG at /home/konrad/ssd/konrad/linux/drivers/xen/grant-table.c:1206! invalid opcode: 0000 [#1] SMP Modules linked in: xen_kbdfront(+) xenfs xen_privcmd CPU: 6 PID: 1389 Comm: modprobe Not tainted 3.13.0-rc1upstream-00021-ga6c892b-dirty #1 Hardware name: Xen HVM domU, BIOS 4.4-unstable 11/26/2013 RIP: 0010:[<ffffffff813ddc40>] [<ffffffff813ddc40>] get_free_entries+0x2e0/0x300 Call Trace: [<ffffffff8150d9a3>] ? evdev_connect+0x1e3/0x240 [<ffffffff813ddd0e>] gnttab_grant_foreign_access+0x2e/0x70 [<ffffffffa0010081>] xenkbd_connect_backend+0x41/0x290 [xen_kbdfront] [<ffffffffa0010a12>] xenkbd_probe+0x2f2/0x324 [xen_kbdfront] [<ffffffff813e5757>] xenbus_dev_probe+0x77/0x130 [<ffffffff813e7217>] xenbus_frontend_dev_probe+0x47/0x50 [<ffffffff8145e9a9>] driver_probe_device+0x89/0x230 [<ffffffff8145ebeb>] __driver_attach+0x9b/0xa0 [<ffffffff8145eb50>] ? driver_probe_device+0x230/0x230 [<ffffffff8145eb50>] ? driver_probe_device+0x230/0x230 [<ffffffff8145cf1c>] bus_for_each_dev+0x8c/0xb0 [<ffffffff8145e7d9>] driver_attach+0x19/0x20 [<ffffffff8145e260>] bus_add_driver+0x1a0/0x220 [<ffffffff8145f1ff>] driver_register+0x5f/0xf0 [<ffffffff813e55c5>] xenbus_register_driver_common+0x15/0x20 [<ffffffff813e76b3>] xenbus_register_frontend+0x23/0x40 [<ffffffffa0015000>] ? 0xffffffffa0014fff [<ffffffffa001502b>] xenkbd_init+0x2b/0x1000 [xen_kbdfront] [<ffffffff81002049>] do_one_initcall+0x49/0x170 .. snip.. which is hardly nice. This patch fixes this by having each PV driver check for: - if running in PV, then it is fine to execute (as that is their native environment). - if running in HVM, check if user wanted 'xen_emul_unplug=never', in which case bail out and don't load any PV drivers. - if running in HVM, and if PCI device 5853:0001 (xen_platform_pci) does not exist, then bail out and not load PV drivers. - (v2) if running in HVM, and if the user wanted 'xen_emul_unplug=ide-disks', then bail out for all PV devices _except_ the block one. Ditto for the network one ('nics'). - (v2) if running in HVM, and if the user wanted 'xen_emul_unplug=unnecessary' then load block PV driver, and also setup the legacy IDE paths. In (v3) make it actually load PV drivers. Reported-by: Sander Eikelenboom <[email protected] Reported-by: Anthony PERARD <[email protected]> Reported-and-Tested-by: Fabio Fantoni <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> [v2: Add extra logic to handle the myrid ways 'xen_emul_unplug' can be used per Ian and Stefano suggestion] [v3: Make the unnecessary case work properly] [v4: s/disks/ide-disks/ spotted by Fabio] Reviewed-by: Stefano Stabellini <[email protected]> Acked-by: Bjorn Helgaas <[email protected]> [for PCI parts] CC: [email protected]
1 parent 802eee9 commit 51c71a3

File tree

9 files changed

+117
-4
lines changed

9 files changed

+117
-4
lines changed

arch/x86/xen/platform-pci-unplug.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,80 @@ static int check_platform_magic(void)
6969
return 0;
7070
}
7171

72+
bool xen_has_pv_devices()
73+
{
74+
if (!xen_domain())
75+
return false;
76+
77+
/* PV domains always have them. */
78+
if (xen_pv_domain())
79+
return true;
80+
81+
/* And user has xen_platform_pci=0 set in guest config as
82+
* driver did not modify the value. */
83+
if (xen_platform_pci_unplug == 0)
84+
return false;
85+
86+
if (xen_platform_pci_unplug & XEN_UNPLUG_NEVER)
87+
return false;
88+
89+
if (xen_platform_pci_unplug & XEN_UNPLUG_ALL)
90+
return true;
91+
92+
/* This is an odd one - we are going to run legacy
93+
* and PV drivers at the same time. */
94+
if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY)
95+
return true;
96+
97+
/* And the caller has to follow with xen_pv_{disk,nic}_devices
98+
* to be certain which driver can load. */
99+
return false;
100+
}
101+
EXPORT_SYMBOL_GPL(xen_has_pv_devices);
102+
103+
static bool __xen_has_pv_device(int state)
104+
{
105+
/* HVM domains might or might not */
106+
if (xen_hvm_domain() && (xen_platform_pci_unplug & state))
107+
return true;
108+
109+
return xen_has_pv_devices();
110+
}
111+
112+
bool xen_has_pv_nic_devices(void)
113+
{
114+
return __xen_has_pv_device(XEN_UNPLUG_ALL_NICS | XEN_UNPLUG_ALL);
115+
}
116+
EXPORT_SYMBOL_GPL(xen_has_pv_nic_devices);
117+
118+
bool xen_has_pv_disk_devices(void)
119+
{
120+
return __xen_has_pv_device(XEN_UNPLUG_ALL_IDE_DISKS |
121+
XEN_UNPLUG_AUX_IDE_DISKS | XEN_UNPLUG_ALL);
122+
}
123+
EXPORT_SYMBOL_GPL(xen_has_pv_disk_devices);
124+
125+
/*
126+
* This one is odd - it determines whether you want to run PV _and_
127+
* legacy (IDE) drivers together. This combination is only possible
128+
* under HVM.
129+
*/
130+
bool xen_has_pv_and_legacy_disk_devices(void)
131+
{
132+
if (!xen_domain())
133+
return false;
134+
135+
/* N.B. This is only ever used in HVM mode */
136+
if (xen_pv_domain())
137+
return false;
138+
139+
if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY)
140+
return true;
141+
142+
return false;
143+
}
144+
EXPORT_SYMBOL_GPL(xen_has_pv_and_legacy_disk_devices);
145+
72146
void xen_unplug_emulated_devices(void)
73147
{
74148
int r;

drivers/block/xen-blkfront.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,7 @@ static int blkfront_probe(struct xenbus_device *dev,
13561356
char *type;
13571357
int len;
13581358
/* no unplug has been done: do not hook devices != xen vbds */
1359-
if (xen_platform_pci_unplug & XEN_UNPLUG_UNNECESSARY) {
1359+
if (xen_has_pv_and_legacy_disk_devices()) {
13601360
int major;
13611361

13621362
if (!VDEV_IS_EXTENDED(vdevice))
@@ -2079,7 +2079,7 @@ static int __init xlblk_init(void)
20792079
if (!xen_domain())
20802080
return -ENODEV;
20812081

2082-
if (xen_hvm_domain() && !xen_platform_pci_unplug)
2082+
if (!xen_has_pv_disk_devices())
20832083
return -ENODEV;
20842084

20852085
if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {

drivers/char/tpm/xen-tpmfront.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <xen/xenbus.h>
1818
#include <xen/page.h>
1919
#include "tpm.h"
20+
#include <xen/platform_pci.h>
2021

2122
struct tpm_private {
2223
struct tpm_chip *chip;
@@ -421,6 +422,9 @@ static int __init xen_tpmfront_init(void)
421422
if (!xen_domain())
422423
return -ENODEV;
423424

425+
if (!xen_has_pv_devices())
426+
return -ENODEV;
427+
424428
return xenbus_register_frontend(&tpmfront_driver);
425429
}
426430
module_init(xen_tpmfront_init);

drivers/input/misc/xen-kbdfront.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <xen/interface/io/fbif.h>
3030
#include <xen/interface/io/kbdif.h>
3131
#include <xen/xenbus.h>
32+
#include <xen/platform_pci.h>
3233

3334
struct xenkbd_info {
3435
struct input_dev *kbd;
@@ -380,6 +381,9 @@ static int __init xenkbd_init(void)
380381
if (xen_initial_domain())
381382
return -ENODEV;
382383

384+
if (!xen_has_pv_devices())
385+
return -ENODEV;
386+
383387
return xenbus_register_frontend(&xenkbd_driver);
384388
}
385389

drivers/net/xen-netfront.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2115,7 +2115,7 @@ static int __init netif_init(void)
21152115
if (!xen_domain())
21162116
return -ENODEV;
21172117

2118-
if (xen_hvm_domain() && !xen_platform_pci_unplug)
2118+
if (!xen_has_pv_nic_devices())
21192119
return -ENODEV;
21202120

21212121
pr_info("Initialising Xen virtual ethernet driver\n");

drivers/pci/xen-pcifront.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/workqueue.h>
2121
#include <linux/bitops.h>
2222
#include <linux/time.h>
23+
#include <xen/platform_pci.h>
2324

2425
#include <asm/xen/swiotlb-xen.h>
2526
#define INVALID_GRANT_REF (0)
@@ -1138,6 +1139,9 @@ static int __init pcifront_init(void)
11381139
if (!xen_pv_domain() || xen_initial_domain())
11391140
return -ENODEV;
11401141

1142+
if (!xen_has_pv_devices())
1143+
return -ENODEV;
1144+
11411145
pci_frontend_registrar(1 /* enable */);
11421146

11431147
return xenbus_register_frontend(&xenpci_driver);

drivers/video/xen-fbfront.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <xen/interface/io/fbif.h>
3636
#include <xen/interface/io/protocols.h>
3737
#include <xen/xenbus.h>
38+
#include <xen/platform_pci.h>
3839

3940
struct xenfb_info {
4041
unsigned char *fb;
@@ -699,6 +700,9 @@ static int __init xenfb_init(void)
699700
if (xen_initial_domain())
700701
return -ENODEV;
701702

703+
if (!xen_has_pv_devices())
704+
return -ENODEV;
705+
702706
return xenbus_register_frontend(&xenfb_driver);
703707
}
704708

drivers/xen/xenbus/xenbus_probe_frontend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ subsys_initcall(xenbus_probe_frontend_init);
496496
#ifndef MODULE
497497
static int __init boot_wait_for_devices(void)
498498
{
499-
if (xen_hvm_domain() && !xen_platform_pci_unplug)
499+
if (!xen_has_pv_devices())
500500
return -ENODEV;
501501

502502
ready_to_wait_for_devices = 1;

include/xen/platform_pci.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,27 @@ static inline int xen_must_unplug_disks(void) {
4848

4949
extern int xen_platform_pci_unplug;
5050

51+
#if defined(CONFIG_XEN_PVHVM)
52+
extern bool xen_has_pv_devices(void);
53+
extern bool xen_has_pv_disk_devices(void);
54+
extern bool xen_has_pv_nic_devices(void);
55+
extern bool xen_has_pv_and_legacy_disk_devices(void);
56+
#else
57+
static inline bool xen_has_pv_devices(void)
58+
{
59+
return IS_ENABLED(CONFIG_XEN);
60+
}
61+
static inline bool xen_has_pv_disk_devices(void)
62+
{
63+
return IS_ENABLED(CONFIG_XEN);
64+
}
65+
static inline bool xen_has_pv_nic_devices(void)
66+
{
67+
return IS_ENABLED(CONFIG_XEN);
68+
}
69+
static inline bool xen_has_pv_and_legacy_disk_devices(void)
70+
{
71+
return false;
72+
}
73+
#endif
5174
#endif /* _XEN_PLATFORM_PCI_H */

0 commit comments

Comments
 (0)