Commit f78541dc authored by Paul Mackerras's avatar Paul Mackerras

powerpc: Merge xmon

The merged version follows the ppc64 version pretty closely mostly,
and in fact ARCH=ppc64 now uses the arch/powerpc/xmon version.
The main difference for ppc64 is that the 'p' command to call
show_state (which was always pretty dodgy) has been replaced by
the ppc32 'p' command, which calls a given procedure (so in fact
the old 'p' command behaviour can be achieved with 'p $show_state').
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent c032524f
...@@ -131,7 +131,7 @@ core-y += arch/powerpc/kernel/ \ ...@@ -131,7 +131,7 @@ core-y += arch/powerpc/kernel/ \
arch/powerpc/sysdev/ \ arch/powerpc/sysdev/ \
arch/powerpc/platforms/ arch/powerpc/platforms/
core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/
#core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_XMON) += arch/powerpc/xmon/
core-$(CONFIG_APUS) += arch/ppc/amiga/ core-$(CONFIG_APUS) += arch/ppc/amiga/
drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/
drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
......
...@@ -271,6 +271,9 @@ __secondary_hold_acknowledge: ...@@ -271,6 +271,9 @@ __secondary_hold_acknowledge:
li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \ li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
MTMSRD(r10); /* (except for mach check in rtas) */ \ MTMSRD(r10); /* (except for mach check in rtas) */ \
stw r0,GPR0(r11); \ stw r0,GPR0(r11); \
lis r10,0x7265; /* put exception frame marker */ \
addi r10,r10,0x6773; \
stw r10,8(r11); \
SAVE_4GPRS(3, r11); \ SAVE_4GPRS(3, r11); \
SAVE_2GPRS(7, r11) SAVE_2GPRS(7, r11)
......
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
#include <asm/cputable.h> #include <asm/cputable.h>
#include <asm/btext.h> #include <asm/btext.h>
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/xmon.h>
#ifdef CONFIG_8xx #ifdef CONFIG_8xx
#include <asm/commproc.h> #include <asm/commproc.h>
...@@ -238,10 +237,6 @@ EXPORT_SYMBOL(console_drivers); ...@@ -238,10 +237,6 @@ EXPORT_SYMBOL(console_drivers);
EXPORT_SYMBOL(cacheable_memcpy); EXPORT_SYMBOL(cacheable_memcpy);
#endif #endif
#ifdef CONFIG_XMON
EXPORT_SYMBOL(xmon);
EXPORT_SYMBOL(xmon_printf);
#endif
EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__up);
EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down);
EXPORT_SYMBOL(__down_interruptible); EXPORT_SYMBOL(__down_interruptible);
......
...@@ -302,8 +302,10 @@ void __init setup_arch(char **cmdline_p) ...@@ -302,8 +302,10 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_XMON #ifdef CONFIG_XMON
xmon_map_scc(); xmon_map_scc();
if (strstr(cmd_line, "xmon")) if (strstr(cmd_line, "xmon")) {
xmon(NULL); xmon_init(1);
debugger(NULL);
}
#endif /* CONFIG_XMON */ #endif /* CONFIG_XMON */
if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include <asm/iSeries/ItLpNaca.h> #include <asm/iSeries/ItLpNaca.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#include <asm/systemcfg.h> #include <asm/systemcfg.h>
#include <asm/xmon.h>
#ifdef DEBUG #ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt) #define DBG(fmt...) udbg_printf(fmt)
......
...@@ -11,6 +11,8 @@ obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o ...@@ -11,6 +11,8 @@ obj-$(CONFIG_PPC32) += div64.o copy_32.o checksum_32.o
obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \ obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o memcpy_64.o usercopy_64.o mem_64.o
obj-$(CONFIG_PPC_ISERIES) += e2a.o obj-$(CONFIG_PPC_ISERIES) += e2a.o
obj-$(CONFIG_XMON) += sstep.o
ifeq ($(CONFIG_PPC64),y) ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_SMP) += locks.o obj-$(CONFIG_SMP) += locks.o
obj-$(CONFIG_DEBUG_KERNEL) += sstep.o obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
......
# Makefile for xmon
ifdef CONFIG_PPC64
EXTRA_CFLAGS += -mno-minimal-toc
endif
obj-$(CONFIG_8xx) += start_8xx.o
obj-$(CONFIG_6xx) += start_32.o
obj-$(CONFIG_4xx) += start_32.o
obj-$(CONFIG_PPC64) += start_64.o
obj-y += xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
/*
* Copyright (C) 1996 Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* NOTE: assert(sizeof(buf) > 23 * sizeof(long))
*/
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
_GLOBAL(xmon_setjmp)
mflr r0
STL r0,0(r3)
STL r1,SZL(r3)
STL r2,2*SZL(r3)
mfcr r0
STL r0,3*SZL(r3)
STL r13,4*SZL(r3)
STL r14,5*SZL(r3)
STL r15,6*SZL(r3)
STL r16,7*SZL(r3)
STL r17,8*SZL(r3)
STL r18,9*SZL(r3)
STL r19,10*SZL(r3)
STL r20,11*SZL(r3)
STL r21,12*SZL(r3)
STL r22,13*SZL(r3)
STL r23,14*SZL(r3)
STL r24,15*SZL(r3)
STL r25,16*SZL(r3)
STL r26,17*SZL(r3)
STL r27,18*SZL(r3)
STL r28,19*SZL(r3)
STL r29,20*SZL(r3)
STL r30,21*SZL(r3)
STL r31,22*SZL(r3)
li r3,0
blr
_GLOBAL(xmon_longjmp)
CMPI r4,0
bne 1f
li r4,1
1: LDL r13,4*SZL(r3)
LDL r14,5*SZL(r3)
LDL r15,6*SZL(r3)
LDL r16,7*SZL(r3)
LDL r17,8*SZL(r3)
LDL r18,9*SZL(r3)
LDL r19,10*SZL(r3)
LDL r20,11*SZL(r3)
LDL r21,12*SZL(r3)
LDL r22,13*SZL(r3)
LDL r23,14*SZL(r3)
LDL r24,15*SZL(r3)
LDL r25,16*SZL(r3)
LDL r26,17*SZL(r3)
LDL r27,18*SZL(r3)
LDL r28,19*SZL(r3)
LDL r29,20*SZL(r3)
LDL r30,21*SZL(r3)
LDL r31,22*SZL(r3)
LDL r0,3*SZL(r3)
mtcrf 0x38,r0
LDL r0,0(r3)
LDL r1,SZL(r3)
LDL r2,2*SZL(r3)
mtlr r0
mr r3,r4
blr
/*
* Grab the register values as they are now.
* This won't do a particularily good job because we really
* want our caller's caller's registers, and our caller has
* already executed its prologue.
* ToDo: We could reach back into the caller's save area to do
* a better job of representing the caller's state (note that
* that will be different for 32-bit and 64-bit, because of the
* different ABIs, though).
*/
_GLOBAL(xmon_save_regs)
STL r0,0*SZL(r3)
STL r2,2*SZL(r3)
STL r3,3*SZL(r3)
STL r4,4*SZL(r3)
STL r5,5*SZL(r3)
STL r6,6*SZL(r3)
STL r7,7*SZL(r3)
STL r8,8*SZL(r3)
STL r9,9*SZL(r3)
STL r10,10*SZL(r3)
STL r11,11*SZL(r3)
STL r12,12*SZL(r3)
STL r13,13*SZL(r3)
STL r14,14*SZL(r3)
STL r15,15*SZL(r3)
STL r16,16*SZL(r3)
STL r17,17*SZL(r3)
STL r18,18*SZL(r3)
STL r19,19*SZL(r3)
STL r20,20*SZL(r3)
STL r21,21*SZL(r3)
STL r22,22*SZL(r3)
STL r23,23*SZL(r3)
STL r24,24*SZL(r3)
STL r25,25*SZL(r3)
STL r26,26*SZL(r3)
STL r27,27*SZL(r3)
STL r28,28*SZL(r3)
STL r29,29*SZL(r3)
STL r30,30*SZL(r3)
STL r31,31*SZL(r3)
/* go up one stack frame for SP */
LDL r4,0(r1)
STL r4,1*SZL(r3)
/* get caller's LR */
LDL r0,LRSAVE(r4)
STL r0,_NIP-STACK_FRAME_OVERHEAD(r3)
STL r0,_LINK-STACK_FRAME_OVERHEAD(r3)
mfmsr r0
STL r0,_MSR-STACK_FRAME_OVERHEAD(r3)
mfctr r0
STL r0,_CTR-STACK_FRAME_OVERHEAD(r3)
mfxer r0
STL r0,_XER-STACK_FRAME_OVERHEAD(r3)
mfcr r0
STL r0,_CCR-STACK_FRAME_OVERHEAD(r3)
li r0,0
STL r0,_TRAP-STACK_FRAME_OVERHEAD(r3)
blr
/*
* Copyright (C) 1996 Paul Mackerras.
*/
#include <linux/config.h>
#include <linux/string.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/page.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/cuda.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sysrq.h>
#include <linux/bitops.h>
#include <asm/xmon.h>
#include <asm/prom.h>
#include <asm/bootx.h>
#include <asm/machdep.h>
#include <asm/errno.h>
#include <asm/pmac_feature.h>
#include <asm/processor.h>
#include <asm/delay.h>
#include <asm/btext.h>
static volatile unsigned char __iomem *sccc, *sccd;
unsigned int TXRDY, RXRDY, DLAB;
static int xmon_expect(const char *str, unsigned int timeout);
static int use_serial;
static int use_screen;
static int via_modem;
static int xmon_use_sccb;
static struct device_node *channel_node;
#define TB_SPEED 25000000
static inline unsigned int readtb(void)
{
unsigned int ret;
asm volatile("mftb %0" : "=r" (ret) :);
return ret;
}
void buf_access(void)
{
if (DLAB)
sccd[3] &= ~DLAB; /* reset DLAB */
}
extern int adb_init(void);
#ifdef CONFIG_PPC_CHRP
/*
* This looks in the "ranges" property for the primary PCI host bridge
* to find the physical address of the start of PCI/ISA I/O space.
* It is basically a cut-down version of pci_process_bridge_OF_ranges.
*/
static unsigned long chrp_find_phys_io_base(void)
{
struct device_node *node;
unsigned int *ranges;
unsigned long base = CHRP_ISA_IO_BASE;
int rlen = 0;
int np;
node = find_devices("isa");
if (node != NULL) {
node = node->parent;
if (node == NULL || node->type == NULL
|| strcmp(node->type, "pci") != 0)
node = NULL;
}
if (node == NULL)
node = find_devices("pci");
if (node == NULL)
return base;
ranges = (unsigned int *) get_property(node, "ranges", &rlen);
np = prom_n_addr_cells(node) + 5;
while ((rlen -= np * sizeof(unsigned int)) >= 0) {
if ((ranges[0] >> 24) == 1 && ranges[2] == 0) {
/* I/O space starting at 0, grab the phys base */
base = ranges[np - 3];
break;
}
ranges += np;
}
return base;
}
#endif /* CONFIG_PPC_CHRP */
#ifdef CONFIG_MAGIC_SYSRQ
static void sysrq_handle_xmon(int key, struct pt_regs *regs,
struct tty_struct *tty)
{
xmon(regs);
}
static struct sysrq_key_op sysrq_xmon_op =
{
.handler = sysrq_handle_xmon,
.help_msg = "Xmon",
.action_msg = "Entering xmon",
};
#endif
void
xmon_map_scc(void)
{
#ifdef CONFIG_PPC_MULTIPLATFORM
volatile unsigned char __iomem *base;
if (_machine == _MACH_Pmac) {
struct device_node *np;
unsigned long addr;
#ifdef CONFIG_BOOTX_TEXT
if (!use_screen && !use_serial
&& !machine_is_compatible("iMac")) {
/* see if there is a keyboard in the device tree
with a parent of type "adb" */
for (np = find_devices("keyboard"); np; np = np->next)
if (np->parent && np->parent->type
&& strcmp(np->parent->type, "adb") == 0)
break;
/* needs to be hacked if xmon_printk is to be used
from within find_via_pmu() */
#ifdef CONFIG_ADB_PMU
if (np != NULL && boot_text_mapped && find_via_pmu())
use_screen = 1;
#endif
#ifdef CONFIG_ADB_CUDA
if (np != NULL && boot_text_mapped && find_via_cuda())
use_screen = 1;
#endif
}
if (!use_screen && (np = find_devices("escc")) != NULL) {
/*
* look for the device node for the serial port
* we're using and see if it says it has a modem
*/
char *name = xmon_use_sccb? "ch-b": "ch-a";
char *slots;
int l;
np = np->child;
while (np != NULL && strcmp(np->name, name) != 0)
np = np->sibling;
if (np != NULL) {
/* XXX should parse this properly */
channel_node = np;
slots = get_property(np, "slot-names", &l);
if (slots != NULL && l >= 10
&& strcmp(slots+4, "Modem") == 0)
via_modem = 1;
}
}
btext_drawstring("xmon uses ");
if (use_screen)
btext_drawstring("screen and keyboard\n");
else {
if (via_modem)
btext_drawstring("modem on ");
btext_drawstring(xmon_use_sccb? "printer": "modem");
btext_drawstring(" port\n");
}
#endif /* CONFIG_BOOTX_TEXT */
#ifdef CHRP_ESCC
addr = 0xc1013020;
#else
addr = 0xf3013020;
#endif
TXRDY = 4;
RXRDY = 1;
np = find_devices("mac-io");
if (np && np->n_addrs)
addr = np->addrs[0].address + 0x13020;
base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
sccc = base + (addr & ~PAGE_MASK);
sccd = sccc + 0x10;
} else {
base = (volatile unsigned char *) isa_io_base;
#ifdef CONFIG_PPC_CHRP
if (_machine == _MACH_chrp)
base = (volatile unsigned char __iomem *)
ioremap(chrp_find_phys_io_base(), 0x1000);
#endif
sccc = base + 0x3fd;
sccd = base + 0x3f8;
if (xmon_use_sccb) {
sccc -= 0x100;
sccd -= 0x100;
}
TXRDY = 0x20;
RXRDY = 1;
DLAB = 0x80;
}
#elif defined(CONFIG_GEMINI)
/* should already be mapped by the kernel boot */
sccc = (volatile unsigned char __iomem *) 0xffeffb0d;
sccd = (volatile unsigned char __iomem *) 0xffeffb08;
TXRDY = 0x20;
RXRDY = 1;
DLAB = 0x80;
#elif defined(CONFIG_405GP)
sccc = (volatile unsigned char __iomem *)0xef600305;
sccd = (volatile unsigned char __iomem *)0xef600300;
TXRDY = 0x20;
RXRDY = 1;
DLAB = 0x80;
#endif /* platform */
register_sysrq_key('x', &sysrq_xmon_op);
}
static int scc_initialized = 0;
void xmon_init_scc(void);
extern void cuda_poll(void);
static inline void do_poll_adb(void)
{
#ifdef CONFIG_ADB_PMU
if (sys_ctrler == SYS_CTRLER_PMU)
pmu_poll_adb();
#endif /* CONFIG_ADB_PMU */
#ifdef CONFIG_ADB_CUDA
if (sys_ctrler == SYS_CTRLER_CUDA)
cuda_poll();
#endif /* CONFIG_ADB_CUDA */
}
int
xmon_write(void *handle, void *ptr, int nb)
{
char *p = ptr;
int i, c, ct;
#ifdef CONFIG_SMP
static unsigned long xmon_write_lock;
int lock_wait = 1000000;
int locked;
while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0)
if (--lock_wait == 0)
break;
#endif
#ifdef CONFIG_BOOTX_TEXT
if (use_screen) {
/* write it on the screen */
for (i = 0; i < nb; ++i)
btext_drawchar(*p++);
goto out;
}
#endif
if (!scc_initialized)
xmon_init_scc();
ct = 0;
for (i = 0; i < nb; ++i) {
while ((*sccc & TXRDY) == 0)
do_poll_adb();
c = p[i];
if (c == '\n' && !ct) {
c = '\r';
ct = 1;
--i;
} else {
ct = 0;
}
buf_access();
*sccd = c;
eieio();
}
out:
#ifdef CONFIG_SMP
if (!locked)
clear_bit(0, &xmon_write_lock);
#endif
return nb;
}
int xmon_wants_key;
int xmon_adb_keycode;
#ifdef CONFIG_BOOTX_TEXT
static int xmon_adb_shiftstate;
static unsigned char xmon_keytab[128] =
"asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
"yt123465=97-80]o" /* 0x10 - 0x1f */
"u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
"\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
"\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
static unsigned char xmon_shift_keytab[128] =
"ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */
"YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */
"U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */
"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */
"\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */
"\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */
static int
xmon_get_adb_key(void)
{
int k, t, on;
xmon_wants_key = 1;
for (;;) {
xmon_adb_keycode = -1;
t = 0;
on = 0;
do {
if (--t < 0) {
on = 1 - on;
btext_drawchar(on? 0xdb: 0x20);
btext_drawchar('\b');
t = 200000;
}
do_poll_adb();
} while (xmon_adb_keycode == -1);
k = xmon_adb_keycode;
if (on)
btext_drawstring(" \b");
/* test for shift keys */
if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
xmon_adb_shiftstate = (k & 0x80) == 0;
continue;
}
if (k >= 0x80)
continue; /* ignore up transitions */
k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k];
if (k != 0)
break;
}
xmon_wants_key = 0;
return k;
}
#endif /* CONFIG_BOOTX_TEXT */
int
xmon_read(void *handle, void *ptr, int nb)
{
char *p = ptr;
int i;
#ifdef CONFIG_BOOTX_TEXT
if (use_screen) {
for (i = 0; i < nb; ++i)
*p++ = xmon_get_adb_key();
return i;
}
#endif
if (!scc_initialized)
xmon_init_scc();
for (i = 0; i < nb; ++i) {
while ((*sccc & RXRDY) == 0)
do_poll_adb();
buf_access();
*p++ = *sccd;
}
return i;
}
int
xmon_read_poll(void)
{
if ((*sccc & RXRDY) == 0) {
do_poll_adb();
return -1;
}
buf_access();
return *sccd;
}
static unsigned char scc_inittab[] = {
13, 0, /* set baud rate divisor */
12, 1,
14, 1, /* baud rate gen enable, src=rtxc */
11, 0x50, /* clocks = br gen */
5, 0xea, /* tx 8 bits, assert DTR & RTS */
4, 0x46, /* x16 clock, 1 stop */
3, 0xc1, /* rx enable, 8 bits */
};
void
xmon_init_scc(void)
{
if ( _machine == _MACH_chrp )
{
sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */
sccd[0] = 12; eieio(); /* DLL = 9600 baud */
sccd[1] = 0; eieio();
sccd[2] = 0; eieio(); /* FCR = 0 */
sccd[3] = 3; eieio(); /* LCR = 8N1 */
sccd[1] = 0; eieio(); /* IER = 0 */
}
else if ( _machine == _MACH_Pmac )
{
int i, x;
if (channel_node != 0)
pmac_call_feature(
PMAC_FTR_SCC_ENABLE,
channel_node,
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
printk(KERN_INFO "Serial port locked ON by debugger !\n");
if (via_modem && channel_node != 0) {
unsigned int t0;
pmac_call_feature(
PMAC_FTR_MODEM_ENABLE,
channel_node, 0, 1);
printk(KERN_INFO "Modem powered up by debugger !\n");
t0 = readtb();
while (readtb() - t0 < 3*TB_SPEED)
eieio();
}
/* use the B channel if requested */
if (xmon_use_sccb) {
sccc = (volatile unsigned char *)
((unsigned long)sccc & ~0x20);
sccd = sccc + 0x10;
}
for (i = 20000; i != 0; --i) {
x = *sccc; eieio();
}
*sccc = 9; eieio(); /* reset A or B side */
*sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
for (i = 0; i < sizeof(scc_inittab); ++i) {
*sccc = scc_inittab[i];
eieio();
}
}
scc_initialized = 1;
if (via_modem) {
for (;;) {
xmon_write(NULL, "ATE1V1\r", 7);
if (xmon_expect("OK", 5)) {
xmon_write(NULL, "ATA\r", 4);
if (xmon_expect("CONNECT", 40))
break;
}
xmon_write(NULL, "+++", 3);
xmon_expect("OK", 3);
}
}
}
void *xmon_stdin;
void *xmon_stdout;
void *xmon_stderr;
int xmon_putc(int c, void *f)
{
char ch = c;
if (c == '\n')
xmon_putc('\r', f);
return xmon_write(f, &ch, 1) == 1? c: -1;
}
int xmon_putchar(int c)
{
return xmon_putc(c, xmon_stdout);
}
int xmon_fputs(char *str, void *f)
{
int n = strlen(str);
return xmon_write(f, str, n) == n? 0: -1;
}
int
xmon_readchar(void)
{
char ch;
for (;;) {
switch (xmon_read(xmon_stdin, &ch, 1)) {
case 1:
return ch;
case -1:
xmon_printf("read(stdin) returned -1\r\n", 0, 0);
return -1;
}
}
}
static char line[256];
static char *lineptr;
static int lineleft;
int xmon_expect(const char *str, unsigned int timeout)
{
int c;
unsigned int t0;
timeout *= TB_SPEED;
t0 = readtb();
do {
lineptr = line;
for (;;) {
c = xmon_read_poll();
if (c == -1) {
if (readtb() - t0 > timeout)
return 0;
continue;
}
if (c == '\n')
break;
if (c != '\r' && lineptr < &line[sizeof(line) - 1])
*lineptr++ = c;
}
*lineptr = 0;
} while (strstr(line, str) == NULL);
return 1;
}
int
xmon_getchar(void)
{
int c;
if (lineleft == 0) {
lineptr = line;
for (;;) {
c = xmon_readchar();
if (c == -1 || c == 4)
break;
if (c == '\r' || c == '\n') {
*lineptr++ = '\n';
xmon_putchar('\n');
break;
}
switch (c) {
case 0177:
case '\b':
if (lineptr > line) {
xmon_putchar('\b');
xmon_putchar(' ');
xmon_putchar('\b');
--lineptr;
}
break;
case 'U' & 0x1F:
while (lineptr > line) {
xmon_putchar('\b');
xmon_putchar(' ');
xmon_putchar('\b');
--lineptr;
}
break;
default:
if (lineptr >= &line[sizeof(line) - 1])
xmon_putchar('\a');
else {
xmon_putchar(c);
*lineptr++ = c;
}
}
}
lineleft = lineptr - line;
lineptr = line;
}
if (lineleft == 0)
return -1;
--lineleft;
return *lineptr++;
}
char *
xmon_fgets(char *str, int nb, void *f)
{
char *p;
int c;
for (p = str; p < str + nb - 1; ) {
c = xmon_getchar();
if (c == -1) {
if (p == str)
return NULL;
break;
}
*p++ = c;
if (c == '\n')
break;
}
*p = 0;
return str;
}
void
xmon_enter(void)
{
#ifdef CONFIG_ADB_PMU
if (_machine == _MACH_Pmac) {
pmu_suspend();
}
#endif
}
void
xmon_leave(void)
{
#ifdef CONFIG_ADB_PMU
if (_machine == _MACH_Pmac) {
pmu_resume();
}
#endif
}
/*
* Copyright (C) 1996 Paul Mackerras.
* Copyright (C) 2000 Dan Malek.
* Quick hack of Paul's code to make XMON work on 8xx processors. Lots
* of assumptions, like the SMC1 is used, it has been initialized by the
* loader at some point, and we can just stuff and suck bytes.
* We rely upon the 8xx uart driver to support us, as the interface
* changes between boot up and operational phases of the kernel.
*/
#include <linux/string.h>
#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/page.h>
#include <linux/kernel.h>
#include <asm/8xx_immap.h>
#include <asm/mpc8xx.h>
#include <asm/commproc.h>
extern void xmon_printf(const char *fmt, ...);
extern int xmon_8xx_write(char *str, int nb);
extern int xmon_8xx_read_poll(void);
extern int xmon_8xx_read_char(void);
void prom_drawhex(uint);
void prom_drawstring(const char *str);
static int use_screen = 1; /* default */
#define TB_SPEED 25000000
static inline unsigned int readtb(void)
{
unsigned int ret;
asm volatile("mftb %0" : "=r" (ret) :);
return ret;
}
void buf_access(void)
{
}
void
xmon_map_scc(void)
{
cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
use_screen = 0;
prom_drawstring("xmon uses serial port\n");
}
static int scc_initialized = 0;
void xmon_init_scc(void);
int
xmon_write(void *handle, void *ptr, int nb)
{
char *p = ptr;
int i, c, ct;
if (!scc_initialized)
xmon_init_scc();
return(xmon_8xx_write(ptr, nb));
}
int xmon_wants_key;
int
xmon_read(void *handle, void *ptr, int nb)
{
char *p = ptr;
int i;
if (!scc_initialized)
xmon_init_scc();
for (i = 0; i < nb; ++i) {
*p++ = xmon_8xx_read_char();
}
return i;
}
int
xmon_read_poll(void)
{
return(xmon_8xx_read_poll());
}
void
xmon_init_scc()
{
scc_initialized = 1;
}
#if 0
extern int (*prom_entry)(void *);
int
xmon_exit(void)
{
struct prom_args {
char *service;
} args;
for (;;) {
args.service = "exit";
(*prom_entry)(&args);
}
}
#endif
void *xmon_stdin;
void *xmon_stdout;
void *xmon_stderr;
void
xmon_init(void)
{
}
int
xmon_putc(int c, void *f)
{
char ch = c;
if (c == '\n')
xmon_putc('\r', f);
return xmon_write(f, &ch, 1) == 1? c: -1;
}
int
xmon_putchar(int c)
{
return xmon_putc(c, xmon_stdout);
}
int
xmon_fputs(char *str, void *f)
{
int n = strlen(str);
return xmon_write(f, str, n) == n? 0: -1;
}
int
xmon_readchar(void)
{
char ch;
for (;;) {
switch (xmon_read(xmon_stdin, &ch, 1)) {
case 1:
return ch;
case -1:
xmon_printf("read(stdin) returned -1\r\n", 0, 0);
return -1;
}
}
}
static char line[256];
static char *lineptr;
static int lineleft;
#if 0
int xmon_expect(const char *str, unsigned int timeout)
{
int c;
unsigned int t0;
timeout *= TB_SPEED;
t0 = readtb();
do {
lineptr = line;
for (;;) {
c = xmon_read_poll();
if (c == -1) {
if (readtb() - t0 > timeout)
return 0;
continue;
}
if (c == '\n')
break;
if (c != '\r' && lineptr < &line[sizeof(line) - 1])
*lineptr++ = c;
}
*lineptr = 0;
} while (strstr(line, str) == NULL);
return 1;
}
#endif
int
xmon_getchar(void)
{
int c;
if (lineleft == 0) {
lineptr = line;
for (;;) {
c = xmon_readchar();
if (c == -1 || c == 4)
break;
if (c == '\r' || c == '\n') {
*lineptr++ = '\n';
xmon_putchar('\n');
break;
}
switch (c) {
case 0177:
case '\b':
if (lineptr > line) {
xmon_putchar('\b');
xmon_putchar(' ');
xmon_putchar('\b');
--lineptr;
}
break;
case 'U' & 0x1F:
while (lineptr > line) {
xmon_putchar('\b');
xmon_putchar(' ');
xmon_putchar('\b');
--lineptr;
}
break;
default:
if (lineptr >= &line[sizeof(line) - 1])
xmon_putchar('\a');
else {
xmon_putchar(c);
*lineptr++ = c;
}
}
}
lineleft = lineptr - line;
lineptr = line;
}
if (lineleft == 0)
return -1;
--lineleft;
return *lineptr++;
}
char *
xmon_fgets(char *str, int nb, void *f)
{
char *p;
int c;
for (p = str; p < str + nb - 1; ) {
c = xmon_getchar();
if (c == -1) {
if (p == str)
return 0;
break;
}
*p++ = c;
if (c == '\n')
break;
}
*p = 0;
return str;
}
void
prom_drawhex(uint val)
{
unsigned char buf[10];
int i;
for (i = 7; i >= 0; i--)
{
buf[i] = "0123456789abcdef"[val & 0x0f];
val >>= 4;
}
buf[8] = '\0';
xmon_fputs(buf, xmon_stdout);
}
void
prom_drawstring(const char *str)
{
xmon_fputs(str, xmon_stdout);
}
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/module.h>
#include <stdarg.h> #include <stdarg.h>
#include "nonstdio.h" #include "nonstdio.h"
extern int xmon_write(void *, void *, int); extern int xmon_write(void *, void *, int);
void void xmon_vfprintf(void *f, const char *fmt, va_list ap)
xmon_vfprintf(void *f, const char *fmt, va_list ap)
{ {
static char xmon_buf[2048]; static char xmon_buf[2048];
int n; int n;
...@@ -33,8 +33,7 @@ xmon_vfprintf(void *f, const char *fmt, va_list ap) ...@@ -33,8 +33,7 @@ xmon_vfprintf(void *f, const char *fmt, va_list ap)
xmon_write(f, xmon_buf, n); xmon_write(f, xmon_buf, n);
} }
void void xmon_printf(const char *fmt, ...)
xmon_printf(const char *fmt, ...)
{ {
va_list ap; va_list ap;
...@@ -42,9 +41,9 @@ xmon_printf(const char *fmt, ...) ...@@ -42,9 +41,9 @@ xmon_printf(const char *fmt, ...)
xmon_vfprintf(stdout, fmt, ap); xmon_vfprintf(stdout, fmt, ap);
va_end(ap); va_end(ap);
} }
EXPORT_SYMBOL(xmon_printf);
void void xmon_fprintf(void *f, const char *fmt, ...)
xmon_fprintf(void *f, const char *fmt, ...)
{ {
va_list ap; va_list ap;
......
...@@ -17,25 +17,31 @@ ...@@ -17,25 +17,31 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/module.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/string.h> #include <asm/string.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/xmon.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/paca.h>
#include <asm/ppcdebug.h>
#include <asm/cputable.h> #include <asm/cputable.h>
#include <asm/rtas.h> #include <asm/rtas.h>
#include <asm/sstep.h> #include <asm/sstep.h>
#include <asm/bug.h> #include <asm/bug.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h> #include <asm/hvcall.h>
#include <asm/paca.h>
#endif
#include "nonstdio.h" #include "nonstdio.h"
#include "privinst.h"
#define scanhex xmon_scanhex #define scanhex xmon_scanhex
#define skipbl xmon_skipbl #define skipbl xmon_skipbl
...@@ -58,7 +64,7 @@ static unsigned long ncsum = 4096; ...@@ -58,7 +64,7 @@ static unsigned long ncsum = 4096;
static int termch; static int termch;
static char tmpstr[128]; static char tmpstr[128];
#define JMP_BUF_LEN (184/sizeof(long)) #define JMP_BUF_LEN 23
static long bus_error_jmp[JMP_BUF_LEN]; static long bus_error_jmp[JMP_BUF_LEN];
static int catch_memory_errors; static int catch_memory_errors;
static long *xmon_fault_jmp[NR_CPUS]; static long *xmon_fault_jmp[NR_CPUS];
...@@ -130,23 +136,36 @@ static void cacheflush(void); ...@@ -130,23 +136,36 @@ static void cacheflush(void);
static int cpu_cmd(void); static int cpu_cmd(void);
static void csum(void); static void csum(void);
static void bootcmds(void); static void bootcmds(void);
static void proccall(void);
void dump_segments(void); void dump_segments(void);
static void symbol_lookup(void); static void symbol_lookup(void);
static void xmon_print_symbol(unsigned long address, const char *mid, static void xmon_print_symbol(unsigned long address, const char *mid,
const char *after); const char *after);
static const char *getvecname(unsigned long vec); static const char *getvecname(unsigned long vec);
static void debug_trace(void);
extern int print_insn_powerpc(unsigned long, unsigned long, int); extern int print_insn_powerpc(unsigned long, unsigned long, int);
extern void printf(const char *fmt, ...); extern void printf(const char *fmt, ...);
extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); extern void xmon_vfprintf(void *f, const char *fmt, va_list ap);
extern int xmon_putc(int c, void *f); extern int xmon_putc(int c, void *f);
extern int putchar(int ch); extern int putchar(int ch);
extern void xmon_enter(void);
extern void xmon_leave(void);
extern int xmon_read_poll(void); extern int xmon_read_poll(void);
extern int setjmp(long *); extern long setjmp(long *);
extern void longjmp(long *, int); extern void longjmp(long *, long);
extern unsigned long _ASR; extern void xmon_save_regs(struct pt_regs *);
#ifdef CONFIG_PPC64
#define REG "%.16lx"
#define REGS_PER_LINE 4
#define LAST_VOLATILE 13
#else
#define REG "%.8lx"
#define REGS_PER_LINE 8
#define LAST_VOLATILE 12
#endif
#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
...@@ -186,47 +205,46 @@ Commands:\n\ ...@@ -186,47 +205,46 @@ Commands:\n\
ml locate a block of memory\n\ ml locate a block of memory\n\
mz zero a block of memory\n\ mz zero a block of memory\n\
mi show information about memory allocation\n\ mi show information about memory allocation\n\
p show the task list\n\ p call a procedure\n\
r print registers\n\ r print registers\n\
s single step\n\ s single step\n\
S print special registers\n\ S print special registers\n\
t print backtrace\n\ t print backtrace\n\
T Enable/Disable PPCDBG flags\n\ T Enable/Disable PPCDBG flags\n\
x exit monitor and recover\n\ x exit monitor and recover\n\
X exit monitor and dont recover\n\ X exit monitor and dont recover\n"
u dump segment table or SLB\n\ #ifdef CONFIG_PPC64
? help\n" " u dump segment table or SLB\n"
"\ #endif
zr reboot\n\ #ifdef CONFIG_PPC_STD_MMU_32
" u dump segment registers\n"
#endif
" ? help\n"
" zr reboot\n\
zh halt\n" zh halt\n"
; ;
static struct pt_regs *xmon_regs; static struct pt_regs *xmon_regs;
extern inline void sync(void) static inline void sync(void)
{ {
asm volatile("sync; isync"); asm volatile("sync; isync");
} }
/* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs). static inline void store_inst(void *p)
A PPC stack frame looks like this: {
asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
High Address }
Back Chain
FP reg save area static inline void cflush(void *p)
GP reg save area {
Local var space asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
Parameter save area (SP+48) }
TOC save area (SP+40)
link editor doubleword (SP+32) static inline void cinval(void *p)
compiler doubleword (SP+24) {
LR save (SP+16) asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
CR save (SP+8) }
Back Chain (SP+0)
Note that the LR (ret addr) may not be saved in the current frame if
no functions have been called from the current function.
*/
/* /*
* Disable surveillance (the service processor watchdog function) * Disable surveillance (the service processor watchdog function)
...@@ -310,8 +328,8 @@ int xmon_core(struct pt_regs *regs, int fromipi) ...@@ -310,8 +328,8 @@ int xmon_core(struct pt_regs *regs, int fromipi)
unsigned long timeout; unsigned long timeout;
#endif #endif
msr = get_msr(); msr = mfmsr();
set_msrd(msr & ~MSR_EE); /* disable interrupts */ mtmsr(msr & ~MSR_EE); /* disable interrupts */
bp = in_breakpoint_table(regs->nip, &offset); bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) { if (bp != NULL) {
...@@ -487,7 +505,7 @@ int xmon_core(struct pt_regs *regs, int fromipi) ...@@ -487,7 +505,7 @@ int xmon_core(struct pt_regs *regs, int fromipi)
insert_cpu_bpts(); insert_cpu_bpts();
set_msrd(msr); /* restore interrupt enable */ mtmsr(msr); /* restore interrupt enable */
return cmd != 'X'; return cmd != 'X';
} }
...@@ -497,56 +515,23 @@ int xmon(struct pt_regs *excp) ...@@ -497,56 +515,23 @@ int xmon(struct pt_regs *excp)
struct pt_regs regs; struct pt_regs regs;
if (excp == NULL) { if (excp == NULL) {
/* Ok, grab regs as they are now. xmon_save_regs(&regs);
This won't do a particularily good job because the
prologue has already been executed.
ToDo: We could reach back into the callers save
area to do a better job of representing the
caller's state.
*/
asm volatile ("std 0,0(%0)\n\
std 1,8(%0)\n\
std 2,16(%0)\n\
std 3,24(%0)\n\
std 4,32(%0)\n\
std 5,40(%0)\n\
std 6,48(%0)\n\
std 7,56(%0)\n\
std 8,64(%0)\n\
std 9,72(%0)\n\
std 10,80(%0)\n\
std 11,88(%0)\n\
std 12,96(%0)\n\
std 13,104(%0)\n\
std 14,112(%0)\n\
std 15,120(%0)\n\
std 16,128(%0)\n\
std 17,136(%0)\n\
std 18,144(%0)\n\
std 19,152(%0)\n\
std 20,160(%0)\n\
std 21,168(%0)\n\
std 22,176(%0)\n\
std 23,184(%0)\n\
std 24,192(%0)\n\
std 25,200(%0)\n\
std 26,208(%0)\n\
std 27,216(%0)\n\
std 28,224(%0)\n\
std 29,232(%0)\n\
std 30,240(%0)\n\
std 31,248(%0)" : : "b" (&regs));
regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
regs.msr = get_msr();
regs.ctr = get_ctr();
regs.xer = get_xer();
regs.ccr = get_cr();
regs.trap = 0;
excp = &regs; excp = &regs;
} }
return xmon_core(excp, 0); return xmon_core(excp, 0);
} }
EXPORT_SYMBOL(xmon);
irqreturn_t
xmon_irq(int irq, void *d, struct pt_regs *regs)
{
unsigned long flags;
local_irq_save(flags);
printf("Keyboard interrupt\n");
xmon(regs);
local_irq_restore(flags);
return IRQ_HANDLED;
}
int xmon_bpt(struct pt_regs *regs) int xmon_bpt(struct pt_regs *regs)
{ {
...@@ -718,7 +703,7 @@ static void insert_cpu_bpts(void) ...@@ -718,7 +703,7 @@ static void insert_cpu_bpts(void)
if (dabr.enabled) if (dabr.enabled)
set_dabr(dabr.address | (dabr.enabled & 7)); set_dabr(dabr.address | (dabr.enabled & 7));
if (iabr && cpu_has_feature(CPU_FTR_IABR)) if (iabr && cpu_has_feature(CPU_FTR_IABR))
set_iabr(iabr->address mtspr(SPRN_IABR, iabr->address
| (iabr->enabled & (BP_IABR|BP_IABR_TE))); | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
} }
...@@ -746,7 +731,7 @@ static void remove_cpu_bpts(void) ...@@ -746,7 +731,7 @@ static void remove_cpu_bpts(void)
{ {
set_dabr(0); set_dabr(0);
if (cpu_has_feature(CPU_FTR_IABR)) if (cpu_has_feature(CPU_FTR_IABR))
set_iabr(0); mtspr(SPRN_IABR, 0);
} }
/* Command interpreting routine */ /* Command interpreting routine */
...@@ -830,9 +815,6 @@ cmds(struct pt_regs *excp) ...@@ -830,9 +815,6 @@ cmds(struct pt_regs *excp)
case '?': case '?':
printf(help_string); printf(help_string);
break; break;
case 'p':
show_state();
break;
case 'b': case 'b':
bpt_cmds(); bpt_cmds();
break; break;
...@@ -846,12 +828,14 @@ cmds(struct pt_regs *excp) ...@@ -846,12 +828,14 @@ cmds(struct pt_regs *excp)
case 'z': case 'z':
bootcmds(); bootcmds();
break; break;
case 'T': case 'p':
debug_trace(); proccall();
break; break;
#ifdef CONFIG_PPC_STD_MMU
case 'u': case 'u':
dump_segments(); dump_segments();
break; break;
#endif
default: default:
printf("Unrecognized command: "); printf("Unrecognized command: ");
do { do {
...@@ -1070,6 +1054,7 @@ bpt_cmds(void) ...@@ -1070,6 +1054,7 @@ bpt_cmds(void)
cmd = inchar(); cmd = inchar();
switch (cmd) { switch (cmd) {
#ifndef CONFIG_8xx
case 'd': /* bd - hardware data breakpoint */ case 'd': /* bd - hardware data breakpoint */
mode = 7; mode = 7;
cmd = inchar(); cmd = inchar();
...@@ -1111,6 +1096,7 @@ bpt_cmds(void) ...@@ -1111,6 +1096,7 @@ bpt_cmds(void)
iabr = bp; iabr = bp;
} }
break; break;
#endif
case 'c': case 'c':
if (!scanhex(&a)) { if (!scanhex(&a)) {
...@@ -1152,7 +1138,7 @@ bpt_cmds(void) ...@@ -1152,7 +1138,7 @@ bpt_cmds(void)
/* print all breakpoints */ /* print all breakpoints */
printf(" type address\n"); printf(" type address\n");
if (dabr.enabled) { if (dabr.enabled) {
printf(" data %.16lx [", dabr.address); printf(" data "REG" [", dabr.address);
if (dabr.enabled & 1) if (dabr.enabled & 1)
printf("r"); printf("r");
if (dabr.enabled & 2) if (dabr.enabled & 2)
...@@ -1231,6 +1217,18 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp, ...@@ -1231,6 +1217,18 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp,
static int xmon_depth_to_print = 64; static int xmon_depth_to_print = 64;
#ifdef CONFIG_PPC64
#define LRSAVE_OFFSET 0x10
#define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */
#define MARKER_OFFSET 0x60
#define REGS_OFFSET 0x70
#else
#define LRSAVE_OFFSET 4
#define REG_FRAME_MARKER 0x72656773
#define MARKER_OFFSET 8
#define REGS_OFFSET 16
#endif
static void xmon_show_stack(unsigned long sp, unsigned long lr, static void xmon_show_stack(unsigned long sp, unsigned long lr,
unsigned long pc) unsigned long pc)
{ {
...@@ -1247,7 +1245,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, ...@@ -1247,7 +1245,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
break; break;
} }
if (!mread(sp + 16, &ip, sizeof(unsigned long)) if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long))
|| !mread(sp, &newsp, sizeof(unsigned long))) { || !mread(sp, &newsp, sizeof(unsigned long))) {
printf("Couldn't read stack frame at %lx\n", sp); printf("Couldn't read stack frame at %lx\n", sp);
break; break;
...@@ -1266,7 +1264,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, ...@@ -1266,7 +1264,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
get_function_bounds(pc, &fnstart, &fnend); get_function_bounds(pc, &fnstart, &fnend);
nextip = 0; nextip = 0;
if (newsp > sp) if (newsp > sp)
mread(newsp + 16, &nextip, mread(newsp + LRSAVE_OFFSET, &nextip,
sizeof(unsigned long)); sizeof(unsigned long));
if (lr == ip) { if (lr == ip) {
if (lr < PAGE_OFFSET if (lr < PAGE_OFFSET
...@@ -1280,24 +1278,24 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, ...@@ -1280,24 +1278,24 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
xmon_print_symbol(lr, " ", "\n"); xmon_print_symbol(lr, " ", "\n");
} }
if (printip) { if (printip) {
printf("[%.16lx] ", sp); printf("["REG"] ", sp);
xmon_print_symbol(ip, " ", " (unreliable)\n"); xmon_print_symbol(ip, " ", " (unreliable)\n");
} }
pc = lr = 0; pc = lr = 0;
} else { } else {
printf("[%.16lx] ", sp); printf("["REG"] ", sp);
xmon_print_symbol(ip, " ", "\n"); xmon_print_symbol(ip, " ", "\n");
} }
/* Look for "regshere" marker to see if this is /* Look for "regshere" marker to see if this is
an exception frame. */ an exception frame. */
if (mread(sp + 0x60, &marker, sizeof(unsigned long)) if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
&& marker == 0x7265677368657265ul) { && marker == REG_FRAME_MARKER) {
if (mread(sp + 0x70, &regs, sizeof(regs)) if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
!= sizeof(regs)) { != sizeof(regs)) {
printf("Couldn't read registers at %lx\n", printf("Couldn't read registers at %lx\n",
sp + 0x70); sp + REGS_OFFSET);
break; break;
} }
printf("--- Exception: %lx %s at ", regs.trap, printf("--- Exception: %lx %s at ", regs.trap,
...@@ -1371,7 +1369,9 @@ void excprint(struct pt_regs *fp) ...@@ -1371,7 +1369,9 @@ void excprint(struct pt_regs *fp)
} }
printf(" current = 0x%lx\n", current); printf(" current = 0x%lx\n", current);
#ifdef CONFIG_PPC64
printf(" paca = 0x%lx\n", get_paca()); printf(" paca = 0x%lx\n", get_paca());
#endif
if (current) { if (current) {
printf(" pid = %ld, comm = %s\n", printf(" pid = %ld, comm = %s\n",
current->pid, current->comm); current->pid, current->comm);
...@@ -1383,7 +1383,7 @@ void excprint(struct pt_regs *fp) ...@@ -1383,7 +1383,7 @@ void excprint(struct pt_regs *fp)
void prregs(struct pt_regs *fp) void prregs(struct pt_regs *fp)
{ {
int n; int n, trap;
unsigned long base; unsigned long base;
struct pt_regs regs; struct pt_regs regs;
...@@ -1396,7 +1396,7 @@ void prregs(struct pt_regs *fp) ...@@ -1396,7 +1396,7 @@ void prregs(struct pt_regs *fp)
__delay(200); __delay(200);
} else { } else {
catch_memory_errors = 0; catch_memory_errors = 0;
printf("*** Error reading registers from %.16lx\n", printf("*** Error reading registers from "REG"\n",
base); base);
return; return;
} }
...@@ -1404,22 +1404,36 @@ void prregs(struct pt_regs *fp) ...@@ -1404,22 +1404,36 @@ void prregs(struct pt_regs *fp)
fp = &regs; fp = &regs;
} }
#ifdef CONFIG_PPC64
if (FULL_REGS(fp)) { if (FULL_REGS(fp)) {
for (n = 0; n < 16; ++n) for (n = 0; n < 16; ++n)
printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", printf("R%.2ld = "REG" R%.2ld = "REG"\n",
n, fp->gpr[n], n+16, fp->gpr[n+16]); n, fp->gpr[n], n+16, fp->gpr[n+16]);
} else { } else {
for (n = 0; n < 7; ++n) for (n = 0; n < 7; ++n)
printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", printf("R%.2ld = "REG" R%.2ld = "REG"\n",
n, fp->gpr[n], n+7, fp->gpr[n+7]); n, fp->gpr[n], n+7, fp->gpr[n+7]);
} }
#else
for (n = 0; n < 32; ++n) {
printf("R%.2d = %.8x%s", n, fp->gpr[n],
(n & 3) == 3? "\n": " ");
if (n == 12 && !FULL_REGS(fp)) {
printf("\n");
break;
}
}
#endif
printf("pc = "); printf("pc = ");
xmon_print_symbol(fp->nip, " ", "\n"); xmon_print_symbol(fp->nip, " ", "\n");
printf("lr = "); printf("lr = ");
xmon_print_symbol(fp->link, " ", "\n"); xmon_print_symbol(fp->link, " ", "\n");
printf("msr = %.16lx cr = %.8lx\n", fp->msr, fp->ccr); printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
printf("ctr = %.16lx xer = %.16lx trap = %8lx\n", printf("ctr = "REG" xer = "REG" trap = %4lx\n",
fp->ctr, fp->xer, fp->trap); fp->ctr, fp->xer, fp->trap);
trap = TRAP(fp);
if (trap == 0x300 || trap == 0x380 || trap == 0x600)
printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr);
} }
void cacheflush(void) void cacheflush(void)
...@@ -1519,8 +1533,7 @@ static unsigned long regno; ...@@ -1519,8 +1533,7 @@ static unsigned long regno;
extern char exc_prolog; extern char exc_prolog;
extern char dec_exc; extern char dec_exc;
void void super_regs(void)
super_regs(void)
{ {
int cmd; int cmd;
unsigned long val; unsigned long val;
...@@ -1536,12 +1549,14 @@ super_regs(void) ...@@ -1536,12 +1549,14 @@ super_regs(void)
asm("mr %0,1" : "=r" (sp) :); asm("mr %0,1" : "=r" (sp) :);
asm("mr %0,2" : "=r" (toc) :); asm("mr %0,2" : "=r" (toc) :);
printf("msr = %.16lx sprg0= %.16lx\n", get_msr(), get_sprg0()); printf("msr = "REG" sprg0= "REG"\n",
printf("pvr = %.16lx sprg1= %.16lx\n", get_pvr(), get_sprg1()); mfmsr(), mfspr(SPRN_SPRG0));
printf("dec = %.16lx sprg2= %.16lx\n", get_dec(), get_sprg2()); printf("pvr = "REG" sprg1= "REG"\n",
printf("sp = %.16lx sprg3= %.16lx\n", sp, get_sprg3()); mfspr(SPRN_PVR), mfspr(SPRN_SPRG1));
printf("toc = %.16lx dar = %.16lx\n", toc, get_dar()); printf("dec = "REG" sprg2= "REG"\n",
printf("srr0 = %.16lx srr1 = %.16lx\n", get_srr0(), get_srr1()); mfspr(SPRN_DEC), mfspr(SPRN_SPRG2));
printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3));
printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR));
#ifdef CONFIG_PPC_ISERIES #ifdef CONFIG_PPC_ISERIES
// Dump out relevant Paca data areas. // Dump out relevant Paca data areas.
printf("Paca: \n"); printf("Paca: \n");
...@@ -1578,11 +1593,6 @@ super_regs(void) ...@@ -1578,11 +1593,6 @@ super_regs(void)
case 'r': case 'r':
printf("spr %lx = %lx\n", regno, read_spr(regno)); printf("spr %lx = %lx\n", regno, read_spr(regno));
break; break;
case 'm':
val = get_msr();
scanhex(&val);
set_msrd(val);
break;
} }
scannl(); scannl();
} }
...@@ -1604,13 +1614,13 @@ mread(unsigned long adrs, void *buf, int size) ...@@ -1604,13 +1614,13 @@ mread(unsigned long adrs, void *buf, int size)
q = (char *)buf; q = (char *)buf;
switch (size) { switch (size) {
case 2: case 2:
*(short *)q = *(short *)p; *(u16 *)q = *(u16 *)p;
break; break;
case 4: case 4:
*(int *)q = *(int *)p; *(u32 *)q = *(u32 *)p;
break; break;
case 8: case 8:
*(long *)q = *(long *)p; *(u64 *)q = *(u64 *)p;
break; break;
default: default:
for( ; n < size; ++n) { for( ; n < size; ++n) {
...@@ -1641,13 +1651,13 @@ mwrite(unsigned long adrs, void *buf, int size) ...@@ -1641,13 +1651,13 @@ mwrite(unsigned long adrs, void *buf, int size)
q = (char *) buf; q = (char *) buf;
switch (size) { switch (size) {
case 2: case 2:
*(short *)p = *(short *)q; *(u16 *)p = *(u16 *)q;
break; break;
case 4: case 4:
*(int *)p = *(int *)q; *(u32 *)p = *(u32 *)q;
break; break;
case 8: case 8:
*(long *)p = *(long *)q; *(u64 *)p = *(u64 *)q;
break; break;
default: default:
for ( ; n < size; ++n) { for ( ; n < size; ++n) {
...@@ -1667,11 +1677,12 @@ mwrite(unsigned long adrs, void *buf, int size) ...@@ -1667,11 +1677,12 @@ mwrite(unsigned long adrs, void *buf, int size)
} }
static int fault_type; static int fault_type;
static int fault_except;
static char *fault_chars[] = { "--", "**", "##" }; static char *fault_chars[] = { "--", "**", "##" };
static int static int handle_fault(struct pt_regs *regs)
handle_fault(struct pt_regs *regs)
{ {
fault_except = TRAP(regs);
switch (TRAP(regs)) { switch (TRAP(regs)) {
case 0x200: case 0x200:
fault_type = 0; fault_type = 0;
...@@ -1960,7 +1971,7 @@ prdump(unsigned long adrs, long ndump) ...@@ -1960,7 +1971,7 @@ prdump(unsigned long adrs, long ndump)
unsigned char temp[16]; unsigned char temp[16];
for (n = ndump; n > 0;) { for (n = ndump; n > 0;) {
printf("%.16lx", adrs); printf(REG, adrs);
putchar(' '); putchar(' ');
r = n < 16? n: 16; r = n < 16? n: 16;
nr = mread(adrs, temp, r); nr = mread(adrs, temp, r);
...@@ -2008,7 +2019,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr) ...@@ -2008,7 +2019,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr)
if (nr == 0) { if (nr == 0) {
if (praddr) { if (praddr) {
const char *x = fault_chars[fault_type]; const char *x = fault_chars[fault_type];
printf("%.16lx %s%s%s%s\n", adr, x, x, x, x); printf(REG" %s%s%s%s\n", adr, x, x, x, x);
} }
break; break;
} }
...@@ -2023,7 +2034,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr) ...@@ -2023,7 +2034,7 @@ ppc_inst_dump(unsigned long adr, long count, int praddr)
dotted = 0; dotted = 0;
last_inst = inst; last_inst = inst;
if (praddr) if (praddr)
printf("%.16lx %.8x", adr, inst); printf(REG" %.8x", adr, inst);
printf("\t"); printf("\t");
print_insn_powerpc(inst, adr, 0); /* always returns 4 */ print_insn_powerpc(inst, adr, 0); /* always returns 4 */
printf("\n"); printf("\n");
...@@ -2152,6 +2163,42 @@ memzcan(void) ...@@ -2152,6 +2163,42 @@ memzcan(void)
printf("%.8x\n", a - mskip); printf("%.8x\n", a - mskip);
} }
void proccall(void)
{
unsigned long args[8];
unsigned long ret;
int i;
typedef unsigned long (*callfunc_t)(unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long);
callfunc_t func;
if (!scanhex(&adrs))
return;
if (termch != '\n')
termch = 0;
for (i = 0; i < 8; ++i)
args[i] = 0;
for (i = 0; i < 8; ++i) {
if (!scanhex(&args[i]) || termch == '\n')
break;
termch = 0;
}
func = (callfunc_t) adrs;
ret = 0;
if (setjmp(bus_error_jmp) == 0) {
catch_memory_errors = 1;
sync();
ret = func(args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7]);
sync();
printf("return value is %x\n", ret);
} else {
printf("*** %x exception occurred\n", fault_except);
}
catch_memory_errors = 0;
}
/* Input scanning routines */ /* Input scanning routines */
int int
skipbl(void) skipbl(void)
...@@ -2174,7 +2221,12 @@ static char *regnames[N_PTREGS] = { ...@@ -2174,7 +2221,12 @@ static char *regnames[N_PTREGS] = {
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
"pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "softe", "pc", "msr", "or3", "ctr", "lr", "xer", "ccr",
#ifdef CONFIG_PPC64
"softe",
#else
"mq",
#endif
"trap", "dar", "dsisr", "res" "trap", "dar", "dsisr", "res"
}; };
...@@ -2280,8 +2332,7 @@ scannl(void) ...@@ -2280,8 +2332,7 @@ scannl(void)
c = inchar(); c = inchar();
} }
int int hexdigit(int c)
hexdigit(int c)
{ {
if( '0' <= c && c <= '9' ) if( '0' <= c && c <= '9' )
return c - '0'; return c - '0';
...@@ -2378,7 +2429,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid, ...@@ -2378,7 +2429,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
const char *name = NULL; const char *name = NULL;
unsigned long offset, size; unsigned long offset, size;
printf("%.16lx", address); printf(REG, address);
if (setjmp(bus_error_jmp) == 0) { if (setjmp(bus_error_jmp) == 0) {
catch_memory_errors = 1; catch_memory_errors = 1;
sync(); sync();
...@@ -2399,55 +2450,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid, ...@@ -2399,55 +2450,7 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
printf("%s", after); printf("%s", after);
} }
static void debug_trace(void) #ifdef CONFIG_PPC64
{
unsigned long val, cmd, on;
cmd = skipbl();
if (cmd == '\n') {
/* show current state */
unsigned long i;
printf("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch);
for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) {
on = PPCDBG_BITVAL(i) & ppc64_debug_switch;
printf("%02x %s %12s ", i, on ? "on " : "off", trace_names[i] ? trace_names[i] : "");
if (((i+1) % 3) == 0)
printf("\n");
}
printf("\n");
return;
}
while (cmd != '\n') {
on = 1; /* default if no sign given */
while (cmd == '+' || cmd == '-') {
on = (cmd == '+');
cmd = inchar();
if (cmd == ' ' || cmd == '\n') { /* Turn on or off based on + or - */
ppc64_debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE;
printf("Setting all values to %s...\n", on ? "on" : "off");
if (cmd == '\n') return;
else cmd = skipbl();
}
else
termch = cmd;
}
termch = cmd; /* not +/- ... let scanhex see it */
scanhex((void *)&val);
if (val >= 64) {
printf("Value %x out of range:\n", val);
return;
}
if (on) {
ppc64_debug_switch |= PPCDBG_BITVAL(val);
printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
} else {
ppc64_debug_switch &= ~PPCDBG_BITVAL(val);
printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : "");
}
cmd = skipbl();
}
}
static void dump_slb(void) static void dump_slb(void)
{ {
int i; int i;
...@@ -2484,6 +2487,27 @@ static void dump_stab(void) ...@@ -2484,6 +2487,27 @@ static void dump_stab(void)
} }
} }
void dump_segments(void)
{
if (cpu_has_feature(CPU_FTR_SLB))
dump_slb();
else
dump_stab();
}
#endif
#ifdef CONFIG_PPC_STD_MMU_32
void dump_segments(void)
{
int i;
printf("sr0-15 =");
for (i = 0; i < 16; ++i)
printf(" %x", mfsrin(i));
printf("\n");
}
#endif
void xmon_init(int enable) void xmon_init(int enable)
{ {
if (enable) { if (enable) {
...@@ -2504,11 +2528,3 @@ void xmon_init(int enable) ...@@ -2504,11 +2528,3 @@ void xmon_init(int enable)
__debugger_fault_handler = NULL; __debugger_fault_handler = NULL;
} }
} }
void dump_segments(void)
{
if (cpu_has_feature(CPU_FTR_SLB))
dump_slb();
else
dump_stab();
}
...@@ -89,7 +89,7 @@ core-y += arch/powerpc/mm/ ...@@ -89,7 +89,7 @@ core-y += arch/powerpc/mm/
core-y += arch/powerpc/sysdev/ core-y += arch/powerpc/sysdev/
core-y += arch/powerpc/platforms/ core-y += arch/powerpc/platforms/
core-y += arch/powerpc/lib/ core-y += arch/powerpc/lib/
core-$(CONFIG_XMON) += arch/ppc64/xmon/ core-$(CONFIG_XMON) += arch/powerpc/xmon/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
boot := arch/ppc64/boot boot := arch/ppc64/boot
......
# Makefile for xmon
EXTRA_CFLAGS += -mno-minimal-toc
obj-y := start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
/*
* Copyright (C) 1996 Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* NOTE: assert(sizeof(buf) > 184)
*/
#include <asm/processor.h>
#include <asm/ppc_asm.h>
_GLOBAL(xmon_setjmp)
mflr r0
std r0,0(r3)
std r1,8(r3)
std r2,16(r3)
mfcr r0
std r0,24(r3)
std r13,32(r3)
std r14,40(r3)
std r15,48(r3)
std r16,56(r3)
std r17,64(r3)
std r18,72(r3)
std r19,80(r3)
std r20,88(r3)
std r21,96(r3)
std r22,104(r3)
std r23,112(r3)
std r24,120(r3)
std r25,128(r3)
std r26,136(r3)
std r27,144(r3)
std r28,152(r3)
std r29,160(r3)
std r30,168(r3)
std r31,176(r3)
li r3,0
blr
_GLOBAL(xmon_longjmp)
cmpdi r4,0
bne 1f
li r4,1
1: ld r13,32(r3)
ld r14,40(r3)
ld r15,48(r3)
ld r16,56(r3)
ld r17,64(r3)
ld r18,72(r3)
ld r19,80(r3)
ld r20,88(r3)
ld r21,96(r3)
ld r22,104(r3)
ld r23,112(r3)
ld r24,120(r3)
ld r25,128(r3)
ld r26,136(r3)
ld r27,144(r3)
ld r28,152(r3)
ld r29,160(r3)
ld r30,168(r3)
ld r31,176(r3)
ld r0,24(r3)
mtcrf 56,r0
ld r0,0(r3)
ld r1,8(r3)
ld r2,16(r3)
mtlr r0
mr r3,r4
blr
...@@ -188,6 +188,10 @@ n: ...@@ -188,6 +188,10 @@ n:
#define LDL ld #define LDL ld
#define STL std #define STL std
#define CMPI cmpdi #define CMPI cmpdi
#define SZL 8
/* offsets for stack frame layout */
#define LRSAVE 16
#else /* 32-bit */ #else /* 32-bit */
#define LOADADDR(rn,name) \ #define LOADADDR(rn,name) \
...@@ -203,6 +207,10 @@ n: ...@@ -203,6 +207,10 @@ n:
#define LDL lwz #define LDL lwz
#define STL stw #define STL stw
#define CMPI cmpwi #define CMPI cmpwi
#define SZL 4
/* offsets for stack frame layout */
#define LRSAVE 4
#endif #endif
......
...@@ -546,6 +546,7 @@ ...@@ -546,6 +546,7 @@
#define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
: : "r" (v)) : : "r" (v))
#define mtmsrd(v) __mtmsrd((v), 0) #define mtmsrd(v) __mtmsrd((v), 0)
#define mtmsr(v) mtmsrd(v)
#else #else
#define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) #define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v))
#endif #endif
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
struct pt_regs; struct pt_regs;
extern void xmon(struct pt_regs *excp); extern int xmon(struct pt_regs *excp);
extern void xmon_printf(const char *fmt, ...); extern void xmon_printf(const char *fmt, ...);
extern void xmon_init(int); extern void xmon_init(int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment