1492 lines
38 KiB
C
1492 lines
38 KiB
C
static char sccsid[] = "@(#)50 1.83 src/bos/kernel/db/POWER/dbdebug.c, sysdb, bos41B, 412_41B_sync 12/6/94 14:34:56";
|
|
/*
|
|
* COMPONENT_NAME: (SYSDB) Kernel Debugger
|
|
*
|
|
* FUNCTIONS: debugger, save_data, check_entry, step_or_break, first_screen,
|
|
* process_cmd, restore_info, rest_disp, tell_reason,
|
|
* in_real_mem, send_mpc_stop, dbcpu_init, db_resume_others,
|
|
* hold_cpus_while_stepping
|
|
* ORIGINS: 27 83
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1988, 1994
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
/*
|
|
* LEVEL 1, 5 Years Bull Confidential Information
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/mstsave.h>
|
|
#include <sys/dbkersym.h>
|
|
#include <sys/dbg_codes.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/lldebug.h>
|
|
#include <sys/iplcb.h>
|
|
#include <sys/vmker.h>
|
|
#include <sys/systemcfg.h>
|
|
#include "debvars.h"
|
|
#undef DEC
|
|
#include "dbdebug.h"
|
|
#include "dbbreak.h"
|
|
#include "dbfunc.h"
|
|
#include "dbfn_init.h"
|
|
#include "pr_proc.h"
|
|
#include "parse.h"
|
|
#include "vdberr.h"
|
|
#include "debaddr.h"
|
|
#ifdef _POWER_PC
|
|
#include <sys/sys_resource.h>
|
|
#endif /* #ifdef _POWER_PC */
|
|
#include <sys/ppda.h>
|
|
#ifdef _POWER_MP
|
|
#include <sys/mpc.h>
|
|
#endif /* #ifdef _POWER_MP */
|
|
#include <sys/machine.h>
|
|
|
|
/*
|
|
* EXTERNAL PROCEDURES CALLED:
|
|
*/
|
|
|
|
extern int mfdsisr();
|
|
extern int mfdar();
|
|
extern struct ppda ppda[];
|
|
#if defined (_POWER_RS1) || defined(_POWER_RSC)
|
|
extern void mfeim();
|
|
extern void mfeis();
|
|
extern void mteim();
|
|
extern void mteis();
|
|
#endif /* #if defined (_POWER_RS1) || ... */
|
|
extern int mfsdr0();
|
|
extern int mfsdr1();
|
|
extern int mfrtcu();
|
|
extern int mfrtcl();
|
|
extern int mfdec();
|
|
|
|
extern void mttid();
|
|
extern void mtdsisr();
|
|
extern void mtdar();
|
|
extern void mtsdr0();
|
|
extern void mtsdr1();
|
|
extern void mtrtcl();
|
|
extern void mtdec();
|
|
extern void mtrtcu();
|
|
extern char initio();
|
|
extern void copy_keyboard_map();
|
|
extern void enable_kbd();
|
|
extern void wait_for_break();
|
|
extern void clrdsp();
|
|
extern char *getterm(); /* get from the terminal */
|
|
extern void putdsp();
|
|
extern void getscn();
|
|
extern int driver();
|
|
extern int get_cmd();
|
|
extern setup_branch_table();
|
|
extern steal_pgmck();
|
|
extern restore_pgmck();
|
|
extern void tell_reason();
|
|
extern void d_ttyclose();
|
|
extern int dump_rv; /* declared in com/sys/db/vdbprf.c for panic() */
|
|
extern ulong dbterm;
|
|
extern char debabend;
|
|
extern char restore_cntl; /* restore_cntl = 1, allow restore */
|
|
extern uchar screen_on; /*flag:display/do not display scrn*/
|
|
extern ulong ipl_cb; /* contains address of ipl control blk*/
|
|
#ifdef _POWER_MP
|
|
extern int db_get_processornum();
|
|
void db_resume_others();
|
|
#endif /* #ifdef _POWER_MP */
|
|
ulong getaprsegid(ulong,ulong); /* Gets segid from addr (dbbreak.c) */
|
|
int branch_taken(ulong); /* Says if branch will be taken -
|
|
from dbdisasm.c. */
|
|
|
|
#ifdef _POWER_MP
|
|
#include <sys/m_param.h>
|
|
unsigned char printbuf[MAXCPU * PRINTBUFSIZE];
|
|
#else /* #ifdef _POWER_MP */
|
|
unsigned char printbuf[PRINTBUFSIZE]; /* circular buf used by kernel printf */
|
|
/* Declared here so it will not be in */
|
|
/* pinned memory */
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
struct db_vmsidata db_vp;
|
|
extern struct watch_data watch_data;
|
|
extern struct brat_data brat_data;
|
|
|
|
#ifdef _POWER_PC
|
|
extern int db_mftbu(); /* time base register support (move to/from) */
|
|
extern int db_mftbl();
|
|
extern void db_mttbu();
|
|
extern void db_mttbl();
|
|
#endif /* #ifdef _POWER_PC */
|
|
|
|
/* Macro SREG - Given an address, it returns the segment register number within
|
|
* the address (the high order nibble).
|
|
*/
|
|
#define SREG(x) ((x)>>SEGSHIFT)
|
|
|
|
/* Defines for restore_info */
|
|
#define SET_BRATWATCH 1
|
|
#define NO_SET_BRATWATCH 0
|
|
|
|
#ifdef _POWER_PC
|
|
/* Determine a bit value in the ioalloc part of the mst */
|
|
#define BIT_VALUE(value, bit) ((value) & ((uint)0x80000000 >> (bit)))
|
|
|
|
ulong_t ioalloc; /* ioallocation mask copy from mst */
|
|
#endif /* #ifdef _POWER_PC */
|
|
|
|
/*
|
|
* NAME: debug
|
|
*
|
|
* FUNCTION: Low Level Kernel Debugger
|
|
*
|
|
* (EXECUTION ENVIRONMENT:)
|
|
*
|
|
* Environment-Specific aspects, such as -
|
|
* Preemptable : no
|
|
* VMM Critical Region: n/a
|
|
* Runs on Fixed Stack: n/a
|
|
* May Page Fault : NO
|
|
* May Backtrack : n/a
|
|
*
|
|
* (DATA STRUCTURES:) a plethora of global data structures ...
|
|
*
|
|
*/
|
|
|
|
struct vars debvars[MAXVARS]; /* found in vdbbreak.h */
|
|
double fr[NUMFPRS]; /* holds floating point reg values */
|
|
ulong sr_on_entry[NUMSEGS]; /* holds the real seg regs at the
|
|
time of entry to the debugger */
|
|
#ifdef _POWER_MP
|
|
|
|
mpc_msg_t mpc_stop; /* mpc message to stop other cpus */
|
|
|
|
volatile struct db_lock debugger_lock = {0,0,-1}; /* to protect db_main */
|
|
|
|
int dbg_cpu; /* fo kdbx, the cpu being in "debugging" state */
|
|
|
|
status_t status[MAXCPU]; /* Set by each cpu when changing its own state
|
|
used to display the status, and to avoid
|
|
spurious MPC_stop sendings
|
|
*/
|
|
action_t action[MAXCPU]; /* Only modified in db_main, under protection
|
|
of debugger_lock. Used by the cpu in
|
|
debugging state to control others (stop, resume)
|
|
*/
|
|
|
|
int selected_cpu = NO_SELECTED_CPU; /* set by the cpu command */
|
|
int cp_selected_cpu = NO_SELECTED_CPU; /* a copy for check_entry */
|
|
|
|
int step_processing_level = 0; /* a step is being executed,
|
|
can be recursive */
|
|
|
|
int switch_ctxt, switch_ctxt_sr1, switch_ctxt_sr2, switch_ctxt_sr13; /* switch command associated data */
|
|
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
ulong rosetta_base;
|
|
#define init1 0xffffffff
|
|
#define init0 0x00000000
|
|
#define CACHE_SIZE_IN_BYTES (64*1024) /* 64K bytes */
|
|
|
|
int debug_init=TRUE; /* initialize the debugger */
|
|
int restore_screen=TRUE; /* 1 = restore display */
|
|
ulong debmid=not_a_module; /* debuggers module id */
|
|
char *in_string, old_string[40];
|
|
|
|
int loop_count=0; /* loop counter */
|
|
int step_count=1; /* step counter */
|
|
int testbit,brk_type,max_ipts;
|
|
int max_real=(1024*1024);
|
|
int step_id;
|
|
int at_breakpoint,cmd,b8;
|
|
char step_s1;
|
|
ushort er; /* ushort entry reason */
|
|
struct parse_out parse_out; /* parser structure */
|
|
struct debaddr debaddr; /* debugger address structure */
|
|
struct mcs_pcs *mcs_pcs1;
|
|
char *dummystr="dummy";
|
|
|
|
char flssrs[16]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
|
|
|
|
int save_reason; /* Var to hold reason for "reason" cmd */
|
|
int save_ext_arg; /* Same for ext_arg */
|
|
|
|
|
|
struct mstsave *mst; /* global mst area ptr */
|
|
struct ppda *ppda_ptr; /* pointer to per processor data struc*/
|
|
|
|
/*
|
|
* NAME: db_main
|
|
*
|
|
* FUNCTION: this is the mainline code for the debugger and it calls
|
|
* the other functions. The global variables used in the debugger
|
|
* are initialized here and in save_data. Check entry reason code
|
|
* and this will determine why the debugger was called and what should
|
|
* be done.
|
|
*
|
|
* RETURN VALUE DESCRIPTION: 0 if no errors and debugger has operated normally
|
|
* 1 if trap was not for debugger
|
|
* negative number if debugger ended abnormally
|
|
*/
|
|
|
|
db_main(mst1, rsn_code, ext_arg)
|
|
struct mstsave *mst1;
|
|
int rsn_code;
|
|
int ext_arg;
|
|
{
|
|
char *t, *addr, *goal, i;
|
|
int cache_line_size;
|
|
int cur_cpu = 0;
|
|
#ifdef _POWER_MP
|
|
if (__power_mp()){
|
|
cur_cpu = cpunb;
|
|
/* check we had good reasons to enter the debug state, else, go back and wait*/
|
|
if ((action[cur_cpu] == stop)
|
|
|| ((selected_cpu != NO_SELECTED_CPU) && (selected_cpu != cur_cpu))){
|
|
action[cur_cpu] = stop;
|
|
return (OK);
|
|
}
|
|
dbg_cpu = cur_cpu; /* for kdbx usage */
|
|
status[cur_cpu] = debugging; /* we entered the debugging state */
|
|
action[cur_cpu] = NONE; /* action may be reset later */
|
|
|
|
if (selected_cpu == NO_SELECTED_CPU){
|
|
/*
|
|
* have to stop others running processors
|
|
*/
|
|
|
|
for(i=0; i< number_of_cpus; i++){
|
|
if (status[i] == running){
|
|
action[i] = stop;
|
|
send_mpc_stop(i);
|
|
}
|
|
}
|
|
}
|
|
cp_selected_cpu = selected_cpu;
|
|
selected_cpu = NO_SELECTED_CPU;
|
|
}
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
/*
|
|
* don't forget to increase the size of the register save
|
|
* area in vdbdata.h8 for the 32 gprs and fprs!
|
|
*/
|
|
#ifdef _POWER_MP
|
|
if (__pegasus())
|
|
db_stop_rtc();
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
/* NOTE: This is the first point at which we can safely do printf's. */
|
|
/* For the kernel printf to work properly from the debugger, we */
|
|
/* must have status[cur_cpu] == debugging *and* the rtc must be */
|
|
/* stopped on MP systems. */
|
|
|
|
/*
|
|
* If the pointer to the mstsave area is NULL, use csa->prev
|
|
* as the mstsave pointer.
|
|
*/
|
|
if (mst1)
|
|
mst = mst1; /* assign to global variable */
|
|
else
|
|
mst = (ppda[cur_cpu])._csa->prev;
|
|
|
|
save_data(); /* save mstsave area */
|
|
/* and init io */
|
|
|
|
save_reason = rsn_code; /* Save reason code for "reason" cmd */
|
|
save_ext_arg = ext_arg; /* Ditto for ext_arg */
|
|
|
|
if(!check_entry(rsn_code)) { /* check reason for entering */
|
|
restore_info(TRUE,SET_BRATWATCH);/*restore breakpoints,etc*/
|
|
|
|
#ifdef _POWER_MP /* have to resume stopped cpus */
|
|
if (__power_mp()){
|
|
db_resume_others();
|
|
return OK; /* the entry has
|
|
been check by db_is_to_call from p_slih,
|
|
if here, there was a reason to enter the debugger, that
|
|
may have disappeared because MP */
|
|
}
|
|
|
|
#endif /* #ifdef _POWER_MP */
|
|
return NOTMYTRAP; /* if not our trap return to kernel */
|
|
}
|
|
|
|
if (step_or_break()) {
|
|
/* breakpt probably for another debugger */
|
|
debabend = OUT;
|
|
#ifdef _POWER_MP /* have to resume stopped cpus */
|
|
if (__power_mp())
|
|
db_resume_others();
|
|
#endif /* #ifdef _POWER_MP */
|
|
return OK; /*leave debugger (looping or stepping)*/
|
|
}
|
|
|
|
/* leave at this point if initialization wasn't successful */
|
|
if (debug_init) {
|
|
restore_info(TRUE,NO_SET_BRATWATCH); /*restore regs,etc*/
|
|
debabend = OUT;
|
|
#ifdef _POWER_MP /* have to resume stopped cpus */
|
|
if (__power_mp())
|
|
db_resume_others();
|
|
#endif /* #ifdef _POWER_MP */
|
|
return(INITRET); /* not yet initialized */
|
|
}
|
|
|
|
/*
|
|
* Setup the branch table, i.e., export display/kbd routines
|
|
* used by panic.
|
|
* Also, steel the program & machine check vectors;
|
|
* they're restore in restore_info.
|
|
*/
|
|
/*setup_branch_table(); */
|
|
/*steal_pgmck(); */
|
|
|
|
/* only do the following if we didn't abend the debugger */
|
|
if (debabend==OUT) {
|
|
debabend = IN; /* track entry/exit to debugger */
|
|
if(first_screen()<0) {
|
|
/*restore breakpoints,etc*/
|
|
restore_info(TRUE,NO_SET_BRATWATCH);
|
|
debabend = OUT; /* track entry/exit to debugger */
|
|
#ifdef _POWER_MP /* have to resume stopped cpus */
|
|
if (__power_mp())
|
|
db_resume_others();
|
|
#endif /* #ifdef _POWER_MP */
|
|
return(NOTTY); /* we couldn't open a tty */
|
|
}
|
|
}
|
|
/* error occured in debugger so don't display screen - that may */
|
|
/* be cause of error */
|
|
else
|
|
printf(" Error: left debugger via interrupt. \n");
|
|
|
|
/* display reason for entering debugger*/
|
|
tell_reason(rsn_code,ext_arg);
|
|
|
|
|
|
i = process_cmd(); /* handle commands */
|
|
|
|
/* finished, exit the debugger */
|
|
if ((rsn_code == DBG_WATCH) || (rsn_code == DBG_BTARGET))
|
|
/* Don't reset the IABR or DABR if we are already here */
|
|
/* because of one, or else we'll go into an infinite loop of*/
|
|
/* brat/watch interrupts. A step point should have been set*/
|
|
/* previously that will allow us to re-establish the IABR & */
|
|
/* DABR settings later. */
|
|
restore_info(FALSE,NO_SET_BRATWATCH);
|
|
else
|
|
restore_info(FALSE,SET_BRATWATCH);
|
|
debabend = OUT;
|
|
|
|
/*
|
|
* since panic() calls brkpoint() and does not call
|
|
* the debugger directly, this is how we tell it we
|
|
* want to take a dump
|
|
*/
|
|
if(i==DUMPRET)
|
|
dump_rv = i;
|
|
else
|
|
dump_rv = 0;
|
|
|
|
return(OK); /* return to kernel */
|
|
}
|
|
|
|
#ifdef _POWER_MP
|
|
/*
|
|
* NAME: send_mpc_stop
|
|
*
|
|
* FUNCTION:
|
|
* sends a mpc signal to cpu i
|
|
*
|
|
*
|
|
* RETURN VALUE DESCRIPTION: Nothing
|
|
*
|
|
*/
|
|
send_mpc_stop(cpu_id)
|
|
int cpu_id;
|
|
{
|
|
mpc_send(cpu_id, mpc_stop);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: mpc_stop_handler
|
|
* Called from mpc interrupt
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* call the debugger with an mpc_stop reason
|
|
*
|
|
*
|
|
*
|
|
* RETURN VALUE DESCRIPTION: none
|
|
*
|
|
*/
|
|
|
|
int mpc_stop_handler()
|
|
{
|
|
debugger(0,DBG_MPC_STOP,0);
|
|
}
|
|
|
|
/*
|
|
* NAME: dbcpu_init
|
|
* Called from debugger_init
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* Initialize the cpu initial structures action and status
|
|
* and registers the mpc handler
|
|
*
|
|
*
|
|
* RETURN VALUE DESCRIPTION: None
|
|
*
|
|
*/
|
|
|
|
void dbcpu_init()
|
|
{
|
|
int i;
|
|
mpc_stop = mpc_register(INTMAX, mpc_stop_handler);
|
|
for (i=0; i< number_of_cpus; i++){
|
|
status[i] = running;
|
|
action[i] = NONE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: hold_cpus_while_stepping
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* take care not to let debug_waiting cpus
|
|
* take control of the debugger
|
|
*
|
|
* RETURN VALUE DESCRIPTION: None
|
|
*
|
|
*/
|
|
|
|
void hold_cpus_while_stepping() /* called only if __power_mp() */
|
|
{
|
|
int i;
|
|
for (i=0; i< number_of_cpus;i++){
|
|
if (status[i] == debug_waiting)
|
|
action[i] = stop;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: db_resume_others
|
|
*
|
|
* FUNCTION:
|
|
*
|
|
* resume stopped cpu if no break instruction beeing executed
|
|
*
|
|
*
|
|
* RETURN VALUE DESCRIPTION: none
|
|
*
|
|
*/
|
|
|
|
void db_resume_others() /* called only if __power_mp() */
|
|
{
|
|
int i;
|
|
/* check if to resume stopped cpus */
|
|
if (step_processing_level == 0)
|
|
for (i=0; i< number_of_cpus;i++){
|
|
if (action[i] == stop)
|
|
action[i] = resume;
|
|
}
|
|
}
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
/*
|
|
* NAME: save_data
|
|
*
|
|
* FUNCTION: this routine will save certain data areas into local debugger
|
|
* save areas. The mstsave area is almost completely saved off as well
|
|
* as the segment registers. The display is initialized if necessary
|
|
* and the first debugger command (?) is set. Debvars is a pointer
|
|
* to a location where debugger variable information is kept. Initio
|
|
* will set some global variables used for the terminal routines.
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
*
|
|
* RETURN VALUE: 0 is always returned to the caller
|
|
*
|
|
*/
|
|
|
|
save_data()
|
|
{
|
|
register int i;
|
|
struct ipl_cb *iplcb_ptr;
|
|
struct ipl_info *iinfo_ptr;
|
|
struct ipl_directory *idir_ptr;
|
|
|
|
/*
|
|
* get address of ram bit map, get size of bit map,
|
|
* get number of bytes each bit in ram bit map represents
|
|
*/
|
|
iplcb_ptr = (struct ipl_cb *) ipl_cb;
|
|
idir_ptr = (struct ipl_directory *)(&iplcb_ptr->s0);
|
|
db_vp.rmapptr = (uint)ipl_cb + realbyt(&idir_ptr->bit_map_offset,4);
|
|
db_vp.rmapsize = realbyt(&idir_ptr->bit_map_size,4)/4;
|
|
iinfo_ptr = (struct ipl_info *)
|
|
((uint)ipl_cb + realbyt(&idir_ptr->ipl_info_offset,4));
|
|
db_vp.rmapblk = realbyt(&iinfo_ptr->bit_map_bytes_per_bit,4);
|
|
|
|
/* force store of & make available floating point registers */
|
|
disown_fp(-1);
|
|
for (i=0; i<NUMGPRS; i++) {
|
|
fr[i] = mst->fpr[i]; /* same # of fprs as gprs */
|
|
debvars[IDGPRS+i].hv = mst->gpr[i];
|
|
|
|
if (i<NUMSEGS) {
|
|
debvars[IDSEGS+i].hv = mst->as.srval[i];
|
|
sr_on_entry[i] = mfsr(i);
|
|
}
|
|
}
|
|
|
|
#ifdef _POWER_PC
|
|
/* pick up the BATs from the mst. The structure of the BATs in
|
|
the mst is:
|
|
|
|
struct {
|
|
ulong_t batu;
|
|
ulong_t batl;
|
|
} dbats[NUM_KERNEL_BATS];
|
|
|
|
while the variables are defined as
|
|
|
|
"bat0u", "bat1u", "bat2u", "bat0l", "bat1l", "bat2l",
|
|
*/
|
|
|
|
if (__power_pc() && !__power_601()) {
|
|
ioalloc = mst->ioalloc;
|
|
for (i=0; i < NUM_KERNEL_BATS; i++) {
|
|
if (BIT_VALUE(ioalloc, i)) {
|
|
debvars[IDBATU+i].hv = mst->dbats[i].batu;
|
|
debvars[IDBATL+i].hv = mst->dbats[i].batl;
|
|
}
|
|
/* If BAT was not allocated by iomem_att then load
|
|
upper BAT value with 0 to indicate it is not a
|
|
valid BAT. */
|
|
else {
|
|
debvars[IDBATU+i].hv = 0;
|
|
debvars[IDBATL+i].hv = mst->dbats[i].batl;
|
|
}
|
|
}
|
|
}
|
|
#endif /* #ifdef _POWER_PC */
|
|
|
|
debvars[IDMSR].hv = mst->msr;
|
|
debvars[IDCR].hv = mst->cr;
|
|
debvars[IDLR].hv = mst->lr;
|
|
debvars[IDCTR].hv = mst->ctr;
|
|
debvars[IDXER].hv = mst->xer;
|
|
debvars[IDFPSCR].hv = mst->fpscr;
|
|
debvars[IDTID].hv = mst->tid;
|
|
|
|
/* Note: it is invalid to read SRR0 and SRR1 with translate on. */
|
|
/* We should be showing the mst's MSR and IAR values instead of */
|
|
/* reading them directly from the registers, so that is what we */
|
|
/* are now doing. */
|
|
debvars[IDSRR0].hv = mst->iar;
|
|
debvars[IDSRR1].hv = mst->msr;
|
|
|
|
/*
|
|
* get the register data using assembler instructions
|
|
*/
|
|
|
|
ppda_ptr=ppda;
|
|
debvars[IDDSISR].hv = ppda_ptr->dsisr;
|
|
debvars[IDDAR].hv = ppda_ptr->dar;
|
|
|
|
#if defined (_POWER_RS1) || defined(_POWER_RSC)
|
|
if ( __power_rs1() || __power_rsc() ) {
|
|
mfeim(&debvars[IDEIM0].hv,&debvars[IDEIM1].hv);
|
|
mfeis(&debvars[IDEIS0].hv,&debvars[IDEIS1].hv);
|
|
}
|
|
#endif /* #if defined (_POWER_RS1) || ... */
|
|
|
|
#if defined (_POWER_RS2)
|
|
if ( __power_rs2() ) {
|
|
/* read and clear peis0,1 */
|
|
read_clear_peis();
|
|
debvars[IDILCR].hv = db_mfilcr();
|
|
}
|
|
#endif /* #if defined (_POWER_RS2) */
|
|
|
|
#if defined(_POWER_PC) && defined(_RS6K)
|
|
#ifdef _SNOOPY
|
|
if (__snoopy()){
|
|
debvars[IDXIRR].hv = 0xffffffff;
|
|
debvars[IDDSIER].hv = 0xffffffff;
|
|
}
|
|
else
|
|
#endif /* #ifdef _SNOOPY */
|
|
if ( __power_pc() && __rs6k() ) {
|
|
debvars[IDXIRR].hv = sys_resource_ptr->
|
|
sys_interrupt_space.sys_intr_regs[0].xirr_poll;
|
|
debvars[IDDSIER].hv = sys_resource_ptr->
|
|
sys_interrupt_space.sys_intr_regs[0].dsier;
|
|
}
|
|
#endif /* #ifdef _POWER_PC && _RS6K */
|
|
|
|
/* SDR0 only exists on RS1's, 2's, & C's. Load it with deadbeef */
|
|
/* on other platforms. */
|
|
#ifdef _POWER_RS
|
|
if (__power_rs())
|
|
debvars[IDSDR0].hv = mfsdr0();
|
|
else
|
|
#endif /* #ifdef _POWER_RS */
|
|
debvars[IDSDR0].hv = 0xdeadbeef;
|
|
debvars[IDSDR1].hv = mfsdr1();
|
|
|
|
#ifdef _POWER_PC
|
|
/* check if we have a 603/604 (time base) or 601 (rtc) */
|
|
if (__power_pc() && !__power_601())
|
|
{
|
|
debvars[IDTBU].hv = db_mftbu();
|
|
debvars[IDTBL].hv = db_mftbl();
|
|
}
|
|
else
|
|
#endif /* #ifdef _POWER_PC */
|
|
/* on 601 or regular POWER architecture use real time counter */
|
|
{
|
|
debvars[IDRTCU].hv = mfrtcu();
|
|
debvars[IDRTCL].hv = mfrtcl();
|
|
}
|
|
debvars[IDDEC].hv = mfdec();
|
|
debvars[IDIAR].hv = mst->iar;
|
|
debvars[IDMQ].hv = mst->mq;
|
|
|
|
/* parms copied to internal structures */
|
|
if (debug_init) { /* if initialization needed */
|
|
strcpy(old_string, "help "); /* ? is default cmd */
|
|
debug_init = FALSE;
|
|
}
|
|
|
|
restore_cntl = FALSE; /* don't restore yet */
|
|
at_breakpoint = FALSE; /* assume not a bkpt */
|
|
/* remove watchpoints then bratpoints then breakpoints */
|
|
#if defined (_POWER_RS2) || defined (_POWER_PC)
|
|
if ( __power_rs2() || __power_pc() )
|
|
if (watch_data.active) clear_watch_regs();
|
|
if ( __power_pc() )
|
|
if (brat_data.active) clear_brat_regs();
|
|
#endif /* #if defined (_POWER_RS2) || defined ... */
|
|
remove_breakpoint_traps(); /* take out any bkpt traps */
|
|
return(0);
|
|
}
|
|
|
|
|
|
#if defined (_POWER_RS2)
|
|
/*
|
|
* NAME: read_clear_peis
|
|
*
|
|
* FUNCTION: Read peis0 and peis1 into lldbg storage, DEBVARS[].
|
|
* Then reset each bit in these registers which is set.
|
|
*
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
*/
|
|
|
|
read_clear_peis()
|
|
{
|
|
|
|
if( __power_rs2() )
|
|
{
|
|
int plvl;
|
|
ulong peis0, peis1; /* save area for external int regs */
|
|
|
|
db_mfpeis(&debvars[IDPEIS0].hv,&debvars[IDPEIS1].hv);
|
|
peis0=debvars[IDPEIS0].hv;
|
|
peis1=debvars[IDPEIS1].hv;
|
|
while( peis0 ) {
|
|
plvl = bitindex( &peis0 );
|
|
peis0 &= ~((ulong)(0x80000000) >> plvl);
|
|
db_rs2peis_reset( plvl );
|
|
}
|
|
while( peis1 ) {
|
|
plvl = bitindex( &peis1 );
|
|
peis1 &= ~((ulong)(0x80000000) >> plvl);
|
|
plvl += 32;
|
|
db_rs2peis_reset( plvl );
|
|
}
|
|
}
|
|
}
|
|
#endif /* #if defined (_POWER_RS2) */
|
|
|
|
|
|
/*
|
|
* NAME: check_entry
|
|
*
|
|
* FUNCTION: Find out why we are in the debugger. Set the entry reason to
|
|
* the correct trap code.
|
|
* Only called if we hit a trap.
|
|
* If not a trap do not bother checking breakpoint table, just
|
|
* return true. Otherwise check to see if trap is in breakpoint
|
|
* table.
|
|
*
|
|
* PARAMETERS: rsn_code = reason for entering debugger. also, many globals
|
|
*
|
|
* RETURN VALUE: FALSE if not my trap (and want to leave debugger), else TRUE
|
|
*
|
|
*/
|
|
|
|
check_entry(rsn_code)
|
|
{
|
|
ulong virt; /* virtual addressing mode indicator */
|
|
int cur_cpu = 0;
|
|
|
|
#ifdef _POWER_MP
|
|
if(rsn_code==DBG_MPC_STOP){ /* in debugger due to "cpu" */
|
|
if (__power_mp()){
|
|
er = E_selected_cpu;
|
|
return TRUE; /* so stay in debugger */
|
|
} else{
|
|
er = 0; /* If this reason and mono, ignore */
|
|
return FALSE; /* return from debugger to kernel */
|
|
}
|
|
}
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
|
|
if(rsn_code == DBG_WATCH) { /* in debugger due to watchpoint */
|
|
#ifdef _POWER_MP
|
|
if (__power_mp())
|
|
cur_cpu = cpunb;
|
|
else
|
|
#endif /* POWER_MP */
|
|
cur_cpu=0;
|
|
if (ppda[cur_cpu].dsisr & DSISR_PROT) { /*check for pageprot*/
|
|
er = 0;
|
|
return FALSE; /* so exit debugger */
|
|
}
|
|
er = W_break; /* watchpoint */
|
|
return TRUE; /* so stay in debugger */
|
|
}
|
|
else
|
|
if(rsn_code == DBG_BTARGET) { /* in debugger due to bratpoint */
|
|
er = B_break; /* bratpoint */
|
|
return TRUE; /* so stay in debugger */
|
|
}
|
|
else
|
|
if(rsn_code!=DBG_TRAP){ /* in debugger due to system error */
|
|
er = 0; /* init this to nothing */
|
|
return TRUE; /* so stay in debugger */
|
|
}
|
|
|
|
virt = INSTT_BIT; /* instruction addressing mode */
|
|
step_s1 = FALSE;
|
|
|
|
|
|
#ifdef _POWER_MP
|
|
brk_type = is_break_for_me(debvars[IDIAR].hv,virt);
|
|
#else /* #ifdef _POWER_MP */
|
|
brk_type = is_break(debvars[IDIAR].hv,virt, FROMDEBVARS);
|
|
#endif /* #ifdef _POWER_MP */
|
|
if (is_static_break(debvars[IDIAR].hv,virt)) {
|
|
er = E_static_break;
|
|
}
|
|
#ifdef _POWER_MP
|
|
else if (is_step_for_me(debvars[IDIAR].hv,virt,&step_id)) {
|
|
#else /* #ifdef _POWER_MP */
|
|
else if (is_step(debvars[IDIAR].hv,virt,&step_id, FROMDEBVARS)) {
|
|
#endif /* #ifdef _POWER_MP */
|
|
if (is_watch_step(&step_id))
|
|
er = W_step; /* must be a watch step trap */
|
|
else
|
|
if (is_brat_step(&step_id))
|
|
er = B_step; /* must be a brat step trap */
|
|
else
|
|
er = E_step; /* must be a step trap */
|
|
}
|
|
else if (brk_type > 0)
|
|
er = E_break; /* breakpoint */
|
|
#ifdef _POWER_MP
|
|
else if (is_step(debvars[IDIAR].hv,virt, &step_id, FROMDEBVARS)
|
|
||is_break(debvars[IDIAR].hv,virt, FROMDEBVARS))
|
|
er = E_break_not_for_me; /* step or break not for me */
|
|
#endif /* #ifdef _POWER_MP */
|
|
else {
|
|
#ifdef _POWER_MP
|
|
if(cp_selected_cpu == cpunb){ /* in debugger due to "cpu" */
|
|
if (__power_mp()){
|
|
er = E_selected_cpu;
|
|
return TRUE; /* so stay in debugger */
|
|
}
|
|
}
|
|
#endif /* #ifdef _POWER_MP */
|
|
er = 0; /* unknown */
|
|
return FALSE; /* return from debugger to kernel */
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: step_or_break
|
|
*
|
|
* FUNCTION: this routine processes a step, breakpoint or static breakpoint
|
|
* trap.
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
*
|
|
* RETURN VALUE: 0 is returned to the caller if you want to stay in the
|
|
* debugger else a 1 is returned which forces the debugger to return
|
|
* control and the next instruction is executed.
|
|
* NOTE: If you will be returning a 1 (TRUE), then you *must* call restore_info
|
|
* to restore the appropriate registers. The caller (db_main) doesn't
|
|
* do this for you.
|
|
*/
|
|
|
|
step_or_break()
|
|
{
|
|
ulong save_iar;
|
|
|
|
switch(er) {
|
|
#ifdef _POWER_MP
|
|
|
|
case E_break_not_for_me:
|
|
/* dont remove the step from step table, skip it */
|
|
if (new_step(TRUE,step_s1,FALSE)) {
|
|
restore_info(TRUE,NO_SET_BRATWATCH);
|
|
if (__power_mp()) /* have to prevent from resuming stopped cpus */
|
|
if (step_processing_level++ ==0)
|
|
hold_cpus_while_stepping();
|
|
return(1);
|
|
}
|
|
else
|
|
{
|
|
er = E_nostep; /* no place to step */
|
|
}
|
|
break;
|
|
#endif /* #ifdef _POWER_MP */
|
|
|
|
case E_step:
|
|
#ifdef _POWER_MP
|
|
if (__power_mp())
|
|
if (step_processing_level > 0)
|
|
step_processing_level--;
|
|
#endif /* #ifdef _POWER_MP */
|
|
remove_this_step(step_id); /* make step inactive*/
|
|
if (is_continue(step_id)) { /* single step b/f go */
|
|
if (brk_type == 0) {/* resume execution */
|
|
#ifdef _POWER_MP /* have to resume stopped cpus */
|
|
if (__power_mp())
|
|
db_resume_others();
|
|
#endif /* #ifdef _POWER_MP */
|
|
restore_info(TRUE,SET_BRATWATCH);
|
|
return(1);
|
|
}
|
|
}
|
|
else { /* single or multi-step */
|
|
step_count--;
|
|
if (step_count > 0) { /* step more if cnt > 0 */
|
|
if (new_step(FALSE,step_s1,FALSE)) {
|
|
#ifdef _POWER_MP /* prevents from resuming stopped cpus */
|
|
if (__power_mp())
|
|
if (step_processing_level++ ==0)
|
|
hold_cpus_while_stepping();
|
|
#endif /* #ifdef _POWER_MP */
|
|
restore_info(TRUE,NO_SET_BRATWATCH);
|
|
return(1);
|
|
}
|
|
else
|
|
er = E_nostep; /* no place to step */
|
|
}
|
|
}
|
|
break;
|
|
|
|
case W_step:
|
|
remove_this_step(step_id); /* make step inactive*/
|
|
restore_info(TRUE,SET_BRATWATCH);
|
|
return(1);
|
|
break;
|
|
|
|
case B_step:
|
|
/* modify to remove two step points */
|
|
remove_this_step(step_id); /* make step inactive*/
|
|
restore_info(TRUE,SET_BRATWATCH);
|
|
return(1);
|
|
break;
|
|
|
|
case B_break:
|
|
/* No matter whether we want to show this branch to the user */
|
|
/* or not, we need to set a step point so that we can turn */
|
|
/* off the brat/watch points, let this instruction run, then */
|
|
/* turn them back on again. */
|
|
if (!new_step(TRUE,FALSE,TRUE)) /* If we can't set step pt, */
|
|
return FALSE; /* we must drop into debug. */
|
|
/* check if branch will be taken */
|
|
if (branch_taken(debvars[IDIAR].hv)) {
|
|
/* If the segid for the current address matches the */
|
|
/* brat segid, then show this IA breakpoint. Note */
|
|
/* that the instruction translation bit controls */
|
|
/* whether we treat the current address as real or */
|
|
/* virtual. */
|
|
if (getaprsegid(brat_data.addr,INSTT_BIT) ==
|
|
brat_data.segid)
|
|
/* This is a brat point we want to show. */
|
|
return(FALSE); /* enter debugger */
|
|
} /* if (branch_taken()) */
|
|
/* Otherwise, we don't want to show this branch. Go ahead */
|
|
/* and run the next instruction - the step point set above */
|
|
/* will give control back to us afterwards. */
|
|
restore_info(FALSE,NO_SET_BRATWATCH);
|
|
return(TRUE);
|
|
break;
|
|
|
|
case W_break:
|
|
/* No matter whether we want to show this opcode to the user */
|
|
/* or not, we need to set a step point so that we can turn */
|
|
/* off the brat/watch points, let this instruction run, then */
|
|
/* turn them back on again. */
|
|
if (!new_step(TRUE,FALSE,TRUE)) /* If we can't set step pt, */
|
|
return FALSE; /* we must drop into debug. */
|
|
/* If the segid for the current address doesn't match the */
|
|
/* segid, then ignore this DA breakpoint. Note that the */
|
|
/* data translation bit controls whether we treat the */
|
|
/* current address as real or virtual. */
|
|
if (getaprsegid(watch_data.addr,DATAT_BIT) != watch_data.segid)
|
|
{
|
|
restore_info(FALSE,NO_SET_BRATWATCH);
|
|
return(TRUE);
|
|
}
|
|
/* Otherwise, this is a watch point we want to show. */
|
|
return(FALSE); /* enter debugger */
|
|
break;
|
|
|
|
case E_break:
|
|
if (brk_type == TRACEPT) { /* a trace breakpoint */
|
|
if (new_step(TRUE,step_s1,FALSE)) { /* step 1 if possible */
|
|
#ifdef _POWER_MP /* prevents from resuming stopped cpus */
|
|
if (__power_mp())
|
|
if (step_processing_level++ ==0)
|
|
hold_cpus_while_stepping();
|
|
#endif /* #ifdef _POWER_MP */
|
|
restore_info(TRUE,NO_SET_BRATWATCH);
|
|
return(1);
|
|
}
|
|
er = E_nostep;
|
|
}
|
|
else {
|
|
if (brk_type == LOOP) { /* check for loop */
|
|
loop_count--;
|
|
if (loop_count>0) { /* looping */
|
|
if (new_step(TRUE,step_s1,FALSE)) {
|
|
#ifdef _POWER_MP /* eventually allows to resume stopped cpus */
|
|
if (__power_mp())
|
|
if (step_processing_level++ ==0)
|
|
hold_cpus_while_stepping();
|
|
#endif /* #ifdef ... */
|
|
restore_info(TRUE,NO_SET_BRATWATCH);
|
|
return(1);
|
|
}
|
|
}
|
|
}
|
|
at_breakpoint = TRUE;
|
|
}
|
|
break;
|
|
|
|
case E_static_break:
|
|
at_breakpoint = TRUE;
|
|
if (debug_init) /* get past trap if initialization failed */
|
|
debvars[IDIAR].hv += sizeof(INSTSIZ); /* instr len */
|
|
} /* end of switch */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: first_screen
|
|
*
|
|
* FUNCTION: this routine determines the termianl type and displays the first
|
|
* debugger screen
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
*
|
|
* RETURN VALUE: 0 for ok, -1 if can't open port.
|
|
*
|
|
*/
|
|
|
|
first_screen()
|
|
{
|
|
int ttynum, rc;
|
|
ulong orig_dbterm = dbterm;
|
|
|
|
if(!dbterm) { /* first time in debugger */
|
|
#ifdef _SNOOPY
|
|
if (__snoopy())
|
|
dbterm= USE_TTY;
|
|
else
|
|
#endif /* #ifdef _SNOOPY */
|
|
for(ttynum=0;(rc=d_ttyopen(ttynum)) != -1;ttynum++) {
|
|
if(rc>0) {
|
|
dbterm = USE_TTY | ttynum ; /*found a port*/
|
|
break;
|
|
}
|
|
}
|
|
if(!dbterm) /* we didn't find any ttys to open */
|
|
return -1;
|
|
}
|
|
else {
|
|
if (dbterm & USE_TTY) { /* async terminal is in use */
|
|
#ifdef _SNOOPY
|
|
if (__snoopy()){
|
|
/* nothing */
|
|
}
|
|
else
|
|
#endif /* #ifdef _SNOOPY */
|
|
if(d_ttyopen(dbterm & TTY_PORT)<=0){ /* open port */
|
|
return -1; /* big trouble,we obviously */
|
|
} /* opened this before */
|
|
}
|
|
}
|
|
restore_cntl = !(dbterm & USE_TTY); /* allow restore if not 3101 */
|
|
|
|
/* if screen isn't active, clear the screen anyway */
|
|
if (screen_on) {
|
|
parse_out.num_tok = 0; /* initialize parser struct */
|
|
debug_screen(&parse_out,DEFLTSCR); /* debugger display */
|
|
}
|
|
else
|
|
clrdsp();
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* NAME: process_cmd
|
|
*
|
|
* FUNCTION: this routine is the main line command processing part of the
|
|
* debugger. The command is read in and then sent off to be processed
|
|
* by driver. The only way to exit this routine is via the quit, step
|
|
* or go commands.
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
*
|
|
* RETURN VALUE: value returned from driver(). The only significant value
|
|
* is one indicating kernel should take a dump. To exit the while
|
|
* loop a called routine must return a non-zero value.
|
|
*
|
|
*/
|
|
|
|
process_cmd()
|
|
{
|
|
int retval=0;
|
|
|
|
do {
|
|
in_string = getterm();
|
|
cmd = get_cmd(in_string, &parse_out);
|
|
if (cmd != INVALID_ID) {
|
|
if (cmd == DITTO_ID)
|
|
cmd = get_cmd(old_string, &parse_out);
|
|
else
|
|
strcpy(old_string, in_string);
|
|
|
|
retval = driver(cmd, &parse_out);
|
|
}
|
|
} while (!retval);
|
|
return(retval);
|
|
}
|
|
|
|
/*
|
|
* NAME: restore_info
|
|
*
|
|
* FUNCTION: this routine restores the information from the debuggers
|
|
* local mst save area into the mst save area and into the segment
|
|
* registers.
|
|
*
|
|
* PARAMETERS: no_user - flag passed to rest_disp() - currently unused
|
|
* bratwatch - flag that determines whether the IABR/DABR should
|
|
* be set from the brat/watch data areas.
|
|
*
|
|
* RETURN VALUE: 0 is always returned by this routine.
|
|
*
|
|
*/
|
|
restore_info(no_user,bratwatch)
|
|
char no_user;
|
|
int bratwatch;
|
|
{
|
|
register int i;
|
|
|
|
/* restore breakpoints then bratpoints the watchpoints as necessary */
|
|
set_breakpoint_traps(debvars[IDIAR].hv); /* set breaks */
|
|
|
|
/* if requested, check the watch and brat data areas to see if the */
|
|
/* watch and/or brat registers need to be set. */
|
|
if (bratwatch == SET_BRATWATCH) {
|
|
if (watch_data.active) set_watch_regs();
|
|
if (brat_data.active) set_brat_regs();
|
|
}
|
|
for (i=0; i<NUMGPRS; i++) { /* restore info back to mst save area */
|
|
mst->gpr[i] = debvars[IDGPRS+i].hv;
|
|
mst->fpr[i] = fr[i];
|
|
if (i<NUMSEGS) {
|
|
mst->as.srval[i] = debvars[IDSEGS+i].hv;
|
|
}
|
|
}
|
|
|
|
#ifdef _POWER_PC
|
|
/* put the BATs back in the mst. */
|
|
if (__power_pc() && !__power_601()) {
|
|
/* Any BAT modifications will have changed the allocation
|
|
mask as well so just restore the current BAT values
|
|
to the mst. */
|
|
for (i=0; i < NUM_KERNEL_BATS; i++) {
|
|
mst->dbats[i].batu = debvars[IDBATU+i].hv;
|
|
mst->dbats[i].batl = debvars[IDBATL+i].hv;
|
|
}
|
|
/* put allocation mask back in the mst */
|
|
mst->ioalloc = ioalloc;
|
|
}
|
|
#endif /* #ifdef _POWER_PC */
|
|
|
|
mst->iar = debvars[IDIAR].hv;
|
|
mst->msr = debvars[IDMSR].hv;
|
|
mst->cr = debvars[IDCR].hv;
|
|
mst->lr = debvars[IDLR].hv;
|
|
mst->ctr = debvars[IDCTR].hv;
|
|
mst->xer = debvars[IDXER].hv;
|
|
mst->fpscr = debvars[IDFPSCR].hv;
|
|
mst->mq = debvars[IDMQ].hv;
|
|
mst->tid = debvars[IDTID].hv;
|
|
ppda_ptr=ppda;
|
|
ppda_ptr->dsisr=debvars[IDDSISR].hv;
|
|
ppda_ptr->dar = debvars[IDDAR].hv;
|
|
|
|
#if defined (_POWER_RS1) || defined(_POWER_RSC)
|
|
if ( __power_rs1() || __power_rsc() ) {
|
|
mteim(debvars[IDEIM0].hv, debvars[IDEIM1].hv);
|
|
mteis(debvars[IDEIS0].hv, debvars[IDEIS1].hv);
|
|
}
|
|
#endif /* #if defined (_POWER_RS1) || ... */
|
|
|
|
#if defined (_POWER_RS2)
|
|
if ( __power_rs2() ) {
|
|
update_peis();
|
|
}
|
|
#endif /* #if defined (_POWER_RS2) */
|
|
|
|
|
|
#ifdef _POWER_RS
|
|
/* SDR0 only exists on the RS boxes. It isn't on any 6xx box. */
|
|
if (__power_rs()) {
|
|
mtsdr0(debvars[IDSDR0].hv);
|
|
}
|
|
#endif /* #ifdef _POWER_RS */
|
|
mtsdr1(debvars[IDSDR1].hv);
|
|
|
|
if ( ! __power_mp() ) {
|
|
#ifdef _POWER_PC
|
|
/* check if we have a 603/604 (time base) or 601 (rtc) */
|
|
if (__power_pc() && !__power_601())
|
|
{
|
|
db_mttbu(debvars[IDTBU].hv);
|
|
db_mttbl(debvars[IDTBL].hv);
|
|
}
|
|
else
|
|
#endif /* #ifdef _POWER_PC */
|
|
/* on 601 or regular POWER architecture use real time counter */
|
|
{
|
|
mtrtcu(debvars[IDRTCU].hv);
|
|
mtrtcl(debvars[IDRTCL].hv);
|
|
}
|
|
}
|
|
mtdec(debvars[IDDEC].hv);
|
|
|
|
rest_disp(no_user);
|
|
|
|
/* restore state (i.e. seg regs) to the way it was on entry */
|
|
for(i=0;i<NUMSEGS;i++)
|
|
mtsr(i,sr_on_entry[i]);
|
|
|
|
return(0);
|
|
}
|
|
|
|
#if defined (_POWER_RS2)
|
|
/*
|
|
* NAME: update_peis
|
|
*
|
|
* FUNCTION: Update peis0 and peis1 according to value specified by
|
|
* user. If values were not changed, use original values
|
|
* saved on entry to the debugger.
|
|
*
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
*/
|
|
|
|
update_peis()
|
|
{
|
|
if( __power_rs2() ) {
|
|
|
|
int i;
|
|
ulong mask;
|
|
|
|
if (debvars[IDPEIS0].hv)
|
|
for (i=0; i<32; i++) {
|
|
mask = ((ulong)(0x80000000) >> i);
|
|
if (debvars[IDPEIS0].hv & mask)
|
|
db_rs2peis_set(i);
|
|
} /* end for loop */
|
|
|
|
if (debvars[IDPEIS1].hv)
|
|
for (i=0; i<32; i++) {
|
|
mask = ((ulong)(0x80000000) >> i);
|
|
if (debvars[IDPEIS1].hv & mask)
|
|
db_rs2peis_set(i+32);
|
|
} /* end for loop */
|
|
|
|
}
|
|
|
|
}
|
|
#endif /* #if defined (_POWER_RS2) */
|
|
|
|
|
|
|
|
/*
|
|
* NAME: rest_disp
|
|
*
|
|
* FUNCTION: this routine restores the display info
|
|
*
|
|
* PARAMETERS: all data areas used are global
|
|
*
|
|
* RETURN VALUE: 0 is always returned by this routine.
|
|
*
|
|
*/
|
|
|
|
rest_disp(no_user)
|
|
char no_user;
|
|
{
|
|
|
|
if ((dbterm & USE_TTY) || no_user) {
|
|
if (dbterm & USE_TTY) {
|
|
#ifdef _SNOOPY
|
|
if (__snoopy()){
|
|
/* nothing */
|
|
}
|
|
else
|
|
#endif /* #ifdef _SNOOPY */
|
|
d_ttyclose(dbterm & TTY_PORT); /* close port */
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* Name: tell_reason()
|
|
*
|
|
* This is a debugger routine that displays a message giving the
|
|
* reason that the debugger was entered.
|
|
*
|
|
* Parameters on entry:
|
|
* int reason_code; Indicates message to be displayed;
|
|
* see dbg_codes.h
|
|
* int parm; Parameter for message, if applicable.
|
|
*
|
|
* Returns:
|
|
* Nothing.
|
|
*
|
|
*/
|
|
|
|
void tell_reason(reason_code,parm)
|
|
int reason_code; /* Message index */
|
|
int parm; /* Optional parameter for message */
|
|
{
|
|
char *p;
|
|
int parm2;
|
|
|
|
switch (reason_code) {
|
|
case DBG_FPEN:
|
|
p = DBG_FPEN_MSG;
|
|
break;
|
|
case DBG_INVAL:
|
|
p = DBG_INVAL_MSG;
|
|
break;
|
|
case DBG_PRIV:
|
|
p = DBG_PRIV_MSG;
|
|
break;
|
|
case DBG_TRAP:
|
|
p = DBG_TRAP_MSG;
|
|
break;
|
|
case DBG_UNK_PR:
|
|
p = DBG_UNK_PR_MSG;
|
|
break;
|
|
case DBG_MCHECK:
|
|
p = DBG_MCHECK_MSG;
|
|
break;
|
|
case DBG_SYSRES:
|
|
p = DBG_SYSRES_MSG;
|
|
break;
|
|
case DBG_ALIGN:
|
|
p = DBG_ALIGN_MSG;
|
|
break;
|
|
case DBG_VM:
|
|
p = DBG_VM_MSG;
|
|
break;
|
|
case DBG_KBD:
|
|
p = DBG_KBD_MSG;
|
|
break;
|
|
case DBG_RECURSE:
|
|
p = DBG_RECURSE_MSG;
|
|
break;
|
|
case DBG_PANIC:
|
|
p = DBG_PANIC_MSG;
|
|
break;
|
|
case DBG_KBD_NORMAL:
|
|
p = DBG_KBD_NORMAL_MSG;
|
|
break;
|
|
case DBG_KBD_SECURE:
|
|
p = DBG_KBD_SECURE_MSG;
|
|
break;
|
|
case DBG_KBD_SERVICE:
|
|
p = DBG_KBD_SERVICE_MSG;
|
|
break;
|
|
case DBG_KBD_SERVICE1:
|
|
p = DBG_KBD_SERVICE1_MSG;
|
|
break;
|
|
case DBG_KBD_SERVICE2:
|
|
p = DBG_KBD_SERVICE2_MSG;
|
|
break;
|
|
case DBG_KBD_SERVICE4:
|
|
p = DBG_KBD_SERVICE4_MSG;
|
|
break;
|
|
case DBG_DSI_IOCC:
|
|
p = DBG_DSI_IOCC_MSG;
|
|
break;
|
|
case DBG_DSI_SLA:
|
|
p = DBG_DSI_SLA_MSG;
|
|
break;
|
|
case DBG_DSI_SCU:
|
|
p = DBG_DSI_SCU_MSG;
|
|
break;
|
|
case DBG_DSI_PROC:
|
|
p = DBG_DSI_PROC_MSG;
|
|
break;
|
|
case DBG_DSI_SGA:
|
|
p = DBG_DSI_SGA_MSG;
|
|
break;
|
|
case DBG_ISI_PROC:
|
|
p = DBG_ISI_PROC_MSG;
|
|
break;
|
|
case DBG_EXT_DMA:
|
|
p = DBG_EXT_DMA_MSG;
|
|
break;
|
|
case DBG_EXT_SCR:
|
|
p = DBG_EXT_SCR_MSG;
|
|
break;
|
|
case DBG_FPT_UN:
|
|
p = DBG_FPT_UN_MSG;
|
|
break;
|
|
case DBG_HTRAP:
|
|
p = DBG_HTRAP_MSG;
|
|
break;
|
|
case DBG_KBDEXT:
|
|
p = DBG_KBDEXT_MSG;
|
|
break;
|
|
case DBG_BUS_TIMEOUT:
|
|
p = DBG_BUS_TIMEOUT_MSG;
|
|
break;
|
|
case DBG_CHAN_CHECK:
|
|
p = DBG_CHAN_CHECK_MSG;
|
|
break;
|
|
case DBG_BTARGET:
|
|
p = DBG_BTARGET_MSG;
|
|
break;
|
|
case DBG_WATCH:
|
|
p = DBG_WATCH_MSG;
|
|
break;
|
|
#ifdef _POWER_MP
|
|
case DBG_MPC_STOP:
|
|
p = DBG_MPC_STOP_MSG;
|
|
break;
|
|
#endif /* #ifdef _POWER_MP */
|
|
default:
|
|
p = "Debugger entered for unknown reason. %d %d";
|
|
parm2 = parm;
|
|
parm = reason_code;
|
|
break;
|
|
}
|
|
|
|
if (panicstr != NULL)
|
|
p = panicstr;
|
|
|
|
printf(p,parm,parm2);
|
|
printf("\n");
|
|
}
|
|
|
|
/*
|
|
* NAME: in_real_mem
|
|
*
|
|
* FUNCTION: Determine if real memory address is valid.
|
|
*
|
|
* RETURNS: 0 if address is not in real memory
|
|
* 1 if address is in real memory
|
|
*/
|
|
|
|
int
|
|
in_real_mem (real_address)
|
|
ulong real_address;
|
|
{
|
|
|
|
int pno,bit,word,get_ptr,ptr,last_byte;
|
|
|
|
#ifdef _RS6K_UP_MCA
|
|
if ( __rs6k_up_mca() ) {
|
|
if ((real_address >= 0xff000000) &&
|
|
(real_address <= 0xffffffff))
|
|
return (1);
|
|
}
|
|
#endif /* #ifdef _RS6K_UP_MCA */
|
|
|
|
|
|
/*
|
|
* extract page number from real address and pass this to db_isbad()
|
|
*/
|
|
pno= (real_address >> 12) & 0x0000ffff;
|
|
|
|
/*
|
|
* get pointer to word in ram bit map
|
|
*/
|
|
bit = (pno * PSIZE) / db_vp.rmapblk;
|
|
word = bit/32;
|
|
ptr = (db_vp.rmapptr & SOFFSET) + (4*word);
|
|
/*
|
|
* get pointer to last address of ram bit map
|
|
*/
|
|
last_byte = (db_vp.rmapptr & SOFFSET) + (db_vp.rmapsize*4);
|
|
|
|
if (ptr>last_byte) /* if out of range of ram bit map */
|
|
return(0); /* return false */
|
|
else {
|
|
get_ptr = realbyt(ptr,4); /* read a word from bitmap */
|
|
|
|
/*
|
|
* move bit to bit position 31 in word,
|
|
* mask and return it.
|
|
*/
|
|
bit = bit - word*32;
|
|
bit = (get_ptr >> (31 - bit)) & 0x1;
|
|
return(!bit);
|
|
}
|
|
}
|
|
|