📄 machdep.c
字号:
/*- * Copyright (c) 1982, 1987, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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. * * @(#)machdep.c 8.2 (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/user.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/sysctl.h>#include <net/netisr.h>#include <vm/vm.h>#include <vm/vm_kern.h>#include <vm/vm_page.h>vm_map_t buffer_map;extern vm_offset_t avail_end;#include <machine/cpu.h>#include <machine/reg.h>#include <machine/psl.h>#include <machine/specialreg.h>#include <i386/isa/rtc.h>#include <i386/i386/cons.h>/* * 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 *//* * Machine-dependent startup code */int boothowto = 0, Maxmem = 0;long dumplo;int physmem, maxmem;extern int bootdev;#ifdef SMALLextern int forcemaxmem;#endifint biosmem;extern cyloffset;cpu_startup(firstaddr) int firstaddr;{ register int unixsize; register unsigned i; register struct pte *pte; int mapaddr, j; register caddr_t v; int maxbufs, base, residual; extern long Usrptsize; vm_offset_t minaddr, maxaddr; vm_size_t size; /* * 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(kernel_pmap, msgbufp, avail_end + i * NBPG, VM_PROT_ALL, TRUE); msgbufmapped = 1;#ifdef KDB kdb_init(); /* startup kernel debugger */#endif /* * Good {morning,afternoon,evening,night}. */ printf(version); 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. * Use 10% of memory for the first 2 Meg, 5% of the remaining * memory. Insure a minimum of 16 buffers. * We allocate 1/2 as many swap buffer headers as file i/o buffers. */ if (bufpages == 0) if (physmem < (2 * 1024 * 1024)) bufpages = physmem / 10 / CLSIZE; else bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE; if (nbuf == 0) { nbuf = bufpages / 2; 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 = (int)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; /*printf("avail mem = %d\n", ptoa(vm_page_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();}#ifdef PGINPROF/* * Return the difference (in microseconds) * between the current time and a previous * time as represented by the arguments. * If there is a pending clock interrupt * which has not been serviced due to high * ipl, return error code. *//*ARGSUSED*/vmtime(otime, olbolt, oicr) register int otime, olbolt, oicr;{ return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);}#endifstruct sigframe { int sf_signum; int sf_code; struct sigcontext *sf_scp; sig_t sf_handler; int sf_eax; int sf_edx; int sf_ecx; struct sigcontext sf_sc;} ;extern int kstack[];/* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * in u. to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */voidsendsig(catcher, sig, mask, code) sig_t catcher; int sig, mask; unsigned code;{ register struct proc *p = curproc; register int *regs; register struct sigframe *fp; struct sigacts *psp = p->p_sigacts; int oonstack, frmtrap; regs = p->p_md.md_regs; oonstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; frmtrap = curpcb->pcb_flags & FM_TRAP; /* * 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'. */ 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 - sizeof(struct sigframe)); psp->ps_sigstk.ss_flags |= SA_ONSTACK; } else { if (frmtrap) fp = (struct sigframe *)(regs[tESP] - sizeof(struct sigframe)); else fp = (struct sigframe *)(regs[sESP] - sizeof(struct sigframe)); } if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) (void)grow(p, (unsigned)fp); if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) { /* * 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; } /* * Build the argument list for the signal handler. */ fp->sf_signum = sig; fp->sf_code = code; fp->sf_scp = &fp->sf_sc; fp->sf_handler = catcher; /* save scratch registers */ if(frmtrap) { fp->sf_eax = regs[tEAX]; fp->sf_edx = regs[tEDX]; fp->sf_ecx = regs[tECX]; } else { fp->sf_eax = regs[sEAX]; fp->sf_edx = regs[sEDX]; fp->sf_ecx = regs[sECX]; } /* * Build the signal context to be used by sigreturn. */ fp->sf_sc.sc_onstack = oonstack; fp->sf_sc.sc_mask = mask; if(frmtrap) { fp->sf_sc.sc_sp = regs[tESP]; fp->sf_sc.sc_fp = regs[tEBP]; fp->sf_sc.sc_pc = regs[tEIP]; fp->sf_sc.sc_ps = regs[tEFLAGS]; regs[tESP] = (int)fp; regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc; } else { fp->sf_sc.sc_sp = regs[sESP]; fp->sf_sc.sc_fp = regs[sEBP]; fp->sf_sc.sc_pc = regs[sEIP]; fp->sf_sc.sc_ps = regs[sEFLAGS]; regs[sESP] = (int)fp; regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc; }}/* * 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;};sigreturn(p, uap, retval) struct proc *p; struct sigreturn_args *uap; int *retval;{ register struct sigcontext *scp; register struct sigframe *fp; register int *regs = p->p_md.md_regs; fp = (struct sigframe *) regs[sESP] ; if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0) return(EINVAL); /* restore scratch registers */ regs[sEAX] = fp->sf_eax ; regs[sEDX] = fp->sf_edx ; regs[sECX] = fp->sf_ecx ; scp = fp->sf_scp; if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0) return(EINVAL);#ifdef notyet if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) { return(EINVAL); }#endif 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 &~ (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP)); regs[sEBP] = scp->sc_fp; regs[sESP] = scp->sc_sp; regs[sEIP] = scp->sc_pc; regs[sEFLAGS] = scp->sc_ps; return(EJUSTRETURN);}int waittime = -1;boot(arghowto) int arghowto;{ register long dummy; /* r12 is reserved */ register int howto; /* r11 == how to boot */ register int devtype; /* r10 == major of root dev */ extern char *panicstr;extern int cold; howto = arghowto; if ((howto&RB_NOSYNC) == 0 && waittime < 0) { register struct buf *bp; int iter, nbusy; waittime = 0; (void) splnet(); printf("syncing disks... "); /* * Release inodes held by texts before update. */ if (panicstr == 0) vnode_pager_umount(NULL); sync((struct sigcontext *)0); for (iter = 0; iter < 20; iter++) { nbusy = 0; for (bp = &buf[nbuf]; --bp >= buf; ) if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY) nbusy++; if (nbusy == 0) break; printf("%d ", nbusy); DELAY(40000 * iter); } if (nbusy) printf("giving up\n"); else printf("done\n"); DELAY(10000); /* wait for printf to finish */ } splhigh(); devtype = major(rootdev); if (howto&RB_HALT) { printf("halting (in tight loop); hit reset\n\n"); splx(0xfffd); /* all but keyboard XXX */ for (;;) ; } else { if (howto & RB_DUMP) { dumpsys(); /*NOTREACHED*/ } }#ifdef lint dummy = 0; dummy = dummy; printf("howto %d, devtype %d\n", arghowto, devtype);#endif#ifdef notdef pg("pausing (hit any key to reset)");#endif reset_cpu(); for(;;) ; /*NOTREACHED*/}int dumpmag = 0x8fca0101; /* magic number for savecore */int dumpsize = 0; /* also for savecore *//* * 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(){ if (dumpdev == NODEV) return; if ((minor(dumpdev)&07) != 1) return; dumpsize = physmem; printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -