trap.c revision 206695
1/* $OpenBSD: trap.c,v 1.19 1998/09/30 12:40:41 pefo Exp $ */ 2/* tracked to 1.23 */ 3/*- 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. 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 and Ralph Campbell. 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 * 4. 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 * from: @(#)trap.c 8.5 (Berkeley) 1/11/94 39 * JNPR: trap.c,v 1.13.2.2 2007/08/29 10:03:49 girish 40 */ 41#include <sys/cdefs.h> 42__FBSDID("$FreeBSD: head/sys/mips/mips/trap.c 206695 2010-04-16 02:56:24Z jmallett $"); 43 44#include "opt_ddb.h" 45#include "opt_global.h" 46#include "opt_ktrace.h" 47 48#define NO_REG_DEFS 1 /* Prevent asm.h from including regdef.h */ 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/sysent.h> 52#include <sys/proc.h> 53#include <sys/kernel.h> 54#include <sys/signalvar.h> 55#include <sys/syscall.h> 56#include <sys/lock.h> 57#include <vm/vm.h> 58#include <vm/vm_extern.h> 59#include <vm/vm_kern.h> 60#include <vm/vm_page.h> 61#include <vm/vm_map.h> 62#include <vm/vm_param.h> 63#include <sys/vmmeter.h> 64#include <sys/ptrace.h> 65#include <sys/user.h> 66#include <sys/buf.h> 67#include <sys/vnode.h> 68#include <sys/pioctl.h> 69#include <sys/sysctl.h> 70#include <sys/syslog.h> 71#include <sys/bus.h> 72#ifdef KTRACE 73#include <sys/ktrace.h> 74#endif 75#include <net/netisr.h> 76 77#include <machine/trap.h> 78#include <machine/psl.h> 79#include <machine/cpu.h> 80#include <machine/pte.h> 81#include <machine/pmap.h> 82#include <machine/md_var.h> 83#include <machine/mips_opcode.h> 84#include <machine/frame.h> 85#include <machine/regnum.h> 86#include <machine/asm.h> 87 88#ifdef DDB 89#include <machine/db_machdep.h> 90#include <ddb/db_sym.h> 91#include <ddb/ddb.h> 92#include <sys/kdb.h> 93#endif 94 95#include <sys/cdefs.h> 96#include <sys/syslog.h> 97 98 99#ifdef TRAP_DEBUG 100int trap_debug = 1; 101#endif 102 103extern unsigned onfault_table[]; 104 105static void log_bad_page_fault(char *, struct trapframe *, int); 106static void log_frame_dump(struct trapframe *frame); 107static void get_mapping_info(vm_offset_t, pd_entry_t **, pt_entry_t **); 108 109#ifdef TRAP_DEBUG 110static void trap_frame_dump(struct trapframe *frame); 111#endif 112 113void (*machExceptionTable[]) (void)= { 114/* 115 * The kernel exception handlers. 116 */ 117 MipsKernIntr, /* external interrupt */ 118 MipsKernGenException, /* TLB modification */ 119 MipsTLBInvalidException,/* TLB miss (load or instr. fetch) */ 120 MipsTLBInvalidException,/* TLB miss (store) */ 121 MipsKernGenException, /* address error (load or I-fetch) */ 122 MipsKernGenException, /* address error (store) */ 123 MipsKernGenException, /* bus error (I-fetch) */ 124 MipsKernGenException, /* bus error (load or store) */ 125 MipsKernGenException, /* system call */ 126 MipsKernGenException, /* breakpoint */ 127 MipsKernGenException, /* reserved instruction */ 128 MipsKernGenException, /* coprocessor unusable */ 129 MipsKernGenException, /* arithmetic overflow */ 130 MipsKernGenException, /* trap exception */ 131 MipsKernGenException, /* virtual coherence exception inst */ 132 MipsKernGenException, /* floating point exception */ 133 MipsKernGenException, /* reserved */ 134 MipsKernGenException, /* reserved */ 135 MipsKernGenException, /* reserved */ 136 MipsKernGenException, /* reserved */ 137 MipsKernGenException, /* reserved */ 138 MipsKernGenException, /* reserved */ 139 MipsKernGenException, /* reserved */ 140 MipsKernGenException, /* watch exception */ 141 MipsKernGenException, /* reserved */ 142 MipsKernGenException, /* reserved */ 143 MipsKernGenException, /* reserved */ 144 MipsKernGenException, /* reserved */ 145 MipsKernGenException, /* reserved */ 146 MipsKernGenException, /* reserved */ 147 MipsKernGenException, /* reserved */ 148 MipsKernGenException, /* virtual coherence exception data */ 149/* 150 * The user exception handlers. 151 */ 152 MipsUserIntr, /* 0 */ 153 MipsUserGenException, /* 1 */ 154 MipsTLBInvalidException,/* 2 */ 155 MipsTLBInvalidException,/* 3 */ 156 MipsUserGenException, /* 4 */ 157 MipsUserGenException, /* 5 */ 158 MipsUserGenException, /* 6 */ 159 MipsUserGenException, /* 7 */ 160 MipsUserGenException, /* 8 */ 161 MipsUserGenException, /* 9 */ 162 MipsUserGenException, /* 10 */ 163 MipsUserGenException, /* 11 */ 164 MipsUserGenException, /* 12 */ 165 MipsUserGenException, /* 13 */ 166 MipsUserGenException, /* 14 */ 167 MipsUserGenException, /* 15 */ 168 MipsUserGenException, /* 16 */ 169 MipsUserGenException, /* 17 */ 170 MipsUserGenException, /* 18 */ 171 MipsUserGenException, /* 19 */ 172 MipsUserGenException, /* 20 */ 173 MipsUserGenException, /* 21 */ 174 MipsUserGenException, /* 22 */ 175 MipsUserGenException, /* 23 */ 176 MipsUserGenException, /* 24 */ 177 MipsUserGenException, /* 25 */ 178 MipsUserGenException, /* 26 */ 179 MipsUserGenException, /* 27 */ 180 MipsUserGenException, /* 28 */ 181 MipsUserGenException, /* 29 */ 182 MipsUserGenException, /* 20 */ 183 MipsUserGenException, /* 31 */ 184}; 185 186char *trap_type[] = { 187 "external interrupt", 188 "TLB modification", 189 "TLB miss (load or instr. fetch)", 190 "TLB miss (store)", 191 "address error (load or I-fetch)", 192 "address error (store)", 193 "bus error (I-fetch)", 194 "bus error (load or store)", 195 "system call", 196 "breakpoint", 197 "reserved instruction", 198 "coprocessor unusable", 199 "arithmetic overflow", 200 "trap", 201 "virtual coherency instruction", 202 "floating point", 203 "reserved 16", 204 "reserved 17", 205 "reserved 18", 206 "reserved 19", 207 "reserved 20", 208 "reserved 21", 209 "reserved 22", 210 "watch", 211 "reserved 24", 212 "reserved 25", 213 "reserved 26", 214 "reserved 27", 215 "reserved 28", 216 "reserved 29", 217 "reserved 30", 218 "virtual coherency data", 219}; 220 221#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) 222struct trapdebug trapdebug[TRAPSIZE], *trp = trapdebug; 223#endif 224 225#if defined(DDB) || defined(DEBUG) 226void stacktrace(struct trapframe *); 227void logstacktrace(struct trapframe *); 228#endif 229 230#define KERNLAND(x) ((int)(x) < 0) 231#define DELAYBRANCH(x) ((int)(x) < 0) 232 233/* 234 * MIPS load/store access type 235 */ 236enum { 237 MIPS_LHU_ACCESS = 1, 238 MIPS_LH_ACCESS, 239 MIPS_LWU_ACCESS, 240 MIPS_LW_ACCESS, 241 MIPS_LD_ACCESS, 242 MIPS_SH_ACCESS, 243 MIPS_SW_ACCESS, 244 MIPS_SD_ACCESS 245}; 246 247char *access_name[] = { 248 "Load Halfword Unsigned", 249 "Load Halfword", 250 "Load Word Unsigned", 251 "Load Word", 252 "Load Doubleword", 253 "Store Halfword", 254 "Store Word", 255 "Store Doubleword" 256}; 257 258 259static int allow_unaligned_acc = 1; 260 261SYSCTL_INT(_vm, OID_AUTO, allow_unaligned_acc, CTLFLAG_RW, 262 &allow_unaligned_acc, 0, "Allow unaligned accesses"); 263 264static int emulate_unaligned_access(struct trapframe *frame); 265 266extern char *syscallnames[]; 267 268/* 269 * Handle an exception. 270 * Called from MipsKernGenException() or MipsUserGenException() 271 * when a processor trap occurs. 272 * In the case of a kernel trap, we return the pc where to resume if 273 * p->p_addr->u_pcb.pcb_onfault is set, otherwise, return old pc. 274 */ 275u_int 276trap(struct trapframe *trapframe) 277{ 278 int type, usermode; 279 int i = 0; 280 unsigned ucode = 0; 281 struct thread *td = curthread; 282 struct proc *p = curproc; 283 vm_prot_t ftype; 284 pt_entry_t *pte; 285 unsigned int entry; 286 pmap_t pmap; 287 int quad_syscall = 0; 288 int access_type; 289 ksiginfo_t ksi; 290 char *msg = NULL; 291 register_t addr = 0; 292 293 trapdebug_enter(trapframe, 0); 294 295 type = (trapframe->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; 296 if (USERMODE(trapframe->sr)) { 297 type |= T_USER; 298 usermode = 1; 299 } else { 300 usermode = 0; 301 } 302 303 /* 304 * Enable hardware interrupts if they were on before the trap. If it 305 * was off disable all so we don't accidently enable it when doing a 306 * return to userland. 307 */ 308 if (trapframe->sr & SR_INT_ENAB) { 309 set_intr_mask(~(trapframe->sr & ALL_INT_MASK)); 310 enableintr(); 311 } else { 312 disableintr(); 313 } 314 315#ifdef TRAP_DEBUG 316 if (trap_debug) { 317 static vm_offset_t last_badvaddr = 0; 318 static vm_offset_t this_badvaddr = 0; 319 static int count = 0; 320 u_int32_t pid; 321 322 printf("trap type %x (%s - ", type, 323 trap_type[type & (~T_USER)]); 324 325 if (type & T_USER) 326 printf("user mode)\n"); 327 else 328 printf("kernel mode)\n"); 329 330#ifdef SMP 331 printf("cpuid = %d\n", PCPU_GET(cpuid)); 332#endif 333 MachTLBGetPID(pid); 334 printf("badaddr = 0x%0x, pc = 0x%0x, ra = 0x%0x, sp = 0x%0x, sr = 0x%x, pid = %d, ASID = 0x%x\n", 335 trapframe->badvaddr, trapframe->pc, trapframe->ra, 336 trapframe->sp, trapframe->sr, 337 (curproc ? curproc->p_pid : -1), pid); 338 339 switch (type & ~T_USER) { 340 case T_TLB_MOD: 341 case T_TLB_LD_MISS: 342 case T_TLB_ST_MISS: 343 case T_ADDR_ERR_LD: 344 case T_ADDR_ERR_ST: 345 this_badvaddr = trapframe->badvaddr; 346 break; 347 case T_SYSCALL: 348 this_badvaddr = trapframe->ra; 349 break; 350 default: 351 this_badvaddr = trapframe->pc; 352 break; 353 } 354 if ((last_badvaddr == this_badvaddr) && 355 ((type & ~T_USER) != T_SYSCALL)) { 356 if (++count == 3) { 357 trap_frame_dump(trapframe); 358 panic("too many faults at %x\n", last_badvaddr); 359 } 360 } else { 361 last_badvaddr = this_badvaddr; 362 count = 0; 363 } 364 } 365#endif 366 switch (type) { 367 case T_MCHECK: 368#ifdef DDB 369 kdb_trap(type, 0, trapframe); 370#endif 371 panic("MCHECK\n"); 372 break; 373 case T_TLB_MOD: 374 /* check for kernel address */ 375 if (KERNLAND(trapframe->badvaddr)) { 376 vm_offset_t pa; 377 378 PMAP_LOCK(kernel_pmap); 379 if (!(pte = pmap_segmap(kernel_pmap, 380 trapframe->badvaddr))) 381 panic("trap: ktlbmod: invalid segmap"); 382 pte += (trapframe->badvaddr >> PGSHIFT) & (NPTEPG - 1); 383 entry = *pte; 384#ifdef SMP 385 /* It is possible that some other CPU changed m-bit */ 386 if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { 387 trapframe->badvaddr &= ~PGOFSET; 388 pmap_update_page(kernel_pmap, 389 trapframe->badvaddr, entry); 390 PMAP_UNLOCK(kernel_pmap); 391 return (trapframe->pc); 392 } 393#else 394 if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) 395 panic("trap: ktlbmod: invalid pte"); 396#endif 397 if (entry & mips_pg_ro_bit()) { 398 /* write to read only page in the kernel */ 399 ftype = VM_PROT_WRITE; 400 PMAP_UNLOCK(kernel_pmap); 401 goto kernel_fault; 402 } 403 entry |= mips_pg_m_bit(); 404 *pte = entry; 405 trapframe->badvaddr &= ~PGOFSET; 406 pmap_update_page(kernel_pmap, trapframe->badvaddr, entry); 407 pa = mips_tlbpfn_to_paddr(entry); 408 if (!page_is_managed(pa)) 409 panic("trap: ktlbmod: unmanaged page"); 410 pmap_set_modified(pa); 411 PMAP_UNLOCK(kernel_pmap); 412 return (trapframe->pc); 413 } 414 /* FALLTHROUGH */ 415 416 case T_TLB_MOD + T_USER: 417 { 418 vm_offset_t pa; 419 420 pmap = &p->p_vmspace->vm_pmap; 421 422 PMAP_LOCK(pmap); 423 if (!(pte = pmap_segmap(pmap, trapframe->badvaddr))) 424 panic("trap: utlbmod: invalid segmap"); 425 pte += (trapframe->badvaddr >> PGSHIFT) & (NPTEPG - 1); 426 entry = *pte; 427#ifdef SMP 428 /* It is possible that some other CPU changed m-bit */ 429 if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { 430 trapframe->badvaddr = (trapframe->badvaddr & ~PGOFSET); 431 pmap_update_page(pmap, trapframe->badvaddr, entry); 432 PMAP_UNLOCK(pmap); 433 goto out; 434 } 435#else 436 if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { 437 panic("trap: utlbmod: invalid pte"); 438 } 439#endif 440 441 if (entry & mips_pg_ro_bit()) { 442 /* write to read only page */ 443 ftype = VM_PROT_WRITE; 444 PMAP_UNLOCK(pmap); 445 goto dofault; 446 } 447 entry |= mips_pg_m_bit(); 448 *pte = entry; 449 trapframe->badvaddr = (trapframe->badvaddr & ~PGOFSET); 450 pmap_update_page(pmap, trapframe->badvaddr, entry); 451 trapframe->badvaddr |= (pmap->pm_asid[PCPU_GET(cpuid)].asid << VMTLB_PID_SHIFT); 452 pa = mips_tlbpfn_to_paddr(entry); 453 if (!page_is_managed(pa)) 454 panic("trap: utlbmod: unmanaged page"); 455 pmap_set_modified(pa); 456 457 PMAP_UNLOCK(pmap); 458 if (!usermode) { 459 return (trapframe->pc); 460 } 461 goto out; 462 } 463 464 case T_TLB_LD_MISS: 465 case T_TLB_ST_MISS: 466 ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; 467 /* check for kernel address */ 468 if (KERNLAND(trapframe->badvaddr)) { 469 vm_offset_t va; 470 int rv; 471 472 kernel_fault: 473 va = trunc_page((vm_offset_t)trapframe->badvaddr); 474 rv = vm_fault(kernel_map, va, ftype, VM_FAULT_NORMAL); 475 if (rv == KERN_SUCCESS) 476 return (trapframe->pc); 477 if ((i = td->td_pcb->pcb_onfault) != 0) { 478 td->td_pcb->pcb_onfault = 0; 479 return (onfault_table[i]); 480 } 481 goto err; 482 } 483 /* 484 * It is an error for the kernel to access user space except 485 * through the copyin/copyout routines. 486 */ 487 if ((i = td->td_pcb->pcb_onfault) == 0) 488 goto err; 489 /* check for fuswintr() or suswintr() getting a page fault */ 490 if (i == 4) { 491 return (onfault_table[i]); 492 } 493 goto dofault; 494 495 case T_TLB_LD_MISS + T_USER: 496 ftype = VM_PROT_READ; 497 goto dofault; 498 499 case T_TLB_ST_MISS + T_USER: 500 ftype = VM_PROT_WRITE; 501dofault: 502 { 503 vm_offset_t va; 504 struct vmspace *vm; 505 vm_map_t map; 506 int rv = 0; 507 508 vm = p->p_vmspace; 509 map = &vm->vm_map; 510 va = trunc_page((vm_offset_t)trapframe->badvaddr); 511 if ((vm_offset_t)trapframe->badvaddr >= VM_MIN_KERNEL_ADDRESS) { 512 /* 513 * Don't allow user-mode faults in kernel 514 * address space. 515 */ 516 goto nogo; 517 } 518 519 /* 520 * Keep swapout from messing with us during this 521 * critical time. 522 */ 523 PROC_LOCK(p); 524 ++p->p_lock; 525 PROC_UNLOCK(p); 526 527 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); 528 529 PROC_LOCK(p); 530 --p->p_lock; 531 PROC_UNLOCK(p); 532#ifdef VMFAULT_TRACE 533 printf("vm_fault(%p (pmap %p), %x (%x), %x, %d) -> %x at pc %x\n", 534 map, &vm->vm_pmap, va, trapframe->badvaddr, ftype, VM_FAULT_NORMAL, 535 rv, trapframe->pc); 536#endif 537 538 if (rv == KERN_SUCCESS) { 539 if (!usermode) { 540 return (trapframe->pc); 541 } 542 goto out; 543 } 544 nogo: 545 if (!usermode) { 546 if ((i = td->td_pcb->pcb_onfault) != 0) { 547 td->td_pcb->pcb_onfault = 0; 548 return (onfault_table[i]); 549 } 550 goto err; 551 } 552 ucode = ftype; 553 i = ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); 554 addr = trapframe->pc; 555 556 msg = "BAD_PAGE_FAULT"; 557 log_bad_page_fault(msg, trapframe, type); 558 559 break; 560 } 561 562 case T_ADDR_ERR_LD + T_USER: /* misaligned or kseg access */ 563 case T_ADDR_ERR_ST + T_USER: /* misaligned or kseg access */ 564 if (allow_unaligned_acc) { 565 int mode; 566 567 if (type == (T_ADDR_ERR_LD + T_USER)) 568 mode = VM_PROT_READ; 569 else 570 mode = VM_PROT_WRITE; 571 572 /* 573 * ADDR_ERR faults have higher priority than TLB 574 * Miss faults. Therefore, it is necessary to 575 * verify that the faulting address is a valid 576 * virtual address within the process' address space 577 * before trying to emulate the unaligned access. 578 */ 579 if (useracc((caddr_t) 580 (((vm_offset_t)trapframe->badvaddr) & 581 ~(sizeof(int) - 1)), sizeof(int) * 2, mode)) { 582 access_type = emulate_unaligned_access( 583 trapframe); 584 if (access_type != 0) 585 goto out; 586 } 587 } 588 msg = "ADDRESS_ERR"; 589 590 /* FALL THROUGH */ 591 592 case T_BUS_ERR_IFETCH + T_USER: /* BERR asserted to cpu */ 593 case T_BUS_ERR_LD_ST + T_USER: /* BERR asserted to cpu */ 594 ucode = 0; /* XXX should be VM_PROT_something */ 595 i = SIGBUS; 596 addr = trapframe->pc; 597 if (!msg) 598 msg = "BUS_ERR"; 599 log_bad_page_fault(msg, trapframe, type); 600 break; 601 602 case T_SYSCALL + T_USER: 603 { 604 struct trapframe *locr0 = td->td_frame; 605 struct sysent *callp; 606 unsigned int code; 607 int nargs, nsaved; 608 register_t args[8]; 609 610 /* 611 * note: PCPU_LAZY_INC() can only be used if we can 612 * afford occassional inaccuracy in the count. 613 */ 614 PCPU_LAZY_INC(cnt.v_syscall); 615 if (td->td_ucred != p->p_ucred) 616 cred_update_thread(td); 617#ifdef KSE 618 if (p->p_flag & P_SA) 619 thread_user_enter(td); 620#endif 621 /* compute next PC after syscall instruction */ 622 td->td_pcb->pcb_tpc = trapframe->pc; /* Remember if restart */ 623 if (DELAYBRANCH(trapframe->cause)) { /* Check BD bit */ 624 locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 625 0); 626 } else { 627 locr0->pc += sizeof(int); 628 } 629 code = locr0->v0; 630 631 switch (code) { 632 case SYS_syscall: 633 /* 634 * Code is first argument, followed by 635 * actual args. 636 */ 637 code = locr0->a0; 638 args[0] = locr0->a1; 639 args[1] = locr0->a2; 640 args[2] = locr0->a3; 641 nsaved = 3; 642 break; 643 644 case SYS___syscall: 645 /* 646 * Like syscall, but code is a quad, so as 647 * to maintain quad alignment for the rest 648 * of the arguments. 649 */ 650 if (_QUAD_LOWWORD == 0) { 651 code = locr0->a0; 652 } else { 653 code = locr0->a1; 654 } 655 args[0] = locr0->a2; 656 args[1] = locr0->a3; 657 nsaved = 2; 658 quad_syscall = 1; 659 break; 660 661 default: 662 args[0] = locr0->a0; 663 args[1] = locr0->a1; 664 args[2] = locr0->a2; 665 args[3] = locr0->a3; 666 nsaved = 4; 667 } 668#ifdef TRAP_DEBUG 669 printf("SYSCALL #%d pid:%u\n", code, p->p_pid); 670#endif 671 672 if (p->p_sysent->sv_mask) 673 code &= p->p_sysent->sv_mask; 674 675 if (code >= p->p_sysent->sv_size) 676 callp = &p->p_sysent->sv_table[0]; 677 else 678 callp = &p->p_sysent->sv_table[code]; 679 680 nargs = callp->sy_narg; 681 682 if (nargs > nsaved) { 683 i = copyin((caddr_t)(locr0->sp + 684 4 * sizeof(register_t)), (caddr_t)&args[nsaved], 685 (u_int)(nargs - nsaved) * sizeof(register_t)); 686 if (i) { 687 locr0->v0 = i; 688 locr0->a3 = 1; 689#ifdef KTRACE 690 if (KTRPOINT(td, KTR_SYSCALL)) 691 ktrsyscall(code, nargs, args); 692#endif 693 goto done; 694 } 695 } 696#ifdef KTRACE 697 if (KTRPOINT(td, KTR_SYSCALL)) 698 ktrsyscall(code, nargs, args); 699#endif 700 td->td_retval[0] = 0; 701 td->td_retval[1] = locr0->v1; 702 703#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) 704 if (trp == trapdebug) 705 trapdebug[TRAPSIZE - 1].code = code; 706 else 707 trp[-1].code = code; 708#endif 709 STOPEVENT(p, S_SCE, nargs); 710 711 PTRACESTOP_SC(p, td, S_PT_SCE); 712 i = (*callp->sy_call) (td, args); 713#if 0 714 /* 715 * Reinitialize proc pointer `p' as it may be 716 * different if this is a child returning from fork 717 * syscall. 718 */ 719 td = curthread; 720 locr0 = td->td_frame; 721#endif 722 trapdebug_enter(locr0, -code); 723 cpu_set_syscall_retval(td, i); 724 725 /* 726 * The sync'ing of I & D caches for SYS_ptrace() is 727 * done by procfs_domem() through procfs_rwmem() 728 * instead of being done here under a special check 729 * for SYS_ptrace(). 730 */ 731 done: 732 /* 733 * Check for misbehavior. 734 */ 735 WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning", 736 (code >= 0 && code < SYS_MAXSYSCALL) ? 737 syscallnames[code] : "???"); 738 KASSERT(td->td_critnest == 0, 739 ("System call %s returning in a critical section", 740 (code >= 0 && code < SYS_MAXSYSCALL) ? 741 syscallnames[code] : "???")); 742 KASSERT(td->td_locks == 0, 743 ("System call %s returning with %d locks held", 744 (code >= 0 && code < SYS_MAXSYSCALL) ? 745 syscallnames[code] : "???", 746 td->td_locks)); 747 userret(td, trapframe); 748#ifdef KTRACE 749 if (KTRPOINT(td, KTR_SYSRET)) 750 ktrsysret(code, i, td->td_retval[0]); 751#endif 752 /* 753 * This works because errno is findable through the 754 * register set. If we ever support an emulation 755 * where this is not the case, this code will need 756 * to be revisited. 757 */ 758 STOPEVENT(p, S_SCX, code); 759 760 PTRACESTOP_SC(p, td, S_PT_SCX); 761 762 mtx_assert(&Giant, MA_NOTOWNED); 763 return (trapframe->pc); 764 } 765 766#ifdef DDB 767 case T_BREAK: 768 kdb_trap(type, 0, trapframe); 769 return (trapframe->pc); 770#endif 771 772 case T_BREAK + T_USER: 773 { 774 uintptr_t va, instr; 775 776 /* compute address of break instruction */ 777 va = trapframe->pc; 778 if (DELAYBRANCH(trapframe->cause)) 779 va += sizeof(int); 780 781 /* read break instruction */ 782 instr = fuword((caddr_t)va); 783#if 0 784 printf("trap: %s (%d) breakpoint %x at %x: (adr %x ins %x)\n", 785 p->p_comm, p->p_pid, instr, trapframe->pc, 786 p->p_md.md_ss_addr, p->p_md.md_ss_instr); /* XXX */ 787#endif 788 if (td->td_md.md_ss_addr != va || instr != BREAK_SSTEP) { 789 i = SIGTRAP; 790 addr = trapframe->pc; 791 break; 792 } 793 /* 794 * The restoration of the original instruction and 795 * the clearing of the berakpoint will be done later 796 * by the call to ptrace_clear_single_step() in 797 * issignal() when SIGTRAP is processed. 798 */ 799 addr = trapframe->pc; 800 i = SIGTRAP; 801 break; 802 } 803 804 case T_IWATCH + T_USER: 805 case T_DWATCH + T_USER: 806 { 807 uintptr_t va; 808 809 /* compute address of trapped instruction */ 810 va = trapframe->pc; 811 if (DELAYBRANCH(trapframe->cause)) 812 va += sizeof(int); 813 printf("watch exception @ %p\n", (void *)va); 814 i = SIGTRAP; 815 addr = va; 816 break; 817 } 818 819 case T_TRAP + T_USER: 820 { 821 uintptr_t va, instr; 822 struct trapframe *locr0 = td->td_frame; 823 824 /* compute address of trap instruction */ 825 va = trapframe->pc; 826 if (DELAYBRANCH(trapframe->cause)) 827 va += sizeof(int); 828 /* read break instruction */ 829 instr = fuword((caddr_t)va); 830 831 if (DELAYBRANCH(trapframe->cause)) { /* Check BD bit */ 832 locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 833 0); 834 } else { 835 locr0->pc += sizeof(int); 836 } 837 addr = va; 838 i = SIGEMT; /* Stuff it with something for now */ 839 break; 840 } 841 842 case T_RES_INST + T_USER: 843 i = SIGILL; 844 addr = trapframe->pc; 845 break; 846 case T_C2E: 847 case T_C2E + T_USER: 848 goto err; 849 break; 850 case T_COP_UNUSABLE: 851 goto err; 852 break; 853 case T_COP_UNUSABLE + T_USER: 854#if !defined(CPU_HAVEFPU) 855 /* FP (COP1) instruction */ 856 if ((trapframe->cause & CR_COP_ERR) == 0x10000000) { 857 i = SIGILL; 858 break; 859 } 860#endif 861 if ((trapframe->cause & CR_COP_ERR) != 0x10000000) { 862 i = SIGILL; /* only FPU instructions allowed */ 863 break; 864 } 865 addr = trapframe->pc; 866 MipsSwitchFPState(PCPU_GET(fpcurthread), td->td_frame); 867 PCPU_SET(fpcurthread, td); 868 td->td_frame->sr |= SR_COP_1_BIT; 869 td->td_md.md_flags |= MDTD_FPUSED; 870 goto out; 871 872 case T_FPE: 873#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) 874 trapDump("fpintr"); 875#else 876 printf("FPU Trap: PC %x CR %x SR %x\n", 877 trapframe->pc, trapframe->cause, trapframe->sr); 878 goto err; 879#endif 880 881 case T_FPE + T_USER: 882 MachFPTrap(trapframe->sr, trapframe->cause, trapframe->pc); 883 goto out; 884 885 case T_OVFLOW + T_USER: 886 i = SIGFPE; 887 addr = trapframe->pc; 888 break; 889 890 case T_ADDR_ERR_LD: /* misaligned access */ 891 case T_ADDR_ERR_ST: /* misaligned access */ 892#ifdef TRAP_DEBUG 893 printf("+++ ADDR_ERR: type = %d, badvaddr = %x\n", type, 894 trapframe->badvaddr); 895#endif 896 /* Only allow emulation on a user address */ 897 if (allow_unaligned_acc && 898 ((vm_offset_t)trapframe->badvaddr < VM_MAXUSER_ADDRESS)) { 899 int mode; 900 901 if (type == T_ADDR_ERR_LD) 902 mode = VM_PROT_READ; 903 else 904 mode = VM_PROT_WRITE; 905 906 /* 907 * ADDR_ERR faults have higher priority than TLB 908 * Miss faults. Therefore, it is necessary to 909 * verify that the faulting address is a valid 910 * virtual address within the process' address space 911 * before trying to emulate the unaligned access. 912 */ 913 if (useracc((caddr_t) 914 (((vm_offset_t)trapframe->badvaddr) & 915 ~(sizeof(int) - 1)), sizeof(int) * 2, mode)) { 916 access_type = emulate_unaligned_access( 917 trapframe); 918 if (access_type != 0) { 919 return (trapframe->pc); 920 } 921 } 922 } 923 /* FALLTHROUGH */ 924 925 case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ 926 if ((i = td->td_pcb->pcb_onfault) != 0) { 927 td->td_pcb->pcb_onfault = 0; 928 return (onfault_table[i]); 929 } 930 /* FALLTHROUGH */ 931 932 default: 933err: 934 935#if !defined(SMP) && defined(DEBUG) 936 stacktrace(!usermode ? trapframe : td->td_frame); 937 trapDump("trap"); 938#endif 939#ifdef SMP 940 printf("cpu:%d-", PCPU_GET(cpuid)); 941#endif 942 printf("Trap cause = %d (%s - ", type, 943 trap_type[type & (~T_USER)]); 944 945 if (type & T_USER) 946 printf("user mode)\n"); 947 else 948 printf("kernel mode)\n"); 949 950#ifdef TRAP_DEBUG 951 printf("badvaddr = %x, pc = %x, ra = %x, sr = 0x%x\n", 952 trapframe->badvaddr, trapframe->pc, trapframe->ra, 953 trapframe->sr); 954#endif 955 956#ifdef KDB 957 if (debugger_on_panic || kdb_active) { 958 kdb_trap(type, 0, trapframe); 959 } 960#endif 961 panic("trap"); 962 } 963 td->td_frame->pc = trapframe->pc; 964 td->td_frame->cause = trapframe->cause; 965 td->td_frame->badvaddr = trapframe->badvaddr; 966 ksiginfo_init_trap(&ksi); 967 ksi.ksi_signo = i; 968 ksi.ksi_code = ucode; 969 ksi.ksi_addr = (void *)addr; 970 ksi.ksi_trapno = type; 971 trapsignal(td, &ksi); 972out: 973 974 /* 975 * Note: we should only get here if returning to user mode. 976 */ 977 userret(td, trapframe); 978 mtx_assert(&Giant, MA_NOTOWNED); 979 return (trapframe->pc); 980} 981 982#if !defined(SMP) && (defined(DDB) || defined(DEBUG)) 983void 984trapDump(char *msg) 985{ 986 int i, s; 987 988 s = disableintr(); 989 printf("trapDump(%s)\n", msg); 990 for (i = 0; i < TRAPSIZE; i++) { 991 if (trp == trapdebug) { 992 trp = &trapdebug[TRAPSIZE - 1]; 993 } else { 994 trp--; 995 } 996 997 if (trp->cause == 0) 998 break; 999 1000 printf("%s: ADR %x PC %x CR %x SR %x\n", 1001 trap_type[(trp->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT], 1002 trp->vadr, trp->pc, trp->cause, trp->status); 1003 1004 printf(" RA %x SP %x code %d\n", trp->ra, trp->sp, trp->code); 1005 } 1006 restoreintr(s); 1007} 1008 1009#endif 1010 1011 1012/* 1013 * Return the resulting PC as if the branch was executed. 1014 */ 1015uintptr_t 1016MipsEmulateBranch(struct trapframe *framePtr, uintptr_t instPC, int fpcCSR, 1017 uintptr_t instptr) 1018{ 1019 InstFmt inst; 1020 register_t *regsPtr = (register_t *) framePtr; 1021 uintptr_t retAddr = 0; 1022 int condition; 1023 1024#define GetBranchDest(InstPtr, inst) \ 1025 (InstPtr + 4 + ((short)inst.IType.imm << 2)) 1026 1027 1028 if (instptr) { 1029 if (instptr < MIPS_KSEG0_START) 1030 inst.word = fuword32((void *)instptr); 1031 else 1032 inst = *(InstFmt *) instptr; 1033 } else { 1034 if ((vm_offset_t)instPC < MIPS_KSEG0_START) 1035 inst.word = fuword32((void *)instPC); 1036 else 1037 inst = *(InstFmt *) instPC; 1038 } 1039 1040 switch ((int)inst.JType.op) { 1041 case OP_SPECIAL: 1042 switch ((int)inst.RType.func) { 1043 case OP_JR: 1044 case OP_JALR: 1045 retAddr = regsPtr[inst.RType.rs]; 1046 break; 1047 1048 default: 1049 retAddr = instPC + 4; 1050 break; 1051 } 1052 break; 1053 1054 case OP_BCOND: 1055 switch ((int)inst.IType.rt) { 1056 case OP_BLTZ: 1057 case OP_BLTZL: 1058 case OP_BLTZAL: 1059 case OP_BLTZALL: 1060 if ((int)(regsPtr[inst.RType.rs]) < 0) 1061 retAddr = GetBranchDest(instPC, inst); 1062 else 1063 retAddr = instPC + 8; 1064 break; 1065 1066 case OP_BGEZ: 1067 case OP_BGEZL: 1068 case OP_BGEZAL: 1069 case OP_BGEZALL: 1070 if ((int)(regsPtr[inst.RType.rs]) >= 0) 1071 retAddr = GetBranchDest(instPC, inst); 1072 else 1073 retAddr = instPC + 8; 1074 break; 1075 1076 case OP_TGEI: 1077 case OP_TGEIU: 1078 case OP_TLTI: 1079 case OP_TLTIU: 1080 case OP_TEQI: 1081 case OP_TNEI: 1082 retAddr = instPC + 4; /* Like syscall... */ 1083 break; 1084 1085 default: 1086 panic("MipsEmulateBranch: Bad branch cond"); 1087 } 1088 break; 1089 1090 case OP_J: 1091 case OP_JAL: 1092 retAddr = (inst.JType.target << 2) | 1093 ((unsigned)(instPC + 4) & 0xF0000000); 1094 break; 1095 1096 case OP_BEQ: 1097 case OP_BEQL: 1098 if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt]) 1099 retAddr = GetBranchDest(instPC, inst); 1100 else 1101 retAddr = instPC + 8; 1102 break; 1103 1104 case OP_BNE: 1105 case OP_BNEL: 1106 if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt]) 1107 retAddr = GetBranchDest(instPC, inst); 1108 else 1109 retAddr = instPC + 8; 1110 break; 1111 1112 case OP_BLEZ: 1113 case OP_BLEZL: 1114 if ((int)(regsPtr[inst.RType.rs]) <= 0) 1115 retAddr = GetBranchDest(instPC, inst); 1116 else 1117 retAddr = instPC + 8; 1118 break; 1119 1120 case OP_BGTZ: 1121 case OP_BGTZL: 1122 if ((int)(regsPtr[inst.RType.rs]) > 0) 1123 retAddr = GetBranchDest(instPC, inst); 1124 else 1125 retAddr = instPC + 8; 1126 break; 1127 1128 case OP_COP1: 1129 switch (inst.RType.rs) { 1130 case OP_BCx: 1131 case OP_BCy: 1132 if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE) 1133 condition = fpcCSR & FPC_COND_BIT; 1134 else 1135 condition = !(fpcCSR & FPC_COND_BIT); 1136 if (condition) 1137 retAddr = GetBranchDest(instPC, inst); 1138 else 1139 retAddr = instPC + 8; 1140 break; 1141 1142 default: 1143 retAddr = instPC + 4; 1144 } 1145 break; 1146 1147 default: 1148 retAddr = instPC + 4; 1149 } 1150 return (retAddr); 1151} 1152 1153 1154#if defined(DDB) || defined(DEBUG) 1155/* 1156 * Print a stack backtrace. 1157 */ 1158void 1159stacktrace(struct trapframe *regs) 1160{ 1161 stacktrace_subr(regs->pc, regs->sp, regs->ra, printf); 1162} 1163#endif 1164 1165static void 1166log_frame_dump(struct trapframe *frame) 1167{ 1168 log(LOG_ERR, "Trapframe Register Dump:\n"); 1169 log(LOG_ERR, "\tzero: %p\tat: %p\tv0: %p\tv1: %p\n", 1170 (void *)0, (void *)frame->ast, (void *)frame->v0, (void *)frame->v1); 1171 1172 log(LOG_ERR, "\ta0: %p\ta1: %p\ta2: %p\ta3: %p\n", 1173 (void *)frame->a0, (void *)frame->a1, (void *)frame->a2, (void *)frame->a3); 1174 1175 log(LOG_ERR, "\tt0: %p\tt1: %p\tt2: %p\tt3: %p\n", 1176 (void *)frame->t0, (void *)frame->t1, (void *)frame->t2, (void *)frame->t3); 1177 1178 log(LOG_ERR, "\tt4: %p\tt5: %p\tt6: %p\tt7: %p\n", 1179 (void *)frame->t4, (void *)frame->t5, (void *)frame->t6, (void *)frame->t7); 1180 1181 log(LOG_ERR, "\tt8: %p\tt9: %p\ts0: %p\ts1: %p\n", 1182 (void *)frame->t8, (void *)frame->t9, (void *)frame->s0, (void *)frame->s1); 1183 1184 log(LOG_ERR, "\ts2: %p\ts3: %p\ts4: %p\ts5: %p\n", 1185 (void *)frame->s2, (void *)frame->s3, (void *)frame->s4, (void *)frame->s5); 1186 1187 log(LOG_ERR, "\ts6: %p\ts7: %p\tk0: %p\tk1: %p\n", 1188 (void *)frame->s6, (void *)frame->s7, (void *)frame->k0, (void *)frame->k1); 1189 1190 log(LOG_ERR, "\tgp: %p\tsp: %p\ts8: %p\tra: %p\n", 1191 (void *)frame->gp, (void *)frame->sp, (void *)frame->s8, (void *)frame->ra); 1192 1193 log(LOG_ERR, "\tsr: %p\tmullo: %p\tmulhi: %p\tbadvaddr: %p\n", 1194 (void *)frame->sr, (void *)frame->mullo, (void *)frame->mulhi, (void *)frame->badvaddr); 1195 1196#ifdef IC_REG 1197 log(LOG_ERR, "\tcause: %p\tpc: %p\tic: %p\n", 1198 (void *)frame->cause, (void *)frame->pc, (void *)frame->ic); 1199#else 1200 log(LOG_ERR, "\tcause: %p\tpc: %p\n", 1201 (void *)frame->cause, (void *)frame->pc); 1202#endif 1203} 1204 1205#ifdef TRAP_DEBUG 1206static void 1207trap_frame_dump(struct trapframe *frame) 1208{ 1209 printf("Trapframe Register Dump:\n"); 1210 printf("\tzero: %p\tat: %p\tv0: %p\tv1: %p\n", 1211 (void *)0, (void *)frame->ast, (void *)frame->v0, (void *)frame->v1); 1212 1213 printf("\ta0: %p\ta1: %p\ta2: %p\ta3: %p\n", 1214 (void *)frame->a0, (void *)frame->a1, (void *)frame->a2, (void *)frame->a3); 1215 1216 printf("\tt0: %p\tt1: %p\tt2: %p\tt3: %p\n", 1217 (void *)frame->t0, (void *)frame->t1, (void *)frame->t2, (void *)frame->t3); 1218 1219 printf("\tt4: %p\tt5: %p\tt6: %p\tt7: %p\n", 1220 (void *)frame->t4, (void *)frame->t5, (void *)frame->t6, (void *)frame->t7); 1221 1222 printf("\tt8: %p\tt9: %p\ts0: %p\ts1: %p\n", 1223 (void *)frame->t8, (void *)frame->t9, (void *)frame->s0, (void *)frame->s1); 1224 1225 printf("\ts2: %p\ts3: %p\ts4: %p\ts5: %p\n", 1226 (void *)frame->s2, (void *)frame->s3, (void *)frame->s4, (void *)frame->s5); 1227 1228 printf("\ts6: %p\ts7: %p\tk0: %p\tk1: %p\n", 1229 (void *)frame->s6, (void *)frame->s7, (void *)frame->k0, (void *)frame->k1); 1230 1231 printf("\tgp: %p\tsp: %p\ts8: %p\tra: %p\n", 1232 (void *)frame->gp, (void *)frame->sp, (void *)frame->s8, (void *)frame->ra); 1233 1234 printf("\tsr: %p\tmullo: %p\tmulhi: %p\tbadvaddr: %p\n", 1235 (void *)frame->sr, (void *)frame->mullo, (void *)frame->mulhi, (void *)frame->badvaddr); 1236 1237#ifdef IC_REG 1238 printf("\tcause: %p\tpc: %p\tic: %p\n", 1239 (void *)frame->cause, (void *)frame->pc, (void *)frame->ic); 1240#else 1241 printf("\tcause: %p\tpc: %p\n", 1242 (void *)frame->cause, (void *)frame->pc); 1243#endif 1244} 1245 1246#endif 1247 1248 1249static void 1250get_mapping_info(vm_offset_t va, pd_entry_t **pdepp, pt_entry_t **ptepp) 1251{ 1252 pt_entry_t *ptep; 1253 pd_entry_t *pdep; 1254 struct proc *p = curproc; 1255 1256 pdep = (&(p->p_vmspace->vm_pmap.pm_segtab[va >> SEGSHIFT])); 1257 if (*pdep) 1258 ptep = pmap_pte(&p->p_vmspace->vm_pmap, va); 1259 else 1260 ptep = (pt_entry_t *)0; 1261 1262 *pdepp = pdep; 1263 *ptepp = ptep; 1264} 1265 1266 1267static void 1268log_bad_page_fault(char *msg, struct trapframe *frame, int trap_type) 1269{ 1270 pt_entry_t *ptep; 1271 pd_entry_t *pdep; 1272 unsigned int *addr; 1273 struct proc *p = curproc; 1274 char *read_or_write; 1275 register_t pc; 1276 1277 trap_type &= ~T_USER; 1278 1279#ifdef SMP 1280 printf("cpuid = %d\n", PCPU_GET(cpuid)); 1281#endif 1282 switch (trap_type) { 1283 case T_TLB_ST_MISS: 1284 case T_ADDR_ERR_ST: 1285 read_or_write = "write"; 1286 break; 1287 case T_TLB_LD_MISS: 1288 case T_ADDR_ERR_LD: 1289 case T_BUS_ERR_IFETCH: 1290 read_or_write = "read"; 1291 break; 1292 default: 1293 read_or_write = ""; 1294 } 1295 1296 pc = frame->pc + (DELAYBRANCH(frame->cause) ? 4 : 0); 1297 log(LOG_ERR, "%s: pid %d (%s), uid %d: pc %p got a %s fault at %p\n", 1298 msg, p->p_pid, p->p_comm, 1299 p->p_ucred ? p->p_ucred->cr_uid : -1, 1300 (void *)pc, 1301 read_or_write, 1302 (void *)frame->badvaddr); 1303 1304 /* log registers in trap frame */ 1305 log_frame_dump(frame); 1306 1307 get_mapping_info((vm_offset_t)pc, &pdep, &ptep); 1308 1309 /* 1310 * Dump a few words around faulting instruction, if the addres is 1311 * valid. 1312 */ 1313 if (!(pc & 3) && (pc != frame->badvaddr) && 1314 (trap_type != T_BUS_ERR_IFETCH) && 1315 useracc((caddr_t)pc, sizeof(int) * 4, VM_PROT_READ)) { 1316 /* dump page table entry for faulting instruction */ 1317 log(LOG_ERR, "Page table info for pc address %p: pde = %p, pte = 0x%lx\n", 1318 (void *)pc, *pdep, ptep ? *ptep : 0); 1319 1320 addr = (unsigned int *)pc; 1321 log(LOG_ERR, "Dumping 4 words starting at pc address %p: \n", 1322 addr); 1323 log(LOG_ERR, "%08x %08x %08x %08x\n", 1324 addr[0], addr[1], addr[2], addr[3]); 1325 } else { 1326 log(LOG_ERR, "pc address %p is inaccessible, pde = 0x%p, pte = 0x%lx\n", 1327 (void *)pc, *pdep, ptep ? *ptep : 0); 1328 } 1329 /* panic("Bad trap");*/ 1330} 1331 1332 1333/* 1334 * Unaligned load/store emulation 1335 */ 1336static int 1337mips_unaligned_load_store(struct trapframe *frame, register_t addr, register_t pc) 1338{ 1339 register_t *reg = (register_t *) frame; 1340 u_int32_t inst = *((u_int32_t *) pc); 1341 u_int32_t value_msb, value; 1342 int access_type = 0; 1343 1344 switch (MIPS_INST_OPCODE(inst)) { 1345 case OP_LHU: 1346 lbu_macro(value_msb, addr); 1347 addr += 1; 1348 lbu_macro(value, addr); 1349 value |= value_msb << 8; 1350 reg[MIPS_INST_RT(inst)] = value; 1351 access_type = MIPS_LHU_ACCESS; 1352 break; 1353 1354 case OP_LH: 1355 lb_macro(value_msb, addr); 1356 addr += 1; 1357 lbu_macro(value, addr); 1358 value |= value_msb << 8; 1359 reg[MIPS_INST_RT(inst)] = value; 1360 access_type = MIPS_LH_ACCESS; 1361 break; 1362 1363 case OP_LWU: 1364 lwl_macro(value, addr); 1365 addr += 3; 1366 lwr_macro(value, addr); 1367 value &= 0xffffffff; 1368 reg[MIPS_INST_RT(inst)] = value; 1369 access_type = MIPS_LWU_ACCESS; 1370 break; 1371 1372 case OP_LW: 1373 lwl_macro(value, addr); 1374 addr += 3; 1375 lwr_macro(value, addr); 1376 reg[MIPS_INST_RT(inst)] = value; 1377 access_type = MIPS_LW_ACCESS; 1378 break; 1379 1380 case OP_SH: 1381 value = reg[MIPS_INST_RT(inst)]; 1382 value_msb = value >> 8; 1383 sb_macro(value_msb, addr); 1384 addr += 1; 1385 sb_macro(value, addr); 1386 access_type = MIPS_SH_ACCESS; 1387 break; 1388 1389 case OP_SW: 1390 value = reg[MIPS_INST_RT(inst)]; 1391 swl_macro(value, addr); 1392 addr += 3; 1393 swr_macro(value, addr); 1394 access_type = MIPS_SW_ACCESS; 1395 break; 1396 1397 default: 1398 break; 1399 } 1400 1401 return access_type; 1402} 1403 1404 1405static int 1406emulate_unaligned_access(struct trapframe *frame) 1407{ 1408 register_t pc; 1409 int access_type = 0; 1410 1411 pc = frame->pc + (DELAYBRANCH(frame->cause) ? 4 : 0); 1412 1413 /* 1414 * Fall through if it's instruction fetch exception 1415 */ 1416 if (!((pc & 3) || (pc == frame->badvaddr))) { 1417 1418 /* 1419 * Handle unaligned load and store 1420 */ 1421 1422 /* 1423 * Return access type if the instruction was emulated. 1424 * Otherwise restore pc and fall through. 1425 */ 1426 access_type = mips_unaligned_load_store(frame, 1427 frame->badvaddr, pc); 1428 1429 if (access_type) { 1430 if (DELAYBRANCH(frame->cause)) 1431 frame->pc = MipsEmulateBranch(frame, frame->pc, 1432 0, 0); 1433 else 1434 frame->pc += 4; 1435 1436 log(LOG_INFO, "Unaligned %s: pc=%p, badvaddr=%p\n", 1437 access_name[access_type - 1], (void *)pc, 1438 (void *)frame->badvaddr); 1439 } 1440 } 1441 return access_type; 1442} 1443