#ifndef _KDB_H
#define _KDB_H

/*
 * Kernel Debugger Architecture Independent Global Headers
 *
 * Copyright (C) 1999-2003 Silicon Graphics, Inc.  All Rights Reserved
 * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Further, this software is distributed without any warranty that it is
 * free of the rightful claim of any third person regarding infringement
 * or the like.  Any license provided herein, whether implied or
 * otherwise, applies only to this software file.  Patent licenses, if
 * any, provided herein do not apply to combinations of this program with
 * other software, or any other product whatsoever.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
 *
 * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
 * Mountain View, CA  94043, or:
 *
 * http://www.sgi.com
 *
 * For further information regarding this notice, see:
 *
 * http://oss.sgi.com/projects/GenInfo/NoticeExplan
 */

#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/kdb.h>

#define KDB_MAJOR_VERSION	4
#define KDB_MINOR_VERSION	3
#define KDB_TEST_VERSION	""

	/*
	 * kdb_initial_cpu is initialized to -1, and is set to the cpu
	 * number whenever the kernel debugger is entered.
	 */
extern volatile int kdb_initial_cpu;	
#ifdef	CONFIG_KDB
#define KDB_IS_RUNNING() (kdb_initial_cpu != -1)
#else
#define KDB_IS_RUNNING() (0)
#endif	/* CONFIG_KDB */

	/*
	 * kdb_on
	 *
	 * 	Defines whether kdb is on or not.  Default value
	 *	is set by CONFIG_KDB_OFF.  Boot with kdb=on/off
	 *	or echo "[01]" > /proc/sys/kernel/kdb to change it.
	 */
extern int kdb_on;

	/* Global 'enter the debugger' variable tested by scheduler, spinlocks
	 * etc., to handle problems when interrupts are not working or are not
	 * safe.
	 */
extern volatile int kdb_enter_debugger;

#ifdef	CONFIG_SERIAL_CONSOLE
	/*
	 * kdb_serial.iobase is initialized to zero, and is set to the I/O
	 * address of the serial port when the console is setup in
	 * serial_console_setup.
	 */
extern struct kdb_serial {
	int io_type;
	unsigned long iobase;
	unsigned long ioreg_shift;
} kdb_serial;
#endif

	/*
	 * kdb_diemsg
	 *
	 *	Contains a pointer to the last string supplied to the
	 *	kernel 'die' panic function.
	 */
extern const char *kdb_diemsg;

#define KDB_FLAG_EARLYKDB	(1 << 0)	/* set from boot parameter kdb=early */
#define KDB_FLAG_CATASTROPHIC	(1 << 1)	/* A catastrophic event has occurred */
#define KDB_FLAG_CMD_INTERRUPT	(1 << 2)	/* Previous command was interrupted */
#define KDB_FLAG_NOIPI		(1 << 3)	/* Do not send IPIs */
#define KDB_FLAG_ONLY_DO_DUMP	(1 << 4)	/* Only do a dump, used when kdb is off */

	/*
	 * Internal debug flags
	 */
#define KDB_DEBUG_FLAG_BT	0x0001		/* Stack traceback debug */
#define KDB_DEBUG_FLAG_BP	0x0002		/* Breakpoint subsystem debug */
#define KDB_DEBUG_FLAG_LBR	0x0004		/* Print last branch register */
#define KDB_DEBUG_FLAG_AR	0x0008		/* Activation record, generic */
#define KDB_DEBUG_FLAG_ARA	0x0010		/* Activation record, arch specific */
/*      KDB_DEBUG_FLAG_CALLBACK	0x0020		WAS Event callbacks to kdb */
#define KDB_DEBUG_FLAG_STATE	0x0040		/* State flags */
#define KDB_DEBUG_FLAG_MASK	0xffff		/* All debug flags */
#define KDB_DEBUG_FLAG_SHIFT	16		/* Shift factor for dbflags */

extern volatile int kdb_flags;			/* Global flags, see kdb_state for per cpu state */

#define KDB_FLAG(flag)		(kdb_flags & KDB_FLAG_##flag)
#define KDB_FLAG_SET(flag)	((void)(kdb_flags |= KDB_FLAG_##flag))
#define KDB_FLAG_CLEAR(flag)	((void)(kdb_flags &= ~KDB_FLAG_##flag))
#define KDB_DEBUG(flag)		(kdb_flags & (KDB_DEBUG_FLAG_##flag << KDB_DEBUG_FLAG_SHIFT))
#define KDB_DEBUG_STATE(text,value)	if (KDB_DEBUG(STATE)) kdb_print_state(text, value)

	/*
	 * Per cpu kdb state.  A cpu can be under kdb control but outside kdb,
	 * for example when doing single step.
	 */
volatile extern int kdb_state[ /*NR_CPUS*/ ];
#define KDB_STATE_KDB		0x00000001	/* Cpu is inside kdb */
#define KDB_STATE_LEAVING	0x00000002	/* Cpu is leaving kdb */
#define KDB_STATE_CMD		0x00000004	/* Running a kdb command */
#define KDB_STATE_KDB_CONTROL	0x00000008	/* This cpu is under kdb control */
#define KDB_STATE_HOLD_CPU	0x00000010	/* Hold this cpu inside kdb */
#define KDB_STATE_DOING_SS	0x00000020	/* Doing ss command */
#define KDB_STATE_DOING_SSB	0x00000040	/* Doing ssb command, DOING_SS is also set */
#define KDB_STATE_SSBPT		0x00000080	/* Install breakpoint after one ss, independent of DOING_SS */
#define KDB_STATE_REENTRY	0x00000100	/* Valid re-entry into kdb */
#define KDB_STATE_SUPPRESS	0x00000200	/* Suppress error messages */
#define KDB_STATE_LONGJMP	0x00000400	/* longjmp() data is available */
#define KDB_STATE_GO_SWITCH	0x00000800	/* go is switching back to initial cpu */
#define KDB_STATE_PRINTF_LOCK	0x00001000	/* Holds kdb_printf lock */
#define KDB_STATE_WAIT_IPI	0x00002000	/* Waiting for kdb_ipi() NMI */
#define KDB_STATE_RECURSE	0x00004000	/* Recursive entry to kdb */
#define KDB_STATE_IP_ADJUSTED	0x00008000	/* Restart IP has been adjusted */
#define KDB_STATE_GO1		0x00010000	/* go only releases one cpu */
#define KDB_STATE_ARCH		0xff000000	/* Reserved for arch specific use */

#define KDB_STATE_CPU(flag,cpu)		(kdb_state[cpu] & KDB_STATE_##flag)
#define KDB_STATE_SET_CPU(flag,cpu)	((void)(kdb_state[cpu] |= KDB_STATE_##flag))
#define KDB_STATE_CLEAR_CPU(flag,cpu)	((void)(kdb_state[cpu] &= ~KDB_STATE_##flag))

#define KDB_STATE(flag)		KDB_STATE_CPU(flag,smp_processor_id())
#define KDB_STATE_SET(flag)	KDB_STATE_SET_CPU(flag,smp_processor_id())
#define KDB_STATE_CLEAR(flag)	KDB_STATE_CLEAR_CPU(flag,smp_processor_id())

	/*
	 * External entry point for the kernel debugger.  The pt_regs
	 * at the time of entry are supplied along with the reason for
	 * entry to the kernel debugger.
	 */

typedef enum {
	KDB_REASON_CALL = 1,		/* Call kdb() directly - regs should be valid */
	KDB_REASON_FAULT,		/* Kernel fault - regs valid */
	KDB_REASON_BREAK,		/* Breakpoint inst. - regs valid */
	KDB_REASON_DEBUG,		/* Debug Fault - regs valid */
	KDB_REASON_OOPS,		/* Kernel Oops - regs valid */
	KDB_REASON_SWITCH,		/* CPU switch - regs valid*/
	KDB_REASON_ENTER,		/* KDB_ENTER() trap/fault - regs valid */
	KDB_REASON_KEYBOARD,		/* Keyboard entry - regs valid */
	KDB_REASON_NMI,			/* Non-maskable interrupt; regs valid */
	KDB_REASON_WATCHDOG,		/* Watchdog interrupt; regs valid */
	KDB_REASON_RECURSE,		/* Recursive entry to kdb; regs probably valid */
	KDB_REASON_SILENT,		/* Silent entry/exit to kdb; regs invalid */
	KDB_REASON_CALL_PRESET,		/* Same as KDB_REASON_CALL but kdb_process_running has been preset */
} kdb_reason_t;

typedef enum {
	KDB_REPEAT_NONE = 0,		/* Do not repeat this command */
	KDB_REPEAT_NO_ARGS,		/* Repeat the command without arguments */
	KDB_REPEAT_WITH_ARGS,		/* Repeat the command including its arguments */
} kdb_repeat_t;

#ifdef	CONFIG_KDB
extern int   kdb(kdb_reason_t, int, struct pt_regs *);
#else
#define kdb(reason,error_code,frame) (0)
#endif

typedef int (*kdb_func_t)(int, const char **, const char **, struct pt_regs *);

	/*
	 * Symbol table format returned by kallsyms.
	 */

typedef struct __ksymtab {
		unsigned long value;		/* Address of symbol */
		const char *mod_name;		/* Module containing symbol or "kernel" */
		unsigned long mod_start;
		unsigned long mod_end;
		const char *sec_name;		/* Section containing symbol */
		unsigned long sec_start;
		unsigned long sec_end;
		const char *sym_name;		/* Full symbol name, including any version */
		unsigned long sym_start;
		unsigned long sym_end;
		} kdb_symtab_t;

	/*
	 * Exported Symbols for kernel loadable modules to use.
	 */
extern int           kdb_register(char *, kdb_func_t, char *, char *, short);
extern int           kdb_register_repeat(char *, kdb_func_t, char *, char *, short, kdb_repeat_t);
extern int           kdb_unregister(char *);

extern int	     kdb_getarea_size(void *, unsigned long, size_t);
extern int	     kdb_putarea_size(unsigned long, void *, size_t);

/* Like get_user and put_user, kdb_getarea and kdb_putarea take variable
 * names, not pointers.  The underlying *_size functions take pointers.
 */
#define kdb_getarea(x,addr)	kdb_getarea_size(&(x), addr, sizeof((x)))
#define kdb_putarea(addr,x)	kdb_putarea_size(addr, &(x), sizeof((x)))

extern int	     kdb_getword(unsigned long *, unsigned long, size_t);
extern int	     kdb_putword(unsigned long, unsigned long, size_t);

extern int	     kdbgetularg(const char *, unsigned long *);
extern char         *kdbgetenv(const char *);
extern int	     kdbgetintenv(const char *, int *);
extern int	     kdbgetaddrarg(int, const char**, int*, unsigned long *,
			           long *, char **, struct pt_regs *);
extern int	     kdbgetsymval(const char *, kdb_symtab_t *);
extern int	     kdbnearsym(unsigned long, kdb_symtab_t *);
extern void	     kdb_printf(const char *,...)
		     __attribute__ ((format (printf, 1, 2)));
extern void	     kdb_init(void);
extern void	     kdb_symbol_print(kdb_machreg_t, const kdb_symtab_t *, unsigned int);
extern char	    *kdb_read(char *buffer, size_t bufsize);
extern char	    *kdb_strdup(const char *str, int type);

#if defined(CONFIG_SMP)
	/*
	 * Kernel debugger non-maskable IPI handler.
	 */
extern int           kdb_ipi(struct pt_regs *, void (*ack_interrupt)(void));
extern void	     smp_kdb_stop(void);
#else	/* CONFIG_SMP */
#define	smp_kdb_stop()
#endif	/* CONFIG_SMP */

	/*
	 * Interface from general kernel to enable any hardware
	 * error reporting mechanisms.  Such as the Intel Machine
	 * Check Architecture, for example.
	 */
extern void	     kdb_enablehwfault(void);

	 /*
	  * Let other code know that kdb is in control.  Routines registered
	  * on this list are called from the initial cpu with 1 when kdb is
	  * entered and 0 when kdb exits.
	  *
	  * WARNING: If a module registers itself on this list (or any notifier
	  * list) then there is a race condition.  The module could be in the
	  * middle of removal on one cpu when it is called via the notifier
	  * chain on another cpu.  It is the responsibility of the module to
	  * prevent this race.  The safest way is for the module to define a
	  * 'can_unload' function which unregisters the module from all
	  * notifier chains before allowing the module to be unloaded.
	  */

extern struct notifier_block *kdb_notifier_list;

	 /*
	  * Do we have a set of registers?
	  */

#define KDB_NULL_REGS(regs) \
	(regs == (struct pt_regs *)NULL ? kdb_printf("%s: null regs - should never happen\n", __FUNCTION__), 1 : 0)

	 /*
	  * Routine for debugging the debugger state.
	  */

extern void kdb_print_state(const char *, int);

#ifdef CONFIG_KDB_USB
#include <linux/usb.h>
#define KDB_USB_ACTIVE 	1 /* Keyboard driver is usbkbd */
#define HID_ACTIVE 	2 /* Keyboard driver is hid    */

struct kdb_usb_exchange {
	void *uhci;			/* pointer to the UHCI structure */
  	struct urb *urb;		/* pointer to the URB */
	unsigned char *buffer;		/* pointer to buffer */
	void (*poll_func)(void *, struct urb *); /* pointer to the polling function */
	void (*reset_timer)(void);	/* pointer to the reset timer function */
	int driver;			/* driver mode, see above KDB_USB_KBD */
};
extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */
#endif /* CONFIG_KDB_USB */

#ifdef	MODULE
#define kdb_module_init(fn) module_init(fn)
#define kdb_module_exit(fn) module_exit(fn)
#else	/* !MODULE */
extern initcall_t __kdb_initcall_start, __kdb_initcall_end;
#define kdb_module_init(fn) \
	static initcall_t __kdb_initcall_##fn __attribute__ ((unused,__section__ (".kdb_initcall.init"))) = fn;
#define kdb_module_exit(fn) \
	static exitcall_t __kdb_exitcall_##fn __attribute__ ((unused,__section__ (".kdb_exitcall.exit"))) = fn;
#endif	/* MODULE */


/*
 * A backport of the 2.5 scheduler is used by many vendors of 2.4-based
 * distributions.
 * We can only guess its presence by the lack of the SCHED_YIELD flag.
 * If the heuristic doesn't work, change this define by hand.
 */
#ifndef SCHED_YIELD
#define __KDB_HAVE_NEW_SCHEDULER    1
#endif

static inline
int kdb_process_cpu(const struct task_struct *p)
{
#ifdef __KDB_HAVE_NEW_SCHEDULER
	return p->cpu;		/* p->cpu for O(1) scheduler */
#else
	return p->processor;	/* p->processor for not O(1) scheduler */
#endif
}

extern struct task_struct *kdb_current_task;
extern struct page * kdb_follow_page(struct mm_struct *, unsigned long, int); /* from mm/memory.c */

#endif	/* !_KDB_H */
