int ykbec_suspend() { struct ykbec_softc *sc = ykbec_sc; int ctrl; /* * Set up wakeup sources: currently only the internal keyboard. */ loongson_set_isa_imr(1 << 1); /* USB */ DPRINTF(("USB\n")); ykbec_write(sc, REG_USB0, USB_FLAG_OFF); ykbec_write(sc, REG_USB1, USB_FLAG_OFF); ykbec_write(sc, REG_USB2, USB_FLAG_OFF); /* EC */ DPRINTF(("REG_PMUCFG\n")); ctrl = PMUCFG_SCI_WAKEUP | PMUCFG_WDT_WAKEUP | PMUCFG_GPWU_WAKEUP | PMUCFG_LPC_WAKEUP | PMUCFG_STOP_MODE | PMUCFG_RESET_8051; ykbec_write(sc, REG_PMUCFG, ctrl); /* FAN */ DPRINTF(("FAN\n")); ykbec_write(sc, REG_FAN_CONTROL, REG_FAN_OFF); /* CPU */ DPRINTF(("CPU\n")); ykbec_chip_config = REGVAL(LOONGSON_CHIP_CONFIG0); enableintr(); REGVAL(LOONGSON_CHIP_CONFIG0) = ykbec_chip_config & ~0x7; (void)REGVAL(LOONGSON_CHIP_CONFIG0); /* * When a resume interrupt fires, we will enter the interrupt * dispatcher, which will do nothing because we are at splhigh, * and execution flow will return here and continue. */ (void)disableintr(); return 0; }
int apm_suspend(int state) { int rv; int s; #if NWSDISPLAY > 0 wsdisplay_suspend(); #endif resettodr(); config_suspend_all(DVACT_QUIESCE); bufq_quiesce(); s = splhigh(); (void)disableintr(); cold = 1; rv = config_suspend_all(DVACT_SUSPEND); suspend_randomness(); #ifdef HIBERNATE if (state == APM_IOC_HIBERNATE) { uvm_pmr_zero_everything(); if (hibernate_suspend()) { printf("apm: hibernate_suspend failed"); hibernate_free(); uvm_pmr_dirty_everything(); return (ECANCELED); } } #endif /* XXX * Flag to disk drivers that they should "power down" the disk * when we get to DVACT_POWERDOWN. */ boothowto |= RB_POWERDOWN; config_suspend_all(DVACT_POWERDOWN); boothowto &= ~RB_POWERDOWN; if (rv == 0) { rv = sys_platform->suspend(); if (rv == 0) rv = sys_platform->resume(); } inittodr(time_second); /* Move the clock forward */ config_suspend_all(DVACT_RESUME); cold = 0; (void)enableintr(); splx(s); resume_randomness(NULL, 0); /* force RNG upper level reseed */ bufq_restart(); config_suspend_all(DVACT_WAKEUP); #if NWSDISPLAY > 0 wsdisplay_resume(); #endif return rv; }
/* * Handle a single exception. */ void itsa(struct trap_frame *trapframe, struct cpu_info *ci, struct proc *p, int type) { int i; unsigned ucode = 0; vm_prot_t ftype; extern vaddr_t onfault_table[]; int onfault; int typ = 0; union sigval sv; struct pcb *pcb; switch (type) { case T_TLB_MOD: /* check for kernel address */ if (trapframe->badvaddr < 0) { pt_entry_t *pte, entry; paddr_t pa; vm_page_t pg; pte = kvtopte(trapframe->badvaddr); entry = *pte; #ifdef DIAGNOSTIC if (!(entry & PG_V) || (entry & PG_M)) panic("trap: ktlbmod: invalid pte"); #endif if (pmap_is_page_ro(pmap_kernel(), trunc_page(trapframe->badvaddr), entry)) { /* write to read only page in the kernel */ ftype = VM_PROT_WRITE; pcb = &p->p_addr->u_pcb; goto kernel_fault; } entry |= PG_M; *pte = entry; KERNEL_LOCK(); pmap_update_kernel_page(trapframe->badvaddr & ~PGOFSET, entry); pa = pfn_to_pad(entry); pg = PHYS_TO_VM_PAGE(pa); if (pg == NULL) panic("trap: ktlbmod: unmanaged page"); pmap_set_modify(pg); KERNEL_UNLOCK(); return; } /* FALLTHROUGH */ case T_TLB_MOD+T_USER: { pt_entry_t *pte, entry; paddr_t pa; vm_page_t pg; pmap_t pmap = p->p_vmspace->vm_map.pmap; if (!(pte = pmap_segmap(pmap, trapframe->badvaddr))) panic("trap: utlbmod: invalid segmap"); pte += uvtopte(trapframe->badvaddr); entry = *pte; #ifdef DIAGNOSTIC if (!(entry & PG_V) || (entry & PG_M)) panic("trap: utlbmod: invalid pte"); #endif if (pmap_is_page_ro(pmap, trunc_page(trapframe->badvaddr), entry)) { /* write to read only page */ ftype = VM_PROT_WRITE; pcb = &p->p_addr->u_pcb; goto fault_common_no_miss; } entry |= PG_M; *pte = entry; KERNEL_LOCK(); pmap_update_user_page(pmap, (trapframe->badvaddr & ~PGOFSET), entry); pa = pfn_to_pad(entry); pg = PHYS_TO_VM_PAGE(pa); if (pg == NULL) panic("trap: utlbmod: unmanaged page"); pmap_set_modify(pg); KERNEL_UNLOCK(); return; } case T_TLB_LD_MISS: case T_TLB_ST_MISS: ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ; pcb = &p->p_addr->u_pcb; /* check for kernel address */ if (trapframe->badvaddr < 0) { vaddr_t va; int rv; kernel_fault: va = trunc_page((vaddr_t)trapframe->badvaddr); onfault = pcb->pcb_onfault; pcb->pcb_onfault = 0; KERNEL_LOCK(); rv = uvm_fault(kernel_map, trunc_page(va), 0, ftype); KERNEL_UNLOCK(); pcb->pcb_onfault = onfault; if (rv == 0) return; if (onfault != 0) { pcb->pcb_onfault = 0; trapframe->pc = onfault_table[onfault]; return; } goto err; } /* * It is an error for the kernel to access user space except * through the copyin/copyout routines. */ if (pcb->pcb_onfault != 0) { /* * We want to resolve the TLB fault before invoking * pcb_onfault if necessary. */ goto fault_common; } else { goto err; } case T_TLB_LD_MISS+T_USER: ftype = VM_PROT_READ; pcb = &p->p_addr->u_pcb; goto fault_common; case T_TLB_ST_MISS+T_USER: ftype = VM_PROT_WRITE; pcb = &p->p_addr->u_pcb; fault_common: #ifdef CPU_R4000 if (r4000_errata != 0) { if (eop_tlb_miss_handler(trapframe, ci, p) != 0) return; } #endif fault_common_no_miss: #ifdef CPU_R4000 if (r4000_errata != 0) { eop_cleanup(trapframe, p); } #endif { vaddr_t va; struct vmspace *vm; vm_map_t map; int rv; vm = p->p_vmspace; map = &vm->vm_map; va = trunc_page((vaddr_t)trapframe->badvaddr); onfault = pcb->pcb_onfault; pcb->pcb_onfault = 0; KERNEL_LOCK(); rv = uvm_fault(map, va, 0, ftype); pcb->pcb_onfault = onfault; /* * If this was a stack access we keep track of the maximum * accessed stack size. Also, if vm_fault gets a protection * failure it is due to accessing the stack region outside * the current limit and we need to reflect that as an access * error. */ if ((caddr_t)va >= vm->vm_maxsaddr) { if (rv == 0) uvm_grow(p, va); else if (rv == EACCES) rv = EFAULT; } KERNEL_UNLOCK(); if (rv == 0) return; if (!USERMODE(trapframe->sr)) { if (onfault != 0) { pcb->pcb_onfault = 0; trapframe->pc = onfault_table[onfault]; return; } goto err; } ucode = ftype; i = SIGSEGV; typ = SEGV_MAPERR; break; } case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ ucode = 0; /* XXX should be VM_PROT_something */ i = SIGBUS; typ = BUS_ADRALN; break; case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ ucode = 0; /* XXX should be VM_PROT_something */ i = SIGBUS; typ = BUS_OBJERR; break; case T_SYSCALL+T_USER: { struct trap_frame *locr0 = p->p_md.md_regs; struct sysent *callp; unsigned int code; register_t tpc; int numsys, error; struct args { register_t i[8]; } args; register_t rval[2]; atomic_add_int(&uvmexp.syscalls, 1); /* compute next PC after syscall instruction */ tpc = trapframe->pc; /* Remember if restart */ if (trapframe->cause & CR_BR_DELAY) locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 0); else locr0->pc += 4; callp = p->p_p->ps_emul->e_sysent; numsys = p->p_p->ps_emul->e_nsysent; code = locr0->v0; switch (code) { case SYS_syscall: case SYS___syscall: /* * Code is first argument, followed by actual args. * __syscall provides the code as a quad to maintain * proper alignment of 64-bit arguments on 32-bit * platforms, which doesn't change anything here. */ code = locr0->a0; if (code >= numsys) callp += p->p_p->ps_emul->e_nosys; /* (illegal) */ else callp += code; i = callp->sy_argsize / sizeof(register_t); args.i[0] = locr0->a1; args.i[1] = locr0->a2; args.i[2] = locr0->a3; if (i > 3) { args.i[3] = locr0->a4; args.i[4] = locr0->a5; args.i[5] = locr0->a6; args.i[6] = locr0->a7; if (i > 7) if ((error = copyin((void *)locr0->sp, &args.i[7], sizeof(register_t)))) goto bad; } break; default: if (code >= numsys) callp += p->p_p->ps_emul->e_nosys; /* (illegal) */ else callp += code; i = callp->sy_narg; args.i[0] = locr0->a0; args.i[1] = locr0->a1; args.i[2] = locr0->a2; args.i[3] = locr0->a3; if (i > 4) { args.i[4] = locr0->a4; args.i[5] = locr0->a5; args.i[6] = locr0->a6; args.i[7] = locr0->a7; } } rval[0] = 0; rval[1] = locr0->v1; #if defined(DDB) || defined(DEBUG) trapdebug[TRAPSIZE * ci->ci_cpuid + (trppos[ci->ci_cpuid] == 0 ? TRAPSIZE : trppos[ci->ci_cpuid]) - 1].code = code; #endif error = mi_syscall(p, code, callp, args.i, rval); switch (error) { case 0: locr0->v0 = rval[0]; locr0->v1 = rval[1]; locr0->a3 = 0; break; case ERESTART: locr0->pc = tpc; break; case EJUSTRETURN: break; /* nothing to do */ default: bad: locr0->v0 = error; locr0->a3 = 1; } mi_syscall_return(p, code, error, rval); return; } case T_BREAK: #ifdef DDB kdb_trap(type, trapframe); #endif /* Reenable interrupts if necessary */ if (trapframe->sr & SR_INT_ENAB) { enableintr(); } return; case T_BREAK+T_USER: { caddr_t va; u_int32_t instr; struct trap_frame *locr0 = p->p_md.md_regs; /* compute address of break instruction */ va = (caddr_t)trapframe->pc; if (trapframe->cause & CR_BR_DELAY) va += 4; /* read break instruction */ copyin(va, &instr, sizeof(int32_t)); switch ((instr & BREAK_VAL_MASK) >> BREAK_VAL_SHIFT) { case 6: /* gcc range error */ i = SIGFPE; typ = FPE_FLTSUB; /* skip instruction */ if (trapframe->cause & CR_BR_DELAY) locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 0); else locr0->pc += 4; break; case 7: /* gcc3 divide by zero */ i = SIGFPE; typ = FPE_INTDIV; /* skip instruction */ if (trapframe->cause & CR_BR_DELAY) locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 0); else locr0->pc += 4; break; #ifdef PTRACE case BREAK_SSTEP_VAL: if (p->p_md.md_ss_addr == (long)va) { #ifdef DEBUG printf("trap: %s (%d): breakpoint at %p " "(insn %08x)\n", p->p_comm, p->p_pid, (void *)p->p_md.md_ss_addr, p->p_md.md_ss_instr); #endif /* Restore original instruction and clear BP */ process_sstep(p, 0); typ = TRAP_BRKPT; } else { typ = TRAP_TRACE; } i = SIGTRAP; break; #endif #ifdef FPUEMUL case BREAK_FPUEMUL_VAL: /* * If this is a genuine FP emulation break, * resume execution to our branch destination. */ if ((p->p_md.md_flags & MDP_FPUSED) != 0 && p->p_md.md_fppgva + 4 == (vaddr_t)va) { struct vm_map *map = &p->p_vmspace->vm_map; p->p_md.md_flags &= ~MDP_FPUSED; locr0->pc = p->p_md.md_fpbranchva; /* * Prevent access to the relocation page. * XXX needs to be fixed to work with rthreads */ uvm_fault_unwire(map, p->p_md.md_fppgva, p->p_md.md_fppgva + PAGE_SIZE); (void)uvm_map_protect(map, p->p_md.md_fppgva, p->p_md.md_fppgva + PAGE_SIZE, UVM_PROT_NONE, FALSE); return; } /* FALLTHROUGH */ #endif default: typ = TRAP_TRACE; i = SIGTRAP; break; } break; } case T_IWATCH+T_USER: case T_DWATCH+T_USER: { caddr_t va; /* compute address of trapped instruction */ va = (caddr_t)trapframe->pc; if (trapframe->cause & CR_BR_DELAY) va += 4; printf("watch exception @ %p\n", va); #ifdef RM7K_PERFCNTR if (rm7k_watchintr(trapframe)) { /* Return to user, don't add any more overhead */ return; } #endif i = SIGTRAP; typ = TRAP_BRKPT; break; } case T_TRAP+T_USER: { caddr_t va; u_int32_t instr; struct trap_frame *locr0 = p->p_md.md_regs; /* compute address of trap instruction */ va = (caddr_t)trapframe->pc; if (trapframe->cause & CR_BR_DELAY) va += 4; /* read break instruction */ copyin(va, &instr, sizeof(int32_t)); if (trapframe->cause & CR_BR_DELAY) locr0->pc = MipsEmulateBranch(locr0, trapframe->pc, 0, 0); else locr0->pc += 4; #ifdef RM7K_PERFCNTR if (instr == 0x040c0000) { /* Performance cntr trap */ int result; result = rm7k_perfcntr(trapframe->a0, trapframe->a1, trapframe->a2, trapframe->a3); locr0->v0 = -result; /* Return to user, don't add any more overhead */ return; } else #endif /* * GCC 4 uses teq with code 7 to signal divide by * zero at runtime. This is one instruction shorter * than the BEQ + BREAK combination used by gcc 3. */ if ((instr & 0xfc00003f) == 0x00000034 /* teq */ && (instr & 0x001fffc0) == ((ZERO << 16) | (7 << 6))) { i = SIGFPE; typ = FPE_INTDIV; } else { i = SIGEMT; /* Stuff it with something for now */ typ = 0; } break; } case T_RES_INST+T_USER: i = SIGILL; typ = ILL_ILLOPC; break; case T_COP_UNUSABLE+T_USER: /* * Note MIPS IV COP1X instructions issued with FPU * disabled correctly report coprocessor 1 as the * unusable coprocessor number. */ if ((trapframe->cause & CR_COP_ERR) != CR_COP1_ERR) { i = SIGILL; /* only FPU instructions allowed */ typ = ILL_ILLOPC; break; } #ifdef FPUEMUL MipsFPTrap(trapframe); #else enable_fpu(p); #endif return; case T_FPE: printf("FPU Trap: PC %lx CR %lx SR %lx\n", trapframe->pc, trapframe->cause, trapframe->sr); goto err; case T_FPE+T_USER: MipsFPTrap(trapframe); return; case T_OVFLOW+T_USER: i = SIGFPE; typ = FPE_FLTOVF; break; case T_ADDR_ERR_LD: /* misaligned access */ case T_ADDR_ERR_ST: /* misaligned access */ case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ pcb = &p->p_addr->u_pcb; if ((onfault = pcb->pcb_onfault) != 0) { pcb->pcb_onfault = 0; trapframe->pc = onfault_table[onfault]; return; } goto err; default: err: disableintr(); #if !defined(DDB) && defined(DEBUG) trapDump("trap", printf); #endif printf("\nTrap cause = %d Frame %p\n", type, trapframe); printf("Trap PC %p RA %p fault %p\n", (void *)trapframe->pc, (void *)trapframe->ra, (void *)trapframe->badvaddr); #ifdef DDB stacktrace(!USERMODE(trapframe->sr) ? trapframe : p->p_md.md_regs); kdb_trap(type, trapframe); #endif panic("trap"); } #ifdef FPUEMUL /* * If a relocated delay slot causes an exception, blame the * original delay slot address - userland is not supposed to * know anything about emulation bowels. */ if ((p->p_md.md_flags & MDP_FPUSED) != 0 && trapframe->badvaddr == p->p_md.md_fppgva) trapframe->badvaddr = p->p_md.md_fpslotva; #endif p->p_md.md_regs->pc = trapframe->pc; p->p_md.md_regs->cause = trapframe->cause; p->p_md.md_regs->badvaddr = trapframe->badvaddr; sv.sival_ptr = (void *)trapframe->badvaddr; KERNEL_LOCK(); trapsignal(p, i, ucode, typ, sv); KERNEL_UNLOCK(); }
/* * Handle an exception. * In the case of a kernel trap, we return the pc where to resume if * pcb_onfault is set, otherwise, return old pc. */ void trap(struct trap_frame *trapframe) { struct cpu_info *ci = curcpu(); struct proc *p = ci->ci_curproc; int type; type = (trapframe->cause & CR_EXC_CODE) >> CR_EXC_CODE_SHIFT; #if defined(CPU_R8000) && !defined(DEBUG_INTERRUPT) if (type != T_INT) #endif trapdebug_enter(ci, trapframe, -1); #ifdef CPU_R8000 if (type != T_INT && type != T_SYSCALL) #else if (type != T_SYSCALL) #endif atomic_add_int(&uvmexp.traps, 1); if (USERMODE(trapframe->sr)) { type |= T_USER; refreshcreds(p); } /* * Enable hardware interrupts if they were on before the trap; * enable IPI interrupts only otherwise. */ switch (type) { #ifdef CPU_R8000 case T_INT: case T_INT | T_USER: #endif case T_BREAK: break; default: if (ISSET(trapframe->sr, SR_INT_ENAB)) enableintr(); else { #ifdef MULTIPROCESSOR ENABLEIPI(); #endif } break; } #ifdef CPU_R8000 /* * Some exception causes on R8000 are actually detected by external * circuitry, and as such are reported as external interrupts. * On R8000 kernels, external interrupts vector to trap() instead of * interrupt(), so that we can process these particular exceptions * as if they were triggered as regular exceptions. */ if ((type & ~T_USER) == T_INT) { /* * Similar reality check as done in interrupt(), in case * an interrupt occured between a write to COP_0_STATUS_REG * and it taking effect. */ if (!ISSET(trapframe->sr, SR_INT_ENAB)) return; if (trapframe->cause & CR_VCE) { #ifndef DEBUG_INTERRUPT trapdebug_enter(ci, trapframe, -1); #endif panic("VCE or TLBX"); } if (trapframe->cause & CR_FPE) { #ifndef DEBUG_INTERRUPT trapdebug_enter(ci, trapframe, -1); #endif itsa(trapframe, ci, p, T_FPE | (type & T_USER)); cp0_reset_cause(CR_FPE); } if (trapframe->cause & CR_INT_MASK) interrupt(trapframe); return; /* no userret */ } else #endif itsa(trapframe, ci, p, type); if (type & T_USER) userret(p); }
void hibernate_enable_intr_machdep(void) { enableintr(); }