141475Smckusick /*
241475Smckusick * Copyright (c) 1988 University of Utah.
363472Sbostic * Copyright (c) 1982, 1986, 1990, 1993
463472Sbostic * The Regents of the University of California. All rights reserved.
541475Smckusick *
641475Smckusick * This code is derived from software contributed to Berkeley by
741475Smckusick * the Systems Programming Group of the University of Utah Computer
841475Smckusick * Science Department.
941475Smckusick *
1041475Smckusick * %sccs.include.redist.c%
1141475Smckusick *
1257344Shibler * from: Utah $Hdr: trap.c 1.37 92/12/20$
1341475Smckusick *
14*68359Scgd * @(#)trap.c 8.7 (Berkeley) 02/19/95
1541475Smckusick */
1641475Smckusick
1756508Sbostic #include <sys/param.h>
1856508Sbostic #include <sys/systm.h>
1956508Sbostic #include <sys/proc.h>
2056508Sbostic #include <sys/acct.h>
2156508Sbostic #include <sys/kernel.h>
2256508Sbostic #include <sys/signalvar.h>
2356508Sbostic #include <sys/resourcevar.h>
2456508Sbostic #include <sys/syscall.h>
2556508Sbostic #include <sys/syslog.h>
2656508Sbostic #include <sys/user.h>
2748465Skarels #ifdef KTRACE
2856508Sbostic #include <sys/ktrace.h>
2948465Skarels #endif
3048465Skarels
3156508Sbostic #include <machine/psl.h>
3256508Sbostic #include <machine/trap.h>
3356508Sbostic #include <machine/cpu.h>
3456508Sbostic #include <machine/reg.h>
3556508Sbostic #include <machine/mtpr.h>
3641475Smckusick
3756508Sbostic #include <vm/vm.h>
3856508Sbostic #include <vm/pmap.h>
3945751Smckusick
4041475Smckusick #ifdef HPUXCOMPAT
4156508Sbostic #include <hp/hpux/hpux.h>
4241475Smckusick #endif
4341475Smckusick
4441475Smckusick struct sysent sysent[];
4541475Smckusick int nsysent;
4641475Smckusick
4741475Smckusick char *trap_type[] = {
4841475Smckusick "Bus error",
4941475Smckusick "Address error",
5041475Smckusick "Illegal instruction",
5141475Smckusick "Zero divide",
5241475Smckusick "CHK instruction",
5341475Smckusick "TRAPV instruction",
5441475Smckusick "Privilege violation",
5541475Smckusick "Trace trap",
5641475Smckusick "MMU fault",
5741475Smckusick "SSIR trap",
5841475Smckusick "Format error",
5941475Smckusick "68881 exception",
6041475Smckusick "Coprocessor violation",
6141475Smckusick "Async system trap"
6241475Smckusick };
6341475Smckusick #define TRAP_TYPES (sizeof trap_type / sizeof trap_type[0])
6441475Smckusick
6549317Shibler /*
6649317Shibler * Size of various exception stack frames (minus the standard 8 bytes)
6749317Shibler */
6849317Shibler short exframesize[] = {
6949317Shibler FMT0SIZE, /* type 0 - normal (68020/030/040) */
7049317Shibler FMT1SIZE, /* type 1 - throwaway (68020/030/040) */
7149317Shibler FMT2SIZE, /* type 2 - normal 6-word (68020/030/040) */
7253933Shibler FMT3SIZE, /* type 3 - FP post-instruction (68040) */
7349317Shibler -1, -1, -1, /* type 4-6 - undefined */
7453933Shibler FMT7SIZE, /* type 7 - access error (68040) */
7549317Shibler 58, /* type 8 - bus fault (68010) */
7649317Shibler FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */
7749317Shibler FMTASIZE, /* type A - short bus fault (68020/030) */
7849317Shibler FMTBSIZE, /* type B - long bus fault (68020/030) */
7949317Shibler -1, -1, -1, -1 /* type C-F - undefined */
8049317Shibler };
8149317Shibler
8254801Storek #ifdef HP380
8353933Shibler #define KDFAULT(c) (mmutype == MMU_68040 ? \
8453933Shibler ((c) & SSW4_TMMASK) == SSW4_TMKD : \
8553933Shibler ((c) & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))
8653933Shibler #define WRFAULT(c) (mmutype == MMU_68040 ? \
8753933Shibler ((c) & SSW4_RW) == 0 : \
8853933Shibler ((c) & (SSW_DF|SSW_RW)) == SSW_DF)
8953933Shibler #else
9053933Shibler #define KDFAULT(c) (((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
9153933Shibler #define WRFAULT(c) (((c) & (SSW_DF|SSW_RW)) == SSW_DF)
9253933Shibler #endif
9353933Shibler
9441475Smckusick #ifdef DEBUG
9541475Smckusick int mmudebug = 0;
9653933Shibler int mmupid = -1;
9753933Shibler #define MDB_FOLLOW 1
9853933Shibler #define MDB_WBFOLLOW 2
9953933Shibler #define MDB_WBFAILED 4
10053933Shibler #define MDB_ISPID(p) (p) == mmupid
10141475Smckusick #endif
10241475Smckusick
10341475Smckusick /*
10454801Storek * trap and syscall both need the following work done before returning
10554801Storek * to user mode.
10654801Storek */
10754801Storek static inline void
userret(p,fp,oticks,faultaddr,fromtrap)10854801Storek userret(p, fp, oticks, faultaddr, fromtrap)
10954801Storek register struct proc *p;
11054801Storek register struct frame *fp;
11154801Storek u_quad_t oticks;
11254801Storek u_int faultaddr;
11354801Storek int fromtrap;
11454801Storek {
11554801Storek int sig, s;
11654801Storek #ifdef HP380
11754801Storek int beenhere = 0;
11854801Storek
11954801Storek again:
12054801Storek #endif
12154801Storek /* take pending signals */
12254801Storek while ((sig = CURSIG(p)) != 0)
12364615Sbostic postsig(sig);
12464615Sbostic p->p_priority = p->p_usrpri;
12554801Storek if (want_resched) {
12654801Storek /*
12754801Storek * Since we are curproc, clock will normally just change
12854801Storek * our priority without moving us from one queue to another
12954801Storek * (since the running process is not on a queue.)
13064542Sbostic * If that happened after we put ourselves on the run queue
13164615Sbostic * but before we mi_switch()'ed, we might not be on the queue
13264542Sbostic * indicated by our priority.
13354801Storek */
13454801Storek s = splstatclock();
13564542Sbostic setrunqueue(p);
13654801Storek p->p_stats->p_ru.ru_nivcsw++;
13764615Sbostic mi_switch();
13854801Storek splx(s);
13954801Storek while ((sig = CURSIG(p)) != 0)
14064615Sbostic postsig(sig);
14154801Storek }
14254801Storek
14354801Storek /*
14454801Storek * If profiling, charge system time to the trapped pc.
14554801Storek */
14664615Sbostic if (p->p_flag & P_PROFIL) {
14756318Shibler extern int psratio;
14856318Shibler
14956318Shibler addupc_task(p, fp->f_pc,
15056318Shibler (int)(p->p_sticks - oticks) * psratio);
15156318Shibler }
15254801Storek #ifdef HP380
15354801Storek /*
15454801Storek * Deal with user mode writebacks (from trap, or from sigreturn).
15554801Storek * If any writeback fails, go back and attempt signal delivery.
15654801Storek * unless we have already been here and attempted the writeback
15754801Storek * (e.g. bad address with user ignoring SIGSEGV). In that case
15854801Storek * we just return to the user without sucessfully completing
15954801Storek * the writebacks. Maybe we should just drop the sucker?
16054801Storek */
16154801Storek if (mmutype == MMU_68040 && fp->f_format == FMT7) {
16254801Storek if (beenhere) {
16354801Storek #ifdef DEBUG
16454801Storek if (mmudebug & MDB_WBFAILED)
16554801Storek printf(fromtrap ?
16654801Storek "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" :
16754801Storek "pid %d(%s): writeback aborted in sigreturn, pc=%x\n",
16854801Storek p->p_pid, p->p_comm, fp->f_pc, faultaddr);
16954801Storek #endif
17054801Storek } else if (sig = writeback(fp, fromtrap)) {
17154801Storek beenhere = 1;
17254801Storek oticks = p->p_sticks;
17354801Storek trapsignal(p, sig, faultaddr);
17454801Storek goto again;
17554801Storek }
17654801Storek }
17754801Storek #endif
17864615Sbostic curpriority = p->p_priority;
17954801Storek }
18054801Storek
18154801Storek /*
18249531Skarels * Trap is called from locore to handle most types of processor traps,
18349531Skarels * including events such as simulated software interrupts/AST's.
18449531Skarels * System calls are broken out for efficiency.
18541475Smckusick */
18641475Smckusick /*ARGSUSED*/
trap(type,code,v,frame)18741475Smckusick trap(type, code, v, frame)
18841475Smckusick int type;
18941475Smckusick unsigned code;
19041475Smckusick register unsigned v;
19141475Smckusick struct frame frame;
19241475Smckusick {
19365483Sbostic extern char fswintr[];
19465483Sbostic register struct proc *p;
19541475Smckusick register int i;
19665483Sbostic u_int ucode;
19754801Storek u_quad_t sticks;
19841475Smckusick
19941475Smckusick cnt.v_trap++;
20054801Storek p = curproc;
20154801Storek ucode = 0;
20241475Smckusick if (USERMODE(frame.f_sr)) {
20349531Skarels type |= T_USER;
20454801Storek sticks = p->p_sticks;
20552380Smckusick p->p_md.md_regs = frame.f_regs;
20641475Smckusick }
20741475Smckusick switch (type) {
20841475Smckusick
20941475Smckusick default:
21041475Smckusick dopanic:
21141475Smckusick printf("trap type %d, code = %x, v = %x\n", type, code, v);
21257344Shibler regdump(&frame, 128);
21349531Skarels type &= ~T_USER;
21441475Smckusick if ((unsigned)type < TRAP_TYPES)
21541475Smckusick panic(trap_type[type]);
21641475Smckusick panic("trap");
21741475Smckusick
21841475Smckusick case T_BUSERR: /* kernel bus error */
21949125Skarels if (!p->p_addr->u_pcb.pcb_onfault)
22041475Smckusick goto dopanic;
22141475Smckusick /*
22241475Smckusick * If we have arranged to catch this fault in any of the
22341475Smckusick * copy to/from user space routines, set PC to return to
22441475Smckusick * indicated location and set flag informing buserror code
22541475Smckusick * that it may need to clean up stack frame.
22641475Smckusick */
22741475Smckusick copyfault:
22849317Shibler frame.f_stackadj = exframesize[frame.f_format];
22949317Shibler frame.f_format = frame.f_vector = 0;
23049125Skarels frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault;
23141475Smckusick return;
23241475Smckusick
23349531Skarels case T_BUSERR|T_USER: /* bus error */
23449531Skarels case T_ADDRERR|T_USER: /* address error */
23553933Shibler ucode = v;
23641475Smckusick i = SIGBUS;
23741475Smckusick break;
23841475Smckusick
23967274Shibler #ifdef HP380
24067274Shibler case T_ADDRERR:
24167274Shibler /*
24267274Shibler * Yow! Looks like we get a kernel exception if the PC
24367274Shibler * in the RTE frame is odd on a 68040 (not on a 68030).
24467274Shibler * It comes through as a user exception for access faults
24567274Shibler * (T_MMUFLT).
24667274Shibler */
24767274Shibler if (*(short *)frame.f_pc != 0x4e73)
24867274Shibler goto dopanic;
24967274Shibler /* fall through */
25067274Shibler #endif
25167274Shibler
25241475Smckusick #ifdef FPCOPROC
25341475Smckusick case T_COPERR: /* kernel coprocessor violation */
25441475Smckusick #endif
25553933Shibler case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */
25653933Shibler case T_FMTERR: /* ...just in case... */
25767274Shibler /*
25867274Shibler * The user has most likely trashed the RTE or FP state info
25967274Shibler * in the stack frame of a signal handler.
26067274Shibler */
26149531Skarels type |= T_USER;
26248465Skarels printf("pid %d: kernel %s exception\n", p->p_pid,
26367274Shibler (type==T_COPERR|T_USER) ? "coprocessor" :
26467274Shibler (type==T_ADDRERR|T_USER) ? "RTE address" :
26567274Shibler "RTE format");
26648465Skarels p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL;
26741475Smckusick i = sigmask(SIGILL);
26841475Smckusick p->p_sigignore &= ~i;
26941475Smckusick p->p_sigcatch &= ~i;
27041475Smckusick p->p_sigmask &= ~i;
27142370Skarels i = SIGILL;
27241475Smckusick ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */
27342370Skarels break;
27441475Smckusick
27541475Smckusick #ifdef FPCOPROC
27649531Skarels case T_COPERR|T_USER: /* user coprocessor violation */
27741475Smckusick /* What is a proper response here? */
27841475Smckusick ucode = 0;
27941475Smckusick i = SIGFPE;
28041475Smckusick break;
28141475Smckusick
28249531Skarels case T_FPERR|T_USER: /* 68881 exceptions */
28341475Smckusick /*
28441475Smckusick * We pass along the 68881 status register which locore stashed
28541475Smckusick * in code for us. Note that there is a possibility that the
28641475Smckusick * bit pattern of this register will conflict with one of the
28741475Smckusick * FPE_* codes defined in signal.h. Fortunately for us, the
28841475Smckusick * only such codes we use are all in the range 1-7 and the low
28941475Smckusick * 3 bits of the status register are defined as 0 so there is
29041475Smckusick * no clash.
29141475Smckusick */
29241475Smckusick ucode = code;
29341475Smckusick i = SIGFPE;
29441475Smckusick break;
29541475Smckusick #endif
29641475Smckusick
29754801Storek #ifdef HP380
29853933Shibler case T_FPEMULI|T_USER: /* unimplemented FP instuction */
29953933Shibler case T_FPEMULD|T_USER: /* unimplemented FP data type */
30053933Shibler /* XXX need to FSAVE */
30153933Shibler printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n",
30253933Shibler p->p_pid, p->p_comm,
30353933Shibler frame.f_format == 2 ? "instruction" : "data type",
30453933Shibler frame.f_pc, frame.f_fmt2.f_iaddr);
30553933Shibler /* XXX need to FRESTORE */
30653933Shibler i = SIGFPE;
30753933Shibler break;
30853933Shibler #endif
30953933Shibler
31049531Skarels case T_ILLINST|T_USER: /* illegal instruction fault */
31141475Smckusick #ifdef HPUXCOMPAT
31257344Shibler if (p->p_md.md_flags & MDP_HPUX) {
31341475Smckusick ucode = HPUX_ILL_ILLINST_TRAP;
31441475Smckusick i = SIGILL;
31541475Smckusick break;
31641475Smckusick }
31741475Smckusick /* fall through */
31841475Smckusick #endif
31949531Skarels case T_PRIVINST|T_USER: /* privileged instruction fault */
32041475Smckusick #ifdef HPUXCOMPAT
32157344Shibler if (p->p_md.md_flags & MDP_HPUX)
32241475Smckusick ucode = HPUX_ILL_PRIV_TRAP;
32341475Smckusick else
32441475Smckusick #endif
32541475Smckusick ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */
32641475Smckusick i = SIGILL;
32741475Smckusick break;
32841475Smckusick
32949531Skarels case T_ZERODIV|T_USER: /* Divide by zero */
33041475Smckusick #ifdef HPUXCOMPAT
33157344Shibler if (p->p_md.md_flags & MDP_HPUX)
33241475Smckusick ucode = HPUX_FPE_INTDIV_TRAP;
33341475Smckusick else
33441475Smckusick #endif
33541475Smckusick ucode = frame.f_format; /* XXX was FPE_INTDIV_TRAP */
33641475Smckusick i = SIGFPE;
33741475Smckusick break;
33841475Smckusick
33949531Skarels case T_CHKINST|T_USER: /* CHK instruction trap */
34041475Smckusick #ifdef HPUXCOMPAT
34157344Shibler if (p->p_md.md_flags & MDP_HPUX) {
34241475Smckusick /* handled differently under hp-ux */
34341475Smckusick i = SIGILL;
34441475Smckusick ucode = HPUX_ILL_CHK_TRAP;
34541475Smckusick break;
34641475Smckusick }
34741475Smckusick #endif
34841475Smckusick ucode = frame.f_format; /* XXX was FPE_SUBRNG_TRAP */
34941475Smckusick i = SIGFPE;
35041475Smckusick break;
35141475Smckusick
35249531Skarels case T_TRAPVINST|T_USER: /* TRAPV instruction trap */
35341475Smckusick #ifdef HPUXCOMPAT
35457344Shibler if (p->p_md.md_flags & MDP_HPUX) {
35541475Smckusick /* handled differently under hp-ux */
35641475Smckusick i = SIGILL;
35741475Smckusick ucode = HPUX_ILL_TRAPV_TRAP;
35841475Smckusick break;
35941475Smckusick }
36041475Smckusick #endif
36141475Smckusick ucode = frame.f_format; /* XXX was FPE_INTOVF_TRAP */
36241475Smckusick i = SIGFPE;
36341475Smckusick break;
36441475Smckusick
36541475Smckusick /*
36641475Smckusick * XXX: Trace traps are a nightmare.
36741475Smckusick *
36841475Smckusick * HP-UX uses trap #1 for breakpoints,
36941475Smckusick * HPBSD uses trap #2,
37041475Smckusick * SUN 3.x uses trap #15,
37148465Skarels * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere).
37241475Smckusick *
37341475Smckusick * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
37441475Smckusick * SUN 3.x traps get passed through as T_TRAP15 and are not really
37548465Skarels * supported yet.
37641475Smckusick */
37741475Smckusick case T_TRACE: /* kernel trace trap */
37848465Skarels case T_TRAP15: /* SUN trace trap */
37941475Smckusick frame.f_sr &= ~PSL_T;
38041475Smckusick i = SIGTRAP;
38141475Smckusick break;
38241475Smckusick
38349531Skarels case T_TRACE|T_USER: /* user trace trap */
38449531Skarels case T_TRAP15|T_USER: /* SUN user trace trap */
38541475Smckusick frame.f_sr &= ~PSL_T;
38641475Smckusick i = SIGTRAP;
38741475Smckusick break;
38841475Smckusick
38943413Shibler case T_ASTFLT: /* system async trap, cannot happen */
39041475Smckusick goto dopanic;
39141475Smckusick
39249531Skarels case T_ASTFLT|T_USER: /* user async trap */
39349125Skarels astpending = 0;
39441475Smckusick /*
39541475Smckusick * We check for software interrupts first. This is because
39641475Smckusick * they are at a higher level than ASTs, and on a VAX would
39741475Smckusick * interrupt the AST. We assume that if we are processing
39841475Smckusick * an AST that we must be at IPL0 so we don't bother to
39941475Smckusick * check. Note that we ensure that we are at least at SIR
40041475Smckusick * IPL while processing the SIR.
40141475Smckusick */
40241475Smckusick spl1();
40341475Smckusick /* fall into... */
40441475Smckusick
40541475Smckusick case T_SSIR: /* software interrupt */
40649531Skarels case T_SSIR|T_USER:
40741475Smckusick if (ssir & SIR_NET) {
40841475Smckusick siroff(SIR_NET);
40941475Smckusick cnt.v_soft++;
41041475Smckusick netintr();
41141475Smckusick }
41241475Smckusick if (ssir & SIR_CLOCK) {
41341475Smckusick siroff(SIR_CLOCK);
41441475Smckusick cnt.v_soft++;
41554801Storek softclock();
41641475Smckusick }
41741475Smckusick /*
41841475Smckusick * If this was not an AST trap, we are all done.
41941475Smckusick */
42050753Skarels if (type != (T_ASTFLT|T_USER)) {
42141475Smckusick cnt.v_trap--;
42241475Smckusick return;
42341475Smckusick }
42441475Smckusick spl0();
42564615Sbostic if (p->p_flag & P_OWEUPC) {
42664615Sbostic p->p_flag &= ~P_OWEUPC;
42754801Storek ADDUPROF(p);
42841475Smckusick }
42941475Smckusick goto out;
43041475Smckusick
43141475Smckusick case T_MMUFLT: /* kernel mode page fault */
43254574Storek /*
43354574Storek * If we were doing profiling ticks or other user mode
43454574Storek * stuff from interrupt code, Just Say No.
43554574Storek */
43654574Storek if (p->p_addr->u_pcb.pcb_onfault == fswintr)
43754574Storek goto copyfault;
43841475Smckusick /* fall into ... */
43941475Smckusick
44049531Skarels case T_MMUFLT|T_USER: /* page fault */
44145751Smckusick {
44245751Smckusick register vm_offset_t va;
44348465Skarels register struct vmspace *vm = p->p_vmspace;
44445751Smckusick register vm_map_t map;
44545751Smckusick int rv;
44645751Smckusick vm_prot_t ftype;
44745751Smckusick extern vm_map_t kernel_map;
44845751Smckusick
44953933Shibler #ifdef DEBUG
45053933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
45153933Shibler printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n",
45253933Shibler p->p_pid, code, v, frame.f_pc, frame.f_sr);
45353933Shibler #endif
45441475Smckusick /*
45545751Smckusick * It is only a kernel address space fault iff:
45649531Skarels * 1. (type & T_USER) == 0 and
45745751Smckusick * 2. pcb_onfault not set or
45845751Smckusick * 3. pcb_onfault set but supervisor space data fault
45945751Smckusick * The last can occur during an exec() copyin where the
46045751Smckusick * argument space is lazy-allocated.
46141475Smckusick */
46245751Smckusick if (type == T_MMUFLT &&
46353933Shibler (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code)))
46445751Smckusick map = kernel_map;
46545751Smckusick else
46648465Skarels map = &vm->vm_map;
46753933Shibler if (WRFAULT(code))
46845751Smckusick ftype = VM_PROT_READ | VM_PROT_WRITE;
46945751Smckusick else
47045751Smckusick ftype = VM_PROT_READ;
47145751Smckusick va = trunc_page((vm_offset_t)v);
47241475Smckusick #ifdef DEBUG
47345751Smckusick if (map == kernel_map && va == 0) {
47445751Smckusick printf("trap: bad kernel access at %x\n", v);
47541475Smckusick goto dopanic;
47641475Smckusick }
47741475Smckusick #endif
47857344Shibler #ifdef HPUXCOMPAT
47957344Shibler if (ISHPMMADDR(va)) {
48057344Shibler vm_offset_t bva;
48157344Shibler
48257344Shibler rv = pmap_mapmulti(map->pmap, va);
48357344Shibler if (rv != KERN_SUCCESS) {
48457344Shibler bva = HPMMBASEADDR(va);
48557344Shibler rv = vm_fault(map, bva, ftype, FALSE);
48657344Shibler if (rv == KERN_SUCCESS)
48757344Shibler (void) pmap_mapmulti(map->pmap, va);
48857344Shibler }
48957344Shibler } else
49057344Shibler #endif
49149317Shibler rv = vm_fault(map, va, ftype, FALSE);
49253933Shibler #ifdef DEBUG
49353933Shibler if (rv && MDB_ISPID(p->p_pid))
49453933Shibler printf("vm_fault(%x, %x, %x, 0) -> %x\n",
49553933Shibler map, va, ftype, rv);
49653933Shibler #endif
49741475Smckusick /*
49849317Shibler * If this was a stack access we keep track of the maximum
49949317Shibler * accessed stack size. Also, if vm_fault gets a protection
50049317Shibler * failure it is due to accessing the stack region outside
50149317Shibler * the current limit and we need to reflect that as an access
50249317Shibler * error.
50341475Smckusick */
50448465Skarels if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) {
50549317Shibler if (rv == KERN_SUCCESS) {
50649317Shibler unsigned nss;
50749317Shibler
50849317Shibler nss = clrnd(btoc(USRSTACK-(unsigned)va));
50949317Shibler if (nss > vm->vm_ssize)
51049317Shibler vm->vm_ssize = nss;
51149317Shibler } else if (rv == KERN_PROTECTION_FAILURE)
51249317Shibler rv = KERN_INVALID_ADDRESS;
51341475Smckusick }
51445751Smckusick if (rv == KERN_SUCCESS) {
51553933Shibler if (type == T_MMUFLT) {
51654801Storek #ifdef HP380
51753933Shibler if (mmutype == MMU_68040)
51853933Shibler (void) writeback(&frame, 1);
51953933Shibler #endif
52041475Smckusick return;
52153933Shibler }
52241475Smckusick goto out;
52341475Smckusick }
52445751Smckusick if (type == T_MMUFLT) {
52549125Skarels if (p->p_addr->u_pcb.pcb_onfault)
52645751Smckusick goto copyfault;
52745751Smckusick printf("vm_fault(%x, %x, %x, 0) -> %x\n",
52845751Smckusick map, va, ftype, rv);
52945751Smckusick printf(" type %x, code [mmu,,ssw]: %x\n",
53045751Smckusick type, code);
53145751Smckusick goto dopanic;
53245751Smckusick }
53348465Skarels ucode = v;
53445751Smckusick i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
53545751Smckusick break;
53645751Smckusick }
53741475Smckusick }
53848465Skarels trapsignal(p, i, ucode);
53949531Skarels if ((type & T_USER) == 0)
54041475Smckusick return;
54141475Smckusick out:
54254801Storek userret(p, &frame, sticks, v, 1);
54341475Smckusick }
54441475Smckusick
54554801Storek #ifdef HP380
54653933Shibler #ifdef DEBUG
54753933Shibler struct writebackstats {
54853933Shibler int calls;
54953933Shibler int cpushes;
55053933Shibler int move16s;
55153933Shibler int wb1s, wb2s, wb3s;
55253933Shibler int wbsize[4];
55353933Shibler } wbstats;
55453933Shibler
55553933Shibler char *f7sz[] = { "longword", "byte", "word", "line" };
55653933Shibler char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" };
55753933Shibler char *f7tm[] = { "d-push", "u-data", "u-code", "M-data",
55853933Shibler "M-code", "k-data", "k-code", "RES" };
55953933Shibler char wberrstr[] =
56053933Shibler "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n";
56153933Shibler #endif
56253933Shibler
56353933Shibler writeback(fp, docachepush)
56453933Shibler struct frame *fp;
56553933Shibler int docachepush;
56653933Shibler {
56753933Shibler register struct fmt7 *f = &fp->f_fmt7;
56853933Shibler register struct proc *p = curproc;
56953933Shibler int err = 0;
57053933Shibler u_int fa;
57153933Shibler caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault;
57253933Shibler
57353933Shibler #ifdef DEBUG
57453933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
57553933Shibler printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa);
57653933Shibler dumpssw(f->f_ssw);
57753933Shibler }
57853933Shibler wbstats.calls++;
57953933Shibler #endif
58053933Shibler /*
58153933Shibler * Deal with special cases first.
58253933Shibler */
58353933Shibler if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) {
58453933Shibler /*
58553933Shibler * Dcache push fault.
58653933Shibler * Line-align the address and write out the push data to
58753933Shibler * the indicated physical address.
58853933Shibler */
58953933Shibler #ifdef DEBUG
59053933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
59153933Shibler printf(" pushing %s to PA %x, data %x",
59253933Shibler f7sz[(f->f_ssw & SSW4_SZMASK) >> 5],
59353933Shibler f->f_fa, f->f_pd0);
59453933Shibler if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN)
59553933Shibler printf("/%x/%x/%x",
59653933Shibler f->f_pd1, f->f_pd2, f->f_pd3);
59753933Shibler printf("\n");
59853933Shibler }
59953933Shibler if (f->f_wb1s & SSW4_WBSV)
60053933Shibler panic("writeback: cache push with WB1S valid");
60153933Shibler wbstats.cpushes++;
60253933Shibler #endif
60353933Shibler /*
60453933Shibler * XXX there are security problems if we attempt to do a
60553933Shibler * cache push after a signal handler has been called.
60653933Shibler */
60753933Shibler if (docachepush) {
60853933Shibler pmap_enter(kernel_pmap, (vm_offset_t)vmmap,
60953933Shibler trunc_page(f->f_fa), VM_PROT_WRITE, TRUE);
61053933Shibler fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF];
61153933Shibler bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16);
61253933Shibler DCFL(pmap_extract(kernel_pmap, (vm_offset_t)fa));
61353933Shibler pmap_remove(kernel_pmap, (vm_offset_t)vmmap,
61453933Shibler (vm_offset_t)&vmmap[NBPG]);
61553933Shibler } else
61653933Shibler printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n",
61753933Shibler p->p_pid, p->p_comm, p->p_ucred->cr_uid);
61853933Shibler } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) {
61953933Shibler /*
62053933Shibler * MOVE16 fault.
62153933Shibler * Line-align the address and write out the push data to
62253933Shibler * the indicated virtual address.
62353933Shibler */
62453933Shibler #ifdef DEBUG
62553933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
62653933Shibler printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n",
62753933Shibler f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1,
62853933Shibler f->f_pd2, f->f_pd3);
62953933Shibler if (f->f_wb1s & SSW4_WBSV)
63053933Shibler panic("writeback: MOVE16 with WB1S valid");
63153933Shibler wbstats.move16s++;
63253933Shibler #endif
63353933Shibler if (KDFAULT(f->f_wb1s))
63453933Shibler bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16);
63553933Shibler else
63653933Shibler err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0);
63753933Shibler if (err) {
63853933Shibler fa = f->f_fa & ~0xF;
63953933Shibler #ifdef DEBUG
64053933Shibler if (mmudebug & MDB_WBFAILED)
64153933Shibler printf(wberrstr, p->p_pid, p->p_comm,
64253933Shibler "MOVE16", fp->f_pc, f->f_fa,
64353933Shibler f->f_fa & ~0xF, f->f_pd0);
64453933Shibler #endif
64553933Shibler }
64653933Shibler } else if (f->f_wb1s & SSW4_WBSV) {
64753933Shibler /*
64853933Shibler * Writeback #1.
64953933Shibler * Position the "memory-aligned" data and write it out.
65053933Shibler */
65153933Shibler register u_int wb1d = f->f_wb1d;
65253933Shibler register int off;
65353933Shibler
65453933Shibler #ifdef DEBUG
65553933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
65653933Shibler dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d);
65753933Shibler wbstats.wb1s++;
65853933Shibler wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
65953933Shibler #endif
66053933Shibler off = (f->f_wb1a & 3) * 8;
66153933Shibler switch (f->f_wb1s & SSW4_SZMASK) {
66253933Shibler case SSW4_SZLW:
66353933Shibler if (off)
66453933Shibler wb1d = (wb1d >> (32 - off)) | (wb1d << off);
66553933Shibler if (KDFAULT(f->f_wb1s))
66653933Shibler *(long *)f->f_wb1a = wb1d;
66753933Shibler else
66853933Shibler err = suword((caddr_t)f->f_wb1a, wb1d);
66953933Shibler break;
67053933Shibler case SSW4_SZB:
67153933Shibler off = 24 - off;
67253933Shibler if (off)
67353933Shibler wb1d >>= off;
67453933Shibler if (KDFAULT(f->f_wb1s))
67553933Shibler *(char *)f->f_wb1a = wb1d;
67653933Shibler else
67753933Shibler err = subyte((caddr_t)f->f_wb1a, wb1d);
67853933Shibler break;
67953933Shibler case SSW4_SZW:
68053933Shibler off = (off + 16) % 32;
68153933Shibler if (off)
68253933Shibler wb1d = (wb1d >> (32 - off)) | (wb1d << off);
68353933Shibler if (KDFAULT(f->f_wb1s))
68453933Shibler *(short *)f->f_wb1a = wb1d;
68553933Shibler else
68653933Shibler err = susword((caddr_t)f->f_wb1a, wb1d);
68753933Shibler break;
68853933Shibler }
68953933Shibler if (err) {
69053933Shibler fa = f->f_wb1a;
69153933Shibler #ifdef DEBUG
69253933Shibler if (mmudebug & MDB_WBFAILED)
69353933Shibler printf(wberrstr, p->p_pid, p->p_comm,
69453933Shibler "#1", fp->f_pc, f->f_fa,
69553933Shibler f->f_wb1a, f->f_wb1d);
69653933Shibler #endif
69753933Shibler }
69853933Shibler }
69953933Shibler /*
70053933Shibler * Deal with the "normal" writebacks.
70153933Shibler *
70253933Shibler * XXX writeback2 is known to reflect a LINE size writeback after
70353933Shibler * a MOVE16 was already dealt with above. Ignore it.
70453933Shibler */
70553933Shibler if (err == 0 && (f->f_wb2s & SSW4_WBSV) &&
70653933Shibler (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) {
70753933Shibler #ifdef DEBUG
70853933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
70953933Shibler dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
71053933Shibler wbstats.wb2s++;
71153933Shibler wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
71253933Shibler #endif
71353933Shibler switch (f->f_wb2s & SSW4_SZMASK) {
71453933Shibler case SSW4_SZLW:
71553933Shibler if (KDFAULT(f->f_wb2s))
71653933Shibler *(long *)f->f_wb2a = f->f_wb2d;
71753933Shibler else
71853933Shibler err = suword((caddr_t)f->f_wb2a, f->f_wb2d);
71953933Shibler break;
72053933Shibler case SSW4_SZB:
72153933Shibler if (KDFAULT(f->f_wb2s))
72253933Shibler *(char *)f->f_wb2a = f->f_wb2d;
72353933Shibler else
72453933Shibler err = subyte((caddr_t)f->f_wb2a, f->f_wb2d);
72553933Shibler break;
72653933Shibler case SSW4_SZW:
72753933Shibler if (KDFAULT(f->f_wb2s))
72853933Shibler *(short *)f->f_wb2a = f->f_wb2d;
72953933Shibler else
73053933Shibler err = susword((caddr_t)f->f_wb2a, f->f_wb2d);
73153933Shibler break;
73253933Shibler }
73353933Shibler if (err) {
73453933Shibler fa = f->f_wb2a;
73553933Shibler #ifdef DEBUG
73653933Shibler if (mmudebug & MDB_WBFAILED) {
73753933Shibler printf(wberrstr, p->p_pid, p->p_comm,
73853933Shibler "#2", fp->f_pc, f->f_fa,
73953933Shibler f->f_wb2a, f->f_wb2d);
74053933Shibler dumpssw(f->f_ssw);
74153933Shibler dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
74253933Shibler }
74353933Shibler #endif
74453933Shibler }
74553933Shibler }
74653933Shibler if (err == 0 && (f->f_wb3s & SSW4_WBSV)) {
74753933Shibler #ifdef DEBUG
74853933Shibler if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
74953933Shibler dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d);
75053933Shibler wbstats.wb3s++;
75153933Shibler wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++;
75253933Shibler #endif
75353933Shibler switch (f->f_wb3s & SSW4_SZMASK) {
75453933Shibler case SSW4_SZLW:
75553933Shibler if (KDFAULT(f->f_wb3s))
75653933Shibler *(long *)f->f_wb3a = f->f_wb3d;
75753933Shibler else
75853933Shibler err = suword((caddr_t)f->f_wb3a, f->f_wb3d);
75953933Shibler break;
76053933Shibler case SSW4_SZB:
76153933Shibler if (KDFAULT(f->f_wb3s))
76253933Shibler *(char *)f->f_wb3a = f->f_wb3d;
76353933Shibler else
76453933Shibler err = subyte((caddr_t)f->f_wb3a, f->f_wb3d);
76553933Shibler break;
76653933Shibler case SSW4_SZW:
76753933Shibler if (KDFAULT(f->f_wb3s))
76853933Shibler *(short *)f->f_wb3a = f->f_wb3d;
76953933Shibler else
77053933Shibler err = susword((caddr_t)f->f_wb3a, f->f_wb3d);
77153933Shibler break;
77253933Shibler #ifdef DEBUG
77353933Shibler case SSW4_SZLN:
77453933Shibler panic("writeback: wb3s indicates LINE write");
77553933Shibler #endif
77653933Shibler }
77753933Shibler if (err) {
77853933Shibler fa = f->f_wb3a;
77953933Shibler #ifdef DEBUG
78053933Shibler if (mmudebug & MDB_WBFAILED)
78153933Shibler printf(wberrstr, p->p_pid, p->p_comm,
78253933Shibler "#3", fp->f_pc, f->f_fa,
78353933Shibler f->f_wb3a, f->f_wb3d);
78453933Shibler #endif
78553933Shibler }
78653933Shibler }
78753933Shibler p->p_addr->u_pcb.pcb_onfault = oonfault;
78853933Shibler /*
78953933Shibler * Determine the cause of the failure if any translating to
79053933Shibler * a signal. If the corresponding VA is valid and RO it is
79153933Shibler * a protection fault (SIGBUS) otherwise consider it an
79253933Shibler * illegal reference (SIGSEGV).
79353933Shibler */
79453933Shibler if (err) {
79553933Shibler if (vm_map_check_protection(&p->p_vmspace->vm_map,
79653933Shibler trunc_page(fa), round_page(fa),
79753933Shibler VM_PROT_READ) &&
79853933Shibler !vm_map_check_protection(&p->p_vmspace->vm_map,
79953933Shibler trunc_page(fa), round_page(fa),
80053933Shibler VM_PROT_WRITE))
80153933Shibler err = SIGBUS;
80253933Shibler else
80353933Shibler err = SIGSEGV;
80453933Shibler }
80553933Shibler return(err);
80653933Shibler }
80753933Shibler
80853933Shibler #ifdef DEBUG
dumpssw(ssw)80953933Shibler dumpssw(ssw)
81053933Shibler register u_short ssw;
81153933Shibler {
81253933Shibler printf(" SSW: %x: ", ssw);
81353933Shibler if (ssw & SSW4_CP)
81453933Shibler printf("CP,");
81553933Shibler if (ssw & SSW4_CU)
81653933Shibler printf("CU,");
81753933Shibler if (ssw & SSW4_CT)
81853933Shibler printf("CT,");
81953933Shibler if (ssw & SSW4_CM)
82053933Shibler printf("CM,");
82153933Shibler if (ssw & SSW4_MA)
82253933Shibler printf("MA,");
82353933Shibler if (ssw & SSW4_ATC)
82453933Shibler printf("ATC,");
82553933Shibler if (ssw & SSW4_LK)
82653933Shibler printf("LK,");
82753933Shibler if (ssw & SSW4_RW)
82853933Shibler printf("RW,");
82953933Shibler printf(" SZ=%s, TT=%s, TM=%s\n",
83053933Shibler f7sz[(ssw & SSW4_SZMASK) >> 5],
83153933Shibler f7tt[(ssw & SSW4_TTMASK) >> 3],
83253933Shibler f7tm[ssw & SSW4_TMMASK]);
83353933Shibler }
83453933Shibler
dumpwb(num,s,a,d)83553933Shibler dumpwb(num, s, a, d)
83653933Shibler int num;
83753933Shibler u_short s;
83853933Shibler u_int a, d;
83953933Shibler {
84053933Shibler register struct proc *p = curproc;
84153933Shibler vm_offset_t pa;
84253933Shibler
84353933Shibler printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n",
84453933Shibler num, a, d, f7sz[(s & SSW4_SZMASK) >> 5],
84553933Shibler f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]);
84653933Shibler printf(" PA ");
84753933Shibler pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)a);
84853933Shibler if (pa == 0)
84953933Shibler printf("<invalid address>");
85053933Shibler else
85153933Shibler printf("%x, current value %x", pa, fuword((caddr_t)a));
85253933Shibler printf("\n");
85353933Shibler }
85453933Shibler #endif
85553933Shibler #endif
85653933Shibler
85741475Smckusick /*
85849531Skarels * Proces a system call.
85941475Smckusick */
syscall(code,frame)86041475Smckusick syscall(code, frame)
86154801Storek u_int code;
86241475Smckusick struct frame frame;
86341475Smckusick {
86441475Smckusick register caddr_t params;
86541475Smckusick register struct sysent *callp;
86654801Storek register struct proc *p;
86765483Sbostic int error, opc, numsys;
86854801Storek u_int argsize;
86944018Skarels struct args {
87044018Skarels int i[8];
87144018Skarels } args;
87244018Skarels int rval[2];
87354801Storek u_quad_t sticks;
87441475Smckusick #ifdef HPUXCOMPAT
87541475Smckusick extern struct sysent hpuxsysent[];
87641475Smckusick extern int hpuxnsysent, notimp();
87741475Smckusick #endif
87841475Smckusick
87941475Smckusick cnt.v_syscall++;
88041475Smckusick if (!USERMODE(frame.f_sr))
88141475Smckusick panic("syscall");
88254801Storek p = curproc;
88354801Storek sticks = p->p_sticks;
88452380Smckusick p->p_md.md_regs = frame.f_regs;
88541475Smckusick opc = frame.f_pc - 2;
88641475Smckusick #ifdef HPUXCOMPAT
88757344Shibler if (p->p_md.md_flags & MDP_HPUX)
88854801Storek callp = hpuxsysent, numsys = hpuxnsysent;
88954801Storek else
89041475Smckusick #endif
89154801Storek callp = sysent, numsys = nsysent;
89249531Skarels params = (caddr_t)frame.f_regs[SP] + sizeof(int);
89354801Storek switch (code) {
89454801Storek
89563469Smckusick case SYS_syscall:
89654801Storek /*
89754801Storek * Code is first argument, followed by actual args.
89854801Storek */
89942370Skarels code = fuword(params);
90049531Skarels params += sizeof(int);
90157344Shibler /*
90257344Shibler * XXX sigreturn requires special stack manipulation
90357344Shibler * that is only done if entered via the sigreturn
90457344Shibler * trap. Cannot allow it here so make sure we fail.
90557344Shibler */
90657344Shibler if (code == SYS_sigreturn)
90757344Shibler code = numsys;
90854801Storek break;
90954801Storek
91063469Smckusick case SYS___syscall:
91154801Storek /*
91263469Smckusick * Like syscall, but code is a quad, so as to maintain
91354801Storek * quad alignment for the rest of the arguments.
91454801Storek */
91541475Smckusick #ifdef HPUXCOMPAT
91657344Shibler if (p->p_md.md_flags & MDP_HPUX)
91754801Storek break;
91841475Smckusick #endif
91954865Smckusick code = fuword(params + _QUAD_LOWWORD * sizeof(int));
92054865Smckusick params += sizeof(quad_t);
92154801Storek break;
92254801Storek
92354865Smckusick default:
92454865Smckusick /* nothing to do by default */
92554865Smckusick break;
92654801Storek }
92754801Storek if (code < numsys)
92854801Storek callp += code;
92954801Storek else
93063469Smckusick callp += SYS_syscall; /* => nosys */
931*68359Scgd argsize = callp->sy_argsize;
93254801Storek if (argsize && (error = copyin(params, (caddr_t)&args, argsize))) {
93341475Smckusick #ifdef KTRACE
93443641Skarels if (KTRPOINT(p, KTR_SYSCALL))
935*68359Scgd ktrsyscall(p->p_tracep, code, argsize, args.i);
93641475Smckusick #endif
93754801Storek goto bad;
93841475Smckusick }
93941475Smckusick #ifdef KTRACE
94043641Skarels if (KTRPOINT(p, KTR_SYSCALL))
941*68359Scgd ktrsyscall(p->p_tracep, code, argsize, args.i);
94241475Smckusick #endif
94343641Skarels rval[0] = 0;
94443641Skarels rval[1] = frame.f_regs[D1];
94541475Smckusick #ifdef HPUXCOMPAT
94642370Skarels /* debug kludge */
94742370Skarels if (callp->sy_call == notimp)
948*68359Scgd error = notimp(p, args.i, rval, code, argsize);
94942370Skarels else
95041475Smckusick #endif
95154801Storek error = (*callp->sy_call)(p, &args, rval);
95254801Storek switch (error) {
95342370Skarels
95454801Storek case 0:
95541475Smckusick /*
95654801Storek * Reinitialize proc pointer `p' as it may be different
95754801Storek * if this is a child returning from fork syscall.
95841475Smckusick */
95954801Storek p = curproc;
96054801Storek frame.f_regs[D0] = rval[0];
96154801Storek frame.f_regs[D1] = rval[1];
96254801Storek frame.f_sr &= ~PSL_C;
96354801Storek break;
96441475Smckusick
96554801Storek case ERESTART:
96654801Storek frame.f_pc = opc;
96754801Storek break;
96854801Storek
96954801Storek case EJUSTRETURN:
97054801Storek break; /* nothing to do */
97154801Storek
97254801Storek default:
97354801Storek bad:
97454801Storek #ifdef HPUXCOMPAT
97557344Shibler if (p->p_md.md_flags & MDP_HPUX)
97654801Storek error = bsdtohpuxerrno(error);
97741475Smckusick #endif
97854801Storek frame.f_regs[D0] = error;
97954801Storek frame.f_sr |= PSL_C;
98054801Storek break;
98141475Smckusick }
98254801Storek
98354801Storek userret(p, &frame, sticks, (u_int)0, 0);
98441475Smckusick #ifdef KTRACE
98543641Skarels if (KTRPOINT(p, KTR_SYSRET))
98643641Skarels ktrsysret(p->p_tracep, code, error, rval[0]);
98741475Smckusick #endif
98841475Smckusick }
989