lkml.org 
[lkml]   [2004]   [May]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [PATCH] NMI trigger switch support for debugging
    Hi Andrew,

    Andrew Morton wrote:

    >AKIYAMA Nobuyuki <akiyama.nobuyuk@jp.fujitsu.com> wrote:
    >
    >
    >>Thank you for your comment.
    >> I remade my patch referring to your suggestion.
    >>
    >>
    >
    >OK. Now I've largely forgotten what your patch did and cannot proceed with
    >it unless it has a good changelog entry.
    >
    >Please maintain a full description of your patches and include that
    >description whenever reissuing the patch.
    >
    >And it needs to be reissued anyway, because your email client wordwrapped it.
    >
    >
    >
    >
    >

    Sorry, I resend document and patch.

    Regards,
    Nobuyuki Akiyama

    -----
    -Summary
    I made a patch for debugging with the help of NMI trigger switch.
    When kernel hangs severely, keyboard operation(e.g.Ctrl-Alt-Del)
    doesn't work properly. This patch enables debugging information
    to be displayed on console in this case.
    I think this feature is necessary as standard functionality.

    -Background
    When a trouble occurs in kernel, we usually begin to investigate
    with following information:
    - panic >> panic message.
    - oops >> CPU registers and stack trace.
    - hang >> **NONE** no standard method established.

    -How it works
    Most IA32 servers have a NMI switch that fires NMI interrupt up.
    The NMI interrupt can interrupt even if kernel is serious state,
    for example deadlock under the interrupt disabled.
    When the NMI switch is pressed after this feature is activated,
    CPU registers and stack trace are displayed on console and then
    panic occurs.
    This feature is activated or deactivated with sysctl.

    On IA32 architecture, only the following are defined as reason
    of NMI interrupt:
    - memory parity error
    - I/O check error
    The reason code of NMI switch is not defined, so this patch assumes
    that all undefined NMI interrupts are fired by MNI switch.
    However, oprofile and NMI watchdog also use undefined NMI interrupt.
    Therefore this feature cannot be used at the same time with oprofile
    and NMI watchdog. This feature hands NMI interrupt over to oprofile
    and NMI watchdog. So, when they have been activated, this feature
    doesn't work even if it is activated.

    -Support architecture
    IA32

    -Setup
    Set up the system control parameter as follows:

    # sysctl -w kernel.unknown_nmi_panic=1
    kernel.unknown_nmi_panic = 1

    If the NMI switch is pressed, CPU registers and stack trace will
    be displayed on console and then panic occurs.


    diff -Nur linux-2.6.6.org/arch/i386/kernel/nmi.c linux-2.6.6/arch/i386/kernel/nmi.c
    --- linux-2.6.6.org/arch/i386/kernel/nmi.c 2004-05-25 20:02:45.000000000 +0900
    +++ linux-2.6.6/arch/i386/kernel/nmi.c 2004-05-26 09:48:23.000000000 +0900
    @@ -25,16 +25,20 @@
    #include <linux/module.h>
    #include <linux/nmi.h>
    #include <linux/sysdev.h>
    +#include <linux/sysctl.h>

    #include <asm/smp.h>
    #include <asm/mtrr.h>
    #include <asm/mpspec.h>
    #include <asm/nmi.h>

    +#include "mach_traps.h"
    +
    unsigned int nmi_watchdog = NMI_NONE;
    static unsigned int nmi_hz = HZ;
    unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
    extern void show_registers(struct pt_regs *regs);
    +int unknown_nmi_panic = 0;

    /*
    * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
    @@ -419,8 +423,6 @@
    nmi_active = 1;
    }

    -static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
    -
    /*
    * the best way to detect whether a CPU has a 'hard lockup' problem
    * is to check it's local APIC timer IRQ counts. If they are not
    @@ -452,6 +454,8 @@
    alert_counter[i] = 0;
    }

    +extern void die_nmi(struct pt_regs *, const char *msg);
    +
    void nmi_watchdog_tick (struct pt_regs * regs)
    {

    @@ -470,21 +474,8 @@
    * wait a few IRQs (5 seconds) before doing the oops ...
    */
    alert_counter[cpu]++;
    - if (alert_counter[cpu] == 5*nmi_hz) {
    - spin_lock(&nmi_print_lock);
    - /*
    - * We are in trouble anyway, lets at least try
    - * to get a message out.
    - */
    - bust_spinlocks(1);
    - printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip);
    - show_registers(regs);
    - printk("console shuts up ...\n");
    - console_silent();
    - spin_unlock(&nmi_print_lock);
    - bust_spinlocks(0);
    - do_exit(SIGSEGV);
    - }
    + if (alert_counter[cpu] == 5*nmi_hz)
    + die_nmi(regs, "NMI Watchdog detected LOCKUP");
    } else {
    last_irq_sums[cpu] = sum;
    alert_counter[cpu] = 0;
    @@ -511,6 +502,45 @@
    }
    }

    +static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
    +{
    + unsigned char reason = get_nmi_reason();
    + char buf[64];
    +
    + if (!(reason & 0xc0)) {
    + sprintf(buf, "NMI received for unknown reason %02x\n", reason);
    + die_nmi(regs, buf);
    + }
    + return 0;
    +}
    +
    +/*
    + * proc handler for /proc/sys/kernel/unknown_nmi_panic
    + */
    +int proc_unknown_nmi_panic(ctl_table *table, int write,
    + struct file *file, void __user *buffer, size_t *length)
    +{
    + int old_state;
    +
    + old_state = unknown_nmi_panic;
    + proc_dointvec(table, write, file, buffer, length);
    + if (!old_state == !unknown_nmi_panic)
    + return 0;
    +
    + if (unknown_nmi_panic) {
    + if (reserve_lapic_nmi() < 0) {
    + unknown_nmi_panic = 0;
    + return -EBUSY;
    + } else {
    + set_nmi_callback(unknown_nmi_panic_callback);
    + }
    + } else {
    + release_lapic_nmi();
    + unset_nmi_callback();
    + }
    + return 0;
    +}
    +
    EXPORT_SYMBOL(nmi_active);
    EXPORT_SYMBOL(nmi_watchdog);
    EXPORT_SYMBOL(reserve_lapic_nmi);
    diff -Nur linux-2.6.6.org/arch/i386/kernel/traps.c linux-2.6.6/arch/i386/kernel/traps.c
    --- linux-2.6.6.org/arch/i386/kernel/traps.c 2004-05-25 20:02:45.000000000 +0900
    +++ linux-2.6.6/arch/i386/kernel/traps.c 2004-05-25 22:54:03.000000000 +0900
    @@ -454,6 +454,27 @@
    printk("Do you have a strange power saving mode enabled?\n");
    }

    +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
    +
    +void die_nmi (struct pt_regs *regs, const char *msg)
    +{
    + spin_lock(&nmi_print_lock);
    + /*
    + * We are in trouble anyway, lets at least try
    + * to get a message out.
    + */
    + bust_spinlocks(1);
    + printk(msg);
    + printk(" on CPU%d, eip %08lx, registers:\n",
    + smp_processor_id(), regs->eip);
    + show_registers(regs);
    + printk("console shuts up ...\n");
    + console_silent();
    + spin_unlock(&nmi_print_lock);
    + bust_spinlocks(0);
    + do_exit(SIGSEGV);
    +}
    +
    static void default_do_nmi(struct pt_regs * regs)
    {
    unsigned char reason = get_nmi_reason();
    diff -Nur linux-2.6.6.org/include/linux/sysctl.h linux-2.6.6/include/linux/sysctl.h
    --- linux-2.6.6.org/include/linux/sysctl.h 2004-05-25 20:03:13.000000000 +0900
    +++ linux-2.6.6/include/linux/sysctl.h 2004-05-25 22:54:03.000000000 +0900
    @@ -133,6 +133,7 @@
    KERN_NGROUPS_MAX=63, /* int: NGROUPS_MAX */
    KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */
    KERN_HZ_TIMER=65, /* int: hz timer on or off */
    + KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */
    };


    diff -Nur linux-2.6.6.org/kernel/sysctl.c linux-2.6.6/kernel/sysctl.c
    --- linux-2.6.6.org/kernel/sysctl.c 2004-05-25 20:03:31.000000000 +0900
    +++ linux-2.6.6/kernel/sysctl.c 2004-05-25 22:54:03.000000000 +0900
    @@ -65,6 +65,12 @@
    extern int printk_ratelimit_jiffies;
    extern int printk_ratelimit_burst;

    +#if defined(__i386__)
    +extern int unknown_nmi_panic;
    +extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *,
    + void __user *, size_t *);
    +#endif
    +
    /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
    static int maxolduid = 65535;
    static int minolduid;
    @@ -636,6 +642,16 @@
    .mode = 0444,
    .proc_handler = &proc_dointvec,
    },
    +#if defined(__i386__)
    + {
    + .ctl_name = KERN_UNKNOWN_NMI_PANIC,
    + .procname = "unknown_nmi_panic",
    + .data = &unknown_nmi_panic,
    + .maxlen = sizeof (int),
    + .mode = 0644,
    + .proc_handler = &proc_unknown_nmi_panic,
    + },
    +#endif
    { .ctl_name = 0 }
    };






    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:03    [W:0.033 / U:30.560 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site