📄 machdep.c
字号:
/* $Id: machdep.c,v 1.1.1.1 2003/11/08 08:41:42 wlin Exp $ *//* * Copyright (c) 2000 Opsycon AB (http://www.opsycon.se) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by * Opsycon Open System Consulting AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *//* * Pmon architecture dependent (and possibly cpu type dependent) code. */#include <stdio.h>#include <termio.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#ifdef _KERNEL#undef _KERNEL#include <sys/ioctl.h>#define _KERNEL#else#include <sys/ioctl.h>#endif#include <machine/cpu.h>#include <machine/frame.h>#include <machine/regnum.h>#include <machine/trap.h>#include <pmon.h>extern int memorysize;extern u_int8_t end[];#ifdef GODSONEV1extern int global_div_num;#endif/* * CPU type markers. */#define CPU_ALL 0x000f /* Belongs to mask */#define CPU_7 0x0001 /* RM7000 */#define CPU_5 0x0002 /* R5000 */#define CPU_GOD1 0x0004#define CPU_GOD2 0x0008#define CPU_41 0x0010 /* R4100 */#define F_FMT 0x1000 /* Field uses format */struct RegMap { char width; char bit; short flags; const char * const name; union { const char * const fmt;/* XXX Tell me why i must cast initializers for the next union? */ const char * const *vn; } fe;};static void dsp_rregs __P((int *));static void dsp_fregs __P((int *));static int cputype;/* * Return a ascii version of the processor type. */const char *md_cpuname(){/* XXX make more sophisticated dealing with rev numbers and 52x0 more precisely */ /* Handle the SandCraft SR71000 */ if (((md_cputype() >> 8) & 0xffff) == 0x0504) { cputype = CPU_7; return ("SR71000"); } switch((md_cputype() >> 8) & 0xff) { case MIPS_E9000: cputype = CPU_7; return("E9000"); case MIPS_RM7000: cputype = CPU_7; return("RM7000"); case MIPS_RM52X0: cputype = CPU_5; return("RM52x0"); case MIPS_GODSON2: cputype = CPU_GOD2; // ????????????? return("GODSON2"); case MIPS_GODSON1: cputype=CPU_GOD1; return("GODSON1"); default: return("unidentified"); }}/* * Dump out exception info for an unscheduled exception */voidmd_dumpexc(struct trapframe *tf){ int w = 100; printf("\r\nException Cause=%s, SR=%p, PC=%p\r\n", md_getexcname(tf), (int)md_getsr(tf), md_getpc(tf)); printf("CONTEXT=%llp, XCONTEXT=%llp\r\n", tf->context, tf->xcontext); printf("BADVADDR=%llp, ENTHI=%llp\r\n", tf->badvaddr, tf->enthi); printf("ENTLO0=%llp, ENTLO1=%llp\r\n\r\n", tf->entlo0, tf->entlo1); dsp_rregs(&w); printf("\r\n"); md_do_stacktrace(0, 0, 0, 0);}/* * Set PC to a new value. */voidmd_setpc(struct trapframe *tf, register_t pc){ if (tf == NULL) tf = cpuinfotab[whatcpu]; tf->pc = (int)pc;}/* * This function clears all client registers for launch. */voidmd_clreg(struct trapframe *tf){ if (tf == NULL) tf = cpuinfotab[whatcpu];// md_fpsave(tf);}/* * This function sets the client stack pointer. */voidmd_setsp(struct trapframe *tf, register_t sp){ if (tf == NULL) tf = cpuinfotab[whatcpu]; tf->sp = sp;}/* * This function sets the client sr to the given value. */voidmd_setsr(struct trapframe *tf, register_t sr){ if (tf == NULL) tf = cpuinfotab[whatcpu]; tf->sr = sr;}/* * This function returns the value of the clients sr. */register_tmd_getsr(struct trapframe *tf){ if (tf == NULL) tf = cpuinfotab[whatcpu]; return(tf->sr);}/* * This function sets the client sr to do a trace. */voidmd_settrace(){}/* * This function sets the client sr to do a trace. */voidmd_setlr(struct trapframe *tf, register_t lr){ if (tf == NULL) tf = cpuinfotab[whatcpu]; tf->ra = lr;}/* * This function returns true if the address range given is * invalid for load, eg will overwrite PMON or its working * areas or other protected memory areas or load into * existing memory. */intmd_valid_load_addr(first_addr, last_addr) paddr_t first_addr; paddr_t last_addr;{ first_addr = CACHED_TO_PHYS(first_addr); last_addr = CACHED_TO_PHYS(last_addr); if((first_addr < (paddr_t)CACHED_TO_PHYS(end)) || (last_addr > (paddr_t)memorysize)) { printf("first_addr 0x%x\tend 0x%x\tlast_addr 0x%x\tmemsize 0x%x\n",first_addr,(paddr_t)CACHED_TO_PHYS(end),last_addr,(paddr_t)memorysize); return(1); } return(0);} /* * This function sets the SP to the new value given if it's * non zero. The old value of sp is returned. */register_tmd_adjstack(struct trapframe *tf, register_t newsp){ register_t oldsp; if (tf == NULL) tf = cpuinfotab[whatcpu]; oldsp = tf->sp; if(newsp != 0) { tf->sp = newsp; } return(oldsp);}/* * This function sets the arguments to client code so * the client sees the arguments as if it was called * with the arguments. */voidmd_setargs(struct trapframe *tf, register_t a1, register_t a2, register_t a3, register_t a4){ if (tf == NULL) tf = cpuinfotab[whatcpu]; tf->a0 = a1; tf->a1 = a2; tf->a2 = a3; tf->a3 = a4;}voidmd_setentry(struct trapframe *tf, register_t pc){ if (tf == NULL) tf = cpuinfotab[whatcpu]; tf->pc = pc;}/* * This function returns the PC value that is supposed * to be used at restore to client state. Do not confuse * with the value of the exception PC. (Diff on some arches). */void *md_getpc(struct trapframe *tf){ if (tf == NULL) tf = cpuinfotab[whatcpu]; return((void *)(int)tf->pc);}/* * This function is called from exception(). It's purpose * is to decode the exception and return the exception * type to the caller for further processing. */intmd_exc_type(struct trapframe *frame){ switch((frame->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT) { case T_BREAK: case T_TRAP: return(EXC_BPT); case T_IWATCH: case T_DWATCH: return(EXC_WTCH); case T_RES_INST:#ifdef BONITOEL return(EXC_RES);#endif case T_INT: case T_TLB_MOD: case T_TLB_LD_MISS: case T_TLB_ST_MISS: case T_ADDR_ERR_LD: case T_ADDR_ERR_ST: case T_BUS_ERR_IFETCH: case T_BUS_ERR_LD_ST: case T_SYSCALL: case T_COP_UNUSABLE: case T_OVFLOW: case T_FPE: return(EXC_BAD); case T_VCEI: case T_VCED: return(EXC_BAD); } return(EXC_BAD);}/* * This function returns the value of the RA reg */register_tmd_getlink(struct trapframe *tf){ if (tf == NULL) tf = cpuinfotab[whatcpu]; return(tf->ra);}/* * This function returns a pointer from the value of the * PC reg when an exception have been taken. */void *md_get_excpc(struct trapframe *tf){ if (tf == NULL) tf = cpuinfotab[whatcpu]; return((void *)(int)tf->pc);}const char *md_getexcname(struct trapframe *tf){ switch((tf->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT) { case T_INT: return("interrupt pending"); case T_TLB_MOD: return("TLB modified"); case T_TLB_LD_MISS: return("TLB miss on load or ifetch"); case T_TLB_ST_MISS: return("TLB miss on store"); case T_ADDR_ERR_LD: return("address error on load or ifetch"); case T_ADDR_ERR_ST: return("address error on store"); case T_BUS_ERR_IFETCH: return("bus error on ifetch"); case T_BUS_ERR_LD_ST: return("bus error on load or store"); case T_SYSCALL: return("system call"); case T_BREAK: return("breakpoint"); case T_RES_INST: return("reserved instruction"); case T_COP_UNUSABLE: return("coprocessor unusable"); case T_OVFLOW: return("arithmetic overflow"); case T_TRAP: return("trap instruction"); case T_VCEI: return("virtual coherency instruction"); case T_FPE: return("floating point"); case T_IWATCH: return("iwatch"); case T_DWATCH: return("dwatch"); case T_VCED: return("virtual coherency data"); } return("exception unknown");}/* * ator returns either 32 bit or 64 bit conversion * depending on CPU word length. */intmd_ator(register_t *vp, char *p, int base){ if (sizeof(register_t)==4) return(atob(vp,p,base)); else#ifdef HAVE_QUAD return(llatob(vp, p, base));#else return(0);#endif}/* * Returns true and sets the location pointed by vp to the value * of the specified register or false if not recognized. Register * names can be n the form <regno> r<nr> or sp. * Some special registers are also detected. *//* * Floating point status register. */char * const rmvalues[] = { "rn", "rz", "rp", "rm", 0};const struct RegMap fsrmap[] = { {1, 24, CPU_ALL|F_FMT, "fs", {" %*b"}}, {1, 23, CPU_ALL|F_FMT, "c", {" %*b"}}, {1, 17, CPU_ALL|F_FMT, "ce", {" %*b"}}, {1, 16, CPU_ALL|F_FMT, "cv", {" %*b"}}, {1, 15, CPU_ALL|F_FMT, "cz", {" %*b"}}, {1, 14, CPU_ALL|F_FMT, "co", {" %*b"}}, {1, 13, CPU_ALL|F_FMT, "cu", {" %*b"}}, {1, 12, CPU_ALL|F_FMT, "ci", {" %*b"}}, {1, 11, CPU_ALL|F_FMT, "ev", {" %*b"}}, {1, 10, CPU_ALL|F_FMT, "ez", {" %*b"}}, {1, 9, CPU_ALL|F_FMT, "eo", {" %*b"}}, {1, 8, CPU_ALL|F_FMT, "eu", {" %*b"}}, {1, 7, CPU_ALL|F_FMT, "ei", {" %*b"}}, {1, 6, CPU_ALL|F_FMT, "fv", {" %*b"}}, {1, 5, CPU_ALL|F_FMT, "fz", {" %*b"}}, {1, 4, CPU_ALL|F_FMT, "fo", {" %*b"}}, {1, 3, CPU_ALL|F_FMT, "fu", {" %*b"}}, {1, 2, CPU_ALL|F_FMT, "fi", {" %*b"}}, {2, 0, CPU_ALL, "rm", {(const char * const)rmvalues}}, {0}};const char * const ksuvalues[] = { "kern", "supv", "user", "????", 0};const struct RegMap statmap[] = { {1, 31, CPU_5|CPU_7|F_FMT, "xx", {" %*b"}}, {4, 28, CPU_ALL|F_FMT, "cu", {" %*b"}}, {1, 27, CPU_ALL|F_FMT, "rp", {" %*b"}}, {1, 26, CPU_ALL|F_FMT, "fr", {" %*b"}}, {1, 25, CPU_ALL|F_FMT, "re", {" %*b"}}, {1, 24, CPU_ALL|F_FMT, "its", {" %*b"}}, {1, 22, CPU_ALL|F_FMT, "bev", {" %*b"}}, {1, 21, CPU_ALL|F_FMT, "ts", {" %*b"}}, {1, 20, CPU_ALL|F_FMT, "sr", {" %*b"}}, {1, 18, CPU_ALL|F_FMT, "ch", {" %*b"}}, {1, 17, CPU_ALL|F_FMT, "ce", {" %*b"}}, {1, 16, CPU_ALL|F_FMT, "de", {" %*b"}}, {8, 8, CPU_ALL|F_FMT, "im", {" %*b"}}, {1, 7, CPU_ALL|F_FMT, "kx", {" %*b"}}, {1, 6, CPU_ALL|F_FMT, "sx", {" %*b"}}, {1, 5, CPU_ALL|F_FMT, "ux", {" %*b"}}, {2, 3, CPU_ALL, "ksu", {(const char * const)ksuvalues}}, {1, 2, CPU_ALL|F_FMT, "erl", {" %*b"}}, {1, 1, CPU_ALL|F_FMT, "exl", {" %*b"}}, {1, 0, CPU_ALL|F_FMT, "ie", {" %*b"}}, {0}};const char * const excodes[] = { "Int", "MOD", "TLBL", "TLBS", "AdEL", "AdES", "IBE", "DBE", "Sys", "Bp", "RI", "CpU", "Ovf", "Trap", "VCEI", "FPE", "Cp2", "Resv", "Resv", "Resv", "Resv", "Resv", "Resv", "Wtch", "Resv", "Resv", "Resv", "Resv", "Resv", "Resv", "Resv", "VCED", 0};const struct RegMap causemap[] = { {1, 31, CPU_ALL|F_FMT, "bd", {" %*b"}}, {2, 28, CPU_ALL|F_FMT, "ce", {" %*d"}}, {1, 26, CPU_7|F_FMT, "w2", {" %*b"}}, {1, 25, CPU_7|F_FMT, "w1", {" %*b"}}, {1, 24, CPU_7|F_FMT, "iv", {" %*b"}}, {16, 8, CPU_7|F_FMT, "ipending", {" %*b"}}, {8, 8, (CPU_ALL&~CPU_7)|F_FMT, "ipending", {" %*b"}}, {4, 2, CPU_ALL, "excode", {(const char * const)excodes}}, {0}};/* RM7000 interrupt control register */const struct RegMap icrmap[] = { {8, 8, CPU_ALL|F_FMT, "im", {" %*b"}}, {1, 7, CPU_ALL|F_FMT, "te", {" %*b"}}, {5, 0, CPU_ALL|F_FMT, "vs", {" %*x"}}, {0}};const struct RegMap pridmap[] = { {8, 8, CPU_ALL|F_FMT, "imp", {" %*d"}}, {8, 0, CPU_ALL|F_FMT, "rev", {" %*d"}}, {0}};const char * const epvalues[] = { "DD", "DDx", "DDxx", "DxDx", "DDxxx", "DDxxxx", "DxxDxx", "DDxxxxx",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -