Home | History | Annotate | Line # | Download | only in m68k
      1 /*	$NetBSD: m68k_trap.c,v 1.4 2024/01/20 00:15:31 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 University of Utah.
      5  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
      6  * All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * the Systems Programming Group of the University of Utah Computer
     10  * Science Department.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  * from: Utah $Hdr: trap.c 1.32 91/04/06$
     37  *
     38  *	@(#)trap.c      7.15 (Berkeley) 8/2/91
     39  */
     40 
     41 #include <sys/cdefs.h>
     42 __KERNEL_RCSID(0, "$NetBSD: m68k_trap.c,v 1.4 2024/01/20 00:15:31 thorpej Exp $");
     43 
     44 #include "opt_m68k_arch.h"
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/proc.h>
     49 #include <sys/kauth.h>
     50 
     51 #include <uvm/uvm_extern.h>
     52 
     53 #include <m68k/cpu.h>
     54 #include <m68k/cacheops.h>
     55 
     56 #include <machine/trap.h>
     57 #include <machine/cpu.h>
     58 #include <machine/pcb.h>
     59 
     60 extern int suline(void *, void *);	/* locore.s */
     61 
     62 volatile int astpending;
     63 
     64 #ifdef M68060
     65 #define	KDFAULT_060(c)	(cputype == CPU_68060 && ((c) & FSLW_TM_SV))
     66 #define	WRFAULT_060(c)	(cputype == CPU_68060 && ((c) & FSLW_RW_W))
     67 #else
     68 #define	KDFAULT_060(c)	0
     69 #define	WRFAULT_060(c)	0
     70 #endif
     71 
     72 #ifdef M68040
     73 #define	KDFAULT_040(c)	(cputype == CPU_68040 && \
     74 			 ((c) & SSW4_TMMASK) == SSW4_TMKD)
     75 #define	WRFAULT_040(c)	(cputype == CPU_68040 && \
     76 			 ((c) & (SSW4_LK|SSW4_RW)) != SSW4_RW)
     77 #else
     78 #define	KDFAULT_040(c)	0
     79 #define	WRFAULT_040(c)	0
     80 #endif
     81 
     82 #if defined(M68030) || defined(M68020)
     83 #define	KDFAULT_OTH(c)	(cputype <= CPU_68030 && \
     84 			 ((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
     85 #define	WRFAULT_OTH(c)	(cputype <= CPU_68030 && \
     86 			 (((c) & SSW_DF) != 0 && \
     87 			 ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0))))
     88 #else
     89 #define	KDFAULT_OTH(c)	0
     90 #define	WRFAULT_OTH(c)	0
     91 #endif
     92 
     93 #define	KDFAULT(c)	(KDFAULT_060(c) || KDFAULT_040(c) || KDFAULT_OTH(c))
     94 #define	WRFAULT(c)	(WRFAULT_060(c) || WRFAULT_040(c) || WRFAULT_OTH(c))
     95 
     96 
     97 #ifdef DEBUG
     98 extern int mmudebug, mmupid;
     99 #define MDB_FOLLOW	1
    100 #define MDB_WBFOLLOW	2
    101 #define MDB_WBFAILED	4
    102 #define MDB_ISPID(pid)	((pid) == mmupid)
    103 #endif
    104 
    105 #ifdef M68040
    106 #ifdef DEBUG
    107 struct writebackstats {
    108 	int calls;
    109 	int cpushes;
    110 	int move16s;
    111 	int wb1s, wb2s, wb3s;
    112 	int wbsize[4];
    113 } wbstats;
    114 
    115 static const char *f7sz[] = { "longword", "byte", "word", "line" };
    116 static const char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" };
    117 static const char *f7tm[] = { "d-push", "u-data", "u-code", "M-data",
    118 		 "M-code", "k-data", "k-code", "RES" };
    119 static const char wberrstr[] =
    120     "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n";
    121 
    122 static void
    123 dumpssw(u_short ssw)
    124 {
    125 	printf(" SSW: %x: ", ssw);
    126 	if (ssw & SSW4_CP)
    127 		printf("CP,");
    128 	if (ssw & SSW4_CU)
    129 		printf("CU,");
    130 	if (ssw & SSW4_CT)
    131 		printf("CT,");
    132 	if (ssw & SSW4_CM)
    133 		printf("CM,");
    134 	if (ssw & SSW4_MA)
    135 		printf("MA,");
    136 	if (ssw & SSW4_ATC)
    137 		printf("ATC,");
    138 	if (ssw & SSW4_LK)
    139 		printf("LK,");
    140 	if (ssw & SSW4_RW)
    141 		printf("RW,");
    142 	printf(" SZ=%s, TT=%s, TM=%s\n",
    143 	       f7sz[(ssw & SSW4_SZMASK) >> 5],
    144 	       f7tt[(ssw & SSW4_TTMASK) >> 3],
    145 	       f7tm[ssw & SSW4_TMMASK]);
    146 }
    147 
    148 static void
    149 dumpwb(int num, u_short s, u_int a, u_int d)
    150 {
    151 	struct proc *p = curproc;
    152 	paddr_t pa;
    153 
    154 	printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n",
    155 	       num, a, d, f7sz[(s & SSW4_SZMASK) >> 5],
    156 	       f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]);
    157 	printf("               PA ");
    158 	if (pmap_extract(p->p_vmspace->vm_map.pmap, (vaddr_t)a, &pa) == false)
    159 		printf("<invalid address>");
    160 	else {
    161 		u_long val;
    162 		if (ufetch_long((void *)a, &val) != 0)
    163 			val = (u_long)-1;
    164 		printf("%lx, current value %lx", pa, val);
    165 	}
    166 	printf("\n");
    167 }
    168 #endif /* DEBUG  */
    169 
    170 /* Because calling memcpy() for 16 bytes is *way* too much overhead ... */
    171 static inline void
    172 fastcopy16(u_int *dst, const u_int *src)
    173 {
    174 	*dst++ = *src++;
    175 	*dst++ = *src++;
    176 	*dst++ = *src++;
    177 	*dst = *src;
    178 }
    179 
    180 int
    181 m68040_writeback(struct frame *fp, int docachepush)
    182 {
    183 	struct fmt7 *f = &fp->f_fmt7;
    184 	struct lwp *l = curlwp;
    185 	struct proc *p = l->l_proc;
    186 	struct pcb *pcb = lwp_getpcb(l);
    187 	int err = 0;
    188 	u_int fa = 0;
    189 	void *oonfault = pcb->pcb_onfault;
    190 	paddr_t pa;
    191 
    192 #ifdef DEBUG
    193 	if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
    194 		printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa);
    195 		dumpssw(f->f_ssw);
    196 	}
    197 	wbstats.calls++;
    198 #endif
    199 	/*
    200 	 * Deal with special cases first.
    201 	 */
    202 	if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) {
    203 		/*
    204 		 * Dcache push fault.
    205 		 * Line-align the address and write out the push data to
    206 		 * the indicated physical address.
    207 		 */
    208 #ifdef DEBUG
    209 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
    210 			printf(" pushing %s to PA %x, data %x",
    211 			       f7sz[(f->f_ssw & SSW4_SZMASK) >> 5],
    212 			       f->f_fa, f->f_pd0);
    213 			if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN)
    214 				printf("/%x/%x/%x",
    215 				       f->f_pd1, f->f_pd2, f->f_pd3);
    216 			printf("\n");
    217 		}
    218 		if (f->f_wb1s & SSW4_WBSV)
    219 			panic("writeback: cache push with WB1S valid");
    220 		wbstats.cpushes++;
    221 #endif
    222 		/*
    223 		 * XXX there are security problems if we attempt to do a
    224 		 * cache push after a signal handler has been called.
    225 		 */
    226 		if (docachepush) {
    227 			pmap_enter(pmap_kernel(), (vaddr_t)vmmap,
    228 			    trunc_page(f->f_fa), VM_PROT_WRITE,
    229 			    VM_PROT_WRITE|PMAP_WIRED);
    230 			pmap_update(pmap_kernel());
    231 			fa = (u_int)&vmmap[m68k_page_offset(f->f_fa) & ~0xF];
    232 			fastcopy16((void *)fa, (void *)&f->f_pd0);
    233 			(void) pmap_extract(pmap_kernel(), (vaddr_t)fa, &pa);
    234 			DCFL(pa);
    235 			pmap_remove(pmap_kernel(), (vaddr_t)vmmap,
    236 				    (vaddr_t)&vmmap[PAGE_SIZE]);
    237 			pmap_update(pmap_kernel());
    238 		} else
    239 			printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n",
    240 			       p->p_pid, p->p_comm, kauth_cred_geteuid(l->l_cred));
    241 	} else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) {
    242 		/*
    243 		 * MOVE16 fault.
    244 		 * Line-align the address and write out the push data to
    245 		 * the indicated virtual address.
    246 		 */
    247 #ifdef DEBUG
    248 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
    249 			printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n",
    250 			       f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1,
    251 			       f->f_pd2, f->f_pd3);
    252 		if (f->f_wb1s & SSW4_WBSV)
    253 			panic("writeback: MOVE16 with WB1S valid");
    254 		wbstats.move16s++;
    255 #endif
    256 		if (KDFAULT(f->f_wb1s))
    257 			fastcopy16((void *)(f->f_fa & ~0xF), (void *)&f->f_pd0);
    258 		else
    259 			err = suline((void *)(f->f_fa & ~0xF), (void *)&f->f_pd0);
    260 		if (err) {
    261 			fa = f->f_fa & ~0xF;
    262 #ifdef DEBUG
    263 			if (mmudebug & MDB_WBFAILED)
    264 				printf(wberrstr, p->p_pid, p->p_comm,
    265 				       "MOVE16", fp->f_pc, f->f_fa,
    266 				       f->f_fa & ~0xF, f->f_pd0);
    267 #endif
    268 		}
    269 	} else if (f->f_wb1s & SSW4_WBSV) {
    270 		/*
    271 		 * Writeback #1.
    272 		 * Position the "memory-aligned" data and write it out.
    273 		 */
    274 		u_int wb1d = f->f_wb1d;
    275 		int off;
    276 
    277 #ifdef DEBUG
    278 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
    279 			dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d);
    280 		wbstats.wb1s++;
    281 		wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
    282 #endif
    283 		off = (f->f_wb1a & 3) * 8;
    284 		switch (f->f_wb1s & SSW4_SZMASK) {
    285 		case SSW4_SZLW:
    286 			if (off)
    287 				wb1d = (wb1d >> (32 - off)) | (wb1d << off);
    288 			if (KDFAULT(f->f_wb1s))
    289 				*(long *)f->f_wb1a = wb1d;
    290 			else
    291 				err = ustore_long((void *)f->f_wb1a, wb1d);
    292 			break;
    293 		case SSW4_SZB:
    294 			off = 24 - off;
    295 			if (off)
    296 				wb1d >>= off;
    297 			if (KDFAULT(f->f_wb1s))
    298 				*(char *)f->f_wb1a = wb1d;
    299 			else
    300 				err = ustore_char((void *)f->f_wb1a, wb1d);
    301 			break;
    302 		case SSW4_SZW:
    303 			off = (off + 16) % 32;
    304 			if (off)
    305 				wb1d = (wb1d >> (32 - off)) | (wb1d << off);
    306 			if (KDFAULT(f->f_wb1s))
    307 				*(short *)f->f_wb1a = wb1d;
    308 			else
    309 				err = ustore_short((void *)f->f_wb1a, wb1d);
    310 			break;
    311 		}
    312 		if (err) {
    313 			fa = f->f_wb1a;
    314 #ifdef DEBUG
    315 			if (mmudebug & MDB_WBFAILED)
    316 				printf(wberrstr, p->p_pid, p->p_comm,
    317 				       "#1", fp->f_pc, f->f_fa,
    318 				       f->f_wb1a, f->f_wb1d);
    319 #endif
    320 		}
    321 	}
    322 	/*
    323 	 * Deal with the "normal" writebacks.
    324 	 *
    325 	 * XXX writeback2 is known to reflect a LINE size writeback after
    326 	 * a MOVE16 was already dealt with above.  Ignore it.
    327 	 */
    328 	if (err == 0 && (f->f_wb2s & SSW4_WBSV) &&
    329 	    (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) {
    330 #ifdef DEBUG
    331 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
    332 			dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
    333 		wbstats.wb2s++;
    334 		wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
    335 #endif
    336 		switch (f->f_wb2s & SSW4_SZMASK) {
    337 		case SSW4_SZLW:
    338 			if (KDFAULT(f->f_wb2s))
    339 				*(long *)f->f_wb2a = f->f_wb2d;
    340 			else
    341 				err = ustore_long((void *)f->f_wb2a, f->f_wb2d);
    342 			break;
    343 		case SSW4_SZB:
    344 			if (KDFAULT(f->f_wb2s))
    345 				*(char *)f->f_wb2a = f->f_wb2d;
    346 			else
    347 				err = ustore_char((void *)f->f_wb2a, f->f_wb2d);
    348 			break;
    349 		case SSW4_SZW:
    350 			if (KDFAULT(f->f_wb2s))
    351 				*(short *)f->f_wb2a = f->f_wb2d;
    352 			else
    353 				err = ustore_short((void *)f->f_wb2a, f->f_wb2d);
    354 			break;
    355 		}
    356 		if (err) {
    357 			fa = f->f_wb2a;
    358 #ifdef DEBUG
    359 			if (mmudebug & MDB_WBFAILED) {
    360 				printf(wberrstr, p->p_pid, p->p_comm,
    361 				       "#2", fp->f_pc, f->f_fa,
    362 				       f->f_wb2a, f->f_wb2d);
    363 				dumpssw(f->f_ssw);
    364 				dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
    365 			}
    366 #endif
    367 		}
    368 	}
    369 	if (err == 0 && (f->f_wb3s & SSW4_WBSV)) {
    370 #ifdef DEBUG
    371 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
    372 			dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d);
    373 		wbstats.wb3s++;
    374 		wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++;
    375 #endif
    376 		switch (f->f_wb3s & SSW4_SZMASK) {
    377 		case SSW4_SZLW:
    378 			if (KDFAULT(f->f_wb3s))
    379 				*(long *)f->f_wb3a = f->f_wb3d;
    380 			else
    381 				err = ustore_long((void *)f->f_wb3a, f->f_wb3d);
    382 			break;
    383 		case SSW4_SZB:
    384 			if (KDFAULT(f->f_wb3s))
    385 				*(char *)f->f_wb3a = f->f_wb3d;
    386 			else
    387 				err = ustore_char((void *)f->f_wb3a, f->f_wb3d);
    388 			break;
    389 		case SSW4_SZW:
    390 			if (KDFAULT(f->f_wb3s))
    391 				*(short *)f->f_wb3a = f->f_wb3d;
    392 			else
    393 				err = ustore_short((void *)f->f_wb3a, f->f_wb3d);
    394 			break;
    395 #ifdef DEBUG
    396 		case SSW4_SZLN:
    397 			panic("writeback: wb3s indicates LINE write");
    398 #endif
    399 		}
    400 		if (err) {
    401 			fa = f->f_wb3a;
    402 #ifdef DEBUG
    403 			if (mmudebug & MDB_WBFAILED)
    404 				printf(wberrstr, p->p_pid, p->p_comm,
    405 				       "#3", fp->f_pc, f->f_fa,
    406 				       f->f_wb3a, f->f_wb3d);
    407 #endif
    408 		}
    409 	}
    410 	pcb->pcb_onfault = oonfault;
    411 	if (err)
    412 		err = SIGSEGV;
    413 	return err;
    414 }
    415 #endif /* M68040 */
    416