Commit f78541dc authored by Paul Mackerras's avatar Paul Mackerras
Browse files

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/ \
arch/powerpc/sysdev/ \
arch/powerpc/platforms/
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/
drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/
drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
......
......@@ -271,6 +271,9 @@ __secondary_hold_acknowledge:
li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
MTMSRD(r10); /* (except for mach check in rtas) */ \
stw r0,GPR0(r11); \
lis r10,0x7265; /* put exception frame marker */ \
addi r10,r10,0x6773; \
stw r10,8(r11); \
SAVE_4GPRS(3, r11); \
SAVE_2GPRS(7, r11)
......
......@@ -44,7 +44,6 @@
#include <asm/cputable.h>
#include <asm/btext.h>
#include <asm/div64.h>
#include <asm/xmon.h>
#ifdef CONFIG_8xx
#include <asm/commproc.h>
......@@ -238,10 +237,6 @@ EXPORT_SYMBOL(console_drivers);
EXPORT_SYMBOL(cacheable_memcpy);
#endif
#ifdef CONFIG_XMON
EXPORT_SYMBOL(xmon);
EXPORT_SYMBOL(xmon_printf);
#endif
EXPORT_SYMBOL(__up);
EXPORT_SYMBOL(__down);
EXPORT_SYMBOL(__down_interruptible);
......
......@@ -302,8 +302,10 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_XMON
xmon_map_scc();
if (strstr(cmd_line, "xmon"))
xmon(NULL);
if (strstr(cmd_line, "xmon")) {
xmon_init(1);
debugger(NULL);
}
#endif /* CONFIG_XMON */
if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab);
......
......@@ -59,6 +59,7 @@
#include <asm/iSeries/ItLpNaca.h>
#include <asm/firmware.h>
#include <asm/systemcfg.h>
#include <asm/xmon.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
......
......@@ -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 \
memcpy_64.o usercopy_64.o mem_64.o
obj-$(CONFIG_PPC_ISERIES) += e2a.o
obj-$(CONFIG_XMON) += sstep.o
ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_SMP) += locks.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) {