/************************************************************* * File: pmon/main.c * Purpose: main module for PMON * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970217 Moved stuff from cmdtable.c into this module. Deleted * cmdtable.c. * 970303 trace_mode defined here. * 970303 Removed dup def for Bpt[] * 970307 EPI tools generates a bunch of #174 warnings - ignore * 970325 Changed def of "Pmon" to FTEXT, was FDATA. * 970401 Lots of stuff adding hwbpts * 970507 Added non-aligned word reads * 970527 Changed is_writeable to use bytes * 970910 Moved hostInit(6) to just before hostInit(4) * 970911 Fixed bug w sstep self branches. Added parens. * 971124 Changed DCACHEI in flush_cmd to DCACHE, needed for the 4011. * 971124 Don't print NVRAM: if no nvmsg. * 980320 Changed read_target and write_target CP0 C0_SR to use R_STATUS * 980320 write_target(XT_PC) fixed. v is arg3. Not arg2. * 980616 Switched from devinit to hostInit(8). * 980713 Added MIPSEB ifdef to read_target() (mips16 -EL disassembly). * 980831 Print "assumed" if CLKFREQ has been set explictly. */ #include #include #ifdef MIPSEB char endian[] = "EB"; #else char endian[] = "EL"; #endif int vflag; int cp1ok; U64 DBGREG[NREGS]; /* debugger's register value holder */ Ulong topClientMem; int pmlst,clilst; /* list of files opened by: PMON & client */ extern int *curlst; /* list of files opened by: current context */ Ulong initial_sr; unsigned long _filebase; char *client_av[MAX_AC]; Ulong hostType; int iflush_needed,dflush_needed; int icache_size; int dcache_size; int icache_line_size; int dcache_line_size; int trace_mode; int trace_count; int trace_verbose; int trace_invalid; int trace_over; int trace_bflag; int trace_cflag; int mode_64bit; Func *c_exception_ptr, *asm_exception_ptr; extern char *regs_sw[]; BrkList brkList[MAX_BPT]; char *bptype_names[] = {"inv","pc","data","itmp","trace","nonrt"}; #ifndef PROMPT #define PROMPT "PMON> " #endif #ifndef DLECHO #define DLECHO "off" #endif #ifndef DLPROTO #define DLPROTO "none" #endif #ifndef HOSTPORT #define HOSTPORT "tty0" #endif #ifndef ETHERHWADDR #define ETHERHWADDR "aa:bb:cc:00:00:00" #endif #ifndef ETHERIPADDR #define ETHERIPADDR "71.0.0.211" #endif int do_diagsw(); EnvRec envlist[] = { {"dlecho",DLECHO,"off on lfeed"}, {"dlproto",DLPROTO,"none XonXoff EtxAck"}, {"hostport",HOSTPORT}, {"prompt",PROMPT}, #ifdef ETHERNET {"etheraddr",ETHERHWADDR}, {"ipaddr",ETHERIPADDR}, #endif {"heaptop"}, {"diag","0","N[:dev]",do_diagsw}, {"clkfreq"}, {0}}; int sdump(),transp(),memtst(),call(),stty(); int flush_cmd(); #if 0 /* not working yet */ int hdb_cmd(); extern Optdesc hdb_opts[]; #endif extern Optdesc load_opts[]; extern Optdesc stty_opts[]; extern Optdesc mt_opts[]; extern Optdesc call_opts[]; extern Optdesc tr_opts[]; extern Optdesc sdump_opts[]; extern Optdesc flush_opts[]; CmdRec cmdlist[] = { {"stty",stty_opts,stty}, {"tr",tr_opts,transp}, {"load",load_opts,load}, {"dump",sdump_opts,sdump}, {"mt",mt_opts,memtst}, {"call",call_opts,call}, {"flush",flush_opts,flush_cmd}, #if 0 /* not working yet */ {"hdb",hdb_opts,hdb_cmd}, #endif {0}}; Ulong specialRead(); int bptReq(Ulong addr,Ulong v); /************************************************************* * pmoninit(adr) * Called from mips.s after caches have been flushed * Executed from cacheable space * o Identifies CPU type (inits cp2 if necessary) * o Sets initial SR value * o Inits devices, command history mechanism, and environment vars * o Checks for NVRAM present * o Prints banner * o Inits breakpoint variables * Returns control to mips.s */ pmoninit(adr) char *adr; { int i,c,n,nlcnt,memsize; char ch,buf[80],nvmsg[40]; initial_sr = mfc0(C0_SR); Status = mkRV(initial_sr); hostInit(8); /* install basic devices */ #ifdef AUTOCONSOLE /* * A (so far) unsuccessful attempt to scan all devices to * assign the console device. */ for (;;) { nlcnt = 0; write(1,"B",1); ioctl(0,FIONREAD,&n); if (n) { for (i=0;i<1000000;i++) { ioctl(0,FIONREAD,&n); for (;n>0;n--) { read(0,&ch,1); if (ch == '\n') nlcnt++; } if (nlcnt >= 2) break; } } if (nlcnt >= 2) break; rotateCfgTbl(); devinit(); } #endif moninit(); for (i=0;cmdlist[i].name;i++) addCmdRec(&cmdlist[i]); for (i=0;envlist[i].name;i++) addEnvRec(&envlist[i]); for (i=0;i>2]); xstop(epc,wasbda); } else if (trace_mode == TRACE_SG) { trace_mode = TRACE_GB; brkInstall(1); /* std */ } else if (!is_bpt(epc)) xstop(epc,wasbda); else { trace_mode = TRACE_GB; brkInstall(1); /* std */ } flush_cache(ICACHE); _go(); } /************************************************************* */ xstop(epc,wasbda) Ulong epc; int wasbda; { brkDelete(3); /* itmp */ if (gdbmode) gdbstop((wasbda)?3:1); if (xvwmode) { /* This exact string is expected by xvw - do not edit! */ printf("!503!undefined breakpoint at %08x\n",epc); } stop(0); } #if 0 /************************************************************* * exception() * An exception has been generated within the client. * Control is passed here from _exception in mips.s */ exception() { U64 epc,cause,inst; int flag,type; if (verbose) fprintf(dfp,"stopped\n"); epc = getPc(); cause = read_target(XT_CP0,C0_CAUSE).lo; type = brkRemove(epc); inst = read_target32(epc); if (verbose) printf("\nException Epc=%08x Cause=%08x(%s) type=%d(%s)\n", epc,cause,getexcname(cause&CAUSE_EXCMASK),type,bptype_names[type]); switch (type) { case BPTYPE_TRACE : if (gdbmode) gdbstop(2); printf("trace_mode=%d\n",trace_mode); if (trace_mode == TRACE_TG) trace_mode = TRACE_GB; else if (trace_mode == TRACE_TB) stop(0); else if (trace_mode == TRACE_TN) { if (trace_count && --trace_count == 0) stop(0); flag=1; if (trace_bflag || trace_cflag) { if (is_branch(epc,inst) && trace_bflag) flag=1; else if (is_jal(epc,inst) && trace_cflag) flag=1; else flag=0; } if (flag) { addpchist(epc); if (trace_verbose) { disasm(prnbuf,epc,inst); printf("%s\n",prnbuf); } else dotik(256,1); } else dotik(256,1); } if (!setTrcbp(epc,trace_over)) stop(0); brkInstall(2); /* trace */ _go(); break; case BPTYPE_ITMP : brkDelete(3); /* itemp */ stop(0); break; case BPTYPE_DATA : /* should never happen */ case BPTYPE_PC : brkDelete(3); /* itemp */ if (gdbmode) gdbstop(1); if (xvwmode) { /* This exact string is expected by xvw - do not edit! */ printf("!503!undefined breakpoint at %08x\n",epc); stop(0); } if (getBpid() == -1) break; stop(0); break; default : #ifdef CROSSVIEW /* break 0x97: a0 1=getchar 2=putchar 3=reboot */ if ((cause&CAUSE_EXCMASK) == EXC_BP && (inst&0x03ffffc0)==0x970000) { switch (Gpr[4]) { case 1 : putGpr(2,getchar()); putPc(epc+4); break; case 2 : putchar(getGpr(5)); putPc(epc+4); break; case 3 : stop(0); } break; } #endif if ((cause&CAUSE_EXCMASK) == EXC_DBE) { if (getBpid() == -1) { if (!setTrcbp(epc,trace_over)) stop(0); brkInstall(2); /* trace */ trace_mode = TRACE_TG; _go(); } } else printf("Exception! EPC=%08x CAUSE=%08x(%s)\n", epc,cause,excodes[(cause&CAUSE_EXCMASK)>>2]); brkDelete(3); /* itemp */ stop(0); } brkInstall(1); /* regular */ _go(); } #endif /************************************************************* * U64 read_target(type,adr,sz) * Read from the target address space * All reads from target memory should come through here * adr The address you want to read from * sz The size of the read operation (1, 2, or 4 bytes) */ U64 read_target(int type,Ulong adr,int sz) { Ulong v,save,cur; int reg; Ushort h0,h1; U64 rv; rv.flags = 0; reg = adr; switch (type) { case XT_MEM : #if 0 if (read_target_mem_ptr && (* read_target_mem_ptr)(adr,sz,&v)) return(v); switch (sz) { case 1 : return (*(Uchar *)(adr)); case 2 : return (*(Ushort *)(adr)); case 4 : return (*(Ulong *)(adr)); } #endif #ifdef LR64360 if (adr < (Ulong)M_DMACR) { /* special code for reading the IRAM */ switch (sz) { case 1 : cur = *((Ulong *)(adr&~3)); return (Uchar)((cur >> (24 - (adr&3)*8 ) ) &0xff); case 2 : cur = *((Ulong *)(adr&~3)); return (Ushort)((cur >> (16 - (adr&3)*8 ) ) &0xffff); case 4 : save = BIU; BIU = (save&~BIU_DS1) | BIU_IS1; v = read_Disolated(adr); BIU = save; return(v); } } #endif switch (sz) { case 1 : return mkRV(inb(adr)); case 2 : return mkRV(inh(adr)); case 4 : adr &= ~1; /* clear the LS bit */ if (adr&2) { h0 = read_target(type,adr,2).lo; h1 = read_target(type,adr+2,2).lo; #ifdef MIPSEB return(mkRV((h0<<16) | h1)); #else return(mkRV((h1<<16) | h0)); #endif } return mkRV(inw(adr)); } case XT_GPR : return Gpr[reg]; case XT_PC : return pcReg; case XT_CP0 : if (reg == C0_CAUSE) return DBGREG[R_CAUSE]; if (reg == C0_EPC) return DBGREG[R_PC]; if (reg == C0_SR) return DBGREG[R_STATUS]; return mkRV(mfc0(reg)); case XT_DBX : return mkRV(mfdbx(reg)); default : printf("%d: read_target: bad type\n",type); } return(rv); } /************************************************************* * write_target(type,adr,v,sz) * write to the target address space * All writes to target memory should come through here * adr The address you want to write to * v The value you want to write * sz The size of the write operation (1, 2, or 4 bytes) */ int write_target(int type,Ulong adr,U64 v,int sz) { Ulong save,cur; int reg; reg = adr; switch (type) { case XT_MEM : #ifdef LR64360 if (adr < (Ulong)M_DMACR) { /* special code for writing the IRAM */ switch (sz) { case 1 : cur = *((Ulong *)(adr&~3)); cur &= ~((Ulong)0xff << (24 - ((adr&3)*8)) ); cur |= (v << (24 - ((adr&3)*8)) ); *((Ulong *)(adr&~3)) = cur; return; case 2 : cur = *((Ulong *)(adr&~3)); cur &= ~((Ulong)0xffff << (16 - ((adr&3)*8)) ); cur |= (v << (16 - ((adr&3)*8)) ); *((Ulong *)(adr&~3)) = cur; return; case 4 : save = BIU; BIU = (save&~BIU_DS1) | BIU_IS1; write_Disolated(adr,v); BIU = save; return; } } #endif switch (sz) { case 1 : outb(adr,v.lo); break; case 2 : outh(adr,v.lo); break; case 4 : if (bptReq(adr,v.lo)) break; outw(adr,v.lo); break; } break; case XT_GPR : Gpr[reg] = v; break; case XT_PC : pcReg = v; break; case XT_CP0 : if (reg == C0_SR) DBGREG[R_STATUS] = v; else mtc0(reg,v); break; case XT_DBX : mtdbx(reg,v); break; default : printf("%d: write_target: bad type\n",type); } } /************************************************************* * swlst(lst) */ swlst(lst) int lst; { switch (lst) { case 1 : curlst = &pmlst; break; case 2 : curlst = &clilst; break; } } /************************************************************* * pmexception(epc,cause) * An exception has been generated within PMON */ pmexception(epc,cause) unsigned long epc,cause; { if (c_exception_ptr) (* c_exception_ptr)(); printf("\nException Epc=%08x Cause=%08x (%s)\n", epc,cause, getexcname(cause&CAUSE_EXCMASK)); monmain(); } /************************************************************* * int disp_Gprs(int n) DEF */ int disp_Gprs(int n) { int i,k,inc; char *fmt; U64 v; if (getGpr(0).flags&U64_64) mode_64bit = 1; if (mode_64bit) { inc = 4; fmt = " %~17s"; } else { inc = 8; fmt = " %~8s"; } for (i=k=0;i<32;i+=inc) { if (n==1) { printf(" "); for (k=i;k>= 1; } return(n); } /************************************************************* * Note: For Processors that have copy-back Dcaches, it's not ok * to DCACHEI once the sw is running from kseg0, because the the * Dcache will contain info that *must* be copied back to ram for * the program to execute correctly after the flush. */ Optdesc flush_opts[] = { {"","flush caches"}, {"-i","flush Icache only"}, {"-d","flush Dcache only"}, {0}}; flush_cmd(ac,av) int ac; char *av[]; { if (ac == 1) { flush_target(ICACHEI); flush_target(DCACHE); } else if (strequ(av[1],"-i")) flush_target(ICACHEI); else if (strequ(av[1],"-d")) flush_target(DCACHE); } #if 0 /* not working yet */ /************************************************************* * This an experimental command that would be used to allow the user to * explictly set hw data breakpoints. At present this is only available * via the 'when' command. */ Optdesc hdb_opts[] = { {"[-r|-w] addr[..addr] [value]","set hardware data breakpoint"}, {"-r","only break on reads"}, {"-w","only break on writes"}, {0}}; hdb_cmd(ac,av) int ac; char *av[]; { int type,cnt,n,i; Ulong addr1,addr2,value; char *p,tmp[80]; char *strstr(); if (ac == 1) { usage: printf("usage: hdb [-r|-w] addr[..addr] [value]\n"); return; } type = 0x30; for (cnt=0,i=1;i= MAX_BPT) { printf("%d: bad bpt number\n",n); return(0); } if (brkList[n].type==0) { printf("%d: bpt is not set\n",n); return(0); } brkList[n].type = 0; return(1); } /************************************************************* */ int which_bpt(addr) Ulong addr; { int i; for (i=0;i1) fprintf(dfp,"setbp_target(%d,%d,%08x,%08x,%08x)\n", n,type,addr,addr2,value); return (* setbp_target_ptr)(n,type,addr,addr2,value); } /************************************************************* */ int brkInstall(type) int type; { if (!brkInstall_ptr) return(-1); return (* brkInstall_ptr)(type); } /************************************************************* */ int brkRemove(epc) Ulong epc; { if (!brkRemove_ptr) return(0); return (* brkRemove_ptr)(epc); } /************************************************************* * stubs */ niceExit() { /* should never be called */ } #define outw(a,v) (*((volatile Ulong *)(a))=(v)) #define LED_BASE 0xbe000020 int ledval[] = { (1|2|4|8|0x10|0x20), /* 0 */ (2|4), /* 1 */ (1|2|0x40|8|0x10), /* 2 */ (1|2|4|8|0x40), /* 3 */ (2|4|0x40|0x20), /* 4 */ (1|4|8|0x40|0x20), /* 5 */ (1|4|8|0x10|0x20|0x40), /* 6 */ (1|2|4), /* 7 */ (1|2|4|8|0x10|0x20|0x40), /* 8 */ (1|2|4|8|0x20|0x40), /* 9 */ (1|2|4|0x10|0x20|0x40), /* A */ (4|8|0x10|0x20|0x40), /* B */ (1|8|0x10|0x20), /* C */ (2|4|8|0x10|0x40), /* D */ (1|8|0x10|0x20|0x40), /* E */ (1|0x10|0x20|0x40) /* F */ };