Machine Check Support
PATCH 2/2 Machine Check Support
Hi,
This patch introduces machine check support as described in the pdf.
Signed-off-by Christoph Egger <[email protected]>
Signature · 12 lines
AMD Saxony, Dresden, Germany Operating System Research Center Legal Information: AMD Saxony Limited Liability Company & Co. KG Sitz (Geschäftsanschrift): Wilschdorfer Landstr. 101, 01109 Dresden, Deutschland Registergericht Dresden: HRA 4896 vertretungsberechtigter Komplementär: AMD Saxony LLC (Sitz Wilmington, Delaware, USA) Geschäftsführer der AMD Saxony LLC: Dr. Hans-R. Deppe, Thomas McCoy
xen/arch/x86/cpu/mcheck/Makefile +3 -0
@@ -1,4 +1,7 @@ obj-y += k7.o +obj-y += amd_nonfatal.o obj-y += k7.o +obj-y += amd_k8.o +obj-y += amd_f10.o obj-y += mce.o obj-y += non-fatal.o obj-y += p4.o
xen/arch/x86/cpu/mcheck/amd_f10.c new file +131 -0
131 lines not on this page · raw message
xen/arch/x86/cpu/mcheck/amd_k8.c new file +324 -0
324 lines not on this page · raw message
xen/arch/x86/cpu/mcheck/amd_nonfatal.c new file +303 -0
303 lines not on this page · raw message
xen/arch/x86/cpu/mcheck/k7.c +3 -4
@@ -66,8 +66,8 @@ static fastcall void k7_machine_check(st } -/* AMD K7 machine check is Intel like */ -void amd_mcheck_init (struct cpuinfo_x86 *c) +/* AMD K7 machine check */ +void amd_k7_mcheck_init (struct cpuinfo_x86 *c) {u32 l, h;int i;
@@ -75,7 +75,6 @@ void amd_mcheck_init(struct cpuinfo_x86 machine_check_vector = k7_machine_check;wmb (); -printk (KERN_INFO "Intel machine check architecture supported.\n" );rdmsr (MSR_IA32_MCG_CAP , l, h);if (l & (1 <<8 ))/* Control register present ? */ wrmsr (MSR_IA32_MCG_CTL ,0xffffffff ,0xffffffff );
@@ -90,6 +89,6 @@ void amd_mcheck_init(struct cpuinfo_x86 }set_in_cr4 (X86_CR4_MCE ); -printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n" , +printk (KERN_INFO "CPU%d: AMD K7 machine check reporting enabled.\n" ,smp_processor_id ()); }
xen/arch/x86/cpu/mcheck/mce.c +521 -35
597 lines not on this page · raw message
xen/arch/x86/cpu/mcheck/mce.h +21 -5
@@ -1,14 +1,30 @@#include <xen/init.h> +#include <asm/traps.h> -void amd_mcheck_init (struct cpuinfo_x86 *c); +/* Init functions */ +void amd_nonfatal_mcheck_init (struct cpuinfo_x86 *c); +void amd_k7_mcheck_init (struct cpuinfo_x86 *c); +void amd_k8_mcheck_init (struct cpuinfo_x86 *c); +void amd_f10_mcheck_init (struct cpuinfo_x86 *c);void intel_p4_mcheck_init (struct cpuinfo_x86 *c);void intel_p5_mcheck_init (struct cpuinfo_x86 *c);void intel_p6_mcheck_init (struct cpuinfo_x86 *c);void winchip_mcheck_init (struct cpuinfo_x86 *c); -/* Call the installed machine check handler for this CPU setup. */ -extern fastcall void (*machine_check_vector)(struct cpu_user_regs *, long error_code); +/* Function pointer used in the handlers to collect additional information +* provided by newer CPU families/models without the need to duplicate +* the whole handler resulting in various handlers each with its own +* tweaks and bugs */ +extern int (*mc_callback_bank_extended)(struct mc_info *mi, +uint16_t bank,uint64_t status); + +/* Helper functions used for collecting error telemetry */ +struct mc_info *x86_mcinfo_getptr (void ); +void x86_mcinfo_clear (struct mc_info *mi); +int x86_mcinfo_add (struct mc_info *mi,void *mcinfo); +void x86_mcinfo_dump (struct mc_info *mi); + +/* Global variables */ extern int mce_disabled__initdata ; -extern int nr_mce_banks; - +extern unsigned int nr_mce_banks;
xen/arch/x86/cpu/mcheck/non-fatal.c +20 -10
@@ -68,19 +68,29 @@ static int __init init_nonfatal_mce_checif (!cpu_has (c,X86_FEATURE_MCA ))return -ENODEV ; -/* Some Athlons misbehave when we frob bank 0 */ -if (boot_cpu_data.x86_vendor ==X86_VENDOR_AMD && - boot_cpu_data.x86 ==6 ) - firstbank =1 ; -else - firstbank =0 ; -/* * Check for non-fatal errors every MCE_RATE s */ -init_timer (&mce_timer, mce_work_fn,NULL ,0 ); -set_timer (&mce_timer,NOW () +MCE_PERIOD ); -printk (KERN_INFO "Machine check exception polling timer started.\n" ); +switch (c->x86_vendor) { +case X86_VENDOR_AMD : +if (c->x86 ==6 ) {/* K7 */ + firstbank =1 ; +init_timer (&mce_timer, mce_work_fn,NULL ,0 ); +set_timer (&mce_timer,NOW () +MCE_PERIOD ); +break ; + } + +/* Assume we are on K8 or newer AMD CPU here */ +amd_nonfatal_mcheck_init (c); +break ; + +case X86_VENDOR_INTEL : +init_timer (&mce_timer, mce_work_fn,NULL ,0 ); +set_timer (&mce_timer,NOW () +MCE_PERIOD ); +break ; + } + +printk (KERN_INFO "MCA: Machine check polling timer started.\n" );return 0 ; }__initcall (init_nonfatal_mce_checker);
xen/arch/x86/cpu/mcheck/x86_mca.h new file +72 -0
72 lines not on this page · raw message
xen/arch/x86/nmi.c +2 -2
@@ -457,10 +457,10 @@ static void do_nmi_stats(unsigned char kif ( ((d = dom0) ==NULL ) || ((v = d->vcpu[0 ]) ==NULL ) )return ; -if ( v->nmi_pending || v->nmi_masked ) +if ( v->nmi_pending || (v->trap_priority >=VCPU_TRAP_NMI ) )printk ("dom0 vpu0: NMI %s%s\n" , v->nmi_pending ?"pending " :"" , - v->nmi_masked ?"masked " :"" ); + (v->trap_priority >=VCPU_TRAP_NMI ) ?"masked " :"" );else printk ("dom0 vcpu0: NMI neither pending nor masked\n" ); }
xen/arch/x86/traps.c +49 -2
75 lines not on this page · raw message
xen/arch/x86/x86_32/asm-offsets.c +5 -1
@@ -67,7 +67,11 @@ void __dummy__(void) arch.guest_context.kernel_sp); OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags); OFFSET(VCPU_nmi_pending, struct vcpu, nmi_pending); - OFFSET(VCPU_nmi_masked, struct vcpu, nmi_masked); + OFFSET(VCPU_mce_pending, struct vcpu, mce_pending); + OFFSET(VCPU_old_trap_priority, struct vcpu, old_trap_priority); + OFFSET(VCPU_trap_priority, struct vcpu, trap_priority); +DEFINE (VCPU_TRAP_NMI ,VCPU_TRAP_NMI ); +DEFINE (VCPU_TRAP_MCE ,VCPU_TRAP_MCE );DEFINE (_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events);BLANK ();
xen/arch/x86/x86_32/entry.S +33 -3
@@ -229,6 +229,8 @@ test_all_events: shl $IRQSTAT_shift,%eax test %ecx,irq_stat(%eax,1) jnz process_softirqs + testb $1,VCPU_mce_pending(%ebx) + jnz process_mce testb $1,VCPU_nmi_pending(%ebx) jnz process_nmi test_guest_events:
@@ -255,15 +257,35 @@ process_softirqs: jmp test_all_events ALIGN +/* %ebx: struct vcpu */ +process_mce: + cmpw $VCPU_TRAP_MCE,VCPU_trap_priority(%ebx) + jae test_guest_events + sti + movb $0,VCPU_mce_pending(%ebx) + call set_guest_machinecheck_trapbounce + test %eax,%eax + jz test_all_events + movw VCPU_trap_priority(%ebx),%dx # safe priority for the + movw %dx,VCPU_old_trap_priority(%ebx) # iret hypercall + movw $VCPU_TRAP_MCE,VCPU_trap_priority(%ebx) + jmp process_trap + + ALIGN +/* %ebx: struct vcpu */ process_nmi: - testb $1,VCPU_nmi_masked(%ebx) - jnz test_guest_events + cmpw $VCPU_TRAP_NMI,VCPU_trap_priority(%ebx) + jae test_guest_events sti movb $0,VCPU_nmi_pending(%ebx) call set_guest_nmi_trapbounce test %eax,%eax jz test_all_events - movb $1,VCPU_nmi_masked(%ebx) + movw VCPU_trap_priority(%ebx),%dx # safe priority for the + movw %dx,VCPU_old_trap_priority(%ebx) # iret hypercall + movw $VCPU_TRAP_NMI,VCPU_trap_priority(%ebx) + /* FALLTHROUGH */ +process_trap: leal VCPU_trap_bounce(%ebx),%edx call create_bounce_frame jmp test_all_events
@@ -681,6 +703,10 @@ ENTRY(hypercall_table) .long do_sysctl /* 35 */ .long do_domctl .long do_kexec_op + .rept __HYPERVISOR_arch_0-((.-hypercall_table)/4) + .long do_ni_hypercall + .endr + .long do_mca /* 48 */ .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr
@@ -724,6 +750,10 @@ ENTRY(hypercall_args_table) .byte 1 /* do_sysctl */ /* 35 */ .byte 1 /* do_domctl */ .byte 2 /* do_kexec_op */ + .rept __HYPERVISOR_arch_0-(.-hypercall_args_table) + .byte 0 /* do_ni_hypercall */ + .endr + .byte 1 /* do_mca */ /* 48 */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr
xen/arch/x86/x86_32/traps.c +2 -2
@@ -259,8 +259,8 @@ unsigned long do_iret(void)if (!cpus_equal (v->cpu_affinity_tmp, v->cpu_affinity))vcpu_set_affinity (v, &v->cpu_affinity_tmp); -/* No longer in NMI context. */ - v->nmi_masked =0 ; +/* Restore previous trap priority */ + v->trap_priority = v->old_trap_priority;/* Restore upcall mask from supplied EFLAGS.IF. */ vcpu_info (v, evtchn_upcall_mask) = !(eflags &X86_EFLAGS_IF );
xen/arch/x86/x86_64/asm-offsets.c +5 -1
@@ -92,7 +92,11 @@ void __dummy__(void) OFFSET(VCPU_kernel_ss, struct vcpu, arch.guest_context.kernel_ss); OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags); OFFSET(VCPU_nmi_pending, struct vcpu, nmi_pending); - OFFSET(VCPU_nmi_masked, struct vcpu, nmi_masked); + OFFSET(VCPU_mce_pending, struct vcpu, mce_pending); + OFFSET(VCPU_old_trap_priority, struct vcpu, old_trap_priority); + OFFSET(VCPU_trap_priority, struct vcpu, trap_priority); +DEFINE (VCPU_TRAP_NMI ,VCPU_TRAP_NMI ); +DEFINE (VCPU_TRAP_MCE ,VCPU_TRAP_MCE );DEFINE (_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events);DEFINE (_VGCF_syscall_disables_events, _VGCF_syscall_disables_events);BLANK ();
xen/arch/x86/x86_64/compat/entry.S +32 -3
@@ -101,6 +101,8 @@ ENTRY(compat_test_all_events) leaq irq_stat(%rip),%rcx testl $~0,(%rcx,%rax,1) jnz compat_process_softirqs + testb $1,VCPU_mce_pending(%rbx) + jnz compat_process_mce testb $1,VCPU_nmi_pending(%rbx) jnz compat_process_nmi compat_test_guest_events:
@@ -129,15 +131,34 @@ compat_process_softirqs: ALIGN /* %rbx: struct vcpu */ +compat_process_mce: + cmpw $VCPU_TRAP_MCE,VCPU_trap_priority(%rbx) + jae compat_test_guest_events + sti + movb $0,VCPU_mce_pending(%rbx) + call set_guest_machinecheck_trapbounce + testl %eax,%eax + jz compat_test_all_events + movw VCPU_trap_priority(%rbx),%dx # safe priority for the + movw %dx,VCPU_old_trap_priority(%rbx) # iret hypercall + movw $VCPU_TRAP_MCE,VCPU_trap_priority(%rbx) + jmp compat_process_trap + + ALIGN +/* %rbx: struct vcpu */ compat_process_nmi: - testb $1,VCPU_nmi_masked(%rbx) - jnz compat_test_guest_events + cmpw $VCPU_TRAP_NMI,VCPU_trap_priority(%rbx) + jae compat_test_guest_events sti movb $0,VCPU_nmi_pending(%rbx) call set_guest_nmi_trapbounce testl %eax,%eax jz compat_test_all_events - movb $1,VCPU_nmi_masked(%rbx) + movw VCPU_trap_priority(%rbx),%dx # safe priority for the + movw %dx,VCPU_old_trap_priority(%rbx) # iret hypercall + movw $VCPU_TRAP_NMI,VCPU_trap_priority(%rbx) + /* FALLTHROUGH */ +compat_process_trap: leaq VCPU_trap_bounce(%rbx),%rdx call compat_create_bounce_frame jmp compat_test_all_events
@@ -386,6 +407,10 @@ ENTRY(compat_hypercall_table) .quad do_sysctl /* 35 */ .quad do_domctl .quad compat_kexec_op + .rept __HYPERVISOR_arch_0-((.-compat_hypercall_table)/8) + .quad compat_ni_hypercall + .endr + .quad do_mca /* 48 */ .rept NR_hypercalls-((.-compat_hypercall_table)/8) .quad compat_ni_hypercall .endr
@@ -429,6 +454,10 @@ ENTRY(compat_hypercall_args_table) .byte 1 /* do_sysctl */ /* 35 */ .byte 1 /* do_domctl */ .byte 2 /* compat_kexec_op */ + .rept __HYPERVISOR_arch_0-(.-compat_hypercall_args_table) + .byte 0 /* compat_ni_hypercall */ + .endr + .byte 1 /* do_mca */ .rept NR_hypercalls-(.-compat_hypercall_args_table) .byte 0 /* compat_ni_hypercall */ .endr
xen/arch/x86/x86_64/compat/traps.c +2 -2
@@ -125,8 +125,8 @@ unsigned int compat_iret(void)if (!cpus_equal (v->cpu_affinity_tmp, v->cpu_affinity))vcpu_set_affinity (v, &v->cpu_affinity_tmp); -/* No longer in NMI context. */ - v->nmi_masked =0 ; +/* Restore previous trap priority */ + v->trap_priority = v->old_trap_priority;/* Restore upcall mask from supplied EFLAGS.IF. */ vcpu_info (v, evtchn_upcall_mask) = !(eflags &X86_EFLAGS_IF );
xen/arch/x86/x86_64/entry.S +32 -3
@@ -205,6 +205,8 @@ test_all_events: leaq irq_stat(%rip),%rcx testl $~0,(%rcx,%rax,1) jnz process_softirqs + testb $1,VCPU_mce_pending(%rbx) + jnz process_mce testb $1,VCPU_nmi_pending(%rbx) jnz process_nmi test_guest_events:
@@ -231,15 +233,34 @@ process_softirqs: ALIGN /* %rbx: struct vcpu */ +process_mce: + cmpw $VCPU_TRAP_MCE,VCPU_trap_priority(%rbx) + jae test_guest_events + sti + movb $0,VCPU_mce_pending(%rbx) + call set_guest_machinecheck_trapbounce + test %eax,%eax + jz test_all_events + movw VCPU_trap_priority(%rbx),%dx # safe priority for the + movw %dx,VCPU_old_trap_priority(%rbx) # iret hypercall + movw $VCPU_TRAP_MCE,VCPU_trap_priority(%rbx) + jmp process_trap + + ALIGN +/* %rbx: struct vcpu */ process_nmi: - testb $1,VCPU_nmi_masked(%rbx) - jnz test_guest_events + cmpw $VCPU_TRAP_NMI,VCPU_trap_priority(%rbx) + jae test_guest_events sti movb $0,VCPU_nmi_pending(%rbx) call set_guest_nmi_trapbounce test %eax,%eax jz test_all_events - movb $1,VCPU_nmi_masked(%rbx) + movw VCPU_trap_priority(%rbx),%dx # safe priority for the + movw %dx,VCPU_old_trap_priority(%rbx) # iret hypercall + movw $VCPU_TRAP_NMI,VCPU_trap_priority(%rbx) + /* FALLTHROUGH */ +process_trap: leaq VCPU_trap_bounce(%rbx),%rdx call create_bounce_frame jmp test_all_events
@@ -671,6 +692,10 @@ ENTRY(hypercall_table) .quad do_sysctl /* 35 */ .quad do_domctl .quad do_kexec_op + .rept __HYPERVISOR_arch_0-((.-hypercall_table)/8) + .quad do_ni_hypercall + .endr + .quad do_mca /* 48 */ .rept NR_hypercalls-((.-hypercall_table)/8) .quad do_ni_hypercall .endr
@@ -715,6 +740,10 @@ ENTRY(hypercall_args_table) .byte 1 /* do_domctl */ .byte 2 /* do_kexec */ .byte 1 /* do_xsm_op */ + .rept __HYPERVISOR_arch_0-(.-hypercall_args_table) + .byte 0 /* do_ni_hypercall */ + .endr + .byte 1 /* do_mca */ /* 48 */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr
xen/arch/x86/x86_64/traps.c +2 -2
@@ -292,8 +292,8 @@ unsigned long do_iret(void)if (!cpus_equal (v->cpu_affinity_tmp, v->cpu_affinity))vcpu_set_affinity (v, &v->cpu_affinity_tmp); -/* No longer in NMI context. */ - v->nmi_masked =0 ; +/* Restore previous trap priority */ + v->trap_priority = v->old_trap_priority;/* Restore upcall mask from supplied EFLAGS.IF. */ vcpu_info (v, evtchn_upcall_mask) = !(iret_saved.rflags &EF_IE );
xen/common/domain.c +3 -1
@@ -651,7 +651,9 @@ void vcpu_reset(struct vcpu *v) v->is_polling =0 ; v->is_initialised =0 ; v->nmi_pending =0 ; - v->nmi_masked =0 ; + v->mce_pending =0 ; + v->old_trap_priority =VCPU_TRAP_NONE ; + v->trap_priority =VCPU_TRAP_NONE ;clear_bit (_VPF_blocked, &v->pause_flags);domain_unlock (v->domain);
xen/common/event_channel.c +15 -0
@@ -586,6 +586,21 @@ void send_guest_vcpu_virq(struct vcpu *vevtchn_set_pending (v, port); } +int guest_enabled_event (struct vcpu *v,int virq) +{ +int port; + +if (unlikely (v ==NULL ) ) +return 0 ; + + port = v->virq_to_evtchn[virq]; +if ( port ==0 ) +return 0 ; + +/* virq is in use */ +return 1 ; +} +void send_guest_global_virq (struct domain *d,int virq) {int port;
xen/include/Makefile +1 -0
@@ -20,6 +20,7 @@ headers-y := \ compat/xen.h \ compat/xencomm.h \ compat/xenoprof.h +headers-$(CONFIG_X86) += compat/arch-x86/xen-mca.h headers-$(CONFIG_X86) += compat/arch-x86/xen.h headers-$(CONFIG_X86) += compat/arch-x86/xen-$(compat-arch-y).h headers-y += compat/arch-$(compat-arch-y).h compat/xlat.h
xen/include/asm-x86/event.h +6 -1
@@ -69,7 +69,12 @@ static inline void local_event_delivery_/* No arch specific virq definition now. Default to global. */ static inline int arch_virq_is_global (int virq) { -return 1 ; +switch (virq) { +case VIRQ_MCA : +return 1 ; +default : +return 1 ; + } }#endif
xen/include/asm-x86/mm.h +3 -0
@@ -141,6 +141,9 @@ static inline u32 pickle_domptr(struct d#define page_get_owner (_p) (unpickle_domptr((_p)->u.inuse._domain))#define page_set_owner (_p,_d) ((_p)->u.inuse._domain = pickle_domptr(_d)) +#define maddr_get_owner (ma) (page_get_owner(maddr_to_page((ma)))) +#define vaddr_get_owner (va) (page_get_owner(virt_to_page((va)))) +#define XENSHARE_writable 0#define XENSHARE_readonly 1 extern void share_xen_page_with_guest(
xen/include/asm-x86/traps.h +12 -1
@@ -27,6 +27,18 @@ struct softirq_trap {int processor;/* physical cpu to inject trap */ }; +struct cpu_user_regs ; + +extern void (*machine_check_vector)(struct cpu_user_regs *regs,long error_code); + +/** +* guest_has_trap_callback +* +* returns true (non-zero) if guest registered a trap handler +*/ +extern int guest_has_trap_callback (struct domain *d,uint16_t vcpuid, +unsigned int trap_nr); +/** * send_guest_trap *
@@ -36,5 +48,4 @@ extern int send_guest_trap(struct domainextern int send_guest_trap (struct domain *d,uint16_t vcpuid,unsigned int trap_nr); -#endif /* ASM_TRAP_H */
xen/include/public/arch-x86/xen-mca.h new file +279 -0
279 lines not on this page · raw message
xen/include/public/arch-x86/xen.h +4 -0
@@ -76,6 +76,10 @@ typedef unsigned long xen_pfn_t;/* Maximum number of virtual CPUs in multi-processor guests. */ #define MAX_VIRT_CPUS 32 + +/* Machine check support */ +#include "xen-mca.h" +#ifndef __ASSEMBLY__typedef unsigned long xen_ulong_t ;
xen/include/xen/event.h +3 -0
@@ -51,6 +51,9 @@ void free_xen_event_channel(void free_xen_event_channel (struct vcpu *local_vcpu,int port); +/* Query if event channel is in use by the guest */ +int guest_enabled_event (struct vcpu *v,int virq); +/* Notify remote end of a Xen-attached event channel.*/ void notify_via_xen_event_channel (int lport);
xen/include/xen/sched.h +13 -2
@@ -112,10 +112,21 @@ struct vcpubool_t is_initialised;/* Currently running on a CPU? */ bool_t is_running; +/* MCE callback pending for this VCPU? */ +bool_t mce_pending;/* NMI callback pending for this VCPU? */ bool_t nmi_pending; -/* Avoid NMI reentry by allowing NMIs to be masked for short periods. */ -bool_t nmi_masked; + +/* Higher priorized traps may interrupt lower priorized traps, +* lower priorized traps wait until higher priorized traps finished. +* Note: This concept is known as "system priority level" (spl) +* in the UNIX world. */ +uint16_t old_trap_priority; +uint16_t trap_priority; +#define VCPU_TRAP_NONE 0 +#define VCPU_TRAP_NMI 1 +#define VCPU_TRAP_MCE 2 +/* Require shutdown to be deferred for some asynchronous operation? */ bool_t defer_shutdown;/* VCPU is paused following shutdown request (d->is_shutting_down)? */
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel