1*5f04920cSrin /* $NetBSD: trap.c,v 1.139 2020/08/10 10:51:21 rin Exp $ */
2aad01611Sagc
3aad01611Sagc /*
48ac3875aSrmind * Copyright (c) 1988 University of Utah.
5aad01611Sagc * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
6aad01611Sagc * All rights reserved.
7aad01611Sagc *
8aad01611Sagc * This code is derived from software contributed to Berkeley by
9aad01611Sagc * the Systems Programming Group of the University of Utah Computer
10aad01611Sagc * Science Department.
11aad01611Sagc *
12aad01611Sagc * Redistribution and use in source and binary forms, with or without
13aad01611Sagc * modification, are permitted provided that the following conditions
14aad01611Sagc * are met:
15aad01611Sagc * 1. Redistributions of source code must retain the above copyright
16aad01611Sagc * notice, this list of conditions and the following disclaimer.
17aad01611Sagc * 2. Redistributions in binary form must reproduce the above copyright
18aad01611Sagc * notice, this list of conditions and the following disclaimer in the
19aad01611Sagc * documentation and/or other materials provided with the distribution.
20aad01611Sagc * 3. Neither the name of the University nor the names of its contributors
21aad01611Sagc * may be used to endorse or promote products derived from this software
22aad01611Sagc * without specific prior written permission.
23aad01611Sagc *
24aad01611Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25aad01611Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26aad01611Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27aad01611Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28aad01611Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29aad01611Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30aad01611Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31aad01611Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32aad01611Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33aad01611Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34aad01611Sagc * SUCH DAMAGE.
35aad01611Sagc *
36aad01611Sagc * from: Utah $Hdr: trap.c 1.32 91/04/06$
37aad01611Sagc *
38aad01611Sagc * @(#)trap.c 7.15 (Berkeley) 8/2/91
39aad01611Sagc */
40ec77f0b3Scgd
41466e784eSjonathan #include "opt_ddb.h"
42c05dadc1Sitohy #include "opt_execfmt.h"
438aee7782Sthorpej #include "opt_compat_sunos.h"
44d505b189Smartin #include "opt_fpu_emulate.h"
45bd01b4a3Smrg #include "opt_m68k_arch.h"
46971b8956Sthorpej
471ea4df81Saymeric #include <sys/cdefs.h>
48*5f04920cSrin __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.139 2020/08/10 10:51:21 rin Exp $");
491ea4df81Saymeric
50b700b86fSchopps #include <sys/param.h>
51b700b86fSchopps #include <sys/systm.h>
52b700b86fSchopps #include <sys/proc.h>
53b700b86fSchopps #include <sys/acct.h>
54b700b86fSchopps #include <sys/kernel.h>
55b700b86fSchopps #include <sys/signalvar.h>
56b700b86fSchopps #include <sys/resourcevar.h>
57b700b86fSchopps #include <sys/syslog.h>
5863451f69Schopps #include <sys/syscall.h>
59ef56cc40Scl #include <sys/userret.h>
60d73ce018Syamt #include <sys/kauth.h>
619af91bf2Schopps
62dc9188e3Smhitch #include <uvm/uvm_extern.h>
63dc9188e3Smhitch
64b700b86fSchopps #include <machine/psl.h>
65b700b86fSchopps #include <machine/trap.h>
66b700b86fSchopps #include <machine/cpu.h>
67da876597Srmind #include <machine/pcb.h>
68b700b86fSchopps #include <machine/pte.h>
6933e84123Smw
70006b6172Sis #include <m68k/fpe/fpu_emulate.h>
7133014f7bSis #include <m68k/cacheops.h>
72006b6172Sis
73df9af289Schopps #ifdef COMPAT_SUNOS
74df9af289Schopps #include <compat/sunos/sunos_syscall.h>
75df9af289Schopps extern struct emul emul_sunos;
76df9af289Schopps #endif
77df9af289Schopps
789caa601eSchopps /*
799caa601eSchopps * XXX Hack until I can figure out what to do about this code's removal
809caa601eSchopps * from m68k/include/frame.h
819caa601eSchopps */
829caa601eSchopps
839caa601eSchopps /* 68040 fault frame */
849caa601eSchopps #define SSW_CP 0x8000 /* Continuation - Floating-Point Post*/
859caa601eSchopps #define SSW_CU 0x4000 /* Continuation - Unimpl. FP */
869caa601eSchopps #define SSW_CT 0x2000 /* Continuation - Trace */
879caa601eSchopps #define SSW_CM 0x1000 /* Continuation - MOVEM */
889caa601eSchopps #define SSW_MA 0x0800 /* Misaligned access */
899caa601eSchopps #define SSW_ATC 0x0400 /* ATC fault */
909caa601eSchopps #define SSW_LK 0x0200 /* Locked transfer */
919caa601eSchopps #define SSW_RW040 0x0100 /* Read/Write */
929caa601eSchopps #define SSW_SZMASK 0x0060 /* Transfer size */
939caa601eSchopps #define SSW_TTMASK 0x0018 /* Transfer type */
949caa601eSchopps #define SSW_TMMASK 0x0007 /* Transfer modifier */
959caa601eSchopps
969caa601eSchopps #define WBS_TMMASK 0x0007
979caa601eSchopps #define WBS_TTMASK 0x0018
989caa601eSchopps #define WBS_SZMASK 0x0060
999caa601eSchopps #define WBS_VALID 0x0080
1009caa601eSchopps
1019caa601eSchopps #define WBS_SIZE_BYTE 0x0020
1029caa601eSchopps #define WBS_SIZE_WORD 0x0040
1039caa601eSchopps #define WBS_SIZE_LONG 0x0000
1049caa601eSchopps #define WBS_SIZE_LINE 0x0060
1059caa601eSchopps
1069caa601eSchopps #define WBS_TT_NORMAL 0x0000
1079caa601eSchopps #define WBS_TT_MOVE16 0x0008
1089caa601eSchopps #define WBS_TT_ALTFC 0x0010
1099caa601eSchopps #define WBS_TT_ACK 0x0018
1109caa601eSchopps
1119caa601eSchopps #define WBS_TM_PUSH 0x0000
1129caa601eSchopps #define WBS_TM_UDATA 0x0001
1139caa601eSchopps #define WBS_TM_UCODE 0x0002
1149caa601eSchopps #define WBS_TM_MMUTD 0x0003
1159caa601eSchopps #define WBS_TM_MMUTC 0x0004
1169caa601eSchopps #define WBS_TM_SDATA 0x0005
1179caa601eSchopps #define WBS_TM_SCODE 0x0006
1189caa601eSchopps #define WBS_TM_RESV 0x0007
1199caa601eSchopps
1209caa601eSchopps #define MMUSR_PA_MASK 0xfffff000
1219caa601eSchopps #define MMUSR_B 0x00000800
1229caa601eSchopps #define MMUSR_G 0x00000400
1239caa601eSchopps #define MMUSR_U1 0x00000200
1249caa601eSchopps #define MMUSR_U0 0x00000100
1259caa601eSchopps #define MMUSR_S 0x00000080
1269caa601eSchopps #define MMUSR_CM 0x00000060
1279caa601eSchopps #define MMUSR_M 0x00000010
1289caa601eSchopps #define MMUSR_0 0x00000008
1299caa601eSchopps #define MMUSR_W 0x00000004
1309caa601eSchopps #define MMUSR_T 0x00000002
1319caa601eSchopps #define MMUSR_R 0x00000001
132f6ab1073Sis
133f6ab1073Sis #define FSLW_STRING "\020\1SEE\3BPE\4TTR\5WE\6RE\7TWE\010WP\011SP" \
134f6ab1073Sis "\012PF\013IL\014PTB\015PTA\016SBE\017PBE"
1359caa601eSchopps /*
1369caa601eSchopps * XXX End hack
1379caa601eSchopps */
138f49dd3efSscottr
139f49dd3efSscottr int astpending;
140f49dd3efSscottr
141dc6e239cSjandberg const char *trap_type[] = {
14233e84123Smw "Bus error",
14333e84123Smw "Address error",
14433e84123Smw "Illegal instruction",
14533e84123Smw "Zero divide",
14633e84123Smw "CHK instruction",
14733e84123Smw "TRAPV instruction",
14833e84123Smw "Privilege violation",
14933e84123Smw "Trace trap",
15033e84123Smw "MMU fault",
15133e84123Smw "SSIR trap",
15233e84123Smw "Format error",
15333e84123Smw "68881 exception",
15433e84123Smw "Coprocessor violation",
15533e84123Smw "Async system trap"
15633e84123Smw };
15706149f6fSmw int trap_types = sizeof trap_type / sizeof trap_type[0];
15833e84123Smw
15933e84123Smw /*
16033e84123Smw * Size of various exception stack frames (minus the standard 8 bytes)
16133e84123Smw */
16233e84123Smw short exframesize[] = {
163f6ab1073Sis FMT0SIZE, /* type 0 - normal (68020/030/040/060) */
16433e84123Smw FMT1SIZE, /* type 1 - throwaway (68020/030/040) */
165f6ab1073Sis FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */
166f6ab1073Sis FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */
167f6ab1073Sis FMT4SIZE, /* type 4 - access error/fp disabled (68060) */
168f6ab1073Sis -1, -1, /* type 5-6 - undefined */
16906149f6fSmw FMT7SIZE, /* type 7 - access error (68040) */
17033e84123Smw 58, /* type 8 - bus fault (68010) */
17133e84123Smw FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */
17233e84123Smw FMTASIZE, /* type A - short bus fault (68020/030) */
17333e84123Smw FMTBSIZE, /* type B - long bus fault (68020/030) */
17433e84123Smw -1, -1, -1, -1 /* type C-F - undefined */
17533e84123Smw };
17633e84123Smw
17733e84123Smw #ifdef DEBUG
17833e84123Smw int mmudebug = 0;
17933e84123Smw #endif
18033e84123Smw
18106149f6fSmw extern struct pcb *curpcb;
18208fd7bc9Saymeric int _write_back(u_int, u_int, u_int, u_int, struct vm_map *);
18323bc2503Sthorpej static void userret(struct lwp *, int, u_quad_t);
18408fd7bc9Saymeric void panictrap(int, u_int, u_int, struct frame *);
18504aa4da3Schs void trapcpfault(struct lwp *, struct frame *, int);
18623bc2503Sthorpej void trapmmufault(int, u_int, u_int, struct frame *, struct lwp *,
18708fd7bc9Saymeric u_quad_t);
188d2eac2f6Smhitch void trap(struct frame *, int, u_int, u_int);
189db6f1b13Sveego #ifdef DDB
190db6f1b13Sveego #include <m68k/db_machdep.h>
19108fd7bc9Saymeric int kdb_trap(int, db_regs_t *);
192db6f1b13Sveego #endif
19308fd7bc9Saymeric void _wb_fault(void);
194db6f1b13Sveego
19506149f6fSmw
19663451f69Schopps static void
userret(struct lwp * l,int pc,u_quad_t oticks)197454af1c0Sdsl userret(struct lwp *l, int pc, u_quad_t oticks)
19863451f69Schopps {
19923bc2503Sthorpej struct proc *p = l->l_proc;
20063451f69Schopps
201ef56cc40Scl /* Invoke MI userret code */
202ef56cc40Scl mi_userret(l);
20323bc2503Sthorpej
2046ceb2246Schopps /*
2056ceb2246Schopps * If profiling, charge recent system time.
2066ceb2246Schopps */
207b07ec3fcSad if (p->p_stflag & PST_PROFIL) {
2086ceb2246Schopps extern int psratio;
20963451f69Schopps
210b07ec3fcSad addupc_task(l, pc, (int)(p->p_sticks - oticks) * psratio);
21163451f69Schopps }
21263451f69Schopps }
21363451f69Schopps
2144350a7f2Sscw /*
2154350a7f2Sscw * Used by the common m68k syscall() and child_return() functions.
2164350a7f2Sscw * XXX: Temporary until all m68k ports share common trap()/userret() code.
2174350a7f2Sscw */
21823bc2503Sthorpej void machine_userret(struct lwp *, struct frame *, u_quad_t);
2194350a7f2Sscw
2204350a7f2Sscw void
machine_userret(struct lwp * l,struct frame * f,u_quad_t t)221454af1c0Sdsl machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
2224350a7f2Sscw {
2234350a7f2Sscw
22423bc2503Sthorpej userret(l, f->f_pc, t);
2254350a7f2Sscw }
2264350a7f2Sscw
227602ef3f3Schopps void
panictrap(int type,u_int code,u_int v,struct frame * fp)22882357f6dSdsl panictrap(int type, u_int code, u_int v, struct frame *fp)
229602ef3f3Schopps {
23012490842Swiz static int panicking = 0;
23112490842Swiz if (panicking++ == 0) {
232ca36ac9eSchristos printf("trap type %d, code = %x, v = %x\n", type, code, v);
2331cd753c6Sthorpej regdump((struct trapframe *)fp, 128);
234602ef3f3Schopps }
235602ef3f3Schopps type &= ~T_USER;
236319c5313Schopps #ifdef DEBUG
237602ef3f3Schopps DCIS(); /* XXX? push cache */
238319c5313Schopps #endif
239602ef3f3Schopps if ((u_int)type < trap_types)
240602ef3f3Schopps panic(trap_type[type]);
241602ef3f3Schopps panic("trap");
242602ef3f3Schopps /*NOTREACHED*/
243602ef3f3Schopps }
244602ef3f3Schopps
245602ef3f3Schopps /*
246602ef3f3Schopps * return to fault handler
247602ef3f3Schopps */
248602ef3f3Schopps void
trapcpfault(struct lwp * l,struct frame * fp,int error)24904aa4da3Schs trapcpfault(struct lwp *l, struct frame *fp, int error)
250602ef3f3Schopps {
2513dc24f5aSrmind struct pcb *pcb = lwp_getpcb(l);
2523dc24f5aSrmind
253602ef3f3Schopps /*
254602ef3f3Schopps * We have arranged to catch this fault in one of the
255602ef3f3Schopps * copy to/from user space routines, set PC to return to
256602ef3f3Schopps * indicated location and set flag informing buserror code
257602ef3f3Schopps * that it may need to clean up stack frame.
258602ef3f3Schopps */
259602ef3f3Schopps fp->f_stackadj = exframesize[fp->f_format];
260602ef3f3Schopps fp->f_format = fp->f_vector = 0;
2613dc24f5aSrmind fp->f_pc = (int)pcb->pcb_onfault;
26204aa4da3Schs fp->f_regs[D0] = error;
263602ef3f3Schopps }
264602ef3f3Schopps
265f6ab1073Sis int donomore = 0;
266f6ab1073Sis
267602ef3f3Schopps void
trapmmufault(int type,u_int code,u_int v,struct frame * fp,struct lwp * l,u_quad_t sticks)26882357f6dSdsl trapmmufault(int type, u_int code, u_int v, struct frame *fp, struct lwp *l, u_quad_t sticks)
269602ef3f3Schopps {
270e138ae4fSis #if defined(DEBUG) && defined(M68060)
271f6ab1073Sis static u_int oldcode=0, oldv=0;
272f6ab1073Sis static struct proc *oldp=0;
273e138ae4fSis #endif
274821ec03eSchs extern struct vm_map *kernel_map;
27523bc2503Sthorpej struct proc *p = l->l_proc;
276db6f1b13Sveego struct vmspace *vm = NULL;
27704aa4da3Schs struct vm_map *map;
2783dc24f5aSrmind struct pcb *pcb;
27904aa4da3Schs void *onfault;
280602ef3f3Schopps vm_prot_t ftype;
281744246faSis vaddr_t va;
28241692372Scl ksiginfo_t ksi;
283602ef3f3Schopps int rv;
284602ef3f3Schopps
28504aa4da3Schs pcb = lwp_getpcb(l);
28604aa4da3Schs onfault = pcb->pcb_onfault;
28704aa4da3Schs
28868723a99Sthorpej KSI_INIT_TRAP(&ksi);
28941692372Scl ksi.ksi_trap = type & ~T_USER;
29041692372Scl
291602ef3f3Schopps /*
292602ef3f3Schopps * It is only a kernel address space fault iff:
293602ef3f3Schopps * 1. (type & T_USER) == 0 and
294602ef3f3Schopps * 2. pcb_onfault not set or
295602ef3f3Schopps * 3. pcb_onfault set but supervisor space data fault
296602ef3f3Schopps * The last can occur during an exec() copyin where the
297602ef3f3Schopps * argument space is lazy-allocated.
298602ef3f3Schopps */
299602ef3f3Schopps #ifdef DEBUG
300602ef3f3Schopps /*
301602ef3f3Schopps * Print out some data about the fault
302602ef3f3Schopps */
3030cd79344Sjtc #ifdef DEBUG_PAGE0
3048818afa4Sthorpej if (v < PAGE_SIZE) /* XXX PAGE0 */
3055dcc668eSchopps mmudebug |= 0x100; /* XXX PAGE0 */
3060cd79344Sjtc #endif
30722087826Schopps if (mmudebug && mmutype == MMU_68040) {
308f6ab1073Sis #ifdef M68060
309f6ab1073Sis if (machineid & AMIGA_68060) {
31035c9c776Sthorpej if (--donomore == 0 || mmudebug & 1) {
31135c9c776Sthorpej char bits[64];
3129a5d3f28Schristos snprintb(bits, sizeof(bits), FSLW_STRING, code);
31335c9c776Sthorpej printf ("68060 access error: pc %x, code %s,"
3149a5d3f28Schristos " ea %x\n", fp->f_pc, bits, v);
31535c9c776Sthorpej }
316f6ab1073Sis if (p == oldp && v == oldv && code == oldcode)
317f6ab1073Sis panic("Identical fault backtoback!");
318f6ab1073Sis if (donomore == 0)
319f6ab1073Sis panic("Tired of faulting.");
320f6ab1073Sis oldp = p;
321f6ab1073Sis oldv = v;
322f6ab1073Sis oldcode = code;
323f6ab1073Sis } else
324f6ab1073Sis #endif
325ca36ac9eSchristos printf("68040 access error: pc %x, code %x,"
326602ef3f3Schopps " ea %x, fa %x\n", fp->f_pc, code, fp->f_fmt7.f_ea, v);
327602ef3f3Schopps if (curpcb)
328db6e62f6Sis printf(" curpcb %p\n", curpcb);
329f6ab1073Sis
330f6ab1073Sis
3315dcc668eSchopps #ifdef DDB /* XXX PAGE0 */
3328818afa4Sthorpej if (v < PAGE_SIZE) /* XXX PAGE0 */
3335dcc668eSchopps Debugger(); /* XXX PAGE0 */
3345dcc668eSchopps #endif /* XXX PAGE0 */
335602ef3f3Schopps }
3360cd79344Sjtc #ifdef DEBUG_PAGE0
3374e276bb0Schopps mmudebug &= ~0x100; /* XXX PAGE0 */
338602ef3f3Schopps #endif
3390cd79344Sjtc #endif
340319c5313Schopps
341319c5313Schopps if (p)
342319c5313Schopps vm = p->p_vmspace;
343319c5313Schopps
34404aa4da3Schs if (type == T_MMUFLT && (l == &lwp0 || onfault == 0 || (
345f6ab1073Sis #ifdef M68060
346f6ab1073Sis machineid & AMIGA_68060 ? code & FSLW_TM_SV :
347f6ab1073Sis #endif
348f6ab1073Sis mmutype == MMU_68040 ? (code & SSW_TMMASK) == FC_SUPERD :
349f6ab1073Sis (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))))
350602ef3f3Schopps map = kernel_map;
351154d3024Srmind else
352602ef3f3Schopps map = &vm->vm_map;
353f6ab1073Sis
3549caa601eSchopps if (
355f6ab1073Sis #ifdef M68060
356f6ab1073Sis machineid & AMIGA_68060 ? code & FSLW_RW_W :
357f6ab1073Sis #endif
3589b0f085dSmhitch mmutype == MMU_68040 ? (code & (SSW_LK|SSW_RW040)) != SSW_RW040 :
3599b0f085dSmhitch ((code & SSW_DF) != 0 &&
3609b0f085dSmhitch ((code & SSW_RW) == 0 || (code & SSW_RM) != 0)))
361b744097aSchs ftype = VM_PROT_WRITE;
362602ef3f3Schopps else
363602ef3f3Schopps ftype = VM_PROT_READ;
364744246faSis va = trunc_page((vaddr_t)v);
365602ef3f3Schopps #ifdef DEBUG
366602ef3f3Schopps if (map == kernel_map && va == 0) {
367ca36ac9eSchristos printf("trap: bad kernel access at %x pc %x\n", v, fp->f_pc);
368602ef3f3Schopps panictrap(type, code, v, fp);
369602ef3f3Schopps }
370602ef3f3Schopps
371602ef3f3Schopps if (mmudebug)
37247fbb9d8Sdrochner printf("vm_fault(%p,%lx,%d)\n", map, va, ftype);
373602ef3f3Schopps #endif
374602ef3f3Schopps
37504aa4da3Schs pcb->pcb_onfault = NULL;
37647fbb9d8Sdrochner rv = uvm_fault(map, va, ftype);
37704aa4da3Schs pcb->pcb_onfault = onfault;
378602ef3f3Schopps
379602ef3f3Schopps #ifdef DEBUG
380602ef3f3Schopps if (mmudebug)
381ca36ac9eSchristos printf("vmfault %s %lx returned %d\n",
382602ef3f3Schopps map == kernel_map ? "kernel" : "user", va, rv);
383602ef3f3Schopps #endif
3849ea6b6e3Schs
385f6ab1073Sis #ifdef M68060
386f6ab1073Sis if ((machineid & AMIGA_68060) == 0 && mmutype == MMU_68040) {
387f6ab1073Sis #else
38822087826Schopps if (mmutype == MMU_68040) {
389f6ab1073Sis #endif
390ac3bc537Schs if (rv != 0) {
391602ef3f3Schopps goto nogo;
392602ef3f3Schopps }
393602ef3f3Schopps
394602ef3f3Schopps /*
395602ef3f3Schopps * The 68040 doesn't re-run instructions that cause
396602ef3f3Schopps * write page faults (unless due to a move16 isntruction).
397602ef3f3Schopps * So once the page is repaired, we have to write the
398602ef3f3Schopps * value of WB2D out to memory ourselves. Because
399602ef3f3Schopps * the writeback could possibly span two pages in
400602ef3f3Schopps * memory, so we need to check both "ends" of the
401602ef3f3Schopps * address to see if they are in the same page or not.
402602ef3f3Schopps * If not, then we need to make sure the second page
403602ef3f3Schopps * is valid, and bring it into memory if it's not.
404602ef3f3Schopps *
405602ef3f3Schopps * This whole process needs to be repeated for WB3 as well.
406602ef3f3Schopps * <sigh>
407602ef3f3Schopps */
408602ef3f3Schopps
409602ef3f3Schopps /* Check WB1 */
410602ef3f3Schopps if (fp->f_fmt7.f_wb1s & WBS_VALID) {
411ca36ac9eSchristos printf ("trap: wb1 was valid, not handled yet\n");
412602ef3f3Schopps panictrap(type, code, v, fp);
413602ef3f3Schopps }
414602ef3f3Schopps
415602ef3f3Schopps /*
416602ef3f3Schopps * Check WB2
417602ef3f3Schopps * skip if it's for a move16 instruction
418602ef3f3Schopps */
419602ef3f3Schopps if(fp->f_fmt7.f_wb2s & WBS_VALID &&
420602ef3f3Schopps ((fp->f_fmt7.f_wb2s & WBS_TTMASK)==WBS_TT_MOVE16) == 0) {
421602ef3f3Schopps if (_write_back(2, fp->f_fmt7.f_wb2s,
422ac3bc537Schs fp->f_fmt7.f_wb2d, fp->f_fmt7.f_wb2a, map) != 0)
423602ef3f3Schopps goto nogo;
424602ef3f3Schopps if ((fp->f_fmt7.f_wb2s & WBS_TMMASK)
425602ef3f3Schopps != (code & SSW_TMMASK))
426602ef3f3Schopps panictrap(type, code, v, fp);
427602ef3f3Schopps }
428602ef3f3Schopps
429602ef3f3Schopps /* Check WB3 */
430602ef3f3Schopps if(fp->f_fmt7.f_wb3s & WBS_VALID) {
431821ec03eSchs struct vm_map *wb3_map;
432602ef3f3Schopps
433602ef3f3Schopps if ((fp->f_fmt7.f_wb3s & WBS_TMMASK) == WBS_TM_SDATA)
434602ef3f3Schopps wb3_map = kernel_map;
435602ef3f3Schopps else
436602ef3f3Schopps wb3_map = &vm->vm_map;
437602ef3f3Schopps if (_write_back(3, fp->f_fmt7.f_wb3s,
438ac3bc537Schs fp->f_fmt7.f_wb3d, fp->f_fmt7.f_wb3a, wb3_map) != 0)
439602ef3f3Schopps goto nogo;
440602ef3f3Schopps }
441602ef3f3Schopps }
442602ef3f3Schopps
443602ef3f3Schopps /*
444602ef3f3Schopps * If this was a stack access we keep track of the maximum
445602ef3f3Schopps * accessed stack size. Also, if vm_fault gets a protection
446602ef3f3Schopps * failure it is due to accessing the stack region outside
447602ef3f3Schopps * the current limit and we need to reflect that as an access
448602ef3f3Schopps * error.
449602ef3f3Schopps */
450ac3bc537Schs if (rv == 0) {
45153524e44Schristos if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
45264969161Sjdolecek uvm_grow(p, va);
453602ef3f3Schopps
454602ef3f3Schopps if (type == T_MMUFLT)
455602ef3f3Schopps return;
45623bc2503Sthorpej userret(l, fp->f_pc, sticks);
457602ef3f3Schopps return;
458602ef3f3Schopps }
459602ef3f3Schopps nogo:
460602ef3f3Schopps if (type == T_MMUFLT) {
46104aa4da3Schs if (onfault) {
46204aa4da3Schs trapcpfault(l, fp, rv);
463602ef3f3Schopps return;
464602ef3f3Schopps }
46547fbb9d8Sdrochner printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
466dc9188e3Smhitch map, va, ftype, rv);
467ca36ac9eSchristos printf(" type %x, code [mmu,,ssw]: %x\n",
468602ef3f3Schopps type, code);
469602ef3f3Schopps panictrap(type, code, v, fp);
470602ef3f3Schopps }
47141692372Scl ksi.ksi_addr = (void *)v;
4720eb69247Smlelstv switch (rv) {
4730eb69247Smlelstv case ENOMEM:
474ab7269f6Schs printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
475ab7269f6Schs p->p_pid, p->p_comm,
476f474dcebSad l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1);
47741692372Scl ksi.ksi_signo = SIGKILL;
4780eb69247Smlelstv break;
4790eb69247Smlelstv case EINVAL:
4800eb69247Smlelstv ksi.ksi_signo = SIGBUS;
4810eb69247Smlelstv ksi.ksi_code = BUS_ADRERR;
4820eb69247Smlelstv break;
4830eb69247Smlelstv case EACCES:
48441692372Scl ksi.ksi_signo = SIGSEGV;
4850eb69247Smlelstv ksi.ksi_code = SEGV_ACCERR;
4860eb69247Smlelstv break;
4870eb69247Smlelstv default:
4880eb69247Smlelstv ksi.ksi_signo = SIGSEGV;
4890eb69247Smlelstv ksi.ksi_code = SEGV_MAPERR;
4900eb69247Smlelstv break;
491ab7269f6Schs }
49241692372Scl trapsignal(l, &ksi);
493602ef3f3Schopps if ((type & T_USER) == 0)
494602ef3f3Schopps return;
49523bc2503Sthorpej userret(l, fp->f_pc, sticks);
496602ef3f3Schopps }
49733e84123Smw /*
49833e84123Smw * Trap is called from locore to handle most types of processor traps,
49933e84123Smw * including events such as simulated software interrupts/AST's.
50033e84123Smw * System calls are broken out for efficiency.
50133e84123Smw */
50233e84123Smw /*ARGSUSED*/
503db6f1b13Sveego void
50482357f6dSdsl trap(struct frame *fp, int type, u_int code, u_int v)
50533e84123Smw {
50623bc2503Sthorpej struct lwp *l;
507602ef3f3Schopps struct proc *p;
5083dc24f5aSrmind struct pcb *pcb;
50941692372Scl ksiginfo_t ksi;
510db6f1b13Sveego u_quad_t sticks = 0;
51133e84123Smw
51223bc2503Sthorpej l = curlwp;
51304aa4da3Schs p = l->l_proc;
51404aa4da3Schs pcb = lwp_getpcb(l);
51504aa4da3Schs
516ccde4787Smatt curcpu()->ci_data.cpu_ntrap++;
517602ef3f3Schopps
51868723a99Sthorpej KSI_INIT_TRAP(&ksi);
51941692372Scl ksi.ksi_trap = type & ~T_USER;
52041692372Scl
521d2eac2f6Smhitch if (USERMODE(fp->f_sr)) {
52233e84123Smw type |= T_USER;
5236ceb2246Schopps sticks = p->p_sticks;
524d2eac2f6Smhitch l->l_md.md_regs = fp->f_regs;
5252b79369cSad LWP_CACHE_CREDS(l, p);
52633e84123Smw }
52706149f6fSmw
52806149f6fSmw #ifdef DDB
52906149f6fSmw if (type == T_TRACE || type == T_BREAKPOINT) {
530d2eac2f6Smhitch if (kdb_trap(type, (db_regs_t *)fp))
53106149f6fSmw return;
53206149f6fSmw }
53306149f6fSmw #endif
534e138ae4fSis #ifdef DEBUG
535f6ab1073Sis if (mmudebug & 2)
536d3662916Schristos printf("%s: t %x c %x v %x adj %x sr %x pc %x fmt %x vc %x\n",
537d3662916Schristos __func__, type, code, v, fp->f_stackadj, fp->f_sr,
538d2eac2f6Smhitch fp->f_pc, fp->f_format, fp->f_vector);
539e138ae4fSis #endif
54033e84123Smw switch (type) {
54133e84123Smw default:
542d2eac2f6Smhitch panictrap(type, code, v, fp);
54333e84123Smw /*
544602ef3f3Schopps * Kernel Bus error
54533e84123Smw */
546602ef3f3Schopps case T_BUSERR:
54704aa4da3Schs if (!pcb->pcb_onfault)
548d2eac2f6Smhitch panictrap(type, code, v, fp);
54904aa4da3Schs trapcpfault(l, fp, EFAULT);
55033e84123Smw return;
551602ef3f3Schopps /*
552602ef3f3Schopps * User Bus/Addr error.
553602ef3f3Schopps */
554602ef3f3Schopps case T_BUSERR|T_USER:
555602ef3f3Schopps case T_ADDRERR|T_USER:
55641692372Scl ksi.ksi_addr = (void *)v;
55741692372Scl ksi.ksi_signo = SIGBUS;
55841692372Scl ksi.ksi_code = (type == (T_BUSERR|T_USER)) ?
55941692372Scl BUS_OBJERR : BUS_ADRERR;
56033e84123Smw break;
561602ef3f3Schopps /*
562602ef3f3Schopps * User illegal/privleged inst fault
563602ef3f3Schopps */
564602ef3f3Schopps case T_ILLINST|T_USER:
565602ef3f3Schopps case T_PRIVINST|T_USER:
566d2eac2f6Smhitch ksi.ksi_addr = (void *)(int)fp->f_format;
56741692372Scl /* XXX was ILL_PRIVIN_FAULT */
56841692372Scl ksi.ksi_signo = SIGILL;
56941692372Scl ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ?
57041692372Scl ILL_PRVOPC : ILL_ILLOPC;
571602ef3f3Schopps break;
572602ef3f3Schopps /*
573602ef3f3Schopps * divde by zero, CHK/TRAPV inst
574602ef3f3Schopps */
575602ef3f3Schopps case T_ZERODIV|T_USER:
576*5f04920cSrin ksi.ksi_code = FPE_INTDIV;
577602ef3f3Schopps case T_CHKINST|T_USER:
578602ef3f3Schopps case T_TRAPVINST|T_USER:
579d2eac2f6Smhitch ksi.ksi_addr = (void *)(int)fp->f_format;
58041692372Scl ksi.ksi_signo = SIGFPE;
581602ef3f3Schopps break;
582006b6172Sis
583006b6172Sis case T_FPEMULI|T_USER:
584006b6172Sis case T_FPEMULD|T_USER:
585006b6172Sis #ifdef FPU_EMULATE
5863dc24f5aSrmind if (fpu_emulate(fp, &pcb->pcb_fpregs, &ksi) == 0)
587d2eac2f6Smhitch ; /* XXX - Deal with tracing? (fp->f_sr & PSL_T) */
588006b6172Sis #else
589006b6172Sis printf("pid %d killed: no floating point support\n", p->p_pid);
59041692372Scl ksi.ksi_signo = SIGILL;
59141692372Scl ksi.ksi_code = ILL_ILLOPC;
592006b6172Sis #endif
593006b6172Sis break;
594006b6172Sis
59533e84123Smw #ifdef FPCOPROC
596602ef3f3Schopps /*
597602ef3f3Schopps * User coprocessor violation
598602ef3f3Schopps */
599602ef3f3Schopps case T_COPERR|T_USER:
60041692372Scl /* XXX What is a proper response here? */
60141692372Scl ksi.ksi_signo = SIGFPE;
60241692372Scl ksi.ksi_code = FPE_FLTINV;
603602ef3f3Schopps break;
604602ef3f3Schopps /*
605602ef3f3Schopps * 6888x exceptions
606602ef3f3Schopps */
607602ef3f3Schopps case T_FPERR|T_USER:
608602ef3f3Schopps /*
609602ef3f3Schopps * We pass along the 68881 status register which locore
610f055e182Smartin * stashed in code for us.
611602ef3f3Schopps */
61241692372Scl ksi.ksi_signo = SIGFPE;
613f055e182Smartin ksi.ksi_code = fpsr2siginfocode(code);
614602ef3f3Schopps break;
615602ef3f3Schopps /*
616602ef3f3Schopps * Kernel coprocessor violation
617602ef3f3Schopps */
618602ef3f3Schopps case T_COPERR:
619602ef3f3Schopps /*FALLTHROUGH*/
62033e84123Smw #endif
621602ef3f3Schopps /*
622602ef3f3Schopps * Kernel format error
623602ef3f3Schopps */
624602ef3f3Schopps case T_FMTERR:
62533e84123Smw /*
62633e84123Smw * The user has most likely trashed the RTE or FP state info
62733e84123Smw * in the stack frame of a signal handler.
62833e84123Smw */
62933e84123Smw type |= T_USER;
630602ef3f3Schopps #ifdef DEBUG
631ca36ac9eSchristos printf("pid %d: kernel %s exception\n", p->p_pid,
63233e84123Smw type==T_COPERR ? "coprocessor" : "format");
633602ef3f3Schopps #endif
634284c2b9aSad mutex_enter(p->p_lock);
635de31133fSjdolecek SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
636de31133fSjdolecek sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
637de31133fSjdolecek sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
638b07ec3fcSad sigdelset(&l->l_sigmask, SIGILL);
639284c2b9aSad mutex_exit(p->p_lock);
640b07ec3fcSad
64141692372Scl ksi.ksi_signo = SIGILL;
642d2eac2f6Smhitch ksi.ksi_addr = (void *)(int)fp->f_format;
64341692372Scl /* XXX was ILL_RESAD_FAULT */
64441692372Scl ksi.ksi_code = (type == T_COPERR) ?
64541692372Scl ILL_COPROC : ILL_ILLOPC;
64633e84123Smw break;
64733e84123Smw /*
648602ef3f3Schopps * Trace traps.
64933e84123Smw *
650602ef3f3Schopps * M68k NetBSD uses trap #2,
65133e84123Smw * SUN 3.x uses trap #15,
65233e84123Smw * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere).
65333e84123Smw *
654602ef3f3Schopps * Amiga traps get mapped by locore.s into T_TRACE.
65533e84123Smw * SUN 3.x traps get passed through as T_TRAP15 and are not really
65633e84123Smw * supported yet.
65733e84123Smw */
658602ef3f3Schopps case T_TRACE:
659602ef3f3Schopps case T_TRAP15:
660d2eac2f6Smhitch fp->f_sr &= ~PSL_T;
66141692372Scl ksi.ksi_signo = SIGTRAP;
66233e84123Smw break;
663602ef3f3Schopps case T_TRACE|T_USER:
664602ef3f3Schopps case T_TRAP15|T_USER:
6652be73160Smw #ifdef COMPAT_SUNOS
666602ef3f3Schopps /*
66796914606Skleink * SunOS uses Trap #2 for a "CPU cache flush".
66896914606Skleink * Just flush the on-chip caches and return.
669602ef3f3Schopps */
670de42a28aSchristos if (p->p_emul == &emul_sunos) {
67196914606Skleink ICIA();
67296914606Skleink DCIU();
673602ef3f3Schopps return;
674602ef3f3Schopps }
6752be73160Smw #endif
676d2eac2f6Smhitch fp->f_sr &= ~PSL_T;
677*5f04920cSrin ksi.ksi_addr = (void *)fp->f_pc;
67841692372Scl ksi.ksi_signo = SIGTRAP;
679*5f04920cSrin if (type == (T_TRAP15|T_USER))
680*5f04920cSrin ksi.ksi_code = TRAP_BRKPT;
681*5f04920cSrin else
682*5f04920cSrin ksi.ksi_code = TRAP_TRACE;
68333e84123Smw break;
684602ef3f3Schopps /*
685602ef3f3Schopps * Kernel AST (should not happen)
686602ef3f3Schopps */
687602ef3f3Schopps case T_ASTFLT:
688d2eac2f6Smhitch panictrap(type, code, v, fp);
689602ef3f3Schopps /*
690602ef3f3Schopps * User AST
691602ef3f3Schopps */
692602ef3f3Schopps case T_ASTFLT|T_USER:
69333e84123Smw astpending = 0;
69433e84123Smw spl0();
695b07ec3fcSad if (l->l_pflag & LP_OWEUPC) {
696b07ec3fcSad l->l_pflag &= ~LP_OWEUPC;
697b07ec3fcSad ADDUPROF(l);
69833e84123Smw }
699d2eac2f6Smhitch userret(l, fp->f_pc, sticks);
700602ef3f3Schopps return;
701602ef3f3Schopps /*
702602ef3f3Schopps * Kernel/User page fault
703602ef3f3Schopps */
704602ef3f3Schopps case T_MMUFLT:
70533e84123Smw case T_MMUFLT|T_USER: /* page fault */
706d2eac2f6Smhitch trapmmufault(type, code, v, fp, l, sticks);
70733e84123Smw return;
70833e84123Smw }
709602ef3f3Schopps
710602ef3f3Schopps #ifdef DEBUG
71141692372Scl if (ksi.ksi_signo != SIGTRAP)
71241692372Scl printf("trapsignal(%d, %d, %d, %x, %x)\n", p->p_pid,
713d2eac2f6Smhitch ksi.ksi_signo, ksi.ksi_code, v, fp->f_pc);
71406149f6fSmw #endif
71541692372Scl if (ksi.ksi_signo)
71641692372Scl trapsignal(l, &ksi);
71733e84123Smw if ((type & T_USER) == 0)
71833e84123Smw return;
719d2eac2f6Smhitch userret(l, fp->f_pc, sticks);
72033e84123Smw }
72133e84123Smw
72233e84123Smw /*
72306149f6fSmw * Process a pending write back
72406149f6fSmw */
725db6f1b13Sveego int
72682357f6dSdsl _write_back (u_int wb, u_int wb_sts, u_int wb_data, u_int wb_addr, struct vm_map *wb_map)
72782357f6dSdsl /* wb: writeback type: 1, 2, or 3 */
72882357f6dSdsl /* wb_sts: writeback status information */
72982357f6dSdsl /* wb_data: data to writeback */
73082357f6dSdsl /* wb_addr: address to writeback to */
73106149f6fSmw {
73206149f6fSmw u_int wb_extra_page = 0;
73306149f6fSmw u_int wb_rc, mmusr;
73404aa4da3Schs void *onfault;
73506149f6fSmw
73606149f6fSmw #ifdef DEBUG
73706149f6fSmw if (mmudebug)
738ca36ac9eSchristos printf("wb%d valid: %x %x %x\n",wb,wb_sts,wb_addr,wb_data);
73906149f6fSmw #endif
74006149f6fSmw
74106149f6fSmw /* See if we're going to span two pages (for word or long transfers) */
74206149f6fSmw
74306149f6fSmw if((wb_sts & WBS_SZMASK) == WBS_SIZE_WORD)
744744246faSis if(trunc_page((vaddr_t)wb_addr) !=
745744246faSis trunc_page((vaddr_t)wb_addr+1))
74606149f6fSmw wb_extra_page = 1;
74706149f6fSmw
74806149f6fSmw if((wb_sts & WBS_SZMASK) == WBS_SIZE_LONG)
749744246faSis if(trunc_page((vaddr_t)wb_addr) !=
750744246faSis trunc_page((vaddr_t)wb_addr+3))
75106149f6fSmw wb_extra_page = 3;
75206149f6fSmw
75306149f6fSmw /*
75406149f6fSmw * if it's writeback 3, we need to check the first page
75506149f6fSmw */
75606149f6fSmw if (wb == 3) {
75706149f6fSmw mmusr = probeva(wb_addr, wb_sts & WBS_TMMASK);
75806149f6fSmw #ifdef DEBUG
75906149f6fSmw if (mmudebug)
760ca36ac9eSchristos printf("wb3: probeva(%x,%x) = %x\n",
76163451f69Schopps wb_addr + wb_extra_page, wb_sts & WBS_TMMASK, mmusr);
76206149f6fSmw #endif
76306149f6fSmw
764d6f84d66Schopps if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) {
76506149f6fSmw #ifdef DEBUG
76606149f6fSmw if (mmudebug)
767ca36ac9eSchristos printf("wb3: need to bring in first page\n");
76806149f6fSmw #endif
76904aa4da3Schs onfault = curpcb->pcb_onfault;
77004aa4da3Schs curpcb->pcb_onfault = NULL;
771dc9188e3Smhitch wb_rc = uvm_fault(wb_map,
772dc9188e3Smhitch trunc_page((vm_offset_t)wb_addr),
77347fbb9d8Sdrochner VM_PROT_READ | VM_PROT_WRITE);
77404aa4da3Schs curpcb->pcb_onfault = onfault;
77506149f6fSmw
776ac3bc537Schs if (wb_rc != 0)
77706149f6fSmw return (wb_rc);
77806149f6fSmw #ifdef DEBUG
77906149f6fSmw if (mmudebug)
780ca36ac9eSchristos printf("wb3: first page brought in.\n");
78106149f6fSmw #endif
78206149f6fSmw }
78306149f6fSmw }
78406149f6fSmw
78506149f6fSmw /*
78606149f6fSmw * now check to see if a second page is required
78706149f6fSmw */
78806149f6fSmw if(wb_extra_page) {
78906149f6fSmw
79006149f6fSmw mmusr = probeva(wb_addr+wb_extra_page, wb_sts & WBS_TMMASK);
79106149f6fSmw #ifdef DEBUG
79206149f6fSmw if (mmudebug)
793ca36ac9eSchristos printf("wb%d: probeva %x %x = %x\n",
79463451f69Schopps wb, wb_addr + wb_extra_page,
79563451f69Schopps wb_sts & WBS_TMMASK,mmusr);
79606149f6fSmw #endif
79706149f6fSmw
798d6f84d66Schopps if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) {
79906149f6fSmw #ifdef DEBUG
80006149f6fSmw if (mmudebug)
801ca36ac9eSchristos printf("wb%d: page boundary crossed."
80263451f69Schopps " Bringing in extra page.\n",wb);
80306149f6fSmw #endif
80406149f6fSmw
80504aa4da3Schs onfault = curpcb->pcb_onfault;
80604aa4da3Schs curpcb->pcb_onfault = NULL;
807dc9188e3Smhitch wb_rc = uvm_fault(wb_map,
808dc9188e3Smhitch trunc_page((vm_offset_t)wb_addr + wb_extra_page),
80947fbb9d8Sdrochner VM_PROT_READ | VM_PROT_WRITE);
81004aa4da3Schs curpcb->pcb_onfault = onfault;
81106149f6fSmw
812ac3bc537Schs if (wb_rc != 0)
81306149f6fSmw return (wb_rc);
81406149f6fSmw }
81506149f6fSmw #ifdef DEBUG
81606149f6fSmw if (mmudebug)
817ca36ac9eSchristos printf("wb%d: extra page brought in okay.\n", wb);
81806149f6fSmw #endif
81906149f6fSmw }
82006149f6fSmw
82106149f6fSmw /* Actually do the write now */
82206149f6fSmw
82306149f6fSmw if ((wb_sts & WBS_TMMASK) == FC_USERD &&
82406149f6fSmw !curpcb->pcb_onfault) {
82553524e44Schristos curpcb->pcb_onfault = (void *) _wb_fault;
82606149f6fSmw }
82706149f6fSmw
82806149f6fSmw switch(wb_sts & WBS_SZMASK) {
82906149f6fSmw
83006149f6fSmw case WBS_SIZE_BYTE :
8312d65de24Sperry __asm volatile ("movec %0,%%dfc ; movesb %1,%2@":: "d" (wb_sts & WBS_TMMASK),
83206149f6fSmw "d" (wb_data),
83306149f6fSmw "a" (wb_addr));
83406149f6fSmw break;
83506149f6fSmw
83606149f6fSmw case WBS_SIZE_WORD :
8372d65de24Sperry __asm volatile ("movec %0,%%dfc ; movesw %1,%2@":: "d" (wb_sts & WBS_TMMASK),
83806149f6fSmw "d" (wb_data),
83906149f6fSmw "a" (wb_addr));
84006149f6fSmw break;
84106149f6fSmw
84206149f6fSmw case WBS_SIZE_LONG :
8432d65de24Sperry __asm volatile ("movec %0,%%dfc ; movesl %1,%2@":: "d" (wb_sts & WBS_TMMASK),
84406149f6fSmw "d" (wb_data),
84506149f6fSmw "a" (wb_addr));
84606149f6fSmw break;
84706149f6fSmw
84806149f6fSmw }
84953524e44Schristos if (curpcb->pcb_onfault == (void *) _wb_fault)
85006149f6fSmw curpcb->pcb_onfault = NULL;
85106149f6fSmw if ((wb_sts & WBS_TMMASK) != FC_USERD)
8522d65de24Sperry __asm volatile ("movec %0,%%dfc\n" : : "d" (FC_USERD));
853ac3bc537Schs return 0;
85406149f6fSmw }
85506149f6fSmw
85606149f6fSmw /*
85706149f6fSmw * fault handler for write back
85806149f6fSmw */
859db6f1b13Sveego void
860df7f595eScegger _wb_fault(void)
86106149f6fSmw {
86206149f6fSmw #ifdef DEBUG
863ca36ac9eSchristos printf ("trap: writeback fault\n");
86406149f6fSmw #endif
86506149f6fSmw return;
86606149f6fSmw }
867