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(®s); 74462306a36Sopenharmony_ci excp = ®s; 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, ®s, 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(®s))); 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 = ®s; 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(®no); 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(®no); 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