162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Routines providing a simple monitor for use on the PowerMac.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1996-2005 Paul Mackerras.
662306a36Sopenharmony_ci * Copyright (C) 2001 PPC64 Team, IBM Corp
762306a36Sopenharmony_ci * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/sched/signal.h>
1362306a36Sopenharmony_ci#include <linux/smp.h>
1462306a36Sopenharmony_ci#include <linux/mm.h>
1562306a36Sopenharmony_ci#include <linux/reboot.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/kallsyms.h>
1862306a36Sopenharmony_ci#include <linux/kmsg_dump.h>
1962306a36Sopenharmony_ci#include <linux/cpumask.h>
2062306a36Sopenharmony_ci#include <linux/export.h>
2162306a36Sopenharmony_ci#include <linux/sysrq.h>
2262306a36Sopenharmony_ci#include <linux/interrupt.h>
2362306a36Sopenharmony_ci#include <linux/irq.h>
2462306a36Sopenharmony_ci#include <linux/bug.h>
2562306a36Sopenharmony_ci#include <linux/nmi.h>
2662306a36Sopenharmony_ci#include <linux/ctype.h>
2762306a36Sopenharmony_ci#include <linux/highmem.h>
2862306a36Sopenharmony_ci#include <linux/security.h>
2962306a36Sopenharmony_ci#include <linux/debugfs.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include <asm/ptrace.h>
3262306a36Sopenharmony_ci#include <asm/smp.h>
3362306a36Sopenharmony_ci#include <asm/string.h>
3462306a36Sopenharmony_ci#include <asm/machdep.h>
3562306a36Sopenharmony_ci#include <asm/xmon.h>
3662306a36Sopenharmony_ci#include <asm/processor.h>
3762306a36Sopenharmony_ci#include <asm/mmu.h>
3862306a36Sopenharmony_ci#include <asm/mmu_context.h>
3962306a36Sopenharmony_ci#include <asm/plpar_wrappers.h>
4062306a36Sopenharmony_ci#include <asm/cputable.h>
4162306a36Sopenharmony_ci#include <asm/rtas.h>
4262306a36Sopenharmony_ci#include <asm/sstep.h>
4362306a36Sopenharmony_ci#include <asm/irq_regs.h>
4462306a36Sopenharmony_ci#include <asm/spu.h>
4562306a36Sopenharmony_ci#include <asm/spu_priv1.h>
4662306a36Sopenharmony_ci#include <asm/setjmp.h>
4762306a36Sopenharmony_ci#include <asm/reg.h>
4862306a36Sopenharmony_ci#include <asm/debug.h>
4962306a36Sopenharmony_ci#include <asm/hw_breakpoint.h>
5062306a36Sopenharmony_ci#include <asm/xive.h>
5162306a36Sopenharmony_ci#include <asm/opal.h>
5262306a36Sopenharmony_ci#include <asm/firmware.h>
5362306a36Sopenharmony_ci#include <asm/code-patching.h>
5462306a36Sopenharmony_ci#include <asm/sections.h>
5562306a36Sopenharmony_ci#include <asm/inst.h>
5662306a36Sopenharmony_ci#include <asm/interrupt.h>
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#ifdef CONFIG_PPC64
5962306a36Sopenharmony_ci#include <asm/hvcall.h>
6062306a36Sopenharmony_ci#include <asm/paca.h>
6162306a36Sopenharmony_ci#include <asm/lppaca.h>
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#include "nonstdio.h"
6562306a36Sopenharmony_ci#include "dis-asm.h"
6662306a36Sopenharmony_ci#include "xmon_bpts.h"
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#ifdef CONFIG_SMP
6962306a36Sopenharmony_cistatic cpumask_t cpus_in_xmon = CPU_MASK_NONE;
7062306a36Sopenharmony_cistatic unsigned long xmon_taken = 1;
7162306a36Sopenharmony_cistatic int xmon_owner;
7262306a36Sopenharmony_cistatic int xmon_gate;
7362306a36Sopenharmony_cistatic int xmon_batch;
7462306a36Sopenharmony_cistatic unsigned long xmon_batch_start_cpu;
7562306a36Sopenharmony_cistatic cpumask_t xmon_batch_cpus = CPU_MASK_NONE;
7662306a36Sopenharmony_ci#else
7762306a36Sopenharmony_ci#define xmon_owner 0
7862306a36Sopenharmony_ci#endif /* CONFIG_SMP */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic unsigned long in_xmon __read_mostly = 0;
8162306a36Sopenharmony_cistatic int xmon_on = IS_ENABLED(CONFIG_XMON_DEFAULT);
8262306a36Sopenharmony_cistatic bool xmon_is_ro = IS_ENABLED(CONFIG_XMON_DEFAULT_RO_MODE);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic unsigned long adrs;
8562306a36Sopenharmony_cistatic int size = 1;
8662306a36Sopenharmony_ci#define MAX_DUMP (64 * 1024)
8762306a36Sopenharmony_cistatic unsigned long ndump = 64;
8862306a36Sopenharmony_ci#define MAX_IDUMP (MAX_DUMP >> 2)
8962306a36Sopenharmony_cistatic unsigned long nidump = 16;
9062306a36Sopenharmony_cistatic unsigned long ncsum = 4096;
9162306a36Sopenharmony_cistatic int termch;
9262306a36Sopenharmony_cistatic char tmpstr[KSYM_NAME_LEN];
9362306a36Sopenharmony_cistatic int tracing_enabled;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic long bus_error_jmp[JMP_BUF_LEN];
9662306a36Sopenharmony_cistatic int catch_memory_errors;
9762306a36Sopenharmony_cistatic int catch_spr_faults;
9862306a36Sopenharmony_cistatic long *xmon_fault_jmp[NR_CPUS];
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Breakpoint stuff */
10162306a36Sopenharmony_cistruct bpt {
10262306a36Sopenharmony_ci	unsigned long	address;
10362306a36Sopenharmony_ci	u32		*instr;
10462306a36Sopenharmony_ci	atomic_t	ref_count;
10562306a36Sopenharmony_ci	int		enabled;
10662306a36Sopenharmony_ci	unsigned long	pad;
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Bits in bpt.enabled */
11062306a36Sopenharmony_ci#define BP_CIABR	1
11162306a36Sopenharmony_ci#define BP_TRAP		2
11262306a36Sopenharmony_ci#define BP_DABR		4
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic struct bpt bpts[NBPTS];
11562306a36Sopenharmony_cistatic struct bpt dabr[HBP_NUM_MAX];
11662306a36Sopenharmony_cistatic struct bpt *iabr;
11762306a36Sopenharmony_cistatic unsigned int bpinstr = PPC_RAW_TRAP();
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#define BP_NUM(bp)	((bp) - bpts + 1)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* Prototypes */
12262306a36Sopenharmony_cistatic int cmds(struct pt_regs *);
12362306a36Sopenharmony_cistatic int mread(unsigned long, void *, int);
12462306a36Sopenharmony_cistatic int mwrite(unsigned long, void *, int);
12562306a36Sopenharmony_cistatic int mread_instr(unsigned long, ppc_inst_t *);
12662306a36Sopenharmony_cistatic int handle_fault(struct pt_regs *);
12762306a36Sopenharmony_cistatic void byterev(unsigned char *, int);
12862306a36Sopenharmony_cistatic void memex(void);
12962306a36Sopenharmony_cistatic int bsesc(void);
13062306a36Sopenharmony_cistatic void dump(void);
13162306a36Sopenharmony_cistatic void show_pte(unsigned long);
13262306a36Sopenharmony_cistatic void prdump(unsigned long, long);
13362306a36Sopenharmony_cistatic int ppc_inst_dump(unsigned long, long, int);
13462306a36Sopenharmony_cistatic void dump_log_buf(void);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#ifdef CONFIG_SMP
13762306a36Sopenharmony_cistatic int xmon_switch_cpu(unsigned long);
13862306a36Sopenharmony_cistatic int xmon_batch_next_cpu(void);
13962306a36Sopenharmony_cistatic int batch_cmds(struct pt_regs *);
14062306a36Sopenharmony_ci#endif
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
14362306a36Sopenharmony_cistatic void dump_opal_msglog(void);
14462306a36Sopenharmony_ci#else
14562306a36Sopenharmony_cistatic inline void dump_opal_msglog(void)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	printf("Machine is not running OPAL firmware.\n");
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void backtrace(struct pt_regs *);
15262306a36Sopenharmony_cistatic void excprint(struct pt_regs *);
15362306a36Sopenharmony_cistatic void prregs(struct pt_regs *);
15462306a36Sopenharmony_cistatic void memops(int);
15562306a36Sopenharmony_cistatic void memlocate(void);
15662306a36Sopenharmony_cistatic void memzcan(void);
15762306a36Sopenharmony_cistatic void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
15862306a36Sopenharmony_ciint skipbl(void);
15962306a36Sopenharmony_ciint scanhex(unsigned long *valp);
16062306a36Sopenharmony_cistatic void scannl(void);
16162306a36Sopenharmony_cistatic int hexdigit(int);
16262306a36Sopenharmony_civoid getstring(char *, int);
16362306a36Sopenharmony_cistatic void flush_input(void);
16462306a36Sopenharmony_cistatic int inchar(void);
16562306a36Sopenharmony_cistatic void take_input(char *);
16662306a36Sopenharmony_cistatic int  read_spr(int, unsigned long *);
16762306a36Sopenharmony_cistatic void write_spr(int, unsigned long);
16862306a36Sopenharmony_cistatic void super_regs(void);
16962306a36Sopenharmony_cistatic void remove_bpts(void);
17062306a36Sopenharmony_cistatic void insert_bpts(void);
17162306a36Sopenharmony_cistatic void remove_cpu_bpts(void);
17262306a36Sopenharmony_cistatic void insert_cpu_bpts(void);
17362306a36Sopenharmony_cistatic struct bpt *at_breakpoint(unsigned long pc);
17462306a36Sopenharmony_cistatic struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp);
17562306a36Sopenharmony_cistatic int  do_step(struct pt_regs *);
17662306a36Sopenharmony_cistatic void bpt_cmds(void);
17762306a36Sopenharmony_cistatic void cacheflush(void);
17862306a36Sopenharmony_cistatic int  cpu_cmd(void);
17962306a36Sopenharmony_cistatic void csum(void);
18062306a36Sopenharmony_cistatic void bootcmds(void);
18162306a36Sopenharmony_cistatic void proccall(void);
18262306a36Sopenharmony_cistatic void show_tasks(void);
18362306a36Sopenharmony_civoid dump_segments(void);
18462306a36Sopenharmony_cistatic void symbol_lookup(void);
18562306a36Sopenharmony_cistatic void xmon_show_stack(unsigned long sp, unsigned long lr,
18662306a36Sopenharmony_ci			    unsigned long pc);
18762306a36Sopenharmony_cistatic void xmon_print_symbol(unsigned long address, const char *mid,
18862306a36Sopenharmony_ci			      const char *after);
18962306a36Sopenharmony_cistatic const char *getvecname(unsigned long vec);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic int do_spu_cmd(void);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#ifdef CONFIG_44x
19462306a36Sopenharmony_cistatic void dump_tlb_44x(void);
19562306a36Sopenharmony_ci#endif
19662306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64
19762306a36Sopenharmony_cistatic void dump_tlb_book3e(void);
19862306a36Sopenharmony_ci#endif
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void clear_all_bpt(void);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#ifdef CONFIG_PPC64
20362306a36Sopenharmony_ci#define REG		"%.16lx"
20462306a36Sopenharmony_ci#else
20562306a36Sopenharmony_ci#define REG		"%.8lx"
20662306a36Sopenharmony_ci#endif
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
20962306a36Sopenharmony_ci#define GETWORD(v)	(((v)[3] << 24) + ((v)[2] << 16) + ((v)[1] << 8) + (v)[0])
21062306a36Sopenharmony_ci#else
21162306a36Sopenharmony_ci#define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
21262306a36Sopenharmony_ci#endif
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic const char *xmon_ro_msg = "Operation disabled: xmon in read-only mode\n";
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic char *help_string = "\
21762306a36Sopenharmony_ciCommands:\n\
21862306a36Sopenharmony_ci  b	show breakpoints\n\
21962306a36Sopenharmony_ci  bd	set data breakpoint\n\
22062306a36Sopenharmony_ci  bi	set instruction breakpoint\n\
22162306a36Sopenharmony_ci  bc	clear breakpoint\n"
22262306a36Sopenharmony_ci#ifdef CONFIG_SMP
22362306a36Sopenharmony_ci  "\
22462306a36Sopenharmony_ci  c	print cpus stopped in xmon\n\
22562306a36Sopenharmony_ci  c#	try to switch to cpu number h (in hex)\n\
22662306a36Sopenharmony_ci  c# $	run command '$' (one of 'r','S' or 't') on all cpus in xmon\n"
22762306a36Sopenharmony_ci#endif
22862306a36Sopenharmony_ci  "\
22962306a36Sopenharmony_ci  C	checksum\n\
23062306a36Sopenharmony_ci  d	dump bytes\n\
23162306a36Sopenharmony_ci  d1	dump 1 byte values\n\
23262306a36Sopenharmony_ci  d2	dump 2 byte values\n\
23362306a36Sopenharmony_ci  d4	dump 4 byte values\n\
23462306a36Sopenharmony_ci  d8	dump 8 byte values\n\
23562306a36Sopenharmony_ci  di	dump instructions\n\
23662306a36Sopenharmony_ci  df	dump float values\n\
23762306a36Sopenharmony_ci  dd	dump double values\n\
23862306a36Sopenharmony_ci  dl    dump the kernel log buffer\n"
23962306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
24062306a36Sopenharmony_ci  "\
24162306a36Sopenharmony_ci  do    dump the OPAL message log\n"
24262306a36Sopenharmony_ci#endif
24362306a36Sopenharmony_ci#ifdef CONFIG_PPC64
24462306a36Sopenharmony_ci  "\
24562306a36Sopenharmony_ci  dp[#]	dump paca for current cpu, or cpu #\n\
24662306a36Sopenharmony_ci  dpa	dump paca for all possible cpus\n"
24762306a36Sopenharmony_ci#endif
24862306a36Sopenharmony_ci  "\
24962306a36Sopenharmony_ci  dr	dump stream of raw bytes\n\
25062306a36Sopenharmony_ci  dv	dump virtual address translation \n\
25162306a36Sopenharmony_ci  dt	dump the tracing buffers (uses printk)\n\
25262306a36Sopenharmony_ci  dtc	dump the tracing buffers for current CPU (uses printk)\n\
25362306a36Sopenharmony_ci"
25462306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
25562306a36Sopenharmony_ci"  dx#   dump xive on CPU #\n\
25662306a36Sopenharmony_ci  dxi#  dump xive irq state #\n\
25762306a36Sopenharmony_ci  dxa   dump xive on all CPUs\n"
25862306a36Sopenharmony_ci#endif
25962306a36Sopenharmony_ci"  e	print exception information\n\
26062306a36Sopenharmony_ci  f	flush cache\n\
26162306a36Sopenharmony_ci  la	lookup symbol+offset of specified address\n\
26262306a36Sopenharmony_ci  ls	lookup address of specified symbol\n\
26362306a36Sopenharmony_ci  lp s [#]	lookup address of percpu symbol s for current cpu, or cpu #\n\
26462306a36Sopenharmony_ci  m	examine/change memory\n\
26562306a36Sopenharmony_ci  mm	move a block of memory\n\
26662306a36Sopenharmony_ci  ms	set a block of memory\n\
26762306a36Sopenharmony_ci  md	compare two blocks of memory\n\
26862306a36Sopenharmony_ci  ml	locate a block of memory\n\
26962306a36Sopenharmony_ci  mz	zero a block of memory\n\
27062306a36Sopenharmony_ci  mi	show information about memory allocation\n\
27162306a36Sopenharmony_ci  p 	call a procedure\n\
27262306a36Sopenharmony_ci  P 	list processes/tasks\n\
27362306a36Sopenharmony_ci  r	print registers\n\
27462306a36Sopenharmony_ci  s	single step\n"
27562306a36Sopenharmony_ci#ifdef CONFIG_SPU_BASE
27662306a36Sopenharmony_ci"  ss	stop execution on all spus\n\
27762306a36Sopenharmony_ci  sr	restore execution on stopped spus\n\
27862306a36Sopenharmony_ci  sf  #	dump spu fields for spu # (in hex)\n\
27962306a36Sopenharmony_ci  sd  #	dump spu local store for spu # (in hex)\n\
28062306a36Sopenharmony_ci  sdi #	disassemble spu local store for spu # (in hex)\n"
28162306a36Sopenharmony_ci#endif
28262306a36Sopenharmony_ci"  S	print special registers\n\
28362306a36Sopenharmony_ci  Sa    print all SPRs\n\
28462306a36Sopenharmony_ci  Sr #	read SPR #\n\
28562306a36Sopenharmony_ci  Sw #v write v to SPR #\n\
28662306a36Sopenharmony_ci  t	print backtrace\n\
28762306a36Sopenharmony_ci  x	exit monitor and recover\n\
28862306a36Sopenharmony_ci  X	exit monitor and don't recover\n"
28962306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64)
29062306a36Sopenharmony_ci"  u	dump segment table or SLB\n"
29162306a36Sopenharmony_ci#elif defined(CONFIG_PPC_BOOK3S_32)
29262306a36Sopenharmony_ci"  u	dump segment registers\n"
29362306a36Sopenharmony_ci#elif defined(CONFIG_44x) || defined(CONFIG_PPC_BOOK3E_64)
29462306a36Sopenharmony_ci"  u	dump TLB\n"
29562306a36Sopenharmony_ci#endif
29662306a36Sopenharmony_ci"  U	show uptime information\n"
29762306a36Sopenharmony_ci"  ?	help\n"
29862306a36Sopenharmony_ci"  # n	limit output to n lines per page (for dp, dpa, dl)\n"
29962306a36Sopenharmony_ci"  zr	reboot\n"
30062306a36Sopenharmony_ci"  zh	halt\n"
30162306a36Sopenharmony_ci;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci#ifdef CONFIG_SECURITY
30462306a36Sopenharmony_cistatic bool xmon_is_locked_down(void)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	static bool lockdown;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (!lockdown) {
30962306a36Sopenharmony_ci		lockdown = !!security_locked_down(LOCKDOWN_XMON_RW);
31062306a36Sopenharmony_ci		if (lockdown) {
31162306a36Sopenharmony_ci			printf("xmon: Disabled due to kernel lockdown\n");
31262306a36Sopenharmony_ci			xmon_is_ro = true;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (!xmon_is_ro) {
31762306a36Sopenharmony_ci		xmon_is_ro = !!security_locked_down(LOCKDOWN_XMON_WR);
31862306a36Sopenharmony_ci		if (xmon_is_ro)
31962306a36Sopenharmony_ci			printf("xmon: Read-only due to kernel lockdown\n");
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	return lockdown;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci#else /* CONFIG_SECURITY */
32562306a36Sopenharmony_cistatic inline bool xmon_is_locked_down(void)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	return false;
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci#endif
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic struct pt_regs *xmon_regs;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic inline void sync(void)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	asm volatile("sync; isync");
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic inline void cflush(void *p)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic inline void cinval(void *p)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * write_ciabr() - write the CIABR SPR
35062306a36Sopenharmony_ci * @ciabr:	The value to write.
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * This function writes a value to the CIARB register either directly
35362306a36Sopenharmony_ci * through mtspr instruction if the kernel is in HV privilege mode or
35462306a36Sopenharmony_ci * call a hypervisor function to achieve the same in case the kernel
35562306a36Sopenharmony_ci * is in supervisor privilege mode.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_cistatic void write_ciabr(unsigned long ciabr)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_ARCH_207S))
36062306a36Sopenharmony_ci		return;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_HVMODE)) {
36362306a36Sopenharmony_ci		mtspr(SPRN_CIABR, ciabr);
36462306a36Sopenharmony_ci		return;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci	plpar_set_ciabr(ciabr);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/**
37062306a36Sopenharmony_ci * set_ciabr() - set the CIABR
37162306a36Sopenharmony_ci * @addr:	The value to set.
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * This function sets the correct privilege value into the HW
37462306a36Sopenharmony_ci * breakpoint address before writing it up in the CIABR register.
37562306a36Sopenharmony_ci */
37662306a36Sopenharmony_cistatic void set_ciabr(unsigned long addr)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	addr &= ~CIABR_PRIV;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_HVMODE))
38162306a36Sopenharmony_ci		addr |= CIABR_PRIV_HYPER;
38262306a36Sopenharmony_ci	else
38362306a36Sopenharmony_ci		addr |= CIABR_PRIV_SUPER;
38462306a36Sopenharmony_ci	write_ciabr(addr);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/*
38862306a36Sopenharmony_ci * Disable surveillance (the service processor watchdog function)
38962306a36Sopenharmony_ci * while we are in xmon.
39062306a36Sopenharmony_ci * XXX we should re-enable it when we leave. :)
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_ci#define SURVEILLANCE_TOKEN	9000
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic inline void disable_surveillance(void)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES
39762306a36Sopenharmony_ci	/* Since this can't be a module, args should end up below 4GB. */
39862306a36Sopenharmony_ci	static struct rtas_args args;
39962306a36Sopenharmony_ci	const s32 token = rtas_function_token(RTAS_FN_SET_INDICATOR);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/*
40262306a36Sopenharmony_ci	 * At this point we have got all the cpus we can into
40362306a36Sopenharmony_ci	 * xmon, so there is hopefully no other cpu calling RTAS
40462306a36Sopenharmony_ci	 * at the moment, even though we don't take rtas.lock.
40562306a36Sopenharmony_ci	 * If we did try to take rtas.lock there would be a
40662306a36Sopenharmony_ci	 * real possibility of deadlock.
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci	if (token == RTAS_UNKNOWN_SERVICE)
40962306a36Sopenharmony_ci		return;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	rtas_call_unlocked(&args, token, 3, 1, NULL,
41262306a36Sopenharmony_ci			   SURVEILLANCE_TOKEN, 0, 0);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci#endif /* CONFIG_PPC_PSERIES */
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci#ifdef CONFIG_SMP
41862306a36Sopenharmony_cistatic int xmon_speaker;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic void get_output_lock(void)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	int me = smp_processor_id() + 0x100;
42362306a36Sopenharmony_ci	int last_speaker = 0, prev;
42462306a36Sopenharmony_ci	long timeout;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (xmon_speaker == me)
42762306a36Sopenharmony_ci		return;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	for (;;) {
43062306a36Sopenharmony_ci		last_speaker = cmpxchg(&xmon_speaker, 0, me);
43162306a36Sopenharmony_ci		if (last_speaker == 0)
43262306a36Sopenharmony_ci			return;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		/*
43562306a36Sopenharmony_ci		 * Wait a full second for the lock, we might be on a slow
43662306a36Sopenharmony_ci		 * console, but check every 100us.
43762306a36Sopenharmony_ci		 */
43862306a36Sopenharmony_ci		timeout = 10000;
43962306a36Sopenharmony_ci		while (xmon_speaker == last_speaker) {
44062306a36Sopenharmony_ci			if (--timeout > 0) {
44162306a36Sopenharmony_ci				udelay(100);
44262306a36Sopenharmony_ci				continue;
44362306a36Sopenharmony_ci			}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci			/* hostile takeover */
44662306a36Sopenharmony_ci			prev = cmpxchg(&xmon_speaker, last_speaker, me);
44762306a36Sopenharmony_ci			if (prev == last_speaker)
44862306a36Sopenharmony_ci				return;
44962306a36Sopenharmony_ci			break;
45062306a36Sopenharmony_ci		}
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic void release_output_lock(void)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	xmon_speaker = 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ciint cpus_are_in_xmon(void)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	return !cpumask_empty(&cpus_in_xmon);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic bool wait_for_other_cpus(int ncpus)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	unsigned long timeout;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* We wait for 2s, which is a metric "little while" */
46962306a36Sopenharmony_ci	for (timeout = 20000; timeout != 0; --timeout) {
47062306a36Sopenharmony_ci		if (cpumask_weight(&cpus_in_xmon) >= ncpus)
47162306a36Sopenharmony_ci			return true;
47262306a36Sopenharmony_ci		udelay(100);
47362306a36Sopenharmony_ci		barrier();
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return false;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci#else /* CONFIG_SMP */
47962306a36Sopenharmony_cistatic inline void get_output_lock(void) {}
48062306a36Sopenharmony_cistatic inline void release_output_lock(void) {}
48162306a36Sopenharmony_ci#endif
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic void xmon_touch_watchdogs(void)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	touch_softlockup_watchdog_sync();
48662306a36Sopenharmony_ci	rcu_cpu_stall_reset();
48762306a36Sopenharmony_ci	touch_nmi_watchdog();
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int xmon_core(struct pt_regs *regs, volatile int fromipi)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	volatile int cmd = 0;
49362306a36Sopenharmony_ci	struct bpt *volatile bp;
49462306a36Sopenharmony_ci	long recurse_jmp[JMP_BUF_LEN];
49562306a36Sopenharmony_ci	bool locked_down;
49662306a36Sopenharmony_ci	unsigned long offset;
49762306a36Sopenharmony_ci	unsigned long flags;
49862306a36Sopenharmony_ci#ifdef CONFIG_SMP
49962306a36Sopenharmony_ci	int cpu;
50062306a36Sopenharmony_ci	int secondary;
50162306a36Sopenharmony_ci#endif
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	local_irq_save(flags);
50462306a36Sopenharmony_ci	hard_irq_disable();
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	locked_down = xmon_is_locked_down();
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (!fromipi) {
50962306a36Sopenharmony_ci		tracing_enabled = tracing_is_on();
51062306a36Sopenharmony_ci		tracing_off();
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	bp = in_breakpoint_table(regs->nip, &offset);
51462306a36Sopenharmony_ci	if (bp != NULL) {
51562306a36Sopenharmony_ci		regs_set_return_ip(regs, bp->address + offset);
51662306a36Sopenharmony_ci		atomic_dec(&bp->ref_count);
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	remove_cpu_bpts();
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci#ifdef CONFIG_SMP
52262306a36Sopenharmony_ci	cpu = smp_processor_id();
52362306a36Sopenharmony_ci	if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
52462306a36Sopenharmony_ci		/*
52562306a36Sopenharmony_ci		 * We catch SPR read/write faults here because the 0x700, 0xf60
52662306a36Sopenharmony_ci		 * etc. handlers don't call debugger_fault_handler().
52762306a36Sopenharmony_ci		 */
52862306a36Sopenharmony_ci		if (catch_spr_faults)
52962306a36Sopenharmony_ci			longjmp(bus_error_jmp, 1);
53062306a36Sopenharmony_ci		get_output_lock();
53162306a36Sopenharmony_ci		excprint(regs);
53262306a36Sopenharmony_ci		printf("cpu 0x%x: Exception %lx %s in xmon, "
53362306a36Sopenharmony_ci		       "returning to main loop\n",
53462306a36Sopenharmony_ci		       cpu, regs->trap, getvecname(TRAP(regs)));
53562306a36Sopenharmony_ci		release_output_lock();
53662306a36Sopenharmony_ci		longjmp(xmon_fault_jmp[cpu], 1);
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (setjmp(recurse_jmp) != 0) {
54062306a36Sopenharmony_ci		if (!in_xmon || !xmon_gate) {
54162306a36Sopenharmony_ci			get_output_lock();
54262306a36Sopenharmony_ci			printf("xmon: WARNING: bad recursive fault "
54362306a36Sopenharmony_ci			       "on cpu 0x%x\n", cpu);
54462306a36Sopenharmony_ci			release_output_lock();
54562306a36Sopenharmony_ci			goto waiting;
54662306a36Sopenharmony_ci		}
54762306a36Sopenharmony_ci		secondary = !(xmon_taken && cpu == xmon_owner);
54862306a36Sopenharmony_ci		goto cmdloop;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	xmon_fault_jmp[cpu] = recurse_jmp;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	bp = NULL;
55462306a36Sopenharmony_ci	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
55562306a36Sopenharmony_ci		bp = at_breakpoint(regs->nip);
55662306a36Sopenharmony_ci	if (bp || regs_is_unrecoverable(regs))
55762306a36Sopenharmony_ci		fromipi = 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	if (!fromipi) {
56062306a36Sopenharmony_ci		get_output_lock();
56162306a36Sopenharmony_ci		if (!locked_down)
56262306a36Sopenharmony_ci			excprint(regs);
56362306a36Sopenharmony_ci		if (bp) {
56462306a36Sopenharmony_ci			printf("cpu 0x%x stopped at breakpoint 0x%tx (",
56562306a36Sopenharmony_ci			       cpu, BP_NUM(bp));
56662306a36Sopenharmony_ci			xmon_print_symbol(regs->nip, " ", ")\n");
56762306a36Sopenharmony_ci		}
56862306a36Sopenharmony_ci		if (regs_is_unrecoverable(regs))
56962306a36Sopenharmony_ci			printf("WARNING: exception is not recoverable, "
57062306a36Sopenharmony_ci			       "can't continue\n");
57162306a36Sopenharmony_ci		release_output_lock();
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	cpumask_set_cpu(cpu, &cpus_in_xmon);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci waiting:
57762306a36Sopenharmony_ci	secondary = 1;
57862306a36Sopenharmony_ci	spin_begin();
57962306a36Sopenharmony_ci	while (secondary && !xmon_gate) {
58062306a36Sopenharmony_ci		if (in_xmon == 0) {
58162306a36Sopenharmony_ci			if (fromipi) {
58262306a36Sopenharmony_ci				spin_end();
58362306a36Sopenharmony_ci				goto leave;
58462306a36Sopenharmony_ci			}
58562306a36Sopenharmony_ci			secondary = test_and_set_bit(0, &in_xmon);
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci		spin_cpu_relax();
58862306a36Sopenharmony_ci		touch_nmi_watchdog();
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci	spin_end();
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (!secondary && !xmon_gate) {
59362306a36Sopenharmony_ci		/* we are the first cpu to come in */
59462306a36Sopenharmony_ci		/* interrupt other cpu(s) */
59562306a36Sopenharmony_ci		int ncpus = num_online_cpus();
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		xmon_owner = cpu;
59862306a36Sopenharmony_ci		mb();
59962306a36Sopenharmony_ci		if (ncpus > 1) {
60062306a36Sopenharmony_ci			/*
60162306a36Sopenharmony_ci			 * A system reset (trap == 0x100) can be triggered on
60262306a36Sopenharmony_ci			 * all CPUs, so when we come in via 0x100 try waiting
60362306a36Sopenharmony_ci			 * for the other CPUs to come in before we send the
60462306a36Sopenharmony_ci			 * debugger break (IPI). This is similar to
60562306a36Sopenharmony_ci			 * crash_kexec_secondary().
60662306a36Sopenharmony_ci			 */
60762306a36Sopenharmony_ci			if (TRAP(regs) !=  INTERRUPT_SYSTEM_RESET || !wait_for_other_cpus(ncpus))
60862306a36Sopenharmony_ci				smp_send_debugger_break();
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			wait_for_other_cpus(ncpus);
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci		remove_bpts();
61362306a36Sopenharmony_ci		disable_surveillance();
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		if (!locked_down) {
61662306a36Sopenharmony_ci			/* for breakpoint or single step, print curr insn */
61762306a36Sopenharmony_ci			if (bp || TRAP(regs) == INTERRUPT_TRACE)
61862306a36Sopenharmony_ci				ppc_inst_dump(regs->nip, 1, 0);
61962306a36Sopenharmony_ci			printf("enter ? for help\n");
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		mb();
62362306a36Sopenharmony_ci		xmon_gate = 1;
62462306a36Sopenharmony_ci		barrier();
62562306a36Sopenharmony_ci		touch_nmi_watchdog();
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci cmdloop:
62962306a36Sopenharmony_ci	while (in_xmon) {
63062306a36Sopenharmony_ci		if (secondary) {
63162306a36Sopenharmony_ci			spin_begin();
63262306a36Sopenharmony_ci			if (cpu == xmon_owner) {
63362306a36Sopenharmony_ci				if (!test_and_set_bit(0, &xmon_taken)) {
63462306a36Sopenharmony_ci					secondary = 0;
63562306a36Sopenharmony_ci					spin_end();
63662306a36Sopenharmony_ci					continue;
63762306a36Sopenharmony_ci				}
63862306a36Sopenharmony_ci				/* missed it */
63962306a36Sopenharmony_ci				while (cpu == xmon_owner)
64062306a36Sopenharmony_ci					spin_cpu_relax();
64162306a36Sopenharmony_ci			}
64262306a36Sopenharmony_ci			spin_cpu_relax();
64362306a36Sopenharmony_ci			touch_nmi_watchdog();
64462306a36Sopenharmony_ci		} else {
64562306a36Sopenharmony_ci			cmd = 1;
64662306a36Sopenharmony_ci#ifdef CONFIG_SMP
64762306a36Sopenharmony_ci			if (xmon_batch)
64862306a36Sopenharmony_ci				cmd = batch_cmds(regs);
64962306a36Sopenharmony_ci#endif
65062306a36Sopenharmony_ci			if (!locked_down && cmd)
65162306a36Sopenharmony_ci				cmd = cmds(regs);
65262306a36Sopenharmony_ci			if (locked_down || cmd != 0) {
65362306a36Sopenharmony_ci				/* exiting xmon */
65462306a36Sopenharmony_ci				insert_bpts();
65562306a36Sopenharmony_ci				xmon_gate = 0;
65662306a36Sopenharmony_ci				wmb();
65762306a36Sopenharmony_ci				in_xmon = 0;
65862306a36Sopenharmony_ci				break;
65962306a36Sopenharmony_ci			}
66062306a36Sopenharmony_ci			/* have switched to some other cpu */
66162306a36Sopenharmony_ci			secondary = 1;
66262306a36Sopenharmony_ci		}
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci leave:
66562306a36Sopenharmony_ci	cpumask_clear_cpu(cpu, &cpus_in_xmon);
66662306a36Sopenharmony_ci	xmon_fault_jmp[cpu] = NULL;
66762306a36Sopenharmony_ci#else
66862306a36Sopenharmony_ci	/* UP is simple... */
66962306a36Sopenharmony_ci	if (in_xmon) {
67062306a36Sopenharmony_ci		printf("Exception %lx %s in xmon, returning to main loop\n",
67162306a36Sopenharmony_ci		       regs->trap, getvecname(TRAP(regs)));
67262306a36Sopenharmony_ci		longjmp(xmon_fault_jmp[0], 1);
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci	if (setjmp(recurse_jmp) == 0) {
67562306a36Sopenharmony_ci		xmon_fault_jmp[0] = recurse_jmp;
67662306a36Sopenharmony_ci		in_xmon = 1;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		excprint(regs);
67962306a36Sopenharmony_ci		bp = at_breakpoint(regs->nip);
68062306a36Sopenharmony_ci		if (bp) {
68162306a36Sopenharmony_ci			printf("Stopped at breakpoint %tx (", BP_NUM(bp));
68262306a36Sopenharmony_ci			xmon_print_symbol(regs->nip, " ", ")\n");
68362306a36Sopenharmony_ci		}
68462306a36Sopenharmony_ci		if (regs_is_unrecoverable(regs))
68562306a36Sopenharmony_ci			printf("WARNING: exception is not recoverable, "
68662306a36Sopenharmony_ci			       "can't continue\n");
68762306a36Sopenharmony_ci		remove_bpts();
68862306a36Sopenharmony_ci		disable_surveillance();
68962306a36Sopenharmony_ci		if (!locked_down) {
69062306a36Sopenharmony_ci			/* for breakpoint or single step, print current insn */
69162306a36Sopenharmony_ci			if (bp || TRAP(regs) == INTERRUPT_TRACE)
69262306a36Sopenharmony_ci				ppc_inst_dump(regs->nip, 1, 0);
69362306a36Sopenharmony_ci			printf("enter ? for help\n");
69462306a36Sopenharmony_ci		}
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (!locked_down)
69862306a36Sopenharmony_ci		cmd = cmds(regs);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	insert_bpts();
70162306a36Sopenharmony_ci	in_xmon = 0;
70262306a36Sopenharmony_ci#endif
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
70562306a36Sopenharmony_ci	if (regs->msr & MSR_DE) {
70662306a36Sopenharmony_ci		bp = at_breakpoint(regs->nip);
70762306a36Sopenharmony_ci		if (bp != NULL) {
70862306a36Sopenharmony_ci			regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
70962306a36Sopenharmony_ci			atomic_inc(&bp->ref_count);
71062306a36Sopenharmony_ci		}
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci#else
71362306a36Sopenharmony_ci	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
71462306a36Sopenharmony_ci		bp = at_breakpoint(regs->nip);
71562306a36Sopenharmony_ci		if (bp != NULL) {
71662306a36Sopenharmony_ci			int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
71762306a36Sopenharmony_ci			if (stepped == 0) {
71862306a36Sopenharmony_ci				regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
71962306a36Sopenharmony_ci				atomic_inc(&bp->ref_count);
72062306a36Sopenharmony_ci			} else if (stepped < 0) {
72162306a36Sopenharmony_ci				printf("Couldn't single-step %s instruction\n",
72262306a36Sopenharmony_ci				    IS_RFID(ppc_inst_read(bp->instr))? "rfid": "mtmsrd");
72362306a36Sopenharmony_ci			}
72462306a36Sopenharmony_ci		}
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci#endif
72762306a36Sopenharmony_ci	if (locked_down)
72862306a36Sopenharmony_ci		clear_all_bpt();
72962306a36Sopenharmony_ci	else
73062306a36Sopenharmony_ci		insert_cpu_bpts();
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	xmon_touch_watchdogs();
73362306a36Sopenharmony_ci	local_irq_restore(flags);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return cmd != 'X' && cmd != EOF;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ciint xmon(struct pt_regs *excp)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct pt_regs regs;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (excp == NULL) {
74362306a36Sopenharmony_ci		ppc_save_regs(&regs);
74462306a36Sopenharmony_ci		excp = &regs;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return xmon_core(excp, 0);
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ciEXPORT_SYMBOL(xmon);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ciirqreturn_t xmon_irq(int irq, void *d)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	unsigned long flags;
75462306a36Sopenharmony_ci	local_irq_save(flags);
75562306a36Sopenharmony_ci	printf("Keyboard interrupt\n");
75662306a36Sopenharmony_ci	xmon(get_irq_regs());
75762306a36Sopenharmony_ci	local_irq_restore(flags);
75862306a36Sopenharmony_ci	return IRQ_HANDLED;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic int xmon_bpt(struct pt_regs *regs)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct bpt *bp;
76462306a36Sopenharmony_ci	unsigned long offset;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
76762306a36Sopenharmony_ci		return 0;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* Are we at the trap at bp->instr[1] for some bp? */
77062306a36Sopenharmony_ci	bp = in_breakpoint_table(regs->nip, &offset);
77162306a36Sopenharmony_ci	if (bp != NULL && (offset == 4 || offset == 8)) {
77262306a36Sopenharmony_ci		regs_set_return_ip(regs, bp->address + offset);
77362306a36Sopenharmony_ci		atomic_dec(&bp->ref_count);
77462306a36Sopenharmony_ci		return 1;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/* Are we at a breakpoint? */
77862306a36Sopenharmony_ci	bp = at_breakpoint(regs->nip);
77962306a36Sopenharmony_ci	if (!bp)
78062306a36Sopenharmony_ci		return 0;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	xmon_core(regs, 0);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 1;
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int xmon_sstep(struct pt_regs *regs)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	if (user_mode(regs))
79062306a36Sopenharmony_ci		return 0;
79162306a36Sopenharmony_ci	xmon_core(regs, 0);
79262306a36Sopenharmony_ci	return 1;
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic int xmon_break_match(struct pt_regs *regs)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	int i;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
80062306a36Sopenharmony_ci		return 0;
80162306a36Sopenharmony_ci	for (i = 0; i < nr_wp_slots(); i++) {
80262306a36Sopenharmony_ci		if (dabr[i].enabled)
80362306a36Sopenharmony_ci			goto found;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cifound:
80862306a36Sopenharmony_ci	xmon_core(regs, 0);
80962306a36Sopenharmony_ci	return 1;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int xmon_iabr_match(struct pt_regs *regs)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
81562306a36Sopenharmony_ci		return 0;
81662306a36Sopenharmony_ci	if (iabr == NULL)
81762306a36Sopenharmony_ci		return 0;
81862306a36Sopenharmony_ci	xmon_core(regs, 0);
81962306a36Sopenharmony_ci	return 1;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int xmon_ipi(struct pt_regs *regs)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci#ifdef CONFIG_SMP
82562306a36Sopenharmony_ci	if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
82662306a36Sopenharmony_ci		xmon_core(regs, 1);
82762306a36Sopenharmony_ci#endif
82862306a36Sopenharmony_ci	return 0;
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_cistatic int xmon_fault_handler(struct pt_regs *regs)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct bpt *bp;
83462306a36Sopenharmony_ci	unsigned long offset;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (in_xmon && catch_memory_errors)
83762306a36Sopenharmony_ci		handle_fault(regs);	/* doesn't return */
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
84062306a36Sopenharmony_ci		bp = in_breakpoint_table(regs->nip, &offset);
84162306a36Sopenharmony_ci		if (bp != NULL) {
84262306a36Sopenharmony_ci			regs_set_return_ip(regs, bp->address + offset);
84362306a36Sopenharmony_ci			atomic_dec(&bp->ref_count);
84462306a36Sopenharmony_ci		}
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return 0;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci/* Force enable xmon if not already enabled */
85162306a36Sopenharmony_cistatic inline void force_enable_xmon(void)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	/* Enable xmon hooks if needed */
85462306a36Sopenharmony_ci	if (!xmon_on) {
85562306a36Sopenharmony_ci		printf("xmon: Enabling debugger hooks\n");
85662306a36Sopenharmony_ci		xmon_on = 1;
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic struct bpt *at_breakpoint(unsigned long pc)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	int i;
86362306a36Sopenharmony_ci	struct bpt *volatile bp;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	bp = bpts;
86662306a36Sopenharmony_ci	for (i = 0; i < NBPTS; ++i, ++bp)
86762306a36Sopenharmony_ci		if (bp->enabled && pc == bp->address)
86862306a36Sopenharmony_ci			return bp;
86962306a36Sopenharmony_ci	return NULL;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	unsigned long off;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	off = nip - (unsigned long)bpt_table;
87762306a36Sopenharmony_ci	if (off >= sizeof(bpt_table))
87862306a36Sopenharmony_ci		return NULL;
87962306a36Sopenharmony_ci	*offp = off & (BPT_SIZE - 1);
88062306a36Sopenharmony_ci	if (off & 3)
88162306a36Sopenharmony_ci		return NULL;
88262306a36Sopenharmony_ci	return bpts + (off / BPT_SIZE);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic struct bpt *new_breakpoint(unsigned long a)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	struct bpt *bp;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	a &= ~3UL;
89062306a36Sopenharmony_ci	bp = at_breakpoint(a);
89162306a36Sopenharmony_ci	if (bp)
89262306a36Sopenharmony_ci		return bp;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
89562306a36Sopenharmony_ci		if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
89662306a36Sopenharmony_ci			bp->address = a;
89762306a36Sopenharmony_ci			bp->instr = (void *)(bpt_table + ((bp - bpts) * BPT_WORDS));
89862306a36Sopenharmony_ci			return bp;
89962306a36Sopenharmony_ci		}
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	printf("Sorry, no free breakpoints.  Please clear one first.\n");
90362306a36Sopenharmony_ci	return NULL;
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic void insert_bpts(void)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	int i;
90962306a36Sopenharmony_ci	ppc_inst_t instr, instr2;
91062306a36Sopenharmony_ci	struct bpt *bp, *bp2;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	bp = bpts;
91362306a36Sopenharmony_ci	for (i = 0; i < NBPTS; ++i, ++bp) {
91462306a36Sopenharmony_ci		if ((bp->enabled & (BP_TRAP|BP_CIABR)) == 0)
91562306a36Sopenharmony_ci			continue;
91662306a36Sopenharmony_ci		if (!mread_instr(bp->address, &instr)) {
91762306a36Sopenharmony_ci			printf("Couldn't read instruction at %lx, "
91862306a36Sopenharmony_ci			       "disabling breakpoint there\n", bp->address);
91962306a36Sopenharmony_ci			bp->enabled = 0;
92062306a36Sopenharmony_ci			continue;
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci		if (!can_single_step(ppc_inst_val(instr))) {
92362306a36Sopenharmony_ci			printf("Breakpoint at %lx is on an instruction that can't be single stepped, disabling it\n",
92462306a36Sopenharmony_ci					bp->address);
92562306a36Sopenharmony_ci			bp->enabled = 0;
92662306a36Sopenharmony_ci			continue;
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci		/*
92962306a36Sopenharmony_ci		 * Check the address is not a suffix by looking for a prefix in
93062306a36Sopenharmony_ci		 * front of it.
93162306a36Sopenharmony_ci		 */
93262306a36Sopenharmony_ci		if (mread_instr(bp->address - 4, &instr2) == 8) {
93362306a36Sopenharmony_ci			printf("Breakpoint at %lx is on the second word of a prefixed instruction, disabling it\n",
93462306a36Sopenharmony_ci			       bp->address);
93562306a36Sopenharmony_ci			bp->enabled = 0;
93662306a36Sopenharmony_ci			continue;
93762306a36Sopenharmony_ci		}
93862306a36Sopenharmony_ci		/*
93962306a36Sopenharmony_ci		 * We might still be a suffix - if the prefix has already been
94062306a36Sopenharmony_ci		 * replaced by a breakpoint we won't catch it with the above
94162306a36Sopenharmony_ci		 * test.
94262306a36Sopenharmony_ci		 */
94362306a36Sopenharmony_ci		bp2 = at_breakpoint(bp->address - 4);
94462306a36Sopenharmony_ci		if (bp2 && ppc_inst_prefixed(ppc_inst_read(bp2->instr))) {
94562306a36Sopenharmony_ci			printf("Breakpoint at %lx is on the second word of a prefixed instruction, disabling it\n",
94662306a36Sopenharmony_ci			       bp->address);
94762306a36Sopenharmony_ci			bp->enabled = 0;
94862306a36Sopenharmony_ci			continue;
94962306a36Sopenharmony_ci		}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci		patch_instruction(bp->instr, instr);
95262306a36Sopenharmony_ci		patch_instruction(ppc_inst_next(bp->instr, bp->instr),
95362306a36Sopenharmony_ci				  ppc_inst(bpinstr));
95462306a36Sopenharmony_ci		if (bp->enabled & BP_CIABR)
95562306a36Sopenharmony_ci			continue;
95662306a36Sopenharmony_ci		if (patch_instruction((u32 *)bp->address,
95762306a36Sopenharmony_ci				      ppc_inst(bpinstr)) != 0) {
95862306a36Sopenharmony_ci			printf("Couldn't write instruction at %lx, "
95962306a36Sopenharmony_ci			       "disabling breakpoint there\n", bp->address);
96062306a36Sopenharmony_ci			bp->enabled &= ~BP_TRAP;
96162306a36Sopenharmony_ci			continue;
96262306a36Sopenharmony_ci		}
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic void insert_cpu_bpts(void)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	int i;
96962306a36Sopenharmony_ci	struct arch_hw_breakpoint brk;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	for (i = 0; i < nr_wp_slots(); i++) {
97262306a36Sopenharmony_ci		if (dabr[i].enabled) {
97362306a36Sopenharmony_ci			brk.address = dabr[i].address;
97462306a36Sopenharmony_ci			brk.type = (dabr[i].enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
97562306a36Sopenharmony_ci			brk.len = 8;
97662306a36Sopenharmony_ci			brk.hw_len = 8;
97762306a36Sopenharmony_ci			__set_breakpoint(i, &brk);
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (iabr)
98262306a36Sopenharmony_ci		set_ciabr(iabr->address);
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic void remove_bpts(void)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	int i;
98862306a36Sopenharmony_ci	struct bpt *bp;
98962306a36Sopenharmony_ci	ppc_inst_t instr;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	bp = bpts;
99262306a36Sopenharmony_ci	for (i = 0; i < NBPTS; ++i, ++bp) {
99362306a36Sopenharmony_ci		if ((bp->enabled & (BP_TRAP|BP_CIABR)) != BP_TRAP)
99462306a36Sopenharmony_ci			continue;
99562306a36Sopenharmony_ci		if (mread_instr(bp->address, &instr)
99662306a36Sopenharmony_ci		    && ppc_inst_equal(instr, ppc_inst(bpinstr))
99762306a36Sopenharmony_ci		    && patch_instruction(
99862306a36Sopenharmony_ci			(u32 *)bp->address, ppc_inst_read(bp->instr)) != 0)
99962306a36Sopenharmony_ci			printf("Couldn't remove breakpoint at %lx\n",
100062306a36Sopenharmony_ci			       bp->address);
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic void remove_cpu_bpts(void)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	hw_breakpoint_disable();
100762306a36Sopenharmony_ci	write_ciabr(0);
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci/* Based on uptime_proc_show(). */
101162306a36Sopenharmony_cistatic void
101262306a36Sopenharmony_cishow_uptime(void)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	struct timespec64 uptime;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
101762306a36Sopenharmony_ci		catch_memory_errors = 1;
101862306a36Sopenharmony_ci		sync();
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci		ktime_get_coarse_boottime_ts64(&uptime);
102162306a36Sopenharmony_ci		printf("Uptime: %lu.%.2lu seconds\n", (unsigned long)uptime.tv_sec,
102262306a36Sopenharmony_ci			((unsigned long)uptime.tv_nsec / (NSEC_PER_SEC/100)));
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci		sync();
102562306a36Sopenharmony_ci		__delay(200);						\
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci	catch_memory_errors = 0;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic void set_lpp_cmd(void)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	unsigned long lpp;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (!scanhex(&lpp)) {
103562306a36Sopenharmony_ci		printf("Invalid number.\n");
103662306a36Sopenharmony_ci		lpp = 0;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci	xmon_set_pagination_lpp(lpp);
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci/* Command interpreting routine */
104162306a36Sopenharmony_cistatic char *last_cmd;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_cistatic int
104462306a36Sopenharmony_cicmds(struct pt_regs *excp)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	int cmd = 0;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	last_cmd = NULL;
104962306a36Sopenharmony_ci	xmon_regs = excp;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	for(;;) {
105462306a36Sopenharmony_ci#ifdef CONFIG_SMP
105562306a36Sopenharmony_ci		printf("%x:", smp_processor_id());
105662306a36Sopenharmony_ci#endif /* CONFIG_SMP */
105762306a36Sopenharmony_ci		printf("mon> ");
105862306a36Sopenharmony_ci		flush_input();
105962306a36Sopenharmony_ci		termch = 0;
106062306a36Sopenharmony_ci		cmd = skipbl();
106162306a36Sopenharmony_ci		if( cmd == '\n' ) {
106262306a36Sopenharmony_ci			if (last_cmd == NULL)
106362306a36Sopenharmony_ci				continue;
106462306a36Sopenharmony_ci			take_input(last_cmd);
106562306a36Sopenharmony_ci			last_cmd = NULL;
106662306a36Sopenharmony_ci			cmd = inchar();
106762306a36Sopenharmony_ci		}
106862306a36Sopenharmony_ci		switch (cmd) {
106962306a36Sopenharmony_ci		case 'm':
107062306a36Sopenharmony_ci			cmd = inchar();
107162306a36Sopenharmony_ci			switch (cmd) {
107262306a36Sopenharmony_ci			case 'm':
107362306a36Sopenharmony_ci			case 's':
107462306a36Sopenharmony_ci			case 'd':
107562306a36Sopenharmony_ci				memops(cmd);
107662306a36Sopenharmony_ci				break;
107762306a36Sopenharmony_ci			case 'l':
107862306a36Sopenharmony_ci				memlocate();
107962306a36Sopenharmony_ci				break;
108062306a36Sopenharmony_ci			case 'z':
108162306a36Sopenharmony_ci				if (xmon_is_ro) {
108262306a36Sopenharmony_ci					printf(xmon_ro_msg);
108362306a36Sopenharmony_ci					break;
108462306a36Sopenharmony_ci				}
108562306a36Sopenharmony_ci				memzcan();
108662306a36Sopenharmony_ci				break;
108762306a36Sopenharmony_ci			case 'i':
108862306a36Sopenharmony_ci				show_mem();
108962306a36Sopenharmony_ci				break;
109062306a36Sopenharmony_ci			default:
109162306a36Sopenharmony_ci				termch = cmd;
109262306a36Sopenharmony_ci				memex();
109362306a36Sopenharmony_ci			}
109462306a36Sopenharmony_ci			break;
109562306a36Sopenharmony_ci		case 'd':
109662306a36Sopenharmony_ci			dump();
109762306a36Sopenharmony_ci			break;
109862306a36Sopenharmony_ci		case 'l':
109962306a36Sopenharmony_ci			symbol_lookup();
110062306a36Sopenharmony_ci			break;
110162306a36Sopenharmony_ci		case 'r':
110262306a36Sopenharmony_ci			prregs(excp);	/* print regs */
110362306a36Sopenharmony_ci			break;
110462306a36Sopenharmony_ci		case 'e':
110562306a36Sopenharmony_ci			excprint(excp);
110662306a36Sopenharmony_ci			break;
110762306a36Sopenharmony_ci		case 'S':
110862306a36Sopenharmony_ci			super_regs();
110962306a36Sopenharmony_ci			break;
111062306a36Sopenharmony_ci		case 't':
111162306a36Sopenharmony_ci			backtrace(excp);
111262306a36Sopenharmony_ci			break;
111362306a36Sopenharmony_ci		case 'f':
111462306a36Sopenharmony_ci			cacheflush();
111562306a36Sopenharmony_ci			break;
111662306a36Sopenharmony_ci		case 's':
111762306a36Sopenharmony_ci			if (do_spu_cmd() == 0)
111862306a36Sopenharmony_ci				break;
111962306a36Sopenharmony_ci			if (do_step(excp))
112062306a36Sopenharmony_ci				return cmd;
112162306a36Sopenharmony_ci			break;
112262306a36Sopenharmony_ci		case 'x':
112362306a36Sopenharmony_ci		case 'X':
112462306a36Sopenharmony_ci			if (tracing_enabled)
112562306a36Sopenharmony_ci				tracing_on();
112662306a36Sopenharmony_ci			return cmd;
112762306a36Sopenharmony_ci		case EOF:
112862306a36Sopenharmony_ci			printf(" <no input ...>\n");
112962306a36Sopenharmony_ci			mdelay(2000);
113062306a36Sopenharmony_ci			return cmd;
113162306a36Sopenharmony_ci		case '?':
113262306a36Sopenharmony_ci			xmon_puts(help_string);
113362306a36Sopenharmony_ci			break;
113462306a36Sopenharmony_ci		case '#':
113562306a36Sopenharmony_ci			set_lpp_cmd();
113662306a36Sopenharmony_ci			break;
113762306a36Sopenharmony_ci		case 'b':
113862306a36Sopenharmony_ci			bpt_cmds();
113962306a36Sopenharmony_ci			break;
114062306a36Sopenharmony_ci		case 'C':
114162306a36Sopenharmony_ci			csum();
114262306a36Sopenharmony_ci			break;
114362306a36Sopenharmony_ci		case 'c':
114462306a36Sopenharmony_ci			if (cpu_cmd())
114562306a36Sopenharmony_ci				return 0;
114662306a36Sopenharmony_ci			break;
114762306a36Sopenharmony_ci		case 'z':
114862306a36Sopenharmony_ci			bootcmds();
114962306a36Sopenharmony_ci			break;
115062306a36Sopenharmony_ci		case 'p':
115162306a36Sopenharmony_ci			if (xmon_is_ro) {
115262306a36Sopenharmony_ci				printf(xmon_ro_msg);
115362306a36Sopenharmony_ci				break;
115462306a36Sopenharmony_ci			}
115562306a36Sopenharmony_ci			proccall();
115662306a36Sopenharmony_ci			break;
115762306a36Sopenharmony_ci		case 'P':
115862306a36Sopenharmony_ci			show_tasks();
115962306a36Sopenharmony_ci			break;
116062306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_PPC_64S_HASH_MMU)
116162306a36Sopenharmony_ci		case 'u':
116262306a36Sopenharmony_ci			dump_segments();
116362306a36Sopenharmony_ci			break;
116462306a36Sopenharmony_ci#elif defined(CONFIG_44x)
116562306a36Sopenharmony_ci		case 'u':
116662306a36Sopenharmony_ci			dump_tlb_44x();
116762306a36Sopenharmony_ci			break;
116862306a36Sopenharmony_ci#elif defined(CONFIG_PPC_BOOK3E_64)
116962306a36Sopenharmony_ci		case 'u':
117062306a36Sopenharmony_ci			dump_tlb_book3e();
117162306a36Sopenharmony_ci			break;
117262306a36Sopenharmony_ci#endif
117362306a36Sopenharmony_ci		case 'U':
117462306a36Sopenharmony_ci			show_uptime();
117562306a36Sopenharmony_ci			break;
117662306a36Sopenharmony_ci		default:
117762306a36Sopenharmony_ci			printf("Unrecognized command: ");
117862306a36Sopenharmony_ci			do {
117962306a36Sopenharmony_ci				if (' ' < cmd && cmd <= '~')
118062306a36Sopenharmony_ci					putchar(cmd);
118162306a36Sopenharmony_ci				else
118262306a36Sopenharmony_ci					printf("\\x%x", cmd);
118362306a36Sopenharmony_ci				cmd = inchar();
118462306a36Sopenharmony_ci			} while (cmd != '\n');
118562306a36Sopenharmony_ci			printf(" (type ? for help)\n");
118662306a36Sopenharmony_ci			break;
118762306a36Sopenharmony_ci		}
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci#ifdef CONFIG_BOOKE
119262306a36Sopenharmony_cistatic int do_step(struct pt_regs *regs)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	regs_set_return_msr(regs, regs->msr | MSR_DE);
119562306a36Sopenharmony_ci	mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
119662306a36Sopenharmony_ci	return 1;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci#else
119962306a36Sopenharmony_ci/*
120062306a36Sopenharmony_ci * Step a single instruction.
120162306a36Sopenharmony_ci * Some instructions we emulate, others we execute with MSR_SE set.
120262306a36Sopenharmony_ci */
120362306a36Sopenharmony_cistatic int do_step(struct pt_regs *regs)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	ppc_inst_t instr;
120662306a36Sopenharmony_ci	int stepped;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	force_enable_xmon();
120962306a36Sopenharmony_ci	/* check we are in 64-bit kernel mode, translation enabled */
121062306a36Sopenharmony_ci	if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
121162306a36Sopenharmony_ci		if (mread_instr(regs->nip, &instr)) {
121262306a36Sopenharmony_ci			stepped = emulate_step(regs, instr);
121362306a36Sopenharmony_ci			if (stepped < 0) {
121462306a36Sopenharmony_ci				printf("Couldn't single-step %s instruction\n",
121562306a36Sopenharmony_ci				       (IS_RFID(instr)? "rfid": "mtmsrd"));
121662306a36Sopenharmony_ci				return 0;
121762306a36Sopenharmony_ci			}
121862306a36Sopenharmony_ci			if (stepped > 0) {
121962306a36Sopenharmony_ci				set_trap(regs, 0xd00);
122062306a36Sopenharmony_ci				printf("stepped to ");
122162306a36Sopenharmony_ci				xmon_print_symbol(regs->nip, " ", "\n");
122262306a36Sopenharmony_ci				ppc_inst_dump(regs->nip, 1, 0);
122362306a36Sopenharmony_ci				return 0;
122462306a36Sopenharmony_ci			}
122562306a36Sopenharmony_ci		}
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci	regs_set_return_msr(regs, regs->msr | MSR_SE);
122862306a36Sopenharmony_ci	return 1;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ci#endif
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_cistatic void bootcmds(void)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	char tmp[64];
123562306a36Sopenharmony_ci	int cmd;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	cmd = inchar();
123862306a36Sopenharmony_ci	if (cmd == 'r') {
123962306a36Sopenharmony_ci		getstring(tmp, 64);
124062306a36Sopenharmony_ci		ppc_md.restart(tmp);
124162306a36Sopenharmony_ci	} else if (cmd == 'h') {
124262306a36Sopenharmony_ci		ppc_md.halt();
124362306a36Sopenharmony_ci	} else if (cmd == 'p') {
124462306a36Sopenharmony_ci		do_kernel_power_off();
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci#ifdef CONFIG_SMP
124962306a36Sopenharmony_cistatic int xmon_switch_cpu(unsigned long cpu)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	int timeout;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	xmon_taken = 0;
125462306a36Sopenharmony_ci	mb();
125562306a36Sopenharmony_ci	xmon_owner = cpu;
125662306a36Sopenharmony_ci	timeout = 10000000;
125762306a36Sopenharmony_ci	while (!xmon_taken) {
125862306a36Sopenharmony_ci		if (--timeout == 0) {
125962306a36Sopenharmony_ci			if (test_and_set_bit(0, &xmon_taken))
126062306a36Sopenharmony_ci				break;
126162306a36Sopenharmony_ci			/* take control back */
126262306a36Sopenharmony_ci			mb();
126362306a36Sopenharmony_ci			xmon_owner = smp_processor_id();
126462306a36Sopenharmony_ci			printf("cpu 0x%lx didn't take control\n", cpu);
126562306a36Sopenharmony_ci			return 0;
126662306a36Sopenharmony_ci		}
126762306a36Sopenharmony_ci		barrier();
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci	return 1;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic int xmon_batch_next_cpu(void)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	unsigned long cpu;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	while (!cpumask_empty(&xmon_batch_cpus)) {
127762306a36Sopenharmony_ci		cpu = cpumask_next_wrap(smp_processor_id(), &xmon_batch_cpus,
127862306a36Sopenharmony_ci					xmon_batch_start_cpu, true);
127962306a36Sopenharmony_ci		if (cpu >= nr_cpu_ids)
128062306a36Sopenharmony_ci			break;
128162306a36Sopenharmony_ci		if (xmon_batch_start_cpu == -1)
128262306a36Sopenharmony_ci			xmon_batch_start_cpu = cpu;
128362306a36Sopenharmony_ci		if (xmon_switch_cpu(cpu))
128462306a36Sopenharmony_ci			return 0;
128562306a36Sopenharmony_ci		cpumask_clear_cpu(cpu, &xmon_batch_cpus);
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	xmon_batch = 0;
128962306a36Sopenharmony_ci	printf("%x:mon> \n", smp_processor_id());
129062306a36Sopenharmony_ci	return 1;
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic int batch_cmds(struct pt_regs *excp)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	int cmd;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	/* simulate command entry */
129862306a36Sopenharmony_ci	cmd = xmon_batch;
129962306a36Sopenharmony_ci	termch = '\n';
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	last_cmd = NULL;
130262306a36Sopenharmony_ci	xmon_regs = excp;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	printf("%x:", smp_processor_id());
130562306a36Sopenharmony_ci	printf("mon> ");
130662306a36Sopenharmony_ci	printf("%c\n", (char)cmd);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	switch (cmd) {
130962306a36Sopenharmony_ci	case 'r':
131062306a36Sopenharmony_ci		prregs(excp);	/* print regs */
131162306a36Sopenharmony_ci		break;
131262306a36Sopenharmony_ci	case 'S':
131362306a36Sopenharmony_ci		super_regs();
131462306a36Sopenharmony_ci		break;
131562306a36Sopenharmony_ci	case 't':
131662306a36Sopenharmony_ci		backtrace(excp);
131762306a36Sopenharmony_ci		break;
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	cpumask_clear_cpu(smp_processor_id(), &xmon_batch_cpus);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	return xmon_batch_next_cpu();
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic int cpu_cmd(void)
132662306a36Sopenharmony_ci{
132762306a36Sopenharmony_ci	unsigned long cpu, first_cpu, last_cpu;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	cpu = skipbl();
133062306a36Sopenharmony_ci	if (cpu == '#') {
133162306a36Sopenharmony_ci		xmon_batch = skipbl();
133262306a36Sopenharmony_ci		if (xmon_batch) {
133362306a36Sopenharmony_ci			switch (xmon_batch) {
133462306a36Sopenharmony_ci			case 'r':
133562306a36Sopenharmony_ci			case 'S':
133662306a36Sopenharmony_ci			case 't':
133762306a36Sopenharmony_ci				cpumask_copy(&xmon_batch_cpus, &cpus_in_xmon);
133862306a36Sopenharmony_ci				if (cpumask_weight(&xmon_batch_cpus) <= 1) {
133962306a36Sopenharmony_ci					printf("There are no other cpus in xmon\n");
134062306a36Sopenharmony_ci					break;
134162306a36Sopenharmony_ci				}
134262306a36Sopenharmony_ci				xmon_batch_start_cpu = -1;
134362306a36Sopenharmony_ci				if (!xmon_batch_next_cpu())
134462306a36Sopenharmony_ci					return 1;
134562306a36Sopenharmony_ci				break;
134662306a36Sopenharmony_ci			default:
134762306a36Sopenharmony_ci				printf("c# only supports 'r', 'S' and 't' commands\n");
134862306a36Sopenharmony_ci			}
134962306a36Sopenharmony_ci			xmon_batch = 0;
135062306a36Sopenharmony_ci			return 0;
135162306a36Sopenharmony_ci		}
135262306a36Sopenharmony_ci	}
135362306a36Sopenharmony_ci	termch = cpu;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (!scanhex(&cpu)) {
135662306a36Sopenharmony_ci		/* print cpus waiting or in xmon */
135762306a36Sopenharmony_ci		printf("cpus stopped:");
135862306a36Sopenharmony_ci		last_cpu = first_cpu = NR_CPUS;
135962306a36Sopenharmony_ci		for_each_possible_cpu(cpu) {
136062306a36Sopenharmony_ci			if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
136162306a36Sopenharmony_ci				if (cpu == last_cpu + 1) {
136262306a36Sopenharmony_ci					last_cpu = cpu;
136362306a36Sopenharmony_ci				} else {
136462306a36Sopenharmony_ci					if (last_cpu != first_cpu)
136562306a36Sopenharmony_ci						printf("-0x%lx", last_cpu);
136662306a36Sopenharmony_ci					last_cpu = first_cpu = cpu;
136762306a36Sopenharmony_ci					printf(" 0x%lx", cpu);
136862306a36Sopenharmony_ci				}
136962306a36Sopenharmony_ci			}
137062306a36Sopenharmony_ci		}
137162306a36Sopenharmony_ci		if (last_cpu != first_cpu)
137262306a36Sopenharmony_ci			printf("-0x%lx", last_cpu);
137362306a36Sopenharmony_ci		printf("\n");
137462306a36Sopenharmony_ci		return 0;
137562306a36Sopenharmony_ci	}
137662306a36Sopenharmony_ci	/* try to switch to cpu specified */
137762306a36Sopenharmony_ci	if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
137862306a36Sopenharmony_ci		printf("cpu 0x%lx isn't in xmon\n", cpu);
137962306a36Sopenharmony_ci#ifdef CONFIG_PPC64
138062306a36Sopenharmony_ci		printf("backtrace of paca[0x%lx].saved_r1 (possibly stale):\n", cpu);
138162306a36Sopenharmony_ci		xmon_show_stack(paca_ptrs[cpu]->saved_r1, 0, 0);
138262306a36Sopenharmony_ci#endif
138362306a36Sopenharmony_ci		return 0;
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	return xmon_switch_cpu(cpu);
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci#else
138962306a36Sopenharmony_cistatic int cpu_cmd(void)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	return 0;
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci#endif /* CONFIG_SMP */
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cistatic unsigned short fcstab[256] = {
139662306a36Sopenharmony_ci	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
139762306a36Sopenharmony_ci	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
139862306a36Sopenharmony_ci	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
139962306a36Sopenharmony_ci	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
140062306a36Sopenharmony_ci	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
140162306a36Sopenharmony_ci	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
140262306a36Sopenharmony_ci	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
140362306a36Sopenharmony_ci	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
140462306a36Sopenharmony_ci	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
140562306a36Sopenharmony_ci	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
140662306a36Sopenharmony_ci	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
140762306a36Sopenharmony_ci	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
140862306a36Sopenharmony_ci	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
140962306a36Sopenharmony_ci	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
141062306a36Sopenharmony_ci	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
141162306a36Sopenharmony_ci	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
141262306a36Sopenharmony_ci	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
141362306a36Sopenharmony_ci	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
141462306a36Sopenharmony_ci	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
141562306a36Sopenharmony_ci	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
141662306a36Sopenharmony_ci	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
141762306a36Sopenharmony_ci	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
141862306a36Sopenharmony_ci	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
141962306a36Sopenharmony_ci	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
142062306a36Sopenharmony_ci	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
142162306a36Sopenharmony_ci	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
142262306a36Sopenharmony_ci	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
142362306a36Sopenharmony_ci	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
142462306a36Sopenharmony_ci	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
142562306a36Sopenharmony_ci	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
142662306a36Sopenharmony_ci	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
142762306a36Sopenharmony_ci	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
142862306a36Sopenharmony_ci};
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci#define FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_cistatic void
143362306a36Sopenharmony_cicsum(void)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	unsigned int i;
143662306a36Sopenharmony_ci	unsigned short fcs;
143762306a36Sopenharmony_ci	unsigned char v;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (!scanhex(&adrs))
144062306a36Sopenharmony_ci		return;
144162306a36Sopenharmony_ci	if (!scanhex(&ncsum))
144262306a36Sopenharmony_ci		return;
144362306a36Sopenharmony_ci	fcs = 0xffff;
144462306a36Sopenharmony_ci	for (i = 0; i < ncsum; ++i) {
144562306a36Sopenharmony_ci		if (mread(adrs+i, &v, 1) == 0) {
144662306a36Sopenharmony_ci			printf("csum stopped at "REG"\n", adrs+i);
144762306a36Sopenharmony_ci			break;
144862306a36Sopenharmony_ci		}
144962306a36Sopenharmony_ci		fcs = FCS(fcs, v);
145062306a36Sopenharmony_ci	}
145162306a36Sopenharmony_ci	printf("%x\n", fcs);
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci/*
145562306a36Sopenharmony_ci * Check if this is a suitable place to put a breakpoint.
145662306a36Sopenharmony_ci */
145762306a36Sopenharmony_cistatic long check_bp_loc(unsigned long addr)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	ppc_inst_t instr;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	addr &= ~3;
146262306a36Sopenharmony_ci	if (!is_kernel_addr(addr)) {
146362306a36Sopenharmony_ci		printf("Breakpoints may only be placed at kernel addresses\n");
146462306a36Sopenharmony_ci		return 0;
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci	if (!mread_instr(addr, &instr)) {
146762306a36Sopenharmony_ci		printf("Can't read instruction at address %lx\n", addr);
146862306a36Sopenharmony_ci		return 0;
146962306a36Sopenharmony_ci	}
147062306a36Sopenharmony_ci	if (!can_single_step(ppc_inst_val(instr))) {
147162306a36Sopenharmony_ci		printf("Breakpoints may not be placed on instructions that can't be single stepped\n");
147262306a36Sopenharmony_ci		return 0;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci	return 1;
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_cistatic int find_free_data_bpt(void)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	int i;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	for (i = 0; i < nr_wp_slots(); i++) {
148262306a36Sopenharmony_ci		if (!dabr[i].enabled)
148362306a36Sopenharmony_ci			return i;
148462306a36Sopenharmony_ci	}
148562306a36Sopenharmony_ci	printf("Couldn't find free breakpoint register\n");
148662306a36Sopenharmony_ci	return -1;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic void print_data_bpts(void)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	int i;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	for (i = 0; i < nr_wp_slots(); i++) {
149462306a36Sopenharmony_ci		if (!dabr[i].enabled)
149562306a36Sopenharmony_ci			continue;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci		printf("   data   "REG"  [", dabr[i].address);
149862306a36Sopenharmony_ci		if (dabr[i].enabled & 1)
149962306a36Sopenharmony_ci			printf("r");
150062306a36Sopenharmony_ci		if (dabr[i].enabled & 2)
150162306a36Sopenharmony_ci			printf("w");
150262306a36Sopenharmony_ci		printf("]\n");
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic char *breakpoint_help_string =
150762306a36Sopenharmony_ci    "Breakpoint command usage:\n"
150862306a36Sopenharmony_ci    "b                show breakpoints\n"
150962306a36Sopenharmony_ci    "b <addr> [cnt]   set breakpoint at given instr addr\n"
151062306a36Sopenharmony_ci    "bc               clear all breakpoints\n"
151162306a36Sopenharmony_ci    "bc <n/addr>      clear breakpoint number n or at addr\n"
151262306a36Sopenharmony_ci    "bi <addr> [cnt]  set hardware instr breakpoint (POWER8 only)\n"
151362306a36Sopenharmony_ci    "bd <addr> [cnt]  set hardware data breakpoint\n"
151462306a36Sopenharmony_ci    "";
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_cistatic void
151762306a36Sopenharmony_cibpt_cmds(void)
151862306a36Sopenharmony_ci{
151962306a36Sopenharmony_ci	int cmd;
152062306a36Sopenharmony_ci	unsigned long a;
152162306a36Sopenharmony_ci	int i;
152262306a36Sopenharmony_ci	struct bpt *bp;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	cmd = inchar();
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	switch (cmd) {
152762306a36Sopenharmony_ci	case 'd': {	/* bd - hardware data breakpoint */
152862306a36Sopenharmony_ci		static const char badaddr[] = "Only kernel addresses are permitted for breakpoints\n";
152962306a36Sopenharmony_ci		int mode;
153062306a36Sopenharmony_ci		if (xmon_is_ro) {
153162306a36Sopenharmony_ci			printf(xmon_ro_msg);
153262306a36Sopenharmony_ci			break;
153362306a36Sopenharmony_ci		}
153462306a36Sopenharmony_ci		if (!ppc_breakpoint_available()) {
153562306a36Sopenharmony_ci			printf("Hardware data breakpoint not supported on this cpu\n");
153662306a36Sopenharmony_ci			break;
153762306a36Sopenharmony_ci		}
153862306a36Sopenharmony_ci		i = find_free_data_bpt();
153962306a36Sopenharmony_ci		if (i < 0)
154062306a36Sopenharmony_ci			break;
154162306a36Sopenharmony_ci		mode = 7;
154262306a36Sopenharmony_ci		cmd = inchar();
154362306a36Sopenharmony_ci		if (cmd == 'r')
154462306a36Sopenharmony_ci			mode = 5;
154562306a36Sopenharmony_ci		else if (cmd == 'w')
154662306a36Sopenharmony_ci			mode = 6;
154762306a36Sopenharmony_ci		else
154862306a36Sopenharmony_ci			termch = cmd;
154962306a36Sopenharmony_ci		dabr[i].address = 0;
155062306a36Sopenharmony_ci		dabr[i].enabled = 0;
155162306a36Sopenharmony_ci		if (scanhex(&dabr[i].address)) {
155262306a36Sopenharmony_ci			if (!is_kernel_addr(dabr[i].address)) {
155362306a36Sopenharmony_ci				printf(badaddr);
155462306a36Sopenharmony_ci				break;
155562306a36Sopenharmony_ci			}
155662306a36Sopenharmony_ci			dabr[i].address &= ~HW_BRK_TYPE_DABR;
155762306a36Sopenharmony_ci			dabr[i].enabled = mode | BP_DABR;
155862306a36Sopenharmony_ci		}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci		force_enable_xmon();
156162306a36Sopenharmony_ci		break;
156262306a36Sopenharmony_ci	}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	case 'i':	/* bi - hardware instr breakpoint */
156562306a36Sopenharmony_ci		if (xmon_is_ro) {
156662306a36Sopenharmony_ci			printf(xmon_ro_msg);
156762306a36Sopenharmony_ci			break;
156862306a36Sopenharmony_ci		}
156962306a36Sopenharmony_ci		if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
157062306a36Sopenharmony_ci			printf("Hardware instruction breakpoint "
157162306a36Sopenharmony_ci			       "not supported on this cpu\n");
157262306a36Sopenharmony_ci			break;
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci		if (iabr) {
157562306a36Sopenharmony_ci			iabr->enabled &= ~BP_CIABR;
157662306a36Sopenharmony_ci			iabr = NULL;
157762306a36Sopenharmony_ci		}
157862306a36Sopenharmony_ci		if (!scanhex(&a))
157962306a36Sopenharmony_ci			break;
158062306a36Sopenharmony_ci		if (!check_bp_loc(a))
158162306a36Sopenharmony_ci			break;
158262306a36Sopenharmony_ci		bp = new_breakpoint(a);
158362306a36Sopenharmony_ci		if (bp != NULL) {
158462306a36Sopenharmony_ci			bp->enabled |= BP_CIABR;
158562306a36Sopenharmony_ci			iabr = bp;
158662306a36Sopenharmony_ci			force_enable_xmon();
158762306a36Sopenharmony_ci		}
158862306a36Sopenharmony_ci		break;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	case 'c':
159162306a36Sopenharmony_ci		if (!scanhex(&a)) {
159262306a36Sopenharmony_ci			/* clear all breakpoints */
159362306a36Sopenharmony_ci			for (i = 0; i < NBPTS; ++i)
159462306a36Sopenharmony_ci				bpts[i].enabled = 0;
159562306a36Sopenharmony_ci			iabr = NULL;
159662306a36Sopenharmony_ci			for (i = 0; i < nr_wp_slots(); i++)
159762306a36Sopenharmony_ci				dabr[i].enabled = 0;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci			printf("All breakpoints cleared\n");
160062306a36Sopenharmony_ci			break;
160162306a36Sopenharmony_ci		}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		if (a <= NBPTS && a >= 1) {
160462306a36Sopenharmony_ci			/* assume a breakpoint number */
160562306a36Sopenharmony_ci			bp = &bpts[a-1];	/* bp nums are 1 based */
160662306a36Sopenharmony_ci		} else {
160762306a36Sopenharmony_ci			/* assume a breakpoint address */
160862306a36Sopenharmony_ci			bp = at_breakpoint(a);
160962306a36Sopenharmony_ci			if (bp == NULL) {
161062306a36Sopenharmony_ci				printf("No breakpoint at %lx\n", a);
161162306a36Sopenharmony_ci				break;
161262306a36Sopenharmony_ci			}
161362306a36Sopenharmony_ci		}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		printf("Cleared breakpoint %tx (", BP_NUM(bp));
161662306a36Sopenharmony_ci		xmon_print_symbol(bp->address, " ", ")\n");
161762306a36Sopenharmony_ci		bp->enabled = 0;
161862306a36Sopenharmony_ci		break;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	default:
162162306a36Sopenharmony_ci		termch = cmd;
162262306a36Sopenharmony_ci		cmd = skipbl();
162362306a36Sopenharmony_ci		if (cmd == '?') {
162462306a36Sopenharmony_ci			printf(breakpoint_help_string);
162562306a36Sopenharmony_ci			break;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci		termch = cmd;
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci		if (xmon_is_ro || !scanhex(&a)) {
163062306a36Sopenharmony_ci			/* print all breakpoints */
163162306a36Sopenharmony_ci			printf("   type            address\n");
163262306a36Sopenharmony_ci			print_data_bpts();
163362306a36Sopenharmony_ci			for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
163462306a36Sopenharmony_ci				if (!bp->enabled)
163562306a36Sopenharmony_ci					continue;
163662306a36Sopenharmony_ci				printf("%tx %s   ", BP_NUM(bp),
163762306a36Sopenharmony_ci				    (bp->enabled & BP_CIABR) ? "inst": "trap");
163862306a36Sopenharmony_ci				xmon_print_symbol(bp->address, "  ", "\n");
163962306a36Sopenharmony_ci			}
164062306a36Sopenharmony_ci			break;
164162306a36Sopenharmony_ci		}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci		if (!check_bp_loc(a))
164462306a36Sopenharmony_ci			break;
164562306a36Sopenharmony_ci		bp = new_breakpoint(a);
164662306a36Sopenharmony_ci		if (bp != NULL) {
164762306a36Sopenharmony_ci			bp->enabled |= BP_TRAP;
164862306a36Sopenharmony_ci			force_enable_xmon();
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci		break;
165162306a36Sopenharmony_ci	}
165262306a36Sopenharmony_ci}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci/* Very cheap human name for vector lookup. */
165562306a36Sopenharmony_cistatic
165662306a36Sopenharmony_ciconst char *getvecname(unsigned long vec)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	char *ret;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	switch (vec) {
166162306a36Sopenharmony_ci	case 0x100:	ret = "(System Reset)"; break;
166262306a36Sopenharmony_ci	case 0x200:	ret = "(Machine Check)"; break;
166362306a36Sopenharmony_ci	case 0x300:	ret = "(Data Access)"; break;
166462306a36Sopenharmony_ci	case 0x380:
166562306a36Sopenharmony_ci		if (radix_enabled())
166662306a36Sopenharmony_ci			ret = "(Data Access Out of Range)";
166762306a36Sopenharmony_ci		else
166862306a36Sopenharmony_ci			ret = "(Data SLB Access)";
166962306a36Sopenharmony_ci		break;
167062306a36Sopenharmony_ci	case 0x400:	ret = "(Instruction Access)"; break;
167162306a36Sopenharmony_ci	case 0x480:
167262306a36Sopenharmony_ci		if (radix_enabled())
167362306a36Sopenharmony_ci			ret = "(Instruction Access Out of Range)";
167462306a36Sopenharmony_ci		else
167562306a36Sopenharmony_ci			ret = "(Instruction SLB Access)";
167662306a36Sopenharmony_ci		break;
167762306a36Sopenharmony_ci	case 0x500:	ret = "(Hardware Interrupt)"; break;
167862306a36Sopenharmony_ci	case 0x600:	ret = "(Alignment)"; break;
167962306a36Sopenharmony_ci	case 0x700:	ret = "(Program Check)"; break;
168062306a36Sopenharmony_ci	case 0x800:	ret = "(FPU Unavailable)"; break;
168162306a36Sopenharmony_ci	case 0x900:	ret = "(Decrementer)"; break;
168262306a36Sopenharmony_ci	case 0x980:	ret = "(Hypervisor Decrementer)"; break;
168362306a36Sopenharmony_ci	case 0xa00:	ret = "(Doorbell)"; break;
168462306a36Sopenharmony_ci	case 0xc00:	ret = "(System Call)"; break;
168562306a36Sopenharmony_ci	case 0xd00:	ret = "(Single Step)"; break;
168662306a36Sopenharmony_ci	case 0xe40:	ret = "(Emulation Assist)"; break;
168762306a36Sopenharmony_ci	case 0xe60:	ret = "(HMI)"; break;
168862306a36Sopenharmony_ci	case 0xe80:	ret = "(Hypervisor Doorbell)"; break;
168962306a36Sopenharmony_ci	case 0xf00:	ret = "(Performance Monitor)"; break;
169062306a36Sopenharmony_ci	case 0xf20:	ret = "(Altivec Unavailable)"; break;
169162306a36Sopenharmony_ci	case 0x1300:	ret = "(Instruction Breakpoint)"; break;
169262306a36Sopenharmony_ci	case 0x1500:	ret = "(Denormalisation)"; break;
169362306a36Sopenharmony_ci	case 0x1700:	ret = "(Altivec Assist)"; break;
169462306a36Sopenharmony_ci	case 0x3000:	ret = "(System Call Vectored)"; break;
169562306a36Sopenharmony_ci	default: ret = "";
169662306a36Sopenharmony_ci	}
169762306a36Sopenharmony_ci	return ret;
169862306a36Sopenharmony_ci}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_cistatic void get_function_bounds(unsigned long pc, unsigned long *startp,
170162306a36Sopenharmony_ci				unsigned long *endp)
170262306a36Sopenharmony_ci{
170362306a36Sopenharmony_ci	unsigned long size, offset;
170462306a36Sopenharmony_ci	const char *name;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	*startp = *endp = 0;
170762306a36Sopenharmony_ci	if (pc == 0)
170862306a36Sopenharmony_ci		return;
170962306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
171062306a36Sopenharmony_ci		catch_memory_errors = 1;
171162306a36Sopenharmony_ci		sync();
171262306a36Sopenharmony_ci		name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
171362306a36Sopenharmony_ci		if (name != NULL) {
171462306a36Sopenharmony_ci			*startp = pc - offset;
171562306a36Sopenharmony_ci			*endp = pc - offset + size;
171662306a36Sopenharmony_ci		}
171762306a36Sopenharmony_ci		sync();
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci	catch_memory_errors = 0;
172062306a36Sopenharmony_ci}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci#define LRSAVE_OFFSET		(STACK_FRAME_LR_SAVE * sizeof(unsigned long))
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_cistatic void xmon_show_stack(unsigned long sp, unsigned long lr,
172562306a36Sopenharmony_ci			    unsigned long pc)
172662306a36Sopenharmony_ci{
172762306a36Sopenharmony_ci	int max_to_print = 64;
172862306a36Sopenharmony_ci	unsigned long ip;
172962306a36Sopenharmony_ci	unsigned long newsp;
173062306a36Sopenharmony_ci	unsigned long marker;
173162306a36Sopenharmony_ci	struct pt_regs regs;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	while (max_to_print--) {
173462306a36Sopenharmony_ci		if (!is_kernel_addr(sp)) {
173562306a36Sopenharmony_ci			if (sp != 0)
173662306a36Sopenharmony_ci				printf("SP (%lx) is in userspace\n", sp);
173762306a36Sopenharmony_ci			break;
173862306a36Sopenharmony_ci		}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
174162306a36Sopenharmony_ci		    || !mread(sp, &newsp, sizeof(unsigned long))) {
174262306a36Sopenharmony_ci			printf("Couldn't read stack frame at %lx\n", sp);
174362306a36Sopenharmony_ci			break;
174462306a36Sopenharmony_ci		}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci		/*
174762306a36Sopenharmony_ci		 * For the first stack frame, try to work out if
174862306a36Sopenharmony_ci		 * LR and/or the saved LR value in the bottommost
174962306a36Sopenharmony_ci		 * stack frame are valid.
175062306a36Sopenharmony_ci		 */
175162306a36Sopenharmony_ci		if ((pc | lr) != 0) {
175262306a36Sopenharmony_ci			unsigned long fnstart, fnend;
175362306a36Sopenharmony_ci			unsigned long nextip;
175462306a36Sopenharmony_ci			int printip = 1;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci			get_function_bounds(pc, &fnstart, &fnend);
175762306a36Sopenharmony_ci			nextip = 0;
175862306a36Sopenharmony_ci			if (newsp > sp)
175962306a36Sopenharmony_ci				mread(newsp + LRSAVE_OFFSET, &nextip,
176062306a36Sopenharmony_ci				      sizeof(unsigned long));
176162306a36Sopenharmony_ci			if (lr == ip) {
176262306a36Sopenharmony_ci				if (!is_kernel_addr(lr)
176362306a36Sopenharmony_ci				    || (fnstart <= lr && lr < fnend))
176462306a36Sopenharmony_ci					printip = 0;
176562306a36Sopenharmony_ci			} else if (lr == nextip) {
176662306a36Sopenharmony_ci				printip = 0;
176762306a36Sopenharmony_ci			} else if (is_kernel_addr(lr)
176862306a36Sopenharmony_ci				   && !(fnstart <= lr && lr < fnend)) {
176962306a36Sopenharmony_ci				printf("[link register   ] ");
177062306a36Sopenharmony_ci				xmon_print_symbol(lr, " ", "\n");
177162306a36Sopenharmony_ci			}
177262306a36Sopenharmony_ci			if (printip) {
177362306a36Sopenharmony_ci				printf("["REG"] ", sp);
177462306a36Sopenharmony_ci				xmon_print_symbol(ip, " ", " (unreliable)\n");
177562306a36Sopenharmony_ci			}
177662306a36Sopenharmony_ci			pc = lr = 0;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci		} else {
177962306a36Sopenharmony_ci			printf("["REG"] ", sp);
178062306a36Sopenharmony_ci			xmon_print_symbol(ip, " ", "\n");
178162306a36Sopenharmony_ci		}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci		/* Look for "regs" marker to see if this is
178462306a36Sopenharmony_ci		   an exception frame. */
178562306a36Sopenharmony_ci		if (mread(sp + STACK_INT_FRAME_MARKER, &marker, sizeof(unsigned long))
178662306a36Sopenharmony_ci		    && marker == STACK_FRAME_REGS_MARKER) {
178762306a36Sopenharmony_ci			if (mread(sp + STACK_INT_FRAME_REGS, &regs, sizeof(regs)) != sizeof(regs)) {
178862306a36Sopenharmony_ci				printf("Couldn't read registers at %lx\n",
178962306a36Sopenharmony_ci				       sp + STACK_INT_FRAME_REGS);
179062306a36Sopenharmony_ci				break;
179162306a36Sopenharmony_ci			}
179262306a36Sopenharmony_ci			printf("--- Exception: %lx %s at ", regs.trap,
179362306a36Sopenharmony_ci			       getvecname(TRAP(&regs)));
179462306a36Sopenharmony_ci			pc = regs.nip;
179562306a36Sopenharmony_ci			lr = regs.link;
179662306a36Sopenharmony_ci			xmon_print_symbol(pc, " ", "\n");
179762306a36Sopenharmony_ci		}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci		if (newsp == 0)
180062306a36Sopenharmony_ci			break;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci		sp = newsp;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_cistatic void backtrace(struct pt_regs *excp)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci	unsigned long sp;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	if (scanhex(&sp))
181162306a36Sopenharmony_ci		xmon_show_stack(sp, 0, 0);
181262306a36Sopenharmony_ci	else
181362306a36Sopenharmony_ci		xmon_show_stack(excp->gpr[1], excp->link, excp->nip);
181462306a36Sopenharmony_ci	scannl();
181562306a36Sopenharmony_ci}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_cistatic void print_bug_trap(struct pt_regs *regs)
181862306a36Sopenharmony_ci{
181962306a36Sopenharmony_ci#ifdef CONFIG_BUG
182062306a36Sopenharmony_ci	const struct bug_entry *bug;
182162306a36Sopenharmony_ci	unsigned long addr;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	if (regs->msr & MSR_PR)
182462306a36Sopenharmony_ci		return;		/* not in kernel */
182562306a36Sopenharmony_ci	addr = regs->nip;	/* address of trap instruction */
182662306a36Sopenharmony_ci	if (!is_kernel_addr(addr))
182762306a36Sopenharmony_ci		return;
182862306a36Sopenharmony_ci	bug = find_bug(regs->nip);
182962306a36Sopenharmony_ci	if (bug == NULL)
183062306a36Sopenharmony_ci		return;
183162306a36Sopenharmony_ci	if (is_warning_bug(bug))
183262306a36Sopenharmony_ci		return;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_BUGVERBOSE
183562306a36Sopenharmony_ci	printf("kernel BUG at %s:%u!\n",
183662306a36Sopenharmony_ci	       (char *)bug + bug->file_disp, bug->line);
183762306a36Sopenharmony_ci#else
183862306a36Sopenharmony_ci	printf("kernel BUG at %px!\n", (void *)bug + bug->bug_addr_disp);
183962306a36Sopenharmony_ci#endif
184062306a36Sopenharmony_ci#endif /* CONFIG_BUG */
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_cistatic void excprint(struct pt_regs *fp)
184462306a36Sopenharmony_ci{
184562306a36Sopenharmony_ci	unsigned long trap;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci#ifdef CONFIG_SMP
184862306a36Sopenharmony_ci	printf("cpu 0x%x: ", smp_processor_id());
184962306a36Sopenharmony_ci#endif /* CONFIG_SMP */
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	trap = TRAP(fp);
185262306a36Sopenharmony_ci	printf("Vector: %lx %s at [%px]\n", fp->trap, getvecname(trap), fp);
185362306a36Sopenharmony_ci	printf("    pc: ");
185462306a36Sopenharmony_ci	xmon_print_symbol(fp->nip, ": ", "\n");
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	printf("    lr: ");
185762306a36Sopenharmony_ci	xmon_print_symbol(fp->link, ": ", "\n");
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	printf("    sp: %lx\n", fp->gpr[1]);
186062306a36Sopenharmony_ci	printf("   msr: %lx\n", fp->msr);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	if (trap == INTERRUPT_DATA_STORAGE ||
186362306a36Sopenharmony_ci	    trap == INTERRUPT_DATA_SEGMENT ||
186462306a36Sopenharmony_ci	    trap == INTERRUPT_ALIGNMENT ||
186562306a36Sopenharmony_ci	    trap == INTERRUPT_MACHINE_CHECK) {
186662306a36Sopenharmony_ci		printf("   dar: %lx\n", fp->dar);
186762306a36Sopenharmony_ci		if (trap != INTERRUPT_DATA_SEGMENT)
186862306a36Sopenharmony_ci			printf(" dsisr: %lx\n", fp->dsisr);
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	printf("  current = 0x%px\n", current);
187262306a36Sopenharmony_ci#ifdef CONFIG_PPC64
187362306a36Sopenharmony_ci	printf("  paca    = 0x%px\t irqmask: 0x%02x\t irq_happened: 0x%02x\n",
187462306a36Sopenharmony_ci	       local_paca, local_paca->irq_soft_mask, local_paca->irq_happened);
187562306a36Sopenharmony_ci#endif
187662306a36Sopenharmony_ci	if (current) {
187762306a36Sopenharmony_ci		printf("    pid   = %d, comm = %s\n",
187862306a36Sopenharmony_ci		       current->pid, current->comm);
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	if (trap == INTERRUPT_PROGRAM)
188262306a36Sopenharmony_ci		print_bug_trap(fp);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	printf(linux_banner);
188562306a36Sopenharmony_ci}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_cistatic void prregs(struct pt_regs *fp)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci	int n, trap;
189062306a36Sopenharmony_ci	unsigned long base;
189162306a36Sopenharmony_ci	struct pt_regs regs;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	if (scanhex(&base)) {
189462306a36Sopenharmony_ci		if (setjmp(bus_error_jmp) == 0) {
189562306a36Sopenharmony_ci			catch_memory_errors = 1;
189662306a36Sopenharmony_ci			sync();
189762306a36Sopenharmony_ci			regs = *(struct pt_regs *)base;
189862306a36Sopenharmony_ci			sync();
189962306a36Sopenharmony_ci			__delay(200);
190062306a36Sopenharmony_ci		} else {
190162306a36Sopenharmony_ci			catch_memory_errors = 0;
190262306a36Sopenharmony_ci			printf("*** Error reading registers from "REG"\n",
190362306a36Sopenharmony_ci			       base);
190462306a36Sopenharmony_ci			return;
190562306a36Sopenharmony_ci		}
190662306a36Sopenharmony_ci		catch_memory_errors = 0;
190762306a36Sopenharmony_ci		fp = &regs;
190862306a36Sopenharmony_ci	}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci#ifdef CONFIG_PPC64
191162306a36Sopenharmony_ci#define R_PER_LINE 2
191262306a36Sopenharmony_ci#else
191362306a36Sopenharmony_ci#define R_PER_LINE 4
191462306a36Sopenharmony_ci#endif
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	for (n = 0; n < 32; ++n) {
191762306a36Sopenharmony_ci		printf("R%.2d = "REG"%s", n, fp->gpr[n],
191862306a36Sopenharmony_ci			(n % R_PER_LINE) == R_PER_LINE - 1 ? "\n" : "   ");
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	printf("pc  = ");
192262306a36Sopenharmony_ci	xmon_print_symbol(fp->nip, " ", "\n");
192362306a36Sopenharmony_ci	if (!trap_is_syscall(fp) && cpu_has_feature(CPU_FTR_CFAR)) {
192462306a36Sopenharmony_ci		printf("cfar= ");
192562306a36Sopenharmony_ci		xmon_print_symbol(fp->orig_gpr3, " ", "\n");
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci	printf("lr  = ");
192862306a36Sopenharmony_ci	xmon_print_symbol(fp->link, " ", "\n");
192962306a36Sopenharmony_ci	printf("msr = "REG"   cr  = %.8lx\n", fp->msr, fp->ccr);
193062306a36Sopenharmony_ci	printf("ctr = "REG"   xer = "REG"   trap = %4lx\n",
193162306a36Sopenharmony_ci	       fp->ctr, fp->xer, fp->trap);
193262306a36Sopenharmony_ci	trap = TRAP(fp);
193362306a36Sopenharmony_ci	if (trap == INTERRUPT_DATA_STORAGE ||
193462306a36Sopenharmony_ci	    trap == INTERRUPT_DATA_SEGMENT ||
193562306a36Sopenharmony_ci	    trap == INTERRUPT_ALIGNMENT)
193662306a36Sopenharmony_ci		printf("dar = "REG"   dsisr = %.8lx\n", fp->dar, fp->dsisr);
193762306a36Sopenharmony_ci}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_cistatic void cacheflush(void)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	int cmd;
194262306a36Sopenharmony_ci	unsigned long nflush;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	cmd = inchar();
194562306a36Sopenharmony_ci	if (cmd != 'i')
194662306a36Sopenharmony_ci		termch = cmd;
194762306a36Sopenharmony_ci	scanhex((void *)&adrs);
194862306a36Sopenharmony_ci	if (termch != '\n')
194962306a36Sopenharmony_ci		termch = 0;
195062306a36Sopenharmony_ci	nflush = 1;
195162306a36Sopenharmony_ci	scanhex(&nflush);
195262306a36Sopenharmony_ci	nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
195362306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
195462306a36Sopenharmony_ci		catch_memory_errors = 1;
195562306a36Sopenharmony_ci		sync();
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		if (cmd != 'i' || IS_ENABLED(CONFIG_PPC_BOOK3S_64)) {
195862306a36Sopenharmony_ci			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
195962306a36Sopenharmony_ci				cflush((void *) adrs);
196062306a36Sopenharmony_ci		} else {
196162306a36Sopenharmony_ci			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
196262306a36Sopenharmony_ci				cinval((void *) adrs);
196362306a36Sopenharmony_ci		}
196462306a36Sopenharmony_ci		sync();
196562306a36Sopenharmony_ci		/* wait a little while to see if we get a machine check */
196662306a36Sopenharmony_ci		__delay(200);
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci	catch_memory_errors = 0;
196962306a36Sopenharmony_ci}
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ciextern unsigned long xmon_mfspr(int spr, unsigned long default_value);
197262306a36Sopenharmony_ciextern void xmon_mtspr(int spr, unsigned long value);
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_cistatic int
197562306a36Sopenharmony_ciread_spr(int n, unsigned long *vp)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	unsigned long ret = -1UL;
197862306a36Sopenharmony_ci	int ok = 0;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
198162306a36Sopenharmony_ci		catch_spr_faults = 1;
198262306a36Sopenharmony_ci		sync();
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci		ret = xmon_mfspr(n, *vp);
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci		sync();
198762306a36Sopenharmony_ci		*vp = ret;
198862306a36Sopenharmony_ci		ok = 1;
198962306a36Sopenharmony_ci	}
199062306a36Sopenharmony_ci	catch_spr_faults = 0;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	return ok;
199362306a36Sopenharmony_ci}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_cistatic void
199662306a36Sopenharmony_ciwrite_spr(int n, unsigned long val)
199762306a36Sopenharmony_ci{
199862306a36Sopenharmony_ci	if (xmon_is_ro) {
199962306a36Sopenharmony_ci		printf(xmon_ro_msg);
200062306a36Sopenharmony_ci		return;
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
200462306a36Sopenharmony_ci		catch_spr_faults = 1;
200562306a36Sopenharmony_ci		sync();
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		xmon_mtspr(n, val);
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci		sync();
201062306a36Sopenharmony_ci	} else {
201162306a36Sopenharmony_ci		printf("SPR 0x%03x (%4d) Faulted during write\n", n, n);
201262306a36Sopenharmony_ci	}
201362306a36Sopenharmony_ci	catch_spr_faults = 0;
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistatic void dump_206_sprs(void)
201762306a36Sopenharmony_ci{
201862306a36Sopenharmony_ci#ifdef CONFIG_PPC64
201962306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_ARCH_206))
202062306a36Sopenharmony_ci		return;
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	/* Actually some of these pre-date 2.06, but whatever */
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	printf("srr0   = %.16lx  srr1  = %.16lx dsisr  = %.8lx\n",
202562306a36Sopenharmony_ci		mfspr(SPRN_SRR0), mfspr(SPRN_SRR1), mfspr(SPRN_DSISR));
202662306a36Sopenharmony_ci	printf("dscr   = %.16lx  ppr   = %.16lx pir    = %.8lx\n",
202762306a36Sopenharmony_ci		mfspr(SPRN_DSCR), mfspr(SPRN_PPR), mfspr(SPRN_PIR));
202862306a36Sopenharmony_ci	printf("amr    = %.16lx  uamor = %.16lx\n",
202962306a36Sopenharmony_ci		mfspr(SPRN_AMR), mfspr(SPRN_UAMOR));
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	if (!(mfmsr() & MSR_HV))
203262306a36Sopenharmony_ci		return;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	printf("sdr1   = %.16lx  hdar  = %.16lx hdsisr = %.8lx\n",
203562306a36Sopenharmony_ci		mfspr(SPRN_SDR1), mfspr(SPRN_HDAR), mfspr(SPRN_HDSISR));
203662306a36Sopenharmony_ci	printf("hsrr0  = %.16lx hsrr1  = %.16lx hdec   = %.16lx\n",
203762306a36Sopenharmony_ci		mfspr(SPRN_HSRR0), mfspr(SPRN_HSRR1), mfspr(SPRN_HDEC));
203862306a36Sopenharmony_ci	printf("lpcr   = %.16lx  pcr   = %.16lx lpidr  = %.8lx\n",
203962306a36Sopenharmony_ci		mfspr(SPRN_LPCR), mfspr(SPRN_PCR), mfspr(SPRN_LPID));
204062306a36Sopenharmony_ci	printf("hsprg0 = %.16lx hsprg1 = %.16lx amor   = %.16lx\n",
204162306a36Sopenharmony_ci		mfspr(SPRN_HSPRG0), mfspr(SPRN_HSPRG1), mfspr(SPRN_AMOR));
204262306a36Sopenharmony_ci	printf("dabr   = %.16lx dabrx  = %.16lx\n",
204362306a36Sopenharmony_ci		mfspr(SPRN_DABR), mfspr(SPRN_DABRX));
204462306a36Sopenharmony_ci#endif
204562306a36Sopenharmony_ci}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_cistatic void dump_207_sprs(void)
204862306a36Sopenharmony_ci{
204962306a36Sopenharmony_ci#ifdef CONFIG_PPC64
205062306a36Sopenharmony_ci	unsigned long msr;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_ARCH_207S))
205362306a36Sopenharmony_ci		return;
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	printf("dpdes  = %.16lx  tir   = %.16lx cir    = %.8lx\n",
205662306a36Sopenharmony_ci		mfspr(SPRN_DPDES), mfspr(SPRN_TIR), mfspr(SPRN_CIR));
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	printf("fscr   = %.16lx  tar   = %.16lx pspb   = %.8lx\n",
205962306a36Sopenharmony_ci		mfspr(SPRN_FSCR), mfspr(SPRN_TAR), mfspr(SPRN_PSPB));
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	msr = mfmsr();
206262306a36Sopenharmony_ci	if (msr & MSR_TM) {
206362306a36Sopenharmony_ci		/* Only if TM has been enabled in the kernel */
206462306a36Sopenharmony_ci		printf("tfhar  = %.16lx  tfiar = %.16lx texasr = %.16lx\n",
206562306a36Sopenharmony_ci			mfspr(SPRN_TFHAR), mfspr(SPRN_TFIAR),
206662306a36Sopenharmony_ci			mfspr(SPRN_TEXASR));
206762306a36Sopenharmony_ci	}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	printf("mmcr0  = %.16lx  mmcr1 = %.16lx mmcr2  = %.16lx\n",
207062306a36Sopenharmony_ci		mfspr(SPRN_MMCR0), mfspr(SPRN_MMCR1), mfspr(SPRN_MMCR2));
207162306a36Sopenharmony_ci	printf("pmc1   = %.8lx pmc2 = %.8lx  pmc3 = %.8lx  pmc4   = %.8lx\n",
207262306a36Sopenharmony_ci		mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
207362306a36Sopenharmony_ci		mfspr(SPRN_PMC3), mfspr(SPRN_PMC4));
207462306a36Sopenharmony_ci	printf("mmcra  = %.16lx   siar = %.16lx pmc5   = %.8lx\n",
207562306a36Sopenharmony_ci		mfspr(SPRN_MMCRA), mfspr(SPRN_SIAR), mfspr(SPRN_PMC5));
207662306a36Sopenharmony_ci	printf("sdar   = %.16lx   sier = %.16lx pmc6   = %.8lx\n",
207762306a36Sopenharmony_ci		mfspr(SPRN_SDAR), mfspr(SPRN_SIER), mfspr(SPRN_PMC6));
207862306a36Sopenharmony_ci	printf("ebbhr  = %.16lx  ebbrr = %.16lx bescr  = %.16lx\n",
207962306a36Sopenharmony_ci		mfspr(SPRN_EBBHR), mfspr(SPRN_EBBRR), mfspr(SPRN_BESCR));
208062306a36Sopenharmony_ci	printf("iamr   = %.16lx\n", mfspr(SPRN_IAMR));
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	if (!(msr & MSR_HV))
208362306a36Sopenharmony_ci		return;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	printf("hfscr  = %.16lx  dhdes = %.16lx rpr    = %.16lx\n",
208662306a36Sopenharmony_ci		mfspr(SPRN_HFSCR), mfspr(SPRN_DHDES), mfspr(SPRN_RPR));
208762306a36Sopenharmony_ci	printf("dawr0  = %.16lx dawrx0 = %.16lx\n",
208862306a36Sopenharmony_ci	       mfspr(SPRN_DAWR0), mfspr(SPRN_DAWRX0));
208962306a36Sopenharmony_ci	if (nr_wp_slots() > 1) {
209062306a36Sopenharmony_ci		printf("dawr1  = %.16lx dawrx1 = %.16lx\n",
209162306a36Sopenharmony_ci		       mfspr(SPRN_DAWR1), mfspr(SPRN_DAWRX1));
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci	printf("ciabr  = %.16lx\n", mfspr(SPRN_CIABR));
209462306a36Sopenharmony_ci#endif
209562306a36Sopenharmony_ci}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_cistatic void dump_300_sprs(void)
209862306a36Sopenharmony_ci{
209962306a36Sopenharmony_ci#ifdef CONFIG_PPC64
210062306a36Sopenharmony_ci	bool hv = mfmsr() & MSR_HV;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_ARCH_300))
210362306a36Sopenharmony_ci		return;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_P9_TIDR)) {
210662306a36Sopenharmony_ci		printf("pidr   = %.16lx  tidr  = %.16lx\n",
210762306a36Sopenharmony_ci			mfspr(SPRN_PID), mfspr(SPRN_TIDR));
210862306a36Sopenharmony_ci	} else {
210962306a36Sopenharmony_ci		printf("pidr   = %.16lx\n",
211062306a36Sopenharmony_ci			mfspr(SPRN_PID));
211162306a36Sopenharmony_ci	}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	printf("psscr  = %.16lx\n",
211462306a36Sopenharmony_ci		hv ? mfspr(SPRN_PSSCR) : mfspr(SPRN_PSSCR_PR));
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	if (!hv)
211762306a36Sopenharmony_ci		return;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	printf("ptcr   = %.16lx  asdr  = %.16lx\n",
212062306a36Sopenharmony_ci		mfspr(SPRN_PTCR), mfspr(SPRN_ASDR));
212162306a36Sopenharmony_ci#endif
212262306a36Sopenharmony_ci}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_cistatic void dump_310_sprs(void)
212562306a36Sopenharmony_ci{
212662306a36Sopenharmony_ci#ifdef CONFIG_PPC64
212762306a36Sopenharmony_ci	if (!cpu_has_feature(CPU_FTR_ARCH_31))
212862306a36Sopenharmony_ci		return;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	printf("mmcr3  = %.16lx, sier2  = %.16lx, sier3  = %.16lx\n",
213162306a36Sopenharmony_ci		mfspr(SPRN_MMCR3), mfspr(SPRN_SIER2), mfspr(SPRN_SIER3));
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci#endif
213462306a36Sopenharmony_ci}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_cistatic void dump_one_spr(int spr, bool show_unimplemented)
213762306a36Sopenharmony_ci{
213862306a36Sopenharmony_ci	unsigned long val;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	val = 0xdeadbeef;
214162306a36Sopenharmony_ci	if (!read_spr(spr, &val)) {
214262306a36Sopenharmony_ci		printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
214362306a36Sopenharmony_ci		return;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (val == 0xdeadbeef) {
214762306a36Sopenharmony_ci		/* Looks like read was a nop, confirm */
214862306a36Sopenharmony_ci		val = 0x0badcafe;
214962306a36Sopenharmony_ci		if (!read_spr(spr, &val)) {
215062306a36Sopenharmony_ci			printf("SPR 0x%03x (%4d) Faulted during read\n", spr, spr);
215162306a36Sopenharmony_ci			return;
215262306a36Sopenharmony_ci		}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci		if (val == 0x0badcafe) {
215562306a36Sopenharmony_ci			if (show_unimplemented)
215662306a36Sopenharmony_ci				printf("SPR 0x%03x (%4d) Unimplemented\n", spr, spr);
215762306a36Sopenharmony_ci			return;
215862306a36Sopenharmony_ci		}
215962306a36Sopenharmony_ci	}
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	printf("SPR 0x%03x (%4d) = 0x%lx\n", spr, spr, val);
216262306a36Sopenharmony_ci}
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_cistatic void super_regs(void)
216562306a36Sopenharmony_ci{
216662306a36Sopenharmony_ci	static unsigned long regno;
216762306a36Sopenharmony_ci	int cmd;
216862306a36Sopenharmony_ci	int spr;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	cmd = skipbl();
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	switch (cmd) {
217362306a36Sopenharmony_ci	case '\n': {
217462306a36Sopenharmony_ci		unsigned long sp, toc;
217562306a36Sopenharmony_ci		asm("mr %0,1" : "=r" (sp) :);
217662306a36Sopenharmony_ci		asm("mr %0,2" : "=r" (toc) :);
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		printf("msr    = "REG"  sprg0 = "REG"\n",
217962306a36Sopenharmony_ci		       mfmsr(), mfspr(SPRN_SPRG0));
218062306a36Sopenharmony_ci		printf("pvr    = "REG"  sprg1 = "REG"\n",
218162306a36Sopenharmony_ci		       mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
218262306a36Sopenharmony_ci		printf("dec    = "REG"  sprg2 = "REG"\n",
218362306a36Sopenharmony_ci		       mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
218462306a36Sopenharmony_ci		printf("sp     = "REG"  sprg3 = "REG"\n", sp, mfspr(SPRN_SPRG3));
218562306a36Sopenharmony_ci		printf("toc    = "REG"  dar   = "REG"\n", toc, mfspr(SPRN_DAR));
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci		dump_206_sprs();
218862306a36Sopenharmony_ci		dump_207_sprs();
218962306a36Sopenharmony_ci		dump_300_sprs();
219062306a36Sopenharmony_ci		dump_310_sprs();
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci		return;
219362306a36Sopenharmony_ci	}
219462306a36Sopenharmony_ci	case 'w': {
219562306a36Sopenharmony_ci		unsigned long val;
219662306a36Sopenharmony_ci		scanhex(&regno);
219762306a36Sopenharmony_ci		val = 0;
219862306a36Sopenharmony_ci		read_spr(regno, &val);
219962306a36Sopenharmony_ci		scanhex(&val);
220062306a36Sopenharmony_ci		write_spr(regno, val);
220162306a36Sopenharmony_ci		dump_one_spr(regno, true);
220262306a36Sopenharmony_ci		break;
220362306a36Sopenharmony_ci	}
220462306a36Sopenharmony_ci	case 'r':
220562306a36Sopenharmony_ci		scanhex(&regno);
220662306a36Sopenharmony_ci		dump_one_spr(regno, true);
220762306a36Sopenharmony_ci		break;
220862306a36Sopenharmony_ci	case 'a':
220962306a36Sopenharmony_ci		/* dump ALL SPRs */
221062306a36Sopenharmony_ci		for (spr = 1; spr < 1024; ++spr)
221162306a36Sopenharmony_ci			dump_one_spr(spr, false);
221262306a36Sopenharmony_ci		break;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	scannl();
221662306a36Sopenharmony_ci}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci/*
221962306a36Sopenharmony_ci * Stuff for reading and writing memory safely
222062306a36Sopenharmony_ci */
222162306a36Sopenharmony_cistatic int
222262306a36Sopenharmony_cimread(unsigned long adrs, void *buf, int size)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	volatile int n;
222562306a36Sopenharmony_ci	char *p, *q;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	n = 0;
222862306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
222962306a36Sopenharmony_ci		catch_memory_errors = 1;
223062306a36Sopenharmony_ci		sync();
223162306a36Sopenharmony_ci		p = (char *)adrs;
223262306a36Sopenharmony_ci		q = (char *)buf;
223362306a36Sopenharmony_ci		switch (size) {
223462306a36Sopenharmony_ci		case 2:
223562306a36Sopenharmony_ci			*(u16 *)q = *(u16 *)p;
223662306a36Sopenharmony_ci			break;
223762306a36Sopenharmony_ci		case 4:
223862306a36Sopenharmony_ci			*(u32 *)q = *(u32 *)p;
223962306a36Sopenharmony_ci			break;
224062306a36Sopenharmony_ci		case 8:
224162306a36Sopenharmony_ci			*(u64 *)q = *(u64 *)p;
224262306a36Sopenharmony_ci			break;
224362306a36Sopenharmony_ci		default:
224462306a36Sopenharmony_ci			for( ; n < size; ++n) {
224562306a36Sopenharmony_ci				*q++ = *p++;
224662306a36Sopenharmony_ci				sync();
224762306a36Sopenharmony_ci			}
224862306a36Sopenharmony_ci		}
224962306a36Sopenharmony_ci		sync();
225062306a36Sopenharmony_ci		/* wait a little while to see if we get a machine check */
225162306a36Sopenharmony_ci		__delay(200);
225262306a36Sopenharmony_ci		n = size;
225362306a36Sopenharmony_ci	}
225462306a36Sopenharmony_ci	catch_memory_errors = 0;
225562306a36Sopenharmony_ci	return n;
225662306a36Sopenharmony_ci}
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_cistatic int
225962306a36Sopenharmony_cimwrite(unsigned long adrs, void *buf, int size)
226062306a36Sopenharmony_ci{
226162306a36Sopenharmony_ci	volatile int n;
226262306a36Sopenharmony_ci	char *p, *q;
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci	n = 0;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	if (xmon_is_ro) {
226762306a36Sopenharmony_ci		printf(xmon_ro_msg);
226862306a36Sopenharmony_ci		return n;
226962306a36Sopenharmony_ci	}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
227262306a36Sopenharmony_ci		catch_memory_errors = 1;
227362306a36Sopenharmony_ci		sync();
227462306a36Sopenharmony_ci		p = (char *) adrs;
227562306a36Sopenharmony_ci		q = (char *) buf;
227662306a36Sopenharmony_ci		switch (size) {
227762306a36Sopenharmony_ci		case 2:
227862306a36Sopenharmony_ci			*(u16 *)p = *(u16 *)q;
227962306a36Sopenharmony_ci			break;
228062306a36Sopenharmony_ci		case 4:
228162306a36Sopenharmony_ci			*(u32 *)p = *(u32 *)q;
228262306a36Sopenharmony_ci			break;
228362306a36Sopenharmony_ci		case 8:
228462306a36Sopenharmony_ci			*(u64 *)p = *(u64 *)q;
228562306a36Sopenharmony_ci			break;
228662306a36Sopenharmony_ci		default:
228762306a36Sopenharmony_ci			for ( ; n < size; ++n) {
228862306a36Sopenharmony_ci				*p++ = *q++;
228962306a36Sopenharmony_ci				sync();
229062306a36Sopenharmony_ci			}
229162306a36Sopenharmony_ci		}
229262306a36Sopenharmony_ci		sync();
229362306a36Sopenharmony_ci		/* wait a little while to see if we get a machine check */
229462306a36Sopenharmony_ci		__delay(200);
229562306a36Sopenharmony_ci		n = size;
229662306a36Sopenharmony_ci	} else {
229762306a36Sopenharmony_ci		printf("*** Error writing address "REG"\n", adrs + n);
229862306a36Sopenharmony_ci	}
229962306a36Sopenharmony_ci	catch_memory_errors = 0;
230062306a36Sopenharmony_ci	return n;
230162306a36Sopenharmony_ci}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_cistatic int
230462306a36Sopenharmony_cimread_instr(unsigned long adrs, ppc_inst_t *instr)
230562306a36Sopenharmony_ci{
230662306a36Sopenharmony_ci	volatile int n;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	n = 0;
230962306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
231062306a36Sopenharmony_ci		catch_memory_errors = 1;
231162306a36Sopenharmony_ci		sync();
231262306a36Sopenharmony_ci		*instr = ppc_inst_read((u32 *)adrs);
231362306a36Sopenharmony_ci		sync();
231462306a36Sopenharmony_ci		/* wait a little while to see if we get a machine check */
231562306a36Sopenharmony_ci		__delay(200);
231662306a36Sopenharmony_ci		n = ppc_inst_len(*instr);
231762306a36Sopenharmony_ci	}
231862306a36Sopenharmony_ci	catch_memory_errors = 0;
231962306a36Sopenharmony_ci	return n;
232062306a36Sopenharmony_ci}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_cistatic int fault_type;
232362306a36Sopenharmony_cistatic int fault_except;
232462306a36Sopenharmony_cistatic char *fault_chars[] = { "--", "**", "##" };
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_cistatic int handle_fault(struct pt_regs *regs)
232762306a36Sopenharmony_ci{
232862306a36Sopenharmony_ci	fault_except = TRAP(regs);
232962306a36Sopenharmony_ci	switch (TRAP(regs)) {
233062306a36Sopenharmony_ci	case 0x200:
233162306a36Sopenharmony_ci		fault_type = 0;
233262306a36Sopenharmony_ci		break;
233362306a36Sopenharmony_ci	case 0x300:
233462306a36Sopenharmony_ci	case 0x380:
233562306a36Sopenharmony_ci		fault_type = 1;
233662306a36Sopenharmony_ci		break;
233762306a36Sopenharmony_ci	default:
233862306a36Sopenharmony_ci		fault_type = 2;
233962306a36Sopenharmony_ci	}
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	longjmp(bus_error_jmp, 1);
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	return 0;
234462306a36Sopenharmony_ci}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci#define SWAP(a, b, t)	((t) = (a), (a) = (b), (b) = (t))
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_cistatic void
234962306a36Sopenharmony_cibyterev(unsigned char *val, int size)
235062306a36Sopenharmony_ci{
235162306a36Sopenharmony_ci	int t;
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	switch (size) {
235462306a36Sopenharmony_ci	case 2:
235562306a36Sopenharmony_ci		SWAP(val[0], val[1], t);
235662306a36Sopenharmony_ci		break;
235762306a36Sopenharmony_ci	case 4:
235862306a36Sopenharmony_ci		SWAP(val[0], val[3], t);
235962306a36Sopenharmony_ci		SWAP(val[1], val[2], t);
236062306a36Sopenharmony_ci		break;
236162306a36Sopenharmony_ci	case 8: /* is there really any use for this? */
236262306a36Sopenharmony_ci		SWAP(val[0], val[7], t);
236362306a36Sopenharmony_ci		SWAP(val[1], val[6], t);
236462306a36Sopenharmony_ci		SWAP(val[2], val[5], t);
236562306a36Sopenharmony_ci		SWAP(val[3], val[4], t);
236662306a36Sopenharmony_ci		break;
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_cistatic int brev;
237162306a36Sopenharmony_cistatic int mnoread;
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_cistatic char *memex_help_string =
237462306a36Sopenharmony_ci    "Memory examine command usage:\n"
237562306a36Sopenharmony_ci    "m [addr] [flags] examine/change memory\n"
237662306a36Sopenharmony_ci    "  addr is optional.  will start where left off.\n"
237762306a36Sopenharmony_ci    "  flags may include chars from this set:\n"
237862306a36Sopenharmony_ci    "    b   modify by bytes (default)\n"
237962306a36Sopenharmony_ci    "    w   modify by words (2 byte)\n"
238062306a36Sopenharmony_ci    "    l   modify by longs (4 byte)\n"
238162306a36Sopenharmony_ci    "    d   modify by doubleword (8 byte)\n"
238262306a36Sopenharmony_ci    "    r   toggle reverse byte order mode\n"
238362306a36Sopenharmony_ci    "    n   do not read memory (for i/o spaces)\n"
238462306a36Sopenharmony_ci    "    .   ok to read (default)\n"
238562306a36Sopenharmony_ci    "NOTE: flags are saved as defaults\n"
238662306a36Sopenharmony_ci    "";
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_cistatic char *memex_subcmd_help_string =
238962306a36Sopenharmony_ci    "Memory examine subcommands:\n"
239062306a36Sopenharmony_ci    "  hexval   write this val to current location\n"
239162306a36Sopenharmony_ci    "  'string' write chars from string to this location\n"
239262306a36Sopenharmony_ci    "  '        increment address\n"
239362306a36Sopenharmony_ci    "  ^        decrement address\n"
239462306a36Sopenharmony_ci    "  /        increment addr by 0x10.  //=0x100, ///=0x1000, etc\n"
239562306a36Sopenharmony_ci    "  \\        decrement addr by 0x10.  \\\\=0x100, \\\\\\=0x1000, etc\n"
239662306a36Sopenharmony_ci    "  `        clear no-read flag\n"
239762306a36Sopenharmony_ci    "  ;        stay at this addr\n"
239862306a36Sopenharmony_ci    "  v        change to byte mode\n"
239962306a36Sopenharmony_ci    "  w        change to word (2 byte) mode\n"
240062306a36Sopenharmony_ci    "  l        change to long (4 byte) mode\n"
240162306a36Sopenharmony_ci    "  u        change to doubleword (8 byte) mode\n"
240262306a36Sopenharmony_ci    "  m addr   change current addr\n"
240362306a36Sopenharmony_ci    "  n        toggle no-read flag\n"
240462306a36Sopenharmony_ci    "  r        toggle byte reverse flag\n"
240562306a36Sopenharmony_ci    "  < count  back up count bytes\n"
240662306a36Sopenharmony_ci    "  > count  skip forward count bytes\n"
240762306a36Sopenharmony_ci    "  x        exit this mode\n"
240862306a36Sopenharmony_ci    "";
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_cistatic void
241162306a36Sopenharmony_cimemex(void)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	int cmd, inc, i, nslash;
241462306a36Sopenharmony_ci	unsigned long n;
241562306a36Sopenharmony_ci	unsigned char val[16];
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	scanhex((void *)&adrs);
241862306a36Sopenharmony_ci	cmd = skipbl();
241962306a36Sopenharmony_ci	if (cmd == '?') {
242062306a36Sopenharmony_ci		printf(memex_help_string);
242162306a36Sopenharmony_ci		return;
242262306a36Sopenharmony_ci	} else {
242362306a36Sopenharmony_ci		termch = cmd;
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci	last_cmd = "m\n";
242662306a36Sopenharmony_ci	while ((cmd = skipbl()) != '\n') {
242762306a36Sopenharmony_ci		switch( cmd ){
242862306a36Sopenharmony_ci		case 'b':	size = 1;	break;
242962306a36Sopenharmony_ci		case 'w':	size = 2;	break;
243062306a36Sopenharmony_ci		case 'l':	size = 4;	break;
243162306a36Sopenharmony_ci		case 'd':	size = 8;	break;
243262306a36Sopenharmony_ci		case 'r': 	brev = !brev;	break;
243362306a36Sopenharmony_ci		case 'n':	mnoread = 1;	break;
243462306a36Sopenharmony_ci		case '.':	mnoread = 0;	break;
243562306a36Sopenharmony_ci		}
243662306a36Sopenharmony_ci	}
243762306a36Sopenharmony_ci	if( size <= 0 )
243862306a36Sopenharmony_ci		size = 1;
243962306a36Sopenharmony_ci	else if( size > 8 )
244062306a36Sopenharmony_ci		size = 8;
244162306a36Sopenharmony_ci	for(;;){
244262306a36Sopenharmony_ci		if (!mnoread)
244362306a36Sopenharmony_ci			n = mread(adrs, val, size);
244462306a36Sopenharmony_ci		printf(REG"%c", adrs, brev? 'r': ' ');
244562306a36Sopenharmony_ci		if (!mnoread) {
244662306a36Sopenharmony_ci			if (brev)
244762306a36Sopenharmony_ci				byterev(val, size);
244862306a36Sopenharmony_ci			putchar(' ');
244962306a36Sopenharmony_ci			for (i = 0; i < n; ++i)
245062306a36Sopenharmony_ci				printf("%.2x", val[i]);
245162306a36Sopenharmony_ci			for (; i < size; ++i)
245262306a36Sopenharmony_ci				printf("%s", fault_chars[fault_type]);
245362306a36Sopenharmony_ci		}
245462306a36Sopenharmony_ci		putchar(' ');
245562306a36Sopenharmony_ci		inc = size;
245662306a36Sopenharmony_ci		nslash = 0;
245762306a36Sopenharmony_ci		for(;;){
245862306a36Sopenharmony_ci			if( scanhex(&n) ){
245962306a36Sopenharmony_ci				for (i = 0; i < size; ++i)
246062306a36Sopenharmony_ci					val[i] = n >> (i * 8);
246162306a36Sopenharmony_ci				if (!brev)
246262306a36Sopenharmony_ci					byterev(val, size);
246362306a36Sopenharmony_ci				mwrite(adrs, val, size);
246462306a36Sopenharmony_ci				inc = size;
246562306a36Sopenharmony_ci			}
246662306a36Sopenharmony_ci			cmd = skipbl();
246762306a36Sopenharmony_ci			if (cmd == '\n')
246862306a36Sopenharmony_ci				break;
246962306a36Sopenharmony_ci			inc = 0;
247062306a36Sopenharmony_ci			switch (cmd) {
247162306a36Sopenharmony_ci			case '\'':
247262306a36Sopenharmony_ci				for(;;){
247362306a36Sopenharmony_ci					n = inchar();
247462306a36Sopenharmony_ci					if( n == '\\' )
247562306a36Sopenharmony_ci						n = bsesc();
247662306a36Sopenharmony_ci					else if( n == '\'' )
247762306a36Sopenharmony_ci						break;
247862306a36Sopenharmony_ci					for (i = 0; i < size; ++i)
247962306a36Sopenharmony_ci						val[i] = n >> (i * 8);
248062306a36Sopenharmony_ci					if (!brev)
248162306a36Sopenharmony_ci						byterev(val, size);
248262306a36Sopenharmony_ci					mwrite(adrs, val, size);
248362306a36Sopenharmony_ci					adrs += size;
248462306a36Sopenharmony_ci				}
248562306a36Sopenharmony_ci				adrs -= size;
248662306a36Sopenharmony_ci				inc = size;
248762306a36Sopenharmony_ci				break;
248862306a36Sopenharmony_ci			case ',':
248962306a36Sopenharmony_ci				adrs += size;
249062306a36Sopenharmony_ci				break;
249162306a36Sopenharmony_ci			case '.':
249262306a36Sopenharmony_ci				mnoread = 0;
249362306a36Sopenharmony_ci				break;
249462306a36Sopenharmony_ci			case ';':
249562306a36Sopenharmony_ci				break;
249662306a36Sopenharmony_ci			case 'x':
249762306a36Sopenharmony_ci			case EOF:
249862306a36Sopenharmony_ci				scannl();
249962306a36Sopenharmony_ci				return;
250062306a36Sopenharmony_ci			case 'b':
250162306a36Sopenharmony_ci			case 'v':
250262306a36Sopenharmony_ci				size = 1;
250362306a36Sopenharmony_ci				break;
250462306a36Sopenharmony_ci			case 'w':
250562306a36Sopenharmony_ci				size = 2;
250662306a36Sopenharmony_ci				break;
250762306a36Sopenharmony_ci			case 'l':
250862306a36Sopenharmony_ci				size = 4;
250962306a36Sopenharmony_ci				break;
251062306a36Sopenharmony_ci			case 'u':
251162306a36Sopenharmony_ci				size = 8;
251262306a36Sopenharmony_ci				break;
251362306a36Sopenharmony_ci			case '^':
251462306a36Sopenharmony_ci				adrs -= size;
251562306a36Sopenharmony_ci				break;
251662306a36Sopenharmony_ci			case '/':
251762306a36Sopenharmony_ci				if (nslash > 0)
251862306a36Sopenharmony_ci					adrs -= 1 << nslash;
251962306a36Sopenharmony_ci				else
252062306a36Sopenharmony_ci					nslash = 0;
252162306a36Sopenharmony_ci				nslash += 4;
252262306a36Sopenharmony_ci				adrs += 1 << nslash;
252362306a36Sopenharmony_ci				break;
252462306a36Sopenharmony_ci			case '\\':
252562306a36Sopenharmony_ci				if (nslash < 0)
252662306a36Sopenharmony_ci					adrs += 1 << -nslash;
252762306a36Sopenharmony_ci				else
252862306a36Sopenharmony_ci					nslash = 0;
252962306a36Sopenharmony_ci				nslash -= 4;
253062306a36Sopenharmony_ci				adrs -= 1 << -nslash;
253162306a36Sopenharmony_ci				break;
253262306a36Sopenharmony_ci			case 'm':
253362306a36Sopenharmony_ci				scanhex((void *)&adrs);
253462306a36Sopenharmony_ci				break;
253562306a36Sopenharmony_ci			case 'n':
253662306a36Sopenharmony_ci				mnoread = 1;
253762306a36Sopenharmony_ci				break;
253862306a36Sopenharmony_ci			case 'r':
253962306a36Sopenharmony_ci				brev = !brev;
254062306a36Sopenharmony_ci				break;
254162306a36Sopenharmony_ci			case '<':
254262306a36Sopenharmony_ci				n = size;
254362306a36Sopenharmony_ci				scanhex(&n);
254462306a36Sopenharmony_ci				adrs -= n;
254562306a36Sopenharmony_ci				break;
254662306a36Sopenharmony_ci			case '>':
254762306a36Sopenharmony_ci				n = size;
254862306a36Sopenharmony_ci				scanhex(&n);
254962306a36Sopenharmony_ci				adrs += n;
255062306a36Sopenharmony_ci				break;
255162306a36Sopenharmony_ci			case '?':
255262306a36Sopenharmony_ci				printf(memex_subcmd_help_string);
255362306a36Sopenharmony_ci				break;
255462306a36Sopenharmony_ci			}
255562306a36Sopenharmony_ci		}
255662306a36Sopenharmony_ci		adrs += inc;
255762306a36Sopenharmony_ci	}
255862306a36Sopenharmony_ci}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_cistatic int
256162306a36Sopenharmony_cibsesc(void)
256262306a36Sopenharmony_ci{
256362306a36Sopenharmony_ci	int c;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	c = inchar();
256662306a36Sopenharmony_ci	switch( c ){
256762306a36Sopenharmony_ci	case 'n':	c = '\n';	break;
256862306a36Sopenharmony_ci	case 'r':	c = '\r';	break;
256962306a36Sopenharmony_ci	case 'b':	c = '\b';	break;
257062306a36Sopenharmony_ci	case 't':	c = '\t';	break;
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci	return c;
257362306a36Sopenharmony_ci}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_cistatic void xmon_rawdump (unsigned long adrs, long ndump)
257662306a36Sopenharmony_ci{
257762306a36Sopenharmony_ci	long n, m, r, nr;
257862306a36Sopenharmony_ci	unsigned char temp[16];
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	for (n = ndump; n > 0;) {
258162306a36Sopenharmony_ci		r = n < 16? n: 16;
258262306a36Sopenharmony_ci		nr = mread(adrs, temp, r);
258362306a36Sopenharmony_ci		adrs += nr;
258462306a36Sopenharmony_ci		for (m = 0; m < r; ++m) {
258562306a36Sopenharmony_ci			if (m < nr)
258662306a36Sopenharmony_ci				printf("%.2x", temp[m]);
258762306a36Sopenharmony_ci			else
258862306a36Sopenharmony_ci				printf("%s", fault_chars[fault_type]);
258962306a36Sopenharmony_ci		}
259062306a36Sopenharmony_ci		n -= r;
259162306a36Sopenharmony_ci		if (nr < r)
259262306a36Sopenharmony_ci			break;
259362306a36Sopenharmony_ci	}
259462306a36Sopenharmony_ci	printf("\n");
259562306a36Sopenharmony_ci}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_cistatic void dump_tracing(void)
259862306a36Sopenharmony_ci{
259962306a36Sopenharmony_ci	int c;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	c = inchar();
260262306a36Sopenharmony_ci	if (c == 'c')
260362306a36Sopenharmony_ci		ftrace_dump(DUMP_ORIG);
260462306a36Sopenharmony_ci	else
260562306a36Sopenharmony_ci		ftrace_dump(DUMP_ALL);
260662306a36Sopenharmony_ci}
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci#ifdef CONFIG_PPC64
260962306a36Sopenharmony_cistatic void dump_one_paca(int cpu)
261062306a36Sopenharmony_ci{
261162306a36Sopenharmony_ci	struct paca_struct *p;
261262306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU
261362306a36Sopenharmony_ci	int i = 0;
261462306a36Sopenharmony_ci#endif
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) != 0) {
261762306a36Sopenharmony_ci		printf("*** Error dumping paca for cpu 0x%x!\n", cpu);
261862306a36Sopenharmony_ci		return;
261962306a36Sopenharmony_ci	}
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	catch_memory_errors = 1;
262262306a36Sopenharmony_ci	sync();
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	p = paca_ptrs[cpu];
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci	printf("paca for cpu 0x%x @ %px:\n", cpu, p);
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	printf(" %-*s = %s\n", 25, "possible", cpu_possible(cpu) ? "yes" : "no");
262962306a36Sopenharmony_ci	printf(" %-*s = %s\n", 25, "present", cpu_present(cpu) ? "yes" : "no");
263062306a36Sopenharmony_ci	printf(" %-*s = %s\n", 25, "online", cpu_online(cpu) ? "yes" : "no");
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci#define DUMP(paca, name, format)				\
263362306a36Sopenharmony_ci	printf(" %-*s = "format"\t(0x%lx)\n", 25, #name, 18, paca->name, \
263462306a36Sopenharmony_ci		offsetof(struct paca_struct, name));
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci	DUMP(p, lock_token, "%#-*x");
263762306a36Sopenharmony_ci	DUMP(p, paca_index, "%#-*x");
263862306a36Sopenharmony_ci#ifndef CONFIG_PPC_KERNEL_PCREL
263962306a36Sopenharmony_ci	DUMP(p, kernel_toc, "%#-*llx");
264062306a36Sopenharmony_ci#endif
264162306a36Sopenharmony_ci	DUMP(p, kernelbase, "%#-*llx");
264262306a36Sopenharmony_ci	DUMP(p, kernel_msr, "%#-*llx");
264362306a36Sopenharmony_ci	DUMP(p, emergency_sp, "%-*px");
264462306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
264562306a36Sopenharmony_ci	DUMP(p, nmi_emergency_sp, "%-*px");
264662306a36Sopenharmony_ci	DUMP(p, mc_emergency_sp, "%-*px");
264762306a36Sopenharmony_ci	DUMP(p, in_nmi, "%#-*x");
264862306a36Sopenharmony_ci	DUMP(p, in_mce, "%#-*x");
264962306a36Sopenharmony_ci	DUMP(p, hmi_event_available, "%#-*x");
265062306a36Sopenharmony_ci#endif
265162306a36Sopenharmony_ci	DUMP(p, data_offset, "%#-*llx");
265262306a36Sopenharmony_ci	DUMP(p, hw_cpu_id, "%#-*x");
265362306a36Sopenharmony_ci	DUMP(p, cpu_start, "%#-*x");
265462306a36Sopenharmony_ci	DUMP(p, kexec_state, "%#-*x");
265562306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
265662306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU
265762306a36Sopenharmony_ci	if (!early_radix_enabled()) {
265862306a36Sopenharmony_ci		for (i = 0; i < SLB_NUM_BOLTED; i++) {
265962306a36Sopenharmony_ci			u64 esid, vsid;
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci			if (!p->slb_shadow_ptr)
266262306a36Sopenharmony_ci				continue;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci			esid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].esid);
266562306a36Sopenharmony_ci			vsid = be64_to_cpu(p->slb_shadow_ptr->save_area[i].vsid);
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci			if (esid || vsid) {
266862306a36Sopenharmony_ci				printf(" %-*s[%d] = 0x%016llx 0x%016llx\n",
266962306a36Sopenharmony_ci				       22, "slb_shadow", i, esid, vsid);
267062306a36Sopenharmony_ci			}
267162306a36Sopenharmony_ci		}
267262306a36Sopenharmony_ci		DUMP(p, vmalloc_sllp, "%#-*x");
267362306a36Sopenharmony_ci		DUMP(p, stab_rr, "%#-*x");
267462306a36Sopenharmony_ci		DUMP(p, slb_used_bitmap, "%#-*x");
267562306a36Sopenharmony_ci		DUMP(p, slb_kern_bitmap, "%#-*x");
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci		if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
267862306a36Sopenharmony_ci			DUMP(p, slb_cache_ptr, "%#-*x");
267962306a36Sopenharmony_ci			for (i = 0; i < SLB_CACHE_ENTRIES; i++)
268062306a36Sopenharmony_ci				printf(" %-*s[%d] = 0x%016x\n",
268162306a36Sopenharmony_ci				       22, "slb_cache", i, p->slb_cache[i]);
268262306a36Sopenharmony_ci		}
268362306a36Sopenharmony_ci	}
268462306a36Sopenharmony_ci#endif
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	DUMP(p, rfi_flush_fallback_area, "%-*px");
268762306a36Sopenharmony_ci#endif
268862306a36Sopenharmony_ci	DUMP(p, dscr_default, "%#-*llx");
268962306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64
269062306a36Sopenharmony_ci	DUMP(p, pgd, "%-*px");
269162306a36Sopenharmony_ci	DUMP(p, kernel_pgd, "%-*px");
269262306a36Sopenharmony_ci	DUMP(p, tcd_ptr, "%-*px");
269362306a36Sopenharmony_ci	DUMP(p, mc_kstack, "%-*px");
269462306a36Sopenharmony_ci	DUMP(p, crit_kstack, "%-*px");
269562306a36Sopenharmony_ci	DUMP(p, dbg_kstack, "%-*px");
269662306a36Sopenharmony_ci#endif
269762306a36Sopenharmony_ci	DUMP(p, __current, "%-*px");
269862306a36Sopenharmony_ci	DUMP(p, kstack, "%#-*llx");
269962306a36Sopenharmony_ci	printf(" %-*s = 0x%016llx\n", 25, "kstack_base", p->kstack & ~(THREAD_SIZE - 1));
270062306a36Sopenharmony_ci#ifdef CONFIG_STACKPROTECTOR
270162306a36Sopenharmony_ci	DUMP(p, canary, "%#-*lx");
270262306a36Sopenharmony_ci#endif
270362306a36Sopenharmony_ci	DUMP(p, saved_r1, "%#-*llx");
270462306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64
270562306a36Sopenharmony_ci	DUMP(p, trap_save, "%#-*x");
270662306a36Sopenharmony_ci#endif
270762306a36Sopenharmony_ci	DUMP(p, irq_soft_mask, "%#-*x");
270862306a36Sopenharmony_ci	DUMP(p, irq_happened, "%#-*x");
270962306a36Sopenharmony_ci#ifdef CONFIG_MMIOWB
271062306a36Sopenharmony_ci	DUMP(p, mmiowb_state.nesting_count, "%#-*x");
271162306a36Sopenharmony_ci	DUMP(p, mmiowb_state.mmiowb_pending, "%#-*x");
271262306a36Sopenharmony_ci#endif
271362306a36Sopenharmony_ci	DUMP(p, irq_work_pending, "%#-*x");
271462306a36Sopenharmony_ci	DUMP(p, sprg_vdso, "%#-*llx");
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
271762306a36Sopenharmony_ci	DUMP(p, tm_scratch, "%#-*llx");
271862306a36Sopenharmony_ci#endif
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
272162306a36Sopenharmony_ci	DUMP(p, idle_state, "%#-*lx");
272262306a36Sopenharmony_ci	if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
272362306a36Sopenharmony_ci		DUMP(p, thread_idle_state, "%#-*x");
272462306a36Sopenharmony_ci		DUMP(p, subcore_sibling_mask, "%#-*x");
272562306a36Sopenharmony_ci	} else {
272662306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
272762306a36Sopenharmony_ci		DUMP(p, requested_psscr, "%#-*llx");
272862306a36Sopenharmony_ci		DUMP(p, dont_stop.counter, "%#-*x");
272962306a36Sopenharmony_ci#endif
273062306a36Sopenharmony_ci	}
273162306a36Sopenharmony_ci#endif
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci	DUMP(p, accounting.utime, "%#-*lx");
273462306a36Sopenharmony_ci	DUMP(p, accounting.stime, "%#-*lx");
273562306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
273662306a36Sopenharmony_ci	DUMP(p, accounting.utime_scaled, "%#-*lx");
273762306a36Sopenharmony_ci#endif
273862306a36Sopenharmony_ci	DUMP(p, accounting.starttime, "%#-*lx");
273962306a36Sopenharmony_ci	DUMP(p, accounting.starttime_user, "%#-*lx");
274062306a36Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
274162306a36Sopenharmony_ci	DUMP(p, accounting.startspurr, "%#-*lx");
274262306a36Sopenharmony_ci	DUMP(p, accounting.utime_sspurr, "%#-*lx");
274362306a36Sopenharmony_ci#endif
274462306a36Sopenharmony_ci	DUMP(p, accounting.steal_time, "%#-*lx");
274562306a36Sopenharmony_ci#undef DUMP
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	catch_memory_errors = 0;
274862306a36Sopenharmony_ci	sync();
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_cistatic void dump_all_pacas(void)
275262306a36Sopenharmony_ci{
275362306a36Sopenharmony_ci	int cpu;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	if (num_possible_cpus() == 0) {
275662306a36Sopenharmony_ci		printf("No possible cpus, use 'dp #' to dump individual cpus\n");
275762306a36Sopenharmony_ci		return;
275862306a36Sopenharmony_ci	}
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	for_each_possible_cpu(cpu)
276162306a36Sopenharmony_ci		dump_one_paca(cpu);
276262306a36Sopenharmony_ci}
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_cistatic void dump_pacas(void)
276562306a36Sopenharmony_ci{
276662306a36Sopenharmony_ci	unsigned long num;
276762306a36Sopenharmony_ci	int c;
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	c = inchar();
277062306a36Sopenharmony_ci	if (c == 'a') {
277162306a36Sopenharmony_ci		dump_all_pacas();
277262306a36Sopenharmony_ci		return;
277362306a36Sopenharmony_ci	}
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	termch = c;	/* Put c back, it wasn't 'a' */
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	if (scanhex(&num))
277862306a36Sopenharmony_ci		dump_one_paca(num);
277962306a36Sopenharmony_ci	else
278062306a36Sopenharmony_ci		dump_one_paca(xmon_owner);
278162306a36Sopenharmony_ci}
278262306a36Sopenharmony_ci#endif
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
278562306a36Sopenharmony_cistatic void dump_one_xive(int cpu)
278662306a36Sopenharmony_ci{
278762306a36Sopenharmony_ci	unsigned int hwid = get_hard_smp_processor_id(cpu);
278862306a36Sopenharmony_ci	bool hv = cpu_has_feature(CPU_FTR_HVMODE);
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	if (hv) {
279162306a36Sopenharmony_ci		opal_xive_dump(XIVE_DUMP_TM_HYP, hwid);
279262306a36Sopenharmony_ci		opal_xive_dump(XIVE_DUMP_TM_POOL, hwid);
279362306a36Sopenharmony_ci		opal_xive_dump(XIVE_DUMP_TM_OS, hwid);
279462306a36Sopenharmony_ci		opal_xive_dump(XIVE_DUMP_TM_USER, hwid);
279562306a36Sopenharmony_ci		opal_xive_dump(XIVE_DUMP_VP, hwid);
279662306a36Sopenharmony_ci		opal_xive_dump(XIVE_DUMP_EMU_STATE, hwid);
279762306a36Sopenharmony_ci	}
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) != 0) {
280062306a36Sopenharmony_ci		catch_memory_errors = 0;
280162306a36Sopenharmony_ci		printf("*** Error dumping xive on cpu %d\n", cpu);
280262306a36Sopenharmony_ci		return;
280362306a36Sopenharmony_ci	}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	catch_memory_errors = 1;
280662306a36Sopenharmony_ci	sync();
280762306a36Sopenharmony_ci	xmon_xive_do_dump(cpu);
280862306a36Sopenharmony_ci	sync();
280962306a36Sopenharmony_ci	__delay(200);
281062306a36Sopenharmony_ci	catch_memory_errors = 0;
281162306a36Sopenharmony_ci}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_cistatic void dump_all_xives(void)
281462306a36Sopenharmony_ci{
281562306a36Sopenharmony_ci	int cpu;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	if (num_online_cpus() == 0) {
281862306a36Sopenharmony_ci		printf("No possible cpus, use 'dx #' to dump individual cpus\n");
281962306a36Sopenharmony_ci		return;
282062306a36Sopenharmony_ci	}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	for_each_online_cpu(cpu)
282362306a36Sopenharmony_ci		dump_one_xive(cpu);
282462306a36Sopenharmony_ci}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_cistatic void dump_xives(void)
282762306a36Sopenharmony_ci{
282862306a36Sopenharmony_ci	unsigned long num;
282962306a36Sopenharmony_ci	int c;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	if (!xive_enabled()) {
283262306a36Sopenharmony_ci		printf("Xive disabled on this system\n");
283362306a36Sopenharmony_ci		return;
283462306a36Sopenharmony_ci	}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	c = inchar();
283762306a36Sopenharmony_ci	if (c == 'a') {
283862306a36Sopenharmony_ci		dump_all_xives();
283962306a36Sopenharmony_ci		return;
284062306a36Sopenharmony_ci	} else if (c == 'i') {
284162306a36Sopenharmony_ci		if (scanhex(&num))
284262306a36Sopenharmony_ci			xmon_xive_get_irq_config(num, NULL);
284362306a36Sopenharmony_ci		else
284462306a36Sopenharmony_ci			xmon_xive_get_irq_all();
284562306a36Sopenharmony_ci		return;
284662306a36Sopenharmony_ci	}
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	termch = c;	/* Put c back, it wasn't 'a' */
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	if (scanhex(&num))
285162306a36Sopenharmony_ci		dump_one_xive(num);
285262306a36Sopenharmony_ci	else
285362306a36Sopenharmony_ci		dump_one_xive(xmon_owner);
285462306a36Sopenharmony_ci}
285562306a36Sopenharmony_ci#endif /* CONFIG_PPC_POWERNV */
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_cistatic void dump_by_size(unsigned long addr, long count, int size)
285862306a36Sopenharmony_ci{
285962306a36Sopenharmony_ci	unsigned char temp[16];
286062306a36Sopenharmony_ci	int i, j;
286162306a36Sopenharmony_ci	u64 val;
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	count = ALIGN(count, 16);
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	for (i = 0; i < count; i += 16, addr += 16) {
286662306a36Sopenharmony_ci		printf(REG, addr);
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci		if (mread(addr, temp, 16) != 16) {
286962306a36Sopenharmony_ci			printf("\nFaulted reading %d bytes from 0x"REG"\n", 16, addr);
287062306a36Sopenharmony_ci			return;
287162306a36Sopenharmony_ci		}
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci		for (j = 0; j < 16; j += size) {
287462306a36Sopenharmony_ci			putchar(' ');
287562306a36Sopenharmony_ci			switch (size) {
287662306a36Sopenharmony_ci			case 1: val = temp[j]; break;
287762306a36Sopenharmony_ci			case 2: val = *(u16 *)&temp[j]; break;
287862306a36Sopenharmony_ci			case 4: val = *(u32 *)&temp[j]; break;
287962306a36Sopenharmony_ci			case 8: val = *(u64 *)&temp[j]; break;
288062306a36Sopenharmony_ci			default: val = 0;
288162306a36Sopenharmony_ci			}
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci			printf("%0*llx", size * 2, val);
288462306a36Sopenharmony_ci		}
288562306a36Sopenharmony_ci		printf("  |");
288662306a36Sopenharmony_ci		for (j = 0; j < 16; ++j) {
288762306a36Sopenharmony_ci			val = temp[j];
288862306a36Sopenharmony_ci			putchar(' ' <= val && val <= '~' ? val : '.');
288962306a36Sopenharmony_ci		}
289062306a36Sopenharmony_ci		printf("|\n");
289162306a36Sopenharmony_ci	}
289262306a36Sopenharmony_ci}
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_cistatic void
289562306a36Sopenharmony_cidump(void)
289662306a36Sopenharmony_ci{
289762306a36Sopenharmony_ci	static char last[] = { "d?\n" };
289862306a36Sopenharmony_ci	int c;
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	c = inchar();
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci#ifdef CONFIG_PPC64
290362306a36Sopenharmony_ci	if (c == 'p') {
290462306a36Sopenharmony_ci		xmon_start_pagination();
290562306a36Sopenharmony_ci		dump_pacas();
290662306a36Sopenharmony_ci		xmon_end_pagination();
290762306a36Sopenharmony_ci		return;
290862306a36Sopenharmony_ci	}
290962306a36Sopenharmony_ci#endif
291062306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
291162306a36Sopenharmony_ci	if (c == 'x') {
291262306a36Sopenharmony_ci		xmon_start_pagination();
291362306a36Sopenharmony_ci		dump_xives();
291462306a36Sopenharmony_ci		xmon_end_pagination();
291562306a36Sopenharmony_ci		return;
291662306a36Sopenharmony_ci	}
291762306a36Sopenharmony_ci#endif
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	if (c == 't') {
292062306a36Sopenharmony_ci		dump_tracing();
292162306a36Sopenharmony_ci		return;
292262306a36Sopenharmony_ci	}
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	if (c == '\n')
292562306a36Sopenharmony_ci		termch = c;
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	scanhex((void *)&adrs);
292862306a36Sopenharmony_ci	if (termch != '\n')
292962306a36Sopenharmony_ci		termch = 0;
293062306a36Sopenharmony_ci	if (c == 'i') {
293162306a36Sopenharmony_ci		scanhex(&nidump);
293262306a36Sopenharmony_ci		if (nidump == 0)
293362306a36Sopenharmony_ci			nidump = 16;
293462306a36Sopenharmony_ci		else if (nidump > MAX_IDUMP)
293562306a36Sopenharmony_ci			nidump = MAX_IDUMP;
293662306a36Sopenharmony_ci		adrs += ppc_inst_dump(adrs, nidump, 1);
293762306a36Sopenharmony_ci		last_cmd = "di\n";
293862306a36Sopenharmony_ci	} else if (c == 'l') {
293962306a36Sopenharmony_ci		dump_log_buf();
294062306a36Sopenharmony_ci	} else if (c == 'o') {
294162306a36Sopenharmony_ci		dump_opal_msglog();
294262306a36Sopenharmony_ci	} else if (c == 'v') {
294362306a36Sopenharmony_ci		/* dump virtual to physical translation */
294462306a36Sopenharmony_ci		show_pte(adrs);
294562306a36Sopenharmony_ci	} else if (c == 'r') {
294662306a36Sopenharmony_ci		scanhex(&ndump);
294762306a36Sopenharmony_ci		if (ndump == 0)
294862306a36Sopenharmony_ci			ndump = 64;
294962306a36Sopenharmony_ci		xmon_rawdump(adrs, ndump);
295062306a36Sopenharmony_ci		adrs += ndump;
295162306a36Sopenharmony_ci		last_cmd = "dr\n";
295262306a36Sopenharmony_ci	} else {
295362306a36Sopenharmony_ci		scanhex(&ndump);
295462306a36Sopenharmony_ci		if (ndump == 0)
295562306a36Sopenharmony_ci			ndump = 64;
295662306a36Sopenharmony_ci		else if (ndump > MAX_DUMP)
295762306a36Sopenharmony_ci			ndump = MAX_DUMP;
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci		switch (c) {
296062306a36Sopenharmony_ci		case '8':
296162306a36Sopenharmony_ci		case '4':
296262306a36Sopenharmony_ci		case '2':
296362306a36Sopenharmony_ci		case '1':
296462306a36Sopenharmony_ci			ndump = ALIGN(ndump, 16);
296562306a36Sopenharmony_ci			dump_by_size(adrs, ndump, c - '0');
296662306a36Sopenharmony_ci			last[1] = c;
296762306a36Sopenharmony_ci			last_cmd = last;
296862306a36Sopenharmony_ci			break;
296962306a36Sopenharmony_ci		default:
297062306a36Sopenharmony_ci			prdump(adrs, ndump);
297162306a36Sopenharmony_ci			last_cmd = "d\n";
297262306a36Sopenharmony_ci		}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci		adrs += ndump;
297562306a36Sopenharmony_ci	}
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_cistatic void
297962306a36Sopenharmony_ciprdump(unsigned long adrs, long ndump)
298062306a36Sopenharmony_ci{
298162306a36Sopenharmony_ci	long n, m, c, r, nr;
298262306a36Sopenharmony_ci	unsigned char temp[16];
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	for (n = ndump; n > 0;) {
298562306a36Sopenharmony_ci		printf(REG, adrs);
298662306a36Sopenharmony_ci		putchar(' ');
298762306a36Sopenharmony_ci		r = n < 16? n: 16;
298862306a36Sopenharmony_ci		nr = mread(adrs, temp, r);
298962306a36Sopenharmony_ci		adrs += nr;
299062306a36Sopenharmony_ci		for (m = 0; m < r; ++m) {
299162306a36Sopenharmony_ci			if ((m & (sizeof(long) - 1)) == 0 && m > 0)
299262306a36Sopenharmony_ci				putchar(' ');
299362306a36Sopenharmony_ci			if (m < nr)
299462306a36Sopenharmony_ci				printf("%.2x", temp[m]);
299562306a36Sopenharmony_ci			else
299662306a36Sopenharmony_ci				printf("%s", fault_chars[fault_type]);
299762306a36Sopenharmony_ci		}
299862306a36Sopenharmony_ci		for (; m < 16; ++m) {
299962306a36Sopenharmony_ci			if ((m & (sizeof(long) - 1)) == 0)
300062306a36Sopenharmony_ci				putchar(' ');
300162306a36Sopenharmony_ci			printf("  ");
300262306a36Sopenharmony_ci		}
300362306a36Sopenharmony_ci		printf("  |");
300462306a36Sopenharmony_ci		for (m = 0; m < r; ++m) {
300562306a36Sopenharmony_ci			if (m < nr) {
300662306a36Sopenharmony_ci				c = temp[m];
300762306a36Sopenharmony_ci				putchar(' ' <= c && c <= '~'? c: '.');
300862306a36Sopenharmony_ci			} else
300962306a36Sopenharmony_ci				putchar(' ');
301062306a36Sopenharmony_ci		}
301162306a36Sopenharmony_ci		n -= r;
301262306a36Sopenharmony_ci		for (; m < 16; ++m)
301362306a36Sopenharmony_ci			putchar(' ');
301462306a36Sopenharmony_ci		printf("|\n");
301562306a36Sopenharmony_ci		if (nr < r)
301662306a36Sopenharmony_ci			break;
301762306a36Sopenharmony_ci	}
301862306a36Sopenharmony_ci}
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_citypedef int (*instruction_dump_func)(unsigned long inst, unsigned long addr);
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_cistatic int
302362306a36Sopenharmony_cigeneric_inst_dump(unsigned long adr, long count, int praddr,
302462306a36Sopenharmony_ci			instruction_dump_func dump_func)
302562306a36Sopenharmony_ci{
302662306a36Sopenharmony_ci	int nr, dotted;
302762306a36Sopenharmony_ci	unsigned long first_adr;
302862306a36Sopenharmony_ci	ppc_inst_t inst, last_inst = ppc_inst(0);
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	dotted = 0;
303162306a36Sopenharmony_ci	for (first_adr = adr; count > 0; --count, adr += ppc_inst_len(inst)) {
303262306a36Sopenharmony_ci		nr = mread_instr(adr, &inst);
303362306a36Sopenharmony_ci		if (nr == 0) {
303462306a36Sopenharmony_ci			if (praddr) {
303562306a36Sopenharmony_ci				const char *x = fault_chars[fault_type];
303662306a36Sopenharmony_ci				printf(REG"  %s%s%s%s\n", adr, x, x, x, x);
303762306a36Sopenharmony_ci			}
303862306a36Sopenharmony_ci			break;
303962306a36Sopenharmony_ci		}
304062306a36Sopenharmony_ci		if (adr > first_adr && ppc_inst_equal(inst, last_inst)) {
304162306a36Sopenharmony_ci			if (!dotted) {
304262306a36Sopenharmony_ci				printf(" ...\n");
304362306a36Sopenharmony_ci				dotted = 1;
304462306a36Sopenharmony_ci			}
304562306a36Sopenharmony_ci			continue;
304662306a36Sopenharmony_ci		}
304762306a36Sopenharmony_ci		dotted = 0;
304862306a36Sopenharmony_ci		last_inst = inst;
304962306a36Sopenharmony_ci		if (praddr)
305062306a36Sopenharmony_ci			printf(REG"  %08lx", adr, ppc_inst_as_ulong(inst));
305162306a36Sopenharmony_ci		printf("\t");
305262306a36Sopenharmony_ci		if (!ppc_inst_prefixed(inst))
305362306a36Sopenharmony_ci			dump_func(ppc_inst_val(inst), adr);
305462306a36Sopenharmony_ci		else
305562306a36Sopenharmony_ci			dump_func(ppc_inst_as_ulong(inst), adr);
305662306a36Sopenharmony_ci		printf("\n");
305762306a36Sopenharmony_ci	}
305862306a36Sopenharmony_ci	return adr - first_adr;
305962306a36Sopenharmony_ci}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_cistatic int
306262306a36Sopenharmony_cippc_inst_dump(unsigned long adr, long count, int praddr)
306362306a36Sopenharmony_ci{
306462306a36Sopenharmony_ci	return generic_inst_dump(adr, count, praddr, print_insn_powerpc);
306562306a36Sopenharmony_ci}
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_civoid
306862306a36Sopenharmony_ciprint_address(unsigned long addr)
306962306a36Sopenharmony_ci{
307062306a36Sopenharmony_ci	xmon_print_symbol(addr, "\t# ", "");
307162306a36Sopenharmony_ci}
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_cistatic void
307462306a36Sopenharmony_cidump_log_buf(void)
307562306a36Sopenharmony_ci{
307662306a36Sopenharmony_ci	struct kmsg_dump_iter iter;
307762306a36Sopenharmony_ci	static unsigned char buf[1024];
307862306a36Sopenharmony_ci	size_t len;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) != 0) {
308162306a36Sopenharmony_ci		printf("Error dumping printk buffer!\n");
308262306a36Sopenharmony_ci		return;
308362306a36Sopenharmony_ci	}
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	catch_memory_errors = 1;
308662306a36Sopenharmony_ci	sync();
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	kmsg_dump_rewind(&iter);
308962306a36Sopenharmony_ci	xmon_start_pagination();
309062306a36Sopenharmony_ci	while (kmsg_dump_get_line(&iter, false, buf, sizeof(buf), &len)) {
309162306a36Sopenharmony_ci		buf[len] = '\0';
309262306a36Sopenharmony_ci		printf("%s", buf);
309362306a36Sopenharmony_ci	}
309462306a36Sopenharmony_ci	xmon_end_pagination();
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	sync();
309762306a36Sopenharmony_ci	/* wait a little while to see if we get a machine check */
309862306a36Sopenharmony_ci	__delay(200);
309962306a36Sopenharmony_ci	catch_memory_errors = 0;
310062306a36Sopenharmony_ci}
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci#ifdef CONFIG_PPC_POWERNV
310362306a36Sopenharmony_cistatic void dump_opal_msglog(void)
310462306a36Sopenharmony_ci{
310562306a36Sopenharmony_ci	unsigned char buf[128];
310662306a36Sopenharmony_ci	ssize_t res;
310762306a36Sopenharmony_ci	volatile loff_t pos = 0;
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	if (!firmware_has_feature(FW_FEATURE_OPAL)) {
311062306a36Sopenharmony_ci		printf("Machine is not running OPAL firmware.\n");
311162306a36Sopenharmony_ci		return;
311262306a36Sopenharmony_ci	}
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) != 0) {
311562306a36Sopenharmony_ci		printf("Error dumping OPAL msglog!\n");
311662306a36Sopenharmony_ci		return;
311762306a36Sopenharmony_ci	}
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	catch_memory_errors = 1;
312062306a36Sopenharmony_ci	sync();
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	xmon_start_pagination();
312362306a36Sopenharmony_ci	while ((res = opal_msglog_copy(buf, pos, sizeof(buf) - 1))) {
312462306a36Sopenharmony_ci		if (res < 0) {
312562306a36Sopenharmony_ci			printf("Error dumping OPAL msglog! Error: %zd\n", res);
312662306a36Sopenharmony_ci			break;
312762306a36Sopenharmony_ci		}
312862306a36Sopenharmony_ci		buf[res] = '\0';
312962306a36Sopenharmony_ci		printf("%s", buf);
313062306a36Sopenharmony_ci		pos += res;
313162306a36Sopenharmony_ci	}
313262306a36Sopenharmony_ci	xmon_end_pagination();
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	sync();
313562306a36Sopenharmony_ci	/* wait a little while to see if we get a machine check */
313662306a36Sopenharmony_ci	__delay(200);
313762306a36Sopenharmony_ci	catch_memory_errors = 0;
313862306a36Sopenharmony_ci}
313962306a36Sopenharmony_ci#endif
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci/*
314262306a36Sopenharmony_ci * Memory operations - move, set, print differences
314362306a36Sopenharmony_ci */
314462306a36Sopenharmony_cistatic unsigned long mdest;		/* destination address */
314562306a36Sopenharmony_cistatic unsigned long msrc;		/* source address */
314662306a36Sopenharmony_cistatic unsigned long mval;		/* byte value to set memory to */
314762306a36Sopenharmony_cistatic unsigned long mcount;		/* # bytes to affect */
314862306a36Sopenharmony_cistatic unsigned long mdiffs;		/* max # differences to print */
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_cistatic void
315162306a36Sopenharmony_cimemops(int cmd)
315262306a36Sopenharmony_ci{
315362306a36Sopenharmony_ci	scanhex((void *)&mdest);
315462306a36Sopenharmony_ci	if( termch != '\n' )
315562306a36Sopenharmony_ci		termch = 0;
315662306a36Sopenharmony_ci	scanhex((void *)(cmd == 's'? &mval: &msrc));
315762306a36Sopenharmony_ci	if( termch != '\n' )
315862306a36Sopenharmony_ci		termch = 0;
315962306a36Sopenharmony_ci	scanhex((void *)&mcount);
316062306a36Sopenharmony_ci	switch( cmd ){
316162306a36Sopenharmony_ci	case 'm':
316262306a36Sopenharmony_ci		if (xmon_is_ro) {
316362306a36Sopenharmony_ci			printf(xmon_ro_msg);
316462306a36Sopenharmony_ci			break;
316562306a36Sopenharmony_ci		}
316662306a36Sopenharmony_ci		memmove((void *)mdest, (void *)msrc, mcount);
316762306a36Sopenharmony_ci		break;
316862306a36Sopenharmony_ci	case 's':
316962306a36Sopenharmony_ci		if (xmon_is_ro) {
317062306a36Sopenharmony_ci			printf(xmon_ro_msg);
317162306a36Sopenharmony_ci			break;
317262306a36Sopenharmony_ci		}
317362306a36Sopenharmony_ci		memset((void *)mdest, mval, mcount);
317462306a36Sopenharmony_ci		break;
317562306a36Sopenharmony_ci	case 'd':
317662306a36Sopenharmony_ci		if( termch != '\n' )
317762306a36Sopenharmony_ci			termch = 0;
317862306a36Sopenharmony_ci		scanhex((void *)&mdiffs);
317962306a36Sopenharmony_ci		memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
318062306a36Sopenharmony_ci		break;
318162306a36Sopenharmony_ci	}
318262306a36Sopenharmony_ci}
318362306a36Sopenharmony_ci
318462306a36Sopenharmony_cistatic void
318562306a36Sopenharmony_cimemdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
318662306a36Sopenharmony_ci{
318762306a36Sopenharmony_ci	unsigned n, prt;
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	prt = 0;
319062306a36Sopenharmony_ci	for( n = nb; n > 0; --n )
319162306a36Sopenharmony_ci		if( *p1++ != *p2++ )
319262306a36Sopenharmony_ci			if( ++prt <= maxpr )
319362306a36Sopenharmony_ci				printf("%px %.2x # %px %.2x\n", p1 - 1,
319462306a36Sopenharmony_ci					p1[-1], p2 - 1, p2[-1]);
319562306a36Sopenharmony_ci	if( prt > maxpr )
319662306a36Sopenharmony_ci		printf("Total of %d differences\n", prt);
319762306a36Sopenharmony_ci}
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_cistatic unsigned mend;
320062306a36Sopenharmony_cistatic unsigned mask;
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_cistatic void
320362306a36Sopenharmony_cimemlocate(void)
320462306a36Sopenharmony_ci{
320562306a36Sopenharmony_ci	unsigned a, n;
320662306a36Sopenharmony_ci	unsigned char val[4];
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci	last_cmd = "ml";
320962306a36Sopenharmony_ci	scanhex((void *)&mdest);
321062306a36Sopenharmony_ci	if (termch != '\n') {
321162306a36Sopenharmony_ci		termch = 0;
321262306a36Sopenharmony_ci		scanhex((void *)&mend);
321362306a36Sopenharmony_ci		if (termch != '\n') {
321462306a36Sopenharmony_ci			termch = 0;
321562306a36Sopenharmony_ci			scanhex((void *)&mval);
321662306a36Sopenharmony_ci			mask = ~0;
321762306a36Sopenharmony_ci			if (termch != '\n') termch = 0;
321862306a36Sopenharmony_ci			scanhex((void *)&mask);
321962306a36Sopenharmony_ci		}
322062306a36Sopenharmony_ci	}
322162306a36Sopenharmony_ci	n = 0;
322262306a36Sopenharmony_ci	for (a = mdest; a < mend; a += 4) {
322362306a36Sopenharmony_ci		if (mread(a, val, 4) == 4
322462306a36Sopenharmony_ci			&& ((GETWORD(val) ^ mval) & mask) == 0) {
322562306a36Sopenharmony_ci			printf("%.16x:  %.16x\n", a, GETWORD(val));
322662306a36Sopenharmony_ci			if (++n >= 10)
322762306a36Sopenharmony_ci				break;
322862306a36Sopenharmony_ci		}
322962306a36Sopenharmony_ci	}
323062306a36Sopenharmony_ci}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_cistatic unsigned long mskip = 0x1000;
323362306a36Sopenharmony_cistatic unsigned long mlim = 0xffffffff;
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_cistatic void
323662306a36Sopenharmony_cimemzcan(void)
323762306a36Sopenharmony_ci{
323862306a36Sopenharmony_ci	unsigned char v;
323962306a36Sopenharmony_ci	unsigned a;
324062306a36Sopenharmony_ci	int ok, ook;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	scanhex(&mdest);
324362306a36Sopenharmony_ci	if (termch != '\n') termch = 0;
324462306a36Sopenharmony_ci	scanhex(&mskip);
324562306a36Sopenharmony_ci	if (termch != '\n') termch = 0;
324662306a36Sopenharmony_ci	scanhex(&mlim);
324762306a36Sopenharmony_ci	ook = 0;
324862306a36Sopenharmony_ci	for (a = mdest; a < mlim; a += mskip) {
324962306a36Sopenharmony_ci		ok = mread(a, &v, 1);
325062306a36Sopenharmony_ci		if (ok && !ook) {
325162306a36Sopenharmony_ci			printf("%.8x .. ", a);
325262306a36Sopenharmony_ci		} else if (!ok && ook)
325362306a36Sopenharmony_ci			printf("%.8lx\n", a - mskip);
325462306a36Sopenharmony_ci		ook = ok;
325562306a36Sopenharmony_ci		if (a + mskip < a)
325662306a36Sopenharmony_ci			break;
325762306a36Sopenharmony_ci	}
325862306a36Sopenharmony_ci	if (ook)
325962306a36Sopenharmony_ci		printf("%.8lx\n", a - mskip);
326062306a36Sopenharmony_ci}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_cistatic void show_task(struct task_struct *volatile tsk)
326362306a36Sopenharmony_ci{
326462306a36Sopenharmony_ci	unsigned int p_state = READ_ONCE(tsk->__state);
326562306a36Sopenharmony_ci	char state;
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	/*
326862306a36Sopenharmony_ci	 * Cloned from kdb_task_state_char(), which is not entirely
326962306a36Sopenharmony_ci	 * appropriate for calling from xmon. This could be moved
327062306a36Sopenharmony_ci	 * to a common, generic, routine used by both.
327162306a36Sopenharmony_ci	 */
327262306a36Sopenharmony_ci	state = (p_state == TASK_RUNNING) ? 'R' :
327362306a36Sopenharmony_ci		(p_state & TASK_UNINTERRUPTIBLE) ? 'D' :
327462306a36Sopenharmony_ci		(p_state & TASK_STOPPED) ? 'T' :
327562306a36Sopenharmony_ci		(p_state & TASK_TRACED) ? 'C' :
327662306a36Sopenharmony_ci		(tsk->exit_state & EXIT_ZOMBIE) ? 'Z' :
327762306a36Sopenharmony_ci		(tsk->exit_state & EXIT_DEAD) ? 'E' :
327862306a36Sopenharmony_ci		(p_state & TASK_INTERRUPTIBLE) ? 'S' : '?';
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	printf("%16px %16lx %16px %6d %6d %c %2d %s\n", tsk,
328162306a36Sopenharmony_ci		tsk->thread.ksp, tsk->thread.regs,
328262306a36Sopenharmony_ci		tsk->pid, rcu_dereference(tsk->parent)->pid,
328362306a36Sopenharmony_ci		state, task_cpu(tsk),
328462306a36Sopenharmony_ci		tsk->comm);
328562306a36Sopenharmony_ci}
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
328862306a36Sopenharmony_cistatic void format_pte(void *ptep, unsigned long pte)
328962306a36Sopenharmony_ci{
329062306a36Sopenharmony_ci	pte_t entry = __pte(pte);
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);
329362306a36Sopenharmony_ci	printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	printf("Flags = %s%s%s%s%s\n",
329662306a36Sopenharmony_ci	       pte_young(entry) ? "Accessed " : "",
329762306a36Sopenharmony_ci	       pte_dirty(entry) ? "Dirty " : "",
329862306a36Sopenharmony_ci	       pte_read(entry)  ? "Read " : "",
329962306a36Sopenharmony_ci	       pte_write(entry) ? "Write " : "",
330062306a36Sopenharmony_ci	       pte_exec(entry)  ? "Exec " : "");
330162306a36Sopenharmony_ci}
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_cistatic void show_pte(unsigned long addr)
330462306a36Sopenharmony_ci{
330562306a36Sopenharmony_ci	unsigned long tskv = 0;
330662306a36Sopenharmony_ci	struct task_struct *volatile tsk = NULL;
330762306a36Sopenharmony_ci	struct mm_struct *volatile mm;
330862306a36Sopenharmony_ci	pgd_t *pgdp;
330962306a36Sopenharmony_ci	p4d_t *p4dp;
331062306a36Sopenharmony_ci	pud_t *pudp;
331162306a36Sopenharmony_ci	pmd_t *pmdp;
331262306a36Sopenharmony_ci	pte_t *ptep;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	if (!scanhex(&tskv))
331562306a36Sopenharmony_ci		mm = &init_mm;
331662306a36Sopenharmony_ci	else
331762306a36Sopenharmony_ci		tsk = (struct task_struct *)tskv;
331862306a36Sopenharmony_ci
331962306a36Sopenharmony_ci	if (tsk == NULL)
332062306a36Sopenharmony_ci		mm = &init_mm;
332162306a36Sopenharmony_ci	else
332262306a36Sopenharmony_ci		mm = tsk->active_mm;
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) != 0) {
332562306a36Sopenharmony_ci		catch_memory_errors = 0;
332662306a36Sopenharmony_ci		printf("*** Error dumping pte for task %px\n", tsk);
332762306a36Sopenharmony_ci		return;
332862306a36Sopenharmony_ci	}
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	catch_memory_errors = 1;
333162306a36Sopenharmony_ci	sync();
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	if (mm == &init_mm)
333462306a36Sopenharmony_ci		pgdp = pgd_offset_k(addr);
333562306a36Sopenharmony_ci	else
333662306a36Sopenharmony_ci		pgdp = pgd_offset(mm, addr);
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci	p4dp = p4d_offset(pgdp, addr);
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci	if (p4d_none(*p4dp)) {
334162306a36Sopenharmony_ci		printf("No valid P4D\n");
334262306a36Sopenharmony_ci		return;
334362306a36Sopenharmony_ci	}
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci	if (p4d_is_leaf(*p4dp)) {
334662306a36Sopenharmony_ci		format_pte(p4dp, p4d_val(*p4dp));
334762306a36Sopenharmony_ci		return;
334862306a36Sopenharmony_ci	}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	printf("p4dp @ 0x%px = 0x%016lx\n", p4dp, p4d_val(*p4dp));
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	pudp = pud_offset(p4dp, addr);
335362306a36Sopenharmony_ci
335462306a36Sopenharmony_ci	if (pud_none(*pudp)) {
335562306a36Sopenharmony_ci		printf("No valid PUD\n");
335662306a36Sopenharmony_ci		return;
335762306a36Sopenharmony_ci	}
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	if (pud_is_leaf(*pudp)) {
336062306a36Sopenharmony_ci		format_pte(pudp, pud_val(*pudp));
336162306a36Sopenharmony_ci		return;
336262306a36Sopenharmony_ci	}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	printf("pudp @ 0x%px = 0x%016lx\n", pudp, pud_val(*pudp));
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_ci	pmdp = pmd_offset(pudp, addr);
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	if (pmd_none(*pmdp)) {
336962306a36Sopenharmony_ci		printf("No valid PMD\n");
337062306a36Sopenharmony_ci		return;
337162306a36Sopenharmony_ci	}
337262306a36Sopenharmony_ci
337362306a36Sopenharmony_ci	if (pmd_is_leaf(*pmdp)) {
337462306a36Sopenharmony_ci		format_pte(pmdp, pmd_val(*pmdp));
337562306a36Sopenharmony_ci		return;
337662306a36Sopenharmony_ci	}
337762306a36Sopenharmony_ci	printf("pmdp @ 0x%px = 0x%016lx\n", pmdp, pmd_val(*pmdp));
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci	ptep = pte_offset_map(pmdp, addr);
338062306a36Sopenharmony_ci	if (!ptep || pte_none(*ptep)) {
338162306a36Sopenharmony_ci		if (ptep)
338262306a36Sopenharmony_ci			pte_unmap(ptep);
338362306a36Sopenharmony_ci		printf("no valid PTE\n");
338462306a36Sopenharmony_ci		return;
338562306a36Sopenharmony_ci	}
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	format_pte(ptep, pte_val(*ptep));
338862306a36Sopenharmony_ci	pte_unmap(ptep);
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	sync();
339162306a36Sopenharmony_ci	__delay(200);
339262306a36Sopenharmony_ci	catch_memory_errors = 0;
339362306a36Sopenharmony_ci}
339462306a36Sopenharmony_ci#else
339562306a36Sopenharmony_cistatic void show_pte(unsigned long addr)
339662306a36Sopenharmony_ci{
339762306a36Sopenharmony_ci	printf("show_pte not yet implemented\n");
339862306a36Sopenharmony_ci}
339962306a36Sopenharmony_ci#endif /* CONFIG_PPC_BOOK3S_64 */
340062306a36Sopenharmony_ci
340162306a36Sopenharmony_cistatic void show_tasks(void)
340262306a36Sopenharmony_ci{
340362306a36Sopenharmony_ci	unsigned long tskv;
340462306a36Sopenharmony_ci	struct task_struct *volatile tsk = NULL;
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci	printf("     task_struct     ->thread.ksp    ->thread.regs    PID   PPID S  P CMD\n");
340762306a36Sopenharmony_ci
340862306a36Sopenharmony_ci	if (scanhex(&tskv))
340962306a36Sopenharmony_ci		tsk = (struct task_struct *)tskv;
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) != 0) {
341262306a36Sopenharmony_ci		catch_memory_errors = 0;
341362306a36Sopenharmony_ci		printf("*** Error dumping task %px\n", tsk);
341462306a36Sopenharmony_ci		return;
341562306a36Sopenharmony_ci	}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	catch_memory_errors = 1;
341862306a36Sopenharmony_ci	sync();
341962306a36Sopenharmony_ci
342062306a36Sopenharmony_ci	if (tsk)
342162306a36Sopenharmony_ci		show_task(tsk);
342262306a36Sopenharmony_ci	else
342362306a36Sopenharmony_ci		for_each_process(tsk)
342462306a36Sopenharmony_ci			show_task(tsk);
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	sync();
342762306a36Sopenharmony_ci	__delay(200);
342862306a36Sopenharmony_ci	catch_memory_errors = 0;
342962306a36Sopenharmony_ci}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_cistatic void proccall(void)
343262306a36Sopenharmony_ci{
343362306a36Sopenharmony_ci	unsigned long args[8];
343462306a36Sopenharmony_ci	unsigned long ret;
343562306a36Sopenharmony_ci	int i;
343662306a36Sopenharmony_ci	typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
343762306a36Sopenharmony_ci			unsigned long, unsigned long, unsigned long,
343862306a36Sopenharmony_ci			unsigned long, unsigned long, unsigned long);
343962306a36Sopenharmony_ci	callfunc_t func;
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci	if (!scanhex(&adrs))
344262306a36Sopenharmony_ci		return;
344362306a36Sopenharmony_ci	if (termch != '\n')
344462306a36Sopenharmony_ci		termch = 0;
344562306a36Sopenharmony_ci	for (i = 0; i < 8; ++i)
344662306a36Sopenharmony_ci		args[i] = 0;
344762306a36Sopenharmony_ci	for (i = 0; i < 8; ++i) {
344862306a36Sopenharmony_ci		if (!scanhex(&args[i]) || termch == '\n')
344962306a36Sopenharmony_ci			break;
345062306a36Sopenharmony_ci		termch = 0;
345162306a36Sopenharmony_ci	}
345262306a36Sopenharmony_ci	func = (callfunc_t) adrs;
345362306a36Sopenharmony_ci	ret = 0;
345462306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
345562306a36Sopenharmony_ci		catch_memory_errors = 1;
345662306a36Sopenharmony_ci		sync();
345762306a36Sopenharmony_ci		ret = func(args[0], args[1], args[2], args[3],
345862306a36Sopenharmony_ci			   args[4], args[5], args[6], args[7]);
345962306a36Sopenharmony_ci		sync();
346062306a36Sopenharmony_ci		printf("return value is 0x%lx\n", ret);
346162306a36Sopenharmony_ci	} else {
346262306a36Sopenharmony_ci		printf("*** %x exception occurred\n", fault_except);
346362306a36Sopenharmony_ci	}
346462306a36Sopenharmony_ci	catch_memory_errors = 0;
346562306a36Sopenharmony_ci}
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci/* Input scanning routines */
346862306a36Sopenharmony_ciint
346962306a36Sopenharmony_ciskipbl(void)
347062306a36Sopenharmony_ci{
347162306a36Sopenharmony_ci	int c;
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	if( termch != 0 ){
347462306a36Sopenharmony_ci		c = termch;
347562306a36Sopenharmony_ci		termch = 0;
347662306a36Sopenharmony_ci	} else
347762306a36Sopenharmony_ci		c = inchar();
347862306a36Sopenharmony_ci	while( c == ' ' || c == '\t' )
347962306a36Sopenharmony_ci		c = inchar();
348062306a36Sopenharmony_ci	return c;
348162306a36Sopenharmony_ci}
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci#define N_PTREGS	44
348462306a36Sopenharmony_cistatic const char *regnames[N_PTREGS] = {
348562306a36Sopenharmony_ci	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
348662306a36Sopenharmony_ci	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
348762306a36Sopenharmony_ci	"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
348862306a36Sopenharmony_ci	"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
348962306a36Sopenharmony_ci	"pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
349062306a36Sopenharmony_ci#ifdef CONFIG_PPC64
349162306a36Sopenharmony_ci	"softe",
349262306a36Sopenharmony_ci#else
349362306a36Sopenharmony_ci	"mq",
349462306a36Sopenharmony_ci#endif
349562306a36Sopenharmony_ci	"trap", "dar", "dsisr", "res"
349662306a36Sopenharmony_ci};
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ciint
349962306a36Sopenharmony_ciscanhex(unsigned long *vp)
350062306a36Sopenharmony_ci{
350162306a36Sopenharmony_ci	int c, d;
350262306a36Sopenharmony_ci	unsigned long v;
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	c = skipbl();
350562306a36Sopenharmony_ci	if (c == '%') {
350662306a36Sopenharmony_ci		/* parse register name */
350762306a36Sopenharmony_ci		char regname[8];
350862306a36Sopenharmony_ci		int i;
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci		for (i = 0; i < sizeof(regname) - 1; ++i) {
351162306a36Sopenharmony_ci			c = inchar();
351262306a36Sopenharmony_ci			if (!isalnum(c)) {
351362306a36Sopenharmony_ci				termch = c;
351462306a36Sopenharmony_ci				break;
351562306a36Sopenharmony_ci			}
351662306a36Sopenharmony_ci			regname[i] = c;
351762306a36Sopenharmony_ci		}
351862306a36Sopenharmony_ci		regname[i] = 0;
351962306a36Sopenharmony_ci		i = match_string(regnames, N_PTREGS, regname);
352062306a36Sopenharmony_ci		if (i < 0) {
352162306a36Sopenharmony_ci			printf("invalid register name '%%%s'\n", regname);
352262306a36Sopenharmony_ci			return 0;
352362306a36Sopenharmony_ci		}
352462306a36Sopenharmony_ci		if (xmon_regs == NULL) {
352562306a36Sopenharmony_ci			printf("regs not available\n");
352662306a36Sopenharmony_ci			return 0;
352762306a36Sopenharmony_ci		}
352862306a36Sopenharmony_ci		*vp = ((unsigned long *)xmon_regs)[i];
352962306a36Sopenharmony_ci		return 1;
353062306a36Sopenharmony_ci	}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	/* skip leading "0x" if any */
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	if (c == '0') {
353562306a36Sopenharmony_ci		c = inchar();
353662306a36Sopenharmony_ci		if (c == 'x') {
353762306a36Sopenharmony_ci			c = inchar();
353862306a36Sopenharmony_ci		} else {
353962306a36Sopenharmony_ci			d = hexdigit(c);
354062306a36Sopenharmony_ci			if (d == EOF) {
354162306a36Sopenharmony_ci				termch = c;
354262306a36Sopenharmony_ci				*vp = 0;
354362306a36Sopenharmony_ci				return 1;
354462306a36Sopenharmony_ci			}
354562306a36Sopenharmony_ci		}
354662306a36Sopenharmony_ci	} else if (c == '$') {
354762306a36Sopenharmony_ci		int i;
354862306a36Sopenharmony_ci		for (i=0; i<63; i++) {
354962306a36Sopenharmony_ci			c = inchar();
355062306a36Sopenharmony_ci			if (isspace(c) || c == '\0') {
355162306a36Sopenharmony_ci				termch = c;
355262306a36Sopenharmony_ci				break;
355362306a36Sopenharmony_ci			}
355462306a36Sopenharmony_ci			tmpstr[i] = c;
355562306a36Sopenharmony_ci		}
355662306a36Sopenharmony_ci		tmpstr[i++] = 0;
355762306a36Sopenharmony_ci		*vp = 0;
355862306a36Sopenharmony_ci		if (setjmp(bus_error_jmp) == 0) {
355962306a36Sopenharmony_ci			catch_memory_errors = 1;
356062306a36Sopenharmony_ci			sync();
356162306a36Sopenharmony_ci			*vp = kallsyms_lookup_name(tmpstr);
356262306a36Sopenharmony_ci			sync();
356362306a36Sopenharmony_ci		}
356462306a36Sopenharmony_ci		catch_memory_errors = 0;
356562306a36Sopenharmony_ci		if (!(*vp)) {
356662306a36Sopenharmony_ci			printf("unknown symbol '%s'\n", tmpstr);
356762306a36Sopenharmony_ci			return 0;
356862306a36Sopenharmony_ci		}
356962306a36Sopenharmony_ci		return 1;
357062306a36Sopenharmony_ci	}
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	d = hexdigit(c);
357362306a36Sopenharmony_ci	if (d == EOF) {
357462306a36Sopenharmony_ci		termch = c;
357562306a36Sopenharmony_ci		return 0;
357662306a36Sopenharmony_ci	}
357762306a36Sopenharmony_ci	v = 0;
357862306a36Sopenharmony_ci	do {
357962306a36Sopenharmony_ci		v = (v << 4) + d;
358062306a36Sopenharmony_ci		c = inchar();
358162306a36Sopenharmony_ci		d = hexdigit(c);
358262306a36Sopenharmony_ci	} while (d != EOF);
358362306a36Sopenharmony_ci	termch = c;
358462306a36Sopenharmony_ci	*vp = v;
358562306a36Sopenharmony_ci	return 1;
358662306a36Sopenharmony_ci}
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_cistatic void
358962306a36Sopenharmony_ciscannl(void)
359062306a36Sopenharmony_ci{
359162306a36Sopenharmony_ci	int c;
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	c = termch;
359462306a36Sopenharmony_ci	termch = 0;
359562306a36Sopenharmony_ci	while( c != '\n' )
359662306a36Sopenharmony_ci		c = inchar();
359762306a36Sopenharmony_ci}
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_cistatic int hexdigit(int c)
360062306a36Sopenharmony_ci{
360162306a36Sopenharmony_ci	if( '0' <= c && c <= '9' )
360262306a36Sopenharmony_ci		return c - '0';
360362306a36Sopenharmony_ci	if( 'A' <= c && c <= 'F' )
360462306a36Sopenharmony_ci		return c - ('A' - 10);
360562306a36Sopenharmony_ci	if( 'a' <= c && c <= 'f' )
360662306a36Sopenharmony_ci		return c - ('a' - 10);
360762306a36Sopenharmony_ci	return EOF;
360862306a36Sopenharmony_ci}
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_civoid
361162306a36Sopenharmony_cigetstring(char *s, int size)
361262306a36Sopenharmony_ci{
361362306a36Sopenharmony_ci	int c;
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	c = skipbl();
361662306a36Sopenharmony_ci	if (c == '\n') {
361762306a36Sopenharmony_ci		*s = 0;
361862306a36Sopenharmony_ci		return;
361962306a36Sopenharmony_ci	}
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	do {
362262306a36Sopenharmony_ci		if( size > 1 ){
362362306a36Sopenharmony_ci			*s++ = c;
362462306a36Sopenharmony_ci			--size;
362562306a36Sopenharmony_ci		}
362662306a36Sopenharmony_ci		c = inchar();
362762306a36Sopenharmony_ci	} while( c != ' ' && c != '\t' && c != '\n' );
362862306a36Sopenharmony_ci	termch = c;
362962306a36Sopenharmony_ci	*s = 0;
363062306a36Sopenharmony_ci}
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_cistatic char line[256];
363362306a36Sopenharmony_cistatic char *lineptr;
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_cistatic void
363662306a36Sopenharmony_ciflush_input(void)
363762306a36Sopenharmony_ci{
363862306a36Sopenharmony_ci	lineptr = NULL;
363962306a36Sopenharmony_ci}
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_cistatic int
364262306a36Sopenharmony_ciinchar(void)
364362306a36Sopenharmony_ci{
364462306a36Sopenharmony_ci	if (lineptr == NULL || *lineptr == 0) {
364562306a36Sopenharmony_ci		if (xmon_gets(line, sizeof(line)) == NULL) {
364662306a36Sopenharmony_ci			lineptr = NULL;
364762306a36Sopenharmony_ci			return EOF;
364862306a36Sopenharmony_ci		}
364962306a36Sopenharmony_ci		lineptr = line;
365062306a36Sopenharmony_ci	}
365162306a36Sopenharmony_ci	return *lineptr++;
365262306a36Sopenharmony_ci}
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_cistatic void
365562306a36Sopenharmony_citake_input(char *str)
365662306a36Sopenharmony_ci{
365762306a36Sopenharmony_ci	lineptr = str;
365862306a36Sopenharmony_ci}
365962306a36Sopenharmony_ci
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_cistatic void
366262306a36Sopenharmony_cisymbol_lookup(void)
366362306a36Sopenharmony_ci{
366462306a36Sopenharmony_ci	int type = inchar();
366562306a36Sopenharmony_ci	unsigned long addr, cpu;
366662306a36Sopenharmony_ci	void __percpu *ptr = NULL;
366762306a36Sopenharmony_ci	static char tmp[64];
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	switch (type) {
367062306a36Sopenharmony_ci	case 'a':
367162306a36Sopenharmony_ci		if (scanhex(&addr))
367262306a36Sopenharmony_ci			xmon_print_symbol(addr, ": ", "\n");
367362306a36Sopenharmony_ci		termch = 0;
367462306a36Sopenharmony_ci		break;
367562306a36Sopenharmony_ci	case 's':
367662306a36Sopenharmony_ci		getstring(tmp, 64);
367762306a36Sopenharmony_ci		if (setjmp(bus_error_jmp) == 0) {
367862306a36Sopenharmony_ci			catch_memory_errors = 1;
367962306a36Sopenharmony_ci			sync();
368062306a36Sopenharmony_ci			addr = kallsyms_lookup_name(tmp);
368162306a36Sopenharmony_ci			if (addr)
368262306a36Sopenharmony_ci				printf("%s: %lx\n", tmp, addr);
368362306a36Sopenharmony_ci			else
368462306a36Sopenharmony_ci				printf("Symbol '%s' not found.\n", tmp);
368562306a36Sopenharmony_ci			sync();
368662306a36Sopenharmony_ci		}
368762306a36Sopenharmony_ci		catch_memory_errors = 0;
368862306a36Sopenharmony_ci		termch = 0;
368962306a36Sopenharmony_ci		break;
369062306a36Sopenharmony_ci	case 'p':
369162306a36Sopenharmony_ci		getstring(tmp, 64);
369262306a36Sopenharmony_ci		if (setjmp(bus_error_jmp) == 0) {
369362306a36Sopenharmony_ci			catch_memory_errors = 1;
369462306a36Sopenharmony_ci			sync();
369562306a36Sopenharmony_ci			ptr = (void __percpu *)kallsyms_lookup_name(tmp);
369662306a36Sopenharmony_ci			sync();
369762306a36Sopenharmony_ci		}
369862306a36Sopenharmony_ci
369962306a36Sopenharmony_ci		if (ptr &&
370062306a36Sopenharmony_ci		    ptr >= (void __percpu *)__per_cpu_start &&
370162306a36Sopenharmony_ci		    ptr < (void __percpu *)__per_cpu_end)
370262306a36Sopenharmony_ci		{
370362306a36Sopenharmony_ci			if (scanhex(&cpu) && cpu < num_possible_cpus()) {
370462306a36Sopenharmony_ci				addr = (unsigned long)per_cpu_ptr(ptr, cpu);
370562306a36Sopenharmony_ci			} else {
370662306a36Sopenharmony_ci				cpu = raw_smp_processor_id();
370762306a36Sopenharmony_ci				addr = (unsigned long)this_cpu_ptr(ptr);
370862306a36Sopenharmony_ci			}
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci			printf("%s for cpu 0x%lx: %lx\n", tmp, cpu, addr);
371162306a36Sopenharmony_ci		} else {
371262306a36Sopenharmony_ci			printf("Percpu symbol '%s' not found.\n", tmp);
371362306a36Sopenharmony_ci		}
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_ci		catch_memory_errors = 0;
371662306a36Sopenharmony_ci		termch = 0;
371762306a36Sopenharmony_ci		break;
371862306a36Sopenharmony_ci	}
371962306a36Sopenharmony_ci}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci/* Print an address in numeric and symbolic form (if possible) */
372362306a36Sopenharmony_cistatic void xmon_print_symbol(unsigned long address, const char *mid,
372462306a36Sopenharmony_ci			      const char *after)
372562306a36Sopenharmony_ci{
372662306a36Sopenharmony_ci	char *modname;
372762306a36Sopenharmony_ci	const char *volatile name = NULL;
372862306a36Sopenharmony_ci	unsigned long offset, size;
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	printf(REG, address);
373162306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
373262306a36Sopenharmony_ci		catch_memory_errors = 1;
373362306a36Sopenharmony_ci		sync();
373462306a36Sopenharmony_ci		name = kallsyms_lookup(address, &size, &offset, &modname,
373562306a36Sopenharmony_ci				       tmpstr);
373662306a36Sopenharmony_ci		sync();
373762306a36Sopenharmony_ci		/* wait a little while to see if we get a machine check */
373862306a36Sopenharmony_ci		__delay(200);
373962306a36Sopenharmony_ci	}
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci	catch_memory_errors = 0;
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	if (name) {
374462306a36Sopenharmony_ci		printf("%s%s+%#lx/%#lx", mid, name, offset, size);
374562306a36Sopenharmony_ci		if (modname)
374662306a36Sopenharmony_ci			printf(" [%s]", modname);
374762306a36Sopenharmony_ci	}
374862306a36Sopenharmony_ci	printf("%s", after);
374962306a36Sopenharmony_ci}
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci#ifdef CONFIG_PPC_64S_HASH_MMU
375262306a36Sopenharmony_civoid dump_segments(void)
375362306a36Sopenharmony_ci{
375462306a36Sopenharmony_ci	int i;
375562306a36Sopenharmony_ci	unsigned long esid,vsid;
375662306a36Sopenharmony_ci	unsigned long llp;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	printf("SLB contents of cpu 0x%x\n", smp_processor_id());
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci	for (i = 0; i < mmu_slb_size; i++) {
376162306a36Sopenharmony_ci		asm volatile("slbmfee  %0,%1" : "=r" (esid) : "r" (i));
376262306a36Sopenharmony_ci		asm volatile("slbmfev  %0,%1" : "=r" (vsid) : "r" (i));
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci		if (!esid && !vsid)
376562306a36Sopenharmony_ci			continue;
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_ci		printf("%02d %016lx %016lx", i, esid, vsid);
376862306a36Sopenharmony_ci
376962306a36Sopenharmony_ci		if (!(esid & SLB_ESID_V)) {
377062306a36Sopenharmony_ci			printf("\n");
377162306a36Sopenharmony_ci			continue;
377262306a36Sopenharmony_ci		}
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci		llp = vsid & SLB_VSID_LLP;
377562306a36Sopenharmony_ci		if (vsid & SLB_VSID_B_1T) {
377662306a36Sopenharmony_ci			printf("  1T  ESID=%9lx  VSID=%13lx LLP:%3lx \n",
377762306a36Sopenharmony_ci				GET_ESID_1T(esid),
377862306a36Sopenharmony_ci				(vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
377962306a36Sopenharmony_ci				llp);
378062306a36Sopenharmony_ci		} else {
378162306a36Sopenharmony_ci			printf(" 256M ESID=%9lx  VSID=%13lx LLP:%3lx \n",
378262306a36Sopenharmony_ci				GET_ESID(esid),
378362306a36Sopenharmony_ci				(vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
378462306a36Sopenharmony_ci				llp);
378562306a36Sopenharmony_ci		}
378662306a36Sopenharmony_ci	}
378762306a36Sopenharmony_ci}
378862306a36Sopenharmony_ci#endif
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_32
379162306a36Sopenharmony_civoid dump_segments(void)
379262306a36Sopenharmony_ci{
379362306a36Sopenharmony_ci	int i;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	printf("sr0-15 =");
379662306a36Sopenharmony_ci	for (i = 0; i < 16; ++i)
379762306a36Sopenharmony_ci		printf(" %x", mfsr(i << 28));
379862306a36Sopenharmony_ci	printf("\n");
379962306a36Sopenharmony_ci}
380062306a36Sopenharmony_ci#endif
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci#ifdef CONFIG_44x
380362306a36Sopenharmony_cistatic void dump_tlb_44x(void)
380462306a36Sopenharmony_ci{
380562306a36Sopenharmony_ci	int i;
380662306a36Sopenharmony_ci
380762306a36Sopenharmony_ci	for (i = 0; i < PPC44x_TLB_SIZE; i++) {
380862306a36Sopenharmony_ci		unsigned long w0,w1,w2;
380962306a36Sopenharmony_ci		asm volatile("tlbre  %0,%1,0" : "=r" (w0) : "r" (i));
381062306a36Sopenharmony_ci		asm volatile("tlbre  %0,%1,1" : "=r" (w1) : "r" (i));
381162306a36Sopenharmony_ci		asm volatile("tlbre  %0,%1,2" : "=r" (w2) : "r" (i));
381262306a36Sopenharmony_ci		printf("[%02x] %08lx %08lx %08lx ", i, w0, w1, w2);
381362306a36Sopenharmony_ci		if (w0 & PPC44x_TLB_VALID) {
381462306a36Sopenharmony_ci			printf("V %08lx -> %01lx%08lx %c%c%c%c%c",
381562306a36Sopenharmony_ci			       w0 & PPC44x_TLB_EPN_MASK,
381662306a36Sopenharmony_ci			       w1 & PPC44x_TLB_ERPN_MASK,
381762306a36Sopenharmony_ci			       w1 & PPC44x_TLB_RPN_MASK,
381862306a36Sopenharmony_ci			       (w2 & PPC44x_TLB_W) ? 'W' : 'w',
381962306a36Sopenharmony_ci			       (w2 & PPC44x_TLB_I) ? 'I' : 'i',
382062306a36Sopenharmony_ci			       (w2 & PPC44x_TLB_M) ? 'M' : 'm',
382162306a36Sopenharmony_ci			       (w2 & PPC44x_TLB_G) ? 'G' : 'g',
382262306a36Sopenharmony_ci			       (w2 & PPC44x_TLB_E) ? 'E' : 'e');
382362306a36Sopenharmony_ci		}
382462306a36Sopenharmony_ci		printf("\n");
382562306a36Sopenharmony_ci	}
382662306a36Sopenharmony_ci}
382762306a36Sopenharmony_ci#endif /* CONFIG_44x */
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3E_64
383062306a36Sopenharmony_cistatic void dump_tlb_book3e(void)
383162306a36Sopenharmony_ci{
383262306a36Sopenharmony_ci	u32 mmucfg;
383362306a36Sopenharmony_ci	u64 ramask;
383462306a36Sopenharmony_ci	int i, tlb, ntlbs, pidsz, lpidsz, rasz;
383562306a36Sopenharmony_ci	int mmu_version;
383662306a36Sopenharmony_ci	static const char *pgsz_names[] = {
383762306a36Sopenharmony_ci		"  1K",
383862306a36Sopenharmony_ci		"  2K",
383962306a36Sopenharmony_ci		"  4K",
384062306a36Sopenharmony_ci		"  8K",
384162306a36Sopenharmony_ci		" 16K",
384262306a36Sopenharmony_ci		" 32K",
384362306a36Sopenharmony_ci		" 64K",
384462306a36Sopenharmony_ci		"128K",
384562306a36Sopenharmony_ci		"256K",
384662306a36Sopenharmony_ci		"512K",
384762306a36Sopenharmony_ci		"  1M",
384862306a36Sopenharmony_ci		"  2M",
384962306a36Sopenharmony_ci		"  4M",
385062306a36Sopenharmony_ci		"  8M",
385162306a36Sopenharmony_ci		" 16M",
385262306a36Sopenharmony_ci		" 32M",
385362306a36Sopenharmony_ci		" 64M",
385462306a36Sopenharmony_ci		"128M",
385562306a36Sopenharmony_ci		"256M",
385662306a36Sopenharmony_ci		"512M",
385762306a36Sopenharmony_ci		"  1G",
385862306a36Sopenharmony_ci		"  2G",
385962306a36Sopenharmony_ci		"  4G",
386062306a36Sopenharmony_ci		"  8G",
386162306a36Sopenharmony_ci		" 16G",
386262306a36Sopenharmony_ci		" 32G",
386362306a36Sopenharmony_ci		" 64G",
386462306a36Sopenharmony_ci		"128G",
386562306a36Sopenharmony_ci		"256G",
386662306a36Sopenharmony_ci		"512G",
386762306a36Sopenharmony_ci		"  1T",
386862306a36Sopenharmony_ci		"  2T",
386962306a36Sopenharmony_ci	};
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci	/* Gather some infos about the MMU */
387262306a36Sopenharmony_ci	mmucfg = mfspr(SPRN_MMUCFG);
387362306a36Sopenharmony_ci	mmu_version = (mmucfg & 3) + 1;
387462306a36Sopenharmony_ci	ntlbs = ((mmucfg >> 2) & 3) + 1;
387562306a36Sopenharmony_ci	pidsz = ((mmucfg >> 6) & 0x1f) + 1;
387662306a36Sopenharmony_ci	lpidsz = (mmucfg >> 24) & 0xf;
387762306a36Sopenharmony_ci	rasz = (mmucfg >> 16) & 0x7f;
387862306a36Sopenharmony_ci	printf("Book3E MMU MAV=%d.0,%d TLBs,%d-bit PID,%d-bit LPID,%d-bit RA\n",
387962306a36Sopenharmony_ci	       mmu_version, ntlbs, pidsz, lpidsz, rasz);
388062306a36Sopenharmony_ci	ramask = (1ull << rasz) - 1;
388162306a36Sopenharmony_ci
388262306a36Sopenharmony_ci	for (tlb = 0; tlb < ntlbs; tlb++) {
388362306a36Sopenharmony_ci		u32 tlbcfg;
388462306a36Sopenharmony_ci		int nent, assoc, new_cc = 1;
388562306a36Sopenharmony_ci		printf("TLB %d:\n------\n", tlb);
388662306a36Sopenharmony_ci		switch(tlb) {
388762306a36Sopenharmony_ci		case 0:
388862306a36Sopenharmony_ci			tlbcfg = mfspr(SPRN_TLB0CFG);
388962306a36Sopenharmony_ci			break;
389062306a36Sopenharmony_ci		case 1:
389162306a36Sopenharmony_ci			tlbcfg = mfspr(SPRN_TLB1CFG);
389262306a36Sopenharmony_ci			break;
389362306a36Sopenharmony_ci		case 2:
389462306a36Sopenharmony_ci			tlbcfg = mfspr(SPRN_TLB2CFG);
389562306a36Sopenharmony_ci			break;
389662306a36Sopenharmony_ci		case 3:
389762306a36Sopenharmony_ci			tlbcfg = mfspr(SPRN_TLB3CFG);
389862306a36Sopenharmony_ci			break;
389962306a36Sopenharmony_ci		default:
390062306a36Sopenharmony_ci			printf("Unsupported TLB number !\n");
390162306a36Sopenharmony_ci			continue;
390262306a36Sopenharmony_ci		}
390362306a36Sopenharmony_ci		nent = tlbcfg & 0xfff;
390462306a36Sopenharmony_ci		assoc = (tlbcfg >> 24) & 0xff;
390562306a36Sopenharmony_ci		for (i = 0; i < nent; i++) {
390662306a36Sopenharmony_ci			u32 mas0 = MAS0_TLBSEL(tlb);
390762306a36Sopenharmony_ci			u32 mas1 = MAS1_TSIZE(BOOK3E_PAGESZ_4K);
390862306a36Sopenharmony_ci			u64 mas2 = 0;
390962306a36Sopenharmony_ci			u64 mas7_mas3;
391062306a36Sopenharmony_ci			int esel = i, cc = i;
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci			if (assoc != 0) {
391362306a36Sopenharmony_ci				cc = i / assoc;
391462306a36Sopenharmony_ci				esel = i % assoc;
391562306a36Sopenharmony_ci				mas2 = cc * 0x1000;
391662306a36Sopenharmony_ci			}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci			mas0 |= MAS0_ESEL(esel);
391962306a36Sopenharmony_ci			mtspr(SPRN_MAS0, mas0);
392062306a36Sopenharmony_ci			mtspr(SPRN_MAS1, mas1);
392162306a36Sopenharmony_ci			mtspr(SPRN_MAS2, mas2);
392262306a36Sopenharmony_ci			asm volatile("tlbre  0,0,0" : : : "memory");
392362306a36Sopenharmony_ci			mas1 = mfspr(SPRN_MAS1);
392462306a36Sopenharmony_ci			mas2 = mfspr(SPRN_MAS2);
392562306a36Sopenharmony_ci			mas7_mas3 = mfspr(SPRN_MAS7_MAS3);
392662306a36Sopenharmony_ci			if (assoc && (i % assoc) == 0)
392762306a36Sopenharmony_ci				new_cc = 1;
392862306a36Sopenharmony_ci			if (!(mas1 & MAS1_VALID))
392962306a36Sopenharmony_ci				continue;
393062306a36Sopenharmony_ci			if (assoc == 0)
393162306a36Sopenharmony_ci				printf("%04x- ", i);
393262306a36Sopenharmony_ci			else if (new_cc)
393362306a36Sopenharmony_ci				printf("%04x-%c", cc, 'A' + esel);
393462306a36Sopenharmony_ci			else
393562306a36Sopenharmony_ci				printf("    |%c", 'A' + esel);
393662306a36Sopenharmony_ci			new_cc = 0;
393762306a36Sopenharmony_ci			printf(" %016llx %04x %s %c%c AS%c",
393862306a36Sopenharmony_ci			       mas2 & ~0x3ffull,
393962306a36Sopenharmony_ci			       (mas1 >> 16) & 0x3fff,
394062306a36Sopenharmony_ci			       pgsz_names[(mas1 >> 7) & 0x1f],
394162306a36Sopenharmony_ci			       mas1 & MAS1_IND ? 'I' : ' ',
394262306a36Sopenharmony_ci			       mas1 & MAS1_IPROT ? 'P' : ' ',
394362306a36Sopenharmony_ci			       mas1 & MAS1_TS ? '1' : '0');
394462306a36Sopenharmony_ci			printf(" %c%c%c%c%c%c%c",
394562306a36Sopenharmony_ci			       mas2 & MAS2_X0 ? 'a' : ' ',
394662306a36Sopenharmony_ci			       mas2 & MAS2_X1 ? 'v' : ' ',
394762306a36Sopenharmony_ci			       mas2 & MAS2_W  ? 'w' : ' ',
394862306a36Sopenharmony_ci			       mas2 & MAS2_I  ? 'i' : ' ',
394962306a36Sopenharmony_ci			       mas2 & MAS2_M  ? 'm' : ' ',
395062306a36Sopenharmony_ci			       mas2 & MAS2_G  ? 'g' : ' ',
395162306a36Sopenharmony_ci			       mas2 & MAS2_E  ? 'e' : ' ');
395262306a36Sopenharmony_ci			printf(" %016llx", mas7_mas3 & ramask & ~0x7ffull);
395362306a36Sopenharmony_ci			if (mas1 & MAS1_IND)
395462306a36Sopenharmony_ci				printf(" %s\n",
395562306a36Sopenharmony_ci				       pgsz_names[(mas7_mas3 >> 1) & 0x1f]);
395662306a36Sopenharmony_ci			else
395762306a36Sopenharmony_ci				printf(" U%c%c%c S%c%c%c\n",
395862306a36Sopenharmony_ci				       mas7_mas3 & MAS3_UX ? 'x' : ' ',
395962306a36Sopenharmony_ci				       mas7_mas3 & MAS3_UW ? 'w' : ' ',
396062306a36Sopenharmony_ci				       mas7_mas3 & MAS3_UR ? 'r' : ' ',
396162306a36Sopenharmony_ci				       mas7_mas3 & MAS3_SX ? 'x' : ' ',
396262306a36Sopenharmony_ci				       mas7_mas3 & MAS3_SW ? 'w' : ' ',
396362306a36Sopenharmony_ci				       mas7_mas3 & MAS3_SR ? 'r' : ' ');
396462306a36Sopenharmony_ci		}
396562306a36Sopenharmony_ci	}
396662306a36Sopenharmony_ci}
396762306a36Sopenharmony_ci#endif /* CONFIG_PPC_BOOK3E_64 */
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_cistatic void xmon_init(int enable)
397062306a36Sopenharmony_ci{
397162306a36Sopenharmony_ci	if (enable) {
397262306a36Sopenharmony_ci		__debugger = xmon;
397362306a36Sopenharmony_ci		__debugger_ipi = xmon_ipi;
397462306a36Sopenharmony_ci		__debugger_bpt = xmon_bpt;
397562306a36Sopenharmony_ci		__debugger_sstep = xmon_sstep;
397662306a36Sopenharmony_ci		__debugger_iabr_match = xmon_iabr_match;
397762306a36Sopenharmony_ci		__debugger_break_match = xmon_break_match;
397862306a36Sopenharmony_ci		__debugger_fault_handler = xmon_fault_handler;
397962306a36Sopenharmony_ci	} else {
398062306a36Sopenharmony_ci		__debugger = NULL;
398162306a36Sopenharmony_ci		__debugger_ipi = NULL;
398262306a36Sopenharmony_ci		__debugger_bpt = NULL;
398362306a36Sopenharmony_ci		__debugger_sstep = NULL;
398462306a36Sopenharmony_ci		__debugger_iabr_match = NULL;
398562306a36Sopenharmony_ci		__debugger_break_match = NULL;
398662306a36Sopenharmony_ci		__debugger_fault_handler = NULL;
398762306a36Sopenharmony_ci	}
398862306a36Sopenharmony_ci}
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci#ifdef CONFIG_MAGIC_SYSRQ
399162306a36Sopenharmony_cistatic void sysrq_handle_xmon(u8 key)
399262306a36Sopenharmony_ci{
399362306a36Sopenharmony_ci	if (xmon_is_locked_down()) {
399462306a36Sopenharmony_ci		clear_all_bpt();
399562306a36Sopenharmony_ci		xmon_init(0);
399662306a36Sopenharmony_ci		return;
399762306a36Sopenharmony_ci	}
399862306a36Sopenharmony_ci	/* ensure xmon is enabled */
399962306a36Sopenharmony_ci	xmon_init(1);
400062306a36Sopenharmony_ci	debugger(get_irq_regs());
400162306a36Sopenharmony_ci	if (!xmon_on)
400262306a36Sopenharmony_ci		xmon_init(0);
400362306a36Sopenharmony_ci}
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_cistatic const struct sysrq_key_op sysrq_xmon_op = {
400662306a36Sopenharmony_ci	.handler =	sysrq_handle_xmon,
400762306a36Sopenharmony_ci	.help_msg =	"xmon(x)",
400862306a36Sopenharmony_ci	.action_msg =	"Entering xmon",
400962306a36Sopenharmony_ci};
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_cistatic int __init setup_xmon_sysrq(void)
401262306a36Sopenharmony_ci{
401362306a36Sopenharmony_ci	register_sysrq_key('x', &sysrq_xmon_op);
401462306a36Sopenharmony_ci	return 0;
401562306a36Sopenharmony_ci}
401662306a36Sopenharmony_cidevice_initcall(setup_xmon_sysrq);
401762306a36Sopenharmony_ci#endif /* CONFIG_MAGIC_SYSRQ */
401862306a36Sopenharmony_ci
401962306a36Sopenharmony_cistatic void clear_all_bpt(void)
402062306a36Sopenharmony_ci{
402162306a36Sopenharmony_ci	int i;
402262306a36Sopenharmony_ci
402362306a36Sopenharmony_ci	/* clear/unpatch all breakpoints */
402462306a36Sopenharmony_ci	remove_bpts();
402562306a36Sopenharmony_ci	remove_cpu_bpts();
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_ci	/* Disable all breakpoints */
402862306a36Sopenharmony_ci	for (i = 0; i < NBPTS; ++i)
402962306a36Sopenharmony_ci		bpts[i].enabled = 0;
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_ci	/* Clear any data or iabr breakpoints */
403262306a36Sopenharmony_ci	iabr = NULL;
403362306a36Sopenharmony_ci	for (i = 0; i < nr_wp_slots(); i++)
403462306a36Sopenharmony_ci		dabr[i].enabled = 0;
403562306a36Sopenharmony_ci}
403662306a36Sopenharmony_ci
403762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
403862306a36Sopenharmony_cistatic int xmon_dbgfs_set(void *data, u64 val)
403962306a36Sopenharmony_ci{
404062306a36Sopenharmony_ci	xmon_on = !!val;
404162306a36Sopenharmony_ci	xmon_init(xmon_on);
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	/* make sure all breakpoints removed when disabling */
404462306a36Sopenharmony_ci	if (!xmon_on) {
404562306a36Sopenharmony_ci		clear_all_bpt();
404662306a36Sopenharmony_ci		get_output_lock();
404762306a36Sopenharmony_ci		printf("xmon: All breakpoints cleared\n");
404862306a36Sopenharmony_ci		release_output_lock();
404962306a36Sopenharmony_ci	}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci	return 0;
405262306a36Sopenharmony_ci}
405362306a36Sopenharmony_ci
405462306a36Sopenharmony_cistatic int xmon_dbgfs_get(void *data, u64 *val)
405562306a36Sopenharmony_ci{
405662306a36Sopenharmony_ci	*val = xmon_on;
405762306a36Sopenharmony_ci	return 0;
405862306a36Sopenharmony_ci}
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ciDEFINE_SIMPLE_ATTRIBUTE(xmon_dbgfs_ops, xmon_dbgfs_get,
406162306a36Sopenharmony_ci			xmon_dbgfs_set, "%llu\n");
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_cistatic int __init setup_xmon_dbgfs(void)
406462306a36Sopenharmony_ci{
406562306a36Sopenharmony_ci	debugfs_create_file("xmon", 0600, arch_debugfs_dir, NULL,
406662306a36Sopenharmony_ci			    &xmon_dbgfs_ops);
406762306a36Sopenharmony_ci	return 0;
406862306a36Sopenharmony_ci}
406962306a36Sopenharmony_cidevice_initcall(setup_xmon_dbgfs);
407062306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_cistatic int xmon_early __initdata;
407362306a36Sopenharmony_ci
407462306a36Sopenharmony_cistatic int __init early_parse_xmon(char *p)
407562306a36Sopenharmony_ci{
407662306a36Sopenharmony_ci	if (xmon_is_locked_down()) {
407762306a36Sopenharmony_ci		xmon_init(0);
407862306a36Sopenharmony_ci		xmon_early = 0;
407962306a36Sopenharmony_ci		xmon_on = 0;
408062306a36Sopenharmony_ci	} else if (!p || strncmp(p, "early", 5) == 0) {
408162306a36Sopenharmony_ci		/* just "xmon" is equivalent to "xmon=early" */
408262306a36Sopenharmony_ci		xmon_init(1);
408362306a36Sopenharmony_ci		xmon_early = 1;
408462306a36Sopenharmony_ci		xmon_on = 1;
408562306a36Sopenharmony_ci	} else if (strncmp(p, "on", 2) == 0) {
408662306a36Sopenharmony_ci		xmon_init(1);
408762306a36Sopenharmony_ci		xmon_on = 1;
408862306a36Sopenharmony_ci	} else if (strncmp(p, "rw", 2) == 0) {
408962306a36Sopenharmony_ci		xmon_init(1);
409062306a36Sopenharmony_ci		xmon_on = 1;
409162306a36Sopenharmony_ci		xmon_is_ro = false;
409262306a36Sopenharmony_ci	} else if (strncmp(p, "ro", 2) == 0) {
409362306a36Sopenharmony_ci		xmon_init(1);
409462306a36Sopenharmony_ci		xmon_on = 1;
409562306a36Sopenharmony_ci		xmon_is_ro = true;
409662306a36Sopenharmony_ci	} else if (strncmp(p, "off", 3) == 0)
409762306a36Sopenharmony_ci		xmon_on = 0;
409862306a36Sopenharmony_ci	else
409962306a36Sopenharmony_ci		return 1;
410062306a36Sopenharmony_ci
410162306a36Sopenharmony_ci	return 0;
410262306a36Sopenharmony_ci}
410362306a36Sopenharmony_ciearly_param("xmon", early_parse_xmon);
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_civoid __init xmon_setup(void)
410662306a36Sopenharmony_ci{
410762306a36Sopenharmony_ci	if (xmon_on)
410862306a36Sopenharmony_ci		xmon_init(1);
410962306a36Sopenharmony_ci	if (xmon_early)
411062306a36Sopenharmony_ci		debugger(NULL);
411162306a36Sopenharmony_ci}
411262306a36Sopenharmony_ci
411362306a36Sopenharmony_ci#ifdef CONFIG_SPU_BASE
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_cistruct spu_info {
411662306a36Sopenharmony_ci	struct spu *spu;
411762306a36Sopenharmony_ci	u64 saved_mfc_sr1_RW;
411862306a36Sopenharmony_ci	u32 saved_spu_runcntl_RW;
411962306a36Sopenharmony_ci	unsigned long dump_addr;
412062306a36Sopenharmony_ci	u8 stopped_ok;
412162306a36Sopenharmony_ci};
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci#define XMON_NUM_SPUS	16	/* Enough for current hardware */
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_cistatic struct spu_info spu_info[XMON_NUM_SPUS];
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_civoid __init xmon_register_spus(struct list_head *list)
412862306a36Sopenharmony_ci{
412962306a36Sopenharmony_ci	struct spu *spu;
413062306a36Sopenharmony_ci
413162306a36Sopenharmony_ci	list_for_each_entry(spu, list, full_list) {
413262306a36Sopenharmony_ci		if (spu->number >= XMON_NUM_SPUS) {
413362306a36Sopenharmony_ci			WARN_ON(1);
413462306a36Sopenharmony_ci			continue;
413562306a36Sopenharmony_ci		}
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci		spu_info[spu->number].spu = spu;
413862306a36Sopenharmony_ci		spu_info[spu->number].stopped_ok = 0;
413962306a36Sopenharmony_ci		spu_info[spu->number].dump_addr = (unsigned long)
414062306a36Sopenharmony_ci				spu_info[spu->number].spu->local_store;
414162306a36Sopenharmony_ci	}
414262306a36Sopenharmony_ci}
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_cistatic void stop_spus(void)
414562306a36Sopenharmony_ci{
414662306a36Sopenharmony_ci	struct spu *spu;
414762306a36Sopenharmony_ci	volatile int i;
414862306a36Sopenharmony_ci	u64 tmp;
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_ci	for (i = 0; i < XMON_NUM_SPUS; i++) {
415162306a36Sopenharmony_ci		if (!spu_info[i].spu)
415262306a36Sopenharmony_ci			continue;
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci		if (setjmp(bus_error_jmp) == 0) {
415562306a36Sopenharmony_ci			catch_memory_errors = 1;
415662306a36Sopenharmony_ci			sync();
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci			spu = spu_info[i].spu;
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_ci			spu_info[i].saved_spu_runcntl_RW =
416162306a36Sopenharmony_ci				in_be32(&spu->problem->spu_runcntl_RW);
416262306a36Sopenharmony_ci
416362306a36Sopenharmony_ci			tmp = spu_mfc_sr1_get(spu);
416462306a36Sopenharmony_ci			spu_info[i].saved_mfc_sr1_RW = tmp;
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci			tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
416762306a36Sopenharmony_ci			spu_mfc_sr1_set(spu, tmp);
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci			sync();
417062306a36Sopenharmony_ci			__delay(200);
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci			spu_info[i].stopped_ok = 1;
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci			printf("Stopped spu %.2d (was %s)\n", i,
417562306a36Sopenharmony_ci					spu_info[i].saved_spu_runcntl_RW ?
417662306a36Sopenharmony_ci					"running" : "stopped");
417762306a36Sopenharmony_ci		} else {
417862306a36Sopenharmony_ci			catch_memory_errors = 0;
417962306a36Sopenharmony_ci			printf("*** Error stopping spu %.2d\n", i);
418062306a36Sopenharmony_ci		}
418162306a36Sopenharmony_ci		catch_memory_errors = 0;
418262306a36Sopenharmony_ci	}
418362306a36Sopenharmony_ci}
418462306a36Sopenharmony_ci
418562306a36Sopenharmony_cistatic void restart_spus(void)
418662306a36Sopenharmony_ci{
418762306a36Sopenharmony_ci	struct spu *spu;
418862306a36Sopenharmony_ci	volatile int i;
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci	for (i = 0; i < XMON_NUM_SPUS; i++) {
419162306a36Sopenharmony_ci		if (!spu_info[i].spu)
419262306a36Sopenharmony_ci			continue;
419362306a36Sopenharmony_ci
419462306a36Sopenharmony_ci		if (!spu_info[i].stopped_ok) {
419562306a36Sopenharmony_ci			printf("*** Error, spu %d was not successfully stopped"
419662306a36Sopenharmony_ci					", not restarting\n", i);
419762306a36Sopenharmony_ci			continue;
419862306a36Sopenharmony_ci		}
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_ci		if (setjmp(bus_error_jmp) == 0) {
420162306a36Sopenharmony_ci			catch_memory_errors = 1;
420262306a36Sopenharmony_ci			sync();
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci			spu = spu_info[i].spu;
420562306a36Sopenharmony_ci			spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
420662306a36Sopenharmony_ci			out_be32(&spu->problem->spu_runcntl_RW,
420762306a36Sopenharmony_ci					spu_info[i].saved_spu_runcntl_RW);
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci			sync();
421062306a36Sopenharmony_ci			__delay(200);
421162306a36Sopenharmony_ci
421262306a36Sopenharmony_ci			printf("Restarted spu %.2d\n", i);
421362306a36Sopenharmony_ci		} else {
421462306a36Sopenharmony_ci			catch_memory_errors = 0;
421562306a36Sopenharmony_ci			printf("*** Error restarting spu %.2d\n", i);
421662306a36Sopenharmony_ci		}
421762306a36Sopenharmony_ci		catch_memory_errors = 0;
421862306a36Sopenharmony_ci	}
421962306a36Sopenharmony_ci}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci#define DUMP_WIDTH	23
422262306a36Sopenharmony_ci#define DUMP_VALUE(format, field, value)				\
422362306a36Sopenharmony_cido {									\
422462306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {				\
422562306a36Sopenharmony_ci		catch_memory_errors = 1;				\
422662306a36Sopenharmony_ci		sync();							\
422762306a36Sopenharmony_ci		printf("  %-*s = "format"\n", DUMP_WIDTH,		\
422862306a36Sopenharmony_ci				#field, value);				\
422962306a36Sopenharmony_ci		sync();							\
423062306a36Sopenharmony_ci		__delay(200);						\
423162306a36Sopenharmony_ci	} else {							\
423262306a36Sopenharmony_ci		catch_memory_errors = 0;				\
423362306a36Sopenharmony_ci		printf("  %-*s = *** Error reading field.\n",		\
423462306a36Sopenharmony_ci					DUMP_WIDTH, #field);		\
423562306a36Sopenharmony_ci	}								\
423662306a36Sopenharmony_ci	catch_memory_errors = 0;					\
423762306a36Sopenharmony_ci} while (0)
423862306a36Sopenharmony_ci
423962306a36Sopenharmony_ci#define DUMP_FIELD(obj, format, field)	\
424062306a36Sopenharmony_ci	DUMP_VALUE(format, field, obj->field)
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_cistatic void dump_spu_fields(struct spu *spu)
424362306a36Sopenharmony_ci{
424462306a36Sopenharmony_ci	printf("Dumping spu fields at address %p:\n", spu);
424562306a36Sopenharmony_ci
424662306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%x", number);
424762306a36Sopenharmony_ci	DUMP_FIELD(spu, "%s", name);
424862306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%lx", local_store_phys);
424962306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", local_store);
425062306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%lx", ls_size);
425162306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%x", node);
425262306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%lx", flags);
425362306a36Sopenharmony_ci	DUMP_FIELD(spu, "%llu", class_0_pending);
425462306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%llx", class_0_dar);
425562306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%llx", class_1_dar);
425662306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%llx", class_1_dsisr);
425762306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%x", irqs[0]);
425862306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%x", irqs[1]);
425962306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%x", irqs[2]);
426062306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%x", slb_replace);
426162306a36Sopenharmony_ci	DUMP_FIELD(spu, "%d", pid);
426262306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", mm);
426362306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", ctx);
426462306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", rq);
426562306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%llx", timestamp);
426662306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%lx", problem_phys);
426762306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", problem);
426862306a36Sopenharmony_ci	DUMP_VALUE("0x%x", problem->spu_runcntl_RW,
426962306a36Sopenharmony_ci			in_be32(&spu->problem->spu_runcntl_RW));
427062306a36Sopenharmony_ci	DUMP_VALUE("0x%x", problem->spu_status_R,
427162306a36Sopenharmony_ci			in_be32(&spu->problem->spu_status_R));
427262306a36Sopenharmony_ci	DUMP_VALUE("0x%x", problem->spu_npc_RW,
427362306a36Sopenharmony_ci			in_be32(&spu->problem->spu_npc_RW));
427462306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", priv2);
427562306a36Sopenharmony_ci	DUMP_FIELD(spu, "0x%p", pdata);
427662306a36Sopenharmony_ci}
427762306a36Sopenharmony_ci
427862306a36Sopenharmony_cistatic int spu_inst_dump(unsigned long adr, long count, int praddr)
427962306a36Sopenharmony_ci{
428062306a36Sopenharmony_ci	return generic_inst_dump(adr, count, praddr, print_insn_spu);
428162306a36Sopenharmony_ci}
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_cistatic void dump_spu_ls(unsigned long num, int subcmd)
428462306a36Sopenharmony_ci{
428562306a36Sopenharmony_ci	unsigned long offset, addr, ls_addr;
428662306a36Sopenharmony_ci
428762306a36Sopenharmony_ci	if (setjmp(bus_error_jmp) == 0) {
428862306a36Sopenharmony_ci		catch_memory_errors = 1;
428962306a36Sopenharmony_ci		sync();
429062306a36Sopenharmony_ci		ls_addr = (unsigned long)spu_info[num].spu->local_store;
429162306a36Sopenharmony_ci		sync();
429262306a36Sopenharmony_ci		__delay(200);
429362306a36Sopenharmony_ci	} else {
429462306a36Sopenharmony_ci		catch_memory_errors = 0;
429562306a36Sopenharmony_ci		printf("*** Error: accessing spu info for spu %ld\n", num);
429662306a36Sopenharmony_ci		return;
429762306a36Sopenharmony_ci	}
429862306a36Sopenharmony_ci	catch_memory_errors = 0;
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	if (scanhex(&offset))
430162306a36Sopenharmony_ci		addr = ls_addr + offset;
430262306a36Sopenharmony_ci	else
430362306a36Sopenharmony_ci		addr = spu_info[num].dump_addr;
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	if (addr >= ls_addr + LS_SIZE) {
430662306a36Sopenharmony_ci		printf("*** Error: address outside of local store\n");
430762306a36Sopenharmony_ci		return;
430862306a36Sopenharmony_ci	}
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci	switch (subcmd) {
431162306a36Sopenharmony_ci	case 'i':
431262306a36Sopenharmony_ci		addr += spu_inst_dump(addr, 16, 1);
431362306a36Sopenharmony_ci		last_cmd = "sdi\n";
431462306a36Sopenharmony_ci		break;
431562306a36Sopenharmony_ci	default:
431662306a36Sopenharmony_ci		prdump(addr, 64);
431762306a36Sopenharmony_ci		addr += 64;
431862306a36Sopenharmony_ci		last_cmd = "sd\n";
431962306a36Sopenharmony_ci		break;
432062306a36Sopenharmony_ci	}
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci	spu_info[num].dump_addr = addr;
432362306a36Sopenharmony_ci}
432462306a36Sopenharmony_ci
432562306a36Sopenharmony_cistatic int do_spu_cmd(void)
432662306a36Sopenharmony_ci{
432762306a36Sopenharmony_ci	static unsigned long num = 0;
432862306a36Sopenharmony_ci	int cmd, subcmd = 0;
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci	cmd = inchar();
433162306a36Sopenharmony_ci	switch (cmd) {
433262306a36Sopenharmony_ci	case 's':
433362306a36Sopenharmony_ci		stop_spus();
433462306a36Sopenharmony_ci		break;
433562306a36Sopenharmony_ci	case 'r':
433662306a36Sopenharmony_ci		restart_spus();
433762306a36Sopenharmony_ci		break;
433862306a36Sopenharmony_ci	case 'd':
433962306a36Sopenharmony_ci		subcmd = inchar();
434062306a36Sopenharmony_ci		if (isxdigit(subcmd) || subcmd == '\n')
434162306a36Sopenharmony_ci			termch = subcmd;
434262306a36Sopenharmony_ci		fallthrough;
434362306a36Sopenharmony_ci	case 'f':
434462306a36Sopenharmony_ci		scanhex(&num);
434562306a36Sopenharmony_ci		if (num >= XMON_NUM_SPUS || !spu_info[num].spu) {
434662306a36Sopenharmony_ci			printf("*** Error: invalid spu number\n");
434762306a36Sopenharmony_ci			return 0;
434862306a36Sopenharmony_ci		}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci		switch (cmd) {
435162306a36Sopenharmony_ci		case 'f':
435262306a36Sopenharmony_ci			dump_spu_fields(spu_info[num].spu);
435362306a36Sopenharmony_ci			break;
435462306a36Sopenharmony_ci		default:
435562306a36Sopenharmony_ci			dump_spu_ls(num, subcmd);
435662306a36Sopenharmony_ci			break;
435762306a36Sopenharmony_ci		}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci		break;
436062306a36Sopenharmony_ci	default:
436162306a36Sopenharmony_ci		return -1;
436262306a36Sopenharmony_ci	}
436362306a36Sopenharmony_ci
436462306a36Sopenharmony_ci	return 0;
436562306a36Sopenharmony_ci}
436662306a36Sopenharmony_ci#else /* ! CONFIG_SPU_BASE */
436762306a36Sopenharmony_cistatic int do_spu_cmd(void)
436862306a36Sopenharmony_ci{
436962306a36Sopenharmony_ci	return -1;
437062306a36Sopenharmony_ci}
437162306a36Sopenharmony_ci#endif
4372