minix/kernel/glo.h
Tomas Hruby 5efa92f754 NMI watchdog is an awesome feature for debugging locked up kernels.
There is not that much use for it on a single CPU, however, deadlock
between kernel and system task can be delected. Or a runaway loop.

If a kernel gets locked up the timer interrupts don't occure (as all
interrupts are disabled in kernel mode). The only chance is to
interrupt the kernel by a non-maskable interrupt.

This patch generates NMIs using performance counters. It uses the most
widely available performace counters. As the performance counters are 
highly model-specific this patch is not guaranteed to work on every
machine.  Unfortunately this is also true for KVM :-/ On the other
hand adding this feature for other models is not extremely difficult
and the framework makes it hopefully easy enough.

Depending on the frequency of the CPU an NMI is generated at most
about every 0.5s If the cpu's speed is less then 2Ghz it is generated
at most every 1s. In general an NMI is generated much less often as
the performance counter counts down only if the cpu is not idle.
Therefore the overhead of this feature is fairly minimal even if the
load is high.

Uppon detecting that the kernel is locked up the kernel dumps the 
state of the kernel registers and panics.

Local APIC must be enabled for the watchdog to work.

The code is _always_ compiled in, however, it is only enabled if  
watchdog=<non-zero> is set in the boot monitor.

One corner case is serial console debugging. As dumping a lot of stuff
to the serial link may take a lot of time, the watchdog does not 
detect lockups during this time!!! as it would result in too many
false positives. 10 nmi have to be handled before the lockup is
detected. This means something between ~5s to 10s.

Another corner case is that the watchdog is enabled only after the
paging is enabled as it would be pure madness to try to get it right.
2010-01-16 20:53:55 +00:00

96 lines
3.3 KiB
C

#ifndef GLO_H
#define GLO_H
/* Global variables used in the kernel. This file contains the declarations;
* storage space for the variables is allocated in table.c, because EXTERN is
* defined as extern unless the _TABLE definition is seen. We rely on the
* compiler's default initialization (0) for several global variables.
*/
#ifdef _TABLE
#undef EXTERN
#define EXTERN
#endif
#include <minix/config.h>
#include <archtypes.h>
#include "config.h"
#include "debug.h"
/* Variables relating to shutting down MINIX. */
EXTERN char kernel_exception; /* TRUE after system exceptions */
EXTERN char shutdown_started; /* TRUE after shutdowns / reboots */
/* Kernel information structures. This groups vital kernel information. */
EXTERN struct kinfo kinfo; /* kernel information for users */
EXTERN struct machine machine; /* machine information for users */
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
EXTERN struct k_randomness krandom; /* gather kernel random information */
EXTERN struct loadinfo kloadinfo; /* status of load average */
/* Process scheduling information and the kernel reentry count. */
EXTERN struct proc *proc_ptr; /* pointer to currently running process */
EXTERN struct proc *bill_ptr; /* process to bill for clock ticks */
EXTERN struct proc *vmrestart; /* first process on vmrestart queue */
EXTERN struct proc *vmrequest; /* first process on vmrequest queue */
EXTERN struct proc *pagefaults; /* first process on pagefault queue */
EXTERN unsigned lost_ticks; /* clock ticks counted outside clock task */
/* Interrupt related variables. */
EXTERN irq_hook_t irq_hooks[NR_IRQ_HOOKS]; /* hooks for general use */
EXTERN int irq_actids[NR_IRQ_VECTORS]; /* IRQ ID bits active */
EXTERN int irq_use; /* map of all in-use irq's */
EXTERN u32_t system_hz; /* HZ value */
/* Miscellaneous. */
EXTERN reg_t mon_ss, mon_sp; /* boot monitor stack */
EXTERN int mon_return; /* true if we can return to monitor */
EXTERN int do_serial_debug;
EXTERN endpoint_t who_e; /* message source endpoint */
EXTERN int who_p; /* message source proc */
EXTERN int sys_call_code; /* kernel call number in SYSTEM */
EXTERN time_t boottime;
EXTERN char params_buffer[512]; /* boot monitor parameters */
EXTERN int minix_panicing;
EXTERN int locklevel;
EXTERN char fpu_presence;
EXTERN char osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
#define MAGICTEST 0xC0FFEE23
EXTERN u32_t magictest; /* global magic number */
#if DEBUG_TRACE
EXTERN int verboseflags;
#endif
#ifdef CONFIG_APIC
EXTERN int config_no_apic; /* optionaly turn off apic */
#endif
#ifdef CONFIG_IDLE_TSC
EXTERN u64_t idle_tsc;
EXTERN u64_t idle_stop;
EXTERN int idle_active;
#endif
EXTERN unsigned cpu_hz[CONFIG_MAX_CPUS];
#define cpu_set_freq(cpu, freq) do {cpu_hz[cpu] = freq;} while (0)
#define cpu_get_freq(cpu) cpu_hz[cpu]
/* VM */
EXTERN int vm_running;
EXTERN int catch_pagefaults;
EXTERN struct proc *ptproc;
/* Timing */
EXTERN util_timingdata_t timingdata[TIMING_CATEGORIES];
/* Variables that are initialized elsewhere are just extern here. */
extern struct boot_image image[]; /* system image processes */
extern char *t_stack[]; /* task stack space */
extern struct segdesc_s gdt[]; /* global descriptor table */
EXTERN volatile int serial_debug_active;
#endif /* GLO_H */