Skip to content

Commit

Permalink
xen: Support 64-bit PV guest receiving NMIs
Browse files Browse the repository at this point in the history
This is based on a patch that Zhenzhong Duan had sent - which
was missing some of the remaining pieces. The kernel has the
logic to handle Xen-type-exceptions using the paravirt interface
in the assembler code (see PARAVIRT_ADJUST_EXCEPTION_FRAME -
pv_irq_ops.adjust_exception_frame and and INTERRUPT_RETURN -
pv_cpu_ops.iret).

That means the nmi handler (and other exception handlers) use
the hypervisor iret.

The other changes that would be neccessary for this would
be to translate the NMI_VECTOR to one of the entries on the
ipi_vector and make xen_send_IPI_mask_allbutself use different
events.

Fortunately for us commit 1db01b4
(xen: Clean up apic ipi interface) implemented this and we piggyback
on the cleanup such that the apic IPI interface will pass the right
vector value for NMI.

With this patch we can trigger NMIs within a PV guest (only tested
x86_64).

For this to work with normal PV guests (not initial domain)
we need the domain to be able to use the APIC ops - they are
already implemented to use the Xen event channels. For that
to be turned on in a PV domU we need to remove the masking
of X86_FEATURE_APIC.

Incidentally that means kgdb will also now work within
a PV guest without using the 'nokgdbroundup' workaround.

Note that the 32-bit version is different and this patch
does not enable that.

CC: Lisa Nguyen <lisa@xenapiadmin.com>
CC: Ben Guthro <benjamin.guthro@citrix.com>
CC: Zhenzhong Duan <zhenzhong.duan@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
[v1: Fixed up per David Vrabel comments]
Reviewed-by: Ben Guthro <benjamin.guthro@citrix.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
  • Loading branch information
Konrad Rzeszutek Wilk authored and Konrad Rzeszutek Wilk committed Aug 9, 2013
1 parent c095ba7 commit 6efa20e
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 8 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/asm/xen/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum ipi_vector {
XEN_CALL_FUNCTION_SINGLE_VECTOR,
XEN_SPIN_UNLOCK_VECTOR,
XEN_IRQ_WORK_VECTOR,
XEN_NMI_VECTOR,

XEN_NR_IPIS,
};
Expand Down
13 changes: 8 additions & 5 deletions arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,7 @@ static void __init xen_init_cpuid_mask(void)

if (!xen_initial_domain())
cpuid_leaf1_edx_mask &=
~((1 << X86_FEATURE_APIC) | /* disable local APIC */
(1 << X86_FEATURE_ACPI)); /* disable ACPI */
~((1 << X86_FEATURE_ACPI)); /* disable ACPI */

cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_X2APIC % 32));

Expand Down Expand Up @@ -735,8 +734,7 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
addr = (unsigned long)xen_int3;
else if (addr == (unsigned long)stack_segment)
addr = (unsigned long)xen_stack_segment;
else if (addr == (unsigned long)double_fault ||
addr == (unsigned long)nmi) {
else if (addr == (unsigned long)double_fault) {
/* Don't need to handle these */
return 0;
#ifdef CONFIG_X86_MCE
Expand All @@ -747,7 +745,12 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val,
*/
;
#endif
} else {
} else if (addr == (unsigned long)nmi)
/*
* Use the native version as well.
*/
;
else {
/* Some other trap using IST? */
if (WARN_ON(val->ist != 0))
return 0;
Expand Down
13 changes: 11 additions & 2 deletions arch/x86/xen/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
/* These are code, but not functions. Defined in entry.S */
extern const char xen_hypervisor_callback[];
extern const char xen_failsafe_callback[];
#ifdef CONFIG_X86_64
extern const char nmi[];
#endif
extern void xen_sysenter_target(void);
extern void xen_syscall_target(void);
extern void xen_syscall32_target(void);
Expand Down Expand Up @@ -525,7 +528,13 @@ void xen_enable_syscall(void)
}
#endif /* CONFIG_X86_64 */
}

void __cpuinit xen_enable_nmi(void)
{
#ifdef CONFIG_X86_64
if (register_callback(CALLBACKTYPE_nmi, nmi))
BUG();
#endif
}
void __init xen_arch_setup(void)
{
xen_panic_handler_init();
Expand All @@ -543,7 +552,7 @@ void __init xen_arch_setup(void)

xen_enable_sysenter();
xen_enable_syscall();

xen_enable_nmi();
#ifdef CONFIG_ACPI
if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/xen/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,12 @@ static inline int xen_map_vector(int vector)
case IRQ_WORK_VECTOR:
xen_vector = XEN_IRQ_WORK_VECTOR;
break;
#ifdef CONFIG_X86_64
case NMI_VECTOR:
case APIC_DM_NMI: /* Some use that instead of NMI_VECTOR */
xen_vector = XEN_NMI_VECTOR;
break;
#endif
default:
xen_vector = -1;
printk(KERN_ERR "xen: vector 0x%x is not implemented\n",
Expand Down
11 changes: 10 additions & 1 deletion drivers/xen/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include <xen/interface/hvm/params.h>
#include <xen/interface/physdev.h>
#include <xen/interface/sched.h>
#include <xen/interface/vcpu.h>
#include <asm/hw_irq.h>

/*
Expand Down Expand Up @@ -1212,7 +1213,15 @@ EXPORT_SYMBOL_GPL(evtchn_put);

void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
{
int irq = per_cpu(ipi_to_irq, cpu)[vector];
int irq;

if (unlikely(vector == XEN_NMI_VECTOR)) {
int rc = HYPERVISOR_vcpu_op(VCPUOP_send_nmi, cpu, NULL);
if (rc < 0)
printk(KERN_WARNING "Sending nmi to CPU%d failed (rc:%d)\n", cpu, rc);
return;
}
irq = per_cpu(ipi_to_irq, cpu)[vector];
BUG_ON(irq < 0);
notify_remote_via_irq(irq);
}
Expand Down
2 changes: 2 additions & 0 deletions include/xen/interface/vcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,6 @@ struct vcpu_register_vcpu_info {
};
DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_vcpu_info);

/* Send an NMI to the specified VCPU. @extra_arg == NULL. */
#define VCPUOP_send_nmi 11
#endif /* __XEN_PUBLIC_VCPU_H__ */

0 comments on commit 6efa20e

Please sign in to comment.