Commit | Line | Data |
---|---|---|
dea92547 KM |
1 | /* |
2 | * Copyright (c) 1988 University of Utah. | |
3 | * Copyright (c) 1992 The Regents of the University of California. | |
4 | * All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * the Systems Programming Group of the University of Utah Computer | |
8 | * Science Department and Ralph Campbell. | |
9 | * | |
10 | * %sccs.include.redist.c% | |
11 | * | |
12 | * from: Utah $Hdr: trap.c 1.32 91/04/06$ | |
13 | * | |
38a01dbe | 14 | * @(#)trap.c 7.9 (Berkeley) %G% |
dea92547 KM |
15 | */ |
16 | ||
38a01dbe KB |
17 | #include <sys/param.h> |
18 | #include <sys/systm.h> | |
19 | #include <sys/proc.h> | |
20 | #include <sys/kernel.h> | |
21 | #include <sys/signalvar.h> | |
22 | #include <sys/syscall.h> | |
23 | #include <sys/user.h> | |
24 | #include <sys/buf.h> | |
dea92547 | 25 | #ifdef KTRACE |
38a01dbe | 26 | #include <sys/ktrace.h> |
dea92547 | 27 | #endif |
38a01dbe | 28 | #include <net/netisr.h> |
dea92547 | 29 | |
38a01dbe KB |
30 | #include <machine/trap.h> |
31 | #include <machine/psl.h> | |
32 | #include <machine/reg.h> | |
33 | #include <machine/cpu.h> | |
34 | #include <machine/pte.h> | |
35 | #include <machine/mips_opcode.h> | |
36 | #include <pmax/pmax/clockreg.h> | |
dea92547 | 37 | |
38a01dbe KB |
38 | #include <vm/vm.h> |
39 | #include <vm/vm_kern.h> | |
40 | #include <vm/vm_page.h> | |
dea92547 KM |
41 | |
42 | /* | |
43 | * This is a kludge to allow X windows to work. | |
44 | */ | |
45 | #define X_KLUGE | |
46 | ||
47 | #ifdef X_KLUGE | |
48 | #define USER_MAP_ADDR 0x4000 | |
49 | #define NPTES 300 | |
50 | static pt_entry_t UserMapPtes[NPTES]; | |
51 | static unsigned nUserMapPtes; | |
52 | static pid_t UserMapPid; | |
53 | #endif | |
54 | ||
55 | struct proc *machFPCurProcPtr; /* pointer to last proc to use FP */ | |
56 | ||
57 | extern void MachKernGenException(); | |
58 | extern void MachUserGenException(); | |
59 | extern void MachKernIntr(); | |
60 | extern void MachUserIntr(); | |
61 | extern void MachTLBModException(); | |
62 | extern void MachTLBMissException(); | |
c80c7ce7 | 63 | static void MemErrorInterrupt(); |
3cd21030 | 64 | extern unsigned MachEmulateBranch(); |
dea92547 KM |
65 | |
66 | void (*machExceptionTable[])() = { | |
67 | /* | |
68 | * The kernel exception handlers. | |
69 | */ | |
70 | MachKernIntr, /* external interrupt */ | |
71 | MachKernGenException, /* TLB modification */ | |
72 | MachTLBMissException, /* TLB miss (load or instr. fetch) */ | |
73 | MachTLBMissException, /* TLB miss (store) */ | |
74 | MachKernGenException, /* address error (load or I-fetch) */ | |
75 | MachKernGenException, /* address error (store) */ | |
76 | MachKernGenException, /* bus error (I-fetch) */ | |
77 | MachKernGenException, /* bus error (load or store) */ | |
78 | MachKernGenException, /* system call */ | |
79 | MachKernGenException, /* breakpoint */ | |
80 | MachKernGenException, /* reserved instruction */ | |
81 | MachKernGenException, /* coprocessor unusable */ | |
82 | MachKernGenException, /* arithmetic overflow */ | |
83 | MachKernGenException, /* reserved */ | |
84 | MachKernGenException, /* reserved */ | |
85 | MachKernGenException, /* reserved */ | |
86 | /* | |
87 | * The user exception handlers. | |
88 | */ | |
89 | MachUserIntr, | |
90 | MachUserGenException, | |
91 | MachUserGenException, | |
92 | MachUserGenException, | |
93 | MachUserGenException, | |
94 | MachUserGenException, | |
95 | MachUserGenException, | |
96 | MachUserGenException, | |
97 | MachUserGenException, | |
98 | MachUserGenException, | |
99 | MachUserGenException, | |
100 | MachUserGenException, | |
101 | MachUserGenException, | |
102 | MachUserGenException, | |
103 | MachUserGenException, | |
104 | MachUserGenException, | |
105 | }; | |
106 | ||
107 | char *trap_type[] = { | |
108 | "external interrupt", | |
109 | "TLB modification", | |
110 | "TLB miss (load or instr. fetch)", | |
111 | "TLB miss (store)", | |
112 | "address error (load or I-fetch)", | |
113 | "address error (store)", | |
114 | "bus error (I-fetch)", | |
115 | "bus error (load or store)", | |
116 | "system call", | |
117 | "breakpoint", | |
118 | "reserved instruction", | |
119 | "coprocessor unusable", | |
120 | "arithmetic overflow", | |
121 | "reserved 13", | |
122 | "reserved 14", | |
123 | "reserved 15", | |
124 | }; | |
125 | ||
126 | #ifdef DEBUG | |
127 | #define TRAPSIZE 10 | |
128 | struct trapdebug { /* trap history buffer for debugging */ | |
129 | u_int status; | |
130 | u_int cause; | |
131 | u_int vadr; | |
132 | u_int pc; | |
133 | u_int ra; | |
134 | u_int code; | |
135 | } trapdebug[TRAPSIZE], *trp = trapdebug; | |
136 | #endif | |
137 | ||
138 | /* | |
139 | * Handle an exception. | |
140 | * Called from MachKernGenException() or MachUserGenException() | |
141 | * when a processor trap occurs. | |
142 | * In the case of a kernel trap, we return the pc where to resume if | |
143 | * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc. | |
144 | */ | |
145 | unsigned | |
3cd21030 | 146 | trap(statusReg, causeReg, vadr, pc, args) |
dea92547 KM |
147 | unsigned statusReg; /* status register at time of the exception */ |
148 | unsigned causeReg; /* cause register at time of exception */ | |
149 | unsigned vadr; /* address (if any) the fault occured on */ | |
150 | unsigned pc; /* program counter where to continue */ | |
151 | { | |
152 | register int type, i; | |
153 | unsigned ucode = 0; | |
154 | register struct proc *p = curproc; | |
c80c7ce7 | 155 | u_quad_t sticks; |
dea92547 KM |
156 | vm_prot_t ftype; |
157 | extern unsigned onfault_table[]; | |
158 | ||
159 | #ifdef DEBUG | |
160 | trp->status = statusReg; | |
161 | trp->cause = causeReg; | |
162 | trp->vadr = vadr; | |
163 | trp->pc = pc; | |
64957cf9 RC |
164 | trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] : |
165 | p->p_md.md_regs[RA]; | |
dea92547 KM |
166 | trp->code = 0; |
167 | if (++trp == &trapdebug[TRAPSIZE]) | |
168 | trp = trapdebug; | |
169 | #endif | |
170 | ||
171 | cnt.v_trap++; | |
172 | type = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT; | |
173 | if (USERMODE(statusReg)) { | |
174 | type |= T_USER; | |
c80c7ce7 | 175 | sticks = p->p_sticks; |
dea92547 KM |
176 | } |
177 | ||
178 | /* | |
179 | * Enable hardware interrupts if they were on before. | |
180 | * We only respond to software interrupts when returning to user mode. | |
181 | */ | |
182 | if (statusReg & MACH_SR_INT_ENA_PREV) | |
183 | splx((statusReg & MACH_HARD_INT_MASK) | MACH_SR_INT_ENA_CUR); | |
184 | ||
185 | switch (type) { | |
186 | case T_TLB_MOD: | |
c80c7ce7 | 187 | /* check for kernel address */ |
dea92547 KM |
188 | if ((int)vadr < 0) { |
189 | register pt_entry_t *pte; | |
190 | register unsigned entry; | |
191 | #ifndef ATTR | |
192 | register vm_offset_t pa; | |
193 | #endif | |
194 | ||
195 | pte = kvtopte(vadr); | |
196 | entry = pte->pt_entry; | |
197 | if (entry & PG_RO) { | |
198 | /* write to read only page in the kernel */ | |
199 | ftype = VM_PROT_WRITE; | |
200 | goto kernel_fault; | |
201 | } | |
202 | entry |= PG_M; | |
203 | pte->pt_entry = entry; | |
204 | vadr &= PG_FRAME; | |
205 | printf("trap: TLBupdate hi %x lo %x i %x\n", vadr, | |
206 | entry, MachTLBUpdate(vadr, entry)); /* XXX */ | |
207 | #ifdef ATTR | |
208 | pmap_attributes[atop(entry - KERNBASE)] |= PMAP_ATTR_MOD; | |
209 | #else | |
210 | pa = entry & PG_FRAME; | |
211 | if (!IS_VM_PHYSADDR(pa)) | |
212 | panic("trap: kmod"); | |
213 | PHYS_TO_VM_PAGE(pa)->clean = FALSE; | |
214 | #endif | |
215 | return (pc); | |
216 | } | |
217 | /* FALLTHROUGH */ | |
218 | ||
219 | case T_TLB_MOD+T_USER: | |
220 | { | |
221 | pmap_hash_t hp; | |
222 | #ifndef ATTR | |
223 | vm_offset_t pa; | |
224 | #endif | |
225 | #ifdef DIAGNOSTIC | |
226 | extern pmap_hash_t zero_pmap_hash; | |
227 | extern pmap_t cur_pmap; | |
228 | ||
229 | if (cur_pmap->pm_hash == zero_pmap_hash) | |
230 | panic("tlbmod"); | |
231 | #endif | |
232 | hp = &((pmap_hash_t)PMAP_HASH_UADDR)[PMAP_HASH(vadr)]; | |
de8146d9 RC |
233 | if (((hp->pmh_pte[0].high ^ vadr) & ~PGOFSET) == 0) |
234 | i = 0; | |
235 | else if (((hp->pmh_pte[1].high ^ vadr) & ~PGOFSET) == 0) | |
236 | i = 1; | |
237 | else | |
238 | panic("trap: tlb umod not found"); | |
239 | if (hp->pmh_pte[i].low & PG_RO) { | |
dea92547 KM |
240 | ftype = VM_PROT_WRITE; |
241 | goto dofault; | |
242 | } | |
de8146d9 RC |
243 | hp->pmh_pte[i].low |= PG_M; |
244 | printf("trap: TLBupdate hi %x lo %x i %x\n", | |
245 | hp->pmh_pte[i].high, hp->pmh_pte[i].low, | |
246 | MachTLBUpdate(hp->pmh_pte[i].high, hp->pmh_pte[i].low)); /* XXX */ | |
dea92547 | 247 | #ifdef ATTR |
de8146d9 RC |
248 | pmap_attributes[atop(hp->pmh_pte[i].low - KERNBASE)] |= |
249 | PMAP_ATTR_MOD; | |
dea92547 | 250 | #else |
de8146d9 | 251 | pa = hp->pmh_pte[i].low & PG_FRAME; |
dea92547 KM |
252 | if (!IS_VM_PHYSADDR(pa)) |
253 | panic("trap: umod"); | |
254 | PHYS_TO_VM_PAGE(pa)->clean = FALSE; | |
255 | #endif | |
256 | if (!USERMODE(statusReg)) | |
257 | return (pc); | |
258 | goto out; | |
259 | } | |
260 | ||
261 | case T_TLB_LD_MISS: | |
262 | case T_TLB_ST_MISS: | |
263 | ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; | |
c80c7ce7 | 264 | /* check for kernel address */ |
dea92547 KM |
265 | if ((int)vadr < 0) { |
266 | register vm_offset_t va; | |
267 | int rv; | |
268 | ||
269 | kernel_fault: | |
270 | va = trunc_page((vm_offset_t)vadr); | |
271 | rv = vm_fault(kernel_map, va, ftype, FALSE); | |
272 | if (rv == KERN_SUCCESS) | |
273 | return (pc); | |
274 | if (i = ((struct pcb *)UADDR)->pcb_onfault) { | |
275 | ((struct pcb *)UADDR)->pcb_onfault = 0; | |
276 | return (onfault_table[i]); | |
277 | } | |
278 | goto err; | |
279 | } | |
c80c7ce7 RC |
280 | /* check for fuswintr() or suswintr() getting a page fault */ |
281 | if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 4) | |
282 | return (onfault_table[i]); | |
dea92547 KM |
283 | goto dofault; |
284 | ||
285 | case T_TLB_LD_MISS+T_USER: | |
286 | ftype = VM_PROT_READ; | |
287 | goto dofault; | |
288 | ||
289 | case T_TLB_ST_MISS+T_USER: | |
290 | ftype = VM_PROT_WRITE; | |
291 | dofault: | |
292 | { | |
293 | register vm_offset_t va; | |
294 | register struct vmspace *vm = p->p_vmspace; | |
295 | register vm_map_t map = &vm->vm_map; | |
296 | int rv; | |
297 | ||
298 | #ifdef X_KLUGE | |
299 | if (p->p_pid == UserMapPid && | |
300 | (va = pmax_btop(vadr - USER_MAP_ADDR)) < nUserMapPtes) { | |
301 | register pt_entry_t *pte; | |
302 | ||
303 | pte = &UserMapPtes[va]; | |
304 | MachTLBWriteRandom((vadr & PG_FRAME) | | |
305 | (vm->vm_pmap.pm_tlbpid << VMMACH_TLB_PID_SHIFT), | |
306 | pte->pt_entry); | |
307 | return (pc); | |
308 | } | |
309 | #endif | |
310 | va = trunc_page((vm_offset_t)vadr); | |
311 | rv = vm_fault(map, va, ftype, FALSE); | |
312 | if (rv != KERN_SUCCESS) { | |
313 | printf("vm_fault(%x, %x, %x, 0) -> %x ADR %x PC %x RA %x\n", | |
314 | map, va, ftype, rv, vadr, pc, | |
315 | !USERMODE(statusReg) ? ((int *)&args)[19] : | |
64957cf9 | 316 | p->p_md.md_regs[RA]); /* XXX */ |
dea92547 | 317 | printf("\tpid %d %s PC %x RA %x\n", p->p_pid, |
64957cf9 RC |
318 | p->p_comm, p->p_md.md_regs[PC], |
319 | p->p_md.md_regs[RA]); /* XXX */ | |
dea92547 KM |
320 | trapDump("vm_fault"); |
321 | } | |
322 | /* | |
323 | * If this was a stack access we keep track of the maximum | |
324 | * accessed stack size. Also, if vm_fault gets a protection | |
325 | * failure it is due to accessing the stack region outside | |
326 | * the current limit and we need to reflect that as an access | |
327 | * error. | |
328 | */ | |
329 | if ((caddr_t)va >= vm->vm_maxsaddr) { | |
330 | if (rv == KERN_SUCCESS) { | |
331 | unsigned nss; | |
332 | ||
333 | nss = clrnd(btoc(USRSTACK-(unsigned)va)); | |
334 | if (nss > vm->vm_ssize) | |
335 | vm->vm_ssize = nss; | |
336 | } else if (rv == KERN_PROTECTION_FAILURE) | |
337 | rv = KERN_INVALID_ADDRESS; | |
338 | } | |
339 | if (rv == KERN_SUCCESS) { | |
340 | if (!USERMODE(statusReg)) | |
341 | return (pc); | |
342 | goto out; | |
343 | } | |
344 | if (!USERMODE(statusReg)) { | |
345 | if (i = ((struct pcb *)UADDR)->pcb_onfault) { | |
346 | ((struct pcb *)UADDR)->pcb_onfault = 0; | |
347 | return (onfault_table[i]); | |
348 | } | |
349 | goto err; | |
350 | } | |
351 | ucode = vadr; | |
352 | i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV; | |
353 | break; | |
354 | } | |
355 | ||
356 | case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ | |
357 | if (vadr == KERNBASE) { | |
358 | struct args { | |
359 | int i[1]; | |
360 | } args; | |
361 | int rval[2]; | |
362 | ||
363 | /* | |
364 | * Assume a signal handler is trying to return | |
365 | * (see sendsig() and sigreturn()). We have to | |
366 | * pop the sigframe struct to get the address of | |
367 | * the sigcontext. | |
368 | */ | |
64957cf9 | 369 | args.i[0] = p->p_md.md_regs[SP] + 4 * sizeof(int); |
dea92547 KM |
370 | (void) sigreturn(curproc, &args, rval); |
371 | goto out; | |
372 | } | |
373 | /* FALLTHROUGH */ | |
374 | ||
375 | case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ | |
376 | case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ | |
377 | case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ | |
378 | i = SIGSEGV; | |
379 | break; | |
380 | ||
381 | case T_SYSCALL+T_USER: | |
382 | { | |
64957cf9 | 383 | register int *locr0 = p->p_md.md_regs; |
dea92547 | 384 | register struct sysent *callp; |
ce771581 KM |
385 | unsigned int code; |
386 | int numsys; | |
dea92547 KM |
387 | struct args { |
388 | int i[8]; | |
389 | } args; | |
390 | int rval[2]; | |
391 | struct sysent *systab; | |
dea92547 KM |
392 | extern int nsysent; |
393 | #ifdef ULTRIXCOMPAT | |
394 | extern struct sysent ultrixsysent[]; | |
395 | extern int ultrixnsysent; | |
396 | #endif | |
397 | ||
398 | cnt.v_syscall++; | |
399 | /* compute next PC after syscall instruction */ | |
400 | if ((int)causeReg < 0) | |
401 | locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0); | |
402 | else | |
403 | locr0[PC] += 4; | |
404 | systab = sysent; | |
405 | numsys = nsysent; | |
406 | #ifdef ULTRIXCOMPAT | |
407 | if (p->p_md.md_flags & MDP_ULTRIX) { | |
408 | systab = ultrixsysent; | |
409 | numsys = ultrixnsysent; | |
410 | } | |
411 | #endif | |
412 | code = locr0[V0]; | |
cfa7230c RC |
413 | switch (code) { |
414 | case SYS_indir: | |
415 | /* | |
416 | * Code is first argument, followed by actual args. | |
417 | */ | |
dea92547 KM |
418 | code = locr0[A0]; |
419 | if (code >= numsys) | |
cfa7230c | 420 | callp = &systab[SYS_indir]; /* (illegal) */ |
dea92547 KM |
421 | else |
422 | callp = &systab[code]; | |
423 | i = callp->sy_narg; | |
424 | args.i[0] = locr0[A1]; | |
425 | args.i[1] = locr0[A2]; | |
426 | args.i[2] = locr0[A3]; | |
427 | if (i > 3) { | |
428 | i = copyin((caddr_t)(locr0[SP] + | |
cfa7230c | 429 | 4 * sizeof(int)), |
dea92547 KM |
430 | (caddr_t)&args.i[3], |
431 | (u_int)(i - 3) * sizeof(int)); | |
432 | if (i) { | |
433 | locr0[V0] = i; | |
434 | locr0[A3] = 1; | |
435 | #ifdef KTRACE | |
436 | if (KTRPOINT(p, KTR_SYSCALL)) | |
437 | ktrsyscall(p->p_tracep, code, | |
438 | callp->sy_narg, args.i); | |
439 | #endif | |
440 | goto done; | |
441 | } | |
442 | } | |
cfa7230c RC |
443 | break; |
444 | ||
445 | case SYS___indir: | |
446 | /* | |
447 | * Like indir, but code is a quad, so as to maintain | |
448 | * quad alignment for the rest of the arguments. | |
449 | */ | |
450 | code = locr0[A0 + _QUAD_LOWWORD]; | |
ce771581 | 451 | if (code >= numsys) |
cfa7230c RC |
452 | callp = &systab[SYS_indir]; /* (illegal) */ |
453 | else | |
454 | callp = &systab[code]; | |
455 | i = callp->sy_narg; | |
456 | args.i[0] = locr0[A2]; | |
457 | args.i[1] = locr0[A3]; | |
458 | if (i > 2) { | |
459 | i = copyin((caddr_t)(locr0[SP] + | |
460 | 4 * sizeof(int)), | |
461 | (caddr_t)&args.i[2], | |
462 | (u_int)(i - 2) * sizeof(int)); | |
463 | if (i) { | |
464 | locr0[V0] = i; | |
465 | locr0[A3] = 1; | |
466 | #ifdef KTRACE | |
467 | if (KTRPOINT(p, KTR_SYSCALL)) | |
468 | ktrsyscall(p->p_tracep, code, | |
469 | callp->sy_narg, args.i); | |
470 | #endif | |
471 | goto done; | |
472 | } | |
473 | } | |
474 | break; | |
475 | ||
476 | default: | |
477 | if (code >= numsys) | |
478 | callp = &systab[SYS_indir]; /* (illegal) */ | |
dea92547 KM |
479 | else |
480 | callp = &systab[code]; | |
481 | i = callp->sy_narg; | |
482 | args.i[0] = locr0[A0]; | |
483 | args.i[1] = locr0[A1]; | |
484 | args.i[2] = locr0[A2]; | |
485 | args.i[3] = locr0[A3]; | |
486 | if (i > 4) { | |
487 | i = copyin((caddr_t)(locr0[SP] + | |
488 | 4 * sizeof(int)), | |
489 | (caddr_t)&args.i[4], | |
490 | (u_int)(i - 4) * sizeof(int)); | |
491 | if (i) { | |
492 | locr0[V0] = i; | |
493 | locr0[A3] = 1; | |
494 | #ifdef KTRACE | |
495 | if (KTRPOINT(p, KTR_SYSCALL)) | |
496 | ktrsyscall(p->p_tracep, code, | |
497 | callp->sy_narg, args.i); | |
498 | #endif | |
499 | goto done; | |
500 | } | |
501 | } | |
502 | } | |
503 | #ifdef KTRACE | |
504 | if (KTRPOINT(p, KTR_SYSCALL)) | |
505 | ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i); | |
506 | #endif | |
507 | rval[0] = 0; | |
508 | rval[1] = locr0[V1]; | |
509 | #ifdef DEBUG | |
510 | if (trp == trapdebug) | |
511 | trapdebug[TRAPSIZE - 1].code = code; | |
512 | else | |
513 | trp[-1].code = code; | |
514 | #endif | |
515 | i = (*callp->sy_call)(p, &args, rval); | |
516 | /* | |
517 | * Reinitialize proc pointer `p' as it may be different | |
518 | * if this is a child returning from fork syscall. | |
519 | */ | |
520 | p = curproc; | |
64957cf9 | 521 | locr0 = p->p_md.md_regs; |
dea92547 KM |
522 | #ifdef DEBUG |
523 | { int s; | |
524 | s = splhigh(); | |
525 | trp->status = statusReg; | |
526 | trp->cause = causeReg; | |
527 | trp->vadr = locr0[SP]; | |
528 | trp->pc = locr0[PC]; | |
529 | trp->ra = locr0[RA]; | |
530 | trp->code = -code; | |
531 | if (++trp == &trapdebug[TRAPSIZE]) | |
532 | trp = trapdebug; | |
533 | splx(s); | |
534 | } | |
535 | #endif | |
cfa7230c RC |
536 | switch (i) { |
537 | case 0: | |
538 | locr0[V0] = rval[0]; | |
539 | locr0[V1] = rval[1]; | |
540 | locr0[A3] = 0; | |
541 | break; | |
542 | ||
543 | case ERESTART: | |
dea92547 | 544 | locr0[PC] = pc; |
cfa7230c RC |
545 | break; |
546 | ||
547 | case EJUSTRETURN: | |
548 | break; /* nothing to do */ | |
549 | ||
550 | default: | |
551 | locr0[V0] = i; | |
552 | locr0[A3] = 1; | |
dea92547 | 553 | } |
dea92547 KM |
554 | done: |
555 | #ifdef KTRACE | |
556 | if (KTRPOINT(p, KTR_SYSRET)) | |
557 | ktrsysret(p->p_tracep, code, i, rval[0]); | |
558 | #endif | |
559 | goto out; | |
560 | } | |
561 | ||
562 | case T_BREAK+T_USER: | |
3cd21030 RC |
563 | { |
564 | register unsigned va, instr; | |
565 | ||
566 | /* compute address of break instruction */ | |
567 | va = pc; | |
568 | if ((int)causeReg < 0) | |
569 | va += 4; | |
570 | ||
571 | /* read break instruction */ | |
de8146d9 | 572 | instr = fuiword((caddr_t)va); |
3cd21030 RC |
573 | #ifdef KADB |
574 | if (instr == MACH_BREAK_BRKPT || instr == MACH_BREAK_SSTEP) | |
575 | goto err; | |
576 | #endif | |
577 | if (p->p_md.md_ss_addr != va || instr != MACH_BREAK_SSTEP) { | |
578 | i = SIGTRAP; | |
579 | break; | |
580 | } | |
581 | ||
582 | /* restore original instruction and clear BP */ | |
583 | i = suiword((caddr_t)va, p->p_md.md_ss_instr); | |
584 | if (i < 0) { | |
585 | vm_offset_t sa, ea; | |
586 | int rv; | |
587 | ||
588 | sa = trunc_page((vm_offset_t)va); | |
589 | ea = round_page((vm_offset_t)va+sizeof(int)-1); | |
590 | rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, | |
591 | VM_PROT_DEFAULT, FALSE); | |
592 | if (rv == KERN_SUCCESS) { | |
593 | i = suiword((caddr_t)va, p->p_md.md_ss_instr); | |
594 | (void) vm_map_protect(&p->p_vmspace->vm_map, | |
595 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, | |
596 | FALSE); | |
597 | } | |
598 | } | |
599 | if (i < 0) { | |
600 | i = SIGTRAP; | |
601 | break; | |
602 | } | |
603 | p->p_md.md_ss_addr = 0; | |
604 | goto out; | |
605 | } | |
dea92547 KM |
606 | |
607 | case T_RES_INST+T_USER: | |
608 | i = SIGILL; | |
609 | break; | |
610 | ||
611 | case T_COP_UNUSABLE+T_USER: | |
612 | if ((causeReg & MACH_CR_COP_ERR) != 0x10000000) { | |
613 | i = SIGILL; /* only FPU instructions allowed */ | |
614 | break; | |
615 | } | |
64957cf9 | 616 | MachSwitchFPState(machFPCurProcPtr, p->p_md.md_regs); |
dea92547 | 617 | machFPCurProcPtr = p; |
64957cf9 | 618 | p->p_md.md_regs[PS] |= MACH_SR_COP_1_BIT; |
dea92547 KM |
619 | p->p_md.md_flags |= MDP_FPUSED; |
620 | goto out; | |
621 | ||
622 | case T_OVFLOW+T_USER: | |
623 | i = SIGFPE; | |
624 | break; | |
625 | ||
626 | case T_ADDR_ERR_LD: /* misaligned access */ | |
627 | case T_ADDR_ERR_ST: /* misaligned access */ | |
628 | case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ | |
629 | if (i = ((struct pcb *)UADDR)->pcb_onfault) { | |
630 | ((struct pcb *)UADDR)->pcb_onfault = 0; | |
631 | return (onfault_table[i]); | |
632 | } | |
633 | /* FALLTHROUGH */ | |
634 | ||
635 | default: | |
636 | err: | |
3cd21030 RC |
637 | #ifdef KADB |
638 | { | |
639 | extern struct pcb kdbpcb; | |
640 | ||
641 | if (USERMODE(statusReg)) | |
642 | kdbpcb = p->p_addr->u_pcb; | |
643 | else { | |
644 | kdbpcb.pcb_regs[ZERO] = 0; | |
645 | kdbpcb.pcb_regs[AST] = ((int *)&args)[2]; | |
646 | kdbpcb.pcb_regs[V0] = ((int *)&args)[3]; | |
647 | kdbpcb.pcb_regs[V1] = ((int *)&args)[4]; | |
648 | kdbpcb.pcb_regs[A0] = ((int *)&args)[5]; | |
649 | kdbpcb.pcb_regs[A1] = ((int *)&args)[6]; | |
650 | kdbpcb.pcb_regs[A2] = ((int *)&args)[7]; | |
651 | kdbpcb.pcb_regs[A3] = ((int *)&args)[8]; | |
652 | kdbpcb.pcb_regs[T0] = ((int *)&args)[9]; | |
653 | kdbpcb.pcb_regs[T1] = ((int *)&args)[10]; | |
654 | kdbpcb.pcb_regs[T2] = ((int *)&args)[11]; | |
655 | kdbpcb.pcb_regs[T3] = ((int *)&args)[12]; | |
656 | kdbpcb.pcb_regs[T4] = ((int *)&args)[13]; | |
657 | kdbpcb.pcb_regs[T5] = ((int *)&args)[14]; | |
658 | kdbpcb.pcb_regs[T6] = ((int *)&args)[15]; | |
659 | kdbpcb.pcb_regs[T7] = ((int *)&args)[16]; | |
660 | kdbpcb.pcb_regs[T8] = ((int *)&args)[17]; | |
661 | kdbpcb.pcb_regs[T9] = ((int *)&args)[18]; | |
662 | kdbpcb.pcb_regs[RA] = ((int *)&args)[19]; | |
663 | kdbpcb.pcb_regs[MULLO] = ((int *)&args)[21]; | |
664 | kdbpcb.pcb_regs[MULHI] = ((int *)&args)[22]; | |
665 | kdbpcb.pcb_regs[PC] = pc; | |
666 | kdbpcb.pcb_regs[SR] = statusReg; | |
667 | bzero((caddr_t)&kdbpcb.pcb_regs[F0], 33 * sizeof(int)); | |
668 | } | |
669 | if (kdb(causeReg, vadr, p, !USERMODE(statusReg))) | |
670 | return (kdbpcb.pcb_regs[PC]); | |
671 | } | |
de8146d9 RC |
672 | #else |
673 | #ifdef DEBUG | |
674 | trapDump("trap"); | |
675 | #endif | |
3cd21030 | 676 | #endif |
dea92547 KM |
677 | panic("trap"); |
678 | } | |
679 | printf("trap: pid %d %s sig %d adr %x pc %x ra %x\n", p->p_pid, | |
64957cf9 | 680 | p->p_comm, i, vadr, pc, p->p_md.md_regs[RA]); /* XXX */ |
dea92547 KM |
681 | trapsignal(p, i, ucode); |
682 | out: | |
683 | /* | |
684 | * Note: we should only get here if returning to user mode. | |
685 | */ | |
c80c7ce7 RC |
686 | /* take pending signals */ |
687 | while ((i = CURSIG(p)) != 0) | |
dea92547 KM |
688 | psig(i); |
689 | p->p_pri = p->p_usrpri; | |
c80c7ce7 | 690 | astpending = 0; |
dea92547 | 691 | if (want_resched) { |
3cd21030 RC |
692 | int s; |
693 | ||
dea92547 KM |
694 | /* |
695 | * Since we are curproc, clock will normally just change | |
696 | * our priority without moving us from one queue to another | |
697 | * (since the running process is not on a queue.) | |
698 | * If that happened after we setrq ourselves but before we | |
699 | * swtch()'ed, we might not be on the queue indicated by | |
700 | * our priority. | |
701 | */ | |
c80c7ce7 | 702 | s = splstatclock(); |
dea92547 KM |
703 | setrq(p); |
704 | p->p_stats->p_ru.ru_nivcsw++; | |
705 | swtch(); | |
3cd21030 | 706 | splx(s); |
c80c7ce7 | 707 | while ((i = CURSIG(p)) != 0) |
dea92547 KM |
708 | psig(i); |
709 | } | |
c80c7ce7 RC |
710 | |
711 | /* | |
712 | * If profiling, charge system time to the trapped pc. | |
713 | */ | |
714 | if (p->p_flag & SPROFIL) | |
715 | addupc_task(p, pc, (int)(p->p_sticks - sticks)); | |
716 | ||
dea92547 KM |
717 | curpri = p->p_pri; |
718 | return (pc); | |
719 | } | |
720 | ||
3cd21030 RC |
721 | #ifdef DS5000 |
722 | struct intr_tab intr_tab[8]; | |
723 | #endif | |
724 | ||
c80c7ce7 | 725 | int temp; /* XXX ULTRIX compiler bug with -O */ |
dea92547 KM |
726 | |
727 | /* | |
728 | * Handle an interrupt. | |
729 | * Called from MachKernIntr() or MachUserIntr() | |
730 | * Note: curproc might be NULL. | |
731 | */ | |
732 | interrupt(statusReg, causeReg, pc) | |
733 | unsigned statusReg; /* status register at time of the exception */ | |
734 | unsigned causeReg; /* cause register at time of exception */ | |
735 | unsigned pc; /* program counter where to continue */ | |
736 | { | |
dea92547 | 737 | register unsigned mask; |
c80c7ce7 | 738 | struct clockframe cf; |
dea92547 KM |
739 | |
740 | #ifdef DEBUG | |
741 | trp->status = statusReg; | |
742 | trp->cause = causeReg; | |
743 | trp->vadr = 0; | |
744 | trp->pc = pc; | |
745 | trp->ra = 0; | |
746 | trp->code = 0; | |
747 | if (++trp == &trapdebug[TRAPSIZE]) | |
748 | trp = trapdebug; | |
749 | #endif | |
750 | ||
751 | cnt.v_intr++; | |
752 | mask = causeReg & statusReg; /* pending interrupts & enable mask */ | |
3cd21030 RC |
753 | #ifdef DS3100 |
754 | /* handle clock interrupts ASAP */ | |
755 | if (mask & MACH_INT_MASK_3) { | |
756 | register volatile struct chiptime *c = | |
757 | (volatile struct chiptime *)MACH_CLOCK_ADDR; | |
758 | ||
c80c7ce7 | 759 | temp = c->regc; /* XXX clear interrupt bits */ |
3cd21030 | 760 | cf.pc = pc; |
c80c7ce7 RC |
761 | cf.sr = statusReg; |
762 | hardclock(&cf); | |
3cd21030 RC |
763 | causeReg &= ~MACH_INT_MASK_3; /* reenable clock interrupts */ |
764 | } | |
dea92547 KM |
765 | /* |
766 | * Enable hardware interrupts which were enabled but not pending. | |
767 | * We only respond to software interrupts when returning to spl0. | |
768 | */ | |
769 | splx((statusReg & ~causeReg & MACH_HARD_INT_MASK) | | |
770 | MACH_SR_INT_ENA_CUR); | |
dea92547 | 771 | if (mask & MACH_INT_MASK_0) |
3cd21030 | 772 | siiintr(0); |
dea92547 | 773 | if (mask & MACH_INT_MASK_1) |
3cd21030 | 774 | leintr(0); |
dea92547 | 775 | if (mask & MACH_INT_MASK_2) |
3cd21030 RC |
776 | dcintr(0); |
777 | if (mask & MACH_INT_MASK_4) | |
778 | MemErrorInterrupt(); | |
779 | #endif /* DS3100 */ | |
780 | #ifdef DS5000 | |
781 | /* handle clock interrupts ASAP */ | |
782 | if (mask & MACH_INT_MASK_1) { | |
dea92547 KM |
783 | register volatile struct chiptime *c = |
784 | (volatile struct chiptime *)MACH_CLOCK_ADDR; | |
3cd21030 RC |
785 | register unsigned csr; |
786 | static int warned = 0; | |
787 | ||
788 | csr = *(unsigned *)MACH_SYS_CSR_ADDR; | |
789 | if ((csr & MACH_CSR_PSWARN) && !warned) { | |
790 | warned = 1; | |
791 | printf("WARNING: power supply is overheating!\n"); | |
792 | } else if (warned && !(csr & MACH_CSR_PSWARN)) { | |
793 | warned = 0; | |
794 | printf("WARNING: power supply is OK again\n"); | |
795 | } | |
dea92547 | 796 | |
c80c7ce7 | 797 | temp = c->regc; /* XXX clear interrupt bits */ |
dea92547 | 798 | cf.pc = pc; |
c80c7ce7 RC |
799 | cf.sr = statusReg; |
800 | hardclock(&cf); | |
3cd21030 | 801 | causeReg &= ~MACH_INT_MASK_1; /* reenable clock interrupts */ |
dea92547 | 802 | } |
3cd21030 RC |
803 | if (mask & MACH_INT_MASK_0) { |
804 | register unsigned csr; | |
805 | register unsigned i, m; | |
806 | ||
807 | csr = *(unsigned *)MACH_SYS_CSR_ADDR; | |
808 | m = csr & (csr >> MACH_CSR_IOINTEN_SHIFT) & MACH_CSR_IOINT_MASK; | |
809 | #if 0 | |
810 | *(unsigned *)MACH_SYS_CSR_ADDR = | |
811 | (csr & ~(MACH_CSR_MBZ | 0xFF)) | | |
812 | (m << MACH_CSR_IOINTEN_SHIFT); | |
813 | #endif | |
814 | /* | |
815 | * Enable hardware interrupts which were enabled but not | |
816 | * pending. We only respond to software interrupts when | |
817 | * returning to spl0. | |
818 | */ | |
819 | splx((statusReg & ~causeReg & MACH_HARD_INT_MASK) | | |
820 | MACH_SR_INT_ENA_CUR); | |
821 | for (i = 0; m; i++, m >>= 1) { | |
822 | if (!(m & 1)) | |
823 | continue; | |
824 | if (intr_tab[i].func) | |
825 | (*intr_tab[i].func)(intr_tab[i].unit); | |
826 | else | |
827 | printf("spurious interrupt %d\n", i); | |
828 | } | |
829 | #if 0 | |
830 | *(unsigned *)MACH_SYS_CSR_ADDR = | |
831 | csr & ~(MACH_CSR_MBZ | 0xFF); | |
832 | #endif | |
833 | } else { | |
834 | /* | |
835 | * Enable hardware interrupts which were enabled but not | |
836 | * pending. We only respond to software interrupts when | |
837 | * returning to spl0. | |
838 | */ | |
839 | splx((statusReg & ~causeReg & MACH_HARD_INT_MASK) | | |
840 | MACH_SR_INT_ENA_CUR); | |
841 | } | |
842 | if (mask & MACH_INT_MASK_3) | |
dea92547 | 843 | MemErrorInterrupt(); |
3cd21030 | 844 | #endif /* DS5000 */ |
dea92547 | 845 | if (mask & MACH_INT_MASK_5) { |
dea92547 KM |
846 | if (!USERMODE(statusReg)) { |
847 | #ifdef DEBUG | |
848 | trapDump("fpintr"); | |
849 | #else | |
850 | printf("FPU interrupt: PC %x CR %x SR %x\n", | |
851 | pc, causeReg, statusReg); | |
852 | #endif | |
853 | } else | |
854 | MachFPInterrupt(statusReg, causeReg, pc); | |
855 | } | |
856 | if (mask & MACH_SOFT_INT_MASK_0) { | |
dea92547 | 857 | clearsoftclock(); |
de8146d9 | 858 | cnt.v_soft++; |
c80c7ce7 | 859 | softclock(); |
dea92547 KM |
860 | } |
861 | /* process network interrupt if we trapped or will very soon */ | |
862 | if ((mask & MACH_SOFT_INT_MASK_1) || | |
863 | netisr && (statusReg & MACH_SOFT_INT_MASK_1)) { | |
864 | clearsoftnet(); | |
de8146d9 | 865 | cnt.v_soft++; |
dea92547 KM |
866 | #ifdef INET |
867 | if (netisr & (1 << NETISR_ARP)) { | |
868 | netisr &= ~(1 << NETISR_ARP); | |
869 | arpintr(); | |
870 | } | |
871 | if (netisr & (1 << NETISR_IP)) { | |
872 | netisr &= ~(1 << NETISR_IP); | |
873 | ipintr(); | |
874 | } | |
875 | #endif | |
876 | #ifdef NS | |
877 | if (netisr & (1 << NETISR_NS)) { | |
878 | netisr &= ~(1 << NETISR_NS); | |
879 | nsintr(); | |
880 | } | |
881 | #endif | |
882 | #ifdef ISO | |
883 | if (netisr & (1 << NETISR_ISO)) { | |
884 | netisr &= ~(1 << NETISR_ISO); | |
885 | clnlintr(); | |
886 | } | |
887 | #endif | |
888 | } | |
889 | } | |
890 | ||
891 | /* | |
892 | * This is called from MachUserIntr() if astpending is set. | |
893 | * This is very similar to the tail of trap(). | |
894 | */ | |
895 | softintr(statusReg, pc) | |
896 | unsigned statusReg; /* status register at time of the exception */ | |
897 | unsigned pc; /* program counter where to continue */ | |
898 | { | |
899 | register struct proc *p = curproc; | |
c80c7ce7 | 900 | int sig; |
dea92547 KM |
901 | |
902 | cnt.v_soft++; | |
c80c7ce7 RC |
903 | /* take pending signals */ |
904 | while ((sig = CURSIG(p)) != 0) | |
905 | psig(sig); | |
dea92547 | 906 | p->p_pri = p->p_usrpri; |
c80c7ce7 RC |
907 | astpending = 0; |
908 | if (p->p_flag & SOWEUPC) { | |
909 | p->p_flag &= ~SOWEUPC; | |
910 | ADDUPROF(p); | |
911 | } | |
dea92547 | 912 | if (want_resched) { |
3cd21030 RC |
913 | int s; |
914 | ||
dea92547 KM |
915 | /* |
916 | * Since we are curproc, clock will normally just change | |
917 | * our priority without moving us from one queue to another | |
918 | * (since the running process is not on a queue.) | |
919 | * If that happened after we setrq ourselves but before we | |
920 | * swtch()'ed, we might not be on the queue indicated by | |
921 | * our priority. | |
922 | */ | |
c80c7ce7 | 923 | s = splstatclock(); |
dea92547 KM |
924 | setrq(p); |
925 | p->p_stats->p_ru.ru_nivcsw++; | |
926 | swtch(); | |
3cd21030 | 927 | splx(s); |
c80c7ce7 RC |
928 | while ((sig = CURSIG(p)) != 0) |
929 | psig(sig); | |
dea92547 KM |
930 | } |
931 | curpri = p->p_pri; | |
932 | } | |
933 | ||
934 | #ifdef DEBUG | |
935 | trapDump(msg) | |
936 | char *msg; | |
937 | { | |
938 | register int i; | |
939 | int s; | |
940 | ||
941 | s = splhigh(); | |
942 | printf("trapDump(%s)\n", msg); | |
943 | for (i = 0; i < TRAPSIZE; i++) { | |
944 | if (trp == trapdebug) | |
945 | trp = &trapdebug[TRAPSIZE - 1]; | |
946 | else | |
947 | trp--; | |
948 | if (trp->cause == 0) | |
949 | break; | |
950 | printf("%s: ADR %x PC %x CR %x SR %x\n", | |
951 | trap_type[(trp->cause & MACH_CR_EXC_CODE) >> | |
952 | MACH_CR_EXC_CODE_SHIFT], | |
953 | trp->vadr, trp->pc, trp->cause, trp->status); | |
954 | printf(" RA %x code %d\n", trp-> ra, trp->code); | |
955 | } | |
956 | bzero(trapdebug, sizeof(trapdebug)); | |
957 | trp = trapdebug; | |
958 | splx(s); | |
959 | } | |
960 | #endif | |
961 | ||
962 | #ifdef X_KLUGE | |
963 | /* | |
964 | * This is a kludge to allow X windows to work. | |
965 | */ | |
966 | caddr_t | |
967 | vmUserMap(size, pa) | |
968 | int size; | |
969 | unsigned pa; | |
970 | { | |
971 | register caddr_t v; | |
972 | unsigned off, entry; | |
973 | ||
974 | if (nUserMapPtes == 0) | |
975 | UserMapPid = curproc->p_pid; | |
976 | else if (UserMapPid != curproc->p_pid) | |
977 | return ((caddr_t)0); | |
978 | off = pa & PGOFSET; | |
979 | size = btoc(off + size); | |
980 | if (nUserMapPtes + size > NPTES) | |
981 | return ((caddr_t)0); | |
982 | v = (caddr_t)(USER_MAP_ADDR + pmax_ptob(nUserMapPtes) + off); | |
983 | entry = (pa & 0x9ffff000) | PG_V | PG_M; | |
984 | if (pa >= MACH_UNCACHED_MEMORY_ADDR) | |
985 | entry |= PG_N; | |
986 | while (size > 0) { | |
987 | UserMapPtes[nUserMapPtes].pt_entry = entry; | |
988 | entry += NBPG; | |
989 | nUserMapPtes++; | |
990 | size--; | |
991 | } | |
992 | return (v); | |
993 | } | |
994 | ||
995 | vmUserUnmap() | |
996 | { | |
997 | int id; | |
998 | ||
999 | nUserMapPtes = 0; | |
1000 | if (UserMapPid == curproc->p_pid) { | |
1001 | id = curproc->p_vmspace->vm_pmap.pm_tlbpid; | |
1002 | if (id >= 0) | |
1003 | MachTLBFlushPID(id); | |
1004 | } | |
1005 | UserMapPid = 0; | |
1006 | } | |
1007 | #endif | |
1008 | ||
1009 | /* | |
1010 | *---------------------------------------------------------------------- | |
1011 | * | |
1012 | * MemErrorInterrupt -- | |
1013 | * | |
1014 | * Handler an interrupt for the control register. | |
1015 | * | |
1016 | * Results: | |
1017 | * None. | |
1018 | * | |
1019 | * Side effects: | |
1020 | * None. | |
1021 | * | |
1022 | *---------------------------------------------------------------------- | |
1023 | */ | |
1024 | static void | |
1025 | MemErrorInterrupt() | |
1026 | { | |
3cd21030 | 1027 | #ifdef DS3100 |
dea92547 KM |
1028 | volatile u_short *sysCSRPtr = (u_short *)MACH_SYS_CSR_ADDR; |
1029 | u_short csr; | |
1030 | ||
1031 | csr = *sysCSRPtr; | |
1032 | ||
1033 | if (csr & MACH_CSR_MEM_ERR) { | |
1034 | printf("Memory error at 0x%x\n", | |
1035 | *(unsigned *)MACH_WRITE_ERROR_ADDR); | |
1036 | panic("Mem error interrupt"); | |
1037 | } | |
1038 | *sysCSRPtr = (csr & ~MACH_CSR_MBZ) | 0xff; | |
3cd21030 RC |
1039 | #endif /* DS3100 */ |
1040 | #ifdef DS5000 | |
1041 | printf("erradr %x\n", *(unsigned *)MACH_ERROR_ADDR); | |
1042 | *(unsigned *)MACH_ERROR_ADDR = 0; | |
1043 | MachEmptyWriteBuffer(); | |
1044 | #endif /* DS5000 */ | |
dea92547 KM |
1045 | } |
1046 | ||
dea92547 KM |
1047 | /* |
1048 | * Return the resulting PC as if the branch was executed. | |
1049 | */ | |
1050 | unsigned | |
1051 | MachEmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch) | |
1052 | unsigned *regsPtr; | |
1053 | unsigned instPC; | |
1054 | unsigned fpcCSR; | |
1055 | int allowNonBranch; | |
1056 | { | |
3cd21030 | 1057 | InstFmt inst; |
dea92547 KM |
1058 | unsigned retAddr; |
1059 | int condition; | |
1060 | extern unsigned GetBranchDest(); | |
1061 | ||
3cd21030 | 1062 | #if 0 |
dea92547 KM |
1063 | printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC, |
1064 | *instPC, fpcCSR); | |
1065 | #endif | |
1066 | ||
3cd21030 RC |
1067 | inst = *(InstFmt *)instPC; |
1068 | switch ((int)inst.JType.op) { | |
dea92547 | 1069 | case OP_SPECIAL: |
3cd21030 | 1070 | switch ((int)inst.RType.func) { |
dea92547 KM |
1071 | case OP_JR: |
1072 | case OP_JALR: | |
3cd21030 | 1073 | retAddr = regsPtr[inst.RType.rs]; |
dea92547 KM |
1074 | break; |
1075 | ||
1076 | default: | |
1077 | if (!allowNonBranch) | |
1078 | panic("MachEmulateBranch: Non-branch"); | |
1079 | retAddr = instPC + 4; | |
1080 | break; | |
1081 | } | |
1082 | break; | |
1083 | ||
1084 | case OP_BCOND: | |
3cd21030 | 1085 | switch ((int)inst.IType.rt) { |
dea92547 KM |
1086 | case OP_BLTZ: |
1087 | case OP_BLTZAL: | |
3cd21030 RC |
1088 | if ((int)(regsPtr[inst.RType.rs]) < 0) |
1089 | retAddr = GetBranchDest((InstFmt *)instPC); | |
dea92547 KM |
1090 | else |
1091 | retAddr = instPC + 8; | |
1092 | break; | |
1093 | ||
1094 | case OP_BGEZAL: | |
1095 | case OP_BGEZ: | |
3cd21030 RC |
1096 | if ((int)(regsPtr[inst.RType.rs]) >= 0) |
1097 | retAddr = GetBranchDest((InstFmt *)instPC); | |
dea92547 KM |
1098 | else |
1099 | retAddr = instPC + 8; | |
1100 | break; | |
1101 | ||
1102 | default: | |
1103 | panic("MachEmulateBranch: Bad branch cond"); | |
1104 | } | |
1105 | break; | |
1106 | ||
1107 | case OP_J: | |
1108 | case OP_JAL: | |
3cd21030 | 1109 | retAddr = (inst.JType.target << 2) | |
dea92547 KM |
1110 | ((unsigned)instPC & 0xF0000000); |
1111 | break; | |
1112 | ||
1113 | case OP_BEQ: | |
3cd21030 RC |
1114 | if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt]) |
1115 | retAddr = GetBranchDest((InstFmt *)instPC); | |
dea92547 KM |
1116 | else |
1117 | retAddr = instPC + 8; | |
1118 | break; | |
1119 | ||
1120 | case OP_BNE: | |
3cd21030 RC |
1121 | if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt]) |
1122 | retAddr = GetBranchDest((InstFmt *)instPC); | |
dea92547 KM |
1123 | else |
1124 | retAddr = instPC + 8; | |
1125 | break; | |
1126 | ||
1127 | case OP_BLEZ: | |
3cd21030 RC |
1128 | if ((int)(regsPtr[inst.RType.rs]) <= 0) |
1129 | retAddr = GetBranchDest((InstFmt *)instPC); | |
dea92547 KM |
1130 | else |
1131 | retAddr = instPC + 8; | |
1132 | break; | |
1133 | ||
1134 | case OP_BGTZ: | |
3cd21030 RC |
1135 | if ((int)(regsPtr[inst.RType.rs]) > 0) |
1136 | retAddr = GetBranchDest((InstFmt *)instPC); | |
dea92547 KM |
1137 | else |
1138 | retAddr = instPC + 8; | |
1139 | break; | |
1140 | ||
3cd21030 RC |
1141 | case OP_COP1: |
1142 | switch (inst.RType.rs) { | |
1143 | case OP_BCx: | |
1144 | case OP_BCy: | |
1145 | if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) | |
dea92547 KM |
1146 | condition = fpcCSR & MACH_FPC_COND_BIT; |
1147 | else | |
1148 | condition = !(fpcCSR & MACH_FPC_COND_BIT); | |
1149 | if (condition) | |
3cd21030 | 1150 | retAddr = GetBranchDest((InstFmt *)instPC); |
dea92547 KM |
1151 | else |
1152 | retAddr = instPC + 8; | |
3cd21030 RC |
1153 | break; |
1154 | ||
1155 | default: | |
1156 | if (!allowNonBranch) | |
1157 | panic("MachEmulateBranch: Bad coproc branch instruction"); | |
dea92547 | 1158 | retAddr = instPC + 4; |
3cd21030 | 1159 | } |
dea92547 KM |
1160 | break; |
1161 | ||
1162 | default: | |
1163 | if (!allowNonBranch) | |
1164 | panic("MachEmulateBranch: Non-branch instruction"); | |
1165 | retAddr = instPC + 4; | |
1166 | } | |
3cd21030 | 1167 | #if 0 |
dea92547 KM |
1168 | printf("Target addr=%x\n", retAddr); |
1169 | #endif | |
1170 | return (retAddr); | |
1171 | } | |
1172 | ||
1173 | unsigned | |
1174 | GetBranchDest(InstPtr) | |
1175 | InstFmt *InstPtr; | |
1176 | { | |
1177 | return ((unsigned)InstPtr + 4 + ((short)InstPtr->IType.imm << 2)); | |
1178 | } | |
3cd21030 RC |
1179 | |
1180 | /* | |
1181 | * This routine is called by procxmt() to single step one instruction. | |
1182 | * We do this by storing a break instruction after the current instruction, | |
1183 | * resuming execution, and then restoring the old instruction. | |
1184 | */ | |
1185 | cpu_singlestep(p) | |
1186 | register struct proc *p; | |
1187 | { | |
1188 | register unsigned va; | |
64957cf9 | 1189 | register int *locr0 = p->p_md.md_regs; |
3cd21030 RC |
1190 | int i; |
1191 | ||
1192 | /* compute next address after current location */ | |
1193 | va = MachEmulateBranch(locr0, locr0[PC], 0, 1); | |
1194 | if (p->p_md.md_ss_addr || p->p_md.md_ss_addr == va || | |
1195 | !useracc((caddr_t)va, 4, B_READ)) { | |
1196 | printf("SS %s (%d): breakpoint already set at %x (va %x)\n", | |
1197 | p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */ | |
1198 | return (EFAULT); | |
1199 | } | |
1200 | p->p_md.md_ss_addr = va; | |
de8146d9 | 1201 | p->p_md.md_ss_instr = fuiword((caddr_t)va); |
3cd21030 RC |
1202 | i = suiword((caddr_t)va, MACH_BREAK_SSTEP); |
1203 | if (i < 0) { | |
1204 | vm_offset_t sa, ea; | |
1205 | int rv; | |
1206 | ||
1207 | sa = trunc_page((vm_offset_t)va); | |
1208 | ea = round_page((vm_offset_t)va+sizeof(int)-1); | |
1209 | rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea, | |
1210 | VM_PROT_DEFAULT, FALSE); | |
1211 | if (rv == KERN_SUCCESS) { | |
1212 | i = suiword((caddr_t)va, MACH_BREAK_SSTEP); | |
1213 | (void) vm_map_protect(&p->p_vmspace->vm_map, | |
1214 | sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE); | |
1215 | } | |
1216 | } | |
1217 | if (i < 0) | |
1218 | return (EFAULT); | |
1219 | printf("SS %s (%d): breakpoint set at %x: %x (pc %x)\n", | |
1220 | p->p_comm, p->p_pid, p->p_md.md_ss_addr, | |
1221 | p->p_md.md_ss_instr, locr0[PC]); /* XXX */ | |
1222 | return (0); | |
1223 | } |