Skip to content

Commit

Permalink
x86/paravirt: Prevent rtc_cmos platform device init on PV guests
Browse files Browse the repository at this point in the history
Adding the rtc platform device in non-privileged Xen PV guests causes
an IRQ conflict because these guests do not have legacy PIC and may
allocate irqs in the legacy range.

In a single VCPU Xen PV guest we should have:

/proc/interrupts:
           CPU0
  0:       4934  xen-percpu-virq      timer0
  1:          0  xen-percpu-ipi       spinlock0
  2:          0  xen-percpu-ipi       resched0
  3:          0  xen-percpu-ipi       callfunc0
  4:          0  xen-percpu-virq      debug0
  5:          0  xen-percpu-ipi       callfuncsingle0
  6:          0  xen-percpu-ipi       irqwork0
  7:        321   xen-dyn-event     xenbus
  8:         90   xen-dyn-event     hvc_console
  ...

But hvc_console cannot get its interrupt because it is already in use
by rtc0 and the console does not work.

  genirq: Flags mismatch irq 8. 00000000 (hvc_console) vs. 00000000 (rtc0)

We can avoid this problem by realizing that unprivileged PV guests (both
Xen and lguests) are not supposed to have rtc_cmos device and so
adding it is not necessary.

Privileged guests (i.e. Xen's dom0) do use it but they should not have
irq conflicts since they allocate irqs above legacy range (above
gsi_top, in fact).

Instead of explicitly testing whether the guest is privileged we can
extend pv_info structure to include information about guest's RTC
support.

Reported-and-tested-by: Sander Eikelenboom <linux@eikelenboom.it>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: vkuznets@redhat.com
Cc: xen-devel@lists.xenproject.org
Cc: konrad.wilk@oracle.com
Cc: stable@vger.kernel.org # 4.2+
Link: http://lkml.kernel.org/r/1449842873-2613-1-git-send-email-boris.ostrovsky@oracle.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
David Vrabel authored and Thomas Gleixner committed Dec 19, 2015
1 parent 91e2eea commit d8c98a1
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 1 deletion.
6 changes: 6 additions & 0 deletions arch/x86/include/asm/paravirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ static inline int paravirt_enabled(void)
return pv_info.paravirt_enabled;
}

static inline int paravirt_has_feature(unsigned int feature)
{
WARN_ON_ONCE(!pv_info.paravirt_enabled);
return (pv_info.features & feature);
}

static inline void load_sp0(struct tss_struct *tss,
struct thread_struct *thread)
{
Expand Down
5 changes: 5 additions & 0 deletions arch/x86/include/asm/paravirt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,14 @@ struct pv_info {
#endif

int paravirt_enabled;
unsigned int features; /* valid only if paravirt_enabled is set */
const char *name;
};

#define paravirt_has(x) paravirt_has_feature(PV_SUPPORTED_##x)
/* Supported features */
#define PV_SUPPORTED_RTC (1<<0)

struct pv_init_ops {
/*
* Patch may replace one of the defined code sequences with
Expand Down
1 change: 1 addition & 0 deletions arch/x86/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ static inline unsigned long current_top_of_stack(void)
#else
#define __cpuid native_cpuid
#define paravirt_enabled() 0
#define paravirt_has(x) 0

static inline void load_sp0(struct tss_struct *tss,
struct thread_struct *thread)
Expand Down
3 changes: 3 additions & 0 deletions arch/x86/kernel/rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ static __init int add_rtc_cmos(void)
}
#endif

if (paravirt_enabled() && !paravirt_has(RTC))
return -ENODEV;

platform_device_register(&rtc_device);
dev_info(&rtc_device.dev,
"registered platform RTC device (no PNP device found)\n");
Expand Down
1 change: 1 addition & 0 deletions arch/x86/lguest/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,7 @@ __init void lguest_init(void)
pv_info.kernel_rpl = 1;
/* Everyone except Xen runs with this set. */
pv_info.shared_kernel_pmd = 1;
pv_info.features = 0;

/*
* We set up all the lguest overrides for sensitive operations. These
Expand Down
4 changes: 3 additions & 1 deletion arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,7 @@ static const struct pv_info xen_info __initconst = {
#ifdef CONFIG_X86_64
.extra_user_64bit_cs = FLAT_USER_CS64,
#endif

.features = 0,
.name = "Xen",
};

Expand Down Expand Up @@ -1535,6 +1535,8 @@ asmlinkage __visible void __init xen_start_kernel(void)

/* Install Xen paravirt ops */
pv_info = xen_info;
if (xen_initial_domain())
pv_info.features |= PV_SUPPORTED_RTC;
pv_init_ops = xen_init_ops;
pv_apic_ops = xen_apic_ops;
if (!xen_pvh_domain()) {
Expand Down

0 comments on commit d8c98a1

Please sign in to comment.