/* $NetBSD: machdep.c,v 1.48 1995/05/16 14:34:19 mycroft Exp $ */ /* * Copyright (c) 1995 Theo de Raadt * Copyright (c) 1988 University of Utah. * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: machdep.c 1.74 92/12/20$ * * @(#)machdep.c 8.10 (Berkeley) 4/20/94 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SYSVMSG #include #endif #ifdef SYSVSEM #include #endif #ifdef SYSVSHM #include #endif #include #include #include #include #include #include #include #include #define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */ #include /* the following is used externally (sysctl_hw) */ char machine[] = "mvme68k"; /* cpu "architecture" */ vm_map_t buffer_map; extern vm_offset_t avail_end; /* * Declare these as initialized data so we can patch them. */ int nswbuf = 0; #ifdef NBUF int nbuf = NBUF; #else int nbuf = 0; #endif #ifdef BUFPAGES int bufpages = BUFPAGES; #else int bufpages = 0; #endif int msgbufmapped; /* set when safe to use msgbuf */ int maxmem; /* max memory per process */ int physmem = MAXMEM; /* max supported memory, changes to actual */ /* * safepri is a safe priority for sleep to set for a spin-wait * during autoconfiguration or after a panic. */ int safepri = PSL_LOWIPL; extern u_int lowram; extern short exframesize[]; #ifdef COMPAT_HPUX extern struct emul emul_hpux; #endif #ifdef COMPAT_SUNOS extern struct emul emul_sunos; #endif /* * Console initialization: called early on from main, * before vm init or startup. Do enough configuration * to choose and initialize a console. */ consinit() { /* * Initialize the console before we print anything out. */ cninit(); #ifdef DDB db_machine_init(); ddb_init(); if (boothowto & RB_KDB) Debugger(); #endif } /* * cpu_startup: allocate memory for variable-sized tables, * initialize cpu, and do autoconfiguration. */ void cpu_startup() { register unsigned i; register caddr_t v, firstaddr; int base, residual; vm_offset_t minaddr, maxaddr; vm_size_t size; #ifdef BUFFERS_UNMANAGED vm_offset_t bufmemp; caddr_t buffermem; int ix; #endif #ifdef DEBUG extern int pmapdebug; int opmapdebug = pmapdebug; pmapdebug = 0; #endif /* * Initialize error message buffer (at end of core). * avail_end was pre-decremented in pmap_bootstrap to compensate. */ for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) pmap_enter(pmap_kernel(), (vm_offset_t)msgbufp, avail_end + i * NBPG, VM_PROT_ALL, TRUE); msgbufmapped = 1; /* * Good {morning,afternoon,evening,night}. */ printf(version); identifycpu(); printf("real mem = %d\n", ctob(physmem)); /* * Allocate space for system data structures. * The first available real memory address is in "firstaddr". * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) #ifdef REAL_CLISTS valloc(cfree, struct cblock, nclist); #endif valloc(callout, struct callout, ncallout); valloc(swapmap, struct map, nswapmap = maxproc * 2); #ifdef SYSVSHM valloc(shmsegs, struct shmid_ds, shminfo.shmmni); #endif #ifdef SYSVSEM valloc(sema, struct semid_ds, seminfo.semmni); valloc(sem, struct sem, seminfo.semmns); /* This is pretty disgusting! */ valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); #endif #ifdef SYSVMSG valloc(msgpool, char, msginfo.msgmax); valloc(msgmaps, struct msgmap, msginfo.msgseg); valloc(msghdrs, struct msg, msginfo.msgtql); valloc(msqids, struct msqid_ds, msginfo.msgmni); #endif /* * Determine how many buffers to allocate. * We just allocate a flat 5%. Insure a minimum of 16 buffers. * We allocate 1/2 as many swap buffer headers as file i/o buffers. */ if (bufpages == 0) bufpages = physmem / 20 / CLSIZE; if (nbuf == 0) { nbuf = bufpages; if (nbuf < 16) nbuf = 16; } if (nswbuf == 0) { nswbuf = (nbuf / 2) &~ 1; /* force even */ if (nswbuf > 256) nswbuf = 256; /* sanity */ } valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (caddr_t) kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); #ifdef BUFFERS_UNMANAGED buffermem = (caddr_t) kmem_alloc(kernel_map, bufpages*CLBYTES); if (buffermem == 0) panic("startup: no room for buffers"); #endif goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); /* * Now allocate buffers proper. They are different than the above * in that they usually occupy more virtual memory than physical. */ size = MAXBSIZE * nbuf; buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers, &maxaddr, size, TRUE); minaddr = (vm_offset_t)buffers; if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0, &minaddr, size, FALSE) != KERN_SUCCESS) panic("startup: cannot allocate buffers"); base = bufpages / nbuf; residual = bufpages % nbuf; for (i = 0; i < nbuf; i++) { vm_size_t curbufsize; vm_offset_t curbuf; /* * First buffers get (base+1) physical pages * allocated for them. The rest get (base) physical pages. * * The rest of each buffer occupies virtual space, * but has no physical memory allocated for it. */ curbuf = (vm_offset_t)buffers + i * MAXBSIZE; curbufsize = CLBYTES * (i < residual ? base+1 : base); vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); vm_map_simplify(buffer_map, curbuf); } /* * Allocate a submap for exec arguments. This map effectively * limits the number of processes exec'ing at any time. */ exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, 16*NCARGS, TRUE); /* * Allocate a submap for physio */ phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, VM_PHYS_SIZE, TRUE); /* * Finally, allocate mbuf pool. Since mclrefcnt is an off-size * we use the more space efficient malloc in place of kmem_alloc. */ mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, M_MBUF, M_NOWAIT); bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr, VM_MBUF_SIZE, FALSE); /* * Initialize callouts */ callfree = callout; for (i = 1; i < ncallout; i++) callout[i-1].c_next = &callout[i]; callout[i-1].c_next = NULL; #ifdef DEBUG pmapdebug = opmapdebug; #endif printf("avail mem = %d\n", ptoa(cnt.v_free_count)); printf("using %d buffers containing %d bytes of memory\n", nbuf, bufpages * CLBYTES); #ifdef MFS /* * Check to see if a mini-root was loaded into memory. It resides * at the start of the next page just after the end of BSS. */ { extern void *smini; if (smini && (boothowto & RB_MINIROOT)) { boothowto |= RB_DFLTROOT; mfs_initminiroot(smini); } } #endif /* * Set up CPU-specific registers, cache, etc. */ initcpu(); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); /* * Configure the system. */ configure(); } /* * Set registers on exec. * XXX Should clear registers except sp, pc, * but would break init; should be fixed soon. */ void setregs(p, pack, stack, retval) register struct proc *p; struct exec_package *pack; u_long stack; register_t *retval; { struct frame *frame = (struct frame *)p->p_md.md_regs; frame->f_pc = pack->ep_entry & ~1; frame->f_regs[SP] = stack; frame->f_regs[A2] = (int)PS_STRINGS; #ifdef FPCOPROC /* restore a null state frame */ p->p_addr->u_pcb.pcb_fpregs.fpf_null = 0; m68881_restore(&p->p_addr->u_pcb.pcb_fpregs); #endif #ifdef COMPAT_HPUX p->p_md.md_flags &= ~MDP_HPUXMMAP; if (p->p_emul == &emul_hpux) { frame->f_regs[A0] = 0; /* not 68010 (bit 31), no FPA (30) */ retval[0] = 0; /* no float card */ #ifdef FPCOPROC retval[1] = 1; /* yes 68881 */ #else retval[1] = 0; /* no 68881 */ #endif } /* * XXX This doesn't have much to do with setting registers but * I didn't want to muck up kern_exec.c with this code, so I * stuck it here. * * Ensure we perform the right action on traps type 1 and 2: * If our parent is an HPUX process and we are being traced, turn * on HPUX style interpretation. Else if we were using the HPUX * style interpretation, revert to the BSD interpretation. * * Note that we do this by changing the trap instruction in the * global "sigcode" array which then gets copied out to the user's * sigcode in the stack. Since we are changing it in the global * array we must always reset it, even for non-HPUX processes. * * Note also that implementing it in this way creates a potential * race where we could have tweaked it for process A which then * blocks in the copyout to the stack and process B comes along * and untweaks it causing A to wind up with the wrong setting * when the copyout continues. However, since we have already * copied something out to this user stack page (thereby faulting * it in), this scenerio is extremely unlikely. */ { extern short sigcodetrap[]; if ((p->p_pptr->p_emul == &emul_hpux) && (p->p_flag & P_TRACED)) { p->p_md.md_flags |= MDP_HPUXTRACE; *sigcodetrap = 0x4E42; } else { p->p_md.md_flags &= ~MDP_HPUXTRACE; *sigcodetrap = 0x4E41; } } #endif } /* * Info for CTL_HW */ char cpu_model[120]; extern char version[]; int cputyp; int cpuspeed; struct mvmeprom_brdid brdid; identifycpu() { char *t, *mc; char speed[6]; char suffix[30]; int len; bzero(suffix, sizeof suffix); mc = (mmutype == MMU_68040 ? "40" : (mmutype == MMU_68030 ? "30" : "20")); switch (cputyp) { #ifdef MVME147 case CPU_147: bcopy(&brdid.suffix, suffix, sizeof brdid.suffix); sprintf(suffix, "MVME%x", brdid.model, suffix); cpuspeed = pccspeed((struct pccreg *)IIOV(0xfffe1000)); sprintf(speed, "%02d", cpuspeed); break; #endif #if defined(MVME162) || defined(MVME167) || defined(MVME177) case CPU_162: case CPU_167: case CPU_177: bzero(speed, sizeof speed); speed[0] = brdid.speed[0]; speed[1] = brdid.speed[1]; if (brdid.speed[2] != '0' && brdid.speed[3] != '0') { speed[2] = '.'; speed[3] = brdid.speed[2]; speed[4] = brdid.speed[3]; } cpuspeed = (speed[0] - '0') * 10 + (speed[1] - '0'); bcopy(brdid.longname, suffix, sizeof(brdid.longname)); for (len = strlen(suffix)-1; len; len--) { if (suffix[len] == ' ') suffix[len] = '\0'; else break; } break; #endif } sprintf(cpu_model, "Motorola %s: %sMHz MC680%s CPU", suffix, speed, mc); switch (mmutype) { case MMU_68040: case MMU_68030: strcat(cpu_model, "+MMU"); break; case MMU_68851: strcat(cpu_model, ", MC68851 MMU"); break; default: printf("%s\nunknown MMU type %d\n", cpu_model, mmutype); panic("startup"); } len = strlen(cpu_model); if (mmutype == MMU_68040) len += sprintf(cpu_model + len, "+FPU, 4k on-chip physical I/D caches"); #if defined(M68030) || defined(M68020) else { int fpu = fpu_gettype(); switch (fpu) { case 0: break; case 1: case 2: len += sprintf(cpu_model + len, ", MC6888%d FPU", fpu); break; case 3: len += sprintf(cpu_model + len, ", unknown FPU", speed); break; } } #endif printf("%s\n", cpu_model); } /* * machine dependent system variables. */ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) int *name; u_int namelen; void *oldp; size_t *oldlenp; void *newp; size_t newlen; struct proc *p; { dev_t consdev; /* all sysctl names at this level are terminal */ if (namelen != 1) return (ENOTDIR); /* overloaded */ switch (name[0]) { case CPU_CONSDEV: if (cn_tab != NULL) consdev = cn_tab->cn_dev; else consdev = NODEV; return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, sizeof consdev)); default: return (EOPNOTSUPP); } /* NOTREACHED */ } #define SS_RTEFRAME 1 #define SS_FPSTATE 2 #define SS_USERREGS 4 struct sigstate { int ss_flags; /* which of the following are valid */ struct frame ss_frame; /* original exception frame */ struct fpframe ss_fpstate; /* 68881/68882 state info */ }; /* * WARNING: code in locore.s assumes the layout shown for sf_signum * thru sf_handler so... don't screw with them! */ struct sigframe { int sf_signum; /* signo for handler */ int sf_code; /* additional info for handler */ struct sigcontext *sf_scp; /* context ptr for handler */ sig_t sf_handler; /* handler addr for u_sigc */ struct sigstate sf_state; /* state of the hardware */ struct sigcontext sf_sc; /* actual context */ }; #ifdef COMPAT_HPUX struct hpuxsigcontext { int hsc_syscall; char hsc_action; char hsc_pad1; char hsc_pad2; char hsc_onstack; int hsc_mask; int hsc_sp; short hsc_ps; int hsc_pc; /* the rest aren't part of the context but are included for our convenience */ short hsc_pad; u_int hsc_magic; /* XXX sigreturn: cookie */ struct sigcontext *hsc_realsc; /* XXX sigreturn: ptr to BSD context */ }; /* * For an HP-UX process, a partial hpuxsigframe follows the normal sigframe. * Tremendous waste of space, but some HP-UX applications (e.g. LCL) need it. */ struct hpuxsigframe { int hsf_signum; int hsf_code; struct sigcontext *hsf_scp; struct hpuxsigcontext hsf_sc; int hsf_regs[15]; }; #endif #ifdef DEBUG int sigdebug = 0; int sigpid = 0; #define SDB_FOLLOW 0x01 #define SDB_KSTACK 0x02 #define SDB_FPSTATE 0x04 #endif /* * Send an interrupt to process. */ void sendsig(catcher, sig, mask, code) sig_t catcher; int sig, mask; u_long code; { register struct proc *p = curproc; register struct sigframe *fp, *kfp; register struct frame *frame; register struct sigacts *psp = p->p_sigacts; register short ft; int oonstack, fsize; extern char sigcode[], esigcode[]; frame = (struct frame *)p->p_md.md_regs; ft = frame->f_format; oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; /* * Allocate and validate space for the signal handler * context. Note that if the stack is in P0 space, the * call to grow() is a nop, and the useracc() check * will fail if the process has not already allocated * the space with a `brk'. */ #ifdef COMPAT_HPUX if (p->p_emul == &emul_hpux) fsize = sizeof(struct sigframe) + sizeof(struct hpuxsigframe); else #endif fsize = sizeof(struct sigframe); if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && (psp->ps_sigonstack & sigmask(sig))) { fp = (struct sigframe *)(psp->ps_sigstk.ss_base + psp->ps_sigstk.ss_size - fsize); psp->ps_sigstk.ss_flags |= SA_ONSTACK; } else fp = (struct sigframe *)(frame->f_regs[SP] - fsize); if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) (void)grow(p, (unsigned)fp); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d ssp %x usp %x scp %x ft %d\n", p->p_pid, sig, &oonstack, fp, &fp->sf_sc, ft); #endif if (useracc((caddr_t)fp, fsize, B_WRITE) == 0) { #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): useracc failed on sig %d\n", p->p_pid, sig); #endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; p->p_sigmask &= ~sig; psignal(p, SIGILL); return; } kfp = (struct sigframe *)malloc((u_long)fsize, M_TEMP, M_WAITOK); /* * Build the argument list for the signal handler. */ kfp->sf_signum = sig; kfp->sf_code = code; kfp->sf_scp = &fp->sf_sc; kfp->sf_handler = catcher; /* * Save necessary hardware state. Currently this includes: * - general registers * - original exception frame (if not a "normal" frame) * - FP coprocessor state */ kfp->sf_state.ss_flags = SS_USERREGS; bcopy((caddr_t)frame->f_regs, (caddr_t)kfp->sf_state.ss_frame.f_regs, sizeof frame->f_regs); if (ft >= FMT7) { #ifdef DEBUG if (ft > 15 || exframesize[ft] < 0) panic("sendsig: bogus frame type"); #endif kfp->sf_state.ss_flags |= SS_RTEFRAME; kfp->sf_state.ss_frame.f_format = frame->f_format; kfp->sf_state.ss_frame.f_vector = frame->f_vector; bcopy((caddr_t)&frame->F_u, (caddr_t)&kfp->sf_state.ss_frame.F_u, exframesize[ft]); /* * Leave an indicator that we need to clean up the kernel * stack. We do this by setting the "pad word" above the * hardware stack frame to the amount the stack must be * adjusted by. * * N.B. we increment rather than just set f_stackadj in * case we are called from syscall when processing a * sigreturn. In that case, f_stackadj may be non-zero. */ frame->f_stackadj += exframesize[ft]; frame->f_format = frame->f_vector = 0; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): copy out %d of frame %d\n", p->p_pid, exframesize[ft], ft); #endif } #ifdef FPCOPROC kfp->sf_state.ss_flags |= SS_FPSTATE; m68881_save(&kfp->sf_state.ss_fpstate); #ifdef DEBUG if ((sigdebug & SDB_FPSTATE) && *(char *)&kfp->sf_state.ss_fpstate) printf("sendsig(%d): copy out FP state (%x) to %x\n", p->p_pid, *(u_int *)&kfp->sf_state.ss_fpstate, &kfp->sf_state.ss_fpstate); #endif #endif /* * Build the signal context to be used by sigreturn. */ kfp->sf_sc.sc_onstack = oonstack; kfp->sf_sc.sc_mask = mask; kfp->sf_sc.sc_sp = frame->f_regs[SP]; kfp->sf_sc.sc_fp = frame->f_regs[A6]; kfp->sf_sc.sc_ap = (int)&fp->sf_state; kfp->sf_sc.sc_pc = frame->f_pc; kfp->sf_sc.sc_ps = frame->f_sr; #ifdef COMPAT_HPUX /* * Create an HP-UX style sigcontext structure and associated goo */ if (p->p_emul == &emul_hpux) { register struct hpuxsigframe *hkfp; hkfp = (struct hpuxsigframe *)&kfp[1]; hkfp->hsf_signum = bsdtohpuxsig(kfp->sf_signum); hkfp->hsf_code = kfp->sf_code; hkfp->hsf_scp = (struct sigcontext *) &((struct hpuxsigframe *)(&fp[1]))->hsf_sc; hkfp->hsf_sc.hsc_syscall = 0; /* XXX */ hkfp->hsf_sc.hsc_action = 0; /* XXX */ hkfp->hsf_sc.hsc_pad1 = hkfp->hsf_sc.hsc_pad2 = 0; hkfp->hsf_sc.hsc_onstack = kfp->sf_sc.sc_onstack; hkfp->hsf_sc.hsc_mask = kfp->sf_sc.sc_mask; hkfp->hsf_sc.hsc_sp = kfp->sf_sc.sc_sp; hkfp->hsf_sc.hsc_ps = kfp->sf_sc.sc_ps; hkfp->hsf_sc.hsc_pc = kfp->sf_sc.sc_pc; hkfp->hsf_sc.hsc_pad = 0; hkfp->hsf_sc.hsc_magic = 0xdeadbeef; hkfp->hsf_sc.hsc_realsc = kfp->sf_scp; bcopy((caddr_t)frame->f_regs, (caddr_t)hkfp->hsf_regs, sizeof (hkfp->hsf_regs)); kfp->sf_signum = hkfp->hsf_signum; kfp->sf_scp = hkfp->hsf_scp; } #endif (void) copyout((caddr_t)kfp, (caddr_t)fp, fsize); frame->f_regs[SP] = (int)fp; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): sig %d scp %x fp %x sc_sp %x sc_ap %x\n", p->p_pid, sig, kfp->sf_scp, fp, kfp->sf_sc.sc_sp, kfp->sf_sc.sc_ap); #endif /* * Signal trampoline code is at base of user stack. */ frame->f_pc = (int)PS_STRINGS - (esigcode - sigcode); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif free((caddr_t)kfp, M_TEMP); } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * psl to gain improper priviledges or to cause * a machine fault. */ /* ARGSUSED */ sys_sigreturn(p, v, retval) struct proc *p; void *v; register_t *retval; { struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; register struct sigcontext *scp; register struct frame *frame; register int rf; struct sigcontext tsigc; struct sigstate tstate; int flags; scp = SCARG(uap, sigcntxp); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); #endif if ((int)scp & 1) return (EINVAL); #ifdef COMPAT_HPUX /* * Grab context as an HP-UX style context and determine if it * was one that we contructed in sendsig. */ if (p->p_emul == &emul_hpux) { struct hpuxsigcontext *hscp = (struct hpuxsigcontext *)scp; struct hpuxsigcontext htsigc; if (useracc((caddr_t)hscp, sizeof (*hscp), B_WRITE) == 0 || copyin((caddr_t)hscp, (caddr_t)&htsigc, sizeof htsigc)) return (EINVAL); /* * If not generated by sendsig or we cannot restore the * BSD-style sigcontext, just restore what we can -- state * will be lost, but them's the breaks. */ hscp = &htsigc; if (hscp->hsc_magic != 0xdeadbeef || (scp = hscp->hsc_realsc) == 0 || useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) { if (hscp->hsc_onstack & 01) p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; p->p_sigmask = hscp->hsc_mask &~ sigcantmask; frame = (struct frame *) p->p_md.md_regs; frame->f_regs[SP] = hscp->hsc_sp; frame->f_pc = hscp->hsc_pc; frame->f_sr = hscp->hsc_ps &~ PSL_USERCLR; return (EJUSTRETURN); } /* * Otherwise, overlay BSD context with possibly modified * HP-UX values. */ tsigc.sc_onstack = hscp->hsc_onstack; tsigc.sc_mask = hscp->hsc_mask; tsigc.sc_sp = hscp->hsc_sp; tsigc.sc_ps = hscp->hsc_ps; tsigc.sc_pc = hscp->hsc_pc; } else #endif /* * Test and fetch the context structure. * We grab it all at once for speed. */ if (useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) return (EINVAL); scp = &tsigc; if ((scp->sc_ps & (PSL_MBZ|PSL_IPL|PSL_S)) != 0) return (EINVAL); /* * Restore the user supplied information */ if (scp->sc_onstack & 01) p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; p->p_sigmask = scp->sc_mask &~ sigcantmask; frame = (struct frame *) p->p_md.md_regs; frame->f_regs[SP] = scp->sc_sp; frame->f_regs[A6] = scp->sc_fp; frame->f_pc = scp->sc_pc; frame->f_sr = scp->sc_ps; /* * Grab pointer to hardware state information. * If zero, the user is probably doing a longjmp. */ if ((rf = scp->sc_ap) == 0) return (EJUSTRETURN); /* * See if there is anything to do before we go to the * expense of copying in close to 1/2K of data */ flags = fuword((caddr_t)rf); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn(%d): sc_ap %x flags %x\n", p->p_pid, rf, flags); #endif /* * fuword failed (bogus sc_ap value). */ if (flags == -1) return (EINVAL); if (flags == 0 || copyin((caddr_t)rf, (caddr_t)&tstate, sizeof tstate)) return (EJUSTRETURN); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sigreturn(%d): ssp %x usp %x scp %x ft %d\n", p->p_pid, &flags, scp->sc_sp, SCARG(uap, sigcntxp), (flags&SS_RTEFRAME) ? tstate.ss_frame.f_format : -1); #endif /* * Restore most of the users registers except for A6 and SP * which were handled above. */ if (flags & SS_USERREGS) bcopy((caddr_t)tstate.ss_frame.f_regs, (caddr_t)frame->f_regs, sizeof(frame->f_regs)-2*NBPW); /* * Restore long stack frames. Note that we do not copy * back the saved SR or PC, they were picked up above from * the sigcontext structure. */ if (flags & SS_RTEFRAME) { register int sz; /* grab frame type and validate */ sz = tstate.ss_frame.f_format; if (sz > 15 || (sz = exframesize[sz]) < 0) return (EINVAL); frame->f_stackadj -= sz; frame->f_format = tstate.ss_frame.f_format; frame->f_vector = tstate.ss_frame.f_vector; bcopy((caddr_t)&tstate.ss_frame.F_u, (caddr_t)&frame->F_u, sz); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn(%d): copy in %d of frame type %d\n", p->p_pid, sz, tstate.ss_frame.f_format); #endif } #ifdef FPCOPROC /* * Finally we restore the original FP context */ if (flags & SS_FPSTATE) m68881_restore(&tstate.ss_fpstate); #ifdef DEBUG if ((sigdebug & SDB_FPSTATE) && *(char *)&tstate.ss_fpstate) printf("sigreturn(%d): copied in FP state (%x) at %x\n", p->p_pid, *(u_int *)&tstate.ss_fpstate, &tstate.ss_fpstate); #endif #endif #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) || ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)) printf("sigreturn(%d): returns\n", p->p_pid); #endif return (EJUSTRETURN); } int waittime = -1; static struct haltvec *halts; /* XXX insert by priority */ void halt_establish(fn, pri) void (*fn) __P((void)); int pri; { struct haltvec *hv, *h; hv = (struct haltvec *)malloc(sizeof(*hv), M_TEMP, M_NOWAIT); if (hv == NULL) return; hv->hv_fn = fn; hv->hv_pri = pri; hv->hv_next = NULL; /* put higher priorities earlier in the list */ h = halts; if (h == NULL) { halts = hv; return; } if (h->hv_pri < pri) { /* higher than first element */ hv->hv_next = halts; halts = hv; return; } while (h) { if (h->hv_next == NULL) { /* no more elements, must be the lowest priority */ h->hv_next = hv; return; } if (h->hv_next->hv_pri < pri) { /* next element is lower */ hv->hv_next = h->hv_next; h->hv_next = hv; return; } h = h->hv_next; } } void boot(howto) register int howto; { /* take a snap shot before clobbering any registers */ if (curproc && curproc->p_addr) savectx(curproc->p_addr); boothowto = howto; if ((howto&RB_NOSYNC) == 0 && waittime < 0) { waittime = 0; vfs_shutdown(); /* * If we've been adjusting the clock, the todr * will be out of synch; adjust it now. */ resettodr(); } splhigh(); /* extreme priority */ if (howto&RB_HALT) { printf("halted\n\n"); while (1) ; } else { struct haltvec *hv; if (howto & RB_DUMP) dumpsys(); for (hv = halts; hv; hv = hv->hv_next) (*hv->hv_fn)(); doboot(); } /*NOTREACHED*/ } /* * These variables are needed by /sbin/savecore */ u_long dumpmag = 0x8fca0101; /* magic number */ int dumpsize = 0; /* pages */ long dumplo = 0; /* blocks */ /* * This is called by configure to set dumplo and dumpsize. * Dumps always skip the first CLBYTES of disk space * in case there might be a disk label stored there. * If there is extra space, put dump at the end to * reduce the chance that swapping trashes it. */ void dumpconf() { int nblks; /* size of dump area */ int maj; if (dumpdev == NODEV) return; maj = major(dumpdev); if (maj < 0 || maj >= nblkdev) panic("dumpconf: bad dumpdev=0x%x", dumpdev); if (bdevsw[maj].d_psize == NULL) return; nblks = (*bdevsw[maj].d_psize)(dumpdev); if (nblks <= ctod(1)) return; /* * XXX include the final RAM page which is not included in physmem. */ dumpsize = physmem + 1; /* Always skip the first CLBYTES, in case there is a label there. */ if (dumplo < ctod(1)) dumplo = ctod(1); /* Put dump at end of partition, and make it fit. */ if (dumpsize > dtoc(nblks - dumplo)) dumpsize = dtoc(nblks - dumplo); if (dumplo < nblks - ctod(dumpsize)) dumplo = nblks - ctod(dumpsize); } /* * Doadump comes here after turning off memory management and * getting on the dump stack, either when called above, or by * the auto-restart code. */ dumpsys() { msgbufmapped = 0; if (dumpdev == NODEV) return; if (dumpsize == 0) { dumpconf(); if (dumpsize == 0) return; } printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); printf("dump "); switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { case ENXIO: printf("device bad\n"); break; case EFAULT: printf("device not ready\n"); break; case EINVAL: printf("area improper\n"); break; case EIO: printf("i/o error\n"); break; case EINTR: printf("aborted from console\n"); break; default: printf("succeeded\n"); break; } } initcpu() { #ifdef MAPPEDCOPY extern u_int mappedcopysize; /* * Initialize lower bound for doing copyin/copyout using * page mapping (if not already set). We don't do this on * VAC machines as it loses big time. */ if (mappedcopysize == 0) { mappedcopysize = NBPG; } #endif } straytrap(pc, evec) int pc; u_short evec; { printf("unexpected trap (vector %d) from %x\n", (evec & 0xFFF) >> 2, pc); } int *nofault; int badpaddr(addr, size) register caddr_t addr; int size; { int off = (int)addr & PGOFSET; caddr_t v, p = (caddr_t)((int)addr & ~PGOFSET); int x; v = mapiodev(p, NBPG); if (v == NULL) return (1); v += off; x = badvaddr(v + off, size); unmapiodev(v, NBPG); return (x); } int badvaddr(addr, size) register caddr_t addr; int size; { register int i; label_t faultbuf; #ifdef lint i = *addr; if (i) return(0); #endif nofault = (int *) &faultbuf; if (setjmp((label_t *)nofault)) { nofault = (int *)0; return (1); } switch (size) { case 1: i = *(volatile char *)addr; break; case 2: i = *(volatile short *)addr; break; case 4: i = *(volatile long *)addr; break; } nofault = (int *)0; return (0); } netintr() { #ifdef INET if (netisr & (1 << NETISR_ARP)) { netisr &= ~(1 << NETISR_ARP); arpintr(); } if (netisr & (1 << NETISR_IP)) { netisr &= ~(1 << NETISR_IP); ipintr(); } #endif #ifdef NS if (netisr & (1 << NETISR_NS)) { netisr &= ~(1 << NETISR_NS); nsintr(); } #endif #ifdef ISO if (netisr & (1 << NETISR_ISO)) { netisr &= ~(1 << NETISR_ISO); clnlintr(); } #endif #ifdef CCITT if (netisr & (1 << NETISR_CCITT)) { netisr &= ~(1 << NETISR_CCITT); ccittintr(); } #endif #include "ppp.h" #if NPPP > 0 if (netisr & (1 << NETISR_PPP)) { netisr &= ~(1 << NETISR_PPP); pppintr(); } #endif } /* * Level 7 interrupts are normally caused by the ABORT switch, * drop into ddb. */ nmihand(frame) struct frame *frame; { #ifdef DDB printf("NMI ... going to debugger\n"); Debugger(); #else /* panic?? */ printf("unexpected level 7 interrupt ignored\n"); #endif } regdump(fp, sbytes) struct frame *fp; /* must not be register */ int sbytes; { static int doingdump = 0; register int i; int s; extern char *hexstr(); if (doingdump) return; s = splhigh(); doingdump = 1; printf("pid = %d, pc = %s, ", curproc ? curproc->p_pid : -1, hexstr(fp->f_pc, 8)); printf("ps = %s, ", hexstr(fp->f_sr, 4)); printf("sfc = %s, ", hexstr(getsfc(), 4)); printf("dfc = %s\n", hexstr(getdfc(), 4)); printf("Registers:\n "); for (i = 0; i < 8; i++) printf(" %d", i); printf("\ndreg:"); for (i = 0; i < 8; i++) printf(" %s", hexstr(fp->f_regs[i], 8)); printf("\nareg:"); for (i = 0; i < 8; i++) printf(" %s", hexstr(fp->f_regs[i+8], 8)); if (sbytes > 0) { if (fp->f_sr & PSL_S) { printf("\n\nKernel stack (%s):", hexstr((int)(((int *)&fp)-1), 8)); dumpmem(((int *)&fp)-1, sbytes, 0); } else { printf("\n\nUser stack (%s):", hexstr(fp->f_regs[SP], 8)); dumpmem((int *)fp->f_regs[SP], sbytes, 1); } } doingdump = 0; splx(s); } #define KSADDR ((int *)((u_int)curproc->p_addr + USPACE - NBPG)) dumpmem(ptr, sz, ustack) register int *ptr; int sz, ustack; { register int i, val; extern char *hexstr(); for (i = 0; i < sz; i++) { if ((i & 7) == 0) printf("\n%s: ", hexstr((int)ptr, 6)); else printf(" "); if (ustack == 1) { if ((val = fuword(ptr++)) == -1) break; } else { if (ustack == 0 && (ptr < KSADDR || ptr > KSADDR+(NBPG/4-1))) break; val = *ptr++; } printf("%s", hexstr(val, 8)); } printf("\n"); } char * hexstr(val, len) register int val; int len; { static char nbuf[9]; register int x, i; if (len > 8) return(""); nbuf[len] = '\0'; for (i = len-1; i >= 0; --i) { x = val & 0xF; if (x > 9) nbuf[i] = x - 10 + 'A'; else nbuf[i] = x + '0'; val >>= 4; } return(nbuf); } #ifdef STACKCHECK char oflowmsg[] = "k-stack overflow"; char uflowmsg[] = "k-stack underflow"; badkstack(oflow, fr) int oflow; struct frame fr; { extern char kstackatbase[]; printf("%s: sp should be %x\n", oflow ? oflowmsg : uflowmsg, kstackatbase - (exframesize[fr.f_format] + 8)); regdump(&fr, 0); panic(oflow ? oflowmsg : uflowmsg); } #endif /* * cpu_exec_aout_makecmds(): * cpu-dependent a.out format hook for execve(). * * Determine of the given exec package refers to something which we * understand and, if so, set up the vmcmds for it. */ cpu_exec_aout_makecmds(p, epp) struct proc *p; struct exec_package *epp; { int error = ENOEXEC; struct exec *execp = epp->ep_hdr; #ifdef COMPAT_SUNOS { extern sunos_exec_aout_makecmds __P((struct proc *, struct exec_package *)); if ((error = sunos_exec_aout_makecmds(p, epp)) == 0) return(0); } #endif return (error); } u_char myea[6] = { 0x08, 0x00, 0x3e, 0xff, 0xff, 0xff }; void myetheraddr(ether) u_char *ether; { bcopy(myea, ether, sizeof myea); } #if defined(M68030) || defined(M68020) int fpu_gettype() { /* * A 68881 idle frame is 28 bytes and a 68882's is 60 bytes. * We, of course, need to have enough room for either. */ int fpframe[60 / sizeof(int)]; label_t faultbuf; u_char b; nofault = (int *) &faultbuf; if (setjmp((label_t *)nofault)) { nofault = (int *)0; return (0); /* no FPU */ } /* * Synchronize FPU or cause a fault. * This should leave the 881/882 in the IDLE state, * state, so we can determine which we have by * examining the size of the FP state frame */ asm("fnop"); nofault = (int *)0; /* * Presumably, this will not cause a fault--the fnop should * have if this will. We save the state in order to get the * size of the frame. */ asm("movl %0, a0; fsave a0@" : : "a" (fpframe) : "a0" ); b = *((u_char *) fpframe + 1); /* * Now, restore a NULL state to reset the FPU. */ fpframe[0] = fpframe[1] = 0; m68881_restore(fpframe); if (b == 0x18) return (1); /* The size of a 68881 IDLE frame is 0x18 */ if (b == 0x38) return (2); /* 68882 frame is 0x38 bytes long */ return (3); /* unknown FPU type */ } #endif #ifdef MVME162 #include /* * XXX * used by locore.s to figure out how much memory is on the machine. * At this stage we only know that our machine is a 162. It is very * unfortunate that the MCchip's address must be encoded here. */ int memsize162() { struct mcreg *mc = (struct mcreg *)0xfff42000; switch (mc->mc_memoptions & MC_MEMOPTIONS_DRAMMASK) { case MC_MEMOPTIONS_DRAM1M: return (1*1024*1024); case MC_MEMOPTIONS_DRAM2M: return (2*1024*1024); case MC_MEMOPTIONS_DRAM4M: return (4*1024*1024); case MC_MEMOPTIONS_DRAM4M2: return (4*1024*1024); case MC_MEMOPTIONS_DRAM8M: return (8*1024*1024); case MC_MEMOPTIONS_DRAM16M: return (16*1024*1024); default: /* * XXX if the machine has no MC-controlled memory, * perhaps it has a MCECC or MEMC040 controller? */ return (memsize1x7()); } } #endif #if defined(MVME162) || defined(MVME167) || defined(MVME177) #include /* * XXX * finish writing this * 1) it is ugly * 2) it only looks at the first MEMC040/MCECC controller */ int memsize1x7() { struct memcreg *memc = (struct memcreg *)0xfff43000; u_long x; x = MEMC_MEMCONF_RTOB(memc->memc_memconf); return (x); } #endif