📄 machdep.c
字号:
#ident "@(#)machdep.c 1.1 92/07/30"/* * Copyright (c) 1986 by Sun Microsystems, Inc. */#include <sys/param.h>#include <sys/errno.h>#include <sys/vmmac.h>#include <sun/openprom.h>#include <machine/buserr.h>#include <machine/enable.h>#include <machine/mmu.h>#include <machine/cpu.h>#include <machine/pte.h>#include <machine/scb.h>#include <machine/psl.h>#include <machine/trap.h>#include <machine/clock.h>#include <machine/intreg.h>#include <machine/eeprom.h>#include <machine/asm_linkage.h>#include <machine/reg.h>#include <machine/frame.h>#include "allregs.h"#include <debug/debug.h>#include <debug/debugger.h>extern int errno;extern char *malloc();int istrap = 0;int scbsyncdone = 0;/* * The next group of variables and routines handle the * Open Boot Prom devinfo or property information. * * These machine-dependent quantities are set from the prom properties. * For the time being, set these to "large, safe" values. * XXX - does this all want to be packaged in a header file? */extern void fiximp();extern int Cpudelay;extern int nwindows;extern u_int npmgrps;extern int vac_size;extern int vac_linesize;extern int segmask;extern int mips_off, mips_on; /* approx. MIPS with cache off/on *//* * properties tchotchkes */#define GETPROPLEN prom_getproplen#define GETPROP prom_getprop#define NEXT prom_nextnode#define CHILD prom_childnodeextern int getprop();/* * Open proms give us romp as a variable */struct sunromvec *romp = (struct sunromvec *)0xFFE81000;int fake_bpt; /* place for a fake breakpoint at startup */jmp_buf debugregs; /* context for debugger */jmp_buf mainregs; /* context for debuggee */jmp_buf_ptr curregs; /* pointer to saved context for each process */int cache_on; /* cache is being used */struct allregs regsave; /* temp save area--align to double */struct scb *mon_tbr, *our_tbr; /* storage for %tbr's */int use_kern_tbr = 0;extern char start[], estack[], etext[], edata[], end[];extern int exit();extern struct scb *gettbr();/* * Definitions for registers in jmp_buf */#define JB_PC 0#define JB_SP 1#define CALL(func) (*(int (*)())((int)(func) - (int)start + (int)real))#define RELOC(adr) ((adr) - (char *)start + real)extern setcontext(), getsegmap(), setsegmap(), getpgmap(), setpgmap();extern printf();void Setpgmap();/* * This routine is called before we are relocated to the correct address, * so everything is done via funny macros when dealing w/ globals. * Also, we have a candidate for "worst abuse of preprocessor" award: * MONSTART and MONEND are actually defined using romp, but _romp * isn't set yet. Call our sunromvec argument "romp" so that the global * variable is hidden in this function and the correct value is used. */early_startup(real, romp) register char *real; register struct sunromvec *romp;{ register u_int cnt, pg, i; register int *from, *to; register int pm, lopm; register int lastpmsav, lastpgsav; register struct memlist *pmem; caddr_t vstart; int too_big = 0; u_int npmgrps; /* yes, this hides the global too */ (void) CALL(setcontext)(0); /* * We need to know npmgrps so we can compute PMGRP_INVALID. * We'll do this again later for the real globals. * Alas! We can't just call getprop(), because the global romp * isn't even mapped in yet. We want to do this: * if ((int)CALL(getprop)(0, "mmu-npmg", &npmgrps) <= 0) * npmgrps = NPMGRPS_60; * but we have to do this: */ if ((*romp->op_config_ops->devr_getproplen) (0, RELOC("mmu-npmg")) == sizeof (int)) { (*romp->op_config_ops->devr_getprop) (0, RELOC("mmu-npmg"), &npmgrps); } else npmgrps = NPMGRPS_60; /* * Find the top of physical memory and take as many pages as we need. * We assume the physmem chunks are in ascending order and the last * chunk is big enough to hold us. (It actually doesn't matter if * the pages are in order; we handle that gracefully.) */ cnt = mmu_btopr(end - start); if (romp->op_romvec_version > 0) { vstart = (caddr_t)(*romp->op2_alloc)((int)start, mmu_ptob(cnt)); if ((u_int)vstart != (u_int)start) too_big = 1; } else { pmem = *romp->v_availmemory; while (pmem->next != (struct memlist *)NULL) pmem = pmem->next; pg = mmu_btopr(pmem->address + pmem->size) - cnt; if (mmu_ptob(cnt) > pmem->size) { too_big = 1; } else { too_big = 0; pmem->size -= mmu_ptob(cnt); } /* * Look for the lowest pmeg in use in the monitor * and "DVMA" space */ lopm = PMGRP_INVALID; for (i = MONSTART; i != 0; i += PMGRPSIZE) if (((pm = CALL(getsegmap)(i)) < lopm) && pm) lopm = pm; /* * Adjust down from there to get our starting pmeg * and save copies of last pmeg and page used. */ lopm -= ((unsigned)(end - start) + PMGRPOFFSET) >> PMGRPSHIFT; lastpmsav = lopm; lastpgsav = pg; for (i = (int)start; i < (int)end; i += MMU_PAGESIZE) { if (CALL(getsegmap)(i) == PMGRP_INVALID) { register u_int j = i & ~PMGRPOFFSET; u_int last = j + NPMENTPERPMGRP * MMU_PAGESIZE; (void) CALL(setsegmap)(i, lopm++); while (j < last) { (void) CALL(setpgmap)(j, 0); j += MMU_PAGESIZE; } } (void) CALL(setpgmap)(i, PG_V | PG_KW | PG_NC | pg++); } } /* * Copy program up to correct address */ for (to = (int *)start, from = (int *)real; to < (int *)edata; ) *to++ = *from++; for (to = (int *)edata; to < (int *)end; ++to) *to = 0; /* * Now we can reference global variables, * save page count and monitor's nmi routine address. * Don't need this information on OBP. */ if (romp->op_romvec_version > 0) { lastpg = 0; lastpm = 0; pagesused = 0; mon_tbr = gettbr(); if (too_big) { CALL(printf)( RELOC("kadb: size %x exceeded available memory\n"), mmu_ptob(cnt)); _exit(1); } } else { lastpg = lastpgsav; lastpm = lastpmsav; pagesused = cnt; mon_tbr = gettbr(); if (too_big) { CALL(printf)( RELOC( "kadb: size %x exceeded available memory %x\n"), mmu_ptob(cnt), pmem->size); _exit(1); } }}/* * Startup code after relocation. */startup(){ register int i; register int pg; u_char intreg; register int vaddr, pmeg; register int cpu; extern void prom_init(); prom_init("Kadb"); /* * Set our implementation parameters from the prom properties. */ fiximp(); if (prom_getversion() > 0) { vaddr = (int)(*romp->op2_map)(COUNTER_ADDR, OBIO, OBIO_COUNTER_ADDR, MMU_PAGESIZE); vaddr = (int)(*romp->op2_map)(INTREG_ADDR, OBIO, OBIO_INTREG_ADDR, MMU_PAGESIZE); } else { /* * We need to get a pmeg for the devices we are mapping in. * Assume the devices lie within the same segment. */ vaddr = EEPROM_ADDR & COUNTER_ADDR & INTREG_ADDR; pmeg = getsegmap(vaddr); if (pmeg == PMGRP_INVALID) { setsegmap(vaddr, --lastpm); } /* * Now map! Remember: on a sun4c, the clock is in the eeprom. */ Setpgmap((caddr_t)EEPROM_ADDR, PG_V|PG_KW|PGT_OBIO|btop(OBIO_EEPROM_ADDR)); Setpgmap((caddr_t)COUNTER_ADDR, PG_V|PG_KW|PGT_OBIO|btop(OBIO_COUNTER_ADDR)); Setpgmap((caddr_t)INTREG_ADDR, PG_V|PG_KW|PGT_OBIO|btop(OBIO_INTREG_ADDR)); } set_clk_mode(IR_ENA_CLK14, 0); /* * Fix up old scb. */ kadbscbsync(); spl13(); /* we can take nmi's now */ /* * Now make text (and dvec) read only, * this also sets a stack redzone */ for (i = (int)start; i < (int)etext; i += MMU_PAGESIZE) { pg = getpgmap(i); Setpgmap(i, (pg & ~PG_PROT) | PG_KR); } cache_on = getenablereg() & ENA_CACHE; if (cache_on) { setdelay(mips_on); } else { setdelay(mips_off); vac_init(); /* invalidate entire cache */ }}scbsync(){ kadbscbsync(); scbsyncdone = 1;}kadbscbsync(){ register struct scb *tbr; register int otbr_pg; extern trapvec tcode; tbr = gettbr(); otbr_pg = getpgmap(tbr); Setpgmap(tbr, (otbr_pg & ~PG_PROT) | PG_KW); tbr->user_trap[TRAPBRKNO-1] = tcode; tbr->user_trap[TRAPBRKNO] = tcode; Setpgmap(tbr, otbr_pg); if (scbstop) { /* * We're running interactively. Trap into the debugger * so the user can look around before continuing. * We use trap TRAPBRKNO-1: "enter debugger" */ scbstop = 0; asm_trap(TRAPBRKNO-1); }}/* * Sys_trap trap handlers. *//* * level15 (memory error) interrupt. */level15(){ /* * For now, the memory error regs are not mapped into the debugger, * so we just print a message. */ printf("memory error\n");}/* * Miscellanous fault error handler */fault(trap, trappc, trapnpc) register int trap; register int trappc; register int trapnpc;{ register int ondebug_stack; register u_int *pc; register u_int realpc; ondebug_stack = (getsp() > (int)etext && getsp() < (int)estack); if (trap == T_DATA_FAULT && nofault && ondebug_stack) { jmp_buf_ptr sav = nofault; nofault = NULL; _longjmp(sav, 1); /*NOTREACHED*/ } traceback(getsp()); /* * If we are on the debugger stack and * abort_jmp is set, do a longjmp to it. */ if (abort_jmp && ondebug_stack) { printf("abort jump: trap %x sp %x pc %x npc %x\n", trap, getsp(), trappc, trapnpc); printf("etext %x estack %x edata %x nofault %x\n", etext, estack, edata, nofault); _longjmp(abort_jmp, 1); /*NOTREACHED*/ } /* * Ok, the user faulted while not in the * debugger. Enter the main cmd loop * so that the user can look around... */ /* * There is a problem here since we really need to tell cmd() * the current registers. We would like to call cmd() in locore * but the interface is not really set up to handle this (yet?) */ printf("fault and calling cmd: trap %x sp %x pc %x npc %x\n", trap, getsp(), trappc, trapnpc); cmd(); /* error not resolved, enter debugger */}long trap_window[25];static jmp_buf_ptr saved_jb;static jmp_buf jb;extern int debugging;/* * Peekc is so named to avoid a naming conflict * with adb which has a variable named peekc */intPeekc(addr) char *addr;{ u_char val; saved_jb = nofault; nofault = jb; errno = 0; if (!_setjmp(jb)) { val = *addr; /* if we get here, it worked */ nofault = saved_jb; return ((int)val); } /* a fault occured */ nofault = saved_jb; errno = EFAULT; return (-1);}shortpeek(addr) short *addr;{ short val; saved_jb = nofault; nofault = jb; errno = 0; if (!_setjmp(jb)) { val = *addr; /* if we get here, it worked */ nofault = saved_jb; return (val); } /* a fault occured */ nofault = saved_jb; errno = EFAULT; return (-1);}longpeekl(addr) long *addr;{ long val; saved_jb = nofault; nofault = jb; errno = 0; if (!_setjmp(jb)) { val = *addr; /* if we get here, it worked */ nofault = saved_jb; return (val); } /* a fault occured */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -