📄 machdep.c
字号:
/* * Copyright (c) 1988 University of Utah. * Copyright (c) 1992 OMRON Corporation. * Copyright (c) 1982, 1986, 1990, 1992, 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.63 91/04/24$ * from: hp300/hp300/machdep.c 8.3 (Berkeley) 11/14/93 * * @(#)machdep.c 8.3 (Berkeley) 1/12/94 */#include <sys/param.h>#include <sys/systm.h>#include <sys/signalvar.h>#include <sys/kernel.h>#include <sys/map.h>#include <sys/proc.h>#include <sys/buf.h>#include <sys/reboot.h>#include <sys/conf.h>#include <sys/file.h>#include <sys/clist.h>#include <sys/callout.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/msgbuf.h>#include <sys/ioctl.h>#include <sys/tty.h>#include <sys/mount.h>#include <sys/user.h>#include <sys/exec.h>#include <sys/sysctl.h>#ifdef SYSVSHM#include <sys/shm.h>#endif#include <machine/cpu.h>#include <machine/reg.h>#include <machine/psl.h>#include <luna68k/luna68k/cons.h>#include <luna68k/luna68k/pte.h>#include <net/netisr.h>#define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */#include <vm/vm_kern.h>/* the following is used externally (sysctl_hw) */char machine[] = "luna68k"; /* 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 NBUFint nbuf = NBUF;#elseint nbuf = 0;#endif#ifdef BUFPAGESint bufpages = BUFPAGES;#elseint bufpages = 0;#endifint 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 FPCOPROCint fpptype = -1;#endif/* * Console initialization: called early on from main, * before vm init or startup. Do enough configuration * to choose and initialize a console. */consinit(){ /* * Set cpuspeed immediately since cninit() called routines * might use delay. */ cpuspeed = MHZ_25; /* * Find what hardware is attached to this machine. */ find_devs(); /* * Initialize the console before we print anything out. */ cninit();}/* * cpu_startup: allocate memory for variable-sized tables, * initialize cpu, and do autoconfiguration. */cpu_startup(){ register unsigned i; register caddr_t v, firstaddr; int base, residual; vm_offset_t minaddr, maxaddr; vm_size_t size;#ifdef DEBUG extern int pmapdebug; int opmapdebug = pmapdebug; pmapdebug = 0;#endif /* * Initialize error message buffer (at end of core). */ for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) pmap_enter(kernel_pmap, (vm_offset_t)msgbufp, avail_end + i * NBPG, VM_PROT_ALL, TRUE); msgbufmapped = 1; /* * Good {morning,afternoon,evening,night}. */ printf(version); identifyfpu(); 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))) valloc(cfree, struct cblock, nclist); valloc(callout, struct callout, ncallout); valloc(swapmap, struct map, nswapmap = maxproc * 2);#ifdef SYSVSHM valloc(shmsegs, struct shmid_ds, shminfo.shmmni);#endif /* * Determine how many buffers to allocate. * Since HPs tend to be long on memory and short on disk speed, * we allocate more buffer space than the BSD standard of * use 10% of memory for the first 2 Meg, 5% of remaining. * We just allocate a flat 10%. 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 / 10 / 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"); 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 <residual> 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); /* * 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. */setregs(p, entry, retval) register struct proc *p; u_long entry; int retval[2];{ struct frame *frame = (struct frame *)p->p_md.md_regs; frame->f_pc = entry & ~1;#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}/* * Info for CTL_HW */extern char machine[];char cpu_model[120];extern char ostype[], osrelease[], version[];identifyfpu(){#ifdef LUNA2 if (machineid == LUNA_II) { sprintf(cpu_model, "LUNA-II (25MHz MC68040 CPU+MMU+FPU)"); printf("%s\n", cpu_model); return; }#endif if ( fpptype == -1 ) { printf("unknow FPU type \n"); panic("startup"); } sprintf(cpu_model, "LUNA-I (20MHz MC68030 CPU+MMU, 20MHz MC6888%d FPU)", fpptype); printf("%s\n", cpu_model);/* printf("LUNA(20Mhz MC68030 CPU, 20Mhz MC6888%d FPU)\n",fpptype); */}#define SS_RTEFRAME 1#define SS_FPSTATE 2#define SS_USERREGS 4struct 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 DEBUGint sigdebug = 0;int sigpid = 0;#define SDB_FOLLOW 0x01#define SDB_KSTACK 0x02#define SDB_FPSTATE 0x04#endif/* * Send an interrupt to process. */voidsendsig(catcher, sig, mask, code) sig_t catcher; int sig, mask; unsigned 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'. */ fsize = sizeof(struct sigframe); if ((psp->ps_flags & SAS_ALTSTACK) && (psp->ps_sigstk.ss_flags & SA_ONSTACK) == 0 && (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; (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. */struct sigreturn_args { struct sigcontext *sigcntxp;};/* ARGSUSED */sigreturn(p, uap, retval) struct proc *p; struct sigreturn_args *uap; int *retval;{ register struct sigcontext *scp; register struct frame *frame; register int rf; struct sigcontext tsigc; struct sigstate tstate; int flags; scp = 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); /* * 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -