⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xmon.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Routines providing a simple monitor for use on the PowerMac. * * Copyright (C) 1996-2005 Paul Mackerras. * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. */#include <linux/config.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/smp.h>#include <linux/mm.h>#include <linux/reboot.h>#include <linux/delay.h>#include <linux/kallsyms.h>#include <linux/cpumask.h>#include <linux/module.h>#include <linux/sysrq.h>#include <linux/interrupt.h>#include <asm/ptrace.h>#include <asm/string.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/xmon.h>#ifdef CONFIG_PMAC_BACKLIGHT#include <asm/backlight.h>#endif#include <asm/processor.h>#include <asm/pgtable.h>#include <asm/mmu.h>#include <asm/mmu_context.h>#include <asm/cputable.h>#include <asm/rtas.h>#include <asm/sstep.h>#include <asm/bug.h>#ifdef CONFIG_PPC64#include <asm/hvcall.h>#include <asm/paca.h>#endif#include "nonstdio.h"#define scanhex	xmon_scanhex#define skipbl	xmon_skipbl#ifdef CONFIG_SMPcpumask_t cpus_in_xmon = CPU_MASK_NONE;static unsigned long xmon_taken = 1;static int xmon_owner;static int xmon_gate;#endif /* CONFIG_SMP */static unsigned long in_xmon = 0;static unsigned long adrs;static int size = 1;#define MAX_DUMP (128 * 1024)static unsigned long ndump = 64;static unsigned long nidump = 16;static unsigned long ncsum = 4096;static int termch;static char tmpstr[128];#define JMP_BUF_LEN	23static long bus_error_jmp[JMP_BUF_LEN];static int catch_memory_errors;static long *xmon_fault_jmp[NR_CPUS];#define setjmp xmon_setjmp#define longjmp xmon_longjmp/* Breakpoint stuff */struct bpt {	unsigned long	address;	unsigned int	instr[2];	atomic_t	ref_count;	int		enabled;	unsigned long	pad;};/* Bits in bpt.enabled */#define BP_IABR_TE	1		/* IABR translation enabled */#define BP_IABR		2#define BP_TRAP		8#define BP_DABR		0x10#define NBPTS	256static struct bpt bpts[NBPTS];static struct bpt dabr;static struct bpt *iabr;static unsigned bpinstr = 0x7fe00008;	/* trap */#define BP_NUM(bp)	((bp) - bpts + 1)/* Prototypes */static int cmds(struct pt_regs *);static int mread(unsigned long, void *, int);static int mwrite(unsigned long, void *, int);static int handle_fault(struct pt_regs *);static void byterev(unsigned char *, int);static void memex(void);static int bsesc(void);static void dump(void);static void prdump(unsigned long, long);static int ppc_inst_dump(unsigned long, long, int);void print_address(unsigned long);static void backtrace(struct pt_regs *);static void excprint(struct pt_regs *);static void prregs(struct pt_regs *);static void memops(int);static void memlocate(void);static void memzcan(void);static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);int skipbl(void);int scanhex(unsigned long *valp);static void scannl(void);static int hexdigit(int);void getstring(char *, int);static void flush_input(void);static int inchar(void);static void take_input(char *);static unsigned long read_spr(int);static void write_spr(int, unsigned long);static void super_regs(void);static void remove_bpts(void);static void insert_bpts(void);static void remove_cpu_bpts(void);static void insert_cpu_bpts(void);static struct bpt *at_breakpoint(unsigned long pc);static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);static int  do_step(struct pt_regs *);static void bpt_cmds(void);static void cacheflush(void);static int  cpu_cmd(void);static void csum(void);static void bootcmds(void);static void proccall(void);void dump_segments(void);static void symbol_lookup(void);static void xmon_print_symbol(unsigned long address, const char *mid,			      const char *after);static const char *getvecname(unsigned long vec);extern int print_insn_powerpc(unsigned long, unsigned long, int);extern void xmon_enter(void);extern void xmon_leave(void);extern long setjmp(long *);extern void longjmp(long *, long);extern void xmon_save_regs(struct pt_regs *);#ifdef CONFIG_PPC64#define REG		"%.16lx"#define REGS_PER_LINE	4#define LAST_VOLATILE	13#else#define REG		"%.8lx"#define REGS_PER_LINE	8#define LAST_VOLATILE	12#endif#define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \			 || ('a' <= (c) && (c) <= 'f') \			 || ('A' <= (c) && (c) <= 'F'))#define isalnum(c)	(('0' <= (c) && (c) <= '9') \			 || ('a' <= (c) && (c) <= 'z') \			 || ('A' <= (c) && (c) <= 'Z'))#define isspace(c)	(c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)static char *help_string = "\Commands:\n\  b	show breakpoints\n\  bd	set data breakpoint\n\  bi	set instruction breakpoint\n\  bc	clear breakpoint\n"#ifdef CONFIG_SMP  "\  c	print cpus stopped in xmon\n\  c#	try to switch to cpu number h (in hex)\n"#endif  "\  C	checksum\n\  d	dump bytes\n\  di	dump instructions\n\  df	dump float values\n\  dd	dump double values\n\  e	print exception information\n\  f	flush cache\n\  la	lookup symbol+offset of specified address\n\  ls	lookup address of specified symbol\n\  m	examine/change memory\n\  mm	move a block of memory\n\  ms	set a block of memory\n\  md	compare two blocks of memory\n\  ml	locate a block of memory\n\  mz	zero a block of memory\n\  mi	show information about memory allocation\n\  p 	call a procedure\n\  r	print registers\n\  s	single step\n\  S	print special registers\n\  t	print backtrace\n\  x	exit monitor and recover\n\  X	exit monitor and dont recover\n"#ifdef CONFIG_PPC64"  u	dump segment table or SLB\n"#endif#ifdef CONFIG_PPC_STD_MMU_32"  u	dump segment registers\n"#endif"  ?	help\n""  zr	reboot\n\  zh	halt\n";static struct pt_regs *xmon_regs;static inline void sync(void){	asm volatile("sync; isync");}static inline void store_inst(void *p){	asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));}static inline void cflush(void *p){	asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));}static inline void cinval(void *p){	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));}/* * Disable surveillance (the service processor watchdog function) * while we are in xmon. * XXX we should re-enable it when we leave. :) */#define SURVEILLANCE_TOKEN	9000static inline void disable_surveillance(void){#ifdef CONFIG_PPC_PSERIES	/* Since this can't be a module, args should end up below 4GB. */	static struct rtas_args args;	/*	 * At this point we have got all the cpus we can into	 * xmon, so there is hopefully no other cpu calling RTAS	 * at the moment, even though we don't take rtas.lock.	 * If we did try to take rtas.lock there would be a	 * real possibility of deadlock.	 */	args.token = rtas_token("set-indicator");	if (args.token == RTAS_UNKNOWN_SERVICE)		return;	args.nargs = 3;	args.nret = 1;	args.rets = &args.args[3];	args.args[0] = SURVEILLANCE_TOKEN;	args.args[1] = 0;	args.args[2] = 0;	enter_rtas(__pa(&args));#endif /* CONFIG_PPC_PSERIES */}#ifdef CONFIG_SMPstatic int xmon_speaker;static void get_output_lock(void){	int me = smp_processor_id() + 0x100;	int last_speaker = 0, prev;	long timeout;	if (xmon_speaker == me)		return;	for (;;) {		if (xmon_speaker == 0) {			last_speaker = cmpxchg(&xmon_speaker, 0, me);			if (last_speaker == 0)				return;		}		timeout = 10000000;		while (xmon_speaker == last_speaker) {			if (--timeout > 0)				continue;			/* hostile takeover */			prev = cmpxchg(&xmon_speaker, last_speaker, me);			if (prev == last_speaker)				return;			break;		}	}}static void release_output_lock(void){	xmon_speaker = 0;}#endifint xmon_core(struct pt_regs *regs, int fromipi){	int cmd = 0;	unsigned long msr;	struct bpt *bp;	long recurse_jmp[JMP_BUF_LEN];	unsigned long offset;#ifdef CONFIG_SMP	int cpu;	int secondary;	unsigned long timeout;#endif	msr = mfmsr();	mtmsr(msr & ~MSR_EE);	/* disable interrupts */	bp = in_breakpoint_table(regs->nip, &offset);	if (bp != NULL) {		regs->nip = bp->address + offset;		atomic_dec(&bp->ref_count);	}	remove_cpu_bpts();#ifdef CONFIG_SMP	cpu = smp_processor_id();	if (cpu_isset(cpu, cpus_in_xmon)) {		get_output_lock();		excprint(regs);		printf("cpu 0x%x: Exception %lx %s in xmon, "		       "returning to main loop\n",		       cpu, regs->trap, getvecname(TRAP(regs)));		release_output_lock();		longjmp(xmon_fault_jmp[cpu], 1);	}	if (setjmp(recurse_jmp) != 0) {		if (!in_xmon || !xmon_gate) {			get_output_lock();			printf("xmon: WARNING: bad recursive fault "			       "on cpu 0x%x\n", cpu);			release_output_lock();			goto waiting;		}		secondary = !(xmon_taken && cpu == xmon_owner);		goto cmdloop;	}	xmon_fault_jmp[cpu] = recurse_jmp;	cpu_set(cpu, cpus_in_xmon);	bp = NULL;	if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))		bp = at_breakpoint(regs->nip);	if (bp || (regs->msr & MSR_RI) == 0)		fromipi = 0;	if (!fromipi) {		get_output_lock();		excprint(regs);		if (bp) {			printf("cpu 0x%x stopped at breakpoint 0x%x (",			       cpu, BP_NUM(bp));			xmon_print_symbol(regs->nip, " ", ")\n");		}		if ((regs->msr & MSR_RI) == 0)			printf("WARNING: exception is not recoverable, "			       "can't continue\n");		release_output_lock();	} waiting:	secondary = 1;	while (secondary && !xmon_gate) {		if (in_xmon == 0) {			if (fromipi)				goto leave;			secondary = test_and_set_bit(0, &in_xmon);		}		barrier();	}	if (!secondary && !xmon_gate) {		/* we are the first cpu to come in */		/* interrupt other cpu(s) */		int ncpus = num_online_cpus();		xmon_owner = cpu;		mb();		if (ncpus > 1) {			smp_send_debugger_break(MSG_ALL_BUT_SELF);			/* wait for other cpus to come in */			for (timeout = 100000000; timeout != 0; --timeout) {				if (cpus_weight(cpus_in_xmon) >= ncpus)					break;				barrier();			}		}		remove_bpts();		disable_surveillance();		/* for breakpoint or single step, print the current instr. */		if (bp || TRAP(regs) == 0xd00)			ppc_inst_dump(regs->nip, 1, 0);		printf("enter ? for help\n");		mb();		xmon_gate = 1;		barrier();	} cmdloop:	while (in_xmon) {		if (secondary) {			if (cpu == xmon_owner) {				if (!test_and_set_bit(0, &xmon_taken)) {					secondary = 0;					continue;				}				/* missed it */				while (cpu == xmon_owner)					barrier();			}			barrier();		} else {			cmd = cmds(regs);			if (cmd != 0) {				/* exiting xmon */				insert_bpts();				xmon_gate = 0;				wmb();				in_xmon = 0;				break;			}			/* have switched to some other cpu */			secondary = 1;		}	} leave:	cpu_clear(cpu, cpus_in_xmon);	xmon_fault_jmp[cpu] = NULL;#else	/* UP is simple... */	if (in_xmon) {		printf("Exception %lx %s in xmon, returning to main loop\n",		       regs->trap, getvecname(TRAP(regs)));		longjmp(xmon_fault_jmp[0], 1);	}	if (setjmp(recurse_jmp) == 0) {		xmon_fault_jmp[0] = recurse_jmp;		in_xmon = 1;		excprint(regs);		bp = at_breakpoint(regs->nip);		if (bp) {			printf("Stopped at breakpoint %x (", BP_NUM(bp));			xmon_print_symbol(regs->nip, " ", ")\n");		}		if ((regs->msr & MSR_RI) == 0)			printf("WARNING: exception is not recoverable, "			       "can't continue\n");		remove_bpts();		disable_surveillance();		/* for breakpoint or single step, print the current instr. */		if (bp || TRAP(regs) == 0xd00)			ppc_inst_dump(regs->nip, 1, 0);		printf("enter ? for help\n");	}	cmd = cmds(regs);	insert_bpts();	in_xmon = 0;#endif	if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {		bp = at_breakpoint(regs->nip);		if (bp != NULL) {			int stepped = emulate_step(regs, bp->instr[0]);			if (stepped == 0) {				regs->nip = (unsigned long) &bp->instr[0];				atomic_inc(&bp->ref_count);			} else if (stepped < 0) {				printf("Couldn't single-step %s instruction\n",				    (IS_RFID(bp->instr[0])? "rfid": "mtmsrd"));			}		}	}	insert_cpu_bpts();	mtmsr(msr);		/* restore interrupt enable */	return cmd != 'X';}int xmon(struct pt_regs *excp){	struct pt_regs regs;	if (excp == NULL) {		xmon_save_regs(&regs);		excp = &regs;	}	return xmon_core(excp, 0);}EXPORT_SYMBOL(xmon);irqreturn_txmon_irq(int irq, void *d, struct pt_regs *regs){	unsigned long flags;	local_irq_save(flags);	printf("Keyboard interrupt\n");	xmon(regs);	local_irq_restore(flags);	return IRQ_HANDLED;}int xmon_bpt(struct pt_regs *regs){	struct bpt *bp;	unsigned long offset;	if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))		return 0;	/* Are we at the trap at bp->instr[1] for some bp? */	bp = in_breakpoint_table(regs->nip, &offset);	if (bp != NULL && offset == 4) {		regs->nip = bp->address + 4;		atomic_dec(&bp->ref_count);		return 1;	}	/* Are we at a breakpoint? */	bp = at_breakpoint(regs->nip);	if (!bp)		return 0;	xmon_core(regs, 0);	return 1;}int xmon_sstep(struct pt_regs *regs){	if (user_mode(regs))		return 0;	xmon_core(regs, 0);	return 1;}int xmon_dabr_match(struct pt_regs *regs){	if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))		return 0;	if (dabr.enabled == 0)		return 0;	xmon_core(regs, 0);	return 1;}int xmon_iabr_match(struct pt_regs *regs){	if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))		return 0;	if (iabr == 0)		return 0;	xmon_core(regs, 0);	return 1;}int xmon_ipi(struct pt_regs *regs){#ifdef CONFIG_SMP	if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))		xmon_core(regs, 1);#endif	return 0;}int xmon_fault_handler(struct pt_regs *regs){	struct bpt *bp;	unsigned long offset;	if (in_xmon && catch_memory_errors)		handle_fault(regs);	/* doesn't return */	if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {		bp = in_breakpoint_table(regs->nip, &offset);		if (bp != NULL) {			regs->nip = bp->address + offset;			atomic_dec(&bp->ref_count);		}	}	return 0;}static struct bpt *at_breakpoint(unsigned long pc){	int i;	struct bpt *bp;	bp = bpts;	for (i = 0; i < NBPTS; ++i, ++bp)		if (bp->enabled && pc == bp->address)			return bp;	return NULL;}static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp){	unsigned long off;	off = nip - (unsigned long) bpts;	if (off >= sizeof(bpts))		return NULL;	off %= sizeof(struct bpt);	if (off != offsetof(struct bpt, instr[0])	    && off != offsetof(struct bpt, instr[1]))		return NULL;	*offp = off - offsetof(struct bpt, instr[0]);	return (struct bpt *) (nip - off);}static struct bpt *new_breakpoint(unsigned long a)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -