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