ia64/xen-unstable

changeset 8563:0ffd94a02318

Pass NMIs to DOM0 via a dedicated callback, Xen/Linux x86_64 support.

Register our NMI handler with Xen. Do an iret via the hypervisor
whenever the return CS is > RING0.

Add include/asm-xen/asm-x86_64/nmi.h as a Xen modified copy of
include/asm-x86_64/nmi.h in order that we can implement
get_nmi_reason() in a manner suitable for Xen.

Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
author Ian.Campbell@xensource.com
date Wed Jan 11 15:53:59 2006 +0000 (2006-01-11)
parents 278e536ade72
children 1c70b9d81731 cc996a91af71
files linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S linux-2.6-xen-sparse/arch/xen/x86_64/kernel/setup.c linux-2.6-xen-sparse/arch/xen/x86_64/kernel/traps.c linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/nmi.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S	Wed Jan 11 15:52:54 2006 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/entry.S	Wed Jan 11 15:53:59 2006 +0000
     1.3 @@ -121,19 +121,19 @@
     1.4  	.endm
     1.5  
     1.6          /*
     1.7 -         * Must be consistent with the definition in arch_x86_64.h:    
     1.8 -         *     struct switch_to_user {
     1.9 +         * Must be consistent with the definition in arch-x86_64.h:    
    1.10 +         *     struct iret_context {
    1.11           *        u64 rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
    1.12           *     };
    1.13           * #define VGCF_IN_SYSCALL (1<<8) 
    1.14           */
    1.15 -        .macro SWITCH_TO_USER flag
    1.16 +        .macro HYPERVISOR_IRET flag
    1.17          subq $8*4,%rsp                   # reuse rip, cs, rflags, rsp, ss in the stack
    1.18          movq %rax,(%rsp)
    1.19          movq %r11,1*8(%rsp)
    1.20          movq %rcx,2*8(%rsp)              # we saved %rcx upon exceptions
    1.21          movq $\flag,3*8(%rsp)
    1.22 -        movq $__HYPERVISOR_switch_to_user,%rax
    1.23 +        movq $__HYPERVISOR_iret,%rax
    1.24          syscall
    1.25          .endm
    1.26  
    1.27 @@ -225,7 +225,7 @@ sysret_check:
    1.28  	jnz  sysret_careful 
    1.29          XEN_UNBLOCK_EVENTS(%rsi)                
    1.30  	RESTORE_ARGS 0,8,0
    1.31 -        SWITCH_TO_USER VGCF_IN_SYSCALL
    1.32 +        HYPERVISOR_IRET VGCF_IN_SYSCALL
    1.33  
    1.34  	/* Handle reschedules */
    1.35  	/* edx:	work, edi: workmask */	
    1.36 @@ -478,7 +478,7 @@ kernel_mode:
    1.37          orb   $3,1*8(%rsp)
    1.38  	iretq
    1.39  user_mode:
    1.40 -	SWITCH_TO_USER 0                        
    1.41 +	HYPERVISOR_IRET 0
    1.42  	
    1.43  	/* edi: workmask, edx: work */	
    1.44  retint_careful:
    1.45 @@ -719,6 +719,16 @@ 11:	movb $0, EVENT_MASK(%rsp)
    1.46  	call evtchn_do_upcall
    1.47          jmp  error_exit
    1.48  
    1.49 +ENTRY(nmi)
    1.50 +	zeroentry do_nmi_callback
    1.51 +ENTRY(do_nmi_callback)
    1.52 +        addq $8, %rsp
    1.53 +        call do_nmi
    1.54 +        RESTORE_REST
    1.55 +        XEN_BLOCK_EVENTS(%rsi)
    1.56 +        GET_THREAD_INFO(%rcx)
    1.57 +        jmp  retint_restore_args
    1.58 +
    1.59          ALIGN
    1.60  restore_all_enable_events:  
    1.61  	XEN_UNBLOCK_EVENTS(%rsi)        # %rsi is already set up...
    1.62 @@ -733,7 +743,7 @@ scrit:	/**** START OF CRITICAL REGION **
    1.63          orb   $3,1*8(%rsp)
    1.64          iretq
    1.65  crit_user_mode:
    1.66 -        SWITCH_TO_USER 0
    1.67 +        HYPERVISOR_IRET 0
    1.68          
    1.69  14:	XEN_LOCKED_BLOCK_EVENTS(%rsi)
    1.70  	XEN_PUT_VCPU_INFO(%rsi)
     2.1 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/setup.c	Wed Jan 11 15:52:54 2006 +0000
     2.2 +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/setup.c	Wed Jan 11 15:53:59 2006 +0000
     2.3 @@ -62,6 +62,7 @@
     2.4  #include <asm-xen/xen-public/physdev.h>
     2.5  #include "setup_arch_pre.h"
     2.6  #include <asm/hypervisor.h>
     2.7 +#include <asm-xen/xen-public/nmi.h>
     2.8  #define PFN_UP(x)       (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
     2.9  #define PFN_PHYS(x)     ((x) << PAGE_SHIFT)
    2.10  #define end_pfn_map end_pfn
     3.1 --- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/traps.c	Wed Jan 11 15:52:54 2006 +0000
     3.2 +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/traps.c	Wed Jan 11 15:53:59 2006 +0000
     3.3 @@ -559,9 +559,11 @@ static void mem_parity_error(unsigned ch
     3.4  	printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
     3.5  	printk("You probably have a hardware problem with your RAM chips\n");
     3.6  
     3.7 +#if 0 /* XEN */
     3.8  	/* Clear and disable the memory parity error line. */
     3.9  	reason = (reason & 0xf) | 4;
    3.10  	outb(reason, 0x61);
    3.11 +#endif /* XEN */
    3.12  }
    3.13  
    3.14  static void io_check_error(unsigned char reason, struct pt_regs * regs)
    3.15 @@ -569,12 +571,14 @@ static void io_check_error(unsigned char
    3.16  	printk("NMI: IOCK error (debug interrupt?)\n");
    3.17  	show_registers(regs);
    3.18  
    3.19 +#if 0 /* XEN */
    3.20  	/* Re-enable the IOCK line, wait for a few seconds */
    3.21  	reason = (reason & 0xf) | 8;
    3.22  	outb(reason, 0x61);
    3.23  	mdelay(2000);
    3.24  	reason &= ~8;
    3.25  	outb(reason, 0x61);
    3.26 +#endif /* XEN */
    3.27  }
    3.28  
    3.29  static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
     4.1 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h	Wed Jan 11 15:52:54 2006 +0000
     4.2 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h	Wed Jan 11 15:53:59 2006 +0000
     4.3 @@ -287,9 +287,9 @@ HYPERVISOR_vcpu_op(
     4.4  }
     4.5  
     4.6  static inline int
     4.7 -HYPERVISOR_switch_to_user(void)
     4.8 +HYPERVISOR_iret(void)
     4.9  {
    4.10 -	return _hypercall0(int, switch_to_user);
    4.11 +	return _hypercall0(int, iret);
    4.12  }
    4.13  
    4.14  static inline int
    4.15 @@ -307,6 +307,14 @@ HYPERVISOR_suspend(
    4.16  			   SHUTDOWN_suspend, srec);
    4.17  }
    4.18  
    4.19 +static inline int
    4.20 +HYPERVISOR_nmi_op(
    4.21 +	unsigned long op,
    4.22 +	unsigned long arg)
    4.23 +{
    4.24 +	return _hypercall2(int, nmi_op, op, arg);
    4.25 +}
    4.26 +
    4.27  #endif /* __HYPERCALL_H__ */
    4.28  
    4.29  /*
     5.1 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h	Wed Jan 11 15:52:54 2006 +0000
     5.2 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/setup_arch_post.h	Wed Jan 11 15:53:59 2006 +0000
     5.3 @@ -35,6 +35,7 @@ void __init machine_specific_modify_cpu_
     5.4  
     5.5  extern void hypervisor_callback(void);
     5.6  extern void failsafe_callback(void);
     5.7 +extern void nmi(void);
     5.8  
     5.9  static void __init machine_specific_arch_setup(void)
    5.10  {
    5.11 @@ -43,5 +44,7 @@ static void __init machine_specific_arch
    5.12                  (unsigned long) failsafe_callback,
    5.13                  (unsigned long) system_call);
    5.14  
    5.15 +	HYPERVISOR_nmi_op(XENNMI_register_callback, (unsigned long)&nmi);
    5.16 +
    5.17  	machine_specific_modify_cpu_capabilities(&boot_cpu_data);
    5.18  }
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/nmi.h	Wed Jan 11 15:53:59 2006 +0000
     6.3 @@ -0,0 +1,75 @@
     6.4 +/*
     6.5 + *  linux/include/asm-i386/nmi.h
     6.6 + */
     6.7 +#ifndef ASM_NMI_H
     6.8 +#define ASM_NMI_H
     6.9 +
    6.10 +#include <linux/pm.h>
    6.11 +
    6.12 +#include <asm-xen/xen-public/nmi.h>
    6.13 +
    6.14 +struct pt_regs;
    6.15 + 
    6.16 +typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
    6.17 + 
    6.18 +/** 
    6.19 + * set_nmi_callback
    6.20 + *
    6.21 + * Set a handler for an NMI. Only one handler may be
    6.22 + * set. Return 1 if the NMI was handled.
    6.23 + */
    6.24 +void set_nmi_callback(nmi_callback_t callback);
    6.25 + 
    6.26 +/** 
    6.27 + * unset_nmi_callback
    6.28 + *
    6.29 + * Remove the handler previously set.
    6.30 + */
    6.31 +void unset_nmi_callback(void);
    6.32 + 
    6.33 +#ifdef CONFIG_PM
    6.34 + 
    6.35 +/** Replace the PM callback routine for NMI. */
    6.36 +struct pm_dev * set_nmi_pm_callback(pm_callback callback);
    6.37 +
    6.38 +/** Unset the PM callback routine back to the default. */
    6.39 +void unset_nmi_pm_callback(struct pm_dev * dev);
    6.40 +
    6.41 +#else
    6.42 +
    6.43 +static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback)
    6.44 +{
    6.45 +	return 0;
    6.46 +} 
    6.47 + 
    6.48 +static inline void unset_nmi_pm_callback(struct pm_dev * dev)
    6.49 +{
    6.50 +}
    6.51 +
    6.52 +#endif /* CONFIG_PM */
    6.53 + 
    6.54 +extern void default_do_nmi(struct pt_regs *);
    6.55 +extern void die_nmi(char *str, struct pt_regs *regs);
    6.56 +
    6.57 +static inline unsigned char get_nmi_reason(void)
    6.58 +{
    6.59 +        shared_info_t *s = HYPERVISOR_shared_info;
    6.60 +        unsigned char reason = 0;
    6.61 +
    6.62 +        /* construct a value which looks like it came from
    6.63 +         * port 0x61.
    6.64 +         */
    6.65 +        if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason))
    6.66 +                reason |= 0x40;
    6.67 +        if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason))
    6.68 +                reason |= 0x80;
    6.69 +
    6.70 +        return reason;
    6.71 +}
    6.72 +
    6.73 +extern int panic_on_timeout;
    6.74 +extern int unknown_nmi_panic;
    6.75 +
    6.76 +extern int check_nmi_watchdog(void);
    6.77 + 
    6.78 +#endif /* ASM_NMI_H */